EpisodeView: Initial refactor to make loading non-blocking.

This commit is contained in:
Jordan Petridis 2018-04-19 02:52:58 +03:00
parent f811a9c8f4
commit 0e4430bae4
No known key found for this signature in database
GPG Key ID: CEABAD9F5683B9A6
3 changed files with 74 additions and 77 deletions

View File

@ -349,6 +349,20 @@ pub(crate) fn episode_exists(title_: &str, podcast_id_: i32) -> Result<bool, Dat
.map_err(From::from) .map_err(From::from)
} }
/// Check `episode` table empty
///
/// Return true if `episode` table is populated.
pub fn is_episodes_populated() -> Result<bool, DataError> {
use schema::episode::dsl::*;
let db = connection();
let con = db.get()?;
select(exists(episode.count()))
.get_result(&con)
.map_err(From::from)
}
pub(crate) fn index_new_episodes(eps: &[NewEpisode]) -> Result<(), DataError> { pub(crate) fn index_new_episodes(eps: &[NewEpisode]) -> Result<(), DataError> {
use schema::episode::dsl::*; use schema::episode::dsl::*;
let db = connection(); let db = connection();

View File

@ -3,10 +3,11 @@ use gtk::prelude::*;
use gtk::Cast; use gtk::Cast;
use failure::Error; use failure::Error;
use hammond_data::dbqueries::is_episodes_populated;
use views::{EmptyView, EpisodesView}; use hammond_data::errors::DataError;
use app::Action; use app::Action;
use views::{EmptyView, EpisodesView};
use std::sync::mpsc::Sender; use std::sync::mpsc::Sender;
@ -24,12 +25,7 @@ impl EpisodeStack {
stack.add_named(&episodes.container, "episodes"); stack.add_named(&episodes.container, "episodes");
stack.add_named(&empty.container, "empty"); stack.add_named(&empty.container, "empty");
set_stack_visible(&stack)?;
if episodes.is_empty() {
stack.set_visible_child_name("empty");
} else {
stack.set_visible_child_name("episodes");
}
Ok(EpisodeStack { stack, sender }) Ok(EpisodeStack { stack, sender })
} }
@ -43,28 +39,23 @@ impl EpisodeStack {
.map_err(|_| format_err!("Failed to downcast stack child to a Box."))?; .map_err(|_| format_err!("Failed to downcast stack child to a Box."))?;
debug!("Name: {:?}", WidgetExt::get_name(&old)); debug!("Name: {:?}", WidgetExt::get_name(&old));
let scrolled_window = old.get_children() // let scrolled_window = old.get_children()
.first() // .first()
.ok_or_else(|| format_err!("Box container has no childs."))? // .ok_or_else(|| format_err!("Box container has no childs."))?
.clone() // .clone()
.downcast::<gtk::ScrolledWindow>() // .downcast::<gtk::ScrolledWindow>()
.map_err(|_| format_err!("Failed to downcast stack child to a ScrolledWindow."))?; // .map_err(|_| format_err!("Failed to downcast stack child to a ScrolledWindow."))?;
debug!("Name: {:?}", WidgetExt::get_name(&scrolled_window)); // debug!("Name: {:?}", WidgetExt::get_name(&scrolled_window));
let eps = EpisodesView::new(self.sender.clone())?; let eps = EpisodesView::new(self.sender.clone())?;
// Copy the vertical scrollbar adjustment from the old view into the new one. // Copy the vertical scrollbar adjustment from the old view into the new one.
scrolled_window // scrolled_window
.get_vadjustment() // .get_vadjustment()
.map(|x| eps.set_vadjustment(&x)); // .map(|x| eps.set_vadjustment(&x));
self.stack.remove(&old); self.stack.remove(&old);
self.stack.add_named(&eps.container, "episodes"); self.stack.add_named(&eps.container, "episodes");
set_stack_visible(&self.stack)?;
if eps.is_empty() {
self.stack.set_visible_child_name("empty");
} else {
self.stack.set_visible_child_name("episodes");
}
old.destroy(); old.destroy();
@ -75,3 +66,13 @@ impl EpisodeStack {
self.stack.clone() self.stack.clone()
} }
} }
fn set_stack_visible(stack: &gtk::Stack) -> Result<(), DataError> {
if is_episodes_populated()? {
stack.set_visible_child_name("episodes");
} else {
stack.set_visible_child_name("empty");
};
Ok(())
}

