Filter the historical list according to a date picker #194
|
@ -126,15 +126,18 @@ impl DateField {
|
||||||
s.append(&s.imp().month.widget());
|
s.append(&s.imp().month.widget());
|
||||||
s.append(&s.imp().day.widget());
|
s.append(&s.imp().day.widget());
|
||||||
|
|
||||||
s.imp().year.set_value(Some(date.year()));
|
s.set_date(date);
|
||||||
s.imp().month.set_value(Some(date.month()));
|
|
||||||
s.imp().day.set_value(Some(date.day()));
|
|
||||||
|
|
||||||
*s.imp().date.borrow_mut() = date;
|
|
||||||
|
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_date(&self, date: chrono::NaiveDate) {
|
||||||
|
self.imp().year.set_value(Some(date.year()));
|
||||||
|
self.imp().month.set_value(Some(date.month()));
|
||||||
|
self.imp().day.set_value(Some(date.day()));
|
||||||
|
|
||||||
|
*self.imp().date.borrow_mut() = date;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn date(&self) -> chrono::NaiveDate {
|
pub fn date(&self) -> chrono::NaiveDate {
|
||||||
self.imp().date.borrow().clone()
|
self.imp().date.borrow().clone()
|
||||||
|
|
|
@ -0,0 +1,168 @@
|
||||||
|
/*
|
||||||
|
Copyright 2024, Savanni D'Gerinel <savanni@luminescent-dreams.com>
|
||||||
|
|
||||||
|
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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
app::App,
|
||||||
|
components::{DateField, DaySummary},
|
||||||
|
types::DayInterval,
|
||||||
|
view_models::DayDetailViewModel,
|
||||||
|
};
|
||||||
|
use chrono::{Duration, Local, Months};
|
||||||
|
use glib::Object;
|
||||||
|
use gtk::{prelude::*, subclass::prelude::*};
|
||||||
|
use std::{cell::RefCell, rc::Rc};
|
||||||
|
|
||||||
|
type OnSearch = dyn Fn(DayInterval) + 'static;
|
||||||
|
|
||||||
|
pub struct DateRangePickerPrivate {
|
||||||
|
start: DateField,
|
||||||
|
end: DateField,
|
||||||
|
|
||||||
|
on_search: RefCell<Box<OnSearch>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[glib::object_subclass]
|
||||||
|
impl ObjectSubclass for DateRangePickerPrivate {
|
||||||
|
const NAME: &'static str = "DateRangePicker";
|
||||||
|
type Type = DateRangePicker;
|
||||||
|
type ParentType = gtk::Box;
|
||||||
|
|
||||||
|
fn new() -> Self {
|
||||||
|
let default_date = Local::now().date_naive();
|
||||||
|
Self {
|
||||||
|
start: DateField::new(default_date),
|
||||||
|
end: DateField::new(default_date),
|
||||||
|
on_search: RefCell::new(Box::new(|_| {})),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectImpl for DateRangePickerPrivate {}
|
||||||
|
impl WidgetImpl for DateRangePickerPrivate {}
|
||||||
|
impl BoxImpl for DateRangePickerPrivate {}
|
||||||
|
|
||||||
|
glib::wrapper! {
|
||||||
|
pub struct DateRangePicker(ObjectSubclass<DateRangePickerPrivate>) @extends gtk::Box, gtk::Widget, @implements gtk::Orientable;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DateRangePicker {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let s: Self = Object::builder().build();
|
||||||
|
s.set_orientation(gtk::Orientation::Vertical);
|
||||||
|
|
||||||
|
let search_button = gtk::Button::with_label("Search");
|
||||||
|
search_button.connect_clicked({
|
||||||
|
let s = s.clone();
|
||||||
|
move |_| (s.imp().on_search.borrow())(s.interval())
|
||||||
|
});
|
||||||
|
|
||||||
|
let last_week_button = gtk::Button::builder().label("last week").build();
|
||||||
|
last_week_button.connect_clicked({
|
||||||
|
let s = s.clone();
|
||||||
|
move |_| {
|
||||||
|
let end = Local::now().date_naive();
|
||||||
|
let start = end - Duration::days(7);
|
||||||
|
s.set_interval(start, end);
|
||||||
|
(s.imp().on_search.borrow())(s.interval());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let two_weeks_button = gtk::Button::builder().label("last two weeks").build();
|
||||||
|
two_weeks_button.connect_clicked({
|
||||||
|
let s = s.clone();
|
||||||
|
move |_| {
|
||||||
|
let end = Local::now().date_naive();
|
||||||
|
let start = end - Duration::days(14);
|
||||||
|
s.set_interval(start, end);
|
||||||
|
(s.imp().on_search.borrow())(s.interval());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let last_month_button = gtk::Button::builder().label("last month").build();
|
||||||
|
last_month_button.connect_clicked({
|
||||||
|
let s = s.clone();
|
||||||
|
move |_| {
|
||||||
|
let end = Local::now().date_naive();
|
||||||
|
let start = end - Months::new(1);
|
||||||
|
s.set_interval(start, end);
|
||||||
|
(s.imp().on_search.borrow())(s.interval());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let six_months_button = gtk::Button::builder().label("last six months").build();
|
||||||
|
six_months_button.connect_clicked({
|
||||||
|
let s = s.clone();
|
||||||
|
move |_| {
|
||||||
|
let end = Local::now().date_naive();
|
||||||
|
let start = end - Months::new(6);
|
||||||
|
s.set_interval(start, end);
|
||||||
|
(s.imp().on_search.borrow())(s.interval());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let last_year_button = gtk::Button::builder().label("last year").build();
|
||||||
|
last_year_button.connect_clicked({
|
||||||
|
let s = s.clone();
|
||||||
|
move |_| {
|
||||||
|
let end = Local::now().date_naive();
|
||||||
|
let start = end - Months::new(12);
|
||||||
|
s.set_interval(start, end);
|
||||||
|
(s.imp().on_search.borrow())(s.interval());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let date_row = gtk::Box::builder()
|
||||||
|
.orientation(gtk::Orientation::Horizontal)
|
||||||
|
.build();
|
||||||
|
date_row.append(&s.imp().start);
|
||||||
|
date_row.append(>k::Label::new(Some("to")));
|
||||||
|
date_row.append(&s.imp().end);
|
||||||
|
date_row.append(&search_button);
|
||||||
|
|
||||||
|
let quick_picker = gtk::Box::builder()
|
||||||
|
.orientation(gtk::Orientation::Horizontal)
|
||||||
|
.build();
|
||||||
|
quick_picker.append(&last_week_button);
|
||||||
|
quick_picker.append(&two_weeks_button);
|
||||||
|
quick_picker.append(&last_month_button);
|
||||||
|
quick_picker.append(&six_months_button);
|
||||||
|
quick_picker.append(&last_year_button);
|
||||||
|
|
||||||
|
s.append(&date_row);
|
||||||
|
s.append(&quick_picker);
|
||||||
|
|
||||||
|
s
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn connect_on_search<OnSearch>(&self, f: OnSearch)
|
||||||
|
where
|
||||||
|
OnSearch: Fn(DayInterval) + 'static,
|
||||||
|
{
|
||||||
|
*self.imp().on_search.borrow_mut() = Box::new(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_interval(&self, start: chrono::NaiveDate, end: chrono::NaiveDate) {
|
||||||
|
self.imp().start.set_date(start);
|
||||||
|
self.imp().end.set_date(end);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn interval(&self) -> DayInterval {
|
||||||
|
DayInterval {
|
||||||
|
start: self.imp().start.date(),
|
||||||
|
end: self.imp().end.date(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,6 +24,9 @@ pub use day::{DayDetail, DayEdit, DaySummary};
|
||||||
mod date_field;
|
mod date_field;
|
||||||
pub use date_field::DateField;
|
pub use date_field::DateField;
|
||||||
|
|
||||||
|
mod date_range;
|
||||||
|
pub use date_range::DateRangePicker;
|
||||||
|
|
||||||
mod singleton;
|
mod singleton;
|
||||||
pub use singleton::{Singleton, SingletonImpl};
|
pub use singleton::{Singleton, SingletonImpl};
|
||||||
|
|
||||||
|
|
|
@ -16,11 +16,10 @@ You should have received a copy of the GNU General Public License along with Fit
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
app::App,
|
app::App,
|
||||||
components::{DateField, DaySummary},
|
components::{DateRangePicker, DaySummary},
|
||||||
types::DayInterval,
|
types::DayInterval,
|
||||||
view_models::DayDetailViewModel,
|
view_models::DayDetailViewModel,
|
||||||
};
|
};
|
||||||
|
|
||||||
use glib::Object;
|
use glib::Object;
|
||||||
use gtk::{prelude::*, subclass::prelude::*};
|
use gtk::{prelude::*, subclass::prelude::*};
|
||||||
use std::{cell::RefCell, rc::Rc};
|
use std::{cell::RefCell, rc::Rc};
|
||||||
|
@ -109,39 +108,12 @@ impl HistoricalView {
|
||||||
|
|
||||||
*s.imp().app.borrow_mut() = Some(app);
|
*s.imp().app.borrow_mut() = Some(app);
|
||||||
|
|
||||||
let start_date = DateField::new(interval.start);
|
let date_range_picker = DateRangePicker::new();
|
||||||
let end_date = DateField::new(interval.end);
|
date_range_picker.connect_on_search({
|
||||||
let search_button = gtk::Button::with_label("Search");
|
|
||||||
search_button.connect_clicked({
|
|
||||||
let s = s.clone();
|
let s = s.clone();
|
||||||
let start_date = start_date.clone();
|
move |interval| s.set_interval(interval)
|
||||||
let end_date = end_date.clone();
|
|
||||||
move |_| {
|
|
||||||
let interval = DayInterval {
|
|
||||||
start: start_date.date(),
|
|
||||||
end: end_date.date(),
|
|
||||||
};
|
|
||||||
s.set_interval(interval);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let date_row = gtk::Box::builder()
|
|
||||||
.orientation(gtk::Orientation::Horizontal)
|
|
||||||
.build();
|
|
||||||
date_row.append(&start_date);
|
|
||||||
date_row.append(>k::Label::new(Some("to")));
|
|
||||||
date_row.append(&end_date);
|
|
||||||
date_row.append(&search_button);
|
|
||||||
|
|
||||||
let quick_picker = gtk::Box::builder()
|
|
||||||
.orientation(gtk::Orientation::Horizontal)
|
|
||||||
.build();
|
|
||||||
quick_picker.append(>k::Button::builder().label("last week").build());
|
|
||||||
quick_picker.append(>k::Button::builder().label("last two weeks").build());
|
|
||||||
quick_picker.append(>k::Button::builder().label("last month").build());
|
|
||||||
quick_picker.append(>k::Button::builder().label("last six months").build());
|
|
||||||
quick_picker.append(>k::Button::builder().label("last year").build());
|
|
||||||
|
|
||||||
let mut model = gio::ListStore::new::<Date>();
|
let mut model = gio::ListStore::new::<Date>();
|
||||||
model.extend(interval.days().map(Date::new));
|
model.extend(interval.days().map(Date::new));
|
||||||
s.imp()
|
s.imp()
|
||||||
|
@ -158,8 +130,7 @@ impl HistoricalView {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
s.append(&date_row);
|
s.append(&date_range_picker);
|
||||||
s.append(&quick_picker);
|
|
||||||
s.append(&s.imp().list_view);
|
s.append(&s.imp().list_view);
|
||||||
|
|
||||||
s
|
s
|
||||||
|
@ -172,10 +143,6 @@ impl HistoricalView {
|
||||||
.list_view
|
.list_view
|
||||||
.set_model(Some(>k::NoSelection::new(Some(model))));
|
.set_model(Some(>k::NoSelection::new(Some(model))));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn time_window(&self) -> DayInterval {
|
|
||||||
self.imp().time_window.borrow().clone()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
Loading…
Reference in New Issue