rn-system-bar 3.0.1 → 3.0.3
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.
package/android/build.gradle
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
// ─────────────────────────────────────────────
|
|
4
4
|
|
|
5
5
|
buildscript {
|
|
6
|
-
ext.kotlin_version = "1.
|
|
6
|
+
ext.kotlin_version = "2.1.20"
|
|
7
7
|
repositories {
|
|
8
8
|
google()
|
|
9
9
|
mavenCentral()
|
|
10
10
|
}
|
|
11
11
|
dependencies {
|
|
12
|
-
classpath "com.android.tools.build:gradle:8.
|
|
12
|
+
classpath "com.android.tools.build:gradle:8.5.0"
|
|
13
13
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
|
14
14
|
}
|
|
15
15
|
}
|
|
@@ -18,12 +18,12 @@ apply plugin: "com.android.library"
|
|
|
18
18
|
apply plugin: "kotlin-android"
|
|
19
19
|
|
|
20
20
|
android {
|
|
21
|
-
|
|
21
|
+
compileSdk 36
|
|
22
22
|
namespace "com.systembar"
|
|
23
23
|
|
|
24
24
|
defaultConfig {
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
minSdk 24
|
|
26
|
+
targetSdk 36
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
compileOptions {
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
// ─────────────────────────────────────────────
|
|
2
2
|
// rn-system-bar · SystemBarModule.kt
|
|
3
|
-
//
|
|
3
|
+
// v4 — Navigation bar removed (handled by expo-navigation-bar).
|
|
4
|
+
// Status bar removed (handled by RN StatusBar).
|
|
5
|
+
// Only: Brightness, Volume, Screen flags, Orientation.
|
|
6
|
+
// Zero deprecated APIs.
|
|
4
7
|
// ─────────────────────────────────────────────
|
|
5
8
|
|
|
6
9
|
package com.systembar
|
|
@@ -8,11 +11,11 @@ package com.systembar
|
|
|
8
11
|
import android.app.Activity
|
|
9
12
|
import android.content.Context
|
|
10
13
|
import android.content.pm.ActivityInfo
|
|
11
|
-
import android.graphics.Color
|
|
12
14
|
import android.media.AudioManager
|
|
13
15
|
import android.os.Build
|
|
14
16
|
import android.provider.Settings
|
|
15
17
|
import android.view.View
|
|
18
|
+
import android.view.WindowInsets
|
|
16
19
|
import android.view.WindowInsetsController
|
|
17
20
|
import android.view.WindowManager
|
|
18
21
|
|
|
@@ -24,7 +27,6 @@ class SystemBarModule(
|
|
|
24
27
|
|
|
25
28
|
override fun getName(): String = "SystemBar"
|
|
26
29
|
|
|
27
|
-
// ── Helper ─────────────────────────────────────
|
|
28
30
|
private fun activity(): Activity? = reactContext.currentActivity
|
|
29
31
|
|
|
30
32
|
private fun audioManager(): AudioManager =
|
|
@@ -35,184 +37,7 @@ class SystemBarModule(
|
|
|
35
37
|
"notification" -> AudioManager.STREAM_NOTIFICATION
|
|
36
38
|
"alarm" -> AudioManager.STREAM_ALARM
|
|
37
39
|
"system" -> AudioManager.STREAM_SYSTEM
|
|
38
|
-
else -> AudioManager.STREAM_MUSIC
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// ═══════════════════════════════════════════════
|
|
42
|
-
// NAVIGATION BAR
|
|
43
|
-
// ═══════════════════════════════════════════════
|
|
44
|
-
|
|
45
|
-
@ReactMethod
|
|
46
|
-
fun setNavigationBarColor(color: String) {
|
|
47
|
-
val act = activity() ?: return
|
|
48
|
-
act.runOnUiThread {
|
|
49
|
-
try {
|
|
50
|
-
act.window.navigationBarColor = Color.parseColor(color)
|
|
51
|
-
} catch (e: Exception) {
|
|
52
|
-
// ignore invalid color
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
@ReactMethod
|
|
58
|
-
fun setNavigationBarVisibility(mode: String) {
|
|
59
|
-
val act = activity() ?: return
|
|
60
|
-
act.runOnUiThread {
|
|
61
|
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
|
62
|
-
val controller = act.window.insetsController ?: return@runOnUiThread
|
|
63
|
-
if (mode == "hidden") {
|
|
64
|
-
controller.hide(android.view.WindowInsets.Type.navigationBars())
|
|
65
|
-
} else {
|
|
66
|
-
controller.show(android.view.WindowInsets.Type.navigationBars())
|
|
67
|
-
}
|
|
68
|
-
} else {
|
|
69
|
-
@Suppress("DEPRECATION")
|
|
70
|
-
if (mode == "hidden") {
|
|
71
|
-
act.window.decorView.systemUiVisibility =
|
|
72
|
-
act.window.decorView.systemUiVisibility or
|
|
73
|
-
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or
|
|
74
|
-
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
|
75
|
-
} else {
|
|
76
|
-
act.window.decorView.systemUiVisibility =
|
|
77
|
-
act.window.decorView.systemUiVisibility and
|
|
78
|
-
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION.inv()
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
@ReactMethod
|
|
85
|
-
fun setNavigationBarButtonStyle(style: String) {
|
|
86
|
-
val act = activity() ?: return
|
|
87
|
-
act.runOnUiThread {
|
|
88
|
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
|
89
|
-
val controller = act.window.insetsController ?: return@runOnUiThread
|
|
90
|
-
controller.setSystemBarsAppearance(
|
|
91
|
-
if (style == "dark")
|
|
92
|
-
WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS
|
|
93
|
-
else 0,
|
|
94
|
-
WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS
|
|
95
|
-
)
|
|
96
|
-
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
97
|
-
@Suppress("DEPRECATION")
|
|
98
|
-
val flags = act.window.decorView.systemUiVisibility
|
|
99
|
-
act.window.decorView.systemUiVisibility = if (style == "dark") {
|
|
100
|
-
flags or View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
|
|
101
|
-
} else {
|
|
102
|
-
flags and View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR.inv()
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
@ReactMethod
|
|
109
|
-
fun setNavigationBarStyle(style: String) {
|
|
110
|
-
// "style" maps to button style + optional color hinting
|
|
111
|
-
val act = activity() ?: return
|
|
112
|
-
act.runOnUiThread {
|
|
113
|
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
|
114
|
-
val controller = act.window.insetsController ?: return@runOnUiThread
|
|
115
|
-
val useLightIcons = style == "light"
|
|
116
|
-
controller.setSystemBarsAppearance(
|
|
117
|
-
if (useLightIcons) 0
|
|
118
|
-
else WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS,
|
|
119
|
-
WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS
|
|
120
|
-
)
|
|
121
|
-
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
122
|
-
@Suppress("DEPRECATION")
|
|
123
|
-
val flags = act.window.decorView.systemUiVisibility
|
|
124
|
-
act.window.decorView.systemUiVisibility = when (style) {
|
|
125
|
-
"dark" -> flags or View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
|
|
126
|
-
else -> flags and View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR.inv()
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
@ReactMethod
|
|
133
|
-
fun setNavigationBarBehavior(behavior: String) {
|
|
134
|
-
val act = activity() ?: return
|
|
135
|
-
act.runOnUiThread {
|
|
136
|
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
|
137
|
-
val controller = act.window.insetsController ?: return@runOnUiThread
|
|
138
|
-
controller.systemBarsBehavior = when (behavior) {
|
|
139
|
-
"inset-swipe" ->
|
|
140
|
-
WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE
|
|
141
|
-
"inset-touch" ->
|
|
142
|
-
WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_TOUCH
|
|
143
|
-
else -> // "overlay-swipe" (default)
|
|
144
|
-
WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
// API < 30: behavior is controlled via systemUiVisibility flags
|
|
148
|
-
// IMMERSIVE_STICKY is the closest to overlay-swipe on older APIs
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// ═══════════════════════════════════════════════
|
|
153
|
-
// STATUS BAR
|
|
154
|
-
// ═══════════════════════════════════════════════
|
|
155
|
-
|
|
156
|
-
@ReactMethod
|
|
157
|
-
fun setStatusBarColor(color: String) {
|
|
158
|
-
val act = activity() ?: return
|
|
159
|
-
act.runOnUiThread {
|
|
160
|
-
try {
|
|
161
|
-
act.window.statusBarColor = Color.parseColor(color)
|
|
162
|
-
} catch (e: Exception) {
|
|
163
|
-
// ignore invalid color
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
@ReactMethod
|
|
169
|
-
fun setStatusBarStyle(style: String) {
|
|
170
|
-
val act = activity() ?: return
|
|
171
|
-
act.runOnUiThread {
|
|
172
|
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
|
173
|
-
val controller = act.window.insetsController ?: return@runOnUiThread
|
|
174
|
-
controller.setSystemBarsAppearance(
|
|
175
|
-
if (style == "dark")
|
|
176
|
-
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
|
|
177
|
-
else 0,
|
|
178
|
-
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
|
|
179
|
-
)
|
|
180
|
-
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
181
|
-
@Suppress("DEPRECATION")
|
|
182
|
-
val flags = act.window.decorView.systemUiVisibility
|
|
183
|
-
act.window.decorView.systemUiVisibility = if (style == "dark") {
|
|
184
|
-
flags or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
|
|
185
|
-
} else {
|
|
186
|
-
flags and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv()
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
@ReactMethod
|
|
193
|
-
fun setStatusBarVisibility(visible: Boolean) {
|
|
194
|
-
val act = activity() ?: return
|
|
195
|
-
act.runOnUiThread {
|
|
196
|
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
|
197
|
-
val controller = act.window.insetsController ?: return@runOnUiThread
|
|
198
|
-
if (visible) {
|
|
199
|
-
controller.show(android.view.WindowInsets.Type.statusBars())
|
|
200
|
-
} else {
|
|
201
|
-
controller.hide(android.view.WindowInsets.Type.statusBars())
|
|
202
|
-
}
|
|
203
|
-
} else {
|
|
204
|
-
@Suppress("DEPRECATION")
|
|
205
|
-
if (visible) {
|
|
206
|
-
act.window.decorView.systemUiVisibility =
|
|
207
|
-
act.window.decorView.systemUiVisibility and
|
|
208
|
-
View.SYSTEM_UI_FLAG_FULLSCREEN.inv()
|
|
209
|
-
} else {
|
|
210
|
-
act.window.decorView.systemUiVisibility =
|
|
211
|
-
act.window.decorView.systemUiVisibility or
|
|
212
|
-
View.SYSTEM_UI_FLAG_FULLSCREEN
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
}
|
|
40
|
+
else -> AudioManager.STREAM_MUSIC
|
|
216
41
|
}
|
|
217
42
|
|
|
218
43
|
// ═══════════════════════════════════════════════
|
|
@@ -235,13 +60,11 @@ class SystemBarModule(
|
|
|
235
60
|
val act = activity()
|
|
236
61
|
if (act != null) {
|
|
237
62
|
val lp = act.window.attributes
|
|
238
|
-
// screenBrightness == -1 means "use system default"
|
|
239
63
|
if (lp.screenBrightness >= 0f) {
|
|
240
64
|
promise.resolve(lp.screenBrightness.toDouble())
|
|
241
65
|
return
|
|
242
66
|
}
|
|
243
67
|
}
|
|
244
|
-
// Fall back to system brightness setting (0–255 → 0.0–1.0)
|
|
245
68
|
val sysBrightness = Settings.System.getInt(
|
|
246
69
|
reactContext.contentResolver,
|
|
247
70
|
Settings.System.SCREEN_BRIGHTNESS,
|
|
@@ -268,23 +91,21 @@ class SystemBarModule(
|
|
|
268
91
|
fun setVolume(level: Float, stream: String) {
|
|
269
92
|
try {
|
|
270
93
|
val am = audioManager()
|
|
271
|
-
val
|
|
272
|
-
val max = am.getStreamMaxVolume(
|
|
94
|
+
val type = streamType(stream)
|
|
95
|
+
val max = am.getStreamMaxVolume(type)
|
|
273
96
|
val vol = (level.coerceIn(0f, 1f) * max).toInt()
|
|
274
97
|
val flags = if (suppressVolumeHUD) 0 else AudioManager.FLAG_SHOW_UI
|
|
275
|
-
am.setStreamVolume(
|
|
276
|
-
} catch (
|
|
277
|
-
// ignore
|
|
278
|
-
}
|
|
98
|
+
am.setStreamVolume(type, vol, flags)
|
|
99
|
+
} catch (_: Exception) {}
|
|
279
100
|
}
|
|
280
101
|
|
|
281
102
|
@ReactMethod
|
|
282
103
|
fun getVolume(stream: String, promise: Promise) {
|
|
283
104
|
try {
|
|
284
105
|
val am = audioManager()
|
|
285
|
-
val
|
|
286
|
-
val current = am.getStreamVolume(
|
|
287
|
-
val max = am.getStreamMaxVolume(
|
|
106
|
+
val type = streamType(stream)
|
|
107
|
+
val current = am.getStreamVolume(type)
|
|
108
|
+
val max = am.getStreamMaxVolume(type)
|
|
288
109
|
promise.resolve(if (max > 0) current.toDouble() / max else 0.0)
|
|
289
110
|
} catch (e: Exception) {
|
|
290
111
|
promise.reject("VOLUME_ERROR", e.message, e)
|
|
@@ -312,32 +133,30 @@ class SystemBarModule(
|
|
|
312
133
|
val act = activity() ?: return
|
|
313
134
|
act.runOnUiThread {
|
|
314
135
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
|
136
|
+
// API 30+ — WindowInsetsController (modern, no deprecated flags)
|
|
315
137
|
val controller = act.window.insetsController ?: return@runOnUiThread
|
|
316
138
|
if (enable) {
|
|
317
139
|
controller.hide(
|
|
318
|
-
|
|
319
|
-
android.view.WindowInsets.Type.navigationBars()
|
|
140
|
+
WindowInsets.Type.statusBars() or WindowInsets.Type.navigationBars()
|
|
320
141
|
)
|
|
321
142
|
controller.systemBarsBehavior =
|
|
322
143
|
WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
|
323
144
|
} else {
|
|
324
145
|
controller.show(
|
|
325
|
-
|
|
326
|
-
android.view.WindowInsets.Type.navigationBars()
|
|
146
|
+
WindowInsets.Type.statusBars() or WindowInsets.Type.navigationBars()
|
|
327
147
|
)
|
|
328
148
|
}
|
|
329
149
|
} else {
|
|
150
|
+
// API 21–29: only path available; suppressed intentionally
|
|
330
151
|
@Suppress("DEPRECATION")
|
|
331
|
-
if (enable) {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
|
152
|
+
act.window.decorView.systemUiVisibility = if (enable) {
|
|
153
|
+
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
|
|
154
|
+
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
|
|
155
|
+
View.SYSTEM_UI_FLAG_FULLSCREEN or
|
|
156
|
+
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or
|
|
157
|
+
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
|
338
158
|
} else {
|
|
339
|
-
|
|
340
|
-
View.SYSTEM_UI_FLAG_VISIBLE
|
|
159
|
+
View.SYSTEM_UI_FLAG_VISIBLE
|
|
341
160
|
}
|
|
342
161
|
}
|
|
343
162
|
}
|
|
@@ -351,11 +170,11 @@ class SystemBarModule(
|
|
|
351
170
|
fun setOrientation(mode: String) {
|
|
352
171
|
val act = activity() ?: return
|
|
353
172
|
act.requestedOrientation = when (mode) {
|
|
354
|
-
"portrait"
|
|
355
|
-
"landscape"
|
|
356
|
-
"landscape-left"
|
|
357
|
-
"landscape-right"
|
|
358
|
-
else
|
|
173
|
+
"portrait" -> ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
|
174
|
+
"landscape" -> ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
|
|
175
|
+
"landscape-left" -> ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
|
|
176
|
+
"landscape-right" -> ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
|
|
177
|
+
else -> ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
|
|
359
178
|
}
|
|
360
179
|
}
|
|
361
|
-
}
|
|
180
|
+
}
|
|
@@ -15,6 +15,7 @@ class SystemBarPackage : ReactPackage {
|
|
|
15
15
|
reactContext: ReactApplicationContext
|
|
16
16
|
): List<NativeModule> = listOf(SystemBarModule(reactContext))
|
|
17
17
|
|
|
18
|
+
@Suppress("DEPRECATION")
|
|
18
19
|
override fun createViewManagers(
|
|
19
20
|
reactContext: ReactApplicationContext
|
|
20
21
|
): List<ViewManager<*, *>> = emptyList()
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rn-system-bar",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.3",
|
|
4
4
|
"description": "Control Android & iOS system bars, brightness, volume, orientation and screen flags from React Native.",
|
|
5
5
|
"main": "index.ts",
|
|
6
6
|
"react-native": "index.ts",
|
|
7
7
|
"types": "src/types.ts",
|
|
8
|
+
"homepage": "https://github.com/your-org/rn-system-bar",
|
|
8
9
|
"license": "MIT",
|
|
9
10
|
"author": "Your Name",
|
|
10
11
|
"keywords": [
|
|
@@ -30,10 +31,5 @@
|
|
|
30
31
|
"peerDependencies": {
|
|
31
32
|
"react": ">=18.0.0",
|
|
32
33
|
"react-native": ">=0.73.0"
|
|
33
|
-
},
|
|
34
|
-
"codegenConfig": {
|
|
35
|
-
"name": "RNSystemBarSpec",
|
|
36
|
-
"type": "modules",
|
|
37
|
-
"jsSrcsDir": "specs"
|
|
38
34
|
}
|
|
39
35
|
}
|
package/src/SystemBar.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
// ─────────────────────────────────────────────
|
|
2
2
|
// rn-system-bar · SystemBar.ts
|
|
3
|
+
// v4 — expo-navigation-bar based, zero deprecated APIs
|
|
3
4
|
// ─────────────────────────────────────────────
|
|
4
5
|
|
|
5
|
-
import
|
|
6
|
+
import * as NavigationBar from "expo-navigation-bar";
|
|
7
|
+
import { NativeModules, Platform, StatusBar } from "react-native";
|
|
6
8
|
|
|
7
9
|
import type {
|
|
8
10
|
NavigationBarBehavior,
|
|
@@ -14,20 +16,15 @@ import type {
|
|
|
14
16
|
VolumeStream,
|
|
15
17
|
} from "./types";
|
|
16
18
|
|
|
17
|
-
const { SystemBar } = NativeModules;
|
|
18
|
-
|
|
19
|
-
// ─── Guard helper ──────────────────────────────
|
|
20
|
-
// Navigation-bar APIs are Android-only.
|
|
21
|
-
// iOS has no navigation bar concept.
|
|
22
|
-
// All other APIs work on both platforms.
|
|
19
|
+
const { SystemBar: SystemBarNative } = NativeModules;
|
|
23
20
|
|
|
24
21
|
const isAndroid = Platform.OS === "android";
|
|
25
22
|
|
|
26
|
-
const androidOnly = (name: string) => {
|
|
23
|
+
const androidOnly = (name: string): boolean => {
|
|
27
24
|
if (!isAndroid) {
|
|
28
25
|
if (__DEV__) {
|
|
29
26
|
console.warn(
|
|
30
|
-
`[rn-system-bar] ${name}() is Android-only and
|
|
27
|
+
`[rn-system-bar] ${name}() is Android-only and is a no-op on iOS.`,
|
|
31
28
|
);
|
|
32
29
|
}
|
|
33
30
|
return false;
|
|
@@ -35,28 +32,28 @@ const androidOnly = (name: string) => {
|
|
|
35
32
|
return true;
|
|
36
33
|
};
|
|
37
34
|
|
|
38
|
-
const
|
|
39
|
-
if (!
|
|
35
|
+
const checkNative = () => {
|
|
36
|
+
if (!SystemBarNative) {
|
|
40
37
|
throw new Error(
|
|
41
|
-
"[rn-system-bar] Native module not found. "
|
|
42
|
-
"Did you forget to run `pod install` (iOS) or rebuild the Android project?"
|
|
38
|
+
"[rn-system-bar] Native module not found. Rebuild your Android/iOS project.",
|
|
43
39
|
);
|
|
44
40
|
}
|
|
45
41
|
};
|
|
46
42
|
|
|
47
43
|
// ═══════════════════════════════════════════════
|
|
48
|
-
// NAVIGATION BAR (Android
|
|
44
|
+
// NAVIGATION BAR — expo-navigation-bar (Android only)
|
|
45
|
+
// Uses WindowInsetsController internally on API 30+.
|
|
46
|
+
// Zero deprecated APIs.
|
|
49
47
|
// ═══════════════════════════════════════════════
|
|
50
48
|
|
|
51
49
|
/**
|
|
52
50
|
* Set navigation bar background color.
|
|
53
|
-
* @param color Hex
|
|
51
|
+
* @param color Hex string e.g. "#000000"
|
|
54
52
|
* @platform android
|
|
55
53
|
*/
|
|
56
|
-
export const setNavigationBarColor = (color: string): void => {
|
|
57
|
-
if (!androidOnly("setNavigationBarColor")) return;
|
|
58
|
-
|
|
59
|
-
SystemBar.setNavigationBarColor(color);
|
|
54
|
+
export const setNavigationBarColor = (color: string): Promise<void> => {
|
|
55
|
+
if (!androidOnly("setNavigationBarColor")) return Promise.resolve();
|
|
56
|
+
return NavigationBar.setBackgroundColorAsync(color);
|
|
60
57
|
};
|
|
61
58
|
|
|
62
59
|
/**
|
|
@@ -64,91 +61,96 @@ export const setNavigationBarColor = (color: string): void => {
|
|
|
64
61
|
* @platform android
|
|
65
62
|
*/
|
|
66
63
|
export const setNavigationBarVisibility = (
|
|
67
|
-
mode: NavigationBarVisibility
|
|
68
|
-
): void => {
|
|
69
|
-
if (!androidOnly("setNavigationBarVisibility")) return;
|
|
70
|
-
|
|
71
|
-
SystemBar.setNavigationBarVisibility(mode);
|
|
64
|
+
mode: NavigationBarVisibility,
|
|
65
|
+
): Promise<void> => {
|
|
66
|
+
if (!androidOnly("setNavigationBarVisibility")) return Promise.resolve();
|
|
67
|
+
return NavigationBar.setVisibilityAsync(mode);
|
|
72
68
|
};
|
|
73
69
|
|
|
74
70
|
/**
|
|
75
|
-
* Set icon/button style
|
|
71
|
+
* Set navigation bar icon/button style.
|
|
76
72
|
* @param style "light" = white icons | "dark" = black icons
|
|
77
73
|
* @platform android
|
|
78
74
|
*/
|
|
79
75
|
export const setNavigationBarButtonStyle = (
|
|
80
|
-
style: NavigationBarButtonStyle
|
|
81
|
-
): void => {
|
|
82
|
-
if (!androidOnly("setNavigationBarButtonStyle")) return;
|
|
83
|
-
|
|
84
|
-
SystemBar.setNavigationBarButtonStyle(style);
|
|
76
|
+
style: NavigationBarButtonStyle,
|
|
77
|
+
): Promise<void> => {
|
|
78
|
+
if (!androidOnly("setNavigationBarButtonStyle")) return Promise.resolve();
|
|
79
|
+
return NavigationBar.setButtonStyleAsync(style);
|
|
85
80
|
};
|
|
86
81
|
|
|
87
82
|
/**
|
|
88
|
-
* Set
|
|
83
|
+
* Set navigation bar visual style.
|
|
89
84
|
* @platform android
|
|
90
85
|
*/
|
|
91
|
-
export const setNavigationBarStyle = (
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
86
|
+
export const setNavigationBarStyle = (
|
|
87
|
+
style: NavigationBarStyle,
|
|
88
|
+
): Promise<void> => {
|
|
89
|
+
if (!androidOnly("setNavigationBarStyle")) return Promise.resolve();
|
|
90
|
+
const buttonStyle: NavigationBarButtonStyle =
|
|
91
|
+
style === "dark" || style === "auto" ? "dark" : "light";
|
|
92
|
+
return NavigationBar.setButtonStyleAsync(buttonStyle);
|
|
95
93
|
};
|
|
96
94
|
|
|
97
95
|
/**
|
|
98
|
-
* Set
|
|
96
|
+
* Set navigation bar gesture behavior.
|
|
99
97
|
* @platform android
|
|
100
98
|
*/
|
|
101
99
|
export const setNavigationBarBehavior = (
|
|
102
|
-
behavior: NavigationBarBehavior
|
|
103
|
-
): void => {
|
|
104
|
-
if (!androidOnly("setNavigationBarBehavior")) return;
|
|
105
|
-
|
|
106
|
-
SystemBar.setNavigationBarBehavior(behavior);
|
|
100
|
+
behavior: NavigationBarBehavior,
|
|
101
|
+
): Promise<void> => {
|
|
102
|
+
if (!androidOnly("setNavigationBarBehavior")) return Promise.resolve();
|
|
103
|
+
return NavigationBar.setBehaviorAsync(behavior);
|
|
107
104
|
};
|
|
108
105
|
|
|
109
106
|
// ═══════════════════════════════════════════════
|
|
110
107
|
// STATUS BAR
|
|
108
|
+
// React Native StatusBar — cross-platform, no deprecated APIs.
|
|
111
109
|
// ═══════════════════════════════════════════════
|
|
112
110
|
|
|
113
111
|
/**
|
|
114
112
|
* Set status bar background color.
|
|
115
|
-
* @
|
|
116
|
-
* @platform android (iOS ignores background color by OS design)
|
|
113
|
+
* @platform android
|
|
117
114
|
*/
|
|
118
|
-
export const setStatusBarColor = (color: string): void => {
|
|
115
|
+
export const setStatusBarColor = (color: string, animated = false): void => {
|
|
119
116
|
if (!androidOnly("setStatusBarColor")) return;
|
|
120
|
-
|
|
121
|
-
SystemBar.setStatusBarColor(color);
|
|
117
|
+
StatusBar.setBackgroundColor(color, animated);
|
|
122
118
|
};
|
|
123
119
|
|
|
124
120
|
/**
|
|
125
|
-
* Set status bar icon style
|
|
126
|
-
*
|
|
121
|
+
* Set status bar icon style.
|
|
122
|
+
* "light" = white icons | "dark" = dark icons
|
|
127
123
|
*/
|
|
128
|
-
export const setStatusBarStyle = (
|
|
129
|
-
|
|
130
|
-
|
|
124
|
+
export const setStatusBarStyle = (
|
|
125
|
+
style: StatusBarStyle,
|
|
126
|
+
animated = false,
|
|
127
|
+
): void => {
|
|
128
|
+
StatusBar.setBarStyle(
|
|
129
|
+
style === "light" ? "light-content" : "dark-content",
|
|
130
|
+
animated,
|
|
131
|
+
);
|
|
131
132
|
};
|
|
132
133
|
|
|
133
134
|
/**
|
|
134
135
|
* Show or hide the status bar.
|
|
135
136
|
*/
|
|
136
|
-
export const setStatusBarVisibility = (
|
|
137
|
-
|
|
138
|
-
|
|
137
|
+
export const setStatusBarVisibility = (
|
|
138
|
+
visible: boolean,
|
|
139
|
+
animated = false,
|
|
140
|
+
): void => {
|
|
141
|
+
StatusBar.setHidden(!visible, animated ? "slide" : "none");
|
|
139
142
|
};
|
|
140
143
|
|
|
141
144
|
// ═══════════════════════════════════════════════
|
|
142
|
-
// BRIGHTNESS
|
|
145
|
+
// BRIGHTNESS — native module
|
|
143
146
|
// ═══════════════════════════════════════════════
|
|
144
147
|
|
|
145
148
|
/**
|
|
146
|
-
* Set screen brightness.
|
|
147
|
-
* @param level 0.0 (min) – 1.0 (max)
|
|
149
|
+
* Set screen brightness (0.0 – 1.0).
|
|
148
150
|
*/
|
|
149
151
|
export const setBrightness = (level: number): void => {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
+
checkNative();
|
|
153
|
+
SystemBarNative.setBrightness(Math.max(0, Math.min(1, level)));
|
|
152
154
|
};
|
|
153
155
|
|
|
154
156
|
/**
|
|
@@ -156,81 +158,76 @@ export const setBrightness = (level: number): void => {
|
|
|
156
158
|
* @returns Promise<number> 0.0 – 1.0
|
|
157
159
|
*/
|
|
158
160
|
export const getBrightness = (): Promise<number> => {
|
|
159
|
-
|
|
160
|
-
return
|
|
161
|
+
checkNative();
|
|
162
|
+
return SystemBarNative.getBrightness();
|
|
161
163
|
};
|
|
162
164
|
|
|
163
165
|
// ═══════════════════════════════════════════════
|
|
164
|
-
// VOLUME
|
|
166
|
+
// VOLUME — native module
|
|
165
167
|
// ═══════════════════════════════════════════════
|
|
166
168
|
|
|
167
169
|
/**
|
|
168
|
-
* Set volume level.
|
|
169
|
-
* @param
|
|
170
|
-
* @param stream Audio stream to target (default: "music")
|
|
170
|
+
* Set volume level (0.0 – 1.0).
|
|
171
|
+
* @param stream "music" | "ring" | "notification" | "alarm" | "system"
|
|
171
172
|
*/
|
|
172
173
|
export const setVolume = (
|
|
173
174
|
level: number,
|
|
174
|
-
stream: VolumeStream = "music"
|
|
175
|
+
stream: VolumeStream = "music",
|
|
175
176
|
): void => {
|
|
176
|
-
|
|
177
|
-
|
|
177
|
+
checkNative();
|
|
178
|
+
SystemBarNative.setVolume(Math.max(0, Math.min(1, level)), stream);
|
|
178
179
|
};
|
|
179
180
|
|
|
180
181
|
/**
|
|
181
|
-
* Get current volume level.
|
|
182
|
-
* @param stream Audio stream to query (default: "music")
|
|
183
|
-
* @returns Promise<number> 0.0 – 1.0
|
|
182
|
+
* Get current volume level (0.0 – 1.0).
|
|
184
183
|
*/
|
|
185
184
|
export const getVolume = (stream: VolumeStream = "music"): Promise<number> => {
|
|
186
|
-
|
|
187
|
-
return
|
|
185
|
+
checkNative();
|
|
186
|
+
return SystemBarNative.getVolume(stream);
|
|
188
187
|
};
|
|
189
188
|
|
|
190
189
|
/**
|
|
191
|
-
* Show or hide the system
|
|
192
|
-
* @param visible false = suppress the volume popup
|
|
190
|
+
* Show or hide the system volume popup.
|
|
193
191
|
* @platform android
|
|
194
192
|
*/
|
|
195
193
|
export const setVolumeHUDVisible = (visible: boolean): void => {
|
|
196
194
|
if (!androidOnly("setVolumeHUDVisible")) return;
|
|
197
|
-
|
|
198
|
-
|
|
195
|
+
checkNative();
|
|
196
|
+
SystemBarNative.setVolumeHUDVisible(visible);
|
|
199
197
|
};
|
|
200
198
|
|
|
201
199
|
// ═══════════════════════════════════════════════
|
|
202
|
-
// SCREEN
|
|
200
|
+
// SCREEN — native module
|
|
203
201
|
// ═══════════════════════════════════════════════
|
|
204
202
|
|
|
205
203
|
/**
|
|
206
|
-
* Prevent the screen from
|
|
207
|
-
* @param enable true = keep screen on | false = allow sleep
|
|
204
|
+
* Prevent the screen from going to sleep.
|
|
208
205
|
*/
|
|
209
206
|
export const keepScreenOn = (enable: boolean): void => {
|
|
210
|
-
|
|
211
|
-
|
|
207
|
+
checkNative();
|
|
208
|
+
SystemBarNative.keepScreenOn(enable);
|
|
212
209
|
};
|
|
213
210
|
|
|
214
211
|
/**
|
|
215
|
-
* Enable
|
|
216
|
-
*
|
|
212
|
+
* Enable immersive fullscreen (hides status + nav bar).
|
|
213
|
+
* Uses WindowInsetsController on API 30+.
|
|
217
214
|
* @platform android
|
|
218
215
|
*/
|
|
219
216
|
export const immersiveMode = (enable: boolean): void => {
|
|
220
217
|
if (!androidOnly("immersiveMode")) return;
|
|
221
|
-
|
|
222
|
-
|
|
218
|
+
checkNative();
|
|
219
|
+
SystemBarNative.immersiveMode(enable);
|
|
223
220
|
};
|
|
224
221
|
|
|
225
222
|
// ═══════════════════════════════════════════════
|
|
226
|
-
// ORIENTATION
|
|
223
|
+
// ORIENTATION — native module
|
|
227
224
|
// ═══════════════════════════════════════════════
|
|
228
225
|
|
|
229
226
|
/**
|
|
230
227
|
* Lock or unlock screen orientation.
|
|
231
|
-
*
|
|
228
|
+
* "portrait" | "landscape" | "landscape-left" | "landscape-right" | "auto"
|
|
232
229
|
*/
|
|
233
230
|
export const setOrientation = (mode: Orientation): void => {
|
|
234
|
-
|
|
235
|
-
|
|
231
|
+
checkNative();
|
|
232
|
+
SystemBarNative.setOrientation(mode);
|
|
236
233
|
};
|