Browse Source

V3 (#5372)

# Changes
* Support RN 0.60
* Migrate to AndroidX
* Improve draw behind StatusBar (Preparation for #4258)
* Don't push BottomTabs when keyboard is displayed (Fixes #4005, #3424)
    - It won't be needed to toggle the BottomTabs when Keyboard is visible
* BottomTab badge and dot indicator are not animated by default on Android (parity with iOS)

# Updating from v2
v3 is currently in alpha. To update simply npm install `3.0.0-alpha.11` - `npm install --save react-native-navigation@3.0.0-alpha.11`.
Breaking changes are outlined below.

## Layout system changes on **Android**
* Parent layouts (BottomsTabs, Stack, SideMenu) are always laid out behind the StatusBar.
* Components (`component` and `externalComponent`) are measured and offset according to the StatusBar.

In this release, We're changing the layout system in order to provide better support for immersive and full screen apps. In this release we've improved support for drawing behind the StatusBar,  next we'll address drawing behind the NavigationBar. 

Use the `drawBehind` and `translucent` options to control the StatusBar
```js
statusBar: {
  drawBehind: true,  // will draw a screen behind the StatusBar
  translucent: true // Usually you'll want to have drawBehind: true when this is true
}
```

While this isn't a breaking API change - there are a few breaking side effects.

### How will my app be effected
1. When the keyboard is opened, BottomTabs will now be drawn behind the keyboard and won't shift upwards. This is in parity with the current behaviour in iOS. For the most part, this isn't a breaking change. Toggling BottomTabs when TextInput's focus changes won't be needed anymore.

2. While parent controllers are drawn behind the StatusBar, their background isn't.
This means that when transitioning from a destinations drawn under the StatusBar to a destination drawn behind it, the application's default background color will be visible behind the StatusBar.
If you application's theme is dark, you might want to change the `windowBackground` property to mitigate this:

Add the following to your application's `style.xml`
```xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="android:windowBackground">@color/backgroundColor</item>
    </style>

    <!--This is your application's default background color.
    It will be visible when the app is first opened (while the splash layout is visible)
    and when transitioning between a destination a screen drawn under the StatusBar to
    a destination drawn behind it-->
    <item name="backgroundColor" type="color">#f00</item>
</resources>
```

## AndroidX migration
We've migrated RNN to AndroidX, please follow migration instructions in the react-native repo.

## Removed SyncUiImplementation
[SyncUiImplementation](https://github.com/wix/react-native-navigation/blob/master/lib/android/app/src/reactNative57WixFork/java/com/reactnativenavigation/react/SyncUiImplementation.java) was used to overcome a bug in RN's UiImplementation. This workaround was added to RN's `UiImplementation` in RN 0.60 (thanks @SudoPlz) and can be removed from RNN.

If you're using `SyncUiImplementation` your app will fail to compile after upgrading to v3. Simply remove the following code from your `MainApplication.java`
```diff
- import com.facebook.react.uimanager.UIImplementationProvider;
- import com.reactnativenavigation.react.SyncUiImplementation;


- @Override
- protected UIImplementationProvider getUIImplementationProvider() {
-     return new SyncUiImplementation.Provider();
- }
```

## BottomTab badge and dot indicator are not animated by default on Android (parity with iOS)
Showing and hiding badge and dot indicator are now not animated by default. Badge animation is now controlled with the `bottomTab.animateBadge` property and dot indicator with `bottomTab.dotIndicator.animate` property.

#### The following option will show a badge with animation
```js
bottomTab: {
  badge: 'new,
  animateBadge: true
}
```

#### The following option will show a dot indicator with animation
```js
bottomTab: {
  dotIndicator: {
    visible: true,
    animate: true
  }
}
```

closes #5228
Guy Carmeli 5 years ago
parent
commit
ef43070c26
No account linked to committer's email address
100 changed files with 1168 additions and 668 deletions
  1. 10
    17
      docs/docs/Installing.md
  2. 12
    10
      lib/android/app/build.gradle
  3. 3
    3
      lib/android/app/src/main/java/com/reactnativenavigation/NavigationActivity.java
  4. 2
    2
      lib/android/app/src/main/java/com/reactnativenavigation/NavigationApplication.java
  5. 3
    1
      lib/android/app/src/main/java/com/reactnativenavigation/anim/BaseAnimator.java
  6. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/anim/FabCollapseBehaviour.java
  7. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/anim/NavigationAnimator.java
  8. 44
    37
      lib/android/app/src/main/java/com/reactnativenavigation/anim/TopBarAnimator.java
  9. 2
    1
      lib/android/app/src/main/java/com/reactnativenavigation/anim/TopBarCollapseBehavior.java
  10. 10
    4
      lib/android/app/src/main/java/com/reactnativenavigation/parse/AnimationOptions.java
  11. 9
    1
      lib/android/app/src/main/java/com/reactnativenavigation/parse/BottomTabOptions.java
  12. 4
    2
      lib/android/app/src/main/java/com/reactnativenavigation/parse/DotIndicatorOptions.java
  13. 5
    2
      lib/android/app/src/main/java/com/reactnativenavigation/parse/LayoutFactory.java
  14. 0
    1
      lib/android/app/src/main/java/com/reactnativenavigation/parse/LayoutOptions.java
  15. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/parse/ModalOptions.java
  16. 3
    3
      lib/android/app/src/main/java/com/reactnativenavigation/parse/Options.java
  17. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/parse/OrientationOptions.java
  18. 13
    1
      lib/android/app/src/main/java/com/reactnativenavigation/parse/StatusBarOptions.java
  19. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/parse/SubtitleOptions.java
  20. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/parse/TitleOptions.java
  21. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/parse/TopBarButtons.java
  22. 4
    0
      lib/android/app/src/main/java/com/reactnativenavigation/parse/TopBarOptions.java
  23. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/parse/TopTabOptions.java
  24. 2
    2
      lib/android/app/src/main/java/com/reactnativenavigation/parse/TopTabsOptions.java
  25. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/parse/Transitions.java
  26. 19
    1
      lib/android/app/src/main/java/com/reactnativenavigation/parse/ValueAnimationOptions.java
  27. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/parse/params/Button.java
  28. 6
    1
      lib/android/app/src/main/java/com/reactnativenavigation/parse/params/Colour.java
  29. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/parse/params/Orientation.java
  30. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/parse/params/Text.java
  31. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/parse/params/TitleDisplayMode.java
  32. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/parse/parsers/LayoutNodeParser.java
  33. 63
    41
      lib/android/app/src/main/java/com/reactnativenavigation/presentation/BottomTabPresenter.java
  34. 18
    33
      lib/android/app/src/main/java/com/reactnativenavigation/presentation/BottomTabsPresenter.java
  35. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/presentation/ComponentPresenter.java
  36. 23
    0
      lib/android/app/src/main/java/com/reactnativenavigation/presentation/ComponentPresenterBase.java
  37. 4
    0
      lib/android/app/src/main/java/com/reactnativenavigation/presentation/ExternalComponentPresenter.java
  38. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/presentation/FabPresenter.java
  39. 4
    1
      lib/android/app/src/main/java/com/reactnativenavigation/presentation/OverlayManager.java
  40. 65
    32
      lib/android/app/src/main/java/com/reactnativenavigation/presentation/Presenter.java
  41. 10
    4
      lib/android/app/src/main/java/com/reactnativenavigation/presentation/RootPresenter.java
  42. 11
    3
      lib/android/app/src/main/java/com/reactnativenavigation/presentation/SideMenuPresenter.java
  43. 93
    83
      lib/android/app/src/main/java/com/reactnativenavigation/presentation/StackPresenter.java
  44. 8
    5
      lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationModule.java
  45. 7
    7
      lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationPackage.java
  46. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationReactInitializer.java
  47. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/react/ReactView.java
  48. 3
    3
      lib/android/app/src/main/java/com/reactnativenavigation/utils/ButtonPresenter.java
  49. 15
    3
      lib/android/app/src/main/java/com/reactnativenavigation/utils/CollectionUtils.java
  50. 2
    2
      lib/android/app/src/main/java/com/reactnativenavigation/utils/ColorUtils.java
  51. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/utils/CommandListenerAdapter.java
  52. 17
    0
      lib/android/app/src/main/java/com/reactnativenavigation/utils/CoordinatorLayoutUtils.java
  53. 2
    2
      lib/android/app/src/main/java/com/reactnativenavigation/utils/ImageLoader.java
  54. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/utils/ImageLoadingListenerAdapter.java
  55. 21
    0
      lib/android/app/src/main/java/com/reactnativenavigation/utils/LateInit.java
  56. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/utils/NativeCommandListener.java
  57. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/utils/ObjectUtils.java
  58. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/utils/ReflectionUtils.java
  59. 30
    0
      lib/android/app/src/main/java/com/reactnativenavigation/utils/StatusBarUtils.java
  60. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/utils/StringUtils.java
  61. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/utils/TextViewUtils.java
  62. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/utils/TypefaceLoader.java
  63. 2
    18
      lib/android/app/src/main/java/com/reactnativenavigation/utils/UiUtils.java
  64. 12
    2
      lib/android/app/src/main/java/com/reactnativenavigation/utils/ViewUtils.java
  65. 15
    0
      lib/android/app/src/main/java/com/reactnativenavigation/utils/WindowInsetsUtils.java
  66. 33
    8
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ChildController.java
  67. 3
    1
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ChildControllersRegistry.java
  68. 41
    8
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ComponentViewController.java
  69. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/IdStack.java
  70. 59
    16
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ParentController.java
  71. 4
    4
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/TitleBarButtonController.java
  72. 52
    11
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ViewController.java
  73. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/YellowBoxDelegate.java
  74. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/YellowBoxHelper.java
  75. 10
    14
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/AttachMode.java
  76. 1
    12
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabFinder.java
  77. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsAttacher.java
  78. 42
    20
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsController.java
  79. 2
    2
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/button/NavigationIconResolver.java
  80. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/externalcomponent/ExternalComponentCreator.java
  81. 36
    4
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/externalcomponent/ExternalComponentViewController.java
  82. 17
    5
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/modal/ModalPresenter.java
  83. 3
    2
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/modal/ModalStack.java
  84. 17
    19
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/navigator/Navigator.java
  85. 53
    52
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/sidemenu/SideMenuController.java
  86. 7
    7
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/BackButtonHelper.java
  87. 41
    33
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/StackController.java
  88. 3
    1
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/StackControllerBuilder.java
  89. 66
    8
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/topbar/TopBarController.java
  90. 2
    2
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabsAdapter.java
  91. 5
    6
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabsController.java
  92. 19
    0
      lib/android/app/src/main/java/com/reactnativenavigation/views/BehaviourAdapter.java
  93. 24
    0
      lib/android/app/src/main/java/com/reactnativenavigation/views/BehaviourDelegate.java
  94. 10
    11
      lib/android/app/src/main/java/com/reactnativenavigation/views/BottomTabs.java
  95. 0
    4
      lib/android/app/src/main/java/com/reactnativenavigation/views/Component.java
  96. 5
    31
      lib/android/app/src/main/java/com/reactnativenavigation/views/ComponentLayout.java
  97. 2
    25
      lib/android/app/src/main/java/com/reactnativenavigation/views/ExternalComponentLayout.java
  98. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/views/Fab.java
  99. 3
    2
      lib/android/app/src/main/java/com/reactnativenavigation/views/SideMenu.java
  100. 0
    0
      lib/android/app/src/main/java/com/reactnativenavigation/views/SideMenuRoot.java

+ 10
- 17
docs/docs/Installing.md View File

45
 	{
45
 	{
46
 		NSURL *jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
46
 		NSURL *jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
47
 		[ReactNativeNavigation bootstrap:jsCodeLocation launchOptions:launchOptions];
47
 		[ReactNativeNavigation bootstrap:jsCodeLocation launchOptions:launchOptions];
48
-		
48
+
49
 		return YES;
49
 		return YES;
50
 	}
50
 	}
51
 
51
 
52
 	@end
52
 	@end
53
 	```
53
 	```
54
 
54
 
55
-3a. If, in Xcode, you see the following error message in `AppDelegate.m` next to `#import "RCTBundleURLProvider.h"`: 
55
+3a. If, in Xcode, you see the following error message in `AppDelegate.m` next to `#import "RCTBundleURLProvider.h"`:
56
 ```
56
 ```
57
 ! 'RCTBundleURLProvider.h' file not found
57
 ! 'RCTBundleURLProvider.h' file not found
58
 ```
58
 ```
59
-This is because the `React` scheme is missing from your project. You can verify this by opening the `Product` menu and the `Scheme` submenu. 
59
+This is because the `React` scheme is missing from your project. You can verify this by opening the `Product` menu and the `Scheme` submenu.
60
 
60
 
61
 To make the `React` scheme available to your project, run `npm install -g react-native-git-upgrade` followed by `react-native-git-upgrade`. Once this is done, you can click back to the menu in Xcode: `Product -> Scheme -> Manage Schemes`, then click '+' to add a new scheme. From the `Target` menu, select "React", and click the checkbox to make the scheme `shared`. This should make the error disappear.
61
 To make the `React` scheme available to your project, run `npm install -g react-native-git-upgrade` followed by `react-native-git-upgrade`. Once this is done, you can click back to the menu in Xcode: `Product -> Scheme -> Manage Schemes`, then click '+' to add a new scheme. From the `Target` menu, select "React", and click the checkbox to make the scheme `shared`. This should make the error disappear.
62
 
62
 
117
 allprojects {
117
 allprojects {
118
 	repositories {
118
 	repositories {
119
 +		google()
119
 +		google()
120
-+		mavenCentral()
121
 		mavenLocal()
120
 		mavenLocal()
122
 		jcenter()
121
 		jcenter()
123
 		maven {
122
 		maven {
133
 }
132
 }
134
 
133
 
135
 ext {
134
 ext {
136
--    buildToolsVersion = "26.0.3"
137
-+    buildToolsVersion = "27.0.3"
138
 -    minSdkVersion = 16
135
 -    minSdkVersion = 16
139
 +    minSdkVersion = 19
136
 +    minSdkVersion = 19
140
     compileSdkVersion = 26
137
     compileSdkVersion = 26
171
 
168
 
172
 dependencies {
169
 dependencies {
173
 -    compile fileTree(dir: "libs", include: ["*.jar"])
170
 -    compile fileTree(dir: "libs", include: ["*.jar"])
174
--    compile "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
175
 -    compile "com.facebook.react:react-native:+"  // From node_modules
171
 -    compile "com.facebook.react:react-native:+"  // From node_modules
176
 +    implementation fileTree(dir: "libs", include: ["*.jar"])
172
 +    implementation fileTree(dir: "libs", include: ["*.jar"])
177
-+    implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
178
 +    implementation "com.facebook.react:react-native:+"  // From node_modules
173
 +    implementation "com.facebook.react:react-native:+"  // From node_modules
179
 +    implementation project(':react-native-navigation')
174
 +    implementation project(':react-native-navigation')
180
 }
175
 }
181
 ```
176
 ```
182
 
177
 
183
 ### 5 RNN and React Native version
178
 ### 5 RNN and React Native version
184
-
185
 react-native-navigation supports multiple React Native versions. Target the React Native version required by your project by specifying the RNN build flavor in `android/app/build.gradle`.
179
 react-native-navigation supports multiple React Native versions. Target the React Native version required by your project by specifying the RNN build flavor in `android/app/build.gradle`.
186
 
180
 
187
 ```diff
181
 ```diff
205
 >`reactNative55` - RN 0.55.x<Br>
199
 >`reactNative55` - RN 0.55.x<Br>
206
 >`reactNative56` - RN 0.56.x<Br>
200
 >`reactNative56` - RN 0.56.x<Br>
207
 >`reactNative57` - RN 0.57.0 - 0.57.4<Br>
201
 >`reactNative57` - RN 0.57.0 - 0.57.4<Br>
208
->`reactNative57_5` - RN 0.57.5 and above<Br>
202
+>`reactNative57_5` - RN 0.57.5 - 0.59.9<Br>
203
+>`reactNative60` - RN 0.60.0 and above
209
 
204
 
210
 Now we need to instruct gradle how to build that flavor. To do so here two solutions:
205
 Now we need to instruct gradle how to build that flavor. To do so here two solutions:
211
 
206
 
212
-#### 5.1 Build app with gradle command 
207
+#### 5.1 Build app with gradle command
213
 
208
 
214
 **prefered solution** The RNN flavor you would like to build is specified in `app/build.gradle`. Therefore in order to compile only that flavor, instead of building your entire project using `./gradlew assembleDebug`, you should instruct gradle to build the app module: `./gradlew app:assembleDebug`. The easiest way is to add a package.json command to build and install your debug Android APK .
209
 **prefered solution** The RNN flavor you would like to build is specified in `app/build.gradle`. Therefore in order to compile only that flavor, instead of building your entire project using `./gradlew assembleDebug`, you should instruct gradle to build the app module: `./gradlew app:assembleDebug`. The easiest way is to add a package.json command to build and install your debug Android APK .
215
 
210
 
258
 -import com.facebook.react.ReactActivity;
253
 -import com.facebook.react.ReactActivity;
259
 +import com.reactnativenavigation.NavigationActivity;
254
 +import com.reactnativenavigation.NavigationActivity;
260
 
255
 
261
--public class MainActivity extends ReactActivity { 
256
+-public class MainActivity extends ReactActivity {
262
 +public class MainActivity extends NavigationActivity {
257
 +public class MainActivity extends NavigationActivity {
263
 -    @Override
258
 -    @Override
264
 -    protected String getMainComponentName() {
259
 -    protected String getMainComponentName() {
272
 ### 7. Update `MainApplication.java`
267
 ### 7. Update `MainApplication.java`
273
 
268
 
274
 This file is located in `android/app/src/main/java/com/<yourproject>/MainApplication.java`.
269
 This file is located in `android/app/src/main/java/com/<yourproject>/MainApplication.java`.
275
-	
270
+
276
 ```diff
271
 ```diff
277
 ...
272
 ...
278
 import android.app.Application;
273
 import android.app.Application;
292
 
287
 
293
 -public class MainApplication extends Application implements ReactApplication {
288
 -public class MainApplication extends Application implements ReactApplication {
294
 +public class MainApplication extends NavigationApplication {
289
 +public class MainApplication extends NavigationApplication {
295
-+    
290
++
296
 +    @Override
291
 +    @Override
297
 +    protected ReactGateway createReactGateway() {
292
 +    protected ReactGateway createReactGateway() {
298
 +        ReactNativeHost host = new NavigationReactNativeHost(this, isDebug(), createAdditionalReactPackages()) {
293
 +        ReactNativeHost host = new NavigationReactNativeHost(this, isDebug(), createAdditionalReactPackages()) {
316
 +            // eg. new VectorIconsPackage()
311
 +            // eg. new VectorIconsPackage()
317
 +        );
312
 +        );
318
 +    }
313
 +    }
319
-+  
314
++
320
 +    @Override
315
 +    @Override
321
 +    public List<ReactPackage> createAdditionalReactPackages() {
316
 +    public List<ReactPackage> createAdditionalReactPackages() {
322
 +        return getPackages();
317
 +        return getPackages();
365
 ## You can use react-native-navigation \o/
360
 ## You can use react-native-navigation \o/
366
 
361
 
367
 Update `index.js` file
362
 Update `index.js` file
368
-
369
-
370
 ```diff
363
 ```diff
371
 +import { Navigation } from "react-native-navigation";
364
 +import { Navigation } from "react-native-navigation";
372
 -import {AppRegistry} from 'react-native';
365
 -import {AppRegistry} from 'react-native';

+ 12
- 10
lib/android/app/build.gradle View File

1
 apply plugin: 'com.android.library'
1
 apply plugin: 'com.android.library'
2
-apply from: '../prepare-robolectric.gradle'
3
 
2
 
4
 def safeExtGet(prop, fallback) {
3
 def safeExtGet(prop, fallback) {
5
     rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
4
     rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
7
 
6
 
8
 def DEFAULT_COMPILE_SDK_VERSION = 28
7
 def DEFAULT_COMPILE_SDK_VERSION = 28
9
 def DEFAULT_MIN_SDK_VERSION = 19
8
 def DEFAULT_MIN_SDK_VERSION = 19
10
-def DEFAULT_SUPPORT_LIB_VERSION = '28.0.0'
11
 def DEFAULT_TARGET_SDK_VERSION = 28
9
 def DEFAULT_TARGET_SDK_VERSION = 28
12
 
10
 
13
 android {
11
 android {
32
     }
30
     }
33
 
31
 
34
     testOptions {
32
     testOptions {
33
+        unitTests.includeAndroidResources = true
35
         unitTests.all { t ->
34
         unitTests.all { t ->
36
             reports {
35
             reports {
37
                 html.enabled true
36
                 html.enabled true
76
             dimension "RNN.reactNativeVersion"
75
             dimension "RNN.reactNativeVersion"
77
             buildConfigField("int", "REACT_NATVE_VERSION_MINOR", "57")
76
             buildConfigField("int", "REACT_NATVE_VERSION_MINOR", "57")
78
         }
77
         }
78
+        reactNative60 {
79
+            dimension "RNN.reactNativeVersion"
80
+            buildConfigField("int", "REACT_NATVE_VERSION_MINOR", "60")
81
+        }
79
     }
82
     }
80
 }
83
 }
81
 
84
 
89
     }
92
     }
90
 }
93
 }
91
 
94
 
92
-def supportLibVersion = safeExtGet('supportLibVersion', DEFAULT_SUPPORT_LIB_VERSION)
93
-
94
 dependencies {
95
 dependencies {
95
-    implementation "com.android.support:design:${supportLibVersion}"
96
-    implementation "com.android.support:appcompat-v7:${supportLibVersion}"
97
-    implementation "com.android.support:support-v4:${supportLibVersion}"
96
+    implementation 'androidx.appcompat:appcompat:1.0.2'
97
+    implementation 'androidx.annotation:annotation:1.1.0'
98
+    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
99
+    implementation 'com.google.android.material:material:1.1.0-alpha08'
98
 
100
 
99
-    implementation 'com.github.wix-playground:ahbottomnavigation:2.4.15'
101
+    implementation 'com.github.wix-playground:ahbottomnavigation:3.0.2'
100
     implementation 'com.github.wix-playground:reflow-animator:1.0.4'
102
     implementation 'com.github.wix-playground:reflow-animator:1.0.4'
101
     implementation 'com.github.clans:fab:1.6.4'
103
     implementation 'com.github.clans:fab:1.6.4'
102
 
104
 
105
 
107
 
106
     // tests
108
     // tests
107
     testImplementation 'junit:junit:4.12'
109
     testImplementation 'junit:junit:4.12'
108
-    testImplementation 'org.robolectric:robolectric:3.5.1'
110
+    testImplementation "org.robolectric:robolectric:4.3-beta-1"
109
     testImplementation 'org.assertj:assertj-core:3.8.0'
111
     testImplementation 'org.assertj:assertj-core:3.8.0'
110
     testImplementation 'com.squareup.assertj:assertj-android:1.1.1'
112
     testImplementation 'com.squareup.assertj:assertj-android:1.1.1'
111
-    testImplementation 'org.mockito:mockito-core:2.13.0'
113
+    testImplementation 'org.mockito:mockito-core:2.28.2'
112
 }
114
 }

+ 3
- 3
lib/android/app/src/main/java/com/reactnativenavigation/NavigationActivity.java View File

5
 import android.graphics.Color;
5
 import android.graphics.Color;
6
 import android.os.Build;
6
 import android.os.Build;
7
 import android.os.Bundle;
7
 import android.os.Bundle;
8
-import android.support.annotation.NonNull;
9
-import android.support.annotation.Nullable;
10
-import android.support.v7.app.AppCompatActivity;
8
+import androidx.annotation.NonNull;
9
+import androidx.annotation.Nullable;
10
+import androidx.appcompat.app.AppCompatActivity;
11
 import android.view.KeyEvent;
11
 import android.view.KeyEvent;
12
 import android.view.View;
12
 import android.view.View;
13
 
13
 

+ 2
- 2
lib/android/app/src/main/java/com/reactnativenavigation/NavigationApplication.java View File

1
 package com.reactnativenavigation;
1
 package com.reactnativenavigation;
2
 
2
 
3
 import android.app.Application;
3
 import android.app.Application;
4
-import android.support.annotation.Nullable;
5
-import android.support.annotation.NonNull;
4
+import androidx.annotation.Nullable;
5
+import androidx.annotation.NonNull;
6
 
6
 
7
 import com.facebook.react.ReactApplication;
7
 import com.facebook.react.ReactApplication;
8
 import com.facebook.react.ReactNativeHost;
8
 import com.facebook.react.ReactNativeHost;

+ 3
- 1
lib/android/app/src/main/java/com/reactnativenavigation/anim/BaseAnimator.java View File

5
 import android.animation.ObjectAnimator;
5
 import android.animation.ObjectAnimator;
6
 import android.animation.TimeInterpolator;
6
 import android.animation.TimeInterpolator;
7
 import android.content.Context;
7
 import android.content.Context;
8
-import android.support.annotation.NonNull;
8
+import androidx.annotation.NonNull;
9
 import android.view.View;
9
 import android.view.View;
10
 import android.view.animation.AccelerateDecelerateInterpolator;
10
 import android.view.animation.AccelerateDecelerateInterpolator;
11
 import android.view.animation.DecelerateInterpolator;
11
 import android.view.animation.DecelerateInterpolator;
34
         set.setDuration(DURATION);
34
         set.setDuration(DURATION);
35
         ObjectAnimator translationY = ObjectAnimator.ofFloat(view, TRANSLATION_Y, this.translationY, 0);
35
         ObjectAnimator translationY = ObjectAnimator.ofFloat(view, TRANSLATION_Y, this.translationY, 0);
36
         ObjectAnimator alpha = ObjectAnimator.ofFloat(view, ALPHA, 0, 1);
36
         ObjectAnimator alpha = ObjectAnimator.ofFloat(view, ALPHA, 0, 1);
37
+        translationY.setDuration(DURATION);
38
+        alpha.setDuration(DURATION);
37
         set.playTogether(translationY, alpha);
39
         set.playTogether(translationY, alpha);
38
         return set;
40
         return set;
39
     }
41
     }

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/anim/FabCollapseBehaviour.java View File

1
 package com.reactnativenavigation.anim;
1
 package com.reactnativenavigation.anim;
2
 
2
 
3
 
3
 
4
-import android.support.annotation.NonNull;
4
+import androidx.annotation.NonNull;
5
 
5
 
6
 import com.reactnativenavigation.interfaces.ScrollEventListener;
6
 import com.reactnativenavigation.interfaces.ScrollEventListener;
7
 
7
 

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/anim/NavigationAnimator.java View File

4
 import android.animation.AnimatorListenerAdapter;
4
 import android.animation.AnimatorListenerAdapter;
5
 import android.animation.AnimatorSet;
5
 import android.animation.AnimatorSet;
6
 import android.content.Context;
6
 import android.content.Context;
7
-import android.support.annotation.RestrictTo;
7
+import androidx.annotation.RestrictTo;
8
 import android.view.View;
8
 import android.view.View;
9
 import android.view.ViewGroup;
9
 import android.view.ViewGroup;
10
 
10
 

+ 44
- 37
lib/android/app/src/main/java/com/reactnativenavigation/anim/TopBarAnimator.java View File

7
 import android.animation.ObjectAnimator;
7
 import android.animation.ObjectAnimator;
8
 import android.animation.TimeInterpolator;
8
 import android.animation.TimeInterpolator;
9
 import android.view.View;
9
 import android.view.View;
10
-import android.view.animation.AccelerateDecelerateInterpolator;
11
 import android.view.animation.DecelerateInterpolator;
10
 import android.view.animation.DecelerateInterpolator;
12
 import android.view.animation.LinearInterpolator;
11
 import android.view.animation.LinearInterpolator;
13
 
12
 
14
 import com.reactnativenavigation.parse.AnimationOptions;
13
 import com.reactnativenavigation.parse.AnimationOptions;
15
-import com.reactnativenavigation.utils.ViewUtils;
14
+import com.reactnativenavigation.views.StackLayout;
16
 import com.reactnativenavigation.views.topbar.TopBar;
15
 import com.reactnativenavigation.views.topbar.TopBar;
17
 
16
 
18
-import javax.annotation.Nullable;
19
-
20
 import static android.view.View.TRANSLATION_Y;
17
 import static android.view.View.TRANSLATION_Y;
18
+import static com.reactnativenavigation.utils.ObjectUtils.perform;
19
+import static com.reactnativenavigation.utils.ViewUtils.getHeight;
21
 
20
 
22
 public class TopBarAnimator {
21
 public class TopBarAnimator {
23
 
22
 
25
     private static final int DURATION = 300;
24
     private static final int DURATION = 300;
26
     private static final TimeInterpolator DECELERATE = new DecelerateInterpolator();
25
     private static final TimeInterpolator DECELERATE = new DecelerateInterpolator();
27
     private static final TimeInterpolator LINEAR = new LinearInterpolator();
26
     private static final TimeInterpolator LINEAR = new LinearInterpolator();
28
-    private static final TimeInterpolator ACCELERATE_DECELERATE = new AccelerateDecelerateInterpolator();
29
 
27
 
30
     private TopBar topBar;
28
     private TopBar topBar;
31
     private String stackId;
29
     private String stackId;
32
     private Animator hideAnimator;
30
     private Animator hideAnimator;
33
     private Animator showAnimator;
31
     private Animator showAnimator;
34
 
32
 
35
-    public TopBarAnimator(TopBar topBar) {
33
+    public TopBarAnimator() {
34
+    }
35
+
36
+    TopBarAnimator(TopBar topBar) {
36
         this.topBar = topBar;
37
         this.topBar = topBar;
37
     }
38
     }
38
 
39
 
39
-    public TopBarAnimator(TopBar topBar, @Nullable String stackId) {
40
+    public void bindView(TopBar topBar, StackLayout stack) {
40
         this.topBar = topBar;
41
         this.topBar = topBar;
41
-        this.stackId = stackId;
42
+        stackId = stack.getStackId();
42
     }
43
     }
43
 
44
 
44
-    public void show(AnimationOptions options) {
45
+    public void show(AnimationOptions options, int translationStartDy) {
45
         topBar.setVisibility(View.VISIBLE);
46
         topBar.setVisibility(View.VISIBLE);
46
         if (options.hasValue() && (!options.id.hasValue() || options.id.get().equals(stackId))) {
47
         if (options.hasValue() && (!options.id.hasValue() || options.id.get().equals(stackId))) {
48
+            options.setValueDy(TRANSLATION_Y, -translationStartDy, 0);
47
             showAnimator = options.getAnimation(topBar);
49
             showAnimator = options.getAnimation(topBar);
48
         } else {
50
         } else {
49
-            showAnimator = getDefaultShowAnimator(-1 * ViewUtils.getHeight(topBar), DECELERATE, DURATION);
51
+            showAnimator = getDefaultShowAnimator(translationStartDy, DECELERATE, DURATION);
50
         }
52
         }
51
-        show();
53
+        showInternal();
52
     }
54
     }
53
 
55
 
54
     public void show(float startTranslation) {
56
     public void show(float startTranslation) {
55
         showAnimator = getDefaultShowAnimator(startTranslation, LINEAR, DEFAULT_COLLAPSE_DURATION);
57
         showAnimator = getDefaultShowAnimator(startTranslation, LINEAR, DEFAULT_COLLAPSE_DURATION);
56
-        show();
58
+        showInternal();
57
     }
59
     }
58
 
60
 
59
-    private void show() {
61
+    private void showInternal() {
60
         showAnimator.addListener(new AnimatorListenerAdapter() {
62
         showAnimator.addListener(new AnimatorListenerAdapter() {
61
             @Override
63
             @Override
62
             public void onAnimationStart(Animator animation) {
64
             public void onAnimationStart(Animator animation) {
63
                 topBar.setVisibility(View.VISIBLE);
65
                 topBar.setVisibility(View.VISIBLE);
64
             }
66
             }
65
         });
67
         });
66
-        topBar.resetAnimationOptions();
67
         if (isAnimatingHide()) hideAnimator.cancel();
68
         if (isAnimatingHide()) hideAnimator.cancel();
68
         showAnimator.start();
69
         showAnimator.start();
69
     }
70
     }
70
 
71
 
71
-    private AnimatorSet getDefaultShowAnimator(float startTranslation, TimeInterpolator interpolator, int duration) {
72
-        ObjectAnimator showAnimator = ObjectAnimator.ofFloat(topBar, TRANSLATION_Y, startTranslation, 0);
73
-        showAnimator.setInterpolator(interpolator);
74
-        showAnimator.setDuration(duration);
75
-        AnimatorSet set = new AnimatorSet();
76
-        set.play(showAnimator);
77
-        return set;
78
-    }
79
-
80
-    public void hide(AnimationOptions options, Runnable onAnimationEnd) {
72
+    public void hide(AnimationOptions options, Runnable onAnimationEnd, float translationStartDy, float translationEndDy) {
81
         if (options.hasValue() && (!options.id.hasValue() || options.id.get().equals(stackId))) {
73
         if (options.hasValue() && (!options.id.hasValue() || options.id.get().equals(stackId))) {
74
+            options.setValueDy(TRANSLATION_Y, translationStartDy, -translationEndDy);
82
             hideAnimator = options.getAnimation(topBar);
75
             hideAnimator = options.getAnimation(topBar);
83
         } else {
76
         } else {
84
-            hideAnimator = getDefaultHideAnimator(0, ACCELERATE_DECELERATE, DURATION);
77
+            hideAnimator = getDefaultHideAnimator(translationStartDy, translationEndDy, DECELERATE, DURATION);
85
         }
78
         }
86
-        hide(onAnimationEnd);
79
+        hideInternal(onAnimationEnd);
87
     }
80
     }
88
 
81
 
89
-    void hide(float startTranslation) {
90
-        hideAnimator = getDefaultHideAnimator(startTranslation, LINEAR, DEFAULT_COLLAPSE_DURATION);
91
-        hide(() -> {});
82
+    public void hide(float translationStart, float translationEndDy) {
83
+        hideAnimator = getDefaultHideAnimator(translationStart, translationEndDy, LINEAR, DEFAULT_COLLAPSE_DURATION);
84
+        hideInternal(() -> {});
92
     }
85
     }
93
 
86
 
94
-    private void hide(Runnable onAnimationEnd) {
87
+    private void hideInternal(Runnable onAnimationEnd) {
95
         hideAnimator.addListener(new AnimatorListenerAdapter() {
88
         hideAnimator.addListener(new AnimatorListenerAdapter() {
96
             @Override
89
             @Override
97
             public void onAnimationEnd(Animator animation) {
90
             public void onAnimationEnd(Animator animation) {
103
         hideAnimator.start();
96
         hideAnimator.start();
104
     }
97
     }
105
 
98
 
106
-    private Animator getDefaultHideAnimator(float startTranslation, TimeInterpolator interpolator, int duration) {
107
-        ObjectAnimator hideAnimator = ObjectAnimator.ofFloat(topBar, TRANSLATION_Y, startTranslation, -1 * topBar.getMeasuredHeight());
108
-        hideAnimator.setInterpolator(interpolator);
109
-        hideAnimator.setDuration(duration);
110
-        return hideAnimator;
111
-    }
112
-
113
     public boolean isAnimatingHide() {
99
     public boolean isAnimatingHide() {
114
         return hideAnimator != null && hideAnimator.isRunning();
100
         return hideAnimator != null && hideAnimator.isRunning();
115
     }
101
     }
117
     public boolean isAnimatingShow() {
103
     public boolean isAnimatingShow() {
118
          return showAnimator != null && showAnimator.isRunning();
104
          return showAnimator != null && showAnimator.isRunning();
119
     }
105
     }
106
+
107
+    public boolean isAnimating() {
108
+        return perform(showAnimator, false, Animator::isRunning) ||
109
+               perform(hideAnimator, false, Animator::isRunning);
110
+    }
111
+
112
+    private AnimatorSet getDefaultShowAnimator(float translationStart, TimeInterpolator interpolator, int duration) {
113
+        ObjectAnimator showAnimator = ObjectAnimator.ofFloat(topBar, TRANSLATION_Y, -getHeight(topBar) - translationStart, 0);
114
+        showAnimator.setInterpolator(interpolator);
115
+        showAnimator.setDuration(duration);
116
+        AnimatorSet set = new AnimatorSet();
117
+        set.play(showAnimator);
118
+        return set;
119
+    }
120
+
121
+    private Animator getDefaultHideAnimator(float translationStart, float translationEndDy, TimeInterpolator interpolator, int duration) {
122
+        ObjectAnimator hideAnimator = ObjectAnimator.ofFloat(topBar, TRANSLATION_Y, translationStart, -topBar.getMeasuredHeight() - translationEndDy);
123
+        hideAnimator.setInterpolator(interpolator);
124
+        hideAnimator.setDuration(duration);
125
+        return hideAnimator;
126
+    }
120
 }
127
 }

+ 2
- 1
lib/android/app/src/main/java/com/reactnativenavigation/anim/TopBarCollapseBehavior.java View File

2
 
2
 
3
 
3
 
4
 import android.view.View;
4
 import android.view.View;
5
+import android.view.ViewGroup;
5
 
6
 
6
 import com.reactnativenavigation.interfaces.ScrollEventListener;
7
 import com.reactnativenavigation.interfaces.ScrollEventListener;
7
 import com.reactnativenavigation.views.topbar.TopBar;
8
 import com.reactnativenavigation.views.topbar.TopBar;
58
 
59
 
59
     @Override
60
     @Override
60
     public void onHide() {
61
     public void onHide() {
61
-        animator.hide(topBar.getTranslationY());
62
+        animator.hide(topBar.getTranslationY(), ((ViewGroup.MarginLayoutParams) topBar.getLayoutParams()).topMargin);
62
     }
63
     }
63
 }
64
 }

+ 10
- 4
lib/android/app/src/main/java/com/reactnativenavigation/parse/AnimationOptions.java View File

20
 import java.util.Iterator;
20
 import java.util.Iterator;
21
 import java.util.List;
21
 import java.util.List;
22
 
22
 
23
-public class AnimationOptions {
23
+import static com.reactnativenavigation.utils.CollectionUtils.*;
24
 
24
 
25
+public class AnimationOptions {
25
     public static AnimationOptions parse(JSONObject json) {
26
     public static AnimationOptions parse(JSONObject json) {
26
         AnimationOptions options = new AnimationOptions();
27
         AnimationOptions options = new AnimationOptions();
27
         if (json == null) return options;
28
         if (json == null) return options;
78
         if (!hasAnimation()) return defaultAnimation;
79
         if (!hasAnimation()) return defaultAnimation;
79
         AnimatorSet animationSet = new AnimatorSet();
80
         AnimatorSet animationSet = new AnimatorSet();
80
         List<Animator> animators = new ArrayList<>();
81
         List<Animator> animators = new ArrayList<>();
81
-        for (ValueAnimationOptions options : valueOptions) {
82
-            animators.add(options.getAnimation(view));
83
-        }
82
+        forEach(valueOptions, options -> animators.add(options.getAnimation(view)));
84
         animationSet.playTogether(animators);
83
         animationSet.playTogether(animators);
85
         return animationSet;
84
         return animationSet;
86
     }
85
     }
110
     public boolean hasAnimation() {
109
     public boolean hasAnimation() {
111
         return !valueOptions.isEmpty();
110
         return !valueOptions.isEmpty();
112
     }
111
     }
112
+
113
+    public void setValueDy(Property<View, Float> animation, float fromDelta, float toDelta) {
114
+        first(valueOptions, o -> o.equals(animation), param -> {
115
+            param.setFromDelta(fromDelta);
116
+            param.setToDelta(toDelta);
117
+        });
118
+    }
113
 }
119
 }

+ 9
- 1
lib/android/app/src/main/java/com/reactnativenavigation/parse/BottomTabOptions.java View File

1
 package com.reactnativenavigation.parse;
1
 package com.reactnativenavigation.parse;
2
 
2
 
3
 import android.graphics.Typeface;
3
 import android.graphics.Typeface;
4
-import android.support.annotation.Nullable;
5
 
4
 
5
+import com.reactnativenavigation.parse.params.Bool;
6
 import com.reactnativenavigation.parse.params.Colour;
6
 import com.reactnativenavigation.parse.params.Colour;
7
+import com.reactnativenavigation.parse.params.NullBool;
7
 import com.reactnativenavigation.parse.params.NullColor;
8
 import com.reactnativenavigation.parse.params.NullColor;
8
 import com.reactnativenavigation.parse.params.NullNumber;
9
 import com.reactnativenavigation.parse.params.NullNumber;
9
 import com.reactnativenavigation.parse.params.NullText;
10
 import com.reactnativenavigation.parse.params.NullText;
10
 import com.reactnativenavigation.parse.params.Number;
11
 import com.reactnativenavigation.parse.params.Number;
11
 import com.reactnativenavigation.parse.params.Text;
12
 import com.reactnativenavigation.parse.params.Text;
13
+import com.reactnativenavigation.parse.parsers.BoolParser;
12
 import com.reactnativenavigation.parse.parsers.ColorParser;
14
 import com.reactnativenavigation.parse.parsers.ColorParser;
13
 import com.reactnativenavigation.parse.parsers.NumberParser;
15
 import com.reactnativenavigation.parse.parsers.NumberParser;
14
 import com.reactnativenavigation.parse.parsers.TextParser;
16
 import com.reactnativenavigation.parse.parsers.TextParser;
16
 
18
 
17
 import org.json.JSONObject;
19
 import org.json.JSONObject;
18
 
20
 
21
+import androidx.annotation.Nullable;
22
+
19
 public class BottomTabOptions {
23
 public class BottomTabOptions {
20
 
24
 
21
     public static BottomTabOptions parse(TypefaceLoader typefaceManager, JSONObject json) {
25
     public static BottomTabOptions parse(TypefaceLoader typefaceManager, JSONObject json) {
30
         options.selectedIconColor = ColorParser.parse(json, "selectedIconColor");
34
         options.selectedIconColor = ColorParser.parse(json, "selectedIconColor");
31
         options.badge = TextParser.parse(json, "badge");
35
         options.badge = TextParser.parse(json, "badge");
32
         options.badgeColor = ColorParser.parse(json, "badgeColor");
36
         options.badgeColor = ColorParser.parse(json, "badgeColor");
37
+        options.animateBadge = BoolParser.parse(json, "animateBadge");
33
         options.testId = TextParser.parse(json, "testID");
38
         options.testId = TextParser.parse(json, "testID");
34
         options.fontFamily = typefaceManager.getTypeFace(json.optString("fontFamily", ""));
39
         options.fontFamily = typefaceManager.getTypeFace(json.optString("fontFamily", ""));
35
         options.fontSize = NumberParser.parse(json, "fontSize");
40
         options.fontSize = NumberParser.parse(json, "fontSize");
47
     public Text testId = new NullText();
52
     public Text testId = new NullText();
48
     public Text badge = new NullText();
53
     public Text badge = new NullText();
49
     public Colour badgeColor = new NullColor();
54
     public Colour badgeColor = new NullColor();
55
+    public Bool animateBadge = new NullBool();
50
     public DotIndicatorOptions dotIndicator = new DotIndicatorOptions();
56
     public DotIndicatorOptions dotIndicator = new DotIndicatorOptions();
51
     public Number fontSize = new NullNumber();
57
     public Number fontSize = new NullNumber();
52
     public Number selectedFontSize = new NullNumber();
58
     public Number selectedFontSize = new NullNumber();
62
         if (other.selectedIconColor.hasValue()) selectedIconColor = other.selectedIconColor;
68
         if (other.selectedIconColor.hasValue()) selectedIconColor = other.selectedIconColor;
63
         if (other.badge.hasValue()) badge = other.badge;
69
         if (other.badge.hasValue()) badge = other.badge;
64
         if (other.badgeColor.hasValue()) badgeColor = other.badgeColor;
70
         if (other.badgeColor.hasValue()) badgeColor = other.badgeColor;
71
+        if (other.animateBadge.hasValue()) animateBadge = other.animateBadge;
65
         if (other.testId.hasValue()) testId = other.testId;
72
         if (other.testId.hasValue()) testId = other.testId;
66
         if (other.fontSize.hasValue()) fontSize = other.fontSize;
73
         if (other.fontSize.hasValue()) fontSize = other.fontSize;
67
         if (other.selectedFontSize.hasValue()) selectedFontSize = other.selectedFontSize;
74
         if (other.selectedFontSize.hasValue()) selectedFontSize = other.selectedFontSize;
78
         if (!selectedIconColor.hasValue()) selectedIconColor = defaultOptions.selectedIconColor;
85
         if (!selectedIconColor.hasValue()) selectedIconColor = defaultOptions.selectedIconColor;
79
         if (!badge.hasValue()) badge = defaultOptions.badge;
86
         if (!badge.hasValue()) badge = defaultOptions.badge;
80
         if (!badgeColor.hasValue()) badgeColor = defaultOptions.badgeColor;
87
         if (!badgeColor.hasValue()) badgeColor = defaultOptions.badgeColor;
88
+        if (!animateBadge.hasValue()) animateBadge = defaultOptions.animateBadge;
81
         if (!fontSize.hasValue()) fontSize = defaultOptions.fontSize;
89
         if (!fontSize.hasValue()) fontSize = defaultOptions.fontSize;
82
         if (!selectedFontSize.hasValue()) selectedFontSize = defaultOptions.selectedFontSize;
90
         if (!selectedFontSize.hasValue()) selectedFontSize = defaultOptions.selectedFontSize;
83
         if (fontFamily == null) fontFamily = defaultOptions.fontFamily;
91
         if (fontFamily == null) fontFamily = defaultOptions.fontFamily;

+ 4
- 2
lib/android/app/src/main/java/com/reactnativenavigation/parse/DotIndicatorOptions.java View File

1
 package com.reactnativenavigation.parse;
1
 package com.reactnativenavigation.parse;
2
 
2
 
3
-import android.support.annotation.Nullable;
4
-
5
 import com.reactnativenavigation.parse.params.Bool;
3
 import com.reactnativenavigation.parse.params.Bool;
6
 import com.reactnativenavigation.parse.params.Colour;
4
 import com.reactnativenavigation.parse.params.Colour;
7
 import com.reactnativenavigation.parse.params.NullBool;
5
 import com.reactnativenavigation.parse.params.NullBool;
14
 
12
 
15
 import org.json.JSONObject;
13
 import org.json.JSONObject;
16
 
14
 
15
+import androidx.annotation.Nullable;
16
+
17
 public class DotIndicatorOptions {
17
 public class DotIndicatorOptions {
18
     public static DotIndicatorOptions parse(@Nullable JSONObject json) {
18
     public static DotIndicatorOptions parse(@Nullable JSONObject json) {
19
         DotIndicatorOptions options = new DotIndicatorOptions();
19
         DotIndicatorOptions options = new DotIndicatorOptions();
22
         options.color = ColorParser.parse(json, "color");
22
         options.color = ColorParser.parse(json, "color");
23
         options.size = NumberParser.parse(json, "size");
23
         options.size = NumberParser.parse(json, "size");
24
         options.visible = BoolParser.parse(json, "visible");
24
         options.visible = BoolParser.parse(json, "visible");
25
+        options.animate = BoolParser.parse(json, "animate");
25
 
26
 
26
         return options;
27
         return options;
27
     }
28
     }
29
     public Colour color = new NullColor();
30
     public Colour color = new NullColor();
30
     public Number size = new NullNumber();
31
     public Number size = new NullNumber();
31
     public Bool visible = new NullBool();
32
     public Bool visible = new NullBool();
33
+    public Bool animate = new NullBool();
32
 
34
 
33
     public boolean hasValue() {
35
     public boolean hasValue() {
34
         return visible.hasValue();
36
         return visible.hasValue();

+ 5
- 2
lib/android/app/src/main/java/com/reactnativenavigation/parse/LayoutFactory.java View File

1
 package com.reactnativenavigation.parse;
1
 package com.reactnativenavigation.parse;
2
 
2
 
3
 import android.app.Activity;
3
 import android.app.Activity;
4
-import android.support.annotation.NonNull;
5
-import android.support.annotation.RestrictTo;
6
 
4
 
7
 import com.facebook.react.ReactInstanceManager;
5
 import com.facebook.react.ReactInstanceManager;
8
 import com.reactnativenavigation.presentation.BottomTabPresenter;
6
 import com.reactnativenavigation.presentation.BottomTabPresenter;
9
 import com.reactnativenavigation.presentation.BottomTabsPresenter;
7
 import com.reactnativenavigation.presentation.BottomTabsPresenter;
10
 import com.reactnativenavigation.presentation.ComponentPresenter;
8
 import com.reactnativenavigation.presentation.ComponentPresenter;
9
+import com.reactnativenavigation.presentation.ExternalComponentPresenter;
11
 import com.reactnativenavigation.presentation.Presenter;
10
 import com.reactnativenavigation.presentation.Presenter;
12
 import com.reactnativenavigation.presentation.RenderChecker;
11
 import com.reactnativenavigation.presentation.RenderChecker;
13
 import com.reactnativenavigation.presentation.SideMenuPresenter;
12
 import com.reactnativenavigation.presentation.SideMenuPresenter;
37
 import java.util.List;
36
 import java.util.List;
38
 import java.util.Map;
37
 import java.util.Map;
39
 
38
 
39
+import androidx.annotation.NonNull;
40
+import androidx.annotation.RestrictTo;
41
+
40
 import static com.reactnativenavigation.parse.Options.parse;
42
 import static com.reactnativenavigation.parse.Options.parse;
41
 
43
 
42
 public class LayoutFactory {
44
 public class LayoutFactory {
168
                 externalComponentCreators.get(externalComponent.name.get()),
170
                 externalComponentCreators.get(externalComponent.name.get()),
169
                 reactInstanceManager,
171
                 reactInstanceManager,
170
                 new EventEmitter(reactInstanceManager.getCurrentReactContext()),
172
                 new EventEmitter(reactInstanceManager.getCurrentReactContext()),
173
+                new ExternalComponentPresenter(),
171
                 parse(typefaceManager, node.getOptions())
174
                 parse(typefaceManager, node.getOptions())
172
         );
175
         );
173
     }
176
     }

+ 0
- 1
lib/android/app/src/main/java/com/reactnativenavigation/parse/LayoutOptions.java View File

35
         if (other.topMargin.hasValue()) topMargin = other.topMargin;
35
         if (other.topMargin.hasValue()) topMargin = other.topMargin;
36
         if (other.orientation.hasValue()) orientation = other.orientation;
36
         if (other.orientation.hasValue()) orientation = other.orientation;
37
         if (other.direction.hasValue()) direction = other.direction;
37
         if (other.direction.hasValue()) direction = other.direction;
38
-
39
     }
38
     }
40
 
39
 
41
     public void mergeWithDefault(LayoutOptions defaultOptions) {
40
     public void mergeWithDefault(LayoutOptions defaultOptions) {

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/parse/ModalOptions.java View File

1
 package com.reactnativenavigation.parse;
1
 package com.reactnativenavigation.parse;
2
 
2
 
3
-import android.support.annotation.NonNull;
3
+import androidx.annotation.NonNull;
4
 
4
 
5
 import com.reactnativenavigation.parse.params.Bool;
5
 import com.reactnativenavigation.parse.params.Bool;
6
 import com.reactnativenavigation.parse.params.NullBool;
6
 import com.reactnativenavigation.parse.params.NullBool;

+ 3
- 3
lib/android/app/src/main/java/com/reactnativenavigation/parse/Options.java View File

1
 package com.reactnativenavigation.parse;
1
 package com.reactnativenavigation.parse;
2
 
2
 
3
-import android.support.annotation.CheckResult;
4
-import android.support.annotation.NonNull;
5
-
6
 import com.reactnativenavigation.parse.params.NullBool;
3
 import com.reactnativenavigation.parse.params.NullBool;
7
 import com.reactnativenavigation.parse.params.NullNumber;
4
 import com.reactnativenavigation.parse.params.NullNumber;
8
 import com.reactnativenavigation.parse.params.NullText;
5
 import com.reactnativenavigation.parse.params.NullText;
10
 
7
 
11
 import org.json.JSONObject;
8
 import org.json.JSONObject;
12
 
9
 
10
+import androidx.annotation.CheckResult;
11
+import androidx.annotation.NonNull;
12
+
13
 public class Options {
13
 public class Options {
14
     public static final Options EMPTY = new Options();
14
     public static final Options EMPTY = new Options();
15
 
15
 

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/parse/OrientationOptions.java View File

1
 package com.reactnativenavigation.parse;
1
 package com.reactnativenavigation.parse;
2
 
2
 
3
-import android.support.annotation.CheckResult;
3
+import androidx.annotation.CheckResult;
4
 
4
 
5
 import com.reactnativenavigation.parse.params.Orientation;
5
 import com.reactnativenavigation.parse.params.Orientation;
6
 
6
 

+ 13
- 1
lib/android/app/src/main/java/com/reactnativenavigation/parse/StatusBarOptions.java View File

1
 package com.reactnativenavigation.parse;
1
 package com.reactnativenavigation.parse;
2
 
2
 
3
-import android.support.annotation.Nullable;
3
+import androidx.annotation.Nullable;
4
 
4
 
5
 import com.reactnativenavigation.parse.params.Bool;
5
 import com.reactnativenavigation.parse.params.Bool;
6
 import com.reactnativenavigation.parse.params.Colour;
6
 import com.reactnativenavigation.parse.params.Colour;
46
         result.textColorScheme = TextColorScheme.fromString(json.optString("style"));
46
         result.textColorScheme = TextColorScheme.fromString(json.optString("style"));
47
         result.visible = BoolParser.parse(json, "visible");
47
         result.visible = BoolParser.parse(json, "visible");
48
         result.drawBehind = BoolParser.parse(json, "drawBehind");
48
         result.drawBehind = BoolParser.parse(json, "drawBehind");
49
+        result.translucent = BoolParser.parse(json, "translucent");
49
 
50
 
50
         return result;
51
         return result;
51
     }
52
     }
54
     public TextColorScheme textColorScheme = TextColorScheme.None;
55
     public TextColorScheme textColorScheme = TextColorScheme.None;
55
     public Bool visible = new NullBool();
56
     public Bool visible = new NullBool();
56
     public Bool drawBehind = new NullBool();
57
     public Bool drawBehind = new NullBool();
58
+    public Bool translucent = new NullBool();
57
 
59
 
58
     public void mergeWith(StatusBarOptions other) {
60
     public void mergeWith(StatusBarOptions other) {
59
         if (other.backgroundColor.hasValue()) backgroundColor = other.backgroundColor;
61
         if (other.backgroundColor.hasValue()) backgroundColor = other.backgroundColor;
60
         if (other.textColorScheme.hasValue()) textColorScheme = other.textColorScheme;
62
         if (other.textColorScheme.hasValue()) textColorScheme = other.textColorScheme;
61
         if (other.visible.hasValue()) visible = other.visible;
63
         if (other.visible.hasValue()) visible = other.visible;
62
         if (other.drawBehind.hasValue()) drawBehind = other.drawBehind;
64
         if (other.drawBehind.hasValue()) drawBehind = other.drawBehind;
65
+        if (other.translucent.hasValue()) translucent = other.translucent;
63
     }
66
     }
64
 
67
 
65
     public void mergeWithDefault(StatusBarOptions defaultOptions) {
68
     public void mergeWithDefault(StatusBarOptions defaultOptions) {
67
         if (!textColorScheme.hasValue()) textColorScheme = defaultOptions.textColorScheme;
70
         if (!textColorScheme.hasValue()) textColorScheme = defaultOptions.textColorScheme;
68
         if (!visible.hasValue()) visible = defaultOptions.visible;
71
         if (!visible.hasValue()) visible = defaultOptions.visible;
69
         if (!drawBehind.hasValue()) drawBehind = defaultOptions.drawBehind;
72
         if (!drawBehind.hasValue()) drawBehind = defaultOptions.drawBehind;
73
+        if (!translucent.hasValue()) translucent = defaultOptions.translucent;
74
+    }
75
+
76
+    public boolean isHiddenOrDrawBehind() {
77
+        return drawBehind.isTrue() || visible.isFalse();
78
+    }
79
+
80
+    public boolean hasTransparency() {
81
+        return translucent.isTrue() || visible.isFalse() || backgroundColor.hasTransparency();
70
     }
82
     }
71
 }
83
 }

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/parse/SubtitleOptions.java View File

1
 package com.reactnativenavigation.parse;
1
 package com.reactnativenavigation.parse;
2
 
2
 
3
 import android.graphics.Typeface;
3
 import android.graphics.Typeface;
4
-import android.support.annotation.Nullable;
4
+import androidx.annotation.Nullable;
5
 
5
 
6
 import com.reactnativenavigation.parse.params.Colour;
6
 import com.reactnativenavigation.parse.params.Colour;
7
 import com.reactnativenavigation.parse.params.Fraction;
7
 import com.reactnativenavigation.parse.params.Fraction;

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/parse/TitleOptions.java View File

1
 package com.reactnativenavigation.parse;
1
 package com.reactnativenavigation.parse;
2
 
2
 
3
 import android.graphics.Typeface;
3
 import android.graphics.Typeface;
4
-import android.support.annotation.Nullable;
4
+import androidx.annotation.Nullable;
5
 
5
 
6
 import com.reactnativenavigation.parse.params.Colour;
6
 import com.reactnativenavigation.parse.params.Colour;
7
 import com.reactnativenavigation.parse.params.Fraction;
7
 import com.reactnativenavigation.parse.params.Fraction;

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/parse/TopBarButtons.java View File

1
 package com.reactnativenavigation.parse;
1
 package com.reactnativenavigation.parse;
2
 
2
 
3
-import android.support.annotation.Nullable;
3
+import androidx.annotation.Nullable;
4
 
4
 
5
 import com.reactnativenavigation.parse.params.Button;
5
 import com.reactnativenavigation.parse.params.Button;
6
 import com.reactnativenavigation.utils.CollectionUtils;
6
 import com.reactnativenavigation.utils.CollectionUtils;

+ 4
- 0
lib/android/app/src/main/java/com/reactnativenavigation/parse/TopBarOptions.java View File

134
             subtitle.text = new NullText();
134
             subtitle.text = new NullText();
135
         }
135
         }
136
     }
136
     }
137
+
138
+    public boolean isHiddenOrDrawBehind() {
139
+        return drawBehind.isTrue() || visible.isFalse();
140
+    }
137
 }
141
 }

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/parse/TopTabOptions.java View File

1
 package com.reactnativenavigation.parse;
1
 package com.reactnativenavigation.parse;
2
 
2
 
3
 import android.graphics.Typeface;
3
 import android.graphics.Typeface;
4
-import android.support.annotation.Nullable;
4
+import androidx.annotation.Nullable;
5
 
5
 
6
 import com.reactnativenavigation.parse.params.NullText;
6
 import com.reactnativenavigation.parse.params.NullText;
7
 import com.reactnativenavigation.parse.params.Text;
7
 import com.reactnativenavigation.parse.params.Text;

+ 2
- 2
lib/android/app/src/main/java/com/reactnativenavigation/parse/TopTabsOptions.java View File

1
 package com.reactnativenavigation.parse;
1
 package com.reactnativenavigation.parse;
2
 
2
 
3
-import android.support.annotation.NonNull;
4
-import android.support.annotation.Nullable;
3
+import androidx.annotation.NonNull;
4
+import androidx.annotation.Nullable;
5
 
5
 
6
 import com.reactnativenavigation.parse.params.Bool;
6
 import com.reactnativenavigation.parse.params.Bool;
7
 import com.reactnativenavigation.parse.params.Colour;
7
 import com.reactnativenavigation.parse.params.Colour;

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/parse/Transitions.java View File

1
 package com.reactnativenavigation.parse;
1
 package com.reactnativenavigation.parse;
2
 
2
 
3
-import android.support.annotation.RestrictTo;
3
+import androidx.annotation.RestrictTo;
4
 
4
 
5
 import org.json.JSONArray;
5
 import org.json.JSONArray;
6
 import org.json.JSONObject;
6
 import org.json.JSONObject;

+ 19
- 1
lib/android/app/src/main/java/com/reactnativenavigation/parse/ValueAnimationOptions.java View File

35
     private Property<View, Float> animProp;
35
     private Property<View, Float> animProp;
36
 
36
 
37
     private FloatParam from = new NullFloatParam();
37
     private FloatParam from = new NullFloatParam();
38
+    private FloatParam fromDelta = new FloatParam(0f);
38
     private FloatParam to = new NullFloatParam();
39
     private FloatParam to = new NullFloatParam();
40
+    private FloatParam toDelta = new FloatParam(0f);
39
     private Number duration = new NullNumber();
41
     private Number duration = new NullNumber();
40
     private Number startDelay = new NullNumber();
42
     private Number startDelay = new NullNumber();
41
     private Interpolation interpolation = Interpolation.NO_VALUE;
43
     private Interpolation interpolation = Interpolation.NO_VALUE;
42
 
44
 
45
+    void setFromDelta(float fromDelta) {
46
+        this.fromDelta = new FloatParam(fromDelta);
47
+    }
48
+
49
+    void setToDelta(float toDelta) {
50
+        this.toDelta = new FloatParam(toDelta);
51
+    }
52
+
43
     Animator getAnimation(View view) {
53
     Animator getAnimation(View view) {
44
         if (!from.hasValue() || !to.hasValue()) throw new IllegalArgumentException("Params 'from' and 'to' are mandatory");
54
         if (!from.hasValue() || !to.hasValue()) throw new IllegalArgumentException("Params 'from' and 'to' are mandatory");
45
-        ObjectAnimator animator = ObjectAnimator.ofFloat(view, animProp, from.get(), to.get());
55
+        ObjectAnimator animator = ObjectAnimator.ofFloat(view,
56
+                animProp,
57
+                from.get() + fromDelta.get(),
58
+                to.get() + toDelta.get()
59
+        );
46
         animator.setInterpolator(interpolation.getInterpolator());
60
         animator.setInterpolator(interpolation.getInterpolator());
47
         if (duration.hasValue()) animator.setDuration(duration.get());
61
         if (duration.hasValue()) animator.setDuration(duration.get());
48
         if (startDelay.hasValue()) animator.setStartDelay(startDelay.get());
62
         if (startDelay.hasValue()) animator.setStartDelay(startDelay.get());
56
         return animProp.equals(((ValueAnimationOptions) o).animProp);
70
         return animProp.equals(((ValueAnimationOptions) o).animProp);
57
     }
71
     }
58
 
72
 
73
+    public boolean equals(Property<View, Float> animationProperty) {
74
+        return animProp.getName().equals(animationProperty.getName());
75
+    }
76
+
59
     @Override
77
     @Override
60
     public int hashCode() {
78
     public int hashCode() {
61
         return animProp.hashCode();
79
         return animProp.hashCode();

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/parse/params/Button.java View File

1
 package com.reactnativenavigation.parse.params;
1
 package com.reactnativenavigation.parse.params;
2
 
2
 
3
 import android.graphics.Typeface;
3
 import android.graphics.Typeface;
4
-import android.support.annotation.Nullable;
4
+import androidx.annotation.Nullable;
5
 import android.view.MenuItem;
5
 import android.view.MenuItem;
6
 
6
 
7
 import com.reactnativenavigation.parse.Component;
7
 import com.reactnativenavigation.parse.Component;

+ 6
- 1
lib/android/app/src/main/java/com/reactnativenavigation/parse/params/Colour.java View File

1
 package com.reactnativenavigation.parse.params;
1
 package com.reactnativenavigation.parse.params;
2
 
2
 
3
-import android.support.annotation.ColorInt;
3
+import android.graphics.Color;
4
+import androidx.annotation.ColorInt;
4
 
5
 
5
 public class Colour extends Param<Integer>{
6
 public class Colour extends Param<Integer>{
6
 
7
 
13
     public String toString() {
14
     public String toString() {
14
         return String.format("#%06X", (0xFFFFFF & get()));
15
         return String.format("#%06X", (0xFFFFFF & get()));
15
     }
16
     }
17
+
18
+    public boolean hasTransparency() {
19
+        return hasValue() && Color.alpha(value) < 1;
20
+    }
16
 }
21
 }

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/parse/params/Orientation.java View File

1
 package com.reactnativenavigation.parse.params;
1
 package com.reactnativenavigation.parse.params;
2
 
2
 
3
 import android.content.pm.ActivityInfo;
3
 import android.content.pm.ActivityInfo;
4
-import android.support.annotation.Nullable;
4
+import androidx.annotation.Nullable;
5
 
5
 
6
 public enum Orientation {
6
 public enum Orientation {
7
     Portrait("portrait", ActivityInfo.SCREEN_ORIENTATION_PORTRAIT),
7
     Portrait("portrait", ActivityInfo.SCREEN_ORIENTATION_PORTRAIT),

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/parse/params/Text.java View File

1
 package com.reactnativenavigation.parse.params;
1
 package com.reactnativenavigation.parse.params;
2
 
2
 
3
-import android.support.annotation.NonNull;
3
+import androidx.annotation.NonNull;
4
 
4
 
5
 public class Text extends Param<String> {
5
 public class Text extends Param<String> {
6
     public Text(String value) {
6
     public Text(String value) {

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/parse/params/TitleDisplayMode.java View File

1
 package com.reactnativenavigation.parse.params;
1
 package com.reactnativenavigation.parse.params;
2
 
2
 
3
-import android.support.annotation.NonNull;
3
+import androidx.annotation.NonNull;
4
 
4
 
5
 import com.aurelhubert.ahbottomnavigation.AHBottomNavigation.TitleState;
5
 import com.aurelhubert.ahbottomnavigation.AHBottomNavigation.TitleState;
6
 
6
 

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/parse/parsers/LayoutNodeParser.java View File

1
 package com.reactnativenavigation.parse.parsers;
1
 package com.reactnativenavigation.parse.parsers;
2
 
2
 
3
-import android.support.annotation.NonNull;
3
+import androidx.annotation.NonNull;
4
 
4
 
5
 import com.reactnativenavigation.parse.LayoutNode;
5
 import com.reactnativenavigation.parse.LayoutNode;
6
 
6
 

+ 63
- 41
lib/android/app/src/main/java/com/reactnativenavigation/presentation/BottomTabPresenter.java View File

2
 
2
 
3
 import android.content.Context;
3
 import android.content.Context;
4
 import android.graphics.drawable.Drawable;
4
 import android.graphics.drawable.Drawable;
5
-import android.support.annotation.NonNull;
6
 
5
 
7
 import com.aurelhubert.ahbottomnavigation.notification.AHNotification;
6
 import com.aurelhubert.ahbottomnavigation.notification.AHNotification;
8
 import com.reactnativenavigation.parse.BottomTabOptions;
7
 import com.reactnativenavigation.parse.BottomTabOptions;
10
 import com.reactnativenavigation.parse.Options;
9
 import com.reactnativenavigation.parse.Options;
11
 import com.reactnativenavigation.utils.ImageLoader;
10
 import com.reactnativenavigation.utils.ImageLoader;
12
 import com.reactnativenavigation.utils.ImageLoadingListenerAdapter;
11
 import com.reactnativenavigation.utils.ImageLoadingListenerAdapter;
12
+import com.reactnativenavigation.utils.LateInit;
13
 import com.reactnativenavigation.viewcontrollers.ViewController;
13
 import com.reactnativenavigation.viewcontrollers.ViewController;
14
 import com.reactnativenavigation.viewcontrollers.bottomtabs.BottomTabFinder;
14
 import com.reactnativenavigation.viewcontrollers.bottomtabs.BottomTabFinder;
15
 import com.reactnativenavigation.views.BottomTabs;
15
 import com.reactnativenavigation.views.BottomTabs;
16
-import com.reactnativenavigation.views.Component;
17
 
16
 
18
 import java.util.List;
17
 import java.util.List;
19
 
18
 
19
+import androidx.annotation.NonNull;
20
+
21
+import static com.reactnativenavigation.utils.CollectionUtils.*;
20
 import static com.reactnativenavigation.utils.UiUtils.dpToPx;
22
 import static com.reactnativenavigation.utils.UiUtils.dpToPx;
21
 
23
 
22
 public class BottomTabPresenter {
24
 public class BottomTabPresenter {
24
     private ImageLoader imageLoader;
26
     private ImageLoader imageLoader;
25
     private Options defaultOptions;
27
     private Options defaultOptions;
26
     private final BottomTabFinder bottomTabFinder;
28
     private final BottomTabFinder bottomTabFinder;
27
-    private BottomTabs bottomTabs;
29
+    private LateInit<BottomTabs> bottomTabs = new LateInit<>();
28
     private final List<ViewController> tabs;
30
     private final List<ViewController> tabs;
29
     private final int defaultDotIndicatorSize;
31
     private final int defaultDotIndicatorSize;
30
 
32
 
42
     }
44
     }
43
 
45
 
44
     public void bindView(BottomTabs bottomTabs) {
46
     public void bindView(BottomTabs bottomTabs) {
45
-        this.bottomTabs = bottomTabs;
47
+        this.bottomTabs.set(bottomTabs);
46
     }
48
     }
47
 
49
 
48
     public void applyOptions() {
50
     public void applyOptions() {
49
-        for (int i = 0; i < tabs.size(); i++) {
50
-            BottomTabOptions tab = tabs.get(i).resolveCurrentOptions(defaultOptions).bottomTabOptions;
51
-            bottomTabs.setTitleTypeface(i, tab.fontFamily);
52
-            bottomTabs.setIconActiveColor(i, tab.selectedIconColor.get(null));
53
-            bottomTabs.setIconInactiveColor(i, tab.iconColor.get(null));
54
-            bottomTabs.setTitleActiveColor(i, tab.selectedTextColor.get(null));
55
-            bottomTabs.setTitleInactiveColor(i, tab.textColor.get(null));
56
-            bottomTabs.setTitleInactiveTextSizeInSp(i, tab.fontSize.hasValue() ? Float.valueOf(tab.fontSize.get()) : null);
57
-            bottomTabs.setTitleActiveTextSizeInSp(i, tab.selectedFontSize.hasValue() ? Float.valueOf(tab.selectedFontSize.get()) : null);
58
-            if (tab.testId.hasValue()) bottomTabs.setTag(i, tab.testId.get());
59
-            if (shouldApplyDot(tab)) applyDotIndicator(i, tab.dotIndicator); else applyBadge(i, tab);
60
-        }
51
+        bottomTabs.perform(bottomTabs -> {
52
+            for (int i = 0; i < tabs.size(); i++) {
53
+                BottomTabOptions tab = tabs.get(i).resolveCurrentOptions(defaultOptions).bottomTabOptions;
54
+                bottomTabs.setTitleTypeface(i, tab.fontFamily);
55
+                bottomTabs.setIconActiveColor(i, tab.selectedIconColor.get(null));
56
+                bottomTabs.setIconInactiveColor(i, tab.iconColor.get(null));
57
+                bottomTabs.setTitleActiveColor(i, tab.selectedTextColor.get(null));
58
+                bottomTabs.setTitleInactiveColor(i, tab.textColor.get(null));
59
+                bottomTabs.setTitleInactiveTextSizeInSp(i, tab.fontSize.hasValue() ? Float.valueOf(tab.fontSize.get()) : null);
60
+                bottomTabs.setTitleActiveTextSizeInSp(i, tab.selectedFontSize.hasValue() ? Float.valueOf(tab.selectedFontSize.get()) : null);
61
+                if (tab.testId.hasValue()) bottomTabs.setTag(i, tab.testId.get());
62
+                if (shouldApplyDot(tab)) applyDotIndicator(i, tab.dotIndicator); else applyBadge(i, tab);
63
+            }
64
+        });
65
+    }
66
+
67
+    public void mergeOptions(Options options) {
68
+        bottomTabs.perform(bottomTabs -> {
69
+            bottomTabs.disableItemsCreation();
70
+            forEach(tabs, tab -> mergeChildOptions(options, tab));
71
+            bottomTabs.enableItemsCreation();
72
+        });
61
     }
73
     }
62
 
74
 
63
-    public void mergeChildOptions(Options options, Component child) {
64
-        int index = bottomTabFinder.findByComponent(child);
65
-        if (index >= 0) {
66
-            BottomTabOptions tab = options.bottomTabOptions;
67
-            if (tab.fontFamily != null) bottomTabs.setTitleTypeface(index, tab.fontFamily);
68
-            if (tab.selectedIconColor.hasValue()) bottomTabs.setIconActiveColor(index, tab.selectedIconColor.get());
69
-            if (tab.iconColor.hasValue()) bottomTabs.setIconInactiveColor(index, tab.iconColor.get());
70
-            if (tab.selectedTextColor.hasValue()) bottomTabs.setTitleActiveColor(index, tab.selectedTextColor.get());
71
-            if (tab.textColor.hasValue()) bottomTabs.setTitleInactiveColor(index, tab.textColor.get());
72
-            if (tab.text.hasValue()) bottomTabs.setText(index, tab.text.get());
73
-            if (tab.icon.hasValue()) imageLoader.loadIcon(context, tab.icon.get(), new ImageLoadingListenerAdapter() {
74
-                @Override
75
-                public void onComplete(@NonNull Drawable drawable) {
76
-                    bottomTabs.setIcon(index, drawable);
77
-                }
78
-            });
79
-            if (tab.testId.hasValue()) bottomTabs.setTag(index, tab.testId.get());
80
-            if (shouldApplyDot(tab)) mergeDotIndicator(index, tab.dotIndicator); else mergeBadge(index, tab);
81
-        }
75
+    public void mergeChildOptions(Options options, ViewController child) {
76
+        bottomTabs.perform(bottomTabs -> {
77
+            int index = bottomTabFinder.findByControllerId(child.getId());
78
+            if (index >= 0) {
79
+                BottomTabOptions tab = options.bottomTabOptions;
80
+                if (tab.fontFamily != null) bottomTabs.setTitleTypeface(index, tab.fontFamily);
81
+                if (tab.selectedIconColor.hasValue()) bottomTabs.setIconActiveColor(index, tab.selectedIconColor.get());
82
+                if (tab.iconColor.hasValue()) bottomTabs.setIconInactiveColor(index, tab.iconColor.get());
83
+                if (tab.selectedTextColor.hasValue()) bottomTabs.setTitleActiveColor(index, tab.selectedTextColor.get());
84
+                if (tab.textColor.hasValue()) bottomTabs.setTitleInactiveColor(index, tab.textColor.get());
85
+                if (tab.text.hasValue()) bottomTabs.setText(index, tab.text.get());
86
+                if (tab.icon.hasValue()) imageLoader.loadIcon(context, tab.icon.get(), new ImageLoadingListenerAdapter() {
87
+                    @Override
88
+                    public void onComplete(@NonNull Drawable drawable) {
89
+                        bottomTabs.setIcon(index, drawable);
90
+                    }
91
+                });
92
+                if (tab.testId.hasValue()) bottomTabs.setTag(index, tab.testId.get());
93
+                if (shouldApplyDot(tab)) mergeDotIndicator(index, tab.dotIndicator); else mergeBadge(index, tab);
94
+            }
95
+        });
82
     }
96
     }
83
 
97
 
84
     private void applyDotIndicator(int tabIndex, DotIndicatorOptions dotIndicator) {
98
     private void applyDotIndicator(int tabIndex, DotIndicatorOptions dotIndicator) {
85
         AHNotification.Builder builder = new AHNotification.Builder()
99
         AHNotification.Builder builder = new AHNotification.Builder()
86
                 .setText("")
100
                 .setText("")
87
                 .setBackgroundColor(dotIndicator.color.get(null))
101
                 .setBackgroundColor(dotIndicator.color.get(null))
88
-                .setSize(dotIndicator.size.get(defaultDotIndicatorSize));
89
-        bottomTabs.setNotification(builder.build(), tabIndex);
102
+                .setSize(dotIndicator.size.get(defaultDotIndicatorSize))
103
+                .animate(dotIndicator.animate.get(false));
104
+        bottomTabs.perform(bottomTabs -> bottomTabs.setNotification(builder.build(), tabIndex));
90
     }
105
     }
91
 
106
 
92
     private void applyBadge(int tabIndex, BottomTabOptions tab) {
107
     private void applyBadge(int tabIndex, BottomTabOptions tab) {
108
+        if (bottomTabs == null) return;
93
         AHNotification.Builder builder = new AHNotification.Builder()
109
         AHNotification.Builder builder = new AHNotification.Builder()
94
                 .setText(tab.badge.get(""))
110
                 .setText(tab.badge.get(""))
95
-                .setBackgroundColor(tab.badgeColor.get(null));
96
-        bottomTabs.setNotification(builder.build(), tabIndex);
111
+                .setBackgroundColor(tab.badgeColor.get(null))
112
+                .animate(tab.animateBadge.get(false));
113
+        bottomTabs.perform(bottomTabs -> bottomTabs.setNotification(builder.build(), tabIndex));
97
     }
114
     }
98
 
115
 
99
     private void mergeBadge(int index, BottomTabOptions tab) {
116
     private void mergeBadge(int index, BottomTabOptions tab) {
117
+        if (bottomTabs == null) return;
100
         if (!tab.badge.hasValue()) return;
118
         if (!tab.badge.hasValue()) return;
101
         AHNotification.Builder builder = new AHNotification.Builder();
119
         AHNotification.Builder builder = new AHNotification.Builder();
102
         if (tab.badge.hasValue()) builder.setText(tab.badge.get());
120
         if (tab.badge.hasValue()) builder.setText(tab.badge.get());
103
         if (tab.badgeColor.hasValue()) builder.setBackgroundColor(tab.badgeColor.get());
121
         if (tab.badgeColor.hasValue()) builder.setBackgroundColor(tab.badgeColor.get());
104
-        bottomTabs.setNotification(builder.build(), index);
122
+        if (tab.badgeColor.hasValue()) builder.setBackgroundColor(tab.badgeColor.get());
123
+        if (tab.animateBadge.hasValue()) builder.animate(tab.animateBadge.get());
124
+        bottomTabs.perform(bottomTabs -> bottomTabs.setNotification(builder.build(), index));
105
     }
125
     }
106
 
126
 
107
     private void mergeDotIndicator(int index, DotIndicatorOptions dotIndicator) {
127
     private void mergeDotIndicator(int index, DotIndicatorOptions dotIndicator) {
128
+        if (bottomTabs == null) return;
108
         AHNotification.Builder builder = new AHNotification.Builder();
129
         AHNotification.Builder builder = new AHNotification.Builder();
109
         if (dotIndicator.color.hasValue()) builder.setBackgroundColor(dotIndicator.color.get());
130
         if (dotIndicator.color.hasValue()) builder.setBackgroundColor(dotIndicator.color.get());
110
         builder.setSize(dotIndicator.visible.isFalse() ? 0 : dotIndicator.size.get(defaultDotIndicatorSize));
131
         builder.setSize(dotIndicator.visible.isFalse() ? 0 : dotIndicator.size.get(defaultDotIndicatorSize));
132
+        if (dotIndicator.animate.hasValue()) builder.animate(dotIndicator.animate.get());
111
         AHNotification notification = builder.build();
133
         AHNotification notification = builder.build();
112
-        if (notification.hasValue()) bottomTabs.setNotification(notification, index);
134
+        if (notification.hasValue()) bottomTabs.perform(bottomTabs -> bottomTabs.setNotification(notification, index));
113
     }
135
     }
114
 
136
 
115
     private boolean shouldApplyDot(BottomTabOptions tab) {
137
     private boolean shouldApplyDot(BottomTabOptions tab) {

+ 18
- 33
lib/android/app/src/main/java/com/reactnativenavigation/presentation/BottomTabsPresenter.java View File

1
 package com.reactnativenavigation.presentation;
1
 package com.reactnativenavigation.presentation;
2
 
2
 
3
 import android.graphics.Color;
3
 import android.graphics.Color;
4
-import android.support.annotation.IntRange;
5
 import android.view.ViewGroup;
4
 import android.view.ViewGroup;
6
-import android.view.ViewGroup.MarginLayoutParams;
7
 
5
 
8
 import com.aurelhubert.ahbottomnavigation.AHBottomNavigation.TitleState;
6
 import com.aurelhubert.ahbottomnavigation.AHBottomNavigation.TitleState;
9
 import com.reactnativenavigation.anim.BottomTabsAnimator;
7
 import com.reactnativenavigation.anim.BottomTabsAnimator;
14
 import com.reactnativenavigation.viewcontrollers.bottomtabs.BottomTabFinder;
12
 import com.reactnativenavigation.viewcontrollers.bottomtabs.BottomTabFinder;
15
 import com.reactnativenavigation.viewcontrollers.bottomtabs.TabSelector;
13
 import com.reactnativenavigation.viewcontrollers.bottomtabs.TabSelector;
16
 import com.reactnativenavigation.views.BottomTabs;
14
 import com.reactnativenavigation.views.BottomTabs;
17
-import com.reactnativenavigation.views.Component;
18
 
15
 
19
 import java.util.List;
16
 import java.util.List;
20
 
17
 
21
-import static com.reactnativenavigation.utils.ViewUtils.getHeight;
18
+import androidx.annotation.IntRange;
22
 
19
 
23
 public class BottomTabsPresenter {
20
 public class BottomTabsPresenter {
24
     private final BottomTabFinder bottomTabFinder;
21
     private final BottomTabFinder bottomTabFinder;
44
         animator = new BottomTabsAnimator(bottomTabs);
41
         animator = new BottomTabsAnimator(bottomTabs);
45
     }
42
     }
46
 
43
 
47
-    public void applyLayoutParamsOptions(Options options, int tabIndex) {
48
-        Options withDefaultOptions = options.copy().withDefaultOptions(defaultOptions);
49
-        applyDrawBehind(withDefaultOptions.bottomTabsOptions, tabIndex);
50
-    }
51
-
52
     public void mergeOptions(Options options) {
44
     public void mergeOptions(Options options) {
53
         mergeBottomTabsOptions(options);
45
         mergeBottomTabsOptions(options);
54
     }
46
     }
57
         applyBottomTabsOptions(options.copy().withDefaultOptions(defaultOptions));
49
         applyBottomTabsOptions(options.copy().withDefaultOptions(defaultOptions));
58
     }
50
     }
59
 
51
 
60
-    public void applyChildOptions(Options options, Component child) {
61
-        int tabIndex = bottomTabFinder.findByComponent(child);
52
+    public void applyChildOptions(Options options, ViewController child) {
53
+        int tabIndex = bottomTabFinder.findByControllerId(child.getId());
62
         if (tabIndex >= 0) {
54
         if (tabIndex >= 0) {
63
-            Options withDefaultOptions = options.copy().withDefaultOptions(defaultOptions);
64
-            applyBottomTabsOptions(withDefaultOptions);
65
-            applyDrawBehind(withDefaultOptions.bottomTabsOptions, tabIndex);
55
+            applyBottomTabsOptions(options.copy().withDefaultOptions(defaultOptions));
56
+            applyDrawBehind(tabIndex);
66
         }
57
         }
67
     }
58
     }
68
 
59
 
69
-    public void mergeChildOptions(Options options, Component child) {
60
+    public void mergeChildOptions(Options options, ViewController child) {
70
         mergeBottomTabsOptions(options);
61
         mergeBottomTabsOptions(options);
71
-        int tabIndex = bottomTabFinder.findByComponent(child);
72
-        if (tabIndex >= 0) mergeDrawBehind(options.bottomTabsOptions, tabIndex);
62
+        int tabIndex = bottomTabFinder.findByControllerId(child.getId());
63
+        if (tabIndex >= 0) mergeDrawBehind(tabIndex);
73
     }
64
     }
74
 
65
 
75
     private void mergeBottomTabsOptions(Options options) {
66
     private void mergeBottomTabsOptions(Options options) {
110
         }
101
         }
111
     }
102
     }
112
 
103
 
113
-    private void applyDrawBehind(BottomTabsOptions options, @IntRange(from = 0) int tabIndex) {
114
-        ViewGroup tab = tabs.get(tabIndex).getView();
115
-        MarginLayoutParams lp = (MarginLayoutParams) tab.getLayoutParams();
116
-        if (options.drawBehind.isTrue()) {
117
-            lp.bottomMargin = 0;
118
-        } else if (options.visible.isTrueOrUndefined()) {
119
-            lp.bottomMargin = getHeight(bottomTabs);
120
-        }
104
+    private void applyDrawBehind(@IntRange(from = 0) int tabIndex) {
105
+        tabs.get(tabIndex).applyBottomInset();
121
     }
106
     }
122
 
107
 
123
-    private void mergeDrawBehind(BottomTabsOptions options, int tabIndex) {
124
-        ViewGroup tab = tabs.get(tabIndex).getView();
125
-        MarginLayoutParams lp = (MarginLayoutParams) tab.getLayoutParams();
126
-        if (options.drawBehind.isTrue()) {
127
-            lp.bottomMargin = 0;
128
-        } else if (options.visible.isTrue() && options.drawBehind.isFalse()) {
129
-            lp.bottomMargin = getHeight(bottomTabs);
130
-        }
108
+    private void mergeDrawBehind(int tabIndex) {
109
+        tabs.get(tabIndex).applyBottomInset();
131
     }
110
     }
132
 
111
 
133
     private void applyBottomTabsOptions(Options options) {
112
     private void applyBottomTabsOptions(Options options) {
164
             bottomTabs.setUseElevation(true, bottomTabsOptions.elevation.get().floatValue());
143
             bottomTabs.setUseElevation(true, bottomTabsOptions.elevation.get().floatValue());
165
         }
144
         }
166
     }
145
     }
146
+
147
+    public void applyBottomInset(int bottomInset) {
148
+        ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) bottomTabs.getLayoutParams();
149
+        lp.bottomMargin = bottomInset;
150
+        bottomTabs.requestLayout();
151
+    }
167
 }
152
 }

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/presentation/ComponentPresenter.java View File

3
 import com.reactnativenavigation.parse.Options;
3
 import com.reactnativenavigation.parse.Options;
4
 import com.reactnativenavigation.views.ComponentLayout;
4
 import com.reactnativenavigation.views.ComponentLayout;
5
 
5
 
6
-public class ComponentPresenter {
6
+public class ComponentPresenter extends ComponentPresenterBase {
7
     public Options defaultOptions;
7
     public Options defaultOptions;
8
 
8
 
9
     public ComponentPresenter(Options defaultOptions) {
9
     public ComponentPresenter(Options defaultOptions) {

+ 23
- 0
lib/android/app/src/main/java/com/reactnativenavigation/presentation/ComponentPresenterBase.java View File

1
+package com.reactnativenavigation.presentation;
2
+
3
+import androidx.annotation.NonNull;
4
+import android.view.View;
5
+import android.view.ViewGroup.MarginLayoutParams;
6
+
7
+public class ComponentPresenterBase {
8
+    public void applyTopInsets(@NonNull View view, int topInsets) {
9
+        MarginLayoutParams lp = (MarginLayoutParams) view.getLayoutParams();
10
+        if (lp.topMargin != topInsets) {
11
+            lp.topMargin = topInsets;
12
+            view.requestLayout();
13
+        }
14
+    }
15
+
16
+    public void applyBottomInset(@NonNull View view, int bottomInset) {
17
+        MarginLayoutParams lp = (MarginLayoutParams) view.getLayoutParams();
18
+        if (lp.bottomMargin!= bottomInset) {
19
+            lp.bottomMargin = bottomInset;
20
+            view.requestLayout();
21
+        }
22
+    }
23
+}

+ 4
- 0
lib/android/app/src/main/java/com/reactnativenavigation/presentation/ExternalComponentPresenter.java View File

1
+package com.reactnativenavigation.presentation;
2
+
3
+public class ExternalComponentPresenter extends ComponentPresenterBase {
4
+}

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/presentation/FabPresenter.java View File

1
 package com.reactnativenavigation.presentation;
1
 package com.reactnativenavigation.presentation;
2
 
2
 
3
 
3
 
4
-import android.support.annotation.NonNull;
4
+import androidx.annotation.NonNull;
5
 import android.view.Gravity;
5
 import android.view.Gravity;
6
 import android.view.View;
6
 import android.view.View;
7
 import android.view.ViewGroup;
7
 import android.view.ViewGroup;

+ 4
- 1
lib/android/app/src/main/java/com/reactnativenavigation/presentation/OverlayManager.java View File

4
 
4
 
5
 import com.reactnativenavigation.utils.CommandListener;
5
 import com.reactnativenavigation.utils.CommandListener;
6
 import com.reactnativenavigation.viewcontrollers.ViewController;
6
 import com.reactnativenavigation.viewcontrollers.ViewController;
7
+import com.reactnativenavigation.views.BehaviourDelegate;
7
 
8
 
8
 import java.util.HashMap;
9
 import java.util.HashMap;
9
 
10
 
11
+import static com.reactnativenavigation.utils.CoordinatorLayoutUtils.matchParentWithBehaviour;
12
+
10
 public class OverlayManager {
13
 public class OverlayManager {
11
     private final HashMap<String, ViewController> overlayRegistry = new HashMap<>();
14
     private final HashMap<String, ViewController> overlayRegistry = new HashMap<>();
12
 
15
 
13
     public void show(ViewGroup overlaysContainer, ViewController overlay, CommandListener listener) {
16
     public void show(ViewGroup overlaysContainer, ViewController overlay, CommandListener listener) {
14
         overlayRegistry.put(overlay.getId(), overlay);
17
         overlayRegistry.put(overlay.getId(), overlay);
15
         overlay.addOnAppearedListener(() -> listener.onSuccess(overlay.getId()));
18
         overlay.addOnAppearedListener(() -> listener.onSuccess(overlay.getId()));
16
-        overlaysContainer.addView(overlay.getView());
19
+        overlaysContainer.addView(overlay.getView(), matchParentWithBehaviour(new BehaviourDelegate(overlay)));
17
     }
20
     }
18
 
21
 
19
     public void dismiss(String componentId, CommandListener listener) {
22
     public void dismiss(String componentId, CommandListener listener) {

+ 65
- 32
lib/android/app/src/main/java/com/reactnativenavigation/presentation/Presenter.java View File

2
 
2
 
3
 import android.app.Activity;
3
 import android.app.Activity;
4
 import android.graphics.Color;
4
 import android.graphics.Color;
5
+import android.graphics.drawable.ColorDrawable;
6
+import android.graphics.drawable.Drawable;
7
+import android.graphics.drawable.LayerDrawable;
5
 import android.os.Build;
8
 import android.os.Build;
6
 import android.view.View;
9
 import android.view.View;
7
 import android.view.ViewGroup.MarginLayoutParams;
10
 import android.view.ViewGroup.MarginLayoutParams;
11
+import android.view.Window;
8
 
12
 
9
 import com.reactnativenavigation.parse.Options;
13
 import com.reactnativenavigation.parse.Options;
10
 import com.reactnativenavigation.parse.OrientationOptions;
14
 import com.reactnativenavigation.parse.OrientationOptions;
11
 import com.reactnativenavigation.parse.StatusBarOptions;
15
 import com.reactnativenavigation.parse.StatusBarOptions;
12
 import com.reactnativenavigation.parse.StatusBarOptions.TextColorScheme;
16
 import com.reactnativenavigation.parse.StatusBarOptions.TextColorScheme;
13
 import com.reactnativenavigation.parse.params.Bool;
17
 import com.reactnativenavigation.parse.params.Bool;
14
-import com.reactnativenavigation.utils.UiUtils;
18
+import com.reactnativenavigation.utils.StatusBarUtils;
19
+import com.reactnativenavigation.viewcontrollers.ParentController;
20
+import com.reactnativenavigation.viewcontrollers.ViewController;
21
+import com.reactnativenavigation.viewcontrollers.navigator.Navigator;
22
+
23
+import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
15
 
24
 
16
 @SuppressWarnings("FieldCanBeLocal")
25
 @SuppressWarnings("FieldCanBeLocal")
17
 public class Presenter {
26
 public class Presenter {
32
         mergeStatusBarOptions(view, options.statusBar);
41
         mergeStatusBarOptions(view, options.statusBar);
33
     }
42
     }
34
 
43
 
35
-    public void applyOptions(View view, Options options) {
44
+    public void applyOptions(ViewController view, Options options) {
36
         Options withDefaultOptions = options.copy().withDefaultOptions(defaultOptions);
45
         Options withDefaultOptions = options.copy().withDefaultOptions(defaultOptions);
37
         applyOrientation(withDefaultOptions.layout.orientation);
46
         applyOrientation(withDefaultOptions.layout.orientation);
38
         applyViewOptions(view, withDefaultOptions);
47
         applyViewOptions(view, withDefaultOptions);
39
-        applyStatusBarOptions(view, withDefaultOptions.statusBar);
40
-    }
41
-
42
-    public void applyRootOptions(View view, Options options) {
43
-        Options withDefaultOptions = options.copy().withDefaultOptions(defaultOptions);
44
-        setDrawBehindStatusBar(view, withDefaultOptions.statusBar);
48
+        applyStatusBarOptions(withDefaultOptions);
45
     }
49
     }
46
 
50
 
47
-    public void onViewBroughtToFront(View view, Options options) {
51
+    public void onViewBroughtToFront(Options options) {
48
         Options withDefaultOptions = options.copy().withDefaultOptions(defaultOptions);
52
         Options withDefaultOptions = options.copy().withDefaultOptions(defaultOptions);
49
-        applyStatusBarOptions(view, withDefaultOptions.statusBar);
53
+        applyStatusBarOptions(withDefaultOptions);
50
     }
54
     }
51
 
55
 
52
     private void applyOrientation(OrientationOptions options) {
56
     private void applyOrientation(OrientationOptions options) {
53
         activity.setRequestedOrientation(options.getValue());
57
         activity.setRequestedOrientation(options.getValue());
54
     }
58
     }
55
 
59
 
56
-    private void applyViewOptions(View view, Options options) {
57
-        if (options.layout.backgroundColor.hasValue()) {
58
-            view.setBackgroundColor(options.layout.backgroundColor.get());
59
-        }
60
-        applyTopMargin(view, options);
60
+    private void applyViewOptions(ViewController view, Options options) {
61
+        applyBackgroundColor(view, options);
62
+        applyTopMargin(view.getView(), options);
61
     }
63
     }
62
 
64
 
63
     private void applyTopMargin(View view, Options options) {
65
     private void applyTopMargin(View view, Options options) {
66
         }
68
         }
67
     }
69
     }
68
 
70
 
69
-    private void applyStatusBarOptions(View view, StatusBarOptions statusBar) {
70
-        setStatusBarBackgroundColor(statusBar);
71
-        setTextColorScheme(statusBar.textColorScheme);
72
-        setStatusBarVisible(view, statusBar.visible, statusBar.drawBehind);
71
+    private void applyBackgroundColor(ViewController view, Options options) {
72
+        if (options.layout.backgroundColor.hasValue()) {
73
+            if (view instanceof Navigator) return;
74
+
75
+            LayerDrawable ld = new LayerDrawable(new Drawable[]{new ColorDrawable(options.layout.backgroundColor.get())});
76
+            int top = view.resolveCurrentOptions().statusBar.drawBehind.isTrue() ? 0 : StatusBarUtils.getStatusBarHeight(view.getActivity());
77
+            if (!(view instanceof ParentController)) {
78
+                MarginLayoutParams lp = (MarginLayoutParams) view.getView().getLayoutParams();
79
+                if (lp.topMargin != 0) top = 0;
80
+            }
81
+            ld.setLayerInset(0, 0, top, 0, 0);
82
+            view.getView().setBackground(ld);
83
+        }
73
     }
84
     }
74
 
85
 
75
-    private void setStatusBarVisible(View view, Bool visible, Bool drawBehind) {
86
+    private void applyStatusBarOptions(Options options) {
87
+        setStatusBarBackgroundColor(options.statusBar);
88
+        setTextColorScheme(options.statusBar.textColorScheme);
89
+        setTranslucent(options.statusBar);
90
+        setStatusBarVisible(options.statusBar.visible);
91
+    }
92
+
93
+    private void setTranslucent(StatusBarOptions options) {
94
+        Window window = activity.getWindow();
95
+        if (options.translucent.isTrue()) {
96
+            window.setFlags(FLAG_TRANSLUCENT_STATUS, FLAG_TRANSLUCENT_STATUS);
97
+        } else {
98
+            window.clearFlags(FLAG_TRANSLUCENT_STATUS);
99
+        }
100
+    }
101
+
102
+    private void setStatusBarVisible(Bool visible) {
103
+        View decorView = activity.getWindow().getDecorView();
104
+        int flags = decorView.getSystemUiVisibility();
76
         if (visible.isFalse()) {
105
         if (visible.isFalse()) {
77
-            view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_FULLSCREEN);
78
-        } else if (drawBehind.isTrue()) {
79
-            view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
106
+            flags |= View.SYSTEM_UI_FLAG_FULLSCREEN;
107
+        } else {
108
+            flags &= ~View.SYSTEM_UI_FLAG_FULLSCREEN;
80
         }
109
         }
110
+        decorView.setSystemUiVisibility(flags);
81
     }
111
     }
82
 
112
 
83
     private void setStatusBarBackgroundColor(StatusBarOptions statusBar) {
113
     private void setStatusBarBackgroundColor(StatusBarOptions statusBar) {
84
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
114
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
85
-            activity.getWindow().setStatusBarColor(statusBar.backgroundColor.get(Color.BLACK));
115
+            int defaultColor = statusBar.visible.isTrueOrUndefined() ? Color.BLACK : Color.TRANSPARENT;
116
+            activity.getWindow().setStatusBarColor(statusBar.backgroundColor.get(defaultColor));
86
         }
117
         }
87
     }
118
     }
88
 
119
 
105
         view.setSystemUiVisibility(flags);
136
         view.setSystemUiVisibility(flags);
106
     }
137
     }
107
 
138
 
108
-    private void setDrawBehindStatusBar(View view, StatusBarOptions statusBar) {
109
-        if (statusBar.visible.isFalse()) {
110
-            ((MarginLayoutParams) view.getLayoutParams()).topMargin = statusBar.drawBehind.isTrue() ?
111
-                    0 : UiUtils.getStatusBarHeight(activity);
112
-        }
113
-    }
114
-
115
-
116
     private void mergeStatusBarOptions(View view, StatusBarOptions statusBar) {
139
     private void mergeStatusBarOptions(View view, StatusBarOptions statusBar) {
117
         mergeStatusBarBackgroundColor(statusBar);
140
         mergeStatusBarBackgroundColor(statusBar);
118
         mergeTextColorScheme(statusBar.textColorScheme);
141
         mergeTextColorScheme(statusBar.textColorScheme);
142
+        mergeTranslucent(statusBar);
119
         mergeStatusBarVisible(view, statusBar.visible, statusBar.drawBehind);
143
         mergeStatusBarVisible(view, statusBar.visible, statusBar.drawBehind);
120
     }
144
     }
121
 
145
 
137
         }
161
         }
138
     }
162
     }
139
 
163
 
164
+    private void mergeTranslucent(StatusBarOptions options) {
165
+        Window window = activity.getWindow();
166
+        if (options.translucent.isTrue()) {
167
+            window.setFlags(FLAG_TRANSLUCENT_STATUS, FLAG_TRANSLUCENT_STATUS);
168
+        } else if (options.translucent.isFalse()) {
169
+            window.clearFlags(FLAG_TRANSLUCENT_STATUS);
170
+        }
171
+    }
172
+
140
     private void mergeStatusBarVisible(View view, Bool visible, Bool drawBehind) {
173
     private void mergeStatusBarVisible(View view, Bool visible, Bool drawBehind) {
141
         if (visible.hasValue()) {
174
         if (visible.hasValue()) {
142
             int flags = view.getSystemUiVisibility();
175
             int flags = view.getSystemUiVisibility();

+ 10
- 4
lib/android/app/src/main/java/com/reactnativenavigation/presentation/RootPresenter.java View File

1
 package com.reactnativenavigation.presentation;
1
 package com.reactnativenavigation.presentation;
2
 
2
 
3
 import android.content.Context;
3
 import android.content.Context;
4
-import android.widget.FrameLayout;
5
 
4
 
6
 import com.facebook.react.ReactInstanceManager;
5
 import com.facebook.react.ReactInstanceManager;
7
 import com.reactnativenavigation.anim.NavigationAnimator;
6
 import com.reactnativenavigation.anim.NavigationAnimator;
8
 import com.reactnativenavigation.parse.Options;
7
 import com.reactnativenavigation.parse.Options;
9
 import com.reactnativenavigation.utils.CommandListener;
8
 import com.reactnativenavigation.utils.CommandListener;
10
 import com.reactnativenavigation.viewcontrollers.ViewController;
9
 import com.reactnativenavigation.viewcontrollers.ViewController;
10
+import com.reactnativenavigation.views.BehaviourDelegate;
11
 import com.reactnativenavigation.views.element.ElementTransitionManager;
11
 import com.reactnativenavigation.views.element.ElementTransitionManager;
12
 
12
 
13
+import androidx.annotation.VisibleForTesting;
14
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
15
+
16
+import static com.reactnativenavigation.utils.CoordinatorLayoutUtils.matchParentWithBehaviour;
17
+
13
 public class RootPresenter {
18
 public class RootPresenter {
14
     private NavigationAnimator animator;
19
     private NavigationAnimator animator;
20
+    private CoordinatorLayout rootLayout;
15
     private LayoutDirectionApplier layoutDirectionApplier;
21
     private LayoutDirectionApplier layoutDirectionApplier;
16
-    private FrameLayout rootLayout;
17
 
22
 
18
-    public void setRootContainer(FrameLayout rootLayout) {
23
+    public void setRootContainer(CoordinatorLayout rootLayout) {
19
         this.rootLayout = rootLayout;
24
         this.rootLayout = rootLayout;
20
     }
25
     }
21
 
26
 
23
         this(new NavigationAnimator(context, new ElementTransitionManager()), new LayoutDirectionApplier());
28
         this(new NavigationAnimator(context, new ElementTransitionManager()), new LayoutDirectionApplier());
24
     }
29
     }
25
 
30
 
31
+    @VisibleForTesting
26
     public RootPresenter(NavigationAnimator animator, LayoutDirectionApplier layoutDirectionApplier) {
32
     public RootPresenter(NavigationAnimator animator, LayoutDirectionApplier layoutDirectionApplier) {
27
         this.animator = animator;
33
         this.animator = animator;
28
         this.layoutDirectionApplier = layoutDirectionApplier;
34
         this.layoutDirectionApplier = layoutDirectionApplier;
30
 
36
 
31
     public void setRoot(ViewController root, Options defaultOptions, CommandListener listener, ReactInstanceManager reactInstanceManager) {
37
     public void setRoot(ViewController root, Options defaultOptions, CommandListener listener, ReactInstanceManager reactInstanceManager) {
32
         layoutDirectionApplier.apply(root, defaultOptions, reactInstanceManager);
38
         layoutDirectionApplier.apply(root, defaultOptions, reactInstanceManager);
33
-        rootLayout.addView(root.getView());
39
+        rootLayout.addView(root.getView(), matchParentWithBehaviour(new BehaviourDelegate(root)));
34
         Options options = root.resolveCurrentOptions(defaultOptions);
40
         Options options = root.resolveCurrentOptions(defaultOptions);
35
         root.setWaitForRender(options.animations.setRoot.waitForRender);
41
         root.setWaitForRender(options.animations.setRoot.waitForRender);
36
         if (options.animations.setRoot.waitForRender.isTrue()) {
42
         if (options.animations.setRoot.waitForRender.isTrue()) {

+ 11
- 3
lib/android/app/src/main/java/com/reactnativenavigation/presentation/SideMenuPresenter.java View File

1
 package com.reactnativenavigation.presentation;
1
 package com.reactnativenavigation.presentation;
2
 
2
 
3
-import android.support.v4.widget.DrawerLayout;
4
 import android.view.Gravity;
3
 import android.view.Gravity;
5
 
4
 
6
 import com.reactnativenavigation.parse.Options;
5
 import com.reactnativenavigation.parse.Options;
7
 import com.reactnativenavigation.parse.SideMenuRootOptions;
6
 import com.reactnativenavigation.parse.SideMenuRootOptions;
7
+import com.reactnativenavigation.views.SideMenu;
8
+
9
+import androidx.annotation.RestrictTo;
10
+import androidx.drawerlayout.widget.DrawerLayout;
8
 
11
 
9
 public class SideMenuPresenter {
12
 public class SideMenuPresenter {
10
 
13
 
11
-    private DrawerLayout sideMenu;
14
+    private SideMenu sideMenu;
12
 
15
 
13
-    public void bindView(DrawerLayout sideMenu) {
16
+    public void bindView(SideMenu sideMenu) {
14
         this.sideMenu = sideMenu;
17
         this.sideMenu = sideMenu;
15
     }
18
     }
16
 
19
 
76
             sideMenu.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, Gravity.RIGHT);
79
             sideMenu.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, Gravity.RIGHT);
77
         }
80
         }
78
     }
81
     }
82
+
83
+    @RestrictTo(RestrictTo.Scope.TESTS)
84
+    public SideMenu getSideMenu() {
85
+        return sideMenu;
86
+    }
79
 }
87
 }

+ 93
- 83
lib/android/app/src/main/java/com/reactnativenavigation/presentation/StackPresenter.java View File

2
 
2
 
3
 import android.app.Activity;
3
 import android.app.Activity;
4
 import android.graphics.Color;
4
 import android.graphics.Color;
5
-import android.support.annotation.Nullable;
6
-import android.support.annotation.RestrictTo;
7
-import android.support.v7.widget.Toolbar;
8
 import android.view.Gravity;
5
 import android.view.Gravity;
9
 import android.view.View;
6
 import android.view.View;
10
 import android.view.ViewGroup.LayoutParams;
7
 import android.view.ViewGroup.LayoutParams;
26
 import com.reactnativenavigation.utils.CollectionUtils;
23
 import com.reactnativenavigation.utils.CollectionUtils;
27
 import com.reactnativenavigation.utils.ImageLoader;
24
 import com.reactnativenavigation.utils.ImageLoader;
28
 import com.reactnativenavigation.utils.ObjectUtils;
25
 import com.reactnativenavigation.utils.ObjectUtils;
26
+import com.reactnativenavigation.utils.StatusBarUtils;
29
 import com.reactnativenavigation.utils.UiUtils;
27
 import com.reactnativenavigation.utils.UiUtils;
30
 import com.reactnativenavigation.viewcontrollers.IReactView;
28
 import com.reactnativenavigation.viewcontrollers.IReactView;
31
 import com.reactnativenavigation.viewcontrollers.ReactViewCreator;
29
 import com.reactnativenavigation.viewcontrollers.ReactViewCreator;
33
 import com.reactnativenavigation.viewcontrollers.TitleBarReactViewController;
31
 import com.reactnativenavigation.viewcontrollers.TitleBarReactViewController;
34
 import com.reactnativenavigation.viewcontrollers.ViewController;
32
 import com.reactnativenavigation.viewcontrollers.ViewController;
35
 import com.reactnativenavigation.viewcontrollers.button.NavigationIconResolver;
33
 import com.reactnativenavigation.viewcontrollers.button.NavigationIconResolver;
34
+import com.reactnativenavigation.viewcontrollers.stack.StackController;
36
 import com.reactnativenavigation.viewcontrollers.topbar.TopBarBackgroundViewController;
35
 import com.reactnativenavigation.viewcontrollers.topbar.TopBarBackgroundViewController;
37
-import com.reactnativenavigation.views.Component;
36
+import com.reactnativenavigation.viewcontrollers.topbar.TopBarController;
38
 import com.reactnativenavigation.views.titlebar.TitleBarReactViewCreator;
37
 import com.reactnativenavigation.views.titlebar.TitleBarReactViewCreator;
39
 import com.reactnativenavigation.views.topbar.TopBar;
38
 import com.reactnativenavigation.views.topbar.TopBar;
40
 import com.reactnativenavigation.views.topbar.TopBarBackgroundViewCreator;
39
 import com.reactnativenavigation.views.topbar.TopBarBackgroundViewCreator;
46
 import java.util.List;
45
 import java.util.List;
47
 import java.util.Map;
46
 import java.util.Map;
48
 
47
 
48
+import androidx.annotation.Nullable;
49
+import androidx.annotation.RestrictTo;
50
+import androidx.appcompat.widget.Toolbar;
51
+
49
 import static com.reactnativenavigation.utils.CollectionUtils.*;
52
 import static com.reactnativenavigation.utils.CollectionUtils.*;
50
 import static com.reactnativenavigation.utils.ObjectUtils.perform;
53
 import static com.reactnativenavigation.utils.ObjectUtils.perform;
51
 
54
 
59
     private final Activity activity;
62
     private final Activity activity;
60
 
63
 
61
     private TopBar topBar;
64
     private TopBar topBar;
65
+    private TopBarController topBarController;
62
     private final TitleBarReactViewCreator titleViewCreator;
66
     private final TitleBarReactViewCreator titleViewCreator;
63
     private TitleBarButtonController.OnClickListener onClickListener;
67
     private TitleBarButtonController.OnClickListener onClickListener;
64
     private final ImageLoader imageLoader;
68
     private final ImageLoader imageLoader;
66
     private final TopBarBackgroundViewCreator topBarBackgroundViewCreator;
70
     private final TopBarBackgroundViewCreator topBarBackgroundViewCreator;
67
     private final ReactViewCreator buttonCreator;
71
     private final ReactViewCreator buttonCreator;
68
     private Options defaultOptions;
72
     private Options defaultOptions;
69
-    private Map<Component, TitleBarReactViewController> titleControllers = new HashMap();
70
-    private Map<Component, TopBarBackgroundViewController> backgroundControllers = new HashMap();
71
-    private Map<Component, Map<String, TitleBarButtonController>> componentRightButtons = new HashMap();
72
-    private Map<Component, Map<String, TitleBarButtonController>> componentLeftButtons = new HashMap();
73
+
73
     private List<TitleBarButtonController> currentRightButtons = new ArrayList<>();
74
     private List<TitleBarButtonController> currentRightButtons = new ArrayList<>();
75
+    private Map<View, TitleBarReactViewController> titleControllers = new HashMap();
76
+    private Map<View, TopBarBackgroundViewController> backgroundControllers = new HashMap();
77
+    private Map<View, Map<String, TitleBarButtonController>> componentRightButtons = new HashMap();
78
+    private Map<View, Map<String, TitleBarButtonController>> componentLeftButtons = new HashMap();
74
 
79
 
75
     public StackPresenter(Activity activity,
80
     public StackPresenter(Activity activity,
76
                           TitleBarReactViewCreator titleViewCreator,
81
                           TitleBarReactViewCreator titleViewCreator,
102
         return defaultOptions;
107
         return defaultOptions;
103
     }
108
     }
104
 
109
 
105
-    public void bindView(TopBar topBar) {
106
-        this.topBar = topBar;
110
+    public void bindView(TopBarController topBarController) {
111
+        this.topBarController = topBarController;
112
+        topBar = topBarController.getView();
107
     }
113
     }
108
 
114
 
109
-    public boolean isRendered(Component component) {
115
+    public boolean isRendered(View component) {
110
         ArrayList<ViewController> controllers = new ArrayList<>(perform(componentRightButtons.get(component), new ArrayList<>(), Map::values));
116
         ArrayList<ViewController> controllers = new ArrayList<>(perform(componentRightButtons.get(component), new ArrayList<>(), Map::values));
111
         controllers.add(backgroundControllers.get(component));
117
         controllers.add(backgroundControllers.get(component));
112
         controllers.add(titleControllers.get(component));
118
         controllers.add(titleControllers.get(component));
113
         return renderChecker.areRendered(filter(controllers, ObjectUtils::notNull));
119
         return renderChecker.areRendered(filter(controllers, ObjectUtils::notNull));
114
     }
120
     }
115
 
121
 
116
-    public void applyLayoutParamsOptions(Options options, View view) {
117
-        Options withDefault = options.copy().withDefaultOptions(defaultOptions);
118
-        if (view instanceof Component) {
119
-            if (withDefault.topBar.drawBehind.isTrue() && !withDefault.layout.topMargin.hasValue()) {
120
-                ((Component) view).drawBehindTopBar();
121
-            } else if (options.topBar.drawBehind.isFalseOrUndefined()) {
122
-                ((Component) view).drawBelowTopBar(topBar);
123
-            }
124
-        }
125
-    }
126
-
127
-    public void mergeOptions(Options options, Component currentChild) {
122
+    public void mergeOptions(Options options, StackController stack, ViewController currentChild) {
128
         mergeOrientation(options.layout.orientation);
123
         mergeOrientation(options.layout.orientation);
129
 //        mergeButtons(topBar, withDefault.topBar.buttons, child);
124
 //        mergeButtons(topBar, withDefault.topBar.buttons, child);
130
-        mergeTopBarOptions(options, currentChild);
125
+        mergeTopBarOptions(options, stack, currentChild);
131
         mergeTopTabsOptions(options.topTabs);
126
         mergeTopTabsOptions(options.topTabs);
132
         mergeTopTabOptions(options.topTabOptions);
127
         mergeTopTabOptions(options.topTabOptions);
133
     }
128
     }
137
         setInitialTopBarVisibility(withDefault.topBar);
132
         setInitialTopBarVisibility(withDefault.topBar);
138
     }
133
     }
139
 
134
 
140
-    public void applyChildOptions(Options options, Component child) {
135
+    public void applyChildOptions(Options options, StackController stack, ViewController child) {
141
         Options withDefault = options.copy().withDefaultOptions(defaultOptions);
136
         Options withDefault = options.copy().withDefaultOptions(defaultOptions);
142
         applyOrientation(withDefault.layout.orientation);
137
         applyOrientation(withDefault.layout.orientation);
143
         applyButtons(withDefault.topBar, child);
138
         applyButtons(withDefault.topBar, child);
144
-        applyTopBarOptions(withDefault, child, options);
139
+        applyTopBarOptions(withDefault, stack, child, options);
145
         applyTopTabsOptions(withDefault.topTabs);
140
         applyTopTabsOptions(withDefault.topTabs);
146
         applyTopTabOptions(withDefault.topTabOptions);
141
         applyTopTabOptions(withDefault.topTabOptions);
147
     }
142
     }
151
         ((Activity) topBar.getContext()).setRequestedOrientation(withDefaultOptions.getValue());
146
         ((Activity) topBar.getContext()).setRequestedOrientation(withDefaultOptions.getValue());
152
     }
147
     }
153
 
148
 
154
-    public void onChildDestroyed(Component child) {
155
-        perform(titleControllers.remove(child), TitleBarReactViewController::destroy);
156
-        perform(backgroundControllers.remove(child), TopBarBackgroundViewController::destroy);
157
-        destroyButtons(componentRightButtons.get(child));
158
-        destroyButtons(componentLeftButtons.get(child));
159
-        componentRightButtons.remove(child);
160
-        componentLeftButtons.remove(child);
149
+    public void onChildDestroyed(ViewController child) {
150
+        perform(titleControllers.remove(child.getView()), TitleBarReactViewController::destroy);
151
+        perform(backgroundControllers.remove(child.getView()), TopBarBackgroundViewController::destroy);
152
+        destroyButtons(componentRightButtons.get(child.getView()));
153
+        destroyButtons(componentLeftButtons.get(child.getView()));
154
+        componentRightButtons.remove(child.getView());
155
+        componentLeftButtons.remove(child.getView());
161
     }
156
     }
162
 
157
 
163
     private void destroyButtons(@Nullable Map<String, TitleBarButtonController> buttons) {
158
     private void destroyButtons(@Nullable Map<String, TitleBarButtonController> buttons) {
164
         if (buttons != null) forEach(buttons.values(), ViewController::destroy);
159
         if (buttons != null) forEach(buttons.values(), ViewController::destroy);
165
     }
160
     }
166
 
161
 
167
-    private void applyTopBarOptions(Options options, Component component, Options componentOptions) {
162
+    private void applyTopBarOptions(Options options, StackController stack, ViewController child, Options componentOptions) {
163
+        final View component = child.getView();
168
         TopBarOptions topBarOptions = options.topBar;
164
         TopBarOptions topBarOptions = options.topBar;
169
         AnimationsOptions animationOptions = options.animations;
165
         AnimationsOptions animationOptions = options.animations;
170
 
166
 
167
+        topBar.setTestId(topBarOptions.testId.get(""));
171
         topBar.setLayoutDirection(options.layout.direction);
168
         topBar.setLayoutDirection(options.layout.direction);
172
         topBar.setHeight(topBarOptions.height.get(UiUtils.getTopBarHeightDp(activity)));
169
         topBar.setHeight(topBarOptions.height.get(UiUtils.getTopBarHeightDp(activity)));
173
         topBar.setElevation(topBarOptions.elevation.get(DEFAULT_ELEVATION));
170
         topBar.setElevation(topBarOptions.elevation.get(DEFAULT_ELEVATION));
224
             topBar.clearBackgroundComponent();
221
             topBar.clearBackgroundComponent();
225
         }
222
         }
226
 
223
 
227
-        if (topBarOptions.testId.hasValue()) topBar.setTestId(topBarOptions.testId.get());
228
-        applyTopBarVisibility(topBarOptions, animationOptions, componentOptions);
229
-        if (topBarOptions.drawBehind.isTrue() && !componentOptions.layout.topMargin.hasValue()) {
230
-            component.drawBehindTopBar();
231
-        } else if (topBarOptions.drawBehind.isFalseOrUndefined()) {
232
-            component.drawBelowTopBar(topBar);
233
-        }
224
+        applyTopBarVisibility(topBarOptions, animationOptions, componentOptions, stack, child);
234
         if (topBarOptions.hideOnScroll.isTrue()) {
225
         if (topBarOptions.hideOnScroll.isTrue()) {
235
             if (component instanceof IReactView) {
226
             if (component instanceof IReactView) {
236
                 topBar.enableCollapse(((IReactView) component).getScrollEventListener());
227
                 topBar.enableCollapse(((IReactView) component).getScrollEventListener());
253
 
244
 
254
     private void setInitialTopBarVisibility(TopBarOptions options) {
245
     private void setInitialTopBarVisibility(TopBarOptions options) {
255
         if (options.visible.isFalse()) {
246
         if (options.visible.isFalse()) {
256
-            topBar.hide();
247
+            topBarController.hide();
257
         }
248
         }
258
         if (options.visible.isTrueOrUndefined()) {
249
         if (options.visible.isTrueOrUndefined()) {
259
-            topBar.show();
250
+            topBarController.show();
260
         }
251
         }
261
     }
252
     }
262
 
253
 
263
-    private void applyTopBarVisibility(TopBarOptions options, AnimationsOptions animationOptions, Options componentOptions) {
254
+    private void applyTopBarVisibility(TopBarOptions options, AnimationsOptions animationOptions, Options componentOptions, StackController stack, ViewController child) {
264
         if (options.visible.isFalse()) {
255
         if (options.visible.isFalse()) {
256
+            topBarController.resetViewProperties();
265
             if (options.animate.isTrueOrUndefined() && componentOptions.animations.push.enabled.isTrueOrUndefined()) {
257
             if (options.animate.isTrueOrUndefined() && componentOptions.animations.push.enabled.isTrueOrUndefined()) {
266
-                topBar.hideAnimate(animationOptions.pop.topBar);
258
+                topBarController.hideAnimate(animationOptions.pop.topBar, 0, getTopBarTranslationAnimationDelta(stack, child));
267
             } else {
259
             } else {
268
-                topBar.hide();
260
+                topBarController.hide();
269
             }
261
             }
270
-        }
271
-        if (options.visible.isTrueOrUndefined()) {
262
+        } else if (options.visible.isTrueOrUndefined()) {
263
+            topBarController.resetViewProperties();
272
             if (options.animate.isTrueOrUndefined() && componentOptions.animations.push.enabled.isTrueOrUndefined()) {
264
             if (options.animate.isTrueOrUndefined() && componentOptions.animations.push.enabled.isTrueOrUndefined()) {
273
-                topBar.showAnimate(animationOptions.push.topBar);
265
+                topBarController.showAnimate(animationOptions.push.topBar, getTopBarTranslationAnimationDelta(stack, child));
274
             } else {
266
             } else {
275
-                topBar.show();
267
+                topBarController.show();
276
             }
268
             }
277
         }
269
         }
278
     }
270
     }
279
 
271
 
280
-    private void applyButtons(TopBarOptions options, Component child) {
272
+    private void applyButtons(TopBarOptions options, ViewController child) {
281
         List<Button> rightButtons = mergeButtonsWithColor(options.buttons.right, options.rightButtonColor, options.rightButtonDisabledColor);
273
         List<Button> rightButtons = mergeButtonsWithColor(options.buttons.right, options.rightButtonColor, options.rightButtonDisabledColor);
282
         List<Button> leftButtons = mergeButtonsWithColor(options.buttons.left, options.leftButtonColor, options.leftButtonDisabledColor);
274
         List<Button> leftButtons = mergeButtonsWithColor(options.buttons.left, options.leftButtonColor, options.leftButtonDisabledColor);
283
 
275
 
284
         if (rightButtons != null) {
276
         if (rightButtons != null) {
285
-            List<TitleBarButtonController> rightButtonControllers = getOrCreateButtonControllers(componentRightButtons.get(child), rightButtons);
286
-            componentRightButtons.put(child, keyBy(rightButtonControllers, TitleBarButtonController::getButtonInstanceId));
277
+            List<TitleBarButtonController> rightButtonControllers = getOrCreateButtonControllers(componentRightButtons.get(child.getView()), rightButtons);
278
+            componentRightButtons.put(child.getView(), keyBy(rightButtonControllers, TitleBarButtonController::getButtonInstanceId));
287
             if (!CollectionUtils.equals(currentRightButtons, rightButtonControllers)) {
279
             if (!CollectionUtils.equals(currentRightButtons, rightButtonControllers)) {
288
                 currentRightButtons = rightButtonControllers;
280
                 currentRightButtons = rightButtonControllers;
289
                 topBar.setRightButtons(rightButtonControllers);
281
                 topBar.setRightButtons(rightButtonControllers);
294
         }
286
         }
295
 
287
 
296
         if (leftButtons != null) {
288
         if (leftButtons != null) {
297
-            List<TitleBarButtonController> leftButtonControllers = getOrCreateButtonControllers(componentLeftButtons.get(child), leftButtons);
298
-            componentLeftButtons.put(child, keyBy(leftButtonControllers, TitleBarButtonController::getButtonInstanceId));
289
+            List<TitleBarButtonController> leftButtonControllers = getOrCreateButtonControllers(componentLeftButtons.get(child.getView()), leftButtons);
290
+            componentLeftButtons.put(child.getView(), keyBy(leftButtonControllers, TitleBarButtonController::getButtonInstanceId));
299
             topBar.setLeftButtons(leftButtonControllers);
291
             topBar.setLeftButtons(leftButtonControllers);
300
         } else {
292
         } else {
301
             topBar.clearLeftButtons();
293
             topBar.clearLeftButtons();
341
         if (topTabOptions.fontFamily != null) topBar.setTopTabFontFamily(topTabOptions.tabIndex, topTabOptions.fontFamily);
333
         if (topTabOptions.fontFamily != null) topBar.setTopTabFontFamily(topTabOptions.tabIndex, topTabOptions.fontFamily);
342
     }
334
     }
343
 
335
 
344
-    public void onChildWillAppear(Options appearing, Options disappearing) {
345
-        if (disappearing.topBar.visible.isTrueOrUndefined() && appearing.topBar.visible.isFalse()) {
346
-            if (disappearing.topBar.animate.isTrueOrUndefined() && disappearing.animations.pop.enabled.isTrueOrUndefined()) {
347
-                topBar.hideAnimate(disappearing.animations.pop.topBar);
336
+    public void onChildWillAppear(StackController parent, ViewController appearing, ViewController disappearing) {
337
+        if (disappearing.options.topBar.visible.isTrueOrUndefined() && appearing.options.topBar.visible.isFalse()) {
338
+            if (disappearing.options.topBar.animate.isTrueOrUndefined() && disappearing.options.animations.pop.enabled.isTrueOrUndefined()) {
339
+                topBarController.hideAnimate(disappearing.options.animations.pop.topBar, 0, getTopBarTranslationAnimationDelta(parent, appearing));
348
             } else {
340
             } else {
349
-                topBar.hide();
341
+                topBarController.hide();
350
             }
342
             }
351
         }
343
         }
352
     }
344
     }
353
 
345
 
354
-    public void mergeChildOptions(Options toMerge, Options resolvedOptions, Component child) {
346
+    public void mergeChildOptions(Options toMerge, Options resolvedOptions, StackController stack, ViewController child) {
355
         TopBarOptions topBar = toMerge.copy().mergeWith(resolvedOptions).withDefaultOptions(defaultOptions).topBar;
347
         TopBarOptions topBar = toMerge.copy().mergeWith(resolvedOptions).withDefaultOptions(defaultOptions).topBar;
356
         mergeOrientation(toMerge.layout.orientation);
348
         mergeOrientation(toMerge.layout.orientation);
357
-        mergeButtons(topBar, toMerge.topBar.buttons, child);
358
-        mergeTopBarOptions(toMerge, child);
349
+        mergeButtons(topBar, toMerge.topBar.buttons, child.getView());
350
+        mergeTopBarOptions(toMerge, stack, child);
359
         mergeTopTabsOptions(toMerge.topTabs);
351
         mergeTopTabsOptions(toMerge.topTabs);
360
         mergeTopTabOptions(toMerge.topTabOptions);
352
         mergeTopTabOptions(toMerge.topTabOptions);
361
     }
353
     }
364
         if (orientationOptions.hasValue()) applyOrientation(orientationOptions);
356
         if (orientationOptions.hasValue()) applyOrientation(orientationOptions);
365
     }
357
     }
366
 
358
 
367
-    private void mergeButtons(TopBarOptions options, TopBarButtons buttons, Component child) {
359
+    private void mergeButtons(TopBarOptions options, TopBarButtons buttons, View child) {
368
         List<Button> rightButtons = mergeButtonsWithColor(buttons.right, options.rightButtonColor, options.rightButtonDisabledColor);
360
         List<Button> rightButtons = mergeButtonsWithColor(buttons.right, options.rightButtonColor, options.rightButtonDisabledColor);
369
         List<Button> leftButtons = mergeButtonsWithColor(buttons.left, options.leftButtonColor, options.leftButtonDisabledColor);
361
         List<Button> leftButtons = mergeButtonsWithColor(buttons.left, options.leftButtonColor, options.leftButtonDisabledColor);
370
 
362
 
407
         return result;
399
         return result;
408
     }
400
     }
409
 
401
 
410
-    private void mergeTopBarOptions(Options options, Component component) {
402
+    private void mergeTopBarOptions(Options options, StackController stack, ViewController child) {
403
+        AnimationsOptions animationsOptions = options.copy().withDefaultOptions(defaultOptions).animations;
411
         TopBarOptions topBarOptions = options.topBar;
404
         TopBarOptions topBarOptions = options.topBar;
412
-        AnimationsOptions animationsOptions = options.animations;
413
-
405
+        final View component = child.getView();
414
         if (options.layout.direction.hasValue()) topBar.setLayoutDirection(options.layout.direction);
406
         if (options.layout.direction.hasValue()) topBar.setLayoutDirection(options.layout.direction);
415
         if (topBarOptions.height.hasValue()) topBar.setHeight(topBarOptions.height.get());
407
         if (topBarOptions.height.hasValue()) topBar.setHeight(topBarOptions.height.get());
416
         if (topBarOptions.elevation.hasValue()) topBar.setElevation(topBarOptions.elevation.get());
408
         if (topBarOptions.elevation.hasValue()) topBar.setElevation(topBarOptions.elevation.get());
459
 
451
 
460
         if (topBarOptions.testId.hasValue()) topBar.setTestId(topBarOptions.testId.get());
452
         if (topBarOptions.testId.hasValue()) topBar.setTestId(topBarOptions.testId.get());
461
 
453
 
454
+        topBarController.resetViewProperties();
462
         if (topBarOptions.visible.isFalse()) {
455
         if (topBarOptions.visible.isFalse()) {
463
             if (topBarOptions.animate.isTrueOrUndefined()) {
456
             if (topBarOptions.animate.isTrueOrUndefined()) {
464
-                topBar.hideAnimate(animationsOptions.pop.topBar);
457
+                topBarController.hideAnimate(animationsOptions.pop.topBar, 0, getTopBarTranslationAnimationDelta(stack, child));
465
             } else {
458
             } else {
466
-                topBar.hide();
459
+                topBarController.hide();
467
             }
460
             }
468
         }
461
         }
469
         if (topBarOptions.visible.isTrue()) {
462
         if (topBarOptions.visible.isTrue()) {
470
             if (topBarOptions.animate.isTrueOrUndefined()) {
463
             if (topBarOptions.animate.isTrueOrUndefined()) {
471
-                topBar.showAnimate(animationsOptions.push.topBar);
464
+                topBarController.showAnimate(animationsOptions.push.topBar, getTopBarTranslationAnimationDelta(stack, child));
472
             } else {
465
             } else {
473
-                topBar.show();
466
+                topBarController.show();
474
             }
467
             }
475
         }
468
         }
476
-        if (topBarOptions.drawBehind.isTrue()) {
477
-            component.drawBehindTopBar();
478
-        }
479
-        if (topBarOptions.drawBehind.isFalse()) {
480
-            component.drawBelowTopBar(topBar);
481
-        }
482
         if (topBarOptions.hideOnScroll.isTrue() && component instanceof IReactView) {
469
         if (topBarOptions.hideOnScroll.isTrue() && component instanceof IReactView) {
483
             topBar.enableCollapse(((IReactView) component).getScrollEventListener());
470
             topBar.enableCollapse(((IReactView) component).getScrollEventListener());
484
         }
471
         }
503
     }
490
     }
504
 
491
 
505
     @RestrictTo(RestrictTo.Scope.TESTS)
492
     @RestrictTo(RestrictTo.Scope.TESTS)
506
-    public Map<Component, TitleBarReactViewController> getTitleComponents() {
493
+    public Map<View, TitleBarReactViewController> getTitleComponents() {
507
         return titleControllers;
494
         return titleControllers;
508
     }
495
     }
509
 
496
 
510
     @RestrictTo(RestrictTo.Scope.TESTS)
497
     @RestrictTo(RestrictTo.Scope.TESTS)
511
-    public Map<Component, TopBarBackgroundViewController> getBackgroundComponents() {
498
+    public Map<View, TopBarBackgroundViewController> getBackgroundComponents() {
512
         return backgroundControllers;
499
         return backgroundControllers;
513
     }
500
     }
514
 
501
 
515
     @RestrictTo(RestrictTo.Scope.TESTS)
502
     @RestrictTo(RestrictTo.Scope.TESTS)
516
-    public List<TitleBarButtonController> getComponentButtons(Component child) {
503
+    public List<TitleBarButtonController> getComponentButtons(View child) {
517
         return merge(getRightButtons(child), getLeftButtons(child), Collections.EMPTY_LIST);
504
         return merge(getRightButtons(child), getLeftButtons(child), Collections.EMPTY_LIST);
518
     }
505
     }
519
 
506
 
520
     @RestrictTo(RestrictTo.Scope.TESTS)
507
     @RestrictTo(RestrictTo.Scope.TESTS)
521
-    public List<TitleBarButtonController> getComponentButtons(Component child, List<TitleBarButtonController> defaultValue) {
508
+    public List<TitleBarButtonController> getComponentButtons(View child, List<TitleBarButtonController> defaultValue) {
522
         return merge(getRightButtons(child), getLeftButtons(child), defaultValue);
509
         return merge(getRightButtons(child), getLeftButtons(child), defaultValue);
523
     }
510
     }
524
 
511
 
525
-    private List<TitleBarButtonController> getRightButtons(Component child) {
512
+    public void applyTopInsets(StackController stack, ViewController child) {
513
+        if (stack.isCurrentChild(child)) applyStatusBarInsets(stack, child);
514
+        child.applyTopInset();
515
+    }
516
+
517
+    private List<TitleBarButtonController> getRightButtons(View child) {
526
         return componentRightButtons.containsKey(child) ? new ArrayList<>(componentRightButtons.get(child).values()) : null;
518
         return componentRightButtons.containsKey(child) ? new ArrayList<>(componentRightButtons.get(child).values()) : null;
527
     }
519
     }
528
 
520
 
529
-    private List<TitleBarButtonController> getLeftButtons(Component child) {
521
+    private List<TitleBarButtonController> getLeftButtons(View child) {
530
         return componentLeftButtons.containsKey(child) ? new ArrayList<>(componentLeftButtons.get(child).values()) : null;
522
         return componentLeftButtons.containsKey(child) ? new ArrayList<>(componentLeftButtons.get(child).values()) : null;
531
     }
523
     }
524
+
525
+    private void applyStatusBarInsets(StackController stack, ViewController child) {
526
+        MarginLayoutParams lp = (MarginLayoutParams) topBar.getLayoutParams();
527
+        lp.topMargin = getTopBarTopMargin(stack, child);
528
+        topBar.requestLayout();
529
+    }
530
+
531
+    private int getTopBarTranslationAnimationDelta(StackController stack, ViewController child) {
532
+        Options options = stack.resolveChildOptions(child).withDefaultOptions(defaultOptions);
533
+        return options.statusBar.hasTransparency() ? getTopBarTopMargin(stack, child) : 0;
534
+    }
535
+
536
+    private int getTopBarTopMargin(StackController stack, ViewController child) {
537
+        Options withDefault = stack.resolveChildOptions(child).withDefaultOptions(defaultOptions);
538
+        int topMargin = UiUtils.dpToPx(activity, withDefault.topBar.topMargin.get(0));
539
+        int statusBarInset = withDefault.statusBar.visible.isTrueOrUndefined() ? StatusBarUtils.getStatusBarHeight(child.getActivity()) : 0;
540
+        return topMargin + statusBarInset;
541
+    }
532
 }
542
 }

+ 8
- 5
lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationModule.java View File

1
 package com.reactnativenavigation.react;
1
 package com.reactnativenavigation.react;
2
 
2
 
3
-import android.support.annotation.NonNull;
4
-import android.support.annotation.Nullable;
5
-
6
 import com.facebook.react.ReactInstanceManager;
3
 import com.facebook.react.ReactInstanceManager;
7
 import com.facebook.react.bridge.Arguments;
4
 import com.facebook.react.bridge.Arguments;
8
 import com.facebook.react.bridge.Promise;
5
 import com.facebook.react.bridge.Promise;
21
 import com.reactnativenavigation.parse.parsers.LayoutNodeParser;
18
 import com.reactnativenavigation.parse.parsers.LayoutNodeParser;
22
 import com.reactnativenavigation.utils.NativeCommandListener;
19
 import com.reactnativenavigation.utils.NativeCommandListener;
23
 import com.reactnativenavigation.utils.Now;
20
 import com.reactnativenavigation.utils.Now;
21
+import com.reactnativenavigation.utils.StatusBarUtils;
24
 import com.reactnativenavigation.utils.TypefaceLoader;
22
 import com.reactnativenavigation.utils.TypefaceLoader;
25
 import com.reactnativenavigation.utils.UiThread;
23
 import com.reactnativenavigation.utils.UiThread;
26
 import com.reactnativenavigation.utils.UiUtils;
24
 import com.reactnativenavigation.utils.UiUtils;
29
 
27
 
30
 import java.util.ArrayList;
28
 import java.util.ArrayList;
31
 
29
 
30
+import androidx.annotation.NonNull;
31
+import androidx.annotation.Nullable;
32
+
33
+import static com.reactnativenavigation.utils.UiUtils.pxToDp;
34
+
32
 public class NavigationModule extends ReactContextBaseJavaModule {
35
 public class NavigationModule extends ReactContextBaseJavaModule {
33
     private static final String NAME = "RNNBridgeModule";
36
     private static final String NAME = "RNNBridgeModule";
34
 
37
 
75
         WritableMap constants = Arguments.createMap();
78
         WritableMap constants = Arguments.createMap();
76
         constants.putString(Constants.BACK_BUTTON_JS_KEY, Constants.BACK_BUTTON_ID);
79
         constants.putString(Constants.BACK_BUTTON_JS_KEY, Constants.BACK_BUTTON_ID);
77
         constants.putDouble(Constants.BOTTOM_TABS_HEIGHT_KEY, Constants.BOTTOM_TABS_HEIGHT);
80
         constants.putDouble(Constants.BOTTOM_TABS_HEIGHT_KEY, Constants.BOTTOM_TABS_HEIGHT);
78
-        constants.putDouble(Constants.STATUS_BAR_HEIGHT_KEY, UiUtils.pxToDp(ctx, UiUtils.getStatusBarHeight(ctx)));
79
-        constants.putDouble(Constants.TOP_BAR_HEIGHT_KEY, UiUtils.pxToDp(ctx, UiUtils.getTopBarHeight(ctx)));
81
+        constants.putDouble(Constants.STATUS_BAR_HEIGHT_KEY, pxToDp(ctx, StatusBarUtils.getStatusBarHeight(ctx)));
82
+        constants.putDouble(Constants.TOP_BAR_HEIGHT_KEY, pxToDp(ctx, UiUtils.getTopBarHeight(ctx)));
80
         promise.resolve(constants);
83
         promise.resolve(constants);
81
     }
84
     }
82
 
85
 

+ 7
- 7
lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationPackage.java View File

1
 package com.reactnativenavigation.react;
1
 package com.reactnativenavigation.react;
2
 
2
 
3
-import android.support.annotation.NonNull;
4
-
5
 import com.facebook.react.ReactNativeHost;
3
 import com.facebook.react.ReactNativeHost;
6
 import com.facebook.react.ReactPackage;
4
 import com.facebook.react.ReactPackage;
7
 import com.facebook.react.bridge.NativeModule;
5
 import com.facebook.react.bridge.NativeModule;
9
 import com.facebook.react.uimanager.ViewManager;
7
 import com.facebook.react.uimanager.ViewManager;
10
 import com.reactnativenavigation.parse.LayoutFactory;
8
 import com.reactnativenavigation.parse.LayoutFactory;
11
 
9
 
12
-import java.util.Collections;
13
 import java.util.List;
10
 import java.util.List;
14
 
11
 
12
+import androidx.annotation.NonNull;
13
+
14
+import static java.util.Collections.singletonList;
15
+
15
 public class NavigationPackage implements ReactPackage {
16
 public class NavigationPackage implements ReactPackage {
16
 
17
 
17
     private ReactNativeHost reactNativeHost;
18
     private ReactNativeHost reactNativeHost;
18
 
19
 
19
-    @SuppressWarnings("WeakerAccess")
20
     public NavigationPackage(final ReactNativeHost reactNativeHost) {
20
     public NavigationPackage(final ReactNativeHost reactNativeHost) {
21
         this.reactNativeHost = reactNativeHost;
21
         this.reactNativeHost = reactNativeHost;
22
     }
22
     }
24
     @NonNull
24
     @NonNull
25
     @Override
25
     @Override
26
     public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
26
     public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
27
-        return Collections.singletonList(new NavigationModule(
27
+        return singletonList(new NavigationModule(
28
                         reactContext,
28
                         reactContext,
29
                         reactNativeHost.getReactInstanceManager(),
29
                         reactNativeHost.getReactInstanceManager(),
30
                         new LayoutFactory(reactNativeHost.getReactInstanceManager())
30
                         new LayoutFactory(reactNativeHost.getReactInstanceManager())
34
 
34
 
35
     @NonNull
35
     @NonNull
36
     @Override
36
     @Override
37
-    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
38
-        return Collections.singletonList(new ElementViewManager());
37
+    public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
38
+        return singletonList(new ElementViewManager());
39
     }
39
     }
40
 }
40
 }

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationReactInitializer.java View File

1
 package com.reactnativenavigation.react;
1
 package com.reactnativenavigation.react;
2
 
2
 
3
-import android.support.annotation.NonNull;
3
+import androidx.annotation.NonNull;
4
 
4
 
5
 import com.facebook.react.ReactInstanceManager;
5
 import com.facebook.react.ReactInstanceManager;
6
 import com.facebook.react.bridge.ReactContext;
6
 import com.facebook.react.bridge.ReactContext;

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/react/ReactView.java View File

3
 import android.annotation.SuppressLint;
3
 import android.annotation.SuppressLint;
4
 import android.content.Context;
4
 import android.content.Context;
5
 import android.os.Bundle;
5
 import android.os.Bundle;
6
-import android.support.annotation.RestrictTo;
6
+import androidx.annotation.RestrictTo;
7
 import android.view.MotionEvent;
7
 import android.view.MotionEvent;
8
 
8
 
9
 import com.facebook.react.ReactInstanceManager;
9
 import com.facebook.react.ReactInstanceManager;

+ 3
- 3
lib/android/app/src/main/java/com/reactnativenavigation/utils/ButtonPresenter.java View File

5
 import android.graphics.PorterDuffColorFilter;
5
 import android.graphics.PorterDuffColorFilter;
6
 import android.graphics.Typeface;
6
 import android.graphics.Typeface;
7
 import android.graphics.drawable.Drawable;
7
 import android.graphics.drawable.Drawable;
8
-import android.support.annotation.NonNull;
9
-import android.support.v7.widget.ActionMenuView;
10
-import android.support.v7.widget.Toolbar;
8
+import androidx.annotation.NonNull;
9
+import androidx.appcompat.widget.ActionMenuView;
10
+import androidx.appcompat.widget.Toolbar;
11
 import android.text.Spannable;
11
 import android.text.Spannable;
12
 import android.text.SpannableString;
12
 import android.text.SpannableString;
13
 import android.text.style.AbsoluteSizeSpan;
13
 import android.text.style.AbsoluteSizeSpan;

+ 15
- 3
lib/android/app/src/main/java/com/reactnativenavigation/utils/CollectionUtils.java View File

1
 package com.reactnativenavigation.utils;
1
 package com.reactnativenavigation.utils;
2
 
2
 
3
-import android.support.annotation.NonNull;
4
-import android.support.annotation.Nullable;
5
-import android.support.v4.util.Pair;
6
 
3
 
7
 import java.util.ArrayList;
4
 import java.util.ArrayList;
8
 import java.util.Collection;
5
 import java.util.Collection;
13
 import java.util.Map;
10
 import java.util.Map;
14
 import java.util.Objects;
11
 import java.util.Objects;
15
 
12
 
13
+import androidx.annotation.NonNull;
14
+import androidx.annotation.Nullable;
15
+import androidx.core.util.Pair;
16
+
16
 public class CollectionUtils {
17
 public class CollectionUtils {
17
     public interface Apply<T> {
18
     public interface Apply<T> {
18
         void on(T t);
19
         void on(T t);
101
         return null;
102
         return null;
102
     }
103
     }
103
 
104
 
105
+    public static @Nullable <T> T first(@Nullable Collection<T> items, Filter<T> by, Functions.Func1<T> apply) {
106
+        if (isNullOrEmpty(items)) return null;
107
+        for (T item : items) {
108
+            if (by.filter(item)) {
109
+                apply.run(item);
110
+                return item;
111
+            }
112
+        }
113
+        return null;
114
+    }
115
+
104
     public static <T> T last(@Nullable List<T> items) {
116
     public static <T> T last(@Nullable List<T> items) {
105
         return CollectionUtils.isNullOrEmpty(items) ? null : items.get(items.size() - 1);
117
         return CollectionUtils.isNullOrEmpty(items) ? null : items.get(items.size() - 1);
106
     }
118
     }

+ 2
- 2
lib/android/app/src/main/java/com/reactnativenavigation/utils/ColorUtils.java View File

3
 public class ColorUtils {
3
 public class ColorUtils {
4
     public static double[] colorToLAB(int color) {
4
     public static double[] colorToLAB(int color) {
5
         final double[] result = new double[3];
5
         final double[] result = new double[3];
6
-        android.support.v4.graphics.ColorUtils.colorToLAB(color, result);
6
+        androidx.core.graphics.ColorUtils.colorToLAB(color, result);
7
         return result;
7
         return result;
8
     }
8
     }
9
 
9
 
10
     public static int labToColor(double[] lab) {
10
     public static int labToColor(double[] lab) {
11
-        return android.support.v4.graphics.ColorUtils.LABToColor(lab[0], lab[1], lab[2]);
11
+        return androidx.core.graphics.ColorUtils.LABToColor(lab[0], lab[1], lab[2]);
12
     }
12
     }
13
 }
13
 }

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/utils/CommandListenerAdapter.java View File

1
 package com.reactnativenavigation.utils;
1
 package com.reactnativenavigation.utils;
2
 
2
 
3
-import android.support.annotation.Nullable;
3
+import androidx.annotation.Nullable;
4
 
4
 
5
 public class CommandListenerAdapter implements CommandListener {
5
 public class CommandListenerAdapter implements CommandListener {
6
 
6
 

+ 17
- 0
lib/android/app/src/main/java/com/reactnativenavigation/utils/CoordinatorLayoutUtils.java View File

1
+package com.reactnativenavigation.utils;
2
+
3
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
4
+
5
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
6
+
7
+public class CoordinatorLayoutUtils {
8
+    public static CoordinatorLayout.LayoutParams matchParentLP() {
9
+        return new CoordinatorLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT);
10
+    }
11
+
12
+    public static CoordinatorLayout.LayoutParams matchParentWithBehaviour(CoordinatorLayout.Behavior behavior) {
13
+        CoordinatorLayout.LayoutParams lp = new CoordinatorLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT);
14
+        lp.setBehavior(behavior);
15
+        return lp;
16
+    }
17
+}

+ 2
- 2
lib/android/app/src/main/java/com/reactnativenavigation/utils/ImageLoader.java View File

7
 import android.graphics.drawable.Drawable;
7
 import android.graphics.drawable.Drawable;
8
 import android.net.Uri;
8
 import android.net.Uri;
9
 import android.os.StrictMode;
9
 import android.os.StrictMode;
10
-import android.support.annotation.NonNull;
11
-import android.support.annotation.Nullable;
10
+import androidx.annotation.NonNull;
11
+import androidx.annotation.Nullable;
12
 
12
 
13
 import com.facebook.react.views.imagehelper.ResourceDrawableIdHelper;
13
 import com.facebook.react.views.imagehelper.ResourceDrawableIdHelper;
14
 import com.reactnativenavigation.NavigationApplication;
14
 import com.reactnativenavigation.NavigationApplication;

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/utils/ImageLoadingListenerAdapter.java View File

1
 package com.reactnativenavigation.utils;
1
 package com.reactnativenavigation.utils;
2
 
2
 
3
 import android.graphics.drawable.Drawable;
3
 import android.graphics.drawable.Drawable;
4
-import android.support.annotation.NonNull;
4
+import androidx.annotation.NonNull;
5
 
5
 
6
 import java.util.List;
6
 import java.util.List;
7
 
7
 

+ 21
- 0
lib/android/app/src/main/java/com/reactnativenavigation/utils/LateInit.java View File

1
+package com.reactnativenavigation.utils;
2
+
3
+import com.reactnativenavigation.utils.Functions.Func1;
4
+
5
+import androidx.annotation.NonNull;
6
+
7
+public class LateInit<T> {
8
+    private T value;
9
+
10
+    public T get() {
11
+        return value;
12
+    }
13
+
14
+    public void set(@NonNull T value) {
15
+        this.value = value;
16
+    }
17
+
18
+    public void perform(Func1<T> task) {
19
+        if (value != null) task.run(value);
20
+    }
21
+}

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/utils/NativeCommandListener.java View File

1
 package com.reactnativenavigation.utils;
1
 package com.reactnativenavigation.utils;
2
 
2
 
3
-import android.support.annotation.Nullable;
3
+import androidx.annotation.Nullable;
4
 
4
 
5
 import com.facebook.react.bridge.Promise;
5
 import com.facebook.react.bridge.Promise;
6
 import com.reactnativenavigation.react.EventEmitter;
6
 import com.reactnativenavigation.react.EventEmitter;

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/utils/ObjectUtils.java View File

1
 package com.reactnativenavigation.utils;
1
 package com.reactnativenavigation.utils;
2
 
2
 
3
-import android.support.annotation.Nullable;
3
+import androidx.annotation.Nullable;
4
 
4
 
5
 import com.reactnativenavigation.utils.Functions.Func1;
5
 import com.reactnativenavigation.utils.Functions.Func1;
6
 import com.reactnativenavigation.utils.Functions.FuncR1;
6
 import com.reactnativenavigation.utils.Functions.FuncR1;

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/utils/ReflectionUtils.java View File

1
 package com.reactnativenavigation.utils;
1
 package com.reactnativenavigation.utils;
2
 
2
 
3
-import android.support.annotation.Nullable;
3
+import androidx.annotation.Nullable;
4
 
4
 
5
 import java.lang.reflect.Field;
5
 import java.lang.reflect.Field;
6
 
6
 

+ 30
- 0
lib/android/app/src/main/java/com/reactnativenavigation/utils/StatusBarUtils.java View File

1
+package com.reactnativenavigation.utils;
2
+
3
+import android.content.Context;
4
+import android.content.res.Resources;
5
+import android.os.Build;
6
+
7
+import static com.reactnativenavigation.utils.UiUtils.dpToPx;
8
+
9
+public class StatusBarUtils {
10
+    private static final int STATUS_BAR_HEIGHT_M = 24;
11
+    private static final int STATUS_BAR_HEIGHT_L = 25;
12
+    private static int statusBarHeight = -1;
13
+
14
+    public static void saveStatusBarHeight(int height) {
15
+        statusBarHeight = height;
16
+    }
17
+
18
+    public static int getStatusBarHeight(Context context) {
19
+        if (statusBarHeight > 0) {
20
+            return statusBarHeight;
21
+        }
22
+        final Resources resources = context.getResources();
23
+        final int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android");
24
+        statusBarHeight = resourceId > 0 ?
25
+                resources.getDimensionPixelSize(resourceId) :
26
+                dpToPx(context, Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? STATUS_BAR_HEIGHT_M : STATUS_BAR_HEIGHT_L);
27
+        return statusBarHeight;
28
+    }
29
+
30
+}

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/utils/StringUtils.java View File

1
 package com.reactnativenavigation.utils;
1
 package com.reactnativenavigation.utils;
2
 
2
 
3
-import android.support.annotation.Nullable;
3
+import androidx.annotation.Nullable;
4
 
4
 
5
 public class StringUtils {
5
 public class StringUtils {
6
 
6
 

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/utils/TextViewUtils.java View File

1
 package com.reactnativenavigation.utils;
1
 package com.reactnativenavigation.utils;
2
 
2
 
3
 import android.graphics.Color;
3
 import android.graphics.Color;
4
-import android.support.annotation.ColorInt;
4
+import androidx.annotation.ColorInt;
5
 import android.text.SpannableString;
5
 import android.text.SpannableString;
6
 import android.text.Spanned;
6
 import android.text.Spanned;
7
 import android.text.SpannedString;
7
 import android.text.SpannedString;

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/utils/TypefaceLoader.java View File

3
 import android.content.Context;
3
 import android.content.Context;
4
 import android.content.res.AssetManager;
4
 import android.content.res.AssetManager;
5
 import android.graphics.Typeface;
5
 import android.graphics.Typeface;
6
-import android.support.annotation.Nullable;
6
+import androidx.annotation.Nullable;
7
 import android.text.TextUtils;
7
 import android.text.TextUtils;
8
 
8
 
9
 import java.io.IOException;
9
 import java.io.IOException;

+ 2
- 18
lib/android/app/src/main/java/com/reactnativenavigation/utils/UiUtils.java View File

2
 
2
 
3
 import android.content.Context;
3
 import android.content.Context;
4
 import android.content.res.Resources;
4
 import android.content.res.Resources;
5
-import android.os.Build;
6
 import android.os.Handler;
5
 import android.os.Handler;
7
 import android.os.Looper;
6
 import android.os.Looper;
8
-import android.support.annotation.NonNull;
9
-import android.support.annotation.Nullable;
7
+import androidx.annotation.NonNull;
8
+import androidx.annotation.Nullable;
10
 import android.util.DisplayMetrics;
9
 import android.util.DisplayMetrics;
11
 import android.view.View;
10
 import android.view.View;
12
 import android.view.ViewTreeObserver;
11
 import android.view.ViewTreeObserver;
13
 import android.view.WindowManager;
12
 import android.view.WindowManager;
14
 
13
 
15
 public class UiUtils {
14
 public class UiUtils {
16
-    private static final int STATUS_BAR_HEIGHT_M = 24;
17
-    private static final int STATUS_BAR_HEIGHT_L = 25;
18
     private static final int DEFAULT_TOOLBAR_HEIGHT = 56;
15
     private static final int DEFAULT_TOOLBAR_HEIGHT = 56;
19
 
16
 
20
-    private static int statusBarHeight = -1;
21
     private static int topBarHeight = -1;
17
     private static int topBarHeight = -1;
22
 
18
 
23
     public static <T extends View> void runOnPreDrawOnce(@Nullable final T view, final Functions.Func1<T> task) {
19
     public static <T extends View> void runOnPreDrawOnce(@Nullable final T view, final Functions.Func1<T> task) {
75
         return metrics;
71
         return metrics;
76
     }
72
     }
77
 
73
 
78
-    public static int getStatusBarHeight(Context context) {
79
-        if (statusBarHeight > 0) {
80
-            return statusBarHeight;
81
-        }
82
-        final Resources resources = context.getResources();
83
-        final int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android");
84
-        statusBarHeight = resourceId > 0 ?
85
-                resources.getDimensionPixelSize(resourceId) :
86
-                dpToPx(context, Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? STATUS_BAR_HEIGHT_M : STATUS_BAR_HEIGHT_L);
87
-        return statusBarHeight;
88
-    }
89
-
90
     public static int getTopBarHeightDp(Context context) {
74
     public static int getTopBarHeightDp(Context context) {
91
         return (int) UiUtils.pxToDp(context, getTopBarHeight(context));
75
         return (int) UiUtils.pxToDp(context, getTopBarHeight(context));
92
     }
76
     }

+ 12
- 2
lib/android/app/src/main/java/com/reactnativenavigation/utils/ViewUtils.java View File

1
 package com.reactnativenavigation.utils;
1
 package com.reactnativenavigation.utils;
2
 
2
 
3
 import android.graphics.Point;
3
 import android.graphics.Point;
4
-import android.support.annotation.Nullable;
4
+import androidx.annotation.Nullable;
5
 import android.view.View;
5
 import android.view.View;
6
 import android.view.ViewGroup;
6
 import android.view.ViewGroup;
7
 import android.view.ViewManager;
7
 import android.view.ViewManager;
14
 import java.util.ArrayList;
14
 import java.util.ArrayList;
15
 import java.util.List;
15
 import java.util.List;
16
 
16
 
17
+import static com.reactnativenavigation.utils.ObjectUtils.perform;
18
+
17
 public class ViewUtils {
19
 public class ViewUtils {
18
     @Nullable
20
     @Nullable
19
     public static <T extends View> T findChildByClass(ViewGroup root, Class<T> clazz) {
21
     public static <T extends View> T findChildByClass(ViewGroup root, Class<T> clazz) {
71
     }
73
     }
72
 
74
 
73
     public static boolean isChildOf(ViewGroup parent, View child) {
75
     public static boolean isChildOf(ViewGroup parent, View child) {
74
-        if (parent == child) return true;
76
+        if (parent == child) return false;
75
 
77
 
76
         for (int i = 0; i < parent.getChildCount(); i++) {
78
         for (int i = 0; i < parent.getChildCount(); i++) {
77
             View view = parent.getChildAt(i);
79
             View view = parent.getChildAt(i);
138
             ((ViewManager) parent).removeView(view);
140
             ((ViewManager) parent).removeView(view);
139
         }
141
         }
140
     }
142
     }
143
+
144
+    public static boolean isVisible(View view) {
145
+        return perform(view, false, v -> v.getVisibility() == View.VISIBLE);
146
+    }
147
+
148
+    public static int topMargin(View view) {
149
+        return ((ViewGroup.MarginLayoutParams) view.getLayoutParams()).topMargin;
150
+    }
141
 }
151
 }

+ 15
- 0
lib/android/app/src/main/java/com/reactnativenavigation/utils/WindowInsetsUtils.java View File

1
+package com.reactnativenavigation.utils;
2
+
3
+import androidx.core.view.WindowInsetsCompat;
4
+import android.util.Log;
5
+
6
+public class WindowInsetsUtils {
7
+    private static final String TAG = "GUYCA";
8
+
9
+    public static void log(WindowInsetsCompat i) {
10
+        Log.i(TAG, "t: " + i.getStableInsetTop() +
11
+                   " sysT: " + i.getSystemWindowInsetTop() +
12
+                   " b: " + i.getStableInsetBottom() +
13
+                   " sysB: " + i.getSystemWindowInsetBottom());
14
+    }
15
+}

+ 33
- 8
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ChildController.java View File

1
 package com.reactnativenavigation.viewcontrollers;
1
 package com.reactnativenavigation.viewcontrollers;
2
 
2
 
3
 import android.app.Activity;
3
 import android.app.Activity;
4
-import android.support.annotation.CallSuper;
4
+import androidx.annotation.CallSuper;
5
+import androidx.core.view.ViewCompat;
6
+import androidx.core.view.WindowInsetsCompat;
7
+import android.view.View;
5
 import android.view.ViewGroup;
8
 import android.view.ViewGroup;
6
 
9
 
7
 import com.reactnativenavigation.parse.Options;
10
 import com.reactnativenavigation.parse.Options;
8
 import com.reactnativenavigation.presentation.Presenter;
11
 import com.reactnativenavigation.presentation.Presenter;
12
+import com.reactnativenavigation.utils.StatusBarUtils;
9
 import com.reactnativenavigation.viewcontrollers.navigator.Navigator;
13
 import com.reactnativenavigation.viewcontrollers.navigator.Navigator;
10
 import com.reactnativenavigation.views.Component;
14
 import com.reactnativenavigation.views.Component;
11
 
15
 
12
 public abstract class ChildController<T extends ViewGroup> extends ViewController<T>  {
16
 public abstract class ChildController<T extends ViewGroup> extends ViewController<T>  {
13
-    final Presenter presenter;
17
+    private final Presenter presenter;
14
     private final ChildControllersRegistry childRegistry;
18
     private final ChildControllersRegistry childRegistry;
15
 
19
 
16
     public ChildControllersRegistry getChildRegistry() {
20
     public ChildControllersRegistry getChildRegistry() {
23
         this.childRegistry = childRegistry;
27
         this.childRegistry = childRegistry;
24
     }
28
     }
25
 
29
 
30
+    @Override
31
+    public T getView() {
32
+        if (view == null) {
33
+            super.getView();
34
+            view.setFitsSystemWindows(true);
35
+            ViewCompat.setOnApplyWindowInsetsListener(view, this::onApplyWindowInsets);
36
+        }
37
+        return view;
38
+    }
39
+
26
     @Override
40
     @Override
27
     @CallSuper
41
     @CallSuper
28
     public void setDefaultOptions(Options defaultOptions) {
42
     public void setDefaultOptions(Options defaultOptions) {
42
     }
56
     }
43
 
57
 
44
     public void onViewBroughtToFront() {
58
     public void onViewBroughtToFront() {
45
-        presenter.onViewBroughtToFront(getView(), options);
59
+        presenter.onViewBroughtToFront(resolveCurrentOptions());
46
     }
60
     }
47
 
61
 
48
     @Override
62
     @Override
49
     public void applyOptions(Options options) {
63
     public void applyOptions(Options options) {
50
         super.applyOptions(options);
64
         super.applyOptions(options);
51
         Options resolvedOptions = resolveCurrentOptions();
65
         Options resolvedOptions = resolveCurrentOptions();
52
-        presenter.applyOptions(getView(), resolvedOptions);
53
-        if (isRoot()) {
54
-            presenter.applyRootOptions(getView(), resolvedOptions);
55
-        }
66
+        presenter.applyOptions(this, resolvedOptions);
56
     }
67
     }
57
 
68
 
58
     @Override
69
     @Override
65
     @Override
76
     @Override
66
     public void destroy() {
77
     public void destroy() {
67
         if (!isDestroyed() && getView() instanceof Component) {
78
         if (!isDestroyed() && getView() instanceof Component) {
68
-            performOnParentController(parent -> parent.onChildDestroyed((Component) getView()));
79
+            performOnParentController(parent -> parent.onChildDestroyed(this));
69
         }
80
         }
70
         super.destroy();
81
         super.destroy();
71
         childRegistry.onChildDestroyed(this);
82
         childRegistry.onChildDestroyed(this);
76
                 !(this instanceof Navigator) &&
87
                 !(this instanceof Navigator) &&
77
                 getView().getParent() != null;
88
                 getView().getParent() != null;
78
     }
89
     }
90
+
91
+    private WindowInsetsCompat onApplyWindowInsets(View view, WindowInsetsCompat insets) {
92
+        StatusBarUtils.saveStatusBarHeight(insets.getSystemWindowInsetTop());
93
+        return applyWindowInsets(findController(view), insets);
94
+    }
95
+
96
+    protected WindowInsetsCompat applyWindowInsets(ViewController view, WindowInsetsCompat insets) {
97
+        return insets.replaceSystemWindowInsets(
98
+                insets.getSystemWindowInsetLeft(),
99
+                0,
100
+                insets.getSystemWindowInsetRight(),
101
+                insets.getSystemWindowInsetBottom()
102
+        );
103
+    }
79
 }
104
 }

+ 3
- 1
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ChildControllersRegistry.java View File

2
 
2
 
3
 import java.util.ArrayDeque;
3
 import java.util.ArrayDeque;
4
 
4
 
5
+import static com.reactnativenavigation.utils.ObjectUtils.perform;
6
+
5
 public class ChildControllersRegistry {
7
 public class ChildControllersRegistry {
6
     private ArrayDeque<ChildController> children = new ArrayDeque<>();
8
     private ArrayDeque<ChildController> children = new ArrayDeque<>();
7
 
9
 
19
     }
21
     }
20
 
22
 
21
     private boolean isTopChild(ChildController child) {
23
     private boolean isTopChild(ChildController child) {
22
-        return children.peek().equals(child);
24
+        return perform(children.peek(), false, c -> c.equals(child));
23
     }
25
     }
24
 
26
 
25
     public int size() {
27
     public int size() {

+ 41
- 8
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ComponentViewController.java View File

1
 package com.reactnativenavigation.viewcontrollers;
1
 package com.reactnativenavigation.viewcontrollers;
2
 
2
 
3
 import android.app.Activity;
3
 import android.app.Activity;
4
-import android.support.annotation.NonNull;
5
 import android.view.View;
4
 import android.view.View;
6
 
5
 
7
 import com.reactnativenavigation.parse.Options;
6
 import com.reactnativenavigation.parse.Options;
8
 import com.reactnativenavigation.presentation.ComponentPresenter;
7
 import com.reactnativenavigation.presentation.ComponentPresenter;
9
 import com.reactnativenavigation.presentation.Presenter;
8
 import com.reactnativenavigation.presentation.Presenter;
9
+import com.reactnativenavigation.utils.StatusBarUtils;
10
 import com.reactnativenavigation.views.ComponentLayout;
10
 import com.reactnativenavigation.views.ComponentLayout;
11
 import com.reactnativenavigation.views.ReactComponent;
11
 import com.reactnativenavigation.views.ReactComponent;
12
 
12
 
13
-public class ComponentViewController extends ChildController<ComponentLayout> {
13
+import androidx.annotation.NonNull;
14
+import androidx.core.view.ViewCompat;
15
+import androidx.core.view.WindowInsetsCompat;
16
+
17
+import static com.reactnativenavigation.utils.ObjectUtils.perform;
14
 
18
 
19
+public class ComponentViewController extends ChildController<ComponentLayout> {
15
     private final String componentName;
20
     private final String componentName;
16
     private ComponentPresenter presenter;
21
     private ComponentPresenter presenter;
17
     private final ReactViewCreator viewCreator;
22
     private final ReactViewCreator viewCreator;
18
 
23
 
24
+    ReactComponent getComponent() {
25
+        return view;
26
+    }
27
+
19
     public ComponentViewController(final Activity activity,
28
     public ComponentViewController(final Activity activity,
20
                                    final ChildControllersRegistry childRegistry,
29
                                    final ChildControllersRegistry childRegistry,
21
                                    final String id,
30
                                    final String id,
39
     @Override
48
     @Override
40
     public void onViewAppeared() {
49
     public void onViewAppeared() {
41
         super.onViewAppeared();
50
         super.onViewAppeared();
42
-        view.sendComponentStart();
51
+        if (view != null) view.sendComponentStart();
43
     }
52
     }
44
 
53
 
45
     @Override
54
     @Override
46
     public void onViewDisappear() {
55
     public void onViewDisappear() {
47
-        view.sendComponentStop();
56
+        if (view != null) view.sendComponentStop();
48
         super.onViewDisappear();
57
         super.onViewDisappear();
49
     }
58
     }
50
 
59
 
55
 
64
 
56
     @Override
65
     @Override
57
     public void applyOptions(Options options) {
66
     public void applyOptions(Options options) {
67
+        if (isRoot()) applyTopInset();
58
         super.applyOptions(options);
68
         super.applyOptions(options);
59
         getView().applyOptions(options);
69
         getView().applyOptions(options);
60
         presenter.applyOptions(getView(), resolveCurrentOptions(presenter.defaultOptions));
70
         presenter.applyOptions(getView(), resolveCurrentOptions(presenter.defaultOptions));
62
 
72
 
63
     @Override
73
     @Override
64
     public boolean isViewShown() {
74
     public boolean isViewShown() {
65
-        return super.isViewShown() && view.isReady();
75
+        return super.isViewShown() && view != null && view.isReady();
66
     }
76
     }
67
 
77
 
68
     @NonNull
78
     @NonNull
76
     public void mergeOptions(Options options) {
86
     public void mergeOptions(Options options) {
77
         if (options == Options.EMPTY) return;
87
         if (options == Options.EMPTY) return;
78
         presenter.mergeOptions(getView(), options);
88
         presenter.mergeOptions(getView(), options);
79
-        performOnParentController(parentController -> parentController.mergeChildOptions(options, this, getView()));
80
         super.mergeOptions(options);
89
         super.mergeOptions(options);
90
+        performOnParentController(parentController -> parentController.mergeChildOptions(options, this));
81
     }
91
     }
82
 
92
 
83
-    ReactComponent getComponent() {
84
-        return view;
93
+    @Override
94
+    public void applyTopInset() {
95
+        if (view != null) presenter.applyTopInsets(view, getTopInset());
96
+    }
97
+
98
+    @Override
99
+    public int getTopInset() {
100
+        int statusBarInset = resolveCurrentOptions().statusBar.isHiddenOrDrawBehind() ? 0 : StatusBarUtils.getStatusBarHeight(getActivity());
101
+        return statusBarInset + perform(getParentController(), 0, p -> p.getTopInset(this));
102
+    }
103
+
104
+    @Override
105
+    public void applyBottomInset() {
106
+        if (view != null) presenter.applyBottomInset(view, getBottomInset());
107
+    }
108
+
109
+    @Override
110
+    protected WindowInsetsCompat applyWindowInsets(ViewController view, WindowInsetsCompat insets) {
111
+        ViewCompat.onApplyWindowInsets(view.getView(), insets.replaceSystemWindowInsets(
112
+                insets.getSystemWindowInsetLeft(),
113
+                insets.getSystemWindowInsetTop(),
114
+                insets.getSystemWindowInsetRight(),
115
+                Math.max(insets.getSystemWindowInsetBottom() - getBottomInset(), 0)
116
+        ));
117
+        return insets;
85
     }
118
     }
86
 
119
 
87
     @Override
120
     @Override

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/IdStack.java View File

1
 package com.reactnativenavigation.viewcontrollers;
1
 package com.reactnativenavigation.viewcontrollers;
2
 
2
 
3
-import android.support.annotation.NonNull;
3
+import androidx.annotation.NonNull;
4
 
4
 
5
 import com.reactnativenavigation.utils.StringUtils;
5
 import com.reactnativenavigation.utils.StringUtils;
6
 
6
 

+ 59
- 16
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ParentController.java View File

1
 package com.reactnativenavigation.viewcontrollers;
1
 package com.reactnativenavigation.viewcontrollers;
2
 
2
 
3
 import android.app.Activity;
3
 import android.app.Activity;
4
-import android.support.annotation.CallSuper;
5
-import android.support.annotation.CheckResult;
6
-import android.support.annotation.NonNull;
7
-import android.support.annotation.Nullable;
8
-import android.support.v4.view.ViewPager;
4
+import android.view.View;
9
 import android.view.ViewGroup;
5
 import android.view.ViewGroup;
10
 
6
 
11
 import com.reactnativenavigation.parse.Options;
7
 import com.reactnativenavigation.parse.Options;
16
 
12
 
17
 import java.util.Collection;
13
 import java.util.Collection;
18
 
14
 
19
-import static com.reactnativenavigation.utils.CollectionUtils.forEach;
15
+import androidx.annotation.CallSuper;
16
+import androidx.annotation.CheckResult;
17
+import androidx.annotation.NonNull;
18
+import androidx.annotation.Nullable;
19
+import androidx.viewpager.widget.ViewPager;
20
+
21
+import static com.reactnativenavigation.utils.CollectionUtils.*;
22
+import static com.reactnativenavigation.utils.ObjectUtils.perform;
20
 
23
 
21
 public abstract class ParentController<T extends ViewGroup> extends ChildController {
24
 public abstract class ParentController<T extends ViewGroup> extends ChildController {
22
 
25
 
46
                 .withDefaultOptions(initialOptions);
49
                 .withDefaultOptions(initialOptions);
47
     }
50
     }
48
 
51
 
52
+    public Options resolveChildOptions(ViewController child) {
53
+	    if (child == this) return resolveCurrentOptions();
54
+        return child
55
+                .resolveCurrentOptions()
56
+                .copy()
57
+                .withDefaultOptions(initialOptions);
58
+    }
59
+
49
     @Override
60
     @Override
50
     @CheckResult
61
     @CheckResult
51
     public Options resolveCurrentOptions(Options defaultOptions) {
62
     public Options resolveCurrentOptions(Options defaultOptions) {
52
         return resolveCurrentOptions().withDefaultOptions(defaultOptions);
63
         return resolveCurrentOptions().withDefaultOptions(defaultOptions);
53
     }
64
     }
54
 
65
 
66
+    public boolean isCurrentChild(ViewController child) {
67
+        return getCurrentChild() == child;
68
+    }
69
+
55
     protected abstract ViewController getCurrentChild();
70
     protected abstract ViewController getCurrentChild();
56
 
71
 
57
     @NonNull
72
     @NonNull
81
 		return null;
96
 		return null;
82
 	}
97
 	}
83
 
98
 
99
+    @Nullable
100
+    @Override
101
+    public ViewController findController(View child) {
102
+        ViewController fromSuper = super.findController(child);
103
+        if (fromSuper != null) return fromSuper;
104
+
105
+        for (ViewController childController : getChildControllers()) {
106
+            ViewController fromChild = childController.findController(child);
107
+            if (fromChild != null) return fromChild;
108
+        }
109
+
110
+        return null;
111
+    }
112
+
84
     @Override
113
     @Override
85
     public boolean containsComponent(Component component) {
114
     public boolean containsComponent(Component component) {
86
         if (super.containsComponent(component)) {
115
         if (super.containsComponent(component)) {
93
     }
122
     }
94
 
123
 
95
     @CallSuper
124
     @CallSuper
96
-    public void applyChildOptions(Options options, Component child) {
125
+    public void applyChildOptions(Options options, ViewController child) {
97
         this.options = initialOptions.mergeWith(options);
126
         this.options = initialOptions.mergeWith(options);
98
-        if (isRoot()) {
99
-            presenter.applyRootOptions(getView(), options);
100
-        }
101
     }
127
     }
102
 
128
 
103
     @CallSuper
129
     @CallSuper
104
-    public void mergeChildOptions(Options options, ViewController childController, Component child) {
130
+    public void mergeChildOptions(Options options, ViewController childController) {
105
 
131
 
106
     }
132
     }
107
 
133
 
108
 	@Override
134
 	@Override
109
 	public void destroy() {
135
 	public void destroy() {
110
 		super.destroy();
136
 		super.destroy();
111
-		for (ViewController child : getChildControllers()) {
112
-			child.destroy();
113
-		}
137
+		forEach(getChildControllers(), ViewController::destroy);
114
 	}
138
 	}
115
 
139
 
116
-	@CallSuper
140
+	@SuppressWarnings("WeakerAccess")
141
+    @CallSuper
117
     protected void clearOptions() {
142
     protected void clearOptions() {
118
 	    performOnParentController(parent -> ((ParentController) parent).clearOptions());
143
 	    performOnParentController(parent -> ((ParentController) parent).clearOptions());
119
         options = initialOptions.copy().clearOneTimeOptions();
144
         options = initialOptions.copy().clearOneTimeOptions();
132
         return getCurrentChild() != null && getCurrentChild().isRendered();
157
         return getCurrentChild() != null && getCurrentChild().isRendered();
133
     }
158
     }
134
 
159
 
135
-    public void onChildDestroyed(Component child) {
160
+    public void onChildDestroyed(ViewController child) {
161
+
162
+    }
163
+
164
+    @Override
165
+    public void applyTopInset() {
166
+	    forEach(getChildControllers(), ViewController::applyTopInset);
167
+    }
168
+
169
+    public int getTopInset(ViewController child) {
170
+        return perform(getParentController(), 0, p -> p.getTopInset(child));
171
+    }
172
+
173
+    @Override
174
+    public void applyBottomInset() {
175
+        forEach(getChildControllers(), ViewController::applyBottomInset);
176
+    }
136
 
177
 
178
+    public int getBottomInset(ViewController child) {
179
+        return perform(getParentController(), 0, p -> p.getBottomInset(child));
137
     }
180
     }
138
 }
181
 }

+ 4
- 4
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/TitleBarButtonController.java View File

4
 import android.app.Activity;
4
 import android.app.Activity;
5
 import android.graphics.Color;
5
 import android.graphics.Color;
6
 import android.graphics.drawable.Drawable;
6
 import android.graphics.drawable.Drawable;
7
-import android.support.annotation.NonNull;
8
-import android.support.annotation.RestrictTo;
9
-import android.support.v7.widget.ActionMenuView;
10
-import android.support.v7.widget.Toolbar;
7
+import androidx.annotation.NonNull;
8
+import androidx.annotation.RestrictTo;
9
+import androidx.appcompat.widget.ActionMenuView;
10
+import androidx.appcompat.widget.Toolbar;
11
 import android.view.Menu;
11
 import android.view.Menu;
12
 import android.view.MenuItem;
12
 import android.view.MenuItem;
13
 import android.widget.ImageButton;
13
 import android.widget.ImageButton;

+ 52
- 11
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ViewController.java View File

1
 package com.reactnativenavigation.viewcontrollers;
1
 package com.reactnativenavigation.viewcontrollers;
2
 
2
 
3
 import android.app.Activity;
3
 import android.app.Activity;
4
-import android.support.annotation.CallSuper;
5
-import android.support.annotation.CheckResult;
6
-import android.support.annotation.NonNull;
7
-import android.support.annotation.Nullable;
8
-import android.support.annotation.VisibleForTesting;
9
 import android.view.View;
4
 import android.view.View;
10
 import android.view.ViewGroup;
5
 import android.view.ViewGroup;
11
 import android.view.ViewManager;
6
 import android.view.ViewManager;
21
 import com.reactnativenavigation.utils.UiThread;
16
 import com.reactnativenavigation.utils.UiThread;
22
 import com.reactnativenavigation.utils.UiUtils;
17
 import com.reactnativenavigation.utils.UiUtils;
23
 import com.reactnativenavigation.viewcontrollers.stack.StackController;
18
 import com.reactnativenavigation.viewcontrollers.stack.StackController;
19
+import com.reactnativenavigation.views.BehaviourAdapter;
24
 import com.reactnativenavigation.views.Component;
20
 import com.reactnativenavigation.views.Component;
25
 import com.reactnativenavigation.views.Renderable;
21
 import com.reactnativenavigation.views.Renderable;
26
 import com.reactnativenavigation.views.element.Element;
22
 import com.reactnativenavigation.views.element.Element;
29
 import java.util.Collections;
25
 import java.util.Collections;
30
 import java.util.List;
26
 import java.util.List;
31
 
27
 
32
-import static com.reactnativenavigation.utils.CollectionUtils.forEach;
28
+import androidx.annotation.CallSuper;
29
+import androidx.annotation.CheckResult;
30
+import androidx.annotation.NonNull;
31
+import androidx.annotation.Nullable;
32
+import androidx.annotation.VisibleForTesting;
33
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
33
 
34
 
34
-public abstract class ViewController<T extends ViewGroup> implements ViewTreeObserver.OnGlobalLayoutListener, ViewGroup.OnHierarchyChangeListener {
35
+import static com.reactnativenavigation.utils.CollectionUtils.*;
36
+import static com.reactnativenavigation.utils.ObjectUtils.perform;
37
+
38
+public abstract class ViewController<T extends ViewGroup> implements ViewTreeObserver.OnGlobalLayoutListener,
39
+        ViewGroup.OnHierarchyChangeListener,
40
+        BehaviourAdapter<T> {
35
 
41
 
36
     private final List<Runnable> onAppearedListeners = new ArrayList();
42
     private final List<Runnable> onAppearedListeners = new ArrayList();
37
     private boolean appearEventPosted;
43
     private boolean appearEventPosted;
136
         return activity;
142
         return activity;
137
     }
143
     }
138
 
144
 
145
+    public void performOnView(Func1<View> task) {
146
+        if (view != null) task.run(view);
147
+    }
148
+
139
     protected void performOnParentController(Func1<ParentController> task) {
149
     protected void performOnParentController(Func1<ParentController> task) {
140
         if (parentController != null) task.run(parentController);
150
         if (parentController != null) task.run(parentController);
141
     }
151
     }
154
             task.run((StackController) parentController);
164
             task.run((StackController) parentController);
155
         } else if (this instanceof StackController) {
165
         } else if (this instanceof StackController) {
156
             task.run((StackController) this);
166
             task.run((StackController) this);
157
-        } else if (parentController != null){
158
-            parentController.performOnParentStack(task);
159
-        }
167
+        } else performOnParentController(parent -> parent.performOnParentStack(task));
160
     }
168
     }
161
 
169
 
162
     public T getView() {
170
     public T getView() {
194
         return isSameId(id) ? this : null;
202
         return isSameId(id) ? this : null;
195
     }
203
     }
196
 
204
 
205
+    @Nullable
206
+    public ViewController findController(View child) {
207
+        return view == child ? this : null;
208
+    }
209
+
197
     public boolean containsComponent(Component component) {
210
     public boolean containsComponent(Component component) {
198
         return getView().equals(component);
211
         return getView().equals(component);
199
     }
212
     }
208
         applyOptions(options);
221
         applyOptions(options);
209
         performOnParentController(parentController -> {
222
         performOnParentController(parentController -> {
210
             parentController.clearOptions();
223
             parentController.clearOptions();
211
-            if (getView() instanceof Component) parentController.applyChildOptions(options, (Component) getView());
224
+            if (getView() instanceof Component) parentController.applyChildOptions(options, this);
212
         });
225
         });
213
         if (!onAppearedListeners.isEmpty() && !appearEventPosted) {
226
         if (!onAppearedListeners.isEmpty() && !appearEventPosted) {
214
             appearEventPosted = true;
227
             appearEventPosted = true;
310
     public List<Element> getElements() {
323
     public List<Element> getElements() {
311
         return getView() instanceof IReactView && view != null? ((IReactView) view).getElements() : Collections.EMPTY_LIST;
324
         return getView() instanceof IReactView && view != null? ((IReactView) view).getElements() : Collections.EMPTY_LIST;
312
     }
325
     }
326
+
327
+    @Override
328
+    @CallSuper
329
+    public boolean onMeasureChild(CoordinatorLayout parent, T child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) {
330
+        perform(findController(child), ViewController::applyTopInset);
331
+        return false;
332
+    }
333
+
334
+    @Override
335
+    public boolean onDependentViewChanged(CoordinatorLayout parent, T child, View dependency) {
336
+        return false;
337
+    }
338
+
339
+    public void applyTopInset() {
340
+
341
+    }
342
+
343
+    public int getTopInset() {
344
+        return 0;
345
+    }
346
+
347
+    public void applyBottomInset() {
348
+
349
+    }
350
+
351
+    public int getBottomInset() {
352
+        return perform(parentController, 0, p -> p.getBottomInset(this));
353
+    }
313
 }
354
 }

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/YellowBoxDelegate.java View File

1
 package com.reactnativenavigation.viewcontrollers;
1
 package com.reactnativenavigation.viewcontrollers;
2
 
2
 
3
-import android.support.annotation.RestrictTo;
3
+import androidx.annotation.RestrictTo;
4
 import android.view.View;
4
 import android.view.View;
5
 import android.view.ViewGroup;
5
 import android.view.ViewGroup;
6
 
6
 

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/YellowBoxHelper.java View File

1
 package com.reactnativenavigation.viewcontrollers;
1
 package com.reactnativenavigation.viewcontrollers;
2
 
2
 
3
-import android.support.annotation.NonNull;
3
+import androidx.annotation.NonNull;
4
 import android.view.View;
4
 import android.view.View;
5
 import android.view.ViewGroup;
5
 import android.view.ViewGroup;
6
 
6
 

+ 10
- 14
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/AttachMode.java View File

1
 package com.reactnativenavigation.viewcontrollers.bottomtabs;
1
 package com.reactnativenavigation.viewcontrollers.bottomtabs;
2
 
2
 
3
-import android.support.annotation.VisibleForTesting;
4
-import android.view.*;
5
-import android.widget.*;
3
+import androidx.annotation.VisibleForTesting;
4
+import android.view.View;
5
+import android.view.ViewGroup;
6
 
6
 
7
-import com.reactnativenavigation.parse.*;
8
-import com.reactnativenavigation.presentation.*;
9
-import com.reactnativenavigation.viewcontrollers.*;
7
+import com.reactnativenavigation.parse.Options;
8
+import com.reactnativenavigation.presentation.BottomTabsPresenter;
9
+import com.reactnativenavigation.viewcontrollers.ViewController;
10
+import com.reactnativenavigation.views.bottomtabs.BottomTabsBehaviour;
10
 
11
 
11
-import java.util.*;
12
+import java.util.List;
12
 
13
 
13
-import static android.view.ViewGroup.LayoutParams.*;
14
+import static com.reactnativenavigation.utils.CoordinatorLayoutUtils.matchParentWithBehaviour;
14
 
15
 
15
 public abstract class AttachMode {
16
 public abstract class AttachMode {
16
     protected final ViewGroup parent;
17
     protected final ViewGroup parent;
17
     protected final BottomTabsPresenter presenter;
18
     protected final BottomTabsPresenter presenter;
18
     protected final List<ViewController> tabs;
19
     protected final List<ViewController> tabs;
19
     final ViewController initialTab;
20
     final ViewController initialTab;
20
-    private final Options resolved;
21
-
22
 
21
 
23
     public static AttachMode get(ViewGroup parent, List<ViewController> tabs, BottomTabsPresenter presenter, Options resolved) {
22
     public static AttachMode get(ViewGroup parent, List<ViewController> tabs, BottomTabsPresenter presenter, Options resolved) {
24
         switch (resolved.bottomTabsOptions.tabsAttachMode) {
23
         switch (resolved.bottomTabsOptions.tabsAttachMode) {
37
         this.parent = parent;
36
         this.parent = parent;
38
         this.tabs = tabs;
37
         this.tabs = tabs;
39
         this.presenter = presenter;
38
         this.presenter = presenter;
40
-        this.resolved = resolved;
41
         initialTab = tabs.get(resolved.bottomTabsOptions.currentTabIndex.get(0));
39
         initialTab = tabs.get(resolved.bottomTabsOptions.currentTabIndex.get(0));
42
     }
40
     }
43
 
41
 
54
     @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
52
     @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
55
     public void attach(ViewController tab) {
53
     public void attach(ViewController tab) {
56
         ViewGroup view = tab.getView();
54
         ViewGroup view = tab.getView();
57
-        view.setLayoutParams(new RelativeLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
58
-        presenter.applyLayoutParamsOptions(resolved, tabs.indexOf(tab));
59
         view.setVisibility(tab == initialTab ? View.VISIBLE : View.INVISIBLE);
55
         view.setVisibility(tab == initialTab ? View.VISIBLE : View.INVISIBLE);
60
-        parent.addView(view);
56
+        parent.addView(view, matchParentWithBehaviour(new BottomTabsBehaviour(tab.getParentController())));
61
     }
57
     }
62
 }
58
 }

+ 1
- 12
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabFinder.java View File

1
 package com.reactnativenavigation.viewcontrollers.bottomtabs;
1
 package com.reactnativenavigation.viewcontrollers.bottomtabs;
2
 
2
 
3
-import android.support.annotation.IntRange;
3
+import androidx.annotation.IntRange;
4
 
4
 
5
 import com.reactnativenavigation.viewcontrollers.ViewController;
5
 import com.reactnativenavigation.viewcontrollers.ViewController;
6
-import com.reactnativenavigation.views.Component;
7
 
6
 
8
 import java.util.List;
7
 import java.util.List;
9
 
8
 
14
         this.tabs = tabs;
13
         this.tabs = tabs;
15
     }
14
     }
16
 
15
 
17
-    @IntRange(from = -1)
18
-    public int findByComponent(Component component) {
19
-        for (int i = 0; i < tabs.size(); i++) {
20
-            if (tabs.get(i).containsComponent(component)) {
21
-                return i;
22
-            }
23
-        }
24
-        return -1;
25
-    }
26
-
27
     @IntRange(from = -1)
16
     @IntRange(from = -1)
28
     public int findByControllerId(String id) {
17
     public int findByControllerId(String id) {
29
         for (int i = 0; i < tabs.size(); i++) {
18
         for (int i = 0; i < tabs.size(); i++) {

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsAttacher.java View File

1
 package com.reactnativenavigation.viewcontrollers.bottomtabs;
1
 package com.reactnativenavigation.viewcontrollers.bottomtabs;
2
 
2
 
3
-import android.support.annotation.VisibleForTesting;
3
+import androidx.annotation.VisibleForTesting;
4
 import android.view.ViewGroup;
4
 import android.view.ViewGroup;
5
 
5
 
6
 import com.reactnativenavigation.parse.Options;
6
 import com.reactnativenavigation.parse.Options;

+ 42
- 20
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsController.java View File

1
 package com.reactnativenavigation.viewcontrollers.bottomtabs;
1
 package com.reactnativenavigation.viewcontrollers.bottomtabs;
2
 
2
 
3
 import android.app.Activity;
3
 import android.app.Activity;
4
-import android.support.annotation.NonNull;
5
-import android.support.annotation.RestrictTo;
4
+import android.view.Gravity;
6
 import android.view.View;
5
 import android.view.View;
7
 import android.view.ViewGroup;
6
 import android.view.ViewGroup;
8
-import android.widget.RelativeLayout;
9
 
7
 
10
 import com.aurelhubert.ahbottomnavigation.AHBottomNavigation;
8
 import com.aurelhubert.ahbottomnavigation.AHBottomNavigation;
11
 import com.aurelhubert.ahbottomnavigation.AHBottomNavigationItem;
9
 import com.aurelhubert.ahbottomnavigation.AHBottomNavigationItem;
21
 import com.reactnativenavigation.viewcontrollers.ParentController;
19
 import com.reactnativenavigation.viewcontrollers.ParentController;
22
 import com.reactnativenavigation.viewcontrollers.ViewController;
20
 import com.reactnativenavigation.viewcontrollers.ViewController;
23
 import com.reactnativenavigation.views.BottomTabs;
21
 import com.reactnativenavigation.views.BottomTabs;
24
-import com.reactnativenavigation.views.Component;
22
+import com.reactnativenavigation.views.bottomtabs.BottomTabsLayout;
25
 
23
 
26
 import java.util.Collection;
24
 import java.util.Collection;
27
 import java.util.List;
25
 import java.util.List;
28
 
26
 
27
+import androidx.annotation.NonNull;
28
+import androidx.annotation.RestrictTo;
29
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
30
+
29
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
31
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
30
-import static android.widget.RelativeLayout.ALIGN_PARENT_BOTTOM;
31
-import static com.reactnativenavigation.react.Constants.BOTTOM_TABS_HEIGHT;
32
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
32
 import static com.reactnativenavigation.utils.CollectionUtils.*;
33
 import static com.reactnativenavigation.utils.CollectionUtils.*;
33
-import static com.reactnativenavigation.utils.UiUtils.dpToPx;
34
+import static com.reactnativenavigation.utils.ObjectUtils.perform;
34
 
35
 
35
-public class BottomTabsController extends ParentController implements AHBottomNavigation.OnTabSelectedListener, TabSelector {
36
+public class BottomTabsController extends ParentController<BottomTabsLayout> implements AHBottomNavigation.OnTabSelectedListener, TabSelector {
36
 
37
 
37
 	private BottomTabs bottomTabs;
38
 	private BottomTabs bottomTabs;
38
 	private List<ViewController> tabs;
39
 	private List<ViewController> tabs;
50
         this.tabsAttacher = tabsAttacher;
51
         this.tabsAttacher = tabsAttacher;
51
         this.presenter = bottomTabsPresenter;
52
         this.presenter = bottomTabsPresenter;
52
         this.tabPresenter = bottomTabPresenter;
53
         this.tabPresenter = bottomTabPresenter;
53
-        forEach(tabs, (tab) -> tab.setParentController(this));
54
+        forEach(tabs, tab -> tab.setParentController(this));
54
     }
55
     }
55
 
56
 
56
     @Override
57
     @Override
62
 
63
 
63
     @NonNull
64
     @NonNull
64
 	@Override
65
 	@Override
65
-	protected ViewGroup createView() {
66
-		RelativeLayout root = new RelativeLayout(getActivity());
67
-		bottomTabs = createBottomTabs();
66
+	protected BottomTabsLayout createView() {
67
+        BottomTabsLayout root = new BottomTabsLayout(getActivity());
68
+
69
+        bottomTabs = createBottomTabs();
68
         tabsAttacher.init(root, resolveCurrentOptions());
70
         tabsAttacher.init(root, resolveCurrentOptions());
69
         presenter.bindView(bottomTabs, this);
71
         presenter.bindView(bottomTabs, this);
70
         tabPresenter.bindView(bottomTabs);
72
         tabPresenter.bindView(bottomTabs);
71
         bottomTabs.setOnTabSelectedListener(this);
73
         bottomTabs.setOnTabSelectedListener(this);
72
-		RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(MATCH_PARENT, dpToPx(getActivity(), BOTTOM_TABS_HEIGHT));
73
-		lp.addRule(ALIGN_PARENT_BOTTOM);
74
+        CoordinatorLayout.LayoutParams lp = new CoordinatorLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT);
75
+        lp.gravity = Gravity.BOTTOM;
74
 		root.addView(bottomTabs, lp);
76
 		root.addView(bottomTabs, lp);
75
-		bottomTabs.addItems(createTabs());
77
+
78
+        bottomTabs.addItems(createTabs());
76
         tabsAttacher.attach();
79
         tabsAttacher.attach();
77
         return root;
80
         return root;
78
 	}
81
 	}
96
     @Override
99
     @Override
97
     public void mergeOptions(Options options) {
100
     public void mergeOptions(Options options) {
98
         presenter.mergeOptions(options);
101
         presenter.mergeOptions(options);
102
+        tabPresenter.mergeOptions(options);
99
         super.mergeOptions(options);
103
         super.mergeOptions(options);
100
         this.options.bottomTabsOptions.clearOneTimeOptions();
104
         this.options.bottomTabsOptions.clearOneTimeOptions();
101
         this.initialOptions.bottomTabsOptions.clearOneTimeOptions();
105
         this.initialOptions.bottomTabsOptions.clearOneTimeOptions();
102
     }
106
     }
103
 
107
 
104
     @Override
108
     @Override
105
-    public void applyChildOptions(Options options, Component child) {
109
+    public void applyChildOptions(Options options, ViewController child) {
106
         super.applyChildOptions(options, child);
110
         super.applyChildOptions(options, child);
107
         presenter.applyChildOptions(resolveCurrentOptions(), child);
111
         presenter.applyChildOptions(resolveCurrentOptions(), child);
108
         performOnParentController(parentController ->
112
         performOnParentController(parentController ->
116
     }
120
     }
117
 
121
 
118
     @Override
122
     @Override
119
-    public void mergeChildOptions(Options options, ViewController childController, Component child) {
120
-        super.mergeChildOptions(options, childController, child);
123
+    public void mergeChildOptions(Options options, ViewController child) {
124
+        super.mergeChildOptions(options, child);
121
         presenter.mergeChildOptions(options, child);
125
         presenter.mergeChildOptions(options, child);
122
         tabPresenter.mergeChildOptions(options, child);
126
         tabPresenter.mergeChildOptions(options, child);
123
         performOnParentController(parentController ->
127
         performOnParentController(parentController ->
124
-                ((ParentController) parentController).mergeChildOptions(options.copy().clearBottomTabsOptions(), childController, child)
128
+                ((ParentController) parentController).mergeChildOptions(options.copy().clearBottomTabsOptions(), child)
125
         );
129
         );
126
     }
130
     }
127
 
131
 
164
 		return bottomTabs.getCurrentItem();
168
 		return bottomTabs.getCurrentItem();
165
 	}
169
 	}
166
 
170
 
167
-	@NonNull
171
+    @Override
172
+    public boolean onMeasureChild(CoordinatorLayout parent, ViewGroup child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) {
173
+        perform(findController(child), ViewController::applyBottomInset);
174
+        return super.onMeasureChild(parent, child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed);
175
+    }
176
+
177
+    @Override
178
+    public int getBottomInset(ViewController child) {
179
+        int bottomTabsInset = resolveChildOptions(child).bottomTabsOptions.drawBehind.isTrue() ? 0 : bottomTabs.getHeight();
180
+        return bottomTabsInset + perform(getParentController(), 0, p -> p.getBottomInset(this));
181
+    }
182
+
183
+    @Override
184
+    public void applyBottomInset() {
185
+        presenter.applyBottomInset(getBottomInset());
186
+        super.applyBottomInset();
187
+    }
188
+
189
+    @NonNull
168
 	@Override
190
 	@Override
169
 	public Collection<ViewController> getChildControllers() {
191
 	public Collection<ViewController> getChildControllers() {
170
 		return tabs;
192
 		return tabs;

+ 2
- 2
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/button/NavigationIconResolver.java View File

2
 
2
 
3
 import android.content.Context;
3
 import android.content.Context;
4
 import android.graphics.drawable.Drawable;
4
 import android.graphics.drawable.Drawable;
5
-import android.support.annotation.NonNull;
6
-import android.support.v4.content.ContextCompat;
5
+import androidx.annotation.NonNull;
6
+import androidx.core.content.ContextCompat;
7
 import android.util.Log;
7
 import android.util.Log;
8
 import android.view.View;
8
 import android.view.View;
9
 
9
 

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/externalcomponent/ExternalComponentCreator.java View File

1
 package com.reactnativenavigation.viewcontrollers.externalcomponent;
1
 package com.reactnativenavigation.viewcontrollers.externalcomponent;
2
 
2
 
3
-import android.support.v4.app.FragmentActivity;
3
+import androidx.fragment.app.FragmentActivity;
4
 
4
 
5
 import com.facebook.react.ReactInstanceManager;
5
 import com.facebook.react.ReactInstanceManager;
6
 
6
 

+ 36
- 4
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/externalcomponent/ExternalComponentViewController.java View File

1
 package com.reactnativenavigation.viewcontrollers.externalcomponent;
1
 package com.reactnativenavigation.viewcontrollers.externalcomponent;
2
 
2
 
3
 import android.app.Activity;
3
 import android.app.Activity;
4
-import android.support.v4.app.FragmentActivity;
4
+import androidx.fragment.app.FragmentActivity;
5
+import androidx.core.view.ViewCompat;
6
+import android.view.View;
5
 
7
 
6
 import com.facebook.react.ReactInstanceManager;
8
 import com.facebook.react.ReactInstanceManager;
7
 import com.reactnativenavigation.parse.ExternalComponent;
9
 import com.reactnativenavigation.parse.ExternalComponent;
8
 import com.reactnativenavigation.parse.Options;
10
 import com.reactnativenavigation.parse.Options;
11
+import com.reactnativenavigation.presentation.ExternalComponentPresenter;
9
 import com.reactnativenavigation.react.EventEmitter;
12
 import com.reactnativenavigation.react.EventEmitter;
13
+import com.reactnativenavigation.utils.CoordinatorLayoutUtils;
14
+import com.reactnativenavigation.utils.StatusBarUtils;
10
 import com.reactnativenavigation.viewcontrollers.NoOpYellowBoxDelegate;
15
 import com.reactnativenavigation.viewcontrollers.NoOpYellowBoxDelegate;
11
 import com.reactnativenavigation.viewcontrollers.ViewController;
16
 import com.reactnativenavigation.viewcontrollers.ViewController;
17
+import com.reactnativenavigation.views.BehaviourDelegate;
12
 import com.reactnativenavigation.views.ExternalComponentLayout;
18
 import com.reactnativenavigation.views.ExternalComponentLayout;
13
 
19
 
20
+import static com.reactnativenavigation.utils.ObjectUtils.perform;
21
+
14
 public class ExternalComponentViewController extends ViewController<ExternalComponentLayout> {
22
 public class ExternalComponentViewController extends ViewController<ExternalComponentLayout> {
15
     private final ExternalComponent externalComponent;
23
     private final ExternalComponent externalComponent;
16
     private final ExternalComponentCreator componentCreator;
24
     private final ExternalComponentCreator componentCreator;
17
     private ReactInstanceManager reactInstanceManager;
25
     private ReactInstanceManager reactInstanceManager;
18
     private final EventEmitter emitter;
26
     private final EventEmitter emitter;
27
+    private final ExternalComponentPresenter presenter;
19
 
28
 
20
-    public ExternalComponentViewController(Activity activity, String id, ExternalComponent externalComponent, ExternalComponentCreator componentCreator, ReactInstanceManager reactInstanceManager, EventEmitter emitter, Options initialOptions) {
29
+    public ExternalComponentViewController(Activity activity, String id, ExternalComponent externalComponent, ExternalComponentCreator componentCreator, ReactInstanceManager reactInstanceManager, EventEmitter emitter, ExternalComponentPresenter presenter, Options initialOptions) {
21
         super(activity, id, new NoOpYellowBoxDelegate(), initialOptions);
30
         super(activity, id, new NoOpYellowBoxDelegate(), initialOptions);
22
         this.externalComponent = externalComponent;
31
         this.externalComponent = externalComponent;
23
         this.componentCreator = componentCreator;
32
         this.componentCreator = componentCreator;
24
         this.reactInstanceManager = reactInstanceManager;
33
         this.reactInstanceManager = reactInstanceManager;
25
         this.emitter = emitter;
34
         this.emitter = emitter;
35
+        this.presenter = presenter;
26
     }
36
     }
27
 
37
 
28
     @Override
38
     @Override
29
     protected ExternalComponentLayout createView() {
39
     protected ExternalComponentLayout createView() {
30
         ExternalComponentLayout content = new ExternalComponentLayout(getActivity());
40
         ExternalComponentLayout content = new ExternalComponentLayout(getActivity());
41
+        enableDrawingBehindStatusBar(content);
31
         content.addView(componentCreator
42
         content.addView(componentCreator
32
                 .create(getActivity(), reactInstanceManager, externalComponent.passProps)
43
                 .create(getActivity(), reactInstanceManager, externalComponent.passProps)
33
-                .asView());
44
+                .asView(), CoordinatorLayoutUtils.matchParentWithBehaviour(new BehaviourDelegate(this)));
34
         return content;
45
         return content;
35
     }
46
     }
36
 
47
 
42
     @Override
53
     @Override
43
     public void mergeOptions(Options options) {
54
     public void mergeOptions(Options options) {
44
         if (options == Options.EMPTY) return;
55
         if (options == Options.EMPTY) return;
45
-        performOnParentController(parentController -> parentController.mergeChildOptions(options, this, getView()));
56
+        performOnParentController(parentController -> parentController.mergeChildOptions(options, this));
46
         super.mergeOptions(options);
57
         super.mergeOptions(options);
47
     }
58
     }
48
 
59
 
58
         emitter.emitComponentDidDisappear(getId(), externalComponent.name.get());
69
         emitter.emitComponentDidDisappear(getId(), externalComponent.name.get());
59
     }
70
     }
60
 
71
 
72
+    @Override
73
+    public void applyTopInset() {
74
+        if (view != null) presenter.applyTopInsets(view, getTopInset());
75
+    }
76
+
77
+    @Override
78
+    public int getTopInset() {
79
+        int statusBarInset = resolveCurrentOptions().statusBar.drawBehind.isTrue() ? 0 : StatusBarUtils.getStatusBarHeight(getActivity());
80
+        return statusBarInset + perform(getParentController(), 0, p -> p.getTopInset(this));
81
+    }
82
+
83
+    @Override
84
+    public void applyBottomInset() {
85
+        if (view != null) presenter.applyBottomInset(view, getBottomInset());
86
+    }
87
+
61
     public FragmentActivity getActivity() {
88
     public FragmentActivity getActivity() {
62
         return (FragmentActivity) super.getActivity();
89
         return (FragmentActivity) super.getActivity();
63
     }
90
     }
91
+
92
+    private void enableDrawingBehindStatusBar(View view) {
93
+        view.setFitsSystemWindows(true);
94
+        ViewCompat.setOnApplyWindowInsetsListener(view, (v, insets) -> insets);
95
+    }
64
 }
96
 }

+ 17
- 5
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/modal/ModalPresenter.java View File

2
 
2
 
3
 import android.animation.Animator;
3
 import android.animation.Animator;
4
 import android.animation.AnimatorListenerAdapter;
4
 import android.animation.AnimatorListenerAdapter;
5
-import android.support.annotation.Nullable;
6
 import android.view.ViewGroup;
5
 import android.view.ViewGroup;
7
 
6
 
8
 import com.reactnativenavigation.anim.ModalAnimator;
7
 import com.reactnativenavigation.anim.ModalAnimator;
11
 import com.reactnativenavigation.utils.CommandListener;
10
 import com.reactnativenavigation.utils.CommandListener;
12
 import com.reactnativenavigation.viewcontrollers.ViewController;
11
 import com.reactnativenavigation.viewcontrollers.ViewController;
13
 
12
 
13
+import androidx.annotation.Nullable;
14
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
15
+
16
+import static com.reactnativenavigation.utils.CoordinatorLayoutUtils.matchParentLP;
17
+
14
 public class ModalPresenter {
18
 public class ModalPresenter {
15
 
19
 
16
     private ViewGroup rootLayout;
20
     private ViewGroup rootLayout;
17
-    private ViewGroup modalsLayout;
21
+    private CoordinatorLayout modalsLayout;
18
     private ModalAnimator animator;
22
     private ModalAnimator animator;
19
     private Options defaultOptions = new Options();
23
     private Options defaultOptions = new Options();
20
 
24
 
22
         this.animator = animator;
26
         this.animator = animator;
23
     }
27
     }
24
 
28
 
25
-    public void setRootLayout(ViewGroup rootLayout) {
29
+    void setRootLayout(ViewGroup rootLayout) {
26
         this.rootLayout = rootLayout;
30
         this.rootLayout = rootLayout;
27
     }
31
     }
28
 
32
 
29
-    void setModalsLayout(ViewGroup modalsLayout) {
33
+    void setModalsLayout(CoordinatorLayout modalsLayout) {
30
         this.modalsLayout = modalsLayout;
34
         this.modalsLayout = modalsLayout;
31
     }
35
     }
32
 
36
 
39
             listener.onError("Can not show modal before activity is created");
43
             listener.onError("Can not show modal before activity is created");
40
             return;
44
             return;
41
         }
45
         }
46
+
42
         Options options = toAdd.resolveCurrentOptions(defaultOptions);
47
         Options options = toAdd.resolveCurrentOptions(defaultOptions);
43
         toAdd.setWaitForRender(options.animations.showModal.waitForRender);
48
         toAdd.setWaitForRender(options.animations.showModal.waitForRender);
44
-        modalsLayout.addView(toAdd.getView());
49
+        modalsLayout.addView(toAdd.getView(), matchParentLP());
50
+
45
         if (options.animations.showModal.enabled.isTrueOrUndefined()) {
51
         if (options.animations.showModal.enabled.isTrueOrUndefined()) {
52
+            toAdd.getView().setAlpha(0);
46
             if (options.animations.showModal.waitForRender.isTrue()) {
53
             if (options.animations.showModal.waitForRender.isTrue()) {
47
                 toAdd.addOnAppearedListener(() -> animateShow(toAdd, toRemove, listener, options));
54
                 toAdd.addOnAppearedListener(() -> animateShow(toAdd, toRemove, listener, options));
48
             } else {
55
             } else {
59
 
66
 
60
     private void animateShow(ViewController toAdd, ViewController toRemove, CommandListener listener, Options options) {
67
     private void animateShow(ViewController toAdd, ViewController toRemove, CommandListener listener, Options options) {
61
         animator.show(toAdd.getView(), options.animations.showModal, new AnimatorListenerAdapter() {
68
         animator.show(toAdd.getView(), options.animations.showModal, new AnimatorListenerAdapter() {
69
+            @Override
70
+            public void onAnimationStart(Animator animation) {
71
+                toAdd.getView().setAlpha(1);
72
+            }
73
+
62
             @Override
74
             @Override
63
             public void onAnimationEnd(Animator animation) {
75
             public void onAnimationEnd(Animator animation) {
64
                 onShowModalEnd(toAdd, toRemove, listener);
76
                 onShowModalEnd(toAdd, toRemove, listener);

+ 3
- 2
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/modal/ModalStack.java View File

1
 package com.reactnativenavigation.viewcontrollers.modal;
1
 package com.reactnativenavigation.viewcontrollers.modal;
2
 
2
 
3
 import android.app.Activity;
3
 import android.app.Activity;
4
-import android.support.annotation.RestrictTo;
4
+import androidx.annotation.RestrictTo;
5
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
5
 import android.view.ViewGroup;
6
 import android.view.ViewGroup;
6
 
7
 
7
 import com.reactnativenavigation.anim.ModalAnimator;
8
 import com.reactnativenavigation.anim.ModalAnimator;
35
         this.presenter = presenter;
36
         this.presenter = presenter;
36
     }
37
     }
37
 
38
 
38
-    public void setModalsLayout(ViewGroup modalsLayout) {
39
+    public void setModalsLayout(CoordinatorLayout modalsLayout) {
39
         presenter.setModalsLayout(modalsLayout);
40
         presenter.setModalsLayout(modalsLayout);
40
     }
41
     }
41
 
42
 

+ 17
- 19
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/navigator/Navigator.java View File

1
 package com.reactnativenavigation.viewcontrollers.navigator;
1
 package com.reactnativenavigation.viewcontrollers.navigator;
2
 
2
 
3
 import android.app.Activity;
3
 import android.app.Activity;
4
-import android.support.annotation.NonNull;
5
-import android.support.annotation.Nullable;
6
-import android.support.annotation.RestrictTo;
7
 import android.view.ViewGroup;
4
 import android.view.ViewGroup;
8
-import android.widget.FrameLayout;
9
 
5
 
6
+import com.facebook.react.ReactInstanceManager;
10
 import com.reactnativenavigation.parse.Options;
7
 import com.reactnativenavigation.parse.Options;
11
 import com.reactnativenavigation.presentation.OverlayManager;
8
 import com.reactnativenavigation.presentation.OverlayManager;
12
 import com.reactnativenavigation.presentation.Presenter;
9
 import com.reactnativenavigation.presentation.Presenter;
22
 import com.reactnativenavigation.viewcontrollers.modal.ModalStack;
19
 import com.reactnativenavigation.viewcontrollers.modal.ModalStack;
23
 import com.reactnativenavigation.viewcontrollers.stack.StackController;
20
 import com.reactnativenavigation.viewcontrollers.stack.StackController;
24
 
21
 
25
-import com.facebook.react.ReactInstanceManager;
26
-
27
 import java.util.Collection;
22
 import java.util.Collection;
28
 import java.util.Collections;
23
 import java.util.Collections;
29
 import java.util.List;
24
 import java.util.List;
30
 
25
 
26
+import androidx.annotation.NonNull;
27
+import androidx.annotation.Nullable;
28
+import androidx.annotation.RestrictTo;
29
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
30
+
31
 public class Navigator extends ParentController {
31
 public class Navigator extends ParentController {
32
 
32
 
33
     private final ModalStack modalStack;
33
     private final ModalStack modalStack;
34
     private final OverlayManager overlayManager;
34
     private final OverlayManager overlayManager;
35
     private final RootPresenter rootPresenter;
35
     private final RootPresenter rootPresenter;
36
     private ViewController root;
36
     private ViewController root;
37
+
37
     private ViewController previousRoot;
38
     private ViewController previousRoot;
38
-    private final FrameLayout rootLayout;
39
-    private final FrameLayout modalsLayout;
40
-    private final FrameLayout overlaysLayout;
39
+
40
+    private final CoordinatorLayout rootLayout;
41
+    private final CoordinatorLayout modalsLayout;
42
+    private final CoordinatorLayout overlaysLayout;
41
     private ViewGroup contentLayout;
43
     private ViewGroup contentLayout;
42
     private Options defaultOptions = new Options();
44
     private Options defaultOptions = new Options();
43
 
45
 
52
         return defaultOptions;
54
         return defaultOptions;
53
     }
55
     }
54
 
56
 
55
-    FrameLayout getRootLayout() {
57
+    CoordinatorLayout getRootLayout() {
56
         return rootLayout;
58
         return rootLayout;
57
     }
59
     }
58
 
60
 
72
         this.modalStack = modalStack;
74
         this.modalStack = modalStack;
73
         this.overlayManager = overlayManager;
75
         this.overlayManager = overlayManager;
74
         this.rootPresenter = rootPresenter;
76
         this.rootPresenter = rootPresenter;
75
-        rootLayout = new FrameLayout(getActivity());
76
-        modalsLayout = new FrameLayout(getActivity());
77
-        overlaysLayout = new FrameLayout(getActivity());
77
+        rootLayout = new CoordinatorLayout(getActivity());
78
+        modalsLayout = new CoordinatorLayout(getActivity());
79
+        overlaysLayout = new CoordinatorLayout(getActivity());
78
     }
80
     }
79
 
81
 
80
     public void bindViews() {
82
     public void bindViews() {
143
         rootPresenter.setRoot(root, defaultOptions, new CommandListenerAdapter(commandListener) {
145
         rootPresenter.setRoot(root, defaultOptions, new CommandListenerAdapter(commandListener) {
144
             @Override
146
             @Override
145
             public void onSuccess(String childId) {
147
             public void onSuccess(String childId) {
146
-                if (removeSplashView) removePreviousContentView();
148
+                if (removeSplashView) contentLayout.removeViewAt(0);
147
                 super.onSuccess(childId);
149
                 super.onSuccess(childId);
148
                 destroyPreviousRoot();
150
                 destroyPreviousRoot();
149
             }
151
             }
150
-
151
-            private void removePreviousContentView() {
152
-                contentLayout.removeViewAt(0);
153
-            }
154
         }, reactInstanceManager);
152
         }, reactInstanceManager);
155
     }
153
     }
156
 
154
 
241
     }
239
     }
242
 
240
 
243
     @RestrictTo(RestrictTo.Scope.TESTS)
241
     @RestrictTo(RestrictTo.Scope.TESTS)
244
-    FrameLayout getModalsLayout() {
242
+    CoordinatorLayout getModalsLayout() {
245
         return modalsLayout;
243
         return modalsLayout;
246
     }
244
     }
247
 }
245
 }

+ 53
- 52
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/sidemenu/SideMenuController.java View File

1
 package com.reactnativenavigation.viewcontrollers.sidemenu;
1
 package com.reactnativenavigation.viewcontrollers.sidemenu;
2
 
2
 
3
 import android.app.Activity;
3
 import android.app.Activity;
4
-import android.content.res.Resources;
5
-import android.support.annotation.NonNull;
6
-import android.support.v4.widget.DrawerLayout;
7
-import android.support.v4.widget.DrawerLayout.LayoutParams;
8
-import android.util.TypedValue;
9
 import android.view.Gravity;
4
 import android.view.Gravity;
10
 import android.view.View;
5
 import android.view.View;
11
 
6
 
12
 import com.reactnativenavigation.parse.Options;
7
 import com.reactnativenavigation.parse.Options;
13
-import com.reactnativenavigation.parse.SideMenuOptions;
14
 import com.reactnativenavigation.parse.params.Bool;
8
 import com.reactnativenavigation.parse.params.Bool;
15
 import com.reactnativenavigation.presentation.Presenter;
9
 import com.reactnativenavigation.presentation.Presenter;
16
 import com.reactnativenavigation.presentation.SideMenuPresenter;
10
 import com.reactnativenavigation.presentation.SideMenuPresenter;
18
 import com.reactnativenavigation.viewcontrollers.ChildControllersRegistry;
12
 import com.reactnativenavigation.viewcontrollers.ChildControllersRegistry;
19
 import com.reactnativenavigation.viewcontrollers.ParentController;
13
 import com.reactnativenavigation.viewcontrollers.ParentController;
20
 import com.reactnativenavigation.viewcontrollers.ViewController;
14
 import com.reactnativenavigation.viewcontrollers.ViewController;
21
-import com.reactnativenavigation.views.*;
15
+import com.reactnativenavigation.views.SideMenu;
16
+import com.reactnativenavigation.views.SideMenuRoot;
22
 
17
 
23
 import java.util.ArrayList;
18
 import java.util.ArrayList;
24
 import java.util.Collection;
19
 import java.util.Collection;
25
 
20
 
26
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
21
+import androidx.annotation.NonNull;
22
+import androidx.annotation.Nullable;
23
+import androidx.annotation.RestrictTo;
24
+import androidx.drawerlayout.widget.DrawerLayout;
25
+import androidx.drawerlayout.widget.DrawerLayout.LayoutParams;
27
 
26
 
28
-public class SideMenuController extends ParentController<DrawerLayout> implements DrawerLayout.DrawerListener {
27
+public class SideMenuController extends ParentController<SideMenuRoot> implements DrawerLayout.DrawerListener {
29
 
28
 
30
 	private ViewController center;
29
 	private ViewController center;
31
 	private ViewController left;
30
 	private ViewController left;
41
 
40
 
42
     @Override
41
     @Override
43
     protected ViewController getCurrentChild() {
42
     protected ViewController getCurrentChild() {
44
-	    if (getView().isDrawerOpen(Gravity.LEFT)) {
45
-            return left;
46
-        } else if (getView().isDrawerOpen(Gravity.RIGHT)) {
47
-            return right;
43
+        if (!isDestroyed()) {
44
+            if (getView().isDrawerOpen(Gravity.LEFT)) {
45
+                return left;
46
+            } else if (getView().isDrawerOpen(Gravity.RIGHT)) {
47
+                return right;
48
+            }
48
         }
49
         }
49
         return center;
50
         return center;
50
     }
51
     }
51
 
52
 
52
     @NonNull
53
     @NonNull
53
 	@Override
54
 	@Override
54
-	protected DrawerLayout createView() {
55
-        DrawerLayout sideMenu = new SideMenu(getActivity());
55
+	protected SideMenuRoot createView() {
56
+        SideMenu sideMenu = new SideMenu(getActivity());
56
         presenter.bindView(sideMenu);
57
         presenter.bindView(sideMenu);
57
         sideMenu.addDrawerListener(this);
58
         sideMenu.addDrawerListener(this);
58
-        return sideMenu;
59
+
60
+        SideMenuRoot root = new SideMenuRoot(getActivity());
61
+        root.addSideMenu(sideMenu, this);
62
+        return root;
59
 	}
63
 	}
60
 
64
 
61
     @Override
65
     @Override
74
 	}
78
 	}
75
 
79
 
76
     @Override
80
     @Override
77
-    public void applyChildOptions(Options options, Component child) {
81
+    public void applyChildOptions(Options options, ViewController child) {
78
         super.applyChildOptions(options, child);
82
         super.applyChildOptions(options, child);
79
         presenter.applyChildOptions(resolveCurrentOptions());
83
         presenter.applyChildOptions(resolveCurrentOptions());
80
         performOnParentController(parentController ->
84
         performOnParentController(parentController ->
83
     }
87
     }
84
 
88
 
85
     @Override
89
     @Override
86
-    public void mergeChildOptions(Options options, ViewController childController, Component child) {
87
-        super.mergeChildOptions(options, childController, child);
90
+    public void mergeChildOptions(Options options, ViewController child) {
91
+        super.mergeChildOptions(options, child);
88
         presenter.mergeChildOptions(options.sideMenuRootOptions);
92
         presenter.mergeChildOptions(options.sideMenuRootOptions);
89
         performOnParentController(parentController ->
93
         performOnParentController(parentController ->
90
-                ((ParentController) parentController).mergeChildOptions(options.copy().clearSideMenuOptions(), childController, child)
94
+                ((ParentController) parentController).mergeChildOptions(options.copy().clearSideMenuOptions(), child)
91
         );
95
         );
92
     }
96
     }
93
 
97
 
98
+    @Override
99
+    public void onViewAppeared() {
100
+        super.onViewAppeared();
101
+        if (left != null) left.performOnView(view -> ((View) view).requestLayout());
102
+        if (right != null) right.performOnView(view -> ((View) view).requestLayout());
103
+    }
104
+
94
     @Override
105
     @Override
95
     public void mergeOptions(Options options) {
106
     public void mergeOptions(Options options) {
96
         super.mergeOptions(options);
107
         super.mergeOptions(options);
100
     @Override
111
     @Override
101
     public Options resolveCurrentOptions() {
112
     public Options resolveCurrentOptions() {
102
         Options options = super.resolveCurrentOptions();
113
         Options options = super.resolveCurrentOptions();
103
-        if (getView().isDrawerOpen(Gravity.LEFT) || getView().isDrawerOpen(Gravity.RIGHT)) {
114
+        if (isDrawerOpen(Gravity.LEFT) || isDrawerOpen(Gravity.RIGHT)) {
104
             options = options.mergeWith(center.resolveCurrentOptions());
115
             options = options.mergeWith(center.resolveCurrentOptions());
105
         }
116
         }
106
         return options;
117
         return options;
107
     }
118
     }
108
 
119
 
109
-    //For onDrawerOpened and onDrawerClosed :
110
-    //Merge the options to the current state, if this happened due to a gesture we need to
111
-    //update the option state
120
+    public boolean isDrawerOpen(int gravity) {
121
+        return !isDestroyed() && getView().isDrawerOpen(gravity);
122
+    }
112
 
123
 
113
     @Override
124
     @Override
114
     public void onDrawerOpened(@NonNull View drawerView) {
125
     public void onDrawerOpened(@NonNull View drawerView) {
144
         return presenter.handleBack() || center.handleBack(listener) || super.handleBack(listener);
155
         return presenter.handleBack() || center.handleBack(listener) || super.handleBack(listener);
145
     }
156
     }
146
 
157
 
158
+    @Nullable
159
+    @Override
160
+    public ViewController findController(View child) {
161
+        return getView().isSideMenu(child) ? this : super.findController(child);
162
+    }
163
+
147
     public void setCenterController(ViewController centerController) {
164
     public void setCenterController(ViewController centerController) {
148
-		this.center = centerController;
149
-		View childView = centerController.getView();
150
-		getView().addView(childView);
165
+		center = centerController;
166
+        getView().setCenter(center);
151
 	}
167
 	}
152
 
168
 
153
     public void setLeftController(ViewController controller) {
169
     public void setLeftController(ViewController controller) {
154
-        this.left = controller;
155
-        int height = getHeight(options.sideMenuRootOptions.left);
156
-        int width = getWidth(options.sideMenuRootOptions.left);
157
-        getView().addView(controller.getView(), new LayoutParams(width, height, Gravity.LEFT));
170
+        left = controller;
171
+        getView().setLeft(left, options);
158
     }
172
     }
159
 
173
 
160
     public void setRightController(ViewController controller) {
174
     public void setRightController(ViewController controller) {
161
-        this.right = controller;
162
-        int height = getHeight(options.sideMenuRootOptions.right);
163
-        int width = getWidth(options.sideMenuRootOptions.right);
164
-        getView().addView(controller.getView(), new LayoutParams(width, height, Gravity.RIGHT));
165
-    }
166
-
167
-    private int getWidth(SideMenuOptions sideMenuOptions) {
168
-        int width = MATCH_PARENT;
169
-        if (sideMenuOptions.width.hasValue()) {
170
-            width = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, sideMenuOptions.width.get(), Resources.getSystem().getDisplayMetrics());
171
-        }
172
-        return width;
173
-    }
174
-
175
-    private int getHeight(SideMenuOptions sideMenuOptions) {
176
-        int height = MATCH_PARENT;
177
-        if (sideMenuOptions.height.hasValue()) {
178
-            height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, sideMenuOptions.height.get(), Resources.getSystem().getDisplayMetrics());
179
-        }
180
-        return height;
175
+        right = controller;
176
+        getView().setRight(right, options);
181
     }
177
     }
182
 
178
 
183
     private ViewController getMatchingView (View drawerView) {
179
     private ViewController getMatchingView (View drawerView) {
203
     }
199
     }
204
 
200
 
205
     private void dispatchSideMenuVisibilityEvents(ViewController drawer, float prevOffset, float offset) {
201
     private void dispatchSideMenuVisibilityEvents(ViewController drawer, float prevOffset, float offset) {
206
-        if (prevOffset == 0 && offset> 0) {
202
+        if (prevOffset == 0 && offset > 0) {
207
             drawer.onViewAppeared();
203
             drawer.onViewAppeared();
208
         } else if (prevOffset > 0 && offset == 0) {
204
         } else if (prevOffset > 0 && offset == 0) {
209
             drawer.onViewDisappear();
205
             drawer.onViewDisappear();
210
         }
206
         }
211
     }
207
     }
208
+
209
+    @RestrictTo(RestrictTo.Scope.TESTS)
210
+    SideMenu getSideMenu() {
211
+        return presenter.getSideMenu();
212
+    }
212
 }
213
 }

+ 7
- 7
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/BackButtonHelper.java View File

5
 import com.reactnativenavigation.viewcontrollers.ViewController;
5
 import com.reactnativenavigation.viewcontrollers.ViewController;
6
 
6
 
7
 public class BackButtonHelper {
7
 public class BackButtonHelper {
8
-    public void addToPushedChild(ViewController child) {
9
-        if (child.options.topBar.buttons.left != null || child.options.topBar.buttons.back.visible.isFalse()) return;
10
-        Options options = new Options();
11
-        options.topBar.buttons.back.setVisible();
12
-        child.mergeOptions(options);
13
-    }
14
-
15
     public void clear(ViewController child) {
8
     public void clear(ViewController child) {
16
         if (!child.options.topBar.buttons.back.hasValue()) {
9
         if (!child.options.topBar.buttons.back.hasValue()) {
17
             child.options.topBar.buttons.back.visible = new Bool(false);
10
             child.options.topBar.buttons.back.visible = new Bool(false);
18
         }
11
         }
19
     }
12
     }
13
+
14
+    void addToPushedChild(ViewController child) {
15
+        if (child.options.topBar.buttons.left != null || child.options.topBar.buttons.back.visible.isFalse()) return;
16
+        Options options = new Options();
17
+        options.topBar.buttons.back.setVisible();
18
+        child.mergeOptions(options);
19
+    }
20
 }
20
 }

+ 41
- 33
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/StackController.java View File

1
 package com.reactnativenavigation.viewcontrollers.stack;
1
 package com.reactnativenavigation.viewcontrollers.stack;
2
 
2
 
3
 import android.app.Activity;
3
 import android.app.Activity;
4
-import android.support.annotation.NonNull;
5
-import android.support.annotation.RestrictTo;
6
-import android.support.annotation.VisibleForTesting;
7
-import android.support.v4.view.ViewPager;
8
 import android.view.View;
4
 import android.view.View;
9
 import android.view.ViewGroup;
5
 import android.view.ViewGroup;
10
-import android.widget.RelativeLayout;
11
 
6
 
12
 import com.reactnativenavigation.anim.NavigationAnimator;
7
 import com.reactnativenavigation.anim.NavigationAnimator;
13
 import com.reactnativenavigation.parse.Options;
8
 import com.reactnativenavigation.parse.Options;
16
 import com.reactnativenavigation.react.Constants;
11
 import com.reactnativenavigation.react.Constants;
17
 import com.reactnativenavigation.utils.CommandListener;
12
 import com.reactnativenavigation.utils.CommandListener;
18
 import com.reactnativenavigation.utils.CommandListenerAdapter;
13
 import com.reactnativenavigation.utils.CommandListenerAdapter;
14
+import com.reactnativenavigation.utils.CompatUtils;
19
 import com.reactnativenavigation.viewcontrollers.ChildControllersRegistry;
15
 import com.reactnativenavigation.viewcontrollers.ChildControllersRegistry;
20
 import com.reactnativenavigation.viewcontrollers.IdStack;
16
 import com.reactnativenavigation.viewcontrollers.IdStack;
21
 import com.reactnativenavigation.viewcontrollers.ParentController;
17
 import com.reactnativenavigation.viewcontrollers.ParentController;
24
 import com.reactnativenavigation.views.Component;
20
 import com.reactnativenavigation.views.Component;
25
 import com.reactnativenavigation.views.ReactComponent;
21
 import com.reactnativenavigation.views.ReactComponent;
26
 import com.reactnativenavigation.views.StackLayout;
22
 import com.reactnativenavigation.views.StackLayout;
23
+import com.reactnativenavigation.views.stack.StackBehaviour;
27
 import com.reactnativenavigation.views.topbar.TopBar;
24
 import com.reactnativenavigation.views.topbar.TopBar;
28
 
25
 
29
 import java.util.Collection;
26
 import java.util.Collection;
30
 import java.util.Iterator;
27
 import java.util.Iterator;
31
 import java.util.List;
28
 import java.util.List;
32
 
29
 
33
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
30
+import androidx.annotation.NonNull;
31
+import androidx.annotation.RestrictTo;
32
+import androidx.annotation.VisibleForTesting;
33
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
34
+import androidx.viewpager.widget.ViewPager;
35
+
34
 import static com.reactnativenavigation.utils.CollectionUtils.*;
36
 import static com.reactnativenavigation.utils.CollectionUtils.*;
37
+import static com.reactnativenavigation.utils.CoordinatorLayoutUtils.matchParentWithBehaviour;
38
+import static com.reactnativenavigation.utils.ObjectUtils.perform;
35
 
39
 
36
 public class StackController extends ParentController<StackLayout> {
40
 public class StackController extends ParentController<StackLayout> {
37
 
41
 
49
         this.presenter = stackPresenter;
53
         this.presenter = stackPresenter;
50
         stackPresenter.setButtonOnClickListener(this::onNavigationButtonPressed);
54
         stackPresenter.setButtonOnClickListener(this::onNavigationButtonPressed);
51
         for (ViewController child : children) {
55
         for (ViewController child : children) {
52
-            stack.push(child.getId(), child);
53
             child.setParentController(this);
56
             child.setParentController(this);
57
+            stack.push(child.getId(), child);
54
             if (size() > 1) backButtonHelper.addToPushedChild(child);
58
             if (size() > 1) backButtonHelper.addToPushedChild(child);
55
         }
59
         }
56
     }
60
     }
61
         if (getCurrentChild().isDestroyed()) return false;
65
         if (getCurrentChild().isDestroyed()) return false;
62
         ViewGroup currentChild = getCurrentChild().getView();
66
         ViewGroup currentChild = getCurrentChild().getView();
63
         if (currentChild instanceof Component) {
67
         if (currentChild instanceof Component) {
64
-            return super.isRendered() && presenter.isRendered((Component) currentChild);
68
+            return super.isRendered() && presenter.isRendered(currentChild);
65
         }
69
         }
66
         return super.isRendered();
70
         return super.isRendered();
67
     }
71
     }
80
     @Override
84
     @Override
81
     public void onAttachToParent() {
85
     public void onAttachToParent() {
82
         if (!isEmpty() && !getCurrentChild().isDestroyed() && !isViewShown()) {
86
         if (!isEmpty() && !getCurrentChild().isDestroyed() && !isViewShown()) {
83
-            presenter.applyChildOptions(resolveCurrentOptions(), (Component) getCurrentChild().getView());
87
+            presenter.applyChildOptions(resolveCurrentOptions(), this, getCurrentChild());
84
         }
88
         }
85
     }
89
     }
86
 
90
 
87
     @Override
91
     @Override
88
     public void mergeOptions(Options options) {
92
     public void mergeOptions(Options options) {
89
-        presenter.mergeOptions(options, (Component) getCurrentChild().getView());
93
+        presenter.mergeOptions(options, this, getCurrentChild());
90
         super.mergeOptions(options);
94
         super.mergeOptions(options);
91
     }
95
     }
92
 
96
 
93
     @Override
97
     @Override
94
-    public void applyChildOptions(Options options, Component child) {
98
+    public void applyChildOptions(Options options, ViewController child) {
95
         super.applyChildOptions(options, child);
99
         super.applyChildOptions(options, child);
96
-        presenter.applyChildOptions(resolveCurrentOptions(), child);
97
-        if (child instanceof ReactComponent) {
98
-            fabOptionsPresenter.applyOptions(this.options.fabOptions, (ReactComponent) child, getView());
100
+        presenter.applyChildOptions(resolveCurrentOptions(), this, child);
101
+        if (child.getView() instanceof ReactComponent) {
102
+            fabOptionsPresenter.applyOptions(this.options.fabOptions, (ReactComponent) child.getView(), getView());
99
         }
103
         }
100
         performOnParentController(parentController ->
104
         performOnParentController(parentController ->
101
                 ((ParentController) parentController).applyChildOptions(
105
                 ((ParentController) parentController).applyChildOptions(
111
     }
115
     }
112
 
116
 
113
     @Override
117
     @Override
114
-    public void mergeChildOptions(Options options, ViewController childController, Component child) {
115
-        super.mergeChildOptions(options, childController, child);
116
-        if (childController.isViewShown() && peek() == childController) {
117
-            presenter.mergeChildOptions(options, resolveCurrentOptions(), child);
118
+    public void mergeChildOptions(Options options, ViewController child) {
119
+        super.mergeChildOptions(options, child);
120
+        if (child.isViewShown() && peek() == child) {
121
+            presenter.mergeChildOptions(options, resolveCurrentOptions(), this, child);
118
             if (options.fabOptions.hasValue() && child instanceof ReactComponent) {
122
             if (options.fabOptions.hasValue() && child instanceof ReactComponent) {
119
                 fabOptionsPresenter.mergeOptions(options.fabOptions, (ReactComponent) child, getView());
123
                 fabOptionsPresenter.mergeOptions(options.fabOptions, (ReactComponent) child, getView());
120
             }
124
             }
127
                                 .clearFabOptions()
131
                                 .clearFabOptions()
128
                                 .clearTopTabOptions()
132
                                 .clearTopTabOptions()
129
                                 .clearTopTabsOptions(),
133
                                 .clearTopTabsOptions(),
130
-                        childController,
131
                         child
134
                         child
132
                 )
135
                 )
133
         );
136
         );
134
     }
137
     }
135
 
138
 
136
     @Override
139
     @Override
137
-    public void onChildDestroyed(Component child) {
140
+    public void onChildDestroyed(ViewController child) {
138
         super.onChildDestroyed(child);
141
         super.onChildDestroyed(child);
139
         presenter.onChildDestroyed(child);
142
         presenter.onChildDestroyed(child);
140
     }
143
     }
173
     }
176
     }
174
 
177
 
175
     private void addChildToStack(ViewController child, View view, Options resolvedOptions) {
178
     private void addChildToStack(ViewController child, View view, Options resolvedOptions) {
176
-        view.setLayoutParams(new RelativeLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
177
         child.setWaitForRender(resolvedOptions.animations.push.waitForRender);
179
         child.setWaitForRender(resolvedOptions.animations.push.waitForRender);
178
-        presenter.applyLayoutParamsOptions(resolvedOptions, view);
179
         if (size() == 1) presenter.applyInitialChildLayoutOptions(resolvedOptions);
180
         if (size() == 1) presenter.applyInitialChildLayoutOptions(resolvedOptions);
180
-        getView().addView(view, getView().getChildCount() - 1);
181
+        getView().addView(view, getView().getChildCount() - 1, matchParentWithBehaviour(new StackBehaviour(this)));
181
     }
182
     }
182
 
183
 
183
     public void setRoot(List<ViewController> children, CommandListener listener) {
184
     public void setRoot(List<ViewController> children, CommandListener listener) {
235
         disappearing.onViewWillDisappear();
236
         disappearing.onViewWillDisappear();
236
         appearing.onViewWillAppear();
237
         appearing.onViewWillAppear();
237
 
238
 
238
-        Options resolvedOptions = resolveCurrentOptions();
239
         ViewGroup appearingView = appearing.getView();
239
         ViewGroup appearingView = appearing.getView();
240
         if (appearingView.getLayoutParams() == null) {
240
         if (appearingView.getLayoutParams() == null) {
241
-            appearingView.setLayoutParams(new RelativeLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
242
-            presenter.applyLayoutParamsOptions(resolvedOptions, appearingView);
241
+            appearingView.setLayoutParams(matchParentWithBehaviour(new StackBehaviour(this)));
243
         }
242
         }
244
         if (appearingView.getParent() == null) {
243
         if (appearingView.getParent() == null) {
245
             getView().addView(appearingView, 0);
244
             getView().addView(appearingView, 0);
246
         }
245
         }
247
-        presenter.onChildWillAppear(appearing.options, disappearing.options);
246
+        presenter.onChildWillAppear(this, appearing, disappearing);
248
         if (disappearingOptions.animations.pop.enabled.isTrueOrUndefined()) {
247
         if (disappearingOptions.animations.pop.enabled.isTrueOrUndefined()) {
249
             animator.pop(disappearing.getView(), disappearingOptions.animations.pop, () -> finishPopping(disappearing, listener));
248
             animator.pop(disappearing.getView(), disappearingOptions.animations.pop, () -> finishPopping(disappearing, listener));
250
         } else {
249
         } else {
329
     @Override
328
     @Override
330
     protected StackLayout createView() {
329
     protected StackLayout createView() {
331
         StackLayout stackLayout = new StackLayout(getActivity(), topBarController, getId());
330
         StackLayout stackLayout = new StackLayout(getActivity(), topBarController, getId());
332
-        presenter.bindView(topBarController.getView());
331
+        presenter.bindView(topBarController);
333
         addInitialChild(stackLayout);
332
         addInitialChild(stackLayout);
334
         return stackLayout;
333
         return stackLayout;
335
     }
334
     }
337
     private void addInitialChild(StackLayout stackLayout) {
336
     private void addInitialChild(StackLayout stackLayout) {
338
         if (isEmpty()) return;
337
         if (isEmpty()) return;
339
         ViewGroup child = peek().getView();
338
         ViewGroup child = peek().getView();
340
-        child.setLayoutParams(new RelativeLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
341
-        Options options = resolveCurrentOptions();
342
-        presenter.applyLayoutParamsOptions(options, child);
343
-        presenter.applyInitialChildLayoutOptions(options);
344
-        stackLayout.addView(child, 0);
339
+        child.setId(CompatUtils.generateViewId());
340
+        presenter.applyInitialChildLayoutOptions(resolveCurrentOptions());
341
+        stackLayout.addView(child, 0, matchParentWithBehaviour(new StackBehaviour(this)));
345
     }
342
     }
346
 
343
 
347
     private void onNavigationButtonPressed(String buttonId) {
344
     private void onNavigationButtonPressed(String buttonId) {
373
         topBarController.clearTopTabs();
370
         topBarController.clearTopTabs();
374
     }
371
     }
375
 
372
 
373
+    @Override
374
+    public boolean onDependentViewChanged(CoordinatorLayout parent, ViewGroup child, View dependency) {
375
+        perform(findController(child), controller -> presenter.applyTopInsets(this, controller));
376
+        return false;
377
+    }
378
+
379
+    @Override
380
+    public int getTopInset(ViewController child) {
381
+        return resolveChildOptions(child).topBar.isHiddenOrDrawBehind() ? 0 : topBarController.getHeight();
382
+    }
383
+
376
     @RestrictTo(RestrictTo.Scope.TESTS)
384
     @RestrictTo(RestrictTo.Scope.TESTS)
377
     public TopBar getTopBar() {
385
     public TopBar getTopBar() {
378
         return topBarController.getView();
386
         return topBarController.getView();

+ 3
- 1
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/StackControllerBuilder.java View File

11
 import com.reactnativenavigation.viewcontrollers.topbar.TopBarController;
11
 import com.reactnativenavigation.viewcontrollers.topbar.TopBarController;
12
 import com.reactnativenavigation.views.element.ElementTransitionManager;
12
 import com.reactnativenavigation.views.element.ElementTransitionManager;
13
 
13
 
14
-import java.util.*;
14
+import java.util.ArrayList;
15
+import java.util.Arrays;
16
+import java.util.List;
15
 
17
 
16
 public class StackControllerBuilder {
18
 public class StackControllerBuilder {
17
     private Activity activity;
19
     private Activity activity;

+ 66
- 8
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/topbar/TopBarController.java View File

1
 package com.reactnativenavigation.viewcontrollers.topbar;
1
 package com.reactnativenavigation.viewcontrollers.topbar;
2
 
2
 
3
 import android.content.Context;
3
 import android.content.Context;
4
-import android.support.v4.view.ViewPager;
5
 import android.view.View;
4
 import android.view.View;
6
 
5
 
6
+import com.reactnativenavigation.anim.TopBarAnimator;
7
+import com.reactnativenavigation.parse.AnimationOptions;
7
 import com.reactnativenavigation.utils.CompatUtils;
8
 import com.reactnativenavigation.utils.CompatUtils;
8
 import com.reactnativenavigation.views.StackLayout;
9
 import com.reactnativenavigation.views.StackLayout;
9
 import com.reactnativenavigation.views.topbar.TopBar;
10
 import com.reactnativenavigation.views.topbar.TopBar;
10
 
11
 
12
+import androidx.annotation.VisibleForTesting;
13
+import androidx.viewpager.widget.ViewPager;
14
+
15
+import static com.reactnativenavigation.utils.ObjectUtils.perform;
16
+import static com.reactnativenavigation.utils.ViewUtils.isVisible;
17
+
11
 
18
 
12
 public class TopBarController {
19
 public class TopBarController {
13
     private TopBar topBar;
20
     private TopBar topBar;
21
+    private TopBarAnimator animator;
22
+
23
+    public TopBarController() {
24
+        animator = new TopBarAnimator();
25
+    }
26
+
27
+    public TopBar getView() {
28
+        return topBar;
29
+    }
14
 
30
 
15
-    public View createView(Context context, StackLayout stackLayout) {
31
+    public int getHeight() {
32
+        return perform(topBar, 0, View::getHeight);
33
+    }
34
+
35
+    @VisibleForTesting
36
+    public void setAnimator(TopBarAnimator animator) {
37
+        this.animator = animator;
38
+    }
39
+
40
+    public TopBar createView(Context context, StackLayout parent) {
16
         if (topBar == null) {
41
         if (topBar == null) {
17
-            topBar = createTopBar(context, stackLayout);
42
+            topBar = createTopBar(context, parent);
18
             topBar.setId(CompatUtils.generateViewId());
43
             topBar.setId(CompatUtils.generateViewId());
44
+            animator.bindView(topBar, parent);
19
         }
45
         }
20
         return topBar;
46
         return topBar;
21
     }
47
     }
22
 
48
 
23
     protected TopBar createTopBar(Context context, StackLayout stackLayout) {
49
     protected TopBar createTopBar(Context context, StackLayout stackLayout) {
24
-        return new TopBar(context, stackLayout);
25
-    }
26
-
27
-    public TopBar getView() {
28
-        return topBar;
50
+        return new TopBar(context);
29
     }
51
     }
30
 
52
 
31
     public void initTopTabs(ViewPager viewPager) {
53
     public void initTopTabs(ViewPager viewPager) {
35
     public void clearTopTabs() {
57
     public void clearTopTabs() {
36
         topBar.clearTopTabs();
58
         topBar.clearTopTabs();
37
     }
59
     }
60
+
61
+    public void show() {
62
+        if (isVisible(topBar) || animator.isAnimatingShow()) return;
63
+        topBar.setVisibility(View.VISIBLE);
64
+    }
65
+
66
+    public void showAnimate(AnimationOptions options, int translationDy) {
67
+        if (isVisible(topBar) || animator.isAnimatingShow()) return;
68
+        animator.show(options, translationDy);
69
+    }
70
+
71
+    public void hide() {
72
+        if (!animator.isAnimatingHide()) {
73
+            topBar.setVisibility(View.GONE);
74
+        }
75
+    }
76
+
77
+    public void hideAnimate(AnimationOptions options, float translationStart, float translationEnd) {
78
+        hideAnimate(options, () -> {}, translationStart, translationEnd);
79
+    }
80
+
81
+    private void hideAnimate(AnimationOptions options, Runnable onAnimationEnd, float translationStart, float translationEnd) {
82
+        if (!isVisible(topBar)) return;
83
+        animator.hide(options, onAnimationEnd, translationStart, translationEnd);
84
+    }
85
+
86
+    public void resetViewProperties() {
87
+        topBar.setTranslationY(0);
88
+        topBar.setTranslationX(0);
89
+        topBar.setAlpha(1);
90
+        topBar.setScaleY(1);
91
+        topBar.setScaleX(1);
92
+        topBar.setRotationX(0);
93
+        topBar.setRotationY(0);
94
+        topBar.setRotation(0);
95
+    }
38
 }
96
 }

+ 2
- 2
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabsAdapter.java View File

1
 package com.reactnativenavigation.viewcontrollers.toptabs;
1
 package com.reactnativenavigation.viewcontrollers.toptabs;
2
 
2
 
3
-import android.support.v4.view.PagerAdapter;
4
-import android.support.v4.view.ViewPager;
3
+import androidx.viewpager.widget.PagerAdapter;
4
+import androidx.viewpager.widget.ViewPager;
5
 import android.view.View;
5
 import android.view.View;
6
 import android.view.ViewGroup;
6
 import android.view.ViewGroup;
7
 
7
 

+ 5
- 6
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabsController.java View File

1
 package com.reactnativenavigation.viewcontrollers.toptabs;
1
 package com.reactnativenavigation.viewcontrollers.toptabs;
2
 
2
 
3
 import android.app.Activity;
3
 import android.app.Activity;
4
-import android.support.annotation.CallSuper;
5
-import android.support.annotation.NonNull;
4
+import androidx.annotation.CallSuper;
5
+import androidx.annotation.NonNull;
6
 import android.view.View;
6
 import android.view.View;
7
 
7
 
8
 import com.reactnativenavigation.parse.Options;
8
 import com.reactnativenavigation.parse.Options;
12
 import com.reactnativenavigation.viewcontrollers.ParentController;
12
 import com.reactnativenavigation.viewcontrollers.ParentController;
13
 import com.reactnativenavigation.viewcontrollers.ViewController;
13
 import com.reactnativenavigation.viewcontrollers.ViewController;
14
 import com.reactnativenavigation.viewcontrollers.ViewVisibilityListenerAdapter;
14
 import com.reactnativenavigation.viewcontrollers.ViewVisibilityListenerAdapter;
15
-import com.reactnativenavigation.views.Component;
16
 import com.reactnativenavigation.views.toptabs.TopTabsLayoutCreator;
15
 import com.reactnativenavigation.views.toptabs.TopTabsLayoutCreator;
17
 import com.reactnativenavigation.views.toptabs.TopTabsViewPager;
16
 import com.reactnativenavigation.views.toptabs.TopTabsViewPager;
18
 
17
 
88
     }
87
     }
89
 
88
 
90
     @Override
89
     @Override
91
-    public void applyChildOptions(Options options, Component child) {
90
+    public void applyChildOptions(Options options, ViewController child) {
92
         super.applyChildOptions(options, child);
91
         super.applyChildOptions(options, child);
93
         performOnParentController(parentController -> ((ParentController) parentController).applyChildOptions(this.options.copy(), child));
92
         performOnParentController(parentController -> ((ParentController) parentController).applyChildOptions(this.options.copy(), child));
94
     }
93
     }
95
 
94
 
96
     @CallSuper
95
     @CallSuper
97
-    public void mergeChildOptions(Options options, ViewController childController, Component child) {
98
-        super.mergeChildOptions(options, childController, child);
96
+    public void mergeChildOptions(Options options, ViewController child) {
97
+        super.mergeChildOptions(options, child);
99
         performOnParentController(parentController -> ((ParentController) parentController).applyChildOptions(options.copy(), child));
98
         performOnParentController(parentController -> ((ParentController) parentController).applyChildOptions(options.copy(), child));
100
     }
99
     }
101
 
100
 

+ 19
- 0
lib/android/app/src/main/java/com/reactnativenavigation/views/BehaviourAdapter.java View File

1
+package com.reactnativenavigation.views;
2
+
3
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
4
+import android.view.View;
5
+import android.view.ViewGroup;
6
+
7
+public interface BehaviourAdapter<V extends ViewGroup> {
8
+    /**
9
+     * @see CoordinatorLayout.Behavior#onMeasureChild
10
+     * @return true if the Behavior measured the child view, false if the CoordinatorLayout should perform its default measurement
11
+     */
12
+    boolean onMeasureChild(CoordinatorLayout parent, V child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed);
13
+
14
+    /**
15
+     * @see CoordinatorLayout.Behavior#onDependentViewChanged
16
+     * @return true if the Behavior changed the child view's size or position, false otherwise
17
+     */
18
+    boolean onDependentViewChanged(CoordinatorLayout parent, V child, View dependency);
19
+}

+ 24
- 0
lib/android/app/src/main/java/com/reactnativenavigation/views/BehaviourDelegate.java View File

1
+package com.reactnativenavigation.views;
2
+
3
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
4
+import android.view.View;
5
+import android.view.ViewGroup;
6
+
7
+public class BehaviourDelegate<V extends ViewGroup> extends CoordinatorLayout.Behavior<V> {
8
+
9
+    private BehaviourAdapter delegate;
10
+
11
+    public BehaviourDelegate(BehaviourAdapter<V> delegate) {
12
+        this.delegate = delegate;
13
+    }
14
+
15
+    @Override
16
+    public boolean onDependentViewChanged(CoordinatorLayout parent, V child, View dependency) {
17
+        return delegate.onDependentViewChanged(parent, child, dependency);
18
+    }
19
+
20
+    @Override
21
+    public boolean onMeasureChild(CoordinatorLayout parent, V child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) {
22
+        return delegate.onMeasureChild(parent, child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed);
23
+    }
24
+}

+ 10
- 11
lib/android/app/src/main/java/com/reactnativenavigation/views/BottomTabs.java View File

3
 import android.annotation.SuppressLint;
3
 import android.annotation.SuppressLint;
4
 import android.content.Context;
4
 import android.content.Context;
5
 import android.graphics.drawable.Drawable;
5
 import android.graphics.drawable.Drawable;
6
-import android.support.annotation.IntRange;
7
 import android.widget.LinearLayout;
6
 import android.widget.LinearLayout;
8
 
7
 
9
 import com.aurelhubert.ahbottomnavigation.AHBottomNavigation;
8
 import com.aurelhubert.ahbottomnavigation.AHBottomNavigation;
10
 import com.aurelhubert.ahbottomnavigation.AHBottomNavigationItem;
9
 import com.aurelhubert.ahbottomnavigation.AHBottomNavigationItem;
10
+import com.reactnativenavigation.BuildConfig;
11
+import com.reactnativenavigation.R;
11
 import com.reactnativenavigation.parse.LayoutDirection;
12
 import com.reactnativenavigation.parse.LayoutDirection;
12
-import com.reactnativenavigation.utils.CompatUtils;
13
+
14
+import androidx.annotation.IntRange;
13
 
15
 
14
 import static com.reactnativenavigation.utils.ViewUtils.findChildByClass;
16
 import static com.reactnativenavigation.utils.ViewUtils.findChildByClass;
15
 
17
 
18
     private boolean itemsCreationEnabled = true;
20
     private boolean itemsCreationEnabled = true;
19
     private boolean shouldCreateItems = true;
21
     private boolean shouldCreateItems = true;
20
 
22
 
23
+    public BottomTabs(Context context) {
24
+        super(context);
25
+        setId(R.id.bottomTabs);
26
+        if (BuildConfig.DEBUG) setContentDescription("BottomTabs");
27
+    }
28
+
21
     public void disableItemsCreation() {
29
     public void disableItemsCreation() {
22
         itemsCreationEnabled = false;
30
         itemsCreationEnabled = false;
23
     }
31
     }
27
         if (shouldCreateItems) createItems();
35
         if (shouldCreateItems) createItems();
28
     }
36
     }
29
 
37
 
30
-    public BottomTabs(Context context) {
31
-        super(context);
32
-        setId(CompatUtils.generateViewId());
33
-    }
34
-
35
     @Override
38
     @Override
36
     protected void createItems() {
39
     protected void createItems() {
37
         if (itemsCreationEnabled) {
40
         if (itemsCreationEnabled) {
50
         super.createItems();
53
         super.createItems();
51
     }
54
     }
52
 
55
 
53
-    public void setBadge(int bottomTabIndex, String badge) {
54
-        setNotification(badge, bottomTabIndex);
55
-    }
56
-
57
     @Override
56
     @Override
58
     public void setCurrentItem(@IntRange(from = 0) int position) {
57
     public void setCurrentItem(@IntRange(from = 0) int position) {
59
         super.setCurrentItem(position);
58
         super.setCurrentItem(position);

+ 0
- 4
lib/android/app/src/main/java/com/reactnativenavigation/views/Component.java View File

1
 package com.reactnativenavigation.views;
1
 package com.reactnativenavigation.views;
2
 
2
 
3
-import com.reactnativenavigation.views.topbar.TopBar;
4
-
5
 public interface Component extends Renderable {
3
 public interface Component extends Renderable {
6
-    void drawBehindTopBar();
7
 
4
 
8
-    void drawBelowTopBar(TopBar topBar);
9
 }
5
 }

+ 5
- 31
lib/android/app/src/main/java/com/reactnativenavigation/views/ComponentLayout.java View File

4
 import android.content.Context;
4
 import android.content.Context;
5
 import android.view.MotionEvent;
5
 import android.view.MotionEvent;
6
 import android.view.View;
6
 import android.view.View;
7
-import android.widget.FrameLayout;
8
-import android.widget.RelativeLayout;
9
 
7
 
10
 import com.reactnativenavigation.interfaces.ScrollEventListener;
8
 import com.reactnativenavigation.interfaces.ScrollEventListener;
11
 import com.reactnativenavigation.parse.Options;
9
 import com.reactnativenavigation.parse.Options;
12
 import com.reactnativenavigation.parse.params.Bool;
10
 import com.reactnativenavigation.parse.params.Bool;
13
-import com.reactnativenavigation.utils.ViewUtils;
14
 import com.reactnativenavigation.viewcontrollers.IReactView;
11
 import com.reactnativenavigation.viewcontrollers.IReactView;
15
 import com.reactnativenavigation.viewcontrollers.TitleBarButtonController;
12
 import com.reactnativenavigation.viewcontrollers.TitleBarButtonController;
16
 import com.reactnativenavigation.views.element.Element;
13
 import com.reactnativenavigation.views.element.Element;
17
-import com.reactnativenavigation.views.topbar.TopBar;
18
 import com.reactnativenavigation.views.touch.OverlayTouchDelegate;
14
 import com.reactnativenavigation.views.touch.OverlayTouchDelegate;
19
 
15
 
20
 import java.util.List;
16
 import java.util.List;
21
 
17
 
22
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
18
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
19
+
20
+import static com.reactnativenavigation.utils.CoordinatorLayoutUtils.matchParentLP;
23
 
21
 
24
 @SuppressLint("ViewConstructor")
22
 @SuppressLint("ViewConstructor")
25
-public class ComponentLayout extends FrameLayout implements ReactComponent, TitleBarButtonController.OnClickListener {
23
+public class ComponentLayout extends CoordinatorLayout implements ReactComponent, TitleBarButtonController.OnClickListener {
26
 
24
 
27
     private IReactView reactView;
25
     private IReactView reactView;
28
     private final OverlayTouchDelegate touchDelegate;
26
     private final OverlayTouchDelegate touchDelegate;
30
     public ComponentLayout(Context context, IReactView reactView) {
28
     public ComponentLayout(Context context, IReactView reactView) {
31
 		super(context);
29
 		super(context);
32
 		this.reactView = reactView;
30
 		this.reactView = reactView;
33
-        addView(reactView.asView(), MATCH_PARENT, MATCH_PARENT);
31
+        addView(reactView.asView(), matchParentLP());
34
         touchDelegate = new OverlayTouchDelegate(reactView);
32
         touchDelegate = new OverlayTouchDelegate(reactView);
35
     }
33
     }
36
 
34
 
82
         reactView.dispatchTouchEventToJs(event);
80
         reactView.dispatchTouchEventToJs(event);
83
     }
81
     }
84
 
82
 
85
-    @Override
86
-    public void drawBehindTopBar() {
87
-        if (getLayoutParams() instanceof RelativeLayout.LayoutParams) {
88
-            RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) getLayoutParams();
89
-            layoutParams.topMargin = 0;
90
-            setLayoutParams(layoutParams);
91
-        }
92
-    }
93
-
94
-    @Override
95
-    public void drawBelowTopBar(TopBar topBar) {
96
-        if (getLayoutParams() instanceof RelativeLayout.LayoutParams) {
97
-            RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) getLayoutParams();
98
-            if (topBar.getLayoutParams() instanceof MarginLayoutParams) {
99
-                layoutParams.topMargin = ViewUtils.getHeight(topBar) + ((MarginLayoutParams) topBar.getLayoutParams()).topMargin;
100
-            } else {
101
-                layoutParams.topMargin = ViewUtils.getHeight(topBar);
102
-            }
103
-            try {
104
-                setLayoutParams(layoutParams);
105
-            } catch (IllegalStateException ignored) { }
106
-        }
107
-    }
108
-
109
     @Override
83
     @Override
110
     public boolean isRendered() {
84
     public boolean isRendered() {
111
         return reactView.isRendered();
85
         return reactView.isRendered();

+ 2
- 25
lib/android/app/src/main/java/com/reactnativenavigation/views/ExternalComponentLayout.java View File

2
 
2
 
3
 import android.annotation.SuppressLint;
3
 import android.annotation.SuppressLint;
4
 import android.content.Context;
4
 import android.content.Context;
5
-import android.widget.FrameLayout;
6
-import android.widget.RelativeLayout;
7
-
8
-import com.reactnativenavigation.views.topbar.TopBar;
9
-
10
-import static android.widget.RelativeLayout.BELOW;
5
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
11
 
6
 
12
 @SuppressLint("ViewConstructor")
7
 @SuppressLint("ViewConstructor")
13
-public class ExternalComponentLayout extends FrameLayout implements Component {
8
+public class ExternalComponentLayout extends CoordinatorLayout implements Component {
14
     public ExternalComponentLayout(Context context) {
9
     public ExternalComponentLayout(Context context) {
15
 		super(context);
10
 		super(context);
16
     }
11
     }
17
 
12
 
18
-    @Override
19
-    public void drawBehindTopBar() {
20
-        if (getParent() instanceof RelativeLayout) {
21
-            RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) getLayoutParams();
22
-            layoutParams.removeRule(BELOW);
23
-            setLayoutParams(layoutParams);
24
-        }
25
-    }
26
-
27
-    @Override
28
-    public void drawBelowTopBar(TopBar topBar) {
29
-        if (getParent() instanceof RelativeLayout) {
30
-            RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) getLayoutParams();
31
-            layoutParams.addRule(BELOW, topBar.getId());
32
-            setLayoutParams(layoutParams);
33
-        }
34
-    }
35
-
36
     @Override
13
     @Override
37
     public boolean isRendered() {
14
     public boolean isRendered() {
38
         return getChildCount() >= 1;
15
         return getChildCount() >= 1;

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/views/Fab.java View File

4
 import android.graphics.PorterDuff;
4
 import android.graphics.PorterDuff;
5
 import android.graphics.PorterDuffColorFilter;
5
 import android.graphics.PorterDuffColorFilter;
6
 import android.graphics.drawable.Drawable;
6
 import android.graphics.drawable.Drawable;
7
-import android.support.annotation.NonNull;
7
+import androidx.annotation.NonNull;
8
 
8
 
9
 import com.github.clans.fab.FloatingActionButton;
9
 import com.github.clans.fab.FloatingActionButton;
10
 import com.reactnativenavigation.anim.FabAnimator;
10
 import com.reactnativenavigation.anim.FabAnimator;

+ 3
- 2
lib/android/app/src/main/java/com/reactnativenavigation/views/SideMenu.java View File

1
 package com.reactnativenavigation.views;
1
 package com.reactnativenavigation.views;
2
 
2
 
3
 import android.content.Context;
3
 import android.content.Context;
4
-import android.support.annotation.NonNull;
5
-import android.support.v4.widget.DrawerLayout;
6
 import android.util.Log;
4
 import android.util.Log;
7
 
5
 
6
+import androidx.annotation.NonNull;
7
+import androidx.drawerlayout.widget.DrawerLayout;
8
+
8
 public class SideMenu extends DrawerLayout {
9
 public class SideMenu extends DrawerLayout {
9
     public SideMenu(@NonNull Context context) {
10
     public SideMenu(@NonNull Context context) {
10
         super(context);
11
         super(context);

+ 0
- 0
lib/android/app/src/main/java/com/reactnativenavigation/views/SideMenuRoot.java View File


Some files were not shown because too many files changed in this diff