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.
- package/LICENSE +1 -1
- package/README.md +13 -7
- package/RNScreens.podspec +36 -6
- package/android/build.gradle +74 -3
- package/android/src/fabric/java/com/swmansion/rnscreens/FabricEnabledViewGroup.kt +49 -0
- package/android/src/fabric/java/com/swmansion/rnscreens/RNScreensComponentsRegistry.java +28 -0
- package/android/src/main/java/com/swmansion/rnscreens/RNScreensPackage.kt +11 -2
- package/android/src/main/java/com/swmansion/rnscreens/Screen.kt +52 -21
- package/android/src/main/java/com/swmansion/rnscreens/ScreenContainer.kt +1 -1
- package/android/src/main/java/com/swmansion/rnscreens/ScreenFragment.kt +64 -33
- package/android/src/main/java/com/swmansion/rnscreens/ScreenStack.kt +9 -31
- package/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.kt +0 -30
- package/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfig.kt +12 -5
- package/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfigViewManager.kt +83 -18
- package/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderSubviewManager.kt +17 -5
- package/android/src/main/java/com/swmansion/rnscreens/ScreenStackViewManager.kt +14 -1
- package/android/src/main/java/com/swmansion/rnscreens/ScreenViewManager.kt +41 -14
- package/android/src/main/java/com/swmansion/rnscreens/ScreenWindowTraits.kt +72 -11
- package/android/src/main/java/com/swmansion/rnscreens/SearchBarManager.kt +18 -1
- package/android/src/main/java/com/swmansion/rnscreens/SearchBarView.kt +7 -2
- package/android/src/main/java/com/swmansion/rnscreens/SearchViewFormatter.kt +29 -2
- package/android/src/main/jni/Android.mk +45 -0
- package/android/src/main/jni/OnLoad.cpp +9 -0
- package/android/src/main/jni/RNScreensComponentsRegistry.cpp +66 -0
- package/android/src/main/jni/RNScreensComponentsRegistry.h +34 -0
- package/android/src/main/res/anim/rns_default_enter_in.xml +18 -0
- package/android/src/main/res/anim/rns_default_enter_out.xml +19 -0
- package/android/src/main/res/anim/rns_default_exit_in.xml +17 -0
- package/android/src/main/res/anim/rns_default_exit_out.xml +18 -0
- package/android/src/main/res/anim/rns_fade_in.xml +7 -0
- package/android/src/main/res/anim/rns_fade_out.xml +7 -0
- package/android/src/main/res/anim/rns_no_animation_20.xml +6 -0
- package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenManagerDelegate.java +71 -0
- package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenManagerInterface.java +30 -0
- package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenStackHeaderConfigManagerDelegate.java +104 -0
- package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenStackHeaderConfigManagerInterface.java +41 -0
- package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenStackHeaderSubviewManagerDelegate.java +31 -0
- package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenStackHeaderSubviewManagerInterface.java +17 -0
- package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenStackManagerDelegate.java +25 -0
- package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenStackManagerInterface.java +16 -0
- package/android/src/paper/java/com/swmansion/rnscreens/FabricEnabledViewGroup.kt +16 -0
- package/common/cpp/Android.mk +38 -0
- package/common/cpp/rnscreens/RNSScreenComponentDescriptor.h +41 -0
- package/common/cpp/rnscreens/RNSScreenShadowNode.cpp +9 -0
- package/common/cpp/rnscreens/RNSScreenShadowNode.h +29 -0
- package/common/cpp/rnscreens/RNSScreenState.cpp +14 -0
- package/common/cpp/rnscreens/RNSScreenState.h +46 -0
- package/createNativeStackNavigator/README.md +12 -0
- package/ios/RNSScreen.h +10 -0
- package/ios/RNSScreen.m +34 -0
- package/ios/RNSScreenComponentView.h +23 -0
- package/ios/RNSScreenComponentView.mm +159 -0
- package/ios/RNSScreenContainer.m +5 -0
- package/ios/RNSScreenController.h +10 -0
- package/ios/RNSScreenController.mm +79 -0
- package/ios/RNSScreenStack.m +22 -7
- package/ios/RNSScreenStackAnimator.m +45 -14
- package/ios/RNSScreenStackComponentView.h +15 -0
- package/ios/RNSScreenStackComponentView.mm +295 -0
- package/ios/RNSScreenStackHeaderConfig.m +4 -1
- package/ios/RNSScreenStackHeaderConfigComponentView.h +42 -0
- package/ios/RNSScreenStackHeaderConfigComponentView.mm +662 -0
- package/ios/RNSScreenStackHeaderSubviewComponentView.h +14 -0
- package/ios/RNSScreenStackHeaderSubviewComponentView.mm +77 -0
- package/ios/RNSScreenWindowTraits.h +1 -0
- package/ios/RNSScreenWindowTraits.m +20 -0
- package/ios/UIViewController+RNScreens.m +10 -0
- package/ios/utils/RNSUIBarButtonItem.h +5 -0
- package/ios/utils/RNSUIBarButtonItem.mm +22 -0
- package/lib/commonjs/fabric/Screen.js +27 -0
- package/lib/commonjs/fabric/Screen.js.map +1 -0
- package/lib/commonjs/fabric/ScreenNativeComponent.js +23 -0
- package/lib/commonjs/fabric/ScreenNativeComponent.js.map +1 -0
- package/lib/commonjs/fabric/ScreenStack.js +27 -0
- package/lib/commonjs/fabric/ScreenStack.js.map +1 -0
- package/lib/commonjs/fabric/ScreenStackHeaderConfigNativeComponent.js +27 -0
- package/lib/commonjs/fabric/ScreenStackHeaderConfigNativeComponent.js.map +1 -0
- package/lib/commonjs/fabric/ScreenStackHeaderSubview.js +34 -0
- package/lib/commonjs/fabric/ScreenStackHeaderSubview.js.map +1 -0
- package/lib/commonjs/fabric/ScreenStackHeaderSubviewNativeComponent.js +27 -0
- package/lib/commonjs/fabric/ScreenStackHeaderSubviewNativeComponent.js.map +1 -0
- package/lib/commonjs/fabric/ScreenStackNativeComponent.js +21 -0
- package/lib/commonjs/fabric/ScreenStackNativeComponent.js.map +1 -0
- package/lib/commonjs/fabric/index.js +40 -0
- package/lib/commonjs/fabric/index.js.map +1 -0
- package/lib/commonjs/index.native.js +32 -15
- package/lib/commonjs/index.native.js.map +1 -1
- package/lib/commonjs/native-stack/views/NativeStackView.js +33 -4
- package/lib/commonjs/native-stack/views/NativeStackView.js.map +1 -1
- package/lib/module/fabric/Screen.js +11 -0
- package/lib/module/fabric/Screen.js.map +1 -0
- package/lib/module/fabric/ScreenNativeComponent.js +11 -0
- package/lib/module/fabric/ScreenNativeComponent.js.map +1 -0
- package/lib/module/fabric/ScreenStack.js +12 -0
- package/lib/module/fabric/ScreenStack.js.map +1 -0
- package/lib/module/fabric/ScreenStackHeaderConfigNativeComponent.js +10 -0
- package/lib/module/fabric/ScreenStackHeaderConfigNativeComponent.js.map +1 -0
- package/lib/module/fabric/ScreenStackHeaderSubview.js +21 -0
- package/lib/module/fabric/ScreenStackHeaderSubview.js.map +1 -0
- package/lib/module/fabric/ScreenStackHeaderSubviewNativeComponent.js +10 -0
- package/lib/module/fabric/ScreenStackHeaderSubviewNativeComponent.js.map +1 -0
- package/lib/module/fabric/ScreenStackNativeComponent.js +9 -0
- package/lib/module/fabric/ScreenStackNativeComponent.js.map +1 -0
- package/lib/module/fabric/index.js +6 -0
- package/lib/module/fabric/index.js.map +1 -0
- package/lib/module/index.native.js +32 -15
- package/lib/module/index.native.js.map +1 -1
- package/lib/module/native-stack/views/NativeStackView.js +33 -4
- package/lib/module/native-stack/views/NativeStackView.js.map +1 -1
- package/lib/typescript/native-stack/types.d.ts +34 -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 +60 -5
- package/native-stack/README.md +39 -3
- package/package.json +17 -3
- package/reanimated/package.json +6 -0
- package/src/fabric/Screen.js +12 -0
- package/src/fabric/ScreenNativeComponent.js +64 -0
- package/src/fabric/ScreenStack.js +8 -0
- package/src/fabric/ScreenStackHeaderConfigNativeComponent.js +54 -0
- package/src/fabric/ScreenStackHeaderSubview.js +20 -0
- package/src/fabric/ScreenStackHeaderSubviewNativeComponent.js +31 -0
- package/src/fabric/ScreenStackNativeComponent.js +19 -0
- package/src/fabric/index.js +11 -0
- package/src/index.native.tsx +35 -14
- package/src/native-stack/types.tsx +34 -0
- package/src/native-stack/views/NativeStackView.tsx +33 -4
- 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
|
|
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/
|
|
127
|
-
- for older versions to the [README in react-native-screens/createNativeStackNavigator](https://github.com/software-mansion/react-native-screens/tree/
|
|
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/
|
|
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/
|
|
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/
|
|
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
|
|
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
|
+
[](https://shopify.com)
|
|
174
180
|
[](https://expo.io)
|
|
175
|
-
[](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
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
|
package/android/build.gradle
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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?) :
|
|
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
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
185
|
+
private fun dispatchOnWillDisappear() {
|
|
157
186
|
dispatchEvent(ScreenLifecycleEvent.WillDisappear, this)
|
|
158
187
|
|
|
159
188
|
dispatchTransitionProgress(0.0f, true)
|
|
160
189
|
}
|
|
161
190
|
|
|
162
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
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
|
|