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,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 @@
|
|
|
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":[]}
|