diff options
Diffstat (limited to 'src/gui/calendar.rs')
-rw-r--r-- | src/gui/calendar.rs | 187 |
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: >k::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 +} |