react-native-screens 3.10.1 → 3.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +13 -7
  3. package/RNScreens.podspec +36 -6
  4. package/android/build.gradle +74 -3
  5. package/android/src/fabric/java/com/swmansion/rnscreens/FabricEnabledViewGroup.kt +49 -0
  6. package/android/src/fabric/java/com/swmansion/rnscreens/RNScreensComponentsRegistry.java +28 -0
  7. package/android/src/main/java/com/swmansion/rnscreens/RNScreensPackage.kt +11 -2
  8. package/android/src/main/java/com/swmansion/rnscreens/Screen.kt +52 -21
  9. package/android/src/main/java/com/swmansion/rnscreens/ScreenContainer.kt +1 -1
  10. package/android/src/main/java/com/swmansion/rnscreens/ScreenFragment.kt +64 -33
  11. package/android/src/main/java/com/swmansion/rnscreens/ScreenStack.kt +9 -31
  12. package/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.kt +0 -30
  13. package/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfig.kt +12 -5
  14. package/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfigViewManager.kt +83 -18
  15. package/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderSubviewManager.kt +17 -5
  16. package/android/src/main/java/com/swmansion/rnscreens/ScreenStackViewManager.kt +14 -1
  17. package/android/src/main/java/com/swmansion/rnscreens/ScreenViewManager.kt +41 -14
  18. package/android/src/main/java/com/swmansion/rnscreens/ScreenWindowTraits.kt +72 -11
  19. package/android/src/main/java/com/swmansion/rnscreens/SearchBarManager.kt +18 -1
  20. package/android/src/main/java/com/swmansion/rnscreens/SearchBarView.kt +7 -2
  21. package/android/src/main/java/com/swmansion/rnscreens/SearchViewFormatter.kt +29 -2
  22. package/android/src/main/jni/Android.mk +45 -0
  23. package/android/src/main/jni/OnLoad.cpp +9 -0
  24. package/android/src/main/jni/RNScreensComponentsRegistry.cpp +66 -0
  25. package/android/src/main/jni/RNScreensComponentsRegistry.h +34 -0
  26. package/android/src/main/res/anim/rns_default_enter_in.xml +18 -0
  27. package/android/src/main/res/anim/rns_default_enter_out.xml +19 -0
  28. package/android/src/main/res/anim/rns_default_exit_in.xml +17 -0
  29. package/android/src/main/res/anim/rns_default_exit_out.xml +18 -0
  30. package/android/src/main/res/anim/rns_fade_in.xml +7 -0
  31. package/android/src/main/res/anim/rns_fade_out.xml +7 -0
  32. package/android/src/main/res/anim/rns_no_animation_20.xml +6 -0
  33. package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenManagerDelegate.java +71 -0
  34. package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenManagerInterface.java +30 -0
  35. package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenStackHeaderConfigManagerDelegate.java +104 -0
  36. package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenStackHeaderConfigManagerInterface.java +41 -0
  37. package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenStackHeaderSubviewManagerDelegate.java +31 -0
  38. package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenStackHeaderSubviewManagerInterface.java +17 -0
  39. package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenStackManagerDelegate.java +25 -0
  40. package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenStackManagerInterface.java +16 -0
  41. package/android/src/paper/java/com/swmansion/rnscreens/FabricEnabledViewGroup.kt +16 -0
  42. package/common/cpp/Android.mk +38 -0
  43. package/common/cpp/rnscreens/RNSScreenComponentDescriptor.h +41 -0
  44. package/common/cpp/rnscreens/RNSScreenShadowNode.cpp +9 -0
  45. package/common/cpp/rnscreens/RNSScreenShadowNode.h +29 -0
  46. package/common/cpp/rnscreens/RNSScreenState.cpp +14 -0
  47. package/common/cpp/rnscreens/RNSScreenState.h +46 -0
  48. package/createNativeStackNavigator/README.md +12 -0
  49. package/ios/RNSScreen.h +10 -0
  50. package/ios/RNSScreen.m +34 -0
  51. package/ios/RNSScreenComponentView.h +23 -0
  52. package/ios/RNSScreenComponentView.mm +159 -0
  53. package/ios/RNSScreenContainer.m +5 -0
  54. package/ios/RNSScreenController.h +10 -0
  55. package/ios/RNSScreenController.mm +79 -0
  56. package/ios/RNSScreenStack.m +22 -7
  57. package/ios/RNSScreenStackAnimator.m +45 -14
  58. package/ios/RNSScreenStackComponentView.h +15 -0
  59. package/ios/RNSScreenStackComponentView.mm +295 -0
  60. package/ios/RNSScreenStackHeaderConfig.m +4 -1
  61. package/ios/RNSScreenStackHeaderConfigComponentView.h +42 -0
  62. package/ios/RNSScreenStackHeaderConfigComponentView.mm +662 -0
  63. package/ios/RNSScreenStackHeaderSubviewComponentView.h +14 -0
  64. package/ios/RNSScreenStackHeaderSubviewComponentView.mm +77 -0
  65. package/ios/RNSScreenWindowTraits.h +1 -0
  66. package/ios/RNSScreenWindowTraits.m +20 -0
  67. package/ios/UIViewController+RNScreens.m +10 -0
  68. package/ios/utils/RNSUIBarButtonItem.h +5 -0
  69. package/ios/utils/RNSUIBarButtonItem.mm +22 -0
  70. package/lib/commonjs/fabric/Screen.js +27 -0
  71. package/lib/commonjs/fabric/Screen.js.map +1 -0
  72. package/lib/commonjs/fabric/ScreenNativeComponent.js +23 -0
  73. package/lib/commonjs/fabric/ScreenNativeComponent.js.map +1 -0
  74. package/lib/commonjs/fabric/ScreenStack.js +27 -0
  75. package/lib/commonjs/fabric/ScreenStack.js.map +1 -0
  76. package/lib/commonjs/fabric/ScreenStackHeaderConfigNativeComponent.js +27 -0
  77. package/lib/commonjs/fabric/ScreenStackHeaderConfigNativeComponent.js.map +1 -0
  78. package/lib/commonjs/fabric/ScreenStackHeaderSubview.js +34 -0
  79. package/lib/commonjs/fabric/ScreenStackHeaderSubview.js.map +1 -0
  80. package/lib/commonjs/fabric/ScreenStackHeaderSubviewNativeComponent.js +27 -0
  81. package/lib/commonjs/fabric/ScreenStackHeaderSubviewNativeComponent.js.map +1 -0
  82. package/lib/commonjs/fabric/ScreenStackNativeComponent.js +21 -0
  83. package/lib/commonjs/fabric/ScreenStackNativeComponent.js.map +1 -0
  84. package/lib/commonjs/fabric/index.js +40 -0
  85. package/lib/commonjs/fabric/index.js.map +1 -0
  86. package/lib/commonjs/index.native.js +32 -15
  87. package/lib/commonjs/index.native.js.map +1 -1
  88. package/lib/commonjs/native-stack/views/NativeStackView.js +33 -4
  89. package/lib/commonjs/native-stack/views/NativeStackView.js.map +1 -1
  90. package/lib/module/fabric/Screen.js +11 -0
  91. package/lib/module/fabric/Screen.js.map +1 -0
  92. package/lib/module/fabric/ScreenNativeComponent.js +11 -0
  93. package/lib/module/fabric/ScreenNativeComponent.js.map +1 -0
  94. package/lib/module/fabric/ScreenStack.js +12 -0
  95. package/lib/module/fabric/ScreenStack.js.map +1 -0
  96. package/lib/module/fabric/ScreenStackHeaderConfigNativeComponent.js +10 -0
  97. package/lib/module/fabric/ScreenStackHeaderConfigNativeComponent.js.map +1 -0
  98. package/lib/module/fabric/ScreenStackHeaderSubview.js +21 -0
  99. package/lib/module/fabric/ScreenStackHeaderSubview.js.map +1 -0
  100. package/lib/module/fabric/ScreenStackHeaderSubviewNativeComponent.js +10 -0
  101. package/lib/module/fabric/ScreenStackHeaderSubviewNativeComponent.js.map +1 -0
  102. package/lib/module/fabric/ScreenStackNativeComponent.js +9 -0
  103. package/lib/module/fabric/ScreenStackNativeComponent.js.map +1 -0
  104. package/lib/module/fabric/index.js +6 -0
  105. package/lib/module/fabric/index.js.map +1 -0
  106. package/lib/module/index.native.js +32 -15
  107. package/lib/module/index.native.js.map +1 -1
  108. package/lib/module/native-stack/views/NativeStackView.js +33 -4
  109. package/lib/module/native-stack/views/NativeStackView.js.map +1 -1
  110. package/lib/typescript/native-stack/types.d.ts +34 -0
  111. package/lib/typescript/reanimated/ReanimatedNativeStackScreen.d.ts +1 -1
  112. package/lib/typescript/reanimated/ReanimatedScreen.d.ts +1 -1
  113. package/lib/typescript/types.d.ts +60 -5
  114. package/native-stack/README.md +39 -3
  115. package/package.json +17 -3
  116. package/reanimated/package.json +6 -0
  117. package/src/fabric/Screen.js +12 -0
  118. package/src/fabric/ScreenNativeComponent.js +64 -0
  119. package/src/fabric/ScreenStack.js +8 -0
  120. package/src/fabric/ScreenStackHeaderConfigNativeComponent.js +54 -0
  121. package/src/fabric/ScreenStackHeaderSubview.js +20 -0
  122. package/src/fabric/ScreenStackHeaderSubviewNativeComponent.js +31 -0
  123. package/src/fabric/ScreenStackNativeComponent.js +19 -0
  124. package/src/fabric/index.js +11 -0
  125. package/src/index.native.tsx +35 -14
  126. package/src/native-stack/types.tsx +34 -0
  127. package/src/native-stack/views/NativeStackView.tsx +33 -4
  128. package/src/types.tsx +60 -5
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2018 Krzysztof Magiera
3
+ Copyright (c) 2018 Software Mansion <swmansion.com>
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  This project aims to expose native navigation container components to React Native. It is not designed to be used as a standalone library but rather as a dependency of a [full-featured navigation library](https://github.com/react-navigation/react-navigation).
4
4
 
5
+ ## Fabric
6
+
7
+ To learn about how to use `react-native-screens` with Fabric architecture, head over to [Fabric README](README-Fabric.md). Instructions on how to run Fabric Example within this repo can be found in the [FabricExample README](FabricExample/README.md).
8
+
5
9
  ## Supported platforms
6
10
 
7
11
  - [x] iOS
@@ -123,8 +127,8 @@ You can also disable the usage of native screens per navigator with [`detachInac
123
127
  To take advantage of the native stack navigator primitive for React Navigation that leverages `UINavigationController` on iOS and `Fragment` on Android, please refer:
124
128
 
125
129
  - for React Navigation >= v6 to the [Native Stack Navigator part of React Navigation documentation](https://reactnavigation.org/docs/native-stack-navigator)
126
- - for React Navigation v5 to the [README in react-native-screens/native-stack](https://github.com/software-mansion/react-native-screens/tree/master/native-stack)
127
- - for older versions to the [README in react-native-screens/createNativeStackNavigator](https://github.com/software-mansion/react-native-screens/tree/master/createNativeStackNavigator)
130
+ - for React Navigation v5 to the [README in react-native-screens/native-stack](https://github.com/software-mansion/react-native-screens/tree/main/native-stack)
131
+ - for older versions to the [README in react-native-screens/createNativeStackNavigator](https://github.com/software-mansion/react-native-screens/tree/main/createNativeStackNavigator)
128
132
 
129
133
  ## Interop with [react-native-navigation](https://github.com/wix/react-native-navigation)
130
134
 
@@ -132,12 +136,12 @@ React-native-navigation library already uses native containers for rendering nav
132
136
 
133
137
  ## Interop with other libraries
134
138
 
135
- This library should work out of the box with all existing react-native libraries. If you experience problems with interoperability please [report an issue](https://github.com/kmagiera/react-native-screens/issues).
139
+ This library should work out of the box with all existing react-native libraries. If you experience problems with interoperability please [report an issue](https://github.com/software-mansion/react-native-screens/issues).
136
140
 
137
141
  ## Guide for navigation library authors
138
142
 
139
143
  If you are building a navigation library you may want to use `react-native-screens` to have control over which parts of the React component tree are attached to the native view hierarchy.
140
- To do that, `react-native-screens` provides you with the components documented [here](https://github.com/kmagiera/react-native-screens/tree/master/guides/GUIDE_FOR_LIBRARY_AUTHORS.md).
144
+ To do that, `react-native-screens` provides you with the components documented [here](https://github.com/software-mansion/react-native-screens/tree/main/guides/GUIDE_FOR_LIBRARY_AUTHORS.md).
141
145
 
142
146
  ## Common problems
143
147
 
@@ -158,10 +162,11 @@ Use `ScrollView` with prop `contentInsetAdjustmentBehavior=“automatic”` as a
158
162
  | [SVG component becomes transparent when goBack](https://github.com/software-mansion/react-native-screens/issues/773) | [related PRs](https://github.com/software-mansion/react-native-screens/issues/773#issuecomment-783469792) |
159
163
  | [Memory leak while moving from one screen to another in the same stack](https://github.com/software-mansion/react-native-screens/issues/843) | [explanation](https://github.com/software-mansion/react-native-screens/issues/843#issuecomment-832034119) |
160
164
  | [LargeHeader stays small after pop/goBack/swipe gesture on iOS 14+](https://github.com/software-mansion/react-native-screens/issues/649) | [potential fix](https://github.com/software-mansion/react-native-screens/issues/649#issuecomment-712199895) |
165
+ | [`onScroll` and `onMomentumScrollEnd` of previous screen triggered in bottom tabs](https://github.com/software-mansion/react-native-screens/issues/1183) | [explanation](https://github.com/software-mansion/react-native-screens/issues/1183#issuecomment-949313111) |
161
166
 
162
167
  ## Contributing
163
168
 
164
- There are many ways to contribute to this project. See [CONTRIBUTING](https://github.com/kmagiera/react-native-screens/tree/master/guides/CONTRIBUTING.md) guide for more information. Thank you for your interest in contributing!
169
+ There are many ways to contribute to this project. See [CONTRIBUTING](https://github.com/software-mansion/react-native-screens/tree/main/guides/CONTRIBUTING.md) guide for more information. Thank you for your interest in contributing!
165
170
 
166
171
  ## License
167
172
 
@@ -169,7 +174,8 @@ React native screens library is licensed under [The MIT License](LICENSE).
169
174
 
170
175
  ## Credits
171
176
 
172
- This project is supported by amazing people from [Expo.io](https://expo.io) and [Software Mansion](https://swmansion.com)
177
+ This project has been build and is maintained thanks to the support from [Shopify](https://shopify.com), [Expo.io](https://expo.io) and [Software Mansion](https://swmansion.com)
173
178
 
179
+ [![shopify](https://avatars1.githubusercontent.com/u/8085?v=3&s=100 'Shopify.com')](https://shopify.com)
174
180
  [![expo](https://avatars2.githubusercontent.com/u/12504344?v=3&s=100 'Expo.io')](https://expo.io)
175
- [![swm](https://logo.swmansion.com/logo?color=white&variant=desktop&width=150&tag=react-native-screens-github 'Software Mansion')](https://swmansion.com)
181
+ [![swm](https://logo.swmansion.com/logo?color=white&variant=desktop&width=150&tag=react-native-reanimated-github 'Software Mansion')](https://swmansion.com)
package/RNScreens.podspec CHANGED
@@ -2,6 +2,13 @@ require "json"
2
2
 
3
3
  package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4
4
 
5
+ fabric_enabled = ENV['RCT_NEW_ARCH_ENABLED']
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
+ folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'
11
+
5
12
  Pod::Spec.new do |s|
6
13
  s.name = "RNScreens"
7
14
  s.version = package["version"]
@@ -16,10 +23,33 @@ Pod::Spec.new do |s|
16
23
  s.platforms = { :ios => "9.0", :tvos => "11.0" }
17
24
  s.source = { :git => "https://github.com/software-mansion/react-native-screens.git", :tag => "#{s.version}" }
18
25
 
19
- s.source_files = "ios/**/*.{h,m}"
20
- s.requires_arc = true
21
-
22
- s.dependency "React-Core"
23
- s.dependency "React-RCTImage"
26
+ if fabric_enabled
27
+ s.pod_target_xcconfig = {
28
+ 'HEADER_SEARCH_PATHS' => '"$(PODS_ROOT)/boost" "$(PODS_ROOT)/boost-for-react-native" "$(PODS_ROOT)/RCT-Folly"'
29
+ }
30
+ s.platforms = { ios: '11.0', tvos: '11.0' }
31
+ s.compiler_flags = folly_compiler_flags
32
+ s.source_files = 'ios/**/*.{h,m,mm,cpp}'
33
+ s.requires_arc = true
34
+
35
+ s.dependency "React"
36
+ s.dependency "React-RCTFabric"
37
+ s.dependency "React-Codegen"
38
+ s.dependency "RCT-Folly", folly_version
39
+ s.dependency "RCTRequired"
40
+ s.dependency "RCTTypeSafety"
41
+ s.dependency "ReactCommon/turbomodule/core"
42
+
43
+ s.subspec "common" do |ss|
44
+ ss.source_files = "common/cpp/**/*.{cpp,h}"
45
+ ss.header_dir = "rnscreens"
46
+ ss.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/common/cpp\"" }
47
+ end
48
+ else
49
+ s.source_files = "ios/**/*.{h,m}"
50
+ s.requires_arc = true
51
+
52
+ s.dependency "React-Core"
53
+ s.dependency "React-RCTImage"
54
+ end
24
55
  end
25
-
@@ -4,7 +4,6 @@ buildscript {
4
4
  }
5
5
  repositories {
6
6
  google()
7
- jcenter()
8
7
  mavenCentral()
9
8
  }
10
9
  dependencies {
@@ -14,11 +13,22 @@ buildscript {
14
13
  }
15
14
  }
16
15
 
16
+ def isNewArchitectureEnabled() {
17
+ // To opt-in for the New Architecture, you can either:
18
+ // - Set `newArchEnabled` to true inside the `gradle.properties` file
19
+ // - Invoke gradle with `-newArchEnabled=true`
20
+ // - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true`
21
+ return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
22
+ }
23
+
17
24
  // spotless is only accessible within react-native-screens repo
18
25
  if (project == rootProject) {
19
26
  apply from: 'spotless.gradle'
20
27
  }
21
28
 
29
+ if (isNewArchitectureEnabled()) {
30
+ apply plugin: "com.facebook.react"
31
+ }
22
32
  apply plugin: 'com.android.library'
23
33
  apply plugin: 'kotlin-android'
24
34
 
@@ -30,6 +40,24 @@ android {
30
40
  targetSdkVersion safeExtGet('targetSdkVersion', 22)
31
41
  versionCode 1
32
42
  versionName "1.0"
43
+ buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
44
+ if (isNewArchitectureEnabled()) {
45
+ var appProject = rootProject.allprojects.find {it.plugins.hasPlugin('com.android.application')}
46
+ externalNativeBuild {
47
+ ndkBuild {
48
+ arguments "APP_PLATFORM=android-21",
49
+ "APP_STL=c++_shared",
50
+ "NDK_TOOLCHAIN_VERSION=clang",
51
+ "GENERATED_SRC_DIR=${appProject.buildDir}/generated/source",
52
+ "PROJECT_BUILD_DIR=${appProject.buildDir}",
53
+ "REACT_ANDROID_DIR=${appProject.rootDir}/../node_modules/react-native/ReactAndroid",
54
+ "REACT_ANDROID_BUILD_DIR=${appProject.rootDir}/../node_modules/react-native/ReactAndroid/build"
55
+ cFlags "-Wall", "-Werror", "-fexceptions", "-frtti", "-DWITH_INSPECTOR=1"
56
+ cppFlags "-std=c++17"
57
+ targets "rnscreens_modules"
58
+ }
59
+ }
60
+ }
33
61
  }
34
62
  lintOptions {
35
63
  abortOnError false
@@ -38,6 +66,35 @@ android {
38
66
  sourceCompatibility JavaVersion.VERSION_1_8
39
67
  targetCompatibility JavaVersion.VERSION_1_8
40
68
  }
69
+ if (isNewArchitectureEnabled()) {
70
+ externalNativeBuild {
71
+ ndkBuild {
72
+ path "src/main/jni/Android.mk"
73
+ }
74
+ }
75
+ }
76
+ packagingOptions {
77
+ // For some reason gradle only complains about the duplicated version of libreact_render libraries
78
+ // while there are more libraries copied in intermediates folder of the lib build directory, we exlude
79
+ // only the ones that make the build fail (ideally we should only include librnscreens_modules but we
80
+ // are only allowed to specify exlude patterns)
81
+ exclude "**/libreact_render*.so"
82
+ }
83
+ sourceSets.main {
84
+ java {
85
+ if (isNewArchitectureEnabled()) {
86
+ srcDirs += [
87
+ "src/fabric/java",
88
+ ]
89
+ } else {
90
+ srcDirs += [
91
+ "src/paper/java",
92
+ "build/generated/source/codegen/java"
93
+ ]
94
+ }
95
+
96
+ }
97
+ }
41
98
  }
42
99
 
43
100
  repositories {
@@ -50,14 +107,28 @@ repositories {
50
107
  mavenCentral()
51
108
  mavenLocal()
52
109
  google()
53
- jcenter()
54
110
  }
55
111
 
56
112
  dependencies {
57
- implementation 'com.facebook.react:react-native:+'
113
+ if (isNewArchitectureEnabled()) {
114
+ implementation project(":ReactAndroid")
115
+ } else {
116
+ implementation 'com.facebook.react:react-native:+'
117
+ }
58
118
  implementation 'androidx.appcompat:appcompat:1.1.0'
59
119
  implementation 'androidx.fragment:fragment:1.2.1'
60
120
  implementation 'androidx.coordinatorlayout:coordinatorlayout:1.1.0'
61
121
  implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0'
62
122
  implementation 'com.google.android.material:material:1.1.0'
123
+ implementation "androidx.core:core-ktx:1.5.0"
124
+ }
125
+
126
+ if (isNewArchitectureEnabled()) {
127
+ react {
128
+ reactRoot = rootProject.file("../node_modules/react-native/")
129
+ jsRootDir = file("../src/fabric/")
130
+ codegenDir = rootProject.file("../node_modules/react-native-codegen/")
131
+ libraryName = "rnscreens"
132
+ codegenJavaPackageName = "com.swmansion.rnscreens"
133
+ }
63
134
  }
@@ -0,0 +1,49 @@
1
+ package com.swmansion.rnscreens
2
+
3
+ import android.view.ViewGroup
4
+ import androidx.annotation.UiThread
5
+ import com.facebook.react.bridge.ReactContext
6
+ import com.facebook.react.bridge.ReadableMap
7
+ import com.facebook.react.bridge.WritableMap
8
+ import com.facebook.react.bridge.WritableNativeMap
9
+ import com.facebook.react.uimanager.FabricViewStateManager
10
+ import com.facebook.react.uimanager.PixelUtil
11
+ import kotlin.math.abs
12
+
13
+ abstract class FabricEnabledViewGroup constructor(context: ReactContext?) : ViewGroup(context), FabricViewStateManager.HasFabricViewStateManager {
14
+ private val mFabricViewStateManager: FabricViewStateManager = FabricViewStateManager()
15
+
16
+ override fun getFabricViewStateManager(): FabricViewStateManager {
17
+ return mFabricViewStateManager
18
+ }
19
+
20
+ protected fun updateScreenSizeFabric(width: Int, height: Int) {
21
+ updateState(width, height)
22
+ }
23
+
24
+ @UiThread
25
+ fun updateState(width: Int, height: Int) {
26
+ val realWidth: Float = PixelUtil.toDIPFromPixel(width.toFloat())
27
+ val realHeight: Float = PixelUtil.toDIPFromPixel(height.toFloat())
28
+
29
+ // Check incoming state values. If they're already the correct value, return early to prevent
30
+ // infinite UpdateState/SetState loop.
31
+ val currentState: ReadableMap? = mFabricViewStateManager.getStateData()
32
+ if (currentState != null) {
33
+ val delta = 0.9f
34
+ val stateFrameHeight: Float = if (currentState.hasKey("frameHeight")) currentState.getDouble("frameHeight").toFloat() else 0f
35
+ val stateFrameWidth: Float = if (currentState.hasKey("frameWidth")) currentState.getDouble("frameWidth").toFloat() else 0f
36
+ if (abs(stateFrameWidth - realWidth) < delta &&
37
+ abs(stateFrameHeight - realHeight) < delta
38
+ ) {
39
+ return
40
+ }
41
+ }
42
+ mFabricViewStateManager.setState {
43
+ val map: WritableMap = WritableNativeMap()
44
+ map.putDouble("frameWidth", realWidth.toDouble())
45
+ map.putDouble("frameHeight", realHeight.toDouble())
46
+ map
47
+ }
48
+ }
49
+ }
@@ -0,0 +1,28 @@
1
+ package com.swmansion.rnscreens;
2
+
3
+ import com.facebook.jni.HybridData;
4
+ import com.facebook.proguard.annotations.DoNotStrip;
5
+ import com.facebook.react.fabric.ComponentFactory;
6
+ import com.facebook.soloader.SoLoader;
7
+
8
+ @DoNotStrip
9
+ public class RNScreensComponentsRegistry {
10
+ static {
11
+ SoLoader.loadLibrary("rnscreens_modules");
12
+ }
13
+
14
+ @DoNotStrip private final HybridData mHybridData;
15
+
16
+ @DoNotStrip
17
+ private native HybridData initHybrid(ComponentFactory componentFactory);
18
+
19
+ @DoNotStrip
20
+ private RNScreensComponentsRegistry(ComponentFactory componentFactory) {
21
+ mHybridData = initHybrid(componentFactory);
22
+ }
23
+
24
+ @DoNotStrip
25
+ public static RNScreensComponentsRegistry register(ComponentFactory componentFactory) {
26
+ return new RNScreensComponentsRegistry(componentFactory);
27
+ }
28
+ }
@@ -4,10 +4,19 @@ import com.facebook.react.ReactPackage
4
4
  import com.facebook.react.bridge.NativeModule
5
5
  import com.facebook.react.bridge.ReactApplicationContext
6
6
  import com.facebook.react.uimanager.ViewManager
7
+ import com.facebook.soloader.SoLoader
7
8
 
8
9
  class RNScreensPackage : ReactPackage {
9
- override fun createNativeModules(reactContext: ReactApplicationContext) =
10
- emptyList<NativeModule>()
10
+ override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
11
+ if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
12
+ // For Fabric, we load c++ native library here, this triggers screen's Fabric
13
+ // component registration which is necessary in order to avoid asking users
14
+ // to manually add init calls in their application code.
15
+ // This should no longer be needed if RN's autolink mechanism has Fabric support
16
+ SoLoader.loadLibrary("rnscreens_modules")
17
+ }
18
+ return emptyList<NativeModule>()
19
+ }
11
20
 
12
21
  override fun createViewManagers(reactContext: ReactApplicationContext) =
13
22
  listOf<ViewManager<*, *>>(
@@ -8,12 +8,18 @@ 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
11
12
  import com.facebook.react.bridge.GuardedRunnable
12
13
  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
13
18
  import com.facebook.react.uimanager.UIManagerModule
14
19
 
15
20
  @SuppressLint("ViewConstructor")
16
- class Screen constructor(context: ReactContext?) : ViewGroup(context) {
21
+ class Screen constructor(context: ReactContext?) : FabricEnabledViewGroup(context) {
22
+
17
23
  var fragment: ScreenFragment? = null
18
24
  var container: ScreenContainer<*>? = null
19
25
  var activityState: ActivityState? = null
@@ -29,6 +35,8 @@ class Screen constructor(context: ReactContext?) : ViewGroup(context) {
29
35
  private var mStatusBarHidden: Boolean? = null
30
36
  private var mStatusBarTranslucent: Boolean? = null
31
37
  private var mStatusBarColor: Int? = null
38
+ private var mNavigationBarColor: Int? = null
39
+ private var mNavigationBarHidden: Boolean? = null
32
40
  var isStatusBarAnimated: Boolean? = null
33
41
  private var mNativeBackButtonDismissalEnabled = true
34
42
 
@@ -46,16 +54,6 @@ class Screen constructor(context: ReactContext?) : ViewGroup(context) {
46
54
  layoutParams = WindowManager.LayoutParams(WindowManager.LayoutParams.TYPE_APPLICATION)
47
55
  }
48
56
 
49
- override fun onAnimationStart() {
50
- super.onAnimationStart()
51
- fragment?.onViewAnimationStart()
52
- }
53
-
54
- override fun onAnimationEnd() {
55
- super.onAnimationEnd()
56
- fragment?.onViewAnimationEnd()
57
- }
58
-
59
57
  override fun dispatchSaveInstanceState(container: SparseArray<Parcelable>) {
60
58
  // do nothing, react native will keep the view hierarchy so no need to serialize/deserialize
61
59
  // view's states. The side effect of restoring is that TextInput components would trigger
@@ -70,18 +68,26 @@ class Screen constructor(context: ReactContext?) : ViewGroup(context) {
70
68
  if (changed) {
71
69
  val width = r - l
72
70
  val height = b - t
73
- val reactContext = context as ReactContext
74
- reactContext.runOnNativeModulesQueueThread(
75
- object : GuardedRunnable(reactContext) {
76
- override fun runGuarded() {
77
- reactContext
78
- .getNativeModule(UIManagerModule::class.java)
79
- ?.updateNodeSize(id, width, height)
80
- }
81
- })
71
+ if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
72
+ updateScreenSizeFabric(width, height)
73
+ } else {
74
+ updateScreenSizePaper(width, height)
75
+ }
82
76
  }
83
77
  }
84
78
 
79
+ private fun updateScreenSizePaper(width: Int, height: Int) {
80
+ val reactContext = context as ReactContext
81
+ reactContext.runOnNativeModulesQueueThread(
82
+ object : GuardedRunnable(reactContext) {
83
+ override fun runGuarded() {
84
+ reactContext
85
+ .getNativeModule(UIManagerModule::class.java)
86
+ ?.updateNodeSize(id, width, height)
87
+ }
88
+ })
89
+ }
90
+
85
91
  val headerConfig: ScreenStackHeaderConfig?
86
92
  get() {
87
93
  val child = getChildAt(0)
@@ -209,6 +215,31 @@ class Screen constructor(context: ReactContext?) : ViewGroup(context) {
209
215
  fragment?.let { ScreenWindowTraits.setColor(this, it.tryGetActivity(), it.tryGetContext()) }
210
216
  }
211
217
 
218
+ var navigationBarColor: Int?
219
+ get() = mNavigationBarColor
220
+ set(navigationBarColor) {
221
+ if (navigationBarColor != null) {
222
+ ScreenWindowTraits.applyDidSetNavigationBarAppearance()
223
+ }
224
+ mNavigationBarColor = navigationBarColor
225
+ fragment?.let { ScreenWindowTraits.setNavigationBarColor(this, it.tryGetActivity()) }
226
+ }
227
+
228
+ var isNavigationBarHidden: Boolean?
229
+ get() = mNavigationBarHidden
230
+ set(navigationBarHidden) {
231
+ if (navigationBarHidden != null) {
232
+ ScreenWindowTraits.applyDidSetNavigationBarAppearance()
233
+ }
234
+ mNavigationBarHidden = navigationBarHidden
235
+ fragment?.let {
236
+ ScreenWindowTraits.setNavigationBarHidden(
237
+ this,
238
+ it.tryGetActivity(),
239
+ )
240
+ }
241
+ }
242
+
212
243
  var nativeBackButtonDismissalEnabled: Boolean
213
244
  get() = mNativeBackButtonDismissalEnabled
214
245
  set(enableNativeBackButtonDismissal) {
@@ -232,6 +263,6 @@ class Screen constructor(context: ReactContext?) : ViewGroup(context) {
232
263
  }
233
264
 
234
265
  enum class WindowTraits {
235
- ORIENTATION, COLOR, STYLE, TRANSLUCENT, HIDDEN, ANIMATED
266
+ ORIENTATION, COLOR, STYLE, TRANSLUCENT, HIDDEN, ANIMATED, NAVIGATION_BAR_COLOR, NAVIGATION_BAR_HIDDEN
236
267
  }
237
268
  }
@@ -166,7 +166,7 @@ open class ScreenContainer<T : ScreenFragment>(context: Context?) : ViewGroup(co
166
166
  while (context !is FragmentActivity && context is ContextWrapper) {
167
167
  context = context.baseContext
168
168
  }
169
- check(context is FragmentActivity) { "In order to use RNScreens components your app's activity need to extend ReactFragmentActivity or ReactCompatActivity" }
169
+ check(context is FragmentActivity) { "In order to use RNScreens components your app's activity need to extend ReactActivity" }
170
170
  setFragmentManager(context.supportFragmentManager)
171
171
  }
172
172
 
@@ -38,6 +38,17 @@ open class ScreenFragment : Fragment {
38
38
  // due to progress value being already 0.0f
39
39
  private var mProgress = -1f
40
40
 
41
+ // those 2 vars are needed since sometimes the events would be dispatched twice in child containers
42
+ // (should only happen if parent has `NONE` animation) and we don't need too complicated logic.
43
+ // We just check if, after the event was dispatched, its "counter-event" has been also dispatched before sending the same event again.
44
+ // We do it for 'willAppear' -> 'willDisappear' and 'appear' -> 'disappear'
45
+ private var canDispatchWillAppear = true
46
+ private var canDispatchAppear = true
47
+
48
+ // we want to know if we are currently transitioning in order not to fire lifecycle events
49
+ // in nested fragments. See more explanation in dispatchViewAnimationEvent
50
+ private var isTransitioning = false
51
+
41
52
  constructor() {
42
53
  throw IllegalStateException(
43
54
  "Screen fragments should never be restored. Follow instructions from https://github.com/software-mansion/react-native-screens/issues/17#issuecomment-424704067 to properly configure your main activity."
@@ -141,33 +152,52 @@ open class ScreenFragment : Fragment {
141
152
  val childScreenContainers: List<ScreenContainer<*>>
142
153
  get() = mChildScreenContainers
143
154
 
144
- fun dispatchOnWillAppear() {
155
+ private fun canDispatchEvent(event: ScreenLifecycleEvent): Boolean {
156
+ return when (event) {
157
+ ScreenLifecycleEvent.WillAppear -> canDispatchWillAppear
158
+ ScreenLifecycleEvent.Appear -> canDispatchAppear
159
+ ScreenLifecycleEvent.WillDisappear -> !canDispatchWillAppear
160
+ ScreenLifecycleEvent.Disappear -> !canDispatchAppear
161
+ }
162
+ }
163
+
164
+ private fun setLastEventDispatched(event: ScreenLifecycleEvent) {
165
+ when (event) {
166
+ ScreenLifecycleEvent.WillAppear -> canDispatchWillAppear = false
167
+ ScreenLifecycleEvent.Appear -> canDispatchAppear = false
168
+ ScreenLifecycleEvent.WillDisappear -> canDispatchWillAppear = true
169
+ ScreenLifecycleEvent.Disappear -> canDispatchAppear = true
170
+ }
171
+ }
172
+
173
+ private fun dispatchOnWillAppear() {
145
174
  dispatchEvent(ScreenLifecycleEvent.WillAppear, this)
146
175
 
147
176
  dispatchTransitionProgress(0.0f, false)
148
177
  }
149
178
 
150
- fun dispatchOnAppear() {
179
+ private fun dispatchOnAppear() {
151
180
  dispatchEvent(ScreenLifecycleEvent.Appear, this)
152
181
 
153
182
  dispatchTransitionProgress(1.0f, false)
154
183
  }
155
184
 
156
- protected fun dispatchOnWillDisappear() {
185
+ private fun dispatchOnWillDisappear() {
157
186
  dispatchEvent(ScreenLifecycleEvent.WillDisappear, this)
158
187
 
159
188
  dispatchTransitionProgress(0.0f, true)
160
189
  }
161
190
 
162
- protected fun dispatchOnDisappear() {
191
+ private fun dispatchOnDisappear() {
163
192
  dispatchEvent(ScreenLifecycleEvent.Disappear, this)
164
193
 
165
194
  dispatchTransitionProgress(1.0f, true)
166
195
  }
167
196
 
168
197
  private fun dispatchEvent(event: ScreenLifecycleEvent, fragment: ScreenFragment) {
169
- if (fragment is ScreenStackFragment) {
198
+ if (fragment is ScreenStackFragment && fragment.canDispatchEvent(event)) {
170
199
  fragment.screen.let {
200
+ fragment.setLastEventDispatched(event)
171
201
  val lifecycleEvent: Event<*> = when (event) {
172
202
  ScreenLifecycleEvent.WillAppear -> ScreenWillAppearEvent(it.id)
173
203
  ScreenLifecycleEvent.Appear -> ScreenAppearEvent(it.id)
@@ -187,12 +217,7 @@ open class ScreenFragment : Fragment {
187
217
  for (sc in mChildScreenContainers) {
188
218
  if (sc.screenCount > 0) {
189
219
  sc.topScreen?.let {
190
- if (it.stackAnimation !== Screen.StackAnimation.NONE || isRemoving) {
191
- // we do not dispatch events in child when it has `none` animation
192
- // and we are going forward since then they will be dispatched in child via
193
- // `onCreateAnimation` of ScreenStackFragment
194
- sc.topScreen?.fragment?.let { fragment -> dispatchEvent(event, fragment) }
195
- }
220
+ sc.topScreen?.fragment?.let { fragment -> dispatchEvent(event, fragment) }
196
221
  }
197
222
  }
198
223
  }
@@ -238,31 +263,37 @@ open class ScreenFragment : Fragment {
238
263
  }
239
264
 
240
265
  fun onViewAnimationStart() {
241
- // onViewAnimationStart is triggered from View#onAnimationStart method of the fragment's root
242
- // view. We override Screen#onAnimationStart and an appropriate method of the StackFragment's
243
- // root view in order to achieve this.
244
- if (isResumed) {
245
- // Android dispatches the animation start event for the fragment that is being added first
246
- // however we want the one being dismissed first to match iOS. It also makes more sense from
247
- // a navigation point of view to have the disappear event first.
248
- // Since there are no explicit relationships between the fragment being added / removed the
249
- // practical way to fix this is delaying dispatching the appear events at the end of the
250
- // frame.
251
- UiThreadUtil.runOnUiThread { dispatchOnWillAppear() }
252
- } else {
253
- dispatchOnWillDisappear()
254
- }
266
+ dispatchViewAnimationEvent(false)
255
267
  }
256
268
 
257
269
  open fun onViewAnimationEnd() {
258
- // onViewAnimationEnd is triggered from View#onAnimationEnd method of the fragment's root view.
259
- // We override Screen#onAnimationEnd and an appropriate method of the StackFragment's root view
260
- // in order to achieve this.
261
- if (isResumed) {
262
- // See the comment in onViewAnimationStart for why this event is delayed.
263
- UiThreadUtil.runOnUiThread { dispatchOnAppear() }
264
- } else {
265
- dispatchOnDisappear()
270
+ dispatchViewAnimationEvent(true)
271
+ }
272
+
273
+ private fun dispatchViewAnimationEvent(animationEnd: Boolean) {
274
+ isTransitioning = !animationEnd
275
+ // if parent fragment is transitioning, we do not want the events dispatched from the child,
276
+ // since we subscribe to parent's animation start/end and dispatch events in child from there
277
+ // check for `isTransitioning` should be enough since the child's animation should take only
278
+ // 20ms due to always being `StackAnimation.NONE` when nested stack being pushed
279
+ val parent = parentFragment
280
+ if (parent == null || (parent is ScreenFragment && !parent.isTransitioning)) {
281
+ // onViewAnimationStart/End is triggered from View#onAnimationStart/End method of the fragment's root
282
+ // view. We override an appropriate method of the StackFragment's
283
+ // root view in order to achieve this.
284
+ if (isResumed) {
285
+ // Android dispatches the animation start event for the fragment that is being added first
286
+ // however we want the one being dismissed first to match iOS. It also makes more sense from
287
+ // a navigation point of view to have the disappear event first.
288
+ // Since there are no explicit relationships between the fragment being added / removed the
289
+ // practical way to fix this is delaying dispatching the appear events at the end of the
290
+ // frame.
291
+ UiThreadUtil.runOnUiThread {
292
+ if (animationEnd) dispatchOnAppear() else dispatchOnWillAppear()
293
+ }
294
+ } else {
295
+ if (animationEnd) dispatchOnDisappear() else dispatchOnWillDisappear()
296
+ }
266
297
  }
267
298
  }
268
299