h-gtk: Restructure the stacks structure.
This commit reimplements support for the empty view in the ShowStack. The current structure is the following: * A Content stack which holds the HomeStack and the ShowStack. It's what is used in the headerbar StackSwitcher. * The HomeStack is composed of the HomeView and an EmptyView. * The ShowStack is composed of the PopulatedStack and an EmptyView. * The PopulatedStack is composed of the ShowsView and the ShowWidget currently. An AboutEpisode widget is planned to be added here also.
This commit is contained in:
parent
734f85a517
commit
3d160fc35c
@ -10,7 +10,7 @@ use hammond_data::Podcast;
|
|||||||
|
|
||||||
use headerbar::Header;
|
use headerbar::Header;
|
||||||
use settings::{self, WindowGeometry};
|
use settings::{self, WindowGeometry};
|
||||||
use stacks::{Content, ShowState};
|
use stacks::{Content, PopulatedState};
|
||||||
use utils;
|
use utils;
|
||||||
use widgets::{mark_all_notif, remove_show_notif};
|
use widgets::{mark_all_notif, remove_show_notif};
|
||||||
|
|
||||||
@ -171,21 +171,23 @@ impl App {
|
|||||||
Ok(Action::RefreshEpisodesView) => content.update_home(),
|
Ok(Action::RefreshEpisodesView) => content.update_home(),
|
||||||
Ok(Action::RefreshEpisodesViewBGR) => content.update_home_if_background(),
|
Ok(Action::RefreshEpisodesViewBGR) => content.update_home_if_background(),
|
||||||
Ok(Action::ReplaceWidget(pd)) => {
|
Ok(Action::ReplaceWidget(pd)) => {
|
||||||
let mut shows = content.get_shows();
|
let shows = content.get_shows();
|
||||||
shows
|
let mut pop = shows.borrow().populated();
|
||||||
.borrow_mut()
|
pop.borrow_mut()
|
||||||
.replace_widget(pd.clone())
|
.replace_widget(pd.clone())
|
||||||
.map_err(|err| error!("Failed to update ShowWidget: {}", err))
|
.map_err(|err| error!("Failed to update ShowWidget: {}", err))
|
||||||
.map_err(|_| error!("Failed ot update ShowWidget {}", pd.title()))
|
.map_err(|_| error!("Failed ot update ShowWidget {}", pd.title()))
|
||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
Ok(Action::ShowWidgetAnimated) => {
|
Ok(Action::ShowWidgetAnimated) => {
|
||||||
let mut shows = content.get_shows();
|
let shows = content.get_shows();
|
||||||
shows.borrow_mut().switch_visible(ShowState::ShowWidget);
|
let mut pop = shows.borrow().populated();
|
||||||
|
pop.borrow_mut().switch_visible(PopulatedState::ShowWidget);
|
||||||
}
|
}
|
||||||
Ok(Action::ShowShowsAnimated) => {
|
Ok(Action::ShowShowsAnimated) => {
|
||||||
let mut shows = content.get_shows();
|
let shows = content.get_shows();
|
||||||
shows.borrow_mut().switch_visible(ShowState::ShowsView);
|
let mut pop = shows.borrow().populated();
|
||||||
|
pop.borrow_mut().switch_visible(PopulatedState::ShowsView);
|
||||||
}
|
}
|
||||||
Ok(Action::HeaderBarShowTile(title)) => headerbar.switch_to_back(&title),
|
Ok(Action::HeaderBarShowTile(title)) => headerbar.switch_to_back(&title),
|
||||||
Ok(Action::HeaderBarNormal) => headerbar.switch_to_normal(),
|
Ok(Action::HeaderBarNormal) => headerbar.switch_to_normal(),
|
||||||
|
|||||||
@ -37,15 +37,14 @@ impl Content {
|
|||||||
|
|
||||||
pub fn update(&self) {
|
pub fn update(&self) {
|
||||||
self.update_home();
|
self.update_home();
|
||||||
self.update_shows_view();
|
self.update_shows();
|
||||||
self.update_widget()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_home(&self) {
|
pub fn update_home(&self) {
|
||||||
self.home
|
self.home
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.update()
|
.update()
|
||||||
.map_err(|err| error!("Failed to update EpisodeView: {}", err))
|
.map_err(|err| error!("Failed to update HomeView: {}", err))
|
||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,25 +54,25 @@ impl Content {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_shows_view(&self) {
|
fn update_shows(&self) {
|
||||||
self.shows
|
self.shows
|
||||||
.borrow_mut()
|
.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()
|
.update_shows()
|
||||||
.map_err(|err| error!("Failed to update ShowsView: {}", err))
|
.map_err(|err| error!("Failed to update ShowsView: {}", err))
|
||||||
.ok();
|
.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) {
|
pub fn update_widget_if_same(&self, pid: i32) {
|
||||||
self.shows
|
let pop = self.shows.borrow().populated();
|
||||||
.borrow_mut()
|
pop.borrow_mut()
|
||||||
.update_widget_if_same(pid)
|
.update_widget_if_same(pid)
|
||||||
.map_err(|err| error!("Failed to update ShowsWidget: {}", err))
|
.map_err(|err| error!("Failed to update ShowsWidget: {}", err))
|
||||||
.ok();
|
.ok();
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
mod content;
|
mod content;
|
||||||
mod home;
|
mod home;
|
||||||
|
mod populated;
|
||||||
mod show;
|
mod show;
|
||||||
|
|
||||||
pub use self::content::Content;
|
pub use self::content::Content;
|
||||||
pub use self::home::HomeStack;
|
pub use self::home::HomeStack;
|
||||||
|
pub use self::populated::{PopulatedStack, PopulatedState};
|
||||||
pub use self::show::{ShowStack, ShowState};
|
pub use self::show::{ShowStack, ShowState};
|
||||||
|
|||||||
154
hammond-gtk/src/stacks/populated.rs
Normal file
154
hammond-gtk/src/stacks/populated.rs
Normal file
@ -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<ShowsPopulated>,
|
||||||
|
show: Rc<ShowWidget>,
|
||||||
|
stack: gtk::Stack,
|
||||||
|
state: PopulatedState,
|
||||||
|
sender: Sender<Action>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PopulatedStack {
|
||||||
|
pub fn new(sender: Sender<Action>) -> Result<PopulatedStack, Error> {
|
||||||
|
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<Podcast>) -> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,148 +2,92 @@ use gtk;
|
|||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
|
|
||||||
use failure::Error;
|
use failure::Error;
|
||||||
|
use hammond_data::dbqueries::is_podcasts_populated;
|
||||||
use hammond_data::dbqueries;
|
|
||||||
use hammond_data::Podcast;
|
|
||||||
|
|
||||||
use app::Action;
|
use app::Action;
|
||||||
use widgets::{ShowWidget, ShowsPopulated};
|
use stacks::PopulatedStack;
|
||||||
|
use widgets::EmptyView;
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::mpsc::Sender;
|
use std::sync::mpsc::Sender;
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum ShowState {
|
pub enum ShowState {
|
||||||
ShowsView,
|
Populated,
|
||||||
ShowWidget,
|
Empty,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ShowStack {
|
pub struct ShowStack {
|
||||||
populated: Rc<ShowsPopulated>,
|
empty: EmptyView,
|
||||||
show: Rc<ShowWidget>,
|
populated: Rc<RefCell<PopulatedStack>>,
|
||||||
stack: gtk::Stack,
|
stack: gtk::Stack,
|
||||||
state: ShowState,
|
state: ShowState,
|
||||||
sender: Sender<Action>,
|
sender: Sender<Action>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ShowStack {
|
impl ShowStack {
|
||||||
pub fn new(sender: Sender<Action>) -> Result<ShowStack, Error> {
|
pub fn new(sender: Sender<Action>) -> Result<Self, Error> {
|
||||||
|
let populated = Rc::new(RefCell::new(PopulatedStack::new(sender.clone())?));
|
||||||
|
let empty = EmptyView::new();
|
||||||
let stack = gtk::Stack::new();
|
let stack = gtk::Stack::new();
|
||||||
let state = ShowState::ShowsView;
|
let state = ShowState::Empty;
|
||||||
let populated = ShowsPopulated::new(sender.clone())?;
|
|
||||||
let show = Rc::new(ShowWidget::default());
|
|
||||||
|
|
||||||
stack.add_named(&populated.container, "shows");
|
stack.add_named(&populated.borrow().container(), "populated");
|
||||||
stack.add_named(&show.container, "widget");
|
stack.add_named(&empty.container, "empty");
|
||||||
|
|
||||||
let show = ShowStack {
|
let mut show = ShowStack {
|
||||||
stack,
|
empty,
|
||||||
populated,
|
populated,
|
||||||
show,
|
stack,
|
||||||
state,
|
state,
|
||||||
sender,
|
sender,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
show.determine_state()?;
|
||||||
Ok(show)
|
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<Podcast>) -> 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 {
|
pub fn get_stack(&self) -> gtk::Stack {
|
||||||
self.stack.clone()
|
self.stack.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn populated(&self) -> Rc<RefCell<PopulatedStack>> {
|
||||||
|
self.populated.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(&mut self) -> Result<(), Error> {
|
||||||
|
self.populated.borrow_mut().update();
|
||||||
|
self.determine_state()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn switch_visible(&mut self, state: ShowState) {
|
fn switch_visible(&mut self, s: ShowState) {
|
||||||
use self::ShowState::*;
|
use self::ShowState::*;
|
||||||
|
|
||||||
match state {
|
match s {
|
||||||
ShowsView => {
|
Populated => {
|
||||||
self.stack
|
self.stack.set_visible_child_name("populated");
|
||||||
.set_visible_child_full("shows", gtk::StackTransitionType::SlideRight);
|
self.state = Populated;
|
||||||
self.state = ShowsView;
|
|
||||||
}
|
}
|
||||||
ShowWidget => {
|
Empty => {
|
||||||
self.stack
|
self.stack.set_visible_child_name("empty");
|
||||||
.set_visible_child_full("widget", gtk::StackTransitionType::SlideLeft);
|
self.state = Empty;
|
||||||
self.state = ShowWidget;
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user