aboutsummaryrefslogtreecommitdiff
path: root/karlgui/src/views/calendar.rs
blob: a145f4aba076b6d3d0b0b3854292356a06719bd6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
use crate::{helper::weekday_to_str, Globals};
use chrono::{Datelike, Duration, NaiveDateTime, Timelike};
use egui::{Color32, Label, Layout, Rect, ScrollArea, Sense, Stroke, Ui, Vec2};
use egui_extras::{Size, StripBuilder};
use std::{collections::BTreeMap, ops::Range};

#[derive(Default)]
pub struct Calendar {
    // offset: NaiveDate,
}

impl Calendar {
    pub fn ui(&mut self, ui: &mut Ui, g: &mut Globals) {
        let start_date = chrono::Utc::now().date_naive(); //self.offset;
        let end_date = start_date + chrono::Duration::days(7);
        let start_dt = start_date.and_hms(0, 0, 0);
        let end_dt = end_date.and_hms(0, 0, 0);

        let task_ids = g.tasks.keys().map(|e| e.to_owned()).collect::<Vec<_>>();
        let instances =
            BTreeMap::from_iter(task_ids.iter().filter_map(|id| {
                Some((id, g.get_instances_range(*id, start_dt, end_dt).to_owned()?))
            }));

        let height = 1500.0;

        ScrollArea::vertical().show(ui, |ui| {
            StripBuilder::new(ui)
                .size(Size::exact(50.0))
                .sizes(Size::remainder(), 7)
                .horizontal(|mut ui| {
                    ui.cell(|ui| {
                        for h in 0..24 {
                            ui.add_sized(
                                Vec2::new(50.0, height / 24.0),
                                Label::new(&format!("{h:02}:00")),
                            );
                        }
                    });
                    for d in 0..7 {
                        ui.cell(|ui| {
                            let time = start_dt + Duration::days(d as i64);
                            let time_end = time + Duration::days(1) - Duration::seconds(1);
                            let instances_here = instances
                                .iter()
                                .map(|(id, rs)| {
                                    (
                                        id,
                                        rs.iter()
                                            .filter(|r| r.overlaps(time..time_end))
                                            .collect::<Vec<_>>(),
                                    )
                                })
                                .filter(|(_, l)| l.len() != 0);

                            ui.vertical(|ui| {
                                ui.heading(weekday_to_str(
                                    time.date().weekday().num_days_from_monday().into(),
                                ));
                                ui.horizontal(|ui| {
                                    for (id, rs) in instances_here {
                                        let task = g.tasks.get(id).unwrap();

                                        let (rect, response) = ui.allocate_exact_size(
                                            Vec2::new(10.0, height),
                                            Sense::hover(),
                                        );

                                        for r in &rs {
                                            let r =
                                                r.start.unwrap_or(time)..r.end.unwrap_or(time_end);
                                            let rect_start = (r.start.hour() as f32
                                                + (r.start.minute() as f32 / 60.0))
                                                / 24.0
                                                * height;
                                            let rect_end = (r.end.hour() as f32
                                                + (r.end.minute() as f32 / 60.0))
                                                / 24.0
                                                * height;
                                            ui.painter().rect(
                                                Rect::from_two_pos(
                                                    rect.min + Vec2::new(0.0, rect_start),
                                                    rect.min + Vec2::new(10.0, rect_end),
                                                ),
                                                0.0,
                                                Color32::KHAKI,
                                                Stroke::new(0.0, Color32::WHITE),
                                            );
                                        }

                                        response.on_hover_ui_at_pointer(|ui| {
                                            ui.heading(&task.name);
                                            if let Some(d) = &task.description {
                                                ui.label(d);
                                            }
                                        });
                                    }
                                })
                            });
                            //     });
                            // });
                        });
                    }
                });
        });

        // TableBuilder::new(ui)
        //     .column(egui_extras::Size::exact(50.0))
        //     .columns(egui_extras::Size::remainder(), 7)
        //     .header(25.0, |mut ui| {
        //         ui.col(|_| {});
        //         for d in 0..7 {
        //             ui.col(|ui| {
        //                 ui.heading(weekday_to_str(d));
        //             });
        //         }
        //     })
        //     .body(|mut ui| {
        //         let mut cols: [Vec<u64>; 7] =
        //             [vec![], vec![], vec![], vec![], vec![], vec![], vec![]];
        //         for h in 0..24 {
        //             ui.row(height, |mut ui| {
        //                 ui.col(|ui| {
        //                     ui.heading(&format!("{h:02}:00"));
        //                 });
        //                 for d in 0..7 {
        //                     let _col = &mut cols[d];
        //                     let time = start_dt + Duration::days(d as i64) + Duration::hours(h);
        //                     let time_end = time + Duration::hours(1) - Duration::seconds(1);
        //                     let instances_here =
        //                         instances.iter().filter(|(_, r)| r.overlaps(time..time_end));

        //                     ui.col(|ui| {
        //                         for (id, _) in instances_here {
        //                             let task = g.tasks.get(id).unwrap();
        //                             let (rect, response) =
        //                                 ui.allocate_at_least(Vec2::new(10.0, 50.0), Sense::hover());
        //                             ui.painter().rect(
        //                                 rect,
        //                                 0.0,
        //                                 Color32::KHAKI,
        //                                 Stroke::new(0.0, Color32::WHITE),
        //                             );
        //                             response.on_hover_ui_at_pointer(|ui| {
        //                                 ui.heading(&task.name);
        //                                 if let Some(d) = &task.description {
        //                                     ui.label(d);
        //                                 }
        //                             });
        //                         }
        //                     });
        //                 }
        //             })
        //         }
        //     })
    }
}

pub trait Overlaps<T> {
    fn overlaps(&self, v: T) -> bool;
}
impl Overlaps<NaiveDateTime> for Range<NaiveDateTime> {
    fn overlaps(&self, v: NaiveDateTime) -> bool {
        self.start <= v && v < self.end
    }
}
impl Overlaps<NaiveDateTime> for Range<Option<NaiveDateTime>> {
    fn overlaps(&self, v: NaiveDateTime) -> bool {
        match (self.start, self.end) {
            (Some(s), Some(e)) => s <= v && v < e,
            (Some(s), None) => s <= v,
            (None, Some(e)) => v < e,
            (None, None) => false,
        }
    }
}
impl Overlaps<Range<NaiveDateTime>> for Range<Option<NaiveDateTime>> {
    fn overlaps(&self, v: Range<NaiveDateTime>) -> bool {
        match (self.start, self.end) {
            (None, None) => false,
            (None, Some(e)) => v.start < e,
            (Some(s), None) => v.end > s,
            (Some(s), Some(e)) => v.start < e && v.end > s,
        }
    }
}