use crate::{
core::{i18n, ni18n_f, Settings, UnitSystem},
model::WeightChange,
plugins::weight::GraphModelWeight,
plugins::{PluginName, PluginSummaryRow},
prelude::*,
};
use adw::prelude::*;
use gtk::{glib, subclass::prelude::*};
use uom::si::mass::{kilogram, pound};
mod imp {
use crate::{core::Database, plugins::PluginSummaryRow, prelude::*, widgets::Arrows};
use adw::subclass::prelude::*;
use gtk::{gio, glib, prelude::*, CompositeTemplate};
#[derive(Debug, CompositeTemplate, Default)]
#[template(resource = "/dev/Cogitri/Health/ui/plugins/weight/summary.ui")]
pub struct PluginWeightSummaryRow {
#[template_child]
pub weight_change: TemplateChild<gtk::Label>,
#[template_child]
pub arrow: TemplateChild<Arrows>,
}
#[glib::object_subclass]
impl ObjectSubclass for PluginWeightSummaryRow {
const NAME: &'static str = "HealthPluginWeightSummaryRow";
type ParentType = PluginSummaryRow;
type Type = super::PluginWeightSummaryRow;
fn class_init(klass: &mut Self::Class) {
Self::bind_template(klass);
}
fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
obj.init_template();
}
}
impl ObjectImpl for PluginWeightSummaryRow {
fn constructed(&self) {
self.parent_constructed();
let obj = self.obj();
Database::instance().connect_weights_updated(glib::clone!(@weak obj => move |_| {
gtk_macros::spawn!(async move {
obj.update().await;
});
}));
}
}
impl WidgetImpl for PluginWeightSummaryRow {}
impl ListBoxRowImpl for PluginWeightSummaryRow {}
impl PreferencesRowImpl for PluginWeightSummaryRow {}
impl ActionRowImpl for PluginWeightSummaryRow {}
impl PluginSummaryRowImpl for PluginWeightSummaryRow {
fn update(&self, obj: &PluginSummaryRow) -> PinnedResultFuture<()> {
Box::pin(gio::GioFuture::new(
obj,
glib::clone!(@weak obj => move |_, _, send| {
gtk_macros::spawn!(async move {
obj.downcast_ref::<super::PluginWeightSummaryRow>()
.unwrap()
.update()
.await;
send.resolve(Ok(()));
});
}),
))
}
}
}
glib::wrapper! {
pub struct PluginWeightSummaryRow(ObjectSubclass<imp::PluginWeightSummaryRow>)
@extends gtk::Widget, gtk::ListBoxRow, adw::PreferencesRow, adw::ActionRow, PluginSummaryRow,
@implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget;
}
impl PluginWeightSummaryRow {
pub fn new(name: PluginName) -> Self {
glib::Object::builder()
.property("plugin-name", &name)
.property("activatable", true)
.build()
}
pub async fn update(&self) {
let imp = self.imp();
let settings = Settings::instance();
let mut weight_model = GraphModelWeight::new();
if let Err(e) = weight_model.reload(glib::TimeSpan::from_days(30)).await {
glib::g_warning!(crate::config::LOG_DOMAIN, "Failed to reload step data: {e}",);
}
if !weight_model.is_empty() {
let last_weight = if settings.unit_system() == UnitSystem::Imperial {
weight_model.last_weight().unwrap().get::<pound>()
} else {
weight_model.last_weight().unwrap().get::<kilogram>()
};
let prev_weight = if settings.unit_system() == UnitSystem::Imperial {
weight_model.penultimate_weight().unwrap().get::<pound>()
} else {
weight_model.penultimate_weight().unwrap().get::<kilogram>()
};
let last_weight_round = last_weight.round_decimal_places(1);
let difference = (last_weight - prev_weight).round_decimal_places(1);
let change = if difference == 0.0 {
WeightChange::NoChange
} else if difference > 0.0 {
WeightChange::Up
} else {
WeightChange::Down
};
imp.arrow.set_weight_change(change);
let subtitle = if settings.unit_system() == UnitSystem::Imperial {
ni18n_f(
"{} pound",
"{} pounds",
last_weight_round as u32,
&[&last_weight_round.to_string()],
)
} else {
ni18n_f(
"{} kilogram",
"{} kilograms",
last_weight_round as u32,
&[&last_weight_round.to_string()],
)
};
self.set_subtitle(&subtitle);
if difference > 0.0 {
let label = if settings.unit_system() == UnitSystem::Imperial {
ni18n_f(
"+ {} pound compared to previous measurement",
"+ {} pounds compared to previous measurement",
difference as u32,
&[&difference.to_string()],
)
} else {
ni18n_f(
"+ {} kilogram compared to previous measurement",
"+ {} kilograms compared to previous measurement",
difference as u32,
&[&difference.to_string()],
)
};
imp.weight_change.set_label(&label)
} else if difference < 0.0 {
let label = if settings.unit_system() == UnitSystem::Imperial {
ni18n_f(
"{} pound compared to previous measurement",
"{} pounds compared to previous measurement",
difference as u32,
&[&difference.to_string()],
)
} else {
ni18n_f(
"{} kilogram compared to previous measurement",
"{} kilograms compared to previous measurement",
difference as u32,
&[&difference.to_string()],
)
};
imp.weight_change.set_label(&label)
} else {
imp.weight_change.set_label(&i18n("No change in weight"));
}
} else {
imp.arrow.set_weight_change(WeightChange::NoChange);
imp.weight_change
.set_label(&i18n("No weight data available"));
}
}
}
#[cfg(test)]
mod test {
use super::{PluginName, PluginWeightSummaryRow};
use crate::utils::init_gtk;
#[gtk::test]
fn new() {
init_gtk();
PluginWeightSummaryRow::new(PluginName::Weight);
}
}