diff --git a/fitnesstrax/app/src/app.rs b/fitnesstrax/app/src/app.rs index 2aafc94..94c83b8 100644 --- a/fitnesstrax/app/src/app.rs +++ b/fitnesstrax/app/src/app.rs @@ -95,6 +95,20 @@ impl App { .await .unwrap() } + + pub async fn get_record(&self, id: RecordId) -> Result>, AppError> { + let db = self.database.clone(); + self.runtime + .spawn_blocking(move || { + if let Some(ref db) = *db.read().unwrap() { + Ok(db.get(&id)) + } else { + Err(AppError::NoDatabase) + } + }) + .await + .unwrap() + } } #[async_trait] diff --git a/fitnesstrax/app/src/app_window.rs b/fitnesstrax/app/src/app_window.rs index d372119..238e2f3 100644 --- a/fitnesstrax/app/src/app_window.rs +++ b/fitnesstrax/app/src/app_window.rs @@ -135,14 +135,15 @@ impl AppWindow { } fn show_historical_view(&self, interval: DayInterval) { - let view = View::Historical(HistoricalView::new(self.app.clone(), interval, { + let on_select_day = { let s = self.clone(); - Rc::new(move |date| { + move |date| { let s = s.clone(); glib::spawn_future_local(async move { + let view_model = DayDetailViewModel::new(date, s.app.clone()).await.unwrap(); let layout = gtk::Box::new(gtk::Orientation::Vertical, 0); layout.append(&adw::HeaderBar::new()); - let view_model = DayDetailViewModel::new(date, s.app.clone()).await.unwrap(); + // layout.append(&DayDetailView::new(date, records, s.app.clone())); layout.append(&DayDetailView::new(view_model)); let page = &adw::NavigationPage::builder() .title(date.format("%Y-%m-%d").to_string()) @@ -150,8 +151,14 @@ impl AppWindow { .build(); s.navigation.push(page); }); - }) - })); + } + }; + + let view = View::Historical(HistoricalView::new( + self.app.clone(), + interval, + Rc::new(on_select_day), + )); self.swap_main(view); } diff --git a/fitnesstrax/app/src/components/day.rs b/fitnesstrax/app/src/components/day.rs index bef67bf..a2cfd1e 100644 --- a/fitnesstrax/app/src/components/day.rs +++ b/fitnesstrax/app/src/components/day.rs @@ -148,31 +148,6 @@ impl DayDetail { .build(), ); - /* - 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 { - Record { - id, - data: ft_core::TraxRecord::Weight(record), - } => Some((id.clone(), record.clone())), - _ => None, - }); - */ - let top_row = gtk::Box::builder() .orientation(gtk::Orientation::Horizontal) .build(); @@ -272,7 +247,20 @@ impl DayEdit { } fn finish(&self) { - (self.imp().on_finished.borrow())() + glib::spawn_future_local({ + let s = self.clone(); + async move { + let view_model = { + let view_model = s.imp().view_model.borrow(); + view_model + .as_ref() + .expect("DayEdit has not been initialized with the view model") + .clone() + }; + let _ = view_model.async_save().await; + (s.imp().on_finished.borrow())() + } + }); } fn add_row(&self, workout: Record) { @@ -308,11 +296,7 @@ fn control_buttons(s: &DayEdit, view_model: &DayDetailViewModel) -> ActionGroup ActionGroup::builder() .primary_action("Save", { let s = s.clone(); - let view_model = view_model.clone(); - move || { - view_model.save(); - s.finish(); - } + move || s.finish() }) .secondary_action("Cancel", { let s = s.clone(); diff --git a/fitnesstrax/app/src/view_models/day_detail.rs b/fitnesstrax/app/src/view_models/day_detail.rs index 7e17388..21688c0 100644 --- a/fitnesstrax/app/src/view_models/day_detail.rs +++ b/fitnesstrax/app/src/view_models/day_detail.rs @@ -120,51 +120,15 @@ impl DayDetailViewModel { date: chrono::NaiveDate, provider: impl RecordProvider + 'static, ) -> Result { - let (weight_records, records): (Vec>, Vec>) = - provider - .records(date, date) - .await? - .into_iter() - .partition(|r| r.data.is_weight()); - let (step_records, records): (Vec>, Vec>) = - records.into_iter().partition(|r| r.data.is_steps()); - - if weight_records.len() > 1 { - eprintln!("warning: multiple weight records found for {}. This is unsupported and the one presented is unpredictable.", date.format("%Y-%m-%d")); - } - if step_records.len() > 1 { - eprintln!("warning: multiple step records found for {}. This is unsupported and the one presented is unpredictable.", date.format("%Y-%m-%d")); - } - - Ok(Self { + let s = Self { provider: Arc::new(provider), date, - weight: Arc::new(RwLock::new( - weight_records - .first() - .and_then(|r| match r.data { - TraxRecord::Weight(ref w) => Some((r.id, w.clone())), - _ => None, - }) - .map(|(id, w)| RecordState::Original(Record { id, data: w })), - )), - steps: Arc::new(RwLock::new( - step_records - .first() - .and_then(|r| match r.data { - TraxRecord::Steps(ref w) => Some((r.id, w.clone())), - _ => None, - }) - .map(|(id, w)| RecordState::Original(Record { id, data: w })), - )), - - records: Arc::new(RwLock::new( - records - .into_iter() - .map(|r| (r.id, RecordState::Original(r))) - .collect::>>(), - )), - }) + weight: Arc::new(RwLock::new(None)), + steps: Arc::new(RwLock::new(None)), + records: Arc::new(RwLock::new(HashMap::new())), + }; + s.populate_records().await; + Ok(s) } pub fn weight(&self) -> Option> { @@ -377,6 +341,7 @@ impl DayDetailViewModel { } } } + self.populate_records().await; } pub async fn revert(&self) { diff --git a/fitnesstrax/app/src/views/historical_view.rs b/fitnesstrax/app/src/views/historical_view.rs index 46fbab6..ead6184 100644 --- a/fitnesstrax/app/src/views/historical_view.rs +++ b/fitnesstrax/app/src/views/historical_view.rs @@ -18,8 +18,6 @@ use crate::{ app::App, components::DaySummary, types::DayInterval, view_models::DayDetailViewModel, }; - - use glib::Object; use gtk::{prelude::*, subclass::prelude::*}; use std::{cell::RefCell, rc::Rc}; @@ -60,31 +58,28 @@ impl ObjectSubclass for HistoricalViewPrivate { factory.connect_bind({ let app = s.app.clone(); move |_, list_item| { - let app = app.clone(); - let list_item = list_item.clone(); - glib::spawn_future_local(async move { - let date = list_item - .downcast_ref::() - .expect("should be a ListItem") - .item() - .and_downcast::() - .expect("should be a DaySummary"); + let date = list_item + .downcast_ref::() + .expect("should be a ListItem") + .item() + .and_downcast::() + .expect("should be a Date"); - let summary = list_item - .downcast_ref::() - .expect("should be a ListItem") - .child() - .and_downcast::() - .expect("should be a DaySummary"); + let summary = list_item + .downcast_ref::() + .expect("should be a ListItem") + .child() + .and_downcast::() + .expect("should be a DaySummary"); - if let Some(app) = app.borrow().clone() { - glib::spawn_future_local(async move { - let view_model = - DayDetailViewModel::new(date.date(), app).await.unwrap(); - summary.set_data(view_model); - }); - } - }); + if let Some(app) = app.borrow().clone() { + glib::spawn_future_local(async move { + let view_model = DayDetailViewModel::new(date.date(), app.clone()) + .await + .unwrap(); + summary.set_data(view_model); + }); + } } });