android TV fix

This commit is contained in:
LagradOst 2021-11-28 13:18:01 +01:00
parent 53288cfaf1
commit b13c1eac01
9 changed files with 150 additions and 25 deletions

View file

@ -145,11 +145,75 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
} }
} }
enum class FocusDirection {
Left,
Right,
Up,
Down,
}
private fun getNextFocus(view: View?, direction: FocusDirection, depth: Int = 0): Int? {
if (view == null || depth >= 10) {
return null
}
val nextId = when (direction) {
FocusDirection.Left -> {
view.nextFocusLeftId
}
FocusDirection.Up -> {
view.nextFocusUpId
}
FocusDirection.Right -> {
view.nextFocusRightId
}
FocusDirection.Down -> {
view.nextFocusDownId
}
}
return if (nextId != -1) {
val next = findViewById<View?>(nextId)
//println("NAME: ${next.accessibilityClassName} | ${next?.isShown}" )
if (next?.isShown == false) {
getNextFocus(next, direction, depth + 1)
} else {
if (depth == 0) {
null
} else {
nextId
}
}
} else {
null
}
}
override fun dispatchKeyEvent(event: KeyEvent?): Boolean { override fun dispatchKeyEvent(event: KeyEvent?): Boolean {
event?.keyCode?.let { keyCode -> event?.keyCode?.let { keyCode ->
when (event.action) { when (event.action) {
ACTION_DOWN -> { ACTION_DOWN -> {
if (currentFocus != null) {
val next = when (keyCode) {
KeyEvent.KEYCODE_DPAD_LEFT -> getNextFocus(currentFocus, FocusDirection.Left)
KeyEvent.KEYCODE_DPAD_RIGHT -> getNextFocus(currentFocus, FocusDirection.Right)
KeyEvent.KEYCODE_DPAD_UP -> getNextFocus(currentFocus, FocusDirection.Up)
KeyEvent.KEYCODE_DPAD_DOWN -> getNextFocus(currentFocus, FocusDirection.Down)
else -> null
}
if (next != null && next != -1) {
val nextView = findViewById<View?>(next)
if(nextView != null) {
nextView.requestFocus()
return true
}
}
when (keyCode) { when (keyCode) {
KeyEvent.KEYCODE_DPAD_CENTER -> { KeyEvent.KEYCODE_DPAD_CENTER -> {
println("DPAD PRESSED $currentFocus") println("DPAD PRESSED $currentFocus")
if (currentFocus is SearchView || currentFocus is SearchView.SearchAutoComplete) { if (currentFocus is SearchView || currentFocus is SearchView.SearchAutoComplete) {
@ -158,7 +222,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
} }
} }
} }
}
//println("Keycode: $keyCode") //println("Keycode: $keyCode")
//showToast( //showToast(
// this, // this,
@ -169,7 +233,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
} }
} }
if(keyEventListener?.invoke(event) == true) { if (keyEventListener?.invoke(event) == true) {
return true return true
} }
return super.dispatchKeyEvent(event) return super.dispatchKeyEvent(event)

View file

@ -12,13 +12,19 @@ import com.lagradost.cloudstream3.ui.search.SearchResultBuilder
class HomeChildItemAdapter( class HomeChildItemAdapter(
var cardList: List<SearchResponse>, var cardList: List<SearchResponse>,
val layout: Int = R.layout.home_result_grid, val layout: Int = R.layout.home_result_grid,
private val clickCallback: (SearchClickCallback) -> Unit private val nextFocusUp: Int? = null,
private val nextFocusDown: Int? = null,
private val clickCallback: (SearchClickCallback) -> Unit,
) : ) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() { RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return CardViewHolder( return CardViewHolder(
LayoutInflater.from(parent.context).inflate(layout, parent, false), clickCallback, itemCount LayoutInflater.from(parent.context).inflate(layout, parent, false),
clickCallback,
itemCount,
nextFocusUp,
nextFocusDown
) )
} }
@ -39,19 +45,23 @@ class HomeChildItemAdapter(
} }
class CardViewHolder class CardViewHolder
constructor(itemView: View, private val clickCallback: (SearchClickCallback) -> Unit, val itemCount: Int) : constructor(
itemView: View, private val clickCallback: (SearchClickCallback) -> Unit, private val itemCount: Int,
private val nextFocusUp: Int? = null,
private val nextFocusDown: Int? = null,
) :
RecyclerView.ViewHolder(itemView) { RecyclerView.ViewHolder(itemView) {
fun bind(card: SearchResponse, index: Int) { fun bind(card: SearchResponse, index: Int) {
// TV focus fixing // TV focus fixing
val nextFocusBehavior = when(index){ val nextFocusBehavior = when (index) {
0 -> true 0 -> true
itemCount - 1 -> false itemCount - 1 -> false
else -> null else -> null
} }
SearchResultBuilder.bind(clickCallback, card, itemView, nextFocusBehavior) SearchResultBuilder.bind(clickCallback, card, itemView, nextFocusBehavior, nextFocusUp, nextFocusDown)
itemView.tag = index itemView.tag = index
//val ani = ScaleAnimation(0.9f, 1.0f, 0.9f, 1f) //val ani = ScaleAnimation(0.9f, 1.0f, 0.9f, 1f)
//ani.fillAfter = true //ani.fillAfter = true

View file

@ -35,6 +35,7 @@ import com.lagradost.cloudstream3.ui.result.START_ACTION_RESUME_LATEST
import com.lagradost.cloudstream3.ui.search.* import com.lagradost.cloudstream3.ui.search.*
import com.lagradost.cloudstream3.ui.search.SearchFragment.Companion.filterSearchResponse import com.lagradost.cloudstream3.ui.search.SearchFragment.Companion.filterSearchResponse
import com.lagradost.cloudstream3.ui.search.SearchHelper.handleSearchClickCallback import com.lagradost.cloudstream3.ui.search.SearchHelper.handleSearchClickCallback
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
import com.lagradost.cloudstream3.utils.AppUtils import com.lagradost.cloudstream3.utils.AppUtils
import com.lagradost.cloudstream3.utils.AppUtils.loadSearchResult import com.lagradost.cloudstream3.utils.AppUtils.loadSearchResult
import com.lagradost.cloudstream3.utils.DataStore.getKey import com.lagradost.cloudstream3.utils.DataStore.getKey
@ -212,7 +213,12 @@ class HomeFragment : Fragment() {
val randomSize = items.size val randomSize = items.size
home_main_poster_recyclerview.adapter = home_main_poster_recyclerview.adapter =
HomeChildItemAdapter(items, R.layout.home_result_big_grid) { callback -> HomeChildItemAdapter(
items,
R.layout.home_result_big_grid,
nextFocusUp = home_main_poster_recyclerview.nextFocusUpId,
nextFocusDown = home_main_poster_recyclerview.nextFocusDownId
) { callback ->
handleSearchClickCallback(activity, callback) handleSearchClickCallback(activity, callback)
} }
home_main_poster_recyclerview.post { home_main_poster_recyclerview.post {
@ -339,7 +345,11 @@ class HomeFragment : Fragment() {
} }
} }
home_bookmarked_child_recyclerview.adapter = HomeChildItemAdapter(ArrayList()) { callback -> home_bookmarked_child_recyclerview.adapter = HomeChildItemAdapter(
ArrayList(),
nextFocusUp = home_bookmarked_child_recyclerview?.nextFocusUpId,
nextFocusDown = home_bookmarked_child_recyclerview?.nextFocusDownId
) { callback ->
if (callback.action == SEARCH_ACTION_SHOW_METADATA) { if (callback.action == SEARCH_ACTION_SHOW_METADATA) {
val id = callback.card.id val id = callback.card.id
if (id != null) { if (id != null) {
@ -355,7 +365,11 @@ class HomeFragment : Fragment() {
} }
} }
home_watch_child_recyclerview.adapter = HomeChildItemAdapter(ArrayList()) { callback -> home_watch_child_recyclerview.adapter = HomeChildItemAdapter(
ArrayList(),
nextFocusUp = home_watch_child_recyclerview?.nextFocusUpId,
nextFocusDown = home_watch_child_recyclerview?.nextFocusDownId
) { callback ->
if (callback.action == SEARCH_ACTION_SHOW_METADATA) { if (callback.action == SEARCH_ACTION_SHOW_METADATA) {
val id = callback.card.id val id = callback.card.id
if (id != null) { if (id != null) {
@ -423,6 +437,16 @@ class HomeFragment : Fragment() {
// nice profile pic on homepage // nice profile pic on homepage
home_profile_picture_holder?.isVisible = false home_profile_picture_holder?.isVisible = false
context?.let { ctx -> context?.let { ctx ->
// just in case
if (ctx.isTvSettings()) {
home_change_api_loading?.isFocusable = true
home_change_api_loading?.isFocusableInTouchMode = true
home_change_api?.isFocusable = true
home_change_api?.isFocusableInTouchMode = true
home_bookmark_select?.isFocusable = true
home_bookmark_select?.isFocusableInTouchMode = true
}
for (syncApi in OAuth2API.OAuth2Apis) { for (syncApi in OAuth2API.OAuth2Apis) {
val login = syncApi.loginInfo(ctx) val login = syncApi.loginInfo(ctx)
val pic = login?.profilePicture val pic = login?.profilePicture
@ -433,5 +457,7 @@ class HomeFragment : Fragment() {
} }
} }
} }
} }
} }

View file

@ -47,7 +47,12 @@ class ParentItemAdapter(
private val moreInfo: FrameLayout = itemView.home_child_more_info private val moreInfo: FrameLayout = itemView.home_child_more_info
fun bind(info: HomePageList) { fun bind(info: HomePageList) {
title.text = info.name title.text = info.name
recyclerView.adapter = HomeChildItemAdapter(info.list, clickCallback = clickCallback) recyclerView.adapter = HomeChildItemAdapter(
info.list,
clickCallback = clickCallback,
nextFocusUp = recyclerView.nextFocusUpId,
nextFocusDown = recyclerView.nextFocusDownId
)
(recyclerView.adapter as HomeChildItemAdapter).notifyDataSetChanged() (recyclerView.adapter as HomeChildItemAdapter).notifyDataSetChanged()
moreInfo.setOnClickListener { moreInfo.setOnClickListener {

View file

@ -1018,7 +1018,7 @@ class PlayerFragment : Fragment() {
private fun handleKeyEvent(event: KeyEvent): Boolean { private fun handleKeyEvent(event: KeyEvent): Boolean {
event.keyCode.let { keyCode -> event.keyCode.let { keyCode ->
when (event.action) { when (keyCode) {
// don't allow dpad move when hidden // don't allow dpad move when hidden
KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_LEFT,
KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_DOWN,
@ -1032,6 +1032,17 @@ class PlayerFragment : Fragment() {
return true return true
} }
} }
// netflix capture back and hide ~monke
KeyEvent.KEYCODE_BACK -> {
if (isShowing) {
onClickChange()
return true
}
}
}
when (event.action) {
KeyEvent.ACTION_DOWN -> { KeyEvent.ACTION_DOWN -> {
when (keyCode) { when (keyCode) {
KeyEvent.KEYCODE_DPAD_CENTER -> { KeyEvent.KEYCODE_DPAD_CENTER -> {

View file

@ -38,7 +38,7 @@ class SearchAdapter(
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) { when (holder) {
is CardViewHolder -> { is CardViewHolder -> {
holder.bind(cardList[position]) holder.bind(cardList[position], position)
} }
} }
} }
@ -59,7 +59,7 @@ class SearchAdapter(
private val compactView = itemView.context.getGridIsCompact() private val compactView = itemView.context.getGridIsCompact()
private val coverHeight: Int = if (compactView) 80.toPx else (resView.itemWidth / 0.68).roundToInt() private val coverHeight: Int = if (compactView) 80.toPx else (resView.itemWidth / 0.68).roundToInt()
fun bind(card: SearchResponse) { fun bind(card: SearchResponse, position: Int) {
if (!compactView) { if (!compactView) {
cardView.apply { cardView.apply {
layoutParams = FrameLayout.LayoutParams( layoutParams = FrameLayout.LayoutParams(
@ -69,7 +69,7 @@ class SearchAdapter(
} }
} }
SearchResultBuilder.bind(clickCallback, card, itemView,) SearchResultBuilder.bind(clickCallback, card, itemView)
} }
} }
} }

View file

@ -22,7 +22,9 @@ object SearchResultBuilder {
clickCallback: (SearchClickCallback) -> Unit, clickCallback: (SearchClickCallback) -> Unit,
card: SearchResponse, card: SearchResponse,
itemView: View, itemView: View,
nextFocusBehavior: Boolean? = null nextFocusBehavior: Boolean? = null,
nextFocusUp: Int? = null,
nextFocusDown: Int? = null,
) { ) {
val cardView: ImageView = itemView.imageView val cardView: ImageView = itemView.imageView
val cardText: TextView? = itemView.imageText val cardText: TextView? = itemView.imageText
@ -57,6 +59,14 @@ object SearchResultBuilder {
) )
} }
if(nextFocusUp != null) {
bg.nextFocusUpId = nextFocusUp
}
if(nextFocusDown != null) {
bg.nextFocusDownId = nextFocusDown
}
when (nextFocusBehavior) { when (nextFocusBehavior) {
true -> bg.nextFocusLeftId = bg.id true -> bg.nextFocusLeftId = bg.id
false -> bg.nextFocusRightId = bg.id false -> bg.nextFocusRightId = bg.id

View file

@ -43,6 +43,7 @@
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
app:iconifiedByDefault="false" app:iconifiedByDefault="false"
tools:ignore="RtlSymmetry"> tools:ignore="RtlSymmetry">
<requestFocus/>
<androidx.core.widget.ContentLoadingProgressBar <androidx.core.widget.ContentLoadingProgressBar
android:id="@+id/search_loading_bar" android:id="@+id/search_loading_bar"
@ -75,7 +76,6 @@
android:layout_gravity="end|center_vertical" android:layout_gravity="end|center_vertical"
app:tint="?attr/textColor" app:tint="?attr/textColor"
android:contentDescription="@string/change_providers_img_des"> android:contentDescription="@string/change_providers_img_des">
<requestFocus/>
</ImageView> </ImageView>
</FrameLayout> </FrameLayout>

View file

@ -8,8 +8,6 @@
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<FrameLayout <FrameLayout
android:nextFocusDown="@id/home_child_recyclerview"
android:foreground="?android:attr/selectableItemBackgroundBorderless" android:foreground="?android:attr/selectableItemBackgroundBorderless"
android:id="@+id/home_child_more_info" android:id="@+id/home_child_more_info"
android:padding="12dp" android:padding="12dp"
@ -32,6 +30,7 @@
</FrameLayout> </FrameLayout>
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:nextFocusUp="@id/home_child_more_info"
android:paddingHorizontal="5dp" android:paddingHorizontal="5dp"
android:clipToPadding="false" android:clipToPadding="false"