react-native-navigation 7.23.1-snapshot.412 → 7.23.1-snapshot.440
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.
- package/lib/android/app/build.gradle +9 -9
- package/lib/android/app/src/main/java/com/reactnativenavigation/options/HardwareBackButtonOptions.kt +35 -2
- package/lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationModule.java +5 -2
- package/lib/android/app/src/main/java/com/reactnativenavigation/react/modal/ModalFrameLayout.kt +3 -3
- package/lib/android/app/src/main/java/com/reactnativenavigation/react/modal/ModalViewManager.kt +11 -8
- package/lib/android/app/src/main/java/com/reactnativenavigation/utils/SystemUiUtils.kt +168 -0
- package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsController.java +42 -2
- package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/child/ChildController.java +12 -16
- package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/component/ComponentViewController.java +18 -11
- package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/externalcomponent/ExternalComponentViewController.java +2 -2
- package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/StackPresenter.java +33 -18
- package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/viewcontroller/Presenter.java +52 -71
- package/lib/android/app/src/main/java/com/reactnativenavigation/views/component/ComponentLayout.java +2 -0
- package/lib/android/app/src/main/java/com/reactnativenavigation/views/element/animators/ReactImageMatrixAnimator.kt +2 -3
- package/lib/android/app/src/main/java/com/reactnativenavigation/views/stack/topbar/TopBar.java +1 -2
- package/lib/android/app/src/test/java/com/reactnativenavigation/BaseTest.java +7 -6
- package/lib/android/app/src/test/java/com/reactnativenavigation/TestActivity.java +5 -0
- package/lib/android/app/src/test/java/com/reactnativenavigation/mocks/ImageLoaderMock.kt +5 -4
- package/lib/android/app/src/test/java/com/reactnativenavigation/mocks/Mocks.kt +3 -2
- package/lib/android/app/src/test/java/com/reactnativenavigation/mocks/TypefaceLoaderMock.kt +1 -1
- package/lib/android/app/src/test/java/com/reactnativenavigation/options/TransitionAnimationOptionsTest.kt +2 -3
- package/lib/android/app/src/test/java/com/reactnativenavigation/presentation/PresenterTest.java +25 -10
- package/lib/android/app/src/test/java/com/reactnativenavigation/utils/MotionEventTest.kt +1 -1
- package/lib/android/app/src/test/java/com/reactnativenavigation/utils/UiThreadTest.java +2 -2
- package/lib/android/app/src/test/java/com/reactnativenavigation/utils/UiUtilsTest.java +1 -1
- package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsControllerTest.kt +572 -0
- package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsPresenterTest.kt +1 -1
- package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/child/ChildControllerTest.java +2 -1
- package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/component/ComponentViewControllerTest.java +5 -5
- package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/fakes/FakeParentController.kt +1 -1
- package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/modal/ModalAnimatorTest.kt +1 -1
- package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/modal/ModalPresenterTest.java +3 -3
- package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/modal/ModalStackTest.java +4 -3
- package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/navigator/RootPresenterTest.kt +5 -5
- package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/parent/ParentControllerTest.java +4 -0
- package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/sidemenu/SideMenuControllerTest.java +6 -2
- package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/StackAnimatorTest.kt +1 -1
- package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/StackControllerTest.kt +3 -3
- package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/StackPresenterTest.kt +4 -4
- package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/TopBarControllerTest.kt +1 -1
- package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/viewcontroller/ViewControllerTest.java +4 -1
- package/lib/android/app/src/test/java/com/reactnativenavigation/views/TitleAndButtonsContainerTest.kt +2 -2
- package/lib/android/app/src/test/java/com/reactnativenavigation/views/animations/BaseViewAnimatorTest.kt +4 -4
- package/lib/android/app/src/test/java/com/reactnativenavigation/views/bottomtabs/BottomTabsContainerTest.kt +1 -1
- package/lib/android/app/src/test/java/com/reactnativenavigation/views/bottomtabs/BottomTabsTest.kt +4 -4
- package/lib/dist/interfaces/Options.d.ts +4 -0
- package/lib/ios/BottomTabPresenter.h +0 -3
- package/lib/ios/BottomTabPresenter.m +0 -8
- package/lib/ios/RNNBasePresenter.h +0 -4
- package/lib/ios/RNNBasePresenter.m +0 -12
- package/lib/ios/RNNBottomTabsController.m +8 -8
- package/lib/ios/RNNComponentPresenter.m +0 -4
- package/lib/ios/RNNComponentViewController.m +0 -4
- package/lib/ios/RNNExternalViewController.m +0 -4
- package/lib/ios/RNNSideMenuChildVC.m +0 -4
- package/lib/ios/RNNSideMenuController.m +0 -4
- package/lib/ios/RNNSplitViewController.m +0 -4
- package/lib/ios/RNNStackController.m +0 -4
- package/lib/src/interfaces/Options.ts +5 -0
- package/package.json +2 -2
- package/lib/android/app/src/main/java/com/reactnativenavigation/utils/StatusBarUtils.kt +0 -39
- package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsControllerTest.java +0 -511
|
@@ -172,13 +172,13 @@ allprojects { p ->
|
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
dependencies {
|
|
175
|
-
implementation "androidx.core:core-ktx:1.
|
|
175
|
+
implementation "androidx.core:core-ktx:1.6.0"
|
|
176
176
|
implementation "org.jetbrains.kotlin:$kotlinStdlib:$kotlinVersion"
|
|
177
177
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinCoroutinesCore"
|
|
178
178
|
implementation "androidx.constraintlayout:constraintlayout:2.0.4"
|
|
179
179
|
|
|
180
|
-
implementation 'androidx.appcompat:appcompat:1.1
|
|
181
|
-
implementation 'androidx.annotation:annotation:1.
|
|
180
|
+
implementation 'androidx.appcompat:appcompat:1.3.1'
|
|
181
|
+
implementation 'androidx.annotation:annotation:1.2.0'
|
|
182
182
|
implementation 'com.google.android.material:material:1.2.0-alpha03'
|
|
183
183
|
|
|
184
184
|
implementation 'com.github.wix-playground:ahbottomnavigation:3.3.0'
|
|
@@ -190,12 +190,12 @@ dependencies {
|
|
|
190
190
|
implementation 'com.facebook.react:react-native:+'
|
|
191
191
|
|
|
192
192
|
// tests
|
|
193
|
-
testImplementation 'junit:junit:4.
|
|
194
|
-
testImplementation "org.robolectric:robolectric:4.
|
|
195
|
-
testImplementation 'org.assertj:assertj-core:3.
|
|
196
|
-
testImplementation '
|
|
197
|
-
testImplementation '
|
|
193
|
+
testImplementation 'junit:junit:4.13.2'
|
|
194
|
+
testImplementation "org.robolectric:robolectric:4.7.2"
|
|
195
|
+
testImplementation 'org.assertj:assertj-core:3.11.1'
|
|
196
|
+
testImplementation 'org.mockito:mockito-core:4.0.0'
|
|
197
|
+
testImplementation 'com.squareup.assertj:assertj-android:1.2.0'
|
|
198
198
|
testImplementation 'org.mockito:mockito-inline:3.4.0'
|
|
199
|
-
testImplementation "
|
|
199
|
+
testImplementation "org.mockito.kotlin:mockito-kotlin:4.0.0"
|
|
200
200
|
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlinVersion"
|
|
201
201
|
}
|
package/lib/android/app/src/main/java/com/reactnativenavigation/options/HardwareBackButtonOptions.kt
CHANGED
|
@@ -6,10 +6,40 @@ import com.reactnativenavigation.options.parsers.BoolParser
|
|
|
6
6
|
import org.json.JSONObject
|
|
7
7
|
|
|
8
8
|
|
|
9
|
+
sealed class HwBackBottomTabsBehaviour {
|
|
10
|
+
object Undefined : HwBackBottomTabsBehaviour() {
|
|
11
|
+
override fun hasValue(): Boolean = false
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
object Exit : HwBackBottomTabsBehaviour()
|
|
15
|
+
object PrevSelection : HwBackBottomTabsBehaviour()
|
|
16
|
+
object JumpToFirst : HwBackBottomTabsBehaviour()
|
|
17
|
+
|
|
18
|
+
open fun hasValue(): Boolean = true
|
|
19
|
+
|
|
20
|
+
companion object {
|
|
21
|
+
private const val BEHAVIOUR_EXIT = "exit"
|
|
22
|
+
private const val BEHAVIOUR_PREV = "previous"
|
|
23
|
+
private const val BEHAVIOUR_FIRST = "first"
|
|
24
|
+
fun fromString(behaviour: String?): HwBackBottomTabsBehaviour {
|
|
25
|
+
return when (behaviour) {
|
|
26
|
+
BEHAVIOUR_PREV -> PrevSelection
|
|
27
|
+
BEHAVIOUR_FIRST -> JumpToFirst
|
|
28
|
+
BEHAVIOUR_EXIT -> Exit
|
|
29
|
+
else -> Undefined
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
9
35
|
open class HardwareBackButtonOptions(json: JSONObject? = null) {
|
|
10
36
|
|
|
11
|
-
@JvmField
|
|
12
|
-
|
|
37
|
+
@JvmField
|
|
38
|
+
var dismissModalOnPress: Bool = NullBool()
|
|
39
|
+
|
|
40
|
+
@JvmField
|
|
41
|
+
var popStackOnPress: Bool = NullBool()
|
|
42
|
+
var bottomTabOnPress: HwBackBottomTabsBehaviour = HwBackBottomTabsBehaviour.Undefined
|
|
13
43
|
|
|
14
44
|
init {
|
|
15
45
|
parse(json)
|
|
@@ -18,16 +48,19 @@ open class HardwareBackButtonOptions(json: JSONObject? = null) {
|
|
|
18
48
|
fun mergeWith(other: HardwareBackButtonOptions) {
|
|
19
49
|
if (other.dismissModalOnPress.hasValue()) dismissModalOnPress = other.dismissModalOnPress
|
|
20
50
|
if (other.popStackOnPress.hasValue()) popStackOnPress = other.popStackOnPress
|
|
51
|
+
if (other.bottomTabOnPress.hasValue()) bottomTabOnPress = other.bottomTabOnPress
|
|
21
52
|
}
|
|
22
53
|
|
|
23
54
|
fun mergeWithDefault(defaultOptions: HardwareBackButtonOptions) {
|
|
24
55
|
if (!dismissModalOnPress.hasValue()) dismissModalOnPress = defaultOptions.dismissModalOnPress
|
|
25
56
|
if (!popStackOnPress.hasValue()) popStackOnPress = defaultOptions.popStackOnPress
|
|
57
|
+
if (!bottomTabOnPress.hasValue()) bottomTabOnPress = defaultOptions.bottomTabOnPress
|
|
26
58
|
}
|
|
27
59
|
|
|
28
60
|
private fun parse(json: JSONObject?) {
|
|
29
61
|
json ?: return
|
|
30
62
|
dismissModalOnPress = BoolParser.parse(json, "dismissModalOnPress")
|
|
31
63
|
popStackOnPress = BoolParser.parse(json, "popStackOnPress")
|
|
64
|
+
bottomTabOnPress = HwBackBottomTabsBehaviour.fromString(json.optString("bottomTabsOnPress"))
|
|
32
65
|
}
|
|
33
66
|
}
|
|
@@ -23,7 +23,7 @@ import com.reactnativenavigation.options.parsers.TypefaceLoader;
|
|
|
23
23
|
import com.reactnativenavigation.react.events.EventEmitter;
|
|
24
24
|
import com.reactnativenavigation.utils.LaunchArgsParser;
|
|
25
25
|
import com.reactnativenavigation.utils.Now;
|
|
26
|
-
import com.reactnativenavigation.utils.
|
|
26
|
+
import com.reactnativenavigation.utils.SystemUiUtils;
|
|
27
27
|
import com.reactnativenavigation.utils.UiThread;
|
|
28
28
|
import com.reactnativenavigation.utils.UiUtils;
|
|
29
29
|
import com.reactnativenavigation.viewcontrollers.navigator.Navigator;
|
|
@@ -34,6 +34,8 @@ import java.util.Objects;
|
|
|
34
34
|
|
|
35
35
|
import static com.reactnativenavigation.utils.UiUtils.pxToDp;
|
|
36
36
|
|
|
37
|
+
import android.app.Activity;
|
|
38
|
+
|
|
37
39
|
public class NavigationModule extends ReactContextBaseJavaModule {
|
|
38
40
|
private static final String NAME = "RNNBridgeModule";
|
|
39
41
|
|
|
@@ -88,10 +90,11 @@ public class NavigationModule extends ReactContextBaseJavaModule {
|
|
|
88
90
|
|
|
89
91
|
private WritableMap createNavigationConstantsMap() {
|
|
90
92
|
ReactApplicationContext ctx = getReactApplicationContext();
|
|
93
|
+
final Activity currentActivity = ctx.getCurrentActivity();
|
|
91
94
|
WritableMap constants = Arguments.createMap();
|
|
92
95
|
constants.putString(Constants.BACK_BUTTON_JS_KEY, Constants.BACK_BUTTON_ID);
|
|
93
96
|
constants.putDouble(Constants.BOTTOM_TABS_HEIGHT_KEY, pxToDp(ctx, UiUtils.getBottomTabsHeight(ctx)));
|
|
94
|
-
constants.putDouble(Constants.STATUS_BAR_HEIGHT_KEY, pxToDp(ctx,
|
|
97
|
+
constants.putDouble(Constants.STATUS_BAR_HEIGHT_KEY, pxToDp(ctx, SystemUiUtils.getStatusBarHeight(currentActivity)));
|
|
95
98
|
constants.putDouble(Constants.TOP_BAR_HEIGHT_KEY, pxToDp(ctx, UiUtils.getTopBarHeight(ctx)));
|
|
96
99
|
return constants;
|
|
97
100
|
}
|
package/lib/android/app/src/main/java/com/reactnativenavigation/react/modal/ModalFrameLayout.kt
CHANGED
|
@@ -2,7 +2,7 @@ package com.reactnativenavigation.react.modal
|
|
|
2
2
|
|
|
3
3
|
import android.widget.FrameLayout
|
|
4
4
|
import com.facebook.react.bridge.ReactContext
|
|
5
|
-
import com.reactnativenavigation.utils.
|
|
5
|
+
import com.reactnativenavigation.utils.SystemUiUtils
|
|
6
6
|
|
|
7
7
|
class ModalFrameLayout(context: ReactContext) : FrameLayout(context) {
|
|
8
8
|
val modalContentLayout = ModalContentLayout(context)
|
|
@@ -11,9 +11,9 @@ class ModalFrameLayout(context: ReactContext) : FrameLayout(context) {
|
|
|
11
11
|
addView(modalContentLayout, MarginLayoutParams(MarginLayoutParams.WRAP_CONTENT, MarginLayoutParams.WRAP_CONTENT)
|
|
12
12
|
.apply {
|
|
13
13
|
val translucent = context.currentActivity?.window?.let {
|
|
14
|
-
|
|
14
|
+
SystemUiUtils.isTranslucent(it)
|
|
15
15
|
} ?: false
|
|
16
|
-
topMargin = if (translucent) 0 else
|
|
16
|
+
topMargin = if (translucent) 0 else SystemUiUtils.getStatusBarHeight(context.currentActivity)
|
|
17
17
|
})
|
|
18
18
|
}
|
|
19
19
|
}
|
package/lib/android/app/src/main/java/com/reactnativenavigation/react/modal/ModalViewManager.kt
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
package com.reactnativenavigation.react.modal
|
|
2
2
|
|
|
3
|
+
import android.app.Activity
|
|
3
4
|
import android.content.Context
|
|
4
5
|
import android.graphics.Point
|
|
5
6
|
import android.view.WindowManager
|
|
@@ -21,7 +22,7 @@ import com.reactnativenavigation.options.parseTransitionAnimationOptions
|
|
|
21
22
|
import com.reactnativenavigation.options.parsers.JSONParser
|
|
22
23
|
import com.reactnativenavigation.react.CommandListener
|
|
23
24
|
import com.reactnativenavigation.react.CommandListenerAdapter
|
|
24
|
-
import com.reactnativenavigation.utils.
|
|
25
|
+
import com.reactnativenavigation.utils.SystemUiUtils
|
|
25
26
|
import com.reactnativenavigation.viewcontrollers.navigator.Navigator
|
|
26
27
|
|
|
27
28
|
private const val MODAL_MANAGER_NAME = "RNNModalViewManager"
|
|
@@ -107,18 +108,18 @@ class ModalViewManager(val reactContext: ReactContext) : ViewGroupManager<ModalH
|
|
|
107
108
|
}
|
|
108
109
|
}
|
|
109
110
|
|
|
110
|
-
private fun getModalHostSize(
|
|
111
|
+
private fun getModalHostSize(activity: Activity): Point {
|
|
111
112
|
val MIN_POINT = Point()
|
|
112
113
|
val MAX_POINT = Point()
|
|
113
114
|
val SIZE_POINT = Point()
|
|
114
|
-
val wm =
|
|
115
|
+
val wm = activity.getSystemService(Context.WINDOW_SERVICE) as WindowManager
|
|
115
116
|
val display = Assertions.assertNotNull(wm).defaultDisplay
|
|
116
117
|
// getCurrentSizeRange will return the min and max width and height that the window can be
|
|
117
118
|
display.getCurrentSizeRange(MIN_POINT, MAX_POINT)
|
|
118
119
|
// getSize will return the dimensions of the screen in its current orientation
|
|
119
120
|
display.getSize(SIZE_POINT)
|
|
120
121
|
val attrs = intArrayOf(android.R.attr.windowFullscreen)
|
|
121
|
-
val theme =
|
|
122
|
+
val theme = activity.theme
|
|
122
123
|
val ta = theme.obtainStyledAttributes(attrs)
|
|
123
124
|
val windowFullscreen = ta.getBoolean(0, false)
|
|
124
125
|
|
|
@@ -126,7 +127,7 @@ private fun getModalHostSize(context: Context): Point {
|
|
|
126
127
|
// because Display.getCurrentSizeRange doesn't include it.
|
|
127
128
|
var statusBarHeight = 0
|
|
128
129
|
if (windowFullscreen) {
|
|
129
|
-
statusBarHeight =
|
|
130
|
+
statusBarHeight = SystemUiUtils.getStatusBarHeight(activity)
|
|
130
131
|
}
|
|
131
132
|
return if (SIZE_POINT.x < SIZE_POINT.y) {
|
|
132
133
|
// If we are vertical the width value comes from min width and height comes from max height
|
|
@@ -140,8 +141,10 @@ private fun getModalHostSize(context: Context): Point {
|
|
|
140
141
|
private class ModalHostShadowNode : LayoutShadowNode() {
|
|
141
142
|
override fun addChildAt(child: ReactShadowNodeImpl, i: Int) {
|
|
142
143
|
super.addChildAt(child, i)
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
144
|
+
themedContext?.currentActivity?.let {
|
|
145
|
+
val modalSize = getModalHostSize(it)
|
|
146
|
+
child.setStyleWidth(modalSize.x.toFloat())
|
|
147
|
+
child.setStyleHeight(modalSize.y.toFloat())
|
|
148
|
+
}
|
|
146
149
|
}
|
|
147
150
|
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
package com.reactnativenavigation.utils
|
|
2
|
+
|
|
3
|
+
import android.app.Activity
|
|
4
|
+
import android.graphics.Color
|
|
5
|
+
import android.graphics.Rect
|
|
6
|
+
import android.os.Build
|
|
7
|
+
import android.view.View
|
|
8
|
+
import android.view.Window
|
|
9
|
+
import androidx.annotation.ColorInt
|
|
10
|
+
import androidx.core.view.WindowCompat
|
|
11
|
+
import androidx.core.view.WindowInsetsCompat
|
|
12
|
+
import androidx.core.view.WindowInsetsControllerCompat
|
|
13
|
+
import kotlin.math.abs
|
|
14
|
+
import kotlin.math.ceil
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
object SystemUiUtils {
|
|
18
|
+
private const val STATUS_BAR_HEIGHT_M = 24
|
|
19
|
+
private const val STATUS_BAR_HEIGHT_L = 25
|
|
20
|
+
private const val STATUS_BAR_HEIGHT_TRANSLUCENCY = 0.65f
|
|
21
|
+
private var statusBarHeight = -1
|
|
22
|
+
var navigationBarDefaultColor = -1
|
|
23
|
+
private set
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@JvmStatic
|
|
27
|
+
fun getStatusBarHeight(activity: Activity?): Int {
|
|
28
|
+
val res = if (statusBarHeight > 0) {
|
|
29
|
+
statusBarHeight
|
|
30
|
+
} else {
|
|
31
|
+
statusBarHeight = activity?.let {
|
|
32
|
+
val rectangle = Rect()
|
|
33
|
+
val window: Window = activity.window
|
|
34
|
+
window.decorView.getWindowVisibleDisplayFrame(rectangle)
|
|
35
|
+
val statusBarHeight: Int = rectangle.top
|
|
36
|
+
val contentView = window.findViewById<View>(Window.ID_ANDROID_CONTENT)
|
|
37
|
+
contentView?.let {
|
|
38
|
+
val contentViewTop = contentView.top
|
|
39
|
+
abs(contentViewTop - statusBarHeight)
|
|
40
|
+
}
|
|
41
|
+
} ?: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) STATUS_BAR_HEIGHT_M else STATUS_BAR_HEIGHT_L
|
|
42
|
+
statusBarHeight
|
|
43
|
+
}
|
|
44
|
+
return res
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
@JvmStatic
|
|
48
|
+
fun saveStatusBarHeight(height: Int) {
|
|
49
|
+
statusBarHeight = height
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@JvmStatic
|
|
54
|
+
fun getStatusBarHeightDp(activity: Activity?): Int {
|
|
55
|
+
return UiUtils.pxToDp(activity, getStatusBarHeight(activity).toFloat())
|
|
56
|
+
.toInt()
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@JvmStatic
|
|
60
|
+
fun hideNavigationBar(window: Window?, view: View) {
|
|
61
|
+
window?.let {
|
|
62
|
+
WindowCompat.setDecorFitsSystemWindows(window, false)
|
|
63
|
+
WindowInsetsControllerCompat(window, view).let { controller ->
|
|
64
|
+
controller.hide(WindowInsetsCompat.Type.navigationBars())
|
|
65
|
+
controller.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
@JvmStatic
|
|
71
|
+
fun showNavigationBar(window: Window?, view: View) {
|
|
72
|
+
window?.let {
|
|
73
|
+
WindowCompat.setDecorFitsSystemWindows(window, true)
|
|
74
|
+
WindowInsetsControllerCompat(window, view).show(WindowInsetsCompat.Type.navigationBars())
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@JvmStatic
|
|
79
|
+
fun setStatusBarColorScheme(window: Window?, view: View, isDark: Boolean) {
|
|
80
|
+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return
|
|
81
|
+
|
|
82
|
+
window?.let {
|
|
83
|
+
WindowInsetsControllerCompat(window, view).isAppearanceLightStatusBars = isDark
|
|
84
|
+
// Workaround: on devices with api 30 status bar icons flickers or get hidden when removing view
|
|
85
|
+
//turns out it is a bug on such devices, fixed by using system flags until it is fixed.
|
|
86
|
+
var flags = view.systemUiVisibility
|
|
87
|
+
flags = if (isDark) {
|
|
88
|
+
flags or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
|
|
89
|
+
} else {
|
|
90
|
+
flags and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv()
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
view.systemUiVisibility = flags
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
@JvmStatic
|
|
98
|
+
fun setStatusBarTranslucent(window: Window?) {
|
|
99
|
+
window?.let {
|
|
100
|
+
setStatusBarColor(window, window.statusBarColor, true)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
@JvmStatic
|
|
105
|
+
fun isTranslucent(window: Window?): Boolean {
|
|
106
|
+
return window?.let {
|
|
107
|
+
Color.alpha(it.statusBarColor) < 255
|
|
108
|
+
} ?: false
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
@JvmStatic
|
|
112
|
+
fun clearStatusBarTranslucency(window: Window?) {
|
|
113
|
+
window?.let {
|
|
114
|
+
setStatusBarColor(it, it.statusBarColor, false)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
@JvmStatic
|
|
119
|
+
fun setStatusBarColor(
|
|
120
|
+
window: Window?,
|
|
121
|
+
@ColorInt color: Int,
|
|
122
|
+
translucent: Boolean
|
|
123
|
+
) {
|
|
124
|
+
val opaqueColor = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
|
125
|
+
Color.BLACK
|
|
126
|
+
}else{
|
|
127
|
+
val alpha = if (translucent) STATUS_BAR_HEIGHT_TRANSLUCENCY else 1f
|
|
128
|
+
val red: Int = Color.red(color)
|
|
129
|
+
val green: Int = Color.green(color)
|
|
130
|
+
val blue: Int = Color.blue(color)
|
|
131
|
+
Color.argb(ceil(alpha * 255).toInt(), red, green, blue)
|
|
132
|
+
}
|
|
133
|
+
window?.statusBarColor = opaqueColor
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
@JvmStatic
|
|
137
|
+
fun hideStatusBar(window: Window?, view: View) {
|
|
138
|
+
window?.let {
|
|
139
|
+
WindowCompat.setDecorFitsSystemWindows(window, false)
|
|
140
|
+
WindowInsetsControllerCompat(window, view).let { controller ->
|
|
141
|
+
controller.hide(WindowInsetsCompat.Type.statusBars())
|
|
142
|
+
controller.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
@JvmStatic
|
|
148
|
+
fun showStatusBar(window: Window?, view: View) {
|
|
149
|
+
window?.let {
|
|
150
|
+
WindowCompat.setDecorFitsSystemWindows(window, true)
|
|
151
|
+
WindowInsetsControllerCompat(window, view).show(WindowInsetsCompat.Type.statusBars())
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
@JvmStatic
|
|
156
|
+
fun setNavigationBarBackgroundColor(window: Window?, color: Int, lightColor: Boolean) {
|
|
157
|
+
window?.let {
|
|
158
|
+
if (navigationBarDefaultColor == -1) {
|
|
159
|
+
navigationBarDefaultColor = window.navigationBarColor
|
|
160
|
+
}
|
|
161
|
+
WindowInsetsControllerCompat(window, window.decorView).let { controller ->
|
|
162
|
+
controller.isAppearanceLightNavigationBars = lightColor
|
|
163
|
+
}
|
|
164
|
+
window.navigationBarColor = color
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
}
|
|
@@ -13,6 +13,7 @@ import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
|
|
13
13
|
import com.aurelhubert.ahbottomnavigation.AHBottomNavigation;
|
|
14
14
|
import com.aurelhubert.ahbottomnavigation.AHBottomNavigationItem;
|
|
15
15
|
import com.reactnativenavigation.options.BottomTabOptions;
|
|
16
|
+
import com.reactnativenavigation.options.HwBackBottomTabsBehaviour;
|
|
16
17
|
import com.reactnativenavigation.options.Options;
|
|
17
18
|
import com.reactnativenavigation.react.CommandListener;
|
|
18
19
|
import com.reactnativenavigation.react.CommandListenerAdapter;
|
|
@@ -29,6 +30,8 @@ import com.reactnativenavigation.views.bottomtabs.BottomTabsContainer;
|
|
|
29
30
|
import com.reactnativenavigation.views.bottomtabs.BottomTabsLayout;
|
|
30
31
|
|
|
31
32
|
import java.util.Collection;
|
|
33
|
+
import java.util.Deque;
|
|
34
|
+
import java.util.LinkedList;
|
|
32
35
|
import java.util.List;
|
|
33
36
|
|
|
34
37
|
import static com.reactnativenavigation.utils.CollectionUtils.forEach;
|
|
@@ -39,6 +42,7 @@ public class BottomTabsController extends ParentController<BottomTabsLayout> imp
|
|
|
39
42
|
|
|
40
43
|
private BottomTabsContainer bottomTabsContainer;
|
|
41
44
|
private BottomTabs bottomTabs;
|
|
45
|
+
private final Deque<Integer> selectionStack;
|
|
42
46
|
private final List<ViewController<?>> tabs;
|
|
43
47
|
private final EventEmitter eventEmitter;
|
|
44
48
|
private final ImageLoader imageLoader;
|
|
@@ -66,6 +70,7 @@ public class BottomTabsController extends ParentController<BottomTabsLayout> imp
|
|
|
66
70
|
this.presenter = bottomTabsPresenter;
|
|
67
71
|
this.tabPresenter = bottomTabPresenter;
|
|
68
72
|
forEach(tabs, tab -> tab.setParentController(this));
|
|
73
|
+
selectionStack = new LinkedList<>();
|
|
69
74
|
}
|
|
70
75
|
|
|
71
76
|
@Override
|
|
@@ -156,7 +161,27 @@ public class BottomTabsController extends ParentController<BottomTabsLayout> imp
|
|
|
156
161
|
|
|
157
162
|
@Override
|
|
158
163
|
public boolean handleBack(CommandListener listener) {
|
|
159
|
-
|
|
164
|
+
final boolean childBack = !tabs.isEmpty() && tabs.get(bottomTabs.getCurrentItem()).handleBack(listener);
|
|
165
|
+
final Options options = resolveCurrentOptions();
|
|
166
|
+
if (!childBack) {
|
|
167
|
+
if (options.hardwareBack.getBottomTabOnPress() instanceof HwBackBottomTabsBehaviour.PrevSelection) {
|
|
168
|
+
if (!selectionStack.isEmpty()) {
|
|
169
|
+
final int prevSelectedTabIndex = selectionStack.poll();
|
|
170
|
+
selectTab(prevSelectedTabIndex, false);
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
} else if (options.hardwareBack.getBottomTabOnPress() instanceof HwBackBottomTabsBehaviour.JumpToFirst) {
|
|
174
|
+
if (getSelectedIndex() != 0) {
|
|
175
|
+
selectTab(0, false);
|
|
176
|
+
return true;
|
|
177
|
+
} else {
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
} else {
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return childBack;
|
|
160
185
|
}
|
|
161
186
|
|
|
162
187
|
@Override
|
|
@@ -203,7 +228,7 @@ public class BottomTabsController extends ParentController<BottomTabsLayout> imp
|
|
|
203
228
|
});
|
|
204
229
|
}
|
|
205
230
|
|
|
206
|
-
int getSelectedIndex() {
|
|
231
|
+
public int getSelectedIndex() {
|
|
207
232
|
return bottomTabs.getCurrentItem();
|
|
208
233
|
}
|
|
209
234
|
|
|
@@ -239,6 +264,12 @@ public class BottomTabsController extends ParentController<BottomTabsLayout> imp
|
|
|
239
264
|
|
|
240
265
|
@Override
|
|
241
266
|
public void selectTab(final int newIndex) {
|
|
267
|
+
final boolean enableSelectionHistory = resolveCurrentOptions().hardwareBack.getBottomTabOnPress() instanceof HwBackBottomTabsBehaviour.PrevSelection;
|
|
268
|
+
selectTab(newIndex, enableSelectionHistory);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
private void selectTab(int newIndex, boolean enableSelectionHistory) {
|
|
272
|
+
saveTabSelection(newIndex, enableSelectionHistory);
|
|
242
273
|
tabsAttacher.onTabSelected(tabs.get(newIndex));
|
|
243
274
|
getCurrentView().setVisibility(View.INVISIBLE);
|
|
244
275
|
bottomTabs.setCurrentItem(newIndex, false);
|
|
@@ -246,6 +277,15 @@ public class BottomTabsController extends ParentController<BottomTabsLayout> imp
|
|
|
246
277
|
getCurrentChild().onViewDidAppear();
|
|
247
278
|
}
|
|
248
279
|
|
|
280
|
+
private void saveTabSelection(int newIndex, boolean enableSelectionHistory) {
|
|
281
|
+
if (enableSelectionHistory) {
|
|
282
|
+
if (selectionStack.isEmpty()
|
|
283
|
+
|| selectionStack.peek() != newIndex
|
|
284
|
+
|| bottomTabs.getCurrentItem() != newIndex)
|
|
285
|
+
selectionStack.offerFirst(bottomTabs.getCurrentItem());
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
249
289
|
@NonNull
|
|
250
290
|
private ViewGroup getCurrentView() {
|
|
251
291
|
return tabs.get(bottomTabs.getCurrentItem()).getView();
|
|
@@ -2,12 +2,16 @@ package com.reactnativenavigation.viewcontrollers.child;
|
|
|
2
2
|
|
|
3
3
|
import android.app.Activity;
|
|
4
4
|
import android.content.res.Configuration;
|
|
5
|
+
import android.os.Build;
|
|
6
|
+
import android.util.Log;
|
|
5
7
|
import android.view.View;
|
|
6
8
|
import android.view.ViewGroup;
|
|
9
|
+
import android.view.WindowInsets;
|
|
7
10
|
|
|
8
11
|
import com.reactnativenavigation.options.Options;
|
|
12
|
+
import com.reactnativenavigation.utils.LogKt;
|
|
13
|
+
import com.reactnativenavigation.viewcontrollers.parent.ParentController;
|
|
9
14
|
import com.reactnativenavigation.viewcontrollers.viewcontroller.Presenter;
|
|
10
|
-
import com.reactnativenavigation.utils.StatusBarUtils;
|
|
11
15
|
import com.reactnativenavigation.viewcontrollers.viewcontroller.NoOpYellowBoxDelegate;
|
|
12
16
|
import com.reactnativenavigation.viewcontrollers.navigator.Navigator;
|
|
13
17
|
import com.reactnativenavigation.viewcontrollers.viewcontroller.ViewController;
|
|
@@ -15,7 +19,9 @@ import com.reactnativenavigation.viewcontrollers.viewcontroller.overlay.ViewCont
|
|
|
15
19
|
import com.reactnativenavigation.views.component.Component;
|
|
16
20
|
|
|
17
21
|
import androidx.annotation.CallSuper;
|
|
22
|
+
import androidx.core.graphics.Insets;
|
|
18
23
|
import androidx.core.view.ViewCompat;
|
|
24
|
+
import androidx.core.view.WindowCompat;
|
|
19
25
|
import androidx.core.view.WindowInsetsCompat;
|
|
20
26
|
|
|
21
27
|
public abstract class ChildController<T extends ViewGroup> extends ViewController<T> {
|
|
@@ -61,7 +67,7 @@ public abstract class ChildController<T extends ViewGroup> extends ViewControlle
|
|
|
61
67
|
}
|
|
62
68
|
|
|
63
69
|
public void onViewBroughtToFront() {
|
|
64
|
-
presenter.onViewBroughtToFront(resolveCurrentOptions());
|
|
70
|
+
presenter.onViewBroughtToFront(this, resolveCurrentOptions());
|
|
65
71
|
}
|
|
66
72
|
|
|
67
73
|
@Override
|
|
@@ -73,7 +79,7 @@ public abstract class ChildController<T extends ViewGroup> extends ViewControlle
|
|
|
73
79
|
@Override
|
|
74
80
|
public void mergeOptions(Options options) {
|
|
75
81
|
if (options == Options.EMPTY) return;
|
|
76
|
-
if (isViewShown()) presenter.mergeOptions(
|
|
82
|
+
if (isViewShown()) presenter.mergeOptions(this, options);
|
|
77
83
|
super.mergeOptions(options);
|
|
78
84
|
performOnParentController(parentController -> parentController.mergeChildOptions(options, this));
|
|
79
85
|
}
|
|
@@ -93,23 +99,13 @@ public abstract class ChildController<T extends ViewGroup> extends ViewControlle
|
|
|
93
99
|
getView().getParent() != null;
|
|
94
100
|
}
|
|
95
101
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
return applyWindowInsets(findController(view), insets);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
protected WindowInsetsCompat applyWindowInsets(ViewController<?> view, WindowInsetsCompat insets) {
|
|
102
|
-
return insets.replaceSystemWindowInsets(
|
|
103
|
-
insets.getSystemWindowInsetLeft(),
|
|
104
|
-
0,
|
|
105
|
-
insets.getSystemWindowInsetRight(),
|
|
106
|
-
insets.getSystemWindowInsetBottom()
|
|
107
|
-
);
|
|
102
|
+
protected WindowInsetsCompat onApplyWindowInsets(View view, WindowInsetsCompat insets) {
|
|
103
|
+
return insets;
|
|
108
104
|
}
|
|
109
105
|
|
|
110
106
|
@Override
|
|
111
107
|
public void onConfigurationChanged(Configuration newConfig) {
|
|
112
108
|
super.onConfigurationChanged(newConfig);
|
|
113
|
-
presenter.onConfigurationChanged(this,options);
|
|
109
|
+
presenter.onConfigurationChanged(this, options);
|
|
114
110
|
}
|
|
115
111
|
}
|
|
@@ -4,10 +4,11 @@ import android.app.Activity;
|
|
|
4
4
|
import android.content.res.Configuration;
|
|
5
5
|
import android.view.View;
|
|
6
6
|
|
|
7
|
+
import com.reactnativenavigation.utils.LogKt;
|
|
7
8
|
import com.reactnativenavigation.viewcontrollers.viewcontroller.ScrollEventListener;
|
|
8
9
|
import com.reactnativenavigation.options.Options;
|
|
9
10
|
import com.reactnativenavigation.viewcontrollers.viewcontroller.Presenter;
|
|
10
|
-
import com.reactnativenavigation.utils.
|
|
11
|
+
import com.reactnativenavigation.utils.SystemUiUtils;
|
|
11
12
|
import com.reactnativenavigation.viewcontrollers.viewcontroller.ReactViewCreator;
|
|
12
13
|
import com.reactnativenavigation.viewcontrollers.child.ChildController;
|
|
13
14
|
import com.reactnativenavigation.viewcontrollers.child.ChildControllersRegistry;
|
|
@@ -127,8 +128,9 @@ public class ComponentViewController extends ChildController<ComponentLayout> {
|
|
|
127
128
|
|
|
128
129
|
@Override
|
|
129
130
|
public int getTopInset() {
|
|
130
|
-
int statusBarInset = resolveCurrentOptions(presenter.defaultOptions).statusBar.isHiddenOrDrawBehind() ? 0 :
|
|
131
|
-
|
|
131
|
+
int statusBarInset = resolveCurrentOptions(presenter.defaultOptions).statusBar.isHiddenOrDrawBehind() ? 0 : SystemUiUtils.getStatusBarHeight(getActivity());
|
|
132
|
+
final Integer perform = perform(getParentController(), 0, p -> p.getTopInset(this));
|
|
133
|
+
return statusBarInset + perform;
|
|
132
134
|
}
|
|
133
135
|
|
|
134
136
|
@Override
|
|
@@ -137,14 +139,19 @@ public class ComponentViewController extends ChildController<ComponentLayout> {
|
|
|
137
139
|
}
|
|
138
140
|
|
|
139
141
|
@Override
|
|
140
|
-
protected WindowInsetsCompat
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
142
|
+
protected WindowInsetsCompat onApplyWindowInsets(View view, WindowInsetsCompat insets) {
|
|
143
|
+
ViewController<?> viewController = findController(view);
|
|
144
|
+
if (viewController == null || viewController.getView() == null) return insets;
|
|
145
|
+
final Insets keyboardInsets = insets.getInsets( WindowInsetsCompat.Type.ime());
|
|
146
|
+
final Insets systemBarsInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars() );
|
|
147
|
+
final int visibleNavBar = resolveCurrentOptions(presenter.defaultOptions).navigationBar.isVisible.isTrueOrUndefined()?1:0;
|
|
148
|
+
final WindowInsetsCompat finalInsets = new WindowInsetsCompat.Builder().setInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.ime(),
|
|
149
|
+
Insets.of(systemBarsInsets.left,
|
|
150
|
+
0,
|
|
151
|
+
systemBarsInsets.right,
|
|
152
|
+
Math.max(visibleNavBar*systemBarsInsets.bottom,keyboardInsets.bottom))
|
|
153
|
+
).build();
|
|
154
|
+
return ViewCompat.onApplyWindowInsets(viewController.getView(), finalInsets);
|
|
148
155
|
}
|
|
149
156
|
|
|
150
157
|
@Override
|
|
@@ -10,7 +10,7 @@ import com.reactnativenavigation.viewcontrollers.viewcontroller.Presenter;
|
|
|
10
10
|
import com.reactnativenavigation.react.events.ComponentType;
|
|
11
11
|
import com.reactnativenavigation.react.events.EventEmitter;
|
|
12
12
|
import com.reactnativenavigation.utils.CoordinatorLayoutUtils;
|
|
13
|
-
import com.reactnativenavigation.utils.
|
|
13
|
+
import com.reactnativenavigation.utils.SystemUiUtils;
|
|
14
14
|
import com.reactnativenavigation.viewcontrollers.child.ChildController;
|
|
15
15
|
import com.reactnativenavigation.viewcontrollers.child.ChildControllersRegistry;
|
|
16
16
|
import com.reactnativenavigation.views.BehaviourDelegate;
|
|
@@ -72,7 +72,7 @@ public class ExternalComponentViewController extends ChildController<ExternalCom
|
|
|
72
72
|
|
|
73
73
|
@Override
|
|
74
74
|
public int getTopInset() {
|
|
75
|
-
int statusBarInset = resolveCurrentOptions().statusBar.drawBehind.isTrue() ? 0 :
|
|
75
|
+
int statusBarInset = resolveCurrentOptions().statusBar.drawBehind.isTrue() ? 0 : SystemUiUtils.getStatusBarHeight(getActivity());
|
|
76
76
|
return statusBarInset + perform(getParentController(), 0, p -> p.getTopInset(this));
|
|
77
77
|
}
|
|
78
78
|
|