[READ-ONLY] Mirror of https://github.com/probablykasper/notifier. Android app for scheduling notifications
android
app
flutter
notifications
1import 'dart:convert' show json;
2import 'package:awesome_notifications/awesome_notifications.dart'
3 show
4 AwesomeNotifications,
5 NotificationCalendar,
6 NotificationContent,
7 NotificationSchedule;
8
9abstract class Repeat {
10 static const never = "never";
11 static const daily = "daily";
12 static const weekly = "weekly";
13 static const monthly = "monthly";
14 static const yearly = "yearly";
15}
16
17defaultDate() {
18 var now = DateTime.now();
19 return DateTime(now.year, now.month, now.day, now.hour + 2);
20}
21
22class NotificationItem {
23 String title;
24 String description;
25 bool disabled;
26 String repeat;
27 int repeatEvery;
28 List<bool> weekdays;
29 DateTime originalDate;
30 DateTime? lastScheduledDate;
31 // bool noSwipeAway;
32
33 NotificationItem({
34 required this.title,
35 required this.description,
36 required this.disabled,
37 required this.repeat,
38 required this.repeatEvery,
39 required this.weekdays,
40 required this.originalDate,
41 required this.lastScheduledDate,
42 });
43 NotificationItem.defaultWith({
44 String? title,
45 String? description,
46 bool? disabled,
47 String? repeat,
48 int? repeatEvery,
49 List<bool>? weekdays,
50 DateTime? originalDate,
51 this.lastScheduledDate,
52 }) : title = title ?? '',
53 description = description ?? '',
54 disabled = disabled ?? false,
55 repeat = repeat ?? Repeat.never,
56 repeatEvery = repeatEvery ?? 1,
57 weekdays =
58 weekdays ?? [false, false, false, false, false, false, false],
59 originalDate = originalDate ?? defaultDate();
60
61 factory NotificationItem.getDefault() {
62 return NotificationItem.defaultWith();
63 }
64
65 DateTime getLatestDate() {
66 return lastScheduledDate ?? originalDate;
67 }
68
69 bool timeHasPassed() {
70 return getLatestDate().millisecondsSinceEpoch <
71 DateTime.now().millisecondsSinceEpoch;
72 }
73
74 factory NotificationItem.fromJson(String str) {
75 var map = json.decode(str);
76 return NotificationItem(
77 title: map['title'],
78 description: map['description'],
79 disabled: map['disabled'],
80 repeat: map['repeat'],
81 repeatEvery: map['repeatEvery'],
82 weekdays: List<bool>.from(map['weekdays']),
83 originalDate: DateTime.fromMillisecondsSinceEpoch(map['originalDate']),
84 lastScheduledDate: map['lastDate'] == null
85 ? null
86 : DateTime.fromMillisecondsSinceEpoch(map['lastDate']),
87 );
88 }
89
90 String toJson() {
91 Map<String, dynamic> map = {
92 'title': title,
93 'description': description,
94 'disabled': disabled,
95 'repeat': repeat,
96 'repeatEvery': repeatEvery,
97 'weekdays': weekdays,
98 'originalDate': originalDate.millisecondsSinceEpoch,
99 'lastDate': lastScheduledDate?.millisecondsSinceEpoch,
100 };
101 return json.encode(map);
102 }
103
104 // Get the next date from the last scheduled date
105 DateTime? _getDirectlyNextDate(DateTime? fromDate) {
106 if (fromDate == null) {
107 return originalDate;
108 } else if (fromDate.isAfter(DateTime.now())) {
109 return fromDate;
110 } else if (repeat == Repeat.never) {
111 return null;
112 } else if (repeat == Repeat.daily) {
113 return DateTime(
114 fromDate.year,
115 fromDate.month,
116 fromDate.day + repeatEvery,
117 originalDate.hour,
118 originalDate.minute,
119 originalDate.second,
120 originalDate.millisecond);
121 } else if (repeat == Repeat.weekly) {
122 var newDay = fromDate.day;
123 final fromZeroBasedWeekday = fromDate.weekday - 1;
124
125 // find the next checked weekday in the "current" week
126 final nextCheckedWeekday =
127 weekdays.indexOf(true, fromZeroBasedWeekday + 1);
128
129 if (nextCheckedWeekday >= 0) {
130 newDay += nextCheckedWeekday - fromZeroBasedWeekday;
131 } else {
132 // if the next date is not in this week
133
134 // go back to monday
135 newDay -= fromZeroBasedWeekday;
136 // go to next week
137 newDay += 7 * repeatEvery;
138
139 // go to first checked weekday
140 final firstCheckedWeekday = weekdays.indexOf(true);
141 if (firstCheckedWeekday >= 0) {
142 newDay += firstCheckedWeekday;
143 } else {
144 // if no weekday is checked, go to the originalDate weekday
145 newDay += originalDate.weekday - 1;
146 }
147 }
148
149 return DateTime(
150 fromDate.year,
151 fromDate.month,
152 newDay,
153 originalDate.hour,
154 originalDate.minute,
155 originalDate.second,
156 originalDate.millisecond,
157 );
158 } else if (repeat == Repeat.monthly) {
159 return DateTime(
160 fromDate.year,
161 fromDate.month + repeatEvery,
162 originalDate.day,
163 originalDate.hour,
164 originalDate.minute,
165 originalDate.second,
166 originalDate.millisecond);
167 } else if (repeat == Repeat.yearly) {
168 return DateTime(
169 fromDate.year + repeatEvery,
170 originalDate.month,
171 originalDate.day,
172 originalDate.hour,
173 originalDate.minute,
174 originalDate.second,
175 originalDate.millisecond);
176 } else {
177 // never happens
178 return null;
179 }
180 }
181
182 DateTime? testGetDirectlyNextDate() {
183 return _getDirectlyNextDate(lastScheduledDate);
184 }
185
186 /// Get the next date for scheduling a notification.
187 /// Returns null for already scheduled non-repeating dates.
188 DateTime? getNextNotificationDate() {
189 var directlyNextDate = _getDirectlyNextDate(lastScheduledDate);
190 if (directlyNextDate == null) {
191 return null;
192 }
193 // If the next date is far in the past, skip forward to the most recent date,
194 // but not into the future because then we could be
195 var now = DateTime.now();
196 var nextDate = directlyNextDate;
197 while (nextDate.isBefore(now)) {
198 var nextNextDate = _getDirectlyNextDate(nextDate);
199 if (nextNextDate != null && nextNextDate.isBefore(now)) {
200 nextDate = nextNextDate;
201 } else {
202 break;
203 }
204 }
205 return nextDate;
206 }
207
208 /// Get the next date for scheduling a notification, but only in the future.
209 /// Returns null for already scheduled non-repeating dates.
210 DateTime? getNextFutureDate() {
211 var directlyNextDate = _getDirectlyNextDate(lastScheduledDate);
212 if (directlyNextDate == null) {
213 return null;
214 }
215 // If the next date is far in the past, skip forward to the most recent date,
216 // but not into the future because then we could be
217 var now = DateTime.now();
218 var nextDate = directlyNextDate;
219 while (nextDate.isBefore(now)) {
220 var nextNextDate = _getDirectlyNextDate(nextDate);
221 if (nextNextDate != null) {
222 nextDate = nextNextDate;
223 } else {
224 break;
225 }
226 }
227 return nextDate;
228 }
229
230 scheduleAt(int id, DateTime date) {
231 NotificationSchedule? schedule;
232 if (date.isAfter(DateTime.now())) {
233 schedule = NotificationCalendar(
234 year: date.year,
235 month: date.month,
236 day: date.day,
237 hour: date.hour,
238 minute: date.minute,
239 second: date.second,
240 preciseAlarm: true,
241 allowWhileIdle: true,
242 );
243 }
244 AwesomeNotifications().createNotification(
245 content: NotificationContent(
246 id: id,
247 channelKey: 'scheduled_notifications',
248 title: title,
249 body: description,
250 ),
251 schedule: schedule,
252 );
253 }
254}