mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
tv changes for better centering + bigger text + better contrast
This commit is contained in:
parent
01e7acdeac
commit
7d6ba8c7a4
5 changed files with 107 additions and 37 deletions
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,8 +535,13 @@ 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_height="match_parent">
|
||||||
|
<ImageView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_gravity="end"
|
android:layout_gravity="end"
|
||||||
|
@ -546,9 +549,18 @@ https://developer.android.com/design/ui/tv/samples/jet-fit
|
||||||
android:focusable="false"
|
android:focusable="false"
|
||||||
android:focusableInTouchMode="false"
|
android:focusableInTouchMode="false"
|
||||||
android:importantForAccessibility="no"
|
android:importantForAccessibility="no"
|
||||||
android:src="@drawable/episodes_shadow"
|
android:src="@drawable/episodes_shadow"/>
|
||||||
android:visibility="gone"
|
<ImageView
|
||||||
tools:visibility="visible" />
|
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"
|
||||||
|
|
Loading…
Reference in a new issue