forked from recloudstream/cloudstream
android TV fix
This commit is contained in:
parent
53288cfaf1
commit
b13c1eac01
9 changed files with 150 additions and 25 deletions
|
@ -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 {
|
||||
event?.keyCode?.let { keyCode ->
|
||||
when (event.action) {
|
||||
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) {
|
||||
|
||||
KeyEvent.KEYCODE_DPAD_CENTER -> {
|
||||
println("DPAD PRESSED $currentFocus")
|
||||
if (currentFocus is SearchView || currentFocus is SearchView.SearchAutoComplete) {
|
||||
|
@ -158,7 +222,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//println("Keycode: $keyCode")
|
||||
//showToast(
|
||||
// this,
|
||||
|
@ -169,7 +233,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
|||
}
|
||||
}
|
||||
|
||||
if(keyEventListener?.invoke(event) == true) {
|
||||
if (keyEventListener?.invoke(event) == true) {
|
||||
return true
|
||||
}
|
||||
return super.dispatchKeyEvent(event)
|
||||
|
|
|
@ -12,13 +12,19 @@ import com.lagradost.cloudstream3.ui.search.SearchResultBuilder
|
|||
class HomeChildItemAdapter(
|
||||
var cardList: List<SearchResponse>,
|
||||
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>() {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
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
|
||||
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) {
|
||||
|
||||
fun bind(card: SearchResponse, index: Int) {
|
||||
|
||||
// TV focus fixing
|
||||
val nextFocusBehavior = when(index){
|
||||
val nextFocusBehavior = when (index) {
|
||||
0 -> true
|
||||
itemCount - 1 -> false
|
||||
else -> null
|
||||
}
|
||||
|
||||
SearchResultBuilder.bind(clickCallback, card, itemView, nextFocusBehavior)
|
||||
SearchResultBuilder.bind(clickCallback, card, itemView, nextFocusBehavior, nextFocusUp, nextFocusDown)
|
||||
itemView.tag = index
|
||||
//val ani = ScaleAnimation(0.9f, 1.0f, 0.9f, 1f)
|
||||
//ani.fillAfter = true
|
||||
|
|
|
@ -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.SearchFragment.Companion.filterSearchResponse
|
||||
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.loadSearchResult
|
||||
import com.lagradost.cloudstream3.utils.DataStore.getKey
|
||||
|
@ -212,7 +213,12 @@ class HomeFragment : Fragment() {
|
|||
|
||||
val randomSize = items.size
|
||||
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)
|
||||
}
|
||||
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) {
|
||||
val id = callback.card.id
|
||||
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) {
|
||||
val id = callback.card.id
|
||||
if (id != null) {
|
||||
|
@ -423,6 +437,16 @@ class HomeFragment : Fragment() {
|
|||
// nice profile pic on homepage
|
||||
home_profile_picture_holder?.isVisible = false
|
||||
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) {
|
||||
val login = syncApi.loginInfo(ctx)
|
||||
val pic = login?.profilePicture
|
||||
|
@ -433,5 +457,7 @@ class HomeFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -47,7 +47,12 @@ class ParentItemAdapter(
|
|||
private val moreInfo: FrameLayout = itemView.home_child_more_info
|
||||
fun bind(info: HomePageList) {
|
||||
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()
|
||||
|
||||
moreInfo.setOnClickListener {
|
||||
|
|
|
@ -1018,7 +1018,7 @@ class PlayerFragment : Fragment() {
|
|||
|
||||
private fun handleKeyEvent(event: KeyEvent): Boolean {
|
||||
event.keyCode.let { keyCode ->
|
||||
when (event.action) {
|
||||
when (keyCode) {
|
||||
// don't allow dpad move when hidden
|
||||
KeyEvent.KEYCODE_DPAD_LEFT,
|
||||
KeyEvent.KEYCODE_DPAD_DOWN,
|
||||
|
@ -1032,6 +1032,17 @@ class PlayerFragment : Fragment() {
|
|||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// netflix capture back and hide ~monke
|
||||
KeyEvent.KEYCODE_BACK -> {
|
||||
if (isShowing) {
|
||||
onClickChange()
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
when (event.action) {
|
||||
KeyEvent.ACTION_DOWN -> {
|
||||
when (keyCode) {
|
||||
KeyEvent.KEYCODE_DPAD_CENTER -> {
|
||||
|
|
|
@ -38,7 +38,7 @@ class SearchAdapter(
|
|||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
when (holder) {
|
||||
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 coverHeight: Int = if (compactView) 80.toPx else (resView.itemWidth / 0.68).roundToInt()
|
||||
|
||||
fun bind(card: SearchResponse) {
|
||||
fun bind(card: SearchResponse, position: Int) {
|
||||
if (!compactView) {
|
||||
cardView.apply {
|
||||
layoutParams = FrameLayout.LayoutParams(
|
||||
|
@ -69,7 +69,7 @@ class SearchAdapter(
|
|||
}
|
||||
}
|
||||
|
||||
SearchResultBuilder.bind(clickCallback, card, itemView,)
|
||||
SearchResultBuilder.bind(clickCallback, card, itemView)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,9 @@ object SearchResultBuilder {
|
|||
clickCallback: (SearchClickCallback) -> Unit,
|
||||
card: SearchResponse,
|
||||
itemView: View,
|
||||
nextFocusBehavior: Boolean? = null
|
||||
nextFocusBehavior: Boolean? = null,
|
||||
nextFocusUp: Int? = null,
|
||||
nextFocusDown: Int? = null,
|
||||
) {
|
||||
val cardView: ImageView = itemView.imageView
|
||||
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) {
|
||||
true -> bg.nextFocusLeftId = bg.id
|
||||
false -> bg.nextFocusRightId = bg.id
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
android:layout_gravity="center_vertical"
|
||||
app:iconifiedByDefault="false"
|
||||
tools:ignore="RtlSymmetry">
|
||||
<requestFocus/>
|
||||
|
||||
<androidx.core.widget.ContentLoadingProgressBar
|
||||
android:id="@+id/search_loading_bar"
|
||||
|
@ -75,7 +76,6 @@
|
|||
android:layout_gravity="end|center_vertical"
|
||||
app:tint="?attr/textColor"
|
||||
android:contentDescription="@string/change_providers_img_des">
|
||||
<requestFocus/>
|
||||
</ImageView>
|
||||
</FrameLayout>
|
||||
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
android:layout_height="wrap_content">
|
||||
|
||||
<FrameLayout
|
||||
android:nextFocusDown="@id/home_child_recyclerview"
|
||||
|
||||
android:foreground="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:id="@+id/home_child_more_info"
|
||||
android:padding="12dp"
|
||||
|
@ -32,6 +30,7 @@
|
|||
</FrameLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:nextFocusUp="@id/home_child_more_info"
|
||||
android:paddingHorizontal="5dp"
|
||||
android:clipToPadding="false"
|
||||
|
||||
|
|
Loading…
Reference in a new issue