tv changes for better centering + bigger text + better contrast

This commit is contained in:
LagradOst 2023-09-11 23:05:10 +02:00
parent 01e7acdeac
commit 7d6ba8c7a4
5 changed files with 107 additions and 37 deletions

View file

@ -7,9 +7,14 @@ import android.content.Context
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.content.res.Resources import android.content.res.Resources
import android.os.Build import android.os.Build
import android.util.DisplayMetrics
import android.util.Log import android.util.Log
import android.view.* import android.view.Gravity
import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.View
import android.view.View.NO_ID import android.view.View.NO_ID
import android.view.ViewGroup
import android.widget.TextView import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
@ -40,7 +45,9 @@ import com.lagradost.cloudstream3.utils.UIHelper.shouldShowPIPMode
import com.lagradost.cloudstream3.utils.UIHelper.toPx import com.lagradost.cloudstream3.utils.UIHelper.toPx
import org.schabi.newpipe.extractor.NewPipe import org.schabi.newpipe.extractor.NewPipe
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import java.util.* import java.util.Locale
import kotlin.math.max
import kotlin.math.min
enum class FocusDirection { enum class FocusDirection {
Start, Start,
@ -63,6 +70,19 @@ object CommonActivity {
return (this as MainActivity?)?.mSessionManager?.currentCastSession return (this as MainActivity?)?.mSessionManager?.currentCastSession
} }
val displayMetrics: DisplayMetrics = Resources.getSystem().displayMetrics
// screenWidth and screenHeight does always
// refer to the screen while in landscape mode
val screenWidth: Int
get() {
return max(displayMetrics.widthPixels, displayMetrics.heightPixels)
}
val screenHeight: Int
get() {
return min(displayMetrics.widthPixels, displayMetrics.heightPixels)
}
var canEnterPipMode: Boolean = false var canEnterPipMode: Boolean = false
var canShowPipMode: Boolean = false var canShowPipMode: Boolean = false
@ -328,6 +348,14 @@ object CommonActivity {
currentLook = currentLook.parent as? View ?: break currentLook = currentLook.parent as? View ?: break
}*/ }*/
private fun View.hasContent() : Boolean {
return isShown && when(this) {
//is RecyclerView -> this.childCount > 0
is ViewGroup -> this.childCount > 0
else -> true
}
}
/** skips the initial stage of searching for an id using the view, see getNextFocus for specification */ /** skips the initial stage of searching for an id using the view, see getNextFocus for specification */
fun continueGetNextFocus( fun continueGetNextFocus(
root: Any?, root: Any?,
@ -348,16 +376,17 @@ object CommonActivity {
} ?: return null } ?: return null
next = localLook(view, nextId) ?: next next = localLook(view, nextId) ?: next
val shown = next.hasContent()
// if cant focus but visible then break and let android decide // if cant focus but visible then break and let android decide
// the exception if is the view is a parent and has children that wants focus // the exception if is the view is a parent and has children that wants focus
val hasChildrenThatWantsFocus = (next as? ViewGroup)?.let { parent -> val hasChildrenThatWantsFocus = (next as? ViewGroup)?.let { parent ->
parent.descendantFocusability == ViewGroup.FOCUS_AFTER_DESCENDANTS && parent.childCount > 0 parent.descendantFocusability == ViewGroup.FOCUS_AFTER_DESCENDANTS && parent.childCount > 0
} ?: false } ?: false
if (!next.isFocusable && next.isShown && !hasChildrenThatWantsFocus) return null if (!next.isFocusable && shown && !hasChildrenThatWantsFocus) return null
// if not shown then continue because we will "skip" over views to get to a replacement // if not shown then continue because we will "skip" over views to get to a replacement
if (!next.isShown) { if (!shown) {
// we don't want a while true loop, so we let android decide if we find a recursive view // we don't want a while true loop, so we let android decide if we find a recursive view
if (next == view) return null if (next == view) return null
return getNextFocus(root, next, direction, depth + 1) return getNextFocus(root, next, direction, depth + 1)

View file

@ -6,6 +6,7 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.content.res.Configuration import android.content.res.Configuration
import android.graphics.Rect
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
@ -52,6 +53,7 @@ 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.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.google.common.collect.Comparators.min
import com.jaredrummler.android.colorpicker.ColorPickerDialogListener import com.jaredrummler.android.colorpicker.ColorPickerDialogListener
import com.lagradost.cloudstream3.APIHolder.allProviders import com.lagradost.cloudstream3.APIHolder.allProviders
import com.lagradost.cloudstream3.APIHolder.apis import com.lagradost.cloudstream3.APIHolder.apis
@ -64,13 +66,13 @@ import com.lagradost.cloudstream3.CommonActivity.loadThemes
import com.lagradost.cloudstream3.CommonActivity.onColorSelectedEvent import com.lagradost.cloudstream3.CommonActivity.onColorSelectedEvent
import com.lagradost.cloudstream3.CommonActivity.onDialogDismissedEvent import com.lagradost.cloudstream3.CommonActivity.onDialogDismissedEvent
import com.lagradost.cloudstream3.CommonActivity.onUserLeaveHint import com.lagradost.cloudstream3.CommonActivity.onUserLeaveHint
import com.lagradost.cloudstream3.CommonActivity.screenHeight
import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.CommonActivity.showToast
import com.lagradost.cloudstream3.CommonActivity.updateLocale import com.lagradost.cloudstream3.CommonActivity.updateLocale
import com.lagradost.cloudstream3.databinding.ActivityMainBinding import com.lagradost.cloudstream3.databinding.ActivityMainBinding
import com.lagradost.cloudstream3.databinding.ActivityMainTvBinding import com.lagradost.cloudstream3.databinding.ActivityMainTvBinding
import com.lagradost.cloudstream3.databinding.BottomResultviewPreviewBinding import com.lagradost.cloudstream3.databinding.BottomResultviewPreviewBinding
import com.lagradost.cloudstream3.mvvm.Resource import com.lagradost.cloudstream3.mvvm.Resource
import com.lagradost.cloudstream3.mvvm.debugAssert
import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
import com.lagradost.cloudstream3.mvvm.observeNullable import com.lagradost.cloudstream3.mvvm.observeNullable
@ -832,6 +834,13 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
focusOutline.get()?.isVisible = false focusOutline.get()?.isVisible = false
} }
} }
/*private val scrollListener = object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
current = current.copy(x = current.x + dx, y = current.y + dy)
setTargetPosition(current)
}
}*/
private fun setTargetPosition(target: FocusTarget) { private fun setTargetPosition(target: FocusTarget) {
focusOutline.get()?.apply { focusOutline.get()?.apply {
@ -874,7 +883,10 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
if (!exactlyTheSame) { if (!exactlyTheSame) {
lastView?.removeOnLayoutChangeListener(layoutListener) lastView?.removeOnLayoutChangeListener(layoutListener)
lastView?.removeOnAttachStateChangeListener(attachListener) lastView?.removeOnAttachStateChangeListener(attachListener)
(lastView?.parent as? RecyclerView)?.removeOnLayoutChangeListener(layoutListener) (lastView?.parent as? RecyclerView)?.apply {
removeOnLayoutChangeListener(layoutListener)
//removeOnScrollListener(scrollListener)
}
} }
val wasGone = focusOutline.isGone val wasGone = focusOutline.isGone
@ -952,7 +964,10 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
focusOutline.isVisible = false focusOutline.isVisible = false
} }
if (!exactlyTheSame) { if (!exactlyTheSame) {
(newFocus.parent as? RecyclerView)?.addOnLayoutChangeListener(layoutListener) (newFocus.parent as? RecyclerView)?.apply {
addOnLayoutChangeListener(layoutListener)
//addOnScrollListener(scrollListener)
}
newFocus.addOnLayoutChangeListener(layoutListener) newFocus.addOnLayoutChangeListener(layoutListener)
newFocus.addOnAttachStateChangeListener(attachListener) newFocus.addOnAttachStateChangeListener(attachListener)
} }
@ -970,8 +985,9 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
) )
// if they are the same within then snap, aka scrolling // if they are the same within then snap, aka scrolling
val deltaMin = 50.toPx val deltaMinX = min(end.width / 2, 60.toPx)
if (start.width == end.width && start.height == end.height && (start.x - end.x).absoluteValue < deltaMin && (start.y - end.y).absoluteValue < deltaMin) { val deltaMinY = min(end.height / 2, 60.toPx)
if (start.width == end.width && start.height == end.height && (start.x - end.x).absoluteValue < deltaMinX && (start.y - end.y).absoluteValue < deltaMinY) {
animator?.cancel() animator?.cancel()
last = start last = start
current = end current = end
@ -1000,7 +1016,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
// animate between a and b // animate between a and b
animator = ValueAnimator.ofFloat(0.0f, 1.0f).apply { animator = ValueAnimator.ofFloat(0.0f, 1.0f).apply {
startDelay = 0 startDelay = 0
duration = 100 duration = 200
addUpdateListener { animation -> addUpdateListener { animation ->
val animatedValue = animation.animatedValue as Float val animatedValue = animation.animatedValue as Float
val target = FocusTarget.lerp(last, current, minOf(animatedValue, 1.0f)) val target = FocusTarget.lerp(last, current, minOf(animatedValue, 1.0f))
@ -1095,7 +1111,29 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
TvFocus.focusOutline = WeakReference(newLocalBinding.focusOutline) TvFocus.focusOutline = WeakReference(newLocalBinding.focusOutline)
newLocalBinding.root.viewTreeObserver.addOnGlobalFocusChangeListener { _, newFocus -> newLocalBinding.root.viewTreeObserver.addOnGlobalFocusChangeListener { _, newFocus ->
// println("refocus $oldFocus -> $newFocus") // println("refocus $oldFocus -> $newFocus")
try {
val r = Rect(0,0,0,0)
newFocus.getDrawingRect(r)
val x = r.centerX()
val y = r.centerY()
val dx = 0 //screenWidth / 2
val dy = screenHeight / 2
val r2 = Rect(x-dx,y-dy,x+dx,y+dy)
newFocus.requestRectangleOnScreen(r2, false)
// TvFocus.current =TvFocus.current.copy(y=y.toFloat())
} catch (_ : Throwable) { }
TvFocus.updateFocusView(newFocus) TvFocus.updateFocusView(newFocus)
/*var focus = newFocus
while(focus != null) {
if(focus is ScrollingView && focus.canScrollVertically()) {
focus.scrollBy()
}
when(focus.parent) {
is View -> focus = newFocus
else -> break
}
}*/
} }
newLocalBinding.root.viewTreeObserver.addOnScrollChangedListener { newLocalBinding.root.viewTreeObserver.addOnScrollChangedListener {
TvFocus.updateFocusView(TvFocus.lastFocus.get(), same = true) TvFocus.updateFocusView(TvFocus.lastFocus.get(), same = true)

View file

@ -38,6 +38,8 @@ import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
import com.lagradost.cloudstream3.CommonActivity.keyEventListener import com.lagradost.cloudstream3.CommonActivity.keyEventListener
import com.lagradost.cloudstream3.CommonActivity.playerEventListener import com.lagradost.cloudstream3.CommonActivity.playerEventListener
import com.lagradost.cloudstream3.CommonActivity.screenHeight
import com.lagradost.cloudstream3.CommonActivity.screenWidth
import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.databinding.PlayerCustomLayoutBinding import com.lagradost.cloudstream3.databinding.PlayerCustomLayoutBinding
import com.lagradost.cloudstream3.databinding.SubtitleOffsetBinding import com.lagradost.cloudstream3.databinding.SubtitleOffsetBinding
@ -126,19 +128,6 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
protected var useTrueSystemBrightness = true protected var useTrueSystemBrightness = true
private val fullscreenNotch = true //TODO SETTING private val fullscreenNotch = true //TODO SETTING
protected val displayMetrics: DisplayMetrics = Resources.getSystem().displayMetrics
// screenWidth and screenHeight does always
// refer to the screen while in landscape mode
protected val screenWidth: Int
get() {
return max(displayMetrics.widthPixels, displayMetrics.heightPixels)
}
protected val screenHeight: Int
get() {
return min(displayMetrics.widthPixels, displayMetrics.heightPixels)
}
private var statusBarHeight: Int? = null private var statusBarHeight: Int? = null
private var navigationBarHeight: Int? = null private var navigationBarHeight: Int? = null

View file

@ -9,6 +9,8 @@ import android.view.ViewGroup
import android.widget.FrameLayout import android.widget.FrameLayout
import androidx.core.view.isGone import androidx.core.view.isGone
import androidx.core.view.isVisible import androidx.core.view.isVisible
import com.lagradost.cloudstream3.CommonActivity.screenHeight
import com.lagradost.cloudstream3.CommonActivity.screenWidth
import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.ui.player.CSPlayerEvent import com.lagradost.cloudstream3.ui.player.CSPlayerEvent
import com.lagradost.cloudstream3.ui.player.PlayerEventSource import com.lagradost.cloudstream3.ui.player.PlayerEventSource

View file

@ -128,7 +128,7 @@ https://developer.android.com/design/ui/tv/samples/jet-fit
<FrameLayout <FrameLayout
android:id="@+id/background_poster_holder" android:id="@+id/background_poster_holder"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="200dp" android:layout_height="150dp"
android:visibility="visible"> android:visibility="visible">
<ImageView <ImageView
@ -147,8 +147,6 @@ https://developer.android.com/design/ui/tv/samples/jet-fit
android:src="@drawable/background_shadow"> android:src="@drawable/background_shadow">
</ImageView> </ImageView>
</FrameLayout> </FrameLayout>
@ -411,7 +409,7 @@ https://developer.android.com/design/ui/tv/samples/jet-fit
android:padding="5dp" android:padding="5dp"
android:requiresFadingEdge="vertical" android:requiresFadingEdge="vertical"
android:textColor="?attr/textColor" android:textColor="?attr/textColor"
android:textSize="12sp" android:textSize="16sp"
tools:text="Ryan Quicksave Romano is an eccentric adventurer with a strange power: he can create a save-point in time and redo his life whenever he dies. Arriving in New Rome, the glitzy capital of sin of a rebuilding Europe, he finds the city torn between mega-corporations, sponsored heroes, superpowered criminals, and true monsters. It's a time of chaos, where potions can grant the power to rule the world and dangers lurk everywhere. " /> tools:text="Ryan Quicksave Romano is an eccentric adventurer with a strange power: he can create a save-point in time and redo his life whenever he dies. Arriving in New Rome, the glitzy capital of sin of a rebuilding Europe, he finds the city torn between mega-corporations, sponsored heroes, superpowered criminals, and true monsters. It's a time of chaos, where potions can grant the power to rule the world and dangers lurk everywhere. " />
<com.google.android.material.chip.ChipGroup <com.google.android.material.chip.ChipGroup
@ -537,18 +535,32 @@ https://developer.android.com/design/ui/tv/samples/jet-fit
</LinearLayout> </LinearLayout>
</androidx.core.widget.NestedScrollView> </androidx.core.widget.NestedScrollView>
<ImageView <FrameLayout
android:visibility="gone"
tools:visibility="visible"
android:id="@+id/episodes_shadow" android:id="@+id/episodes_shadow"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent">
android:layout_gravity="end" <ImageView
android:clickable="false" android:layout_width="match_parent"
android:focusable="false" android:layout_height="match_parent"
android:focusableInTouchMode="false" android:layout_gravity="end"
android:importantForAccessibility="no" android:clickable="false"
android:src="@drawable/episodes_shadow" android:focusable="false"
android:visibility="gone" android:focusableInTouchMode="false"
tools:visibility="visible" /> android:importantForAccessibility="no"
android:src="@drawable/episodes_shadow"/>
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="end"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:importantForAccessibility="no"
android:src="@drawable/episodes_shadow"/>
</FrameLayout>
<LinearLayout <LinearLayout
android:id="@+id/episode_holder_tv" android:id="@+id/episode_holder_tv"