feat(todo): reminders on the device, Upcoming's week strip, the task pane and search (ADR 0033, D2, D5, D8)

A task with a time takes reminders, minutes before it, in its sealed
payload; each device plans the coming ones whenever the tasks change and
schedules them with the system through flutter_local_notifications
(Android, iOS, macOS, Windows; on Linux the running app shows them), at
the minute where Android allows exact alarms. Notifying is asked for
when a task first gets a reminder; signing out or switching person
cancels them. Upcoming gets its week strip: the month opening
Material's calendar, the weeks before and after, a dot under each day
with tasks; a day picked scrolls the agenda to it, and scrolling moves
the strip along. From expanded windows on, a task opens in a pane
beside the list rather than in a dialog. Search, from every tab's app
bar, finds projects by name and tasks by every word typed, in their
title, description or labels, whatever the case and accents, on the
device alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-11-01 12:16:19 +01:00
commit 666e8dbcbb
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64
5 changed files with 2140 additions and 57 deletions

View file

@ -119,5 +119,23 @@
"repeatEnds": "Endet",
"repeatEndsNever": "Nie",
"repeatEndsOn": "An einem Tag",
"repeatEndsAfter": "{count, plural, =1{Nach einem Mal} other{Nach {count} Malen}}"
"repeatEndsAfter": "{count, plural, =1{Nach einem Mal} other{Nach {count} Malen}}",
"remindersTitle": "Erinnerungen",
"remindersNone": "Keine Erinnerungen",
"reminderAtTime": "Zur Uhrzeit",
"reminderMinutesBefore": "{count, plural, =1{1 Minute vorher} other{{count} Minuten vorher}}",
"reminderHoursBefore": "{count, plural, =1{1 Stunde vorher} other{{count} Stunden vorher}}",
"reminderDaysBefore": "{count, plural, =1{1 Tag vorher} other{{count} Tage vorher}}",
"reminderDue": "Fällig um {time}",
"remindersChannel": "Erinnerungen an Aufgaben",
"remindersNotAllowed": "Benachrichtigungen sind für Halkyon Todo aus: Erinnerungen erscheinen, sobald du sie in den Systemeinstellungen erlaubst.",
"remindersOnThisDevice": "Erinnerungen kommen auf jedem deiner Geräte, das deine Aufgaben öffnet.",
"weekPrevious": "Vorige Woche",
"weekNext": "Folgende Woche",
"searchTitle": "Suchen",
"searchHint": "Aufgaben und Projekte suchen",
"searchEmpty": "Finde eine Aufgabe über die Wörter in ihrem Titel, ihrer Beschreibung oder ihren Labels. Die Suche läuft auf diesem Gerät: deine Instanz kann deine Aufgaben nicht lesen.",
"searchNone": "Nichts gefunden für „{query}“.",
"searchProjects": "Projekte",
"searchTasks": "Aufgaben"
}

View file

@ -144,5 +144,28 @@
"repeatEndsNever": "Never",
"repeatEndsOn": "On a day",
"repeatEndsAfter": "{count, plural, =1{After once} other{After {count} times}}",
"@repeatEndsAfter": {"placeholders": {"count": {"type": "int"}}}
"@repeatEndsAfter": {"placeholders": {"count": {"type": "int"}}},
"remindersTitle": "Reminders",
"remindersNone": "No reminders",
"reminderAtTime": "At its time",
"reminderMinutesBefore": "{count, plural, =1{1 minute before} other{{count} minutes before}}",
"@reminderMinutesBefore": {"placeholders": {"count": {"type": "int"}}},
"reminderHoursBefore": "{count, plural, =1{1 hour before} other{{count} hours before}}",
"@reminderHoursBefore": {"placeholders": {"count": {"type": "int"}}},
"reminderDaysBefore": "{count, plural, =1{1 day before} other{{count} days before}}",
"@reminderDaysBefore": {"placeholders": {"count": {"type": "int"}}},
"reminderDue": "Due at {time}",
"@reminderDue": {"placeholders": {"time": {"type": "String"}}},
"remindersChannel": "Task reminders",
"remindersNotAllowed": "Notifications are off for Halkyon Todo: reminders show once you allow them in the system's settings.",
"remindersOnThisDevice": "Reminders come on each of your devices that opens your tasks.",
"weekPrevious": "Previous week",
"weekNext": "Following week",
"searchTitle": "Search",
"searchHint": "Search tasks and projects",
"searchEmpty": "Find a task by the words in its title, its description or its labels. Search runs on this device: your instance can't read your tasks.",
"searchNone": "Nothing found for “{query}”.",
"@searchNone": {"placeholders": {"query": {"type": "String"}}},
"searchProjects": "Projects",
"searchTasks": "Tasks"
}

View file

