rn-system-bar 3.0.2 → 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 +334 -247
- 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 +215 -141
- package/src/types.ts +70 -43
- package/src/useSystemBar.ts +191 -0
|
@@ -9,13 +9,14 @@ import com.facebook.react.bridge.NativeModule
|
|
|
9
9
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
10
10
|
import com.facebook.react.uimanager.ViewManager
|
|
11
11
|
|
|
12
|
+
// @Suppress at class level — covers all overrides of deprecated ReactPackage members
|
|
13
|
+
@Suppress("DEPRECATION", "OVERRIDE_DEPRECATION")
|
|
12
14
|
class SystemBarPackage : ReactPackage {
|
|
13
15
|
|
|
14
16
|
override fun createNativeModules(
|
|
15
17
|
reactContext: ReactApplicationContext
|
|
16
18
|
): List<NativeModule> = listOf(SystemBarModule(reactContext))
|
|
17
19
|
|
|
18
|
-
@Suppress("DEPRECATION")
|
|
19
20
|
override fun createViewManagers(
|
|
20
21
|
reactContext: ReactApplicationContext
|
|
21
22
|
): List<ViewManager<*, *>> = emptyList()
|
package/index.ts
CHANGED
|
@@ -4,3 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
export * from "./src/SystemBar";
|
|
6
6
|
export * from "./src/types";
|
|
7
|
+
export {
|
|
8
|
+
useSystemBar,
|
|
9
|
+
useBattery,
|
|
10
|
+
useNetwork,
|
|
11
|
+
useScreencast,
|
|
12
|
+
useFontScale,
|
|
13
|
+
useHaptic,
|
|
14
|
+
} from "./src/useSystemBar";
|
|
15
|
+
export type { SystemBarConfig } from "./src/useSystemBar";
|
package/ios/SystemBarModule.m
CHANGED
|
@@ -1,40 +1,60 @@
|
|
|
1
1
|
// ─────────────────────────────────────────────
|
|
2
|
-
// rn-system-bar · SystemBarModule.m
|
|
2
|
+
// rn-system-bar · SystemBarModule.m v5
|
|
3
3
|
// Objective-C bridge — exposes Swift to React Native
|
|
4
4
|
// ─────────────────────────────────────────────
|
|
5
5
|
|
|
6
6
|
#import <React/RCTBridgeModule.h>
|
|
7
|
+
#import <React/RCTEventEmitter.h>
|
|
7
8
|
|
|
8
|
-
@interface RCT_EXTERN_MODULE(SystemBar,
|
|
9
|
-
|
|
10
|
-
// Status Bar
|
|
11
|
-
RCT_EXTERN_METHOD(setStatusBarStyle:(NSString *)style)
|
|
12
|
-
RCT_EXTERN_METHOD(setStatusBarVisibility:(BOOL)visible)
|
|
9
|
+
@interface RCT_EXTERN_MODULE(SystemBar, RCTEventEmitter)
|
|
13
10
|
|
|
14
11
|
// Brightness
|
|
15
12
|
RCT_EXTERN_METHOD(setBrightness:(float)level)
|
|
16
|
-
RCT_EXTERN_METHOD(getBrightness:(RCTPromiseResolveBlock)resolve
|
|
17
|
-
rejecter:(RCTPromiseRejectBlock)reject)
|
|
13
|
+
RCT_EXTERN_METHOD(getBrightness:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
|
18
14
|
|
|
19
15
|
// Volume
|
|
20
16
|
RCT_EXTERN_METHOD(setVolume:(float)level stream:(NSString *)stream)
|
|
21
|
-
RCT_EXTERN_METHOD(getVolume:(NSString *)stream
|
|
22
|
-
resolver:(RCTPromiseResolveBlock)resolve
|
|
23
|
-
rejecter:(RCTPromiseRejectBlock)reject)
|
|
17
|
+
RCT_EXTERN_METHOD(getVolume:(NSString *)stream resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
|
24
18
|
|
|
25
19
|
// Screen
|
|
26
20
|
RCT_EXTERN_METHOD(keepScreenOn:(BOOL)enable)
|
|
21
|
+
RCT_EXTERN_METHOD(setSecureScreen:(BOOL)enable)
|
|
27
22
|
|
|
28
23
|
// Orientation
|
|
29
24
|
RCT_EXTERN_METHOD(setOrientation:(NSString *)mode)
|
|
30
25
|
|
|
31
|
-
//
|
|
26
|
+
// Network
|
|
27
|
+
RCT_EXTERN_METHOD(getNetworkInfo:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
|
28
|
+
RCT_EXTERN_METHOD(startNetworkListener)
|
|
29
|
+
RCT_EXTERN_METHOD(stopNetworkListener)
|
|
30
|
+
|
|
31
|
+
// Battery
|
|
32
|
+
RCT_EXTERN_METHOD(getBatteryInfo:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
|
33
|
+
RCT_EXTERN_METHOD(startBatteryListener)
|
|
34
|
+
RCT_EXTERN_METHOD(stopBatteryListener)
|
|
35
|
+
|
|
36
|
+
// Haptics
|
|
37
|
+
RCT_EXTERN_METHOD(haptic:(NSString *)pattern)
|
|
38
|
+
|
|
39
|
+
// Screencast
|
|
40
|
+
RCT_EXTERN_METHOD(getScreencastInfo:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
|
41
|
+
RCT_EXTERN_METHOD(startScreencastListener)
|
|
42
|
+
RCT_EXTERN_METHOD(stopScreencastListener)
|
|
43
|
+
|
|
44
|
+
// Font Scale
|
|
45
|
+
RCT_EXTERN_METHOD(getFontScaleInfo:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
|
46
|
+
RCT_EXTERN_METHOD(startFontScaleListener)
|
|
47
|
+
RCT_EXTERN_METHOD(stopFontScaleListener)
|
|
48
|
+
|
|
49
|
+
// Android-only stubs
|
|
32
50
|
RCT_EXTERN_METHOD(setNavigationBarColor:(NSString *)color)
|
|
33
51
|
RCT_EXTERN_METHOD(setNavigationBarVisibility:(NSString *)mode)
|
|
34
52
|
RCT_EXTERN_METHOD(setNavigationBarButtonStyle:(NSString *)style)
|
|
35
53
|
RCT_EXTERN_METHOD(setNavigationBarStyle:(NSString *)style)
|
|
36
54
|
RCT_EXTERN_METHOD(setNavigationBarBehavior:(NSString *)behavior)
|
|
37
55
|
RCT_EXTERN_METHOD(setStatusBarColor:(NSString *)color)
|
|
56
|
+
RCT_EXTERN_METHOD(setStatusBarStyle:(NSString *)style)
|
|
57
|
+
RCT_EXTERN_METHOD(setStatusBarVisibility:(BOOL)visible)
|
|
38
58
|
RCT_EXTERN_METHOD(setVolumeHUDVisible:(BOOL)visible)
|
|
39
59
|
RCT_EXTERN_METHOD(immersiveMode:(BOOL)enable)
|
|
40
60
|
|
|
@@ -1,46 +1,47 @@
|
|
|
1
1
|
// ─────────────────────────────────────────────
|
|
2
|
-
// rn-system-bar · SystemBarModule.swift
|
|
3
|
-
//
|
|
2
|
+
// rn-system-bar · SystemBarModule.swift v5
|
|
3
|
+
// New: Network, Battery, Haptics, Screencast, FontScale
|
|
4
4
|
// ─────────────────────────────────────────────
|
|
5
5
|
|
|
6
6
|
import Foundation
|
|
7
7
|
import UIKit
|
|
8
8
|
import AVFoundation
|
|
9
|
+
import CoreHaptics
|
|
10
|
+
import Network
|
|
11
|
+
import SystemConfiguration
|
|
9
12
|
|
|
10
13
|
@objc(SystemBar)
|
|
11
|
-
class SystemBarModule:
|
|
14
|
+
class SystemBarModule: RCTEventEmitter {
|
|
12
15
|
|
|
13
|
-
// ──
|
|
14
|
-
|
|
15
|
-
return
|
|
16
|
+
// ── Event names ────────────────────────────
|
|
17
|
+
override func supportedEvents() -> [String]! {
|
|
18
|
+
return [
|
|
19
|
+
"SystemBar_NetworkChange",
|
|
20
|
+
"SystemBar_BatteryChange",
|
|
21
|
+
"SystemBar_ScreencastChange",
|
|
22
|
+
"SystemBar_FontScaleChange",
|
|
23
|
+
]
|
|
16
24
|
}
|
|
17
25
|
|
|
18
|
-
|
|
19
|
-
// STATUS BAR (iOS supports these natively)
|
|
20
|
-
// ─────────────────────────────────────────────
|
|
26
|
+
override static func requiresMainQueueSetup() -> Bool { return false }
|
|
21
27
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
: UIStatusBarStyle.darkContent
|
|
28
|
+
// ── Listeners state ────────────────────────
|
|
29
|
+
private var networkMonitor: NWPathMonitor?
|
|
30
|
+
private var batteryObservers: [NSObjectProtocol] = []
|
|
31
|
+
private var screencastObserver: NSObjectProtocol?
|
|
32
|
+
private var fontScaleObserver: NSObjectProtocol?
|
|
33
|
+
private var hasListeners = false
|
|
29
34
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
35
|
+
override func startObserving() { hasListeners = true }
|
|
36
|
+
override func stopObserving() { hasListeners = false }
|
|
33
37
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
DispatchQueue.main.async {
|
|
37
|
-
UIApplication.shared.isStatusBarHidden = !visible
|
|
38
|
-
}
|
|
38
|
+
private func emit(_ event: String, body: Any) {
|
|
39
|
+
if hasListeners { sendEvent(withName: event, body: body) }
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
//
|
|
42
|
+
// ═══════════════════════════════════════════════
|
|
42
43
|
// BRIGHTNESS
|
|
43
|
-
//
|
|
44
|
+
// ═══════════════════════════════════════════════
|
|
44
45
|
|
|
45
46
|
@objc
|
|
46
47
|
func setBrightness(_ level: Float) {
|
|
@@ -51,86 +52,244 @@ class SystemBarModule: NSObject {
|
|
|
51
52
|
|
|
52
53
|
@objc
|
|
53
54
|
func getBrightness(_ resolve: @escaping RCTPromiseResolveBlock,
|
|
54
|
-
rejecter reject:
|
|
55
|
-
DispatchQueue.main.async {
|
|
56
|
-
resolve(Double(UIScreen.main.brightness))
|
|
57
|
-
}
|
|
55
|
+
rejecter reject: RCTPromiseRejectBlock) {
|
|
56
|
+
DispatchQueue.main.async { resolve(Double(UIScreen.main.brightness)) }
|
|
58
57
|
}
|
|
59
58
|
|
|
60
|
-
//
|
|
59
|
+
// ═══════════════════════════════════════════════
|
|
61
60
|
// VOLUME
|
|
62
|
-
//
|
|
61
|
+
// ═══════════════════════════════════════════════
|
|
63
62
|
|
|
64
|
-
@objc
|
|
65
|
-
func setVolume(_ level: Float, stream: String) {
|
|
66
|
-
// AVAudioSession volume cannot be set programmatically on iOS
|
|
67
|
-
// (Apple restriction). Use MPVolumeView or inform user.
|
|
68
|
-
// We silently ignore to prevent crashes.
|
|
69
|
-
}
|
|
63
|
+
@objc func setVolume(_ level: Float, stream: String) { /* iOS restriction — no-op */ }
|
|
70
64
|
|
|
71
65
|
@objc
|
|
72
66
|
func getVolume(_ stream: String,
|
|
73
67
|
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
74
|
-
rejecter reject:
|
|
75
|
-
|
|
76
|
-
resolve(Double(session.outputVolume))
|
|
68
|
+
rejecter reject: RCTPromiseRejectBlock) {
|
|
69
|
+
resolve(Double(AVAudioSession.sharedInstance().outputVolume))
|
|
77
70
|
}
|
|
78
71
|
|
|
79
|
-
//
|
|
72
|
+
// ═══════════════════════════════════════════════
|
|
80
73
|
// SCREEN
|
|
81
|
-
//
|
|
74
|
+
// ═══════════════════════════════════════════════
|
|
82
75
|
|
|
83
|
-
@objc
|
|
84
|
-
|
|
85
|
-
DispatchQueue.main.async {
|
|
86
|
-
UIApplication.shared.isIdleTimerDisabled = enable
|
|
87
|
-
}
|
|
76
|
+
@objc func keepScreenOn(_ enable: Bool) {
|
|
77
|
+
DispatchQueue.main.async { UIApplication.shared.isIdleTimerDisabled = enable }
|
|
88
78
|
}
|
|
89
79
|
|
|
90
|
-
//
|
|
80
|
+
// ═══════════════════════════════════════════════
|
|
91
81
|
// ORIENTATION
|
|
92
|
-
//
|
|
82
|
+
// ═══════════════════════════════════════════════
|
|
93
83
|
|
|
94
|
-
@objc
|
|
95
|
-
func setOrientation(_ mode: String) {
|
|
84
|
+
@objc func setOrientation(_ mode: String) {
|
|
96
85
|
DispatchQueue.main.async {
|
|
97
|
-
var mask: UIInterfaceOrientationMask
|
|
86
|
+
var mask: UIInterfaceOrientationMask
|
|
98
87
|
switch mode {
|
|
99
|
-
case "portrait":
|
|
100
|
-
|
|
101
|
-
case "landscape":
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
mask = .landscapeLeft
|
|
105
|
-
case "landscape-right":
|
|
106
|
-
mask = .landscapeRight
|
|
107
|
-
default: // "auto"
|
|
108
|
-
mask = .all
|
|
88
|
+
case "portrait": mask = .portrait
|
|
89
|
+
case "landscape": mask = .landscape
|
|
90
|
+
case "landscape-left": mask = .landscapeLeft
|
|
91
|
+
case "landscape-right":mask = .landscapeRight
|
|
92
|
+
default: mask = .all
|
|
109
93
|
}
|
|
110
|
-
|
|
111
|
-
// iOS 16+
|
|
112
94
|
if #available(iOS 16.0, *) {
|
|
113
|
-
|
|
114
|
-
.
|
|
115
|
-
windowScene?.requestGeometryUpdate(
|
|
116
|
-
.iOS(interfaceOrientations: mask)
|
|
117
|
-
)
|
|
95
|
+
(UIApplication.shared.connectedScenes.first as? UIWindowScene)?
|
|
96
|
+
.requestGeometryUpdate(.iOS(interfaceOrientations: mask))
|
|
118
97
|
} else {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
98
|
+
UIDevice.current.setValue(UIInterfaceOrientation.portrait.rawValue, forKey: "orientation")
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ═══════════════════════════════════════════════
|
|
104
|
+
// 🆕 NETWORK INFO
|
|
105
|
+
// ═══════════════════════════════════════════════
|
|
106
|
+
|
|
107
|
+
private func currentNetworkMap() -> [String: Any] {
|
|
108
|
+
var isConnected = false
|
|
109
|
+
var type = "unknown"
|
|
110
|
+
|
|
111
|
+
// Use NWPathMonitor snapshot via reachability
|
|
112
|
+
if let reachability = SCNetworkReachabilityCreateWithName(nil, "apple.com") {
|
|
113
|
+
var flags: SCNetworkReachabilityFlags = []
|
|
114
|
+
SCNetworkReachabilityGetFlags(reachability, &flags)
|
|
115
|
+
isConnected = flags.contains(.reachable) && !flags.contains(.connectionRequired)
|
|
116
|
+
if flags.contains(.isWWAN) { type = "cellular" }
|
|
117
|
+
else if isConnected { type = "wifi" }
|
|
118
|
+
else { type = "none" }
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
let airplaneMode = false // iOS doesn't expose this to apps
|
|
122
|
+
return [
|
|
123
|
+
"type": type,
|
|
124
|
+
"isConnected": isConnected,
|
|
125
|
+
"isAirplaneMode": airplaneMode,
|
|
126
|
+
"ssid": NSNull(),
|
|
127
|
+
"cellularGeneration": NSNull(),
|
|
128
|
+
]
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
@objc
|
|
132
|
+
func getNetworkInfo(_ resolve: @escaping RCTPromiseResolveBlock,
|
|
133
|
+
rejecter reject: RCTPromiseRejectBlock) {
|
|
134
|
+
resolve(currentNetworkMap())
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
@objc func startNetworkListener() {
|
|
138
|
+
networkMonitor?.cancel()
|
|
139
|
+
let monitor = NWPathMonitor()
|
|
140
|
+
monitor.pathUpdateHandler = { [weak self] _ in
|
|
141
|
+
self?.emit("SystemBar_NetworkChange", body: self?.currentNetworkMap() ?? [:])
|
|
142
|
+
}
|
|
143
|
+
monitor.start(queue: DispatchQueue.global(qos: .background))
|
|
144
|
+
networkMonitor = monitor
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
@objc func stopNetworkListener() {
|
|
148
|
+
networkMonitor?.cancel(); networkMonitor = nil
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// ═══════════════════════════════════════════════
|
|
152
|
+
// 🆕 BATTERY
|
|
153
|
+
// ═══════════════════════════════════════════════
|
|
154
|
+
|
|
155
|
+
private func currentBatteryMap() -> [String: Any] {
|
|
156
|
+
UIDevice.current.isBatteryMonitoringEnabled = true
|
|
157
|
+
let raw = UIDevice.current.batteryLevel // -1 if unknown
|
|
158
|
+
let level = raw >= 0 ? Int(raw * 100) : -1
|
|
159
|
+
let state: String
|
|
160
|
+
switch UIDevice.current.batteryState {
|
|
161
|
+
case .charging: state = "charging"
|
|
162
|
+
case .full: state = "full"
|
|
163
|
+
case .unplugged: state = "discharging"
|
|
164
|
+
default: state = "unknown"
|
|
165
|
+
}
|
|
166
|
+
let isCharging = state == "charging" || state == "full"
|
|
167
|
+
return [
|
|
168
|
+
"level": level,
|
|
169
|
+
"state": state,
|
|
170
|
+
"isCharging": isCharging,
|
|
171
|
+
"isLow": level >= 0 && level <= 20 && !isCharging,
|
|
172
|
+
]
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
@objc
|
|
176
|
+
func getBatteryInfo(_ resolve: @escaping RCTPromiseResolveBlock,
|
|
177
|
+
rejecter reject: RCTPromiseRejectBlock) {
|
|
178
|
+
UIDevice.current.isBatteryMonitoringEnabled = true
|
|
179
|
+
resolve(currentBatteryMap())
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
@objc func startBatteryListener() {
|
|
183
|
+
UIDevice.current.isBatteryMonitoringEnabled = true
|
|
184
|
+
let nc = NotificationCenter.default
|
|
185
|
+
batteryObservers = [
|
|
186
|
+
nc.addObserver(forName: UIDevice.batteryLevelDidChangeNotification, object: nil, queue: .main) { [weak self] _ in
|
|
187
|
+
self?.emit("SystemBar_BatteryChange", body: self?.currentBatteryMap() ?? [:])
|
|
188
|
+
},
|
|
189
|
+
nc.addObserver(forName: UIDevice.batteryStateDidChangeNotification, object: nil, queue: .main) { [weak self] _ in
|
|
190
|
+
self?.emit("SystemBar_BatteryChange", body: self?.currentBatteryMap() ?? [:])
|
|
191
|
+
},
|
|
192
|
+
]
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
@objc func stopBatteryListener() {
|
|
196
|
+
batteryObservers.forEach { NotificationCenter.default.removeObserver($0) }
|
|
197
|
+
batteryObservers = []
|
|
198
|
+
UIDevice.current.isBatteryMonitoringEnabled = false
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// ═══════════════════════════════════════════════
|
|
202
|
+
// 🆕 HAPTIC FEEDBACK
|
|
203
|
+
// ═══════════════════════════════════════════════
|
|
204
|
+
|
|
205
|
+
@objc func haptic(_ pattern: String) {
|
|
206
|
+
DispatchQueue.main.async {
|
|
207
|
+
switch pattern {
|
|
208
|
+
case "light":
|
|
209
|
+
UIImpactFeedbackGenerator(style: .light).impactOccurred()
|
|
210
|
+
case "medium":
|
|
211
|
+
UIImpactFeedbackGenerator(style: .medium).impactOccurred()
|
|
212
|
+
case "heavy":
|
|
213
|
+
UIImpactFeedbackGenerator(style: .heavy).impactOccurred()
|
|
214
|
+
case "success":
|
|
215
|
+
UINotificationFeedbackGenerator().notificationOccurred(.success)
|
|
216
|
+
case "warning":
|
|
217
|
+
UINotificationFeedbackGenerator().notificationOccurred(.warning)
|
|
218
|
+
case "error":
|
|
219
|
+
UINotificationFeedbackGenerator().notificationOccurred(.error)
|
|
220
|
+
case "selection":
|
|
221
|
+
UISelectionFeedbackGenerator().selectionChanged()
|
|
222
|
+
default:
|
|
223
|
+
UIImpactFeedbackGenerator(style: .medium).impactOccurred()
|
|
124
224
|
}
|
|
125
225
|
}
|
|
126
226
|
}
|
|
127
227
|
|
|
128
|
-
//
|
|
129
|
-
//
|
|
130
|
-
//
|
|
131
|
-
|
|
132
|
-
|
|
228
|
+
// ═══════════════════════════════════════════════
|
|
229
|
+
// 🆕 SCREENCAST
|
|
230
|
+
// ═══════════════════════════════════════════════
|
|
231
|
+
|
|
232
|
+
private func currentScreencastMap() -> [String: Any] {
|
|
233
|
+
let isCasting = UIScreen.screens.count > 1
|
|
234
|
+
return [
|
|
235
|
+
"isCasting": isCasting,
|
|
236
|
+
"displayName": isCasting ? "External Display" : NSNull(),
|
|
237
|
+
]
|
|
238
|
+
}
|
|
133
239
|
|
|
240
|
+
@objc
|
|
241
|
+
func getScreencastInfo(_ resolve: @escaping RCTPromiseResolveBlock,
|
|
242
|
+
rejecter reject: RCTPromiseRejectBlock) {
|
|
243
|
+
resolve(currentScreencastMap())
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
@objc func startScreencastListener() {
|
|
247
|
+
screencastObserver = NotificationCenter.default.addObserver(
|
|
248
|
+
forName: UIScreen.didConnectNotification, object: nil, queue: .main
|
|
249
|
+
) { [weak self] _ in
|
|
250
|
+
self?.emit("SystemBar_ScreencastChange", body: self?.currentScreencastMap() ?? [:])
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
@objc func stopScreencastListener() {
|
|
255
|
+
if let obs = screencastObserver { NotificationCenter.default.removeObserver(obs) }
|
|
256
|
+
screencastObserver = nil
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// setSecureScreen — iOS doesn't support this via public API (no-op)
|
|
260
|
+
@objc func setSecureScreen(_ enable: Bool) {}
|
|
261
|
+
|
|
262
|
+
// ═══════════════════════════════════════════════
|
|
263
|
+
// 🆕 FONT SCALE
|
|
264
|
+
// ═══════════════════════════════════════════════
|
|
265
|
+
|
|
266
|
+
private func currentFontScaleMap() -> [String: Any] {
|
|
267
|
+
return [
|
|
268
|
+
"fontScale": Double(UIApplication.shared.preferredContentSizeCategory == .large ? 1.0 : 1.0),
|
|
269
|
+
"density": Double(UIScreen.main.scale),
|
|
270
|
+
]
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
@objc
|
|
274
|
+
func getFontScaleInfo(_ resolve: @escaping RCTPromiseResolveBlock,
|
|
275
|
+
rejecter reject: RCTPromiseRejectBlock) {
|
|
276
|
+
resolve(currentFontScaleMap())
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
@objc func startFontScaleListener() {
|
|
280
|
+
fontScaleObserver = NotificationCenter.default.addObserver(
|
|
281
|
+
forName: UIContentSizeCategory.didChangeNotification, object: nil, queue: .main
|
|
282
|
+
) { [weak self] _ in
|
|
283
|
+
self?.emit("SystemBar_FontScaleChange", body: self?.currentFontScaleMap() ?? [:])
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
@objc func stopFontScaleListener() {
|
|
288
|
+
if let obs = fontScaleObserver { NotificationCenter.default.removeObserver(obs) }
|
|
289
|
+
fontScaleObserver = nil
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// ── Android-only stubs ─────────────────────
|
|
134
293
|
@objc func setNavigationBarColor(_ color: String) {}
|
|
135
294
|
@objc func setNavigationBarVisibility(_ mode: String) {}
|
|
136
295
|
@objc func setNavigationBarButtonStyle(_ style: String) {}
|
|
@@ -139,7 +298,6 @@ class SystemBarModule: NSObject {
|
|
|
139
298
|
@objc func setStatusBarColor(_ color: String) {}
|
|
140
299
|
@objc func setVolumeHUDVisible(_ visible: Bool) {}
|
|
141
300
|
@objc func immersiveMode(_ enable: Bool) {}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
@objc static func requiresMainQueueSetup() -> Bool { return false }
|
|
301
|
+
@objc func setStatusBarStyle(_ style: String) {}
|
|
302
|
+
@objc func setStatusBarVisibility(_ visible: Bool) {}
|
|
145
303
|
}
|
package/lib/index.d.ts
ADDED
package/lib/index.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ─────────────────────────────────────────────
|
|
3
|
+
// rn-system-bar · index.ts
|
|
4
|
+
// ─────────────────────────────────────────────
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
17
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
18
|
+
};
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.useHaptic = exports.useFontScale = exports.useScreencast = exports.useNetwork = exports.useBattery = exports.useSystemBar = void 0;
|
|
21
|
+
__exportStar(require("./src/SystemBar"), exports);
|
|
22
|
+
__exportStar(require("./src/types"), exports);
|
|
23
|
+
var useSystemBar_1 = require("./src/useSystemBar");
|
|
24
|
+
Object.defineProperty(exports, "useSystemBar", { enumerable: true, get: function () { return useSystemBar_1.useSystemBar; } });
|
|
25
|
+
Object.defineProperty(exports, "useBattery", { enumerable: true, get: function () { return useSystemBar_1.useBattery; } });
|
|
26
|
+
Object.defineProperty(exports, "useNetwork", { enumerable: true, get: function () { return useSystemBar_1.useNetwork; } });
|
|
27
|
+
Object.defineProperty(exports, "useScreencast", { enumerable: true, get: function () { return useSystemBar_1.useScreencast; } });
|
|
28
|
+
Object.defineProperty(exports, "useFontScale", { enumerable: true, get: function () { return useSystemBar_1.useFontScale; } });
|
|
29
|
+
Object.defineProperty(exports, "useHaptic", { enumerable: true, get: function () { return useSystemBar_1.useHaptic; } });
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { TurboModule } from "react-native";
|
|
2
|
+
export interface Spec extends TurboModule {
|
|
3
|
+
setNavigationBarColor(color: string): void;
|
|
4
|
+
setNavigationBarVisibility(mode: string): void;
|
|
5
|
+
setNavigationBarButtonStyle(style: string): void;
|
|
6
|
+
setNavigationBarStyle(style: string): void;
|
|
7
|
+
setNavigationBarBehavior(behavior: string): void;
|
|
8
|
+
setStatusBarColor(color: string): void;
|
|
9
|
+
setStatusBarStyle(style: string): void;
|
|
10
|
+
setStatusBarVisibility(visible: boolean): void;
|
|
11
|
+
setBrightness(level: number): void;
|
|
12
|
+
getBrightness(): Promise<number>;
|
|
13
|
+
setVolume(level: number, stream: string): void;
|
|
14
|
+
getVolume(stream: string): Promise<number>;
|
|
15
|
+
setVolumeHUDVisible(visible: boolean): void;
|
|
16
|
+
keepScreenOn(enable: boolean): void;
|
|
17
|
+
immersiveMode(enable: boolean): void;
|
|
18
|
+
setOrientation(mode: string): void;
|
|
19
|
+
}
|
|
20
|
+
declare const _default: Spec;
|
|
21
|
+
export default _default;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ─────────────────────────────────────────────
|
|
3
|
+
// rn-system-bar · NativeSystemBar.ts
|
|
4
|
+
// TurboModule spec — New Architecture (JSI)
|
|
5
|
+
// ─────────────────────────────────────────────
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
const react_native_1 = require("react-native");
|
|
8
|
+
exports.default = react_native_1.TurboModuleRegistry.getEnforcing("SystemBar");
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { BatteryInfo, FontScaleInfo, HapticPattern, NavigationBarBehavior, NavigationBarButtonStyle, NavigationBarStyle, NavigationBarVisibility, NetworkInfo, Orientation, ScreencastInfo, StatusBarStyle, VolumeStream } from "./types";
|
|
2
|
+
export declare const setNavigationBarColor: (color: string) => Promise<void>;
|
|
3
|
+
export declare const setNavigationBarVisibility: (mode: NavigationBarVisibility) => Promise<void>;
|
|
4
|
+
export declare const setNavigationBarButtonStyle: (style: NavigationBarButtonStyle) => Promise<void>;
|
|
5
|
+
export declare const setNavigationBarStyle: (style: NavigationBarStyle) => Promise<void>;
|
|
6
|
+
export declare const setNavigationBarBehavior: (behavior: NavigationBarBehavior) => Promise<void>;
|
|
7
|
+
export declare const setStatusBarColor: (color: string, animated?: boolean) => void;
|
|
8
|
+
export declare const setStatusBarStyle: (style: StatusBarStyle, animated?: boolean) => void;
|
|
9
|
+
export declare const setStatusBarVisibility: (visible: boolean, animated?: boolean) => void;
|
|
10
|
+
export declare const setBrightness: (level: number) => void;
|
|
11
|
+
export declare const getBrightness: () => Promise<number>;
|
|
12
|
+
export declare const setVolume: (level: number, stream?: VolumeStream) => void;
|
|
13
|
+
export declare const getVolume: (stream?: VolumeStream) => Promise<number>;
|
|
14
|
+
export declare const setVolumeHUDVisible: (visible: boolean) => void;
|
|
15
|
+
export declare const keepScreenOn: (enable: boolean) => void;
|
|
16
|
+
export declare const immersiveMode: (enable: boolean) => void;
|
|
17
|
+
export declare const setOrientation: (mode: Orientation) => void;
|
|
18
|
+
/**
|
|
19
|
+
* Get current network connection info.
|
|
20
|
+
* Includes: type, isConnected, isAirplaneMode, ssid, cellularGeneration
|
|
21
|
+
*/
|
|
22
|
+
export declare const getNetworkInfo: () => Promise<NetworkInfo>;
|
|
23
|
+
/**
|
|
24
|
+
* Subscribe to network changes.
|
|
25
|
+
* @returns unsubscribe function — call it in useEffect cleanup
|
|
26
|
+
* @example
|
|
27
|
+
* const unsub = onNetworkChange((info) => console.log(info));
|
|
28
|
+
* return () => unsub();
|
|
29
|
+
*/
|
|
30
|
+
export declare const onNetworkChange: (callback: (info: NetworkInfo) => void) => (() => void);
|
|
31
|
+
/**
|
|
32
|
+
* Get current battery info: level (0–100), state, isCharging, isLow.
|
|
33
|
+
*/
|
|
34
|
+
export declare const getBatteryInfo: () => Promise<BatteryInfo>;
|
|
35
|
+
/**
|
|
36
|
+
* Subscribe to battery level / state changes.
|
|
37
|
+
* @returns unsubscribe function
|
|
38
|
+
*/
|
|
39
|
+
export declare const onBatteryChange: (callback: (info: BatteryInfo) => void) => (() => void);
|
|
40
|
+
/**
|
|
41
|
+
* Trigger haptic feedback.
|
|
42
|
+
*
|
|
43
|
+
* iOS: Uses UIImpactFeedbackGenerator / UINotificationFeedbackGenerator.
|
|
44
|
+
* Android: Uses Vibrator / VibrationEffect (API 26+).
|
|
45
|
+
*
|
|
46
|
+
* @param pattern "light" | "medium" | "heavy" | "success" | "warning" | "error" | "selection"
|
|
47
|
+
*/
|
|
48
|
+
export declare const haptic: (pattern: HapticPattern) => void;
|
|
49
|
+
/**
|
|
50
|
+
* Check if screen is currently being cast or mirrored.
|
|
51
|
+
*/
|
|
52
|
+
export declare const getScreencastInfo: () => Promise<ScreencastInfo>;
|
|
53
|
+
/**
|
|
54
|
+
* Subscribe to screencast state changes (started / stopped).
|
|
55
|
+
* @returns unsubscribe function
|
|
56
|
+
*/
|
|
57
|
+
export declare const onScreencastChange: (callback: (info: ScreencastInfo) => void) => (() => void);
|
|
58
|
+
/**
|
|
59
|
+
* Prevent screen content from appearing in screenshots / recordings.
|
|
60
|
+
* Useful for sensitive screens (payments, passwords).
|
|
61
|
+
* @platform android
|
|
62
|
+
*/
|
|
63
|
+
export declare const setSecureScreen: (enable: boolean) => void;
|
|
64
|
+
/**
|
|
65
|
+
* Get current system font scale and display density.
|
|
66
|
+
* Useful for adapting layout to accessibility settings.
|
|
67
|
+
*/
|
|
68
|
+
export declare const getFontScaleInfo: () => Promise<FontScaleInfo>;
|
|
69
|
+
/**
|
|
70
|
+
* Subscribe to font scale changes (user changes system text size).
|
|
71
|
+
* @returns unsubscribe function
|
|
72
|
+
*/
|
|
73
|
+
export declare const onFontScaleChange: (callback: (info: FontScaleInfo) => void) => (() => void);
|