Probably fixed the extremely weird crashes on Android TV

This commit is contained in:
Blatzar 2022-09-22 19:38:45 +02:00
parent da09310595
commit 3e09ea9704
3 changed files with 73 additions and 10 deletions

View file

@ -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
} }

View file

@ -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
)
} }
} }
} }

View file

@ -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>