refactor: move row to model

This commit is contained in:
Fabrizio Iannetti 2024-12-21 19:09:54 +01:00
parent a19ac366cb
commit edf434b36f
6 changed files with 565 additions and 516 deletions

825
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,2 +1,3 @@
pub mod events;
pub mod ical_bridge;
pub mod ical_bridge;
pub mod row;

113
src/model/row.rs Normal file
View File

@ -0,0 +1,113 @@
use chrono::{Datelike, Duration, Months, Days, NaiveDate, Weekday};
use std::vec::Vec;
#[derive(Debug)]
pub struct CalendarRow {
pub begin: NaiveDate, // first actual day in the row
pub end: NaiveDate, // the day just after the last one in the row
}
pub enum RowDay {
InRange(NaiveDate),
NotInRange,
}
impl RowDay {
pub fn new(row: &CalendarRow, day: NaiveDate) -> RowDay {
if day >= row.begin && day < row.end {
RowDay::InRange(day)
} else {
RowDay::NotInRange
}
}
}
/// A row in the calendar.
///
/// The row is always aligned to a week, i.e. the first
/// day of the row is the first day of the week (for now always Monday)
impl CalendarRow {
/// A row that spans the month containing the given day
pub fn for_month(day: NaiveDate) -> CalendarRow {
let begin = day.with_day0(0).unwrap();
CalendarRow {
begin,
end: begin + Months::new(1),
}
}
/// A row that spans the week containing the given day
pub fn for_week(day: NaiveDate) -> CalendarRow {
let begin = day.week(Weekday::Mon).first_day();
CalendarRow {
begin,
end: begin + Duration::try_weeks(1).unwrap(),
}
}
/// Get the day for the given column of the row
pub fn date_for_col(self: &Self, col: i64) -> RowDay {
RowDay::new(
self,
self.begin.week(Weekday::Mon).first_day() + Duration::try_days(col).unwrap(),
)
}
pub fn num_days(&self) -> i64 {
(self.end - self.begin).num_days()
}
pub fn num_cols(&self) -> i64 {
(self.last_day() - self.first_day()).num_days() + 1
}
pub fn first_day(&self) -> NaiveDate {
self.begin.week(Weekday::Mon).first_day()
}
pub fn last_day(&self) -> NaiveDate {
self.end.pred_opt().unwrap().week(Weekday::Mon).last_day()
}
}
pub struct CalendarPage {
col_count: usize,
rows: Vec<CalendarRow>,
}
impl CalendarPage {
pub fn new_month_wide(row_count: u32, day: NaiveDate) -> Self {
let mut page = CalendarPage {
col_count: 37,
rows: Vec::with_capacity(row_count as usize),
};
for row_num in 0..row_count {
page.rows.push(CalendarRow::for_month(day + Months::new(row_num)));
}
return page;
}
pub fn new_week_wide(row_count: u32, day: NaiveDate) -> Self {
let mut page = CalendarPage {
col_count: 7,
rows: Vec::with_capacity(row_count as usize),
};
for row_num in 0..row_count {
let days_offset = Days::new((row_num as u64) * 7);
page.rows.push(CalendarRow::for_week(day + days_offset));
}
return page;
}
pub fn get_row_count(&self) -> usize {
self.rows.len()
}
pub fn get_rows(&self) -> &[CalendarRow] {
&self.rows
}
pub fn get_col_count(&self) -> usize {
self.col_count
}
}

View File

@ -1,4 +1,3 @@
pub mod basics;
pub mod calendar;
pub mod controls;
mod row;

View File

