rn-persistent-timer 1.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/README.md +607 -0
- package/android/.gradle/7.4.2/checksums/checksums.lock +0 -0
- package/android/.gradle/7.4.2/fileChanges/last-build.bin +0 -0
- package/android/.gradle/7.4.2/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/7.4.2/gc.properties +0 -0
- package/android/.gradle/vcs-1/gc.properties +0 -0
- package/android/build.gradle +15 -0
- package/android/src/main/java/com/rnpersistenttimer/RNPersistentTimerModule.java +164 -0
- package/android/src/main/java/com/rnpersistenttimer/RNPersistentTimerPackage.java +27 -0
- package/android/src/main/java/com/rnpersistenttimer/TimerForegroundService.java +280 -0
- package/ios/RNPersistentTimer.h +10 -0
- package/ios/RNPersistentTimer.m +221 -0
- package/lib/commonjs/NativeTimerModule.js +46 -0
- package/lib/commonjs/NativeTimerModule.js.map +1 -0
- package/lib/commonjs/PersistentTimerManager.js +337 -0
- package/lib/commonjs/PersistentTimerManager.js.map +1 -0
- package/lib/commonjs/index.js +76 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/types.js +2 -0
- package/lib/commonjs/types.js.map +1 -0
- package/lib/commonjs/usePersistentTimer.js +159 -0
- package/lib/commonjs/usePersistentTimer.js.map +1 -0
- package/lib/commonjs/utils.js +112 -0
- package/lib/commonjs/utils.js.map +1 -0
- package/lib/module/NativeTimerModule.js +40 -0
- package/lib/module/NativeTimerModule.js.map +1 -0
- package/lib/module/PersistentTimerManager.js +329 -0
- package/lib/module/PersistentTimerManager.js.map +1 -0
- package/lib/module/index.js +17 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/types.js +2 -0
- package/lib/module/types.js.map +1 -0
- package/lib/module/usePersistentTimer.js +153 -0
- package/lib/module/usePersistentTimer.js.map +1 -0
- package/lib/module/utils.js +100 -0
- package/lib/module/utils.js.map +1 -0
- package/lib/typescript/NativeTimerModule.d.ts +31 -0
- package/lib/typescript/NativeTimerModule.d.ts.map +1 -0
- package/lib/typescript/PersistentTimerManager.d.ts +37 -0
- package/lib/typescript/PersistentTimerManager.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +7 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/types.d.ts +167 -0
- package/lib/typescript/types.d.ts.map +1 -0
- package/lib/typescript/usePersistentTimer.d.ts +16 -0
- package/lib/typescript/usePersistentTimer.d.ts.map +1 -0
- package/lib/typescript/utils.d.ts +36 -0
- package/lib/typescript/utils.d.ts.map +1 -0
- package/package.json +98 -0
- package/src/NativeTimerModule.ts +73 -0
- package/src/PersistentTimerManager.ts +410 -0
- package/src/index.ts +41 -0
- package/src/types.ts +198 -0
- package/src/usePersistentTimer.tsx +173 -0
- package/src/utils.ts +91 -0
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* RNPersistentTimer.m
|
|
3
|
+
* iOS Native Module — bridges timer management to React Native
|
|
4
|
+
* Uses BGTaskScheduler for killed-state, UIBackgroundTaskIdentifier for background
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
#import <React/RCTBridgeModule.h>
|
|
8
|
+
#import <React/RCTEventEmitter.h>
|
|
9
|
+
#import <BackgroundTasks/BackgroundTasks.h>
|
|
10
|
+
|
|
11
|
+
@interface RNPersistentTimer : RCTEventEmitter <RCTBridgeModule>
|
|
12
|
+
|
|
13
|
+
@property (nonatomic, strong) NSMutableDictionary<NSString *, NSNumber *> *timerStartTimes;
|
|
14
|
+
@property (nonatomic, strong) NSMutableDictionary<NSString *, NSString *> *timerModes;
|
|
15
|
+
@property (nonatomic, strong) NSMutableDictionary<NSString *, NSNumber *> *timerDurations;
|
|
16
|
+
@property (nonatomic, strong) NSTimer *tickTimer;
|
|
17
|
+
@property (nonatomic, assign) UIBackgroundTaskIdentifier bgTask;
|
|
18
|
+
|
|
19
|
+
@end
|
|
20
|
+
|
|
21
|
+
@implementation RNPersistentTimer
|
|
22
|
+
|
|
23
|
+
RCT_EXPORT_MODULE();
|
|
24
|
+
|
|
25
|
+
- (instancetype)init {
|
|
26
|
+
if (self = [super init]) {
|
|
27
|
+
_timerStartTimes = [NSMutableDictionary dictionary];
|
|
28
|
+
_timerModes = [NSMutableDictionary dictionary];
|
|
29
|
+
_timerDurations = [NSMutableDictionary dictionary];
|
|
30
|
+
_bgTask = UIBackgroundTaskInvalid;
|
|
31
|
+
|
|
32
|
+
// Register for app lifecycle notifications
|
|
33
|
+
[[NSNotificationCenter defaultCenter]
|
|
34
|
+
addObserver:self
|
|
35
|
+
selector:@selector(appWillBackground)
|
|
36
|
+
name:UIApplicationDidEnterBackgroundNotification
|
|
37
|
+
object:nil];
|
|
38
|
+
[[NSNotificationCenter defaultCenter]
|
|
39
|
+
addObserver:self
|
|
40
|
+
selector:@selector(appWillForeground)
|
|
41
|
+
name:UIApplicationWillEnterForegroundNotification
|
|
42
|
+
object:nil];
|
|
43
|
+
}
|
|
44
|
+
return self;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// ─── Events ──────────────────────────────────────────────────────────────────
|
|
48
|
+
|
|
49
|
+
- (NSArray<NSString *> *)supportedEvents {
|
|
50
|
+
return @[
|
|
51
|
+
@"RNPersistentTimer_tick",
|
|
52
|
+
@"RNPersistentTimer_complete",
|
|
53
|
+
@"RNPersistentTimer_error",
|
|
54
|
+
@"RNPersistentTimer_background",
|
|
55
|
+
@"RNPersistentTimer_foreground"
|
|
56
|
+
];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// ─── JS Methods ──────────────────────────────────────────────────────────────
|
|
60
|
+
|
|
61
|
+
RCT_EXPORT_METHOD(startTimer:(NSDictionary *)options
|
|
62
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
63
|
+
reject:(RCTPromiseRejectBlock)reject) {
|
|
64
|
+
NSString *timerId = options[@"timerId"];
|
|
65
|
+
NSString *mode = options[@"mode"] ?: @"stopwatch";
|
|
66
|
+
NSInteger elapsed = [options[@"elapsed"] integerValue];
|
|
67
|
+
double startedAt = [options[@"startedAt"] doubleValue];
|
|
68
|
+
NSInteger duration = [options[@"duration"] integerValue];
|
|
69
|
+
|
|
70
|
+
// Adjust start time for already-elapsed seconds
|
|
71
|
+
double adjustedStart = startedAt - (elapsed * 1000.0);
|
|
72
|
+
self.timerStartTimes[timerId] = @(adjustedStart);
|
|
73
|
+
self.timerModes[timerId] = mode;
|
|
74
|
+
self.timerDurations[timerId] = @(duration);
|
|
75
|
+
|
|
76
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
77
|
+
if (!self.tickTimer || !self.tickTimer.isValid) {
|
|
78
|
+
self.tickTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
|
|
79
|
+
target:self
|
|
80
|
+
selector:@selector(tick)
|
|
81
|
+
userInfo:nil
|
|
82
|
+
repeats:YES];
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
resolve(nil);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
RCT_EXPORT_METHOD(stopTimer:(NSString *)timerId
|
|
90
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
91
|
+
reject:(RCTPromiseRejectBlock)reject) {
|
|
92
|
+
[self.timerStartTimes removeObjectForKey:timerId];
|
|
93
|
+
[self.timerModes removeObjectForKey:timerId];
|
|
94
|
+
[self.timerDurations removeObjectForKey:timerId];
|
|
95
|
+
|
|
96
|
+
if (self.timerStartTimes.count == 0) {
|
|
97
|
+
[self.tickTimer invalidate];
|
|
98
|
+
self.tickTimer = nil;
|
|
99
|
+
[self endBackgroundTask];
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
resolve(nil);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
RCT_EXPORT_METHOD(getElapsed:(NSString *)timerId
|
|
106
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
107
|
+
reject:(RCTPromiseRejectBlock)reject) {
|
|
108
|
+
NSNumber *startedAt = self.timerStartTimes[timerId];
|
|
109
|
+
if (!startedAt) {
|
|
110
|
+
resolve(@(0));
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
double now = [[NSDate date] timeIntervalSince1970] * 1000.0;
|
|
114
|
+
NSInteger secs = (NSInteger)((now - startedAt.doubleValue) / 1000.0);
|
|
115
|
+
resolve(@(secs));
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
RCT_EXPORT_METHOD(getActiveTimers:(RCTPromiseResolveBlock)resolve
|
|
119
|
+
reject:(RCTPromiseRejectBlock)reject) {
|
|
120
|
+
resolve(self.timerStartTimes.allKeys);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
RCT_EXPORT_METHOD(cancelAll:(RCTPromiseResolveBlock)resolve
|
|
124
|
+
reject:(RCTPromiseRejectBlock)reject) {
|
|
125
|
+
[self.timerStartTimes removeAllObjects];
|
|
126
|
+
[self.timerModes removeAllObjects];
|
|
127
|
+
[self.timerDurations removeAllObjects];
|
|
128
|
+
[self.tickTimer invalidate];
|
|
129
|
+
self.tickTimer = nil;
|
|
130
|
+
[self endBackgroundTask];
|
|
131
|
+
resolve(nil);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
RCT_EXPORT_METHOD(isKilledStateSupported:(RCTPromiseResolveBlock)resolve
|
|
135
|
+
reject:(RCTPromiseRejectBlock)reject) {
|
|
136
|
+
// iOS: killed-state relies on BGTaskScheduler (iOS 13+)
|
|
137
|
+
if (@available(iOS 13.0, *)) {
|
|
138
|
+
resolve(@(YES));
|
|
139
|
+
} else {
|
|
140
|
+
resolve(@(NO));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// ─── Tick ────────────────────────────────────────────────────────────────────
|
|
145
|
+
|
|
146
|
+
- (void)tick {
|
|
147
|
+
double now = [[NSDate date] timeIntervalSince1970] * 1000.0;
|
|
148
|
+
|
|
149
|
+
for (NSString *timerId in self.timerStartTimes) {
|
|
150
|
+
double startedAt = [self.timerStartTimes[timerId] doubleValue];
|
|
151
|
+
NSString *mode = self.timerModes[timerId] ?: @"stopwatch";
|
|
152
|
+
NSInteger duration = [self.timerDurations[timerId] integerValue];
|
|
153
|
+
|
|
154
|
+
NSInteger elapsedSecs = (NSInteger)((now - startedAt) / 1000.0);
|
|
155
|
+
|
|
156
|
+
NSInteger remaining = -1;
|
|
157
|
+
if ([mode isEqualToString:@"countdown"]) {
|
|
158
|
+
remaining = MAX(0, duration - elapsedSecs);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
[self sendEventWithName:@"RNPersistentTimer_tick"
|
|
162
|
+
body:@{
|
|
163
|
+
@"timerId": timerId,
|
|
164
|
+
@"elapsed": @(elapsedSecs),
|
|
165
|
+
@"remaining": @(remaining),
|
|
166
|
+
}];
|
|
167
|
+
|
|
168
|
+
if ([mode isEqualToString:@"countdown"] && remaining == 0) {
|
|
169
|
+
[self sendEventWithName:@"RNPersistentTimer_complete"
|
|
170
|
+
body:@{ @"timerId": timerId }];
|
|
171
|
+
[self stopTimer:timerId
|
|
172
|
+
resolve:^(id result){}
|
|
173
|
+
reject:^(NSString *c, NSString *m, NSError *e){}];
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// ─── App Lifecycle ────────────────────────────────────────────────────────────
|
|
179
|
+
|
|
180
|
+
- (void)appWillBackground {
|
|
181
|
+
if (self.timerStartTimes.count == 0) return;
|
|
182
|
+
|
|
183
|
+
[self sendEventWithName:@"RNPersistentTimer_background" body:@{}];
|
|
184
|
+
|
|
185
|
+
// Request background execution time from iOS
|
|
186
|
+
UIApplication *app = [UIApplication sharedApplication];
|
|
187
|
+
__weak typeof(self) weakSelf = self;
|
|
188
|
+
self.bgTask = [app beginBackgroundTaskWithName:@"RNPersistentTimer"
|
|
189
|
+
expirationHandler:^{
|
|
190
|
+
// iOS will kill background task — schedule BGTask for continued execution
|
|
191
|
+
[weakSelf scheduleBGTask];
|
|
192
|
+
[weakSelf endBackgroundTask];
|
|
193
|
+
}];
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
- (void)appWillForeground {
|
|
197
|
+
[self sendEventWithName:@"RNPersistentTimer_foreground" body:@{}];
|
|
198
|
+
[self endBackgroundTask];
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
- (void)endBackgroundTask {
|
|
202
|
+
if (self.bgTask != UIBackgroundTaskInvalid) {
|
|
203
|
+
[[UIApplication sharedApplication] endBackgroundTask:self.bgTask];
|
|
204
|
+
self.bgTask = UIBackgroundTaskInvalid;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// ─── BGTaskScheduler (iOS 13+) ───────────────────────────────────────────────
|
|
209
|
+
// Register "com.yourapp.timer" in Info.plist BGTaskSchedulerPermittedIdentifiers
|
|
210
|
+
|
|
211
|
+
- (void)scheduleBGTask {
|
|
212
|
+
if (@available(iOS 13.0, *)) {
|
|
213
|
+
BGAppRefreshTaskRequest *request =
|
|
214
|
+
[[BGAppRefreshTaskRequest alloc] initWithIdentifier:@"com.yourapp.timer"];
|
|
215
|
+
request.earliestBeginDate = [NSDate dateWithTimeIntervalSinceNow:1];
|
|
216
|
+
NSError *error;
|
|
217
|
+
[[BGTaskScheduler sharedScheduler] submitTaskRequest:request error:&error];
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
@end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.isIOS = exports.isAndroid = exports.NativeTimerModule = exports.NativeTimerEmitter = exports.NATIVE_EVENTS = void 0;
|
|
7
|
+
var _reactNative = require("react-native");
|
|
8
|
+
// rn-persistent-timer — Native Bridge
|
|
9
|
+
// Bridges TypeScript ↔ Android (ForegroundService) & iOS (BGTaskScheduler)
|
|
10
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
11
|
+
|
|
12
|
+
const {
|
|
13
|
+
RNPersistentTimer
|
|
14
|
+
} = _reactNative.NativeModules;
|
|
15
|
+
if (__DEV__ && !RNPersistentTimer) {
|
|
16
|
+
console.warn('[rn-persistent-timer] Native module not found.\n' + 'iOS → run `npx pod-install` then rebuild.\n' + 'Android → rebuild the Android project.\n' + 'Foreground (JS-only) timers still work; background/kill-state features are disabled.');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// ─── Start options passed to the native layer ────────────────────────────────
|
|
20
|
+
|
|
21
|
+
// ─── Module interface ─────────────────────────────────────────────────────────
|
|
22
|
+
|
|
23
|
+
const NativeTimerModule = exports.NativeTimerModule = RNPersistentTimer ? {
|
|
24
|
+
startTimer: options => RNPersistentTimer.startTimer(options),
|
|
25
|
+
stopTimer: timerId => RNPersistentTimer.stopTimer(timerId),
|
|
26
|
+
getElapsed: timerId => RNPersistentTimer.getElapsed(timerId),
|
|
27
|
+
cancelAll: () => RNPersistentTimer.cancelAll(),
|
|
28
|
+
getActiveTimers: () => RNPersistentTimer.getActiveTimers(),
|
|
29
|
+
isKilledStateSupported: () => RNPersistentTimer.isKilledStateSupported()
|
|
30
|
+
} : null;
|
|
31
|
+
|
|
32
|
+
// ─── Native event emitter (optional background tick push) ────────────────────
|
|
33
|
+
|
|
34
|
+
const NativeTimerEmitter = exports.NativeTimerEmitter = RNPersistentTimer ? new _reactNative.NativeEventEmitter(RNPersistentTimer) : null;
|
|
35
|
+
const NATIVE_EVENTS = exports.NATIVE_EVENTS = {
|
|
36
|
+
TICK: 'RNPersistentTimer_tick',
|
|
37
|
+
COMPLETE: 'RNPersistentTimer_complete',
|
|
38
|
+
ERROR: 'RNPersistentTimer_error',
|
|
39
|
+
BACKGROUND: 'RNPersistentTimer_background',
|
|
40
|
+
FOREGROUND: 'RNPersistentTimer_foreground'
|
|
41
|
+
};
|
|
42
|
+
// ─── Platform helpers ─────────────────────────────────────────────────────────
|
|
43
|
+
|
|
44
|
+
const isAndroid = exports.isAndroid = _reactNative.Platform.OS === 'android';
|
|
45
|
+
const isIOS = exports.isIOS = _reactNative.Platform.OS === 'ios';
|
|
46
|
+
//# sourceMappingURL=NativeTimerModule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_reactNative","require","RNPersistentTimer","NativeModules","__DEV__","console","warn","NativeTimerModule","exports","startTimer","options","stopTimer","timerId","getElapsed","cancelAll","getActiveTimers","isKilledStateSupported","NativeTimerEmitter","NativeEventEmitter","NATIVE_EVENTS","TICK","COMPLETE","ERROR","BACKGROUND","FOREGROUND","isAndroid","Platform","OS","isIOS"],"sourceRoot":"../../src","sources":["NativeTimerModule.ts"],"mappings":";;;;;;AAIA,IAAAA,YAAA,GAAAC,OAAA;AAJA;AACA;AACA;;AAIA,MAAM;EAAEC;AAAkB,CAAC,GAAGC,0BAAa;AAE3C,IAAIC,OAAO,IAAI,CAACF,iBAAiB,EAAE;EACjCG,OAAO,CAACC,IAAI,CACV,kDAAkD,GAChD,8CAA8C,GAC9C,0CAA0C,GAC1C,sFACJ,CAAC;AACH;;AAEA;;AAYA;;AAWO,MAAMC,iBAA4C,GAAAC,OAAA,CAAAD,iBAAA,GAAGL,iBAAiB,GACzE;EACEO,UAAU,EAAGC,OAA2B,IACtCR,iBAAiB,CAACO,UAAU,CAACC,OAAO,CAAC;EACvCC,SAAS,EAAGC,OAAe,IAAKV,iBAAiB,CAACS,SAAS,CAACC,OAAO,CAAC;EACpEC,UAAU,EAAGD,OAAe,IAAKV,iBAAiB,CAACW,UAAU,CAACD,OAAO,CAAC;EACtEE,SAAS,EAAEA,CAAA,KAAMZ,iBAAiB,CAACY,SAAS,CAAC,CAAC;EAC9CC,eAAe,EAAEA,CAAA,KAAMb,iBAAiB,CAACa,eAAe,CAAC,CAAC;EAC1DC,sBAAsB,EAAEA,CAAA,KAAMd,iBAAiB,CAACc,sBAAsB,CAAC;AACzE,CAAC,GACD,IAAI;;AAER;;AAEO,MAAMC,kBAA6C,GAAAT,OAAA,CAAAS,kBAAA,GAAGf,iBAAiB,GAC1E,IAAIgB,+BAAkB,CAAChB,iBAAiB,CAAC,GACzC,IAAI;AAED,MAAMiB,aAAa,GAAAX,OAAA,CAAAW,aAAA,GAAG;EAC3BC,IAAI,EAAE,wBAAwB;EAC9BC,QAAQ,EAAE,4BAA4B;EACtCC,KAAK,EAAE,yBAAyB;EAChCC,UAAU,EAAE,8BAA8B;EAC1CC,UAAU,EAAE;AACd,CAAU;AAKV;;AAEO,MAAMC,SAAS,GAAAjB,OAAA,CAAAiB,SAAA,GAAGC,qBAAQ,CAACC,EAAE,KAAK,SAAS;AAC3C,MAAMC,KAAK,GAAApB,OAAA,CAAAoB,KAAA,GAAGF,qBAAQ,CAACC,EAAE,KAAK,KAAK","ignoreList":[]}
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.PersistentTimerManager = void 0;
|
|
7
|
+
var _reactNative = require("react-native");
|
|
8
|
+
var _asyncStorage = _interopRequireDefault(require("@react-native-async-storage/async-storage"));
|
|
9
|
+
var _NativeTimerModule = require("./NativeTimerModule");
|
|
10
|
+
var _utils = require("./utils");
|
|
11
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
|
+
// rn-persistent-timer — PersistentTimerManager
|
|
13
|
+
// Handles foreground, background, and killed-state timer logic
|
|
14
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
15
|
+
|
|
16
|
+
const STORAGE_KEY_PREFIX = '@rn_persistent_timer_';
|
|
17
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
class PersistentTimerManager {
|
|
20
|
+
_state = 'idle';
|
|
21
|
+
_elapsed = 0;
|
|
22
|
+
_startedAt = null;
|
|
23
|
+
_pausedAt = null;
|
|
24
|
+
_tickInterval = null;
|
|
25
|
+
_handlers = {};
|
|
26
|
+
_appState = 'foreground';
|
|
27
|
+
_appStateSubscription = null;
|
|
28
|
+
constructor(config) {
|
|
29
|
+
this._config = {
|
|
30
|
+
timerId: config.timerId,
|
|
31
|
+
mode: config.mode ?? 'stopwatch',
|
|
32
|
+
duration: config.duration ?? 0,
|
|
33
|
+
runInBackground: config.runInBackground !== false,
|
|
34
|
+
// default true
|
|
35
|
+
runInKilledState: config.runInKilledState === true,
|
|
36
|
+
// default false
|
|
37
|
+
pauseOnBackground: config.pauseOnBackground === true,
|
|
38
|
+
resetOnForeground: config.resetOnForeground === true,
|
|
39
|
+
interval: config.interval ?? 1000,
|
|
40
|
+
showNotification: config.showNotification !== false,
|
|
41
|
+
notification: config.notification ?? {}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ─── Public API ─────────────────────────────────────────────────────────────
|
|
46
|
+
|
|
47
|
+
start() {
|
|
48
|
+
if (this._state === 'running') {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (this._state === 'completed') {
|
|
52
|
+
console.warn('[rn-persistent-timer] Timer already completed. Call reset() first.');
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
this._startedAt = Date.now() - this._elapsed * 1000;
|
|
56
|
+
this._state = 'running';
|
|
57
|
+
this._startJSTick();
|
|
58
|
+
this._listenAppState();
|
|
59
|
+
if (this._config.runInBackground) {
|
|
60
|
+
this._startNativeBackground();
|
|
61
|
+
}
|
|
62
|
+
if (this._config.runInKilledState) {
|
|
63
|
+
void this._persistState();
|
|
64
|
+
}
|
|
65
|
+
this._emit('onStart', this.getSnapshot());
|
|
66
|
+
}
|
|
67
|
+
pause() {
|
|
68
|
+
if (this._state !== 'running') {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
this._pausedAt = Date.now();
|
|
72
|
+
this._elapsed = Math.floor((Date.now() - (this._startedAt ?? Date.now())) / 1000);
|
|
73
|
+
this._state = 'paused';
|
|
74
|
+
this._stopJSTick();
|
|
75
|
+
this._stopNativeBackground();
|
|
76
|
+
if (this._config.runInKilledState) {
|
|
77
|
+
void this._persistState();
|
|
78
|
+
}
|
|
79
|
+
this._emit('onPause', this.getSnapshot());
|
|
80
|
+
}
|
|
81
|
+
resume() {
|
|
82
|
+
if (this._state !== 'paused') {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
this._startedAt = Date.now() - this._elapsed * 1000;
|
|
86
|
+
this._pausedAt = null;
|
|
87
|
+
this._state = 'running';
|
|
88
|
+
this._startJSTick();
|
|
89
|
+
if (this._config.runInBackground) {
|
|
90
|
+
this._startNativeBackground();
|
|
91
|
+
}
|
|
92
|
+
if (this._config.runInKilledState) {
|
|
93
|
+
void this._persistState();
|
|
94
|
+
}
|
|
95
|
+
this._emit('onResume', this.getSnapshot());
|
|
96
|
+
}
|
|
97
|
+
stop() {
|
|
98
|
+
if (this._state === 'idle') {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
this._stopJSTick();
|
|
102
|
+
this._stopNativeBackground();
|
|
103
|
+
this._state = 'idle';
|
|
104
|
+
void this._clearPersistedState();
|
|
105
|
+
this._emit('stop', this.getSnapshot());
|
|
106
|
+
}
|
|
107
|
+
reset() {
|
|
108
|
+
this._stopJSTick();
|
|
109
|
+
this._stopNativeBackground();
|
|
110
|
+
this._elapsed = 0;
|
|
111
|
+
this._startedAt = null;
|
|
112
|
+
this._pausedAt = null;
|
|
113
|
+
this._state = 'idle';
|
|
114
|
+
void this._clearPersistedState();
|
|
115
|
+
this._emit('onReset', this.getSnapshot());
|
|
116
|
+
}
|
|
117
|
+
getSnapshot() {
|
|
118
|
+
const elapsed = this._getElapsed();
|
|
119
|
+
const remaining = this._config.mode === 'countdown' ? Math.max(0, this._config.duration - elapsed) : null;
|
|
120
|
+
const progress = this._config.mode === 'countdown' && this._config.duration > 0 ? 1 - (remaining ?? 0) / this._config.duration : null;
|
|
121
|
+
return {
|
|
122
|
+
timerId: this._config.timerId,
|
|
123
|
+
elapsed,
|
|
124
|
+
remaining,
|
|
125
|
+
state: this._state,
|
|
126
|
+
appState: this._appState,
|
|
127
|
+
startedAt: this._startedAt,
|
|
128
|
+
pausedAt: this._pausedAt,
|
|
129
|
+
formattedElapsed: (0, _utils.formatTime)(elapsed),
|
|
130
|
+
formattedRemaining: remaining !== null ? (0, _utils.formatTime)(remaining) : null,
|
|
131
|
+
progress
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
destroy() {
|
|
135
|
+
this.stop();
|
|
136
|
+
if (this._appStateSubscription) {
|
|
137
|
+
this._appStateSubscription.remove();
|
|
138
|
+
this._appStateSubscription = null;
|
|
139
|
+
}
|
|
140
|
+
this._handlers = {};
|
|
141
|
+
}
|
|
142
|
+
on(event, handler) {
|
|
143
|
+
if (!this._handlers[event]) {
|
|
144
|
+
this._handlers[event] = [];
|
|
145
|
+
}
|
|
146
|
+
this._handlers[event].push(handler);
|
|
147
|
+
}
|
|
148
|
+
off(event, handler) {
|
|
149
|
+
if (!this._handlers[event]) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
this._handlers[event] = this._handlers[event].filter(h => h !== handler);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// ─── Internal Tick ───────────────────────────────────────────────────────────
|
|
156
|
+
|
|
157
|
+
_startJSTick() {
|
|
158
|
+
this._stopJSTick();
|
|
159
|
+
this._tickInterval = setInterval(() => {
|
|
160
|
+
this._onTick();
|
|
161
|
+
}, this._config.interval);
|
|
162
|
+
}
|
|
163
|
+
_stopJSTick() {
|
|
164
|
+
if (this._tickInterval !== null) {
|
|
165
|
+
clearInterval(this._tickInterval);
|
|
166
|
+
this._tickInterval = null;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
_onTick() {
|
|
170
|
+
const snap = this.getSnapshot();
|
|
171
|
+
if (this._config.mode === 'countdown' && snap.remaining === 0) {
|
|
172
|
+
this._state = 'completed';
|
|
173
|
+
this._stopJSTick();
|
|
174
|
+
this._stopNativeBackground();
|
|
175
|
+
void this._clearPersistedState();
|
|
176
|
+
this._emit('onComplete', snap);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
this._emit('onTick', snap);
|
|
180
|
+
}
|
|
181
|
+
_getElapsed() {
|
|
182
|
+
if (this._state === 'running' && this._startedAt !== null) {
|
|
183
|
+
return Math.floor((Date.now() - this._startedAt) / 1000);
|
|
184
|
+
}
|
|
185
|
+
return this._elapsed;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// ─── App State ───────────────────────────────────────────────────────────────
|
|
189
|
+
|
|
190
|
+
_listenAppState() {
|
|
191
|
+
if (this._appStateSubscription) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
this._appStateSubscription = _reactNative.AppState.addEventListener('change', nextAppState => {
|
|
195
|
+
const prev = this._appState;
|
|
196
|
+
if (nextAppState === 'active') {
|
|
197
|
+
this._appState = 'foreground';
|
|
198
|
+
if (prev === 'background' && this._config.runInBackground) {
|
|
199
|
+
this._syncFromNative();
|
|
200
|
+
}
|
|
201
|
+
if (this._config.resetOnForeground) {
|
|
202
|
+
this.reset();
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
if (this._state === 'running') {
|
|
206
|
+
this._startJSTick();
|
|
207
|
+
}
|
|
208
|
+
this._emit('onForeground', this.getSnapshot());
|
|
209
|
+
} else if (nextAppState === 'background' || nextAppState === 'inactive') {
|
|
210
|
+
this._appState = 'background';
|
|
211
|
+
if (this._config.pauseOnBackground) {
|
|
212
|
+
this.pause();
|
|
213
|
+
} else {
|
|
214
|
+
this._stopJSTick();
|
|
215
|
+
}
|
|
216
|
+
this._emit('onBackground', this.getSnapshot());
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// ─── Native Background ───────────────────────────────────────────────────────
|
|
222
|
+
|
|
223
|
+
_startNativeBackground() {
|
|
224
|
+
if (!_NativeTimerModule.NativeTimerModule) {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
try {
|
|
228
|
+
_NativeTimerModule.NativeTimerModule.startTimer({
|
|
229
|
+
timerId: this._config.timerId,
|
|
230
|
+
mode: this._config.mode,
|
|
231
|
+
duration: this._config.duration,
|
|
232
|
+
elapsed: this._getElapsed(),
|
|
233
|
+
startedAt: this._startedAt ?? Date.now(),
|
|
234
|
+
showNotification: this._config.showNotification,
|
|
235
|
+
notification: this._config.notification
|
|
236
|
+
});
|
|
237
|
+
} catch (e) {
|
|
238
|
+
this._emit('error', e);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
_stopNativeBackground() {
|
|
242
|
+
if (!_NativeTimerModule.NativeTimerModule) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
try {
|
|
246
|
+
_NativeTimerModule.NativeTimerModule.stopTimer(this._config.timerId);
|
|
247
|
+
} catch (e) {
|
|
248
|
+
this._emit('error', e);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
_syncFromNative() {
|
|
252
|
+
if (!_NativeTimerModule.NativeTimerModule) {
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
_NativeTimerModule.NativeTimerModule.getElapsed(this._config.timerId).then(nativeElapsed => {
|
|
256
|
+
if (nativeElapsed != null) {
|
|
257
|
+
this._elapsed = nativeElapsed;
|
|
258
|
+
this._startedAt = Date.now() - nativeElapsed * 1000;
|
|
259
|
+
}
|
|
260
|
+
}).catch(() => {
|
|
261
|
+
// Fallback: wall-clock diff handles it via _startedAt
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// ─── Killed-State Persistence ────────────────────────────────────────────────
|
|
266
|
+
|
|
267
|
+
async _persistState() {
|
|
268
|
+
try {
|
|
269
|
+
const record = {
|
|
270
|
+
timerId: this._config.timerId,
|
|
271
|
+
config: this._config,
|
|
272
|
+
state: this._state,
|
|
273
|
+
elapsed: this._getElapsed(),
|
|
274
|
+
startedAt: this._startedAt,
|
|
275
|
+
pausedAt: this._pausedAt,
|
|
276
|
+
savedAt: Date.now()
|
|
277
|
+
};
|
|
278
|
+
await _asyncStorage.default.setItem(`${STORAGE_KEY_PREFIX}${this._config.timerId}`, JSON.stringify(record));
|
|
279
|
+
} catch (e) {
|
|
280
|
+
console.warn('[rn-persistent-timer] Failed to persist state:', e);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
async _clearPersistedState() {
|
|
284
|
+
try {
|
|
285
|
+
await _asyncStorage.default.removeItem(`${STORAGE_KEY_PREFIX}${this._config.timerId}`);
|
|
286
|
+
} catch {
|
|
287
|
+
// Swallow
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// ─── Static Restore ──────────────────────────────────────────────────────────
|
|
292
|
+
|
|
293
|
+
static async restore(timerId) {
|
|
294
|
+
try {
|
|
295
|
+
const raw = await _asyncStorage.default.getItem(`${STORAGE_KEY_PREFIX}${timerId}`);
|
|
296
|
+
if (!raw) {
|
|
297
|
+
return null;
|
|
298
|
+
}
|
|
299
|
+
const saved = JSON.parse(raw);
|
|
300
|
+
const now = Date.now();
|
|
301
|
+
const secondsSinceSave = Math.floor((now - saved.savedAt) / 1000);
|
|
302
|
+
let elapsed = saved.elapsed;
|
|
303
|
+
if (saved.state === 'running') {
|
|
304
|
+
elapsed = saved.elapsed + secondsSinceSave;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Cap countdown timers at their duration
|
|
308
|
+
if (saved.config.mode === 'countdown' && elapsed >= saved.config.duration) {
|
|
309
|
+
elapsed = saved.config.duration;
|
|
310
|
+
saved.state = 'completed';
|
|
311
|
+
}
|
|
312
|
+
return {
|
|
313
|
+
config: saved.config,
|
|
314
|
+
state: saved.state,
|
|
315
|
+
elapsed,
|
|
316
|
+
secondsLost: secondsSinceSave
|
|
317
|
+
};
|
|
318
|
+
} catch {
|
|
319
|
+
return null;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// ─── Event Emitter ───────────────────────────────────────────────────────────
|
|
324
|
+
|
|
325
|
+
_emit(event, data) {
|
|
326
|
+
const handlers = this._handlers[event] ?? [];
|
|
327
|
+
for (const h of handlers) {
|
|
328
|
+
try {
|
|
329
|
+
h(data);
|
|
330
|
+
} catch (e) {
|
|
331
|
+
console.error(`[rn-persistent-timer] Handler error for "${event}":`, e);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
exports.PersistentTimerManager = PersistentTimerManager;
|
|
337
|
+
//# sourceMappingURL=PersistentTimerManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_reactNative","require","_asyncStorage","_interopRequireDefault","_NativeTimerModule","_utils","e","__esModule","default","STORAGE_KEY_PREFIX","PersistentTimerManager","_state","_elapsed","_startedAt","_pausedAt","_tickInterval","_handlers","_appState","_appStateSubscription","constructor","config","_config","timerId","mode","duration","runInBackground","runInKilledState","pauseOnBackground","resetOnForeground","interval","showNotification","notification","start","console","warn","Date","now","_startJSTick","_listenAppState","_startNativeBackground","_persistState","_emit","getSnapshot","pause","Math","floor","_stopJSTick","_stopNativeBackground","resume","stop","_clearPersistedState","reset","elapsed","_getElapsed","remaining","max","progress","state","appState","startedAt","pausedAt","formattedElapsed","formatTime","formattedRemaining","destroy","remove","on","event","handler","push","off","filter","h","setInterval","_onTick","clearInterval","snap","RNAppState","addEventListener","nextAppState","prev","_syncFromNative","NativeTimerModule","startTimer","stopTimer","getElapsed","then","nativeElapsed","catch","record","savedAt","AsyncStorage","setItem","JSON","stringify","removeItem","restore","raw","getItem","saved","parse","secondsSinceSave","secondsLost","data","handlers","error","exports"],"sourceRoot":"../../src","sources":["PersistentTimerManager.ts"],"mappings":"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","ignoreList":[]}
|