forked from recloudstream/cloudstream
Probably fixed the extremely weird crashes on Android TV
This commit is contained in:
parent
da09310595
commit
3e09ea9704
3 changed files with 73 additions and 10 deletions
|
@ -60,7 +60,7 @@ class EpisodeAdapter(
|
||||||
private val clickCallback: (EpisodeClickEvent) -> Unit,
|
private val clickCallback: (EpisodeClickEvent) -> Unit,
|
||||||
private val downloadClickCallback: (DownloadClickEvent) -> Unit,
|
private val downloadClickCallback: (DownloadClickEvent) -> Unit,
|
||||||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||||
private var cardList: MutableList<ResultEpisode> = mutableListOf()
|
var cardList: MutableList<ResultEpisode> = mutableListOf()
|
||||||
|
|
||||||
private val mBoundViewHolders: HashSet<DownloadButtonViewHolder> = HashSet()
|
private val mBoundViewHolders: HashSet<DownloadButtonViewHolder> = HashSet()
|
||||||
private fun getAllBoundViewHolders(): Set<DownloadButtonViewHolder?>? {
|
private fun getAllBoundViewHolders(): Set<DownloadButtonViewHolder?>? {
|
||||||
|
@ -239,7 +239,6 @@ class EpisodeAdapter(
|
||||||
|
|
||||||
itemView.setOnLongClickListener {
|
itemView.setOnLongClickListener {
|
||||||
clickCallback.invoke(EpisodeClickEvent(ACTION_SHOW_OPTIONS, card))
|
clickCallback.invoke(EpisodeClickEvent(ACTION_SHOW_OPTIONS, card))
|
||||||
|
|
||||||
return@setOnLongClickListener true
|
return@setOnLongClickListener true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,6 +95,7 @@ import kotlinx.android.synthetic.main.fragment_result.result_vpn
|
||||||
import kotlinx.android.synthetic.main.fragment_result_swipe.*
|
import kotlinx.android.synthetic.main.fragment_result_swipe.*
|
||||||
import kotlinx.android.synthetic.main.fragment_result_tv.*
|
import kotlinx.android.synthetic.main.fragment_result_tv.*
|
||||||
import kotlinx.android.synthetic.main.result_sync.*
|
import kotlinx.android.synthetic.main.result_sync.*
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
|
||||||
|
|
||||||
|
@ -412,7 +413,39 @@ open class ResultFragment : ResultTrailerPlayer() {
|
||||||
is ResourceSome.Success -> {
|
is ResourceSome.Success -> {
|
||||||
result_episodes?.isVisible = true
|
result_episodes?.isVisible = true
|
||||||
result_episode_loading?.isVisible = false
|
result_episode_loading?.isVisible = false
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Okay so what is this fuckery?
|
||||||
|
* Basically Android TV will crash if you request a new focus while
|
||||||
|
* the adapter gets updated.
|
||||||
|
*
|
||||||
|
* This means that if you load thumbnails and request a next focus at the same time
|
||||||
|
* the app will crash without any way to catch it!
|
||||||
|
*
|
||||||
|
* How to bypass this?
|
||||||
|
* This code basically steals the focus for 500ms and puts it in an inescapable view
|
||||||
|
* then lets out the focus by requesting focus to result_episodes
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Do not use this.isTv, that is the player
|
||||||
|
val isTv = isTvSettings()
|
||||||
|
val hasEpisodes =
|
||||||
|
!(result_episodes?.adapter as? EpisodeAdapter?)?.cardList.isNullOrEmpty()
|
||||||
|
|
||||||
|
if (isTv && hasEpisodes) {
|
||||||
|
// Make it impossible to focus anywhere else!
|
||||||
|
temporary_no_focus?.isFocusable = true
|
||||||
|
temporary_no_focus?.requestFocus()
|
||||||
|
}
|
||||||
|
|
||||||
(result_episodes?.adapter as? EpisodeAdapter?)?.updateList(episodes.value)
|
(result_episodes?.adapter as? EpisodeAdapter?)?.updateList(episodes.value)
|
||||||
|
|
||||||
|
if (isTv && hasEpisodes) main {
|
||||||
|
delay(500)
|
||||||
|
temporary_no_focus?.isFocusable = false
|
||||||
|
// This might make some people sad as it changes the focus when leaving an episode :(
|
||||||
|
result_episodes?.requestFocus()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -458,7 +491,14 @@ open class ResultFragment : ResultTrailerPlayer() {
|
||||||
val storedData = getStoredData(activity ?: context ?: return) ?: return
|
val storedData = getStoredData(activity ?: context ?: return) ?: return
|
||||||
|
|
||||||
//viewModel.clear()
|
//viewModel.clear()
|
||||||
viewModel.load(activity, storedData.url ?: return, storedData.apiName, storedData.showFillers, storedData.dubStatus, storedData.start)
|
viewModel.load(
|
||||||
|
activity,
|
||||||
|
storedData.url ?: return,
|
||||||
|
storedData.apiName,
|
||||||
|
storedData.showFillers,
|
||||||
|
storedData.dubStatus,
|
||||||
|
storedData.start
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -916,7 +956,14 @@ open class ResultFragment : ResultTrailerPlayer() {
|
||||||
|
|
||||||
if (storedData?.url != null) {
|
if (storedData?.url != null) {
|
||||||
result_reload_connectionerror.setOnClickListener {
|
result_reload_connectionerror.setOnClickListener {
|
||||||
viewModel.load(activity, storedData.url, storedData.apiName, storedData.showFillers, storedData.dubStatus, storedData.start)
|
viewModel.load(
|
||||||
|
activity,
|
||||||
|
storedData.url,
|
||||||
|
storedData.apiName,
|
||||||
|
storedData.showFillers,
|
||||||
|
storedData.dubStatus,
|
||||||
|
storedData.start
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
result_reload_connection_open_in_browser?.setOnClickListener {
|
result_reload_connection_open_in_browser?.setOnClickListener {
|
||||||
|
@ -952,7 +999,14 @@ open class ResultFragment : ResultTrailerPlayer() {
|
||||||
|
|
||||||
if (restart || !viewModel.hasLoaded()) {
|
if (restart || !viewModel.hasLoaded()) {
|
||||||
//viewModel.clear()
|
//viewModel.clear()
|
||||||
viewModel.load(activity, storedData.url, storedData.apiName, storedData.showFillers, storedData.dubStatus, storedData.start)
|
viewModel.load(
|
||||||
|
activity,
|
||||||
|
storedData.url,
|
||||||
|
storedData.apiName,
|
||||||
|
storedData.showFillers,
|
||||||
|
storedData.dubStatus,
|
||||||
|
storedData.start
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -420,14 +420,14 @@
|
||||||
|
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:nextFocusRight="@id/result_bookmark_button"
|
|
||||||
android:id="@+id/result_movie_progress_downloaded_holder"
|
android:id="@+id/result_movie_progress_downloaded_holder"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="5dp"
|
android:layout_marginStart="5dp"
|
||||||
android:layout_marginEnd="5dp"
|
android:layout_marginEnd="5dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:minWidth="250dp">
|
android:minWidth="250dp"
|
||||||
|
android:nextFocusRight="@id/result_bookmark_button">
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/result_download_movie"
|
android:id="@+id/result_download_movie"
|
||||||
|
@ -510,17 +510,17 @@
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:nextFocusLeft="@id/result_movie_progress_downloaded_holder"
|
|
||||||
android:nextFocusDown="@id/result_resume_series_button_play"
|
|
||||||
|
|
||||||
android:id="@+id/result_bookmark_button"
|
android:id="@+id/result_bookmark_button"
|
||||||
style="@style/BlackButton"
|
style="@style/BlackButton"
|
||||||
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_marginStart="5dp"
|
android:layout_marginStart="5dp"
|
||||||
android:layout_marginEnd="5dp"
|
android:layout_marginEnd="5dp"
|
||||||
android:layout_marginBottom="10dp"
|
android:layout_marginBottom="10dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:minWidth="250dp"
|
android:minWidth="250dp"
|
||||||
|
android:nextFocusLeft="@id/result_movie_progress_downloaded_holder"
|
||||||
|
android:nextFocusDown="@id/result_resume_series_button_play"
|
||||||
android:text="@string/type_none"
|
android:text="@string/type_none"
|
||||||
android:visibility="visible" />
|
android:visibility="visible" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
@ -753,6 +753,16 @@
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
tools:listitem="@layout/result_episode" />
|
tools:listitem="@layout/result_episode" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/temporary_no_focus"
|
||||||
|
android:layout_width="1dp"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:focusable="false"
|
||||||
|
android:nextFocusLeft="@id/temporary_no_focus"
|
||||||
|
android:nextFocusRight="@id/temporary_no_focus"
|
||||||
|
android:nextFocusUp="@id/temporary_no_focus"
|
||||||
|
android:nextFocusDown="@id/temporary_no_focus" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue