From 6098b1b5a062f1bc7d0b680473c92768ee45742a Mon Sep 17 00:00:00 2001 From: tboba Date: Mon, 18 Sep 2023 14:17:19 +0200 Subject: [PATCH 1/3] Add focused states on page transitions --- .../com/swmansion/rnscreens/ScreenFragment.kt | 7 ++++++ .../rnscreens/ScreenStackFragment.kt | 25 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/android/src/main/java/com/swmansion/rnscreens/ScreenFragment.kt b/android/src/main/java/com/swmansion/rnscreens/ScreenFragment.kt index a5967056fb..12de0ecc2f 100644 --- a/android/src/main/java/com/swmansion/rnscreens/ScreenFragment.kt +++ b/android/src/main/java/com/swmansion/rnscreens/ScreenFragment.kt @@ -2,13 +2,16 @@ package com.swmansion.rnscreens import android.annotation.SuppressLint import android.app.Activity +import android.app.UiModeManager import android.content.Context +import android.content.res.Configuration import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.view.ViewParent import android.widget.FrameLayout +import androidx.core.content.getSystemService import androidx.fragment.app.Fragment import com.facebook.react.bridge.ReactContext import com.facebook.react.bridge.UiThreadUtil @@ -155,6 +158,10 @@ open class ScreenFragment : Fragment, ScreenFragmentWrapper { override val childScreenContainers: List get() = mChildScreenContainers + fun isTelevision(): Boolean { + return context?.getSystemService()?.currentModeType == Configuration.UI_MODE_TYPE_TELEVISION + } + override fun canDispatchLifecycleEvent(event: ScreenLifecycleEvent): Boolean = when (event) { ScreenLifecycleEvent.WillAppear -> canDispatchWillAppear ScreenLifecycleEvent.Appear -> canDispatchAppear diff --git a/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.kt b/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.kt index 725bcf879a..edfa20f321 100644 --- a/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.kt +++ b/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.kt @@ -26,6 +26,8 @@ class ScreenStackFragment : ScreenFragment, ScreenStackFragmentWrapper { private var mShadowHidden = false private var mIsTranslucent = false + private var mLastFocusedChild: View? = null + var searchView: CustomSearchView? = null var onSearchViewCreate: ((searchView: CustomSearchView) -> Unit)? = null @@ -89,6 +91,11 @@ class ScreenStackFragment : ScreenFragment, ScreenStackFragmentWrapper { } } + override fun onStart() { + mLastFocusedChild?.requestFocus() + super.onStart() + } + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -123,6 +130,11 @@ class ScreenStackFragment : ScreenFragment, ScreenStackFragmentWrapper { return view } + override fun onStop() { + mLastFocusedChild = findLastFocusedChild() + super.onStop() + } + override fun onPrepareOptionsMenu(menu: Menu) { updateToolbarMenu(menu) return super.onPrepareOptionsMenu(menu) @@ -163,6 +175,19 @@ class ScreenStackFragment : ScreenFragment, ScreenStackFragmentWrapper { } } + private fun findLastFocusedChild(): View? { + // If current device is not television, we don't want to save last focused child. + if (!isTelevision()) return null + + var view: View? = screen + while (view != null) { + if (view.isFocused) return view + view = if (view is ViewGroup) view.focusedChild else null + } + + return null + } + override fun canNavigateBack(): Boolean { val container: ScreenContainer? = screen.container check(container is ScreenStack) { "ScreenStackFragment added into a non-stack container" } From 4466f8d6df6cac984534a13781bbc6f94f0491ec Mon Sep 17 00:00:00 2001 From: tboba Date: Mon, 18 Sep 2023 15:01:30 +0200 Subject: [PATCH 2/3] Change if from findLastFocusedChild to onStop --- .../main/java/com/swmansion/rnscreens/ScreenStackFragment.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.kt b/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.kt index edfa20f321..5ee1c96571 100644 --- a/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.kt +++ b/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.kt @@ -131,7 +131,7 @@ class ScreenStackFragment : ScreenFragment, ScreenStackFragmentWrapper { } override fun onStop() { - mLastFocusedChild = findLastFocusedChild() + if (isTelevision()) mLastFocusedChild = findLastFocusedChild() super.onStop() } @@ -176,9 +176,6 @@ class ScreenStackFragment : ScreenFragment, ScreenStackFragmentWrapper { } private fun findLastFocusedChild(): View? { - // If current device is not television, we don't want to save last focused child. - if (!isTelevision()) return null - var view: View? = screen while (view != null) { if (view.isFocused) return view From f31aee27daa5f09e6a82acdcd8a37e4867b17acd Mon Sep 17 00:00:00 2001 From: tboba Date: Tue, 19 Sep 2023 15:10:28 +0200 Subject: [PATCH 3/3] Move ScreenFragment#isTelevision to DeviceUtils --- .../java/com/swmansion/rnscreens/ScreenFragment.kt | 7 ------- .../com/swmansion/rnscreens/ScreenStackFragment.kt | 5 ++++- .../com/swmansion/rnscreens/utils/DeviceUtils.kt | 12 ++++++++++++ 3 files changed, 16 insertions(+), 8 deletions(-) create mode 100644 android/src/main/java/com/swmansion/rnscreens/utils/DeviceUtils.kt diff --git a/android/src/main/java/com/swmansion/rnscreens/ScreenFragment.kt b/android/src/main/java/com/swmansion/rnscreens/ScreenFragment.kt index 12de0ecc2f..a5967056fb 100644 --- a/android/src/main/java/com/swmansion/rnscreens/ScreenFragment.kt +++ b/android/src/main/java/com/swmansion/rnscreens/ScreenFragment.kt @@ -2,16 +2,13 @@ package com.swmansion.rnscreens import android.annotation.SuppressLint import android.app.Activity -import android.app.UiModeManager import android.content.Context -import android.content.res.Configuration import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.view.ViewParent import android.widget.FrameLayout -import androidx.core.content.getSystemService import androidx.fragment.app.Fragment import com.facebook.react.bridge.ReactContext import com.facebook.react.bridge.UiThreadUtil @@ -158,10 +155,6 @@ open class ScreenFragment : Fragment, ScreenFragmentWrapper { override val childScreenContainers: List get() = mChildScreenContainers - fun isTelevision(): Boolean { - return context?.getSystemService()?.currentModeType == Configuration.UI_MODE_TYPE_TELEVISION - } - override fun canDispatchLifecycleEvent(event: ScreenLifecycleEvent): Boolean = when (event) { ScreenLifecycleEvent.WillAppear -> canDispatchWillAppear ScreenLifecycleEvent.Appear -> canDispatchAppear diff --git a/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.kt b/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.kt index 5ee1c96571..358e200fed 100644 --- a/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.kt +++ b/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.kt @@ -19,6 +19,7 @@ import androidx.coordinatorlayout.widget.CoordinatorLayout import com.facebook.react.uimanager.PixelUtil import com.google.android.material.appbar.AppBarLayout import com.google.android.material.appbar.AppBarLayout.ScrollingViewBehavior +import com.swmansion.rnscreens.utils.DeviceUtils class ScreenStackFragment : ScreenFragment, ScreenStackFragmentWrapper { private var mAppBarLayout: AppBarLayout? = null @@ -131,7 +132,9 @@ class ScreenStackFragment : ScreenFragment, ScreenStackFragmentWrapper { } override fun onStop() { - if (isTelevision()) mLastFocusedChild = findLastFocusedChild() + if (DeviceUtils.isPlatformAndroidTV(context)) + mLastFocusedChild = findLastFocusedChild() + super.onStop() } diff --git a/android/src/main/java/com/swmansion/rnscreens/utils/DeviceUtils.kt b/android/src/main/java/com/swmansion/rnscreens/utils/DeviceUtils.kt new file mode 100644 index 0000000000..57ddaaa5d3 --- /dev/null +++ b/android/src/main/java/com/swmansion/rnscreens/utils/DeviceUtils.kt @@ -0,0 +1,12 @@ +package com.swmansion.rnscreens.utils + +import android.content.Context +import android.content.pm.PackageManager + +object DeviceUtils { + + fun isPlatformAndroidTV(context: Context?): Boolean { + return context?.packageManager?.hasSystemFeature(PackageManager.FEATURE_LEANBACK) == true + } + +}