//! Simple calendar applications. mod ui; mod model; use ui::calendar; use model::{ events::EventsCollection, ical_bridge::load_calendar, }; use chrono::{Datelike, NaiveDate, Months, Utc}; use calendar::{CalendarParams, CalendarView }; use calendar::CalendarViewMode as ViewMode; use std::path; use clap::Parser; use log::info; use simplelog::{SimpleLogger, Config}; use iced::{ alignment, executor, Alignment, Application, Command, Element, Length, Settings, widget::{ Column, Row, Container, Button, Text, pick_list, }, theme, }; #[cfg(feature = "tracing")] extern crate lttng_ust; #[cfg(feature = "tracing")] use lttng_ust::import_tracepoints; #[cfg(feature = "tracing")] import_tracepoints!( concat!(env!("OUT_DIR"), "/tracepoints.rs"), tracepoints ); struct CalendarFlags { calendar_paths: std::vec::Vec, } #[derive(Parser, Debug)] #[command(version, about)] struct CliArgs { files: Vec, } pub fn main() -> iced::Result { set_up_logger(); let args = CliArgs::parse(); let calendar_files = args.files.iter().map(|arg| { info!("CalFile: {}", arg); path::PathBuf::from(arg) }).collect(); CalendarApp::run(Settings::with_flags(CalendarFlags {calendar_paths: calendar_files})) } fn set_up_logger() { SimpleLogger::init(log::LevelFilter::Info, Config::default()).unwrap(); } #[derive(Default)] struct CalendarApp { month: NaiveDate, controls: Controls, events: EventsCollection, } #[derive(Debug, Clone, Copy)] enum Message { NextWeek, PrevWeek, NextMonth, PrevMonth, NextYear, PrevYear, ViewModeSelected(ViewMode), } //#[derive(Default)] struct Controls { mode: Option, } impl Default for Controls { fn default() -> Controls { Controls { mode : Some(ViewMode::Year) } } } impl std::fmt::Display for ViewMode { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, "{}", match self { ViewMode::Week => "Week", ViewMode::Month => "Month", ViewMode::Year => "Year", } ) } } impl Controls { const MODES : [ViewMode; 3] = [ViewMode::Week, ViewMode::Month, ViewMode::Year]; fn view<'a>(&'a self, month_name: &'a str, year: i32) -> Element { let description = match self.mode { Some(ViewMode::Month) => month_name, _ => "" }; Row::new() .align_items(Alignment::Center) .padding(5) .spacing(10) .push( pick_list( &Controls::MODES[..], self.mode, Message::ViewModeSelected, ).placeholder("mode") ) .push( Button::new(Text::new("<")) .on_press(self.get_msg_prev()) .style(theme::Button::Secondary), ) .push( Button::new(Text::new(">")) .on_press(self.get_msg_next()) .style(theme::Button::Secondary), ) .push( Text::new(description) .width(Length::Fill) .horizontal_alignment(alignment::Horizontal::Left) .size(40), ) .push( Text::new(year.to_string()) .width(Length::Fill) .horizontal_alignment(alignment::Horizontal::Right) .size(40), ) .into() } fn get_msg_next(&self) -> Message { match self.mode { Some(ViewMode::Week) => Message::NextWeek, Some(ViewMode::Month) => Message::NextMonth, Some(ViewMode::Year) => Message::NextYear, None => todo!(), } } fn get_msg_prev(&self) -> Message { match self.mode { Some(ViewMode::Week) => Message::PrevWeek, Some(ViewMode::Month) => Message::PrevMonth, Some(ViewMode::Year) => Message::PrevYear, None => todo!(), } } } impl Application for CalendarApp { type Executor = executor::Default; type Message = Message; type Theme = iced::Theme; type Flags = CalendarFlags; fn new(flags: Self::Flags) -> (Self, Command) { let month = Utc::now().date_naive(); let mut ret = (CalendarApp { month, events: EventsCollection::new(), ..CalendarApp::default() }, Command::none()); for calendar_path in flags.calendar_paths { load_calendar(&calendar_path, &mut ret.0.events); } ret } fn title(&self) -> String { String::from("Calendar") } fn update(&mut self, message: Message) -> Command { match message { Message::PrevWeek => { self.month = self.month; // TODO } Message::NextWeek => { self.month = self.month; // TODO } Message::PrevMonth => { self.month = self.month - Months::new(1); } Message::NextMonth => { self.month = self.month + Months::new(1); } Message::PrevYear => { self.month = self.month - Months::new(12); } Message::NextYear => { self.month = self.month + Months::new(12); } Message::ViewModeSelected(mode) => { self.controls.mode = Some(mode); } } Command::none() } fn view(&self) -> Element { #[cfg(feature = "tracing")] tracepoints::calendar::view_entry(); const MONTH_NAMES: [&str;12] = [ "gennaio", "febbraio", "marzo", "aprile", "maggio", "giugno", "luglio", "agosto", "settembre", "ottobre", "novembre", "dicembre", ]; let content = Column::new() .align_items(Alignment::Center) .push(self.controls.view(MONTH_NAMES[self.month.month0() as usize], self.month.year())) .push(CalendarView::new(self.controls.mode.unwrap_or(ViewMode::Year), &CalendarParams::new(), self.month, &self.events)) ; let container = Container::new(content) .width(Length::Fill) .height(Length::Fill) .center_x() .center_y() .into(); #[cfg(feature = "tracing")] tracepoints::calendar::view_exit(); container } }