h-gtk: Refactor part of the ShowStack.
This commit is contained in:
parent
173d2d3a3a
commit
6406c3af13
@ -24,8 +24,6 @@ pub enum Action {
|
|||||||
RefreshEpisodesView,
|
RefreshEpisodesView,
|
||||||
RefreshEpisodesViewBGR,
|
RefreshEpisodesViewBGR,
|
||||||
RefreshShowsView,
|
RefreshShowsView,
|
||||||
RefreshWidget,
|
|
||||||
RefreshWidgetIfVis,
|
|
||||||
ReplaceWidget(Arc<Podcast>),
|
ReplaceWidget(Arc<Podcast>),
|
||||||
RefreshWidgetIfSame(i32),
|
RefreshWidgetIfSame(i32),
|
||||||
ShowWidgetAnimated,
|
ShowWidgetAnimated,
|
||||||
@ -36,7 +34,6 @@ pub enum Action {
|
|||||||
HeaderBarHideUpdateIndicator,
|
HeaderBarHideUpdateIndicator,
|
||||||
MarkAllPlayerNotification(Arc<Podcast>),
|
MarkAllPlayerNotification(Arc<Podcast>),
|
||||||
RemoveShow(Arc<Podcast>),
|
RemoveShow(Arc<Podcast>),
|
||||||
SetShowWidgetAlignment(Arc<Podcast>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -170,21 +167,26 @@ impl App {
|
|||||||
match receiver.try_recv() {
|
match receiver.try_recv() {
|
||||||
Ok(Action::RefreshAllViews) => content.update(),
|
Ok(Action::RefreshAllViews) => content.update(),
|
||||||
Ok(Action::RefreshShowsView) => content.update_shows_view(),
|
Ok(Action::RefreshShowsView) => content.update_shows_view(),
|
||||||
Ok(Action::RefreshWidget) => content.update_widget(),
|
|
||||||
Ok(Action::RefreshWidgetIfVis) => content.update_widget_if_visible(),
|
|
||||||
Ok(Action::RefreshWidgetIfSame(id)) => content.update_widget_if_same(id),
|
Ok(Action::RefreshWidgetIfSame(id)) => content.update_widget_if_same(id),
|
||||||
Ok(Action::RefreshEpisodesView) => content.update_episode_view(),
|
Ok(Action::RefreshEpisodesView) => content.update_episode_view(),
|
||||||
Ok(Action::RefreshEpisodesViewBGR) => content.update_episode_view_if_baground(),
|
Ok(Action::RefreshEpisodesViewBGR) => content.update_episode_view_if_baground(),
|
||||||
Ok(Action::ReplaceWidget(pd)) => {
|
Ok(Action::ReplaceWidget(pd)) => {
|
||||||
content
|
let mut shows = content.get_shows();
|
||||||
.get_shows()
|
shows
|
||||||
|
.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) => content.get_shows().switch_widget_animated(),
|
Ok(Action::ShowWidgetAnimated) => {
|
||||||
Ok(Action::ShowShowsAnimated) => content.get_shows().switch_podcasts_animated(),
|
let mut shows = content.get_shows();
|
||||||
|
shows.borrow().switch_widget_animated();
|
||||||
|
}
|
||||||
|
Ok(Action::ShowShowsAnimated) => {
|
||||||
|
let mut shows = content.get_shows();
|
||||||
|
shows.borrow().switch_podcasts_animated();
|
||||||
|
}
|
||||||
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(),
|
||||||
Ok(Action::HeaderBarShowUpdateIndicator) => headerbar.show_update_notification(),
|
Ok(Action::HeaderBarShowUpdateIndicator) => headerbar.show_update_notification(),
|
||||||
@ -197,13 +199,6 @@ impl App {
|
|||||||
let notif = remove_show_notif(pd, sender.clone());
|
let notif = remove_show_notif(pd, sender.clone());
|
||||||
notif.show(&overlay);
|
notif.show(&overlay);
|
||||||
}
|
}
|
||||||
Ok(Action::SetShowWidgetAlignment(pd)) => {
|
|
||||||
content
|
|
||||||
.get_shows()
|
|
||||||
.set_widget_scroll_alignment(pd)
|
|
||||||
.map_err(|err| error!("Failed to set ShowWidget alignment: {}", err))
|
|
||||||
.ok();
|
|
||||||
}
|
|
||||||
Err(_) => (),
|
Err(_) => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -67,18 +67,18 @@ macro_rules! clone {
|
|||||||
|
|
||||||
// They do not need to be public
|
// They do not need to be public
|
||||||
// But it helps when looking at the generated docs.
|
// But it helps when looking at the generated docs.
|
||||||
pub mod stacks;
|
mod stacks;
|
||||||
pub mod views;
|
mod views;
|
||||||
pub mod widgets;
|
mod widgets;
|
||||||
|
|
||||||
pub mod app;
|
mod app;
|
||||||
pub mod headerbar;
|
mod headerbar;
|
||||||
|
|
||||||
pub mod appnotif;
|
mod appnotif;
|
||||||
pub mod manager;
|
mod manager;
|
||||||
pub mod settings;
|
mod settings;
|
||||||
pub mod static_resource;
|
mod static_resource;
|
||||||
pub mod utils;
|
mod utils;
|
||||||
|
|
||||||
use app::App;
|
use app::App;
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,7 @@ use std::sync::mpsc::Sender;
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Content {
|
pub struct Content {
|
||||||
stack: gtk::Stack,
|
stack: gtk::Stack,
|
||||||
shows: Rc<ShowStack>,
|
shows: Rc<RefCell<ShowStack>>,
|
||||||
episodes: Rc<RefCell<EpisodeStack>>,
|
episodes: Rc<RefCell<EpisodeStack>>,
|
||||||
sender: Sender<Action>,
|
sender: Sender<Action>,
|
||||||
}
|
}
|
||||||
@ -23,10 +23,10 @@ impl Content {
|
|||||||
pub fn new(sender: Sender<Action>) -> Result<Content, Error> {
|
pub fn new(sender: Sender<Action>) -> Result<Content, Error> {
|
||||||
let stack = gtk::Stack::new();
|
let stack = gtk::Stack::new();
|
||||||
let episodes = Rc::new(RefCell::new(EpisodeStack::new(sender.clone())?));
|
let episodes = Rc::new(RefCell::new(EpisodeStack::new(sender.clone())?));
|
||||||
let shows = Rc::new(ShowStack::new(sender.clone())?);
|
let shows = Rc::new(RefCell::new(ShowStack::new(sender.clone())?));
|
||||||
|
|
||||||
stack.add_titled(&episodes.borrow().get_stack(), "episodes", "Episodes");
|
stack.add_titled(&episodes.borrow().get_stack(), "episodes", "Episodes");
|
||||||
stack.add_titled(&shows.get_stack(), "shows", "Shows");
|
stack.add_titled(&shows.borrow().get_stack(), "shows", "Shows");
|
||||||
|
|
||||||
Ok(Content {
|
Ok(Content {
|
||||||
stack,
|
stack,
|
||||||
@ -59,6 +59,7 @@ impl Content {
|
|||||||
|
|
||||||
pub fn update_shows_view(&self) {
|
pub fn update_shows_view(&self) {
|
||||||
self.shows
|
self.shows
|
||||||
|
.borrow_mut()
|
||||||
.update_podcasts()
|
.update_podcasts()
|
||||||
.map_err(|err| error!("Failed to update ShowsView: {}", err))
|
.map_err(|err| error!("Failed to update ShowsView: {}", err))
|
||||||
.ok();
|
.ok();
|
||||||
@ -66,6 +67,7 @@ impl Content {
|
|||||||
|
|
||||||
pub fn update_widget(&self) {
|
pub fn update_widget(&self) {
|
||||||
self.shows
|
self.shows
|
||||||
|
.borrow_mut()
|
||||||
.update_widget()
|
.update_widget()
|
||||||
.map_err(|err| error!("Failed to update ShowsWidget: {}", err))
|
.map_err(|err| error!("Failed to update ShowsWidget: {}", err))
|
||||||
.ok();
|
.ok();
|
||||||
@ -73,24 +75,17 @@ impl Content {
|
|||||||
|
|
||||||
pub fn update_widget_if_same(&self, pid: i32) {
|
pub fn update_widget_if_same(&self, pid: i32) {
|
||||||
self.shows
|
self.shows
|
||||||
|
.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();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_widget_if_visible(&self) {
|
|
||||||
if self.stack.get_visible_child_name() == Some("shows".to_string())
|
|
||||||
&& self.shows.get_stack().get_visible_child_name() == Some("widget".to_string())
|
|
||||||
{
|
|
||||||
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 get_shows(&self) -> Rc<ShowStack> {
|
pub fn get_shows(&self) -> Rc<RefCell<ShowStack>> {
|
||||||
self.shows.clone()
|
self.shows.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -51,11 +51,11 @@ impl EpisodeStack {
|
|||||||
|
|
||||||
fn replace_view(&mut self) -> Result<(), Error> {
|
fn replace_view(&mut self) -> Result<(), Error> {
|
||||||
// Get the container of the view
|
// Get the container of the view
|
||||||
let old = self.episodes.container.clone();
|
let old = &self.episodes.container.clone();
|
||||||
let eps = EpisodesView::new(self.sender.clone())?;
|
let eps = EpisodesView::new(self.sender.clone())?;
|
||||||
|
|
||||||
// Remove the old widget and add the new one
|
// Remove the old widget and add the new one
|
||||||
self.stack.remove(&old);
|
self.stack.remove(old);
|
||||||
self.stack.add_named(&eps.container, "episodes");
|
self.stack.add_named(&eps.container, "episodes");
|
||||||
|
|
||||||
// replace view in the struct too
|
// replace view in the struct too
|
||||||
|
|||||||
@ -4,4 +4,4 @@ mod show;
|
|||||||
|
|
||||||
pub use self::content::Content;
|
pub use self::content::Content;
|
||||||
pub use self::episode::EpisodeStack;
|
pub use self::episode::EpisodeStack;
|
||||||
pub use self::show::{ShowStack, SHOW_WIDGET_VALIGNMENT};
|
pub use self::show::ShowStack;
|
||||||
|
|||||||
@ -3,7 +3,6 @@ use gtk::prelude::*;
|
|||||||
use gtk::Cast;
|
use gtk::Cast;
|
||||||
|
|
||||||
use failure::Error;
|
use failure::Error;
|
||||||
use send_cell::SendCell;
|
|
||||||
|
|
||||||
use hammond_data::dbqueries;
|
use hammond_data::dbqueries;
|
||||||
use hammond_data::errors::DataError;
|
use hammond_data::errors::DataError;
|
||||||
@ -14,17 +13,16 @@ use views::{EmptyView, ShowsPopulated};
|
|||||||
use app::Action;
|
use app::Action;
|
||||||
use widgets::ShowWidget;
|
use widgets::ShowWidget;
|
||||||
|
|
||||||
|
use std::rc::Rc;
|
||||||
use std::sync::mpsc::Sender;
|
use std::sync::mpsc::Sender;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::Arc;
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
pub static ref SHOW_WIDGET_VALIGNMENT: Mutex<Option<(i32, SendCell<gtk::Adjustment>)>> =
|
|
||||||
Mutex::new(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ShowStack {
|
pub struct ShowStack {
|
||||||
stack: gtk::Stack,
|
stack: gtk::Stack,
|
||||||
|
podcasts: ShowsPopulated,
|
||||||
|
show: Rc<ShowWidget>,
|
||||||
|
empty: EmptyView,
|
||||||
sender: Sender<Action>,
|
sender: Sender<Action>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,19 +30,22 @@ impl ShowStack {
|
|||||||
pub fn new(sender: Sender<Action>) -> Result<ShowStack, Error> {
|
pub fn new(sender: Sender<Action>) -> Result<ShowStack, Error> {
|
||||||
let stack = gtk::Stack::new();
|
let stack = gtk::Stack::new();
|
||||||
|
|
||||||
let show = ShowStack {
|
let podcasts = ShowsPopulated::new(sender.clone())?;
|
||||||
stack,
|
let show = Rc::new(ShowWidget::default());
|
||||||
sender: sender.clone(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let pop = ShowsPopulated::new(sender.clone())?;
|
|
||||||
let widget = ShowWidget::default();
|
|
||||||
let empty = EmptyView::new();
|
let empty = EmptyView::new();
|
||||||
|
|
||||||
show.stack.add_named(&pop.container, "podcasts");
|
stack.add_named(&podcasts.container, "podcasts");
|
||||||
show.stack.add_named(&widget.container, "widget");
|
stack.add_named(&show.container, "widget");
|
||||||
show.stack.add_named(&empty.container, "empty");
|
stack.add_named(&empty.container, "empty");
|
||||||
set_stack_visible(&show.get_stack())?;
|
set_stack_visible(&stack)?;
|
||||||
|
|
||||||
|
let show = ShowStack {
|
||||||
|
stack,
|
||||||
|
podcasts,
|
||||||
|
show,
|
||||||
|
empty,
|
||||||
|
sender,
|
||||||
|
};
|
||||||
|
|
||||||
Ok(show)
|
Ok(show)
|
||||||
}
|
}
|
||||||
@ -87,19 +88,15 @@ impl ShowStack {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn replace_widget(&self, pd: Arc<Podcast>) -> Result<(), Error> {
|
pub fn replace_widget(&mut self, pd: Arc<Podcast>) -> Result<(), Error> {
|
||||||
let old = self.stack
|
let old = self.show.container.clone();
|
||||||
.get_child_by_name("widget")
|
|
||||||
.ok_or_else(|| format_err!("Faild to get \"widget\" child from the stack."))?
|
|
||||||
.downcast::<gtk::Box>()
|
|
||||||
.map_err(|_| format_err!("Failed to downcast stack child to a Box."))?;
|
|
||||||
|
|
||||||
let oldname = WidgetExt::get_name(&old);
|
let oldname = WidgetExt::get_name(&old);
|
||||||
debug!("Name: {:?}", oldname);
|
debug!("Name: {:?}", oldname);
|
||||||
oldname
|
oldname
|
||||||
.clone()
|
.clone()
|
||||||
.and_then(|id| id.parse().ok())
|
.and_then(|id| id.parse().ok())
|
||||||
.map(|id| save_alignment(id, &old));
|
.map(|id| self.show.save_vadjustment(id));
|
||||||
|
|
||||||
let new = ShowWidget::new(pd, self.sender.clone());
|
let new = ShowWidget::new(pd, self.sender.clone());
|
||||||
// Each composite ShowWidget is a gtkBox with the Podcast.id encoded in the
|
// Each composite ShowWidget is a gtkBox with the Podcast.id encoded in the
|
||||||
@ -111,19 +108,19 @@ impl ShowStack {
|
|||||||
WidgetExt::get_name(&new.container)
|
WidgetExt::get_name(&new.container)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let root = new.container.clone();
|
||||||
|
self.show = new;
|
||||||
self.stack.remove(&old);
|
self.stack.remove(&old);
|
||||||
self.stack.add_named(&new.container, "widget");
|
self.stack.add_named(&root, "widget");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_widget(&self) -> Result<(), Error> {
|
pub fn update_widget(&mut self) -> Result<(), Error> {
|
||||||
let vis = self.stack
|
let vis = self.stack
|
||||||
.get_visible_child_name()
|
.get_visible_child_name()
|
||||||
.ok_or_else(|| format_err!("Failed to get visible child name."))?;
|
.ok_or_else(|| format_err!("Failed to get visible child name."))?;
|
||||||
let old = self.stack
|
|
||||||
.get_child_by_name("widget")
|
|
||||||
.ok_or_else(|| format_err!("Faild to get \"widget\" child from the stack."))?;
|
|
||||||
|
|
||||||
|
let old = self.show.container.clone();
|
||||||
let id = WidgetExt::get_name(&old);
|
let id = WidgetExt::get_name(&old);
|
||||||
if id == Some("GtkBox".to_string()) || id.is_none() {
|
if id == Some("GtkBox".to_string()) || id.is_none() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@ -138,12 +135,10 @@ impl ShowStack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Only update widget if it's podcast_id is equal to pid.
|
// Only update widget if it's podcast_id is equal to pid.
|
||||||
pub fn update_widget_if_same(&self, pid: i32) -> Result<(), Error> {
|
pub fn update_widget_if_same(&mut self, pid: i32) -> Result<(), Error> {
|
||||||
let old = self.stack
|
let old = &self.show.container.clone();
|
||||||
.get_child_by_name("widget")
|
|
||||||
.ok_or_else(|| format_err!("Faild to get \"widget\" child from the stack."))?;
|
|
||||||
|
|
||||||
let id = WidgetExt::get_name(&old);
|
let id = WidgetExt::get_name(old);
|
||||||
if id != Some(pid.to_string()) || id.is_none() {
|
if id != Some(pid.to_string()) || id.is_none() {
|
||||||
debug!("Different widget. Early return");
|
debug!("Different widget. Early return");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@ -151,43 +146,6 @@ impl ShowStack {
|
|||||||
self.update_widget()
|
self.update_widget()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_widget_scroll_alignment(&self, pd: Arc<Podcast>) -> Result<(), Error> {
|
|
||||||
let guard = SHOW_WIDGET_VALIGNMENT
|
|
||||||
.lock()
|
|
||||||
.map_err(|err| format_err!("Failed to lock widget align mutex: {}", err))?;
|
|
||||||
|
|
||||||
if let Some((oldid, ref sendcell)) = *guard {
|
|
||||||
// Only copy the old scrollbar if both widget's represent the same podcast.
|
|
||||||
debug!("PID: {}", pd.id());
|
|
||||||
debug!("OLDID: {}", oldid);
|
|
||||||
if pd.id() != oldid {
|
|
||||||
debug!("Early return");
|
|
||||||
return Ok(());
|
|
||||||
};
|
|
||||||
|
|
||||||
let widget = self.stack
|
|
||||||
.get_child_by_name("widget")
|
|
||||||
.ok_or_else(|| format_err!("Faild to get \"widget\" child from the stack."))?
|
|
||||||
.downcast::<gtk::Box>()
|
|
||||||
.map_err(|_| format_err!("Failed to downcast stack child to a Box."))?;
|
|
||||||
|
|
||||||
let scrolled_window = widget
|
|
||||||
.get_children()
|
|
||||||
.first()
|
|
||||||
.ok_or_else(|| format_err!("Box container has no childs."))?
|
|
||||||
.clone()
|
|
||||||
.downcast::<gtk::ScrolledWindow>()
|
|
||||||
.map_err(|_| format_err!("Failed to downcast stack child to a ScrolledWindow."))?;
|
|
||||||
|
|
||||||
// Copy the vertical scrollbar adjustment from the old view into the new one.
|
|
||||||
sendcell
|
|
||||||
.try_get()
|
|
||||||
.map(|x| scrolled_window.set_vadjustment(&x));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn switch_podcasts_animated(&self) {
|
pub fn switch_podcasts_animated(&self) {
|
||||||
self.stack
|
self.stack
|
||||||
.set_visible_child_full("podcasts", gtk::StackTransitionType::SlideRight);
|
.set_visible_child_full("podcasts", gtk::StackTransitionType::SlideRight);
|
||||||
@ -213,24 +171,3 @@ fn set_stack_visible(stack: >k::Stack) -> Result<(), DataError> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// ATTENTION: EXPECTS THE SHOW WIDGET CONTAINER
|
|
||||||
fn save_alignment(oldid: i32, widget: >k::Box) -> Result<(), Error> {
|
|
||||||
let scrolled_window = widget
|
|
||||||
.get_children()
|
|
||||||
.first()
|
|
||||||
.ok_or_else(|| format_err!("Box container has no childs."))?
|
|
||||||
.clone()
|
|
||||||
.downcast::<gtk::ScrolledWindow>()
|
|
||||||
.map_err(|_| format_err!("Failed to downcast stack child to a ScrolledWindow."))?;
|
|
||||||
|
|
||||||
if let Ok(mut guard) = SHOW_WIDGET_VALIGNMENT.lock() {
|
|
||||||
let adj = scrolled_window
|
|
||||||
.get_vadjustment()
|
|
||||||
.ok_or_else(|| format_err!("Could not get the adjustment"))?;
|
|
||||||
*guard = Some((oldid, SendCell::new(adj)));
|
|
||||||
debug!("Widget Alignment was saved with ID: {}.", oldid);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|||||||
@ -67,12 +67,6 @@ impl ShowsPopulated {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Set scrolled window vertical adjustment.
|
|
||||||
pub fn set_vadjustment(&self, vadjustment: >k::Adjustment) {
|
|
||||||
self.scrolled_window.set_vadjustment(vadjustment)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|||||||
@ -6,6 +6,7 @@ use failure::Error;
|
|||||||
use html2pango::markup_from_raw;
|
use html2pango::markup_from_raw;
|
||||||
use open;
|
use open;
|
||||||
use rayon;
|
use rayon;
|
||||||
|
use send_cell::SendCell;
|
||||||
|
|
||||||
use hammond_data::dbqueries;
|
use hammond_data::dbqueries;
|
||||||
use hammond_data::utils::delete_show;
|
use hammond_data::utils::delete_show;
|
||||||
@ -16,8 +17,14 @@ use appnotif::InAppNotification;
|
|||||||
use utils::{self, lazy_load};
|
use utils::{self, lazy_load};
|
||||||
use widgets::EpisodeWidget;
|
use widgets::EpisodeWidget;
|
||||||
|
|
||||||
|
use std::rc::Rc;
|
||||||
use std::sync::mpsc::{SendError, Sender};
|
use std::sync::mpsc::{SendError, Sender};
|
||||||
use std::sync::Arc;
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref SHOW_WIDGET_VALIGNMENT: Mutex<Option<(i32, SendCell<gtk::Adjustment>)>> =
|
||||||
|
Mutex::new(None);
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ShowWidget {
|
pub struct ShowWidget {
|
||||||
@ -60,9 +67,12 @@ impl Default for ShowWidget {
|
|||||||
|
|
||||||
impl ShowWidget {
|
impl ShowWidget {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(pd: Arc<Podcast>, sender: Sender<Action>) -> ShowWidget {
|
pub fn new(pd: Arc<Podcast>, sender: Sender<Action>) -> Rc<ShowWidget> {
|
||||||
let pdw = ShowWidget::default();
|
let pdw = Rc::new(ShowWidget::default());
|
||||||
pdw.init(pd, sender);
|
pdw.init(pd.clone(), sender.clone());
|
||||||
|
populate_listbox(&pdw, pd, sender)
|
||||||
|
.map_err(|err| error!("Failed to populate the listbox: {}", err))
|
||||||
|
.ok();
|
||||||
pdw
|
pdw
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,10 +90,6 @@ impl ShowWidget {
|
|||||||
|
|
||||||
self.set_description(pd.description());
|
self.set_description(pd.description());
|
||||||
|
|
||||||
self.populate_listbox(pd.clone(), sender.clone())
|
|
||||||
.map_err(|err| error!("Failed to populate the listbox: {}", err))
|
|
||||||
.ok();
|
|
||||||
|
|
||||||
self.set_cover(pd.clone())
|
self.set_cover(pd.clone())
|
||||||
.map_err(|err| error!("Failed to set a cover: {}", err))
|
.map_err(|err| error!("Failed to set a cover: {}", err))
|
||||||
.ok();
|
.ok();
|
||||||
@ -125,59 +131,98 @@ impl ShowWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Set scrolled window vertical adjustment.
|
/// Save the scrollabar vajustment to the cache.
|
||||||
pub fn set_vadjustment(&self, vadjustment: >k::Adjustment) {
|
pub fn save_vadjustment(&self, oldid: i32) -> Result<(), Error> {
|
||||||
self.scrolled_window.set_vadjustment(vadjustment)
|
if let Ok(mut guard) = SHOW_WIDGET_VALIGNMENT.lock() {
|
||||||
}
|
let adj = self.scrolled_window
|
||||||
|
.get_vadjustment()
|
||||||
#[inline]
|
.ok_or_else(|| format_err!("Could not get the adjustment"))?;
|
||||||
/// Populate the listbox with the shows episodes.
|
*guard = Some((oldid, SendCell::new(adj)));
|
||||||
fn populate_listbox(&self, pd: Arc<Podcast>, sender: Sender<Action>) -> Result<(), Error> {
|
debug!("Widget Alignment was saved with ID: {}.", oldid);
|
||||||
use crossbeam_channel::bounded;
|
|
||||||
use crossbeam_channel::TryRecvError::*;
|
|
||||||
|
|
||||||
let count = dbqueries::get_pd_episodes_count(&pd)?;
|
|
||||||
|
|
||||||
let (sender_, receiver) = bounded(1);
|
|
||||||
rayon::spawn(clone!(pd => move || {
|
|
||||||
let episodes = dbqueries::get_pd_episodeswidgets(&pd).unwrap();
|
|
||||||
// The receiver can be dropped if there's an early return
|
|
||||||
// like on show without episodes for example.
|
|
||||||
sender_.send(episodes).ok();
|
|
||||||
}));
|
|
||||||
|
|
||||||
if count == 0 {
|
|
||||||
let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/empty_show.ui");
|
|
||||||
let container: gtk::Box = builder.get_object("empty_show").unwrap();
|
|
||||||
self.episodes.add(&container);
|
|
||||||
return Ok(());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let list = self.episodes.clone();
|
|
||||||
gtk::idle_add(move || {
|
|
||||||
let episodes = match receiver.try_recv() {
|
|
||||||
Ok(e) => e,
|
|
||||||
Err(Empty) => return glib::Continue(true),
|
|
||||||
Err(Disconnected) => return glib::Continue(false),
|
|
||||||
};
|
|
||||||
|
|
||||||
let constructor = clone!(sender => move |ep| {
|
|
||||||
EpisodeWidget::new(ep, sender.clone()).container
|
|
||||||
});
|
|
||||||
|
|
||||||
let callback = clone!(pd, sender => move || {
|
|
||||||
sender.send(Action::SetShowWidgetAlignment(pd.clone()))
|
|
||||||
.map_err(|err| error!("Action Sender: {}", err))
|
|
||||||
.ok();
|
|
||||||
});
|
|
||||||
|
|
||||||
lazy_load(episodes, list.clone(), constructor, callback);
|
|
||||||
|
|
||||||
glib::Continue(false)
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
/// Set scrolled window vertical adjustment.
|
||||||
|
fn set_vadjustment(&self, pd: Arc<Podcast>) -> Result<(), Error> {
|
||||||
|
let guard = SHOW_WIDGET_VALIGNMENT
|
||||||
|
.lock()
|
||||||
|
.map_err(|err| format_err!("Failed to lock widget align mutex: {}", err))?;
|
||||||
|
|
||||||
|
if let Some((oldid, ref sendcell)) = *guard {
|
||||||
|
// Only copy the old scrollbar if both widget's represent the same podcast.
|
||||||
|
debug!("PID: {}", pd.id());
|
||||||
|
debug!("OLDID: {}", oldid);
|
||||||
|
if pd.id() != oldid {
|
||||||
|
debug!("Early return");
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
|
||||||
|
// Copy the vertical scrollbar adjustment from the old view into the new one.
|
||||||
|
sendcell
|
||||||
|
.try_get()
|
||||||
|
.map(|x| self.scrolled_window.set_vadjustment(&x));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
/// Populate the listbox with the shows episodes.
|
||||||
|
fn populate_listbox(
|
||||||
|
show: &Rc<ShowWidget>,
|
||||||
|
pd: Arc<Podcast>,
|
||||||
|
sender: Sender<Action>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
use crossbeam_channel::bounded;
|
||||||
|
use crossbeam_channel::TryRecvError::*;
|
||||||
|
|
||||||
|
let count = dbqueries::get_pd_episodes_count(&pd)?;
|
||||||
|
|
||||||
|
let (sender_, receiver) = bounded(1);
|
||||||
|
rayon::spawn(clone!(pd => move || {
|
||||||
|
let episodes = dbqueries::get_pd_episodeswidgets(&pd).unwrap();
|
||||||
|
// The receiver can be dropped if there's an early return
|
||||||
|
// like on show without episodes for example.
|
||||||
|
sender_.send(episodes).ok();
|
||||||
|
}));
|
||||||
|
|
||||||
|
if count == 0 {
|
||||||
|
let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/empty_show.ui");
|
||||||
|
let container: gtk::Box = builder.get_object("empty_show").unwrap();
|
||||||
|
show.episodes.add(&container);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let show_ = show.clone();
|
||||||
|
gtk::idle_add(move || {
|
||||||
|
let episodes = match receiver.try_recv() {
|
||||||
|
Ok(e) => e,
|
||||||
|
Err(Empty) => return glib::Continue(true),
|
||||||
|
Err(Disconnected) => return glib::Continue(false),
|
||||||
|
};
|
||||||
|
|
||||||
|
let list = show_.episodes.clone();
|
||||||
|
|
||||||
|
let constructor = clone!(sender => move |ep| {
|
||||||
|
EpisodeWidget::new(ep, sender.clone()).container
|
||||||
|
});
|
||||||
|
|
||||||
|
let callback = clone!(pd, show_ => move || {
|
||||||
|
show_.set_vadjustment(pd.clone())
|
||||||
|
.map_err(|err| error!("Failed to set ShowWidget Alignment: {}", err))
|
||||||
|
.ok();
|
||||||
|
});
|
||||||
|
|
||||||
|
lazy_load(episodes, list.clone(), constructor, callback);
|
||||||
|
|
||||||
|
glib::Continue(false)
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user