react-native-navigation 7.23.1-snapshot.310 → 7.23.1-snapshot.365

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 (44) hide show
  1. package/jest.config.js +40 -0
  2. package/lib/android/app/build.gradle +14 -12
  3. package/lib/android/app/src/main/java/com/reactnativenavigation/options/FontOptions.kt +2 -2
  4. package/lib/android/app/src/main/java/com/reactnativenavigation/options/LayoutFactory.java +32 -17
  5. package/lib/android/app/src/main/java/com/reactnativenavigation/options/Options.java +1 -1
  6. package/lib/android/app/src/main/java/com/reactnativenavigation/options/parsers/TypefaceLoader.kt +16 -10
  7. package/lib/android/app/src/main/java/com/reactnativenavigation/react/modal/ModalFrameLayout.kt +1 -1
  8. package/lib/android/app/src/main/java/com/reactnativenavigation/utils/StatusBarUtils.kt +39 -0
  9. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabPresenter.java +5 -2
  10. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/component/ComponentViewController.java +7 -6
  11. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/modal/ModalPresenter.java +6 -4
  12. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/StackController.java +14 -6
  13. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/topbar/TopBarController.kt +1 -1
  14. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/topbar/button/ButtonSpan.kt +1 -1
  15. package/lib/android/app/src/reactNative51/java/com/reactnativenavigation/react/NavigationReactNativeHost.java +2 -1
  16. package/lib/android/app/src/test/java/com/reactnativenavigation/mocks/TypefaceLoaderMock.kt +4 -0
  17. package/lib/android/app/src/test/java/com/reactnativenavigation/utils/LayoutFactoryTest.java +25 -2
  18. package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/modal/ModalPresenterTest.java +4 -0
  19. package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/modal/ModalStackTest.java +13 -1
  20. package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/navigator/NavigatorTest.java +2 -2
  21. package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/StackControllerTest.kt +10 -5
  22. package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/TopBarControllerTest.kt +10 -9
  23. package/lib/dist/commands/LayoutTreeCrawler.js +1 -1
  24. package/lib/dist/commands/OptionsProcessor.js +2 -2
  25. package/lib/dist/components/Store.d.ts +2 -0
  26. package/lib/dist/components/Store.js +8 -0
  27. package/lib/ios/RNNAssert.h +2 -2
  28. package/lib/ios/RNNBottomTabOptions.m +2 -1
  29. package/lib/ios/RNNButtonBuilder.m +3 -3
  30. package/lib/ios/RNNButtonOptions.m +4 -4
  31. package/lib/ios/RNNCommandsHandler.m +1 -4
  32. package/lib/ios/RNNDotIndicatorPresenter.m +2 -1
  33. package/lib/ios/RNNModalManager.h +2 -0
  34. package/lib/ios/RNNModalManager.m +13 -6
  35. package/lib/ios/RNNSegmentedControl.h +1 -1
  36. package/lib/ios/RNNTabBarItemCreator.m +3 -2
  37. package/lib/ios/RNNUIBarButtonItem.h +1 -1
  38. package/lib/ios/RNNUIBarButtonItem.m +3 -3
  39. package/lib/ios/TopBarPresenter.m +8 -4
  40. package/lib/src/commands/LayoutTreeCrawler.ts +1 -1
  41. package/lib/src/commands/OptionsProcessor.ts +2 -2
  42. package/lib/src/components/Store.ts +9 -0
  43. package/package.json +12 -53
  44. package/lib/android/app/src/main/java/com/reactnativenavigation/utils/StatusBarUtils.java +0 -41
package/jest.config.js ADDED
@@ -0,0 +1,40 @@
1
+ module.exports = {
2
+ preset: 'react-native',
3
+ transformIgnorePatterns: [
4
+ 'node_modules/(?!(@react-native|react-native|react-native-ui-lib|react-native-animatable)/)',
5
+ ],
6
+ transform: {
7
+ '\\.[jt]sx?$': 'babel-jest',
8
+ },
9
+ roots: [
10
+ '<rootDir>/lib/src/',
11
+ '<rootDir>/playground/src/',
12
+ '<rootDir>/integration/',
13
+ '<rootDir>/scripts/',
14
+ '<rootDir>/e2e/',
15
+ ],
16
+ setupFilesAfterEnv: ['./jest-setup.js'],
17
+ testPathIgnorePatterns: ['/node_modules/'],
18
+ moduleNameMapper: {
19
+ 'react-native-navigation/Mock': '<rootDir>/lib/src/Mock',
20
+ 'react-native-navigation': '<rootDir>/lib/src',
21
+ '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
22
+ '<rootDir>/playground/img/layouts@2x.png',
23
+ },
24
+ collectCoverageFrom: [
25
+ 'lib/src/**/*.ts',
26
+ 'lib/src/**/*.tsx',
27
+ 'integration/**/*.js',
28
+ '!lib/dist/index.js',
29
+ '!lib/dist/Navigation.js',
30
+ '!lib/dist/adapters/**/*',
31
+ '!lib/dist/interfaces/**/*',
32
+ '!lib/dist/**/*.test.*',
33
+ '!integration/**/*.test.*',
34
+ '!integration/*.test.*',
35
+ '!e2e/**/*test.js',
36
+ ],
37
+ resetMocks: true,
38
+ resetModules: true,
39
+ coverageReporters: ['json', 'lcov', 'text', 'html'],
40
+ };
@@ -3,27 +3,29 @@ import org.gradle.api.tasks.testing.logging.TestExceptionFormat
3
3
 
