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.
Files changed (55) hide show
  1. package/README.md +607 -0
  2. package/android/.gradle/7.4.2/checksums/checksums.lock +0 -0
  3. package/android/.gradle/7.4.2/fileChanges/last-build.bin +0 -0
  4. package/android/.gradle/7.4.2/fileHashes/fileHashes.lock +0 -0
  5. package/android/.gradle/7.4.2/gc.properties +0 -0
  6. package/android/.gradle/vcs-1/gc.properties +0 -0
  7. package/android/build.gradle +15 -0
  8. package/android/src/main/java/com/rnpersistenttimer/RNPersistentTimerModule.java +164 -0
  9. package/android/src/main/java/com/rnpersistenttimer/RNPersistentTimerPackage.java +27 -0
  10. package/android/src/main/java/com/rnpersistenttimer/TimerForegroundService.java +280 -0
  11. package/ios/RNPersistentTimer.h +10 -0
  12. package/ios/RNPersistentTimer.m +221 -0
  13. package/lib/commonjs/NativeTimerModule.js +46 -0
  14. package/lib/commonjs/NativeTimerModule.js.map +1 -0
  15. package/lib/commonjs/PersistentTimerManager.js +337 -0
  16. package/lib/commonjs/PersistentTimerManager.js.map +1 -0
  17. package/lib/commonjs/index.js +76 -0
  18. package/lib/commonjs/index.js.map +1 -0
  19. package/lib/commonjs/types.js +2 -0
  20. package/lib/commonjs/types.js.map +1 -0
  21. package/lib/commonjs/usePersistentTimer.js +159 -0
  22. package/lib/commonjs/usePersistentTimer.js.map +1 -0
  23. package/lib/commonjs/utils.js +112 -0
  24. package/lib/commonjs/utils.js.map +1 -0
  25. package/lib/module/NativeTimerModule.js +40 -0
  26. package/lib/module/NativeTimerModule.js.map +1 -0
  27. package/lib/module/PersistentTimerManager.js +329 -0
  28. package/lib/module/PersistentTimerManager.js.map +1 -0
  29. package/lib/module/index.js +17 -0
  30. package/lib/module/index.js.map +1 -0
  31. package/lib/module/types.js +2 -0
  32. package/lib/module/types.js.map +1 -0
  33. package/lib/module/usePersistentTimer.js +153 -0
  34. package/lib/module/usePersistentTimer.js.map +1 -0
  35. package/lib/module/utils.js +100 -0
  36. package/lib/module/utils.js.map +1 -0
  37. package/lib/typescript/NativeTimerModule.d.ts +31 -0
  38. package/lib/typescript/NativeTimerModule.d.ts.map +1 -0
  39. package/lib/typescript/PersistentTimerManager.d.ts +37 -0
  40. package/lib/typescript/PersistentTimerManager.d.ts.map +1 -0
  41. package/lib/typescript/index.d.ts +7 -0
  42. package/lib/typescript/index.d.ts.map +1 -0
  43. package/lib/typescript/types.d.ts +167 -0
  44. package/lib/typescript/types.d.ts.map +1 -0
  45. package/lib/typescript/usePersistentTimer.d.ts +16 -0
  46. package/lib/typescript/usePersistentTimer.d.ts.map +1 -0
  47. package/lib/typescript/utils.d.ts +36 -0
  48. package/lib/typescript/utils.d.ts.map +1 -0
  49. package/package.json +98 -0
  50. package/src/NativeTimerModule.ts +73 -0
  51. package/src/PersistentTimerManager.ts +410 -0
  52. package/src/index.ts +41 -0
  53. package/src/types.ts +198 -0
  54. package/src/usePersistentTimer.tsx +173 -0
  55. 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":[]}