react-native-alarmageddon 1.0.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/src/index.ts ADDED
@@ -0,0 +1,317 @@
1
+ import {
2
+ NativeModules,
3
+ NativeEventEmitter,
4
+ PermissionsAndroid,
5
+ Platform,
6
+ EmitterSubscription,
7
+ } from 'react-native';
8
+
9
+ /**
10
+ * Parameters for scheduling an alarm
11
+ */
12
+ export type AlarmParams = {
13
+ /** Unique identifier for the alarm */
14
+ id: string;
15
+ /** ISO 8601 datetime string for when the alarm should trigger */
16
+ datetimeISO: string;
17
+ /** Title shown in the notification */
18
+ title?: string;
19
+ /** Body text shown in the notification */
20
+ body?: string;
21
+ /** URI of the sound to play (uses default alarm sound if not provided) */
22
+ soundUri?: string;
23
+ /** Whether to vibrate when alarm triggers (default: true) */
24
+ vibrate?: boolean;
25
+ /** Number of minutes for snooze (default: 5) */
26
+ snoozeMinutes?: number;
27
+ /** Number of seconds before alarm auto-stops (default: 60) */
28
+ autoStopSeconds?: number;
29
+ };
30
+
31
+ /**
32
+ * Stored alarm data returned from listAlarms
33
+ */
34
+ export type StoredAlarm = {
35
+ id: string;
36
+ datetimeISO: string;
37
+ title: string;
38
+ body: string;
39
+ vibrate: boolean;
40
+ snoozeMinutes: number;
41
+ autoStopSeconds: number;
42
+ };
43
+
44
+ /**
45
+ * Permission request result
46
+ */
47
+ export type PermissionResult = {
48
+ granted: boolean;
49
+ exactAlarmGranted?: boolean;
50
+ };
51
+
52
+ /**
53
+ * Active alarm info
54
+ */
55
+ export type ActiveAlarmInfo = {
56
+ activeAlarmId: string;
57
+ } | null;
58
+
59
+ /**
60
+ * Native module interface
61
+ */
62
+ interface AlarmModuleInterface {
63
+ scheduleAlarm(alarm: AlarmParams): Promise<void>;
64
+ cancelAlarm(id: string): Promise<void>;
65
+ listAlarms(): Promise<StoredAlarm[]>;
66
+ requestPermissions(): Promise<PermissionResult>;
67
+ checkExactAlarmPermission(): Promise<boolean>;
68
+ openExactAlarmSettings(): Promise<void>;
69
+ snoozeAlarm(id: string, minutes: number): Promise<void>;
70
+ stopCurrentAlarm(id: string): Promise<void>;
71
+ snoozeCurrentAlarm(id: string, minutes: number): Promise<void>;
72
+ getCurrentAlarmPlaying(): Promise<ActiveAlarmInfo>;
73
+ addListener(eventName: string): void;
74
+ removeListeners(count: number): void;
75
+ }
76
+
77
+ const { AlarmModule } = NativeModules as { AlarmModule: AlarmModuleInterface };
78
+
79
+ // Validate module exists
80
+ if (!AlarmModule) {
81
+ throw new Error(
82
+ 'react-native-alarmageddon: NativeModule is null. ' +
83
+ 'Ensure you have linked the native module correctly. ' +
84
+ 'On Android, run `npx react-native run-android` to rebuild.'
85
+ );
86
+ }
87
+
88
+ const eventEmitter = new NativeEventEmitter(NativeModules.AlarmModule);
89
+
90
+ /**
91
+ * Request notification permission (required on Android 13+)
92
+ * @returns Promise resolving to true if permission granted
93
+ */
94
+ async function requestNotificationPermission(): Promise<boolean> {
95
+ if (Platform.OS !== 'android') {
96
+ return true;
97
+ }
98
+
99
+ try {
100
+ if (Platform.Version >= 33) {
101
+ const status = await PermissionsAndroid.request(
102
+ 'android.permission.POST_NOTIFICATIONS' as any
103
+ );
104
+ return status === PermissionsAndroid.RESULTS.GRANTED;
105
+ }
106
+ return true;
107
+ } catch (error) {
108
+ console.warn('Failed to request notification permission:', error);
109
+ return false;
110
+ }
111
+ }
112
+
113
+ /**
114
+ * Request exact alarm permission (required on Android 12+)
115
+ * Opens system settings if not granted
116
+ * @returns Promise resolving to permission result
117
+ */
118
+ async function requestExactAlarmPermission(): Promise<PermissionResult> {
119
+ if (Platform.OS !== 'android') {
120
+ return { granted: true, exactAlarmGranted: true };
121
+ }
122
+
123
+ return AlarmModule.requestPermissions();
124
+ }
125
+
126
+ /**
127
+ * Check if exact alarm permission is granted
128
+ * @returns Promise resolving to true if permission granted
129
+ */
130
+ async function checkExactAlarmPermission(): Promise<boolean> {
131
+ if (Platform.OS !== 'android') {
132
+ return true;
133
+ }
134
+
135
+ return AlarmModule.checkExactAlarmPermission();
136
+ }
137
+
138
+ /**
139
+ * Open system settings for exact alarm permission
140
+ */
141
+ async function openExactAlarmSettings(): Promise<void> {
142
+ if (Platform.OS === 'android') {
143
+ return AlarmModule.openExactAlarmSettings();
144
+ }
145
+ }
146
+
147
+ /**
148
+ * Ensure all required permissions are granted
149
+ * Requests both notification and exact alarm permissions
150
+ * @returns Promise resolving to true if all permissions granted
151
+ */
152
+ async function ensurePermissions(): Promise<boolean> {
153
+ if (Platform.OS !== 'android') {
154
+ return true;
155
+ }
156
+
157
+ const [notificationGranted, exactAlarmResult] = await Promise.all([
158
+ requestNotificationPermission(),
159
+ requestExactAlarmPermission(),
160
+ ]);
161
+
162
+ return notificationGranted && exactAlarmResult.granted;
163
+ }
164
+
165
+ /**
166
+ * Schedule an alarm
167
+ * @param alarm - Alarm parameters
168
+ */
169
+ async function scheduleAlarm(alarm: AlarmParams): Promise<void> {
170
+ if (!alarm.id) {
171
+ throw new Error('Alarm ID is required');
172
+ }
173
+ if (!alarm.datetimeISO) {
174
+ throw new Error('datetimeISO is required');
175
+ }
176
+
177
+ return AlarmModule.scheduleAlarm(alarm);
178
+ }
179
+
180
+ /**
181
+ * Cancel a scheduled alarm
182
+ * @param id - Alarm ID to cancel
183
+ */
184
+ async function cancelAlarm(id: string): Promise<void> {
185
+ if (!id) {
186
+ throw new Error('Alarm ID is required');
187
+ }
188
+ return AlarmModule.cancelAlarm(id);
189
+ }
190
+
191
+ /**
192
+ * List all scheduled alarms
193
+ * @returns Promise resolving to array of stored alarms
194
+ */
195
+ async function listAlarms(): Promise<StoredAlarm[]> {
196
+ return AlarmModule.listAlarms();
197
+ }
198
+
199
+ /**
200
+ * Snooze an alarm for a specified number of minutes
201
+ * @param id - Alarm ID to snooze
202
+ * @param minutes - Number of minutes to snooze (default: 5)
203
+ */
204
+ async function snoozeAlarm(id: string, minutes: number = 5): Promise<void> {
205
+ if (!id) {
206
+ throw new Error('Alarm ID is required');
207
+ }
208
+ return AlarmModule.snoozeAlarm(id, minutes);
209
+ }
210
+
211
+ /**
212
+ * Stop the currently playing alarm
213
+ * @param id - Alarm ID to stop
214
+ */
215
+ async function stopCurrentAlarm(id: string): Promise<void> {
216
+ if (!id) {
217
+ throw new Error('Alarm ID is required');
218
+ }
219
+ return AlarmModule.stopCurrentAlarm(id);
220
+ }
221
+
222
+ /**
223
+ * Snooze the currently playing alarm
224
+ * @param id - Alarm ID to snooze
225
+ * @param minutes - Number of minutes to snooze (default: 5)
226
+ */
227
+ async function snoozeCurrentAlarm(id: string, minutes: number = 5): Promise<void> {
228
+ if (!id) {
229
+ throw new Error('Alarm ID is required');
230
+ }
231
+ return AlarmModule.snoozeCurrentAlarm(id, minutes);
232
+ }
233
+
234
+ /**
235
+ * Get the currently playing alarm (if any)
236
+ * @returns Promise resolving to active alarm info or null
237
+ */
238
+ async function getCurrentAlarmPlaying(): Promise<ActiveAlarmInfo> {
239
+ return AlarmModule.getCurrentAlarmPlaying();
240
+ }
241
+
242
+ /**
243
+ * Subscribe to alarm state changes
244
+ * Callback receives the alarm ID when an alarm starts, or null when stopped
245
+ * @param callback - Function called when alarm state changes
246
+ * @returns Cleanup function to remove the subscription
247
+ */
248
+ function onAlarmStateChange(
249
+ callback: (alarmId: string | null) => void
250
+ ): () => void {
251
+ const subscription: EmitterSubscription = eventEmitter.addListener(
252
+ 'activeAlarmId',
253
+ callback
254
+ );
255
+ return () => subscription.remove();
256
+ }
257
+
258
+ /**
259
+ * Add event listener for alarm state changes
260
+ * @param event - Event name ('activeAlarmId')
261
+ * @param callback - Callback function
262
+ * @returns EmitterSubscription for removal
263
+ */
264
+ function addEventListener(
265
+ event: 'activeAlarmId',
266
+ callback: (alarmId: string | null) => void
267
+ ): EmitterSubscription {
268
+ return eventEmitter.addListener(event, callback);
269
+ }
270
+
271
+ /**
272
+ * Main module export with all alarm functions
273
+ */
274
+ const RNAlarmModule = {
275
+ // Permissions
276
+ ensurePermissions,
277
+ requestNotificationPermission,
278
+ requestExactAlarmPermission,
279
+ checkExactAlarmPermission,
280
+ openExactAlarmSettings,
281
+
282
+ // Alarm management
283
+ scheduleAlarm,
284
+ cancelAlarm,
285
+ listAlarms,
286
+ snoozeAlarm,
287
+
288
+ // Active alarm control
289
+ stopCurrentAlarm,
290
+ snoozeCurrentAlarm,
291
+ getCurrentAlarmPlaying,
292
+
293
+ // Event handling
294
+ onAlarmStateChange,
295
+ addEventListener,
296
+ };
297
+
298
+ export default RNAlarmModule;
299
+ export { RNAlarmModule };
300
+
301
+ // Export individual functions for tree-shaking
302
+ export {
303
+ ensurePermissions,
304
+ requestNotificationPermission,
305
+ requestExactAlarmPermission,
306
+ checkExactAlarmPermission,
307
+ openExactAlarmSettings,
308
+ scheduleAlarm,
309
+ cancelAlarm,
310
+ listAlarms,
311
+ snoozeAlarm,
312
+ stopCurrentAlarm,
313
+ snoozeCurrentAlarm,
314
+ getCurrentAlarmPlaying,
315
+ onAlarmStateChange,
316
+ addEventListener,
317
+ };