Add support for multiple reminders

This commit is contained in:
2025-06-09 13:44:52 +02:00
parent 52dd10ac10
commit bff145d27f
6 changed files with 41 additions and 18 deletions

View File

@@ -74,13 +74,15 @@ delete = type:deleteIcon _ action:[a-zA-Z]+ {
/**************************************************************************************************************************************/ /**************************************************************************************************************************************/
reminder = reminderIcon _ time:(longTime / shortTime)? { reminder = reminderIcon _ time:(defaultTime / longTime / shortTime)|..,(_ "," _)| {
return { return {
feature: "reminder", feature: "reminder",
time time
} }
} }
defaultTime = "_"
longTime = hour:[0-9]|1..2| ":" minute:[0-9]|1..2| { longTime = hour:[0-9]|1..2| ":" minute:[0-9]|1..2| {
return `${hour.join("").padStart(2, '0')}:${minute.join("").padStart(2, '0')}`; return `${hour.join("").padStart(2, '0')}:${minute.join("").padStart(2, '0')}`;
} }

View File

@@ -16,14 +16,14 @@ const backends = [
export async function remind(config: Config, profileConfig: ProfileConfig, db: TaskDatabase) { export async function remind(config: Config, profileConfig: ProfileConfig, db: TaskDatabase) {
const now = dayjs().format("HH:mm"); const now = dayjs().format("HH:mm");
await run(config, profileConfig, db, db[now]); await run(config, profileConfig, db[now]);
if(profileConfig?.defaultTime && profileConfig?.defaultTime === now) { if(profileConfig?.defaultTime && profileConfig?.defaultTime === now) {
run(config, profileConfig, db, db.default); run(config, profileConfig, db._);
} }
} }
async function run(config: Config, profileConfig: ProfileConfig, db: TaskDatabase, tasks?: Task[]) { async function run(config: Config, profileConfig: ProfileConfig, tasks?: Task[]) {
if(!tasks) { if(!tasks) {
return; return;
} }

View File

@@ -1,6 +1,10 @@
import fs from "fs"; import fs from "fs";
import { Task, TaskDatabase } from "../types/task"; import { Task, TaskDatabase } from "../types/task";
type FlatReminder = {
task: Task;
time: string;
}
/** /**
* Applies the mapper for each task from list, groups them by time and dumps the data into JSON formatted file. * Applies the mapper for each task from list, groups them by time and dumps the data into JSON formatted file.
@@ -21,12 +25,29 @@ export function serializeDatabase(tasks: Task[]): string {
* Applies the mapper for each task from list and groups them by time. * Applies the mapper for each task from list and groups them by time.
*/ */
export function createDatabase(tasks: Task[]): TaskDatabase { export function createDatabase(tasks: Task[]): TaskDatabase {
return tasks
return tasks.filter(t => t.reminder).reduce((acc, t) => { .flatMap(flatTimes)
if (t.reminder) { .reduce(pushTaskToDatabase, {} as TaskDatabase);
(acc[t.reminder] = (acc[t.reminder] || [])).push(t);
};
return acc;
}, {} as TaskDatabase);
} }
/**
* Returns list pairs of input task and consecutive reminder times.
* If reminder is missing, returns empty array.
* If reminder is empty array, returns ['_'], where '_' designates the default time.
* @param task input task
* @returns list pairs of input task and consecutive reminder times
*/
function flatTimes(task: Task): FlatReminder[] {
if (task.reminder === undefined) {
return [];
}
return task.reminder.length === 0
? [{ task, time: '_' }]
: task.reminder.map(time => ({ task, time }));
}
function pushTaskToDatabase(db: TaskDatabase, { task, time }: FlatReminder): TaskDatabase {
(db[time] = db[time] ?? []).push(task);
return db;
}

View File

@@ -128,11 +128,11 @@ export class DynamicTask implements Task {
return this.#features<ParsedTaskDependency>("dependency").find(x => x.type === '⛔')?.deps || []; return this.#features<ParsedTaskDependency>("dependency").find(x => x.type === '⛔')?.deps || [];
} }
get reminder(): string|undefined { get reminder(): string[]|undefined {
const feature = this.parsed.meta.find(x => x.feature === 'reminder'); const feature = this.parsed.meta.find(x => x.feature === 'reminder');
if (feature) { if (feature) {
return feature.time || "default"; return feature.time;
} }
return undefined; return undefined;
@@ -209,7 +209,7 @@ export class DynamicTask implements Task {
o("delete", this.onDelete), o("delete", this.onDelete),
o("id", this.id), o("id", this.id),
o("deps", this.dependsOn?.join(",")), o("deps", this.dependsOn?.join(",")),
o("reminder", this.reminder), o("reminder", this.reminder?.join(",")),
o("tags", this.tags.join(",")) o("tags", this.tags.join(","))
]; ];
@@ -255,7 +255,7 @@ export class DynamicTask implements Task {
break; break;
case 'reminder': case 'reminder':
segments.push(['⏰', meta.time ?? ""]); segments.push(['⏰', meta.time.join(",")]);
break; break;
case 'recurrence': case 'recurrence':

View File

@@ -54,5 +54,5 @@ export type ParsedTaskDependency = {
export type ParsedTaskReminder = { export type ParsedTaskReminder = {
feature: 'reminder'; feature: 'reminder';
time: string; time: string[];
} }

View File

@@ -17,7 +17,7 @@ export type Task = {
onDelete?: string; onDelete?: string;
id?: string; id?: string;
dependsOn?: string[]; dependsOn?: string[];
reminder?: string; reminder?: string[];
sourceFile: string; sourceFile: string;
sourceLine: number; sourceLine: number;
source: string; source: string;