102 lines
3.1 KiB
Rust
102 lines
3.1 KiB
Rust
// SPDX-FileCopyrightText: 2022 Matteo Settenvini <matteo.settenvini@montecristosoftware.eu>
|
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
use {
|
|
crate::constants,
|
|
crate::recipe::Recipe,
|
|
chrono::{DateTime, Datelike, Local, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc},
|
|
ics::escape_text,
|
|
ics::properties as calprop,
|
|
ics::Event as CalEvent,
|
|
std::rc::Rc,
|
|
};
|
|
|
|
pub struct Event {
|
|
pub uid: String,
|
|
pub ends_at: NaiveDateTime,
|
|
pub recipe: Rc<Recipe>,
|
|
}
|
|
|
|
#[derive(strum_macros::Display)]
|
|
pub enum Meal {
|
|
Lunch,
|
|
Dinner,
|
|
}
|
|
|
|
impl Event {
|
|
pub fn new(date: NaiveDate, meal: Meal, recipe: Rc<Recipe>) -> Self {
|
|
let uid = format!(
|
|
"{}-{}@{}.montecristosoftware.eu",
|
|
date,
|
|
meal,
|
|
env!("CARGO_PKG_NAME")
|
|
);
|
|
|
|
let meal_time = match meal {
|
|
Meal::Lunch => NaiveTime::from_hms(12, 00, 00),
|
|
Meal::Dinner => NaiveTime::from_hms(19, 00, 00),
|
|
};
|
|
|
|
let ends_at = NaiveDateTime::new(date, meal_time);
|
|
|
|
Event {
|
|
uid,
|
|
ends_at,
|
|
recipe,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> From<Event> for CalEvent<'a> {
|
|
fn from(ev: Event) -> Self {
|
|
let start_time = Local
|
|
.from_local_datetime(&(*&ev.ends_at - ev.recipe.total_time()))
|
|
.unwrap();
|
|
let end_time = Local.from_local_datetime(&ev.ends_at).unwrap();
|
|
let timezone = iana_time_zone::get_timezone().unwrap();
|
|
|
|
let mut event = ics::Event::new(ev.uid.clone(), dt_utc_fmt(&Utc::now()));
|
|
event.push(calprop::Summary::new(escape_text(ev.recipe.name.clone())));
|
|
event.push(calprop::Description::new(format!(
|
|
"cookbook@{}",
|
|
ev.recipe.id
|
|
)));
|
|
event.push(calprop::Location::new(escape_text(ev.recipe.url.clone())));
|
|
|
|
let mut dtstart = calprop::DtStart::new(dt_fmt(&start_time));
|
|
dtstart.append(ics::parameters!("TZID" => timezone.clone()));
|
|
event.push(dtstart);
|
|
|
|
let mut dtend = calprop::DtEnd::new(dt_fmt(&end_time));
|
|
dtend.append(ics::parameters!("TZID" => timezone));
|
|
event.push(dtend);
|
|
|
|
// TODO make configurable yearly repetition, for now this suits my personal uses
|
|
const DAY_NAMES: [&str; 7] = ["MO", "TU", "WE", "TH", "FR", "SA", "SU"];
|
|
event.push(calprop::RRule::new(format!(
|
|
"FREQ=YEARLY;BYDAY={weekday};BYWEEKNO={weekno}",
|
|
weekday = DAY_NAMES
|
|
.get(start_time.weekday().num_days_from_monday() as usize)
|
|
.unwrap(),
|
|
weekno = start_time.iso_week().week(),
|
|
)));
|
|
|
|
let mut trigger = calprop::Trigger::new("-PT15M");
|
|
trigger.append(ics::parameters!("RELATED" => "START"));
|
|
let alarm = ics::Alarm::display(
|
|
trigger,
|
|
calprop::Description::new(escape_text(ev.recipe.name.clone())),
|
|
);
|
|
event.add_alarm(alarm);
|
|
event
|
|
}
|
|
}
|
|
|
|
fn dt_fmt(datetime: &DateTime<Local>) -> String {
|
|
datetime.format(constants::ICAL_LOCALTIME_FMT).to_string()
|
|
}
|
|
|
|
fn dt_utc_fmt(datetime: &DateTime<Utc>) -> String {
|
|
datetime.format(constants::ICAL_UTCTIME_FMT).to_string()
|
|
}
|