Reload data when the user saves on the DayEdit panel
This required some big overhauls. The view model no longer takes records. It only takes the date that it is responsible for, and it will ask the database for records pertaining to that date. This means that once the view model has saved all of its records, it can simply reload those records from the database. This has the effect that as soon as the user moves from DayEdit back to DayDetail, all of the interesting information has been repopulated.
This commit is contained in:
parent
cfc7df5e2f
commit
cb55d6aae0
|
@ -95,6 +95,20 @@ impl App {
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_record(&self, id: RecordId) -> Result<Option<Record<TraxRecord>>, 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]
|
#[async_trait]
|
||||||
|
|
|
@ -135,14 +135,15 @@ impl AppWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_historical_view(&self, interval: DayInterval) {
|
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();
|
let s = self.clone();
|
||||||
Rc::new(move |date| {
|
move |date| {
|
||||||
let s = s.clone();
|
let s = s.clone();
|
||||||
glib::spawn_future_local(async move {
|
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);
|
let layout = gtk::Box::new(gtk::Orientation::Vertical, 0);
|
||||||
layout.append(&adw::HeaderBar::new());
|
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));
|
layout.append(&DayDetailView::new(view_model));
|
||||||
let page = &adw::NavigationPage::builder()
|
let page = &adw::NavigationPage::builder()
|
||||||
.title(date.format("%Y-%m-%d").to_string())
|
.title(date.format("%Y-%m-%d").to_string())
|
||||||
|
@ -150,8 +151,14 @@ impl AppWindow {
|
||||||
.build();
|
.build();
|
||||||
s.navigation.push(page);
|
s.navigation.push(page);
|
||||||
});
|
});
|
||||||
})
|
}
|
||||||
}));
|
};
|
||||||
|
|
||||||
|
let view = View::Historical(HistoricalView::new(
|
||||||
|
self.app.clone(),
|
||||||
|
interval,
|
||||||
|
Rc::new(on_select_day),
|
||||||
|
));
|
||||||
self.swap_main(view);
|
self.swap_main(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -148,31 +148,6 @@ impl DayDetail {
|
||||||
.build(),
|
.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::<WeightView>() {
|
|
||||||
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()
|
let top_row = gtk::Box::builder()
|
||||||
.orientation(gtk::Orientation::Horizontal)
|
.orientation(gtk::Orientation::Horizontal)
|
||||||
.build();
|
.build();
|
||||||
|
@ -272,7 +247,20 @@ impl DayEdit {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish(&self) {
|
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<TraxRecord>) {
|
fn add_row(&self, workout: Record<TraxRecord>) {
|
||||||
|
@ -308,11 +296,7 @@ fn control_buttons(s: &DayEdit, view_model: &DayDetailViewModel) -> ActionGroup
|
||||||
ActionGroup::builder()
|
ActionGroup::builder()
|
||||||
.primary_action("Save", {
|
.primary_action("Save", {
|
||||||
let s = s.clone();
|
let s = s.clone();
|
||||||
let view_model = view_model.clone();
|
move || s.finish()
|
||||||
move || {
|
|
||||||
view_model.save();
|
|
||||||
s.finish();
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.secondary_action("Cancel", {
|
.secondary_action("Cancel", {
|
||||||
let s = s.clone();
|
let s = s.clone();
|
||||||
|
|
|
@ -120,51 +120,15 @@ impl DayDetailViewModel {
|
||||||
date: chrono::NaiveDate,
|
date: chrono::NaiveDate,
|
||||||
provider: impl RecordProvider + 'static,
|
provider: impl RecordProvider + 'static,
|
||||||
) -> Result<Self, ReadError> {
|
) -> Result<Self, ReadError> {
|
||||||
let (weight_records, records): (Vec<Record<TraxRecord>>, Vec<Record<TraxRecord>>) =
|
let s = Self {
|
||||||
provider
|
|
||||||
.records(date, date)
|
|
||||||
.await?
|
|
||||||
.into_iter()
|
|
||||||
.partition(|r| r.data.is_weight());
|
|
||||||
let (step_records, records): (Vec<Record<TraxRecord>>, Vec<Record<TraxRecord>>) =
|
|
||||||
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 {
|
|
||||||
provider: Arc::new(provider),
|
provider: Arc::new(provider),
|
||||||
date,
|
date,
|
||||||
weight: Arc::new(RwLock::new(
|
weight: Arc::new(RwLock::new(None)),
|
||||||
weight_records
|
steps: Arc::new(RwLock::new(None)),
|
||||||
.first()
|
records: Arc::new(RwLock::new(HashMap::new())),
|
||||||
.and_then(|r| match r.data {
|
};
|
||||||
TraxRecord::Weight(ref w) => Some((r.id, w.clone())),
|
s.populate_records().await;
|
||||||
_ => None,
|
Ok(s)
|
||||||
})
|
|
||||||
.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::<HashMap<RecordId, RecordState<TraxRecord>>>(),
|
|
||||||
)),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn weight(&self) -> Option<si::Kilogram<f64>> {
|
pub fn weight(&self) -> Option<si::Kilogram<f64>> {
|
||||||
|
@ -376,6 +340,7 @@ impl DayDetailViewModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.populate_records().await;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn revert(&self) {
|
pub async fn revert(&self) {
|
||||||
|
|
|
@ -18,8 +18,6 @@ use crate::{
|
||||||
app::App, components::DaySummary, types::DayInterval, view_models::DayDetailViewModel,
|
app::App, components::DaySummary, types::DayInterval, view_models::DayDetailViewModel,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
use glib::Object;
|
use glib::Object;
|
||||||
use gtk::{prelude::*, subclass::prelude::*};
|
use gtk::{prelude::*, subclass::prelude::*};
|
||||||
use std::{cell::RefCell, rc::Rc};
|
use std::{cell::RefCell, rc::Rc};
|
||||||
|
@ -60,31 +58,28 @@ impl ObjectSubclass for HistoricalViewPrivate {
|
||||||
factory.connect_bind({
|
factory.connect_bind({
|
||||||
let app = s.app.clone();
|
let app = s.app.clone();
|
||||||
move |_, list_item| {
|
move |_, list_item| {
|
||||||
let app = app.clone();
|
let date = list_item
|
||||||
let list_item = list_item.clone();
|
.downcast_ref::<gtk::ListItem>()
|
||||||
glib::spawn_future_local(async move {
|
.expect("should be a ListItem")
|
||||||
let date = list_item
|
.item()
|
||||||
.downcast_ref::<gtk::ListItem>()
|
.and_downcast::<Date>()
|
||||||
.expect("should be a ListItem")
|
.expect("should be a Date");
|
||||||
.item()
|
|
||||||
.and_downcast::<Date>()
|
|
||||||
.expect("should be a DaySummary");
|
|
||||||
|
|
||||||
let summary = list_item
|
let summary = list_item
|
||||||
.downcast_ref::<gtk::ListItem>()
|
.downcast_ref::<gtk::ListItem>()
|
||||||
.expect("should be a ListItem")
|
.expect("should be a ListItem")
|
||||||
.child()
|
.child()
|
||||||
.and_downcast::<DaySummary>()
|
.and_downcast::<DaySummary>()
|
||||||
.expect("should be a DaySummary");
|
.expect("should be a DaySummary");
|
||||||
|
|
||||||
if let Some(app) = app.borrow().clone() {
|
if let Some(app) = app.borrow().clone() {
|
||||||
glib::spawn_future_local(async move {
|
glib::spawn_future_local(async move {
|
||||||
let view_model =
|
let view_model = DayDetailViewModel::new(date.date(), app.clone())
|
||||||
DayDetailViewModel::new(date.date(), app).await.unwrap();
|
.await
|
||||||
summary.set_data(view_model);
|
.unwrap();
|
||||||
});
|
summary.set_data(view_model);
|
||||||
}
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue