react-native-screens 4.9.0-beta.1 → 4.9.1
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 +2 -1
- package/android/build.gradle +7 -0
- package/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.kt +8 -7
- package/android/src/main/java/com/swmansion/rnscreens/bottomsheet/DimmingView.kt +20 -6
- package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenContainerManagerInterface.java +2 -2
- package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenContentWrapperManagerInterface.java +2 -2
- package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenFooterManagerInterface.java +2 -2
- package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenManagerInterface.java +2 -2
- package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenStackHeaderConfigManagerInterface.java +2 -2
- package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenStackHeaderSubviewManagerInterface.java +2 -2
- package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenStackManagerInterface.java +2 -2
- package/android/src/paper/java/com/facebook/react/viewmanagers/RNSSearchBarManagerInterface.java +2 -2
- package/android/src/paper/java/com/swmansion/rnscreens/NativeScreensModuleSpec.java +1 -2
- package/android/src/versioned/pointerevents/77/com/swmansion/rnscreens/ScreensCoordinatorLayoutPointerEventsImpl.kt +11 -0
- package/android/src/versioned/pointerevents/77/com/swmansion/rnscreens/bottomsheet/DimmingViewPointerEvents.kt +15 -0
- package/android/src/versioned/pointerevents/latest/com/swmansion/rnscreens/ScreensCoordinatorLayoutPointerEventsImpl.kt +11 -0
- package/android/src/versioned/pointerevents/latest/com/swmansion/rnscreens/bottomsheet/DimmingViewPointerEvents.kt +16 -0
- package/ios/RNSScreenStack.mm +1 -1
- package/ios/utils/RNSDefines.h +18 -0
- package/package.json +1 -1
- package/android/src/main/java/com/swmansion/rnscreens/bottomsheet/GestureTransparentViewGroup.kt +0 -23
package/README.md
CHANGED
|
@@ -107,7 +107,7 @@ Screens are already integrated with the React Native's most popular navigation l
|
|
|
107
107
|
## Supported react-native version
|
|
108
108
|
|
|
109
109
|
Below we present tables with mapping of the library version to the last supported react-native version. These tables are for the `4.x` line of the library. For compat tables
|
|
110
|
-
of `3.x` line please see
|
|
110
|
+
of `3.x` line please see [readme on the `3.x` branch](https://github.com/software-mansion/react-native-screens/tree/3.x?tab=readme-ov-file#supported-react-native-version).
|
|
111
111
|
|
|
112
112
|
### Support for Paper
|
|
113
113
|
|
|
@@ -115,6 +115,7 @@ Paper is the default rendering system for React Native versions prior to 0.76.
|
|
|
115
115
|
|
|
116
116
|
| library version | react-native version |
|
|
117
117
|
| --------------- | -------------------- |
|
|
118
|
+
| 4.9.0+ | 0.76.0+ |
|
|
118
119
|
| 4.5.0+ | 0.74.0+ |
|
|
119
120
|
| 4.0.0+ | 0.72.0+ |
|
|
120
121
|
|
package/android/build.gradle
CHANGED
|
@@ -194,6 +194,13 @@ android {
|
|
|
194
194
|
} else {
|
|
195
195
|
srcDirs += "src/versioned/backgroundcolor/latest"
|
|
196
196
|
}
|
|
197
|
+
|
|
198
|
+
// Native only classes that use PointerEvents
|
|
199
|
+
if (REACT_NATIVE_MINOR_VERSION <= 77) {
|
|
200
|
+
srcDirs += "src/versioned/pointerevents/77"
|
|
201
|
+
} else {
|
|
202
|
+
srcDirs += "src/versioned/pointerevents/latest"
|
|
203
|
+
}
|
|
197
204
|
}
|
|
198
205
|
res {
|
|
199
206
|
if (safeExtGet(['compileSdkVersion', 'compileSdk'], rnsDefaultCompileSdkVersion) >= 33) {
|
|
@@ -27,7 +27,6 @@ import androidx.appcompat.widget.Toolbar
|
|
|
27
27
|
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
|
28
28
|
import androidx.core.view.WindowInsetsCompat
|
|
29
29
|
import com.facebook.react.uimanager.PixelUtil
|
|
30
|
-
import com.facebook.react.uimanager.PointerEvents
|
|
31
30
|
import com.facebook.react.uimanager.ReactPointerEventsView
|
|
32
31
|
import com.facebook.react.uimanager.UIManagerHelper
|
|
33
32
|
import com.google.android.material.appbar.AppBarLayout
|
|
@@ -722,9 +721,16 @@ class ScreenStackFragment :
|
|
|
722
721
|
private class ScreensCoordinatorLayout(
|
|
723
722
|
context: Context,
|
|
724
723
|
private val fragment: ScreenStackFragment,
|
|
724
|
+
private val pointerEventsImpl: ReactPointerEventsView,
|
|
725
725
|
// ) : CoordinatorLayout(context), ReactCompoundViewGroup, ReactHitSlopView {
|
|
726
726
|
) : CoordinatorLayout(context),
|
|
727
|
-
ReactPointerEventsView {
|
|
727
|
+
ReactPointerEventsView by pointerEventsImpl {
|
|
728
|
+
constructor(context: Context, fragment: ScreenStackFragment) : this(
|
|
729
|
+
context,
|
|
730
|
+
fragment,
|
|
731
|
+
ScreensCoordinatorLayoutPointerEventsImpl(),
|
|
732
|
+
)
|
|
733
|
+
|
|
728
734
|
override fun onApplyWindowInsets(insets: WindowInsets?): WindowInsets = super.onApplyWindowInsets(insets)
|
|
729
735
|
|
|
730
736
|
private val animationListener: Animation.AnimationListener =
|
|
@@ -801,11 +807,6 @@ class ScreenStackFragment :
|
|
|
801
807
|
// // bottom – The Y coordinate of the bottom of the rectangle
|
|
802
808
|
// return Rect(screen.x.toInt(), -screen.y.toInt(), screen.x.toInt() + screen.width, screen.y.toInt() + screen.height)
|
|
803
809
|
// }
|
|
804
|
-
|
|
805
|
-
// We set pointer events to BOX_NONE, because we don't want the ScreensCoordinatorLayout
|
|
806
|
-
// to be target of react gestures and effectively prevent interaction with screens
|
|
807
|
-
// underneath the current screen (useful in `modal` & `formSheet` presentation).
|
|
808
|
-
override val pointerEvents: PointerEvents = PointerEvents.BOX_NONE
|
|
809
810
|
}
|
|
810
811
|
|
|
811
812
|
private class ScreensAnimation(
|
|
@@ -5,7 +5,6 @@ import android.content.Context
|
|
|
5
5
|
import android.graphics.Color
|
|
6
6
|
import android.view.MotionEvent
|
|
7
7
|
import android.view.ViewGroup
|
|
8
|
-
import com.facebook.react.uimanager.PointerEvents
|
|
9
8
|
import com.facebook.react.uimanager.ReactCompoundViewGroup
|
|
10
9
|
import com.facebook.react.uimanager.ReactPointerEventsView
|
|
11
10
|
import com.swmansion.rnscreens.ext.equalWithRespectToEps
|
|
@@ -17,13 +16,24 @@ import com.swmansion.rnscreens.ext.equalWithRespectToEps
|
|
|
17
16
|
* This dimming view has one more additional feature: it blocks gestures if its alpha > 0.
|
|
18
17
|
*/
|
|
19
18
|
@SuppressLint("ViewConstructor") // Only we instantiate this view
|
|
20
|
-
class DimmingView(
|
|
19
|
+
internal class DimmingView(
|
|
21
20
|
context: Context,
|
|
22
21
|
initialAlpha: Float = 0.6F,
|
|
22
|
+
private val pointerEventsProxy: DimmingViewPointerEventsProxy
|
|
23
23
|
) : ViewGroup(context),
|
|
24
24
|
ReactCompoundViewGroup,
|
|
25
|
-
ReactPointerEventsView {
|
|
26
|
-
|
|
25
|
+
ReactPointerEventsView by pointerEventsProxy {
|
|
26
|
+
|
|
27
|
+
constructor(context: Context, initialAlpha: Float = 0.6F) : this(
|
|
28
|
+
context, initialAlpha,
|
|
29
|
+
DimmingViewPointerEventsProxy(null)
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
init {
|
|
33
|
+
pointerEventsProxy.pointerEventsImpl = DimmingViewPointerEventsImpl(this)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
internal val blockGestures
|
|
27
37
|
get() = !alpha.equalWithRespectToEps(0F)
|
|
28
38
|
|
|
29
39
|
init {
|
|
@@ -59,8 +69,12 @@ class DimmingView(
|
|
|
59
69
|
y: Float,
|
|
60
70
|
) = blockGestures
|
|
61
71
|
|
|
62
|
-
override
|
|
63
|
-
|
|
72
|
+
override fun onDetachedFromWindow() {
|
|
73
|
+
super.onDetachedFromWindow()
|
|
74
|
+
|
|
75
|
+
// Break reference cycle, since the pointerEventsImpl strongly retains this.
|
|
76
|
+
pointerEventsProxy.pointerEventsImpl = null
|
|
77
|
+
}
|
|
64
78
|
|
|
65
79
|
companion object {
|
|
66
80
|
const val TAG = "DimmingView"
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
package com.facebook.react.viewmanagers;
|
|
11
11
|
|
|
12
12
|
import android.view.View;
|
|
13
|
-
import com.facebook.react.uimanager.ViewManagerWithGeneratedInterface;
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
|
|
15
|
+
public interface RNSScreenContainerManagerInterface<T extends View> {
|
|
16
16
|
// No props
|
|
17
17
|
}
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
package com.facebook.react.viewmanagers;
|
|
11
11
|
|
|
12
12
|
import android.view.View;
|
|
13
|
-
import com.facebook.react.uimanager.ViewManagerWithGeneratedInterface;
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
|
|
15
|
+
public interface RNSScreenContentWrapperManagerInterface<T extends View> {
|
|
16
16
|
// No props
|
|
17
17
|
}
|
package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenFooterManagerInterface.java
CHANGED
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
package com.facebook.react.viewmanagers;
|
|
11
11
|
|
|
12
12
|
import android.view.View;
|
|
13
|
-
import com.facebook.react.uimanager.ViewManagerWithGeneratedInterface;
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
|
|
15
|
+
public interface RNSScreenFooterManagerInterface<T extends View> {
|
|
16
16
|
// No props
|
|
17
17
|
}
|
package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenManagerInterface.java
CHANGED
|
@@ -13,9 +13,9 @@ import android.view.View;
|
|
|
13
13
|
import androidx.annotation.Nullable;
|
|
14
14
|
import com.facebook.react.bridge.ReadableArray;
|
|
15
15
|
import com.facebook.react.bridge.ReadableMap;
|
|
16
|
-
import com.facebook.react.uimanager.ViewManagerWithGeneratedInterface;
|
|
17
16
|
|
|
18
|
-
|
|
17
|
+
|
|
18
|
+
public interface RNSScreenManagerInterface<T extends View> {
|
|
19
19
|
void setSheetAllowedDetents(T view, @Nullable ReadableArray value);
|
|
20
20
|
void setSheetLargestUndimmedDetent(T view, int value);
|
|
21
21
|
void setSheetGrabberVisible(T view, boolean value);
|
|
@@ -11,9 +11,9 @@ package com.facebook.react.viewmanagers;
|
|
|
11
11
|
|
|
12
12
|
import android.view.View;
|
|
13
13
|
import androidx.annotation.Nullable;
|
|
14
|
-
import com.facebook.react.uimanager.ViewManagerWithGeneratedInterface;
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
|
|
16
|
+
public interface RNSScreenStackHeaderConfigManagerInterface<T extends View> {
|
|
17
17
|
void setBackgroundColor(T view, @Nullable Integer value);
|
|
18
18
|
void setBackTitle(T view, @Nullable String value);
|
|
19
19
|
void setBackTitleFontFamily(T view, @Nullable String value);
|
|
@@ -11,8 +11,8 @@ package com.facebook.react.viewmanagers;
|
|
|
11
11
|
|
|
12
12
|
import android.view.View;
|
|
13
13
|
import androidx.annotation.Nullable;
|
|
14
|
-
import com.facebook.react.uimanager.ViewManagerWithGeneratedInterface;
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
|
|
16
|
+
public interface RNSScreenStackHeaderSubviewManagerInterface<T extends View> {
|
|
17
17
|
void setType(T view, @Nullable String value);
|
|
18
18
|
}
|
package/android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenStackManagerInterface.java
CHANGED
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
package com.facebook.react.viewmanagers;
|
|
11
11
|
|
|
12
12
|
import android.view.View;
|
|
13
|
-
import com.facebook.react.uimanager.ViewManagerWithGeneratedInterface;
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
|
|
15
|
+
public interface RNSScreenStackManagerInterface<T extends View> {
|
|
16
16
|
// No props
|
|
17
17
|
}
|
package/android/src/paper/java/com/facebook/react/viewmanagers/RNSSearchBarManagerInterface.java
CHANGED
|
@@ -11,9 +11,9 @@ package com.facebook.react.viewmanagers;
|
|
|
11
11
|
|
|
12
12
|
import android.view.View;
|
|
13
13
|
import androidx.annotation.Nullable;
|
|
14
|
-
import com.facebook.react.uimanager.ViewManagerWithGeneratedInterface;
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
|
|
16
|
+
public interface RNSSearchBarManagerInterface<T extends View> {
|
|
17
17
|
void setHideWhenScrolling(T view, boolean value);
|
|
18
18
|
void setAutoCapitalize(T view, @Nullable String value);
|
|
19
19
|
void setPlaceholder(T view, @Nullable String value);
|
|
@@ -16,11 +16,10 @@ import com.facebook.proguard.annotations.DoNotStrip;
|
|
|
16
16
|
import com.facebook.react.bridge.ReactApplicationContext;
|
|
17
17
|
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
|
18
18
|
import com.facebook.react.bridge.ReactMethod;
|
|
19
|
-
import com.facebook.react.bridge.ReactModuleWithSpec;
|
|
20
19
|
import com.facebook.react.turbomodule.core.interfaces.TurboModule;
|
|
21
20
|
import javax.annotation.Nonnull;
|
|
22
21
|
|
|
23
|
-
public abstract class NativeScreensModuleSpec extends ReactContextBaseJavaModule implements
|
|
22
|
+
public abstract class NativeScreensModuleSpec extends ReactContextBaseJavaModule implements TurboModule {
|
|
24
23
|
public static final String NAME = "RNSModule";
|
|
25
24
|
|
|
26
25
|
public NativeScreensModuleSpec(ReactApplicationContext reactContext) {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
package com.swmansion.rnscreens
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.uimanager.PointerEvents
|
|
4
|
+
import com.facebook.react.uimanager.ReactPointerEventsView
|
|
5
|
+
|
|
6
|
+
internal class ScreensCoordinatorLayoutPointerEventsImpl : ReactPointerEventsView {
|
|
7
|
+
// We set pointer events to BOX_NONE, because we don't want the ScreensCoordinatorLayout
|
|
8
|
+
// to be target of react gestures and effectively prevent interaction with screens
|
|
9
|
+
// underneath the current screen (useful in `modal` & `formSheet` presentation).
|
|
10
|
+
override fun getPointerEvents(): PointerEvents = PointerEvents.BOX_NONE
|
|
11
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
package com.swmansion.rnscreens.bottomsheet
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.uimanager.PointerEvents
|
|
4
|
+
import com.facebook.react.uimanager.ReactPointerEventsView
|
|
5
|
+
import com.swmansion.rnscreens.bottomsheet.DimmingView
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
internal class DimmingViewPointerEventsImpl(val dimmingView: DimmingView) : ReactPointerEventsView {
|
|
9
|
+
override fun getPointerEvents(): PointerEvents = if (dimmingView.blockGestures == false) PointerEvents.AUTO else PointerEvents.NONE
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
internal class DimmingViewPointerEventsProxy(var pointerEventsImpl: DimmingViewPointerEventsImpl?) :
|
|
13
|
+
ReactPointerEventsView {
|
|
14
|
+
override fun getPointerEvents(): PointerEvents = pointerEventsImpl?.pointerEvents ?: PointerEvents.NONE
|
|
15
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
package com.swmansion.rnscreens
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.uimanager.PointerEvents
|
|
4
|
+
import com.facebook.react.uimanager.ReactPointerEventsView
|
|
5
|
+
|
|
6
|
+
internal class ScreensCoordinatorLayoutPointerEventsImpl() : ReactPointerEventsView {
|
|
7
|
+
// We set pointer events to BOX_NONE, because we don't want the ScreensCoordinatorLayout
|
|
8
|
+
// to be target of react gestures and effectively prevent interaction with screens
|
|
9
|
+
// underneath the current screen (useful in `modal` & `formSheet` presentation).
|
|
10
|
+
override val pointerEvents: PointerEvents = PointerEvents.BOX_NONE
|
|
11
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
package com.swmansion.rnscreens.bottomsheet
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.uimanager.PointerEvents
|
|
4
|
+
import com.facebook.react.uimanager.ReactPointerEventsView
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
internal class DimmingViewPointerEventsImpl(val dimmingView: DimmingView) : ReactPointerEventsView {
|
|
8
|
+
override val pointerEvents: PointerEvents
|
|
9
|
+
get() = if (dimmingView.blockGestures == false) PointerEvents.AUTO else PointerEvents.NONE
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
internal class DimmingViewPointerEventsProxy(var pointerEventsImpl: DimmingViewPointerEventsImpl?) :
|
|
13
|
+
ReactPointerEventsView {
|
|
14
|
+
override val pointerEvents: PointerEvents
|
|
15
|
+
get() = pointerEventsImpl?.pointerEvents ?: PointerEvents.NONE
|
|
16
|
+
}
|
package/ios/RNSScreenStack.mm
CHANGED
|
@@ -1232,7 +1232,7 @@ RNS_IGNORE_SUPER_CALL_END
|
|
|
1232
1232
|
withSurfaceTelemetry:(const facebook::react::SurfaceTelemetry &)surfaceTelemetry
|
|
1233
1233
|
{
|
|
1234
1234
|
for (const auto &mutation : transaction.getMutations()) {
|
|
1235
|
-
if (mutation
|
|
1235
|
+
if (MUTATION_PARENT_TAG(mutation) == self.tag &&
|
|
1236
1236
|
(mutation.type == react::ShadowViewMutation::Type::Insert ||
|
|
1237
1237
|
mutation.type == react::ShadowViewMutation::Type::Remove)) {
|
|
1238
1238
|
// we need to wait until children have their layout set. At this point they don't have the layout
|
package/ios/utils/RNSDefines.h
CHANGED
|
@@ -5,3 +5,21 @@
|
|
|
5
5
|
_Pragma("clang diagnostic ignored \"-Wobjc-missing-super-calls\"")
|
|
6
6
|
|
|
7
7
|
#define RNS_IGNORE_SUPER_CALL_END _Pragma("clang diagnostic pop")
|
|
8
|
+
|
|
9
|
+
#if defined __has_include
|
|
10
|
+
#if __has_include(<React-RCTAppDelegate/RCTReactNativeFactory.h>) ||\
|
|
11
|
+
__has_include(<React_RCTAppDelegate/RCTReactNativeFactory.h>) // added in 78; underscore is used in dynamic frameworks
|
|
12
|
+
#define RNS_REACT_NATIVE_VERSION_MINOR_BELOW_78 0
|
|
13
|
+
#else
|
|
14
|
+
#define RNS_REACT_NATIVE_VERSION_MINOR_BELOW_78 1
|
|
15
|
+
#endif
|
|
16
|
+
#else
|
|
17
|
+
#define RNS_REACT_NATIVE_VERSION_MINOR_BELOW_78 \
|
|
18
|
+
1 // Wild guess, close eyes and hope for the best.
|
|
19
|
+
#endif
|
|
20
|
+
|
|
21
|
+
#if RNS_REACT_NATIVE_VERSION_MINOR_BELOW_78
|
|
22
|
+
#define MUTATION_PARENT_TAG(mutation) mutation.parentShadowView.tag
|
|
23
|
+
#else
|
|
24
|
+
#define MUTATION_PARENT_TAG(mutation) mutation.parentTag
|
|
25
|
+
#endif
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-screens",
|
|
3
|
-
"version": "4.9.
|
|
3
|
+
"version": "4.9.1",
|
|
4
4
|
"description": "Native navigation primitives for your React Native app.",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"submodules": "git submodule update --init --recursive && (cd react-navigation && yarn && yarn build && cd ../)",
|
package/android/src/main/java/com/swmansion/rnscreens/bottomsheet/GestureTransparentViewGroup.kt
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
package com.swmansion.rnscreens.bottomsheet
|
|
2
|
-
|
|
3
|
-
import android.content.Context
|
|
4
|
-
import android.widget.FrameLayout
|
|
5
|
-
import com.facebook.react.uimanager.PointerEvents
|
|
6
|
-
import com.facebook.react.uimanager.ReactPointerEventsView
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* View group that will be ignored by RN event system, and won't be target of touches.
|
|
10
|
-
*
|
|
11
|
-
* Currently used as container for the form sheet, so that user can interact with the view
|
|
12
|
-
* under the sheet (otherwise RN captures the gestures).
|
|
13
|
-
*/
|
|
14
|
-
class GestureTransparentViewGroup(
|
|
15
|
-
context: Context,
|
|
16
|
-
) : FrameLayout(context),
|
|
17
|
-
ReactPointerEventsView {
|
|
18
|
-
override val pointerEvents: PointerEvents = PointerEvents.BOX_NONE
|
|
19
|
-
|
|
20
|
-
companion object {
|
|
21
|
-
const val TAG = "GestureTransparentFrameLayout"
|
|
22
|
-
}
|
|
23
|
-
}
|