aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoris2024-01-20 22:08:44 +0100
committerJoris2024-01-20 22:08:44 +0100
commit36cd29b459bb41bff1cf6d079fd30100bd89cec1 (patch)
tree1cd3c0b64ab7dd1c35c580e47cdb5fe3b92f8532
parent44a32d874cb0540aede1adcf3e6ef9bd7a928c90 (diff)
Allow to specify week of month for repetition
-rw-r--r--src/gui/form/repetition.rs67
-rw-r--r--src/model/repetition.rs18
2 files changed, 59 insertions, 26 deletions
diff --git a/src/gui/form/repetition.rs b/src/gui/form/repetition.rs
index 4da65ac..a83aea5 100644
--- a/src/gui/form/repetition.rs
+++ b/src/gui/form/repetition.rs
@@ -12,11 +12,17 @@ use crate::model::{
use crate::validation;
static WEEKDAYS_STR: [&str; 7] = [
- "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche",
+ "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi", "dimanche",
];
static WEEKDAYS: [Weekday; 7] = [Mon, Tue, Wed, Thu, Fri, Sat, Sun];
+static WEEKS_STR: [&str; 4] = [
+ "1er", "2ème", "3ème", "4ème"
+];
+
+static WEEKS: [u8; 4] = [1, 2, 3, 4];
+
pub struct Model {
pub view: gtk::Box,
no_radio: gtk::CheckButton,
@@ -24,8 +30,9 @@ pub struct Model {
day_interval_entry: gtk::Entry,
monthly_radio: gtk::CheckButton,
monthly_entry: gtk::Entry,
- first_day_radio: gtk::CheckButton,
- first_day_dropdown: gtk::DropDown,
+ day_of_month_radio: gtk::CheckButton,
+ week_of_month: gtk::DropDown,
+ day_of_week: gtk::DropDown,
yearly_radio: gtk::CheckButton,
until: gtk::Entry,
}
@@ -70,18 +77,19 @@ pub fn view(repetition: Option<&Repetition>) -> Model {
radio_input(&no_radio, !default.is_empty(), &monthly_entry, "Mensuel");
view.append(&monthly_box);
- let (active, default) = match frequency {
+ let (active, default_week, default_day) = match frequency {
Some(Frequency::Monthly {
- day: DayOfMonth::Weekday { weekday },
- }) => (true, weekday),
- _ => (false, Mon),
+ day: DayOfMonth::Weekday { week, day },
+ }) => (true, week, day),
+ _ => (false, 1, Mon),
};
- let first_day_dropdown = gtk::DropDown::from_strings(&WEEKDAYS_STR);
- first_day_dropdown
- .set_selected(WEEKDAYS.iter().position(|d| d == &default).unwrap_or(0) as u32);
- let (first_day_of_month_box, first_day_radio) =
- radio_input(&no_radio, active, &first_day_dropdown, "1er jour du mois");
- view.append(&first_day_of_month_box);
+ let week_of_month = gtk::DropDown::from_strings(&WEEKS_STR);
+ week_of_month.set_selected(WEEKS.iter().position(|d| d == &default_week).unwrap_or(0) as u32);
+ let day_of_week = gtk::DropDown::from_strings(&WEEKDAYS_STR);
+ day_of_week.set_selected(WEEKDAYS.iter().position(|d| d == &default_day).unwrap_or(0) as u32);
+ let (day_of_month_box, day_of_month_radio) =
+ radio_day_of_month(&no_radio, active, &week_of_month, &day_of_week);
+ view.append(&day_of_month_box);
let yearly_radio = gtk::CheckButton::builder()
.group(&no_radio)
@@ -106,8 +114,9 @@ pub fn view(repetition: Option<&Repetition>) -> Model {
day_interval_entry,
monthly_radio,
monthly_entry,
- first_day_radio,
- first_day_dropdown,
+ day_of_month_radio,
+ week_of_month,
+ day_of_week,
yearly_radio,
until,
}
@@ -131,6 +140,27 @@ fn radio_input(
(radio_box, radio)
}
+fn radio_day_of_month(
+ radio_group: &impl IsA<gtk::CheckButton>,
+ active: bool,
+ number: &impl IsA<gtk::Widget>,
+ day: &impl IsA<gtk::Widget>,
+) -> (gtk::Box, gtk::CheckButton) {
+ let radio_box = gtk::Box::builder().build();
+ let radio = gtk::CheckButton::builder()
+ .group(radio_group)
+ .active(active)
+ .build();
+ radio_box.append(&radio);
+ number.add_css_class("g-Form__RadioInput");
+ radio_box.append(number);
+ day.add_css_class("g-Form__RadioInput");
+ radio_box.append(day);
+ let text = gtk::Text::builder().text("du mois.").build();
+ radio_box.append(&text);
+ (radio_box, radio)
+}
+
fn label(text: &str) -> gtk::Label {
gtk::Label::builder()
.label(text)
@@ -153,10 +183,11 @@ pub fn validate(
Ok(Some(Frequency::Monthly {
day: DayOfMonth::Day { day },
}))
- } else if model.first_day_radio.is_active() {
- let weekday = WEEKDAYS[model.first_day_dropdown.selected() as usize];
+ } else if model.day_of_month_radio.is_active() {
+ let week = WEEKS[model.week_of_month.selected() as usize];
+ let day = WEEKDAYS[model.day_of_week.selected() as usize];
Ok(Some(Frequency::Monthly {
- day: DayOfMonth::Weekday { weekday },
+ day: DayOfMonth::Weekday { week, day },
}))
} else if model.yearly_radio.is_active() {
Ok(Some(Frequency::Yearly))
diff --git a/src/model/repetition.rs b/src/model/repetition.rs
index 360cf5f..07fc4d4 100644
--- a/src/model/repetition.rs
+++ b/src/model/repetition.rs
@@ -19,7 +19,7 @@ pub enum Frequency {
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum DayOfMonth {
Day { day: u8 },
- Weekday { weekday: Weekday },
+ Weekday { week: u8, day: Weekday },
}
pub fn validate_period(str: &str) -> Result<u32, String> {
@@ -74,10 +74,10 @@ impl Repetition {
None => vec![],
},
Frequency::Monthly {
- day: DayOfMonth::Weekday { weekday },
+ day: DayOfMonth::Weekday { week, day },
} => repeat(
- first_weekday_of_month(event, weekday),
- Box::new(|d| first_weekday_of_month(next_month(d), weekday)),
+ day_of_month(event, week, day),
+ Box::new(|d| day_of_month(next_month(d), week, day)),
),
Frequency::Yearly => repeat(
// TODO: error handling
@@ -97,9 +97,9 @@ impl Repetition {
}
}
-fn first_weekday_of_month(date: NaiveDate, weekday: Weekday) -> NaiveDate {
+fn day_of_month(date: NaiveDate, week: u8, day: Weekday) -> NaiveDate {
// TODO: error handling
- NaiveDate::from_weekday_of_month_opt(date.year(), date.month(), weekday, 1).unwrap()
+ NaiveDate::from_weekday_of_month_opt(date.year(), date.month(), day, week).unwrap()
}
fn next_month(date: NaiveDate) -> NaiveDate {
@@ -177,7 +177,8 @@ mod tests {
fn weekday_of_month() {
let repetition = from_freq(Frequency::Monthly {
day: DayOfMonth::Weekday {
- weekday: Weekday::Tue,
+ week: 1,
+ day: Weekday::Tue,
},
});
assert_eq!(
@@ -228,7 +229,8 @@ mod tests {
let repetition = Repetition {
frequency: Frequency::Monthly {
day: DayOfMonth::Weekday {
- weekday: Weekday::Fri,
+ week: 1,
+ day: Weekday::Fri,
},
},
removed_occurences: HashSet::from([1, 2, 3]),