@ -783,6 +783,114 @@ abstract class AppLocalizations {
/// In en, this message translates to:
/// **'{count, plural, =1{After once} other{After {count} times}}'**
String repeatEndsAfter(int count);
/// No description provided for @remindersTitle.
///
/// In en, this message translates to:
/// **'Reminders'**
String get remindersTitle;
/// No description provided for @remindersNone.
///
/// In en, this message translates to:
/// **'No reminders'**
String get remindersNone;
/// No description provided for @reminderAtTime.
///
/// In en, this message translates to:
/// **'At its time'**
String get reminderAtTime;
/// No description provided for @reminderMinutesBefore.
///
/// In en, this message translates to:
/// **'{count, plural, =1{1 minute before} other{{count} minutes before}}'**
String reminderMinutesBefore(int count);
/// No description provided for @reminderHoursBefore.
///
/// In en, this message translates to:
/// **'{count, plural, =1{1 hour before} other{{count} hours before}}'**
String reminderHoursBefore(int count);
/// No description provided for @reminderDaysBefore.
///
/// In en, this message translates to:
/// **'{count, plural, =1{1 day before} other{{count} days before}}'**
String reminderDaysBefore(int count);
/// No description provided for @reminderDue.
///
/// In en, this message translates to:
/// **'Due at {time}'**
String reminderDue(String time);
/// No description provided for @remindersChannel.
///
/// In en, this message translates to:
/// **'Task reminders'**
String get remindersChannel;
/// No description provided for @remindersNotAllowed.
///
/// In en, this message translates to:
/// **'Notifications are off for Halkyon Todo: reminders show once you allow them in the system\'s settings.'**
String get remindersNotAllowed;
/// No description provided for @remindersOnThisDevice.
///
/// In en, this message translates to:
/// **'Reminders come on each of your devices that opens your tasks.'**
String get remindersOnThisDevice;
/// No description provided for @weekPrevious.
///
/// In en, this message translates to:
/// **'Previous week'**
String get weekPrevious;
/// No description provided for @weekNext.
///
/// In en, this message translates to:
/// **'Following week'**
String get weekNext;
/// No description provided for @searchTitle.
///
/// In en, this message translates to:
/// **'Search'**
String get searchTitle;
/// No description provided for @searchHint.
///
/// In en, this message translates to:
/// **'Search tasks and projects'**
String get searchHint;
/// No description provided for @searchEmpty.
///
/// In en, this message translates to:
/// **'Find a task by the words in its title, its description or its labels. Search runs on this device: your instance can\'t read your tasks.'**
String get searchEmpty;
/// No description provided for @searchNone.
///
/// In en, this message translates to:
/// **'Nothing found for “{query}”.'**
String searchNone(String query);
/// No description provided for @searchProjects.
///
/// In en, this message translates to:
/// **'Projects'**
String get searchProjects;
/// No description provided for @searchTasks.
///
/// In en, this message translates to:
/// **'Tasks'**
String get searchTasks;
}
class _AppLocalizationsDelegate

View file

@ -467,4 +467,89 @@ class AppLocalizationsDe extends AppLocalizations {
);
return '$_temp0';
}
@override
String get remindersTitle => 'Erinnerungen';
@override
String get remindersNone => 'Keine Erinnerungen';
@override
String get reminderAtTime => 'Zur Uhrzeit';
@override
String reminderMinutesBefore(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count Minuten vorher',
one: '1 Minute vorher',
);
return '$_temp0';
}
@override
String reminderHoursBefore(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count Stunden vorher',
one: '1 Stunde vorher',
);
return '$_temp0';
}
@override
String reminderDaysBefore(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count Tage vorher',
one: '1 Tag vorher',
);
return '$_temp0';
}
@override
String reminderDue(String time) {
return 'Fällig um $time';
}
@override
String get remindersChannel => 'Erinnerungen an Aufgaben';
@override
String get remindersNotAllowed =>
'Benachrichtigungen sind für Halkyon Todo aus: Erinnerungen erscheinen, sobald du sie in den Systemeinstellungen erlaubst.';
@override
String get remindersOnThisDevice =>
'Erinnerungen kommen auf jedem deiner Geräte, das deine Aufgaben öffnet.';
@override
String get weekPrevious => 'Vorige Woche';
@override
String get weekNext => 'Folgende Woche';
@override
String get searchTitle => 'Suchen';
@override
String get searchHint => 'Aufgaben und Projekte suchen';
@override
String get searchEmpty =>
'Finde eine Aufgabe über die Wörter in ihrem Titel, ihrer Beschreibung oder ihren Labels. Die Suche läuft auf diesem Gerät: deine Instanz kann deine Aufgaben nicht lesen.';
@override
String searchNone(String query) {
return 'Nichts gefunden für „$query“.';
}
@override
String get searchProjects => 'Projekte';
@override
String get searchTasks => 'Aufgaben';
}

View file

@ -467,6 +467,91 @@ class AppLocalizationsEn extends AppLocalizations {
);
return '$_temp0';
}
@override
String get remindersTitle => 'Reminders';
@override
String get remindersNone => 'No reminders';
@override
String get reminderAtTime => 'At its time';
@override
String reminderMinutesBefore(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count minutes before',
one: '1 minute before',
);
return '$_temp0';
}
@override
String reminderHoursBefore(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count hours before',
one: '1 hour before',
);
return '$_temp0';
}
@override
String reminderDaysBefore(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count days before',
one: '1 day before',
);
return '$_temp0';
}
@override
String reminderDue(String time) {
return 'Due at $time';
}
@override
String get remindersChannel => 'Task reminders';
@override
String get remindersNotAllowed =>
'Notifications are off for Halkyon Todo: reminders show once you allow them in the system\'s settings.';
@override
String get remindersOnThisDevice =>
'Reminders come on each of your devices that opens your tasks.';
@override
String get weekPrevious => 'Previous week';
@override
String get weekNext => 'Following week';
@override
String get searchTitle => 'Search';
@override
String get searchHint => 'Search tasks and projects';
@override
String get searchEmpty =>
'Find a task by the words in its title, its description or its labels. Search runs on this device: your instance can\'t read your tasks.';
@override
String searchNone(String query) {
return 'Nothing found for “$query”.';
}
@override
String get searchProjects => 'Projects';
@override
String get searchTasks => 'Tasks';
}
/// The translations for English, as used in the United Kingdom (`en_GB`).