Better focus on Android TV

(Thank you ocean for reporting)
This commit is contained in:
Lag 2023-03-18 23:55:58 +01:00
parent 5245eff6e1
commit 4235c826a5
6 changed files with 71 additions and 27 deletions

View file

@ -185,7 +185,7 @@ open class ParentItemAdapter(
) :
RecyclerView.ViewHolder(itemView) {
val title: TextView = itemView.home_child_more_info
val recyclerView: RecyclerView = itemView.home_child_recyclerview
private val recyclerView: RecyclerView = itemView.home_child_recyclerview
fun update(expand: HomeViewModel.ExpandableHomepageList) {
val info = expand.list

View file

@ -7,13 +7,13 @@ import androidx.recyclerview.widget.RecyclerView
import com.lagradost.cloudstream3.mvvm.logError
fun RecyclerView?.setLinearListLayout(isHorizontal: Boolean = true) {
if(this == null) return
if (this == null) return
this.layoutManager =
this.context?.let { LinearListLayout(it).apply { if (isHorizontal) setHorizontal() else setVertical() } }
?: this.layoutManager
}
class LinearListLayout(context: Context?) :
open class LinearListLayout(context: Context?) :
LinearLayoutManager(context) {
fun setHorizontal() {
@ -24,7 +24,8 @@ class LinearListLayout(context: Context?) :
orientation = VERTICAL
}
private fun getCorrectParent(focused: View): View? {
private fun getCorrectParent(focused: View?): View? {
if (focused == null) return null
var current: View? = focused
val last: ArrayList<View> = arrayListOf(focused)
while (current != null && current !is RecyclerView) {
@ -54,10 +55,17 @@ class LinearListLayout(context: Context?) :
linearSmoothScroller.targetPosition = position
startSmoothScroll(linearSmoothScroller)
}*/
override fun onInterceptFocusSearch(focused: View, direction: Int): View? {
val dir = if (orientation == HORIZONTAL) {
if (direction == View.FOCUS_DOWN || direction == View.FOCUS_UP) return null
if (direction == View.FOCUS_DOWN || direction == View.FOCUS_UP) {
// This scrolls the recyclerview before doing focus search, which
// allows the focus search to work better.
// Without this the recyclerview focus location on the screen
// would change when scrolling between recyclerviews.
(focused.parent as? RecyclerView)?.focusSearch(direction)
return null
}
if (direction == View.FOCUS_RIGHT) 1 else -1
} else {
if (direction == View.FOCUS_RIGHT || direction == View.FOCUS_LEFT) return null

View file

@ -22,6 +22,7 @@ import androidx.core.view.isVisible
import androidx.core.widget.doOnTextChanged
import androidx.lifecycle.ViewModelProvider
import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.RecyclerView
import com.discord.panels.OverlappingPanelsLayout
import com.google.android.material.chip.Chip
import com.google.android.material.chip.ChipDrawable
@ -531,6 +532,25 @@ open class ResultFragment : ResultTrailerPlayer() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
result_cast_items?.layoutManager = object : LinearListLayout(view.context) {
override fun onRequestChildFocus(
parent: RecyclerView,
state: RecyclerView.State,
child: View,
focused: View?
): Boolean {
// Make the cast always focus the first visible item when focused
// from somewhere else. Otherwise it jumps to the last item.
return if (parent.focusedChild == null) {
scrollToPosition(this.findFirstCompletelyVisibleItemPosition())
true
} else {
super.onRequestChildFocus(parent, state, child, focused)
}
}
}.apply {
this.orientation = RecyclerView.HORIZONTAL
}
result_cast_items?.adapter = ActorAdaptor()
updateUIListener = ::updateUI

View file

@ -157,6 +157,28 @@ class SettingsAccount : PreferenceFragmentCompat() {
)
dialog.dismissSafe()
}
val displayedItems = listOf(
dialog.login_username_input,
dialog.login_email_input,
dialog.login_server_input,
dialog.login_password_input
).filter { it.isVisible }
displayedItems.foldRight(displayedItems.firstOrNull()) { item, previous ->
item?.id?.let { previous?.nextFocusDownId = it }
previous?.id?.let { item?.nextFocusUpId = it }
item
}
displayedItems.firstOrNull()?.let {
dialog.create_account?.nextFocusDownId = it.id
it.nextFocusUpId = dialog.create_account.id
}
dialog.apply_btt?.id?.let {
displayedItems.lastOrNull()?.nextFocusDownId = it
}
dialog.text1?.text = api.name
if (api.storesPasswordInPlainText) {

View file

@ -199,17 +199,13 @@
android:id="@+id/result_back"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_gravity="center_vertical"
android:layout_marginEnd="10dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:clickable="true"
android:contentDescription="@string/go_back"
android:focusable="true"
android:gravity="center_vertical"
android:nextFocusDown="@id/result_description"
android:src="@drawable/ic_baseline_arrow_back_24"
app:tint="?attr/white" />
@ -385,8 +381,8 @@
<com.google.android.material.chip.ChipGroup
style="@style/ChipParent"
android:id="@+id/result_tag"
style="@style/ChipParent"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
@ -423,11 +419,11 @@
<LinearLayout
android:animateLayoutChanges="true"
android:id="@+id/result_movie_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:animateLayoutChanges="true"
android:orientation="horizontal"
tools:visibility="visible">
@ -568,6 +564,7 @@
android:layout_weight="1"
android:minWidth="250dp"
android:nextFocusLeft="@id/result_movie_progress_downloaded_holder"
android:nextFocusRight="@id/result_bookmark_button"
android:nextFocusDown="@id/result_resume_series_button_play"
android:text="@string/type_none"
android:visibility="visible" />

View file

@ -2,33 +2,30 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_marginStart="@dimen/navbar_width"
android:id="@+id/home_child_more_info"
android:padding="12dp"
style="@style/WatchHeaderText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/WatchHeaderText"
android:layout_marginStart="@dimen/navbar_width"
android:layout_marginEnd="0dp"
android:padding="12dp"
tools:text="Trending" />
<androidx.recyclerview.widget.RecyclerView
android:nextFocusUp="@id/home_child_more_info"
android:paddingEnd="5dp"
android:paddingStart="@dimen/navbar_width"
android:clipToPadding="false"
android:descendantFocusability="afterDescendants"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
android:id="@+id/home_child_recyclerview"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:descendantFocusability="afterDescendants"
android:nextFocusUp="@id/home_child_more_info"
android:orientation="horizontal"
android:paddingStart="@dimen/navbar_width"
android:paddingEnd="5dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/home_result_grid" />
</LinearLayout>