rn-system-bar 3.0.3 → 3.1.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.
- package/android/src/main/java/com/systembar/SystemBarModule.kt +345 -75
- package/android/src/main/java/com/systembar/SystemBarPackage.kt +2 -1
- package/index.ts +9 -0
- package/ios/SystemBarModule.m +32 -12
- package/ios/SystemBarModule.swift +241 -83
- package/lib/index.d.ts +4 -0
- package/lib/index.js +29 -0
- package/lib/specs/NativeSystemBar.d.ts +21 -0
- package/lib/specs/NativeSystemBar.js +8 -0
- package/lib/src/SystemBar.d.ts +73 -0
- package/lib/src/SystemBar.js +292 -0
- package/lib/src/types.d.ts +44 -0
- package/lib/src/types.js +5 -0
- package/lib/src/useSystemBar.d.ts +49 -0
- package/lib/src/useSystemBar.js +194 -0
- package/package.json +14 -4
- package/rn-system-bar.podspec +1 -1
- package/src/SystemBar.ts +199 -122
- package/src/types.ts +70 -43
- package/src/useSystemBar.ts +191 -0
package/src/SystemBar.ts
CHANGED
|
@@ -1,233 +1,310 @@
|
|
|
1
1
|
// ─────────────────────────────────────────────
|
|
2
|
-
// rn-system-bar · SystemBar.ts
|
|
3
|
-
//
|
|
2
|
+
// rn-system-bar · SystemBar.ts v5
|
|
3
|
+
// All features — Android + iOS
|
|
4
4
|
// ─────────────────────────────────────────────
|
|
5
5
|
|
|
6
|
-
import
|
|
7
|
-
import { NativeModules, Platform, StatusBar } from "react-native";
|
|
6
|
+
import { NativeModules, Platform, StatusBar, Vibration } from "react-native";
|
|
8
7
|
|
|
9
8
|
import type {
|
|
9
|
+
BatteryInfo,
|
|
10
|
+
FontScaleInfo,
|
|
11
|
+
HapticPattern,
|
|
10
12
|
NavigationBarBehavior,
|
|
11
13
|
NavigationBarButtonStyle,
|
|
12
14
|
NavigationBarStyle,
|
|
13
15
|
NavigationBarVisibility,
|
|
16
|
+
NetworkInfo,
|
|
14
17
|
Orientation,
|
|
18
|
+
ScreencastInfo,
|
|
15
19
|
StatusBarStyle,
|
|
16
20
|
VolumeStream,
|
|
17
21
|
} from "./types";
|
|
18
22
|
|
|
19
|
-
|
|
23
|
+
// expo-navigation-bar — peer dep, loaded at runtime
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
25
|
+
const NavBar = (() => {
|
|
26
|
+
try { return require("expo-navigation-bar"); }
|
|
27
|
+
catch { return null; }
|
|
28
|
+
})();
|
|
29
|
+
|
|
30
|
+
const { SystemBar: Native } = NativeModules;
|
|
20
31
|
|
|
21
32
|
const isAndroid = Platform.OS === "android";
|
|
33
|
+
const isIOS = Platform.OS === "ios";
|
|
22
34
|
|
|
23
35
|
const androidOnly = (name: string): boolean => {
|
|
24
36
|
if (!isAndroid) {
|
|
25
|
-
if (__DEV__) {
|
|
26
|
-
console.warn(
|
|
27
|
-
`[rn-system-bar] ${name}() is Android-only and is a no-op on iOS.`,
|
|
28
|
-
);
|
|
29
|
-
}
|
|
37
|
+
if (__DEV__) console.warn(`[rn-system-bar] ${name}() is Android-only, no-op on iOS.`);
|
|
30
38
|
return false;
|
|
31
39
|
}
|
|
32
40
|
return true;
|
|
33
41
|
};
|
|
34
42
|
|
|
35
43
|
const checkNative = () => {
|
|
36
|
-
if (!
|
|
37
|
-
throw new Error(
|
|
38
|
-
"[rn-system-bar] Native module not found. Rebuild your Android/iOS project.",
|
|
39
|
-
);
|
|
40
|
-
}
|
|
44
|
+
if (!Native) throw new Error("[rn-system-bar] Native module not found. Rebuild your project.");
|
|
41
45
|
};
|
|
42
46
|
|
|
43
47
|
// ═══════════════════════════════════════════════
|
|
44
|
-
// NAVIGATION BAR — expo-navigation-bar
|
|
45
|
-
// Uses WindowInsetsController internally on API 30+.
|
|
46
|
-
// Zero deprecated APIs.
|
|
48
|
+
// NAVIGATION BAR (Android — expo-navigation-bar)
|
|
47
49
|
// ═══════════════════════════════════════════════
|
|
48
50
|
|
|
49
|
-
/**
|
|
50
|
-
* Set navigation bar background color.
|
|
51
|
-
* @param color Hex string e.g. "#000000"
|
|
52
|
-
* @platform android
|
|
53
|
-
*/
|
|
54
51
|
export const setNavigationBarColor = (color: string): Promise<void> => {
|
|
55
52
|
if (!androidOnly("setNavigationBarColor")) return Promise.resolve();
|
|
56
|
-
return
|
|
53
|
+
return NavBar?.setBackgroundColorAsync(color) ?? Promise.resolve();
|
|
57
54
|
};
|
|
58
55
|
|
|
59
|
-
|
|
60
|
-
* Show or hide the navigation bar.
|
|
61
|
-
* @platform android
|
|
62
|
-
*/
|
|
63
|
-
export const setNavigationBarVisibility = (
|
|
64
|
-
mode: NavigationBarVisibility,
|
|
65
|
-
): Promise<void> => {
|
|
56
|
+
export const setNavigationBarVisibility = (mode: NavigationBarVisibility): Promise<void> => {
|
|
66
57
|
if (!androidOnly("setNavigationBarVisibility")) return Promise.resolve();
|
|
67
|
-
return
|
|
58
|
+
return NavBar?.setVisibilityAsync(mode) ?? Promise.resolve();
|
|
68
59
|
};
|
|
69
60
|
|
|
70
|
-
|
|
71
|
-
* Set navigation bar icon/button style.
|
|
72
|
-
* @param style "light" = white icons | "dark" = black icons
|
|
73
|
-
* @platform android
|
|
74
|
-
*/
|
|
75
|
-
export const setNavigationBarButtonStyle = (
|
|
76
|
-
style: NavigationBarButtonStyle,
|
|
77
|
-
): Promise<void> => {
|
|
61
|
+
export const setNavigationBarButtonStyle = (style: NavigationBarButtonStyle): Promise<void> => {
|
|
78
62
|
if (!androidOnly("setNavigationBarButtonStyle")) return Promise.resolve();
|
|
79
|
-
return
|
|
63
|
+
return NavBar?.setButtonStyleAsync(style) ?? Promise.resolve();
|
|
80
64
|
};
|
|
81
65
|
|
|
82
|
-
|
|
83
|
-
* Set navigation bar visual style.
|
|
84
|
-
* @platform android
|
|
85
|
-
*/
|
|
86
|
-
export const setNavigationBarStyle = (
|
|
87
|
-
style: NavigationBarStyle,
|
|
88
|
-
): Promise<void> => {
|
|
66
|
+
export const setNavigationBarStyle = (style: NavigationBarStyle): Promise<void> => {
|
|
89
67
|
if (!androidOnly("setNavigationBarStyle")) return Promise.resolve();
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
return NavigationBar.setButtonStyleAsync(buttonStyle);
|
|
68
|
+
const btn: NavigationBarButtonStyle = style === "dark" || style === "auto" ? "dark" : "light";
|
|
69
|
+
return NavBar?.setButtonStyleAsync(btn) ?? Promise.resolve();
|
|
93
70
|
};
|
|
94
71
|
|
|
95
|
-
|
|
96
|
-
* Set navigation bar gesture behavior.
|
|
97
|
-
* @platform android
|
|
98
|
-
*/
|
|
99
|
-
export const setNavigationBarBehavior = (
|
|
100
|
-
behavior: NavigationBarBehavior,
|
|
101
|
-
): Promise<void> => {
|
|
72
|
+
export const setNavigationBarBehavior = (behavior: NavigationBarBehavior): Promise<void> => {
|
|
102
73
|
if (!androidOnly("setNavigationBarBehavior")) return Promise.resolve();
|
|
103
|
-
return
|
|
74
|
+
return NavBar?.setBehaviorAsync(behavior) ?? Promise.resolve();
|
|
104
75
|
};
|
|
105
76
|
|
|
106
77
|
// ═══════════════════════════════════════════════
|
|
107
78
|
// STATUS BAR
|
|
108
|
-
// React Native StatusBar — cross-platform, no deprecated APIs.
|
|
109
79
|
// ═══════════════════════════════════════════════
|
|
110
80
|
|
|
111
|
-
/**
|
|
112
|
-
* Set status bar background color.
|
|
113
|
-
* @platform android
|
|
114
|
-
*/
|
|
115
81
|
export const setStatusBarColor = (color: string, animated = false): void => {
|
|
116
82
|
if (!androidOnly("setStatusBarColor")) return;
|
|
117
83
|
StatusBar.setBackgroundColor(color, animated);
|
|
118
84
|
};
|
|
119
85
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
* "light" = white icons | "dark" = dark icons
|
|
123
|
-
*/
|
|
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
|
-
);
|
|
86
|
+
export const setStatusBarStyle = (style: StatusBarStyle, animated = false): void => {
|
|
87
|
+
StatusBar.setBarStyle(style === "light" ? "light-content" : "dark-content", animated);
|
|
132
88
|
};
|
|
133
89
|
|
|
134
|
-
|
|
135
|
-
* Show or hide the status bar.
|
|
136
|
-
*/
|
|
137
|
-
export const setStatusBarVisibility = (
|
|
138
|
-
visible: boolean,
|
|
139
|
-
animated = false,
|
|
140
|
-
): void => {
|
|
90
|
+
export const setStatusBarVisibility = (visible: boolean, animated = false): void => {
|
|
141
91
|
StatusBar.setHidden(!visible, animated ? "slide" : "none");
|
|
142
92
|
};
|
|
143
93
|
|
|
144
94
|
// ═══════════════════════════════════════════════
|
|
145
|
-
// BRIGHTNESS
|
|
95
|
+
// BRIGHTNESS
|
|
96
|
+
// ═══════════════════════════════════════════════
|
|
97
|
+
|
|
98
|
+
export const setBrightness = (level: number): void => {
|
|
99
|
+
checkNative();
|
|
100
|
+
Native.setBrightness(Math.max(0, Math.min(1, level)));
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
export const getBrightness = (): Promise<number> => {
|
|
104
|
+
checkNative();
|
|
105
|
+
return Native.getBrightness();
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// ═══════════════════════════════════════════════
|
|
109
|
+
// VOLUME
|
|
110
|
+
// ═══════════════════════════════════════════════
|
|
111
|
+
|
|
112
|
+
export const setVolume = (level: number, stream: VolumeStream = "music"): void => {
|
|
113
|
+
checkNative();
|
|
114
|
+
Native.setVolume(Math.max(0, Math.min(1, level)), stream);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
export const getVolume = (stream: VolumeStream = "music"): Promise<number> => {
|
|
118
|
+
checkNative();
|
|
119
|
+
return Native.getVolume(stream);
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export const setVolumeHUDVisible = (visible: boolean): void => {
|
|
123
|
+
if (!androidOnly("setVolumeHUDVisible")) return;
|
|
124
|
+
checkNative();
|
|
125
|
+
Native.setVolumeHUDVisible(visible);
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
// ═══════════════════════════════════════════════
|
|
129
|
+
// SCREEN
|
|
130
|
+
// ═══════════════════════════════════════════════
|
|
131
|
+
|
|
132
|
+
export const keepScreenOn = (enable: boolean): void => {
|
|
133
|
+
checkNative();
|
|
134
|
+
Native.keepScreenOn(enable);
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
export const immersiveMode = (enable: boolean): void => {
|
|
138
|
+
if (!androidOnly("immersiveMode")) return;
|
|
139
|
+
checkNative();
|
|
140
|
+
Native.immersiveMode(enable);
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
// ═══════════════════════════════════════════════
|
|
144
|
+
// ORIENTATION
|
|
145
|
+
// ═══════════════════════════════════════════════
|
|
146
|
+
|
|
147
|
+
export const setOrientation = (mode: Orientation): void => {
|
|
148
|
+
checkNative();
|
|
149
|
+
Native.setOrientation(mode);
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
// ═══════════════════════════════════════════════
|
|
153
|
+
// 🆕 NETWORK INFO
|
|
146
154
|
// ═══════════════════════════════════════════════
|
|
147
155
|
|
|
148
156
|
/**
|
|
149
|
-
*
|
|
157
|
+
* Get current network connection info.
|
|
158
|
+
* Includes: type, isConnected, isAirplaneMode, ssid, cellularGeneration
|
|
150
159
|
*/
|
|
151
|
-
export const
|
|
160
|
+
export const getNetworkInfo = (): Promise<NetworkInfo> => {
|
|
152
161
|
checkNative();
|
|
153
|
-
|
|
162
|
+
return Native.getNetworkInfo();
|
|
154
163
|
};
|
|
155
164
|
|
|
156
165
|
/**
|
|
157
|
-
*
|
|
158
|
-
* @returns
|
|
166
|
+
* Subscribe to network changes.
|
|
167
|
+
* @returns unsubscribe function — call it in useEffect cleanup
|
|
168
|
+
* @example
|
|
169
|
+
* const unsub = onNetworkChange((info) => console.log(info));
|
|
170
|
+
* return () => unsub();
|
|
159
171
|
*/
|
|
160
|
-
export const
|
|
172
|
+
export const onNetworkChange = (
|
|
173
|
+
callback: (info: NetworkInfo) => void
|
|
174
|
+
): (() => void) => {
|
|
161
175
|
checkNative();
|
|
162
|
-
|
|
176
|
+
// Native side emits "SystemBar_NetworkChange" events
|
|
177
|
+
const { DeviceEventEmitter } = require("react-native");
|
|
178
|
+
Native.startNetworkListener();
|
|
179
|
+
const sub = DeviceEventEmitter.addListener("SystemBar_NetworkChange", callback);
|
|
180
|
+
return () => {
|
|
181
|
+
sub.remove();
|
|
182
|
+
Native.stopNetworkListener();
|
|
183
|
+
};
|
|
163
184
|
};
|
|
164
185
|
|
|
165
186
|
// ═══════════════════════════════════════════════
|
|
166
|
-
//
|
|
187
|
+
// 🆕 BATTERY
|
|
167
188
|
// ═══════════════════════════════════════════════
|
|
168
189
|
|
|
169
190
|
/**
|
|
170
|
-
*
|
|
171
|
-
* @param stream "music" | "ring" | "notification" | "alarm" | "system"
|
|
191
|
+
* Get current battery info: level (0–100), state, isCharging, isLow.
|
|
172
192
|
*/
|
|
173
|
-
export const
|
|
174
|
-
level: number,
|
|
175
|
-
stream: VolumeStream = "music",
|
|
176
|
-
): void => {
|
|
193
|
+
export const getBatteryInfo = (): Promise<BatteryInfo> => {
|
|
177
194
|
checkNative();
|
|
178
|
-
|
|
195
|
+
return Native.getBatteryInfo();
|
|
179
196
|
};
|
|
180
197
|
|
|
181
198
|
/**
|
|
182
|
-
*
|
|
199
|
+
* Subscribe to battery level / state changes.
|
|
200
|
+
* @returns unsubscribe function
|
|
183
201
|
*/
|
|
184
|
-
export const
|
|
202
|
+
export const onBatteryChange = (
|
|
203
|
+
callback: (info: BatteryInfo) => void
|
|
204
|
+
): (() => void) => {
|
|
185
205
|
checkNative();
|
|
186
|
-
|
|
206
|
+
const { DeviceEventEmitter } = require("react-native");
|
|
207
|
+
Native.startBatteryListener();
|
|
208
|
+
const sub = DeviceEventEmitter.addListener("SystemBar_BatteryChange", callback);
|
|
209
|
+
return () => {
|
|
210
|
+
sub.remove();
|
|
211
|
+
Native.stopBatteryListener();
|
|
212
|
+
};
|
|
187
213
|
};
|
|
188
214
|
|
|
215
|
+
// ═══════════════════════════════════════════════
|
|
216
|
+
// 🆕 HAPTIC FEEDBACK
|
|
217
|
+
// ═══════════════════════════════════════════════
|
|
218
|
+
|
|
189
219
|
/**
|
|
190
|
-
*
|
|
191
|
-
*
|
|
220
|
+
* Trigger haptic feedback.
|
|
221
|
+
*
|
|
222
|
+
* iOS: Uses UIImpactFeedbackGenerator / UINotificationFeedbackGenerator.
|
|
223
|
+
* Android: Uses Vibrator / VibrationEffect (API 26+).
|
|
224
|
+
*
|
|
225
|
+
* @param pattern "light" | "medium" | "heavy" | "success" | "warning" | "error" | "selection"
|
|
192
226
|
*/
|
|
193
|
-
export const
|
|
194
|
-
if (
|
|
195
|
-
|
|
196
|
-
|
|
227
|
+
export const haptic = (pattern: HapticPattern): void => {
|
|
228
|
+
if (isIOS) {
|
|
229
|
+
checkNative();
|
|
230
|
+
Native.haptic(pattern);
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Android fallback using RN's built-in Vibration API
|
|
235
|
+
// when native module is unavailable
|
|
236
|
+
if (isAndroid) {
|
|
237
|
+
checkNative();
|
|
238
|
+
Native.haptic(pattern);
|
|
239
|
+
}
|
|
197
240
|
};
|
|
198
241
|
|
|
199
242
|
// ═══════════════════════════════════════════════
|
|
200
|
-
//
|
|
243
|
+
// 🆕 SCREENCAST DETECTION
|
|
201
244
|
// ═══════════════════════════════════════════════
|
|
202
245
|
|
|
203
246
|
/**
|
|
204
|
-
*
|
|
247
|
+
* Check if screen is currently being cast or mirrored.
|
|
205
248
|
*/
|
|
206
|
-
export const
|
|
249
|
+
export const getScreencastInfo = (): Promise<ScreencastInfo> => {
|
|
250
|
+
checkNative();
|
|
251
|
+
return Native.getScreencastInfo();
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Subscribe to screencast state changes (started / stopped).
|
|
256
|
+
* @returns unsubscribe function
|
|
257
|
+
*/
|
|
258
|
+
export const onScreencastChange = (
|
|
259
|
+
callback: (info: ScreencastInfo) => void
|
|
260
|
+
): (() => void) => {
|
|
207
261
|
checkNative();
|
|
208
|
-
|
|
262
|
+
const { DeviceEventEmitter } = require("react-native");
|
|
263
|
+
Native.startScreencastListener();
|
|
264
|
+
const sub = DeviceEventEmitter.addListener("SystemBar_ScreencastChange", callback);
|
|
265
|
+
return () => {
|
|
266
|
+
sub.remove();
|
|
267
|
+
Native.stopScreencastListener();
|
|
268
|
+
};
|
|
209
269
|
};
|
|
210
270
|
|
|
211
271
|
/**
|
|
212
|
-
*
|
|
213
|
-
*
|
|
272
|
+
* Prevent screen content from appearing in screenshots / recordings.
|
|
273
|
+
* Useful for sensitive screens (payments, passwords).
|
|
214
274
|
* @platform android
|
|
215
275
|
*/
|
|
216
|
-
export const
|
|
217
|
-
if (!androidOnly("
|
|
276
|
+
export const setSecureScreen = (enable: boolean): void => {
|
|
277
|
+
if (!androidOnly("setSecureScreen")) return;
|
|
218
278
|
checkNative();
|
|
219
|
-
|
|
279
|
+
Native.setSecureScreen(enable);
|
|
220
280
|
};
|
|
221
281
|
|
|
222
282
|
// ═══════════════════════════════════════════════
|
|
223
|
-
//
|
|
283
|
+
// 🆕 FONT SCALE / DISPLAY INFO
|
|
224
284
|
// ═══════════════════════════════════════════════
|
|
225
285
|
|
|
226
286
|
/**
|
|
227
|
-
*
|
|
228
|
-
*
|
|
287
|
+
* Get current system font scale and display density.
|
|
288
|
+
* Useful for adapting layout to accessibility settings.
|
|
229
289
|
*/
|
|
230
|
-
export const
|
|
290
|
+
export const getFontScaleInfo = (): Promise<FontScaleInfo> => {
|
|
291
|
+
checkNative();
|
|
292
|
+
return Native.getFontScaleInfo();
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Subscribe to font scale changes (user changes system text size).
|
|
297
|
+
* @returns unsubscribe function
|
|
298
|
+
*/
|
|
299
|
+
export const onFontScaleChange = (
|
|
300
|
+
callback: (info: FontScaleInfo) => void
|
|
301
|
+
): (() => void) => {
|
|
231
302
|
checkNative();
|
|
232
|
-
|
|
303
|
+
const { DeviceEventEmitter } = require("react-native");
|
|
304
|
+
Native.startFontScaleListener();
|
|
305
|
+
const sub = DeviceEventEmitter.addListener("SystemBar_FontScaleChange", callback);
|
|
306
|
+
return () => {
|
|
307
|
+
sub.remove();
|
|
308
|
+
Native.stopFontScaleListener();
|
|
309
|
+
};
|
|
233
310
|
};
|
package/src/types.ts
CHANGED
|
@@ -1,30 +1,21 @@
|
|
|
1
1
|
// ─────────────────────────────────────────────
|
|
2
|
-
// rn-system-bar · types.ts
|
|
2
|
+
// rn-system-bar · types.ts v5
|
|
3
3
|
// ─────────────────────────────────────────────
|
|
4
4
|
|
|
5
|
+
// ── Navigation Bar ────────────────────────────
|
|
5
6
|
export type NavigationBarBehavior =
|
|
6
|
-
| "overlay-swipe"
|
|
7
|
-
| "inset-swipe"
|
|
8
|
-
| "inset-touch";
|
|
7
|
+
| "overlay-swipe"
|
|
8
|
+
| "inset-swipe"
|
|
9
|
+
| "inset-touch";
|
|
9
10
|
|
|
10
|
-
export type NavigationBarButtonStyle =
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
export type NavigationBarButtonStyle = "light" | "dark";
|
|
12
|
+
export type NavigationBarStyle = "auto" | "inverted" | "light" | "dark";
|
|
13
|
+
export type NavigationBarVisibility = "visible" | "hidden";
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
| "inverted" // Inverted from system
|
|
17
|
-
| "light" // Light background nav bar
|
|
18
|
-
| "dark"; // Dark background nav bar
|
|
19
|
-
|
|
20
|
-
export type NavigationBarVisibility =
|
|
21
|
-
| "visible"
|
|
22
|
-
| "hidden";
|
|
23
|
-
|
|
24
|
-
export type StatusBarStyle =
|
|
25
|
-
| "light" // Light icons (for dark backgrounds)
|
|
26
|
-
| "dark"; // Dark icons (for light backgrounds)
|
|
15
|
+
// ── Status Bar ────────────────────────────────
|
|
16
|
+
export type StatusBarStyle = "light" | "dark";
|
|
27
17
|
|
|
18
|
+
// ── Orientation ───────────────────────────────
|
|
28
19
|
export type Orientation =
|
|
29
20
|
| "portrait"
|
|
30
21
|
| "landscape"
|
|
@@ -32,6 +23,7 @@ export type Orientation =
|
|
|
32
23
|
| "landscape-right"
|
|
33
24
|
| "auto";
|
|
34
25
|
|
|
26
|
+
// ── Volume ────────────────────────────────────
|
|
35
27
|
export type VolumeStream =
|
|
36
28
|
| "music"
|
|
37
29
|
| "ring"
|
|
@@ -39,32 +31,67 @@ export type VolumeStream =
|
|
|
39
31
|
| "alarm"
|
|
40
32
|
| "system";
|
|
41
33
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
34
|
+
// ── Network ───────────────────────────────────
|
|
35
|
+
export type NetworkType =
|
|
36
|
+
| "wifi"
|
|
37
|
+
| "cellular"
|
|
38
|
+
| "ethernet"
|
|
39
|
+
| "none"
|
|
40
|
+
| "unknown";
|
|
41
|
+
|
|
42
|
+
export interface NetworkInfo {
|
|
43
|
+
/** Current connection type */
|
|
44
|
+
type: NetworkType;
|
|
45
|
+
/** true if any network is reachable */
|
|
46
|
+
isConnected: boolean;
|
|
47
|
+
/** true if in airplane mode */
|
|
48
|
+
isAirplaneMode: boolean;
|
|
49
|
+
/** WiFi SSID — Android only; null on iOS / when not connected */
|
|
50
|
+
ssid: string | null;
|
|
51
|
+
/** Cellular network generation: "2G" | "3G" | "4G" | "5G" | null */
|
|
52
|
+
cellularGeneration: "2G" | "3G" | "4G" | "5G" | null;
|
|
53
|
+
}
|
|
49
54
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
55
|
+
// ── Battery ───────────────────────────────────
|
|
56
|
+
export type BatteryState =
|
|
57
|
+
| "charging"
|
|
58
|
+
| "discharging"
|
|
59
|
+
| "full"
|
|
60
|
+
| "unknown";
|
|
54
61
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
62
|
+
export interface BatteryInfo {
|
|
63
|
+
/** 0–100 */
|
|
64
|
+
level: number;
|
|
65
|
+
/** Current charging state */
|
|
66
|
+
state: BatteryState;
|
|
67
|
+
/** Shorthand: is it plugged in? */
|
|
68
|
+
isCharging: boolean;
|
|
69
|
+
/** Low battery threshold (<= 20%) */
|
|
70
|
+
isLow: boolean;
|
|
71
|
+
}
|
|
58
72
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
73
|
+
// ── Haptics ───────────────────────────────────
|
|
74
|
+
export type HapticPattern =
|
|
75
|
+
| "light" // subtle tap
|
|
76
|
+
| "medium" // standard tap
|
|
77
|
+
| "heavy" // strong tap
|
|
78
|
+
| "success" // double bump — success feedback
|
|
79
|
+
| "warning" // single bump — warning feedback
|
|
80
|
+
| "error" // triple bump — error feedback
|
|
81
|
+
| "selection"; // light tick — selection change
|
|
63
82
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
83
|
+
// ── Screencast ────────────────────────────────
|
|
84
|
+
export interface ScreencastInfo {
|
|
85
|
+
/** true if screen is currently being cast / mirrored */
|
|
86
|
+
isCasting: boolean;
|
|
87
|
+
/** Name of the display being cast to, or null */
|
|
88
|
+
displayName: string | null;
|
|
89
|
+
}
|
|
67
90
|
|
|
68
|
-
|
|
69
|
-
|
|
91
|
+
// ── Font Scale ────────────────────────────────
|
|
92
|
+
export interface FontScaleInfo {
|
|
93
|
+
/** System font scale multiplier, e.g. 1.0 = default, 1.3 = large */
|
|
94
|
+
fontScale: number;
|
|
95
|
+
/** Display density (Android: dp ratio, iOS: scale) */
|
|
96
|
+
density: number;
|
|
70
97
|
}
|