fix(todo): the permission to notify asked wherever a reminder is planned, and Settings saying while it is off (ADR 0033, D31)
On a fresh install Todo's reminders never showed: the permission to notify (Android 13's POST_NOTIFICATIONS, iOS' and macOS' alert) was asked only where a task's sheet chose its first reminder, so reminders typed in quick add, added by the automatic reminder or brought by sync were scheduled and dropped by the system without a word. Now NotificationAccess, the device's, reads whether notifications are allowed whenever the plan holds a reminder and asks where they aren't, once an app start, so that a refusal isn't met with the dialog again and again; the task sheet asks through it. While reminders are planned and notifications are off, Settings' Reminders say so, with Turn on: asked again, and where that doesn't allow it, the system's notification settings of the app opened (flutter_local_notifications' own call, nothing added). Read again whenever the app comes back. Whats-New: Todo asks to notify as soon as there is a reminder, and Settings › Reminders shows when notifications are off, with Turn on. Whats-New-De: Todo fragt nach Benachrichtigungen, sobald es eine Erinnerung gibt, und Einstellungen › Erinnerungen zeigt, wenn sie aus sind, mit Einschalten. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
d49331b210
commit
82f1bf2739
2 changed files with 458 additions and 33 deletions
|
|
@ -3926,6 +3926,146 @@ void main() {
|
|||
);
|
||||
});
|
||||
});
|
||||
|
||||
group('Notifications asked for wherever a reminder is planned (D31)', () {
|
||||
/// Whether Settings' Reminders say that notifications are off.
|
||||
Finder off() => find.text('Notifications are off');
|
||||
|
||||
testWidgets('a reminder typed in quick add asks to notify, once an '
|
||||
'app start, however many follow', (tester) async {
|
||||
reminders.allowed = false;
|
||||
await start(tester, usedBefore: true);
|
||||
expect(reminders.asked, 0, reason: 'nothing to remind of yet');
|
||||
await goTab(tester, 'Inbox');
|
||||
|
||||
await quickAdd(tester, 'Leave !30m');
|
||||
expect(reminders.scheduled, hasLength(1));
|
||||
expect(reminders.asked, 1);
|
||||
|
||||
await quickAdd(tester, 'Call back !1h');
|
||||
expect(reminders.scheduled, hasLength(2));
|
||||
expect(reminders.asked, 1, reason: 'refused once, not asked again');
|
||||
});
|
||||
|
||||
testWidgets('the automatic reminder of a task given a time asks to '
|
||||
'notify', (tester) async {
|
||||
await start(tester, usedBefore: true);
|
||||
await tester.runAsync(
|
||||
() => SettingsRepository(settingsRows, keys).write(
|
||||
const TodoSettings(reminders: ReminderSettings(automatic: 15)),
|
||||
),
|
||||
);
|
||||
settingsRows.bringRemoteChanges();
|
||||
await tester.pumpAndSettle();
|
||||
await goTab(tester, 'Inbox');
|
||||
|
||||
await quickAdd(tester, 'Call tomorrow 9am');
|
||||
|
||||
expect(reminders.scheduled, hasLength(1));
|
||||
expect(reminders.asked, 1);
|
||||
expect(reminders.enabled, isTrue);
|
||||
});
|
||||
|
||||
testWidgets('a reminder another device synced asks to notify; nothing '
|
||||
'is asked where none is planned', (tester) async {
|
||||
final tomorrow = Day.of(DateTime.now()).plus(1);
|
||||
await start(tester, usedBefore: true);
|
||||
await seed(
|
||||
tester,
|
||||
TaskContent(
|
||||
title: 'Call the bank',
|
||||
projectId: inbox(),
|
||||
date: TaskDate(tomorrow, time: 14 * 60),
|
||||
),
|
||||
);
|
||||
await goTab(tester, 'Inbox');
|
||||
await quickAdd(tester, 'Buy milk');
|
||||
expect(reminders.asked, 0, reason: 'nothing to remind of');
|
||||
await openSettings(tester);
|
||||
expect(off(), findsNothing, reason: 'no reminder needs them');
|
||||
await tester.pageBack();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await seed(
|
||||
tester,
|
||||
TaskContent(
|
||||
title: 'Dentist',
|
||||
projectId: inbox(),
|
||||
date: TaskDate(tomorrow, time: 9 * 60),
|
||||
reminders: const [30],
|
||||
),
|
||||
);
|
||||
|
||||
expect(reminders.asked, 1);
|
||||
});
|
||||
|
||||
testWidgets("refused, Settings' Reminders say notifications are off; "
|
||||
"Turn on asks again, then opens the system's settings, and "
|
||||
'notifications allowed there count once Todo is back', (
|
||||
tester,
|
||||
) async {
|
||||
final tomorrow = Day.of(DateTime.now()).plus(1);
|
||||
reminders.allowed = false;
|
||||
await start(tester, usedBefore: true);
|
||||
await seed(
|
||||
tester,
|
||||
TaskContent(
|
||||
title: 'Dentist',
|
||||
projectId: inbox(),
|
||||
date: TaskDate(tomorrow, time: 9 * 60),
|
||||
reminders: const [30],
|
||||
),
|
||||
);
|
||||
expect(reminders.asked, 1);
|
||||
|
||||
await openSettings(tester);
|
||||
expect(off(), findsOneWidget);
|
||||
await tester.tap(find.widgetWithText(FilledButton, 'Turn on'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(reminders.asked, 2);
|
||||
expect(
|
||||
reminders.openedSettings,
|
||||
1,
|
||||
reason: 'refused again, or the system no longer asks',
|
||||
);
|
||||
expect(off(), findsOneWidget);
|
||||
|
||||
// Allowed in the system's settings, then back to Todo.
|
||||
reminders.enabled = true;
|
||||
tester.binding
|
||||
..handleAppLifecycleStateChanged(AppLifecycleState.inactive)
|
||||
..handleAppLifecycleStateChanged(AppLifecycleState.resumed);
|
||||
await tester.pumpAndSettle();
|
||||
expect(off(), findsNothing);
|
||||
expect(reminders.asked, 2);
|
||||
});
|
||||
|
||||
testWidgets('Turn on allowed asks no more and opens nothing', (
|
||||
tester,
|
||||
) async {
|
||||
final tomorrow = Day.of(DateTime.now()).plus(1);
|
||||
reminders.allowed = false;
|
||||
await start(tester, usedBefore: true);
|
||||
await seed(
|
||||
tester,
|
||||
TaskContent(
|
||||
title: 'Dentist',
|
||||
projectId: inbox(),
|
||||
date: TaskDate(tomorrow, time: 9 * 60),
|
||||
reminders: const [30],
|
||||
),
|
||||
);
|
||||
await openSettings(tester);
|
||||
|
||||
reminders.allowed = true;
|
||||
await tester.tap(find.widgetWithText(FilledButton, 'Turn on'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(reminders.asked, 2);
|
||||
expect(reminders.openedSettings, 0);
|
||||
expect(off(), findsNothing);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
group("Upcoming's strip (ADR 0033, D8, D14)", () {
|
||||
|
|
|
|||
|
|
@ -15,9 +15,17 @@ class MemoryReminderGateway() implements ReminderGateway {
|
|||
/// What the person answers when asked.
|
||||
bool allowed = true;
|
||||
|
||||
/// Whether the app may notify now: not on a fresh install until the
|
||||
/// person is asked and allows it (Android 13 on, iOS, macOS), or allows
|
||||
/// it in the system's settings meanwhile.
|
||||
bool enabled = false;
|
||||
|
||||
/// How often they were asked.
|
||||
int asked = 0;
|
||||
|
||||
/// How often the system's notification settings of the app were opened.
|
||||
int openedSettings = 0;
|
||||
|
||||
@override
|
||||
Future<void> replace(
|
||||
List<ReminderNotice> notices, {
|
||||
|
|
@ -29,9 +37,17 @@ class MemoryReminderGateway() implements ReminderGateway {
|
|||
replaced++;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> notificationsAllowed() async => enabled;
|
||||
|
||||
@override
|
||||
Future<bool> askPermission() async {
|
||||
asked++;
|
||||
return allowed;
|
||||
return enabled = allowed;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> openSettings() async {
|
||||
openedSettings++;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue