react-native-navigation 7.24.3-snapshot.492 → 7.25.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.
@@ -2,6 +2,8 @@ package com.reactnativenavigation.options;
2
2
 
3
3
  import android.content.Context;
4
4
 
5
+
6
+ import com.reactnativenavigation.options.layout.LayoutOptions;
5
7
  import com.reactnativenavigation.options.params.NullNumber;
6
8
  import com.reactnativenavigation.options.params.NullText;
7
9
  import com.reactnativenavigation.options.parsers.TypefaceLoader;
@@ -0,0 +1,44 @@
1
+ package com.reactnativenavigation.options.layout
2
+
3
+ import com.reactnativenavigation.utils.dp
4
+ import org.json.JSONObject
5
+
6
+ class LayoutInsets(
7
+ var top: Int?=null,
8
+ var left: Int?=null,
9
+ var bottom: Int?=null,
10
+ var right: Int?=null
11
+ ) {
12
+ fun merge(toMerge: LayoutInsets?, defaults: LayoutInsets?) {
13
+ toMerge?.let { options->
14
+ options.top?.let { this.top = it }
15
+ options.bottom?.let { this.bottom = it }
16
+ options.left?.let { this.left = it }
17
+ options.right?.let { this.right = it }
18
+ }
19
+
20
+ defaults?.let {
21
+ options->
22
+ top = top?:options.top
23
+ left = left?:options.left
24
+ right = right?:options.right
25
+ bottom = bottom?:options.bottom
26
+ }
27
+ }
28
+
29
+ companion object{
30
+ fun parse(jsonObject: JSONObject?): LayoutInsets {
31
+ return LayoutInsets(
32
+ jsonObject?.optInt("top")?.dp,
33
+ jsonObject?.optInt("left")?.dp,
34
+ jsonObject?.optInt("bottom")?.dp,
35
+ jsonObject?.optInt("right")?.dp
36
+ )
37
+ }
38
+ }
39
+
40
+ fun hasValue(): Boolean {
41
+ return top!=null || bottom!=null || left!=null || right!=null
42
+ }
43
+
44
+ }
@@ -0,0 +1,71 @@
1
+ package com.reactnativenavigation.options.layout
2
+
3
+ import android.content.Context
4
+ import com.reactnativenavigation.options.LayoutDirection
5
+ import com.reactnativenavigation.options.OrientationOptions
6
+ import com.reactnativenavigation.options.params.*
7
+ import com.reactnativenavigation.options.params.Number
8
+ import com.reactnativenavigation.options.parsers.BoolParser
9
+ import com.reactnativenavigation.options.parsers.NumberParser
10
+ import org.json.JSONObject
11
+
12
+ class LayoutOptions {
13
+ @JvmField
14
+ var backgroundColor: ThemeColour = NullThemeColour()
15
+
16
+ @JvmField
17
+ var componentBackgroundColor: ThemeColour = NullThemeColour()
18
+
19
+ @JvmField
20
+ var topMargin: Number = NullNumber()
21
+
22
+ @JvmField
23
+ var adjustResize: Bool = NullBool()
24
+
25
+ @JvmField
26
+ var orientation = OrientationOptions()
27
+
28
+ @JvmField
29
+ var direction = LayoutDirection.DEFAULT
30
+
31
+ var insets: LayoutInsets = LayoutInsets()
32
+
33
+
34
+ fun mergeWith(other: LayoutOptions) {
35
+ if (other.backgroundColor.hasValue()) backgroundColor = other.backgroundColor
36
+ if (other.componentBackgroundColor.hasValue()) componentBackgroundColor = other.componentBackgroundColor
37
+ if (other.topMargin.hasValue()) topMargin = other.topMargin
38
+ if (other.orientation.hasValue()) orientation = other.orientation
39
+ if (other.direction.hasValue()) direction = other.direction
40
+ if (other.adjustResize.hasValue()) adjustResize = other.adjustResize
41
+ insets.merge(other.insets, null)
42
+ }
43
+
44
+ fun mergeWithDefault(defaultOptions: LayoutOptions) {
45
+ if (!backgroundColor.hasValue()) backgroundColor = defaultOptions.backgroundColor
46
+ if (!componentBackgroundColor.hasValue()) componentBackgroundColor = defaultOptions.componentBackgroundColor
47
+ if (!topMargin.hasValue()) topMargin = defaultOptions.topMargin
48
+ if (!orientation.hasValue()) orientation = defaultOptions.orientation
49
+ if (!direction.hasValue()) direction = defaultOptions.direction
50
+ if (!adjustResize.hasValue()) adjustResize = defaultOptions.adjustResize
51
+ insets.merge(null, defaultOptions.insets)
52
+
53
+ }
54
+
55
+ companion object {
56
+ @JvmStatic
57
+ fun parse(context: Context?, json: JSONObject?): LayoutOptions {
58
+ val result = LayoutOptions()
59
+ if (json == null) return result
60
+ result.backgroundColor = ThemeColour.parse(context!!, json.optJSONObject("backgroundColor"))
61
+ result.componentBackgroundColor = ThemeColour.parse(context, json.optJSONObject("componentBackgroundColor"))
62
+ result.topMargin = NumberParser.parse(json, "topMargin")
63
+ result.insets = LayoutInsets.parse(json.optJSONObject("insets"))
64
+ result.orientation = OrientationOptions.parse(json)
65
+ result.direction = LayoutDirection.fromString(json.optString("direction", ""))
66
+ result.adjustResize = BoolParser.parse(json, "adjustResize")
67
+ return result
68
+ }
69
+ }
70
+
71
+ }
@@ -0,0 +1,9 @@
1
+ package com.reactnativenavigation.utils
2
+
3
+ import android.content.res.Resources
4
+
5
+ val Int.dp: Int
6
+ get() = (this * Resources.getSystem().displayMetrics.density).toInt()
7
+
8
+ val Float.dp: Int
9
+ get() = (this * Resources.getSystem().displayMetrics.density).toInt()
@@ -144,16 +144,17 @@ public class ComponentViewController extends ChildController<ComponentLayout> {
144
144
  protected WindowInsetsCompat onApplyWindowInsets(View view, WindowInsetsCompat insets) {
145
145
  ViewController<?> viewController = findController(view);
146
146
  if (viewController == null || viewController.getView() == null) return insets;
147
- final Insets keyboardInsets = insets.getInsets( WindowInsetsCompat.Type.ime());
147
+ final int keyboardBottomInset = options.layout.adjustResize.get(true) ? insets.getInsets( WindowInsetsCompat.Type.ime()).bottom : 0;
148
148
  final Insets systemBarsInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars() );
149
149
  final int visibleNavBar = resolveCurrentOptions(presenter.defaultOptions).navigationBar.isVisible.isTrueOrUndefined()?1:0;
150
150
  final WindowInsetsCompat finalInsets = new WindowInsetsCompat.Builder().setInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.ime(),
151
151
  Insets.of(systemBarsInsets.left,
152
152
  0,
153
153
  systemBarsInsets.right,
154
- Math.max(visibleNavBar*systemBarsInsets.bottom,keyboardInsets.bottom))
154
+ Math.max(visibleNavBar*systemBarsInsets.bottom,keyboardBottomInset))
155
155
  ).build();
