2024-02-10 16:38:25 +00:00
/*
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/>.
* /
2024-02-18 21:59:14 +00:00
use crate ::{ components ::{ i32_field_builder , TextEntry , month_field_builder } , types ::ParseError } ;
2024-02-15 14:11:34 +00:00
use chrono ::{ Datelike , Local } ;
use glib ::Object ;
use gtk ::{ prelude ::* , subclass ::prelude ::* } ;
2024-02-10 16:38:25 +00:00
use std ::{ cell ::RefCell , rc ::Rc } ;
2024-02-15 14:11:34 +00:00
pub struct DateFieldPrivate {
2024-02-16 14:16:42 +00:00
date : Rc < RefCell < chrono ::NaiveDate > > ,
2024-02-15 14:11:34 +00:00
year : TextEntry < i32 > ,
month : TextEntry < u32 > ,
day : TextEntry < u32 > ,
}
#[ glib::object_subclass ]
impl ObjectSubclass for DateFieldPrivate {
const NAME : & 'static str = " DateField " ;
type Type = DateField ;
type ParentType = gtk ::Box ;
fn new ( ) -> Self {
2024-02-16 14:16:42 +00:00
let date = Rc ::new ( RefCell ::new ( Local ::now ( ) . date_naive ( ) ) ) ;
2024-02-18 21:59:14 +00:00
let year = i32_field_builder ( )
. with_value ( date . borrow ( ) . year ( ) )
. with_on_update (
2024-02-16 14:16:42 +00:00
{
let date = date . clone ( ) ;
move | value | {
if let Some ( year ) = value {
let mut date = date . borrow_mut ( ) ;
if let Some ( new_date ) = date . with_year ( year ) {
* date = new_date ;
}
}
}
2024-02-18 21:59:14 +00:00
} )
. with_length ( 4 )
. with_css_classes ( vec! [ " date-field__year " . to_owned ( ) ] ) . build ( ) ;
2024-02-16 14:16:42 +00:00
2024-02-18 21:59:14 +00:00
let month = month_field_builder ( )
. with_value ( date . borrow ( ) . month ( ) )
. with_on_update (
2024-02-16 14:16:42 +00:00
{
let date = date . clone ( ) ;
move | value | {
if let Some ( month ) = value {
let mut date = date . borrow_mut ( ) ;
if let Some ( new_date ) = date . with_month ( month ) {
* date = new_date ;
}
}
}
2024-02-18 21:59:14 +00:00
} )
. with_css_classes ( vec! [ " date-field__month " . to_owned ( ) ] )
. build ( ) ;
2024-02-16 14:16:42 +00:00
/* Modify this so that it enforces the number of days per month */
2024-02-18 21:59:14 +00:00
let day = TextEntry ::builder ( )
. with_placeholder ( " day " . to_owned ( ) )
. with_value ( date . borrow ( ) . day ( ) )
. with_renderer ( | v | format! ( " {} " , v ) )
. with_parser ( | v | v . parse ::< u32 > ( ) . map_err ( | _ | ParseError ) )
. with_on_update ( {
2024-02-16 14:16:42 +00:00
let date = date . clone ( ) ;
move | value | {
if let Some ( day ) = value {
let mut date = date . borrow_mut ( ) ;
if let Some ( new_date ) = date . with_day ( day ) {
* date = new_date ;
}
}
}
2024-02-18 21:59:14 +00:00
} )
. with_css_classes ( vec! [ " date-field__day " . to_owned ( ) ] )
. build ( ) ;
2024-02-15 14:11:34 +00:00
Self {
2024-02-16 14:16:42 +00:00
date ,
2024-02-15 14:11:34 +00:00
year ,
month ,
day ,
}
}
2024-02-16 14:16:42 +00:00
2024-02-10 16:38:25 +00:00
}
2024-02-15 14:11:34 +00:00
impl ObjectImpl for DateFieldPrivate { }
impl WidgetImpl for DateFieldPrivate { }
impl BoxImpl for DateFieldPrivate { }
glib ::wrapper! {
pub struct DateField ( ObjectSubclass < DateFieldPrivate > ) @ extends gtk ::Box , gtk ::Widget ;
}
/* Render a date in the format 2006 Jan 01. The entire date is editable. When the user moves to one part of the date, it will be erased and replaced with a grey placeholder.
* /
2024-02-10 16:38:25 +00:00
impl DateField {
pub fn new ( date : chrono ::NaiveDate ) -> Self {
2024-02-15 14:11:34 +00:00
let s : Self = Object ::builder ( ) . build ( ) ;
println! ( " {} " , date ) ;
2024-02-10 16:38:25 +00:00
2024-02-15 14:11:34 +00:00
s . append ( & s . imp ( ) . year . widget ( ) ) ;
s . append ( & s . imp ( ) . month . widget ( ) ) ;
s . append ( & s . imp ( ) . day . widget ( ) ) ;
2024-02-16 23:21:34 +00:00
s . set_date ( date ) ;
2024-02-10 16:38:25 +00:00
s
}
2024-02-16 23:21:34 +00:00
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 ;
}
2024-02-16 14:16:42 +00:00
pub fn date ( & self ) -> chrono ::NaiveDate {
2024-02-18 16:28:40 +00:00
* self . imp ( ) . date . borrow ( )
2024-02-16 14:16:42 +00:00
}
/*
pub fn is_valid ( & self ) -> bool {
false
}
* /
}
2024-02-10 16:38:25 +00:00
2024-02-15 14:11:34 +00:00
#[ cfg(test) ]
mod test {
use super ::* ;
use crate ::gtk_init ::gtk_init ;
2024-02-16 14:16:42 +00:00
// Enabling this test pushes tests on the TextField into an infinite loop. That likely indicates a bad interaction within the TextField itself, and that is going to need to be fixed.
#[ test ]
#[ ignore ]
fn it_allows_valid_dates ( ) {
let reference = chrono ::NaiveDate ::from_ymd_opt ( 2006 , 01 , 02 ) . unwrap ( ) ;
let field = DateField ::new ( reference ) ;
field . imp ( ) . year . set_value ( Some ( 2023 ) ) ;
field . imp ( ) . month . set_value ( Some ( 10 ) ) ;
field . imp ( ) . day . set_value ( Some ( 13 ) ) ;
2024-02-18 21:59:14 +00:00
// assert!(field.is_valid());
2024-02-16 14:16:42 +00:00
}
#[ test ]
#[ ignore ]
fn it_disallows_out_of_range_months ( ) {
unimplemented! ( )
}
#[ test ]
#[ ignore ]
fn it_allows_days_within_range_for_month ( ) {
unimplemented! ( )
}
2024-02-10 16:38:25 +00:00
}