Description
I'm writing up the usage guide now (see #2477), and quickly found that scheduling repeating notifications is complicated. I'm sure this is at least partially historical, but users have three methods to choose from:
zonedSchedule()
, with a non-nullmatchDateTimeComponents
periodicallyShow()
, with a givenRepeatInterval
periodicallyShowWithDuration()
, with a givenDuration
Fundamentally, there are four ways to show a scheduled notification:
- show once
- show then repeat given certain conditions, like date, day of week, etc
- show then repeat on a given interval
The differences between the methods
From what I can tell, the main difference between zonedSchedule()
and periodicallyShow()
is that periodicallyShow()
starts now, whereas zonedSchedule()
takes a TZDateTime
parameter. It's true that UNTimeIntervalNotificationTrigger
doesn't take in a date/time to start the timer and starts immediately. So there's no way to say "send a notification every 30 minutes, starting in 2 hours from now".
To get around this, we can use an approach similar to Android, where we schedule a background task for the given date and time, which then schedules the first UNTimeIntervalNotificationTrigger
.
The only difference between periodicallyShow()
and periodicallyShowWithDuration()
is the ability to pass an arbitrary duration, but Android, iOS, and MacOS support an arbitrary duration, so we should just always allow an arbitrary duration, preferring Duration(days: 1)
to RepeatInterval.daily
. In fact, on Android and Darwin, the enum is converted to milliseconds, and on Linux and Windows periodic notifications are not supported at all.
New proposal
sealed class NotificationRepeatDetails { }
class NotificationRepeatInterval extends NotificationRepeatDetails {
Duration duration;
}
class NotificationRepeatDate extends NotificationRepeatDetails {
DateTimeComponents components;
}
void schedule({
required int id,
required TZDateTime scheduleDateTime,
String? title,
String? body,
String? payload,
NotificationDetails? details,
NotificationRepeatDetails? repeatsOn,
);
Since this will be a breaking change anyway, I renamed some parameters. I removed uiLocalNotificationDateInterpretation
since it only applies to devices running iOS 10 or earlier, but Flutter hasn't supported those versions since Flutter 3.13, and this plugin only supports Flutter ^3.19. I also think we should move androidScheduleMode
to be an optional parameter on AndroidNotificationDetails()
, defaulting to something reasonable like .inexact
, but I can see an argument not to since it doesn't apply to show()
.
Examples
final location = getLocation(...);
final now = TZDateTime.now(location);
// Schedule a notification tomorrow at 8 pm
plugin.schedule(
id: 0,
scheduledDateTime: now.copyWith(hour: 20, minute: 00),
// title, body, details
);
// Schedule a repeating reminder, every day at noon
plugin.schedule(
id: 1,
scheduledDateTime: now.copyWith(hour: 12, minute: 00),
repeatsOn: NotificationRepeatDate(DateTimeComponents.time),
// title, body, details
);
// Schedule a reminder every 30 minutes to take a break, starting in 30 minutes from now
plugin.schedule(
id: 2,
scheduledDateTime: now.add(Duration(minutes: 30)),
repeatsOn: NotificationRepeatInterval(Duration(minutes: 30)),
// title, body, details
);
@MaikuB What are your thoughts on implementing this for v20? It is breaking but it would significantly simplify the API, favoring one method over three, and rid us of a lot of unused code. Again, I'd be happy to contribute a PR