diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/FeatureToggles.kt b/lib/android/app/src/main/java/com/reactnativenavigation/FeatureToggles.kt index 72323ca1f5e..94db1c69c93 100644 --- a/lib/android/app/src/main/java/com/reactnativenavigation/FeatureToggles.kt +++ b/lib/android/app/src/main/java/com/reactnativenavigation/FeatureToggles.kt @@ -3,11 +3,13 @@ package com.reactnativenavigation import androidx.annotation.VisibleForTesting enum class RNNToggles { - TOP_BAR_COLOR_ANIMATION, + TOP_BAR_COLOR_ANIMATION__PUSH, + TOP_BAR_COLOR_ANIMATION__TABS, } private val ToggleDefaults = mapOf( - RNNToggles.TOP_BAR_COLOR_ANIMATION to false + RNNToggles.TOP_BAR_COLOR_ANIMATION__PUSH to false, + RNNToggles.TOP_BAR_COLOR_ANIMATION__TABS to false, ) object RNNFeatureToggles { diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/NavigationActivity.java b/lib/android/app/src/main/java/com/reactnativenavigation/NavigationActivity.java index 481aaf07220..f3f0d5a57ee 100644 --- a/lib/android/app/src/main/java/com/reactnativenavigation/NavigationActivity.java +++ b/lib/android/app/src/main/java/com/reactnativenavigation/NavigationActivity.java @@ -3,7 +3,6 @@ import android.annotation.TargetApi; import android.content.Intent; import android.content.res.Configuration; -import android.graphics.Color; import android.os.Build; import android.os.Bundle; import android.view.KeyEvent; @@ -12,8 +11,8 @@ import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; import com.facebook.react.modules.core.PermissionAwareActivity; import com.facebook.react.modules.core.PermissionListener; -import com.reactnativenavigation.options.Options; import com.reactnativenavigation.viewcontrollers.overlay.OverlayManager; +import com.reactnativenavigation.viewcontrollers.statusbar.StatusBarPresenter; import com.reactnativenavigation.viewcontrollers.viewcontroller.RootPresenter; import com.reactnativenavigation.react.JsDevReloadHandler; import com.reactnativenavigation.react.ReactGateway; @@ -51,6 +50,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { navigator.bindViews(); getReactGateway().onActivityCreated(this); setBackPressedCallback(); + StatusBarPresenter.Companion.init(this); } @Override diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/utils/ColorUtils.java b/lib/android/app/src/main/java/com/reactnativenavigation/utils/ColorUtils.java index cc5afbfd659..99cab710c7a 100644 --- a/lib/android/app/src/main/java/com/reactnativenavigation/utils/ColorUtils.java +++ b/lib/android/app/src/main/java/com/reactnativenavigation/utils/ColorUtils.java @@ -1,5 +1,7 @@ package com.reactnativenavigation.utils; +import android.graphics.Color; + public class ColorUtils { public static double[] colorToLAB(int color) { final double[] result = new double[3]; @@ -10,4 +12,13 @@ public static double[] colorToLAB(int color) { public static int labToColor(double[] lab) { return androidx.core.graphics.ColorUtils.LABToColor(lab[0], lab[1], lab[2]); } + + public static boolean isColorLight(int color) { + double darkness = 1 - (0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color)) / 255; + return darkness < 0.5; + } + + public static int setAlpha(int color, int alpha) { + return (color & 0x00FFFFFF) | (alpha << 24); + } } diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/utils/SystemUiUtils.kt b/lib/android/app/src/main/java/com/reactnativenavigation/utils/SystemUiUtils.kt index 95e244e72a0..16d01b2ba8e 100644 --- a/lib/android/app/src/main/java/com/reactnativenavigation/utils/SystemUiUtils.kt +++ b/lib/android/app/src/main/java/com/reactnativenavigation/utils/SystemUiUtils.kt @@ -3,7 +3,6 @@ package com.reactnativenavigation.utils import android.app.Activity import android.graphics.Color import android.graphics.Rect -import android.os.Build import android.view.View import android.view.Window import androidx.annotation.ColorInt @@ -16,7 +15,6 @@ import kotlin.math.ceil object SystemUiUtils { private const val STATUS_BAR_HEIGHT_M = 24 - private const val STATUS_BAR_HEIGHT_L = 25 internal const val STATUS_BAR_HEIGHT_TRANSLUCENCY = 0.65f private var statusBarHeight = -1 var navigationBarDefaultColor = -1 @@ -38,7 +36,7 @@ object SystemUiUtils { val contentViewTop = contentView.top abs(contentViewTop - statusBarHeight) } - } ?: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) STATUS_BAR_HEIGHT_M else STATUS_BAR_HEIGHT_L + } ?: STATUS_BAR_HEIGHT_M statusBarHeight } return res @@ -77,8 +75,6 @@ object SystemUiUtils { @JvmStatic fun setStatusBarColorScheme(window: Window?, view: View, isDark: Boolean) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return - window?.let { WindowInsetsControllerCompat(window, view).isAppearanceLightStatusBars = isDark // Workaround: on devices with api 30 status bar icons flickers or get hidden when removing view @@ -121,18 +117,17 @@ object SystemUiUtils { @ColorInt color: Int, translucent: Boolean ) { - val opaqueColor = - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { - Color.BLACK - } else { - val colorAlpha = Color.alpha(color) - val alpha = if (translucent && colorAlpha == 255) STATUS_BAR_HEIGHT_TRANSLUCENCY else colorAlpha/255.0f - val red: Int = Color.red(color) - val green: Int = Color.green(color) - val blue: Int = Color.blue(color) - Color.argb(ceil(alpha * 255).toInt(), red, green, blue) - } - window?.statusBarColor = opaqueColor + val colorAlpha = Color.alpha(color) + val alpha = if (translucent && colorAlpha == 255) STATUS_BAR_HEIGHT_TRANSLUCENCY else colorAlpha/255.0f + val red: Int = Color.red(color) + val green: Int = Color.green(color) + val blue: Int = Color.blue(color) + val opaqueColor = Color.argb(ceil(alpha * 255).toInt(), red, green, blue) + setStatusBarColor(window, opaqueColor) + } + + fun setStatusBarColor(window: Window?, color: Int) { + window?.statusBarColor = color } @JvmStatic diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabPresenter.java b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabPresenter.java index 0a49cf669a4..b69caa509b7 100644 --- a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabPresenter.java +++ b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabPresenter.java @@ -9,7 +9,6 @@ import androidx.annotation.NonNull; -import com.aurelhubert.ahbottomnavigation.AHTextView; import com.aurelhubert.ahbottomnavigation.notification.AHNotification; import com.reactnativenavigation.options.BottomTabOptions; import com.reactnativenavigation.options.DotIndicatorOptions; diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsController.java b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsController.java index e61df575d94..fa1ea72b4ee 100644 --- a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsController.java +++ b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsController.java @@ -271,11 +271,11 @@ public void selectTab(final int newIndex) { private void selectTab(int newIndex, boolean enableSelectionHistory) { saveTabSelection(newIndex, enableSelectionHistory); tabsAttacher.onTabSelected(tabs.get(newIndex)); - getCurrentView().setVisibility(View.INVISIBLE); + getCurrentChild().onDeselected(); + + ViewController previouslyVisible = getCurrentChild(); bottomTabs.setCurrentItem(newIndex, false); - getCurrentView().setVisibility(View.VISIBLE); - getCurrentChild().onViewWillAppear(); - getCurrentChild().onViewDidAppear(); + getCurrentChild().onSelected(previouslyVisible); } private void saveTabSelection(int newIndex, boolean enableSelectionHistory) { @@ -287,11 +287,6 @@ private void saveTabSelection(int newIndex, boolean enableSelectionHistory) { } } - @NonNull - private ViewGroup getCurrentView() { - return tabs.get(bottomTabs.getCurrentItem()).getView(); - } - public Animator getPushAnimation(Options appearingOptions) { return presenter.getPushAnimation(appearingOptions); } diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/component/ComponentPresenter.java b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/component/ComponentPresenter.java index e98973678e0..1f915f9875d 100644 --- a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/component/ComponentPresenter.java +++ b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/component/ComponentPresenter.java @@ -1,6 +1,12 @@ package com.reactnativenavigation.viewcontrollers.component; +import android.animation.Animator; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import com.reactnativenavigation.options.Options; +import com.reactnativenavigation.viewcontrollers.statusbar.StatusBarPresenter; import com.reactnativenavigation.views.component.ComponentLayout; public class ComponentPresenter extends ComponentPresenterBase { @@ -35,4 +41,16 @@ public void onConfigurationChanged(ComponentLayout view, Options options) { Options withDefault = options.withDefaultOptions(defaultOptions); setBackgroundColor(view, withDefault); } + + @Nullable + public Animator getStatusBarPushAnimation(@NonNull Options appearingOptions) { + Options appearingOptionsWithDefault = appearingOptions.copy().withDefaultOptions(defaultOptions); + return StatusBarPresenter.instance.getStatusBarPushAnimation(appearingOptionsWithDefault); + } + + @Nullable + public Animator getStatusBarPopAnimation(@NonNull Options appearingOptions, @NonNull Options disappearingOptions) { + Options appearingOptionsWithDefault = appearingOptions.copy().withDefaultOptions(defaultOptions); + return StatusBarPresenter.instance.getStatusBarPopAnimation(appearingOptionsWithDefault, disappearingOptions); + } } diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/component/ComponentViewController.java b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/component/ComponentViewController.java index b9e7d271e43..8e63201baf4 100644 --- a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/component/ComponentViewController.java +++ b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/component/ComponentViewController.java @@ -17,13 +17,12 @@ import com.reactnativenavigation.utils.SystemUiUtils; import com.reactnativenavigation.viewcontrollers.child.ChildController; import com.reactnativenavigation.viewcontrollers.child.ChildControllersRegistry; -import com.reactnativenavigation.viewcontrollers.stack.statusbar.StatusBarController; import com.reactnativenavigation.viewcontrollers.viewcontroller.Presenter; import com.reactnativenavigation.viewcontrollers.viewcontroller.ReactViewCreator; import com.reactnativenavigation.viewcontrollers.viewcontroller.ScrollEventListener; import com.reactnativenavigation.views.component.ComponentLayout; -public class ComponentViewController extends ChildController implements StatusBarController { +public class ComponentViewController extends ChildController { private final String componentName; private final ComponentPresenter presenter; private final ReactViewCreator viewCreator; @@ -65,27 +64,16 @@ public void setDefaultOptions(Options defaultOptions) { presenter.setDefaultOptions(defaultOptions); } - @Override - public StatusBarController getStatusBarController() { - return this; - } - @Nullable @Override - public Animator getStatusBarPushAnimation(@NonNull Options appearingOptions) { - if (super.presenter != null) { - return super.presenter.getStatusBarPushAnimation(appearingOptions); - } - return null; + public Animator getPushAnimations(Options appearingOptions) { + return this.presenter.getStatusBarPushAnimation(appearingOptions); } @Nullable @Override - public Animator getStatusBarPopAnimation(@NonNull Options appearingOptions, @NonNull Options disappearingOptions) { - if (super.presenter != null) { - return super.presenter.getStatusBarPopAnimation(appearingOptions, disappearingOptions); - } - return null; + public Animator getPopAnimations(Options appearingOptions, Options disappearingOptions) { + return this.presenter.getStatusBarPopAnimation(appearingOptions, disappearingOptions); } @Override diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/StackController.java b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/StackController.java index e9411f047e7..dfc5cc670c7 100644 --- a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/StackController.java +++ b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/StackController.java @@ -1,10 +1,23 @@ package com.reactnativenavigation.viewcontrollers.stack; +import static com.reactnativenavigation.react.Constants.HARDWARE_BACK_BUTTON_ID; +import static com.reactnativenavigation.utils.CollectionUtils.requireLast; +import static com.reactnativenavigation.utils.CoordinatorLayoutUtils.matchParentWithBehaviour; +import static com.reactnativenavigation.utils.CoordinatorLayoutUtils.updateBottomMargin; +import static com.reactnativenavigation.utils.ObjectUtils.perform; + import android.app.Activity; import android.content.res.Configuration; import android.view.View; import android.view.ViewGroup; +import androidx.annotation.NonNull; +import androidx.annotation.RestrictTo; +import androidx.annotation.Size; +import androidx.annotation.VisibleForTesting; +import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.viewpager.widget.ViewPager; + import com.facebook.react.ReactRootView; import com.reactnativenavigation.options.ButtonOptions; import com.reactnativenavigation.options.Options; @@ -18,7 +31,9 @@ import com.reactnativenavigation.viewcontrollers.stack.topbar.TopBarController; import com.reactnativenavigation.viewcontrollers.stack.topbar.button.BackButtonHelper; import com.reactnativenavigation.viewcontrollers.viewcontroller.Presenter; +import com.reactnativenavigation.viewcontrollers.viewcontroller.TopBarVisibilityInfo; import com.reactnativenavigation.viewcontrollers.viewcontroller.ViewController; +import com.reactnativenavigation.viewcontrollers.viewcontroller.ViewControllerVisibilityInfo; import com.reactnativenavigation.views.component.Component; import com.reactnativenavigation.views.stack.StackBehaviour; import com.reactnativenavigation.views.stack.StackLayout; @@ -31,19 +46,6 @@ import java.util.Iterator; import java.util.List; -import androidx.annotation.NonNull; -import androidx.annotation.RestrictTo; -import androidx.annotation.Size; -import androidx.annotation.VisibleForTesting; -import androidx.coordinatorlayout.widget.CoordinatorLayout; -import androidx.viewpager.widget.ViewPager; - -import static com.reactnativenavigation.react.Constants.HARDWARE_BACK_BUTTON_ID; -import static com.reactnativenavigation.utils.CollectionUtils.*; -import static com.reactnativenavigation.utils.CoordinatorLayoutUtils.matchParentWithBehaviour; -import static com.reactnativenavigation.utils.CoordinatorLayoutUtils.updateBottomMargin; -import static com.reactnativenavigation.utils.ObjectUtils.perform; - public class StackController extends ParentController { private IdStack> stack = new IdStack<>(); @@ -95,6 +97,19 @@ public ViewController getCurrentChild() { return stack.peek(); } + @Override + public void onSelected(ViewController previousVC) { + presenter.bindNewViewController(previousVC, this); + super.onSelected(previousVC); + } + + @NonNull + @Override + public ViewControllerVisibilityInfo getVisibilityInfo() { + TopBarVisibilityInfo topBarInfo = topBarController.getVisibilityInfo(); + return new ViewControllerVisibilityInfo(topBarInfo); + } + @Override public void onAttachToParent() { if (!isEmpty() && !getCurrentChild().isDestroyed() && !isViewShown()) { diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/StackPresenter.java b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/StackPresenter.java index 11cfc850ab9..09807552e18 100644 --- a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/StackPresenter.java +++ b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/StackPresenter.java @@ -37,6 +37,7 @@ import com.reactnativenavigation.viewcontrollers.stack.topbar.button.ButtonPresenter; import com.reactnativenavigation.viewcontrollers.stack.topbar.button.IconResolver; import com.reactnativenavigation.viewcontrollers.stack.topbar.title.TitleBarReactViewController; +import com.reactnativenavigation.viewcontrollers.statusbar.StatusBarPresenter; import com.reactnativenavigation.viewcontrollers.viewcontroller.IReactView; import com.reactnativenavigation.viewcontrollers.viewcontroller.ViewController; import com.reactnativenavigation.views.stack.topbar.TopBar; @@ -191,6 +192,12 @@ public void onChildDestroyed(ViewController child) { componentLeftButtons.remove(child.getView()); } + public void bindNewViewController(ViewController previousVC, ViewController newVC) { + Options options = newVC.resolveCurrentOptions(defaultOptions); + topBarController.bindNewViewController(previousVC, newVC); + StatusBarPresenter.instance.bindViewController(options.statusBar); + } + private void destroyButtons(@Nullable Map buttons) { if (buttons != null) forEach(buttons.values(), ViewController::destroy); @@ -423,17 +430,17 @@ public List getAdditionalPushAnimations( Options appearingOptions) { return CollectionUtils.asList( topBarController.getPushAnimation(appearingOptions, getTopBarTranslationAnimationDelta(stack, appearingCtrl)), - perform(appearingCtrl.getStatusBarController(), null, sbc -> sbc.getStatusBarPushAnimation(appearingOptions)), - perform(bottomTabsController, null, btc -> btc.getPushAnimation(appearingOptions)) - ); + perform(appearingCtrl, null, vc -> vc.getPushAnimations(appearingOptions)), + perform(bottomTabsController, null, btc -> btc.getPushAnimation(appearingOptions) + )); } public List getAdditionalPopAnimations(Options appearingOptions, Options disappearingOptions, ViewController appearingCtrl) { return CollectionUtils.asList( topBarController.getPopAnimation(appearingOptions, disappearingOptions), - perform(appearingCtrl.getStatusBarController(), null, sbc -> sbc.getStatusBarPopAnimation(appearingOptions, disappearingOptions)), - perform(bottomTabsController, null, btc -> btc.getPopAnimation(appearingOptions, disappearingOptions)) - ); + perform(appearingCtrl, null, vc -> vc.getPopAnimations(appearingOptions, disappearingOptions)), + perform(bottomTabsController, null, btc -> btc.getPopAnimation(appearingOptions, disappearingOptions) + )); } public List getAdditionalSetRootAnimations(StackController stack, ViewController appearing, diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/statusbar/StatusBarController.kt b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/statusbar/StatusBarController.kt deleted file mode 100644 index 98e8a037dfa..00000000000 --- a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/statusbar/StatusBarController.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.reactnativenavigation.viewcontrollers.stack.statusbar - -import android.animation.Animator -import com.reactnativenavigation.options.Options - -interface StatusBarController { - fun getStatusBarPushAnimation(appearingOptions: Options): Animator? - fun getStatusBarPopAnimation(appearingOptions: Options, disappearingOptions: Options): Animator? -} diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/statusbar/StatusBarPresenter.kt b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/statusbar/StatusBarPresenter.kt deleted file mode 100644 index 06412dec790..00000000000 --- a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/statusbar/StatusBarPresenter.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.reactnativenavigation.viewcontrollers.stack.statusbar - -import android.animation.Animator -import com.reactnativenavigation.options.Options - -interface StatusBarPresenter { - fun getStatusBarPushAnimation(appearingOptions: Options): Animator? - fun getStatusBarPopAnimation(appearingOptions: Options, disappearingOptions: Options): Animator? -} diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/topbar/TopBarController.kt b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/topbar/TopBarController.kt index 1438a3e6999..bb2ec2f8245 100644 --- a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/topbar/TopBarController.kt +++ b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/topbar/TopBarController.kt @@ -4,12 +4,14 @@ import android.animation.Animator import android.animation.AnimatorSet import android.content.Context import android.graphics.drawable.ColorDrawable +import android.os.Build import android.view.MenuItem import android.view.View import androidx.core.animation.addListener +import androidx.core.animation.doOnEnd import androidx.viewpager.widget.ViewPager import com.reactnativenavigation.RNNFeatureToggles -import com.reactnativenavigation.RNNToggles.TOP_BAR_COLOR_ANIMATION +import com.reactnativenavigation.RNNToggles import com.reactnativenavigation.options.Alignment import com.reactnativenavigation.options.AnimationOptions import com.reactnativenavigation.options.Options @@ -20,6 +22,8 @@ import com.reactnativenavigation.utils.ViewUtils import com.reactnativenavigation.utils.resetViewProperties import com.reactnativenavigation.viewcontrollers.stack.topbar.button.ButtonController import com.reactnativenavigation.viewcontrollers.stack.topbar.title.TitleBarReactViewController +import com.reactnativenavigation.viewcontrollers.viewcontroller.TopBarVisibilityInfo +import com.reactnativenavigation.viewcontrollers.viewcontroller.ViewController import com.reactnativenavigation.views.animations.ColorAnimator import com.reactnativenavigation.views.stack.StackLayout import com.reactnativenavigation.views.stack.topbar.TopBar @@ -43,6 +47,9 @@ open class TopBarController( val leftButtonCount: Int get() = leftButtonBar.buttonCount + val visibilityInfo: TopBarVisibilityInfo + get() = TopBarVisibilityInfo(view.isShown, getBackgroundColor()) + fun createView(context: Context, parent: StackLayout): TopBar { if (!::view.isInitialized) { view = createTopBar(context, parent) @@ -73,6 +80,14 @@ open class TopBarController( } } + fun getBackgroundColor(): Int? { + return if (view.background is ColorDrawable) { + (view.background as ColorDrawable).color + } else { + null + } + } + fun getRightButton(index: Int): MenuItem = rightButtonBar.getButton(index) fun getPushAnimation(appearingOptions: Options, additionalDy: Float = 0f): Animator? { @@ -132,6 +147,24 @@ open class TopBarController( ) } + fun bindNewViewController(previousVC: ViewController<*>?, newVC: ViewController<*>?) { + if (!RNNFeatureToggles.isEnabled(RNNToggles.TOP_BAR_COLOR_ANIMATION__TABS)) { + return + } + + previousVC?.visibilityInfo?.topBarVisibilityInfo?.solidColor?.let { fromColor -> + newVC?.visibilityInfo?.topBarVisibilityInfo?.solidColor?.let { toColor -> + colorAnimator.getAnimation(view, fromColor, toColor).apply { + doOnEnd { + hasPendingColorAnim = false + } + hasPendingColorAnim = true + start() + } + } + } + } + fun show() { if (ViewUtils.isVisible(view) || appearAnimator.isAnimatingShow()) return view.resetViewProperties() @@ -191,7 +224,7 @@ open class TopBarController( if (targetColor.hasValue() && view.background is ColorDrawable - && RNNFeatureToggles.isEnabled(TOP_BAR_COLOR_ANIMATION)) { + && RNNFeatureToggles.isEnabled(RNNToggles.TOP_BAR_COLOR_ANIMATION__PUSH)) { return colorAnimator.getAnimation( view, (view.background as ColorDrawable).color, diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/statusbar/StatusBarPresenter.kt b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/statusbar/StatusBarPresenter.kt new file mode 100644 index 00000000000..6b060ed4dc6 --- /dev/null +++ b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/statusbar/StatusBarPresenter.kt @@ -0,0 +1,212 @@ +package com.reactnativenavigation.viewcontrollers.statusbar + +import android.animation.Animator +import android.app.Activity +import android.graphics.Color +import android.view.View +import android.view.Window +import com.reactnativenavigation.RNNFeatureToggles.isEnabled +import com.reactnativenavigation.RNNToggles +import com.reactnativenavigation.options.Options +import com.reactnativenavigation.options.StatusBarOptions +import com.reactnativenavigation.options.StatusBarOptions.TextColorScheme +import com.reactnativenavigation.options.params.Bool +import com.reactnativenavigation.utils.ColorUtils.isColorLight +import com.reactnativenavigation.utils.StubAnimationListener.Companion.onAnimatorEnd +import com.reactnativenavigation.utils.SystemUiUtils.clearStatusBarTranslucency +import com.reactnativenavigation.utils.SystemUiUtils.getStatusBarColor +import com.reactnativenavigation.utils.SystemUiUtils.hideStatusBar +import com.reactnativenavigation.utils.SystemUiUtils.isTranslucent +import com.reactnativenavigation.utils.SystemUiUtils.setStatusBarColor +import com.reactnativenavigation.utils.SystemUiUtils.setStatusBarColorScheme +import com.reactnativenavigation.utils.SystemUiUtils.setStatusBarTranslucent +import com.reactnativenavigation.utils.SystemUiUtils.showStatusBar +import com.reactnativenavigation.viewcontrollers.viewcontroller.StatusBarColorAnimator +import com.reactnativenavigation.viewcontrollers.viewcontroller.ViewController +import java.lang.ref.WeakReference + +class StatusBarPresenter private constructor( + activity: Activity, + private val sbColorAnimator: StatusBarColorAnimator = StatusBarColorAnimator(activity)) { + + private val window = WeakReference(activity.window) + private var hasPendingColorAnim = false + + fun applyOptions(viewController: ViewController<*>, options: StatusBarOptions) { + if (!hasPendingColorAnim) { + setStatusBarBackgroundColor(options) + setTranslucent(options) + } + setTextColorScheme(options) + setStatusBarVisible(viewController, options.visible) + } + + fun mergeOptions(view: View, statusBar: StatusBarOptions) { + mergeStatusBarBackgroundColor(statusBar) + mergeTextColorScheme(statusBar) + mergeTranslucent(statusBar) + mergeStatusBarVisible(view, statusBar.visible) + } + + fun onConfigurationChanged(options: StatusBarOptions) { + setStatusBarBackgroundColor(options) + setTextColorScheme(options) + } + + fun bindViewController(newOptions: StatusBarOptions) { + if (!isEnabled(RNNToggles.TOP_BAR_COLOR_ANIMATION__TABS)) { + return + } + + if (newOptions.backgroundColor.canApplyValue()) { + val currentColor = getCurrentStatusBarBackgroundColor() ?: return + val newColor = getStatusBarBackgroundColor(newOptions) + createStatusBarColorAnimation( + from = currentColor, + to = newColor, + translucent = newOptions.translucent.isTrue, + ).start() + } + } + + fun getStatusBarPushAnimation(appearingOptions: Options): Animator? = + if (isEnabled(RNNToggles.TOP_BAR_COLOR_ANIMATION__PUSH)) { + getStatusBarColorAnimation(appearingOptions.statusBar) + } else null + + fun getStatusBarPopAnimation(appearingOptions: Options, disappearingOptions: Options): Animator? = + if (isEnabled(RNNToggles.TOP_BAR_COLOR_ANIMATION__PUSH)) { + getStatusBarColorAnimation(appearingOptions.statusBar) + } else null + + private fun setStatusBarBackgroundColor(statusBar: StatusBarOptions) { + if (statusBar.backgroundColor.canApplyValue()) { + val statusBarBackgroundColor: Int = getStatusBarBackgroundColor(statusBar) + setStatusBarBackgroundColor(statusBarBackgroundColor, statusBar.translucent.isTrue) + } + } + + private fun setStatusBarBackgroundColor(color: Int, translucent: Boolean) { + setStatusBarColor(window.get(), color, translucent) + } + + private fun getStatusBarBackgroundColor(statusBar: StatusBarOptions): Int { + val defaultColor = + if (statusBar.visible.isTrueOrUndefined) Color.BLACK else Color.TRANSPARENT + return statusBar.backgroundColor.get(defaultColor)!! + } + + private fun setTextColorScheme(statusBar: StatusBarOptions) { + val view = window.get()?.decorView + //View.post is a Workaround, added to solve internal Samsung + //Android 9 issues. For more info see https://github.com/wix/react-native-navigation/pull/7231 + view?.post { + setStatusBarColorScheme( + window.get(), + view, + isDarkTextColorScheme(statusBar) + ) + } + } + + private fun setTranslucent(options: StatusBarOptions) { + val window = window.get() + if (options.translucent.isTrue) { + setStatusBarTranslucent(window) + } else if (isTranslucent(window)) { + clearStatusBarTranslucency(window) + } + } + + private fun setStatusBarVisible(viewController: ViewController<*>, visible: Bool) { + val window = window.get() ?: return + val view = if (viewController.view != null) viewController.view else window.decorView + if (visible.isFalse) { + hideStatusBar(window, view) + } else { + showStatusBar(window, view) + } + } + + private fun mergeStatusBarBackgroundColor(statusBar: StatusBarOptions) { + if (statusBar.backgroundColor.hasValue()) { + val statusBarBackgroundColor = getStatusBarBackgroundColor(statusBar) + setStatusBarColor( + window.get(), statusBarBackgroundColor, + statusBar.translucent.isTrue + ) + } + } + + private fun mergeTextColorScheme(statusBar: StatusBarOptions) { + if (!statusBar.textColorScheme.hasValue()) return + setTextColorScheme(statusBar) + } + + private fun mergeTranslucent(options: StatusBarOptions) { + val window: Window = window.get() ?: return + if (options.translucent.isTrue) { + setStatusBarTranslucent(window) + } else if (options.translucent.isFalse && isTranslucent(window)) { + clearStatusBarTranslucency(window) + } + } + + private fun mergeStatusBarVisible(view: View, visible: Bool) { + if (visible.hasValue()) { + if (visible.isTrue) { + showStatusBar(window.get(), view) + } else { + hideStatusBar(window.get(), view) + } + } + } + + private fun isDarkTextColorScheme(statusBar: StatusBarOptions): Boolean { + if (statusBar.textColorScheme == TextColorScheme.Dark) { + return true + } + + if (statusBar.textColorScheme == TextColorScheme.Light) { + return false + } + return isColorLight(getStatusBarBackgroundColor(statusBar)) + } + + private fun getStatusBarColorAnimation(statusBarOptions: StatusBarOptions): Animator? { + if (isEnabled(RNNToggles.TOP_BAR_COLOR_ANIMATION__TABS)) { + getCurrentStatusBarBackgroundColor()?.let { currentColor -> + val targetColor = statusBarOptions.backgroundColor + + if (targetColor.hasValue()) { + val translucent = statusBarOptions.translucent.isTrue + return createStatusBarColorAnimation( + from = currentColor, + to = targetColor.get(), + translucent = translucent, + ) + } + } + } + return null + } + + private fun createStatusBarColorAnimation(from: Int, to: Int, translucent: Boolean): Animator = + sbColorAnimator.getAnimator(from, to, translucent).apply { + addListener(onAnimatorEnd { + hasPendingColorAnim = false + }) + hasPendingColorAnim = true + } + + private fun getCurrentStatusBarBackgroundColor() = + getStatusBarColor(window.get()) + + companion object { + lateinit var instance: StatusBarPresenter + + fun init(activity: Activity) { + instance = StatusBarPresenter(activity) + } + } +} diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/viewcontroller/Presenter.java b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/viewcontroller/Presenter.java index a41b1a32eed..f1e16de088b 100644 --- a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/viewcontroller/Presenter.java +++ b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/viewcontroller/Presenter.java @@ -1,9 +1,7 @@ package com.reactnativenavigation.viewcontrollers.viewcontroller; -import static com.reactnativenavigation.utils.StubAnimationListener.onAnimatorEnd; +import static com.reactnativenavigation.utils.ColorUtils.isColorLight; -import android.animation.Animator; -import android.animation.ValueAnimator; import android.app.Activity; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; @@ -12,44 +10,24 @@ import android.view.View; import android.view.ViewGroup; import android.view.ViewGroup.MarginLayoutParams; -import android.view.Window; -import androidx.annotation.NonNull; - -import com.reactnativenavigation.RNNFeatureToggles; -import com.reactnativenavigation.RNNToggles; -import com.reactnativenavigation.options.AnimationOptions; import com.reactnativenavigation.options.NavigationBarOptions; import com.reactnativenavigation.options.Options; import com.reactnativenavigation.options.OrientationOptions; import com.reactnativenavigation.options.StatusBarOptions; -import com.reactnativenavigation.options.StatusBarOptions.TextColorScheme; import com.reactnativenavigation.options.layout.LayoutInsets; -import com.reactnativenavigation.options.params.Bool; -import com.reactnativenavigation.options.params.ThemeColour; import com.reactnativenavigation.utils.SystemUiUtils; import com.reactnativenavigation.viewcontrollers.navigator.Navigator; import com.reactnativenavigation.viewcontrollers.parent.ParentController; -import com.reactnativenavigation.viewcontrollers.stack.statusbar.StatusBarPresenter; -import com.reactnativenavigation.views.animations.ColorAnimator; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import com.reactnativenavigation.viewcontrollers.statusbar.StatusBarPresenter; -public class Presenter implements StatusBarPresenter { +public class Presenter { private final Activity activity; - private final ColorAnimator colorAnimator; private Options defaultOptions; - private Boolean hasPendingColorAnim = false; public Presenter(Activity activity, Options defaultOptions) { - this(activity, defaultOptions, new ColorAnimator()); - } - - public Presenter(Activity activity, Options defaultOptions, ColorAnimator colorAnimator) { this.activity = activity; - this.colorAnimator = colorAnimator; this.defaultOptions = defaultOptions; } @@ -77,13 +55,13 @@ public void applyOptions(ViewController view, Options options) { Options withDefaultOptions = options.copy().withDefaultOptions(defaultOptions); applyOrientation(withDefaultOptions.layout.orientation); applyViewOptions(view, withDefaultOptions); - applyStatusBarOptions(view, withDefaultOptions); + applyStatusBarOptions(view, withDefaultOptions.statusBar); applyNavigationBarOptions(withDefaultOptions.navigationBar); } public void onViewBroughtToFront(ViewController viewController, Options options) { Options withDefaultOptions = options.copy().withDefaultOptions(defaultOptions); - applyStatusBarOptions(viewController, withDefaultOptions); + applyStatusBarOptions(viewController, withDefaultOptions.statusBar); } private void applyOrientation(OrientationOptions options) { @@ -126,152 +104,12 @@ private void applyBackgroundColor(ViewController view, Options options) { } } - private void applyStatusBarOptions(ViewController viewController, Options options) { - StatusBarOptions statusBar = options.copy().withDefaultOptions(defaultOptions).statusBar; - - if (!hasPendingColorAnim) { - setStatusBarBackgroundColor(statusBar); - } - setTextColorScheme(statusBar); - setTranslucent(statusBar); - setStatusBarVisible(viewController, statusBar.visible); - } - - @Nullable - @Override - public Animator getStatusBarPushAnimation(@NotNull Options appearingOptions) { - StatusBarOptions statusBarOptions = appearingOptions.statusBar; - return getStatusBarColorAnimation(statusBarOptions); - } - - @androidx.annotation.Nullable - @Override - public Animator getStatusBarPopAnimation(@NonNull Options appearingOptions, @NonNull Options disappearingOptions) { - StatusBarOptions statusBarOptions = appearingOptions.statusBar; - return getStatusBarColorAnimation(statusBarOptions); - } - - private Animator getStatusBarColorAnimation(StatusBarOptions statusBarOptions) { - if (RNNFeatureToggles.isEnabled(RNNToggles.TOP_BAR_COLOR_ANIMATION)) { - ThemeColour targetColor = statusBarOptions.backgroundColor; - - if (targetColor.hasValue()) { - boolean translucent = statusBarOptions.translucent.isTrue(); - ValueAnimator animator = colorAnimator.getAnimation( - getCurrentStatusBarBackgroundColor(), - targetColor.get() - ); - - animator.addUpdateListener(animation -> - setStatusBarBackgroundColor((int) animation.getAnimatedValue(), translucent)); - - animator.addListener(onAnimatorEnd(animation -> { - hasPendingColorAnim = false; - return null; - })); - - hasPendingColorAnim = true; - return animator; - } - } - hasPendingColorAnim = false; - return null; - } - - private void setTranslucent(StatusBarOptions options) { - Window window = activity.getWindow(); - if (options.translucent.isTrue()) { - SystemUiUtils.setStatusBarTranslucent(window); - } else if (SystemUiUtils.isTranslucent(window)) { - SystemUiUtils.clearStatusBarTranslucency(window); - } - } - - private void setStatusBarVisible(ViewController viewController, Bool visible) { - final View view = viewController.view != null ? viewController.view : activity.getWindow().getDecorView(); - if (visible.isFalse()) { - SystemUiUtils.hideStatusBar(activity.getWindow(), view); - } else { - SystemUiUtils.showStatusBar(activity.getWindow(), view); - } - } - - private void setStatusBarBackgroundColor(StatusBarOptions statusBar) { - if (statusBar.backgroundColor.canApplyValue()) { - final int statusBarBackgroundColor = getStatusBarBackgroundColor(statusBar); - setStatusBarBackgroundColor(statusBarBackgroundColor, statusBar.translucent.isTrue()); - } - } - - private void setStatusBarBackgroundColor(int color, Boolean translucent) { - SystemUiUtils.setStatusBarColor(activity.getWindow(), color, translucent); - } - - private boolean isDarkTextColorScheme(StatusBarOptions statusBar) { - if (statusBar.textColorScheme == TextColorScheme.Dark) { - return true; - } else if (statusBar.textColorScheme == TextColorScheme.Light) { - return false; - } - - return isColorLight(getStatusBarBackgroundColor(statusBar)); + private void applyStatusBarOptions(ViewController viewController, StatusBarOptions options) { + StatusBarPresenter.instance.applyOptions(viewController, options); } - private int getStatusBarBackgroundColor(StatusBarOptions statusBar) { - int defaultColor = statusBar.visible.isTrueOrUndefined() ? Color.BLACK : Color.TRANSPARENT; - return statusBar.backgroundColor.get(defaultColor); - } - - private int getCurrentStatusBarBackgroundColor() { - return SystemUiUtils.getStatusBarColor(activity.getWindow()); - } - - private void setTextColorScheme(StatusBarOptions statusBar) { - final View view = activity.getWindow().getDecorView(); - //View.post is a Workaround, added to solve internal Samsung - //Android 9 issues. For more info see https://github.com/wix/react-native-navigation/pull/7231 - view.post(() -> { - SystemUiUtils.setStatusBarColorScheme(activity.getWindow(), view, isDarkTextColorScheme(statusBar)); - }); - } - - private void mergeStatusBarOptions(View view, StatusBarOptions statusBar) { - mergeStatusBarBackgroundColor(statusBar); - mergeTextColorScheme(statusBar); - mergeTranslucent(statusBar); - mergeStatusBarVisible(view, statusBar.visible); - } - - private void mergeStatusBarBackgroundColor(StatusBarOptions statusBar) { - if (statusBar.backgroundColor.hasValue()) { - final int statusBarBackgroundColor = getStatusBarBackgroundColor(statusBar); - SystemUiUtils.setStatusBarColor(activity.getWindow(), statusBarBackgroundColor, - statusBar.translucent.isTrue()); - } - } - - private void mergeTextColorScheme(StatusBarOptions statusBar) { - if (!statusBar.textColorScheme.hasValue()) return; - setTextColorScheme(statusBar); - } - - private void mergeTranslucent(StatusBarOptions options) { - Window window = activity.getWindow(); - if (options.translucent.isTrue()) { - SystemUiUtils.setStatusBarTranslucent(window); - } else if (options.translucent.isFalse() && SystemUiUtils.isTranslucent(window)) { - SystemUiUtils.clearStatusBarTranslucency(window); - } - } - - private void mergeStatusBarVisible(View view, Bool visible) { - if (visible.hasValue()) { - if (visible.isTrue()) { - SystemUiUtils.showStatusBar(activity.getWindow(), view); - } else { - SystemUiUtils.hideStatusBar(activity.getWindow(), view); - } - } + private void mergeStatusBarOptions(View view, StatusBarOptions statusBarOptions) { + StatusBarPresenter.instance.mergeOptions(view, statusBarOptions); } private void applyNavigationBarOptions(NavigationBarOptions options) { @@ -309,16 +147,10 @@ private void setNavigationBarBackgroundColor(NavigationBarOptions navigationBar) } } - private boolean isColorLight(int color) { - double darkness = 1 - (0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color)) / 255; - return darkness < 0.5; - } - public void onConfigurationChanged(ViewController controller, Options options) { Options withDefault = options.withDefaultOptions(defaultOptions); setNavigationBarBackgroundColor(withDefault.navigationBar); - setStatusBarBackgroundColor(withDefault.statusBar); - setTextColorScheme(withDefault.statusBar); + StatusBarPresenter.instance.onConfigurationChanged(withDefault.statusBar); applyBackgroundColor(controller, withDefault); } } diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/viewcontroller/StatusBarColorAnimator.kt b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/viewcontroller/StatusBarColorAnimator.kt new file mode 100644 index 00000000000..795d285efea --- /dev/null +++ b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/viewcontroller/StatusBarColorAnimator.kt @@ -0,0 +1,28 @@ +package com.reactnativenavigation.viewcontrollers.viewcontroller + +import android.animation.ValueAnimator +import android.app.Activity +import com.reactnativenavigation.utils.ColorUtils +import com.reactnativenavigation.utils.SystemUiUtils +import com.reactnativenavigation.views.animations.ColorAnimator +import java.lang.ref.WeakReference + +private const val STATUS_BAR_TRANSLUCENCY_ALPHA = (SystemUiUtils.STATUS_BAR_HEIGHT_TRANSLUCENCY * 255).toInt() + +class StatusBarColorAnimator(val activity: Activity) { + private val colorAnimator = ColorAnimator() + private val window = WeakReference(activity.window) + + fun getAnimator(from: Int, to: Int, isTranslucent: Boolean): ValueAnimator = + colorAnimator.getAnimation( + from = from, + to = embedTranslucency(to, isTranslucent) + ).apply { + addUpdateListener { animation -> + SystemUiUtils.setStatusBarColor(window.get(), animation.animatedValue as Int) + } + } + + private fun embedTranslucency(color: Int, isTranslucent: Boolean): Int = + if (!isTranslucent) color else ColorUtils.setAlpha(color, STATUS_BAR_TRANSLUCENCY_ALPHA) +} diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/viewcontroller/ViewController.java b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/viewcontroller/ViewController.java index a25ee7c869d..32f90d47db2 100644 --- a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/viewcontroller/ViewController.java +++ b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/viewcontroller/ViewController.java @@ -3,6 +3,7 @@ import static com.reactnativenavigation.utils.CollectionUtils.forEach; import static com.reactnativenavigation.utils.ObjectUtils.perform; +import android.animation.Animator; import android.app.Activity; import android.content.res.Configuration; import android.view.View; @@ -12,11 +13,11 @@ import androidx.annotation.CallSuper; import androidx.annotation.CheckResult; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.coordinatorlayout.widget.CoordinatorLayout; -import com.reactnativenavigation.BuildConfig; import com.reactnativenavigation.options.Options; import com.reactnativenavigation.options.params.Bool; import com.reactnativenavigation.options.params.NullBool; @@ -27,7 +28,6 @@ import com.reactnativenavigation.utils.UiUtils; import com.reactnativenavigation.viewcontrollers.parent.ParentController; import com.reactnativenavigation.viewcontrollers.stack.StackController; -import com.reactnativenavigation.viewcontrollers.stack.statusbar.StatusBarController; import com.reactnativenavigation.viewcontrollers.viewcontroller.overlay.ViewControllerOverlay; import com.reactnativenavigation.views.BehaviourAdapter; import com.reactnativenavigation.views.component.Component; @@ -92,10 +92,6 @@ public ViewController(Activity activity, String id, YellowBoxDelegate yellowBoxD options = initialOptions.copy(); } - public StatusBarController getStatusBarController() { - return null; - } - public void setWaitForRender(Bool waitForRender) { this.waitForRender = waitForRender; } @@ -118,10 +114,34 @@ public void removeOnAppearedListener(Runnable onAppearedListener) { public abstract T createView(); + public void onSelected(ViewController previousVC) { + setVisible(); + } + + public void onDeselected() { + setInvisible(); + } + + public void setVisible() { + getView().setVisibility(View.VISIBLE); + + onViewWillAppear(); + onViewDidAppear(); + } + + public void setInvisible() { + getView().setVisibility(View.INVISIBLE); + } + public void setViewVisibilityListener(ViewVisibilityListener viewVisibilityListener) { this.viewVisibilityListener = viewVisibilityListener; } + @NonNull + public ViewControllerVisibilityInfo getVisibilityInfo() { + return new ViewControllerVisibilityInfo(null); + } + @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) public void ensureViewIsCreated() { getView(); @@ -177,7 +197,6 @@ public void applyOptions(Options options) { } public void setDefaultOptions(Options defaultOptions) { - } public Activity getActivity() { @@ -357,6 +376,14 @@ public void onChildViewRemoved(View view, View view1) { } + public Animator getPushAnimations(Options appearingOptions) { + return null; + } + + public Animator getPopAnimations(Options appearingOptions, Options disappearingOptions) { + return null; + } + protected void runOnPreDraw(Func1 task) { if (!isDestroyed) UiUtils.runOnPreDrawOnce(getView(), task); } diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/viewcontroller/ViewControllerVisibilityInfo.kt b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/viewcontroller/ViewControllerVisibilityInfo.kt new file mode 100644 index 00000000000..c04b014dca5 --- /dev/null +++ b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/viewcontroller/ViewControllerVisibilityInfo.kt @@ -0,0 +1,5 @@ +package com.reactnativenavigation.viewcontrollers.viewcontroller + +data class TopBarVisibilityInfo(val isShown: Boolean, val solidColor: Int?) + +data class ViewControllerVisibilityInfo(val topBarVisibilityInfo: TopBarVisibilityInfo?) diff --git a/lib/android/app/src/test/java/com/reactnativenavigation/BaseTest.kt b/lib/android/app/src/test/java/com/reactnativenavigation/BaseTest.kt index 4a7d078a7d7..cadb5347ec2 100644 --- a/lib/android/app/src/test/java/com/reactnativenavigation/BaseTest.kt +++ b/lib/android/app/src/test/java/com/reactnativenavigation/BaseTest.kt @@ -59,6 +59,8 @@ abstract class BaseTest { Mockito.`when`(res.getColor(ArgumentMatchers.anyInt())).thenReturn(0x00000) Mockito.`when`(res.getColor(ArgumentMatchers.anyInt(), ArgumentMatchers.any())) .thenReturn(0x00000) + + RNNFeatureToggles.init() } diff --git a/lib/android/app/src/test/java/com/reactnativenavigation/mocks/TitleBarReactViewCreatorMock.java b/lib/android/app/src/test/java/com/reactnativenavigation/mocks/TitleBarReactViewCreatorMock.java index 03d29ca938c..16787818630 100644 --- a/lib/android/app/src/test/java/com/reactnativenavigation/mocks/TitleBarReactViewCreatorMock.java +++ b/lib/android/app/src/test/java/com/reactnativenavigation/mocks/TitleBarReactViewCreatorMock.java @@ -1,13 +1,13 @@ package com.reactnativenavigation.mocks; +import static org.mockito.Mockito.mock; + import android.app.Activity; import com.facebook.react.ReactInstanceManager; import com.reactnativenavigation.views.stack.topbar.titlebar.TitleBarReactView; import com.reactnativenavigation.views.stack.topbar.titlebar.TitleBarReactViewCreator; -import static org.mockito.Mockito.mock; - public class TitleBarReactViewCreatorMock extends TitleBarReactViewCreator { public TitleBarReactViewCreatorMock() { super(mock(ReactInstanceManager.class)); diff --git a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsControllerTest.kt b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsControllerTest.kt index abc19305509..ee9091bf0ac 100644 --- a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsControllerTest.kt +++ b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsControllerTest.kt @@ -27,6 +27,7 @@ import com.reactnativenavigation.viewcontrollers.bottomtabs.attacher.BottomTabsA import com.reactnativenavigation.viewcontrollers.child.ChildControllersRegistry import com.reactnativenavigation.viewcontrollers.fakes.FakeParentController import com.reactnativenavigation.viewcontrollers.stack.StackController +import com.reactnativenavigation.viewcontrollers.statusbar.StatusBarPresenter import com.reactnativenavigation.viewcontrollers.viewcontroller.Presenter import com.reactnativenavigation.viewcontrollers.viewcontroller.ViewController import com.reactnativenavigation.views.bottomtabs.BottomTabs @@ -67,6 +68,7 @@ class BottomTabsControllerTest : BaseTest() { activity = newActivity() childRegistry = ChildControllersRegistry() eventEmitter = Mockito.mock(EventEmitter::class.java) + StatusBarPresenter.init(activity) prepareViewsForTests() saveStatusBarHeight(63) } diff --git a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/TopBarControllerTest.kt b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/TopBarControllerTest.kt index 2a1dc4f8052..c0b24b83a93 100644 --- a/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/TopBarControllerTest.kt +++ b/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/TopBarControllerTest.kt @@ -217,7 +217,7 @@ class TopBarControllerTest : BaseTest() { val colorAnimator = ValueAnimator() givenColorAnimator(colorAnimator, BKG_COLOR) givenTopBarBackgroundAsColor() - givenFeatureToggleOverrides(RNNToggles.TOP_BAR_COLOR_ANIMATION to false) + givenFeatureToggleOverrides(RNNToggles.TOP_BAR_COLOR_ANIMATION__PUSH to false) val result = uut.getPushAnimation(options) assertThat(result).isNull() @@ -286,7 +286,7 @@ class TopBarControllerTest : BaseTest() { val disappearOpts = OptionHelper.emptyOptions() givenColorAnimator(colorAnimator, BKG_COLOR) givenTopBarBackgroundAsColor() - givenFeatureToggleOverrides(RNNToggles.TOP_BAR_COLOR_ANIMATION to false) + givenFeatureToggleOverrides(RNNToggles.TOP_BAR_COLOR_ANIMATION__PUSH to false) val result = uut.getPopAnimation(appearOpts, disappearOpts) assertThat(result).isNull() @@ -357,8 +357,9 @@ class TopBarControllerTest : BaseTest() { } private fun initFeatureToggles() { + RNNFeatureToggles.clear() RNNFeatureToggles.init( - RNNToggles.TOP_BAR_COLOR_ANIMATION to true + RNNToggles.TOP_BAR_COLOR_ANIMATION__PUSH to true ) } diff --git a/playground/android/app/src/main/java/com/reactnativenavigation/playground/MainApplication.java b/playground/android/app/src/main/java/com/reactnativenavigation/playground/MainApplication.java index 3853724e73d..60638bb5912 100644 --- a/playground/android/app/src/main/java/com/reactnativenavigation/playground/MainApplication.java +++ b/playground/android/app/src/main/java/com/reactnativenavigation/playground/MainApplication.java @@ -49,7 +49,8 @@ protected boolean isNewArchEnabled() { public MainApplication() { super(new HashMap<>() {{ - put(RNNToggles.TOP_BAR_COLOR_ANIMATION, true); + put(RNNToggles.TOP_BAR_COLOR_ANIMATION__PUSH, true); + put(RNNToggles.TOP_BAR_COLOR_ANIMATION__TABS, true); }}); } diff --git a/playground/src/screens/NavigationScreen.tsx b/playground/src/screens/NavigationScreen.tsx index f188dcdd430..d2e4da5b6c7 100644 --- a/playground/src/screens/NavigationScreen.tsx +++ b/playground/src/screens/NavigationScreen.tsx @@ -29,10 +29,17 @@ interface Props extends NavigationProps {} export default class NavigationScreen extends NavigationComponent { static options() { return { + statusBar: { + backgroundColor: 'orange', + translucent: false, + }, topBar: { title: { text: 'Navigation', }, + background: { + color: 'orange', + }, }, bottomTab: { text: 'Navigation',