4
4
  apply plugin: 'com.android.library'
5
5
  apply plugin: 'kotlin-android'
6
- apply plugin: 'kotlin-android-extensions'
7
6
 
8
7
  def safeExtGet(prop, fallback) {
9
8
  rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
10
9
  }
11
10
 
12
- def DEFAULT_COMPILE_SDK_VERSION = 29
13
- def DEFAULT_MIN_SDK_VERSION = 19
14
- def DEFAULT_TARGET_SDK_VERSION = 29
15
- def kotlinVersion = rootProject.ext.get("RNNKotlinVersion")
16
- def kotlinStdlib = safeExtGet('RNNKotlinStdlib', 'kotlin-stdlib-jdk8')
17
- def kotlinCoroutinesCore = safeExtGet('RNNKotlinCoroutinesCore', '1.4.3')
11
+ def safeExtGetFallbackLowerBound(prop, fallback) {
12
+ Math.max(safeExtGet(prop,fallback),fallback)
13
+ }
18
14
 
15
+ def DEFAULT_COMPILE_SDK_VERSION = 30
16
+ def DEFAULT_MIN_SDK_VERSION = 21
17
+ def DEFAULT_TARGET_SDK_VERSION = 30
18
+ def DEFAULT_KOTLIN_VERSION = "1.5.31"
19
+ def DEFAULT_KOTLIN_STDLIB = 'kotlin-stdlib-jdk8'
20
+ def kotlinVersion = safeExtGet("RNNKotlinVersion", DEFAULT_KOTLIN_VERSION)
21
+ def kotlinStdlib = safeExtGet('RNNKotlinStdlib',DEFAULT_KOTLIN_STDLIB )
22
+ def kotlinCoroutinesCore = safeExtGet('RNNKotlinCoroutinesCore', '1.5.2')
19
23
  android {
20
- compileSdkVersion safeExtGet('compileSdkVersion', DEFAULT_COMPILE_SDK_VERSION)
24
+ compileSdkVersion safeExtGetFallbackLowerBound('compileSdkVersion', DEFAULT_COMPILE_SDK_VERSION)
21
25
 
22
26
  defaultConfig {
23
- minSdkVersion safeExtGet('minSdkVersion', DEFAULT_MIN_SDK_VERSION)
24
- targetSdkVersion safeExtGet('targetSdkVersion', DEFAULT_TARGET_SDK_VERSION)
25
- versionCode 1
26
- versionName "1.0"
27
+ minSdkVersion safeExtGetFallbackLowerBound('minSdkVersion', DEFAULT_MIN_SDK_VERSION)
28
+ targetSdkVersion safeExtGetFallbackLowerBound('targetSdkVersion', DEFAULT_TARGET_SDK_VERSION)
27
29
  }
28
30
  buildTypes {
29
31
  release {
@@ -26,11 +26,11 @@ class FontOptions {
26
26
 
27
27
  @JvmOverloads fun getTypeface(typefaceLoader: TypefaceLoader, defaultTypeface: Typeface? = null): Typeface? {
28
28
  if (isDirty) {
29
- _typeface = typefaceLoader.getTypeFace(fontFamily.get(""), fontStyle.get(""), fontWeight.get(""))
29
+ _typeface = typefaceLoader.getTypeFace(fontFamily.get(null), fontStyle.get(""), fontWeight.get(""), defaultTypeface)
30
30
  isDirty = false
31
31
  }
32
32
  return _typeface
33
- ?: defaultTypeface?.let { typefaceLoader.getTypeFace(fontFamily.get(""), fontStyle.get(""), fontWeight.get(""), it) }
33
+ ?: defaultTypeface?.let { typefaceLoader.getTypeFace(fontFamily.get(null), fontStyle.get(""), fontWeight.get(""), it) }
34
34
  }
35
35
 
36
36
  fun mergeWith(other: FontOptions) {
@@ -1,9 +1,11 @@
1
1
  package com.reactnativenavigation.options;
2
2
 
3
3
  import android.app.Activity;
4
+ import android.content.Context;
4
5
 
5
6
  import com.facebook.react.ReactInstanceManager;
6
7
  import com.facebook.react.bridge.ReactContext;
8
+ import com.reactnativenavigation.NavigationApplication;
7
9
  import com.reactnativenavigation.options.parsers.TypefaceLoader;
8
10
  import com.reactnativenavigation.react.events.EventEmitter;
9
11
  import com.reactnativenavigation.utils.Assertions;
@@ -45,6 +47,8 @@ import androidx.annotation.RestrictTo;
45
47
  import static com.reactnativenavigation.options.Options.parse;
46
48
  import static com.reactnativenavigation.utils.CollectionUtils.*;
47
49
 
50
+ import org.json.JSONObject;
51
+
48
52
  public class LayoutFactory {
49
53
  private Activity activity;
50
54
  private ChildControllersRegistry childRegistry;
@@ -75,15 +79,15 @@ public class LayoutFactory {
75
79
  final ReactContext context = reactInstanceManager.getCurrentReactContext();
76
80
  switch (node.type) {
77
81
  case Component:
78
- return createComponent(context, node);
82
+ return createComponent(node);
79
83
  case ExternalComponent:
80
84
  return createExternalComponent(context, node);
81
85
  case Stack:
82
- return createStack(context, node);
86
+ return createStack(node);
83
87
  case BottomTabs:
84
- return createBottomTabs(context, node);
88
+ return createBottomTabs(node);
85
89
  case SideMenuRoot:
86
- return createSideMenuRoot(context, node);
90
+ return createSideMenuRoot(node);
87
91
  case SideMenuCenter:
88
92
  return createSideMenuContent(node);
89
93
  case SideMenuLeft:
@@ -91,17 +95,17 @@ public class LayoutFactory {
91
95
  case SideMenuRight:
92
96
  return createSideMenuRight(node);
93
97
  case TopTabs:
94
- return createTopTabs(context, node);
98
+ return createTopTabs(node);
95
99
  default:
96
100
  throw new IllegalArgumentException("Invalid node type: " + node.type);
97
101
  }
98
102
  }
99
103
 
100
- private ViewController<?> createSideMenuRoot(ReactContext context, LayoutNode node) {
104
+ private ViewController<?> createSideMenuRoot(LayoutNode node) {
101
105
  SideMenuController sideMenuController = new SideMenuController(activity,
102
106
  childRegistry,
103
107
  node.id,
104
- parse(context, typefaceManager, node.getOptions()),
108
+ parseOptions( node.getOptions()),
105
109
  new SideMenuPresenter(),
106
110
  new Presenter(activity, defaultOptions)
107
111
  );
@@ -153,7 +157,7 @@ public class LayoutFactory {
153
157
  return create(node.children.get(0));
154
158
  }
155
159
 
156
- private ViewController<?> createComponent(ReactContext context, LayoutNode node) {
160
+ private ViewController<?> createComponent(LayoutNode node) {
157
161
  String id = node.id;
158
162
  String name = node.data.optString("name");
159
163
  return new ComponentViewController(activity,
@@ -161,7 +165,7 @@ public class LayoutFactory {
161
165
  id,
162
166
  name,
163
167
  new ComponentViewCreator(reactInstanceManager),
164
- parse(context, typefaceManager, node.getOptions()),
168
+ parseOptions(node.getOptions()),
165
169
  new Presenter(activity, defaultOptions),
166
170
  new ComponentPresenter(defaultOptions)
167
171
  );
@@ -178,17 +182,17 @@ public class LayoutFactory {
178
182
  reactInstanceManager,
179
183
  new EventEmitter(context),
180
184
  new ExternalComponentPresenter(),
181
- parse(context, typefaceManager, node.getOptions())
185
+ parseOptions(node.getOptions())
182
186
  );
183
187
  }
184
188
 
185
- private ViewController<?> createStack(ReactContext context, LayoutNode node) {
189
+ private ViewController<?> createStack(LayoutNode node) {
186
190
  return new StackControllerBuilder(activity, eventEmitter)
187
191
  .setChildren(createChildren(node.children))
188
192
  .setChildRegistry(childRegistry)
189
193
  .setTopBarController(new TopBarController())
190
194
  .setId(node.id)
191
- .setInitialOptions(parse(context, typefaceManager, node.getOptions()))
195
+ .setInitialOptions(parseOptions(node.getOptions()))
192
196
  .setStackPresenter(new StackPresenter(activity,
193
197
  new TitleBarReactViewCreator(reactInstanceManager),
194
198
  new TopBarBackgroundViewCreator(reactInstanceManager),
@@ -210,7 +214,7 @@ public class LayoutFactory {
210
214
  return result;
211
215
  }
212
216
 
213
- private ViewController<?> createBottomTabs(ReactContext context, LayoutNode node) {
217
+ private ViewController<?> createBottomTabs(LayoutNode node) {
214
218
  List<ViewController<?>> tabs = map(node.children, this::create);
215
219
  BottomTabsPresenter bottomTabsPresenter = new BottomTabsPresenter(tabs, defaultOptions, new BottomTabsAnimator());
216
220
  return new BottomTabsController(activity,
@@ -219,24 +223,35 @@ public class LayoutFactory {
219
223
  eventEmitter,
220
224
  new ImageLoader(),
221
225
  node.id,
222
- parse(context, typefaceManager, node.getOptions()),
226
+ parseOptions( node.getOptions()),
223
227
  new Presenter(activity, defaultOptions),
224
228
  new BottomTabsAttacher(tabs, bottomTabsPresenter, defaultOptions),
225
229
  bottomTabsPresenter,
226
230
  new BottomTabPresenter(activity, tabs, new ImageLoader(), new TypefaceLoader(activity), defaultOptions));
227
231
  }
228
232
 
229
- private ViewController<?> createTopTabs(ReactContext context, LayoutNode node) {
233
+ private ViewController<?> createTopTabs(LayoutNode node) {
230
234
  final List<ViewController<?>> tabs = new ArrayList<>();
231
235
  for (int i = 0; i < node.children.size(); i++) {
232
236
  ViewController<?> tabController = create(node.children.get(i));
233
- Options options = parse(context, typefaceManager, node.children.get(i).getOptions());
237
+ Options options = parseOptions(node.children.get(i).getOptions());
234
238
  options.setTopTabIndex(i);
235
239
  tabs.add(tabController);
236
240
  }
237
- return new TopTabsController(activity, childRegistry, node.id, tabs, new TopTabsLayoutCreator(activity, tabs), parse(context, typefaceManager, node.getOptions()), new Presenter(activity, defaultOptions));
241
+ return new TopTabsController(activity, childRegistry, node.id, tabs, new TopTabsLayoutCreator(activity, tabs)
242
+ , parseOptions(node.getOptions()), new Presenter(activity, defaultOptions));
238
243
  }
239
244
 
245
+ private Options parseOptions(JSONObject jsonOptions) {
246
+ Context context = reactInstanceManager.getCurrentReactContext();
247
+ if (context == null) {
248
+ context = activity == null ? NavigationApplication.instance : activity;
249
+ }
250
+ if (typefaceManager == null) {
251
+ typefaceManager = new TypefaceLoader(context);
252
+ }
253
+ return parse(context, typefaceManager, jsonOptions);
254
+ }
240
255
  @NonNull
241
256
  @RestrictTo(RestrictTo.Scope.TESTS)
242
257
  public Options getDefaultOptions() {
@@ -15,7 +15,7 @@ public class Options {
15
15
  public static final Options EMPTY = new Options();
16
16
 
17
17
  @NonNull
18
- public static Options parse(Context context, TypefaceLoader typefaceManager, JSONObject json) {
18
+ public static Options parse(@NonNull Context context, TypefaceLoader typefaceManager, JSONObject json) {
19
19
  Options result = new Options();
20
20
  if (json == null) return result;
21
21
 
@@ -2,21 +2,27 @@ package com.reactnativenavigation.options.parsers
2
2
 
3
3
  import android.content.Context
4
4
  import android.graphics.Typeface
5
+ import com.aurelhubert.ahbottomnavigation.AHTextView
5
6
  import com.reactnativenavigation.utils.ReactTypefaceUtils
6
7
 
7
8
  open class TypefaceLoader(private val context: Context) {
8
- @JvmOverloads open fun getTypeFace(
9
- fontFamilyName: String?,
10
- fontStyle: String?,
11
- fontWeight: String?,
12
- defaultTypeFace: Typeface? = null
9
+ open val defaultTypeFace: Typeface by lazy {
10
+ AHTextView(context).typeface ?: Typeface.DEFAULT
11
+ }
12
+
13
+ @JvmOverloads
14
+ open fun getTypeFace(
15
+ fontFamilyName: String?,
16
+ fontStyle: String?,
17
+ fontWeight: String?,
18
+ defaultTypeFace: Typeface? = null
13
19
  ): Typeface? {
14
20
  return ReactTypefaceUtils.applyStyles(
15
- defaultTypeFace,
16
- ReactTypefaceUtils.parseFontStyle(fontStyle),
17
- ReactTypefaceUtils.parseFontWeight(fontWeight),
18
- fontFamilyName,
19
- context.assets
21
+ defaultTypeFace,
22
+ ReactTypefaceUtils.parseFontStyle(fontStyle),
23
+ ReactTypefaceUtils.parseFontWeight(fontWeight),
24
+ fontFamilyName,
25
+ context.assets
20
26
  )
21
27
  }
22
28
  }
@@ -11,7 +11,7 @@ class ModalFrameLayout(context: ReactContext) : FrameLayout(context) {
11
11
  addView(modalContentLayout, MarginLayoutParams(MarginLayoutParams.WRAP_CONTENT, MarginLayoutParams.WRAP_CONTENT)
12
12
  .apply {
13
13
  val translucent = context.currentActivity?.window?.let {
14
- StatusBarUtils.isTranslucent(context.currentActivity?.window)
14
+ StatusBarUtils.isTranslucent(it)
15
15
  } ?: false
16
16
  topMargin = if (translucent) 0 else StatusBarUtils.getStatusBarHeight(context)
17
17
  })
@@ -0,0 +1,39 @@
1
+ package com.reactnativenavigation.utils
2
+
3
+ import android.content.Context
4
+ import android.os.Build
5
+ import android.view.Window
6
+ import android.view.WindowManager
7
+
8
+ object StatusBarUtils {
9
+ private const val STATUS_BAR_HEIGHT_M = 24
10
+ private const val STATUS_BAR_HEIGHT_L = 25
11
+ private var statusBarHeight = -1
12
+ @JvmStatic
13
+ fun saveStatusBarHeight(height: Int) {
14
+ statusBarHeight = height
15
+ }
16
+ @JvmStatic
17
+ fun getStatusBarHeight(context: Context): Int {
18
+ if (statusBarHeight > 0) {
19
+ return statusBarHeight
20
+ }
21
+ val resources = context.resources
22
+ val resourceId = resources.getIdentifier("status_bar_height", "dimen", "android")
23
+ statusBarHeight = if (resourceId > 0) resources.getDimensionPixelSize(resourceId) else UiUtils.dpToPx(
24
+ context,
25
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) STATUS_BAR_HEIGHT_M else STATUS_BAR_HEIGHT_L
26
+ )
27
+ return statusBarHeight
28
+ }
29
+ @JvmStatic
30
+ fun getStatusBarHeightDp(context: Context): Int {
31
+ return UiUtils.pxToDp(context, getStatusBarHeight(context).toFloat())
32
+ .toInt()
33
+ }
34
+ @JvmStatic
35
+ fun isTranslucent(window: Window): Boolean {
36
+ val lp = window.attributes
37
+ return lp != null && lp.flags and WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS == WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
38
+ }
39
+ }
@@ -9,6 +9,7 @@ import android.graphics.drawable.Drawable;
9
9
 
10
10
  import androidx.annotation.NonNull;
11
11
 
12
+ import com.aurelhubert.ahbottomnavigation.AHTextView;
12
13
  import com.aurelhubert.ahbottomnavigation.notification.AHNotification;
13
14
  import com.reactnativenavigation.options.BottomTabOptions;
14
15
  import com.reactnativenavigation.options.DotIndicatorOptions;
@@ -27,6 +28,7 @@ public class BottomTabPresenter {
27
28
  private final Context context;
28
29
  private final ImageLoader imageLoader;
29
30
  private final TypefaceLoader typefaceLoader;
31
+ private final Typeface defaultTypeface;
30
32
  private Options defaultOptions;
31
33
  private final BottomTabFinder bottomTabFinder;
32
34
  private final LateInit<BottomTabs> bottomTabs = new LateInit<>();
@@ -39,6 +41,7 @@ public class BottomTabPresenter {
39
41
  this.bottomTabFinder = new BottomTabFinder(tabs);
40
42
  this.imageLoader = imageLoader;
41
43
  this.typefaceLoader = typefaceLoader;
44
+ this.defaultTypeface = typefaceLoader.getDefaultTypeFace();
42
45
  this.defaultOptions = defaultOptions;
43
46
  defaultDotIndicatorSize = dpToPx(context, 6);
44
47
  }
@@ -57,7 +60,7 @@ public class BottomTabPresenter {
57
60
  BottomTabOptions tab = tabs.get(i).resolveCurrentOptions(defaultOptions).bottomTabOptions;
58
61
  bottomTabs.setIconWidth(i, tab.iconWidth.get(null));
59
62
  bottomTabs.setIconHeight(i, tab.iconHeight.get(null));
60
- bottomTabs.setTitleTypeface(i, tab.font.getTypeface(typefaceLoader, Typeface.DEFAULT));
63
+ bottomTabs.setTitleTypeface(i, tab.font.getTypeface(typefaceLoader, defaultTypeface));
61
64
  if (tab.selectedIconColor.canApplyValue()) bottomTabs.setIconActiveColor(i, tab.selectedIconColor.get(null));
62
65
  if (tab.iconColor.canApplyValue()) bottomTabs.setIconInactiveColor(i, tab.iconColor.get(null));
63
66
  bottomTabs.setTitleActiveColor(i, tab.selectedTextColor.get(null));
@@ -86,7 +89,7 @@ public class BottomTabPresenter {
86
89
  BottomTabOptions tab = options.bottomTabOptions;
87
90
  if (tab.iconWidth.hasValue()) bottomTabs.setIconWidth(index, tab.iconWidth.get(null));
88
91
  if (tab.iconHeight.hasValue()) bottomTabs.setIconHeight(index, tab.iconHeight.get(null));
89
- if (tab.font.hasValue()) bottomTabs.setTitleTypeface(index, tab.font.getTypeface(typefaceLoader, Typeface.DEFAULT));
92
+ if (tab.font.hasValue()) bottomTabs.setTitleTypeface(index, tab.font.getTypeface(typefaceLoader, defaultTypeface));
90
93
  if (canMergeColor(tab.selectedIconColor)) bottomTabs.setIconActiveColor(index, tab.selectedIconColor.get());
91
94
  if (canMergeColor(tab.iconColor)) bottomTabs.setIconInactiveColor(index, tab.iconColor.get());
92
95
  if (tab.selectedTextColor.hasValue()) bottomTabs.setTitleActiveColor(index, tab.selectedTextColor.get());
@@ -15,6 +15,7 @@ import com.reactnativenavigation.viewcontrollers.viewcontroller.ViewController;
15
15
  import com.reactnativenavigation.views.component.ComponentLayout;
16
16
 
17
17
  import androidx.annotation.NonNull;
18
+ import androidx.core.graphics.Insets;
18
19
  import androidx.core.view.ViewCompat;
19
20
  import androidx.core.view.WindowInsetsCompat;
20
21
 
@@ -137,13 +138,13 @@ public class ComponentViewController extends ChildController<ComponentLayout> {
137
138
 
138
139
  @Override
139
140
  protected WindowInsetsCompat applyWindowInsets(ViewController<?> view, WindowInsetsCompat insets) {
140
- ViewCompat.onApplyWindowInsets(view.getView(), insets.replaceSystemWindowInsets(
141
- insets.getSystemWindowInsetLeft(),
142
- insets.getSystemWindowInsetTop(),
141
+ final WindowInsetsCompat.Builder builder = new WindowInsetsCompat.Builder();
142
+ final WindowInsetsCompat finalInsets = builder.setSystemWindowInsets(Insets.of(insets.getSystemWindowInsetLeft(),
143
+ Math.max(insets.getSystemWindowInsetTop() - getTopInset(), 0),
143
144
  insets.getSystemWindowInsetRight(),
144
- Math.max(insets.getSystemWindowInsetBottom() - getBottomInset(), 0)
145
- ));
146
- return insets;
145
+ Math.max(insets.getSystemWindowInsetBottom() - getBottomInset(), 0))).build();
146
+ ViewCompat.onApplyWindowInsets(view.getView(), finalInsets);
147
+ return finalInsets;
147
148
  }
148
149
 
149
150
  @Override
@@ -90,10 +90,12 @@ public class ModalPresenter {
90
90
  }
91
91
 
92
92
  private void onShowModalEnd(ViewController<?> toAdd, @Nullable ViewController<?> toRemove, CommandListener listener) {
93
- toAdd.onViewDidAppear();
94
- if (toRemove != null && toAdd.resolveCurrentOptions(defaultOptions).modal.presentationStyle != ModalPresentationStyle.OverCurrentContext) {
95
- toRemove.detachView();
96
- }
93
+ toAdd.addOnAppearedListener(()->{
94
+ toAdd.onViewDidAppear();
95
+ if (toRemove != null && toAdd.resolveCurrentOptions(defaultOptions).modal.presentationStyle != ModalPresentationStyle.OverCurrentContext) {
96
+ toRemove.detachView();
97
+ }
98
+ });
97
99
  listener.onSuccess(toAdd.getId());
98
100
  }
99
101
 
@@ -5,6 +5,7 @@ import android.content.res.Configuration;
5
5
  import android.view.View;
6
6
  import android.view.ViewGroup;
7
7
 
8
+ import com.facebook.react.ReactRootView;
8
9
  import com.reactnativenavigation.options.ButtonOptions;
9
10
  import com.reactnativenavigation.options.Options;
10
11
  import com.reactnativenavigation.options.StackAnimationOptions;
@@ -175,9 +176,7 @@ public class StackController extends ParentController<StackLayout> {
175
176
  presenter.getAdditionalPushAnimations(this, child, resolvedOptions),
176
177
  () -> onPushAnimationComplete(child, toRemove, listener));
177
178
  } else {
178
- child.onViewDidAppear();
179
- getView().removeView(toRemove.getView());
180
- listener.onSuccess(child.getId());
179
+ onPushAnimationComplete(child, toRemove, listener);
181
180
  }
182
181
  } else {
183
182
  listener.onSuccess(child.getId());
@@ -191,8 +190,10 @@ public class StackController extends ParentController<StackLayout> {
191
190
  }
192
191
 
193
192
  private void onPushAnimationComplete(ViewController<?> toAdd, ViewController<?> toRemove, CommandListener listener) {
194
- toAdd.onViewDidAppear();
195
- if (!peek().equals(toRemove)) getView().removeView(toRemove.getView());
193
+ toAdd.addOnAppearedListener(() -> {
194
+ toAdd.onViewDidAppear();
195
+ if (!peek().equals(toRemove)) getView().removeView(toRemove.getView());
196
+ });
196
197
  listener.onSuccess(toAdd.getId());
197
198
  }
198
199
 
@@ -421,12 +422,19 @@ public class StackController extends ParentController<StackLayout> {
421
422
  if (isEmpty()) return;
422
423
  ViewController<?> childController = peek();
423
424
  ViewGroup child = childController.getView();
424
- child.setId(CompatUtils.generateViewId());
425
+ setChildId(child);
425
426
  childController.addOnAppearedListener(this::startChildrenBellowTopChild);
426
427
  stackLayout.addView(child, 0, matchParentWithBehaviour(new StackBehaviour(this)));
427
428
  presenter.applyInitialChildLayoutOptions(resolveCurrentOptions());
428
429
  }
429
430
 
431
+ private void setChildId(ViewGroup child) {
432
+ //From RN > 64 we can't set id to child that is ReactRootView
433
+ //see:https://github.com/facebook/react-native/blob/main/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java#L676
434
+ if (!(child instanceof ReactRootView))
435
+ child.setId(CompatUtils.generateViewId());
436
+ }
437
+
430
438
  private void startChildrenBellowTopChild() {
431
439
  ArrayList<ViewController<?>> children = new ArrayList<>(getChildControllers());
432
440
  for (int i = children.size() - 2; i >= 0; i--) {
@@ -250,9 +250,9 @@ open class TopBarController(private val animator: TopBarAnimator = TopBarAnimato
250
250
  }
251
251
  toRemove.forEach {
252
252
  buttonBar.removeButton(it.value.buttonIntId)
253
- btnControllers.remove(it.key)
254
253
  }
255
254
  toDestroy.values.forEach {
255
+ btnControllers.remove(it.id)
256
256
  it.destroy()
257
257
  }
258
258
  toAdd.forEach {
@@ -25,7 +25,7 @@ class ButtonSpan(
25
25
 
26
26
  fun apply(paint: Paint) {
27
27
  with(button.font) {
28
- val typeface = getTypeface(typefaceLoader, Typeface.DEFAULT)
28
+ val typeface = getTypeface(typefaceLoader, paint.typeface)
29
29
  val fakeStyle = (paint.typeface?.style ?: 0) and (typeface?.style?.inv() ?: 1)
30
30
  if (fakeStyle and Typeface.BOLD != 0) paint.isFakeBoldText = true
31
31
  if (fakeStyle and Typeface.ITALIC != 0) paint.textSkewX = -0.25f
@@ -8,6 +8,7 @@ import com.facebook.react.ReactPackage;
8
8
  import com.facebook.react.common.LifecycleState;
9
9
  import com.facebook.react.devsupport.interfaces.DevBundleDownloadListener;
10
10
  import com.reactnativenavigation.NavigationApplication;
11
+ import com.facebook.hermes.reactexecutor.HermesExecutorFactory;
11
12
 
12
13
  import androidx.annotation.NonNull;
13
14
  import androidx.annotation.Nullable;
@@ -44,7 +45,7 @@ public abstract class NavigationReactNativeHost extends ReactNativeHost implemen
44
45
  .setJSMainModulePath(getJSMainModuleName())
45
46
  .setUseDeveloperSupport(getUseDeveloperSupport())
46
47
  .setRedBoxHandler(getRedBoxHandler())
47
- .setJavaScriptExecutorFactory(getJavaScriptExecutorFactory())
48
+ .setJavaScriptExecutorFactory(new HermesExecutorFactory())
48
49
  .setUIImplementationProvider(getUIImplementationProvider())
49
50
  .setInitialLifecycleState(LifecycleState.BEFORE_CREATE)
50
51
  .setDevBundleDownloadListener(getDevBundleDownloadListener());
@@ -9,8 +9,12 @@ class TypefaceLoaderMock() : TypefaceLoader(mock()) {
9
9
 
10
10
  constructor(mockTypefaces: Map<String, Typeface>?) : this() {
11
11
  this.mockTypefaces = mockTypefaces
12
+
12
13
  }
13
14
 
15
+ override val defaultTypeFace: Typeface
16
+ get() = Typeface.DEFAULT
17
+
14
18
  override fun getTypeFace(fontFamilyName: String?, fontStyle: String?, fontWeight: String?, defaultTypeFace: Typeface?): Typeface? {
15
19
  return mockTypefaces?.getOrDefault(fontFamilyName, defaultTypeFace) ?: defaultTypeFace
16
20
  }
@@ -15,14 +15,19 @@ import org.mockito.Mockito;
15
15
  import java.util.HashMap;
16
16
 
17
17
  import static org.assertj.core.api.Java6Assertions.assertThat;
18
+ import static org.assertj.core.api.Java6Assertions.fail;
18
19
  import static org.mockito.Mockito.mock;
20
+ import static org.mockito.Mockito.when;
19
21
 
20
22
  public class LayoutFactoryTest extends BaseTest {
21
23
  private LayoutFactory uut;
24
+ private ReactInstanceManager mockReactInstanceManager;
22
25
 
23
26
  @Override
24
27
  public void beforeEach() {
25
- uut = new LayoutFactory(mock(ReactInstanceManager.class));
28
+ super.beforeEach();
29
+ mockReactInstanceManager = mock(ReactInstanceManager.class);
30
+ uut = new LayoutFactory(mockReactInstanceManager);
26
31
  uut.init(
27
32
  newActivity(),
28
33
  Mockito.mock(EventEmitter.class),
@@ -36,6 +41,16 @@ public class LayoutFactoryTest extends BaseTest {
36
41
  assertThat(uut.create(component())).isNotNull();
37
42
  }
38
43
 
44
+ @Test
45
+ public void shouldParseOptionsWhenReactContextIsNull() {
46
+ when(mockReactInstanceManager.getCurrentReactContext()).thenReturn(null);
47
+ try {
48
+ uut.create(component());
49
+ } catch (Exception e) {
50
+ fail("Create should not fail! when react instance has null context");
51
+ }
52
+ }
53
+
39
54
  @Test
40
55
  public void defaultOptionsAreNotNull() {
41
56
  assertThat(uut.getDefaultOptions()).isNotNull();
@@ -50,6 +65,14 @@ public class LayoutFactoryTest extends BaseTest {
50
65
  }
51
66
 
52
67
  private LayoutNode component() throws JSONException {
53
- return new LayoutNode("Component1", LayoutNode.Type.Component, new JSONObject().put("name", "com.component"), null);
68
+ final JSONObject component = new JSONObject();
69
+ final JSONObject layout = new JSONObject();
70
+ final JSONObject backgroundColor = new JSONObject();
71
+ backgroundColor.put("dark",0);
72
+ backgroundColor.put("light",1);
73
+ layout.put("backgroundColor",backgroundColor );
74
+ component.put("name", "com.component");
75
+ component.put("options",new JSONObject().put("layout", layout));
76
+ return new LayoutNode("Component1", LayoutNode.Type.Component, component, null);
54
77
  }
55
78
  }
@@ -50,6 +50,7 @@ public class ModalPresenterTest extends BaseTest {
50
50
 
51
51
  @Override
52
52
  public void beforeEach() {
53
+ super.beforeEach();
53
54
  Activity activity = newActivity();
54
55
  ChildControllersRegistry childRegistry = new ChildControllersRegistry();
55
56
 
@@ -210,6 +211,7 @@ public class ModalPresenterTest extends BaseTest {
210
211
  uut.setRootLayout(spy);
211
212
 
212
213
  uut.showModal(modal1, root, new CommandListenerAdapter());
214
+ idleMainLooper();
213
215
  uut.dismissModal(modal1, root, root, new CommandListenerAdapter());
214
216
 
215
217
  verify(spy).addView(root.getView(), 0);
@@ -237,6 +239,7 @@ public class ModalPresenterTest extends BaseTest {
237
239
  verify(modal1).onViewWillAppear();
238
240
 
239
241
  uut.showModal(modal2, modal1, new CommandListenerAdapter());
242
+ idleMainLooper();
240
243
  assertThat(modal1.getView().getParent()).isNull();
241
244
 
242
245
  Shadows.shadowOf(Looper.getMainLooper()).idle();
@@ -253,6 +256,7 @@ public class ModalPresenterTest extends BaseTest {
253
256
 
254
257
  uut.showModal(modal1, root, new CommandListenerAdapter());
255
258
  uut.showModal(modal2, modal1, new CommandListenerAdapter());
259
+ idleMainLooper();
256
260
  assertThat(modal1.getView().getParent()).isNull();
257
261
  assertThat(root.getView().getParent()).isNull();
258
262