From 43cd408e2cb4812fcc90a6219afc028afe3d9649 Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Fri, 22 Dec 2023 17:32:45 -0500 Subject: [PATCH] Start elaborating upon the HistoricalView I've created the DaySummary structure and set up a list view to go into the historical view. One hard-coded date is visible as a placeholder to start filling things into the day summary. --- Cargo.lock | 1 + fitnesstrax/app/Cargo.toml | 1 + fitnesstrax/app/src/app_window.rs | 2 +- fitnesstrax/app/src/components/day.rs | 63 ++++++++++++++ fitnesstrax/app/src/components/mod.rs | 3 + fitnesstrax/app/src/views/historical_view.rs | 87 +++++++++++++++++++- 6 files changed, 154 insertions(+), 3 deletions(-) create mode 100644 fitnesstrax/app/src/components/day.rs diff --git a/Cargo.lock b/Cargo.lock index fe046b8..acdedd3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1021,6 +1021,7 @@ name = "fitnesstrax" version = "0.1.0" dependencies = [ "async-channel", + "chrono", "emseries", "ft-core", "gio", diff --git a/fitnesstrax/app/Cargo.toml b/fitnesstrax/app/Cargo.toml index b450f5d..3f36189 100644 --- a/fitnesstrax/app/Cargo.toml +++ b/fitnesstrax/app/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" [dependencies] adw = { version = "0.5", package = "libadwaita", features = [ "v1_2" ] } async-channel = { version = "2.1" } +chrono = { version = "0.4" } emseries = { path = "../../emseries" } ft-core = { path = "../core" } gio = { version = "0.18" } diff --git a/fitnesstrax/app/src/app_window.rs b/fitnesstrax/app/src/app_window.rs index c6d834b..a7651ae 100644 --- a/fitnesstrax/app/src/app_window.rs +++ b/fitnesstrax/app/src/app_window.rs @@ -144,7 +144,7 @@ impl AppWindow { }) .upcast(), ), - ViewName::Historical => View::Historical(HistoricalView::new().upcast()), + ViewName::Historical => View::Historical(HistoricalView::new(vec![]).upcast()), } } } diff --git a/fitnesstrax/app/src/components/day.rs b/fitnesstrax/app/src/components/day.rs new file mode 100644 index 0000000..3b8bb75 --- /dev/null +++ b/fitnesstrax/app/src/components/day.rs @@ -0,0 +1,63 @@ +/* +Copyright 2023, Savanni D'Gerinel + +This file is part of FitnessTrax. + +FitnessTrax is free software: you can redistribute it and/or modify it under the terms of the GNU +General Public License as published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +FitnessTrax is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License along with FitnessTrax. If not, see . +*/ + +// use chrono::NaiveDate; +// use ft_core::TraxRecord; +use glib::Object; +use gtk::{prelude::*, subclass::prelude::*}; + +#[derive(Default)] +pub struct DaySummaryPrivate { + date: gtk::Label, +} + +#[glib::object_subclass] +impl ObjectSubclass for DaySummaryPrivate { + const NAME: &'static str = "DaySummary"; + type Type = DaySummary; + type ParentType = gtk::Box; + + fn new() -> Self { + Self { + date: gtk::Label::new(None), + } + } +} + +impl ObjectImpl for DaySummaryPrivate {} +impl WidgetImpl for DaySummaryPrivate {} +impl BoxImpl for DaySummaryPrivate {} + +glib::wrapper! { + pub struct DaySummary(ObjectSubclass) @extends gtk::Box, gtk::Widget, @implements gtk::Orientable; +} + +impl DaySummary { + pub fn new() -> Self { + let s: Self = Object::builder().build(); + s.set_orientation(gtk::Orientation::Vertical); + + s.append(&s.imp().date); + + s + } + + pub fn set_date(&self, date: chrono::NaiveDate) { + self.imp() + .date + .set_text(&date.format("%y-%m-%d").to_string()); + } +} diff --git a/fitnesstrax/app/src/components/mod.rs b/fitnesstrax/app/src/components/mod.rs index 7fcba76..858f6c2 100644 --- a/fitnesstrax/app/src/components/mod.rs +++ b/fitnesstrax/app/src/components/mod.rs @@ -14,6 +14,9 @@ General Public License for more details. You should have received a copy of the GNU General Public License along with FitnessTrax. If not, see . */ +mod day; + +pub use day::DaySummary; use glib::Object; use gtk::{prelude::*, subclass::prelude::*}; use std::{cell::RefCell, path::PathBuf, rc::Rc}; diff --git a/fitnesstrax/app/src/views/historical_view.rs b/fitnesstrax/app/src/views/historical_view.rs index b69e960..89cd6a3 100644 --- a/fitnesstrax/app/src/views/historical_view.rs +++ b/fitnesstrax/app/src/views/historical_view.rs @@ -14,8 +14,11 @@ General Public License for more details. You should have received a copy of the GNU General Public License along with FitnessTrax. If not, see . */ +use crate::components::DaySummary; +use ft_core::TraxRecord; use glib::Object; use gtk::{prelude::*, subclass::prelude::*}; +use std::cell::RefCell; /// The historical view will show a window into the main database. It will show some version of /// daily summaries, daily details, and will provide all functions the user may need for editing @@ -38,17 +41,97 @@ impl WidgetImpl for HistoricalViewPrivate {} impl BoxImpl for HistoricalViewPrivate {} glib::wrapper! { - pub struct HistoricalView(ObjectSubclass) @extends gtk::Box, gtk::Widget; + pub struct HistoricalView(ObjectSubclass) @extends gtk::Box, gtk::Widget, @implements gtk::Orientable; } impl HistoricalView { - pub fn new() -> Self { + pub fn new(_records: Vec) -> Self { let s: Self = Object::builder().build(); + s.set_orientation(gtk::Orientation::Vertical); let label = gtk::Label::builder() .label("Database has been configured and now it is time to show data") .build(); s.append(&label); + + let day_records: Vec = vec![DayRecords::new( + chrono::NaiveDate::from_ymd_opt(2023, 10, 13).unwrap(), + vec![], + )]; + + let model = gio::ListStore::new::(); + model.extend_from_slice(&day_records); + + let factory = gtk::SignalListItemFactory::new(); + factory.connect_setup(move |_, list_item| { + list_item + .downcast_ref::() + .expect("should be a ListItem") + .set_child(Some(&DaySummary::new())); + }); + + factory.connect_bind(move |_, list_item| { + let records = list_item + .downcast_ref::() + .expect("should be a ListItem") + .item() + .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"); + + summary.set_date(records.date()); + }); + + let lst = gtk::ListView::builder() + .model(>k::NoSelection::new(Some(model))) + .factory(&factory) + .build(); + + s.append(&lst); + s } } + +#[derive(Default)] +pub struct DayRecordsPrivate { + date: RefCell, + records: RefCell>, +} + +#[glib::object_subclass] +impl ObjectSubclass for DayRecordsPrivate { + const NAME: &'static str = "DayRecords"; + type Type = DayRecords; +} + +impl ObjectImpl for DayRecordsPrivate {} + +glib::wrapper! { + pub struct DayRecords(ObjectSubclass); +} + +impl DayRecords { + pub fn new(date: chrono::NaiveDate, records: Vec) -> Self { + let s: Self = Object::builder().build(); + + *s.imp().date.borrow_mut() = date; + *s.imp().records.borrow_mut() = records; + + s + } + + pub fn date(&self) -> chrono::NaiveDate { + self.imp().date.borrow().clone() + } + + pub fn records(&self) -> Vec { + self.imp().records.borrow().clone() + } +}