Create Duration and Distance structures to handle rendering

These structures handle parsing and rendering of a Duration and a Distance, allowing that knowledge to be centralized and reused. Then I'm using those structures in a variety of places in order to ensure that the information gets rendered consistently.
This commit is contained in:
Savanni D'Gerinel 2024-01-29 08:26:41 -05:00
parent 76f4b31466
commit 9fc9d2b758
3 changed files with 26 additions and 21 deletions

View File

@ -20,7 +20,7 @@ use crate::{
components::{
steps_editor, time_distance_summary, weight_field, ActionGroup, Steps, WeightLabel,
},
types::WeightFormatter,
types::{DistanceFormatter, DurationFormatter, WeightFormatter},
view_models::DayDetailViewModel,
};
use emseries::{Record, RecordId};
@ -106,7 +106,10 @@ impl DaySummary {
self.append(&row);
let biking_summary = view_model.time_distance_summary(TimeDistanceActivity::BikeRide);
if let Some(label) = time_distance_summary(biking_summary.0, biking_summary.1) {
if let Some(label) = time_distance_summary(
DistanceFormatter::from(biking_summary.0),
DurationFormatter::from(biking_summary.1),
) {
self.append(&label);
}
}
@ -397,7 +400,7 @@ where
biking_button.connect_clicked({
let view_model = view_model.clone();
move |_| {
let workout = view_model.new_time_distance(TimeDistanceActivity::Walking);
let workout = view_model.new_time_distance(TimeDistanceActivity::BikeRide);
add_row(workout.map(TraxRecord::TimeDistance));
}
});

View File

@ -19,7 +19,7 @@ You should have received a copy of the GNU General Public License along with Fit
// use dimensioned::si;
use crate::{
components::{distance_field, duration_field, time_field},
types::{DistanceFormatter, DurationFormatter, TimeFormatter},
types::{DistanceFormatter, DurationFormatter, FormatOption, TimeFormatter},
};
use dimensioned::si;
use ft_core::{TimeDistance, TimeDistanceActivity};
@ -28,20 +28,17 @@ use gtk::{prelude::*, subclass::prelude::*};
use std::{cell::RefCell, rc::Rc};
pub fn time_distance_summary(
distance: si::Meter<f64>,
duration: si::Second<f64>,
distance: DistanceFormatter,
duration: DurationFormatter,
) -> Option<gtk::Label> {
let text = match (distance > si::M, duration > si::S) {
let text = match (*distance > si::M, *duration > si::S) {
(true, true) => Some(format!(
"{} kilometers of biking in {} minutes",
distance.value_unsafe / 1000.,
duration.value_unsafe / 60.
"{} of biking in {}",
distance.format(FormatOption::Full),
duration.format(FormatOption::Full)
)),
(true, false) => Some(format!(
"{} kilometers of biking",
distance.value_unsafe / 1000.
)),
(false, true) => Some(format!("{} seconds of biking", duration.value_unsafe / 60.)),
(true, false) => Some(format!("{} of biking", distance.format(FormatOption::Full))),
(false, true) => Some(format!("{} of biking", duration.format(FormatOption::Full))),
(false, false) => None,
};
@ -75,7 +72,7 @@ pub fn time_distance_detail(record: ft_core::TimeDistance) -> gtk::Box {
.label(
record
.distance
.map(|dist| format!("{}", dist))
.map(|dist| DistanceFormatter::from(dist).format(FormatOption::Abbreviated))
.unwrap_or("".to_owned()),
)
.build(),
@ -87,7 +84,9 @@ pub fn time_distance_detail(record: ft_core::TimeDistance) -> gtk::Box {
.label(
record
.duration
.map(|duration| format!("{}", duration))
.map(|duration| {
DurationFormatter::from(duration).format(FormatOption::Abbreviated)
})
.unwrap_or("".to_owned()),
)
.build(),

View File

@ -14,10 +14,7 @@ General Public License for more details.
You should have received a copy of the GNU General Public License along with FitnessTrax. If not, see <https://www.gnu.org/licenses/>.
*/
#[allow(unused_imports)]
use crate::app::{ReadError, RecordProvider, WriteError};
#[allow(unused_imports)]
use chrono::NaiveDate;
use crate::app::{ReadError, RecordProvider};
use dimensioned::si;
use emseries::{Record, RecordId, Recordable};
use ft_core::{TimeDistance, TimeDistanceActivity, TraxRecord};
@ -27,6 +24,12 @@ use std::{
sync::{Arc, RwLock},
};
// These are actually a used imports. Clippy isn't detecting their use, probably because of complexity around the async trait macros.
#[allow(unused_imports)]
use crate::app::WriteError;
#[allow(unused_imports)]
use chrono::NaiveDate;
#[derive(Clone, Debug)]
enum RecordState<T: Clone + Recordable> {
Original(Record<T>),