react-native-navigation 7.42.0 → 7.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/lib/android/app/src/main/java/com/reactnativenavigation/FeatureToggles.kt +62 -0
  2. package/lib/android/app/src/main/java/com/reactnativenavigation/NavigationActivity.java +2 -2
  3. package/lib/android/app/src/main/java/com/reactnativenavigation/NavigationApplication.java +13 -3
  4. package/lib/android/app/src/main/java/com/reactnativenavigation/options/ValueAnimationOptions.kt +3 -3
  5. package/lib/android/app/src/main/java/com/reactnativenavigation/utils/ColorUtils.java +11 -0
  6. package/lib/android/app/src/main/java/com/reactnativenavigation/utils/StubAnimationListener.kt +19 -0
  7. package/lib/android/app/src/main/java/com/reactnativenavigation/utils/SystemUiUtils.kt +17 -16
  8. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabPresenter.java +0 -1
  9. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsAnimator.kt +2 -2
  10. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsController.java +4 -9
  11. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/child/ChildController.java +7 -14
  12. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/component/ComponentPresenter.java +18 -0
  13. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/component/ComponentViewController.java +24 -12
  14. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/StackController.java +52 -24
  15. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/StackPresenter.java +20 -10
  16. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/topbar/{TopBarAnimator.kt → TopBarAppearanceAnimator.kt} +4 -2
  17. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/topbar/TopBarCollapseBehavior.kt +1 -1
  18. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/topbar/TopBarController.kt +154 -26
  19. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/statusbar/StatusBarPresenter.kt +212 -0
  20. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/viewcontroller/Presenter.java +12 -107
  21. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/viewcontroller/StatusBarColorAnimator.kt +28 -0
  22. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/viewcontroller/ViewController.java +34 -2
  23. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/viewcontroller/ViewControllerVisibilityInfo.kt +5 -0
  24. package/lib/android/app/src/main/java/com/reactnativenavigation/views/animations/{BaseViewAnimator.kt → BaseViewAppearanceAnimator.kt} +4 -4
  25. package/lib/android/app/src/main/java/com/reactnativenavigation/views/animations/ColorAnimator.kt +22 -0
  26. package/lib/android/app/src/main/java/com/reactnativenavigation/views/animations/DefaultViewAnimatorCreator.kt +8 -8
  27. package/lib/android/app/src/main/java/com/reactnativenavigation/views/animations/ViewAnimatorCreator.kt +2 -2
  28. package/lib/android/app/src/main/java/com/reactnativenavigation/views/animations/ViewBkgColorProperty.kt +17 -0
  29. package/lib/dist/src/commands/OptionsProcessor.js +8 -1
  30. package/lib/dist/src/interfaces/Options.d.ts +33 -3
  31. package/lib/ios/BottomTabsBasePresenter.m +1 -1
  32. package/lib/ios/RNNConvert.h +0 -1
  33. package/lib/ios/RNNConvert.m +3 -8
  34. package/lib/ios/RNNStackPresenter.m +1 -1
  35. package/lib/src/commands/OptionsProcessor.ts +13 -2
  36. package/lib/src/interfaces/Options.ts +38 -3
  37. package/package.json +1 -1
@@ -1,28 +1,44 @@
1
1
  package com.reactnativenavigation.viewcontrollers.stack.topbar
2
2
 
3
3
  import android.animation.Animator
4
+ import android.animation.AnimatorSet
4
5
  import android.content.Context
6
+ import android.graphics.drawable.ColorDrawable
7
+ import android.os.Build
5
8
  import android.view.MenuItem
6
9
  import android.view.View
10
+ import androidx.core.animation.addListener
11
+ import androidx.core.animation.doOnEnd
7
12
  import androidx.viewpager.widget.ViewPager
13
+ import com.reactnativenavigation.RNNFeatureToggles
14
+ import com.reactnativenavigation.RNNToggles
8
15
  import com.reactnativenavigation.options.Alignment
9
16
  import com.reactnativenavigation.options.AnimationOptions
10
17
  import com.reactnativenavigation.options.Options
18
+ import com.reactnativenavigation.options.TopBarOptions
19
+ import com.reactnativenavigation.options.animations.ViewAnimationOptions
11
20
  import com.reactnativenavigation.utils.CollectionUtils.forEachIndexed
12
21
  import com.reactnativenavigation.utils.ViewUtils
13
22
  import com.reactnativenavigation.utils.resetViewProperties
