diff --git a/android/src/main/java/com/swmansion/rnscreens/CustomSearchView.kt b/android/src/main/java/com/swmansion/rnscreens/CustomSearchView.kt index 0b60b687d1..b6961844b5 100644 --- a/android/src/main/java/com/swmansion/rnscreens/CustomSearchView.kt +++ b/android/src/main/java/com/swmansion/rnscreens/CustomSearchView.kt @@ -22,7 +22,9 @@ class CustomSearchView(context: Context, fragment: Fragment) : SearchView(contex isIconified = true } } + private val backPressOverrider = FragmentBackPressOverrider(fragment, mOnBackPressedCallback) + var overrideBackAction: Boolean set(value) { backPressOverrider.overrideBackAction = value diff --git a/android/src/main/java/com/swmansion/rnscreens/LifecycleHelper.kt b/android/src/main/java/com/swmansion/rnscreens/LifecycleHelper.kt index 1c86cfe0ed..41bfc802df 100644 --- a/android/src/main/java/com/swmansion/rnscreens/LifecycleHelper.kt +++ b/android/src/main/java/com/swmansion/rnscreens/LifecycleHelper.kt @@ -43,8 +43,7 @@ class LifecycleHelper { } fun unregister(view: T) where T : View, T : LifecycleObserver? { - val lifecycle = mViewToLifecycleMap[view] - lifecycle?.removeObserver(view) + mViewToLifecycleMap[view]?.removeObserver(view) } companion object { diff --git a/android/src/main/java/com/swmansion/rnscreens/RNScreensPackage.kt b/android/src/main/java/com/swmansion/rnscreens/RNScreensPackage.kt index d363350e5f..3adb211196 100644 --- a/android/src/main/java/com/swmansion/rnscreens/RNScreensPackage.kt +++ b/android/src/main/java/com/swmansion/rnscreens/RNScreensPackage.kt @@ -15,7 +15,7 @@ class RNScreensPackage : ReactPackage { // This should no longer be needed if RN's autolink mechanism has Fabric support SoLoader.loadLibrary("rnscreens_modules") } - return emptyList() + return emptyList() } override fun createViewManagers(reactContext: ReactApplicationContext) = diff --git a/android/src/main/java/com/swmansion/rnscreens/Screen.kt b/android/src/main/java/com/swmansion/rnscreens/Screen.kt index c126a8f36d..dac3ac9013 100644 --- a/android/src/main/java/com/swmansion/rnscreens/Screen.kt +++ b/android/src/main/java/com/swmansion/rnscreens/Screen.kt @@ -84,12 +84,7 @@ class Screen constructor(context: ReactContext?) : FabricEnabledViewGroup(contex } val headerConfig: ScreenStackHeaderConfig? - get() { - val child = getChildAt(0) - return if (child is ScreenStackHeaderConfig) { - child - } else null - } + get() = getChildAt(0) as? ScreenStackHeaderConfig /** * While transitioning this property allows to optimize rendering behavior on Android and provide diff --git a/android/src/main/java/com/swmansion/rnscreens/ScreenContainer.kt b/android/src/main/java/com/swmansion/rnscreens/ScreenContainer.kt index ad064c4a2a..39a5113547 100644 --- a/android/src/main/java/com/swmansion/rnscreens/ScreenContainer.kt +++ b/android/src/main/java/com/swmansion/rnscreens/ScreenContainer.kt @@ -35,6 +35,7 @@ open class ScreenContainer(context: Context?) : ViewGroup(co } } private var mParentScreenFragment: ScreenFragment? = null + override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { var i = 0 val size = childCount @@ -116,19 +117,10 @@ open class ScreenContainer(context: Context?) : ViewGroup(co val screenCount: Int get() = mScreenFragments.size - fun getScreenAt(index: Int): Screen { - return mScreenFragments[index].screen - } + fun getScreenAt(index: Int): Screen = mScreenFragments[index].screen open val topScreen: Screen? - get() { - for (screenFragment in mScreenFragments) { - if (getActivityState(screenFragment) === ActivityState.ON_TOP) { - return screenFragment.screen - } - } - return null - } + get() = mScreenFragments.firstOrNull { getActivityState(it) === ActivityState.ON_TOP }?.screen private fun setFragmentManager(fm: FragmentManager) { mFragmentManager = fm @@ -200,10 +192,9 @@ open class ScreenContainer(context: Context?) : ViewGroup(co } protected fun createTransaction(): FragmentTransaction { - val fragmentManager = requireNotNull(mFragmentManager, { "mFragmentManager is null when creating transaction" }) - val transaction = fragmentManager.beginTransaction() - transaction.setReorderingAllowed(true) - return transaction + return requireNotNull(mFragmentManager) { "mFragmentManager is null when creating transaction" } + .beginTransaction() + .setReorderingAllowed(true) } private fun attachScreen(transaction: FragmentTransaction, screenFragment: ScreenFragment) { @@ -214,13 +205,11 @@ open class ScreenContainer(context: Context?) : ViewGroup(co transaction.remove(screenFragment) } - private fun getActivityState(screenFragment: ScreenFragment): ActivityState? { - return screenFragment.screen.activityState - } + private fun getActivityState(screenFragment: ScreenFragment): ActivityState? = + screenFragment.screen.activityState - open fun hasScreen(screenFragment: ScreenFragment?): Boolean { - return mScreenFragments.contains(screenFragment) - } + open fun hasScreen(screenFragment: ScreenFragment?): Boolean = + mScreenFragments.contains(screenFragment) override fun onAttachedToWindow() { super.onAttachedToWindow() @@ -233,9 +222,7 @@ open class ScreenContainer(context: Context?) : ViewGroup(co val transaction = fragmentManager.beginTransaction() var hasFragments = false for (fragment in fragmentManager.fragments) { - if (fragment is ScreenFragment && - fragment.screen.container === this - ) { + if (fragment is ScreenFragment && fragment.screen.container === this) { transaction.remove(fragment) hasFragments = true } @@ -276,19 +263,15 @@ open class ScreenContainer(context: Context?) : ViewGroup(co // children are not already detached, which may lead to calling `onDetachedFromWindow` on them // twice. // We also get the size earlier, because we will be removing child views in `for` loop. - val size = childCount - for (i in size - 1 downTo 0) { + for (i in childCount - 1 downTo 0) { removeViewAt(i) } } override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { super.onMeasure(widthMeasureSpec, heightMeasureSpec) - var i = 0 - val size = childCount - while (i < size) { + for (i in 0 until childCount) { getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec) - i++ } } @@ -332,7 +315,11 @@ open class ScreenContainer(context: Context?) : ViewGroup(co open fun onUpdate() { createTransaction().let { // detach screens that are no longer active - val orphaned: MutableSet = HashSet(requireNotNull(mFragmentManager, { "mFragmentManager is null when performing update in ScreenContainer" }).fragments) + val orphaned: MutableSet = HashSet( + requireNotNull(mFragmentManager) { + "mFragmentManager is null when performing update in ScreenContainer" + }.fragments + ) for (screenFragment in mScreenFragments) { if (getActivityState(screenFragment) === ActivityState.INACTIVE && screenFragment.isAdded diff --git a/android/src/main/java/com/swmansion/rnscreens/ScreenContainerViewManager.kt b/android/src/main/java/com/swmansion/rnscreens/ScreenContainerViewManager.kt index 8da228a374..4cf0a1443e 100644 --- a/android/src/main/java/com/swmansion/rnscreens/ScreenContainerViewManager.kt +++ b/android/src/main/java/com/swmansion/rnscreens/ScreenContainerViewManager.kt @@ -9,13 +9,9 @@ import com.facebook.react.uimanager.ViewGroupManager @ReactModule(name = ScreenContainerViewManager.REACT_CLASS) class ScreenContainerViewManager : ViewGroupManager>() { - override fun getName(): String { - return REACT_CLASS - } + override fun getName(): String = REACT_CLASS - override fun createViewInstance(reactContext: ThemedReactContext): ScreenContainer { - return ScreenContainer(reactContext) - } + override fun createViewInstance(reactContext: ThemedReactContext): ScreenContainer = ScreenContainer(reactContext) override fun addView(parent: ScreenContainer<*>, child: View, index: Int) { require(child is Screen) { "Attempt attach child that is not of type RNScreens" } @@ -30,21 +26,13 @@ class ScreenContainerViewManager : ViewGroupManager>() { parent.removeAllScreens() } - override fun getChildCount(parent: ScreenContainer<*>): Int { - return parent.screenCount - } + override fun getChildCount(parent: ScreenContainer<*>): Int = parent.screenCount - override fun getChildAt(parent: ScreenContainer<*>, index: Int): View { - return parent.getScreenAt(index) - } + override fun getChildAt(parent: ScreenContainer<*>, index: Int): View = parent.getScreenAt(index) - override fun createShadowNodeInstance(context: ReactApplicationContext): LayoutShadowNode { - return ScreensShadowNode(context) - } + override fun createShadowNodeInstance(context: ReactApplicationContext): LayoutShadowNode = ScreensShadowNode(context) - override fun needsCustomLayoutForChildren(): Boolean { - return true - } + override fun needsCustomLayoutForChildren(): Boolean = true companion object { const val REACT_CLASS = "RNSScreenContainer" diff --git a/android/src/main/java/com/swmansion/rnscreens/ScreenFragment.kt b/android/src/main/java/com/swmansion/rnscreens/ScreenFragment.kt index d2e13eacb5..f9b1a71bba 100644 --- a/android/src/main/java/com/swmansion/rnscreens/ScreenFragment.kt +++ b/android/src/main/java/com/swmansion/rnscreens/ScreenFragment.kt @@ -74,13 +74,12 @@ open class ScreenFragment : Fragment { container: ViewGroup?, savedInstanceState: Bundle? ): View? { - val wrapper = context?.let { ScreensFrameLayout(it) } - - val params = FrameLayout.LayoutParams( + screen.layoutParams = FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT ) - screen.layoutParams = params - wrapper?.addView(recycleView(screen)) + val wrapper = context?.let { ScreensFrameLayout(it) }?.apply { + addView(recycleView(screen)) + } return wrapper } @@ -153,13 +152,11 @@ open class ScreenFragment : Fragment { val childScreenContainers: List> get() = mChildScreenContainers - private fun canDispatchEvent(event: ScreenLifecycleEvent): Boolean { - return when (event) { - ScreenLifecycleEvent.WillAppear -> canDispatchWillAppear - ScreenLifecycleEvent.Appear -> canDispatchAppear - ScreenLifecycleEvent.WillDisappear -> !canDispatchWillAppear - ScreenLifecycleEvent.Disappear -> !canDispatchAppear - } + private fun canDispatchEvent(event: ScreenLifecycleEvent): Boolean = when (event) { + ScreenLifecycleEvent.WillAppear -> canDispatchWillAppear + ScreenLifecycleEvent.Appear -> canDispatchAppear + ScreenLifecycleEvent.WillDisappear -> !canDispatchWillAppear + ScreenLifecycleEvent.Disappear -> !canDispatchAppear } private fun setLastEventDispatched(event: ScreenLifecycleEvent) { @@ -173,25 +170,21 @@ open class ScreenFragment : Fragment { private fun dispatchOnWillAppear() { dispatchEvent(ScreenLifecycleEvent.WillAppear, this) - dispatchTransitionProgress(0.0f, false) } private fun dispatchOnAppear() { dispatchEvent(ScreenLifecycleEvent.Appear, this) - dispatchTransitionProgress(1.0f, false) } private fun dispatchOnWillDisappear() { dispatchEvent(ScreenLifecycleEvent.WillDisappear, this) - dispatchTransitionProgress(0.0f, true) } private fun dispatchOnDisappear() { dispatchEvent(ScreenLifecycleEvent.Disappear, this) - dispatchTransitionProgress(1.0f, true) } @@ -215,20 +208,16 @@ open class ScreenFragment : Fragment { } private fun dispatchEventInChildContainers(event: ScreenLifecycleEvent) { - for (sc in mChildScreenContainers) { - if (sc.screenCount > 0) { - sc.topScreen?.let { - sc.topScreen?.fragment?.let { fragment -> dispatchEvent(event, fragment) } - } - } + mChildScreenContainers.filter { it.screenCount > 0 }.forEach { + it.topScreen?.fragment?.let { fragment -> dispatchEvent(event, fragment) } } } fun dispatchHeaderBackButtonClickedEvent() { val screenContext = screen.context as ReactContext - val eventDispatcher: EventDispatcher? = - UIManagerHelper.getEventDispatcherForReactTag(screenContext, screen.id) - eventDispatcher?.dispatchEvent(HeaderBackButtonClickedEvent(screen.id)) + UIManagerHelper + .getEventDispatcherForReactTag(screenContext, screen.id) + ?.dispatchEvent(HeaderBackButtonClickedEvent(screen.id)) } fun dispatchTransitionProgress(alpha: Float, closing: Boolean) { @@ -244,13 +233,13 @@ open class ScreenFragment : Fragment { val container: ScreenContainer<*>? = screen.container val goingForward = if (container is ScreenStack) container.goingForward else false val screenContext = screen.context as ReactContext - val eventDispatcher: EventDispatcher? = - UIManagerHelper.getEventDispatcherForReactTag(screenContext, screen.id) - eventDispatcher?.dispatchEvent( - ScreenTransitionProgressEvent( - screen.id, mProgress, closing, goingForward, coalescingKey + UIManagerHelper + .getEventDispatcherForReactTag(screenContext, screen.id) + ?.dispatchEvent( + ScreenTransitionProgressEvent( + screen.id, mProgress, closing, goingForward, coalescingKey + ) ) - ) } } } @@ -305,9 +294,9 @@ open class ScreenFragment : Fragment { // we only send dismissed even when the screen has been removed from its container val screenContext = screen.context if (screenContext is ReactContext) { - val eventDispatcher: EventDispatcher? = - UIManagerHelper.getEventDispatcherForReactTag(screenContext, screen.id) - eventDispatcher?.dispatchEvent(ScreenDismissedEvent(screen.id)) + UIManagerHelper + .getEventDispatcherForReactTag(screenContext, screen.id) + ?.dispatchEvent(ScreenDismissedEvent(screen.id)) } } mChildScreenContainers.clear() diff --git a/android/src/main/java/com/swmansion/rnscreens/ScreenStack.kt b/android/src/main/java/com/swmansion/rnscreens/ScreenStack.kt index 54a8a64221..34aed7959d 100644 --- a/android/src/main/java/com/swmansion/rnscreens/ScreenStack.kt +++ b/android/src/main/java/com/swmansion/rnscreens/ScreenStack.kt @@ -5,7 +5,6 @@ import android.graphics.Canvas import android.view.View import com.facebook.react.bridge.ReactContext import com.facebook.react.uimanager.UIManagerHelper -import com.facebook.react.uimanager.events.EventDispatcher import com.swmansion.rnscreens.Screen.StackAnimation import com.swmansion.rnscreens.events.StackFinishTransitioningEvent import java.util.Collections @@ -23,6 +22,7 @@ class ScreenStack(context: Context?) : ScreenContainer(cont private var reverseLastTwoChildren = false private var previousChildrenCount = 0 var goingForward = false + fun dismiss(screenFragment: ScreenStackFragment) { mDismissed.add(screenFragment) performUpdatesNow() @@ -30,23 +30,19 @@ class ScreenStack(context: Context?) : ScreenContainer(cont override val topScreen: Screen? get() = mTopScreen?.screen + val rootScreen: Screen get() { - var i = 0 - val size = screenCount - while (i < size) { + for (i in 0 until screenCount) { val screen = getScreenAt(i) if (!mDismissed.contains(screen.fragment)) { return screen } - i++ } throw IllegalStateException("Stack has no root screen set") } - override fun adapt(screen: Screen): ScreenStackFragment { - return ScreenStackFragment(screen) - } + override fun adapt(screen: Screen) = ScreenStackFragment(screen) override fun startViewTransition(view: View) { super.startViewTransition(view) @@ -68,16 +64,13 @@ class ScreenStack(context: Context?) : ScreenContainer(cont } private fun dispatchOnFinishTransitioning() { - val eventDispatcher: EventDispatcher? = - UIManagerHelper.getEventDispatcherForReactTag((context as ReactContext), id) - eventDispatcher?.dispatchEvent( - StackFinishTransitioningEvent(id) - ) + UIManagerHelper + .getEventDispatcherForReactTag((context as ReactContext), id) + ?.dispatchEvent(StackFinishTransitioningEvent(id)) } override fun removeScreenAt(index: Int) { - val toBeRemoved = getScreenAt(index) - mDismissed.remove(toBeRemoved.fragment) + mDismissed.remove(getScreenAt(index).fragment) super.removeScreenAt(index) } @@ -86,9 +79,8 @@ class ScreenStack(context: Context?) : ScreenContainer(cont super.removeAllScreens() } - override fun hasScreen(screenFragment: ScreenFragment?): Boolean { - return super.hasScreen(screenFragment) && !mDismissed.contains(screenFragment) - } + override fun hasScreen(screenFragment: ScreenFragment?): Boolean = + super.hasScreen(screenFragment) && !mDismissed.contains(screenFragment) override fun onUpdate() { // When going back from a nested stack with a single screen on it, we may hit an edge case @@ -252,9 +244,7 @@ class ScreenStack(context: Context?) : ScreenContainer(cont } override fun notifyContainerUpdate() { - for (screen in mStack) { - screen.onContainerUpdate() - } + mStack.forEach { it.onContainerUpdate() } } // below methods are taken from @@ -310,16 +300,14 @@ class ScreenStack(context: Context?) : ScreenContainer(cont super.drawChild(op.canvas, op.child, op.drawingTime) } - private fun obtainDrawingOp(): DrawingOp { - return if (drawingOpPool.isEmpty()) { - DrawingOp() - } else drawingOpPool.removeAt(drawingOpPool.size - 1) - } + private fun obtainDrawingOp(): DrawingOp = + if (drawingOpPool.isEmpty()) DrawingOp() else drawingOpPool.removeAt(drawingOpPool.size - 1) private inner class DrawingOp { var canvas: Canvas? = null var child: View? = null var drawingTime: Long = 0 + operator fun set(canvas: Canvas?, child: View?, drawingTime: Long): DrawingOp { this.canvas = canvas this.child = child @@ -336,18 +324,11 @@ class ScreenStack(context: Context?) : ScreenContainer(cont } companion object { - private fun isTransparent(fragment: ScreenStackFragment): Boolean { - return ( - fragment.screen.stackPresentation - === Screen.StackPresentation.TRANSPARENT_MODAL - ) - } + private fun isTransparent(fragment: ScreenStackFragment): Boolean = + fragment.screen.stackPresentation === Screen.StackPresentation.TRANSPARENT_MODAL - private fun needsDrawReordering(fragment: ScreenStackFragment): Boolean { - return ( - fragment.screen.stackAnimation === StackAnimation.SLIDE_FROM_BOTTOM || - fragment.screen.stackAnimation === StackAnimation.FADE_FROM_BOTTOM - ) - } + private fun needsDrawReordering(fragment: ScreenStackFragment): Boolean = + fragment.screen.stackAnimation === StackAnimation.SLIDE_FROM_BOTTOM || + fragment.screen.stackAnimation === StackAnimation.FADE_FROM_BOTTOM } } diff --git a/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.kt b/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.kt index d9d32d7efd..86a7654805 100644 --- a/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.kt +++ b/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.kt @@ -51,11 +51,9 @@ class ScreenStackFragment : ScreenFragment { fun setToolbar(toolbar: Toolbar) { mAppBarLayout?.addView(toolbar) - val params = AppBarLayout.LayoutParams( + toolbar.layoutParams = AppBarLayout.LayoutParams( AppBarLayout.LayoutParams.MATCH_PARENT, AppBarLayout.LayoutParams.WRAP_CONTENT - ) - params.scrollFlags = 0 - toolbar.layoutParams = params + ).apply { scrollFlags = 0 } mToolbar = toolbar } @@ -76,8 +74,7 @@ class ScreenStackFragment : ScreenFragment { } override fun onContainerUpdate() { - val headerConfig = screen.headerConfig - headerConfig?.onUpdate() + screen.headerConfig?.onUpdate() } override fun onViewAnimationEnd() { @@ -99,22 +96,24 @@ class ScreenStackFragment : ScreenFragment { ): View? { val view: ScreensCoordinatorLayout? = context?.let { ScreensCoordinatorLayout(it, this) } - val params = CoordinatorLayout.LayoutParams( + + screen.layoutParams = CoordinatorLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT - ) - params.behavior = if (mIsTranslucent) null else ScrollingViewBehavior() - screen.layoutParams = params + ).apply { behavior = if (mIsTranslucent) null else ScrollingViewBehavior() } + view?.addView(recycleView(screen)) - mAppBarLayout = context?.let { AppBarLayout(it) } - // By default AppBarLayout will have a background color set but since we cover the whole layout - // with toolbar (that can be semi-transparent) the bar layout background color does not pay a - // role. On top of that it breaks screens animations when alfa offscreen compositing is off - // (which is the default) - mAppBarLayout?.setBackgroundColor(Color.TRANSPARENT) - mAppBarLayout?.layoutParams = AppBarLayout.LayoutParams( - AppBarLayout.LayoutParams.MATCH_PARENT, AppBarLayout.LayoutParams.WRAP_CONTENT - ) + mAppBarLayout = context?.let { AppBarLayout(it) }?.apply { + // By default AppBarLayout will have a background color set but since we cover the whole layout + // with toolbar (that can be semi-transparent) the bar layout background color does not pay a + // role. On top of that it breaks screens animations when alfa offscreen compositing is off + // (which is the default) + setBackgroundColor(Color.TRANSPARENT) + layoutParams = AppBarLayout.LayoutParams( + AppBarLayout.LayoutParams.MATCH_PARENT, AppBarLayout.LayoutParams.WRAP_CONTENT + ) + } + view?.addView(mAppBarLayout) if (mShadowHidden) { mAppBarLayout?.targetElevation = 0f @@ -157,9 +156,10 @@ class ScreenStackFragment : ScreenFragment { searchView = newSearchView onSearchViewCreate?.invoke(newSearchView) } - val item = menu.add("") - item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS) - item.actionView = searchView + menu.add("").apply { + setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS) + actionView = searchView + } } } @@ -213,18 +213,23 @@ class ScreenStackFragment : ScreenFragment { // and also this is not necessary when going back since the lifecycle methods // are correctly dispatched then. // We also add fakeAnimation to the set of animations, which sends the progress of animation - val fakeAnimation = ScreensAnimation(mFragment) - fakeAnimation.duration = animation.duration + val fakeAnimation = ScreensAnimation(mFragment).apply { duration = animation.duration } + if (animation is AnimationSet && !mFragment.isRemoving) { - animation.addAnimation(fakeAnimation) - animation.setAnimationListener(mAnimationListener) - super.startAnimation(animation) + animation.apply { + addAnimation(fakeAnimation) + setAnimationListener(mAnimationListener) + }.also { + super.startAnimation(it) + } } else { - val set = AnimationSet(true) - set.addAnimation(animation) - set.addAnimation(fakeAnimation) - set.setAnimationListener(mAnimationListener) - super.startAnimation(set) + AnimationSet(true).apply { + addAnimation(animation) + addAnimation(fakeAnimation) + setAnimationListener(mAnimationListener) + }.also { + super.startAnimation(it) + } } } diff --git a/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfig.kt b/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfig.kt index 5b3e0080cd..aa4c27c0c4 100644 --- a/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfig.kt +++ b/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfig.kt @@ -1,6 +1,5 @@ package com.swmansion.rnscreens -import android.annotation.SuppressLint import android.content.Context import android.graphics.PorterDuff import android.os.Build @@ -101,23 +100,9 @@ class ScreenStackHeaderConfig(context: Context) : ViewGroup(context) { } private val screen: Screen? - get() { - val screen = parent - return if (screen is Screen) { - screen - } else null - } + get() = parent as? Screen private val screenStack: ScreenStack? - get() { - val screen = screen - if (screen != null) { - val container = screen.container - if (container is ScreenStack) { - return container - } - } - return null - } + get() = screen?.container as? ScreenStack val screenFragment: ScreenStackFragment? get() { val screen = parent @@ -133,9 +118,11 @@ class ScreenStackHeaderConfig(context: Context) : ViewGroup(context) { fun onUpdate() { val stack = screenStack val isTop = stack == null || stack.topScreen == parent + if (!mIsAttachedToWindow || !isTop || mDestroyed) { return } + val activity = screenFragment?.activity as AppCompatActivity? ?: return if (mDirection != null) { if (mDirection == "rtl") { @@ -158,15 +145,18 @@ class ScreenStackHeaderConfig(context: Context) : ViewGroup(context) { } ScreenWindowTraits.trySetWindowTraits(it, activity, reactContext) } + if (mIsHidden) { if (toolbar.parent != null) { screenFragment?.removeToolbar() } return } + if (toolbar.parent == null) { screenFragment?.setToolbar(toolbar) } + if (mIsTopInsetEnabled) { headerTopInset.let { toolbar.setPadding(0, it ?: 0, 0, 0) @@ -176,6 +166,7 @@ class ScreenStackHeaderConfig(context: Context) : ViewGroup(context) { toolbar.setPadding(0, 0, 0, 0) } } + activity.setSupportActionBar(toolbar) // non-null toolbar is set in the line above and it is used here val actionBar = requireNotNull(activity.supportActionBar) @@ -212,10 +203,12 @@ class ScreenStackHeaderConfig(context: Context) : ViewGroup(context) { // which would impact the position of custom header views rendered at the center. toolbar.contentInsetStartWithNavigation = 0 } + val titleTextView = titleTextView if (mTitleColor != 0) { toolbar.setTitleTextColor(mTitleColor) } + if (titleTextView != null) { if (mTitleFontFamily != null || mTitleFontWeight > 0) { val titleTypeface = ReactTypefaceUtils.applyStyles( @@ -233,8 +226,7 @@ class ScreenStackHeaderConfig(context: Context) : ViewGroup(context) { // color if (mTintColor != 0) { - val navigationIcon = toolbar.navigationIcon - navigationIcon?.setColorFilter(mTintColor, PorterDuff.Mode.SRC_ATOP) + toolbar.navigationIcon?.setColorFilter(mTintColor, PorterDuff.Mode.SRC_ATOP) } // subviews @@ -243,6 +235,7 @@ class ScreenStackHeaderConfig(context: Context) : ViewGroup(context) { toolbar.removeViewAt(i) } } + var i = 0 val size = mConfigSubviews.size while (i < size) { @@ -290,9 +283,7 @@ class ScreenStackHeaderConfig(context: Context) : ViewGroup(context) { } } - fun getConfigSubview(index: Int): ScreenStackHeaderSubview { - return mConfigSubviews[index] - } + fun getConfigSubview(index: Int): ScreenStackHeaderSubview = mConfigSubviews[index] val configSubviewsCount: Int get() = mConfigSubviews.size @@ -314,16 +305,13 @@ class ScreenStackHeaderConfig(context: Context) : ViewGroup(context) { private val titleTextView: TextView? get() { - var i = 0 - val size = toolbar.childCount - while (i < size) { + for (i in 0 until toolbar.childCount) { val view = toolbar.getChildAt(i) if (view is TextView) { if (view.text == toolbar.title) { return view } } - i++ } return null } diff --git a/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfigViewManager.kt b/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfigViewManager.kt index cad5603197..f17630319f 100644 --- a/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfigViewManager.kt +++ b/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfigViewManager.kt @@ -21,13 +21,9 @@ class ScreenStackHeaderConfigViewManager : ViewGroupManager(this) } - override fun getName(): String { - return REACT_CLASS - } + override fun getName(): String = REACT_CLASS - override fun createViewInstance(reactContext: ThemedReactContext): ScreenStackHeaderConfig { - return ScreenStackHeaderConfig(reactContext) - } + override fun createViewInstance(reactContext: ThemedReactContext) = ScreenStackHeaderConfig(reactContext) override fun addView(parent: ScreenStackHeaderConfig, child: View, index: Int) { if (child !is ScreenStackHeaderSubview) { @@ -50,17 +46,11 @@ class ScreenStackHeaderConfigViewManager : ViewGroupManager { - return mDelegate - } + protected override fun getDelegate(): ViewManagerDelegate = mDelegate companion object { const val REACT_CLASS = "RNSScreenStackHeaderConfig" diff --git a/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderSubview.kt b/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderSubview.kt index 8fbe5ae317..74a2c8b123 100644 --- a/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderSubview.kt +++ b/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderSubview.kt @@ -12,9 +12,7 @@ class ScreenStackHeaderSubview(context: ReactContext?) : ReactViewGroup(context) var type = Type.RIGHT val config: ScreenStackHeaderConfig? - get() { - return (parent as? CustomToolbar)?.config - } + get() = (parent as? CustomToolbar)?.config override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY && @@ -32,9 +30,7 @@ class ScreenStackHeaderSubview(context: ReactContext?) : ReactViewGroup(context) setMeasuredDimension(mReactWidth, mReactHeight) } - override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { - // no-op - } + override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) = Unit enum class Type { LEFT, CENTER, RIGHT, BACK, SEARCH_BAR diff --git a/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderSubviewManager.kt b/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderSubviewManager.kt index 9afa7818c3..b2d2505ffd 100644 --- a/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderSubviewManager.kt +++ b/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderSubviewManager.kt @@ -17,13 +17,9 @@ class ScreenStackHeaderSubviewManager : ViewGroupManager(this) } - override fun getName(): String { - return REACT_CLASS - } + override fun getName() = REACT_CLASS - override fun createViewInstance(context: ThemedReactContext): ScreenStackHeaderSubview { - return ScreenStackHeaderSubview(context) - } + override fun createViewInstance(context: ThemedReactContext) = ScreenStackHeaderSubview(context) @ReactProp(name = "type") override fun setType(view: ScreenStackHeaderSubview, type: String?) { @@ -37,9 +33,7 @@ class ScreenStackHeaderSubviewManager : ViewGroupManager { - return mDelegate - } + protected override fun getDelegate(): ViewManagerDelegate = mDelegate companion object { const val REACT_CLASS = "RNSScreenStackHeaderSubview" diff --git a/android/src/main/java/com/swmansion/rnscreens/ScreenStackViewManager.kt b/android/src/main/java/com/swmansion/rnscreens/ScreenStackViewManager.kt index fb4c78901f..d1176a4d49 100644 --- a/android/src/main/java/com/swmansion/rnscreens/ScreenStackViewManager.kt +++ b/android/src/main/java/com/swmansion/rnscreens/ScreenStackViewManager.kt @@ -3,7 +3,6 @@ package com.swmansion.rnscreens import android.view.View import android.view.ViewGroup import com.facebook.react.bridge.ReactApplicationContext -import com.facebook.react.common.MapBuilder import com.facebook.react.module.annotations.ReactModule import com.facebook.react.uimanager.LayoutShadowNode import com.facebook.react.uimanager.ThemedReactContext @@ -21,13 +20,9 @@ class ScreenStackViewManager : ViewGroupManager(), RNSScreenStackMa mDelegate = RNSScreenStackManagerDelegate(this) } - override fun getName(): String { - return REACT_CLASS - } + override fun getName() = REACT_CLASS - override fun createViewInstance(reactContext: ThemedReactContext): ScreenStack { - return ScreenStack(reactContext) - } + override fun createViewInstance(reactContext: ThemedReactContext) = ScreenStack(reactContext) override fun addView(parent: ScreenStack, child: View, index: Int) { require(child is Screen) { "Attempt attach child that is not of type RNScreen" } @@ -44,10 +39,8 @@ class ScreenStackViewManager : ViewGroupManager(), RNSScreenStackMa } private fun startTransitionRecursive(parent: ViewGroup?) { - var i = 0 parent?.let { - val size = it.childCount - while (i < size) { + for (i in 0 until it.childCount) { val child = it.getChildAt(i) child?.let { view -> it.startViewTransition(view) } if (child is ScreenStackHeaderConfig) { @@ -58,37 +51,23 @@ class ScreenStackViewManager : ViewGroupManager(), RNSScreenStackMa if (child is ViewGroup) { startTransitionRecursive(child) } - i++ } } } - override fun getChildCount(parent: ScreenStack): Int { - return parent.screenCount - } + override fun getChildCount(parent: ScreenStack) = parent.screenCount - override fun getChildAt(parent: ScreenStack, index: Int): View { - return parent.getScreenAt(index) - } + override fun getChildAt(parent: ScreenStack, index: Int): View = parent.getScreenAt(index) - override fun createShadowNodeInstance(context: ReactApplicationContext): LayoutShadowNode { - return ScreensShadowNode(context) - } + override fun createShadowNodeInstance(context: ReactApplicationContext): LayoutShadowNode = ScreensShadowNode(context) - override fun needsCustomLayoutForChildren(): Boolean { - return true - } + override fun needsCustomLayoutForChildren() = true - protected override fun getDelegate(): ViewManagerDelegate { - return mDelegate - } + protected override fun getDelegate(): ViewManagerDelegate = mDelegate - override fun getExportedCustomDirectEventTypeConstants(): MutableMap { - return MapBuilder.of( - StackFinishTransitioningEvent.EVENT_NAME, - MapBuilder.of("registrationName", "onFinishTransitioning"), - ) - } + override fun getExportedCustomDirectEventTypeConstants(): MutableMap = mutableMapOf( + StackFinishTransitioningEvent.EVENT_NAME to mutableMapOf("registrationName" to "onFinishTransitioning") + ) companion object { const val REACT_CLASS = "RNSScreenStack" diff --git a/android/src/main/java/com/swmansion/rnscreens/ScreenViewManager.kt b/android/src/main/java/com/swmansion/rnscreens/ScreenViewManager.kt index 792be5046e..736e06b652 100644 --- a/android/src/main/java/com/swmansion/rnscreens/ScreenViewManager.kt +++ b/android/src/main/java/com/swmansion/rnscreens/ScreenViewManager.kt @@ -17,7 +17,6 @@ import com.swmansion.rnscreens.events.ScreenDismissedEvent import com.swmansion.rnscreens.events.ScreenTransitionProgressEvent import com.swmansion.rnscreens.events.ScreenWillAppearEvent import com.swmansion.rnscreens.events.ScreenWillDisappearEvent -import com.swmansion.rnscreens.events.StackFinishTransitioningEvent @ReactModule(name = ScreenViewManager.REACT_CLASS) class ScreenViewManager : ViewGroupManager(), RNSScreenManagerInterface { @@ -27,13 +26,9 @@ class ScreenViewManager : ViewGroupManager(), RNSScreenManagerInterface< mDelegate = RNSScreenManagerDelegate(this) } - override fun getName(): String { - return REACT_CLASS - } + override fun getName() = REACT_CLASS - override fun createViewInstance(reactContext: ThemedReactContext): Screen { - return Screen(reactContext) - } + override fun createViewInstance(reactContext: ThemedReactContext) = Screen(reactContext) override fun setActivityState(view: Screen, activityState: Float) { setActivityState(view, activityState.toInt()) @@ -180,9 +175,7 @@ class ScreenViewManager : ViewGroupManager(), RNSScreenManagerInterface< ) } - protected override fun getDelegate(): ViewManagerDelegate { - return mDelegate - } + protected override fun getDelegate(): ViewManagerDelegate = mDelegate companion object { const val REACT_CLASS = "RNSScreen" diff --git a/android/src/main/java/com/swmansion/rnscreens/ScreenWindowTraits.kt b/android/src/main/java/com/swmansion/rnscreens/ScreenWindowTraits.kt index e8ea668ca8..56278236cd 100644 --- a/android/src/main/java/com/swmansion/rnscreens/ScreenWindowTraits.kt +++ b/android/src/main/java/com/swmansion/rnscreens/ScreenWindowTraits.kt @@ -25,6 +25,7 @@ object ScreenWindowTraits { private var mDidSetStatusBarAppearance = false private var mDidSetNavigationBarAppearance = false private var mDefaultStatusBarColor: Int? = null + internal fun applyDidSetOrientation() { mDidSetOrientation = true }