Prepare for reminding
This commit is contained in:
parent
c1c0ced266
commit
aebbcd7815
5 changed files with 124 additions and 5 deletions
96
src/reminder.rs
Normal file
96
src/reminder.rs
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
use crate::task;
|
||||
use crate::util;
|
||||
|
||||
use anyhow::Context as _;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum BatchingInterval {
|
||||
Monthly,
|
||||
Weekly,
|
||||
OnTheDay,
|
||||
}
|
||||
|
||||
pub async fn remind_due_tasks(ctx: &crate::Context, tasks: &[task::Task]) -> anyhow::Result<()> {
|
||||
for task in tasks {
|
||||
let Some(due_date) = task.state.due_date_if_open() else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let batching_interval = find_batching_interval(ctx, due_date, task);
|
||||
log::debug!("Reminding {task} with interval {batching_interval:?}.");
|
||||
|
||||
if !is_time_to_remind(ctx, due_date, batching_interval) {
|
||||
log::debug!("Not yet time, skipping.");
|
||||
continue;
|
||||
}
|
||||
|
||||
if is_overdue(ctx, due_date) {
|
||||
log::info!("Task {task} is already overdue!");
|
||||
}
|
||||
|
||||
log::warn!("TODO: Remind {task}");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn find_batching_interval(
|
||||
ctx: &crate::Context,
|
||||
due_date: &jiff::Zoned,
|
||||
task: &task::Task,
|
||||
) -> BatchingInterval {
|
||||
let time_until_due = due_date - &ctx.timestamp;
|
||||
|
||||
if let Some(recurring) = &task.recurring {
|
||||
match &recurring.interval {
|
||||
task::RecurringInterval::Months(_) => BatchingInterval::Monthly,
|
||||
task::RecurringInterval::Weeks(_) => BatchingInterval::Weekly,
|
||||
task::RecurringInterval::Days(_) => BatchingInterval::OnTheDay,
|
||||
}
|
||||
} else {
|
||||
// For tasks that are not recurring, the batching interval is determined based on how
|
||||
// far in the future the task is due.
|
||||
|
||||
let weeks_until_due = time_until_due
|
||||
.total((jiff::Unit::Week, jiff::SpanRelativeTo::days_are_24_hours()))
|
||||
.unwrap();
|
||||
if weeks_until_due >= 3. {
|
||||
BatchingInterval::Monthly
|
||||
} else if weeks_until_due >= 1. {
|
||||
BatchingInterval::Weekly
|
||||
} else {
|
||||
BatchingInterval::OnTheDay
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_time_to_remind(
|
||||
ctx: &crate::Context,
|
||||
due_date: &jiff::Zoned,
|
||||
batching_interval: BatchingInterval,
|
||||
) -> bool {
|
||||
let batch_time = match batching_interval {
|
||||
BatchingInterval::Monthly => due_date.first_of_month().unwrap(),
|
||||
BatchingInterval::Weekly => start_of_week(due_date).unwrap(),
|
||||
BatchingInterval::OnTheDay => due_date.clone(),
|
||||
};
|
||||
|
||||
let batch_time = batch_time
|
||||
.round(
|
||||
jiff::ZonedRound::new()
|
||||
.smallest(jiff::Unit::Day)
|
||||
.mode(jiff::RoundMode::Floor),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
ctx.timestamp >= batch_time
|
||||
}
|
||||
|
||||
fn is_overdue(ctx: &crate::Context, due_date: &jiff::Zoned) -> bool {
|
||||
&ctx.timestamp >= due_date
|
||||
}
|
||||
|
||||
fn start_of_week(t: &jiff::Zoned) -> anyhow::Result<jiff::Zoned> {
|
||||
Ok(t.tomorrow()?
|
||||
.nth_weekday(-1, jiff::civil::Weekday::Monday)?)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue