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.
- package/jest.config.js +40 -0
- package/lib/android/app/build.gradle +14 -12
- package/lib/android/app/src/main/java/com/reactnativenavigation/options/FontOptions.kt +2 -2
- package/lib/android/app/src/main/java/com/reactnativenavigation/options/LayoutFactory.java +32 -17
- package/lib/android/app/src/main/java/com/reactnativenavigation/options/Options.java +1 -1
- package/lib/android/app/src/main/java/com/reactnativenavigation/options/parsers/TypefaceLoader.kt +16 -10
- package/lib/android/app/src/main/java/com/reactnativenavigation/react/modal/ModalFrameLayout.kt +1 -1
- package/lib/android/app/src/main/java/com/reactnativenavigation/utils/StatusBarUtils.kt +39 -0
- package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabPresenter.java +5 -2
- package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/component/ComponentViewController.java +7 -6
- package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/modal/ModalPresenter.java +6 -4
- package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/StackController.java +14 -6
- package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/topbar/TopBarController.kt +1 -1
- package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/topbar/button/ButtonSpan.kt +1 -1
- package/lib/android/app/src/reactNative51/java/com/reactnativenavigation/react/NavigationReactNativeHost.java +2 -1
- package/lib/android/app/src/test/java/com/reactnativenavigation/mocks/TypefaceLoaderMock.kt +4 -0
- package/lib/android/app/src/test/java/com/reactnativenavigation/utils/LayoutFactoryTest.java +25 -2
- package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/modal/ModalPresenterTest.java +4 -0
- package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/modal/ModalStackTest.java +13 -1
- package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/navigator/NavigatorTest.java +2 -2
- package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/StackControllerTest.kt +10 -5
- package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/TopBarControllerTest.kt +10 -9
- package/lib/dist/commands/LayoutTreeCrawler.js +1 -1
- package/lib/dist/commands/OptionsProcessor.js +2 -2
- package/lib/dist/components/Store.d.ts +2 -0
- package/lib/dist/components/Store.js +8 -0
- package/lib/ios/RNNAssert.h +2 -2
- package/lib/ios/RNNBottomTabOptions.m +2 -1
- package/lib/ios/RNNButtonBuilder.m +3 -3
- package/lib/ios/RNNButtonOptions.m +4 -4
- package/lib/ios/RNNCommandsHandler.m +1 -4
- package/lib/ios/RNNDotIndicatorPresenter.m +2 -1
- package/lib/ios/RNNModalManager.h +2 -0
- package/lib/ios/RNNModalManager.m +13 -6
- package/lib/ios/RNNSegmentedControl.h +1 -1
- package/lib/ios/RNNTabBarItemCreator.m +3 -2
- package/lib/ios/RNNUIBarButtonItem.h +1 -1
- package/lib/ios/RNNUIBarButtonItem.m +3 -3
- package/lib/ios/TopBarPresenter.m +8 -4
- package/lib/src/commands/LayoutTreeCrawler.ts +1 -1
- package/lib/src/commands/OptionsProcessor.ts +2 -2
- package/lib/src/components/Store.ts +9 -0
- package/package.json +12 -53
- 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
|
|
13
|
-
|
|
14
|
-
|
|
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
|
|
24
|
+
compileSdkVersion safeExtGetFallbackLowerBound('compileSdkVersion', DEFAULT_COMPILE_SDK_VERSION)
|
|
21
25
|
|
|
22
26
|
defaultConfig {
|
|
23
|
-
minSdkVersion
|
|
24
|
-
targetSdkVersion
|
|
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(
|
|
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(
|
|
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(
|
|
82
|
+
return createComponent(node);
|
|
79
83
|
case ExternalComponent:
|
|
80
84
|
return createExternalComponent(context, node);
|
|
81
85
|
case Stack:
|
|
82
|
-
return createStack(
|
|
86
|
+
return createStack(node);
|
|
83
87
|
case BottomTabs:
|
|
84
|
-
return createBottomTabs(
|
|
88
|
+
return createBottomTabs(node);
|
|
85
89
|
case SideMenuRoot:
|
|
86
|
-
return createSideMenuRoot(
|
|
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(
|
|
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(
|
|
104
|
+
private ViewController<?> createSideMenuRoot(LayoutNode node) {
|
|
101
105
|
SideMenuController sideMenuController = new SideMenuController(activity,
|
|
102
106
|
childRegistry,
|
|
103
107
|
node.id,
|
|
104
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
185
|
+
parseOptions(node.getOptions())
|
|
182
186
|
);
|
|
183
187
|
}
|
|
184
188
|
|
|
185
|
-
private ViewController<?> createStack(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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 =
|
|
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)
|
|
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
|
|
package/lib/android/app/src/main/java/com/reactnativenavigation/options/parsers/TypefaceLoader.kt
CHANGED
|
@@ -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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
21
|
+
defaultTypeFace,
|
|
22
|
+
ReactTypefaceUtils.parseFontStyle(fontStyle),
|
|
23
|
+
ReactTypefaceUtils.parseFontWeight(fontWeight),
|
|
24
|
+
fontFamilyName,
|
|
25
|
+
context.assets
|
|
20
26
|
)
|
|
21
27
|
}
|
|
22
28
|
}
|
package/lib/android/app/src/main/java/com/reactnativenavigation/react/modal/ModalFrameLayout.kt
CHANGED
|
@@ -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(
|
|
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,
|
|
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,
|
|
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
|
-
|
|
141
|
-
|
|
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
|
|
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.
|
|
94
|
-
|
|
95
|
-
toRemove.
|
|
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
|
|
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.
|
|
195
|
-
|
|
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
|
|
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,
|
|
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(
|
|
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
|
}
|
package/lib/android/app/src/test/java/com/reactnativenavigation/utils/LayoutFactoryTest.java
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|