View File

@ -7,9 +7,11 @@ use hammond_data::dbqueries;
use hammond_data::EpisodeWidgetQuery; use hammond_data::EpisodeWidgetQuery;
use app::Action; use app::Action;
use utils::lazy_load_full;
use utils::{get_ignored_shows, set_image_from_path}; use utils::{get_ignored_shows, set_image_from_path};
use widgets::EpisodeWidget; use widgets::EpisodeWidget;
use std::rc::Rc;
use std::sync::mpsc::Sender; use std::sync::mpsc::Sender;
use std::sync::Arc; use std::sync::Arc;
@ -78,85 +80,65 @@ impl Default for EpisodesView {
// TODO: REFACTOR ME // TODO: REFACTOR ME
impl EpisodesView { impl EpisodesView {
#[inline] #[inline]
pub fn new(sender: Sender<Action>) -> Result<EpisodesView, Error> { pub fn new(sender: Sender<Action>) -> Result<Rc<EpisodesView>, Error> {
let view = EpisodesView::default(); let view = Rc::new(EpisodesView::default());
let ignore = get_ignored_shows()?; let ignore = get_ignored_shows()?;
let episodes = dbqueries::get_episodes_widgets_filter_limit(&ignore, 50)?; let episodes = dbqueries::get_episodes_widgets_filter_limit(&ignore, 200)?;
let now_utc = Utc::now(); let now_utc = Utc::now();
episodes.into_iter().for_each(|ep| { let view_ = view.clone();
let func = move |ep: EpisodeWidgetQuery| {
let epoch = ep.epoch(); let epoch = ep.epoch();
let viewep = EpisodesViewWidget::new(ep, sender.clone()); let viewep = EpisodesViewWidget::new(ep, sender.clone());
let t = split(&now_utc, i64::from(epoch)); let t = split(&now_utc, i64::from(epoch));
match t { match t {
ListSplit::Today => { ListSplit::Today => {
view.today_list.add(&viewep.container); view_.today_list.add(&viewep.container);
} }
ListSplit::Yday => { ListSplit::Yday => {
view.yday_list.add(&viewep.container); view_.yday_list.add(&viewep.container);
} }
ListSplit::Week => { ListSplit::Week => {
view.week_list.add(&viewep.container); view_.week_list.add(&viewep.container);
} }
ListSplit::Month => { ListSplit::Month => {
view.month_list.add(&viewep.container); view_.month_list.add(&viewep.container);
} }
ListSplit::Rest => { ListSplit::Rest => {
view.rest_list.add(&viewep.container); view_.rest_list.add(&viewep.container);
} }
} }
};
let callback = clone!(view => move || {
if view.today_list.get_children().is_empty() {
view.today_box.hide();
}
if view.yday_list.get_children().is_empty() {
view.yday_box.hide();
}
if view.week_list.get_children().is_empty() {
view.week_box.hide();
}
if view.month_list.get_children().is_empty() {
view.month_box.hide();
}
if view.rest_list.get_children().is_empty() {
view.rest_box.hide();
}
}); });
if view.today_list.get_children().is_empty() { lazy_load_full(episodes, func, callback);
view.today_box.hide();
}
if view.yday_list.get_children().is_empty() {
view.yday_box.hide();
}
if view.week_list.get_children().is_empty() {
view.week_box.hide();
}
if view.month_list.get_children().is_empty() {
view.month_box.hide();
}
if view.rest_list.get_children().is_empty() {
view.rest_box.hide();
}
view.container.show_all(); view.container.show_all();
Ok(view) Ok(view)
} }
#[inline]
pub fn is_empty(&self) -> bool {
if !self.today_list.get_children().is_empty() {
return false;
}
if !self.yday_list.get_children().is_empty() {
return false;
}
if !self.week_list.get_children().is_empty() {
return false;
}
if !self.month_list.get_children().is_empty() {
return false;
}
if !self.rest_list.get_children().is_empty() {
return false;
}
true
}
#[inline] #[inline]
/// Set scrolled window vertical adjustment. /// Set scrolled window vertical adjustment.
pub fn set_vadjustment(&self, vadjustment: &gtk::Adjustment) { pub fn set_vadjustment(&self, vadjustment: &gtk::Adjustment) {