rn-system-bar 3.1.7 → 3.1.8
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/README.md +81 -40
- package/android/src/main/java/com/systembar/SystemBarModule.kt +288 -13
- package/index.ts +23 -2
- package/ios/SystemBarModule.m +13 -6
- package/ios/SystemBarModule.swift +44 -9
- package/lib/index.d.ts +3 -2
- package/lib/index.js +13 -2
- package/lib/specs/NativeSystemBar.d.ts +9 -0
- package/lib/src/SystemBar.d.ts +83 -5
- package/lib/src/SystemBar.js +161 -12
- package/lib/src/types.d.ts +61 -1
- package/lib/src/useSystemBar.d.ts +35 -4
- package/lib/src/useSystemBar.js +71 -7
- package/lib/src/useTheme.d.ts +24 -0
- package/lib/src/useTheme.js +81 -0
- package/package.json +3 -2
- package/specs/NativeSystemBar.ts +21 -6
- package/src/SystemBar.ts +194 -21
- package/src/types.ts +85 -1
- package/src/useSystemBar.ts +206 -28
- package/src/useTheme.ts +95 -0
|
@@ -226,36 +226,70 @@ class SystemBarModule: RCTEventEmitter {
|
|
|
226
226
|
}
|
|
227
227
|
|
|
228
228
|
// ═══════════════════════════════════════════════
|
|
229
|
-
// 🆕 SCREENCAST
|
|
229
|
+
// 🆕 SYSTEM SCREENCAST (external display / AirPlay mirror)
|
|
230
|
+
// Detects OS-level external screens via UIScreen.
|
|
230
231
|
// ═══════════════════════════════════════════════
|
|
231
232
|
|
|
232
|
-
private func
|
|
233
|
+
private func currentSystemScreencastMap() -> [String: Any] {
|
|
233
234
|
let isCasting = UIScreen.screens.count > 1
|
|
234
235
|
return [
|
|
235
236
|
"isCasting": isCasting,
|
|
236
237
|
"displayName": isCasting ? "External Display" : NSNull(),
|
|
238
|
+
"displays": UIScreen.screens.dropFirst().enumerated().map { idx, _ in
|
|
239
|
+
["id": idx + 1, "name": "External Display \(idx + 1)", "isValid": true]
|
|
240
|
+
},
|
|
237
241
|
]
|
|
238
242
|
}
|
|
239
243
|
|
|
240
244
|
@objc
|
|
241
|
-
func
|
|
242
|
-
|
|
243
|
-
resolve(
|
|
245
|
+
func getSystemScreencastInfo(_ resolve: @escaping RCTPromiseResolveBlock,
|
|
246
|
+
rejecter reject: RCTPromiseRejectBlock) {
|
|
247
|
+
resolve(currentSystemScreencastMap())
|
|
244
248
|
}
|
|
245
249
|
|
|
246
|
-
@objc func
|
|
250
|
+
@objc func startSystemScreencastListener() {
|
|
247
251
|
screencastObserver = NotificationCenter.default.addObserver(
|
|
248
252
|
forName: UIScreen.didConnectNotification, object: nil, queue: .main
|
|
249
253
|
) { [weak self] _ in
|
|
250
|
-
self?.emit("
|
|
254
|
+
self?.emit("SystemBar_SystemScreencastChange", body: self?.currentSystemScreencastMap() ?? [:])
|
|
251
255
|
}
|
|
252
256
|
}
|
|
253
257
|
|
|
254
|
-
@objc func
|
|
258
|
+
@objc func stopSystemScreencastListener() {
|
|
255
259
|
if let obs = screencastObserver { NotificationCenter.default.removeObserver(obs) }
|
|
256
260
|
screencastObserver = nil
|
|
257
261
|
}
|
|
258
262
|
|
|
263
|
+
// ═══════════════════════════════════════════════
|
|
264
|
+
// APP-ONLY CAST (Android MediaRouter — iOS stubs)
|
|
265
|
+
// AirPlay is system-managed on iOS; no public API for app-only casting.
|
|
266
|
+
// ═══════════════════════════════════════════════
|
|
267
|
+
|
|
268
|
+
@objc func startAppCastScan() {
|
|
269
|
+
// iOS: AirPlay is system-managed — no-op. Emit idle state.
|
|
270
|
+
emit("SystemBar_AppCastChange", body: [
|
|
271
|
+
"state": "idle", "devices": [], "connectedDevice": NSNull(), "error": NSNull()
|
|
272
|
+
])
|
|
273
|
+
}
|
|
274
|
+
@objc func stopAppCastScan() {}
|
|
275
|
+
|
|
276
|
+
@objc func connectAppCast(_ deviceId: String, pairingPin: String?) {
|
|
277
|
+
emit("SystemBar_AppCastChange", body: [
|
|
278
|
+
"state": "idle", "devices": [], "connectedDevice": NSNull(),
|
|
279
|
+
"error": "App-only cast not supported on iOS"
|
|
280
|
+
])
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
@objc func disconnectAppCast() {}
|
|
284
|
+
|
|
285
|
+
@objc
|
|
286
|
+
func getAppCastInfo(_ resolve: @escaping RCTPromiseResolveBlock,
|
|
287
|
+
rejecter reject: RCTPromiseRejectBlock) {
|
|
288
|
+
resolve([
|
|
289
|
+
"state": "idle", "devices": [], "connectedDevice": NSNull(), "error": NSNull()
|
|
290
|
+
])
|
|
291
|
+
}
|
|
292
|
+
|
|
259
293
|
// setSecureScreen — iOS doesn't support this via public API (no-op)
|
|
260
294
|
@objc func setSecureScreen(_ enable: Bool) {}
|
|
261
295
|
|
|
@@ -295,9 +329,10 @@ class SystemBarModule: RCTEventEmitter {
|
|
|
295
329
|
@objc func setNavigationBarButtonStyle(_ style: String) {}
|
|
296
330
|
@objc func setNavigationBarStyle(_ style: String) {}
|
|
297
331
|
@objc func setNavigationBarBehavior(_ behavior: String) {}
|
|
332
|
+
// color: hex | "transparent" | "translucent" — Android only
|
|
298
333
|
@objc func setStatusBarColor(_ color: String) {}
|
|
299
334
|
@objc func setVolumeHUDVisible(_ visible: Bool) {}
|
|
300
335
|
@objc func immersiveMode(_ enable: Bool) {}
|
|
301
336
|
@objc func setStatusBarStyle(_ style: String) {}
|
|
302
337
|
@objc func setStatusBarVisibility(_ visible: Bool) {}
|
|
303
|
-
}
|
|
338
|
+
}
|
package/lib/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export * from "./src/SystemBar";
|
|
2
2
|
export * from "./src/types";
|
|
3
|
-
export {
|
|
4
|
-
export
|
|
3
|
+
export { setGlobalThemeMode, useTheme } from "./src/useTheme";
|
|
4
|
+
export { useAppCast, useScreencast, useSystemBar, useSystemScreencast, useTheme as useThemeHook, useThemeSystemBar, } from "./src/useSystemBar";
|
|
5
|
+
export type { SystemBarConfig, ThemedSystemBarConfig, UseAppCastReturn, } from "./src/useSystemBar";
|
package/lib/index.js
CHANGED
|
@@ -17,9 +17,20 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
17
17
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
18
18
|
};
|
|
19
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
-
exports.
|
|
20
|
+
exports.useThemeSystemBar = exports.useThemeHook = exports.useSystemScreencast = exports.useSystemBar = exports.useScreencast = exports.useAppCast = exports.useTheme = exports.setGlobalThemeMode = void 0;
|
|
21
|
+
// All imperative JS/TS APIs
|
|
21
22
|
__exportStar(require("./src/SystemBar"), exports);
|
|
23
|
+
// All TypeScript types
|
|
22
24
|
__exportStar(require("./src/types"), exports);
|
|
25
|
+
// Theme hook (standalone access)
|
|
26
|
+
var useTheme_1 = require("./src/useTheme");
|
|
27
|
+
Object.defineProperty(exports, "setGlobalThemeMode", { enumerable: true, get: function () { return useTheme_1.setGlobalThemeMode; } });
|
|
28
|
+
Object.defineProperty(exports, "useTheme", { enumerable: true, get: function () { return useTheme_1.useTheme; } });
|
|
29
|
+
// React hooks
|
|
23
30
|
var useSystemBar_1 = require("./src/useSystemBar");
|
|
24
|
-
Object.defineProperty(exports, "
|
|
31
|
+
Object.defineProperty(exports, "useAppCast", { enumerable: true, get: function () { return useSystemBar_1.useAppCast; } });
|
|
25
32
|
Object.defineProperty(exports, "useScreencast", { enumerable: true, get: function () { return useSystemBar_1.useScreencast; } });
|
|
33
|
+
Object.defineProperty(exports, "useSystemBar", { enumerable: true, get: function () { return useSystemBar_1.useSystemBar; } });
|
|
34
|
+
Object.defineProperty(exports, "useSystemScreencast", { enumerable: true, get: function () { return useSystemBar_1.useSystemScreencast; } });
|
|
35
|
+
Object.defineProperty(exports, "useThemeHook", { enumerable: true, get: function () { return useSystemBar_1.useTheme; } });
|
|
36
|
+
Object.defineProperty(exports, "useThemeSystemBar", { enumerable: true, get: function () { return useSystemBar_1.useThemeSystemBar; } });
|
|
@@ -15,7 +15,16 @@ export interface Spec extends TurboModule {
|
|
|
15
15
|
setVolumeHUDVisible(visible: boolean): void;
|
|
16
16
|
keepScreenOn(enable: boolean): void;
|
|
17
17
|
immersiveMode(enable: boolean): void;
|
|
18
|
+
setSecureScreen(enable: boolean): void;
|
|
18
19
|
setOrientation(mode: string): void;
|
|
20
|
+
getSystemScreencastInfo(): Promise<Object>;
|
|
21
|
+
startSystemScreencastListener(): void;
|
|
22
|
+
stopSystemScreencastListener(): void;
|
|
23
|
+
startAppCastScan(): void;
|
|
24
|
+
stopAppCastScan(): void;
|
|
25
|
+
connectAppCast(deviceId: string, pairingPin: string | null): void;
|
|
26
|
+
disconnectAppCast(): void;
|
|
27
|
+
getAppCastInfo(): Promise<Object>;
|
|
19
28
|
}
|
|
20
29
|
declare const _default: Spec;
|
|
21
30
|
export default _default;
|
package/lib/src/SystemBar.d.ts
CHANGED
|
@@ -1,15 +1,42 @@
|
|
|
1
|
-
import type { NavigationBarBehavior, NavigationBarButtonStyle, NavigationBarStyle, NavigationBarVisibility, Orientation,
|
|
2
|
-
|
|
1
|
+
import type { AppCastInfo, NavigationBarBehavior, NavigationBarButtonStyle, NavigationBarColorValue, NavigationBarStyle, NavigationBarVisibility, Orientation, StatusBarColorValue, StatusBarStyle, SystemScreencastInfo, VolumeStream } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Set the navigation bar background colour.
|
|
4
|
+
*
|
|
5
|
+
* @param color
|
|
6
|
+
* - Any hex string → solid colour e.g. `"#1a1a2e"`
|
|
7
|
+
* - `"transparent"` → fully transparent (content draws behind bar)
|
|
8
|
+
* - `"translucent"` → semi-transparent (system scrim over content)
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* setNavigationBarColor("#000000"); // solid black
|
|
12
|
+
* setNavigationBarColor("transparent"); // glass / edge-to-edge
|
|
13
|
+
* setNavigationBarColor("translucent"); // frosted glass
|
|
14
|
+
*/
|
|
15
|
+
export declare const setNavigationBarColor: (color: NavigationBarColorValue) => void;
|
|
16
|
+
/**
|
|
17
|
+
* Hide or show the navigation bar.
|
|
18
|
+
*
|
|
19
|
+
* @param mode `"visible"` | `"hidden"`
|
|
20
|
+
*/
|
|
3
21
|
export declare const setNavigationBarVisibility: (mode: NavigationBarVisibility) => void;
|
|
4
22
|
export declare const setNavigationBarButtonStyle: (style: NavigationBarButtonStyle) => void;
|
|
5
23
|
export declare const setNavigationBarStyle: (style: NavigationBarStyle) => void;
|
|
6
24
|
export declare const setNavigationBarBehavior: (behavior: NavigationBarBehavior) => void;
|
|
25
|
+
/**
|
|
26
|
+
* Set the status bar background colour (Android only).
|
|
27
|
+
*
|
|
28
|
+
* @param color
|
|
29
|
+
* - Any hex string → solid colour
|
|
30
|
+
* - `"transparent"` → fully transparent
|
|
31
|
+
* - `"translucent"` → semi-transparent
|
|
32
|
+
*/
|
|
33
|
+
export declare const setStatusBarColor: (color: StatusBarColorValue) => void;
|
|
7
34
|
export declare const setStatusBarStyle: (style: StatusBarStyle) => void;
|
|
8
35
|
export declare const setStatusBarVisibility: (visible: boolean) => void;
|
|
9
36
|
export declare const setBrightness: (level: number) => void;
|
|
10
37
|
export declare const getBrightness: () => Promise<number>;
|
|
11
38
|
/**
|
|
12
|
-
* Subscribe to system brightness changes (polls every
|
|
39
|
+
* Subscribe to system brightness changes (polls every 500 ms on Android).
|
|
13
40
|
* @returns unsubscribe function
|
|
14
41
|
*/
|
|
15
42
|
export declare const onBrightnessChange: (callback: (brightness: number) => void) => (() => void);
|
|
@@ -25,5 +52,56 @@ export declare const keepScreenOn: (enable: boolean) => void;
|
|
|
25
52
|
export declare const immersiveMode: (enable: boolean) => void;
|
|
26
53
|
export declare const setSecureScreen: (enable: boolean) => void;
|
|
27
54
|
export declare const setOrientation: (mode: Orientation) => void;
|
|
28
|
-
|
|
29
|
-
|
|
55
|
+
/**
|
|
56
|
+
* One-shot snapshot of system-level external display state.
|
|
57
|
+
* Works on both Android (DisplayManager) and iOS (UIScreen.screens).
|
|
58
|
+
*/
|
|
59
|
+
export declare const getSystemScreencastInfo: () => Promise<SystemScreencastInfo>;
|
|
60
|
+
/**
|
|
61
|
+
* Subscribe to system external-display changes.
|
|
62
|
+
* Fires when an HDMI / Miracast / AirPlay display connects or disconnects.
|
|
63
|
+
* @returns unsubscribe function
|
|
64
|
+
*/
|
|
65
|
+
export declare const onSystemScreencastChange: (callback: (info: SystemScreencastInfo) => void) => (() => void);
|
|
66
|
+
/** @deprecated Use getSystemScreencastInfo() */
|
|
67
|
+
export declare const getScreencastInfo: () => Promise<SystemScreencastInfo>;
|
|
68
|
+
/** @deprecated Use onSystemScreencastChange() */
|
|
69
|
+
export declare const onScreencastChange: (callback: (info: SystemScreencastInfo) => void) => (() => void);
|
|
70
|
+
/**
|
|
71
|
+
* Start scanning for nearby castable devices (Chromecast, TV, etc.).
|
|
72
|
+
* Listen for results via `onAppCastChange`.
|
|
73
|
+
* Android: uses MediaRouter. iOS: no-op (AirPlay is system-only).
|
|
74
|
+
*/
|
|
75
|
+
export declare const startAppCastScan: () => void;
|
|
76
|
+
/**
|
|
77
|
+
* Stop the device discovery scan.
|
|
78
|
+
*/
|
|
79
|
+
export declare const stopAppCastScan: () => void;
|
|
80
|
+
/**
|
|
81
|
+
* Connect to a discovered device and begin casting this app's screen.
|
|
82
|
+
* @param deviceId The `id` field from `AppCastDevice` (MediaRouter route ID).
|
|
83
|
+
* @param pairingPin Optional PIN string if `requiresPairing` is true.
|
|
84
|
+
*/
|
|
85
|
+
export declare const connectAppCast: (deviceId: string, pairingPin?: string) => void;
|
|
86
|
+
/**
|
|
87
|
+
* Disconnect the active in-app cast session.
|
|
88
|
+
*/
|
|
89
|
+
export declare const disconnectAppCast: () => void;
|
|
90
|
+
/**
|
|
91
|
+
* Get the current in-app cast snapshot (state + device list).
|
|
92
|
+
*/
|
|
93
|
+
export declare const getAppCastInfo: () => Promise<AppCastInfo>;
|
|
94
|
+
/**
|
|
95
|
+
* Subscribe to in-app cast state changes.
|
|
96
|
+
* Fires on: device discovered/lost, state changes (scanning → connecting → connected),
|
|
97
|
+
* pairing requests, errors.
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* const unsub = onAppCastChange((info) => {
|
|
101
|
+
* if (info.state === "connected") console.log("Casting to", info.connectedDevice?.name);
|
|
102
|
+
* if (info.error) console.warn("Cast error:", info.error);
|
|
103
|
+
* });
|
|
104
|
+
*
|
|
105
|
+
* @returns unsubscribe function
|
|
106
|
+
*/
|
|
107
|
+
export declare const onAppCastChange: (callback: (info: AppCastInfo) => void) => (() => void);
|
package/lib/src/SystemBar.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// All APIs → native Kotlin / iOS Swift.
|
|
6
6
|
// ─────────────────────────────────────────────
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.onScreencastChange = exports.getScreencastInfo = exports.setOrientation = exports.setSecureScreen = exports.immersiveMode = exports.keepScreenOn = exports.onVolumeChange = exports.setVolumeHUDVisible = exports.getVolume = exports.setVolume = exports.onBrightnessChange = exports.getBrightness = exports.setBrightness = exports.setStatusBarVisibility = exports.setStatusBarStyle = exports.setNavigationBarBehavior = exports.setNavigationBarStyle = exports.setNavigationBarButtonStyle = exports.setNavigationBarVisibility = exports.setNavigationBarColor = void 0;
|
|
8
|
+
exports.onAppCastChange = exports.getAppCastInfo = exports.disconnectAppCast = exports.connectAppCast = exports.stopAppCastScan = exports.startAppCastScan = exports.onScreencastChange = exports.getScreencastInfo = exports.onSystemScreencastChange = exports.getSystemScreencastInfo = exports.setOrientation = exports.setSecureScreen = exports.immersiveMode = exports.keepScreenOn = exports.onVolumeChange = exports.setVolumeHUDVisible = exports.getVolume = exports.setVolume = exports.onBrightnessChange = exports.getBrightness = exports.setBrightness = exports.setStatusBarVisibility = exports.setStatusBarStyle = exports.setStatusBarColor = exports.setNavigationBarBehavior = exports.setNavigationBarStyle = exports.setNavigationBarButtonStyle = exports.setNavigationBarVisibility = exports.setNavigationBarColor = void 0;
|
|
9
9
|
const react_native_1 = require("react-native");
|
|
10
10
|
const { SystemBar: Native } = react_native_1.NativeModules;
|
|
11
11
|
const isAndroid = react_native_1.Platform.OS === "android";
|
|
@@ -24,13 +24,31 @@ const checkNative = () => {
|
|
|
24
24
|
// ═══════════════════════════════════════════════
|
|
25
25
|
// NAVIGATION BAR (Android — 100% native)
|
|
26
26
|
// ═══════════════════════════════════════════════
|
|
27
|
+
/**
|
|
28
|
+
* Set the navigation bar background colour.
|
|
29
|
+
*
|
|
30
|
+
* @param color
|
|
31
|
+
* - Any hex string → solid colour e.g. `"#1a1a2e"`
|
|
32
|
+
* - `"transparent"` → fully transparent (content draws behind bar)
|
|
33
|
+
* - `"translucent"` → semi-transparent (system scrim over content)
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* setNavigationBarColor("#000000"); // solid black
|
|
37
|
+
* setNavigationBarColor("transparent"); // glass / edge-to-edge
|
|
38
|
+
* setNavigationBarColor("translucent"); // frosted glass
|
|
39
|
+
*/
|
|
27
40
|
const setNavigationBarColor = (color) => {
|
|
28
41
|
if (!androidOnly("setNavigationBarColor"))
|
|
29
42
|
return;
|
|
30
43
|
checkNative();
|
|
31
|
-
Native.setNavigationBarColor(color);
|
|
44
|
+
Native.setNavigationBarColor(color); // Kotlin handles the special values
|
|
32
45
|
};
|
|
33
46
|
exports.setNavigationBarColor = setNavigationBarColor;
|
|
47
|
+
/**
|
|
48
|
+
* Hide or show the navigation bar.
|
|
49
|
+
*
|
|
50
|
+
* @param mode `"visible"` | `"hidden"`
|
|
51
|
+
*/
|
|
34
52
|
const setNavigationBarVisibility = (mode) => {
|
|
35
53
|
if (!androidOnly("setNavigationBarVisibility"))
|
|
36
54
|
return;
|
|
@@ -62,6 +80,21 @@ exports.setNavigationBarBehavior = setNavigationBarBehavior;
|
|
|
62
80
|
// ═══════════════════════════════════════════════
|
|
63
81
|
// STATUS BAR (native — no RN StatusBar)
|
|
64
82
|
// ═══════════════════════════════════════════════
|
|
83
|
+
/**
|
|
84
|
+
* Set the status bar background colour (Android only).
|
|
85
|
+
*
|
|
86
|
+
* @param color
|
|
87
|
+
* - Any hex string → solid colour
|
|
88
|
+
* - `"transparent"` → fully transparent
|
|
89
|
+
* - `"translucent"` → semi-transparent
|
|
90
|
+
*/
|
|
91
|
+
const setStatusBarColor = (color) => {
|
|
92
|
+
if (!androidOnly("setStatusBarColor"))
|
|
93
|
+
return;
|
|
94
|
+
checkNative();
|
|
95
|
+
Native.setStatusBarColor(color);
|
|
96
|
+
};
|
|
97
|
+
exports.setStatusBarColor = setStatusBarColor;
|
|
65
98
|
const setStatusBarStyle = (style) => {
|
|
66
99
|
checkNative();
|
|
67
100
|
Native.setStatusBarStyle(style);
|
|
@@ -86,7 +119,7 @@ const getBrightness = () => {
|
|
|
86
119
|
};
|
|
87
120
|
exports.getBrightness = getBrightness;
|
|
88
121
|
/**
|
|
89
|
-
* Subscribe to system brightness changes (polls every
|
|
122
|
+
* Subscribe to system brightness changes (polls every 500 ms on Android).
|
|
90
123
|
* @returns unsubscribe function
|
|
91
124
|
*/
|
|
92
125
|
const onBrightnessChange = (callback) => {
|
|
@@ -166,21 +199,137 @@ const setOrientation = (mode) => {
|
|
|
166
199
|
};
|
|
167
200
|
exports.setOrientation = setOrientation;
|
|
168
201
|
// ═══════════════════════════════════════════════
|
|
169
|
-
// SCREENCAST
|
|
202
|
+
// SYSTEM SCREENCAST (external display / HDMI / Miracast)
|
|
203
|
+
// Reads DisplayManager — detects any externally mirrored display.
|
|
170
204
|
// ═══════════════════════════════════════════════
|
|
171
|
-
|
|
205
|
+
/**
|
|
206
|
+
* One-shot snapshot of system-level external display state.
|
|
207
|
+
* Works on both Android (DisplayManager) and iOS (UIScreen.screens).
|
|
208
|
+
*/
|
|
209
|
+
const getSystemScreencastInfo = () => {
|
|
210
|
+
checkNative();
|
|
211
|
+
return Native.getSystemScreencastInfo();
|
|
212
|
+
};
|
|
213
|
+
exports.getSystemScreencastInfo = getSystemScreencastInfo;
|
|
214
|
+
/**
|
|
215
|
+
* Subscribe to system external-display changes.
|
|
216
|
+
* Fires when an HDMI / Miracast / AirPlay display connects or disconnects.
|
|
217
|
+
* @returns unsubscribe function
|
|
218
|
+
*/
|
|
219
|
+
const onSystemScreencastChange = (callback) => {
|
|
172
220
|
checkNative();
|
|
173
|
-
|
|
221
|
+
const { DeviceEventEmitter } = require("react-native");
|
|
222
|
+
Native.startSystemScreencastListener();
|
|
223
|
+
const sub = DeviceEventEmitter.addListener("SystemBar_SystemScreencastChange", callback);
|
|
224
|
+
return () => {
|
|
225
|
+
sub.remove();
|
|
226
|
+
Native.stopSystemScreencastListener();
|
|
227
|
+
};
|
|
174
228
|
};
|
|
175
|
-
exports.
|
|
176
|
-
|
|
229
|
+
exports.onSystemScreencastChange = onSystemScreencastChange;
|
|
230
|
+
// ─────────────────────────────────────────────
|
|
231
|
+
// Legacy aliases (backward compat)
|
|
232
|
+
// ─────────────────────────────────────────────
|
|
233
|
+
/** @deprecated Use getSystemScreencastInfo() */
|
|
234
|
+
exports.getScreencastInfo = exports.getSystemScreencastInfo;
|
|
235
|
+
/** @deprecated Use onSystemScreencastChange() */
|
|
236
|
+
exports.onScreencastChange = exports.onSystemScreencastChange;
|
|
237
|
+
// ═══════════════════════════════════════════════
|
|
238
|
+
// APP-ONLY CAST (MediaRouter — Chromecast / TV)
|
|
239
|
+
// Mirrors only this app's screen — NOT the whole system.
|
|
240
|
+
// Flow: startAppCastScan() → onAppCastChange (devices arrive)
|
|
241
|
+
// → connectAppCast(deviceId) → onAppCastChange (state = "connected")
|
|
242
|
+
// → disconnectAppCast()
|
|
243
|
+
// ═══════════════════════════════════════════════
|
|
244
|
+
/**
|
|
245
|
+
* Start scanning for nearby castable devices (Chromecast, TV, etc.).
|
|
246
|
+
* Listen for results via `onAppCastChange`.
|
|
247
|
+
* Android: uses MediaRouter. iOS: no-op (AirPlay is system-only).
|
|
248
|
+
*/
|
|
249
|
+
const startAppCastScan = () => {
|
|
250
|
+
if (!androidOnly("startAppCastScan"))
|
|
251
|
+
return;
|
|
252
|
+
checkNative();
|
|
253
|
+
Native.startAppCastScan();
|
|
254
|
+
};
|
|
255
|
+
exports.startAppCastScan = startAppCastScan;
|
|
256
|
+
/**
|
|
257
|
+
* Stop the device discovery scan.
|
|
258
|
+
*/
|
|
259
|
+
const stopAppCastScan = () => {
|
|
260
|
+
if (!androidOnly("stopAppCastScan"))
|
|
261
|
+
return;
|
|
262
|
+
checkNative();
|
|
263
|
+
Native.stopAppCastScan();
|
|
264
|
+
};
|
|
265
|
+
exports.stopAppCastScan = stopAppCastScan;
|
|
266
|
+
/**
|
|
267
|
+
* Connect to a discovered device and begin casting this app's screen.
|
|
268
|
+
* @param deviceId The `id` field from `AppCastDevice` (MediaRouter route ID).
|
|
269
|
+
* @param pairingPin Optional PIN string if `requiresPairing` is true.
|
|
270
|
+
*/
|
|
271
|
+
const connectAppCast = (deviceId, pairingPin) => {
|
|
272
|
+
if (!androidOnly("connectAppCast"))
|
|
273
|
+
return;
|
|
274
|
+
checkNative();
|
|
275
|
+
Native.connectAppCast(deviceId, pairingPin !== null && pairingPin !== void 0 ? pairingPin : null);
|
|
276
|
+
};
|
|
277
|
+
exports.connectAppCast = connectAppCast;
|
|
278
|
+
/**
|
|
279
|
+
* Disconnect the active in-app cast session.
|
|
280
|
+
*/
|
|
281
|
+
const disconnectAppCast = () => {
|
|
282
|
+
if (!androidOnly("disconnectAppCast"))
|
|
283
|
+
return;
|
|
284
|
+
checkNative();
|
|
285
|
+
Native.disconnectAppCast();
|
|
286
|
+
};
|
|
287
|
+
exports.disconnectAppCast = disconnectAppCast;
|
|
288
|
+
/**
|
|
289
|
+
* Get the current in-app cast snapshot (state + device list).
|
|
290
|
+
*/
|
|
291
|
+
const getAppCastInfo = () => {
|
|
292
|
+
if (!isAndroid) {
|
|
293
|
+
return Promise.resolve({
|
|
294
|
+
state: "idle",
|
|
295
|
+
devices: [],
|
|
296
|
+
connectedDevice: null,
|
|
297
|
+
error: null,
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
checkNative();
|
|
301
|
+
return Native.getAppCastInfo();
|
|
302
|
+
};
|
|
303
|
+
exports.getAppCastInfo = getAppCastInfo;
|
|
304
|
+
/**
|
|
305
|
+
* Subscribe to in-app cast state changes.
|
|
306
|
+
* Fires on: device discovered/lost, state changes (scanning → connecting → connected),
|
|
307
|
+
* pairing requests, errors.
|
|
308
|
+
*
|
|
309
|
+
* @example
|
|
310
|
+
* const unsub = onAppCastChange((info) => {
|
|
311
|
+
* if (info.state === "connected") console.log("Casting to", info.connectedDevice?.name);
|
|
312
|
+
* if (info.error) console.warn("Cast error:", info.error);
|
|
313
|
+
* });
|
|
314
|
+
*
|
|
315
|
+
* @returns unsubscribe function
|
|
316
|
+
*/
|
|
317
|
+
const onAppCastChange = (callback) => {
|
|
318
|
+
if (!isAndroid) {
|
|
319
|
+
// iOS: immediately call with idle state, return no-op
|
|
320
|
+
callback({
|
|
321
|
+
state: "idle",
|
|
322
|
+
devices: [],
|
|
323
|
+
connectedDevice: null,
|
|
324
|
+
error: null,
|
|
325
|
+
});
|
|
326
|
+
return () => { };
|
|
327
|
+
}
|
|
177
328
|
checkNative();
|
|
178
329
|
const { DeviceEventEmitter } = require("react-native");
|
|
179
|
-
|
|
180
|
-
const sub = DeviceEventEmitter.addListener("SystemBar_ScreencastChange", callback);
|
|
330
|
+
const sub = DeviceEventEmitter.addListener("SystemBar_AppCastChange", callback);
|
|
181
331
|
return () => {
|
|
182
332
|
sub.remove();
|
|
183
|
-
Native.stopScreencastListener();
|
|
184
333
|
};
|
|
185
334
|
};
|
|
186
|
-
exports.
|
|
335
|
+
exports.onAppCastChange = onAppCastChange;
|
package/lib/src/types.d.ts
CHANGED
|
@@ -3,6 +3,37 @@ export type NavigationBarButtonStyle = "light" | "dark";
|
|
|
3
3
|
export type NavigationBarStyle = "auto" | "inverted" | "light" | "dark";
|
|
4
4
|
export type NavigationBarVisibility = "visible" | "hidden";
|
|
5
5
|
export type StatusBarStyle = "light" | "dark";
|
|
6
|
+
/**
|
|
7
|
+
* Navigation bar color value.
|
|
8
|
+
*
|
|
9
|
+
* - Any CSS hex string → solid colour e.g. "#1a1a2e", "#000"
|
|
10
|
+
* - `"transparent"` → fully transparent (FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS +
|
|
11
|
+
* transparent color; content draws behind bar)
|
|
12
|
+
* - `"translucent"` → semi-transparent (FLAG_TRANSLUCENT_NAVIGATION)
|
|
13
|
+
*/
|
|
14
|
+
export type NavigationBarColorValue = string | "transparent" | "translucent";
|
|
15
|
+
/**
|
|
16
|
+
* Status bar background color value.
|
|
17
|
+
*
|
|
18
|
+
* - Any CSS hex string → solid colour
|
|
19
|
+
* - `"transparent"` → fully transparent (draws behind content)
|
|
20
|
+
* - `"translucent"` → semi-transparent
|
|
21
|
+
*/
|
|
22
|
+
export type StatusBarColorValue = string | "transparent" | "translucent";
|
|
23
|
+
/**
|
|
24
|
+
* "system" → follow the OS Appearance (dark/light).
|
|
25
|
+
* "dark" → force dark.
|
|
26
|
+
* "light" → force light.
|
|
27
|
+
*/
|
|
28
|
+
export type ThemeMode = "system" | "dark" | "light";
|
|
29
|
+
export interface ThemeState {
|
|
30
|
+
/** Resolved dark-mode flag. Always a concrete boolean. */
|
|
31
|
+
isDark: boolean;
|
|
32
|
+
/** Currently active override ("system" = following OS). */
|
|
33
|
+
mode: ThemeMode;
|
|
34
|
+
/** Set the override mode. Pass "system" to revert to OS. */
|
|
35
|
+
setMode: (mode: ThemeMode) => void;
|
|
36
|
+
}
|
|
6
37
|
export type Orientation = "portrait" | "landscape" | "landscape-left" | "landscape-right" | "auto";
|
|
7
38
|
export type VolumeStream = "music" | "ring" | "notification" | "alarm" | "system";
|
|
8
39
|
export interface ScreencastDisplay {
|
|
@@ -10,8 +41,37 @@ export interface ScreencastDisplay {
|
|
|
10
41
|
name: string;
|
|
11
42
|
isValid: boolean;
|
|
12
43
|
}
|
|
13
|
-
|
|
44
|
+
/** Result of getSystemScreencastInfo() — physical/HDMI/Miracast external display. */
|
|
45
|
+
export interface SystemScreencastInfo {
|
|
14
46
|
isCasting: boolean;
|
|
15
47
|
displayName: string | null;
|
|
16
48
|
displays: ScreencastDisplay[];
|
|
17
49
|
}
|
|
50
|
+
/** Connection state of the in-app cast session. */
|
|
51
|
+
export type AppCastState = "idle" | "scanning" | "connecting" | "connected" | "disconnecting";
|
|
52
|
+
/** A discovered castable device (TV, Chromecast, etc.). */
|
|
53
|
+
export interface AppCastDevice {
|
|
54
|
+
/** Unique route ID from MediaRouter. */
|
|
55
|
+
id: string;
|
|
56
|
+
/** Human-readable device name e.g. "Living Room TV". */
|
|
57
|
+
name: string;
|
|
58
|
+
/** Device description / model string (may be null). */
|
|
59
|
+
description: string | null;
|
|
60
|
+
/** Signal strength 0–100, or null if unavailable. */
|
|
61
|
+
signalStrength: number | null;
|
|
62
|
+
/** Whether a pairing/PIN step is required. */
|
|
63
|
+
requiresPairing: boolean;
|
|
64
|
+
}
|
|
65
|
+
/** Full snapshot of in-app cast state. */
|
|
66
|
+
export interface AppCastInfo {
|
|
67
|
+
state: AppCastState;
|
|
68
|
+
/** Devices found during the last scan. */
|
|
69
|
+
devices: AppCastDevice[];
|
|
70
|
+
/** The device currently connected (or connecting). */
|
|
71
|
+
connectedDevice: AppCastDevice | null;
|
|
72
|
+
/** Error message from the last failed operation. */
|
|
73
|
+
error: string | null;
|
|
74
|
+
}
|
|
75
|
+
/** @deprecated Use SystemScreencastInfo */
|
|
76
|
+
export interface ScreencastInfo extends SystemScreencastInfo {
|
|
77
|
+
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type { NavigationBarBehavior, NavigationBarButtonStyle, NavigationBarStyle, NavigationBarVisibility, Orientation,
|
|
1
|
+
import type { AppCastInfo, NavigationBarBehavior, NavigationBarButtonStyle, NavigationBarColorValue, NavigationBarStyle, NavigationBarVisibility, Orientation, StatusBarColorValue, StatusBarStyle, SystemScreencastInfo, ThemeMode, ThemeState } from "./types";
|
|
2
2
|
export interface SystemBarConfig {
|
|
3
|
-
navigationBarColor?:
|
|
3
|
+
navigationBarColor?: NavigationBarColorValue;
|
|
4
4
|
navigationBarVisibility?: NavigationBarVisibility;
|
|
5
5
|
navigationBarButtonStyle?: NavigationBarButtonStyle;
|
|
6
6
|
navigationBarStyle?: NavigationBarStyle;
|
|
7
7
|
navigationBarBehavior?: NavigationBarBehavior;
|
|
8
|
-
statusBarColor?:
|
|
8
|
+
statusBarColor?: StatusBarColorValue;
|
|
9
9
|
statusBarStyle?: StatusBarStyle;
|
|
10
10
|
statusBarVisible?: boolean;
|
|
11
11
|
statusBarAnimated?: boolean;
|
|
@@ -16,4 +16,35 @@ export interface SystemBarConfig {
|
|
|
16
16
|
secureScreen?: boolean;
|
|
17
17
|
}
|
|
18
18
|
export declare const useSystemBar: (config: SystemBarConfig) => void;
|
|
19
|
-
export
|
|
19
|
+
export interface ThemedSystemBarConfig {
|
|
20
|
+
/** Config applied when the resolved theme is DARK. */
|
|
21
|
+
dark?: SystemBarConfig;
|
|
22
|
+
/** Config applied when the resolved theme is LIGHT. */
|
|
23
|
+
light?: SystemBarConfig;
|
|
24
|
+
/**
|
|
25
|
+
* Static config merged under both themes.
|
|
26
|
+
* Theme-specific (dark/light) values always win.
|
|
27
|
+
*/
|
|
28
|
+
base?: SystemBarConfig;
|
|
29
|
+
}
|
|
30
|
+
export declare const useThemeSystemBar: (config: ThemedSystemBarConfig) => ThemeState;
|
|
31
|
+
export { useTheme } from "./useTheme";
|
|
32
|
+
export type { ThemeMode, ThemeState };
|
|
33
|
+
export declare const useSystemScreencast: () => SystemScreencastInfo;
|
|
34
|
+
/** @deprecated Renamed to useSystemScreencast() */
|
|
35
|
+
export declare const useScreencast: () => SystemScreencastInfo;
|
|
36
|
+
export interface UseAppCastReturn extends AppCastInfo {
|
|
37
|
+
/** Start scanning for nearby castable devices (TV, Chromecast, etc.). */
|
|
38
|
+
scan: () => void;
|
|
39
|
+
/** Stop the device discovery scan. */
|
|
40
|
+
stopScan: () => void;
|
|
41
|
+
/**
|
|
42
|
+
* Connect to a discovered device and begin casting this app's screen.
|
|
43
|
+
* @param deviceId The `id` field from `AppCastDevice`.
|
|
44
|
+
* @param pairingPin Optional PIN string if `requiresPairing` is true.
|
|
45
|
+
*/
|
|
46
|
+
connect: (deviceId: string, pairingPin?: string) => void;
|
|
47
|
+
/** End the active cast session and return to idle. */
|
|
48
|
+
disconnect: () => void;
|
|
49
|
+
}
|
|
50
|
+
export declare const useAppCast: () => UseAppCastReturn;
|