/* 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 crate::components::DaySummary; use dimensioned::si::KG; use ft_core::{TraxRecord, Weight}; 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 /// records. pub struct HistoricalViewPrivate {} #[glib::object_subclass] impl ObjectSubclass for HistoricalViewPrivate { const NAME: &'static str = "HistoricalView"; type Type = HistoricalView; type ParentType = gtk::Box; fn new() -> Self { Self {} } } impl ObjectImpl for HistoricalViewPrivate {} impl WidgetImpl for HistoricalViewPrivate {} impl BoxImpl for HistoricalViewPrivate {} glib::wrapper! { pub struct HistoricalView(ObjectSubclass) @extends gtk::Box, gtk::Widget, @implements gtk::Orientable; } impl HistoricalView { 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![TraxRecord::Weight(Weight { date: chrono::NaiveDate::from_ymd_opt(2023, 10, 13).unwrap(), weight: 100. * KG, })], )]; 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()); summary.set_records(records.records()); }); 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() } }