EpisodeWidget: Add a Date state machine.

This commit is contained in:
Jordan Petridis 2018-02-19 18:14:34 +00:00
parent a88a1c5f1f
commit c856b88008
No known key found for this signature in database
GPG Key ID: CEABAD9F5683B9A6
2 changed files with 127 additions and 37 deletions

View File

@ -1,11 +1,9 @@
use glib; use glib;
use gtk; use gtk;
use chrono::prelude::*;
use gtk::prelude::*; use gtk::prelude::*;
use failure::Error; use failure::Error;
use humansize::{file_size_opts as size_opts, FileSize}; use humansize::FileSize;
use open; use open;
use take_mut; use take_mut;
@ -22,30 +20,10 @@ use std::path::Path;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::sync::mpsc::Sender; use std::sync::mpsc::Sender;
lazy_static! {
pub static ref SIZE_OPTS: Arc<size_opts::FileSizeOpts> = {
// Declare a custom humansize option struct
// See: https://docs.rs/humansize/1.0.2/humansize/file_size_opts/struct.FileSizeOpts.html
Arc::new(size_opts::FileSizeOpts {
divider: size_opts::Kilo::Binary,
units: size_opts::Kilo::Decimal,
decimal_places: 0,
decimal_zeroes: 0,
fixed_at: size_opts::FixedAt::No,
long_units: false,
space: true,
suffix: "",
allow_negative: false,
})
};
static ref NOW: DateTime<Utc> = Utc::now();
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct EpisodeWidget { pub struct EpisodeWidget {
pub container: gtk::Box, pub container: gtk::Box,
date: gtk::Label, date: Arc<Mutex<DateMachine>>,
title: Arc<Mutex<TitleMachine>>, title: Arc<Mutex<TitleMachine>>,
duration: Arc<Mutex<DurationMachine>>, duration: Arc<Mutex<DurationMachine>>,
media: Arc<Mutex<MediaMachine>>, media: Arc<Mutex<MediaMachine>>,
@ -73,6 +51,7 @@ impl Default for EpisodeWidget {
let prog_separator: gtk::Label = builder.get_object("prog_separator").unwrap(); let prog_separator: gtk::Label = builder.get_object("prog_separator").unwrap();
let title_machine = Arc::new(Mutex::new(TitleMachine::new(title, false))); let title_machine = Arc::new(Mutex::new(TitleMachine::new(title, false)));
let date_machine = Arc::new(Mutex::new(DateMachine::new(date, 0)));
let dur = DurationMachine::new(duration, separator1, None); let dur = DurationMachine::new(duration, separator1, None);
let duration_machine = Arc::new(Mutex::new(dur)); let duration_machine = Arc::new(Mutex::new(dur));
let _media = MediaMachine::new( let _media = MediaMachine::new(
@ -91,7 +70,7 @@ impl Default for EpisodeWidget {
container, container,
title: title_machine, title: title_machine,
duration: duration_machine, duration: duration_machine,
date, date: date_machine,
media: media_machine, media: media_machine,
} }
} }
@ -108,11 +87,13 @@ impl EpisodeWidget {
WidgetExt::set_name(&self.container, &episode.rowid().to_string()); WidgetExt::set_name(&self.container, &episode.rowid().to_string());
// Set the date label. // Set the date label.
self.set_date(episode.epoch()); if let Err(err) = self.set_date(episode.epoch()) {
error!("Failed to determine date state: {}", err);
}
// Set the title label state. // Set the title label state.
if let Err(err) = self.set_title(&episode) { if let Err(err) = self.set_title(&episode) {
error!("Failed to set title state: {}", err); error!("Failed to determine title state: {}", err);
} }
// Set the duaration label. // Set the duaration label.
@ -166,14 +147,12 @@ impl EpisodeWidget {
} }
/// Set the date label depending on the current time. /// Set the date label depending on the current time.
fn set_date(&self, epoch: i32) { fn set_date(&self, epoch: i32) -> Result<(), Error> {
let date = Utc.timestamp(i64::from(epoch), 0); let mut lock = self.date.lock().map_err(|err| format_err!("{}", err))?;
if NOW.year() == date.year() { take_mut::take(lock.deref_mut(), |date| {
self.date.set_text(date.format("%e %b").to_string().trim()); date.determine_state(i64::from(epoch))
} else { });
self.date Ok(())
.set_text(date.format("%e %b %Y").to_string().trim());
};
} }
/// Set the duration label. /// Set the duration label.

View File

@ -8,13 +8,34 @@
use chrono; use chrono;
use glib; use glib;
use gtk; use gtk;
use chrono::prelude::*;
use gtk::prelude::*; use gtk::prelude::*;
use humansize::FileSize; use humansize::{file_size_opts as size_opts, FileSize};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use manager::Progress as OtherProgress; use manager::Progress as OtherProgress;
use widgets::episode::SIZE_OPTS;
lazy_static! {
pub static ref SIZE_OPTS: Arc<size_opts::FileSizeOpts> = {
// Declare a custom humansize option struct
// See: https://docs.rs/humansize/1.0.2/humansize/file_size_opts/struct.FileSizeOpts.html
Arc::new(size_opts::FileSizeOpts {
divider: size_opts::Kilo::Binary,
units: size_opts::Kilo::Decimal,
decimal_places: 0,
decimal_zeroes: 0,
fixed_at: size_opts::FixedAt::No,
long_units: false,
space: true,
suffix: "",
allow_negative: false,
})
};
static ref NOW: DateTime<Utc> = Utc::now();
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct UnInitialized; pub struct UnInitialized;
@ -153,6 +174,96 @@ impl TitleMachine {
} }
} }
#[derive(Debug, Clone)]
pub struct Usual;
#[derive(Debug, Clone)]
pub struct YearShown;
impl From<Usual> for YearShown {
fn from(_: Usual) -> Self {
YearShown {}
}
}
impl From<YearShown> for Usual {
fn from(_: YearShown) -> Self {
Usual {}
}
}
#[derive(Debug, Clone)]
pub struct Date<S> {
date: gtk::Label,
epoch: i64,
state: S,
}
impl Date<Usual> {
fn new(date: gtk::Label, epoch: i64) -> Self {
let ts = Utc.timestamp(i64::from(epoch), 0);
date.set_text(ts.format("%e %b").to_string().trim());
Date {
date,
epoch,
state: Usual {},
}
}
}
impl From<Date<Usual>> for Date<YearShown> {
fn from(f: Date<Usual>) -> Self {
let ts = Utc.timestamp(f.epoch, 0);
f.date.set_text(ts.format("%e %b %Y").to_string().trim());
Date {
date: f.date,
epoch: f.epoch,
state: YearShown {},
}
}
}
impl From<Date<YearShown>> for Date<Usual> {
fn from(f: Date<YearShown>) -> Self {
let ts = Utc.timestamp(f.epoch, 0);
f.date.set_text(ts.format("%e %b").to_string().trim());
Date {
date: f.date,
epoch: f.epoch,
state: Usual {},
}
}
}
#[derive(Debug, Clone)]
pub enum DateMachine {
Usual(Date<Usual>),
WithYear(Date<YearShown>),
}
impl DateMachine {
pub fn new(label: gtk::Label, epoch: i64) -> Self {
let m = DateMachine::Usual(Date::<Usual>::new(label, epoch));
m.determine_state(epoch)
}
pub fn determine_state(self, epoch: i64) -> Self {
use self::DateMachine::*;
let ts = Utc.timestamp(epoch, 0);
let is_old = NOW.year() == ts.year();
match (self, is_old) {
(date @ Usual(_), false) => date,
(date @ WithYear(_), true) => date,
(Usual(val), true) => WithYear(val.into()),
(WithYear(val), false) => Usual(val.into()),
}
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Duration<S: Visibility> { pub struct Duration<S: Visibility> {
// TODO: make duration and separator diff types // TODO: make duration and separator diff types