mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
testing follow focus on tv
This commit is contained in:
parent
51a6e917b5
commit
3e4a5bdf4c
7 changed files with 164 additions and 62 deletions
|
@ -83,7 +83,7 @@ object CommonActivity {
|
||||||
val act = activity ?: return
|
val act = activity ?: return
|
||||||
if (message == null) return
|
if (message == null) return
|
||||||
act.runOnUiThread {
|
act.runOnUiThread {
|
||||||
showToast(act, message.asString(act), duration)
|
showToast(act, message.asString(act), duration)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -443,63 +443,58 @@ object CommonActivity {
|
||||||
|
|
||||||
fun dispatchKeyEvent(act: Activity?, event: KeyEvent?): Boolean? {
|
fun dispatchKeyEvent(act: Activity?, event: KeyEvent?): Boolean? {
|
||||||
if (act == null) return null
|
if (act == null) return null
|
||||||
|
val currentFocus = act.currentFocus
|
||||||
|
|
||||||
event?.keyCode?.let { keyCode ->
|
event?.keyCode?.let { keyCode ->
|
||||||
when (event.action) {
|
if (currentFocus == null || event.action != KeyEvent.ACTION_DOWN) return@let
|
||||||
KeyEvent.ACTION_DOWN -> {
|
val next = when (keyCode) {
|
||||||
if (act.currentFocus != null) {
|
KeyEvent.KEYCODE_DPAD_LEFT -> getNextFocus(
|
||||||
val next = when (keyCode) {
|
act,
|
||||||
KeyEvent.KEYCODE_DPAD_LEFT -> getNextFocus(
|
currentFocus,
|
||||||
act,
|
FocusDirection.Left
|
||||||
act.currentFocus,
|
)
|
||||||
FocusDirection.Left
|
|
||||||
)
|
|
||||||
|
|
||||||
KeyEvent.KEYCODE_DPAD_RIGHT -> getNextFocus(
|
KeyEvent.KEYCODE_DPAD_RIGHT -> getNextFocus(
|
||||||
act,
|
act,
|
||||||
act.currentFocus,
|
currentFocus,
|
||||||
FocusDirection.Right
|
FocusDirection.Right
|
||||||
)
|
)
|
||||||
|
|
||||||
KeyEvent.KEYCODE_DPAD_UP -> getNextFocus(
|
KeyEvent.KEYCODE_DPAD_UP -> getNextFocus(
|
||||||
act,
|
act,
|
||||||
act.currentFocus,
|
currentFocus,
|
||||||
FocusDirection.Up
|
FocusDirection.Up
|
||||||
)
|
)
|
||||||
|
|
||||||
KeyEvent.KEYCODE_DPAD_DOWN -> getNextFocus(
|
KeyEvent.KEYCODE_DPAD_DOWN -> getNextFocus(
|
||||||
act,
|
act,
|
||||||
act.currentFocus,
|
currentFocus,
|
||||||
FocusDirection.Down
|
FocusDirection.Down
|
||||||
)
|
)
|
||||||
|
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
if (next != null && next != -1) {
|
if (next != null && next != -1) {
|
||||||
val nextView = act.findViewById<View?>(next)
|
val nextView = act.findViewById<View?>(next)
|
||||||
if (nextView != null) {
|
if (nextView != null) {
|
||||||
nextView.requestFocus()
|
nextView.requestFocus()
|
||||||
keyEventListener?.invoke(Pair(event, true))
|
keyEventListener?.invoke(Pair(event, true))
|
||||||
return true
|
return true
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
when (keyCode) {
|
|
||||||
KeyEvent.KEYCODE_DPAD_CENTER -> {
|
|
||||||
if (act.currentFocus is SearchView || act.currentFocus is SearchView.SearchAutoComplete) {
|
|
||||||
UIHelper.showInputMethod(act.currentFocus?.findFocus())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//println("Keycode: $keyCode")
|
|
||||||
//showToast(
|
|
||||||
// this,
|
|
||||||
// "Got Keycode $keyCode | ${KeyEvent.keyCodeToString(keyCode)} \n ${event?.action}",
|
|
||||||
// Toast.LENGTH_LONG
|
|
||||||
//)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER && (act.currentFocus is SearchView || act.currentFocus is SearchView.SearchAutoComplete)) {
|
||||||
|
UIHelper.showInputMethod(act.currentFocus?.findFocus())
|
||||||
|
}
|
||||||
|
|
||||||
|
//println("Keycode: $keyCode")
|
||||||
|
//showToast(
|
||||||
|
// this,
|
||||||
|
// "Got Keycode $keyCode | ${KeyEvent.keyCodeToString(keyCode)} \n ${event?.action}",
|
||||||
|
// Toast.LENGTH_LONG
|
||||||
|
//)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keyEventListener?.invoke(Pair(event, false)) == true) {
|
if (keyEventListener?.invoke(Pair(event, false)) == true) {
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package com.lagradost.cloudstream3
|
package com.lagradost.cloudstream3
|
||||||
|
|
||||||
|
import android.animation.ObjectAnimator
|
||||||
|
import android.animation.ValueAnimator
|
||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
@ -11,12 +13,17 @@ import android.os.Bundle
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.*
|
import android.view.*
|
||||||
|
import android.view.animation.Animation
|
||||||
|
import android.view.animation.AnimationSet
|
||||||
|
import android.widget.LinearLayout
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
import androidx.annotation.IdRes
|
import androidx.annotation.IdRes
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
import androidx.core.view.doOnLayout
|
||||||
|
import androidx.core.view.isGone
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
@ -28,12 +35,22 @@ import androidx.navigation.NavOptions
|
||||||
import androidx.navigation.fragment.NavHostFragment
|
import androidx.navigation.fragment.NavHostFragment
|
||||||
import androidx.navigation.ui.setupWithNavController
|
import androidx.navigation.ui.setupWithNavController
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import androidx.transition.ChangeBounds
|
||||||
|
import androidx.transition.ChangeTransform
|
||||||
|
import androidx.transition.Scene
|
||||||
|
import androidx.transition.TransitionManager
|
||||||
|
import androidx.transition.TransitionManager.beginDelayedTransition
|
||||||
|
import androidx.transition.TransitionSet
|
||||||
import com.fasterxml.jackson.databind.DeserializationFeature
|
import com.fasterxml.jackson.databind.DeserializationFeature
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||||
import com.google.android.gms.cast.framework.*
|
import com.google.android.gms.cast.framework.*
|
||||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
|
import com.google.android.material.button.MaterialButton
|
||||||
import com.google.android.material.navigationrail.NavigationRailView
|
import com.google.android.material.navigationrail.NavigationRailView
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import com.jaredrummler.android.colorpicker.ColorPickerDialogListener
|
import com.jaredrummler.android.colorpicker.ColorPickerDialogListener
|
||||||
|
@ -119,6 +136,7 @@ import com.lagradost.nicehttp.ResponseParser
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.lang.ref.WeakReference
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import java.net.URLDecoder
|
import java.net.URLDecoder
|
||||||
import java.nio.charset.Charset
|
import java.nio.charset.Charset
|
||||||
|
@ -553,7 +571,6 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun dispatchKeyEvent(event: KeyEvent?): Boolean {
|
override fun dispatchKeyEvent(event: KeyEvent?): Boolean {
|
||||||
CommonActivity.dispatchKeyEvent(this, event)?.let {
|
CommonActivity.dispatchKeyEvent(this, event)?.let {
|
||||||
return it
|
return it
|
||||||
|
@ -728,6 +745,68 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
var binding: ActivityMainBinding? = null
|
var binding: ActivityMainBinding? = null
|
||||||
|
var focusOutline: WeakReference<View> = WeakReference(null)
|
||||||
|
var lastFocus: WeakReference<View> = WeakReference(null)
|
||||||
|
val layoutListener: View.OnLayoutChangeListener =
|
||||||
|
View.OnLayoutChangeListener { v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom ->
|
||||||
|
updateFocusView(
|
||||||
|
v
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateFocusView(newFocus: View?) {
|
||||||
|
val focusOutline = focusOutline.get() ?: return
|
||||||
|
//lastFocus.get()?.removeOnLayoutChangeListener(layoutListener)
|
||||||
|
val wasGone = focusOutline.isGone
|
||||||
|
focusOutline.isVisible =
|
||||||
|
newFocus != null && newFocus.measuredHeight > 0 && newFocus.measuredWidth > 0 && newFocus.isVisible && newFocus !is MaterialButton
|
||||||
|
|
||||||
|
if (newFocus != null) {
|
||||||
|
lastFocus = WeakReference(newFocus)
|
||||||
|
|
||||||
|
val out = IntArray(2)
|
||||||
|
newFocus.getLocationInWindow(out)
|
||||||
|
val (x, y) = out
|
||||||
|
/*(newFocus.parent as? RecyclerView)?.let { recycle ->
|
||||||
|
println("PARET IS RECYLE")
|
||||||
|
val position = recycle.getChildAdapterPosition(newFocus)
|
||||||
|
recycle.scrollToPosition(position)
|
||||||
|
|
||||||
|
(recycle.layoutManager as? GridLayoutManager)?.let {
|
||||||
|
if(it.orientation == LinearLayout.HORIZONTAL) {
|
||||||
|
println("SCROLL")
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}*/
|
||||||
|
// newFocus.addOnLayoutChangeListener(layoutListener)
|
||||||
|
|
||||||
|
|
||||||
|
// val set = AnimationSet(true)
|
||||||
|
if(!wasGone) {
|
||||||
|
(focusOutline.parent as? ViewGroup)?.let {
|
||||||
|
TransitionManager.endTransitions(it)
|
||||||
|
TransitionManager.beginDelayedTransition(
|
||||||
|
it,
|
||||||
|
TransitionSet().addTransition(ChangeBounds())
|
||||||
|
.addTransition(ChangeTransform())
|
||||||
|
.setDuration(100)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ObjectAnimator.ofFloat(focusOutline, "translationX",focusOutline.translationX, x.toFloat()
|
||||||
|
|
||||||
|
|
||||||
|
focusOutline.layoutParams = focusOutline.layoutParams?.apply {
|
||||||
|
width = newFocus.measuredWidth
|
||||||
|
height = newFocus.measuredHeight
|
||||||
|
}
|
||||||
|
focusOutline.translationX = x.toFloat()
|
||||||
|
focusOutline.translationY = y.toFloat()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
app.initClient(this)
|
app.initClient(this)
|
||||||
|
@ -763,12 +842,12 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
||||||
// backup when we update the app, I don't trust myself to not boot lock users, might want to make this a setting?
|
// backup when we update the app, I don't trust myself to not boot lock users, might want to make this a setting?
|
||||||
try {
|
try {
|
||||||
val appVer = BuildConfig.VERSION_NAME
|
val appVer = BuildConfig.VERSION_NAME
|
||||||
val lastAppAutoBackup : String = getKey("VERSION_NAME") ?: ""
|
val lastAppAutoBackup: String = getKey("VERSION_NAME") ?: ""
|
||||||
if (appVer != lastAppAutoBackup) {
|
if (appVer != lastAppAutoBackup) {
|
||||||
setKey("VERSION_NAME", BuildConfig.VERSION_NAME)
|
setKey("VERSION_NAME", BuildConfig.VERSION_NAME)
|
||||||
backup()
|
backup()
|
||||||
}
|
}
|
||||||
} catch (t : Throwable) {
|
} catch (t: Throwable) {
|
||||||
logError(t)
|
logError(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -777,6 +856,15 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
||||||
if (isTvSettings()) {
|
if (isTvSettings()) {
|
||||||
val newLocalBinding = ActivityMainTvBinding.inflate(layoutInflater, null, false)
|
val newLocalBinding = ActivityMainTvBinding.inflate(layoutInflater, null, false)
|
||||||
setContentView(newLocalBinding.root)
|
setContentView(newLocalBinding.root)
|
||||||
|
focusOutline = WeakReference(newLocalBinding.focusOutline)
|
||||||
|
newLocalBinding.root.viewTreeObserver.addOnGlobalFocusChangeListener { _, newFocus ->
|
||||||
|
// println("refocus $oldFocus -> $newFocus")
|
||||||
|
updateFocusView(newFocus)
|
||||||
|
}
|
||||||
|
newLocalBinding.root.viewTreeObserver.addOnScrollChangedListener {
|
||||||
|
updateFocusView(lastFocus.get())
|
||||||
|
}
|
||||||
|
|
||||||
ActivityMainBinding.bind(newLocalBinding.root) // this may crash
|
ActivityMainBinding.bind(newLocalBinding.root) // this may crash
|
||||||
} else {
|
} else {
|
||||||
val newLocalBinding = ActivityMainBinding.inflate(layoutInflater, null, false)
|
val newLocalBinding = ActivityMainBinding.inflate(layoutInflater, null, false)
|
||||||
|
@ -816,7 +904,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
||||||
|
|
||||||
if (PluginManager.checkSafeModeFile()) {
|
if (PluginManager.checkSafeModeFile()) {
|
||||||
normalSafeApiCall {
|
normalSafeApiCall {
|
||||||
showToast( R.string.safe_mode_file, Toast.LENGTH_LONG)
|
showToast(R.string.safe_mode_file, Toast.LENGTH_LONG)
|
||||||
}
|
}
|
||||||
} else if (lastError == null) {
|
} else if (lastError == null) {
|
||||||
ioSafe {
|
ioSafe {
|
||||||
|
|
|
@ -2,9 +2,11 @@
|
||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
|
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||||
<stroke android:width="2dp"
|
<stroke android:width="2dp"
|
||||||
android:color="?attr/white"/>
|
android:color="?attr/white"/>
|
||||||
<corners
|
<!-- <corners
|
||||||
android:bottomLeftRadius="@dimen/rounded_image_radius"
|
android:bottomLeftRadius="@dimen/rounded_image_radius"
|
||||||
android:bottomRightRadius="@dimen/rounded_image_radius"
|
android:bottomRightRadius="@dimen/rounded_image_radius"
|
||||||
android:topLeftRadius="@dimen/rounded_image_radius"
|
android:topLeftRadius="@dimen/rounded_image_radius"
|
||||||
android:topRightRadius="@dimen/rounded_image_radius" />
|
android:topRightRadius="@dimen/rounded_image_radius" />
|
||||||
|
-->
|
||||||
|
|
||||||
</shape>
|
</shape>
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item android:state_focused="true"
|
<!--<item android:state_focused="true"
|
||||||
android:drawable="@drawable/outline"/> <!-- focused -->
|
android:drawable="@drawable/outline"/>--> <!-- focused -->
|
||||||
</selector>
|
</selector>
|
|
@ -77,4 +77,21 @@
|
||||||
tools:ignore="FragmentTagUsage" />
|
tools:ignore="FragmentTagUsage" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:focusable="false"
|
||||||
|
android:focusableInTouchMode="false"
|
||||||
|
android:clickable="false"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:id="@+id/focus_outline"
|
||||||
|
android:src="@drawable/outline"
|
||||||
|
android:layout_width="100dp"
|
||||||
|
android:layout_height="100dp">
|
||||||
|
</ImageView>
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
|
@ -35,11 +35,10 @@
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/home_preview_change_api"
|
android:id="@+id/home_preview_change_api"
|
||||||
style="@style/BlackButton"
|
style="@style/RegularButtonTV"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_gravity="top|start"
|
android:layout_gravity="top|start"
|
||||||
android:layout_marginStart="@dimen/navbar_width"
|
android:layout_marginStart="@dimen/navbar_width"
|
||||||
android:backgroundTint="@color/semiWhite"
|
|
||||||
android:minWidth="150dp" />
|
android:minWidth="150dp" />
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
|
@ -92,7 +91,7 @@
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/home_preview_play_btt"
|
android:id="@+id/home_preview_play_btt"
|
||||||
style="@style/WhiteButton"
|
style="@style/RegularButtonTV"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_margin="0dp"
|
android:layout_margin="0dp"
|
||||||
android:minWidth="150dp"
|
android:minWidth="150dp"
|
||||||
|
@ -105,7 +104,7 @@
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/home_preview_info_btt"
|
android:id="@+id/home_preview_info_btt"
|
||||||
style="@style/BlackButton"
|
style="@style/RegularButtonTV"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:minWidth="150dp"
|
android:minWidth="150dp"
|
||||||
|
|
||||||
|
|
|
@ -85,7 +85,8 @@
|
||||||
|
|
||||||
<style name="ChipFilled" parent="@style/Widget.Material3.Chip.Filter">
|
<style name="ChipFilled" parent="@style/Widget.Material3.Chip.Filter">
|
||||||
<item name="chipBackgroundColor">@color/chip_color</item>
|
<item name="chipBackgroundColor">@color/chip_color</item>
|
||||||
<item name="chipStrokeColor">@color/white_transparent_toggle</item>
|
<!-- <item name="chipStrokeColor">@color/white_transparent_toggle</item>-->
|
||||||
|
<item name="chipStrokeColor">@color/transparent</item>
|
||||||
<item name="chipStrokeWidth">2dp</item>
|
<item name="chipStrokeWidth">2dp</item>
|
||||||
<item name="textColor">@color/chip_color_text</item>
|
<item name="textColor">@color/chip_color_text</item>
|
||||||
<item name="android:textColor">@color/chip_color_text</item>
|
<item name="android:textColor">@color/chip_color_text</item>
|
||||||
|
|
Loading…
Reference in a new issue