react-native-flic2 2.0.0-beta.2 → 2.0.0-beta.21
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/Flic2.podspec +14 -4
- package/Flic2Device.podspec +21 -0
- package/Flic2Simulator.podspec +20 -0
- package/README.md +140 -22
- package/android/build.gradle +1 -1
- package/android/src/main/java/{com → nl/xguard}/flic2/ActivityUtil.kt +1 -1
- package/android/src/main/java/{com → nl/xguard}/flic2/Flic2ButtonListener.kt +19 -3
- package/android/src/main/java/{com → nl/xguard}/flic2/Flic2Converter.kt +2 -3
- package/android/src/main/java/{com → nl/xguard}/flic2/Flic2Module.kt +70 -53
- package/android/src/main/java/{com → nl/xguard}/flic2/Flic2Package.kt +2 -1
- package/android/src/main/java/{com → nl/xguard}/flic2/Flic2Service.kt +11 -22
- package/ios/Flic2.mm +45 -29
- package/ios/Flic2SimulatorStub.h +5 -0
- package/ios/Flic2SimulatorStub.mm +134 -0
- package/lib/module/NativeFlic2.js +45 -1
- package/lib/module/NativeFlic2.js.map +1 -1
- package/lib/module/index.js +10 -14
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/NativeFlic2.d.ts +14 -49
- package/lib/typescript/src/NativeFlic2.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +17 -52
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +23 -23
- package/src/NativeFlic2.ts +76 -29
- package/src/index.ts +25 -40
- package/lib/module/index.bak.js +0 -161
- package/lib/module/index.bak.js.map +0 -1
- package/lib/typescript/src/index.bak.d.ts +0 -1
- package/lib/typescript/src/index.bak.d.ts.map +0 -1
- package/src/index.bak.tsx +0 -159
package/Flic2.podspec
CHANGED
|
@@ -13,10 +13,20 @@ Pod::Spec.new do |s|
|
|
|
13
13
|
s.platforms = { :ios => min_ios_version_supported }
|
|
14
14
|
s.source = { :git => "https://github.com/X-Guard/react-native-flic2.git", :tag => "#{s.version}" }
|
|
15
15
|
|
|
16
|
-
s
|
|
17
|
-
s.private_header_files = "ios/**/*.h"
|
|
16
|
+
install_modules_dependencies(s)
|
|
18
17
|
|
|
19
|
-
|
|
18
|
+
# Keep the root spec codegen-only so consumers can opt into
|
|
19
|
+
# Device/Simulator implementations explicitly.
|
|
20
|
+
s.default_subspecs = []
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
s.subspec "Device" do |sp|
|
|
23
|
+
sp.source_files = "ios/Flic2.{h,mm}"
|
|
24
|
+
sp.private_header_files = "ios/Flic2.h"
|
|
25
|
+
sp.ios.vendored_frameworks = "ios/flic2lib.framework"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
s.subspec "Simulator" do |sp|
|
|
29
|
+
sp.source_files = "ios/Flic2SimulatorStub.{h,mm}"
|
|
30
|
+
sp.private_header_files = "ios/Flic2SimulatorStub.h"
|
|
31
|
+
end
|
|
22
32
|
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
|
|
4
|
+
|
|
5
|
+
Pod::Spec.new do |s|
|
|
6
|
+
s.name = "Flic2Device"
|
|
7
|
+
s.version = package["version"]
|
|
8
|
+
s.summary = package["description"]
|
|
9
|
+
s.homepage = package["homepage"]
|
|
10
|
+
s.license = package["license"]
|
|
11
|
+
s.authors = package["author"]
|
|
12
|
+
|
|
13
|
+
s.platforms = { :ios => min_ios_version_supported }
|
|
14
|
+
s.source = { :git => "https://github.com/X-Guard/react-native-flic2.git", :tag => "#{s.version}" }
|
|
15
|
+
|
|
16
|
+
install_modules_dependencies(s)
|
|
17
|
+
|
|
18
|
+
s.source_files = "ios/Flic2.{h,mm}"
|
|
19
|
+
s.private_header_files = "ios/Flic2.h"
|
|
20
|
+
s.ios.vendored_frameworks = "ios/flic2lib.framework"
|
|
21
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
|
|
4
|
+
|
|
5
|
+
Pod::Spec.new do |s|
|
|
6
|
+
s.name = "Flic2Simulator"
|
|
7
|
+
s.version = package["version"]
|
|
8
|
+
s.summary = package["description"]
|
|
9
|
+
s.homepage = package["homepage"]
|
|
10
|
+
s.license = package["license"]
|
|
11
|
+
s.authors = package["author"]
|
|
12
|
+
|
|
13
|
+
s.platforms = { :ios => min_ios_version_supported }
|
|
14
|
+
s.source = { :git => "https://github.com/X-Guard/react-native-flic2.git", :tag => "#{s.version}" }
|
|
15
|
+
|
|
16
|
+
install_modules_dependencies(s)
|
|
17
|
+
|
|
18
|
+
s.source_files = "ios/Flic2SimulatorStub.{h,mm}"
|
|
19
|
+
s.private_header_files = "ios/Flic2SimulatorStub.h"
|
|
20
|
+
end
|
package/README.md
CHANGED
|
@@ -37,6 +37,15 @@ npm install react-native-flic2
|
|
|
37
37
|
cd ios && pod install && cd ..
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
+
**Need simulator builds?**
|
|
41
|
+
See `Troubleshooting` -> `Running on iOS Simulator` for a full configuration
|
|
42
|
+
example and launch commands.
|
|
43
|
+
|
|
44
|
+
**Important (iOS pod wiring):**
|
|
45
|
+
The autolinked root `Flic2` pod is codegen-only in the 2.x beta setup.
|
|
46
|
+
To get a real iOS runtime implementation, add `Flic2Device` in your Podfile
|
|
47
|
+
(and `Flic2Simulator` for simulator-specific configurations).
|
|
48
|
+
|
|
40
49
|
2. **Add Bluetooth permissions to `Info.plist`:**
|
|
41
50
|
Add the following keys to your `ios/YourApp/Info.plist`:
|
|
42
51
|
```xml
|
|
@@ -66,6 +75,65 @@ The library automatically includes the necessary permissions in `AndroidManifest
|
|
|
66
75
|
|
|
67
76
|
You'll need to request these permissions before scanning for buttons. Use a library like `react-native-permissions` or implement permission requests manually.
|
|
68
77
|
|
|
78
|
+
#### Customizing the Foreground Service Notification (Android)
|
|
79
|
+
|
|
80
|
+
The library runs a foreground service to keep Flic2 buttons connected in the background. You can customize the notification appearance by adding metadata to your app's `AndroidManifest.xml`:
|
|
81
|
+
|
|
82
|
+
```xml
|
|
83
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
84
|
+
<application>
|
|
85
|
+
<!-- Your existing application configuration -->
|
|
86
|
+
|
|
87
|
+
<!-- Customize Flic2 foreground service notification -->
|
|
88
|
+
<meta-data
|
|
89
|
+
android:name="nl.xguard.flic2.notification_title"
|
|
90
|
+
android:value="My Flic2 Service" />
|
|
91
|
+
<meta-data
|
|
92
|
+
android:name="nl.xguard.flic2.notification_text"
|
|
93
|
+
android:value="Flic2 buttons are active" />
|
|
94
|
+
<meta-data
|
|
95
|
+
android:name="nl.xguard.flic2.notification_icon"
|
|
96
|
+
android:resource="@drawable/ic_notification" />
|
|
97
|
+
<meta-data
|
|
98
|
+
android:name="nl.xguard.flic2.notification_channel_name"
|
|
99
|
+
android:value="Flic2 Notifications" />
|
|
100
|
+
<meta-data
|
|
101
|
+
android:name="nl.xguard.flic2.notification_channel_description"
|
|
102
|
+
android:value="Notifications for Flic2 button connections" />
|
|
103
|
+
<meta-data
|
|
104
|
+
android:name="nl.xguard.flic2.notification_id"
|
|
105
|
+
android:value="123321" />
|
|
106
|
+
<meta-data
|
|
107
|
+
android:name="nl.xguard.flic2.notification_channel_id"
|
|
108
|
+
android:value="my_custom_channel_id" />
|
|
109
|
+
</application>
|
|
110
|
+
</manifest>
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Available Configuration Options:**
|
|
114
|
+
|
|
115
|
+
- `nl.xguard.flic2.notification_title` - Notification title (default: "Flic 2")
|
|
116
|
+
- `nl.xguard.flic2.notification_text` - Notification text (default: "Flic 2 service is running")
|
|
117
|
+
- `nl.xguard.flic2.notification_icon` - Notification icon resource ID (default: system info icon)
|
|
118
|
+
- Use `@drawable/your_icon_name` or `@mipmap/your_icon_name` format
|
|
119
|
+
- `nl.xguard.flic2.notification_channel_name` - Notification channel name (default: "Flic2Channel")
|
|
120
|
+
- `nl.xguard.flic2.notification_channel_description` - Notification channel description (default: "Flic2Channel")
|
|
121
|
+
- `nl.xguard.flic2.notification_id` - Notification ID integer (default: 123321)
|
|
122
|
+
- `nl.xguard.flic2.notification_channel_id` - Notification channel ID string (default: "Notification_Channel_Flic2Service")
|
|
123
|
+
|
|
124
|
+
**Example with Custom Icon:**
|
|
125
|
+
|
|
126
|
+
1. Add your notification icon to `android/app/src/main/res/drawable/` (e.g., `ic_flic2_notification.png`)
|
|
127
|
+
|
|
128
|
+
2. Add metadata to `AndroidManifest.xml`:
|
|
129
|
+
```xml
|
|
130
|
+
<meta-data
|
|
131
|
+
android:name="nl.xguard.flic2.notification_icon"
|
|
132
|
+
android:resource="@drawable/ic_flic2_notification" />
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
**Note:** The notification icon must be a white/transparent icon suitable for Android notifications. If you don't specify a custom icon, the system default info icon will be used.
|
|
136
|
+
|
|
69
137
|
## Basic Usage
|
|
70
138
|
|
|
71
139
|
### 1. Initialize the Library (Global Setup)
|
|
@@ -390,7 +458,7 @@ export default Flic2Example;
|
|
|
390
458
|
|
|
391
459
|
### Initialization
|
|
392
460
|
|
|
393
|
-
#### `initialize(): Promise<
|
|
461
|
+
#### `initialize(): Promise<void>`
|
|
394
462
|
|
|
395
463
|
Initialize the Flic2 manager. This must be called before using any other methods.
|
|
396
464
|
|
|
@@ -400,7 +468,7 @@ await Flic2.initialize();
|
|
|
400
468
|
|
|
401
469
|
### Scanning
|
|
402
470
|
|
|
403
|
-
#### `startScan(): Promise<
|
|
471
|
+
#### `startScan(): Promise<void>`
|
|
404
472
|
|
|
405
473
|
Start scanning for new Flic2 buttons. The scan will emit `scanStatusChange` events.
|
|
406
474
|
|
|
@@ -408,7 +476,7 @@ Start scanning for new Flic2 buttons. The scan will emit `scanStatusChange` even
|
|
|
408
476
|
await Flic2.startScan();
|
|
409
477
|
```
|
|
410
478
|
|
|
411
|
-
#### `stopScan(): Promise<
|
|
479
|
+
#### `stopScan(): Promise<void>`
|
|
412
480
|
|
|
413
481
|
Stop an ongoing scan.
|
|
414
482
|
|
|
@@ -442,7 +510,7 @@ Get a specific button by UUID.
|
|
|
442
510
|
const button = await Flic2.getButton('button-uuid');
|
|
443
511
|
```
|
|
444
512
|
|
|
445
|
-
#### `connectAllKnownButtons(): Promise<
|
|
513
|
+
#### `connectAllKnownButtons(): Promise<void>`
|
|
446
514
|
|
|
447
515
|
Connect to all previously known buttons.
|
|
448
516
|
|
|
@@ -450,7 +518,7 @@ Connect to all previously known buttons.
|
|
|
450
518
|
await Flic2.connectAllKnownButtons();
|
|
451
519
|
```
|
|
452
520
|
|
|
453
|
-
#### `disconnectAllKnownButtons(): Promise<
|
|
521
|
+
#### `disconnectAllKnownButtons(): Promise<void>`
|
|
454
522
|
|
|
455
523
|
Disconnect all connected buttons.
|
|
456
524
|
|
|
@@ -458,7 +526,7 @@ Disconnect all connected buttons.
|
|
|
458
526
|
await Flic2.disconnectAllKnownButtons();
|
|
459
527
|
```
|
|
460
528
|
|
|
461
|
-
#### `forgetButton(uuid: string): Promise<
|
|
529
|
+
#### `forgetButton(uuid: string): Promise<void>`
|
|
462
530
|
|
|
463
531
|
Forget (unpair) a specific button.
|
|
464
532
|
|
|
@@ -466,7 +534,7 @@ Forget (unpair) a specific button.
|
|
|
466
534
|
await Flic2.forgetButton('button-uuid');
|
|
467
535
|
```
|
|
468
536
|
|
|
469
|
-
#### `forgetAllButtons(): Promise<
|
|
537
|
+
#### `forgetAllButtons(): Promise<void>`
|
|
470
538
|
|
|
471
539
|
Forget all buttons.
|
|
472
540
|
|
|
@@ -476,50 +544,54 @@ await Flic2.forgetAllButtons();
|
|
|
476
544
|
|
|
477
545
|
### Button Configuration
|
|
478
546
|
|
|
479
|
-
#### `buttonConnect(uuid: string): Promise<
|
|
547
|
+
#### `buttonConnect(uuid: string): Promise<FlicButton>`
|
|
480
548
|
|
|
481
|
-
Connect to a specific button.
|
|
549
|
+
Connect to a specific button. Returns the button object.
|
|
482
550
|
|
|
483
551
|
```tsx
|
|
484
|
-
await Flic2.buttonConnect('button-uuid');
|
|
552
|
+
const button = await Flic2.buttonConnect('button-uuid');
|
|
485
553
|
```
|
|
486
554
|
|
|
487
|
-
#### `buttonDisconnect(uuid: string): Promise<
|
|
555
|
+
#### `buttonDisconnect(uuid: string): Promise<FlicButton>`
|
|
488
556
|
|
|
489
|
-
Disconnect a specific button.
|
|
557
|
+
Disconnect a specific button. Returns the button object.
|
|
490
558
|
|
|
491
559
|
```tsx
|
|
492
|
-
await Flic2.buttonDisconnect('button-uuid');
|
|
560
|
+
const button = await Flic2.buttonDisconnect('button-uuid');
|
|
493
561
|
```
|
|
494
562
|
|
|
495
|
-
#### `buttonSetNickname(uuid: string, nickname: string): Promise<
|
|
563
|
+
#### `buttonSetNickname(uuid: string, nickname: string): Promise<FlicButton>`
|
|
496
564
|
|
|
497
|
-
Set a custom nickname for a button.
|
|
565
|
+
Set a custom nickname for a button. Returns the updated button object.
|
|
498
566
|
|
|
499
567
|
```tsx
|
|
500
|
-
await Flic2.buttonSetNickname('button-uuid', 'My Button');
|
|
568
|
+
const button = await Flic2.buttonSetNickname('button-uuid', 'My Button');
|
|
501
569
|
```
|
|
502
570
|
|
|
503
|
-
#### `buttonSetTriggerMode(uuid: string, mode: TriggerModeType): Promise<
|
|
571
|
+
#### `buttonSetTriggerMode(uuid: string, mode: TriggerModeType): Promise<FlicButton>`
|
|
504
572
|
|
|
505
|
-
Set the trigger mode for a button. Modes:
|
|
573
|
+
Set the trigger mode for a button. Returns the updated button object. Modes:
|
|
506
574
|
- `0`: Click and Hold
|
|
507
575
|
- `1`: Click and Double Click
|
|
508
576
|
- `2`: Click and Double Click and Hold
|
|
509
577
|
- `3`: Click only
|
|
510
578
|
|
|
579
|
+
**Note:** This method is only supported on iOS. On Android, it will reject with an error.
|
|
580
|
+
|
|
511
581
|
```tsx
|
|
512
|
-
await Flic2.buttonSetTriggerMode('button-uuid', 3); // Click only
|
|
582
|
+
const button = await Flic2.buttonSetTriggerMode('button-uuid', 3); // Click only
|
|
513
583
|
```
|
|
514
584
|
|
|
515
|
-
#### `buttonSetLatencyMode(uuid: string, mode: LatencyModeType): Promise<
|
|
585
|
+
#### `buttonSetLatencyMode(uuid: string, mode: LatencyModeType): Promise<FlicButton>`
|
|
516
586
|
|
|
517
|
-
Set the latency mode for a button. Modes:
|
|
587
|
+
Set the latency mode for a button. Returns the updated button object. Modes:
|
|
518
588
|
- `0`: Normal latency
|
|
519
589
|
- `1`: Low latency
|
|
520
590
|
|
|
591
|
+
**Note:** This method is only supported on iOS. On Android, it will reject with an error.
|
|
592
|
+
|
|
521
593
|
```tsx
|
|
522
|
-
await Flic2.buttonSetLatencyMode('button-uuid', 1); // Low latency
|
|
594
|
+
const button = await Flic2.buttonSetLatencyMode('button-uuid', 1); // Low latency
|
|
523
595
|
```
|
|
524
596
|
|
|
525
597
|
#### `getBatteryHealth(uuid: string): Promise<boolean>`
|
|
@@ -728,6 +800,52 @@ const scanForButtons = async () => {
|
|
|
728
800
|
|
|
729
801
|
## Troubleshooting
|
|
730
802
|
|
|
803
|
+
### Running on iOS Simulator
|
|
804
|
+
|
|
805
|
+
`flic2lib` is device-only. For simulator builds, use the no-op simulator pod and a
|
|
806
|
+
dedicated simulator build configuration.
|
|
807
|
+
|
|
808
|
+
1. Add a simulator configuration in Xcode (for example `DebugSimulator`) and a scheme that uses it.
|
|
809
|
+
2. Map pods by configuration in your app `Podfile`:
|
|
810
|
+
|
|
811
|
+
```ruby
|
|
812
|
+
# Example
|
|
813
|
+
project 'YourApp.xcodeproj', {
|
|
814
|
+
'Debug' => :debug,
|
|
815
|
+
'DebugSimulator' => :debug,
|
|
816
|
+
'Release' => :release,
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
target 'YourApp' do
|
|
820
|
+
# ... your existing use_react_native! setup
|
|
821
|
+
|
|
822
|
+
pod 'Flic2Device',
|
|
823
|
+
:path => '../node_modules/react-native-flic2',
|
|
824
|
+
:configurations => ['Debug', 'Release']
|
|
825
|
+
|
|
826
|
+
pod 'Flic2Simulator',
|
|
827
|
+
:path => '../node_modules/react-native-flic2',
|
|
828
|
+
:configurations => ['DebugSimulator']
|
|
829
|
+
end
|
|
830
|
+
```
|
|
831
|
+
|
|
832
|
+
3. Install pods normally (no env flags):
|
|
833
|
+
|
|
834
|
+
```sh
|
|
835
|
+
cd ios && bundle exec pod install && cd ..
|
|
836
|
+
```
|
|
837
|
+
|
|
838
|
+
4. Launch simulator build (example):
|
|
839
|
+
|
|
840
|
+
```sh
|
|
841
|
+
npx react-native run-ios --scheme YourAppSimulator --mode DebugSimulator --simulator "iPhone 17"
|
|
842
|
+
```
|
|
843
|
+
|
|
844
|
+
Expected behavior on simulator:
|
|
845
|
+
- App builds and launches.
|
|
846
|
+
- Flic calls are no-op fallback behavior.
|
|
847
|
+
- Real button communication works only on physical devices.
|
|
848
|
+
|
|
731
849
|
### Buttons not connecting
|
|
732
850
|
|
|
733
851
|
- Ensure Bluetooth is enabled on the device
|
package/android/build.gradle
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
package
|
|
1
|
+
package nl.xguard.flic2
|
|
2
2
|
|
|
3
3
|
import com.facebook.react.bridge.Arguments
|
|
4
4
|
import com.facebook.react.bridge.WritableMap
|
|
@@ -47,7 +47,15 @@ class Flic2ButtonEventListener(
|
|
|
47
47
|
val event = if (isDown) "buttonDown" else "buttonUp"
|
|
48
48
|
emitEvent(createButtonEvent(button, event).apply {
|
|
49
49
|
putBoolean("queued", wasQueued)
|
|
50
|
-
|
|
50
|
+
// Match old Android implementation and iOS:
|
|
51
|
+
// - Age is in seconds
|
|
52
|
+
// - Only meaningful for queued events; 0 for real-time events
|
|
53
|
+
val ageSeconds = if (wasQueued) {
|
|
54
|
+
(button.getReadyTimestamp() - timestamp) / 1000.0
|
|
55
|
+
} else {
|
|
56
|
+
0.0
|
|
57
|
+
}
|
|
58
|
+
putDouble("age", ageSeconds)
|
|
51
59
|
})
|
|
52
60
|
}
|
|
53
61
|
|
|
@@ -94,7 +102,15 @@ class Flic2ButtonEventListener(
|
|
|
94
102
|
}
|
|
95
103
|
emitEvent(createButtonEvent(button, event).apply {
|
|
96
104
|
putBoolean("queued", wasQueued)
|
|
97
|
-
|
|
105
|
+
// Match old Android implementation and iOS:
|
|
106
|
+
// - Age is in seconds
|
|
107
|
+
// - Only meaningful for queued events; 0 for real-time events
|
|
108
|
+
val ageSeconds = if (wasQueued) {
|
|
109
|
+
(button.getReadyTimestamp() - timestamp) / 1000.0
|
|
110
|
+
} else {
|
|
111
|
+
0.0
|
|
112
|
+
}
|
|
113
|
+
putDouble("age", ageSeconds)
|
|
98
114
|
})
|
|
99
115
|
}
|
|
100
116
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
package
|
|
1
|
+
package nl.xguard.flic2
|
|
2
2
|
|
|
3
3
|
import com.facebook.react.bridge.Arguments
|
|
4
4
|
import com.facebook.react.bridge.WritableArray
|
|
@@ -31,8 +31,7 @@ object Flic2Converter {
|
|
|
31
31
|
putInt("firmwareRevision", button.getFirmwareVersion())
|
|
32
32
|
|
|
33
33
|
// Check if ready by comparing connection state
|
|
34
|
-
|
|
35
|
-
putBoolean("isReady", isReady)
|
|
34
|
+
putBoolean("isReady", connState == Flic2Button.CONNECTION_STATE_CONNECTED_READY)
|
|
36
35
|
|
|
37
36
|
// Get battery level from BatteryLevel object
|
|
38
37
|
val batteryLevel = button.getLastKnownBatteryLevel()
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
package
|
|
1
|
+
package nl.xguard.flic2
|
|
2
2
|
|
|
3
3
|
import android.content.ComponentName
|
|
4
4
|
import android.content.Context
|
|
@@ -48,8 +48,7 @@ class Flic2Module(reactContext: ReactApplicationContext) :
|
|
|
48
48
|
private val serviceConnection = object : ServiceConnection {
|
|
49
49
|
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
|
|
50
50
|
Log.d(TAG, "Service connected")
|
|
51
|
-
|
|
52
|
-
flic2Service = binder.getService()
|
|
51
|
+
flic2Service = (service as Flic2Service.Flic2ServiceBinder).getService()
|
|
53
52
|
serviceBound = true
|
|
54
53
|
|
|
55
54
|
// Set up listeners for existing buttons
|
|
@@ -63,10 +62,7 @@ class Flic2Module(reactContext: ReactApplicationContext) :
|
|
|
63
62
|
|
|
64
63
|
// Resolve the initialize promise if pending
|
|
65
64
|
initializePromise?.let { promise ->
|
|
66
|
-
promise.resolve(
|
|
67
|
-
putBoolean("success", true)
|
|
68
|
-
putString("message", "Manager initialized successfully")
|
|
69
|
-
})
|
|
65
|
+
promise.resolve(null)
|
|
70
66
|
initializePromise = null
|
|
71
67
|
}
|
|
72
68
|
}
|
|
@@ -90,6 +86,31 @@ class Flic2Module(reactContext: ReactApplicationContext) :
|
|
|
90
86
|
|
|
91
87
|
override fun invalidate() {
|
|
92
88
|
super.invalidate()
|
|
89
|
+
|
|
90
|
+
// Remove all button listeners before cleanup to prevent callbacks after teardown
|
|
91
|
+
try {
|
|
92
|
+
val manager = flic2Service?.getManager()
|
|
93
|
+
if (manager != null) {
|
|
94
|
+
buttonListeners.forEach { (uuid, listener) ->
|
|
95
|
+
try {
|
|
96
|
+
// Find the button and remove the listener
|
|
97
|
+
val button = manager.buttons.find { it.uuid == uuid }
|
|
98
|
+
if (button != null) {
|
|
99
|
+
button.removeListener(listener)
|
|
100
|
+
Log.d(TAG, "Removed listener for button during invalidate: $uuid")
|
|
101
|
+
}
|
|
102
|
+
} catch (e: Exception) {
|
|
103
|
+
Log.w(TAG, "Failed to remove listener for button during invalidate: $uuid", e)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
} catch (e: Exception) {
|
|
108
|
+
Log.w(TAG, "Error during listener cleanup in invalidate", e)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Clear listeners map
|
|
112
|
+
buttonListeners.clear()
|
|
113
|
+
|
|
93
114
|
moduleScope.cancel()
|
|
94
115
|
if (serviceBound) {
|
|
95
116
|
reactApplicationContext.unbindService(serviceConnection)
|
|
@@ -107,8 +128,7 @@ class Flic2Module(reactContext: ReactApplicationContext) :
|
|
|
107
128
|
val intent = Intent(reactApplicationContext, Flic2Service::class.java)
|
|
108
129
|
|
|
109
130
|
// Check if service is already running
|
|
110
|
-
|
|
111
|
-
if (!isRunning) {
|
|
131
|
+
if (!ActivityUtil.isServiceRunning(reactApplicationContext, Flic2Service::class.java)) {
|
|
112
132
|
// Start service
|
|
113
133
|
ActivityUtil.startForegroundService(reactApplicationContext, intent)
|
|
114
134
|
}
|
|
@@ -182,8 +202,6 @@ class Flic2Module(reactContext: ReactApplicationContext) :
|
|
|
182
202
|
override fun onComplete(result: Int, subCode: Int, button: Flic2Button?) {
|
|
183
203
|
Log.d(TAG, "Scan complete: result=$result, button=${button?.uuid}")
|
|
184
204
|
|
|
185
|
-
val resultCode = mapScanResultToCode(result)
|
|
186
|
-
|
|
187
205
|
if (result == Flic2ScanCallback.RESULT_SUCCESS && button != null) {
|
|
188
206
|
// Auto-connect (trigger mode not available in Android v1.1.0+)
|
|
189
207
|
button.connect()
|
|
@@ -202,24 +220,20 @@ class Flic2Module(reactContext: ReactApplicationContext) :
|
|
|
202
220
|
putMap("button", Flic2Converter.buttonToMap(button))
|
|
203
221
|
})
|
|
204
222
|
} else {
|
|
205
|
-
|
|
206
|
-
Log.e(TAG, "Scan failed with error code: $errorCode")
|
|
223
|
+
Log.e(TAG, "Scan failed with error code: ${Flic2Converter.scanResultToString(result)}")
|
|
207
224
|
}
|
|
208
225
|
|
|
209
226
|
// Emit scan completion with result code
|
|
210
227
|
emitOnScanStatusChange(Arguments.createMap().apply {
|
|
211
228
|
putString("event", "completion")
|
|
212
229
|
putString("eventName", "completion")
|
|
213
|
-
putInt("result",
|
|
230
|
+
putInt("result", mapScanResultToCode(result))
|
|
214
231
|
})
|
|
215
232
|
}
|
|
216
233
|
})
|
|
217
234
|
|
|
218
235
|
// Return immediately - scan results will come through events
|
|
219
|
-
promise.resolve(
|
|
220
|
-
putBoolean("success", true)
|
|
221
|
-
putString("message", "Scan started")
|
|
222
|
-
})
|
|
236
|
+
promise.resolve(null)
|
|
223
237
|
}
|
|
224
238
|
|
|
225
239
|
override fun stopScan(promise: Promise) {
|
|
@@ -233,10 +247,7 @@ class Flic2Module(reactContext: ReactApplicationContext) :
|
|
|
233
247
|
scanJob?.cancel()
|
|
234
248
|
manager.stopScan()
|
|
235
249
|
|
|
236
|
-
promise.resolve(
|
|
237
|
-
putBoolean("success", true)
|
|
238
|
-
putString("message", "Scan stopped")
|
|
239
|
-
})
|
|
250
|
+
promise.resolve(null)
|
|
240
251
|
} catch (e: Exception) {
|
|
241
252
|
Log.e(TAG, "Failed to stop scan", e)
|
|
242
253
|
promise.reject("STOP_SCAN_ERROR", "Failed to stop scan: ${e.message}", e)
|
|
@@ -260,7 +271,18 @@ class Flic2Module(reactContext: ReactApplicationContext) :
|
|
|
260
271
|
// Disconnect before forgetting like iOS
|
|
261
272
|
button.disconnectOrAbortPendingConnection()
|
|
262
273
|
|
|
263
|
-
//
|
|
274
|
+
// Explicitly remove listener from button before forgetting (matches old implementation)
|
|
275
|
+
val listener = buttonListeners[uuid]
|
|
276
|
+
if (listener != null) {
|
|
277
|
+
try {
|
|
278
|
+
button.removeListener(listener)
|
|
279
|
+
Log.d(TAG, "Removed listener for button: $uuid")
|
|
280
|
+
} catch (e: Exception) {
|
|
281
|
+
Log.w(TAG, "Failed to remove listener for button: $uuid", e)
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Remove listener from map
|
|
264
286
|
buttonListeners.remove(uuid)
|
|
265
287
|
|
|
266
288
|
// Forget button
|
|
@@ -269,10 +291,7 @@ class Flic2Module(reactContext: ReactApplicationContext) :
|
|
|
269
291
|
// Update foreground service state after removing button
|
|
270
292
|
updateForegroundServiceState(manager.buttons.size)
|
|
271
293
|
|
|
272
|
-
promise.resolve(
|
|
273
|
-
putBoolean("success", true)
|
|
274
|
-
putString("message", "Button forgotten")
|
|
275
|
-
})
|
|
294
|
+
promise.resolve(null)
|
|
276
295
|
} catch (e: Exception) {
|
|
277
296
|
Log.e(TAG, "Failed to forget button", e)
|
|
278
297
|
promise.reject("FORGET_ERROR", "Failed to forget button: ${e.message}", e)
|
|
@@ -291,10 +310,7 @@ class Flic2Module(reactContext: ReactApplicationContext) :
|
|
|
291
310
|
|
|
292
311
|
button.connect()
|
|
293
312
|
|
|
294
|
-
promise.resolve(
|
|
295
|
-
putBoolean("success", true)
|
|
296
|
-
putString("message", "Connection initiated")
|
|
297
|
-
})
|
|
313
|
+
promise.resolve(Flic2Converter.buttonToMap(button))
|
|
298
314
|
} catch (e: Exception) {
|
|
299
315
|
Log.e(TAG, "Failed to connect button", e)
|
|
300
316
|
promise.reject("CONNECT_ERROR", "Failed to connect: ${e.message}", e)
|
|
@@ -311,10 +327,7 @@ class Flic2Module(reactContext: ReactApplicationContext) :
|
|
|
311
327
|
|
|
312
328
|
button.disconnectOrAbortPendingConnection()
|
|
313
329
|
|
|
314
|
-
promise.resolve(
|
|
315
|
-
putBoolean("success", true)
|
|
316
|
-
putString("message", "Disconnection initiated")
|
|
317
|
-
})
|
|
330
|
+
promise.resolve(Flic2Converter.buttonToMap(button))
|
|
318
331
|
} catch (e: Exception) {
|
|
319
332
|
Log.e(TAG, "Failed to disconnect button", e)
|
|
320
333
|
promise.reject("DISCONNECT_ERROR", "Failed to disconnect: ${e.message}", e)
|
|
@@ -346,10 +359,7 @@ class Flic2Module(reactContext: ReactApplicationContext) :
|
|
|
346
359
|
// v1.1.0 uses setName() method instead of property
|
|
347
360
|
button.setName(nickname)
|
|
348
361
|
|
|
349
|
-
promise.resolve(
|
|
350
|
-
putBoolean("success", true)
|
|
351
|
-
putString("message", "Nickname set")
|
|
352
|
-
})
|
|
362
|
+
promise.resolve(Flic2Converter.buttonToMap(button))
|
|
353
363
|
} catch (e: Exception) {
|
|
354
364
|
Log.e(TAG, "Failed to set nickname", e)
|
|
355
365
|
promise.reject("SET_NICKNAME_ERROR", "Failed to set nickname: ${e.message}", e)
|
|
@@ -372,10 +382,7 @@ class Flic2Module(reactContext: ReactApplicationContext) :
|
|
|
372
382
|
button.connect()
|
|
373
383
|
}
|
|
374
384
|
|
|
375
|
-
promise.resolve(
|
|
376
|
-
putBoolean("success", true)
|
|
377
|
-
putString("message", "All buttons connection initiated")
|
|
378
|
-
})
|
|
385
|
+
promise.resolve(null)
|
|
379
386
|
} catch (e: Exception) {
|
|
380
387
|
Log.e(TAG, "Failed to connect all buttons", e)
|
|
381
388
|
promise.reject("CONNECT_ALL_ERROR", "Failed to connect all buttons: ${e.message}", e)
|
|
@@ -397,10 +404,7 @@ class Flic2Module(reactContext: ReactApplicationContext) :
|
|
|
397
404
|
button.disconnectOrAbortPendingConnection()
|
|
398
405
|
}
|
|
399
406
|
|
|
400
|
-
promise.resolve(
|
|
401
|
-
putBoolean("success", true)
|
|
402
|
-
putString("message", "All buttons disconnection initiated")
|
|
403
|
-
})
|
|
407
|
+
promise.resolve(null)
|
|
404
408
|
} catch (e: Exception) {
|
|
405
409
|
Log.e(TAG, "Failed to disconnect all buttons", e)
|
|
406
410
|
promise.reject("DISCONNECT_ALL_ERROR", "Failed to disconnect all buttons: ${e.message}", e)
|
|
@@ -419,18 +423,31 @@ class Flic2Module(reactContext: ReactApplicationContext) :
|
|
|
419
423
|
val buttons = manager.buttons.toList()
|
|
420
424
|
|
|
421
425
|
buttons.forEach { button ->
|
|
426
|
+
// Explicitly remove listener from button before forgetting (matches old implementation)
|
|
427
|
+
val listener = buttonListeners[button.uuid]
|
|
428
|
+
if (listener != null) {
|
|
429
|
+
try {
|
|
430
|
+
button.removeListener(listener)
|
|
431
|
+
Log.d(TAG, "Removed listener for button: ${button.uuid}")
|
|
432
|
+
} catch (e: Exception) {
|
|
433
|
+
Log.w(TAG, "Failed to remove listener for button: ${button.uuid}", e)
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// Remove listener from map
|
|
422
438
|
buttonListeners.remove(button.uuid)
|
|
439
|
+
|
|
440
|
+
// Disconnect before forgetting
|
|
423
441
|
button.disconnectOrAbortPendingConnection()
|
|
442
|
+
|
|
443
|
+
// Forget button
|
|
424
444
|
manager.forgetButton(button)
|
|
425
445
|
}
|
|
426
446
|
|
|
427
447
|
// Update foreground service state after removing all buttons
|
|
428
448
|
updateForegroundServiceState(manager.buttons.size)
|
|
429
449
|
|
|
430
|
-
promise.resolve(
|
|
431
|
-
putBoolean("success", true)
|
|
432
|
-
putString("message", "All buttons forgotten")
|
|
433
|
-
})
|
|
450
|
+
promise.resolve(null)
|
|
434
451
|
} catch (e: Exception) {
|
|
435
452
|
Log.e(TAG, "Failed to forget all buttons", e)
|
|
436
453
|
promise.reject("FORGET_ALL_ERROR", "Failed to forget all buttons: ${e.message}", e)
|
|
@@ -445,8 +462,7 @@ class Flic2Module(reactContext: ReactApplicationContext) :
|
|
|
445
462
|
return
|
|
446
463
|
}
|
|
447
464
|
|
|
448
|
-
|
|
449
|
-
promise.resolve(scanning)
|
|
465
|
+
promise.resolve(scanJob != null && scanJob?.isActive == true)
|
|
450
466
|
} catch (e: Exception) {
|
|
451
467
|
Log.e(TAG, "Failed to check scanning status", e)
|
|
452
468
|
promise.reject("IS_SCANNING_ERROR", "Failed to check scanning status: ${e.message}", e)
|
|
@@ -502,3 +518,4 @@ class Flic2Module(reactContext: ReactApplicationContext) :
|
|
|
502
518
|
}
|
|
503
519
|
}
|
|
504
520
|
}
|
|
521
|
+
|