react-native-screens 4.25.0-beta.1 → 4.25.0-beta.2
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/android/src/main/java/com/swmansion/rnscreens/gamma/stack/header/StackHeaderAppBarLayout.kt +6 -14
- package/android/src/main/java/com/swmansion/rnscreens/gamma/stack/header/StackHeaderAppBarLayoutBehavior.kt +29 -0
- package/android/src/main/java/com/swmansion/rnscreens/gamma/stack/header/StackHeaderCoordinator.kt +56 -0
- package/android/src/main/java/com/swmansion/rnscreens/gamma/stack/header/config/StackHeaderConfig.kt +11 -0
- package/android/src/main/java/com/swmansion/rnscreens/gamma/stack/header/config/StackHeaderConfigProviding.kt +5 -0
- package/android/src/main/java/com/swmansion/rnscreens/gamma/stack/header/config/StackHeaderConfigViewManager.kt +35 -0
- package/android/src/main/java/com/swmansion/rnscreens/gamma/stack/header/subview/StackHeaderSubview.kt +3 -7
- package/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/container/TabsActionOrigin.kt +26 -0
- package/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/container/TabsContainer.kt +227 -151
- package/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/container/TabsNavigationState.kt +60 -0
- package/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/container/{TabsContainerDelegate.kt → TabsNavigationStateObserver.kt} +19 -14
- package/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/container/TabsNavigationStateObserverRegistry.kt +88 -0
- package/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/host/TabsHost.kt +40 -24
- package/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/host/TabsHostEventEmitter.kt +11 -9
- package/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/host/TabsHostViewManager.kt +19 -7
- package/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/host/event/TabsHostTabSelectedEvent.kt +4 -3
- package/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/host/event/TabsHostTabSelectionPreventedEvent.kt +3 -3
- package/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/host/event/TabsHostTabSelectionRejectedEvent.kt +11 -10
- package/ios/conversion/RNSConversions-Tabs.mm +19 -0
- package/ios/conversion/RNSConversions.h +3 -0
- package/ios/tabs/bottom-accessory/RNSTabsBottomAccessoryHelper.mm +34 -5
- package/ios/tabs/host/RNSTabBarController.h +152 -99
- package/ios/tabs/host/RNSTabBarController.mm +137 -113
- package/ios/tabs/host/RNSTabsHostComponentView.h +7 -8
- package/ios/tabs/host/RNSTabsHostComponentView.mm +37 -33
- package/ios/tabs/host/RNSTabsHostEventEmitter.h +4 -4
- package/ios/tabs/host/RNSTabsHostEventEmitter.mm +5 -3
- package/ios/tabs/host/RNSTabsNavigationState.h +142 -27
- package/ios/tabs/host/RNSTabsNavigationState.mm +35 -2
- package/ios/tabs/host/RNSTabsNavigationStateObserverRegistry.h +62 -0
- package/ios/tabs/host/RNSTabsNavigationStateObserverRegistry.mm +104 -0
- package/lib/commonjs/components/gamma/stack/header/StackHeaderConfig.android.js +46 -1
- package/lib/commonjs/components/gamma/stack/header/StackHeaderConfig.android.js.map +1 -1
- package/lib/commonjs/components/safe-area/SafeAreaView.web.js +2 -3
- package/lib/commonjs/components/safe-area/SafeAreaView.web.js.map +1 -1
- package/lib/commonjs/components/tabs/host/TabsHost.android.js +2 -2
- package/lib/commonjs/components/tabs/host/TabsHost.android.js.map +1 -1
- package/lib/commonjs/components/tabs/host/TabsHost.ios.js +2 -2
- package/lib/commonjs/components/tabs/host/TabsHost.ios.js.map +1 -1
- package/lib/commonjs/fabric/gamma/stack/StackHeaderConfigAndroidNativeComponent.js.map +1 -1
- package/lib/commonjs/flags.js +1 -0
- package/lib/commonjs/flags.js.map +1 -1
- package/lib/module/components/gamma/stack/header/StackHeaderConfig.android.js +46 -1
- package/lib/module/components/gamma/stack/header/StackHeaderConfig.android.js.map +1 -1
- package/lib/module/components/safe-area/SafeAreaView.web.js +1 -1
- package/lib/module/components/safe-area/SafeAreaView.web.js.map +1 -1
- package/lib/module/components/tabs/host/TabsHost.android.js +2 -2
- package/lib/module/components/tabs/host/TabsHost.android.js.map +1 -1
- package/lib/module/components/tabs/host/TabsHost.ios.js +2 -2
- package/lib/module/components/tabs/host/TabsHost.ios.js.map +1 -1
- package/lib/module/fabric/gamma/stack/StackHeaderConfigAndroidNativeComponent.js.map +1 -1
- package/lib/module/flags.js +1 -0
- package/lib/module/flags.js.map +1 -1
- package/lib/typescript/components/gamma/split/SplitHost.types.d.ts +1 -1
- package/lib/typescript/components/gamma/split/SplitHost.types.d.ts.map +1 -1
- package/lib/typescript/components/gamma/stack/header/StackHeaderConfig.android.d.ts.map +1 -1
- package/lib/typescript/components/gamma/stack/header/StackHeaderConfig.android.types.d.ts +183 -8
- package/lib/typescript/components/gamma/stack/header/StackHeaderConfig.android.types.d.ts.map +1 -1
- package/lib/typescript/components/gamma/stack/header/StackHeaderConfig.types.d.ts +37 -0
- package/lib/typescript/components/gamma/stack/header/StackHeaderConfig.types.d.ts.map +1 -1
- package/lib/typescript/components/gamma/stack/header/android/StackHeaderSubview.android.types.d.ts +1 -1
- package/lib/typescript/components/gamma/stack/header/android/StackHeaderSubview.android.types.d.ts.map +1 -1
- package/lib/typescript/components/gamma/stack/host/StackHost.types.d.ts +1 -1
- package/lib/typescript/components/gamma/stack/host/StackHost.types.d.ts.map +1 -1
- package/lib/typescript/components/safe-area/SafeAreaView.web.d.ts +1 -1
- package/lib/typescript/components/safe-area/SafeAreaView.web.d.ts.map +1 -1
- package/lib/typescript/components/tabs/host/TabsHost.types.d.ts +27 -17
- package/lib/typescript/components/tabs/host/TabsHost.types.d.ts.map +1 -1
- package/lib/typescript/components/tabs/index.d.ts +1 -1
- package/lib/typescript/components/tabs/index.d.ts.map +1 -1
- package/lib/typescript/fabric/gamma/stack/StackHeaderConfigAndroidNativeComponent.d.ts +5 -0
- package/lib/typescript/fabric/gamma/stack/StackHeaderConfigAndroidNativeComponent.d.ts.map +1 -1
- package/lib/typescript/fabric/tabs/TabsHostAndroidNativeComponent.d.ts +4 -4
- package/lib/typescript/fabric/tabs/TabsHostAndroidNativeComponent.d.ts.map +1 -1
- package/lib/typescript/fabric/tabs/TabsHostIOSNativeComponent.d.ts +4 -4
- package/lib/typescript/fabric/tabs/TabsHostIOSNativeComponent.d.ts.map +1 -1
- package/lib/typescript/flags.d.ts +1 -0
- package/lib/typescript/flags.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/gamma/split/SplitHost.types.ts +1 -1
- package/src/components/gamma/stack/header/StackHeaderConfig.android.tsx +72 -2
- package/src/components/gamma/stack/header/StackHeaderConfig.android.types.ts +183 -8
- package/src/components/gamma/stack/header/StackHeaderConfig.types.ts +37 -0
- package/src/components/gamma/stack/header/android/StackHeaderSubview.android.types.ts +1 -1
- package/src/components/gamma/stack/host/StackHost.types.ts +1 -1
- package/src/components/safe-area/SafeAreaView.web.tsx +1 -1
- package/src/components/tabs/host/TabsHost.android.tsx +2 -2
- package/src/components/tabs/host/TabsHost.ios.tsx +2 -2
- package/src/components/tabs/host/TabsHost.types.ts +27 -17
- package/src/components/tabs/index.ts +1 -1
- package/src/fabric/gamma/stack/StackHeaderConfigAndroidNativeComponent.ts +6 -0
- package/src/fabric/tabs/TabsHostAndroidNativeComponent.ts +4 -4
- package/src/fabric/tabs/TabsHostIOSNativeComponent.ts +4 -4
- package/src/flags.ts +1 -0
- package/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/container/TabsContainerOps.kt +0 -7
- package/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/container/TabsNavState.kt +0 -43
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
package com.swmansion.rnscreens.gamma.tabs.container
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Holds the set of [TabsNavigationStateObserver]s registered against a [TabsContainer]
|
|
5
|
+
* and fans out container events to all of them.
|
|
6
|
+
*
|
|
7
|
+
* Observers are held with strong references; callers must explicitly call
|
|
8
|
+
* [TabsContainer.removeNavigationStateObserver] before observer dealloc, or rely on the
|
|
9
|
+
* host invoking [TabsContainer.tearDown] (which calls [clear]) on container teardown.
|
|
10
|
+
*
|
|
11
|
+
* # Reentrance
|
|
12
|
+
*
|
|
13
|
+
* Recursive emission is forbidden. While an `emit*` call is in flight:
|
|
14
|
+
* - additional `emit*` calls fail-fast with [IllegalStateException] (recursion is a
|
|
15
|
+
* programmer error — it would deliver out-of-order events to later observers),
|
|
16
|
+
* - [add] / [remove] are rejected gracefully and return `false`.
|
|
17
|
+
*
|
|
18
|
+
* The registry is single-threaded — use it from a single thread (typically the UI
|
|
19
|
+
* thread on Android). It does not synchronize.
|
|
20
|
+
*/
|
|
21
|
+
internal class TabsNavigationStateObserverRegistry {
|
|
22
|
+
private val observers: MutableList<TabsNavigationStateObserver> = mutableListOf()
|
|
23
|
+
private var isEmitting: Boolean = false
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Register an observer. Returns `false` if the observer is already registered or
|
|
27
|
+
* if called during an in-flight `emit*` (modifications during emission are rejected).
|
|
28
|
+
*/
|
|
29
|
+
fun add(observer: TabsNavigationStateObserver): Boolean {
|
|
30
|
+
if (isEmitting) return false
|
|
31
|
+
if (observers.contains(observer)) return false
|
|
32
|
+
observers.add(observer)
|
|
33
|
+
return true
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Unregister an observer. Returns `false` if the observer was not registered or
|
|
38
|
+
* if called during an in-flight `emit*` (modifications during emission are rejected).
|
|
39
|
+
*/
|
|
40
|
+
fun remove(observer: TabsNavigationStateObserver): Boolean {
|
|
41
|
+
if (isEmitting) return false
|
|
42
|
+
return observers.remove(observer)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Drop all registered observers. Must not be called during an in-flight `emit*`.
|
|
47
|
+
*/
|
|
48
|
+
fun clear() {
|
|
49
|
+
check(!isEmitting) { "[RNScreens] TabsNavigationStateObserverRegistry.clear during emission" }
|
|
50
|
+
observers.clear()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
fun emitOnNavigationStateUpdate(
|
|
54
|
+
navState: TabsNavigationState,
|
|
55
|
+
isRepeated: Boolean,
|
|
56
|
+
hasTriggeredSpecialEffect: Boolean,
|
|
57
|
+
actionOrigin: TabsActionOrigin,
|
|
58
|
+
) {
|
|
59
|
+
emitSignal { observer -> observer.onNavigationStateUpdate(navState, isRepeated, hasTriggeredSpecialEffect, actionOrigin) }
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
fun emitOnNavigationStateUpdateRejected(
|
|
63
|
+
currentNavState: TabsNavigationState,
|
|
64
|
+
rejectedRequest: TabsNavigationStateUpdateRequest,
|
|
65
|
+
reason: TabsNavigationStateRejectionReason,
|
|
66
|
+
) {
|
|
67
|
+
emitSignal { observer -> observer.onNavigationStateUpdateRejected(currentNavState, rejectedRequest, reason) }
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
fun emitOnNavigationStateUpdatePrevented(
|
|
71
|
+
currentNavState: TabsNavigationState,
|
|
72
|
+
preventedScreenKey: String,
|
|
73
|
+
) {
|
|
74
|
+
emitSignal { observer -> observer.onNavigationStateUpdatePrevented(currentNavState, preventedScreenKey) }
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
private fun emitSignal(emitBlock: (TabsNavigationStateObserver) -> Unit) {
|
|
78
|
+
check(!isEmitting) { "[RNScreens] Recursive emission on TabsNavigationStateObserverRegistry" }
|
|
79
|
+
isEmitting = true
|
|
80
|
+
try {
|
|
81
|
+
observers.forEach {
|
|
82
|
+
emitBlock(it)
|
|
83
|
+
}
|
|
84
|
+
} finally {
|
|
85
|
+
isEmitting = false
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -12,11 +12,12 @@ import com.facebook.react.uimanager.ThemedReactContext
|
|
|
12
12
|
import com.facebook.react.uimanager.UIManagerHelper
|
|
13
13
|
import com.swmansion.rnscreens.gamma.common.colorscheme.ColorScheme
|
|
14
14
|
import com.swmansion.rnscreens.gamma.helpers.getFabricUIManagerNotNull
|
|
15
|
-
import com.swmansion.rnscreens.gamma.tabs.container.
|
|
15
|
+
import com.swmansion.rnscreens.gamma.tabs.container.TabsActionOrigin
|
|
16
16
|
import com.swmansion.rnscreens.gamma.tabs.container.TabsContainer
|
|
17
|
-
import com.swmansion.rnscreens.gamma.tabs.container.
|
|
18
|
-
import com.swmansion.rnscreens.gamma.tabs.container.
|
|
19
|
-
import com.swmansion.rnscreens.gamma.tabs.container.
|
|
17
|
+
import com.swmansion.rnscreens.gamma.tabs.container.TabsNavigationState
|
|
18
|
+
import com.swmansion.rnscreens.gamma.tabs.container.TabsNavigationStateObserver
|
|
19
|
+
import com.swmansion.rnscreens.gamma.tabs.container.TabsNavigationStateRejectionReason
|
|
20
|
+
import com.swmansion.rnscreens.gamma.tabs.container.TabsNavigationStateUpdateRequest
|
|
20
21
|
import com.swmansion.rnscreens.gamma.tabs.screen.TabsScreen
|
|
21
22
|
import com.swmansion.rnscreens.utils.RNSLog
|
|
22
23
|
import kotlin.properties.Delegates
|
|
@@ -26,13 +27,13 @@ import kotlin.properties.Delegates
|
|
|
26
27
|
class TabsHost(
|
|
27
28
|
val reactContext: ThemedReactContext,
|
|
28
29
|
) : FrameLayout(reactContext),
|
|
29
|
-
|
|
30
|
+
TabsNavigationStateObserver,
|
|
30
31
|
UIManagerListener {
|
|
31
32
|
private val renderedScreens: ArrayList<TabsScreen> = arrayListOf()
|
|
32
|
-
private var
|
|
33
|
+
private var jsNavStateRequest: TabsNavigationStateUpdateRequest? = null
|
|
33
34
|
|
|
34
35
|
private val container: TabsContainer =
|
|
35
|
-
TabsContainer(reactContext
|
|
36
|
+
TabsContainer(reactContext).apply {
|
|
36
37
|
layoutParams =
|
|
37
38
|
LayoutParams(
|
|
38
39
|
LayoutParams.MATCH_PARENT,
|
|
@@ -40,7 +41,7 @@ class TabsHost(
|
|
|
40
41
|
)
|
|
41
42
|
}
|
|
42
43
|
|
|
43
|
-
internal var
|
|
44
|
+
internal var rejectStaleNavigationStateUpdates: Boolean by container::rejectStaleNavigationStateUpdates
|
|
44
45
|
|
|
45
46
|
internal lateinit var eventEmitter: TabsHostEventEmitter
|
|
46
47
|
|
|
@@ -59,6 +60,9 @@ class TabsHost(
|
|
|
59
60
|
|
|
60
61
|
init {
|
|
61
62
|
addView(container)
|
|
63
|
+
check(container.addNavigationStateObserver(this)) {
|
|
64
|
+
"[RNScreens] Failed to register TabsHost as navigation state observer"
|
|
65
|
+
}
|
|
62
66
|
UIManagerHelper
|
|
63
67
|
.getFabricUIManagerNotNull(reactContext)
|
|
64
68
|
.addUIManagerEventListener(this)
|
|
@@ -109,9 +113,9 @@ class TabsHost(
|
|
|
109
113
|
container.removeAllTabsScreens()
|
|
110
114
|
}
|
|
111
115
|
|
|
112
|
-
internal fun
|
|
113
|
-
|
|
114
|
-
container.
|
|
116
|
+
internal fun updateJSNavigationStateUpdateRequest(navStateRequest: TabsNavigationStateUpdateRequest) {
|
|
117
|
+
jsNavStateRequest = navStateRequest
|
|
118
|
+
container.setPendingNavigationStateUpdate(navStateRequest.copy())
|
|
115
119
|
}
|
|
116
120
|
|
|
117
121
|
private val layoutCallback =
|
|
@@ -155,42 +159,54 @@ class TabsHost(
|
|
|
155
159
|
eventEmitter = TabsHostEventEmitter(reactContext, id)
|
|
156
160
|
}
|
|
157
161
|
|
|
158
|
-
override fun
|
|
159
|
-
navState:
|
|
162
|
+
override fun onNavigationStateUpdate(
|
|
163
|
+
navState: TabsNavigationState,
|
|
160
164
|
isRepeated: Boolean,
|
|
161
165
|
hasTriggeredSpecialEffect: Boolean,
|
|
162
|
-
|
|
166
|
+
actionOrigin: TabsActionOrigin,
|
|
163
167
|
) {
|
|
164
168
|
eventEmitter.emitOnTabSelectedEvent(
|
|
165
|
-
navState.
|
|
169
|
+
navState.selectedScreenKey,
|
|
166
170
|
navState.provenance,
|
|
167
171
|
isRepeated,
|
|
168
172
|
hasTriggeredSpecialEffect,
|
|
169
|
-
|
|
173
|
+
actionOrigin,
|
|
170
174
|
)
|
|
171
175
|
}
|
|
172
176
|
|
|
173
|
-
override fun
|
|
174
|
-
currentNavState:
|
|
175
|
-
|
|
176
|
-
reason:
|
|
177
|
+
override fun onNavigationStateUpdateRejected(
|
|
178
|
+
currentNavState: TabsNavigationState,
|
|
179
|
+
rejectedRequest: TabsNavigationStateUpdateRequest,
|
|
180
|
+
reason: TabsNavigationStateRejectionReason,
|
|
177
181
|
) {
|
|
178
182
|
eventEmitter.emitOnTabSelectionRejectedEvent(
|
|
179
183
|
currentNavState,
|
|
180
|
-
|
|
184
|
+
rejectedRequest,
|
|
181
185
|
reason,
|
|
182
186
|
)
|
|
183
187
|
}
|
|
184
188
|
|
|
185
|
-
override fun
|
|
186
|
-
currentNavState:
|
|
189
|
+
override fun onNavigationStateUpdatePrevented(
|
|
190
|
+
currentNavState: TabsNavigationState,
|
|
187
191
|
preventedScreenKey: String,
|
|
188
192
|
) {
|
|
189
193
|
eventEmitter.emitOnTabSelectionPreventedEvent(currentNavState, preventedScreenKey)
|
|
190
194
|
}
|
|
191
195
|
|
|
192
196
|
override fun didMountItems(uiManager: UIManager) {
|
|
193
|
-
container.
|
|
197
|
+
container.flushPendingUpdates()
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Called by [TabsHostViewManager.onDropViewInstance] when this view is recycled.
|
|
202
|
+
* Idempotent: safe to call multiple times.
|
|
203
|
+
*/
|
|
204
|
+
internal fun tearDown() {
|
|
205
|
+
container.removeNavigationStateObserver(this)
|
|
206
|
+
container.tearDown()
|
|
207
|
+
UIManagerHelper
|
|
208
|
+
.getFabricUIManagerNotNull(reactContext)
|
|
209
|
+
.removeUIManagerEventListener(this)
|
|
194
210
|
}
|
|
195
211
|
|
|
196
212
|
override fun willDispatchViewUpdates(uiManager: UIManager) = Unit
|
package/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/host/TabsHostEventEmitter.kt
CHANGED
|
@@ -2,8 +2,10 @@ package com.swmansion.rnscreens.gamma.tabs.host
|
|
|
2
2
|
|
|
3
3
|
import com.facebook.react.bridge.ReactContext
|
|
4
4
|
import com.swmansion.rnscreens.gamma.common.event.BaseEventEmitter
|
|
5
|
-
import com.swmansion.rnscreens.gamma.tabs.container.
|
|
6
|
-
import com.swmansion.rnscreens.gamma.tabs.container.
|
|
5
|
+
import com.swmansion.rnscreens.gamma.tabs.container.TabsActionOrigin
|
|
6
|
+
import com.swmansion.rnscreens.gamma.tabs.container.TabsNavigationState
|
|
7
|
+
import com.swmansion.rnscreens.gamma.tabs.container.TabsNavigationStateRejectionReason
|
|
8
|
+
import com.swmansion.rnscreens.gamma.tabs.container.TabsNavigationStateUpdateRequest
|
|
7
9
|
import com.swmansion.rnscreens.gamma.tabs.host.event.TabsHostTabSelectedEvent
|
|
8
10
|
import com.swmansion.rnscreens.gamma.tabs.host.event.TabsHostTabSelectionPreventedEvent
|
|
9
11
|
import com.swmansion.rnscreens.gamma.tabs.host.event.TabsHostTabSelectionRejectedEvent
|
|
@@ -20,7 +22,7 @@ internal class TabsHostEventEmitter(
|
|
|
20
22
|
provenance: Int,
|
|
21
23
|
isRepeated: Boolean,
|
|
22
24
|
hasTriggeredSpecialEffect: Boolean,
|
|
23
|
-
|
|
25
|
+
actionOrigin: TabsActionOrigin,
|
|
24
26
|
) {
|
|
25
27
|
reactEventDispatcher.dispatchEvent(
|
|
26
28
|
TabsHostTabSelectedEvent(
|
|
@@ -30,7 +32,7 @@ internal class TabsHostEventEmitter(
|
|
|
30
32
|
provenance,
|
|
31
33
|
isRepeated,
|
|
32
34
|
hasTriggeredSpecialEffect,
|
|
33
|
-
|
|
35
|
+
actionOrigin,
|
|
34
36
|
),
|
|
35
37
|
)
|
|
36
38
|
}
|
|
@@ -40,16 +42,16 @@ internal class TabsHostEventEmitter(
|
|
|
40
42
|
* Carries both the active state and the rejected update so that JS can reconcile.
|
|
41
43
|
*/
|
|
42
44
|
fun emitOnTabSelectionRejectedEvent(
|
|
43
|
-
currentNavState:
|
|
44
|
-
|
|
45
|
-
rejectionReason:
|
|
45
|
+
currentNavState: TabsNavigationState,
|
|
46
|
+
rejectedRequest: TabsNavigationStateUpdateRequest,
|
|
47
|
+
rejectionReason: TabsNavigationStateRejectionReason,
|
|
46
48
|
) {
|
|
47
49
|
reactEventDispatcher.dispatchEvent(
|
|
48
50
|
TabsHostTabSelectionRejectedEvent(
|
|
49
51
|
surfaceId,
|
|
50
52
|
viewTag,
|
|
51
53
|
currentNavState,
|
|
52
|
-
|
|
54
|
+
rejectedRequest,
|
|
53
55
|
rejectionReason,
|
|
54
56
|
),
|
|
55
57
|
)
|
|
@@ -60,7 +62,7 @@ internal class TabsHostEventEmitter(
|
|
|
60
62
|
* because the target screen has `preventNativeSelection` enabled.
|
|
61
63
|
*/
|
|
62
64
|
fun emitOnTabSelectionPreventedEvent(
|
|
63
|
-
currentNavState:
|
|
65
|
+
currentNavState: TabsNavigationState,
|
|
64
66
|
preventedScreenKey: String,
|
|
65
67
|
) {
|
|
66
68
|
reactEventDispatcher.dispatchEvent(
|
package/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/host/TabsHostViewManager.kt
CHANGED
|
@@ -11,7 +11,8 @@ import com.facebook.react.viewmanagers.RNSTabsHostAndroidManagerDelegate
|
|
|
11
11
|
import com.facebook.react.viewmanagers.RNSTabsHostAndroidManagerInterface
|
|
12
12
|
import com.swmansion.rnscreens.gamma.common.colorscheme.ColorScheme
|
|
13
13
|
import com.swmansion.rnscreens.gamma.helpers.makeEventRegistrationInfo
|
|
14
|
-
import com.swmansion.rnscreens.gamma.tabs.container.
|
|
14
|
+
import com.swmansion.rnscreens.gamma.tabs.container.TabsActionOrigin
|
|
15
|
+
import com.swmansion.rnscreens.gamma.tabs.container.TabsNavigationStateUpdateRequest
|
|
15
16
|
import com.swmansion.rnscreens.gamma.tabs.host.event.TabsHostTabSelectedEvent
|
|
16
17
|
import com.swmansion.rnscreens.gamma.tabs.host.event.TabsHostTabSelectionPreventedEvent
|
|
17
18
|
import com.swmansion.rnscreens.gamma.tabs.host.event.TabsHostTabSelectionRejectedEvent
|
|
@@ -72,21 +73,32 @@ class TabsHostViewManager :
|
|
|
72
73
|
view.onViewManagerAddEventEmitters()
|
|
73
74
|
}
|
|
74
75
|
|
|
75
|
-
override fun
|
|
76
|
+
override fun onDropViewInstance(view: TabsHost) {
|
|
77
|
+
view.tearDown()
|
|
78
|
+
super.onDropViewInstance(view)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
override fun setNavStateRequest(
|
|
76
82
|
view: TabsHost,
|
|
77
83
|
value: ReadableMap?,
|
|
78
84
|
) {
|
|
79
|
-
val
|
|
80
|
-
val selectedScreenKey = requireNotNull(
|
|
81
|
-
val
|
|
82
|
-
view.
|
|
85
|
+
val navStateRequestMap = requireNotNull(value) { "[RNScreens] navStateRequest must not be nullish" }
|
|
86
|
+
val selectedScreenKey = requireNotNull(navStateRequestMap.getString("selectedScreenKey"))
|
|
87
|
+
val baseProvenance = requireNotNull(navStateRequestMap.getInt("baseProvenance"))
|
|
88
|
+
view.updateJSNavigationStateUpdateRequest(
|
|
89
|
+
TabsNavigationStateUpdateRequest(
|
|
90
|
+
selectedScreenKey = selectedScreenKey,
|
|
91
|
+
baseProvenance = baseProvenance,
|
|
92
|
+
actionOrigin = TabsActionOrigin.PROGRAMMATIC_JS,
|
|
93
|
+
),
|
|
94
|
+
)
|
|
83
95
|
}
|
|
84
96
|
|
|
85
97
|
override fun setRejectStaleNavStateUpdates(
|
|
86
98
|
view: TabsHost,
|
|
87
99
|
value: Boolean,
|
|
88
100
|
) {
|
|
89
|
-
view.
|
|
101
|
+
view.rejectStaleNavigationStateUpdates = value
|
|
90
102
|
}
|
|
91
103
|
|
|
92
104
|
override fun setTabBarHidden(
|
|
@@ -4,6 +4,7 @@ import com.facebook.react.bridge.Arguments
|
|
|
4
4
|
import com.facebook.react.bridge.WritableMap
|
|
5
5
|
import com.facebook.react.uimanager.events.Event
|
|
6
6
|
import com.swmansion.rnscreens.gamma.common.event.NamingAwareEventType
|
|
7
|
+
import com.swmansion.rnscreens.gamma.tabs.container.TabsActionOrigin
|
|
7
8
|
|
|
8
9
|
class TabsHostTabSelectedEvent(
|
|
9
10
|
surfaceId: Int,
|
|
@@ -12,7 +13,7 @@ class TabsHostTabSelectedEvent(
|
|
|
12
13
|
val provenance: Int,
|
|
13
14
|
val isRepeated: Boolean,
|
|
14
15
|
val hasTriggeredSpecialEffect: Boolean,
|
|
15
|
-
val
|
|
16
|
+
val actionOrigin: TabsActionOrigin,
|
|
16
17
|
) : Event<TabsHostTabSelectedEvent>(surfaceId, viewId),
|
|
17
18
|
NamingAwareEventType {
|
|
18
19
|
override fun getEventName() = EVENT_NAME
|
|
@@ -28,7 +29,7 @@ class TabsHostTabSelectedEvent(
|
|
|
28
29
|
putInt(EK_PROVENANCE, provenance)
|
|
29
30
|
putBoolean(EK_IS_REPEATED, isRepeated)
|
|
30
31
|
putBoolean(EK_HAS_TRIGGERED_SPECIAL_EFFECT, hasTriggeredSpecialEffect)
|
|
31
|
-
|
|
32
|
+
putString(EK_ACTION_ORIGIN, actionOrigin.toString())
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
companion object : NamingAwareEventType {
|
|
@@ -39,7 +40,7 @@ class TabsHostTabSelectedEvent(
|
|
|
39
40
|
private const val EK_PROVENANCE = "provenance"
|
|
40
41
|
private const val EK_IS_REPEATED = "isRepeated"
|
|
41
42
|
private const val EK_HAS_TRIGGERED_SPECIAL_EFFECT = "hasTriggeredSpecialEffect"
|
|
42
|
-
private const val
|
|
43
|
+
private const val EK_ACTION_ORIGIN = "actionOrigin"
|
|
43
44
|
|
|
44
45
|
override fun getEventName() = EVENT_NAME
|
|
45
46
|
|
|
@@ -4,7 +4,7 @@ import com.facebook.react.bridge.Arguments
|
|
|
4
4
|
import com.facebook.react.bridge.WritableMap
|
|
5
5
|
import com.facebook.react.uimanager.events.Event
|
|
6
6
|
import com.swmansion.rnscreens.gamma.common.event.NamingAwareEventType
|
|
7
|
-
import com.swmansion.rnscreens.gamma.tabs.container.
|
|
7
|
+
import com.swmansion.rnscreens.gamma.tabs.container.TabsNavigationState
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* React Native event dispatched to JS when a tab selection is prevented because the target
|
|
@@ -15,7 +15,7 @@ import com.swmansion.rnscreens.gamma.tabs.container.TabsNavState
|
|
|
15
15
|
class TabsHostTabSelectionPreventedEvent(
|
|
16
16
|
surfaceId: Int,
|
|
17
17
|
viewId: Int,
|
|
18
|
-
val currentNavState:
|
|
18
|
+
val currentNavState: TabsNavigationState,
|
|
19
19
|
val preventedScreenKey: String,
|
|
20
20
|
) : Event<TabsHostTabSelectionPreventedEvent>(surfaceId, viewId),
|
|
21
21
|
NamingAwareEventType {
|
|
@@ -27,7 +27,7 @@ class TabsHostTabSelectionPreventedEvent(
|
|
|
27
27
|
|
|
28
28
|
override fun getEventData(): WritableMap? =
|
|
29
29
|
Arguments.createMap().apply {
|
|
30
|
-
putString(EK_SELECTED_KEY, currentNavState.
|
|
30
|
+
putString(EK_SELECTED_KEY, currentNavState.selectedScreenKey)
|
|
31
31
|
putInt(EK_PROVENANCE, currentNavState.provenance)
|
|
32
32
|
putString(EK_PREVENTED_KEY, preventedScreenKey)
|
|
33
33
|
}
|
|
@@ -4,22 +4,23 @@ import com.facebook.react.bridge.Arguments
|
|
|
4
4
|
import com.facebook.react.bridge.WritableMap
|
|
5
5
|
import com.facebook.react.uimanager.events.Event
|
|
6
6
|
import com.swmansion.rnscreens.gamma.common.event.NamingAwareEventType
|
|
7
|
-
import com.swmansion.rnscreens.gamma.tabs.container.
|
|
8
|
-
import com.swmansion.rnscreens.gamma.tabs.container.
|
|
7
|
+
import com.swmansion.rnscreens.gamma.tabs.container.TabsNavigationState
|
|
8
|
+
import com.swmansion.rnscreens.gamma.tabs.container.TabsNavigationStateRejectionReason
|
|
9
|
+
import com.swmansion.rnscreens.gamma.tabs.container.TabsNavigationStateUpdateRequest
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* React Native event dispatched to JS when a tab selection request is rejected by the container.
|
|
12
13
|
*
|
|
13
|
-
* Carries the currently active navigation state ([currentNavState]), the rejected
|
|
14
|
-
* ([
|
|
14
|
+
* Carries the currently active navigation state ([currentNavState]), the rejected request
|
|
15
|
+
* ([rejectedRequest]), and the [rejectionReason]. This event is never coalesced — every
|
|
15
16
|
* rejection is delivered individually so the JS side has a complete picture of state transitions.
|
|
16
17
|
*/
|
|
17
18
|
class TabsHostTabSelectionRejectedEvent(
|
|
18
19
|
surfaceId: Int,
|
|
19
20
|
viewId: Int,
|
|
20
|
-
val currentNavState:
|
|
21
|
-
val
|
|
22
|
-
val rejectionReason:
|
|
21
|
+
val currentNavState: TabsNavigationState,
|
|
22
|
+
val rejectedRequest: TabsNavigationStateUpdateRequest,
|
|
23
|
+
val rejectionReason: TabsNavigationStateRejectionReason,
|
|
23
24
|
) : Event<TabsHostTabSelectionRejectedEvent>(surfaceId, viewId),
|
|
24
25
|
NamingAwareEventType {
|
|
25
26
|
override fun getEventName() = EVENT_NAME
|
|
@@ -31,10 +32,10 @@ class TabsHostTabSelectionRejectedEvent(
|
|
|
31
32
|
|
|
32
33
|
override fun getEventData(): WritableMap? =
|
|
33
34
|
Arguments.createMap().apply {
|
|
34
|
-
putString(EK_SELECTED_KEY, currentNavState.
|
|
35
|
+
putString(EK_SELECTED_KEY, currentNavState.selectedScreenKey)
|
|
35
36
|
putInt(EK_PROVENANCE, currentNavState.provenance)
|
|
36
|
-
putString(EK_REJECTED_KEY,
|
|
37
|
-
putInt(EK_REJECTED_PROVENANCE,
|
|
37
|
+
putString(EK_REJECTED_KEY, rejectedRequest.selectedScreenKey)
|
|
38
|
+
putInt(EK_REJECTED_PROVENANCE, rejectedRequest.baseProvenance)
|
|
38
39
|
putString(EK_REJECTION_REASON, rejectionReason.toString())
|
|
39
40
|
}
|
|
40
41
|
|
|
@@ -233,6 +233,25 @@ RNSOnTabSelectionRejectedRejectionReasonFromRNSTabsNavigationStateRejectionReaso
|
|
|
233
233
|
}
|
|
234
234
|
}
|
|
235
235
|
|
|
236
|
+
react::RNSTabsHostIOSEventEmitter::OnTabSelectedActionOrigin RNSOnTabSelectedActionOriginFromRNSTabsActionOrigin(
|
|
237
|
+
RNSTabsActionOrigin actionOrigin)
|
|
238
|
+
{
|
|
239
|
+
using enum facebook::react::RNSTabsHostIOSEventEmitter::OnTabSelectedActionOrigin;
|
|
240
|
+
switch (actionOrigin) {
|
|
241
|
+
case RNSTabsActionOriginUser:
|
|
242
|
+
return User;
|
|
243
|
+
case RNSTabsActionOriginProgrammaticJs:
|
|
244
|
+
return ProgrammaticJs;
|
|
245
|
+
case RNSTabsActionOriginProgrammaticNative:
|
|
246
|
+
return ProgrammaticNative;
|
|
247
|
+
case RNSTabsActionOriginImplicit:
|
|
248
|
+
return Implicit;
|
|
249
|
+
default:
|
|
250
|
+
RCTLogError(@"[RNScreens] Unexpected actionOrigin: %ld", actionOrigin);
|
|
251
|
+
}
|
|
252
|
+
return User;
|
|
253
|
+
}
|
|
254
|
+
|
|
236
255
|
RNSTabsIconType RNSTabsIconTypeFromIcon(react::RNSTabsScreenIOSIconType iconType)
|
|
237
256
|
{
|
|
238
257
|
using enum facebook::react::RNSTabsScreenIOSIconType;
|
|
@@ -63,6 +63,9 @@ react::RNSTabsHostIOSEventEmitter::OnTabSelectionRejectedRejectionReason
|
|
|
63
63
|
RNSOnTabSelectionRejectedRejectionReasonFromRNSTabsNavigationStateRejectionReason(
|
|
64
64
|
RNSTabsNavigationStateRejectionReason reason);
|
|
65
65
|
|
|
66
|
+
react::RNSTabsHostIOSEventEmitter::OnTabSelectedActionOrigin RNSOnTabSelectedActionOriginFromRNSTabsActionOrigin(
|
|
67
|
+
RNSTabsActionOrigin actionOrigin);
|
|
68
|
+
|
|
66
69
|
RNSTabsIconType RNSTabsIconTypeFromIcon(react::RNSTabsScreenIOSIconType iconType);
|
|
67
70
|
|
|
68
71
|
RNSTabsScreenSystemItem RNSTabsScreenSystemItemFromReactRNSTabsScreenSystemItem(
|
|
@@ -8,8 +8,11 @@
|
|
|
8
8
|
|
|
9
9
|
namespace react = facebook::react;
|
|
10
10
|
|
|
11
|
+
static void *RNSTabsBottomAccessoryNativeWrapperViewContext = &RNSTabsBottomAccessoryNativeWrapperViewContext;
|
|
12
|
+
|
|
11
13
|
@implementation RNSTabsBottomAccessoryHelper {
|
|
12
14
|
RNSTabsBottomAccessoryComponentView *__weak _bottomAccessoryView;
|
|
15
|
+
UIView *__weak _observedNativeWrapperView;
|
|
13
16
|
|
|
14
17
|
#if REACT_NATIVE_VERSION_MINOR < 82
|
|
15
18
|
BOOL _initialStateUpdateSent;
|
|
@@ -35,6 +38,7 @@ namespace react = facebook::react;
|
|
|
35
38
|
|
|
36
39
|
- (void)initState
|
|
37
40
|
{
|
|
41
|
+
_observedNativeWrapperView = nil;
|
|
38
42
|
#if REACT_NATIVE_VERSION_MINOR < 82
|
|
39
43
|
_initialStateUpdateSent = NO;
|
|
40
44
|
_displayLink = nil;
|
|
@@ -110,9 +114,32 @@ namespace react = facebook::react;
|
|
|
110
114
|
|
|
111
115
|
#pragma mark - Observing frame changes
|
|
112
116
|
|
|
117
|
+
- (void)unregisterForAccessoryFrameChanges
|
|
118
|
+
{
|
|
119
|
+
UIView *observedNativeWrapperView = _observedNativeWrapperView;
|
|
120
|
+
if (observedNativeWrapperView == nil) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
[observedNativeWrapperView removeObserver:self
|
|
125
|
+
forKeyPath:@"center"
|
|
126
|
+
context:RNSTabsBottomAccessoryNativeWrapperViewContext];
|
|
127
|
+
_observedNativeWrapperView = nil;
|
|
128
|
+
}
|
|
129
|
+
|
|
113
130
|
- (void)registerForAccessoryFrameChanges
|
|
114
131
|
{
|
|
115
|
-
|
|
132
|
+
UIView *nativeWrapperView = self.nativeWrapperView;
|
|
133
|
+
if (_observedNativeWrapperView == nativeWrapperView) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
[self unregisterForAccessoryFrameChanges];
|
|
138
|
+
[nativeWrapperView addObserver:self
|
|
139
|
+
forKeyPath:@"center"
|
|
140
|
+
options:NSKeyValueObservingOptionInitial
|
|
141
|
+
context:RNSTabsBottomAccessoryNativeWrapperViewContext];
|
|
142
|
+
_observedNativeWrapperView = nativeWrapperView;
|
|
116
143
|
}
|
|
117
144
|
|
|
118
145
|
- (void)observeValueForKeyPath:(NSString *)keyPath
|
|
@@ -120,7 +147,11 @@ namespace react = facebook::react;
|
|
|
120
147
|
change:(NSDictionary *)change
|
|
121
148
|
context:(void *)context
|
|
122
149
|
{
|
|
123
|
-
|
|
150
|
+
if (context == RNSTabsBottomAccessoryNativeWrapperViewContext) {
|
|
151
|
+
[self notifyWrapperViewFrameHasChanged];
|
|
152
|
+
} else {
|
|
153
|
+
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
|
|
154
|
+
}
|
|
124
155
|
}
|
|
125
156
|
|
|
126
157
|
- (UIView *)nativeWrapperView
|
|
@@ -192,9 +223,7 @@ namespace react = facebook::react;
|
|
|
192
223
|
{
|
|
193
224
|
[_bottomAccessoryView unregisterForTraitChanges:_traitChangeRegistration];
|
|
194
225
|
_traitChangeRegistration = nil;
|
|
195
|
-
|
|
196
|
-
// If we're called from didMoveToWindow, it's not a problem, but I'm not sure if this will always be the case.
|
|
197
|
-
[_bottomAccessoryView.superview.superview removeObserver:self forKeyPath:@"center"];
|
|
226
|
+
[self unregisterForAccessoryFrameChanges];
|
|
198
227
|
_bottomAccessoryView = nil;
|
|
199
228
|
#if REACT_NATIVE_VERSION_MINOR < 82
|
|
200
229
|
[self invalidateDisplayLink];
|