diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt index 7e7624eb..3dd5a495 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt @@ -13,16 +13,15 @@ import android.os.Bundle import android.util.AttributeSet import android.util.Log import android.view.* -import android.view.animation.Animation -import android.view.animation.AnimationSet -import android.widget.LinearLayout import android.widget.Toast import androidx.activity.result.ActivityResultLauncher import androidx.annotation.IdRes +import androidx.annotation.MainThread import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import androidx.constraintlayout.widget.ConstraintLayout -import androidx.core.view.doOnLayout +import androidx.core.animation.addListener +import androidx.core.view.ViewCompat import androidx.core.view.isGone import androidx.core.view.isVisible import androidx.fragment.app.FragmentActivity @@ -35,22 +34,12 @@ import androidx.navigation.NavOptions import androidx.navigation.fragment.NavHostFragment import androidx.navigation.ui.setupWithNavController 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.ObjectMapper import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.google.android.gms.cast.framework.* import com.google.android.material.bottomnavigation.BottomNavigationView 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.snackbar.Snackbar import com.jaredrummler.android.colorpicker.ColorPickerDialogListener @@ -108,6 +97,7 @@ import com.lagradost.cloudstream3.ui.setup.SetupFragmentExtensions import com.lagradost.cloudstream3.utils.* import com.lagradost.cloudstream3.utils.AppUtils.html import com.lagradost.cloudstream3.utils.AppUtils.isCastApiAvailable +import com.lagradost.cloudstream3.utils.AppUtils.isLtr import com.lagradost.cloudstream3.utils.AppUtils.isNetworkAvailable import com.lagradost.cloudstream3.utils.AppUtils.loadCache import com.lagradost.cloudstream3.utils.AppUtils.loadRepository @@ -131,6 +121,7 @@ import com.lagradost.cloudstream3.utils.UIHelper.getResourceColor import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard import com.lagradost.cloudstream3.utils.UIHelper.navigate import com.lagradost.cloudstream3.utils.UIHelper.requestRW +import com.lagradost.cloudstream3.utils.UIHelper.toPx import com.lagradost.nicehttp.Requests import com.lagradost.nicehttp.ResponseParser import kotlinx.coroutines.sync.Mutex @@ -140,6 +131,7 @@ import java.lang.ref.WeakReference import java.net.URI import java.net.URLDecoder import java.nio.charset.Charset +import kotlin.math.absoluteValue import kotlin.reflect.KClass import kotlin.system.exitProcess @@ -472,13 +464,24 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener { binding?.navHostFragment?.apply { val params = layoutParams as ConstraintLayout.LayoutParams + val push = if (!dontPush && isTvSettings()) resources.getDimensionPixelSize(R.dimen.navbar_width) else 0 + + if(!this.isLtr()) { + params.setMargins( + params.leftMargin, + params.topMargin, + push, + params.bottomMargin + ) + } else { + params.setMargins( + push, + params.topMargin, + params.rightMargin, + params.bottomMargin + ) + } - params.setMargins( - if (!dontPush && isTvSettings()) resources.getDimensionPixelSize(R.dimen.navbar_width) else 0, - params.topMargin, - params.rightMargin, - params.bottomMargin - ) layoutParams = params } @@ -572,9 +575,22 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener { } override fun dispatchKeyEvent(event: KeyEvent?): Boolean { - CommonActivity.dispatchKeyEvent(this, event)?.let { - return it + val start = System.currentTimeMillis() + try { + val response = CommonActivity.dispatchKeyEvent(this, event) + + if (response != null) + return response + } finally { + debugAssert({ + val end = System.currentTimeMillis() + val delta = end - start + delta > 100 + }) { + "Took over 100ms to navigate, smth is VERY wrong" + } } + return super.dispatchKeyEvent(event) } @@ -745,85 +761,186 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener { } private var binding: ActivityMainBinding? = null - private var focusOutline: WeakReference = WeakReference(null) - private var lastFocus: WeakReference = WeakReference(null) - private val layoutListener: View.OnLayoutChangeListener = - View.OnLayoutChangeListener { v, _, _, _, _, _, _, _, _ -> - updateFocusView( - v - ) - } - private val attachListener : View.OnAttachStateChangeListener = object : View.OnAttachStateChangeListener { - override fun onViewAttachedToWindow(v: View) { - updateFocusView(v) - } - override fun onViewDetachedFromWindow(v: View) { - // removes the focus view but not the listener as updateFocusView(null) will remove the listener - focusOutline.get()?.isVisible = false - } - } - - private fun updateFocusView(newFocus: View?) { - val focusOutline = focusOutline.get() ?: return - lastFocus.get()?.removeOnLayoutChangeListener(layoutListener) - lastFocus.get()?.removeOnAttachStateChangeListener(attachListener) - val wasGone = focusOutline.isGone - - val visible = - newFocus != null && newFocus.measuredHeight > 0 && newFocus.measuredWidth > 0 && newFocus.isShown && newFocus.tag != "tv_no_focus_tag" - focusOutline.isVisible = visible - if (newFocus != null) { - lastFocus = WeakReference(newFocus) - - val out = IntArray(2) - newFocus.getLocationInWindow(out) - val (x, y) = out - // out of bounds = 0,0 - if(x == 0 && y == 0) { - focusOutline.isVisible = false - } - /*(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) - newFocus.addOnAttachStateChangeListener(attachListener) - - // val set = AnimationSet(true) - if(!wasGone) { - (focusOutline.parent as? ViewGroup)?.let { - TransitionManager.endTransitions(it) - TransitionManager.beginDelayedTransition( - it, - TransitionSet().addTransition(ChangeBounds()) - .addTransition(ChangeTransform()) - .setDuration(100) + object TvFocus { + data class FocusTarget( + val width: Int, + val height: Int, + val x: Float, + val y: Float, + ) { + companion object { + fun lerp(a: FocusTarget, b: FocusTarget, lerp: Float): FocusTarget { + val ilerp = 1 - lerp + return FocusTarget( + width = (a.width * ilerp + b.width * lerp).toInt(), + height = (a.height * ilerp + b.height * lerp).toInt(), + x = a.x * ilerp + b.x * lerp, + y = a.y * ilerp + b.y * lerp ) } } - // ObjectAnimator.ofFloat(focusOutline, "translationX",focusOutline.translationX, x.toFloat() + } + var last: FocusTarget = FocusTarget(0, 0, 0.0f, 0.0f) + var current: FocusTarget = FocusTarget(0, 0, 0.0f, 0.0f) - focusOutline.layoutParams = focusOutline.layoutParams?.apply { - width = newFocus.measuredWidth - height = newFocus.measuredHeight + var focusOutline: WeakReference = WeakReference(null) + var lastFocus: WeakReference = WeakReference(null) + private val layoutListener: View.OnLayoutChangeListener = + View.OnLayoutChangeListener { v, _, _, _, _, _, _, _, _ -> + updateFocusView( + v, same = true + ) + } + private val attachListener: View.OnAttachStateChangeListener = + object : View.OnAttachStateChangeListener { + override fun onViewAttachedToWindow(v: View) { + updateFocusView(v) + } + + override fun onViewDetachedFromWindow(v: View) { + // removes the focus view but not the listener as updateFocusView(null) will remove the listener + focusOutline.get()?.isVisible = false + } + } + + private fun setTargetPosition(target: FocusTarget) { + focusOutline.get()?.apply { + layoutParams = layoutParams?.apply { + width = target.width + height = target.height + } + + translationX = target.x + translationY = target.y + } + } + + private var animator: ValueAnimator? = null + + @MainThread + fun updateFocusView(newFocus: View?, same: Boolean = false) { + val focusOutline = focusOutline.get() ?: return + lastFocus.get()?.apply { + removeOnLayoutChangeListener(layoutListener) + removeOnAttachStateChangeListener(attachListener) + } + + val wasGone = focusOutline.isGone + + val visible = + newFocus != null && newFocus.measuredHeight > 0 && newFocus.measuredWidth > 0 && newFocus.isShown && newFocus.tag != "tv_no_focus_tag" + focusOutline.isVisible = visible + + if (newFocus != null) { + lastFocus = WeakReference(newFocus) + + val out = IntArray(2) + newFocus.getLocationInWindow(out) + val (screenX, screenY) = out + var (x,y) = screenX.toFloat() to screenY.toFloat() + val (currentX, currentY) = focusOutline.translationX to focusOutline.translationY + // println(">><<< $x $y $currentX $currentY") + if(!newFocus.isLtr()) { + x = x - focusOutline.rootView.width + newFocus.measuredWidth + } + + // out of bounds = 0,0 + if (screenX == 0 && screenY == 0) { + focusOutline.isVisible = false + } + + newFocus.addOnLayoutChangeListener(layoutListener) + newFocus.addOnAttachStateChangeListener(attachListener) + + val start = FocusTarget( + x = currentX, + y = currentY, + width = focusOutline.measuredWidth, + height = focusOutline.measuredHeight + ) + val end = FocusTarget( + x = x, + y = y, + width = newFocus.measuredWidth, + height = newFocus.measuredHeight + ) + + // if they are the same within then snap, aka scrolling + val deltaMin = 50.toPx + if (start.width == end.width && start.height == end.height && (start.x - end.x).absoluteValue < deltaMin && (start.y - end.y).absoluteValue < deltaMin) { + animator?.cancel() + last = start + current = end + setTargetPosition(end) + return + } + + // if running then "reuse" + if (animator?.isRunning == true) { + current = end + return + } else { + animator?.cancel() + } + + + last = start + current = end + + // if previously gone, then tp + if (wasGone) { + setTargetPosition(current) + return + } + + // animate between a and b + animator = ValueAnimator.ofFloat(0.0f, 1.0f).apply { + startDelay = 0 + duration = 100 + addUpdateListener { animation -> + val animatedValue = animation.animatedValue as Float + val target = FocusTarget.lerp(last, current, minOf(animatedValue, 1.0f)) + setTargetPosition(target) + } + start() + } + + // post check + if (!same) { + newFocus.postDelayed({ + updateFocusView(lastFocus.get(), same = true) + }, 200) + } + + /* + + the following is working, but somewhat bad code code + + if (!wasGone) { + (focusOutline.parent as? ViewGroup)?.let { + TransitionManager.endTransitions(it) + TransitionManager.beginDelayedTransition( + it, + TransitionSet().addTransition(ChangeBounds()) + .addTransition(ChangeTransform()) + .setDuration(100) + ) + } + } + + focusOutline.layoutParams = focusOutline.layoutParams?.apply { + width = newFocus.measuredWidth + height = newFocus.measuredHeight + } + focusOutline.translationX = x.toFloat() + focusOutline.translationY = y.toFloat()*/ } - focusOutline.translationX = x.toFloat() - focusOutline.translationY = y.toFloat() } } + override fun onCreate(savedInstanceState: Bundle?) { app.initClient(this) val settingsManager = PreferenceManager.getDefaultSharedPreferences(this) @@ -872,13 +989,13 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener { if (isTvSettings()) { val newLocalBinding = ActivityMainTvBinding.inflate(layoutInflater, null, false) setContentView(newLocalBinding.root) - focusOutline = WeakReference(newLocalBinding.focusOutline) + TvFocus.focusOutline = WeakReference(newLocalBinding.focusOutline) newLocalBinding.root.viewTreeObserver.addOnGlobalFocusChangeListener { _, newFocus -> // println("refocus $oldFocus -> $newFocus") - updateFocusView(newFocus) + TvFocus.updateFocusView(newFocus) } newLocalBinding.root.viewTreeObserver.addOnScrollChangedListener { - updateFocusView(lastFocus.get()) + TvFocus.updateFocusView(TvFocus.lastFocus.get(), same = true) } ActivityMainBinding.bind(newLocalBinding.root) // this may crash @@ -1230,16 +1347,21 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener { }*/ if (BuildConfig.DEBUG) { - var providersAndroidManifestString = "Current androidmanifest should be:\n" - for (api in allProviders) { - providersAndroidManifestString += "\n" + try { + var providersAndroidManifestString = "Current androidmanifest should be:\n" + for (api in allProviders) { + providersAndroidManifestString += "\n" + } + println(providersAndroidManifestString) + + } catch (t: Throwable) { + logError(t) } - println(providersAndroidManifestString) } handleAppIntent(intent) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeParentItemAdapter.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeParentItemAdapter.kt index f6c3fead..d4c0bd62 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeParentItemAdapter.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeParentItemAdapter.kt @@ -177,7 +177,7 @@ open class ParentItemAdapter( ).apply { isHorizontal = info.isHorizontalImages } - recyclerView.setLinearListLayout() + //recyclerView.setLinearListLayout() } } @@ -192,7 +192,7 @@ open class ParentItemAdapter( isHorizontal = info.isHorizontalImages hasNext = expand.hasNext } - recyclerView.setLinearListLayout() + // recyclerView.setLinearListLayout() title.text = info.name recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() { diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/EpisodeAdapter.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/EpisodeAdapter.kt index 541116f5..6b63e623 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/EpisodeAdapter.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/EpisodeAdapter.kt @@ -19,6 +19,7 @@ import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueT import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings import com.lagradost.cloudstream3.utils.AppUtils.html import com.lagradost.cloudstream3.utils.UIHelper.setImage +import com.lagradost.cloudstream3.utils.UIHelper.toPx import com.lagradost.cloudstream3.utils.VideoDownloadHelper import java.util.* @@ -48,7 +49,8 @@ const val ACTION_PLAY_EPISODE_IN_WEB_VIDEO = 16 const val ACTION_PLAY_EPISODE_IN_MPV = 17 const val ACTION_MARK_AS_WATCHED = 18 - +const val TV_EP_SIZE_LARGE = 400 +const val TV_EP_SIZE_SMALL = 300 data class EpisodeClickEvent(val action: Int, val data: ResultEpisode) class EpisodeAdapter( @@ -172,7 +174,7 @@ class EpisodeAdapter( localCard = card val setWidth = - if (isTvSettings()) ViewGroup.LayoutParams.WRAP_CONTENT else ViewGroup.LayoutParams.MATCH_PARENT + if (isTvSettings()) TV_EP_SIZE_LARGE.toPx else ViewGroup.LayoutParams.MATCH_PARENT binding.episodeLinHolder.layoutParams.width = setWidth binding.episodeHolderLarge.layoutParams.width = setWidth @@ -293,7 +295,7 @@ class EpisodeAdapter( binding.episodeHolder.layoutParams.apply { width = - if (isTvSettings()) ViewGroup.LayoutParams.WRAP_CONTENT else ViewGroup.LayoutParams.MATCH_PARENT + if (isTvSettings()) TV_EP_SIZE_SMALL.toPx else ViewGroup.LayoutParams.MATCH_PARENT } binding.apply { diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/LinearListLayout.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/LinearListLayout.kt index affbcbb4..434355a2 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/LinearListLayout.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/LinearListLayout.kt @@ -2,15 +2,19 @@ package com.lagradost.cloudstream3.ui.result import android.content.Context import android.view.View +import android.view.View.LAYOUT_DIRECTION_LTR import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.lagradost.cloudstream3.mvvm.logError +import com.lagradost.cloudstream3.utils.AppUtils.isLtr +import com.lagradost.cloudstream3.utils.AppUtils.isRtl fun RecyclerView?.setLinearListLayout(isHorizontal: Boolean = true) { if (this == null) return + this.layoutManager = this.context?.let { LinearListLayout(it).apply { if (isHorizontal) setHorizontal() else setVertical() } } - ?: this.layoutManager + // ?: this.layoutManager } open class LinearListLayout(context: Context?) : @@ -56,7 +60,7 @@ open class LinearListLayout(context: Context?) : startSmoothScroll(linearSmoothScroller) }*/ override fun onInterceptFocusSearch(focused: View, direction: Int): View? { - val dir = if (orientation == HORIZONTAL) { + var dir = if (orientation == HORIZONTAL) { if (direction == View.FOCUS_DOWN || direction == View.FOCUS_UP) { // This scrolls the recyclerview before doing focus search, which // allows the focus search to work better. @@ -71,6 +75,9 @@ open class LinearListLayout(context: Context?) : if (direction == View.FOCUS_RIGHT || direction == View.FOCUS_LEFT) return null if (direction == View.FOCUS_DOWN) 1 else -1 } + if(this.isLayoutRTL) { + dir = -dir + } return try { getPosition(getCorrectParent(focused))?.let { position -> diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentPhone.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentPhone.kt index f67625d4..e1514d63 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentPhone.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentPhone.kt @@ -62,6 +62,8 @@ import com.lagradost.cloudstream3.ui.search.SearchHelper import com.lagradost.cloudstream3.utils.AppUtils.getNameFull import com.lagradost.cloudstream3.utils.AppUtils.html import com.lagradost.cloudstream3.utils.AppUtils.isCastApiAvailable +import com.lagradost.cloudstream3.utils.AppUtils.isLtr +import com.lagradost.cloudstream3.utils.AppUtils.isRtl import com.lagradost.cloudstream3.utils.AppUtils.loadCache import com.lagradost.cloudstream3.utils.AppUtils.openBrowser import com.lagradost.cloudstream3.utils.ExtractorLink diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentTv.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentTv.kt index 506f7f10..69127e86 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentTv.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentTv.kt @@ -14,6 +14,7 @@ import android.view.animation.DecelerateInterpolator import androidx.appcompat.app.AlertDialog import androidx.core.view.isGone import androidx.core.view.isVisible +import androidx.core.widget.NestedScrollView import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.RecyclerView @@ -30,6 +31,7 @@ import com.lagradost.cloudstream3.mvvm.observe import com.lagradost.cloudstream3.mvvm.observeNullable import com.lagradost.cloudstream3.ui.WatchType import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup +import com.lagradost.cloudstream3.ui.player.CSPlayerEvent import com.lagradost.cloudstream3.ui.player.ExtractorLinkGenerator import com.lagradost.cloudstream3.ui.player.GeneratorPlayer import com.lagradost.cloudstream3.ui.result.ResultFragment.getStoredData @@ -38,6 +40,8 @@ import com.lagradost.cloudstream3.ui.search.SearchAdapter import com.lagradost.cloudstream3.ui.search.SearchHelper import com.lagradost.cloudstream3.utils.AppUtils.getNameFull import com.lagradost.cloudstream3.utils.AppUtils.html +import com.lagradost.cloudstream3.utils.AppUtils.isLtr +import com.lagradost.cloudstream3.utils.AppUtils.isRtl import com.lagradost.cloudstream3.utils.AppUtils.loadCache import com.lagradost.cloudstream3.utils.Coroutines.ioSafe import com.lagradost.cloudstream3.utils.Coroutines.main @@ -254,6 +258,12 @@ class ResultFragmentTv : Fragment() { resultEpisodesShow.onFocusChangeListener = rightListener resultDescription.onFocusChangeListener = leftListener resultBookmarkButton.onFocusChangeListener = leftListener + resultEpisodesShow.setOnClickListener { + // toggle, to make it more touch accessable just in case someone thinks that a + // tv layout is better but is using a touch device + toggleEpisodes(!episodeHolderTv.isVisible) + } + redirectToPlay.setOnFocusChangeListener { _, hasFocus -> if (!hasFocus) return@setOnFocusChangeListener toggleEpisodes(false) @@ -272,6 +282,12 @@ class ResultFragmentTv : Fragment() { } } } + + // parallax on background + resultFinishLoading.setOnScrollChangeListener(NestedScrollView.OnScrollChangeListener { _, _, scrollY, _, oldScrollY -> + backgroundPosterHolder.translationY = -scrollY.toFloat() * 0.8f + }) + redirectToEpisodes.setOnFocusChangeListener { _, hasFocus -> if (!hasFocus) return@setOnFocusChangeListener toggleEpisodes(true) @@ -290,10 +306,10 @@ class ResultFragmentTv : Fragment() { } } - resultEpisodes.layoutManager = - LinearListLayout(resultEpisodes.context).apply { + resultEpisodes.setLinearListLayout(false)/*.layoutManager = + LinearListLayout(resultEpisodes.context, resultEpisodes.isRtl()).apply { setVertical() - } + }*/ resultReloadConnectionerror.setOnClickListener { viewModel.load( diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/AppUtils.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/AppUtils.kt index be99b536..48917889 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/AppUtils.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/AppUtils.kt @@ -20,6 +20,9 @@ import android.os.* import android.provider.MediaStore import android.text.Spanned import android.util.Log +import android.view.View +import android.view.View.LAYOUT_DIRECTION_LTR +import android.view.View.LAYOUT_DIRECTION_RTL import android.view.animation.DecelerateInterpolator import android.widget.Toast import androidx.activity.result.contract.ActivityResultContracts @@ -90,6 +93,9 @@ object AppUtils { return if (layoutManager == null || adapter == null) false else layoutManager.findLastCompletelyVisibleItemPosition() < adapter.itemCount - 7 // bit more than 1 to make it more seamless } + fun View.isLtr() = this.layoutDirection == LAYOUT_DIRECTION_LTR + fun View.isRtl() = this.layoutDirection == LAYOUT_DIRECTION_RTL + fun BottomSheetDialog?.ownHide() { this?.hide() } diff --git a/app/src/main/res/drawable/outline_drawable_less.xml b/app/src/main/res/drawable/outline_drawable_less.xml index 0b641074..db74a092 100644 --- a/app/src/main/res/drawable/outline_drawable_less.xml +++ b/app/src/main/res/drawable/outline_drawable_less.xml @@ -1,4 +1,5 @@ - + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main_tv.xml b/app/src/main/res/layout/activity_main_tv.xml index a70a40cd..77baf1d3 100644 --- a/app/src/main/res/layout/activity_main_tv.xml +++ b/app/src/main/res/layout/activity_main_tv.xml @@ -83,6 +83,7 @@ android:layout_height="match_parent"> @@ -152,12 +153,12 @@ https://developer.android.com/design/ui/tv/samples/jet-fit @@ -479,8 +481,8 @@ https://developer.android.com/design/ui/tv/samples/jet-fit android:fadingEdge="horizontal" android:focusable="false" android:focusableInTouchMode="false" - android:nextFocusUp="@id/result_back" - android:nextFocusDown="@id/result_play_movie" + android:nextFocusUp="@id/result_episodes_show" + android:nextFocusDown="@id/result_recommendations_filter_selection" android:orientation="horizontal" android:paddingTop="5dp" android:requiresFadingEdge="horizontal" @@ -502,9 +504,9 @@ https://developer.android.com/design/ui/tv/samples/jet-fit android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="10dp" - android:nextFocusUp="@id/result_episodes" - + android:nextFocusUp="@id/result_cast_items" android:nextFocusDown="@id/result_recommendations_list" + android:orientation="horizontal" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" tools:itemCount="2" @@ -525,7 +527,6 @@ https://developer.android.com/design/ui/tv/samples/jet-fit android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="?attr/primaryBlackBackground" android:clipToPadding="false" android:descendantFocusability="afterDescendants" android:nextFocusUp="@id/result_recommendations_filter_selection" diff --git a/app/src/main/res/layout/fragment_search_tv.xml b/app/src/main/res/layout/fragment_search_tv.xml index bb59d503..63c61393 100644 --- a/app/src/main/res/layout/fragment_search_tv.xml +++ b/app/src/main/res/layout/fragment_search_tv.xml @@ -122,18 +122,17 @@ tools:listitem="@layout/homepage_parent" /> - - +