1import type {
2  PermissionExpiration,
3  PermissionResponse,
4  PermissionStatus,
5  Subscription,
6} from 'expo-modules-core';
7
8import { CalendarTriggerInput as NativeCalendarTriggerInput } from './NotificationScheduler.types';
9
10/**
11 * An object represents a notification delivered by a push notification system.
12 *
13 * On Android under `remoteMessage` field a JS version of the Firebase `RemoteMessage` may be accessed.
14 * On iOS under `payload` you may find full contents of [`UNNotificationContent`'s](https://developer.apple.com/documentation/usernotifications/unnotificationcontent?language=objc) [`userInfo`](https://developer.apple.com/documentation/usernotifications/unnotificationcontent/1649869-userinfo?language=objc), for example [remote notification payload](https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CreatingtheNotificationPayload.html)
15 * On web there is no extra data.
16 */
17export type PushNotificationTrigger = {
18  type: 'push';
19  /**
20   * @platform ios
21   */
22  payload?: Record<string, unknown>;
23  /**
24   * @platform android
25   */
26  remoteMessage?: FirebaseRemoteMessage;
27};
28
29/**
30 * A trigger related to a [`UNCalendarNotificationTrigger`](https://developer.apple.com/documentation/usernotifications/uncalendarnotificationtrigger?language=objc).
31 * @platform ios
32 */
33export interface CalendarNotificationTrigger {
34  type: 'calendar';
35  repeats: boolean;
36  dateComponents: {
37    era?: number;
38    year?: number;
39    month?: number;
40    day?: number;
41    hour?: number;
42    minute?: number;
43    second?: number;
44    weekday?: number;
45    weekdayOrdinal?: number;
46    quarter?: number;
47    weekOfMonth?: number;
48    weekOfYear?: number;
49    yearForWeekOfYear?: number;
50    nanosecond?: number;
51    isLeapMonth: boolean;
52    timeZone?: string;
53    calendar?: string;
54  };
55}
56
57/**
58 * The region used to determine when the system sends the notification.
59 * @platform ios
60 */
61interface Region {
62  type: string;
63  /**
64   * The identifier for the region object.
65   */
66  identifier: string;
67  /**
68   * A Boolean indicating that notifications are generated upon entry into the region.
69   */
70  notifyOnEntry: boolean;
71  /**
72   * A Boolean indicating that notifications are generated upon exit from the region.
73   */
74  notifyOnExit: boolean;
75}
76
77/**
78 * A circular geographic region, specified as a center point and radius. Based on Core Location [`CLCircularRegion`](https://developer.apple.com/documentation/corelocation/clcircularregion) class.
79 * @platform ios
80 */
81export interface CircularRegion extends Region {
82  type: 'circular';
83  /**
84   * The radius (measured in meters) that defines the geographic area’s outer boundary.
85   */
86  radius: number;
87  /**
88   * The center point of the geographic area.
89   */
90  center: {
91    latitude: number;
92    longitude: number;
93  };
94}
95
96/**
97 * A region used to detect the presence of iBeacon devices. Based on Core Location [`CLBeaconRegion`](https://developer.apple.com/documentation/corelocation/clbeaconregion) class.
98 * @platform ios
99 */
100export interface BeaconRegion extends Region {
101  type: 'beacon';
102  /**
103   * A Boolean value that indicates whether Core Location sends beacon notifications when the device’s display is on.
104   */
105  notifyEntryStateOnDisplay: boolean;
106  /**
107   * The major value from the beacon identity constraint that defines the beacon region.
108   */
109  major: number | null;
110  /**
111   * The minor value from the beacon identity constraint that defines the beacon region.
112   */
113  minor: number | null;
114  /**
115   * The UUID value from the beacon identity constraint that defines the beacon region.
116   */
117  uuid?: string;
118  /**
119   * The beacon identity constraint that defines the beacon region.
120   */
121  beaconIdentityConstraint?: {
122    uuid: string;
123    major: number | null;
124    minor: number | null;
125  };
126}
127
128/**
129 * A trigger related to a [`UNLocationNotificationTrigger`](https://developer.apple.com/documentation/usernotifications/unlocationnotificationtrigger?language=objc).
130 * @platform ios
131 */
132export interface LocationNotificationTrigger {
133  type: 'location';
134  repeats: boolean;
135  region: CircularRegion | BeaconRegion;
136}
137
138/**
139 * A trigger related to an elapsed time interval. May be repeating (see `repeats` field).
140 */
141export interface TimeIntervalNotificationTrigger {
142  type: 'timeInterval';
143  repeats: boolean;
144  seconds: number;
145}
146
147/**
148 * A trigger related to a daily notification.
149 * > The same functionality will be achieved on iOS with a `CalendarNotificationTrigger`.
150 * @platform android
151 */
152export interface DailyNotificationTrigger {
153  type: 'daily';
154  hour: number;
155  minute: number;
156}
157
158/**
159 * A trigger related to a weekly notification.
160 * > The same functionality will be achieved on iOS with a `CalendarNotificationTrigger`.
161 * @platform android
162 */
163export interface WeeklyNotificationTrigger {
164  type: 'weekly';
165  weekday: number;
166  hour: number;
167  minute: number;
168}
169
170/**
171 * A trigger related to a yearly notification.
172 * > The same functionality will be achieved on iOS with a `CalendarNotificationTrigger`.
173 * @platform android
174 */
175export interface YearlyNotificationTrigger {
176  type: 'yearly';
177  day: number;
178  month: number;
179  hour: number;
180  minute: number;
181}
182
183// @docsMissing
184/**
185 * A Firebase `RemoteMessage` that caused the notification to be delivered to the app.
186 */
187export interface FirebaseRemoteMessage {
188  collapseKey: string | null;
189  data: { [key: string]: string };
190  from: string | null;
191  messageId: string | null;
192  messageType: string | null;
193  originalPriority: number;
194  priority: number;
195  sentTime: number;
196  to: string | null;
197  ttl: number;
198  notification: null | FirebaseRemoteMessageNotification;
199}
200
201// @docsMissing
202export interface FirebaseRemoteMessageNotification {
203  body: string | null;
204  bodyLocalizationArgs: string[] | null;
205  bodyLocalizationKey: string | null;
206  channelId: string | null;
207  clickAction: string | null;
208  color: string | null;
209  usesDefaultLightSettings: boolean;
210  usesDefaultSound: boolean;
211  usesDefaultVibrateSettings: boolean;
212  eventTime: number | null;
213  icon: string | null;
214  imageUrl: string | null;
215  lightSettings: number[] | null;
216  link: string | null;
217  localOnly: boolean;
218  notificationCount: number | null;
219  notificationPriority: number | null;
220  sound: string | null;
221  sticky: boolean;
222  tag: string | null;
223  ticker: string | null;
224  title: string | null;
225  titleLocalizationArgs: string[] | null;
226  titleLocalizationKey: string | null;
227  vibrateTimings: number[] | null;
228  visibility: number | null;
229}
230
231/**
232 * Represents a notification trigger that is unknown to `expo-notifications` and that it didn't know how to serialize for JS.
233 */
234export interface UnknownNotificationTrigger {
235  type: 'unknown';
236}
237
238/**
239 * A union type containing different triggers which may cause the notification to be delivered to the application.
240 */
241export type NotificationTrigger =
242  | PushNotificationTrigger
243  | CalendarNotificationTrigger
244  | LocationNotificationTrigger
245  | TimeIntervalNotificationTrigger
246  | DailyNotificationTrigger
247  | WeeklyNotificationTrigger
248  | YearlyNotificationTrigger
249  | UnknownNotificationTrigger;
250
251/**
252 * A trigger that will cause the notification to be delivered immediately.
253 */
254export type ChannelAwareTriggerInput = {
255  channelId: string;
256};
257
258/**
259 * A trigger that will cause the notification to be delivered once or many times when the date components match the specified values.
260 * Corresponds to native [`UNCalendarNotificationTrigger`](https://developer.apple.com/documentation/usernotifications/uncalendarnotificationtrigger?language=objc).
261 * @platform ios
262 */
263export type CalendarTriggerInput = NativeCalendarTriggerInput['value'] & {
264  channelId?: string;
265  repeats?: boolean;
266};
267
268/**
269 * A trigger that will cause the notification to be delivered once or many times (depends on the `repeats` field) after `seconds` time elapse.
270 * > **On iOS**, when `repeats` is `true`, the time interval must be 60 seconds or greater. Otherwise, the notification won't be triggered.
271 */
272export interface TimeIntervalTriggerInput {
273  channelId?: string;
274  repeats?: boolean;
275  seconds: number;
276}
277
278/**
279 * A trigger that will cause the notification to be delivered once per day.
280 */
281export interface DailyTriggerInput {
282  channelId?: string;
283  hour: number;
284  minute: number;
285  repeats: true;
286}
287
288/**
289 * A trigger that will cause the notification to be delivered once every week.
290 * > **Note:** Weekdays are specified with a number from `1` through `7`, with `1` indicating Sunday.
291 */
292export interface WeeklyTriggerInput {
293  channelId?: string;
294  weekday: number;
295  hour: number;
296  minute: number;
297  repeats: true;
298}
299
300/**
301 * A trigger that will cause the notification to be delivered once every year.
302 * > **Note:** all properties are specified in JavaScript Date's ranges.
303 */
304export interface YearlyTriggerInput {
305  channelId?: string;
306  day: number;
307  month: number;
308  hour: number;
309  minute: number;
310  repeats: true;
311}
312
313/**
314 * A trigger that will cause the notification to be delivered once at the specified `Date`.
315 * If you pass in a `number` it will be interpreted as a Unix timestamp.
316 */
317export type DateTriggerInput = Date | number | { channelId?: string; date: Date | number };
318
319/**
320 * A type represents time-based, schedulable triggers. For these triggers you can check the next trigger date
321 * with [`getNextTriggerDateAsync`](#notificationsgetnexttriggerdateasynctrigger).
322 */
323export type SchedulableNotificationTriggerInput =
324  | DateTriggerInput
325  | TimeIntervalTriggerInput
326  | DailyTriggerInput
327  | WeeklyTriggerInput
328  | YearlyTriggerInput
329  | CalendarTriggerInput;
330
331/**
332 * A type represents possible triggers with which you can schedule notifications.
333 * A `null` trigger means that the notification should be scheduled for delivery immediately.
334 */
335export type NotificationTriggerInput =
336  | null
337  | ChannelAwareTriggerInput
338  | SchedulableNotificationTriggerInput;
339
340/**
341 * An enum corresponding to values appropriate for Android's [`Notification#priority`](https://developer.android.com/reference/android/app/Notification#priority) field.
342 */
343export enum AndroidNotificationPriority {
344  MIN = 'min',
345  LOW = 'low',
346  DEFAULT = 'default',
347  HIGH = 'high',
348  MAX = 'max',
349}
350
351/**
352 * An object represents notification's content.
353 */
354export type NotificationContent = {
355  /**
356   * Notification title - the bold text displayed above the rest of the content.
357   */
358  title: string | null;
359  /**
360   * On Android: `subText` - the display depends on the device.
361   *
362   * On iOS: `subtitle` - the bold text displayed between title and the rest of the content.
363   */
364  subtitle: string | null;
365  /**
366   * Notification body - the main content of the notification.
367   */
368  body: string | null;
369  /**
370   * Data associated with the notification, not displayed
371   */
372  data: Record<string, any>;
373  sound: 'default' | 'defaultCritical' | 'custom' | null;
374} & (NotificationContentIos | NotificationContentAndroid);
375
376/**
377 * See [Apple documentation](https://developer.apple.com/documentation/usernotifications/unnotificationcontent?language=objc) for more information on specific fields.
378 */
379export type NotificationContentIos = {
380  /**
381   * The name of the image or storyboard to use when your app launches because of the notification.
382   */
383  launchImageName: string | null;
384  /**
385   * The number that your app’s icon displays.
386   */
387  badge: number | null;
388  /**
389   * The visual and audio attachments to display alongside the notification’s main content.
390   */
391  attachments: NotificationContentAttachmentIos[];
392  /**
393   * The text the system adds to the notification summary to provide additional context.
394   */
395  summaryArgument?: string | null;
396  /**
397   * The number the system adds to the notification summary when the notification represents multiple items.
398   */
399  summaryArgumentCount?: number;
400  /**
401   * The identifier of the notification’s category.
402   */
403  categoryIdentifier: string | null;
404  /**
405   * The identifier that groups related notifications.
406   */
407  threadIdentifier: string | null;
408  /**
409   * The value your app uses to determine which scene to display to handle the notification.
410   */
411  targetContentIdentifier?: string;
412};
413
414// @docsMissing
415/**
416 * @platform ios
417 */
418export type NotificationContentAttachmentIos = {
419  identifier: string | null;
420  url: string | null;
421  type: string | null;
422  typeHint?: string;
423  hideThumbnail?: boolean;
424  thumbnailClipArea?: { x: number; y: number; width: number; height: number };
425  thumbnailTime?: number;
426};
427
428/**
429 * See [Android developer documentation](https://developer.android.com/reference/android/app/Notification#fields) for more information on specific fields.
430 */
431export type NotificationContentAndroid = {
432  /**
433   * Application badge number associated with the notification.
434   */
435  badge?: number;
436  /**
437   * Accent color (in `#AARRGGBB` or `#RRGGBB` format) to be applied by the standard Style templates when presenting this notification.
438   */
439  color?: string;
440  /**
441   * Relative priority for this notification. Priority is an indication of how much of the user's valuable attention should be consumed by this notification.
442   * Low-priority notifications may be hidden from the user in certain situations, while the user might be interrupted for a higher-priority notification.
443   * The system will make a determination about how to interpret this priority when presenting the notification.
444   */
445  priority?: AndroidNotificationPriority;
446  /**
447   * The pattern with which to vibrate.
448   */
449  vibrationPattern?: number[];
450};
451
452/**
453 * An object represents a request to present a notification. It has content — how it's being represented, and a trigger — what triggers the notification.
454 * Many notifications ([`Notification`](#notification)) may be triggered with the same request (for example, a repeating notification).
455 */
456export interface NotificationRequest {
457  identifier: string;
458  content: NotificationContent;
459  trigger: NotificationTrigger;
460}
461
462// TODO(simek): asses if we can base this type on `NotificationContent`, since most of the fields looks like repetition
463/**
464 * An object represents notification content that you pass in to `presentNotificationAsync` or as a part of `NotificationRequestInput`.
465 */
466export type NotificationContentInput = {
467  /**
468   * Notification title - the bold text displayed above the rest of the content.
469   */
470  title?: string | null;
471  /**
472   * On Android: `subText` - the display depends on the device.
473   *
474   * On iOS: `subtitle` - the bold text displayed between title and the rest of the content.
475   */
476  subtitle?: string | null;
477  /**
478   * The main content of the notification.
479   */
480  body?: string | null;
481  /**
482   * Data associated with the notification, not displayed.
483   */
484  data?: Record<string, any>;
485  /**
486   * Application badge number associated with the notification.
487   */
488  badge?: number;
489  sound?: boolean | string;
490  /**
491   * The name of the image or storyboard to use when your app launches because of the notification.
492   */
493  launchImageName?: string;
494  /**
495   * The pattern with which to vibrate.
496   * @platform android
497   */
498  vibrate?: number[];
499  /**
500   * Relative priority for this notification. Priority is an indication of how much of the user's valuable attention should be consumed by this notification.
501   * Low-priority notifications may be hidden from the user in certain situations, while the user might be interrupted for a higher-priority notification.
502   * The system will make a determination about how to interpret this priority when presenting the notification.
503   * @platform android
504   */
505  priority?: string;
506  /**
507   * Accent color (in `#AARRGGBB` or `#RRGGBB` format) to be applied by the standard Style templates when presenting this notification.
508   * @platform android
509   */
510  color?: string;
511  /**
512   * If set to `true`, the notification cannot be dismissed by swipe. This setting defaults
513   * to `false` if not provided or is invalid. Corresponds directly do Android's `isOngoing` behavior.
514   * See [Android developer documentation](https://developer.android.com/reference/android/app/Notification.Builder#setOngoing(boolean))
515   * for more details.
516   * @platform android
517   */
518  autoDismiss?: boolean;
519  /**
520   * The identifier of the notification’s category.
521   * @platform ios
522   */
523  categoryIdentifier?: string;
524  /**
525   * If set to `false`, the notification will not be automatically dismissed when clicked.
526   * the setting used when the value is not provided or is invalid is `true` (the notification
527   * will be dismissed automatically). Corresponds directly to Android's `setAutoCancel`
528   * behavior. In Firebase terms this property of a notification is called `sticky`.
529   *
530   * See [Android developer documentation](https://developer.android.com/reference/android/app/Notification.Builder#setAutoCancel(boolean))
531   * and [Firebase documentation](https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages#AndroidNotification.FIELDS.sticky)
532   * for more details.
533   * @platform android
534   */
535  sticky?: boolean;
536  /**
537   * The visual and audio attachments to display alongside the notification’s main content.
538   * @platform ios
539   */
540  attachments?: NotificationContentAttachmentIos[];
541};
542
543/**
544 * An object represents a notification request you can pass into `scheduleNotificationAsync`.
545 */
546export interface NotificationRequestInput {
547  identifier?: string;
548  content: NotificationContentInput;
549  trigger: NotificationTriggerInput;
550}
551
552/**
553 * An object represents a single notification that has been triggered by some request ([`NotificationRequest`](#notificationrequest)) at some point in time.
554 */
555export interface Notification {
556  date: number;
557  request: NotificationRequest;
558}
559
560/**
561 * An object represents user's interaction with the notification.
562 * > **Note:** If the user taps on a notification `actionIdentifier` will be equal to [`Notifications.DEFAULT_ACTION_IDENTIFIER`](#notificationsdefault_action_identifier).
563 */
564export interface NotificationResponse {
565  notification: Notification;
566  actionIdentifier: string;
567  userText?: string;
568}
569
570/**
571 * An object represents behavior that should be applied to the incoming notification.
572 * > On Android, setting `shouldPlaySound: false` will result in the drop-down notification alert **not** showing, no matter what the priority is.
573 * > This setting will also override any channel-specific sounds you may have configured.
574 */
575export interface NotificationBehavior {
576  shouldShowAlert: boolean;
577  shouldPlaySound: boolean;
578  shouldSetBadge: boolean;
579  priority?: AndroidNotificationPriority;
580}
581
582export interface NotificationAction {
583  /**
584   * A unique string that identifies this action. If a user takes this action (for example, selects this button in the system's Notification UI),
585   * your app will receive this `actionIdentifier` via the [`NotificationResponseReceivedListener`](#addnotificationresponsereceivedlistenerlistener).
586   */
587  identifier: string;
588  /**
589   * The title of the button triggering this action.
590   */
591  buttonTitle: string;
592  /**
593   * Object which, if provided, will result in a button that prompts the user for a text response.
594   */
595  textInput?: {
596    /**
597     * A string which will be used as the title for the button used for submitting the text response.
598     * @platform ios
599     */
600    submitButtonTitle: string;
601    /**
602     * A string that serves as a placeholder until the user begins typing. Defaults to no placeholder string.
603     */
604    placeholder: string;
605  };
606  /**
607   * Object representing the additional configuration options.
608   */
609  options?: {
610    /**
611     * Boolean indicating whether the button title will be highlighted a different color (usually red).
612     * This usually signifies a destructive action such as deleting data.
613     * @platform ios
614     */
615    isDestructive?: boolean;
616    /**
617     * Boolean indicating whether triggering the action will require authentication from the user.
618     * @platform ios
619     */
620    isAuthenticationRequired?: boolean;
621    /**
622     * Boolean indicating whether triggering this action foregrounds the app.
623     * If `false` and your app is killed (not just backgrounded), [`NotificationResponseReceived` listeners](#addnotificationresponsereceivedlistenerlistener)
624     * will not be triggered when a user selects this action.
625     * @default true
626     */
627    opensAppToForeground?: boolean;
628  };
629}
630
631// @docsMissing
632export interface NotificationCategory {
633  identifier: string;
634  actions: NotificationAction[];
635  options?: NotificationCategoryOptions;
636}
637
638/**
639 * @platform ios
640 */
641export type NotificationCategoryOptions = {
642  /**
643   * Customizable placeholder for the notification preview text. This is shown if the user has disabled notification previews for the app.
644   * Defaults to the localized iOS system default placeholder (`Notification`).
645   */
646  previewPlaceholder?: string;
647  /**
648   * Array of [Intent Class Identifiers](https://developer.apple.com/documentation/sirikit/intent_class_identifiers). When a notification is delivered,
649   * the presence of an intent identifier lets the system know that the notification is potentially related to the handling of a request made through Siri.
650   * @default []
651   */
652  intentIdentifiers?: string[];
653  /**
654   * A format string for the summary description used when the system groups the category’s notifications.
655   */
656  categorySummaryFormat?: string;
657  /**
658   * A boolean indicating whether to send actions for handling when the notification is dismissed (the user must explicitly dismiss
659   * the notification interface - ignoring a notification or flicking away a notification banner does not trigger this action).
660   * @default false
661   */
662  customDismissAction?: boolean;
663  /**
664   * A boolean indicating whether to allow CarPlay to display notifications of this type. **Apps must be approved for CarPlay to make use of this feature.**
665   * @default false
666   */
667  allowInCarPlay?: boolean;
668  /**
669   * A boolean indicating whether to show the notification's title, even if the user has disabled notification previews for the app.
670   * @default false
671   */
672  showTitle?: boolean;
673  /**
674   * A boolean indicating whether to show the notification's subtitle, even if the user has disabled notification previews for the app.
675   * @default false
676   */
677  showSubtitle?: boolean;
678  /**
679   * A boolean indicating whether to allow notifications to be automatically read by Siri when the user is using AirPods.
680   * @default false
681   */
682  allowAnnouncement?: boolean;
683};
684
685export type { Subscription, PermissionResponse, PermissionStatus, PermissionExpiration };
686