Render and be able to edit bike rides (and sorta other time distance workouts) #169
|
@ -95,6 +95,20 @@ impl App {
|
|||
.await
|
||||
.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]
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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::<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()
|
||||
.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<TraxRecord>) {
|
||||
|
@ -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();
|
||||
|
|
|
@ -120,51 +120,15 @@ impl DayDetailViewModel {
|
|||
date: chrono::NaiveDate,
|
||||
provider: impl RecordProvider + 'static,
|
||||
) -> Result<Self, ReadError> {
|
||||
let (weight_records, records): (Vec<Record<TraxRecord>>, Vec<Record<TraxRecord>>) =
|
||||
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 {
|
||||
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::<HashMap<RecordId, RecordState<TraxRecord>>>(),
|
||||
)),
|
||||
})
|
||||
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<si::Kilogram<f64>> {
|
||||
|
@ -377,6 +341,7 @@ impl DayDetailViewModel {
|
|||
}
|
||||
}
|
||||
}
|
||||
self.populate_records().await;
|
||||
}
|
||||
|
||||
pub async fn revert(&self) {
|
||||
|
|
|
@ -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::<gtk::ListItem>()
|
||||
.expect("should be a ListItem")
|
||||
.item()
|
||||
.and_downcast::<Date>()
|
||||
.expect("should be a DaySummary");
|
||||
let date = list_item
|
||||
.downcast_ref::<gtk::ListItem>()
|
||||
.expect("should be a ListItem")
|
||||
.item()
|
||||
.and_downcast::<Date>()
|
||||
.expect("should be a Date");
|
||||
|
||||
let summary = list_item
|
||||
.downcast_ref::<gtk::ListItem>()
|
||||
.expect("should be a ListItem")
|
||||
.child()
|
||||
.and_downcast::<DaySummary>()
|
||||
.expect("should be a DaySummary");
|
||||
let summary = list_item
|
||||
.downcast_ref::<gtk::ListItem>()
|
||||
.expect("should be a ListItem")
|
||||
.child()
|
||||
.and_downcast::<DaySummary>()
|
||||
.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);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue