react-native-edge-to-edge 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +1,10 @@
1
1
  package com.zoontek.rnedgetoedge
2
2
 
3
- import android.app.Activity
4
3
  import android.content.res.Configuration
5
4
  import android.graphics.Color
6
5
  import android.os.Build
7
- import android.util.TypedValue
6
+ import android.os.Handler
7
+ import android.os.Looper
8
8
  import android.view.WindowManager
9
9
 
10
10
  import androidx.core.content.ContextCompat
@@ -13,36 +13,33 @@ import androidx.core.view.WindowInsetsCompat
13
13
  import androidx.core.view.WindowInsetsControllerCompat
14
14
 
15
15
  import com.facebook.common.logging.FLog
16
+ import com.facebook.react.bridge.ReactApplicationContext
16
17
  import com.facebook.react.bridge.ReadableMap
17
18
  import com.facebook.react.common.ReactConstants
18
19
 
19
20
  object RNEdgeToEdgeModuleImpl {
20
21
  const val NAME = "RNEdgeToEdge"
21
- private var isInitialHostResume = true
22
22
 
23
- fun onHostResume(activity: Activity?) {
24
- if (activity == null) {
25
- return FLog.w(ReactConstants.TAG, "$NAME: Ignored, current activity is null.")
26
- }
23
+ private fun applyEdgeToEdge(reactContext: ReactApplicationContext) {
24
+ val activity = reactContext.currentActivity
25
+ ?: return FLog.w(ReactConstants.TAG, "$NAME: Ignored, current activity is null.")
27
26
 
28
27
  activity.runOnUiThread {
29
28
  val window = activity.window
30
29
  val view = window.decorView
31
30
  val context = view.context
32
31
 
33
- val isDarkMode =
34
- view.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK ==
35
- Configuration.UI_MODE_NIGHT_YES
36
-
37
32
  WindowCompat.setDecorFitsSystemWindows(window, false)
38
33
 
39
34
  window.statusBarColor = Color.TRANSPARENT
35
+ window.navigationBarColor = ContextCompat.getColor(context, R.color.navigationBarColor)
40
36
 
41
- window.navigationBarColor = when {
42
- Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> Color.TRANSPARENT
43
- Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !isDarkMode ->
44
- ContextCompat.getColor(context, R.color.systemBarLightScrim)
45
- else -> ContextCompat.getColor(context, R.color.systemBarDarkScrim)
37
+ val isDarkMode =
38
+ view.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK ==
39
+ Configuration.UI_MODE_NIGHT_YES
40
+
41
+ WindowInsetsControllerCompat(window, view).run {
42
+ isAppearanceLightNavigationBars = !isDarkMode
46
43
  }
47
44
 
48
45
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
@@ -50,38 +47,26 @@ object RNEdgeToEdgeModuleImpl {
50
47
  window.isNavigationBarContrastEnforced = true
51
48
  }
52
49
 
53
- WindowInsetsControllerCompat(window, view).run {
54
- if (isInitialHostResume) {
55
- val typedValue = TypedValue()
56
-
57
- isAppearanceLightStatusBars = activity
58
- .theme
59
- .resolveAttribute(android.R.attr.windowLightStatusBar, typedValue, true) &&
60
- typedValue.data != 0
61
- }
62
-
63
- isInitialHostResume = false
64
- isAppearanceLightNavigationBars = !isDarkMode
65
- }
66
-
67
50
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
68
51
  window.attributes.layoutInDisplayCutoutMode = when {
69
- Build.VERSION.SDK_INT >= Build.VERSION_CODES.R ->
70
- WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
52
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
71
53
  else -> WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
72
54
  }
73
55
  }
74
56
  }
75
57
  }
76
58
 
77
- fun onHostDestroy() {
78
- isInitialHostResume = true
59
+ fun onHostResume(reactContext: ReactApplicationContext) {
60
+ applyEdgeToEdge(reactContext)
79
61
  }
80
62
 
81
- fun setSystemBarsConfig(activity: Activity?, config: ReadableMap) {
82
- if (activity == null) {
83
- return FLog.w(ReactConstants.TAG, "$NAME: Ignored, current activity is null.")
84
- }
63
+ fun onConfigChange(reactContext: ReactApplicationContext) {
64
+ Handler(Looper.getMainLooper()).postDelayed({ applyEdgeToEdge(reactContext) }, 100)
65
+ }
66
+
67
+ fun setSystemBarsConfig(reactContext: ReactApplicationContext, config: ReadableMap) {
68
+ val activity = reactContext.currentActivity
69
+ ?: return FLog.w(ReactConstants.TAG, "$NAME: Ignored, current activity is null.")
85
70
 
86
71
  val statusBarHidden =
87
72
  config.takeIf { it.hasKey("statusBarHidden") }?.getBoolean("statusBarHidden")
@@ -2,7 +2,5 @@
2
2
  <resources>
3
3
  <!-- https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/res/remote_color_resources_res/values/colors.xml;l=67 -->
4
4
  <!-- https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/res/res/color/system_bar_background_semi_transparent.xml -->
5
- <color name="systemBarDarkScrim">#801b1b1b</color>
6
- <!-- https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/com/android/internal/policy/DecorView.java;l=142 -->
7
- <color name="systemBarLightScrim">#e6ffffff</color>
5
+ <color name="navigationBarColor">#801b1b1b</color>
8
6
  </resources>
@@ -8,9 +8,9 @@
8
8
  <item name="android:fitsSystemWindows">false</item>
9
9
  <item name="android:windowDrawsSystemBarBackgrounds">true</item>
10
10
  <item name="android:statusBarColor">@android:color/transparent</item>
11
+ <item name="android:navigationBarColor">@color/navigationBarColor</item>
11
12
  </style>
12
13
 
13
14
  <style name="Theme.EdgeToEdge" parent="Theme.EdgeToEdge.Common">
14
- <item name="android:navigationBarColor">@color/systemBarDarkScrim</item>
15
15
  </style>
16
16
  </resources>
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <resources>
3
+ <style name="Theme.EdgeToEdge.Base" parent="Theme.AppCompat.DayNight.NoActionBar">
4
+ <item name="android:windowLightStatusBar">false</item>
5
+ <item name="android:windowLightNavigationBar">false</item>
6
+ </style>
7
+ </resources>
@@ -0,0 +1,5 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <resources>
3
+ <!-- https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/com/android/internal/policy/DecorView.java;l=142 -->
4
+ <color name="navigationBarColor">#e6ffffff</color>
5
+ </resources>
@@ -1,8 +1,11 @@
1
1
  <?xml version="1.0" encoding="utf-8"?>
2
2
  <resources>
3
+ <style name="Theme.EdgeToEdge.Base" parent="Theme.AppCompat.DayNight.NoActionBar">
4
+ <item name="android:windowLightStatusBar">true</item>
5
+ <item name="android:windowLightNavigationBar">true</item>
6
+ </style>
7
+
3
8
  <style name="Theme.EdgeToEdge" parent="Theme.EdgeToEdge.Common">
4
9
  <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
5
- <item name="android:navigationBarColor">@color/systemBarLightScrim</item>
6
- <item name="android:windowLightNavigationBar">true</item>
7
10
  </style>
8
11
  </resources>
@@ -0,0 +1,4 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <resources>
3
+ <color name="navigationBarColor">@android:color/transparent</color>
4
+ </resources>
@@ -4,6 +4,5 @@
4
4
  <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
5
5
  <item name="android:enforceStatusBarContrast">false</item>
6
6
  <item name="android:enforceNavigationBarContrast">true</item>
7
- <item name="android:navigationBarColor">@android:color/transparent</item>
8
7
  </style>
9
8
  </resources>
@@ -4,6 +4,5 @@
4
4
  <item name="android:windowLayoutInDisplayCutoutMode">always</item>
5
5
  <item name="android:enforceStatusBarContrast">false</item>
6
6
  <item name="android:enforceNavigationBarContrast">true</item>
7
- <item name="android:navigationBarColor">@android:color/transparent</item>
8
7
  </style>
9
8
  </resources>
@@ -1,19 +1,32 @@
1
1
  package com.zoontek.rnedgetoedge
2
2
 
3
+ import android.content.BroadcastReceiver
4
+ import android.content.Context
5
+ import android.content.Intent
6
+ import android.content.IntentFilter
7
+
3
8
  import com.facebook.react.bridge.LifecycleEventListener
4
9
  import com.facebook.react.bridge.ReactApplicationContext
5
10
  import com.facebook.react.bridge.ReadableMap
6
11
  import com.facebook.react.module.annotations.ReactModule
7
12
 
8
13
  @ReactModule(name = RNEdgeToEdgeModuleImpl.NAME)
9
- class RNEdgeToEdgeModule(reactContext: ReactApplicationContext?) :
14
+ class RNEdgeToEdgeModule(reactContext: ReactApplicationContext) :
10
15
  NativeRNEdgeToEdgeSpec(reactContext), LifecycleEventListener {
11
16
 
17
+ private val configChangeReceiver = object : BroadcastReceiver() {
18
+ override fun onReceive(context: Context, intent: Intent) {
19
+ RNEdgeToEdgeModuleImpl.onConfigChange(reactContext)
20
+ }
21
+ }
22
+
12
23
  init {
24
+ reactApplicationContext.registerReceiver(configChangeReceiver, IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED))
13
25
  reactApplicationContext.addLifecycleEventListener(this)
14
26
  }
15
27
 
16
28
  override fun invalidate() {
29
+ reactApplicationContext.unregisterReceiver(configChangeReceiver)
17
30
  reactApplicationContext.removeLifecycleEventListener(this)
18
31
  }
19
32
 
@@ -22,16 +35,14 @@ class RNEdgeToEdgeModule(reactContext: ReactApplicationContext?) :
22
35
  }
23
36
 
24
37
  override fun onHostResume() {
25
- RNEdgeToEdgeModuleImpl.onHostResume(currentActivity)
38
+ RNEdgeToEdgeModuleImpl.onHostResume(reactApplicationContext)
26
39
  }
27
40
 
28
41
  override fun onHostPause() {}
29
42
 
30
- override fun onHostDestroy() {
31
- RNEdgeToEdgeModuleImpl.onHostDestroy()
32
- }
43
+ override fun onHostDestroy() {}
33
44
 
34
45
  override fun setSystemBarsConfig(config: ReadableMap) {
35
- RNEdgeToEdgeModuleImpl.setSystemBarsConfig(currentActivity, config)
46
+ RNEdgeToEdgeModuleImpl.setSystemBarsConfig(reactApplicationContext, config)
36
47
  }
37
48
  }
@@ -1,5 +1,10 @@
1
1
  package com.zoontek.rnedgetoedge
2
2
 
3
+ import android.content.BroadcastReceiver
4
+ import android.content.Context
5
+ import android.content.Intent
6
+ import android.content.IntentFilter
7
+
3
8
  import com.facebook.react.bridge.LifecycleEventListener
4
9
  import com.facebook.react.bridge.ReactApplicationContext
5
10
  import com.facebook.react.bridge.ReactContextBaseJavaModule
@@ -8,14 +13,22 @@ import com.facebook.react.bridge.ReadableMap
8
13
  import com.facebook.react.module.annotations.ReactModule
9
14
 
10
15
  @ReactModule(name = RNEdgeToEdgeModuleImpl.NAME)
11
- class RNEdgeToEdgeModule(reactContext: ReactApplicationContext?) :
16
+ class RNEdgeToEdgeModule(reactContext: ReactApplicationContext) :
12
17
  ReactContextBaseJavaModule(reactContext), LifecycleEventListener {
13
18
 
19
+ private val configChangeReceiver = object : BroadcastReceiver() {
20
+ override fun onReceive(context: Context, intent: Intent) {
21
+ RNEdgeToEdgeModuleImpl.onConfigChange(reactContext)
22
+ }
23
+ }
24
+
14
25
  init {
26
+ reactApplicationContext.registerReceiver(configChangeReceiver, IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED))
15
27
  reactApplicationContext.addLifecycleEventListener(this)
16
28
  }
17
29
 
18
30
  override fun invalidate() {
31
+ reactApplicationContext.unregisterReceiver(configChangeReceiver)
19
32
  reactApplicationContext.removeLifecycleEventListener(this)
20
33
  }
21
34
 
@@ -24,17 +37,15 @@ class RNEdgeToEdgeModule(reactContext: ReactApplicationContext?) :
24
37
  }
25
38
 
26
39
  override fun onHostResume() {
27
- RNEdgeToEdgeModuleImpl.onHostResume(currentActivity)
40
+ RNEdgeToEdgeModuleImpl.onHostResume(reactApplicationContext)
28
41
  }
29
42
 
30
43
  override fun onHostPause() {}
31
44
 
32
- override fun onHostDestroy() {
33
- RNEdgeToEdgeModuleImpl.onHostDestroy()
34
- }
45
+ override fun onHostDestroy() {}
35
46
 
36
47
  @ReactMethod
37
48
  fun setSystemBarsConfig(config: ReadableMap) {
38
- RNEdgeToEdgeModuleImpl.setSystemBarsConfig(currentActivity, config)
49
+ RNEdgeToEdgeModuleImpl.setSystemBarsConfig(reactApplicationContext, config)
39
50
  }
40
51
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-edge-to-edge",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "license": "MIT",
5
5
  "description": "Effortlessly enable edge-to-edge display in React Native",
6
6
  "author": "Mathieu Acthernoene <zoontek@gmail.com>",
@@ -1,6 +0,0 @@
1
- <?xml version="1.0" encoding="utf-8"?>
2
- <resources>
3
- <style name="Theme.EdgeToEdge" parent="Theme.EdgeToEdge.Common">
4
- <item name="android:navigationBarColor">@color/systemBarLightScrim</item>
5
- </style>
6
- </resources>