aboutsummaryrefslogtreecommitdiff
path: root/src/gui/calendar.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/calendar.rs')
-rw-r--r--src/gui/calendar.rs187
1 files changed, 187 insertions, 0 deletions
diff --git a/src/gui/calendar.rs b/src/gui/calendar.rs
new file mode 100644
index 0000000..918438d
--- /dev/null
+++ b/src/gui/calendar.rs
@@ -0,0 +1,187 @@
+use gtk4 as gtk;
+
+use async_channel::Sender;
+use chrono::{Datelike, NaiveDate};
+use gtk::glib;
+use gtk::prelude::*;
+use std::collections::HashMap;
+
+use crate::{gui::update, gui::update::Msg, gui::App, model::event, model::event::Event};
+
+static DAYS: [&str; 7] = ["LUN", "MAR", "MER", "JEU", "VEN", "SAM", "DIM"];
+static MONTHES: [&str; 12] = [
+ "Jan", "Fév", "Mar", "Avr", "Mai", "Juin", "Juil", "Aoû", "Sep", "Oct", "Nov", "Déc",
+];
+
+pub fn create(
+ tx: Sender<Msg>,
+ today: NaiveDate,
+ start_date: NaiveDate,
+ end_date: NaiveDate,
+ events: &[Event],
+ repeated_events: &[Event],
+) -> gtk::Grid {
+ let grid = gtk::Grid::builder().build();
+
+ for col in 0..7 {
+ grid.attach(&day_title(col), col, 0, 1, 1);
+ }
+
+ let repetitions = event::repetitions_between(repeated_events, start_date, end_date);
+ attach_days(tx, &grid, start_date, today, events, &repetitions);
+
+ grid
+}
+
+fn attach_days(
+ tx: Sender<Msg>,
+ grid: &gtk::Grid,
+ start_date: NaiveDate,
+ today: NaiveDate,
+ events: &[Event],
+ repetitions: &HashMap<NaiveDate, Vec<Event>>,
+) {
+ let mut d = start_date;
+ for row in 1..5 {
+ for col in 0..7 {
+ grid.attach(
+ &day_entry(tx.clone(), d, today, events, repetitions),
+ col,
+ row,
+ 1,
+ 1,
+ );
+ d = d.succ();
+ }
+ }
+}
+
+pub fn refresh_date(app: &App, date: NaiveDate, repetitions: &HashMap<NaiveDate, Vec<Event>>) {
+ let d = date.signed_duration_since(app.start_date).num_days();
+
+ let col = (d % 7) as i32;
+ let row = 1 + (d / 7) as i32;
+
+ app.grid.attach(
+ &day_entry(app.tx.clone(), date, app.today, &app.events, repetitions),
+ col,
+ row,
+ 1,
+ 1,
+ )
+}
+
+fn day_title(col: i32) -> gtk::Box {
+ let vbox = gtk::Box::builder()
+ .orientation(gtk::Orientation::Vertical)
+ .build();
+
+ vbox.add_css_class("g-Calendar__DayTitle");
+
+ let label = gtk::Label::builder().label(DAYS[col as usize]).build();
+
+ vbox.append(&label);
+
+ vbox
+}
+
+pub fn day_entry(
+ tx: Sender<Msg>,
+ date: NaiveDate,
+ today: NaiveDate,
+ events: &[Event],
+ repetitions: &HashMap<NaiveDate, Vec<Event>>,
+) -> gtk::ScrolledWindow {
+ let vbox = gtk::Box::builder()
+ .orientation(gtk::Orientation::Vertical)
+ .build();
+
+ vbox.add_css_class("g-Calendar__Day");
+
+ let gesture = gtk::GestureClick::new();
+ gesture.connect_pressed(glib::clone!(@strong tx => move |_, n, _, _| {
+ if n == 2 {
+ update::send(tx.clone(), Msg::ShowAddForm { date });
+ }
+ }));
+ vbox.add_controller(&gesture);
+
+ if date == today {
+ vbox.add_css_class("g-Calendar__Day--Today");
+ }
+
+ vbox.append(&day_label(date));
+
+ let mut events = events
+ .iter()
+ .filter(|e| e.date == date)
+ .collect::<Vec<&Event>>();
+ let repeated_events = repetitions.get(&date).cloned().unwrap_or_default();
+ events.extend(repeated_events.iter());
+ events.sort_by_key(|e| e.start);
+
+ if !events.is_empty() {
+ vbox.append(&day_events(tx, events));
+ }
+
+ gtk::ScrolledWindow::builder()
+ .hscrollbar_policy(gtk::PolicyType::Never)
+ .hexpand(true)
+ .vexpand(true)
+ .child(&vbox)
+ .build()
+}
+
+fn day_label(date: NaiveDate) -> gtk::Label {
+ let label = gtk::Label::builder()
+ .label(&format!(
+ "{} {}",
+ date.day(),
+ MONTHES[date.month0() as usize]
+ ))
+ .halign(gtk::Align::Start)
+ .build();
+
+ label.add_css_class("g-Calendar__DayNumber");
+
+ label
+}
+
+fn day_events(tx: Sender<Msg>, events: Vec<&Event>) -> gtk::Box {
+ let vbox = gtk::Box::builder()
+ .orientation(gtk::Orientation::Vertical)
+ .build();
+
+ for event in events {
+ let hbox = gtk::Box::builder()
+ .orientation(gtk::Orientation::Horizontal)
+ .hexpand(true)
+ .build();
+
+ let gesture = gtk::GestureClick::new();
+ gesture.connect_pressed(
+ glib::clone!(@strong event, @strong tx => move |gesture, n, _, _| {
+ gesture.set_state(gtk::EventSequenceState::Claimed);
+ if n == 2 {
+ update::send(tx.clone(), Msg::ShowUpdateForm { event: event.clone() });
+ }
+ }),
+ );
+ hbox.add_controller(&gesture);
+
+ hbox.add_css_class("g-Calendar__DayEvent");
+
+ let event_txt = &event.pprint();
+ let label = gtk::Label::builder()
+ .label(event_txt)
+ .ellipsize(gtk::pango::EllipsizeMode::End)
+ .tooltip_text(event_txt)
+ .halign(gtk::Align::Start)
+ .build();
+
+ hbox.append(&label);
+ vbox.append(&hbox);
+ }
+
+ vbox
+}