@ -9,10 +9,8 @@
// implemented by `iced_wgpu` and other renderers.
use super::basics::CellGrid;
use super::row::CalendarRow;
use super::row::RowDay;
use crate::model::row::{CalendarRow, RowDay, CalendarPage};
use crate::model::events::EventType;
use crate::model::events::Organizer;
use crate::model::events::{Event, EventsCollection};
use chrono::{
Datelike,
@ -114,7 +112,7 @@ impl CalendarParams {
fn render_events_in_row<Renderer>(
params: &CalendarParams,
renderer: &mut Renderer,
cal_row: CalendarRow,
cal_row: &CalendarRow,
row_bounds: Rectangle,
min_row_height: f32,
font_size: Pixels,
@ -341,6 +339,7 @@ pub struct CalendarView<'a> {
row_name_font_size: f32,
margin: f32,
locale: Locale,
calendar_page: CalendarPage,
}
impl<'a> CalendarView<'a> {
@ -350,6 +349,11 @@ impl<'a> CalendarView<'a> {
CalendarViewMode::Month => day.with_day0(0).unwrap(),
CalendarViewMode::Year => day.with_month0(0).unwrap().with_day0(0).unwrap()
};
let calendar_page = match mode {
CalendarViewMode::Week => CalendarPage::new_week_wide(1, first_day),
CalendarViewMode::Month => CalendarPage::new_week_wide(6, first_day),
CalendarViewMode::Year => CalendarPage::new_month_wide(12, first_day),
};
CalendarView {
first_day,
params: params.clone(),
@ -358,6 +362,7 @@ impl<'a> CalendarView<'a> {
row_name_font_size: 24.0,
margin: 10.0,
locale: Locale::it_IT,
calendar_page,
}
}
@ -554,45 +559,47 @@ impl<'a> CalendarView<'a> {
);
// use the minimum row height to compute available space for event bars
// to avoid inconsistentencies when rowas have slightly different heights
// to avoid inconsistentencies when rows have slightly different heights
// and some can fit more event bars than others
let min_row_height = grid.compute_min_height();
for row in grid.rows().iter() {
let row_grid = CellGrid::new(
row.x,
row.y,
row.width,
row.height,
self.get_days_per_row(),
1,
);
let mut row_index = 0;
let row_num: f32 = self.calendar_page.get_row_count() as f32;
let col_num = self.calendar_page.get_col_count() as i64;
for row in self.calendar_page.get_rows() {
let beg_y = (bounds.y + bounds.height * (row_index as f32) / row_num).trunc();
let end_y = (bounds.y + bounds.height * ((row_index + 1) as f32) / row_num).trunc();
let mut row_bounds: Rectangle = Rectangle {
x: row.x,
y: row.y,
width: row.width,
height: row.height,
x: bounds.x,
y: beg_y,
width: bounds.width,
height: end_y - beg_y,
};
let cal_row = self.get_calendar_row(self.first_day, row.pos_y);
let row_len: f32 = col_num as f32;
for column_index in 0..col_num {
for cell in row_grid.iter() {
let dat_for_col = cal_row.date_for_col(cell.pos_x.into());
if let RowDay::InRange(current_day) = dat_for_col {
let day_bounds = Rectangle {
x: cell.x,
y: cell.y,
width: cell.width + 1.0,
height: cell.height + 1.0,
};
let beg_x = (bounds.x + bounds.width * (column_index as f32) / row_len).trunc();
let end_x = (bounds.x + bounds.width * ((column_index + 1) as f32) / row_len).trunc();
let day_bounds = Rectangle{
x: beg_x,
y: beg_y,
width: end_x - beg_x + 1.0,
height: end_y - beg_y + 1.0,
};
let date_for_col = row.date_for_col(column_index);
// draw the cell here
if let RowDay::InRange(current_day) = date_for_col {
// update bounds for the rectangle with the actual days
if current_day == cal_row.begin {
let diff = cell.x - row_bounds.x;
row_bounds.x = cell.x;
if current_day == row.begin {
let diff = beg_x - row_bounds.x;
row_bounds.x = beg_x;
row_bounds.width -= diff;
} else if current_day + Duration::try_days(1).unwrap() == cal_row.end {
row_bounds.width = cell.x - row_bounds.x + cell.width;
} else if current_day + Duration::try_days(1).unwrap() == row.end {
row_bounds.width = end_x - row_bounds.x;
}
// label: day number
@ -640,12 +647,12 @@ impl<'a> CalendarView<'a> {
day_bounds,
);
}
}
}
let content = "10";
render_events_in_row(
&self.params,
renderer,
cal_row,
row,
row_bounds,
min_row_height,
font_size,
@ -653,7 +660,9 @@ impl<'a> CalendarView<'a> {
content,
self.events,
);
}
row_index += 1;
}
}
}

View File

@ -1,58 +0,0 @@
use chrono::{Datelike, Duration, Months, NaiveDate, Weekday};
#[derive(Debug)]
pub struct CalendarRow {
pub begin: NaiveDate,
pub end: NaiveDate,
}
pub enum RowDay {
InRange(NaiveDate),
NotInRange,
}
impl RowDay {
pub fn new(row: &CalendarRow, day: NaiveDate) -> RowDay {
if day >= row.begin && day < row.end {
RowDay::InRange(day)
} else {
RowDay::NotInRange
}
}
}
/// A row in the calendar.
///
/// The row is always aligned to a week, i.e. the first
/// day of the row is the first day of the week (for now always Monday)
impl CalendarRow {
/// A row that spans the month containing the given day
pub fn for_month(day: NaiveDate) -> CalendarRow {
let begin = day.with_day0(0).unwrap();
CalendarRow {
begin,
end: begin + Months::new(1),
}
}
/// A row that spans the week containing the given day
pub fn for_week(day: NaiveDate) -> CalendarRow {
let begin = day.week(Weekday::Mon).first_day();
CalendarRow {
begin,
end: begin + Duration::try_weeks(1).unwrap(),
}
}
/// Get the day for the given column of the row
pub fn date_for_col(self: &Self, col: i64) -> RowDay {
RowDay::new(
self,
self.begin.week(Weekday::Mon).first_day() + Duration::try_days(col).unwrap(),
)
}
pub fn num_days(&self) -> i64 {
(self.end - self.begin).num_days()
}
}