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,329 @@
1
+ // rn-persistent-timer — PersistentTimerManager
2
+ // Handles foreground, background, and killed-state timer logic
3
+ // ─────────────────────────────────────────────────────────────────────────────
4
+
5
+ import { AppState as RNAppState } from 'react-native';
6
+ import AsyncStorage from '@react-native-async-storage/async-storage';
7
+ import { NativeTimerModule } from './NativeTimerModule';
8
+ import { formatTime } from './utils';
9
+ const STORAGE_KEY_PREFIX = '@rn_persistent_timer_';
10
+ // ─────────────────────────────────────────────────────────────────────────────
11
+
12
+ export class PersistentTimerManager {
13
+ _state = 'idle';
14
+ _elapsed = 0;
15
+ _startedAt = null;
16
+ _pausedAt = null;
17
+ _tickInterval = null;
18
+ _handlers = {};
19
+ _appState = 'foreground';
20
+ _appStateSubscription = null;
21
+ constructor(config) {
22
+ this._config = {
23
+ timerId: config.timerId,
24
+ mode: config.mode ?? 'stopwatch',
25
+ duration: config.duration ?? 0,
26
+ runInBackground: config.runInBackground !== false,
27
+ // default true
28
+ runInKilledState: config.runInKilledState === true,
29
+ // default false
30
+ pauseOnBackground: config.pauseOnBackground === true,
31
+ resetOnForeground: config.resetOnForeground === true,
32
+ interval: config.interval ?? 1000,
33
+ showNotification: config.showNotification !== false,
34
+ notification: config.notification ?? {}
35
+ };
36
+ }
37
+
38
+ // ─── Public API ─────────────────────────────────────────────────────────────
39
+
40
+ start() {
41
+ if (this._state === 'running') {
42
+ return;
43
+ }
44
+ if (this._state === 'completed') {
45
+ console.warn('[rn-persistent-timer] Timer already completed. Call reset() first.');
46
+ return;
47
+ }
48
+ this._startedAt = Date.now() - this._elapsed * 1000;
49
+ this._state = 'running';
50
+ this._startJSTick();
51
+ this._listenAppState();
52
+ if (this._config.runInBackground) {
53
+ this._startNativeBackground();
54
+ }
55
+ if (this._config.runInKilledState) {
56
+ void this._persistState();
57
+ }
58
+ this._emit('onStart', this.getSnapshot());
59
+ }
60
+ pause() {
61
+ if (this._state !== 'running') {
62
+ return;
63
+ }
64
+ this._pausedAt = Date.now();
65
+ this._elapsed = Math.floor((Date.now() - (this._startedAt ?? Date.now())) / 1000);
66
+ this._state = 'paused';
67
+ this._stopJSTick();
68
+ this._stopNativeBackground();
69
+ if (this._config.runInKilledState) {
70
+ void this._persistState();
71
+ }
72
+ this._emit('onPause', this.getSnapshot());
73
+ }
74
+ resume() {
75
+ if (this._state !== 'paused') {
76
+ return;
77
+ }
78
+ this._startedAt = Date.now() - this._elapsed * 1000;
79
+ this._pausedAt = null;
80
+ this._state = 'running';
81
+ this._startJSTick();
82
+ if (this._config.runInBackground) {
83
+ this._startNativeBackground();
84
+ }
85
+ if (this._config.runInKilledState) {
86
+ void this._persistState();
87
+ }
88
+ this._emit('onResume', this.getSnapshot());
89
+ }
90
+ stop() {
91
+ if (this._state === 'idle') {
92
+ return;
93
+ }
94
+ this._stopJSTick();
95
+ this._stopNativeBackground();
96
+ this._state = 'idle';
97
+ void this._clearPersistedState();
98
+ this._emit('stop', this.getSnapshot());
99
+ }
100
+ reset() {
101
+ this._stopJSTick();
102
+ this._stopNativeBackground();
103
+ this._elapsed = 0;
104
+ this._startedAt = null;
105
+ this._pausedAt = null;
106
+ this._state = 'idle';
107
+ void this._clearPersistedState();
108
+ this._emit('onReset', this.getSnapshot());
109
+ }
110
+ getSnapshot() {
111
+ const elapsed = this._getElapsed();
112
+ const remaining = this._config.mode === 'countdown' ? Math.max(0, this._config.duration - elapsed) : null;
113
+ const progress = this._config.mode === 'countdown' && this._config.duration > 0 ? 1 - (remaining ?? 0) / this._config.duration : null;
114
+ return {
115
+ timerId: this._config.timerId,
116
+ elapsed,
117
+ remaining,
118
+ state: this._state,
119
+ appState: this._appState,
120
+ startedAt: this._startedAt,
121
+ pausedAt: this._pausedAt,
122
+ formattedElapsed: formatTime(elapsed),
123
+ formattedRemaining: remaining !== null ? formatTime(remaining) : null,
124
+ progress
125
+ };
126
+ }
127
+ destroy() {
128
+ this.stop();
129
+ if (this._appStateSubscription) {
130
+ this._appStateSubscription.remove();
131
+ this._appStateSubscription = null;
132
+ }
133
+ this._handlers = {};
134
+ }
135
+ on(event, handler) {
136
+ if (!this._handlers[event]) {
137
+ this._handlers[event] = [];
138
+ }
139
+ this._handlers[event].push(handler);
140
+ }
141
+ off(event, handler) {
142
+ if (!this._handlers[event]) {
143
+ return;
144
+ }
145
+ this._handlers[event] = this._handlers[event].filter(h => h !== handler);
146
+ }
147
+
148
+ // ─── Internal Tick ───────────────────────────────────────────────────────────
149
+
150
+ _startJSTick() {
151
+ this._stopJSTick();
152
+ this._tickInterval = setInterval(() => {
153
+ this._onTick();
154
+ }, this._config.interval);
155
+ }
156
+ _stopJSTick() {
157
+ if (this._tickInterval !== null) {
158
+ clearInterval(this._tickInterval);
159
+ this._tickInterval = null;
160
+ }
161
+ }
162
+ _onTick() {
163
+ const snap = this.getSnapshot();
164
+ if (this._config.mode === 'countdown' && snap.remaining === 0) {
165
+ this._state = 'completed';
166
+ this._stopJSTick();
167
+ this._stopNativeBackground();
168
+ void this._clearPersistedState();
169
+ this._emit('onComplete', snap);
170
+ return;
171
+ }
172
+ this._emit('onTick', snap);
173
+ }
174
+ _getElapsed() {
175
+ if (this._state === 'running' && this._startedAt !== null) {
176
+ return Math.floor((Date.now() - this._startedAt) / 1000);
177
+ }
178
+ return this._elapsed;
179
+ }
180
+
181
+ // ─── App State ───────────────────────────────────────────────────────────────
182
+
183
+ _listenAppState() {
184
+ if (this._appStateSubscription) {
185
+ return;
186
+ }
187
+ this._appStateSubscription = RNAppState.addEventListener('change', nextAppState => {
188
+ const prev = this._appState;
189
+ if (nextAppState === 'active') {
190
+ this._appState = 'foreground';
191
+ if (prev === 'background' && this._config.runInBackground) {
192
+ this._syncFromNative();
193
+ }
194
+ if (this._config.resetOnForeground) {
195
+ this.reset();
196
+ return;
197
+ }
198
+ if (this._state === 'running') {
199
+ this._startJSTick();
200
+ }
201
+ this._emit('onForeground', this.getSnapshot());
202
+ } else if (nextAppState === 'background' || nextAppState === 'inactive') {
203
+ this._appState = 'background';
204
+ if (this._config.pauseOnBackground) {
205
+ this.pause();
206
+ } else {
207
+ this._stopJSTick();
208
+ }
209
+ this._emit('onBackground', this.getSnapshot());
210
+ }
211
+ });
212
+ }
213
+
214
+ // ─── Native Background ───────────────────────────────────────────────────────
215
+
216
+ _startNativeBackground() {
217
+ if (!NativeTimerModule) {
218
+ return;
219
+ }
220
+ try {
221
+ NativeTimerModule.startTimer({
222
+ timerId: this._config.timerId,
223
+ mode: this._config.mode,
224
+ duration: this._config.duration,
225
+ elapsed: this._getElapsed(),
226
+ startedAt: this._startedAt ?? Date.now(),
227
+ showNotification: this._config.showNotification,
228
+ notification: this._config.notification
229
+ });
230
+ } catch (e) {
231
+ this._emit('error', e);
232
+ }
233
+ }
234
+ _stopNativeBackground() {
235
+ if (!NativeTimerModule) {
236
+ return;
237
+ }
238
+ try {
239
+ NativeTimerModule.stopTimer(this._config.timerId);
240
+ } catch (e) {
241
+ this._emit('error', e);
242
+ }
243
+ }
244
+ _syncFromNative() {
245
+ if (!NativeTimerModule) {
246
+ return;
247
+ }
248
+ NativeTimerModule.getElapsed(this._config.timerId).then(nativeElapsed => {
249
+ if (nativeElapsed != null) {
250
+ this._elapsed = nativeElapsed;
251
+ this._startedAt = Date.now() - nativeElapsed * 1000;
252
+ }
253
+ }).catch(() => {
254
+ // Fallback: wall-clock diff handles it via _startedAt
255
+ });
256
+ }
257
+
258
+ // ─── Killed-State Persistence ────────────────────────────────────────────────
259
+
260
+ async _persistState() {
261
+ try {
262
+ const record = {
263
+ timerId: this._config.timerId,
264
+ config: this._config,
265
+ state: this._state,
266
+ elapsed: this._getElapsed(),
267
+ startedAt: this._startedAt,
268
+ pausedAt: this._pausedAt,
269
+ savedAt: Date.now()
270
+ };
271
+ await AsyncStorage.setItem(`${STORAGE_KEY_PREFIX}${this._config.timerId}`, JSON.stringify(record));
272
+ } catch (e) {
273
+ console.warn('[rn-persistent-timer] Failed to persist state:', e);
274
+ }
275
+ }
276
+ async _clearPersistedState() {
277
+ try {
278
+ await AsyncStorage.removeItem(`${STORAGE_KEY_PREFIX}${this._config.timerId}`);
279
+ } catch {
280
+ // Swallow
281
+ }
282
+ }
283
+
284
+ // ─── Static Restore ──────────────────────────────────────────────────────────
285
+
286
+ static async restore(timerId) {
287
+ try {
288
+ const raw = await AsyncStorage.getItem(`${STORAGE_KEY_PREFIX}${timerId}`);
289
+ if (!raw) {
290
+ return null;
291
+ }
292
+ const saved = JSON.parse(raw);
293
+ const now = Date.now();
294
+ const secondsSinceSave = Math.floor((now - saved.savedAt) / 1000);
295
+ let elapsed = saved.elapsed;
296
+ if (saved.state === 'running') {
297
+ elapsed = saved.elapsed + secondsSinceSave;
298
+ }
299
+
300
+ // Cap countdown timers at their duration
301
+ if (saved.config.mode === 'countdown' && elapsed >= saved.config.duration) {
302
+ elapsed = saved.config.duration;
303
+ saved.state = 'completed';
304
+ }
305
+ return {
306
+ config: saved.config,
307
+ state: saved.state,
308
+ elapsed,
309
+ secondsLost: secondsSinceSave
310
+ };
311
+ } catch {
312
+ return null;
313
+ }
314
+ }
315
+
316
+ // ─── Event Emitter ───────────────────────────────────────────────────────────
317
+
318
+ _emit(event, data) {
319
+ const handlers = this._handlers[event] ?? [];
320
+ for (const h of handlers) {
321
+ try {
322
+ h(data);
323
+ } catch (e) {
324
+ console.error(`[rn-persistent-timer] Handler error for "${event}":`, e);
325
+ }
326
+ }
327
+ }
328
+ }
329
+ //# sourceMappingURL=PersistentTimerManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["AppState","RNAppState","AsyncStorage","NativeTimerModule","formatTime","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","formattedRemaining","destroy","remove","on","event","handler","push","off","filter","h","setInterval","_onTick","clearInterval","snap","addEventListener","nextAppState","prev","_syncFromNative","startTimer","e","stopTimer","getElapsed","then","nativeElapsed","catch","record","savedAt","setItem","JSON","stringify","removeItem","restore","raw","getItem","saved","parse","secondsSinceSave","secondsLost","data","handlers","error"],"sourceRoot":"../../src","sources":["PersistentTimerManager.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,17 @@
1
+ // rn-persistent-timer — Public API Barrel
2
+ // ─────────────────────────────────────────────────────────────────────────────
3
+
4
+ // Hook
5
+ export { usePersistentTimer } from './usePersistentTimer';
6
+
7
+ // Class
8
+ export { PersistentTimerManager } from './PersistentTimerManager';
9
+
10
+ // Utilities
11
+ export { formatTime, parseTime, isBackgroundTimerSupported, isKilledStateTimerSupported, getActiveTimers, cancelAllTimers } from './utils';
12
+
13
+ // Types — re-export everything so consumers only need one import path
14
+
15
+ // Native internals (advanced use only)
16
+ export { NativeTimerModule, NativeTimerEmitter, NATIVE_EVENTS } from './NativeTimerModule';
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["usePersistentTimer","PersistentTimerManager","formatTime","parseTime","isBackgroundTimerSupported","isKilledStateTimerSupported","getActiveTimers","cancelAllTimers","NativeTimerModule","NativeTimerEmitter","NATIVE_EVENTS"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":"AAAA;AACA;;AAEA;AACA,SAASA,kBAAkB,QAAQ,sBAAsB;;AAEzD;AACA,SAASC,sBAAsB,QAAQ,0BAA0B;;AAEjE;AACA,SACEC,UAAU,EACVC,SAAS,EACTC,0BAA0B,EAC1BC,2BAA2B,EAC3BC,eAAe,EACfC,eAAe,QACV,SAAS;;AAEhB;;AAeA;AACA,SACEC,iBAAiB,EACjBC,kBAAkB,EAClBC,aAAa,QACR,qBAAqB","ignoreList":[]}
@@ -0,0 +1,2 @@
1
+
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../src","sources":["types.ts"],"mappings":"","ignoreList":[]}
@@ -0,0 +1,153 @@
1
+ // rn-persistent-timer — usePersistentTimer Hook
2
+ // ─────────────────────────────────────────────────────────────────────────────
3
+
4
+ import { useState, useEffect, useRef, useCallback } from 'react';
5
+ import { PersistentTimerManager } from './PersistentTimerManager';
6
+ import { formatTime } from './utils';
7
+ // ─────────────────────────────────────────────────────────────────────────────
8
+
9
+ function makeInitialSnapshot(config) {
10
+ const mode = config.mode ?? 'stopwatch';
11
+ const duration = config.duration ?? 0;
12
+ return {
13
+ timerId: config.timerId,
14
+ elapsed: 0,
15
+ remaining: mode === 'countdown' ? duration : null,
16
+ state: 'idle',
17
+ appState: 'foreground',
18
+ startedAt: null,
19
+ pausedAt: null,
20
+ formattedElapsed: '00:00:00',
21
+ formattedRemaining: mode === 'countdown' ? formatTime(duration) : null,
22
+ progress: mode === 'countdown' ? 0 : null
23
+ };
24
+ }
25
+
26
+ // ─────────────────────────────────────────────────────────────────────────────
27
+
28
+ /**
29
+ * React hook for persistent timers.
30
+ *
31
+ * @example
32
+ * ```tsx
33
+ * const { snapshot, start, pause, reset, isRunning } = usePersistentTimer({
34
+ * timerId: 'workout-timer',
35
+ * mode: 'stopwatch',
36
+ * runInBackground: true,
37
+ * onTick: (snap) => console.log(snap.formattedElapsed),
38
+ * });
39
+ * ```
40
+ */
41
+ export function usePersistentTimer(config) {
42
+ const managerRef = useRef(null);
43
+ const [snapshot, setSnapshot] = useState(() => makeInitialSnapshot(config));
44
+
45
+ // Stable callback refs — avoids re-creating the manager when callbacks change
46
+ const callbacksRef = useRef({});
47
+ callbacksRef.current = {
48
+ onTick: config.onTick,
49
+ onStart: config.onStart,
50
+ onPause: config.onPause,
51
+ onResume: config.onResume,
52
+ onReset: config.onReset,
53
+ onComplete: config.onComplete,
54
+ onBackground: config.onBackground,
55
+ onForeground: config.onForeground,
56
+ onRestore: config.onRestore,
57
+ onError: config.onError
58
+ };
59
+ useEffect(() => {
60
+ const manager = new PersistentTimerManager({
61
+ timerId: config.timerId,
62
+ mode: config.mode,
63
+ duration: config.duration,
64
+ runInBackground: config.runInBackground,
65
+ runInKilledState: config.runInKilledState,
66
+ pauseOnBackground: config.pauseOnBackground,
67
+ resetOnForeground: config.resetOnForeground,
68
+ interval: config.interval,
69
+ showNotification: config.showNotification,
70
+ notification: config.notification
71
+ });
72
+
73
+ // Snapshot callbacks — update React state then call user callback
74
+
75
+ const wire = (managerEvent, cbKey) => {
76
+ manager.on(managerEvent, snap => {
77
+ setSnapshot({
78
+ ...snap
79
+ });
80
+ callbacksRef.current[cbKey]?.(snap);
81
+ });
82
+ };
83
+ wire('onTick', 'onTick');
84
+ wire('onStart', 'onStart');
85
+ wire('onPause', 'onPause');
86
+ wire('onResume', 'onResume');
87
+ wire('onReset', 'onReset');
88
+ wire('onComplete', 'onComplete');
89
+ wire('onBackground', 'onBackground');
90
+ wire('onForeground', 'onForeground');
91
+ wire('onRestore', 'onRestore');
92
+
93
+ // Error callback — receives Error, not TimerSnapshot
94
+ manager.on('error', err => {
95
+ callbacksRef.current.onError?.(err);
96
+ });
97
+
98
+ // Restore from killed state if applicable
99
+ if (config.runInKilledState) {
100
+ PersistentTimerManager.restore(config.timerId).then(restored => {
101
+ if (!restored) {
102
+ return;
103
+ }
104
+
105
+ // Replay internal state onto the manager
106
+ manager._elapsed = restored.elapsed;
107
+ manager._state = restored.state;
108
+ const snap = manager.getSnapshot();
109
+ setSnapshot({
110
+ ...snap
111
+ });
112
+ callbacksRef.current.onRestore?.(snap);
113
+
114
+ // Auto-resume if the timer was running when the app was killed
115
+ if (restored.state === 'running') {
116
+ manager.start();
117
+ }
118
+ });
119
+ }
120
+ managerRef.current = manager;
121
+ return () => {
122
+ manager.destroy();
123
+ managerRef.current = null;
124
+ };
125
+ // Re-create the manager only if timerId changes
126
+ // eslint-disable-next-line react-hooks/exhaustive-deps
127
+ }, [config.timerId]);
128
+
129
+ // ─── Stable controls ──────────────────────────────────────────────────────
130
+
131
+ const start = useCallback(() => managerRef.current?.start(), []);
132
+ const pause = useCallback(() => managerRef.current?.pause(), []);
133
+ const resume = useCallback(() => managerRef.current?.resume(), []);
134
+ const reset = useCallback(() => managerRef.current?.reset(), []);
135
+ const stop = useCallback(() => managerRef.current?.stop(), []);
136
+ const destroy = useCallback(() => managerRef.current?.destroy(), []);
137
+ const getSnapshot = useCallback(() => managerRef.current?.getSnapshot() ?? snapshot, [snapshot]);
138
+ return {
139
+ snapshot,
140
+ isRunning: snapshot.state === 'running',
141
+ isPaused: snapshot.state === 'paused',
142
+ isCompleted: snapshot.state === 'completed',
143
+ appState: snapshot.appState,
144
+ start,
145
+ pause,
146
+ resume,
147
+ reset,
148
+ stop,
149
+ destroy,
150
+ getSnapshot
151
+ };
152
+ }
153
+ //# sourceMappingURL=usePersistentTimer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["useState","useEffect","useRef","useCallback","PersistentTimerManager","formatTime","makeInitialSnapshot","config","mode","duration","timerId","elapsed","remaining","state","appState","startedAt","pausedAt","formattedElapsed","formattedRemaining","progress","usePersistentTimer","managerRef","snapshot","setSnapshot","callbacksRef","current","onTick","onStart","onPause","onResume","onReset","onComplete","onBackground","onForeground","onRestore","onError","manager","runInBackground","runInKilledState","pauseOnBackground","resetOnForeground","interval","showNotification","notification","wire","managerEvent","cbKey","on","snap","err","restore","then","restored","_elapsed","_state","getSnapshot","start","destroy","pause","resume","reset","stop","isRunning","isPaused","isCompleted"],"sourceRoot":"../../src","sources":["usePersistentTimer.tsx"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,100 @@
1
+ // rn-persistent-timer — Utility Functions
2
+ // ─────────────────────────────────────────────────────────────────────────────
3
+
4
+ /**
5
+ * Format a number of seconds into an `HH:MM:SS` string.
6
+ *
7
+ * @example
8
+ * formatTime(3661); // '01:01:01'
9
+ * formatTime(59); // '00:00:59'
10
+ */
11
+ export function formatTime(seconds) {
12
+ const s = Math.max(0, Math.floor(seconds));
13
+ const h = Math.floor(s / 3600);
14
+ const m = Math.floor(s % 3600 / 60);
15
+ const sec = s % 60;
16
+ return [h, m, sec].map(v => String(v).padStart(2, '0')).join(':');
17
+ }
18
+
19
+ /**
20
+ * Parse an `HH:MM:SS` or `MM:SS` string into total seconds.
21
+ *
22
+ * @example
23
+ * parseTime('01:30:00'); // 5400
24
+ * parseTime('05:30'); // 330
25
+ */
26
+ export function parseTime(formatted) {
27
+ const parts = formatted.split(':').map(Number);
28
+ if (parts.length === 3) {
29
+ return parts[0] * 3600 + parts[1] * 60 + parts[2];
30
+ }
31
+ if (parts.length === 2) {
32
+ return parts[0] * 60 + parts[1];
33
+ }
34
+ return parts[0] ?? 0;
35
+ }
36
+
37
+ /**
38
+ * Returns `true` if the native background-timer module is available on this
39
+ * device / build. Always returns `false` in Expo Go.
40
+ */
41
+ export async function isBackgroundTimerSupported() {
42
+ const {
43
+ NativeTimerModule
44
+ } = await import('./NativeTimerModule');
45
+ return Boolean(NativeTimerModule);
46
+ }
47
+
48
+ /**
49
+ * Returns `true` if the killed-state persistence feature is supported.
50
+ * Requires the native module **and** platform capabilities
51
+ * (WorkManager on Android, BGTaskScheduler on iOS 13+).
52
+ */
53
+ export async function isKilledStateTimerSupported() {
54
+ const {
55
+ NativeTimerModule
56
+ } = await import('./NativeTimerModule');
57
+ if (!NativeTimerModule) {
58
+ return false;
59
+ }
60
+ try {
61
+ return (await NativeTimerModule.isKilledStateSupported?.()) ?? false;
62
+ } catch {
63
+ return false;
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Return the IDs of all timers currently active in the native layer.
69
+ */
70
+ export async function getActiveTimers() {
71
+ const {
72
+ NativeTimerModule
73
+ } = await import('./NativeTimerModule');
74
+ if (!NativeTimerModule) {
75
+ return [];
76
+ }
77
+ try {
78
+ return await NativeTimerModule.getActiveTimers();
79
+ } catch {
80
+ return [];
81
+ }
82
+ }
83
+
84
+ /**
85
+ * Cancel every active timer in both the native layer and JS.
86
+ */
87
+ export async function cancelAllTimers() {
88
+ const {
89
+ NativeTimerModule
90
+ } = await import('./NativeTimerModule');
91
+ if (!NativeTimerModule) {
92
+ return;
93
+ }
94
+ try {
95
+ await NativeTimerModule.cancelAll();
96
+ } catch {
97
+ // Swallow — best-effort cleanup
98
+ }
99
+ }
100
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["formatTime","seconds","s","Math","max","floor","h","m","sec","map","v","String","padStart","join","parseTime","formatted","parts","split","Number","length","isBackgroundTimerSupported","NativeTimerModule","Boolean","isKilledStateTimerSupported","isKilledStateSupported","getActiveTimers","cancelAllTimers","cancelAll"],"sourceRoot":"../../src","sources":["utils.ts"],"mappings":"AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASA,UAAUA,CAACC,OAAe,EAAU;EAClD,MAAMC,CAAC,GAAGC,IAAI,CAACC,GAAG,CAAC,CAAC,EAAED,IAAI,CAACE,KAAK,CAACJ,OAAO,CAAC,CAAC;EAC1C,MAAMK,CAAC,GAAGH,IAAI,CAACE,KAAK,CAACH,CAAC,GAAG,IAAI,CAAC;EAC9B,MAAMK,CAAC,GAAGJ,IAAI,CAACE,KAAK,CAAEH,CAAC,GAAG,IAAI,GAAI,EAAE,CAAC;EACrC,MAAMM,GAAG,GAAGN,CAAC,GAAG,EAAE;EAClB,OAAO,CAACI,CAAC,EAAEC,CAAC,EAAEC,GAAG,CAAC,CAACC,GAAG,CAAEC,CAAC,IAAKC,MAAM,CAACD,CAAC,CAAC,CAACE,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAACC,IAAI,CAAC,GAAG,CAAC;AACrE;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,SAASA,CAACC,SAAiB,EAAU;EACnD,MAAMC,KAAK,GAAGD,SAAS,CAACE,KAAK,CAAC,GAAG,CAAC,CAACR,GAAG,CAACS,MAAM,CAAC;EAC9C,IAAIF,KAAK,CAACG,MAAM,KAAK,CAAC,EAAE;IACtB,OAAOH,KAAK,CAAC,CAAC,CAAC,GAAI,IAAI,GAAGA,KAAK,CAAC,CAAC,CAAC,GAAI,EAAE,GAAGA,KAAK,CAAC,CAAC,CAAE;EACtD;EACA,IAAIA,KAAK,CAACG,MAAM,KAAK,CAAC,EAAE;IACtB,OAAOH,KAAK,CAAC,CAAC,CAAC,GAAI,EAAE,GAAGA,KAAK,CAAC,CAAC,CAAE;EACnC;EACA,OAAOA,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACtB;;AAEA;AACA;AACA;AACA;AACA,OAAO,eAAeI,0BAA0BA,CAAA,EAAqB;EACnE,MAAM;IAAEC;EAAkB,CAAC,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC;EACjE,OAAOC,OAAO,CAACD,iBAAiB,CAAC;AACnC;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO,eAAeE,2BAA2BA,CAAA,EAAqB;EACpE,MAAM;IAAEF;EAAkB,CAAC,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC;EACjE,IAAI,CAACA,iBAAiB,EAAE;IACtB,OAAO,KAAK;EACd;EACA,IAAI;IACF,OAAO,OAAMA,iBAAiB,CAACG,sBAAsB,GAAG,CAAC,KAAI,KAAK;EACpE,CAAC,CAAC,MAAM;IACN,OAAO,KAAK;EACd;AACF;;AAEA;AACA;AACA;AACA,OAAO,eAAeC,eAAeA,CAAA,EAAsB;EACzD,MAAM;IAAEJ;EAAkB,CAAC,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC;EACjE,IAAI,CAACA,iBAAiB,EAAE;IACtB,OAAO,EAAE;EACX;EACA,IAAI;IACF,OAAO,MAAMA,iBAAiB,CAACI,eAAe,CAAC,CAAC;EAClD,CAAC,CAAC,MAAM;IACN,OAAO,EAAE;EACX;AACF;;AAEA;AACA;AACA;AACA,OAAO,eAAeC,eAAeA,CAAA,EAAkB;EACrD,MAAM;IAAEL;EAAkB,CAAC,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC;EACjE,IAAI,CAACA,iBAAiB,EAAE;IACtB;EACF;EACA,IAAI;IACF,MAAMA,iBAAiB,CAACM,SAAS,CAAC,CAAC;EACrC,CAAC,CAAC,MAAM;IACN;EAAA;AAEJ","ignoreList":[]}