Create placeholders in the historical view for days that are unpopulated.

This commit is contained in:
Savanni D'Gerinel 2023-12-27 21:49:44 -05:00
parent 6d9e2ea382
commit 7a6e902fdd
2 changed files with 112 additions and 22 deletions

View File

@ -90,12 +90,14 @@ impl DaySummary {
*self.imp().weight.borrow_mut() = Some(label); *self.imp().weight.borrow_mut() = Some(label);
} }
/*
self.append( self.append(
&gtk::Label::builder() &gtk::Label::builder()
.halign(gtk::Align::Start) .halign(gtk::Align::Start)
.label("15km of biking in 60 minutes") .label("15km of biking in 60 minutes")
.build(), .build(),
); );
*/
} }
} }

View File

@ -15,7 +15,8 @@ You should have received a copy of the GNU General Public License along with Fit
*/ */
use crate::components::DaySummary; use crate::components::DaySummary;
use emseries::{Record, Recordable, Timestamp}; use chrono::{Duration, Local, NaiveDate};
use emseries::Record;
use ft_core::TraxRecord; use ft_core::TraxRecord;
use glib::Object; use glib::Object;
use gtk::{prelude::*, subclass::prelude::*}; use gtk::{prelude::*, subclass::prelude::*};
@ -24,7 +25,9 @@ use std::{cell::RefCell, collections::HashMap, rc::Rc};
/// The historical view will show a window into the main database. It will show some version of /// The historical view will show a window into the main database. It will show some version of
/// daily summaries, daily details, and will provide all functions the user may need for editing /// daily summaries, daily details, and will provide all functions the user may need for editing
/// records. /// records.
pub struct HistoricalViewPrivate {} pub struct HistoricalViewPrivate {
time_window: RefCell<DayInterval>,
}
#[glib::object_subclass] #[glib::object_subclass]
impl ObjectSubclass for HistoricalViewPrivate { impl ObjectSubclass for HistoricalViewPrivate {
@ -33,7 +36,9 @@ impl ObjectSubclass for HistoricalViewPrivate {
type ParentType = gtk::Box; type ParentType = gtk::Box;
fn new() -> Self { fn new() -> Self {
Self {} Self {
time_window: RefCell::new(DayInterval::default()),
}
} }
} }
@ -54,10 +59,11 @@ impl HistoricalView {
s.set_orientation(gtk::Orientation::Vertical); s.set_orientation(gtk::Orientation::Vertical);
s.set_css_classes(&["historical"]); s.set_css_classes(&["historical"]);
let day_records: GroupedRecords = GroupedRecords::from(records); let grouped_records =
GroupedRecords::new((*s.imp().time_window.borrow()).clone()).with_data(records);
let model = gio::ListStore::new::<DayRecords>(); let mut model = gio::ListStore::new::<DayRecords>();
model.extend_from_slice(&day_records.0); model.extend(grouped_records.items());
let factory = gtk::SignalListItemFactory::new(); let factory = gtk::SignalListItemFactory::new();
factory.connect_setup(move |_, list_item| { factory.connect_setup(move |_, list_item| {
@ -149,23 +155,105 @@ impl DayRecords {
} }
} }
struct GroupedRecords(Vec<DayRecords>); struct GroupedRecords {
interval: DayInterval,
data: HashMap<NaiveDate, DayRecords>,
}
impl From<Vec<Record<TraxRecord>>> for GroupedRecords { impl GroupedRecords {
fn from(records: Vec<Record<TraxRecord>>) -> GroupedRecords { fn new(interval: DayInterval) -> Self {
GroupedRecords( let mut s = Self {
records interval: interval.clone(),
.into_iter() data: HashMap::new(),
.fold(HashMap::new(), |mut acc, rec| { };
acc.entry(rec.date()) interval.days().for_each(|date| {
.and_modify(|entry: &mut DayRecords| (*entry).add_record(rec.clone())) let _ = s.data.insert(date, DayRecords::new(date, vec![]));
.or_insert(DayRecords::new(rec.date(), vec![rec])); });
acc s
}
fn with_data(mut self, records: Vec<Record<TraxRecord>>) -> Self {
records.into_iter().for_each(|record| {
self.data
.entry(record.date())
.and_modify(|entry: &mut DayRecords| (*entry).add_record(record.clone()))
.or_insert(DayRecords::new(record.date(), vec![record]));
});
self
}
fn items<'a>(&'a self) -> impl Iterator<Item = DayRecords> + 'a {
/*
GroupedRecordIterator {
interval: self.interval.clone(),
data: &self.data,
}
*/
self.interval.days().map(|date| {
self.data
.get(&date)
.map(|rec| rec.clone())
.unwrap_or(DayRecords::new(date, vec![]))
}) })
.values() }
.cloned() }
.collect::<Vec<DayRecords>>(),
) /*
struct GroupedRecordIterator<'a> {
interval: DayInterval,
data: &'a HashMap<NaiveDate, DayRecords>,
}
impl <'a> Iterator for GroupedRecordIterator<'a> {
type Item = &'a DayRecords;
fn next(&mut self) -> Option<&'a DayRecords> {
}
}
*/
#[derive(Clone, Debug, PartialEq, Eq)]
struct DayInterval {
start: NaiveDate,
end: NaiveDate,
}
impl Default for DayInterval {
fn default() -> Self {
Self {
start: (Local::now() - Duration::days(7)).date_naive(),
end: Local::now().date_naive(),
}
}
}
impl DayInterval {
fn days(&self) -> impl Iterator<Item = NaiveDate> {
DayIterator {
current: self.start.clone(),
end: self.end.clone(),
}
}
}
struct DayIterator {
current: NaiveDate,
end: NaiveDate,
}
impl Iterator for DayIterator {
type Item = NaiveDate;
fn next(&mut self) -> Option<Self::Item> {
if self.current <= self.end {
let val = self.current.clone();
self.current += Duration::days(1);
Some(val)
} else {
None
}
} }
} }