diff --git a/hammond-gtk/src/app.rs b/hammond-gtk/src/app.rs index 9f10fa4..667fe38 100644 --- a/hammond-gtk/src/app.rs +++ b/hammond-gtk/src/app.rs @@ -10,7 +10,7 @@ use hammond_data::Podcast; use headerbar::Header; use settings::{self, WindowGeometry}; -use stacks::{Content, ShowState}; +use stacks::{Content, PopulatedState}; use utils; use widgets::{mark_all_notif, remove_show_notif}; @@ -171,21 +171,23 @@ impl App { Ok(Action::RefreshEpisodesView) => content.update_home(), Ok(Action::RefreshEpisodesViewBGR) => content.update_home_if_background(), Ok(Action::ReplaceWidget(pd)) => { - let mut shows = content.get_shows(); - shows - .borrow_mut() + let shows = content.get_shows(); + let mut pop = shows.borrow().populated(); + pop.borrow_mut() .replace_widget(pd.clone()) .map_err(|err| error!("Failed to update ShowWidget: {}", err)) .map_err(|_| error!("Failed ot update ShowWidget {}", pd.title())) .ok(); } Ok(Action::ShowWidgetAnimated) => { - let mut shows = content.get_shows(); - shows.borrow_mut().switch_visible(ShowState::ShowWidget); + let shows = content.get_shows(); + let mut pop = shows.borrow().populated(); + pop.borrow_mut().switch_visible(PopulatedState::ShowWidget); } Ok(Action::ShowShowsAnimated) => { - let mut shows = content.get_shows(); - shows.borrow_mut().switch_visible(ShowState::ShowsView); + let shows = content.get_shows(); + let mut pop = shows.borrow().populated(); + pop.borrow_mut().switch_visible(PopulatedState::ShowsView); } Ok(Action::HeaderBarShowTile(title)) => headerbar.switch_to_back(&title), Ok(Action::HeaderBarNormal) => headerbar.switch_to_normal(), diff --git a/hammond-gtk/src/stacks/content.rs b/hammond-gtk/src/stacks/content.rs index c0274c7..a6af0b6 100644 --- a/hammond-gtk/src/stacks/content.rs +++ b/hammond-gtk/src/stacks/content.rs @@ -37,15 +37,14 @@ impl Content { pub fn update(&self) { self.update_home(); - self.update_shows_view(); - self.update_widget() + self.update_shows(); } pub fn update_home(&self) { self.home .borrow_mut() .update() - .map_err(|err| error!("Failed to update EpisodeView: {}", err)) + .map_err(|err| error!("Failed to update HomeView: {}", err)) .ok(); } @@ -55,25 +54,25 @@ impl Content { } } - pub fn update_shows_view(&self) { + fn update_shows(&self) { self.shows .borrow_mut() + .update() + .map_err(|err| error!("Failed to update ShowsView: {}", err)) + .ok(); + } + + pub fn update_shows_view(&self) { + let pop = self.shows.borrow().populated(); + pop.borrow_mut() .update_shows() .map_err(|err| error!("Failed to update ShowsView: {}", err)) .ok(); } - pub fn update_widget(&self) { - self.shows - .borrow_mut() - .update_widget() - .map_err(|err| error!("Failed to update ShowsWidget: {}", err)) - .ok(); - } - pub fn update_widget_if_same(&self, pid: i32) { - self.shows - .borrow_mut() + let pop = self.shows.borrow().populated(); + pop.borrow_mut() .update_widget_if_same(pid) .map_err(|err| error!("Failed to update ShowsWidget: {}", err)) .ok(); diff --git a/hammond-gtk/src/stacks/mod.rs b/hammond-gtk/src/stacks/mod.rs index cfa465b..abab9f8 100644 --- a/hammond-gtk/src/stacks/mod.rs +++ b/hammond-gtk/src/stacks/mod.rs @@ -1,7 +1,9 @@ mod content; mod home; +mod populated; mod show; pub use self::content::Content; pub use self::home::HomeStack; +pub use self::populated::{PopulatedStack, PopulatedState}; pub use self::show::{ShowStack, ShowState}; diff --git a/hammond-gtk/src/stacks/populated.rs b/hammond-gtk/src/stacks/populated.rs new file mode 100644 index 0000000..f713071 --- /dev/null +++ b/hammond-gtk/src/stacks/populated.rs @@ -0,0 +1,154 @@ +use gtk; +use gtk::prelude::*; + +use failure::Error; + +use hammond_data::dbqueries; +use hammond_data::Podcast; + +use app::Action; +use widgets::{ShowWidget, ShowsPopulated}; + +use std::rc::Rc; +use std::sync::mpsc::Sender; +use std::sync::Arc; + +#[derive(Debug, Clone)] +pub enum PopulatedState { + ShowsView, + ShowWidget, +} + +#[derive(Debug, Clone)] +pub struct PopulatedStack { + container: gtk::Box, + populated: Rc, + show: Rc, + stack: gtk::Stack, + state: PopulatedState, + sender: Sender, +} + +impl PopulatedStack { + pub fn new(sender: Sender) -> Result { + let stack = gtk::Stack::new(); + let state = PopulatedState::ShowsView; + let populated = ShowsPopulated::new(sender.clone())?; + let show = Rc::new(ShowWidget::default()); + let container = gtk::Box::new(gtk::Orientation::Horizontal, 0); + + stack.add_named(&populated.container, "shows"); + stack.add_named(&show.container, "widget"); + container.add(&stack); + container.show_all(); + + let show = PopulatedStack { + container, + stack, + populated, + show, + state, + sender, + }; + + Ok(show) + } + + pub fn update(&mut self) { + self.update_widget().map_err(|err| format!("{}", err)).ok(); + self.update_shows().map_err(|err| format!("{}", err)).ok(); + } + + pub fn update_shows(&mut self) -> Result<(), Error> { + let old = &self.populated.container.clone(); + debug!("Name: {:?}", WidgetExt::get_name(old)); + + let pop = ShowsPopulated::new(self.sender.clone())?; + self.populated = pop; + self.stack.remove(old); + self.stack.add_named(&self.populated.container, "shows"); + + // The current visible child might change depending on + // removal and insertion in the gtk::Stack, so we have + // to make sure it will stay the same. + let s = self.state.clone(); + self.switch_visible(s); + + old.destroy(); + Ok(()) + } + + pub fn replace_widget(&mut self, pd: Arc) -> Result<(), Error> { + let old = self.show.container.clone(); + + // save the ShowWidget vertical scrollabar alignment + self.show + .podcast_id() + .map(|id| self.show.save_vadjustment(id)); + + let new = ShowWidget::new(pd, self.sender.clone()); + self.show = new; + self.stack.remove(&old); + self.stack.add_named(&self.show.container, "widget"); + + // The current visible child might change depending on + // removal and insertion in the gtk::Stack, so we have + // to make sure it will stay the same. + let s = self.state.clone(); + self.switch_visible(s); + + Ok(()) + } + + pub fn update_widget(&mut self) -> Result<(), Error> { + let old = self.show.container.clone(); + let id = self.show.podcast_id(); + if id.is_none() { + return Ok(()); + } + + let pd = dbqueries::get_podcast_from_id(id.unwrap_or_default())?; + self.replace_widget(Arc::new(pd))?; + + // The current visible child might change depending on + // removal and insertion in the gtk::Stack, so we have + // to make sure it will stay the same. + let s = self.state.clone(); + self.switch_visible(s); + + old.destroy(); + Ok(()) + } + + // Only update widget if its podcast_id is equal to pid. + pub fn update_widget_if_same(&mut self, pid: i32) -> Result<(), Error> { + if self.show.podcast_id() != Some(pid) { + debug!("Different widget. Early return"); + return Ok(()); + } + + self.update_widget() + } + + pub fn container(&self) -> gtk::Box { + self.container.clone() + } + + #[inline] + pub fn switch_visible(&mut self, state: PopulatedState) { + use self::PopulatedState::*; + + match state { + ShowsView => { + self.stack + .set_visible_child_full("shows", gtk::StackTransitionType::SlideRight); + self.state = ShowsView; + } + ShowWidget => { + self.stack + .set_visible_child_full("widget", gtk::StackTransitionType::SlideLeft); + self.state = ShowWidget; + } + } + } +} diff --git a/hammond-gtk/src/stacks/show.rs b/hammond-gtk/src/stacks/show.rs index 9f0c242..89df1f0 100644 --- a/hammond-gtk/src/stacks/show.rs +++ b/hammond-gtk/src/stacks/show.rs @@ -2,148 +2,92 @@ use gtk; use gtk::prelude::*; use failure::Error; - -use hammond_data::dbqueries; -use hammond_data::Podcast; +use hammond_data::dbqueries::is_podcasts_populated; use app::Action; -use widgets::{ShowWidget, ShowsPopulated}; +use stacks::PopulatedStack; +use widgets::EmptyView; +use std::cell::RefCell; use std::rc::Rc; use std::sync::mpsc::Sender; -use std::sync::Arc; #[derive(Debug, Clone)] pub enum ShowState { - ShowsView, - ShowWidget, + Populated, + Empty, } #[derive(Debug, Clone)] pub struct ShowStack { - populated: Rc, - show: Rc, + empty: EmptyView, + populated: Rc>, stack: gtk::Stack, state: ShowState, sender: Sender, } impl ShowStack { - pub fn new(sender: Sender) -> Result { + pub fn new(sender: Sender) -> Result { + let populated = Rc::new(RefCell::new(PopulatedStack::new(sender.clone())?)); + let empty = EmptyView::new(); let stack = gtk::Stack::new(); - let state = ShowState::ShowsView; - let populated = ShowsPopulated::new(sender.clone())?; - let show = Rc::new(ShowWidget::default()); + let state = ShowState::Empty; - stack.add_named(&populated.container, "shows"); - stack.add_named(&show.container, "widget"); + stack.add_named(&populated.borrow().container(), "populated"); + stack.add_named(&empty.container, "empty"); - let show = ShowStack { - stack, + let mut show = ShowStack { + empty, populated, - show, + stack, state, sender, }; + show.determine_state()?; Ok(show) } - // pub fn update(&self) { - // self.update_widget(); - // self.update_podcasts(); - // } - - pub fn update_shows(&mut self) -> Result<(), Error> { - let old = &self.populated.container.clone(); - debug!("Name: {:?}", WidgetExt::get_name(old)); - - let pop = ShowsPopulated::new(self.sender.clone())?; - self.populated = pop; - self.stack.remove(old); - self.stack.add_named(&self.populated.container, "shows"); - - // The current visible child might change depending on - // removal and insertion in the gtk::Stack, so we have - // to make sure it will stay the same. - let s = self.state.clone(); - self.switch_visible(s); - - old.destroy(); - Ok(()) - } - - pub fn replace_widget(&mut self, pd: Arc) -> Result<(), Error> { - let old = self.show.container.clone(); - - // save the ShowWidget vertical scrollabar alignment - self.show - .podcast_id() - .map(|id| self.show.save_vadjustment(id)); - - let new = ShowWidget::new(pd, self.sender.clone()); - self.show = new; - self.stack.remove(&old); - self.stack.add_named(&self.show.container, "widget"); - - // The current visible child might change depending on - // removal and insertion in the gtk::Stack, so we have - // to make sure it will stay the same. - let s = self.state.clone(); - self.switch_visible(s); - - Ok(()) - } - - pub fn update_widget(&mut self) -> Result<(), Error> { - let old = self.show.container.clone(); - let id = self.show.podcast_id(); - if id.is_none() { - return Ok(()); - } - - let pd = dbqueries::get_podcast_from_id(id.unwrap_or_default())?; - self.replace_widget(Arc::new(pd))?; - - // The current visible child might change depending on - // removal and insertion in the gtk::Stack, so we have - // to make sure it will stay the same. - let s = self.state.clone(); - self.switch_visible(s); - - old.destroy(); - Ok(()) - } - - // Only update widget if its podcast_id is equal to pid. - pub fn update_widget_if_same(&mut self, pid: i32) -> Result<(), Error> { - if self.show.podcast_id() != Some(pid) { - debug!("Different widget. Early return"); - return Ok(()); - } - - self.update_widget() - } - pub fn get_stack(&self) -> gtk::Stack { self.stack.clone() } + pub fn populated(&self) -> Rc> { + self.populated.clone() + } + + pub fn update(&mut self) -> Result<(), Error> { + self.populated.borrow_mut().update(); + self.determine_state() + } + #[inline] - pub fn switch_visible(&mut self, state: ShowState) { + fn switch_visible(&mut self, s: ShowState) { use self::ShowState::*; - match state { - ShowsView => { - self.stack - .set_visible_child_full("shows", gtk::StackTransitionType::SlideRight); - self.state = ShowsView; + match s { + Populated => { + self.stack.set_visible_child_name("populated"); + self.state = Populated; } - ShowWidget => { - self.stack - .set_visible_child_full("widget", gtk::StackTransitionType::SlideLeft); - self.state = ShowWidget; + Empty => { + self.stack.set_visible_child_name("empty"); + self.state = Empty; } - } + }; + } + + #[inline] + fn determine_state(&mut self) -> Result<(), Error> { + use self::ShowState::*; + + if is_podcasts_populated()? { + self.switch_visible(Populated); + } else { + self.switch_visible(Empty); + }; + + Ok(()) } }