forked from recloudstream/cloudstream
Better focus on Android TV
(Thank you ocean for reporting)
This commit is contained in:
parent
5245eff6e1
commit
4235c826a5
6 changed files with 71 additions and 27 deletions
|
@ -185,7 +185,7 @@ open class ParentItemAdapter(
|
||||||
) :
|
) :
|
||||||
RecyclerView.ViewHolder(itemView) {
|
RecyclerView.ViewHolder(itemView) {
|
||||||
val title: TextView = itemView.home_child_more_info
|
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) {
|
fun update(expand: HomeViewModel.ExpandableHomepageList) {
|
||||||
val info = expand.list
|
val info = expand.list
|
||||||
|
|
|
@ -13,7 +13,7 @@ fun RecyclerView?.setLinearListLayout(isHorizontal: Boolean = true) {
|
||||||
?: this.layoutManager
|
?: this.layoutManager
|
||||||
}
|
}
|
||||||
|
|
||||||
class LinearListLayout(context: Context?) :
|
open class LinearListLayout(context: Context?) :
|
||||||
LinearLayoutManager(context) {
|
LinearLayoutManager(context) {
|
||||||
|
|
||||||
fun setHorizontal() {
|
fun setHorizontal() {
|
||||||
|
@ -24,7 +24,8 @@ class LinearListLayout(context: Context?) :
|
||||||
orientation = VERTICAL
|
orientation = VERTICAL
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getCorrectParent(focused: View): View? {
|
private fun getCorrectParent(focused: View?): View? {
|
||||||
|
if (focused == null) return null
|
||||||
var current: View? = focused
|
var current: View? = focused
|
||||||
val last: ArrayList<View> = arrayListOf(focused)
|
val last: ArrayList<View> = arrayListOf(focused)
|
||||||
while (current != null && current !is RecyclerView) {
|
while (current != null && current !is RecyclerView) {
|
||||||
|
@ -54,10 +55,17 @@ class LinearListLayout(context: Context?) :
|
||||||
linearSmoothScroller.targetPosition = position
|
linearSmoothScroller.targetPosition = position
|
||||||
startSmoothScroll(linearSmoothScroller)
|
startSmoothScroll(linearSmoothScroller)
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
override fun onInterceptFocusSearch(focused: View, direction: Int): View? {
|
override fun onInterceptFocusSearch(focused: View, direction: Int): View? {
|
||||||
val dir = if (orientation == HORIZONTAL) {
|
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
|
if (direction == View.FOCUS_RIGHT) 1 else -1
|
||||||
} else {
|
} else {
|
||||||
if (direction == View.FOCUS_RIGHT || direction == View.FOCUS_LEFT) return null
|
if (direction == View.FOCUS_RIGHT || direction == View.FOCUS_LEFT) return null
|
||||||
|
|
|
@ -22,6 +22,7 @@ import androidx.core.view.isVisible
|
||||||
import androidx.core.widget.doOnTextChanged
|
import androidx.core.widget.doOnTextChanged
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.discord.panels.OverlappingPanelsLayout
|
import com.discord.panels.OverlappingPanelsLayout
|
||||||
import com.google.android.material.chip.Chip
|
import com.google.android.material.chip.Chip
|
||||||
import com.google.android.material.chip.ChipDrawable
|
import com.google.android.material.chip.ChipDrawable
|
||||||
|
@ -531,6 +532,25 @@ open class ResultFragment : ResultTrailerPlayer() {
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
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()
|
result_cast_items?.adapter = ActorAdaptor()
|
||||||
|
|
||||||
updateUIListener = ::updateUI
|
updateUIListener = ::updateUI
|
||||||
|
|
|
@ -157,6 +157,28 @@ class SettingsAccount : PreferenceFragmentCompat() {
|
||||||
)
|
)
|
||||||
dialog.dismissSafe()
|
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
|
dialog.text1?.text = api.name
|
||||||
|
|
||||||
if (api.storesPasswordInPlainText) {
|
if (api.storesPasswordInPlainText) {
|
||||||
|
|
|
@ -199,17 +199,13 @@
|
||||||
android:id="@+id/result_back"
|
android:id="@+id/result_back"
|
||||||
android:layout_width="30dp"
|
android:layout_width="30dp"
|
||||||
android:layout_height="30dp"
|
android:layout_height="30dp"
|
||||||
|
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_vertical"
|
||||||
android:layout_marginEnd="10dp"
|
android:layout_marginEnd="10dp"
|
||||||
|
|
||||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:contentDescription="@string/go_back"
|
android:contentDescription="@string/go_back"
|
||||||
|
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
|
|
||||||
android:nextFocusDown="@id/result_description"
|
android:nextFocusDown="@id/result_description"
|
||||||
android:src="@drawable/ic_baseline_arrow_back_24"
|
android:src="@drawable/ic_baseline_arrow_back_24"
|
||||||
app:tint="?attr/white" />
|
app:tint="?attr/white" />
|
||||||
|
@ -385,8 +381,8 @@
|
||||||
|
|
||||||
|
|
||||||
<com.google.android.material.chip.ChipGroup
|
<com.google.android.material.chip.ChipGroup
|
||||||
style="@style/ChipParent"
|
|
||||||
android:id="@+id/result_tag"
|
android:id="@+id/result_tag"
|
||||||
|
style="@style/ChipParent"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
@ -423,11 +419,11 @@
|
||||||
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:animateLayoutChanges="true"
|
|
||||||
android:id="@+id/result_movie_parent"
|
android:id="@+id/result_movie_parent"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="5dp"
|
android:layout_marginTop="5dp"
|
||||||
|
android:animateLayoutChanges="true"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
tools:visibility="visible">
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
@ -568,6 +564,7 @@
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:minWidth="250dp"
|
android:minWidth="250dp"
|
||||||
android:nextFocusLeft="@id/result_movie_progress_downloaded_holder"
|
android:nextFocusLeft="@id/result_movie_progress_downloaded_holder"
|
||||||
|
android:nextFocusRight="@id/result_bookmark_button"
|
||||||
android:nextFocusDown="@id/result_resume_series_button_play"
|
android:nextFocusDown="@id/result_resume_series_button_play"
|
||||||
android:text="@string/type_none"
|
android:text="@string/type_none"
|
||||||
android:visibility="visible" />
|
android:visibility="visible" />
|
||||||
|
|
|
@ -2,33 +2,30 @@
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_marginStart="@dimen/navbar_width"
|
|
||||||
android:id="@+id/home_child_more_info"
|
|
||||||
android:padding="12dp"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/home_child_more_info"
|
||||||
style="@style/WatchHeaderText"
|
style="@style/WatchHeaderText"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="@dimen/navbar_width"
|
||||||
android:layout_marginEnd="0dp"
|
android:layout_marginEnd="0dp"
|
||||||
|
android:padding="12dp"
|
||||||
tools:text="Trending" />
|
tools:text="Trending" />
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<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:id="@+id/home_child_recyclerview"
|
||||||
android:orientation="horizontal"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
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" />
|
tools:listitem="@layout/home_result_grid" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
Loading…
Reference in a new issue