Skip to content

Commit

Permalink
Merge pull request #52392 from margelo/feat/edge-to-edge
Browse files Browse the repository at this point in the history
feat: edge-to-edge mode on Android
  • Loading branch information
mountiny authored Nov 25, 2024
2 parents 69ea17e + 84175de commit 6cb0256
Show file tree
Hide file tree
Showing 31 changed files with 607 additions and 139 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import android.database.CursorWindow
import android.os.Process
import androidx.multidex.MultiDexApplication
import com.expensify.chat.bootsplash.BootSplashPackage
import com.expensify.chat.navbar.NavBarManagerPackage
import com.expensify.chat.shortcutManagerModule.ShortcutManagerPackage
import com.facebook.react.PackageList
import com.facebook.react.ReactApplication
Expand Down Expand Up @@ -36,6 +37,7 @@ class MainApplication : MultiDexApplication(), ReactApplication {
add(BootSplashPackage())
add(ExpensifyAppPackage())
add(RNTextInputResetPackage())
add(NavBarManagerPackage())
}

override fun getJSMainModuleName() = ".expo/.virtual-metro-entry"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.expensify.chat.navbar

import androidx.core.view.WindowInsetsControllerCompat
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod
import com.facebook.react.bridge.UiThreadUtil;

class NavBarManagerModule(
private val mReactContext: ReactApplicationContext,
) : ReactContextBaseJavaModule(mReactContext) {
override fun getName(): String = "RNNavBarManager"

@ReactMethod
fun setButtonStyle(style: String) {
UiThreadUtil.runOnUiThread {
mReactContext.currentActivity?.window?.let {
WindowInsetsControllerCompat(it, it.decorView).let { controller ->
when (style) {
"light" -> controller.isAppearanceLightNavigationBars = false
"dark" -> controller.isAppearanceLightNavigationBars = true
}
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.expensify.chat.navbar

import com.facebook.react.ReactPackage
import com.facebook.react.bridge.NativeModule
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.uimanager.ViewManager

class NavBarManagerPackage : ReactPackage {
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
return emptyList()
}

override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
val modules: MutableList<NativeModule> = ArrayList()
modules.add(NavBarManagerModule(reactContext))
return modules
}
}
4 changes: 4 additions & 0 deletions android/app/src/main/res/values/styles.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
<style name="BaseAppTheme" parent="Theme.AppCompat.NoActionBar">
<item name="android:colorEdgeEffect">@color/gray4</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:enforceNavigationBarContrast">false</item>
<item name="colorAccent">@color/accent</item>
<item name="android:editTextBackground">@drawable/rn_edit_text_material</item>
<item name="popupTheme">@style/AppTheme.Popup</item>
Expand Down Expand Up @@ -59,6 +61,8 @@

<style name="BootTheme" parent="Theme.SplashScreen">
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:enforceNavigationBarContrast">false</item>
<item name="windowSplashScreenAnimatedIcon">@drawable/bootsplash_logo</item>
<item name="windowSplashScreenBackground">@color/bootsplash_background</item>
</style>
Expand Down
214 changes: 214 additions & 0 deletions patches/react-native+0.75.2+023+modal-navigation-bar-translucent.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
diff --git a/node_modules/react-native/Libraries/Modal/Modal.d.ts b/node_modules/react-native/Libraries/Modal/Modal.d.ts
index 4cc2df2..a501b27 100644
--- a/node_modules/react-native/Libraries/Modal/Modal.d.ts
+++ b/node_modules/react-native/Libraries/Modal/Modal.d.ts
@@ -94,6 +94,11 @@ export interface ModalPropsAndroid {
* Determines whether your modal should go under the system statusbar.
*/
statusBarTranslucent?: boolean | undefined;
+
+ /**
+ * Determines whether your modal should go under the system navigationbar.
+ */
+ navigationBarTranslucent?: boolean | undefined;
}

export type ModalProps = ModalBaseProps &
diff --git a/node_modules/react-native/Libraries/Modal/Modal.js b/node_modules/react-native/Libraries/Modal/Modal.js
index 1942d9e..1ffbe4c 100644
--- a/node_modules/react-native/Libraries/Modal/Modal.js
+++ b/node_modules/react-native/Libraries/Modal/Modal.js
@@ -95,6 +95,14 @@ export type Props = $ReadOnly<{|
*/
statusBarTranslucent?: ?boolean,

+ /**
+ * The `navigationBarTranslucent` prop determines whether your modal should go under
+ * the system navigationbar.
+ *
+ * See https://reactnative.dev/docs/modal.html#navigationbartranslucent-android
+ */
+ navigationBarTranslucent?: ?boolean,
+
/**
* The `hardwareAccelerated` prop controls whether to force hardware
* acceleration for the underlying window.
@@ -170,6 +178,14 @@ function confirmProps(props: Props) {
`Modal with '${props.presentationStyle}' presentation style and 'transparent' value is not supported.`,
);
}
+ if (
+ props.navigationBarTranslucent === true &&
+ props.statusBarTranslucent !== true
+ ) {
+ console.warn(
+ 'Modal with translucent navigation bar and without translucent status bar is not supported.',
+ );
+ }
}
}

@@ -291,6 +307,7 @@ class Modal extends React.Component<Props, State> {
onDismiss={onDismiss}
visible={this.props.visible}
statusBarTranslucent={this.props.statusBarTranslucent}
+ navigationBarTranslucent={this.props.navigationBarTranslucent}
identifier={this._identifier}
style={styles.modal}
// $FlowFixMe[method-unbinding] added when improving typing for this parameters
diff --git a/node_modules/react-native/React/Views/RCTModalHostView.h b/node_modules/react-native/React/Views/RCTModalHostView.h
index 2fcdcae..0469c23 100644
--- a/node_modules/react-native/React/Views/RCTModalHostView.h
+++ b/node_modules/react-native/React/Views/RCTModalHostView.h
@@ -27,6 +27,7 @@

// Android only
@property (nonatomic, assign) BOOL statusBarTranslucent;
+@property (nonatomic, assign) BOOL navigationBarTranslucent;
@property (nonatomic, assign) BOOL hardwareAccelerated;
@property (nonatomic, assign) BOOL animated;

diff --git a/node_modules/react-native/React/Views/RCTModalHostViewManager.m b/node_modules/react-native/React/Views/RCTModalHostViewManager.m
index e2ae7e2..a694008 100644
--- a/node_modules/react-native/React/Views/RCTModalHostViewManager.m
+++ b/node_modules/react-native/React/Views/RCTModalHostViewManager.m
@@ -118,6 +118,7 @@ - (void)invalidate
RCT_EXPORT_VIEW_PROPERTY(presentationStyle, UIModalPresentationStyle)
RCT_EXPORT_VIEW_PROPERTY(transparent, BOOL)
RCT_EXPORT_VIEW_PROPERTY(statusBarTranslucent, BOOL)
+RCT_EXPORT_VIEW_PROPERTY(navigationBarTranslucent, BOOL)
RCT_EXPORT_VIEW_PROPERTY(hardwareAccelerated, BOOL)
RCT_EXPORT_VIEW_PROPERTY(animated, BOOL)
RCT_EXPORT_VIEW_PROPERTY(onShow, RCTDirectEventBlock)
diff --git a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostManager.kt b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostManager.kt
index d5e053c..fddda45 100644
--- a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostManager.kt
+++ b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostManager.kt
@@ -59,6 +59,15 @@ public class ReactModalHostManager :
view.statusBarTranslucent = statusBarTranslucent
}

+
+ @ReactProp(name = "navigationBarTranslucent")
+ public override fun setNavigationBarTranslucent(
+ view: ReactModalHostView,
+ navigationBarTranslucent: Boolean
+ ) {
+ view.navigationBarTranslucent = navigationBarTranslucent
+ }
+
@ReactProp(name = "hardwareAccelerated")
public override fun setHardwareAccelerated(
view: ReactModalHostView,
diff --git a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.kt b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.kt
index f6e0d82..03380cb 100644
--- a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.kt
+++ b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.kt
@@ -46,6 +46,7 @@ import com.facebook.react.uimanager.UIManagerModule
import com.facebook.react.uimanager.events.EventDispatcher
import com.facebook.react.views.common.ContextUtils
import com.facebook.react.views.view.ReactViewGroup
+import com.facebook.react.views.view.setSystemBarsTranslucency
import java.util.Objects
import kotlin.math.abs

@@ -78,6 +79,12 @@ public class ReactModalHostView(context: ThemedReactContext) :
createNewDialog = true
}

+ public var navigationBarTranslucent: Boolean = false
+ set(value) {
+ field = value
+ createNewDialog = true
+ }
+
public var animationType: String? = null
set(value) {
field = value
@@ -296,6 +303,7 @@ public class ReactModalHostView(context: ThemedReactContext) :
} else {
frameLayout.fitsSystemWindows = true
}
+ dialog?.window?.setSystemBarsTranslucency(navigationBarTranslucent)
return frameLayout
}

diff --git a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/WindowUtil.kt b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/WindowUtil.kt
new file mode 100644
index 0000000..24057c4
--- /dev/null
+++ b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/WindowUtil.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+package com.facebook.react.views.view
+
+import android.content.res.Configuration
+import android.graphics.Color
+import android.os.Build
+import android.view.Window
+import android.view.WindowManager
+import androidx.core.view.ViewCompat
+import androidx.core.view.WindowCompat
+import androidx.core.view.WindowInsetsControllerCompat
+
+@Suppress("DEPRECATION")
+public fun Window.setSystemBarsTranslucency(isTranslucent: Boolean) {
+ WindowCompat.setDecorFitsSystemWindows(this, !isTranslucent)
+
+ if (isTranslucent) {
+ val isDarkMode =
+ context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK ==
+ Configuration.UI_MODE_NIGHT_YES
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ isStatusBarContrastEnforced = false
+ isNavigationBarContrastEnforced = true
+ }
+
+ statusBarColor = Color.TRANSPARENT
+ navigationBarColor = when {
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> Color.TRANSPARENT
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1 && !isDarkMode ->
+ Color.argb(0xe6, 0xFF, 0xFF, 0xFF)
+ else -> Color.argb(0x80, 0x1b, 0x1b, 0x1b)
+ }
+
+ WindowInsetsControllerCompat(this, this.decorView).run {
+ isAppearanceLightNavigationBars = !isDarkMode
+ }
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ attributes.layoutInDisplayCutoutMode = when {
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.R ->
+ WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
+ else -> WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/node_modules/react-native/src/private/specs/components/RCTModalHostViewNativeComponent.js b/node_modules/react-native/src/private/specs/components/RCTModalHostViewNativeComponent.js
index 86bf895..58ec294 100644
--- a/node_modules/react-native/src/private/specs/components/RCTModalHostViewNativeComponent.js
+++ b/node_modules/react-native/src/private/specs/components/RCTModalHostViewNativeComponent.js
@@ -58,6 +58,14 @@ type NativeProps = $ReadOnly<{|
*/
statusBarTranslucent?: WithDefault<boolean, false>,

+ /**
+ * The `navigationBarTranslucent` prop determines whether your modal should go under
+ * the system navigationbar.
+ *
+ * See https://reactnative.dev/docs/modal#navigationBarTranslucent
+ */
+ navigationBarTranslucent?: WithDefault<boolean, false>,
+
/**
* The `hardwareAccelerated` prop controls whether to force hardware
* acceleration for the underlying window.

This file was deleted.

File renamed without changes.
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
diff --git a/node_modules/react-native-modal/dist/modal.d.ts b/node_modules/react-native-modal/dist/modal.d.ts
index bd6419e..029762c 100644
--- a/node_modules/react-native-modal/dist/modal.d.ts
+++ b/node_modules/react-native-modal/dist/modal.d.ts
@@ -46,6 +46,7 @@ declare const defaultProps: {
scrollOffsetMax: number;
scrollHorizontal: boolean;
statusBarTranslucent: boolean;
+ navigationBarTranslucent: boolean;
supportedOrientations: ("landscape" | "portrait" | "portrait-upside-down" | "landscape-left" | "landscape-right")[];
};
export declare type ModalProps = ViewProps & {
@@ -137,6 +138,7 @@ export declare class ReactNativeModal extends React.Component<ModalProps, State>
scrollOffsetMax: number;
scrollHorizontal: boolean;
statusBarTranslucent: boolean;
+ navigationBarTranslucent: boolean;
supportedOrientations: ("landscape" | "portrait" | "portrait-upside-down" | "landscape-left" | "landscape-right")[];
};
state: State;
diff --git a/node_modules/react-native-modal/dist/modal.js b/node_modules/react-native-modal/dist/modal.js
index 46277ea..feec991 100644
--- a/node_modules/react-native-modal/dist/modal.js
+++ b/node_modules/react-native-modal/dist/modal.js
@@ -38,6 +38,7 @@ const defaultProps = {
scrollOffsetMax: 0,
scrollHorizontal: false,
statusBarTranslucent: false,
+ navigationBarTranslucent: false,
supportedOrientations: ['portrait', 'landscape'],
};
const extractAnimationFromProps = (props) => ({
Loading

0 comments on commit 6cb0256

Please sign in to comment.