From 9b7c19fd2473b04a9d6e5d13d681828aeea09aac Mon Sep 17 00:00:00 2001 From: Lucas Tulio Date: Tue, 29 Aug 2017 17:11:51 -0300 Subject: [PATCH 01/23] fix(permission): check for overlay permission in debug only --- .../android/react/navigation/ReactNavigationCoordinator.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactNavigationCoordinator.java b/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactNavigationCoordinator.java index 196b9a46..95defb6f 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactNavigationCoordinator.java +++ b/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactNavigationCoordinator.java @@ -9,6 +9,8 @@ import android.os.Looper; import android.provider.Settings; import android.widget.Toast; + +import com.airbnb.android.BuildConfig; import com.facebook.react.ReactInstanceManager; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReadableMap; @@ -179,7 +181,7 @@ public ReadableMap getInitialConfigForModuleName(String screenName) { } public void start(final Application application) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(application)) { + if (BuildConfig.DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(application)) { handleOverlayPermissionsMissing(application); return; } From 23b2770c7b51f032495e27a95958d90013420e8e Mon Sep 17 00:00:00 2001 From: Lucas Tulio Date: Tue, 29 Aug 2017 17:21:43 -0300 Subject: [PATCH 02/23] chore(*): move package to @loggi --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index cb24fc1a..cdd47592 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { - "name": "native-navigation", - "version": "0.2.1", + "name": "@loggi/native-navigation", + "version": "0.2.2", "description": "Native Navigation for React Native", "main": "index.js", "scripts": { From 86a766fe2e1a8ac39709abd83180845c6260b51a Mon Sep 17 00:00:00 2001 From: Lucas Tulio Date: Wed, 30 Aug 2017 11:16:25 -0300 Subject: [PATCH 03/23] fix(build-config): trust the app's buildconfig, not the lib one --- .../android/react/navigation/ReactNavigationCoordinator.java | 5 ++--- package.json | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactNavigationCoordinator.java b/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactNavigationCoordinator.java index 95defb6f..bff3910a 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactNavigationCoordinator.java +++ b/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactNavigationCoordinator.java @@ -10,7 +10,6 @@ import android.provider.Settings; import android.widget.Toast; -import com.airbnb.android.BuildConfig; import com.facebook.react.ReactInstanceManager; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReadableMap; @@ -180,8 +179,8 @@ public ReadableMap getInitialConfigForModuleName(String screenName) { return getOrDefault(screenName).initialConfig; } - public void start(final Application application) { - if (BuildConfig.DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(application)) { + public void start(final Application application, boolean isDebug) { + if (isDebug && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(application)) { handleOverlayPermissionsMissing(application); return; } diff --git a/package.json b/package.json index cdd47592..787f7a97 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@loggi/native-navigation", - "version": "0.2.2", + "version": "0.2.3", "description": "Native Navigation for React Native", "main": "index.js", "scripts": { From 14980bc5638b90a8c432a800c24e9c048ed1cdee Mon Sep 17 00:00:00 2001 From: Lucas Tulio Date: Wed, 30 Aug 2017 16:35:32 -0300 Subject: [PATCH 04/23] chore(*): use local rn --- lib/android/build.gradle | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/android/build.gradle b/lib/android/build.gradle index 659845a2..ecd51e79 100644 --- a/lib/android/build.gradle +++ b/lib/android/build.gradle @@ -33,6 +33,12 @@ android { } } +repositories { + maven { + url "../../../../react-native/android" + } +} + dependencies { compile 'com.android.support:appcompat-v7:25.2.0' compile 'com.android.support:support-annotations:25.2.0' diff --git a/package.json b/package.json index 787f7a97..e3e17d4d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@loggi/native-navigation", - "version": "0.2.3", + "version": "0.2.4", "description": "Native Navigation for React Native", "main": "index.js", "scripts": { From 9db23d5c86c625c5aea3a5cdd47d6a17af605d0c Mon Sep 17 00:00:00 2001 From: Lucas Tulio Date: Mon, 18 Sep 2017 11:34:19 -0300 Subject: [PATCH 05/23] chore(build): provided jackson --- lib/android/build.gradle | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/android/build.gradle b/lib/android/build.gradle index ecd51e79..7e4b214c 100644 --- a/lib/android/build.gradle +++ b/lib/android/build.gradle @@ -43,7 +43,7 @@ dependencies { compile 'com.android.support:appcompat-v7:25.2.0' compile 'com.android.support:support-annotations:25.2.0' compile 'com.android.support:design:25.2.0' - compile 'com.fasterxml.jackson.core:jackson-databind:2.8.3' + provided 'com.fasterxml.jackson.core:jackson-databind:2.8.3' compile 'com.facebook.fresco:fresco:1.0.1' compile 'com.facebook.fresco:imagepipeline-okhttp3:1.0.1' provided 'com.facebook.react:react-native:+' diff --git a/package.json b/package.json index e3e17d4d..997a82d0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@loggi/native-navigation", - "version": "0.2.4", + "version": "0.2.5", "description": "Native Navigation for React Native", "main": "index.js", "scripts": { From e7e6a35c16ab84a30bb308156f278f8a3ede75fa Mon Sep 17 00:00:00 2001 From: Renato Augusto Gama dos Santos Date: Wed, 20 Sep 2017 20:09:20 -0300 Subject: [PATCH 06/23] feat(navigation): Remove margin when bar is hidden and avoid status bar color blink in transition --- .../DefaultNavigationImplementation.java | 30 ++++++++++++++----- .../react/navigation/ReactInterface.java | 2 ++ .../react/navigation/ReactNativeFragment.java | 19 ++++++++++-- 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/lib/android/src/main/java/com/airbnb/android/react/navigation/DefaultNavigationImplementation.java b/lib/android/src/main/java/com/airbnb/android/react/navigation/DefaultNavigationImplementation.java index 60c2912b..908e3e18 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/navigation/DefaultNavigationImplementation.java +++ b/lib/android/src/main/java/com/airbnb/android/react/navigation/DefaultNavigationImplementation.java @@ -143,21 +143,24 @@ private void reconcileStatusBarStyleOnLollipop( ReadableMap next, boolean firstCall ) { - if (firstCall || numberHasChanged("statusBarColor", prev, next)) { + boolean nextHasColor = next.hasKey("statusBarColor"); + + if ((nextHasColor && firstCall) || numberHasChanged("statusBarColor", prev, next)) { boolean animated = false; + if (next.hasKey("statusBarAnimation")) { animated = !("none".equals(next.getString("statusBarAnimation"))); } Integer color = defaults.statusBarColor; - if (next.hasKey("statusBarColor")) { + if (nextHasColor) { color = next.getInt("statusBarColor"); } if (animated) { int curColor = activity.getWindow().getStatusBarColor(); ValueAnimator colorAnimation = ValueAnimator.ofObject( - new ArgbEvaluator(), curColor, color); + new ArgbEvaluator(), curColor, color); colorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override @@ -165,20 +168,25 @@ public void onAnimationUpdate(ValueAnimator animator) { activity.getWindow().setStatusBarColor((Integer) animator.getAnimatedValue()); } }); + colorAnimation - .setDuration(300) - .setStartDelay(0); + .setDuration(300) + .setStartDelay(0); colorAnimation.start(); } else { activity.getWindow().setStatusBarColor(color); } } - if (firstCall || boolHasChanged("statusBarTranslucent", prev, next)) { + boolean nextHasTranslucent = next.hasKey("statusBarTranslucent"); + + if ((nextHasTranslucent && firstCall) || boolHasChanged("statusBarTranslucent", prev, next)) { boolean translucent = defaults.statusBarTranslucent; - if (next.hasKey("statusBarTranslucent")) { + + if (nextHasTranslucent) { translucent = next.getBoolean("statusBarTranslucent"); } + View decorView = activity.getWindow().getDecorView(); // If the status bar is translucent hook into the window insets calculations // and consume all the top insets so no padding will be added under the status bar. @@ -374,14 +382,22 @@ public void reconcileNavigationProperties( if (firstCall || boolHasChanged("hidden", prev, next)) { boolean hidden = false; + ViewStub viewStub = component.getViewStub(); + ViewGroup.MarginLayoutParams marginLayoutParams = (ViewGroup.MarginLayoutParams) viewStub.getLayoutParams(); if (next.hasKey("hidden")) { hidden = next.getBoolean("hidden"); } if (hidden && bar.isShowing()) { + marginLayoutParams.setMargins(0, 0, 0, 0); bar.hide(); } else if (!hidden && !bar.isShowing()) { + TypedValue value = new TypedValue(); + Resources.Theme currentTheme = viewStub.getContext().getTheme(); + boolean hasValue = currentTheme.resolveAttribute(R.attr.actionBarSize, value, true); + int marginTop = hasValue ? value.data : 0; + marginLayoutParams.setMargins(0, marginTop, 0, 0); bar.show(); } } diff --git a/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactInterface.java b/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactInterface.java index 61e2473f..97ad4df0 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactInterface.java +++ b/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactInterface.java @@ -1,6 +1,7 @@ package com.airbnb.android.react.navigation; import android.support.v4.app.FragmentActivity; +import android.view.ViewStub; import com.facebook.react.ReactRootView; import com.facebook.react.bridge.ReadableMap; @@ -12,6 +13,7 @@ public interface ReactInterface { String getInstanceId(); ReactRootView getReactRootView(); ReactToolbar getToolbar(); + ViewStub getViewStub(); boolean isDismissible(); void signalFirstRenderComplete(); void notifySharedElementAddition(); diff --git a/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactNativeFragment.java b/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactNativeFragment.java index c0c226b3..6dffd635 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactNativeFragment.java +++ b/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactNativeFragment.java @@ -72,6 +72,7 @@ public void run() { private ReadableMap renderedConfig = ConversionUtil.EMPTY_MAP; private ReactNativeFragmentViewGroup contentContainer; private ReactRootView reactRootView; + private ViewStub viewStub = null; // private ReactInterfaceManager activityManager; private final Handler handler = new Handler(); private PermissionListener permissionListener; @@ -121,6 +122,7 @@ private void initReactNative() { if (reactRootView != null || getView() == null) { return; } + if (!isSuccessfullyInitialized()) { // TODO(lmr): need a different way of doing this // TODO(lmr): move to utils @@ -156,9 +158,11 @@ public void run() { private void onAttachWithReactContext() { Log.d(TAG, "onCreateWithReactContext"); + if (getView() == null) { return; } + loadingView.setVisibility(View.GONE); if (!isSuccessfullyInitialized()) { @@ -166,16 +170,22 @@ private void onAttachWithReactContext() { // ReactNativeUtils.showAlertBecauseChecksFailed(getActivity(), null); return; } + String moduleName = getArguments().getString(ReactNativeIntents.EXTRA_MODULE_NAME); Bundle props = getArguments().getBundle(ReactNativeIntents.EXTRA_PROPS); + if (props == null) { props = new Bundle(); } + props.putString(INSTANCE_ID_PROP, instanceId); + if (viewStub == null || reactRootView == null) { + viewStub = (ViewStub) getView().findViewById(R.id.react_root_view_stub); + } + if (reactRootView == null) { - ViewStub reactViewStub = (ViewStub) getView().findViewById(R.id.react_root_view_stub); - reactRootView = (ReactRootView) reactViewStub.inflate(); + reactRootView = (ReactRootView) viewStub.inflate(); } getImplementation().reconcileNavigationProperties( @@ -369,6 +379,11 @@ public ReactRootView getReactRootView() { return reactRootView; } + @Override + public ViewStub getViewStub() { + return viewStub; + } + @Override public ReactToolbar getToolbar() { return toolbar; From 7e94caa92e8675adf5d7cf28a0305e285770d3ea Mon Sep 17 00:00:00 2001 From: Renato Augusto Gama dos Santos Date: Wed, 20 Sep 2017 20:10:09 -0300 Subject: [PATCH 07/23] chore(*): Bump @loggi/native-navigation version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 997a82d0..f33b397e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@loggi/native-navigation", - "version": "0.2.5", + "version": "0.2.6", "description": "Native Navigation for React Native", "main": "index.js", "scripts": { From 99d4c53baed52f6ab7edb4ae6f5e5eba1cbb0bce Mon Sep 17 00:00:00 2001 From: Renato Augusto Gama dos Santos Date: Wed, 20 Sep 2017 20:21:26 -0300 Subject: [PATCH 08/23] feat(native-navigation): Fix indentation problems --- .../react/navigation/DefaultNavigationImplementation.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/android/src/main/java/com/airbnb/android/react/navigation/DefaultNavigationImplementation.java b/lib/android/src/main/java/com/airbnb/android/react/navigation/DefaultNavigationImplementation.java index 908e3e18..1ab7449b 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/navigation/DefaultNavigationImplementation.java +++ b/lib/android/src/main/java/com/airbnb/android/react/navigation/DefaultNavigationImplementation.java @@ -159,9 +159,7 @@ private void reconcileStatusBarStyleOnLollipop( if (animated) { int curColor = activity.getWindow().getStatusBarColor(); - ValueAnimator colorAnimation = ValueAnimator.ofObject( - new ArgbEvaluator(), curColor, color); - + ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), curColor, color); colorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animator) { @@ -169,9 +167,7 @@ public void onAnimationUpdate(ValueAnimator animator) { } }); - colorAnimation - .setDuration(300) - .setStartDelay(0); + colorAnimation.setDuration(300).setStartDelay(0); colorAnimation.start(); } else { activity.getWindow().setStatusBarColor(color); From 83f4f07717c78bc5a5e7ba33844d148d7b010cac Mon Sep 17 00:00:00 2001 From: Renato Augusto Gama dos Santos Date: Fri, 29 Sep 2017 16:49:45 -0300 Subject: [PATCH 09/23] feat(native-navigation): Improve fragment transition --- .../airbnb/android/react/navigation/ScreenCoordinator.java | 2 +- lib/android/src/main/res/anim/no_animation.xml | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 lib/android/src/main/res/anim/no_animation.xml diff --git a/lib/android/src/main/java/com/airbnb/android/react/navigation/ScreenCoordinator.java b/lib/android/src/main/java/com/airbnb/android/react/navigation/ScreenCoordinator.java index 1d89d4c7..a632b07e 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/navigation/ScreenCoordinator.java +++ b/lib/android/src/main/java/com/airbnb/android/react/navigation/ScreenCoordinator.java @@ -39,7 +39,7 @@ public class ScreenCoordinator { enum PresentAnimation { Modal(R.anim.slide_up, R.anim.delay, R.anim.delay, R.anim.slide_down), - Push(R.anim.slide_in_right, R.anim.slide_out_left, R.anim.slide_in_left, R.anim.slide_out_right), + Push(R.anim.slide_in_right, R.anim.no_animation, R.anim.no_animation, R.anim.slide_out_right), Fade(R.anim.fade_in, R.anim.fade_out, R.anim.fade_in, R.anim.fade_out); @AnimRes int enter; diff --git a/lib/android/src/main/res/anim/no_animation.xml b/lib/android/src/main/res/anim/no_animation.xml new file mode 100644 index 00000000..0cff8591 --- /dev/null +++ b/lib/android/src/main/res/anim/no_animation.xml @@ -0,0 +1,4 @@ + + From 22e15b068f6a8b9cbecf6c65dc9198dac74b3b35 Mon Sep 17 00:00:00 2001 From: Renato Augusto Gama dos Santos Date: Fri, 29 Sep 2017 16:50:20 -0300 Subject: [PATCH 10/23] chore(*): Bump @loggi/native-navigation version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f33b397e..7b8c23f6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@loggi/native-navigation", - "version": "0.2.6", + "version": "0.2.7", "description": "Native Navigation for React Native", "main": "index.js", "scripts": { From 326cccb661db3bada61e969c8ce2b3f3205872a0 Mon Sep 17 00:00:00 2001 From: Lucas Tulio Date: Tue, 31 Oct 2017 19:51:51 -0200 Subject: [PATCH 11/23] fix(backstack): fix backstack being empty --- .../android/react/navigation/ScreenCoordinator.java | 11 ++++++++++- package.json | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/android/src/main/java/com/airbnb/android/react/navigation/ScreenCoordinator.java b/lib/android/src/main/java/com/airbnb/android/react/navigation/ScreenCoordinator.java index a632b07e..b8dc0325 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/navigation/ScreenCoordinator.java +++ b/lib/android/src/main/java/com/airbnb/android/react/navigation/ScreenCoordinator.java @@ -109,6 +109,9 @@ public void pushScreen(Fragment fragment, @Nullable Bundle options) { ft.setCustomAnimations(anim.enter, anim.exit, anim.popEnter, anim.popExit); } BackStack bsi = getCurrentBackStack(); + if (bsi == null) { + return; + } ft .detach(currentFragment) .add(container.getId(), fragment) @@ -209,6 +212,9 @@ public void onBackPressed() { public void pop() { BackStack bsi = getCurrentBackStack(); + if (bsi == null) { + return; + } if (bsi.getSize() == 1) { dismiss(); return; @@ -281,7 +287,10 @@ private Fragment getCurrentFragment() { } private BackStack getCurrentBackStack() { - return backStacks.peek(); + if (backStacks.size() > 0) { + return backStacks.peek(); + } + return null; } @NonNull diff --git a/package.json b/package.json index 7b8c23f6..be4fad02 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@loggi/native-navigation", - "version": "0.2.7", + "version": "0.2.8", "description": "Native Navigation for React Native", "main": "index.js", "scripts": { From a8377b3363febcc49e464ab0b4c94bbb1dbb2014 Mon Sep 17 00:00:00 2001 From: Klayton Faria Date: Tue, 7 Nov 2017 12:19:33 -0200 Subject: [PATCH 12/23] refac(NativeNavigationPackage): Remove override on a deprecated API --- .../android/react/navigation/NativeNavigationPackage.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/android/src/main/java/com/airbnb/android/react/navigation/NativeNavigationPackage.java b/lib/android/src/main/java/com/airbnb/android/react/navigation/NativeNavigationPackage.java index 6ffdd9da..8ea6b184 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/navigation/NativeNavigationPackage.java +++ b/lib/android/src/main/java/com/airbnb/android/react/navigation/NativeNavigationPackage.java @@ -17,7 +17,8 @@ public class NativeNavigationPackage implements ReactPackage { new NavigatorModule(reactContext, ReactNavigationCoordinator.sharedInstance)); } - @Override public List> createJSModules() { + // Deprecated in RN 0.47 + public List> createJSModules() { return Collections.emptyList(); } From a7cfadb83a84c58474e8f30399f0c7f0cbc0d315 Mon Sep 17 00:00:00 2001 From: Klayton Faria Date: Tue, 7 Nov 2017 12:19:47 -0200 Subject: [PATCH 13/23] chore(*): Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index be4fad02..b395ec56 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@loggi/native-navigation", - "version": "0.2.8", + "version": "0.2.9", "description": "Native Navigation for React Native", "main": "index.js", "scripts": { From 325f0a231649e446e108c9c15e3cbab4fdac55c9 Mon Sep 17 00:00:00 2001 From: Klayton Faria Date: Wed, 8 Nov 2017 15:54:38 -0200 Subject: [PATCH 14/23] chore(*): Update dependencies to prevent build crashes on app-driver --- lib/android/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/android/build.gradle b/lib/android/build.gradle index 7e4b214c..2140dd82 100644 --- a/lib/android/build.gradle +++ b/lib/android/build.gradle @@ -44,7 +44,7 @@ dependencies { compile 'com.android.support:support-annotations:25.2.0' compile 'com.android.support:design:25.2.0' provided 'com.fasterxml.jackson.core:jackson-databind:2.8.3' - compile 'com.facebook.fresco:fresco:1.0.1' - compile 'com.facebook.fresco:imagepipeline-okhttp3:1.0.1' + compile 'com.facebook.fresco:fresco:1.3.0' + compile 'com.facebook.fresco:imagepipeline-okhttp3:1.3.0' provided 'com.facebook.react:react-native:+' } From 5c7dde43adc766e6779626c9a4217c1251c1020f Mon Sep 17 00:00:00 2001 From: Klayton Faria Date: Wed, 8 Nov 2017 15:57:44 -0200 Subject: [PATCH 15/23] chore(*): Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b395ec56..5db7f5b2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@loggi/native-navigation", - "version": "0.2.9", + "version": "0.2.10", "description": "Native Navigation for React Native", "main": "index.js", "scripts": { From efbcce52c300a79dd18cf933671c5f12c116359e Mon Sep 17 00:00:00 2001 From: Lucas Tulio Date: Fri, 12 Jan 2018 12:15:47 -0200 Subject: [PATCH 16/23] feat(stack): restoring backStack if the app gets killed --- .../react/navigation/ScreenCoordinator.java | 56 +++++++++++++++---- package.json | 2 +- 2 files changed, 45 insertions(+), 13 deletions(-) diff --git a/lib/android/src/main/java/com/airbnb/android/react/navigation/ScreenCoordinator.java b/lib/android/src/main/java/com/airbnb/android/react/navigation/ScreenCoordinator.java index b8dc0325..48d8e5d6 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/navigation/ScreenCoordinator.java +++ b/lib/android/src/main/java/com/airbnb/android/react/navigation/ScreenCoordinator.java @@ -70,11 +70,41 @@ enum PresentAnimation { @AnimRes private int nextPopExitAnim; public ScreenCoordinator(AppCompatActivity activity, ScreenCoordinatorLayout container, - @Nullable Bundle savedInstanceState) { + @Nullable Bundle savedInstanceState) { this.activity = activity; this.container = container; container.setFragmentManager(activity.getSupportFragmentManager()); // TODO: restore state + + restoreStack(); + } + + /** + * If there are Fragments in the Activity stack, restore them into our backStack. We know the + * order in which to restore the Fragments by tagging them with the size of the backStack at the + * time they were added. + * + * This is useful for when the app goes to background on a device with "Don't keep activities" + * turned on. It also restores the backStack in case Android kills the app due to memory pressure. + */ + private void restoreStack() { + boolean hasFragments = true; + int fragmentIndex = 0; + + while (hasFragments) { + Fragment fragment = activity.getSupportFragmentManager().findFragmentByTag(String.valueOf(fragmentIndex)); + if (fragment != null) { + if (getCurrentBackStack() == null) { + BackStack backStack = new BackStack(getNextStackTag(), PresentAnimation.Modal, null); + backStacks.push(backStack); + } + getCurrentBackStack().pushFragment(fragment); + + fragmentIndex++; + } else { + hasFragments = false; + } + } } void onSaveInstanceState(Bundle outState) { @@ -103,7 +133,7 @@ public void pushScreen(Fragment fragment, @Nullable Bundle options) { } if (ViewUtils.isAtLeastLollipop() && options != null && options.containsKey(TRANSITION_GROUP)) { - setupFragmentForSharedElement(currentFragment, fragment, ft, options); + setupFragmentForSharedElement(currentFragment, fragment, ft, options); } else { PresentAnimation anim = PresentAnimation.Push; ft.setCustomAnimations(anim.enter, anim.exit, anim.popEnter, anim.popExit); @@ -112,9 +142,10 @@ public void pushScreen(Fragment fragment, @Nullable Bundle options) { if (bsi == null) { return; } + ft .detach(currentFragment) - .add(container.getId(), fragment) + .add(container.getId(), fragment, String.valueOf(bsi.getSize())) .addToBackStack(null) .commit(); bsi.pushFragment(fragment); @@ -143,10 +174,10 @@ public void presentScreen(String moduleName) { } public void presentScreen( - String moduleName, - @Nullable Bundle props, - @Nullable Bundle options, - @Nullable Promise promise) { + String moduleName, + @Nullable Bundle props, + @Nullable Bundle options, + @Nullable Promise promise) { // TODO: use options Fragment fragment = ReactNativeFragment.newInstance(moduleName, props); presentScreen(fragment, PresentAnimation.Modal, promise); @@ -182,18 +213,19 @@ public void presentScreen(Fragment fragment, PresentAnimation anim, @Nullable Pr backStacks.push(bsi); // TODO: dry this up with pushScreen FragmentTransaction ft = activity.getSupportFragmentManager().beginTransaction() - .setAllowOptimization(true) - .setCustomAnimations(anim.enter, anim.exit, anim.popEnter, anim.popExit); + .setAllowOptimization(true) + .setCustomAnimations(anim.enter, anim.exit, anim.popEnter, anim.popExit); Fragment currentFragment = getCurrentFragment(); if (currentFragment != null && !isFragmentTranslucent(fragment)) { container.willDetachCurrentScreen(); ft.detach(currentFragment); } + ft - .add(container.getId(), fragment) - .addToBackStack(bsi.getTag()) - .commit(); + .add(container.getId(), fragment, String.valueOf(bsi.getSize())) + .addToBackStack(bsi.getTag()) + .commit(); activity.getSupportFragmentManager().executePendingTransactions(); bsi.pushFragment(fragment); Log.d(TAG, toString()); diff --git a/package.json b/package.json index 6dfe663a..caa27506 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@loggi/native-navigation", - "version": "0.2.10", + "version": "0.2.11", "description": "Native Navigation for React Native", "main": "index.js", "scripts": { From 399870f3fcadd3f63d53c1d131eaa4dbeeaefbd1 Mon Sep 17 00:00:00 2001 From: Lucas Tulio Date: Tue, 16 Jan 2018 09:26:25 -0200 Subject: [PATCH 17/23] style(*): keep code style --- .../react/navigation/ScreenCoordinator.java | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/lib/android/src/main/java/com/airbnb/android/react/navigation/ScreenCoordinator.java b/lib/android/src/main/java/com/airbnb/android/react/navigation/ScreenCoordinator.java index 48d8e5d6..451932a6 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/navigation/ScreenCoordinator.java +++ b/lib/android/src/main/java/com/airbnb/android/react/navigation/ScreenCoordinator.java @@ -70,7 +70,7 @@ enum PresentAnimation { @AnimRes private int nextPopExitAnim; public ScreenCoordinator(AppCompatActivity activity, ScreenCoordinatorLayout container, - @Nullable Bundle savedInstanceState) { + @Nullable Bundle savedInstanceState) { this.activity = activity; this.container = container; container.setFragmentManager(activity.getSupportFragmentManager()); @@ -133,7 +133,7 @@ public void pushScreen(Fragment fragment, @Nullable Bundle options) { } if (ViewUtils.isAtLeastLollipop() && options != null && options.containsKey(TRANSITION_GROUP)) { - setupFragmentForSharedElement(currentFragment, fragment, ft, options); + setupFragmentForSharedElement(currentFragment, fragment, ft, options); } else { PresentAnimation anim = PresentAnimation.Push; ft.setCustomAnimations(anim.enter, anim.exit, anim.popEnter, anim.popExit); @@ -142,7 +142,6 @@ public void pushScreen(Fragment fragment, @Nullable Bundle options) { if (bsi == null) { return; } - ft .detach(currentFragment) .add(container.getId(), fragment, String.valueOf(bsi.getSize())) @@ -174,10 +173,10 @@ public void presentScreen(String moduleName) { } public void presentScreen( - String moduleName, - @Nullable Bundle props, - @Nullable Bundle options, - @Nullable Promise promise) { + String moduleName, + @Nullable Bundle props, + @Nullable Bundle options, + @Nullable Promise promise) { // TODO: use options Fragment fragment = ReactNativeFragment.newInstance(moduleName, props); presentScreen(fragment, PresentAnimation.Modal, promise); @@ -213,8 +212,8 @@ public void presentScreen(Fragment fragment, PresentAnimation anim, @Nullable Pr backStacks.push(bsi); // TODO: dry this up with pushScreen FragmentTransaction ft = activity.getSupportFragmentManager().beginTransaction() - .setAllowOptimization(true) - .setCustomAnimations(anim.enter, anim.exit, anim.popEnter, anim.popExit); + .setAllowOptimization(true) + .setCustomAnimations(anim.enter, anim.exit, anim.popEnter, anim.popExit); Fragment currentFragment = getCurrentFragment(); if (currentFragment != null && !isFragmentTranslucent(fragment)) { @@ -223,9 +222,9 @@ public void presentScreen(Fragment fragment, PresentAnimation anim, @Nullable Pr } ft - .add(container.getId(), fragment, String.valueOf(bsi.getSize())) - .addToBackStack(bsi.getTag()) - .commit(); + .add(container.getId(), fragment, String.valueOf(bsi.getSize())) + .addToBackStack(bsi.getTag()) + .commit(); activity.getSupportFragmentManager().executePendingTransactions(); bsi.pushFragment(fragment); Log.d(TAG, toString()); From dc6fd2ae8a6d5de47b3537e8c8293b866a680c04 Mon Sep 17 00:00:00 2001 From: Lucas Tulio Date: Wed, 17 Jan 2018 10:33:21 -0200 Subject: [PATCH 18/23] fix(navigation): remove render delay --- .../airbnb/android/react/navigation/ReactNativeFragment.java | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactNativeFragment.java b/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactNativeFragment.java index 6dffd635..ff2782f2 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactNativeFragment.java +++ b/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactNativeFragment.java @@ -48,7 +48,7 @@ public class ReactNativeFragment extends Fragment implements ReactInterface, private static final String INSTANCE_ID_PROP = "nativeNavigationInstanceId"; private static final String ON_BUTTON_PRESS = "onButtonPress"; private static final String INITIAL_BAR_HEIGHT_PROP = "nativeNavigationInitialBarHeight"; - private static final int RENDER_TIMEOUT_IN_MS = 1700; // TODO(lmr): put this back down when done debugging + private static final int RENDER_TIMEOUT_IN_MS = 1; // An incrementing ID to identify each ReactNativeActivity instance (used in `instanceId`) private static int UUID = 1; diff --git a/package.json b/package.json index caa27506..84b53cf6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@loggi/native-navigation", - "version": "0.2.11", + "version": "0.2.12", "description": "Native Navigation for React Native", "main": "index.js", "scripts": { From 8993d1e7ec0223db6aa3c857fcc2b17bc2ccccb0 Mon Sep 17 00:00:00 2001 From: Lucas Tulio Date: Wed, 17 Jan 2018 10:46:20 -0200 Subject: [PATCH 19/23] fix(navigation): remove render delay altogether --- .../android/react/navigation/ReactNativeFragment.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactNativeFragment.java b/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactNativeFragment.java index ff2782f2..545227f6 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactNativeFragment.java +++ b/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactNativeFragment.java @@ -48,7 +48,6 @@ public class ReactNativeFragment extends Fragment implements ReactInterface, private static final String INSTANCE_ID_PROP = "nativeNavigationInstanceId"; private static final String ON_BUTTON_PRESS = "onButtonPress"; private static final String INITIAL_BAR_HEIGHT_PROP = "nativeNavigationInitialBarHeight"; - private static final int RENDER_TIMEOUT_IN_MS = 1; // An incrementing ID to identify each ReactNativeActivity instance (used in `instanceId`) private static int UUID = 1; @@ -145,12 +144,7 @@ public void run() { // doing the transition. If this never happens for some reason, we are going to push // anyway in 250ms. The handler should get canceled + called sooner though (it's za race). isWaitingForRenderToFinish = true; - handler.postDelayed(new Runnable() { - @Override public void run() { - Log.d(TAG, "render timeout callback called"); - startPostponedEnterTransition(); - } - }, RENDER_TIMEOUT_IN_MS); + startPostponedEnterTransition(); } // activityManager = new ReactInterfaceManager(this); reactNavigationCoordinator.registerComponent(this, instanceId); From 7a2a54fef44077410e429084196c7741a818b664 Mon Sep 17 00:00:00 2001 From: Lucas Tulio Date: Tue, 27 Feb 2018 22:10:32 -0300 Subject: [PATCH 20/23] fix(lifecycle): add missing onHostDestroy call --- .../airbnb/android/react/navigation/ReactAwareActivity.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactAwareActivity.java b/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactAwareActivity.java index 4bfd8db7..5d79daf7 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactAwareActivity.java +++ b/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactAwareActivity.java @@ -28,6 +28,12 @@ protected void onResume() { reactInstanceManager.onHostResume(this, this); } + @Override + protected void onDestroy() { + super.onDestroy(); + reactInstanceManager.onHostDestroy(this); + } + @Override public void invokeDefaultOnBackPressed() { onBackPressed(); From 5b7ef882d640ec88d325e7447938532707a67a7d Mon Sep 17 00:00:00 2001 From: Lucas Tulio Date: Tue, 27 Feb 2018 22:11:27 -0300 Subject: [PATCH 21/23] chore(*): bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 84b53cf6..bda32340 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@loggi/native-navigation", - "version": "0.2.12", + "version": "0.2.13", "description": "Native Navigation for React Native", "main": "index.js", "scripts": { From 3c8712a703c6a61dfe9f9eb0362547d358f862b9 Mon Sep 17 00:00:00 2001 From: Lucas Tulio Date: Tue, 8 May 2018 18:41:39 -0300 Subject: [PATCH 22/23] fix(navigation): do not throw exception when ensure Activity fails --- .../react/navigation/NavigatorModule.java | 41 +++++++++++-------- package.json | 2 +- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/lib/android/src/main/java/com/airbnb/android/react/navigation/NavigatorModule.java b/lib/android/src/main/java/com/airbnb/android/react/navigation/NavigatorModule.java index 7738fd7b..a3461b2a 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/navigation/NavigatorModule.java +++ b/lib/android/src/main/java/com/airbnb/android/react/navigation/NavigatorModule.java @@ -97,11 +97,13 @@ public void run() { if (activity == null) { return; } - ensureCoordinatorComponent(activity); - ((ScreenCoordinatorComponent) activity).getScreenCoordinator().pushScreen( - screenName, - ConversionUtil.toBundle(props), - ConversionUtil.toBundle(options)); + + if (isCoordinatorComponent(activity)) { + ((ScreenCoordinatorComponent) activity).getScreenCoordinator().pushScreen( + screenName, + ConversionUtil.toBundle(props), + ConversionUtil.toBundle(options)); + } } }); } @@ -127,12 +129,13 @@ public void run() { if (activity == null) { return; } - ensureCoordinatorComponent(activity); + if (isCoordinatorComponent(activity)) { ((ScreenCoordinatorComponent) activity).getScreenCoordinator().presentScreen( - screenName, - ConversionUtil.toBundle(props), - ConversionUtil.toBundle(options), - promise); + screenName, + ConversionUtil.toBundle(props), + ConversionUtil.toBundle(options), + promise); + } } }); } @@ -158,8 +161,10 @@ public void run() { if (activity == null) { return; } - ensureCoordinatorComponent(activity); - ((ScreenCoordinatorComponent) activity).getScreenCoordinator().dismiss(Activity.RESULT_OK, payloadToMap(payload)); + + if (isCoordinatorComponent(activity)) { + ((ScreenCoordinatorComponent) activity).getScreenCoordinator().dismiss(Activity.RESULT_OK, payloadToMap(payload)); + } } }); } @@ -175,8 +180,10 @@ public void run() { if (activity == null) { return; } - ensureCoordinatorComponent(activity); - ((ScreenCoordinatorComponent) activity).getScreenCoordinator().pop(); + + if (isCoordinatorComponent(activity)) { + ((ScreenCoordinatorComponent) activity).getScreenCoordinator().pop(); + } } }); } @@ -222,10 +229,8 @@ private void dismiss(Activity activity, ReadableMap payload) { activity.finish(); } - private void ensureCoordinatorComponent(Activity activity) { - if (!(activity instanceof ScreenCoordinatorComponent)) { - throw new IllegalStateException("Your activity must implement ScreenCoordinatorComponent."); - } + private boolean isCoordinatorComponent(Activity activity) { + return activity instanceof ScreenCoordinatorComponent; } /** diff --git a/package.json b/package.json index bda32340..5fb9abd8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@loggi/native-navigation", - "version": "0.2.13", + "version": "0.2.14", "description": "Native Navigation for React Native", "main": "index.js", "scripts": { From c7fc4327e3b661ef13722dd666d3ef2e18729f87 Mon Sep 17 00:00:00 2001 From: Lucas Tulio Date: Tue, 8 May 2018 18:45:22 -0300 Subject: [PATCH 23/23] chore(navigator): add a warning log when ensure fails --- .../airbnb/android/react/navigation/NavigatorModule.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/android/src/main/java/com/airbnb/android/react/navigation/NavigatorModule.java b/lib/android/src/main/java/com/airbnb/android/react/navigation/NavigatorModule.java index a3461b2a..c244f751 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/navigation/NavigatorModule.java +++ b/lib/android/src/main/java/com/airbnb/android/react/navigation/NavigatorModule.java @@ -5,6 +5,7 @@ import android.os.Handler; import android.os.Looper; import android.support.annotation.Nullable; +import android.util.Log; import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReactApplicationContext; @@ -26,6 +27,7 @@ class NavigatorModule extends ReactContextBaseJavaModule { private static final String CLOSE_BEHAVIOR_DISMISS = "dismiss"; private static final String RESULT_CODE = "resultCode"; + private static final String TAG = NavigatorModule.class.getSimpleName(); private final Handler handler = new Handler(Looper.getMainLooper()); private final ReactNavigationCoordinator coordinator; @@ -230,7 +232,12 @@ private void dismiss(Activity activity, ReadableMap payload) { } private boolean isCoordinatorComponent(Activity activity) { - return activity instanceof ScreenCoordinatorComponent; + if (activity instanceof ScreenCoordinatorComponent) { + return true; + } else { + Log.w(TAG, "Activity is not a ScreenCoordinatorComponent."); + return false; + } } /**