diff --git a/android/src/main/java/com/swmansion/rnscreens/Screen.java b/android/src/main/java/com/swmansion/rnscreens/Screen.java index cf89ac4d..9c9074c7 100644 --- a/android/src/main/java/com/swmansion/rnscreens/Screen.java +++ b/android/src/main/java/com/swmansion/rnscreens/Screen.java @@ -2,7 +2,6 @@ package com.swmansion.rnscreens; import android.content.Context; import android.graphics.Paint; -import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.InputMethodManager; @@ -13,7 +12,6 @@ import androidx.fragment.app.Fragment; import com.facebook.react.bridge.GuardedRunnable; import com.facebook.react.bridge.ReactContext; -import com.facebook.react.uimanager.MeasureSpecAssertions; import com.facebook.react.uimanager.PointerEvents; import com.facebook.react.uimanager.ReactPointerEventsView; import com.facebook.react.uimanager.UIManagerModule; diff --git a/android/src/main/java/com/swmansion/rnscreens/ScreenStack.java b/android/src/main/java/com/swmansion/rnscreens/ScreenStack.java index 15884fa1..af68298d 100644 --- a/android/src/main/java/com/swmansion/rnscreens/ScreenStack.java +++ b/android/src/main/java/com/swmansion/rnscreens/ScreenStack.java @@ -25,6 +25,10 @@ public class ScreenStack extends ScreenContainer { onUpdate(); } + public Screen getTopScreen() { + return mTopScreen.getScreen(); + } + public Screen getRootScreen() { for (int i = 0, size = getScreenCount(); i < size; i++) { Screen screen = getScreenAt(i); @@ -51,9 +55,7 @@ public class ScreenStack extends ScreenContainer { protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); for (int i = 0, size = getChildCount(); i < size; i++) { - getChildAt(i).measure( - MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.EXACTLY)); + getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec); } } @@ -169,5 +171,9 @@ public class ScreenStack extends ScreenContainer { mStack.addAll(mScreenFragments); tryCommitTransaction(); + + for (ScreenStackFragment screen : mStack) { + screen.onStackUpdate(); + } } } diff --git a/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.java b/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.java index d8292503..ea6ab79c 100644 --- a/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.java +++ b/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.java @@ -52,6 +52,13 @@ public class ScreenStackFragment extends ScreenFragment { } } + public void onStackUpdate() { + View child = mScreenView.getChildAt(0); + if (child instanceof ScreenStackHeaderConfig) { + ((ScreenStackHeaderConfig) child).onUpdate(); + } + } + @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, diff --git a/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfig.java b/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfig.java index f349f33b..4a6695c4 100644 --- a/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfig.java +++ b/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfig.java @@ -1,7 +1,6 @@ package com.swmansion.rnscreens; import android.content.Context; -import android.graphics.Color; import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; import android.util.TypedValue; @@ -29,17 +28,26 @@ public class ScreenStackHeaderConfig extends ViewGroup { private int mTitleFontSize; private int mBackgroundColor; private boolean mIsHidden; + private boolean mGestureEnabled = true; private boolean mIsBackButtonHidden; private boolean mIsShadowHidden; private int mTintColor; private final Toolbar mToolbar; + private boolean mIsAttachedToWindow = false; + private OnBackPressedCallback mBackCallback = new OnBackPressedCallback(false) { @Override public void handleOnBackPressed() { - getScreenStack().dismiss(getScreenFragment()); + ScreenStack stack = getScreenStack(); + Screen current = getScreen(); + if (stack.getTopScreen() == current) { + stack.dismiss(getScreenFragment()); + } + mBackCallback.remove(); } }; + private OnClickListener mBackClickListener = new OnClickListener() { @Override public void onClick(View view) { @@ -68,7 +76,14 @@ public class ScreenStackHeaderConfig extends ViewGroup { @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); - update(); + mIsAttachedToWindow = true; + onUpdate(); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + mIsAttachedToWindow = false; } private Screen getScreen() { @@ -101,14 +116,27 @@ public class ScreenStackHeaderConfig extends ViewGroup { return null; } - private void installBackCallback() { - mBackCallback.remove(); - Fragment fragment = getScreenFragment(); - fragment.requireActivity().getOnBackPressedDispatcher().addCallback(fragment, mBackCallback); - } - - private void update() { + public void onUpdate() { Screen parent = (Screen) getParent(); + final ScreenStack stack = getScreenStack(); + boolean isRoot = stack == null ? true : stack.getRootScreen() == parent; + boolean isTop = stack == null ? true : stack.getTopScreen() == parent; + + // we need to clean up back handler especially in the case given screen is no longer on top + // because we don't want it to capture back event if it is not responsible for handling it + // as that would block other handlers from running + mBackCallback.remove(); + + if (!mIsAttachedToWindow || !isTop) { + return; + } + + if (!isRoot && isTop && mGestureEnabled) { + Fragment fragment = getScreenFragment(); + fragment.requireActivity().getOnBackPressedDispatcher().addCallback(fragment, mBackCallback); + mBackCallback.setEnabled(true); + } + if (mIsHidden) { if (mToolbar.getParent() != null) { getScreenFragment().removeToolbar(); @@ -125,13 +153,7 @@ public class ScreenStackHeaderConfig extends ViewGroup { ActionBar actionBar = activity.getSupportActionBar(); // hide back button - final ScreenStack stack = getScreenStack(); - boolean isRoot = stack == null ? true : stack.getRootScreen() == parent; actionBar.setDisplayHomeAsUpEnabled(isRoot ? false : !mIsBackButtonHidden); - if (!isRoot) { - installBackCallback(); - } - mBackCallback.setEnabled(!isRoot); // when setSupportActionBar is called a toolbar wrapper gets initialized that overwrites // navigation click listener. The default behavior set in the wrapper is to call into @@ -268,6 +290,10 @@ public class ScreenStackHeaderConfig extends ViewGroup { mIsShadowHidden = hideShadow; } + public void setGestureEnabled(boolean gestureEnabled) { + mGestureEnabled = gestureEnabled; + } + public void setHideBackButton(boolean hideBackButton) { mIsBackButtonHidden = hideBackButton; } diff --git a/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfigViewManager.java b/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfigViewManager.java index 1adb924c..88a968d7 100644 --- a/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfigViewManager.java +++ b/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfigViewManager.java @@ -82,6 +82,11 @@ public class ScreenStackHeaderConfigViewManager extends ViewGroupManager { public void setStackPresentation(Screen view, String presentation) { if ("push".equals(presentation)) { view.setStackPresentation(Screen.StackPresentation.PUSH); - } else if ("modal".equals(presentation)) { + } else if ("modal".equals(presentation) || "containedModal".equals(presentation)) { + // at the moment Android implementation does not handle contained vs regular modals view.setStackPresentation(Screen.StackPresentation.MODAL); - } else if ("transparentModal".equals(presentation)) { + } else if ("transparentModal".equals(presentation) || "containedTransparentModal".equals((presentation))) { + // at the moment Android implementation does not handle contained vs regular modals view.setStackPresentation(Screen.StackPresentation.TRANSPARENT_MODAL); } else { throw new JSApplicationIllegalArgumentException("Unknown presentation type " + presentation);