react-native-screens 3.14.0 → 3.16.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.
- package/README.md +34 -1
- package/RNScreens.podspec +1 -4
- package/android/build.gradle +1 -1
- package/android/src/main/java/com/swmansion/rnscreens/Screen.kt +0 -5
- package/android/src/main/java/com/swmansion/rnscreens/ScreenContainer.kt +50 -21
- package/android/src/main/java/com/swmansion/rnscreens/ScreenFragment.kt +22 -21
- package/android/src/main/java/com/swmansion/rnscreens/ScreenStack.kt +7 -5
- package/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfig.kt +1 -2
- package/android/src/main/java/com/swmansion/rnscreens/ScreenStackViewManager.kt +9 -0
- package/android/src/main/java/com/swmansion/rnscreens/ScreenViewManager.kt +3 -6
- package/android/src/main/java/com/swmansion/rnscreens/ScreenWindowTraits.kt +4 -4
- package/android/src/paper/java/com/swmansion/rnscreens/FabricEnabledViewGroup.kt +4 -10
- package/ios/RNSScreen.h +1 -0
- package/ios/RNSScreen.mm +29 -10
- package/ios/RNSScreenStack.mm +61 -18
- package/ios/RNSScreenStackHeaderConfig.mm +2 -2
- package/ios/RNSScreenStackHeaderSubview.h +1 -1
- package/lib/commonjs/fabric/ScreenNativeComponent.js.map +1 -1
- package/lib/commonjs/index.js +4 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/index.native.js +60 -53
- package/lib/commonjs/index.native.js.map +1 -1
- package/lib/commonjs/native-stack/views/NativeStackView.js +3 -27
- package/lib/commonjs/native-stack/views/NativeStackView.js.map +1 -1
- package/lib/commonjs/reanimated/ReanimatedNativeStackScreen.js +4 -2
- package/lib/commonjs/reanimated/ReanimatedNativeStackScreen.js.map +1 -1
- package/lib/commonjs/reanimated/ReanimatedScreen.js +1 -1
- package/lib/commonjs/reanimated/ReanimatedScreen.js.map +1 -1
- package/lib/module/fabric/ScreenNativeComponent.js.map +1 -1
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.native.js +61 -53
- package/lib/module/index.native.js.map +1 -1
- package/lib/module/native-stack/views/NativeStackView.js +3 -27
- package/lib/module/native-stack/views/NativeStackView.js.map +1 -1
- package/lib/module/reanimated/ReanimatedNativeStackScreen.js +5 -3
- package/lib/module/reanimated/ReanimatedNativeStackScreen.js.map +1 -1
- package/lib/module/reanimated/ReanimatedScreen.js +2 -2
- package/lib/module/reanimated/ReanimatedScreen.js.map +1 -1
- package/lib/typescript/index.d.ts +1 -0
- package/lib/typescript/native-stack/types.d.ts +5 -0
- package/lib/typescript/reanimated/ReanimatedNativeStackScreen.d.ts +1 -1
- package/lib/typescript/reanimated/ReanimatedScreen.d.ts +1 -1
- package/lib/typescript/types.d.ts +5 -0
- package/native-stack/README.md +6 -0
- package/package.json +1 -1
- package/src/fabric/ScreenNativeComponent.js +1 -1
- package/src/index.native.tsx +56 -56
- package/src/index.tsx +2 -0
- package/src/native-stack/types.tsx +5 -0
- package/src/native-stack/views/NativeStackView.tsx +2 -23
- package/src/reanimated/ReanimatedNativeStackScreen.tsx +5 -3
- package/src/reanimated/ReanimatedScreen.tsx +2 -2
- package/src/types.tsx +5 -0
- package/lib/commonjs/fabric/FullWindowOverlay.js +0 -26
- package/lib/commonjs/fabric/FullWindowOverlay.js.map +0 -1
- package/lib/commonjs/fabric/Screen.js +0 -29
- package/lib/commonjs/fabric/Screen.js.map +0 -1
- package/lib/commonjs/fabric/ScreenContainer.js +0 -28
- package/lib/commonjs/fabric/ScreenContainer.js.map +0 -1
- package/lib/commonjs/fabric/ScreenNavigationContainer.js +0 -28
- package/lib/commonjs/fabric/ScreenNavigationContainer.js.map +0 -1
- package/lib/commonjs/fabric/ScreenStack.js +0 -26
- package/lib/commonjs/fabric/ScreenStack.js.map +0 -1
- package/lib/commonjs/fabric/ScreenStackHeaderSubview.js +0 -37
- package/lib/commonjs/fabric/ScreenStackHeaderSubview.js.map +0 -1
- package/lib/commonjs/fabric/SearchBar.js +0 -37
- package/lib/commonjs/fabric/SearchBar.js.map +0 -1
- package/lib/commonjs/fabric/index.js +0 -72
- package/lib/commonjs/fabric/index.js.map +0 -1
- package/lib/module/fabric/FullWindowOverlay.js +0 -15
- package/lib/module/fabric/FullWindowOverlay.js.map +0 -1
- package/lib/module/fabric/Screen.js +0 -16
- package/lib/module/fabric/Screen.js.map +0 -1
- package/lib/module/fabric/ScreenContainer.js +0 -17
- package/lib/module/fabric/ScreenContainer.js.map +0 -1
- package/lib/module/fabric/ScreenNavigationContainer.js +0 -17
- package/lib/module/fabric/ScreenNavigationContainer.js.map +0 -1
- package/lib/module/fabric/ScreenStack.js +0 -15
- package/lib/module/fabric/ScreenStack.js.map +0 -1
- package/lib/module/fabric/ScreenStackHeaderSubview.js +0 -24
- package/lib/module/fabric/ScreenStackHeaderSubview.js.map +0 -1
- package/lib/module/fabric/SearchBar.js +0 -24
- package/lib/module/fabric/SearchBar.js.map +0 -1
- package/lib/module/fabric/index.js +0 -10
- package/lib/module/fabric/index.js.map +0 -1
- package/src/fabric/FullWindowOverlay.js +0 -13
- package/src/fabric/Screen.js +0 -15
- package/src/fabric/ScreenContainer.js +0 -16
- package/src/fabric/ScreenNavigationContainer.js +0 -16
- package/src/fabric/ScreenStack.js +0 -10
- package/src/fabric/ScreenStackHeaderSubview.js +0 -22
- package/src/fabric/SearchBar.js +0 -20
- package/src/fabric/index.js +0 -19
package/README.md
CHANGED
|
@@ -18,7 +18,31 @@ To learn about how to use `react-native-screens` with Fabric architecture, head
|
|
|
18
18
|
|
|
19
19
|
### iOS
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
On iOS obtaining current device orientation [requires asking the system to generate orientation notifications](https://developer.apple.com/documentation/uikit/uidevice/1620053-orientation?language=objc). Our library uses them to enforce correct interface orientation when navigating between screens.
|
|
22
|
+
To make sure that there are no issues with screen orientation you should put following code in your `AppDelegate.m`:
|
|
23
|
+
|
|
24
|
+
```objective-c
|
|
25
|
+
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
|
26
|
+
{
|
|
27
|
+
...
|
|
28
|
+
#if !TARGET_OS_TV
|
|
29
|
+
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
|
|
30
|
+
#endif // !TARGET_OS_TV
|
|
31
|
+
...
|
|
32
|
+
return YES:
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
- (void)applicationWillTerminate:(UIApplication *)application
|
|
36
|
+
{
|
|
37
|
+
#if !TARGET_OS_TV
|
|
38
|
+
[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
|
|
39
|
+
#endif // !TARGET_OS_TV
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
You can see example of these changes being introduced in our [example applications](https://github.com/software-mansion/react-native-screens/blob/main/TestsExample/ios/TestsExample/AppDelegate.mm).
|
|
44
|
+
|
|
45
|
+
Other aspects of installation should be completely handled with auto-linking, just ensure you installed pods after adding this module.
|
|
22
46
|
|
|
23
47
|
### Android
|
|
24
48
|
|
|
@@ -71,9 +95,18 @@ Screens are already integrated with the React Native's most popular navigation l
|
|
|
71
95
|
|
|
72
96
|
| version | react-native version |
|
|
73
97
|
| ------- | -------------------- |
|
|
98
|
+
| 3.14.0+ | 0.64.0+ |
|
|
74
99
|
| 3.0.0+ | 0.62.0+ |
|
|
75
100
|
| 2.0.0+ | 0.60.0+ |
|
|
76
101
|
|
|
102
|
+
### Support for Fabric
|
|
103
|
+
[Fabric](https://reactnative.dev/architecture/fabric-renderer) is React Native's new rendering system. As of [version `3.14.0`](https://github.com/software-mansion/react-native-screens/releases/tag/3.14.0) of this project, Fabric is supported only for react-native 0.69+. Support for `0.68.x` has been dropped.
|
|
104
|
+
|
|
105
|
+
| version | react-native version |
|
|
106
|
+
| ------- | -------------------- |
|
|
107
|
+
| 3.14.0+ | 0.69.0+ |
|
|
108
|
+
|
|
109
|
+
|
|
77
110
|
## Usage with [react-navigation](https://github.com/react-navigation/react-navigation)
|
|
78
111
|
|
|
79
112
|
Screens support is built into [react-navigation](https://github.com/react-navigation/react-navigation) starting from version [2.14.0](https://github.com/react-navigation/react-navigation/releases/tag/2.14.0) for all the different navigator types (stack, tab, drawer, etc).
|
package/RNScreens.podspec
CHANGED
|
@@ -4,9 +4,6 @@ package = JSON.parse(File.read(File.join(__dir__, "package.json")))
|
|
|
4
4
|
|
|
5
5
|
fabric_enabled = ENV['RCT_NEW_ARCH_ENABLED'] == '1'
|
|
6
6
|
|
|
7
|
-
# folly_version must match the version used in React Native
|
|
8
|
-
# See folly_version in react-native/React/FBReactNativeSpec/FBReactNativeSpec.podspec
|
|
9
|
-
folly_version = '2021.06.28.00-v2'
|
|
10
7
|
folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'
|
|
11
8
|
|
|
12
9
|
Pod::Spec.new do |s|
|
|
@@ -36,7 +33,7 @@ Pod::Spec.new do |s|
|
|
|
36
33
|
s.dependency "React"
|
|
37
34
|
s.dependency "React-RCTFabric"
|
|
38
35
|
s.dependency "React-Codegen"
|
|
39
|
-
s.dependency "RCT-Folly"
|
|
36
|
+
s.dependency "RCT-Folly"
|
|
40
37
|
s.dependency "RCTRequired"
|
|
41
38
|
s.dependency "RCTTypeSafety"
|
|
42
39
|
s.dependency "ReactCommon/turbomodule/core"
|
package/android/build.gradle
CHANGED
|
@@ -8,13 +8,8 @@ import android.util.SparseArray
|
|
|
8
8
|
import android.view.ViewGroup
|
|
9
9
|
import android.view.WindowManager
|
|
10
10
|
import android.webkit.WebView
|
|
11
|
-
import androidx.annotation.UiThread
|
|
12
11
|
import com.facebook.react.bridge.GuardedRunnable
|
|
13
12
|
import com.facebook.react.bridge.ReactContext
|
|
14
|
-
import com.facebook.react.bridge.ReadableMap
|
|
15
|
-
import com.facebook.react.bridge.WritableMap
|
|
16
|
-
import com.facebook.react.bridge.WritableNativeMap
|
|
17
|
-
import com.facebook.react.uimanager.PixelUtil
|
|
18
13
|
import com.facebook.react.uimanager.UIManagerModule
|
|
19
14
|
|
|
20
15
|
@SuppressLint("ViewConstructor")
|
|
@@ -135,6 +135,41 @@ open class ScreenContainer<T : ScreenFragment>(context: Context?) : ViewGroup(co
|
|
|
135
135
|
performUpdatesNow()
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
+
private fun findFragmentManagerForReactRootView(rootView: ReactRootView): FragmentManager {
|
|
139
|
+
var context = rootView.context
|
|
140
|
+
|
|
141
|
+
// ReactRootView is expected to be initialized with the main React Activity as a context but
|
|
142
|
+
// in case of Expo the activity is wrapped in ContextWrapper and we need to unwrap it
|
|
143
|
+
while (context !is FragmentActivity && context is ContextWrapper) {
|
|
144
|
+
context = context.baseContext
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
check(context is FragmentActivity) {
|
|
148
|
+
"In order to use RNScreens components your app's activity need to extend ReactActivity"
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// In case React Native is loaded on a Fragment (not directly in activity) we need to find
|
|
152
|
+
// fragment manager whose fragment's view is ReactRootView. As of now, we detect such case by
|
|
153
|
+
// checking whether any fragments are attached to activity which hosts ReactRootView.
|
|
154
|
+
// See: https://github.com/software-mansion/react-native-screens/issues/1506 on why the cases
|
|
155
|
+
// must be treated separately.
|
|
156
|
+
return if (context.supportFragmentManager.fragments.isEmpty()) {
|
|
157
|
+
// We are in standard React Native application w/o custom native navigation based on fragments.
|
|
158
|
+
context.supportFragmentManager
|
|
159
|
+
} else {
|
|
160
|
+
// We are in some custom setup & we want to use the closest fragment manager in hierarchy.
|
|
161
|
+
// `findFragment` method throws IllegalStateException when it fails to resolve appropriate
|
|
162
|
+
// fragment. It might happen when e.g. React Native is loaded directly in Activity
|
|
163
|
+
// but some custom fragments are still used. Such use case seems highly unlikely
|
|
164
|
+
// so, as for now we let application crash.
|
|
165
|
+
try {
|
|
166
|
+
FragmentManager.findFragment<Fragment>(rootView).childFragmentManager
|
|
167
|
+
} catch (ex: IllegalStateException) {
|
|
168
|
+
throw IllegalStateException("Failed to find fragment for React Root View")
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
138
173
|
private fun setupFragmentManager() {
|
|
139
174
|
var parent: ViewParent = this
|
|
140
175
|
// We traverse view hierarchy up until we find screen parent or a root view
|
|
@@ -146,28 +181,22 @@ open class ScreenContainer<T : ScreenFragment>(context: Context?) : ViewGroup(co
|
|
|
146
181
|
// If parent is of type Screen it means we are inside a nested fragment structure.
|
|
147
182
|
// Otherwise we expect to connect directly with root view and get root fragment manager
|
|
148
183
|
if (parent is Screen) {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
// in case of Expo the activity is wrapped in ContextWrapper and we need to unwrap it
|
|
165
|
-
var context = parent.context
|
|
166
|
-
while (context !is FragmentActivity && context is ContextWrapper) {
|
|
167
|
-
context = context.baseContext
|
|
184
|
+
checkNotNull(
|
|
185
|
+
parent.fragment?.let { screenFragment ->
|
|
186
|
+
mParentScreenFragment = screenFragment
|
|
187
|
+
screenFragment.registerChildScreenContainer(this)
|
|
188
|
+
setFragmentManager(screenFragment.childFragmentManager)
|
|
189
|
+
}
|
|
190
|
+
) { "Parent Screen does not have its Fragment attached" }
|
|
191
|
+
} else {
|
|
192
|
+
// we expect top level view to be of type ReactRootView, this isn't really necessary but in
|
|
193
|
+
// order to find root view we test if parent is null. This could potentially happen also when
|
|
194
|
+
// the view is detached from the hierarchy and that test would not correctly indicate the root
|
|
195
|
+
// view. So in order to make sure we indeed reached the root we test if it is of a correct type.
|
|
196
|
+
// This allows us to provide a more descriptive error message for the aforementioned case.
|
|
197
|
+
check(parent is ReactRootView) { "ScreenContainer is not attached under ReactRootView" }
|
|
198
|
+
setFragmentManager(findFragmentManagerForReactRootView(parent))
|
|
168
199
|
}
|
|
169
|
-
check(context is FragmentActivity) { "In order to use RNScreens components your app's activity need to extend ReactActivity" }
|
|
170
|
-
setFragmentManager(context.supportFragmentManager)
|
|
171
200
|
}
|
|
172
201
|
|
|
173
202
|
protected fun createTransaction(): FragmentTransaction {
|
|
@@ -12,8 +12,9 @@ import android.widget.FrameLayout
|
|
|
12
12
|
import androidx.fragment.app.Fragment
|
|
13
13
|
import com.facebook.react.bridge.ReactContext
|
|
14
14
|
import com.facebook.react.bridge.UiThreadUtil
|
|
15
|
-
import com.facebook.react.uimanager.
|
|
15
|
+
import com.facebook.react.uimanager.UIManagerHelper
|
|
16
16
|
import com.facebook.react.uimanager.events.Event
|
|
17
|
+
import com.facebook.react.uimanager.events.EventDispatcher
|
|
17
18
|
import com.swmansion.rnscreens.events.HeaderBackButtonClickedEvent
|
|
18
19
|
import com.swmansion.rnscreens.events.ScreenAppearEvent
|
|
19
20
|
import com.swmansion.rnscreens.events.ScreenDisappearEvent
|
|
@@ -204,10 +205,10 @@ open class ScreenFragment : Fragment {
|
|
|
204
205
|
ScreenLifecycleEvent.WillDisappear -> ScreenWillDisappearEvent(it.id)
|
|
205
206
|
ScreenLifecycleEvent.Disappear -> ScreenDisappearEvent(it.id)
|
|
206
207
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
208
|
+
val screenContext = screen.context as ReactContext
|
|
209
|
+
val eventDispatcher: EventDispatcher? =
|
|
210
|
+
UIManagerHelper.getEventDispatcherForReactTag(screenContext, screen.id)
|
|
211
|
+
eventDispatcher?.dispatchEvent(lifecycleEvent)
|
|
211
212
|
fragment.dispatchEventInChildContainers(event)
|
|
212
213
|
}
|
|
213
214
|
}
|
|
@@ -224,10 +225,10 @@ open class ScreenFragment : Fragment {
|
|
|
224
225
|
}
|
|
225
226
|
|
|
226
227
|
fun dispatchHeaderBackButtonClickedEvent() {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
228
|
+
val screenContext = screen.context as ReactContext
|
|
229
|
+
val eventDispatcher: EventDispatcher? =
|
|
230
|
+
UIManagerHelper.getEventDispatcherForReactTag(screenContext, screen.id)
|
|
231
|
+
eventDispatcher?.dispatchEvent(HeaderBackButtonClickedEvent(screen.id))
|
|
231
232
|
}
|
|
232
233
|
|
|
233
234
|
fun dispatchTransitionProgress(alpha: Float, closing: Boolean) {
|
|
@@ -242,14 +243,14 @@ open class ScreenFragment : Fragment {
|
|
|
242
243
|
val coalescingKey = (if (mProgress == 0.0f) 1 else if (mProgress == 1.0f) 2 else 3).toShort()
|
|
243
244
|
val container: ScreenContainer<*>? = screen.container
|
|
244
245
|
val goingForward = if (container is ScreenStack) container.goingForward else false
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
)
|
|
246
|
+
val screenContext = screen.context as ReactContext
|
|
247
|
+
val eventDispatcher: EventDispatcher? =
|
|
248
|
+
UIManagerHelper.getEventDispatcherForReactTag(screenContext, screen.id)
|
|
249
|
+
eventDispatcher?.dispatchEvent(
|
|
250
|
+
ScreenTransitionProgressEvent(
|
|
251
|
+
screen.id, mProgress, closing, goingForward, coalescingKey
|
|
252
252
|
)
|
|
253
|
+
)
|
|
253
254
|
}
|
|
254
255
|
}
|
|
255
256
|
}
|
|
@@ -302,11 +303,11 @@ open class ScreenFragment : Fragment {
|
|
|
302
303
|
val container = screen.container
|
|
303
304
|
if (container == null || !container.hasScreen(this)) {
|
|
304
305
|
// we only send dismissed even when the screen has been removed from its container
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
306
|
+
val screenContext = screen.context
|
|
307
|
+
if (screenContext is ReactContext) {
|
|
308
|
+
val eventDispatcher: EventDispatcher? =
|
|
309
|
+
UIManagerHelper.getEventDispatcherForReactTag(screenContext, screen.id)
|
|
310
|
+
eventDispatcher?.dispatchEvent(ScreenDismissedEvent(screen.id))
|
|
310
311
|
}
|
|
311
312
|
}
|
|
312
313
|
mChildScreenContainers.clear()
|
|
@@ -4,7 +4,8 @@ import android.content.Context
|
|
|
4
4
|
import android.graphics.Canvas
|
|
5
5
|
import android.view.View
|
|
6
6
|
import com.facebook.react.bridge.ReactContext
|
|
7
|
-
import com.facebook.react.uimanager.
|
|
7
|
+
import com.facebook.react.uimanager.UIManagerHelper
|
|
8
|
+
import com.facebook.react.uimanager.events.EventDispatcher
|
|
8
9
|
import com.swmansion.rnscreens.Screen.StackAnimation
|
|
9
10
|
import com.swmansion.rnscreens.events.StackFinishTransitioningEvent
|
|
10
11
|
import java.util.Collections
|
|
@@ -67,10 +68,11 @@ class ScreenStack(context: Context?) : ScreenContainer<ScreenStackFragment>(cont
|
|
|
67
68
|
}
|
|
68
69
|
|
|
69
70
|
private fun dispatchOnFinishTransitioning() {
|
|
70
|
-
|
|
71
|
-
.
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
val eventDispatcher: EventDispatcher? =
|
|
72
|
+
UIManagerHelper.getEventDispatcherForReactTag((context as ReactContext), id)
|
|
73
|
+
eventDispatcher?.dispatchEvent(
|
|
74
|
+
StackFinishTransitioningEvent(id)
|
|
75
|
+
)
|
|
74
76
|
}
|
|
75
77
|
|
|
76
78
|
override fun removeScreenAt(index: Int) {
|
|
@@ -130,7 +130,6 @@ class ScreenStackHeaderConfig(context: Context) : ViewGroup(context) {
|
|
|
130
130
|
return null
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
-
@SuppressLint("ObsoleteSdkInt") // to be removed when support for < 0.64 is dropped
|
|
134
133
|
fun onUpdate() {
|
|
135
134
|
val stack = screenStack
|
|
136
135
|
val isTop = stack == null || stack.topScreen == parent
|
|
@@ -138,7 +137,7 @@ class ScreenStackHeaderConfig(context: Context) : ViewGroup(context) {
|
|
|
138
137
|
return
|
|
139
138
|
}
|
|
140
139
|
val activity = screenFragment?.activity as AppCompatActivity? ?: return
|
|
141
|
-
if (
|
|
140
|
+
if (mDirection != null) {
|
|
142
141
|
if (mDirection == "rtl") {
|
|
143
142
|
toolbar.layoutDirection = LAYOUT_DIRECTION_RTL
|
|
144
143
|
} else if (mDirection == "ltr") {
|
|
@@ -3,6 +3,7 @@ package com.swmansion.rnscreens
|
|
|
3
3
|
import android.view.View
|
|
4
4
|
import android.view.ViewGroup
|
|
5
5
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
|
+
import com.facebook.react.common.MapBuilder
|
|
6
7
|
import com.facebook.react.module.annotations.ReactModule
|
|
7
8
|
import com.facebook.react.uimanager.LayoutShadowNode
|
|
8
9
|
import com.facebook.react.uimanager.ThemedReactContext
|
|
@@ -10,6 +11,7 @@ import com.facebook.react.uimanager.ViewGroupManager
|
|
|
10
11
|
import com.facebook.react.uimanager.ViewManagerDelegate
|
|
11
12
|
import com.facebook.react.viewmanagers.RNSScreenStackManagerDelegate
|
|
12
13
|
import com.facebook.react.viewmanagers.RNSScreenStackManagerInterface
|
|
14
|
+
import com.swmansion.rnscreens.events.StackFinishTransitioningEvent
|
|
13
15
|
|
|
14
16
|
@ReactModule(name = ScreenStackViewManager.REACT_CLASS)
|
|
15
17
|
class ScreenStackViewManager : ViewGroupManager<ScreenStack>(), RNSScreenStackManagerInterface<ScreenStack> {
|
|
@@ -81,6 +83,13 @@ class ScreenStackViewManager : ViewGroupManager<ScreenStack>(), RNSScreenStackMa
|
|
|
81
83
|
return mDelegate
|
|
82
84
|
}
|
|
83
85
|
|
|
86
|
+
override fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any> {
|
|
87
|
+
return MapBuilder.of(
|
|
88
|
+
StackFinishTransitioningEvent.EVENT_NAME,
|
|
89
|
+
MapBuilder.of("registrationName", "onFinishTransitioning"),
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
|
|
84
93
|
companion object {
|
|
85
94
|
const val REACT_CLASS = "RNSScreenStack"
|
|
86
95
|
}
|
|
@@ -162,7 +162,7 @@ class ScreenViewManager : ViewGroupManager<Screen>(), RNSScreenManagerInterface<
|
|
|
162
162
|
override fun setSwipeDirection(view: Screen?, value: String?) = Unit
|
|
163
163
|
|
|
164
164
|
override fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any> {
|
|
165
|
-
|
|
165
|
+
return MapBuilder.of(
|
|
166
166
|
ScreenDismissedEvent.EVENT_NAME,
|
|
167
167
|
MapBuilder.of("registrationName", "onDismissed"),
|
|
168
168
|
ScreenWillAppearEvent.EVENT_NAME,
|
|
@@ -173,14 +173,11 @@ class ScreenViewManager : ViewGroupManager<Screen>(), RNSScreenManagerInterface<
|
|
|
173
173
|
MapBuilder.of("registrationName", "onWillDisappear"),
|
|
174
174
|
ScreenDisappearEvent.EVENT_NAME,
|
|
175
175
|
MapBuilder.of("registrationName", "onDisappear"),
|
|
176
|
-
|
|
177
|
-
MapBuilder.of("registrationName", "
|
|
176
|
+
HeaderBackButtonClickedEvent.EVENT_NAME,
|
|
177
|
+
MapBuilder.of("registrationName", "onHeaderBackButtonClicked"),
|
|
178
178
|
ScreenTransitionProgressEvent.EVENT_NAME,
|
|
179
179
|
MapBuilder.of("registrationName", "onTransitionProgress")
|
|
180
180
|
)
|
|
181
|
-
// there is no `MapBuilder.of` with more than 7 items
|
|
182
|
-
map[HeaderBackButtonClickedEvent.EVENT_NAME] = MapBuilder.of("registrationName", "onHeaderBackButtonClicked")
|
|
183
|
-
return map
|
|
184
181
|
}
|
|
185
182
|
|
|
186
183
|
protected override fun getDelegate(): ViewManagerDelegate<Screen> {
|
|
@@ -48,7 +48,7 @@ object ScreenWindowTraits {
|
|
|
48
48
|
|
|
49
49
|
@SuppressLint("ObsoleteSdkInt") // to be removed when support for < 0.64 is dropped
|
|
50
50
|
internal fun setColor(screen: Screen, activity: Activity?, context: ReactContext?) {
|
|
51
|
-
if (activity == null || context == null
|
|
51
|
+
if (activity == null || context == null) {
|
|
52
52
|
return
|
|
53
53
|
}
|
|
54
54
|
if (mDefaultStatusBarColor == null) {
|
|
@@ -112,8 +112,8 @@ object ScreenWindowTraits {
|
|
|
112
112
|
// and consume all the top insets so no padding will be added under the status bar.
|
|
113
113
|
val decorView = activity.window.decorView
|
|
114
114
|
if (translucent) {
|
|
115
|
-
|
|
116
|
-
val defaultInsets =
|
|
115
|
+
ViewCompat.setOnApplyWindowInsetsListener(decorView) { v, insets ->
|
|
116
|
+
val defaultInsets = ViewCompat.onApplyWindowInsets(v, insets)
|
|
117
117
|
defaultInsets.replaceSystemWindowInsets(
|
|
118
118
|
defaultInsets.systemWindowInsetLeft,
|
|
119
119
|
0,
|
|
@@ -122,7 +122,7 @@ object ScreenWindowTraits {
|
|
|
122
122
|
)
|
|
123
123
|
}
|
|
124
124
|
} else {
|
|
125
|
-
|
|
125
|
+
ViewCompat.setOnApplyWindowInsetsListener(decorView, null)
|
|
126
126
|
}
|
|
127
127
|
ViewCompat.requestApplyInsets(decorView)
|
|
128
128
|
}
|
|
@@ -2,15 +2,9 @@ package com.swmansion.rnscreens
|
|
|
2
2
|
|
|
3
3
|
import android.view.ViewGroup
|
|
4
4
|
import com.facebook.react.bridge.ReactContext
|
|
5
|
-
import androidx.annotation.UiThread
|
|
6
|
-
import com.facebook.react.uimanager.PixelUtil
|
|
7
|
-
import com.facebook.react.bridge.ReadableMap
|
|
8
|
-
import com.facebook.react.bridge.WritableMap
|
|
9
|
-
import com.facebook.react.bridge.WritableNativeMap
|
|
10
|
-
import kotlin.math.abs
|
|
11
5
|
|
|
12
6
|
abstract class FabricEnabledViewGroup constructor(context: ReactContext?) : ViewGroup(context) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
7
|
+
protected fun updateScreenSizeFabric(width: Int, height: Int) {
|
|
8
|
+
// do nothing
|
|
9
|
+
}
|
|
10
|
+
}
|
package/ios/RNSScreen.h
CHANGED
package/ios/RNSScreen.mm
CHANGED
|
@@ -508,6 +508,11 @@
|
|
|
508
508
|
}
|
|
509
509
|
}
|
|
510
510
|
|
|
511
|
+
- (BOOL)isModal
|
|
512
|
+
{
|
|
513
|
+
return self.stackPresentation != RNSScreenStackPresentationPush;
|
|
514
|
+
}
|
|
515
|
+
|
|
511
516
|
#pragma mark - Fabric specific
|
|
512
517
|
#ifdef RN_FABRIC_ENABLED
|
|
513
518
|
|
|
@@ -545,6 +550,17 @@
|
|
|
545
550
|
_dismissed = NO;
|
|
546
551
|
_state.reset();
|
|
547
552
|
_touchHandler = nil;
|
|
553
|
+
|
|
554
|
+
// We set this prop to default value here to workaround view-recycling.
|
|
555
|
+
// Let's assume the view has had _stackPresentation == <some modal stack presentation> set
|
|
556
|
+
// before below line was executed. Then, when instantiated again (with the same modal presentation)
|
|
557
|
+
// updateProps:oldProps: method would be called and setter for stack presentation would not be called.
|
|
558
|
+
// This is crucial as in that setter we register `self.controller` as a delegate
|
|
559
|
+
// (UIAdaptivePresentationControllerDelegate) to presentation controller and this leads to buggy modal behaviour as we
|
|
560
|
+
// rely on UIAdaptivePresentationControllerDelegate callbacks. Restoring the default value and then comparing against
|
|
561
|
+
// it in updateProps:oldProps: allows for setter to be called, however if there was some additional logic to execute
|
|
562
|
+
// when stackPresentation is set to "push" the setter would not be triggered.
|
|
563
|
+
_stackPresentation = RNSScreenStackPresentationPush;
|
|
548
564
|
}
|
|
549
565
|
|
|
550
566
|
- (void)updateProps:(facebook::react::Props::Shared const &)props
|
|
@@ -598,9 +614,12 @@
|
|
|
598
614
|
}
|
|
599
615
|
#endif
|
|
600
616
|
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
617
|
+
// Notice that we compare against _stackPresentation, not oldScreenProps.stackPresentation.
|
|
618
|
+
// See comment in prepareForRecycle method for explanation.
|
|
619
|
+
RNSScreenStackPresentation newStackPresentation =
|
|
620
|
+
[RNSConvert RNSScreenStackPresentationFromCppEquivalent:newScreenProps.stackPresentation];
|
|
621
|
+
if (newStackPresentation != _stackPresentation) {
|
|
622
|
+
[self setStackPresentation:newStackPresentation];
|
|
604
623
|
}
|
|
605
624
|
|
|
606
625
|
if (newScreenProps.stackAnimation != oldScreenProps.stackAnimation) {
|
|
@@ -739,7 +758,8 @@ Class<RCTComponentViewProtocol> RNSScreenCls(void)
|
|
|
739
758
|
- (void)viewWillDisappear:(BOOL)animated
|
|
740
759
|
{
|
|
741
760
|
[super viewWillDisappear:animated];
|
|
742
|
-
|
|
761
|
+
// self.navigationController might be null when we are dismissing a modal
|
|
762
|
+
if (!self.transitionCoordinator.isInteractive && self.navigationController != nil) {
|
|
743
763
|
// user might have long pressed ios 14 back button item,
|
|
744
764
|
// so he can go back more than one screen and we need to dismiss more screens in JS stack then.
|
|
745
765
|
// We check it by calculating the difference between the index of currently displayed screen
|
|
@@ -1038,18 +1058,17 @@ Class<RCTComponentViewProtocol> RNSScreenCls(void)
|
|
|
1038
1058
|
{
|
|
1039
1059
|
return self.screenView.homeIndicatorHidden;
|
|
1040
1060
|
}
|
|
1041
|
-
|
|
1042
|
-
- (int)getIndexOfView:(UIView *)view
|
|
1043
|
-
{
|
|
1044
|
-
return (int)[[self.screenView.reactSuperview reactSubviews] indexOfObject:view];
|
|
1045
|
-
}
|
|
1046
|
-
|
|
1047
1061
|
- (int)getParentChildrenCount
|
|
1048
1062
|
{
|
|
1049
1063
|
return (int)[[self.screenView.reactSuperview reactSubviews] count];
|
|
1050
1064
|
}
|
|
1051
1065
|
#endif
|
|
1052
1066
|
|
|
1067
|
+
- (int)getIndexOfView:(UIView *)view
|
|
1068
|
+
{
|
|
1069
|
+
return (int)[[self.screenView.reactSuperview reactSubviews] indexOfObject:view];
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1053
1072
|
// since on Fabric the view of controller can be a snapshot of type `UIView`,
|
|
1054
1073
|
// when we want to check props of ScreenView, we need to get them from _initialView
|
|
1055
1074
|
- (RNSScreenView *)screenView
|
package/ios/RNSScreenStack.mm
CHANGED
|
@@ -598,22 +598,16 @@
|
|
|
598
598
|
|
|
599
599
|
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
|
|
600
600
|
{
|
|
601
|
-
RNSScreenView *topScreen =
|
|
602
|
-
|
|
603
|
-
if (![topScreen isKindOfClass:[RNSScreenView class]] || !topScreen.gestureEnabled ||
|
|
604
|
-
_controller.viewControllers.count < 2) {
|
|
605
|
-
return NO;
|
|
606
|
-
}
|
|
601
|
+
RNSScreenView *topScreen = _reactSubviews.lastObject;
|
|
607
602
|
|
|
608
603
|
#if TARGET_OS_TV
|
|
609
604
|
[self cancelTouchesInParent];
|
|
610
605
|
return YES;
|
|
611
606
|
#else
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
if ([gestureRecognizer
|
|
616
|
-
[self isInGestureResponseDistance:gestureRecognizer topScreen:topScreen]) {
|
|
607
|
+
// RNSPanGestureRecognizer will receive events iff topScreen.fullScreenSwipeEnabled == YES;
|
|
608
|
+
// Events are filtered in gestureRecognizer:shouldReceivePressOrTouchEvent: method
|
|
609
|
+
if ([gestureRecognizer isKindOfClass:[RNSPanGestureRecognizer class]]) {
|
|
610
|
+
if ([self isInGestureResponseDistance:gestureRecognizer topScreen:topScreen]) {
|
|
617
611
|
_isFullWidthSwiping = YES;
|
|
618
612
|
[self cancelTouchesInParent];
|
|
619
613
|
return YES;
|
|
@@ -621,6 +615,7 @@
|
|
|
621
615
|
return NO;
|
|
622
616
|
}
|
|
623
617
|
|
|
618
|
+
// Now we're dealing with RNSScreenEdgeGestureRecognizer (or _UIParallaxTransitionPanGestureRecognizer)
|
|
624
619
|
if (topScreen.customAnimationOnSwipe && [RNSScreenStackAnimator isCustomAnimation:topScreen.stackAnimation]) {
|
|
625
620
|
if ([gestureRecognizer isKindOfClass:[RNSScreenEdgeGestureRecognizer class]]) {
|
|
626
621
|
// if we do not set any explicit `semanticContentAttribute`, it is `UISemanticContentAttributeUnspecified` instead
|
|
@@ -639,10 +634,8 @@
|
|
|
639
634
|
if ([gestureRecognizer isKindOfClass:[RNSScreenEdgeGestureRecognizer class]]) {
|
|
640
635
|
// it should only recognize with `customAnimationOnSwipe` set
|
|
641
636
|
return NO;
|
|
642
|
-
} else if ([gestureRecognizer isKindOfClass:[RNSPanGestureRecognizer class]]) {
|
|
643
|
-
// it should only recognize with `fullScreenSwipeEnabled` set
|
|
644
|
-
return NO;
|
|
645
637
|
}
|
|
638
|
+
// _UIParallaxTransitionPanGestureRecognizer (other...)
|
|
646
639
|
[self cancelTouchesInParent];
|
|
647
640
|
return YES;
|
|
648
641
|
}
|
|
@@ -675,7 +668,7 @@
|
|
|
675
668
|
|
|
676
669
|
- (void)handleSwipe:(UIPanGestureRecognizer *)gestureRecognizer
|
|
677
670
|
{
|
|
678
|
-
RNSScreenView *topScreen =
|
|
671
|
+
RNSScreenView *topScreen = _reactSubviews.lastObject;
|
|
679
672
|
float translation;
|
|
680
673
|
float velocity;
|
|
681
674
|
float distance;
|
|
@@ -807,6 +800,8 @@
|
|
|
807
800
|
return [super hitTest:point withEvent:event];
|
|
808
801
|
}
|
|
809
802
|
|
|
803
|
+
#if !TARGET_OS_TV
|
|
804
|
+
|
|
810
805
|
- (BOOL)isScrollViewPanGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
|
|
811
806
|
{
|
|
812
807
|
// NOTE: This hack is required to restore native behavior of edge swipe (interactive pop gesture)
|
|
@@ -819,18 +814,66 @@
|
|
|
819
814
|
return scrollView.panGestureRecognizer == gestureRecognizer;
|
|
820
815
|
}
|
|
821
816
|
|
|
817
|
+
// Custom method for compatibility with iOS < 13.4
|
|
818
|
+
// RNSScreenStackView is a UIGestureRecognizerDelegate for three types of gesture recognizers:
|
|
819
|
+
// RNSPanGestureRecognizer, RNSScreenEdgeGestureRecognizer, _UIParallaxTransitionPanGestureRecognizer
|
|
820
|
+
// Be careful when adding another type of gesture recognizer.
|
|
821
|
+
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceivePressOrTouchEvent:(NSObject *)event
|
|
822
|
+
{
|
|
823
|
+
RNSScreenView *topScreen = _reactSubviews.lastObject;
|
|
824
|
+
|
|
825
|
+
if (![topScreen isKindOfClass:[RNSScreenView class]] || !topScreen.gestureEnabled ||
|
|
826
|
+
_controller.viewControllers.count < 2 || [topScreen isModal]) {
|
|
827
|
+
return NO;
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
// We want to pass events to RNSPanGestureRecognizer iff full screen swipe is enabled.
|
|
831
|
+
if ([gestureRecognizer isKindOfClass:[RNSPanGestureRecognizer class]]) {
|
|
832
|
+
return topScreen.fullScreenSwipeEnabled;
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
// RNSScreenEdgeGestureRecognizer || _UIParallaxTransitionPanGestureRecognizer
|
|
836
|
+
return YES;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceivePress:(UIPress *)press;
|
|
840
|
+
{
|
|
841
|
+
return [self gestureRecognizer:gestureRecognizer shouldReceivePressOrTouchEvent:press];
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch;
|
|
845
|
+
{
|
|
846
|
+
return [self gestureRecognizer:gestureRecognizer shouldReceivePressOrTouchEvent:touch];
|
|
847
|
+
}
|
|
848
|
+
|
|
822
849
|
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
|
|
823
850
|
shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
|
|
824
851
|
{
|
|
825
|
-
|
|
852
|
+
if ([gestureRecognizer isKindOfClass:[RNSPanGestureRecognizer class]] &&
|
|
853
|
+
[self isScrollViewPanGestureRecognizer:otherGestureRecognizer]) {
|
|
854
|
+
RNSPanGestureRecognizer *panGestureRecognizer = (RNSPanGestureRecognizer *)gestureRecognizer;
|
|
855
|
+
BOOL isBackGesture = [panGestureRecognizer translationInView:panGestureRecognizer.view].x > 0 &&
|
|
856
|
+
_controller.viewControllers.count > 1;
|
|
857
|
+
|
|
858
|
+
if (gestureRecognizer.state == UIGestureRecognizerStateBegan || isBackGesture) {
|
|
859
|
+
return NO;
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
return YES;
|
|
863
|
+
}
|
|
864
|
+
return NO;
|
|
826
865
|
}
|
|
827
866
|
|
|
828
867
|
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
|
|
829
868
|
shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
|
|
830
869
|
{
|
|
831
|
-
return
|
|
870
|
+
return (
|
|
871
|
+
[gestureRecognizer isKindOfClass:[UIScreenEdgePanGestureRecognizer class]] &&
|
|
872
|
+
[self isScrollViewPanGestureRecognizer:otherGestureRecognizer]);
|
|
832
873
|
}
|
|
833
874
|
|
|
875
|
+
#endif // !TARGET_OS_TV
|
|
876
|
+
|
|
834
877
|
- (void)insertReactSubview:(RNSScreenView *)subview atIndex:(NSInteger)atIndex
|
|
835
878
|
{
|
|
836
879
|
if (![subview isKindOfClass:[RNSScreenView class]]) {
|
|
@@ -926,7 +969,7 @@
|
|
|
926
969
|
- (void)mountingTransactionWillMount:(facebook::react::MountingTransaction const &)transaction
|
|
927
970
|
withSurfaceTelemetry:(facebook::react::SurfaceTelemetry const &)surfaceTelemetry
|
|
928
971
|
{
|
|
929
|
-
for (auto mutation : transaction.getMutations()) {
|
|
972
|
+
for (auto &mutation : transaction.getMutations()) {
|
|
930
973
|
if (mutation.type == facebook::react::ShadowViewMutation::Type::Remove &&
|
|
931
974
|
mutation.parentShadowView.componentName != nil &&
|
|
932
975
|
strcmp(mutation.parentShadowView.componentName, "RNSScreenStack") == 0) {
|