diff --git a/emseries/src/types.rs b/emseries/src/types.rs index 80f215d..018a99b 100644 --- a/emseries/src/types.rs +++ b/emseries/src/types.rs @@ -178,7 +178,7 @@ impl fmt::Display for RecordId { /// directly, as the database will create them. #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] pub struct Record { - pub(crate) id: RecordId, + pub id: RecordId, pub data: T, } diff --git a/fitnesstrax/app/src/app_window.rs b/fitnesstrax/app/src/app_window.rs index 2397d34..534116d 100644 --- a/fitnesstrax/app/src/app_window.rs +++ b/fitnesstrax/app/src/app_window.rs @@ -32,7 +32,6 @@ use std::{cell::RefCell, path::PathBuf, rc::Rc}; #[derive(Clone)] pub struct AppWindow { app: App, - app_id: String, layout: gtk::Box, current_view: Rc>, settings: gio::Settings, @@ -106,7 +105,6 @@ impl AppWindow { let s = Self { app: ft_app, - app_id: app_id.to_owned(), layout, current_view: Rc::new(RefCell::new(initial_view)), settings: gio::Settings::new(app_id), diff --git a/fitnesstrax/app/src/components/day.rs b/fitnesstrax/app/src/components/day.rs index 23da6c2..f6f8b98 100644 --- a/fitnesstrax/app/src/components/day.rs +++ b/fitnesstrax/app/src/components/day.rs @@ -17,10 +17,11 @@ You should have received a copy of the GNU General Public License along with Fit // use chrono::NaiveDate; // use ft_core::TraxRecord; use dimensioned::si; +use emseries::Record; use ft_core::{RecordType, TimeDistance, TraxRecord, Weight}; use glib::Object; use gtk::{prelude::*, subclass::prelude::*}; -use std::cell::RefCell; +use std::{cell::RefCell, rc::Rc}; pub struct DaySummaryPrivate { date: gtk::Label, @@ -66,7 +67,7 @@ impl DaySummary { s } - pub fn set_data(&self, date: chrono::NaiveDate, records: Vec) { + pub fn set_data(&self, date: chrono::NaiveDate, records: Vec>) { self.imp() .date .set_text(&date.format("%Y-%m-%d").to_string()); @@ -75,8 +76,10 @@ impl DaySummary { self.remove(weight_label); } - if let Some(TraxRecord::Weight(weight_record)) = - records.iter().filter(|f| f.is_weight()).next() + if let Some(Record { + data: TraxRecord::Weight(weight_record), + .. + }) = records.iter().filter(|f| f.data.is_weight()).next() { let label = gtk::Label::builder() .halign(gtk::Align::Start) @@ -128,37 +131,71 @@ glib::wrapper! { } impl DayDetail { - pub fn new(date: chrono::NaiveDate, records: Vec) -> Self { + pub fn new(date: chrono::NaiveDate, records: Vec>) -> Self { let s: Self = Object::builder().build(); s.set_orientation(gtk::Orientation::Vertical); + let click_controller = gtk::GestureClick::new(); + click_controller.connect_released({ + let s = s.clone(); + move |_, _, _, _| { + println!("clicked outside of focusable entity"); + if let Some(widget) = s.focus_child().and_downcast_ref::() { + println!("focused child is the weight view"); + widget.blur(); + } + } + }); + s.add_controller(click_controller); + let weight_record = records.iter().find_map(|record| match record { - TraxRecord::Weight(record) => Some(record.clone()), + Record { + id, + data: TraxRecord::Weight(record), + } => Some((id.clone(), record.clone())), _ => None, }); - let weight_view = WeightView::new(weight_record, |weight| { - println!("on_blur on the weight view: {:?}", weight) - }); + let weight_view = match weight_record { + Some((unique_id, record)) => WeightView::new(Some(record), move |weight| { + println!( + "on_blur on the weight view. Need to record {:?}, {:?}", + unique_id, weight + ); + }), + None => WeightView::new(None, |weight| { + println!( + "on_blur on the weight view. Need to create a new record for {:?}", + weight + ); + }), + }; s.append(&weight_view); records.into_iter().for_each(|record| { let record_view = match record { - TraxRecord::BikeRide(record) => Some( + Record { + data: TraxRecord::BikeRide(record), + .. + } => Some( TimeDistanceView::new(RecordType::BikeRide, record).upcast::(), ), - TraxRecord::Row(record) => { - Some(TimeDistanceView::new(RecordType::Row, record).upcast::()) - } - TraxRecord::Run(record) => { - Some(TimeDistanceView::new(RecordType::Row, record).upcast::()) - } - TraxRecord::Swim(record) => { - Some(TimeDistanceView::new(RecordType::Row, record).upcast::()) - } - TraxRecord::Walk(record) => { - Some(TimeDistanceView::new(RecordType::Row, record).upcast::()) - } + Record { + data: TraxRecord::Row(record), + .. + } => Some(TimeDistanceView::new(RecordType::Row, record).upcast::()), + Record { + data: TraxRecord::Run(record), + .. + } => Some(TimeDistanceView::new(RecordType::Row, record).upcast::()), + Record { + data: TraxRecord::Swim(record), + .. + } => Some(TimeDistanceView::new(RecordType::Row, record).upcast::()), + Record { + data: TraxRecord::Walk(record), + .. + } => Some(TimeDistanceView::new(RecordType::Row, record).upcast::()), _ => None, }; @@ -179,6 +216,7 @@ pub struct WeightViewPrivate { view: RefCell, edit: RefCell, current: RefCell, + on_edit_finished: RefCell)>>, } impl Default for WeightViewPrivate { @@ -197,6 +235,7 @@ impl Default for WeightViewPrivate { view: RefCell::new(view), edit: RefCell::new(edit), current: RefCell::new(current.upcast()), + on_edit_finished: RefCell::new(Box::new(|_| {})), } } } @@ -217,12 +256,14 @@ glib::wrapper! { } impl WeightView { - pub fn new(weight: Option, on_blur: OnBlur) -> Self + pub fn new(weight: Option, on_edit_finished: OnEditFinished) -> Self where - OnBlur: Fn(si::Kilogram), + OnEditFinished: Fn(si::Kilogram) + 'static, { let s: Self = Object::builder().build(); + *s.imp().on_edit_finished.borrow_mut() = Box::new(on_edit_finished); + *s.imp().record.borrow_mut() = weight; s.view(); @@ -234,16 +275,7 @@ impl WeightView { } }); - let edit_click_controller = gtk::GestureClick::new(); - edit_click_controller.connect_released({ - let s = s.clone(); - move |_, _, _, _| { - s.view(); - } - }); - s.imp().view.borrow().add_controller(view_click_controller); - s.imp().edit.borrow().add_controller(edit_click_controller); s } @@ -278,6 +310,13 @@ impl WeightView { self.append(&new_view); *current = new_view; } + + fn blur(&self) { + if *self.imp().current.borrow() == *self.imp().edit.borrow() { + self.imp().on_edit_finished.borrow()(0. * si::KG); + self.view(); + } + } } #[derive(Default)] diff --git a/fitnesstrax/app/src/views/historical_view.rs b/fitnesstrax/app/src/views/historical_view.rs index 8583f62..79c85dd 100644 --- a/fitnesstrax/app/src/views/historical_view.rs +++ b/fitnesstrax/app/src/views/historical_view.rs @@ -48,18 +48,13 @@ glib::wrapper! { impl HistoricalView { pub fn new(records: Vec>, on_select_day: Rc) -> Self where - SelectFn: Fn(chrono::NaiveDate, Vec) + 'static, + SelectFn: Fn(chrono::NaiveDate, Vec>) + 'static, { let s: Self = Object::builder().build(); s.set_orientation(gtk::Orientation::Vertical); s.set_css_classes(&["historical"]); - let day_records: GroupedRecords = GroupedRecords::from( - records - .into_iter() - .map(|r| r.data) - .collect::>(), - ); + let day_records: GroupedRecords = GroupedRecords::from(records); let model = gio::ListStore::new::(); model.extend_from_slice(&day_records.0); @@ -116,7 +111,7 @@ impl HistoricalView { #[derive(Default)] pub struct DayRecordsPrivate { date: RefCell, - records: RefCell>, + records: RefCell>>, } #[glib::object_subclass] @@ -132,7 +127,7 @@ glib::wrapper! { } impl DayRecords { - pub fn new(date: chrono::NaiveDate, records: Vec) -> Self { + pub fn new(date: chrono::NaiveDate, records: Vec>) -> Self { let s: Self = Object::builder().build(); *s.imp().date.borrow_mut() = date; @@ -145,30 +140,26 @@ impl DayRecords { self.imp().date.borrow().clone() } - pub fn records(&self) -> Vec { + pub fn records(&self) -> Vec> { self.imp().records.borrow().clone() } - pub fn add_record(&self, record: TraxRecord) { + pub fn add_record(&self, record: Record) { self.imp().records.borrow_mut().push(record); } } struct GroupedRecords(Vec); -impl From> for GroupedRecords { - fn from(records: Vec) -> GroupedRecords { +impl From>> for GroupedRecords { + fn from(records: Vec>) -> GroupedRecords { GroupedRecords( records .into_iter() .fold(HashMap::new(), |mut acc, rec| { - let date = match rec.timestamp() { - Timestamp::DateTime(dtz) => dtz.date_naive(), - Timestamp::Date(date) => date, - }; - acc.entry(date) + acc.entry(rec.date()) .and_modify(|entry: &mut DayRecords| (*entry).add_record(rec.clone())) - .or_insert(DayRecords::new(date, vec![rec])); + .or_insert(DayRecords::new(rec.date(), vec![rec])); acc }) .values()