14
23
  import com.reactnativenavigation.viewcontrollers.stack.topbar.button.ButtonController
15
24
  import com.reactnativenavigation.viewcontrollers.stack.topbar.title.TitleBarReactViewController
25
+ import com.reactnativenavigation.viewcontrollers.viewcontroller.TopBarVisibilityInfo
26
+ import com.reactnativenavigation.viewcontrollers.viewcontroller.ViewController
27
+ import com.reactnativenavigation.views.animations.ColorAnimator
16
28
  import com.reactnativenavigation.views.stack.StackLayout
17
29
  import com.reactnativenavigation.views.stack.topbar.TopBar
18
30
  import com.reactnativenavigation.views.stack.topbar.titlebar.ButtonBar
19
31
 
20
32
 
21
- open class TopBarController(private val animator: TopBarAnimator = TopBarAnimator()) {
33
+ open class TopBarController(
34
+ private val appearAnimator: TopBarAppearanceAnimator = TopBarAppearanceAnimator(),
35
+ private val colorAnimator: ColorAnimator = ColorAnimator(),
36
+ ) {
22
37
  lateinit var view: TopBar
23
38
  private lateinit var leftButtonBar: ButtonBar
24
39
  private lateinit var rightButtonBar: ButtonBar
25
40
 
41
+ private var hasPendingColorAnim = false
26
42
 
27
43
  val height: Int
28
44
  get() = view.height
@@ -31,70 +47,142 @@ open class TopBarController(private val animator: TopBarAnimator = TopBarAnimato
31
47
  val leftButtonCount: Int
32
48
  get() = leftButtonBar.buttonCount
33
49
 
34
- fun getRightButton(index: Int): MenuItem = rightButtonBar.getButton(index)
50
+ val visibilityInfo: TopBarVisibilityInfo
51
+ get() = TopBarVisibilityInfo(view.isShown, getBackgroundColor())
35
52
 
36
53
  fun createView(context: Context, parent: StackLayout): TopBar {
37
54
  if (!::view.isInitialized) {
38
55
  view = createTopBar(context, parent)
39
56
  leftButtonBar = view.leftButtonBar
40
57
  rightButtonBar = view.rightButtonBar
41
- animator.bindView(view)
58
+ appearAnimator.bindView(view)
42
59
  }
43
60
  return view
44
61
  }
45
62
 
46
- protected open fun createTopBar(context: Context, stackLayout: StackLayout): TopBar {
47
- return TopBar(context)
48
- }
49
-
50
63
  fun initTopTabs(viewPager: ViewPager?) = view.initTopTabs(viewPager)
51
64
 
52
65
  fun clearTopTabs() = view.clearTopTabs()
53
66
 
67
+ fun setBackgroundColor(topBarOptions: TopBarOptions, defaultColor: Int) {
68
+ val color = topBarOptions.background.color
69
+
70
+ if (!hasPendingColorAnim) {
71
+ view.setBackgroundColor(color.get(defaultColor)!!)
72
+ }
73
+ }
74
+
75
+ fun setBackgroundColor(topBarOptions: TopBarOptions) {
76
+ val color = topBarOptions.background.color
77
+
78
+ if (color.hasValue() && !hasPendingColorAnim) {
79
+ view.setBackgroundColor(color.get())
80
+ }
81
+ }
82
+
83
+ fun getBackgroundColor(): Int? {
84
+ return if (view.background is ColorDrawable) {
85
+ (view.background as ColorDrawable).color
86
+ } else {
87
+ null
88
+ }
89
+ }
90
+
91
+ fun getRightButton(index: Int): MenuItem = rightButtonBar.getButton(index)
92
+
54
93
  fun getPushAnimation(appearingOptions: Options, additionalDy: Float = 0f): Animator? {
55
- if (appearingOptions.topBar.animate.isFalse) return null
56
- return animator.getPushAnimation(
57
- appearingOptions.animations.push.topBar,
58
- appearingOptions.topBar.visible,
59
- additionalDy
60
- )
94
+ val topBarOptions = appearingOptions.topBar
95
+ val topBarAnimOptions = appearingOptions.animations.push.topBar
96
+
97
+ hasPendingColorAnim = false
98
+
99
+ mutableListOf(
100
+ getAppearancePushAnimation(topBarOptions, topBarAnimOptions, additionalDy),
101
+ getBkgColorAnimation(topBarOptions)?.apply {
102
+ hasPendingColorAnim = true
103
+
104
+ addListener(onEnd = {
105
+ hasPendingColorAnim = false
106
+ })
107
+ },
108
+ ).filterNotNull().let {
109
+ return if (it.isNotEmpty()) {
110
+ AnimatorSet().apply { playTogether(it) }
111
+ } else {
112
+ null
113
+ }
114
+ }
61
115
  }
62
116
 
63
117
  fun getPopAnimation(appearingOptions: Options, disappearingOptions: Options): Animator? {
64
- if (appearingOptions.topBar.animate.isFalse) return null
65
- return animator.getPopAnimation(
66
- disappearingOptions.animations.pop.topBar,
67
- appearingOptions.topBar.visible
68
- )
118
+ val topBarOptions = appearingOptions.topBar
119
+ val topBarAnimOptions = disappearingOptions.animations.pop.topBar
120
+
121
+ hasPendingColorAnim = false
122
+
123
+ mutableListOf(
124
+ getAppearancePopAnimation(topBarOptions, topBarAnimOptions),
125
+ getBkgColorAnimation(topBarOptions)?.apply {
126
+ hasPendingColorAnim = true
127
+
128
+ addListener(onEnd = {
129
+ hasPendingColorAnim = false
130
+ })
131
+ },
132
+ ).filterNotNull().let {
133
+ return if (it.isNotEmpty()) {
134
+ AnimatorSet().apply { playTogether(it) }
135
+ } else {
136
+ null
137
+ }
138
+ }
69
139
  }
70
140
 
71
141
  fun getSetStackRootAnimation(appearingOptions: Options, additionalDy: Float = 0f): Animator? {
72
142
  if (appearingOptions.topBar.animate.isFalse) return null
73
- return animator.getSetStackRootAnimation(
143
+ return appearAnimator.getSetStackRootAnimation(
74
144
  appearingOptions.animations.setStackRoot.topBar,
75
145
  appearingOptions.topBar.visible,
76
146
  additionalDy
77
147
  )
78
148
  }
79
149
 
150
+ fun bindNewViewController(previousVC: ViewController<*>?, newVC: ViewController<*>?) {
151
+ if (!RNNFeatureToggles.isEnabled(RNNToggles.TOP_BAR_COLOR_ANIMATION__TABS)) {
152
+ return
153
+ }
154
+
155
+ previousVC?.visibilityInfo?.topBarVisibilityInfo?.solidColor?.let { fromColor ->
156
+ newVC?.visibilityInfo?.topBarVisibilityInfo?.solidColor?.let { toColor ->
157
+ colorAnimator.getAnimation(view, fromColor, toColor).apply {
158
+ doOnEnd {
159
+ hasPendingColorAnim = false
160
+ }
161
+ hasPendingColorAnim = true
162
+ start()
163
+ }
164
+ }
165
+ }
166
+ }
167
+
80
168
  fun show() {
81
- if (ViewUtils.isVisible(view) || animator.isAnimatingShow()) return
169
+ if (ViewUtils.isVisible(view) || appearAnimator.isAnimatingShow()) return
82
170
  view.resetViewProperties()
83
171
  view.visibility = View.VISIBLE
84
172
  }
85
173
 
86
174
  fun showAnimate(options: AnimationOptions, additionalDy: Float) {
87
- if (ViewUtils.isVisible(view) || animator.isAnimatingShow()) return
88
- animator.show(options, additionalDy)
175
+ if (ViewUtils.isVisible(view) || appearAnimator.isAnimatingShow()) return
176
+ appearAnimator.show(options, additionalDy)
89
177
  }
90
178
 
91
179
  fun hide() {
92
- if (!animator.isAnimatingHide()) view.visibility = View.GONE
180
+ if (!appearAnimator.isAnimatingHide()) view.visibility = View.GONE
93
181
  }
94
182
 
95
183
  fun hideAnimate(options: AnimationOptions, additionalDy: Float) {
96
- if (!ViewUtils.isVisible(view) || animator.isAnimatingHide()) return
97
- animator.hide(options, additionalDy)
184
+ if (!ViewUtils.isVisible(view) || appearAnimator.isAnimatingHide()) return
185
+ appearAnimator.hide(options, additionalDy)
98
186
  }
99
187
 
100
188
  fun setTitleComponent(component: TitleBarReactViewController) {
@@ -126,4 +214,44 @@ open class TopBarController(private val animator: TopBarAnimator = TopBarAnimato
126
214
  toRemove.forEach { view.removeLeftButton(it) }
127
215
  forEachIndexed(toAdd) { b: ButtonController, i: Int -> b.addToMenu(leftButtonBar, i * 10) }
128
216
  }
129
- }
217
+
218
+ protected open fun createTopBar(context: Context, stackLayout: StackLayout): TopBar {
219
+ return TopBar(context)
220
+ }
221
+
222
+ private fun getBkgColorAnimation(topBarOptions: TopBarOptions): Animator? {
223
+ val targetColor = topBarOptions.background.color
224
+
225
+ if (targetColor.hasValue()
226
+ && view.background is ColorDrawable
227
+ && RNNFeatureToggles.isEnabled(RNNToggles.TOP_BAR_COLOR_ANIMATION__PUSH)) {
228
+ return colorAnimator.getAnimation(
229
+ view,
230
+ (view.background as ColorDrawable).color,
231
+ targetColor.get()
232
+ )
233
+ }
234
+ return null
235
+ }
236
+
237
+ private fun getAppearancePushAnimation(topBarOptions: TopBarOptions, topBarAnimOptions: ViewAnimationOptions, additionalDy: Float) =
238
+ if (!topBarOptions.animate.isFalse) {
239
+ appearAnimator.getPushAnimation(
240
+ topBarAnimOptions,
241
+ topBarOptions.visible,
242
+ additionalDy,
243
+ )
244
+ } else {
245
+ null
246
+ }
247
+
248
+ private fun getAppearancePopAnimation(topBarOptions: TopBarOptions, topBarAnimOptions: ViewAnimationOptions) =
249
+ if (!topBarOptions.animate.isFalse) {
250
+ appearAnimator.getPopAnimation(
251
+ topBarAnimOptions,
252
+ topBarOptions.visible,
253
+ )
254
+ } else {
255
+ null
256
+ }
257
+ }
@@ -0,0 +1,212 @@
1
+ package com.reactnativenavigation.viewcontrollers.statusbar
2
+
3
+ import android.animation.Animator
4
+ import android.app.Activity
5
+ import android.graphics.Color
6
+ import android.view.View
7
+ import android.view.Window
8
+ import com.reactnativenavigation.RNNFeatureToggles.isEnabled
9
+ import com.reactnativenavigation.RNNToggles
10
+ import com.reactnativenavigation.options.Options
11
+ import com.reactnativenavigation.options.StatusBarOptions
12
+ import com.reactnativenavigation.options.StatusBarOptions.TextColorScheme
13
+ import com.reactnativenavigation.options.params.Bool
14
+ import com.reactnativenavigation.utils.ColorUtils.isColorLight
15
+ import com.reactnativenavigation.utils.StubAnimationListener.Companion.onAnimatorEnd
16
+ import com.reactnativenavigation.utils.SystemUiUtils.clearStatusBarTranslucency
17
+ import com.reactnativenavigation.utils.SystemUiUtils.getStatusBarColor
18
+ import com.reactnativenavigation.utils.SystemUiUtils.hideStatusBar
19
+ import com.reactnativenavigation.utils.SystemUiUtils.isTranslucent
20
+ import com.reactnativenavigation.utils.SystemUiUtils.setStatusBarColor
21
+ import com.reactnativenavigation.utils.SystemUiUtils.setStatusBarColorScheme
22
+ import com.reactnativenavigation.utils.SystemUiUtils.setStatusBarTranslucent
23
+ import com.reactnativenavigation.utils.SystemUiUtils.showStatusBar
24
+ import com.reactnativenavigation.viewcontrollers.viewcontroller.StatusBarColorAnimator
25
+ import com.reactnativenavigation.viewcontrollers.viewcontroller.ViewController
26
+ import java.lang.ref.WeakReference
27
+
28
+ class StatusBarPresenter private constructor(
29
+ activity: Activity,
30
+ private val sbColorAnimator: StatusBarColorAnimator = StatusBarColorAnimator(activity)) {
31
+
32
+ private val window = WeakReference(activity.window)
33
+ private var hasPendingColorAnim = false
34
+
35
+ fun applyOptions(viewController: ViewController<*>, options: StatusBarOptions) {
36
+ if (!hasPendingColorAnim) {
37
+ setStatusBarBackgroundColor(options)
38
+ setTranslucent(options)
39
+ }
40
+ setTextColorScheme(options)
41
+ setStatusBarVisible(viewController, options.visible)
42
+ }
43
+
44
+ fun mergeOptions(view: View, statusBar: StatusBarOptions) {
45
+ mergeStatusBarBackgroundColor(statusBar)
46
+ mergeTextColorScheme(statusBar)
47
+ mergeTranslucent(statusBar)
48
+ mergeStatusBarVisible(view, statusBar.visible)
49
+ }
50
+
51
+ fun onConfigurationChanged(options: StatusBarOptions) {
52
+ setStatusBarBackgroundColor(options)
53
+ setTextColorScheme(options)
54
+ }
55
+
56
+ fun bindViewController(newOptions: StatusBarOptions) {
57
+ if (!isEnabled(RNNToggles.TOP_BAR_COLOR_ANIMATION__TABS)) {
58
+ return
59
+ }
60
+
61
+ if (newOptions.backgroundColor.canApplyValue()) {
62
+ val currentColor = getCurrentStatusBarBackgroundColor() ?: return
63
+ val newColor = getStatusBarBackgroundColor(newOptions)
64
+ createStatusBarColorAnimation(
65
+ from = currentColor,
66
+ to = newColor,
67
+ translucent = newOptions.translucent.isTrue,
68
+ ).start()
69
+ }
70
+ }
71
+
72
+ fun getStatusBarPushAnimation(appearingOptions: Options): Animator? =
73
+ if (isEnabled(RNNToggles.TOP_BAR_COLOR_ANIMATION__PUSH)) {
74
+ getStatusBarColorAnimation(appearingOptions.statusBar)
75
+ } else null
76
+
77
+ fun getStatusBarPopAnimation(appearingOptions: Options, disappearingOptions: Options): Animator? =
78
+ if (isEnabled(RNNToggles.TOP_BAR_COLOR_ANIMATION__PUSH)) {
79
+ getStatusBarColorAnimation(appearingOptions.statusBar)
80
+ } else null
81
+
82
+ private fun setStatusBarBackgroundColor(statusBar: StatusBarOptions) {
83
+ if (statusBar.backgroundColor.canApplyValue()) {
84
+ val statusBarBackgroundColor: Int = getStatusBarBackgroundColor(statusBar)
85
+ setStatusBarBackgroundColor(statusBarBackgroundColor, statusBar.translucent.isTrue)
86
+ }
87
+ }
88
+
89
+ private fun setStatusBarBackgroundColor(color: Int, translucent: Boolean) {
90
+ setStatusBarColor(window.get(), color, translucent)
91
+ }
92
+
93
+ private fun getStatusBarBackgroundColor(statusBar: StatusBarOptions): Int {
94
+ val defaultColor =
95
+ if (statusBar.visible.isTrueOrUndefined) Color.BLACK else Color.TRANSPARENT
96
+ return statusBar.backgroundColor.get(defaultColor)!!
97
+ }
98
+
99
+ private fun setTextColorScheme(statusBar: StatusBarOptions) {
100
+ val view = window.get()?.decorView
101
+ //View.post is a Workaround, added to solve internal Samsung
102
+ //Android 9 issues. For more info see https://github.com/wix/react-native-navigation/pull/7231
103
+ view?.post {
104
+ setStatusBarColorScheme(
105
+ window.get(),
106
+ view,
107
+ isDarkTextColorScheme(statusBar)
108
+ )
109
+ }
110
+ }
111
+
112
+ private fun setTranslucent(options: StatusBarOptions) {
113
+ val window = window.get()
114
+ if (options.translucent.isTrue) {
115
+ setStatusBarTranslucent(window)
116
+ } else if (isTranslucent(window)) {
117
+ clearStatusBarTranslucency(window)
118
+ }
119
+ }
120
+
121
+ private fun setStatusBarVisible(viewController: ViewController<*>, visible: Bool) {
122
+ val window = window.get() ?: return
123
+ val view = if (viewController.view != null) viewController.view else window.decorView
124
+ if (visible.isFalse) {
125
+ hideStatusBar(window, view)
126
+ } else {
127
+ showStatusBar(window, view)
128
+ }
129
+ }
130
+
131
+ private fun mergeStatusBarBackgroundColor(statusBar: StatusBarOptions) {
132
+ if (statusBar.backgroundColor.hasValue()) {
133
+ val statusBarBackgroundColor = getStatusBarBackgroundColor(statusBar)
134
+ setStatusBarColor(
135
+ window.get(), statusBarBackgroundColor,
136
+ statusBar.translucent.isTrue
137
+ )
138
+ }
139
+ }
140
+
141
+ private fun mergeTextColorScheme(statusBar: StatusBarOptions) {
142
+ if (!statusBar.textColorScheme.hasValue()) return
143
+ setTextColorScheme(statusBar)
144
+ }
145
+
146
+ private fun mergeTranslucent(options: StatusBarOptions) {
147
+ val window: Window = window.get() ?: return
148
+ if (options.translucent.isTrue) {
149
+ setStatusBarTranslucent(window)
150
+ } else if (options.translucent.isFalse && isTranslucent(window)) {
151
+ clearStatusBarTranslucency(window)
152
+ }
153
+ }
154
+
155
+ private fun mergeStatusBarVisible(view: View, visible: Bool) {
156
+ if (visible.hasValue()) {
157
+ if (visible.isTrue) {
158
+ showStatusBar(window.get(), view)
159
+ } else {
160
+ hideStatusBar(window.get(), view)
161
+ }
162
+ }
163
+ }
164
+
165
+ private fun isDarkTextColorScheme(statusBar: StatusBarOptions): Boolean {
166
+ if (statusBar.textColorScheme == TextColorScheme.Dark) {
167
+ return true
168
+ }
169
+
170
+ if (statusBar.textColorScheme == TextColorScheme.Light) {
171
+ return false
172
+ }
173
+ return isColorLight(getStatusBarBackgroundColor(statusBar))
174
+ }
175
+
176
+ private fun getStatusBarColorAnimation(statusBarOptions: StatusBarOptions): Animator? {
177
+ if (isEnabled(RNNToggles.TOP_BAR_COLOR_ANIMATION__TABS)) {
178
+ getCurrentStatusBarBackgroundColor()?.let { currentColor ->
179
+ val targetColor = statusBarOptions.backgroundColor
180
+
181
+ if (targetColor.hasValue()) {
182
+ val translucent = statusBarOptions.translucent.isTrue
183
+ return createStatusBarColorAnimation(
184
+ from = currentColor,
185
+ to = targetColor.get(),
186
+ translucent = translucent,
187
+ )
188
+ }
189
+ }
190
+ }
191
+ return null
192
+ }
193
+
194
+ private fun createStatusBarColorAnimation(from: Int, to: Int, translucent: Boolean): Animator =
195
+ sbColorAnimator.getAnimator(from, to, translucent).apply {
196
+ addListener(onAnimatorEnd {
197
+ hasPendingColorAnim = false
198
+ })
199
+ hasPendingColorAnim = true
200
+ }
201
+
202
+ private fun getCurrentStatusBarBackgroundColor() =
203
+ getStatusBarColor(window.get())
204
+
205
+ companion object {
206
+ lateinit var instance: StatusBarPresenter
207
+
208
+ fun init(activity: Activity) {
209
+ instance = StatusBarPresenter(activity)
210
+ }
211
+ }
212
+ }
@@ -1,5 +1,7 @@
1
1
  package com.reactnativenavigation.viewcontrollers.viewcontroller;
2
2
 
3
+ import static com.reactnativenavigation.utils.ColorUtils.isColorLight;
4
+
3
5
  import android.app.Activity;
4
6
  import android.graphics.Color;
5
7
  import android.graphics.drawable.ColorDrawable;
@@ -8,27 +10,25 @@ import android.graphics.drawable.LayerDrawable;
8
10
  import android.view.View;
9
11
  import android.view.ViewGroup;
10
12
  import android.view.ViewGroup.MarginLayoutParams;
11
- import android.view.Window;
12
13
 
13
14
  import com.reactnativenavigation.options.NavigationBarOptions;
14
15
  import com.reactnativenavigation.options.Options;
15
16
  import com.reactnativenavigation.options.OrientationOptions;
16
17
  import com.reactnativenavigation.options.StatusBarOptions;
17
- import com.reactnativenavigation.options.StatusBarOptions.TextColorScheme;
18
18
  import com.reactnativenavigation.options.layout.LayoutInsets;
19
- import com.reactnativenavigation.options.params.Bool;
20
19
  import com.reactnativenavigation.utils.SystemUiUtils;
21
- import com.reactnativenavigation.viewcontrollers.parent.ParentController;
22
20
  import com.reactnativenavigation.viewcontrollers.navigator.Navigator;
21
+ import com.reactnativenavigation.viewcontrollers.parent.ParentController;
22
+ import com.reactnativenavigation.viewcontrollers.statusbar.StatusBarPresenter;
23
23
 
24
24
  public class Presenter {
25
25
  private final Activity activity;
26
+
26
27
  private Options defaultOptions;
27
28
 
28
29
  public Presenter(Activity activity, Options defaultOptions) {
29
30
  this.activity = activity;
30
31
  this.defaultOptions = defaultOptions;
31
-
32
32
  }
33
33
 
34
34
  public void setDefaultOptions(Options defaultOptions) {
@@ -55,13 +55,13 @@ public class Presenter {
55
55
  Options withDefaultOptions = options.copy().withDefaultOptions(defaultOptions);
56
56
  applyOrientation(withDefaultOptions.layout.orientation);
57
57
  applyViewOptions(view, withDefaultOptions);
58
- applyStatusBarOptions(view, withDefaultOptions);
58
+ applyStatusBarOptions(view, withDefaultOptions.statusBar);
59
59
  applyNavigationBarOptions(withDefaultOptions.navigationBar);
60
60
  }
61
61
 
62
62
  public void onViewBroughtToFront(ViewController<?> viewController, Options options) {
63
63
  Options withDefaultOptions = options.copy().withDefaultOptions(defaultOptions);
64
- applyStatusBarOptions(viewController, withDefaultOptions);
64
+ applyStatusBarOptions(viewController, withDefaultOptions.statusBar);
65
65
  }
66
66
 
67
67
  private void applyOrientation(OrientationOptions options) {
@@ -104,101 +104,12 @@ public class Presenter {
104
104
  }
105
105
  }
106
106
 
107
- private void applyStatusBarOptions(ViewController viewController, Options options) {
108
- StatusBarOptions statusBar = options.copy().withDefaultOptions(defaultOptions).statusBar;
109
- setStatusBarBackgroundColor(statusBar);
110
- setTextColorScheme(statusBar);
111
- setTranslucent(statusBar);
112
- setStatusBarVisible(viewController, statusBar.visible);
113
- }
114
-
115
- private void setTranslucent(StatusBarOptions options) {
116
- Window window = activity.getWindow();
117
- if (options.translucent.isTrue()) {
118
- SystemUiUtils.setStatusBarTranslucent(window);
119
- } else if (SystemUiUtils.isTranslucent(window)) {
120
- SystemUiUtils.clearStatusBarTranslucency(window);
121
- }
122
- }
123
-
124
- private void setStatusBarVisible(ViewController viewController, Bool visible) {
125
- final View view = viewController.view != null ? viewController.view : activity.getWindow().getDecorView();
126
- if (visible.isFalse()) {
127
- SystemUiUtils.hideStatusBar(activity.getWindow(), view);
128
- } else {
129
- SystemUiUtils.showStatusBar(activity.getWindow(), view);
130
- }
131
- }
132
-
133
- private void setStatusBarBackgroundColor(StatusBarOptions statusBar) {
134
- if (statusBar.backgroundColor.canApplyValue()) {
135
- final int statusBarBackgroundColor = getStatusBarBackgroundColor(statusBar);
136
- SystemUiUtils.setStatusBarColor(activity.getWindow(), statusBarBackgroundColor,
137
- statusBar.translucent.isTrue());
138
- }
139
- }
140
-
141
- private boolean isDarkTextColorScheme(StatusBarOptions statusBar) {
142
- if (statusBar.textColorScheme == TextColorScheme.Dark) {
143
- return true;
144
- } else if (statusBar.textColorScheme == TextColorScheme.Light) {
145
- return false;
146
- }
147
-
148
- return isColorLight(getStatusBarBackgroundColor(statusBar));
107
+ private void applyStatusBarOptions(ViewController viewController, StatusBarOptions options) {
108
+ StatusBarPresenter.instance.applyOptions(viewController, options);
149
109
  }
150
110
 
151
- private int getStatusBarBackgroundColor(StatusBarOptions statusBar) {
152
- int defaultColor = statusBar.visible.isTrueOrUndefined() ? Color.BLACK : Color.TRANSPARENT;
153
- return statusBar.backgroundColor.get(defaultColor);
154
- }
155
-
156
- private void setTextColorScheme(StatusBarOptions statusBar) {
157
- final View view = activity.getWindow().getDecorView();
158
- //View.post is a Workaround, added to solve internal Samsung
159
- //Android 9 issues. For more info see https://github.com/wix/react-native-navigation/pull/7231
160
- view.post(() -> {
161
- SystemUiUtils.setStatusBarColorScheme(activity.getWindow(), view, isDarkTextColorScheme(statusBar));
162
- });
163
- }
164
-
165
- private void mergeStatusBarOptions(View view, StatusBarOptions statusBar) {
166
- mergeStatusBarBackgroundColor(statusBar);
167
- mergeTextColorScheme(statusBar);
168
- mergeTranslucent(statusBar);
169
- mergeStatusBarVisible(view, statusBar.visible);
170
- }
171
-
172
- private void mergeStatusBarBackgroundColor(StatusBarOptions statusBar) {
173
- if (statusBar.backgroundColor.hasValue()) {
174
- final int statusBarBackgroundColor = getStatusBarBackgroundColor(statusBar);
175
- SystemUiUtils.setStatusBarColor(activity.getWindow(), statusBarBackgroundColor,
176
- statusBar.translucent.isTrue());
177
- }
178
- }
179
-
180
- private void mergeTextColorScheme(StatusBarOptions statusBar) {
181
- if (!statusBar.textColorScheme.hasValue()) return;
182
- setTextColorScheme(statusBar);
183
- }
184
-
185
- private void mergeTranslucent(StatusBarOptions options) {
186
- Window window = activity.getWindow();
187
- if (options.translucent.isTrue()) {
188
- SystemUiUtils.setStatusBarTranslucent(window);
189
- } else if (options.translucent.isFalse() && SystemUiUtils.isTranslucent(window)) {
190
- SystemUiUtils.clearStatusBarTranslucency(window);
191
- }
192
- }
193
-
194
- private void mergeStatusBarVisible(View view, Bool visible) {
195
- if (visible.hasValue()) {
196
- if (visible.isTrue()) {
197
- SystemUiUtils.showStatusBar(activity.getWindow(), view);
198
- } else {
199
- SystemUiUtils.hideStatusBar(activity.getWindow(), view);
200
- }
201
- }
111
+ private void mergeStatusBarOptions(View view, StatusBarOptions statusBarOptions) {
112
+ StatusBarPresenter.instance.mergeOptions(view, statusBarOptions);
202
113
  }
203
114
 
204
115
  private void applyNavigationBarOptions(NavigationBarOptions options) {
@@ -236,16 +147,10 @@ public class Presenter {
236
147
  }
237
148
  }
238
149
 
239
- private boolean isColorLight(int color) {
240
- double darkness = 1 - (0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color)) / 255;
241
- return darkness < 0.5;
242
- }
243
-
244
150
  public void onConfigurationChanged(ViewController controller, Options options) {
245
151
  Options withDefault = options.withDefaultOptions(defaultOptions);
246
152
  setNavigationBarBackgroundColor(withDefault.navigationBar);
247
- setStatusBarBackgroundColor(withDefault.statusBar);
248
- setTextColorScheme(withDefault.statusBar);
153
+ StatusBarPresenter.instance.onConfigurationChanged(withDefault.statusBar);
249
154
  applyBackgroundColor(controller, withDefault);
250
155
  }
251
156
  }
@@ -0,0 +1,28 @@
1
+ package com.reactnativenavigation.viewcontrollers.viewcontroller
2
+
3
+ import android.animation.ValueAnimator
4
+ import android.app.Activity
5
+ import com.reactnativenavigation.utils.ColorUtils
6
+ import com.reactnativenavigation.utils.SystemUiUtils
7
+ import com.reactnativenavigation.views.animations.ColorAnimator
8
+ import java.lang.ref.WeakReference
9
+
10
+ private const val STATUS_BAR_TRANSLUCENCY_ALPHA = (SystemUiUtils.STATUS_BAR_HEIGHT_TRANSLUCENCY * 255).toInt()
11
+
12
+ class StatusBarColorAnimator(val activity: Activity) {
13
+ private val colorAnimator = ColorAnimator()
14
+ private val window = WeakReference(activity.window)
15
+
16
+ fun getAnimator(from: Int, to: Int, isTranslucent: Boolean): ValueAnimator =
17
+ colorAnimator.getAnimation(
18
+ from = from,
19
+ to = embedTranslucency(to, isTranslucent)
20
+ ).apply {
21
+ addUpdateListener { animation ->
22
+ SystemUiUtils.setStatusBarColor(window.get(), animation.animatedValue as Int)
23
+ }
24
+ }
25
+
26
+ private fun embedTranslucency(color: Int, isTranslucent: Boolean): Int =
27
+ if (!isTranslucent) color else ColorUtils.setAlpha(color, STATUS_BAR_TRANSLUCENCY_ALPHA)
28
+ }