156
- return ViewCompat.onApplyWindowInsets(viewController.getView(), finalInsets);
156
+ ViewCompat.onApplyWindowInsets(viewController.getView(), finalInsets);
157
+ return insets;
157
158
  }
158
159
 
159
160
  @Override
@@ -4,11 +4,13 @@ import android.app.Activity;
4
4
  import android.content.res.Configuration;
5
5
  import android.view.View;
6
6
  import android.view.ViewGroup;
7
+ import android.view.WindowInsets;
7
8
 
8
9
  import androidx.annotation.NonNull;
9
10
  import androidx.annotation.Nullable;
10
11
  import androidx.annotation.RestrictTo;
11
12
  import androidx.coordinatorlayout.widget.CoordinatorLayout;
13
+ import androidx.core.view.WindowInsetsCompat;
12
14
 
13
15
  import com.facebook.react.ReactInstanceManager;
14
16
  import com.reactnativenavigation.options.Options;
@@ -82,6 +84,8 @@ public class Navigator extends ParentController<ViewGroup> {
82
84
  overlaysLayout = new CoordinatorLayout(getActivity());
83
85
  }
84
86
 
87
+
88
+
85
89
  public void bindViews() {
86
90
  modalStack.setModalsLayout(modalsLayout);
87
91
  modalStack.setRootLayout(rootLayout);
@@ -147,6 +151,7 @@ public class Navigator extends ParentController<ViewGroup> {
147
151
  final ViewController<?> disappearing = previousRoot;
148
152
  root = appearing;
149
153
  root.setOverlay(new RootOverlay(getActivity(), contentLayout));
154
+ root.setParentController(this);
150
155
  rootPresenter.setRoot(appearing, disappearing, defaultOptions, new CommandListenerAdapter(commandListener) {
151
156
  @Override
152
157
  public void onSuccess(String childId) {
@@ -5,18 +5,17 @@ import android.graphics.Color;
5
5
  import android.graphics.drawable.ColorDrawable;
6
6
  import android.graphics.drawable.Drawable;
7
7
  import android.graphics.drawable.LayerDrawable;
8
- import android.os.Build;
9
8
  import android.view.View;
9
+ import android.view.ViewGroup;
10
10
  import android.view.ViewGroup.MarginLayoutParams;
11
11
  import android.view.Window;
12
12
 
13
- import androidx.core.content.ContextCompat;
14
-
15
13
  import com.reactnativenavigation.options.NavigationBarOptions;
16
14
  import com.reactnativenavigation.options.Options;
17
15
  import com.reactnativenavigation.options.OrientationOptions;
18
16
  import com.reactnativenavigation.options.StatusBarOptions;
19
17
  import com.reactnativenavigation.options.StatusBarOptions.TextColorScheme;
18
+ import com.reactnativenavigation.options.layout.LayoutInsets;
20
19
  import com.reactnativenavigation.options.params.Bool;
21
20
  import com.reactnativenavigation.utils.SystemUiUtils;
22
21
  import com.reactnativenavigation.viewcontrollers.parent.ParentController;
@@ -25,6 +24,7 @@ import com.reactnativenavigation.viewcontrollers.navigator.Navigator;
25
24
  public class Presenter {
26
25
  private final Activity activity;
27
26
  private Options defaultOptions;
27
+
28
28
  public Presenter(Activity activity, Options defaultOptions) {
29
29
  this.activity = activity;
30
30
  this.defaultOptions = defaultOptions;
@@ -40,9 +40,15 @@ public class Presenter {
40
40
  }
41
41
 
42
42
  public void mergeOptions(ViewController<?> viewController, Options options) {
43
- final Options withDefaults = viewController.resolveCurrentOptions().copy().mergeWith(options).withDefaultOptions(defaultOptions);
43
+ final Options withDefaults = viewController.resolveCurrentOptions().copy().mergeWith(options).withDefaultOptions(defaultOptions);
44
44
  mergeStatusBarOptions(viewController.getView(), withDefaults.statusBar);
45
45
  mergeNavigationBarOptions(withDefaults.navigationBar);
46
+ applyLayoutInsetsOnMostTopParent(viewController,withDefaults.layout.getInsets());
47
+ }
48
+
49
+ private void applyLayoutInsetsOnMostTopParent(ViewController<?> viewController, LayoutInsets layoutInsets) {
50
+ final ViewController<?> topMostParent = viewController.getTopMostParent();
51
+ applyLayoutInsets(topMostParent.getView(), layoutInsets);
46
52
  }
47
53
 
48
54
  public void applyOptions(ViewController view, Options options) {
@@ -65,6 +71,16 @@ public class Presenter {
65
71
  private void applyViewOptions(ViewController view, Options options) {
66
72
  applyBackgroundColor(view, options);
67
73
  applyTopMargin(view.getView(), options);
74
+ applyLayoutInsetsOnMostTopParent(view, options.layout.getInsets());
75
+ }
76
+
77
+ private void applyLayoutInsets(ViewGroup view, LayoutInsets layoutInsets) {
78
+ if ( view!=null && layoutInsets.hasValue()) {
79
+ view.setPadding(layoutInsets.getLeft() == null ? view.getPaddingLeft() : layoutInsets.getLeft(),
80
+ layoutInsets.getTop() == null ? view.getPaddingTop() : layoutInsets.getTop(),
81
+ layoutInsets.getRight() == null ?view.getPaddingRight() : layoutInsets.getRight(),
82
+ layoutInsets.getBottom() == null ? view.getPaddingBottom() : layoutInsets.getBottom());
83
+ }
68
84
  }
69
85
 
70
86
  private void applyTopMargin(View view, Options options) {
@@ -209,12 +225,12 @@ public class Presenter {
209
225
  }
210
226
 
211
227
  private void setNavigationBarBackgroundColor(NavigationBarOptions navigationBar) {
212
- int navigationBarDefaultColor = SystemUiUtils.INSTANCE.getNavigationBarDefaultColor();
213
- navigationBarDefaultColor = navigationBarDefaultColor==-1?Color.BLACK:navigationBarDefaultColor;
228
+ int navigationBarDefaultColor = SystemUiUtils.INSTANCE.getNavigationBarDefaultColor();
229
+ navigationBarDefaultColor = navigationBarDefaultColor == -1 ? Color.BLACK : navigationBarDefaultColor;
214
230
  if (navigationBar.backgroundColor.canApplyValue()) {
215
231
  int color = navigationBar.backgroundColor.get(navigationBarDefaultColor);
216
232
  SystemUiUtils.setNavigationBarBackgroundColor(activity.getWindow(), color, isColorLight(color));
217
- }else{
233
+ } else {
218
234
  SystemUiUtils.setNavigationBarBackgroundColor(activity.getWindow(), navigationBarDefaultColor, isColorLight(navigationBarDefaultColor));
219
235
 
220
236
  }
@@ -1,5 +1,8 @@
1
1
  package com.reactnativenavigation.viewcontrollers.viewcontroller;
2
2
 
3
+ import static com.reactnativenavigation.utils.CollectionUtils.forEach;
4
+ import static com.reactnativenavigation.utils.ObjectUtils.perform;
5
+
3
6
  import android.app.Activity;
4
7
  import android.content.res.Configuration;
5
8
  import android.view.View;
@@ -31,9 +34,6 @@ import com.reactnativenavigation.views.component.Renderable;
31
34
  import java.util.ArrayList;
32
35
  import java.util.List;
33
36
 
34
- import static com.reactnativenavigation.utils.CollectionUtils.forEach;
35
- import static com.reactnativenavigation.utils.ObjectUtils.perform;
36
-
37
37
  public abstract class ViewController<T extends ViewGroup> implements ViewTreeObserver.OnGlobalLayoutListener,
38
38
  ViewGroup.OnHierarchyChangeListener,
39
39
  BehaviourAdapter {
@@ -157,6 +157,14 @@ public abstract class ViewController<T extends ViewGroup> implements ViewTreeObs
157
157
  }
158
158
  }
159
159
 
160
+ public ViewController<?> getTopMostParent(){
161
+ if(parentController!=null){
162
+ return parentController.getTopMostParent();
163
+ }else{
164
+ return this;
165
+ }
166
+ }
167
+
160
168
  @CallSuper
161
169
  public void applyOptions(Options options) {
162
170
 
@@ -289,6 +297,7 @@ public abstract class ViewController<T extends ViewGroup> implements ViewTreeObs
289
297
  if (view.getParent() instanceof ViewGroup) {
290
298
  ((ViewManager) view.getParent()).removeView(view);
291
299
  }
300
+ setParentController(null);
292
301
  view = null;
293
302
  isDestroyed = true;
294
303
  }
@@ -133,6 +133,16 @@ export interface OptionsLayout {
133
133
  * #### (iOS specific)
134
134
  */
135
135
  autoHideHomeIndicator?: boolean;
136
+ /**
137
+ * Add insets to the top layout
138
+ */
139
+ insets?: Insets;
140
+ /**
141
+ * Resizes the layout when keyboard is visible
142
+ * @default true
143
+ * #### (Android specific)
144
+ */
145
+ adjustResize?: boolean;
136
146
  }
137
147
  export declare enum OptionsModalPresentationStyle {
138
148
  formSheet = "formSheet",
@@ -58,6 +58,15 @@
58
58
  }
59
59
 
60
60
  - (void)applyOptions:(RNNNavigationOptions *)options {
61
+ UIViewController *viewController = self.boundViewController;
62
+ RNNNavigationOptions *withDefault = [options withDefault:[self defaultOptions]];
63
+ if (withDefault.layout.insets.hasValue) {
64
+ viewController.topMostViewController.additionalSafeAreaInsets =
65
+ UIEdgeInsetsMake([withDefault.layout.insets.top withDefault:0],
66
+ [withDefault.layout.insets.left withDefault:0],
67
+ [withDefault.layout.insets.bottom withDefault:0],
68
+ [withDefault.layout.insets.right withDefault:0]);
69
+ }
61
70
  }
62
71
 
63
72
  - (void)mergeOptions:(RNNNavigationOptions *)mergeOptions
@@ -83,6 +92,14 @@
83
92
  _prefersHomeIndicatorAutoHidden = mergeOptions.layout.autoHideHomeIndicator.get;
84
93
  [self.boundViewController setNeedsUpdateOfHomeIndicatorAutoHidden];
85
94
  }
95
+
96
+ if (mergeOptions.layout.insets.hasValue) {
97
+ self.boundViewController.topMostViewController.additionalSafeAreaInsets =
98
+ UIEdgeInsetsMake([withDefault.layout.insets.top withDefault:0],
99
+ [withDefault.layout.insets.left withDefault:0],
100
+ [withDefault.layout.insets.bottom withDefault:0],
101
+ [withDefault.layout.insets.right withDefault:0]);
102
+ }
86
103
  }
87
104
 
88
105
  - (void)renderComponents:(RNNNavigationOptions *)options
@@ -88,6 +88,7 @@
88
88
  }
89
89
 
90
90
  - (void)viewDidLayoutSubviews {
91
+ [super viewDidLayoutSubviews];
91
92
  [self.presenter viewDidLayoutSubviews];
92
93
  [_dotIndicatorPresenter bottomTabsDidLayoutSubviews:self];
93
94
  }
@@ -111,6 +111,11 @@
111
111
  [self updateReactViewConstraints];
112
112
  }
113
113
 
114
+ - (void)viewDidLayoutSubviews {
115
+ [super viewDidLayoutSubviews];
116
+ [self.presenter applyOptionsOnViewDidLayoutSubviews:self.resolveOptions];
117
+ }
118
+
114
119
  - (void)updateReactViewConstraints {
115
120
  if (self.isViewLoaded && self.reactView) {
116
121
  [NSLayoutConstraint deactivateConstraints:_reactViewConstraints];
@@ -1,5 +1,5 @@
1
+ #import "RNNInsetsOptions.h"
1
2
  #import "RNNOptions.h"
2
-
3
3
  @interface RNNLayoutOptions : RNNOptions
4
4
 
5
5
  @property(nonatomic, strong) Color *backgroundColor;
@@ -7,6 +7,7 @@
7
7
  @property(nonatomic, strong) Text *direction;
8
8
  @property(nonatomic, strong) id orientation;
9
9
  @property(nonatomic, strong) Bool *autoHideHomeIndicator;
10
+ @property(nonatomic, strong) RNNInsetsOptions *insets;
10
11
 
11
12
  - (UIInterfaceOrientationMask)supportedOrientations;
12
13
 
@@ -11,6 +11,7 @@
11
11
  self.direction = [TextParser parse:dict key:@"direction"];
12
12
  self.orientation = dict[@"orientation"];
13
13
  self.autoHideHomeIndicator = [BoolParser parse:dict key:@"autoHideHomeIndicator"];
14
+ self.insets = [[RNNInsetsOptions alloc] initWithDict:dict[@"insets"]];
14
15
  return self;
15
16
  }
16
17
 
@@ -25,6 +26,9 @@
25
26
  self.orientation = options.orientation;
26
27
  if (options.autoHideHomeIndicator)
27
28
  self.autoHideHomeIndicator = options.autoHideHomeIndicator;
29
+ if (options.insets.hasValue) {
30
+ self.insets = options.insets;
31
+ }
28
32
  }
29
33
 
30
34
  - (UIInterfaceOrientationMask)supportedOrientations {
@@ -88,6 +88,7 @@
88
88
  }
89
89
 
90
90
  - (void)applyOptionsOnViewDidLayoutSubviews:(RNNNavigationOptions *)options {
91
+ [super applyOptionsOnViewDidLayoutSubviews:options];
91
92
  RNNNavigationOptions *withDefault = [options withDefault:[self defaultOptions]];
92
93
  if (withDefault.topBar.background.component.name.hasValue) {
93
94
  [self presentBackgroundComponent];
@@ -180,6 +180,18 @@ export interface OptionsLayout {
180
180
  * #### (iOS specific)
181
181
  */
182
182
  autoHideHomeIndicator?: boolean;
183
+
184
+ /**
185
+ * Add insets to the top layout
186
+ */
187
+ insets?: Insets;
188
+
189
+ /**
190
+ * Resizes the layout when keyboard is visible
191
+ * @default true
192
+ * #### (Android specific)
193
+ */
194
+ adjustResize?: boolean;
183
195
  }
184
196
 
185
197
  export enum OptionsModalPresentationStyle {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-navigation",
3
- "version": "7.24.3-snapshot.492",
3
+ "version": "7.25.0",
4
4
  "description": "React Native Navigation - truly native navigation for iOS and Android",
5
5
  "license": "MIT",
6
6
  "nativePackage": true,
@@ -66,6 +66,8 @@
66
66
  "tslib": "1.9.3"
67
67
  },
68
68
  "devDependencies": {
69
+ "pixelmatch": "^5.2.1",
70
+ "pngjs": "^6.0.0",
69
71
  "@babel/plugin-proposal-export-default-from": "7.10.1",
70
72
  "@babel/plugin-proposal-export-namespace-from": "7.10.1",
71
73
  "@babel/types": "7.15.6",
@@ -1,48 +0,0 @@
1
- package com.reactnativenavigation.options;
2
-
3
- import android.content.Context;
4
-
5
- import com.reactnativenavigation.options.params.NullNumber;
6
- import com.reactnativenavigation.options.params.Number;
7
- import com.reactnativenavigation.options.params.ThemeColour;
8
- import com.reactnativenavigation.options.params.NullThemeColour;
9
- import com.reactnativenavigation.options.parsers.NumberParser;
10
-
11
- import org.json.JSONObject;
12
-
13
- public class LayoutOptions {
14
- public static LayoutOptions parse(Context context, JSONObject json) {
15
- LayoutOptions result = new LayoutOptions();
16
- if (json == null) return result;
17
-
18
- result.backgroundColor = ThemeColour.parse(context, json.optJSONObject("backgroundColor"));
19
- result.componentBackgroundColor = ThemeColour.parse(context, json.optJSONObject("componentBackgroundColor"));
20
- result.topMargin = NumberParser.parse(json, "topMargin");
21
- result.orientation = OrientationOptions.parse(json);
22
- result.direction = LayoutDirection.fromString(json.optString("direction", ""));
23
-
24
- return result;
25
- }
26
-
27
- public ThemeColour backgroundColor = new NullThemeColour();
28
- public ThemeColour componentBackgroundColor = new NullThemeColour();
29
- public Number topMargin = new NullNumber();
30
- public OrientationOptions orientation = new OrientationOptions();
31
- public LayoutDirection direction = LayoutDirection.DEFAULT;
32
-
33
- public void mergeWith(LayoutOptions other) {
34
- if (other.backgroundColor.hasValue()) backgroundColor = other.backgroundColor;
35
- if (other.componentBackgroundColor.hasValue()) componentBackgroundColor = other.componentBackgroundColor;
36
- if (other.topMargin.hasValue()) topMargin = other.topMargin;
37
- if (other.orientation.hasValue()) orientation = other.orientation;
38
- if (other.direction.hasValue()) direction = other.direction;
39
- }
40
-
41
- public void mergeWithDefault(LayoutOptions defaultOptions) {
42
- if (!backgroundColor.hasValue()) backgroundColor = defaultOptions.backgroundColor;
43
- if (!componentBackgroundColor.hasValue()) componentBackgroundColor = defaultOptions.componentBackgroundColor;
44
- if (!topMargin.hasValue()) topMargin = defaultOptions.topMargin;
45
- if (!orientation.hasValue()) orientation = defaultOptions.orientation;
46
- if (!direction.hasValue()) direction = defaultOptions.direction;
47
- }
48
- }