EpisodeWidget: Add a Date state machine.
This commit is contained in:
parent
a88a1c5f1f
commit
c856b88008
@ -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.
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user