// TODO: Things that should be done. // // * Wherever there's a function that take 2 or more arguments of the same type, // eg: fn new(total_size: gtk::Label, local_size: gtk::Label ..) // Wrap the types into Struct-tuples and imple deref so it won't be possible to pass // the wrong argument to the wrong position. use chrono; use gtk; use gtk::prelude::*; #[derive(Debug, Clone)] pub struct UnInitialized; #[derive(Debug, Clone)] pub struct Shown; #[derive(Debug, Clone)] pub struct Hidden; pub trait Visibility {} impl Visibility for Shown {} impl Visibility for Hidden {} impl From for Shown { fn from(_: Hidden) -> Self { Shown {} } } impl From for Hidden { fn from(_: Shown) -> Self { Hidden {} } } impl Into for UnInitialized { fn into(self) -> Hidden { Hidden {} } } impl Into for UnInitialized { fn into(self) -> Shown { Shown {} } } #[derive(Debug, Clone)] pub struct Normal; #[derive(Debug, Clone)] pub struct GreyedOut; impl From for GreyedOut { fn from(_: Normal) -> Self { GreyedOut {} } } impl From for Normal { fn from(_: GreyedOut) -> Self { Normal {} } } #[derive(Debug, Clone)] pub struct Title { title: gtk::Label, state: S, } impl Title { #[allow(unused_must_use)] // This does not need to be &mut since gtk-rs does not model ownership // But I think it wouldn't heart if we treat it as a Rust api. fn set_title(&mut self, s: &str) { self.title.set_text(s); } } impl Title { fn new(title: gtk::Label) -> Self { Title { title, state: Normal {}, } } } impl From> for Title { fn from(f: Title) -> Self { f.title .get_style_context() .map(|c| c.add_class("dim-label")); Title { title: f.title, state: f.state.into(), } } } impl From> for Title { fn from(f: Title) -> Self { f.title .get_style_context() .map(|c| c.remove_class("dim-label")); Title { title: f.title, state: f.state.into(), } } } #[derive(Debug, Clone)] pub enum TitleMachine { Normal(Title), GreyedOut(Title), } impl TitleMachine { pub fn new(label: gtk::Label, is_played: bool) -> Self { let m = TitleMachine::Normal(Title::::new(label)); m.determine_state(is_played) } pub fn determine_state(self, is_played: bool) -> Self { use self::TitleMachine::*; match (self, is_played) { (title @ Normal(_), false) => title, (title @ GreyedOut(_), true) => title, (Normal(val), true) => GreyedOut(val.into()), (GreyedOut(val), false) => Normal(val.into()), } } pub fn set_title(&mut self, s: &str) { use self::TitleMachine::*; match *self { Normal(ref mut val) => val.set_title(s), GreyedOut(ref mut val) => val.set_title(s), } } } #[derive(Debug, Clone)] pub struct Duration { // TODO: make duration and separator diff types duration: gtk::Label, separator: gtk::Label, state: S, } impl Duration { // This needs a better name. // TODO: make me mut fn set_duration(&self, minutes: i64) { self.duration.set_text(&format!("{} min", minutes)); } } impl Duration { fn new(duration: gtk::Label, separator: gtk::Label) -> Self { duration.hide(); separator.hide(); Duration { duration, separator, state: Hidden {}, } } } impl From> for Duration { fn from(f: Duration) -> Self { f.duration.show(); f.separator.show(); Duration { duration: f.duration, separator: f.separator, state: f.state.into(), } } } impl From> for Duration { fn from(f: Duration) -> Self { f.duration.hide(); f.separator.hide(); Duration { duration: f.duration, separator: f.separator, state: f.state.into(), } } } #[derive(Debug, Clone)] pub enum DurationMachine { Hidden(Duration), Shown(Duration), } impl DurationMachine { pub fn new(duration: gtk::Label, separator: gtk::Label, seconds: Option) -> Self { let m = DurationMachine::Hidden(Duration::::new(duration, separator)); m.determine_state(seconds) } pub fn determine_state(self, seconds: Option) -> Self { match (self, seconds) { (DurationMachine::Hidden(val), None) => DurationMachine::Hidden(val.into()), (DurationMachine::Shown(val), None) => DurationMachine::Hidden(val.into()), (DurationMachine::Hidden(val), Some(s)) => { let minutes = chrono::Duration::seconds(s.into()).num_minutes(); if minutes == 0 { DurationMachine::Hidden(val.into()) } else { val.set_duration(minutes); DurationMachine::Shown(val.into()) } } (DurationMachine::Shown(val), Some(s)) => { let minutes = chrono::Duration::seconds(s.into()).num_minutes(); if minutes == 0 { DurationMachine::Hidden(val.into()) } else { val.set_duration(minutes); DurationMachine::Shown(val.into()) } } } } } #[derive(Debug, Clone)] pub struct Size { size: gtk::Label, separator: gtk::Label, state: S, } impl Size { fn set_size(self, s: &str) -> Size { self.size.set_text(s); self.separator.show(); self.into() } } impl Size { fn set_size(self, s: &str) -> Size { self.size.set_text(s); self.separator.show(); self.into() } } impl Size { fn new(size: gtk::Label, separator: gtk::Label) -> Self { size.hide(); separator.hide(); Size { size, separator, state: UnInitialized {}, } } fn set_size(self, s: &str) -> Size { self.size.set_text(s); self.separator.show(); self.into() } } impl From> for Size { fn from(f: Size) -> Self { f.size.hide(); f.separator.hide(); Size { size: f.size, separator: f.separator, state: f.state.into(), } } } impl From> for Size { fn from(f: Size) -> Self { f.size.show(); f.separator.show(); Size { size: f.size, separator: f.separator, state: f.state.into(), } } } impl From> for Size { /// This is suposed to be called only from Size::::set_size. fn from(f: Size) -> Self { f.size.show(); f.separator.show(); Size { size: f.size, separator: f.separator, state: f.state.into(), } } } impl From> for Size { /// This is suposed to be called only from Size::::set_size. fn from(f: Size) -> Self { f.size.hide(); f.separator.hide(); Size { size: f.size, separator: f.separator, state: f.state.into(), } } } #[derive(Debug, Clone)] pub struct Download; #[derive(Debug, Clone)] pub struct Play; #[derive(Debug, Clone)] // FIXME: Needs better name. // Should each button also has it's own type and machine? pub struct DownloadPlay { play: gtk::Button, download: gtk::Button, state: S, } impl DownloadPlay { fn new(play: gtk::Button, download: gtk::Button) -> Self { play.hide(); download.hide(); DownloadPlay { play, download, state: UnInitialized {}, } } } impl From> for DownloadPlay { fn from(f: DownloadPlay) -> Self { f.play.hide(); f.download.show(); DownloadPlay { play: f.play, download: f.download, state: Download {}, } } } impl From> for DownloadPlay { fn from(f: DownloadPlay) -> Self { f.play.show(); f.download.hide(); DownloadPlay { play: f.play, download: f.download, state: Play {}, } } } impl From> for DownloadPlay { fn from(f: DownloadPlay) -> Self { f.play.hide(); f.download.hide(); DownloadPlay { play: f.play, download: f.download, state: Hidden {}, } } } impl From> for DownloadPlay { fn from(f: DownloadPlay) -> Self { f.play.hide(); f.download.hide(); DownloadPlay { play: f.play, download: f.download, state: Hidden {}, } } } impl From> for DownloadPlay { fn from(f: DownloadPlay) -> Self { f.play.hide(); f.download.show(); DownloadPlay { play: f.play, download: f.download, state: Download {}, } } } impl From> for DownloadPlay { fn from(f: DownloadPlay) -> Self { f.play.show(); f.download.show(); DownloadPlay { play: f.play, download: f.download, state: Play {}, } } } impl From> for DownloadPlay { fn from(f: DownloadPlay) -> Self { f.play.hide(); f.download.show(); DownloadPlay { play: f.play, download: f.download, state: Download {}, } } } impl From> for DownloadPlay { fn from(f: DownloadPlay) -> Self { f.play.show(); f.download.show(); DownloadPlay { play: f.play, download: f.download, state: Play {}, } } } impl From> for DownloadPlay { fn from(f: DownloadPlay) -> Self { f.play.hide(); f.download.hide(); DownloadPlay { play: f.play, download: f.download, state: Hidden {}, } } } #[derive(Debug, Clone)] pub struct Progress { bar: gtk::ProgressBar, cancel: gtk::Button, local_size: gtk::Label, prog_separator: gtk::Label, state: S, } impl Progress { fn new( bar: gtk::ProgressBar, cancel: gtk::Button, local_size: gtk::Label, prog_separator: gtk::Label, ) -> Self { bar.hide(); cancel.hide(); local_size.hide(); prog_separator.hide(); Progress { bar, cancel, local_size, prog_separator, state: UnInitialized {}, } } } impl From> for Progress { fn from(f: Progress) -> Self { f.bar.show(); f.cancel.show(); f.local_size.show(); f.prog_separator.show(); Progress { bar: f.bar, cancel: f.cancel, local_size: f.local_size, prog_separator: f.prog_separator, state: Shown {}, } } } impl From> for Progress { fn from(f: Progress) -> Self { f.bar.hide(); f.cancel.hide(); f.local_size.hide(); f.prog_separator.hide(); Progress { bar: f.bar, cancel: f.cancel, local_size: f.local_size, prog_separator: f.prog_separator, state: Hidden {}, } } } impl From> for Progress { fn from(f: Progress) -> Self { f.bar.show(); f.cancel.show(); f.local_size.show(); f.prog_separator.show(); Progress { bar: f.bar, cancel: f.cancel, local_size: f.local_size, prog_separator: f.prog_separator, state: Shown {}, } } } impl From> for Progress { fn from(f: Progress) -> Self { f.bar.hide(); f.cancel.hide(); f.local_size.hide(); f.prog_separator.hide(); Progress { bar: f.bar, cancel: f.cancel, local_size: f.local_size, prog_separator: f.prog_separator, state: Hidden {}, } } } #[derive(Debug, Clone)] pub struct Media { dl: DownloadPlay, size: Size, progress: Progress, } // From New from InProgress impl From> for Media { fn from(f: Media) -> Self { Media { dl: f.dl.into(), size: f.size.into(), progress: f.progress.into(), } } } // From NewWithoutSize from InProgress impl From