Skip to content

Commit 5460804

Browse files
committed
Expand recurring caldav events
Fixes #2186
1 parent 7d68c03 commit 5460804

4 files changed

Lines changed: 102 additions & 12 deletions

File tree

Cargo.lock

Lines changed: 59 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ env_logger = "0.11"
4343
futures = { version = "0.3.31", default-features = false }
4444
glob = { version = "0.3.1", optional = true }
4545
iana-time-zone = "0.1.60"
46-
icalendar = { version = "0.16.2", features = ["chrono-tz"] }
46+
icalendar = { git = "https://github.com/hoodie/icalendar", rev = "46b9a8859b81854c42d823ed21773d77afac63a7", features = ["chrono-tz", "recurrence"] }
4747
icu_calendar = { version = "1.3.0", optional = true }
4848
icu_datetime = { version = "1.3.0", optional = true }
4949
icu_locid = { version = "1.3.0", optional = true }

cspell.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ words:
139139
- retval
140140
- rofi
141141
- rofication
142+
- rrule
142143
- rsplit
143144
- rtattr
144145
- rtattrs

src/blocks/calendar/caldav.rs

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::{str::FromStr as _, time::Duration, vec};
22

3-
use chrono::{DateTime, Local, Utc};
4-
use icalendar::{Component as _, EventLike as _};
3+
use chrono::{DateTime, Datelike as _, Local, TimeZone as _, Timelike as _, Utc};
4+
use icalendar::{Component as _, EventLike as _, rrule::Tz};
55
use reqwest::{
66
self, ClientBuilder, Method, Url,
77
header::{CONTENT_TYPE, HeaderMap, HeaderValue},
@@ -301,20 +301,57 @@ fn parse_events(multi_status: Multistatus) -> Result<Vec<Event>, CalendarError>
301301
icalendar::Calendar::from_str(&data).map_err(CalendarError::Parsing)?;
302302
for component in calendar.components {
303303
if let icalendar::CalendarComponent::Event(event) = component {
304-
let start_at = event.get_start().and_then(|d| match d {
304+
let mut start_at = event.get_start().and_then(|d| match d {
305305
icalendar::DatePerhapsTime::DateTime(dt) => dt.try_into_utc(),
306306
icalendar::DatePerhapsTime::Date(d) => d
307307
.and_hms_opt(0, 0, 0)
308308
.and_then(|d| d.and_local_timezone(Local).earliest())
309309
.map(|d| d.to_utc()),
310310
});
311-
let end_at = event.get_end().and_then(|d| match d {
311+
let mut end_at = event.get_end().and_then(|d| match d {
312312
icalendar::DatePerhapsTime::DateTime(dt) => dt.try_into_utc(),
313313
icalendar::DatePerhapsTime::Date(d) => d
314314
.and_hms_opt(23, 59, 59)
315315
.and_then(|d| d.and_local_timezone(Local).earliest())
316316
.map(|d| d.to_utc()),
317317
});
318+
319+
let today_dt = Local::now()
320+
.date_naive()
321+
.and_hms_opt(0, 0, 0)
322+
.expect("A valid time")
323+
.and_local_timezone(Local)
324+
.earliest()
325+
.expect("A valid datetime")
326+
.to_utc();
327+
let today_rrule_dt = Tz::UTC
328+
.with_ymd_and_hms(
329+
today_dt.year(),
330+
today_dt.month(),
331+
today_dt.day(),
332+
today_dt.hour(),
333+
today_dt.minute(),
334+
today_dt.second(),
335+
)
336+
.earliest()
337+
.unwrap();
338+
339+
if let Some(s) = start_at
340+
&& let Some(rrule_set) = event.get_recurrence()
341+
&& let Some(new_start) = rrule_set
342+
.after(today_rrule_dt)
343+
.all(1)
344+
.dates
345+
.first()
346+
.map(|dt| dt.to_utc())
347+
{
348+
start_at.replace(new_start);
349+
if let Some(e) = end_at {
350+
let duration = e - s;
351+
end_at.replace(new_start + duration);
352+
}
353+
}
354+
318355
result.push(Event {
319356
uid: event.get_uid().map(Into::into),
320357
summary: event.get_summary().map(Into::into),

0 commit comments

Comments
 (0)