EpisodeWidget: Handle updating states, withotu having to reload the views.

This code is ugly and terrible but it works™. Previsously when a download
would finish it would refresh all the views. Now the if the widget get's
into the Donwloading state, it will setup a callback that will check
periodicly if it's still downloading and update the widget state when
the episode stops downloading.
This commit is contained in:
Jordan Petridis 2018-04-28 14:09:26 +03:00
parent 63e2ea987e
commit 03bd951848
No known key found for this signature in database
GPG Key ID: CEABAD9F5683B9A6
3 changed files with 56 additions and 30 deletions

View File

@ -103,6 +103,20 @@ pub fn get_episode_from_rowid(ep_id: i32) -> Result<Episode, DataError> {
.map_err(From::from) .map_err(From::from)
} }
pub fn get_episode_widget_from_rowid(ep_id: i32) -> Result<EpisodeWidgetQuery, DataError> {
use schema::episode::dsl::*;
let db = connection();
let con = db.get()?;
episode
.select((
rowid, title, uri, local_uri, epoch, length, duration, played, podcast_id,
))
.filter(rowid.eq(ep_id))
.get_result::<EpisodeWidgetQuery>(&con)
.map_err(From::from)
}
pub fn get_episode_local_uri_from_id(ep_id: i32) -> Result<Option<String>, DataError> { pub fn get_episode_local_uri_from_id(ep_id: i32) -> Result<Option<String>, DataError> {
use schema::episode::dsl::*; use schema::episode::dsl::*;
let db = connection(); let db = connection();

View File

@ -5,10 +5,7 @@ use rayon;
use hammond_data::dbqueries; use hammond_data::dbqueries;
use hammond_downloader::downloader::{get_episode, DownloadProgress}; use hammond_downloader::downloader::{get_episode, DownloadProgress};
use app::Action;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::mpsc::Sender;
use std::sync::{Arc, Mutex, RwLock}; use std::sync::{Arc, Mutex, RwLock};
// use std::sync::atomic::AtomicUsize; // use std::sync::atomic::AtomicUsize;
// use std::path::PathBuf; // use std::path::PathBuf;
@ -78,7 +75,7 @@ lazy_static! {
static ref DLPOOL: rayon::ThreadPool = rayon::ThreadPoolBuilder::new().build().unwrap(); static ref DLPOOL: rayon::ThreadPool = rayon::ThreadPoolBuilder::new().build().unwrap();
} }
pub fn add(id: i32, directory: String, sender: Sender<Action>) -> Result<(), Error> { pub fn add(id: i32, directory: String) -> Result<(), Error> {
// Create a new `Progress` struct to keep track of dl progress. // Create a new `Progress` struct to keep track of dl progress.
let prog = Arc::new(Mutex::new(Progress::default())); let prog = Arc::new(Mutex::new(Progress::default()));
@ -88,11 +85,10 @@ pub fn add(id: i32, directory: String, sender: Sender<Action>) -> Result<(), Err
}; };
DLPOOL.spawn(move || { DLPOOL.spawn(move || {
if let Ok(episode) = dbqueries::get_episode_from_rowid(id) { if let Ok(mut episode) = dbqueries::get_episode_widget_from_rowid(id) {
let id = episode.rowid(); let id = episode.rowid();
let pid = episode.podcast_id();
get_episode(&mut episode.into(), directory.as_str(), Some(prog)) get_episode(&mut episode, directory.as_str(), Some(prog))
.map_err(|err| error!("Download Failed: {}", err)) .map_err(|err| error!("Download Failed: {}", err))
.ok(); .ok();
@ -104,15 +100,6 @@ pub fn add(id: i32, directory: String, sender: Sender<Action>) -> Result<(), Err
// if let Ok(m) = ACTIVE_DOWNLOADS.read() { // if let Ok(m) = ACTIVE_DOWNLOADS.read() {
// debug!("ACTIVE DOWNLOADS: {:#?}", m); // debug!("ACTIVE DOWNLOADS: {:#?}", m);
// } // }
sender
.send(Action::RefreshWidgetIfSame(pid))
.map_err(|err| error!("Action Sender: {}", err))
.ok();
sender
.send(Action::RefreshEpisodesView)
.map_err(|err| error!("Action Sender: {}", err))
.ok();
} }
}); });

View File

@ -128,10 +128,10 @@ impl EpisodeWidget {
.and_then(|_| { .and_then(|_| {
info!("Donwload started succesfully."); info!("Donwload started succesfully.");
determine_media_state(media_machine.clone(), &ep) determine_media_state(media_machine.clone(), &ep)
}) })
.map_err(|err| error!("Error: {}", err)) .map_err(|err| error!("Error: {}", err))
.map_err(|_| error!("Could not determine Media State")) .map_err(|_| error!("Could not determine Media State"))
.ok(); .ok();
} }
// Restore sensitivity after operations above complete // Restore sensitivity after operations above complete
@ -190,20 +190,42 @@ fn determine_media_state(
// Show or hide the play/delete/download buttons upon widget initialization. // Show or hide the play/delete/download buttons upon widget initialization.
if let Some(prog) = active_dl { if let Some(prog) = active_dl {
let episode = episode.clone();
// set a callback that will update the state when the download finishes
let id = episode.rowid();
let callback = clone!(media_machine => move || {
if let Ok(guard) = manager::ACTIVE_DOWNLOADS.read() {
if !guard.contains_key(&id) {
if let Ok(ep) = dbqueries::get_episode_widget_from_rowid(id) {
determine_media_state(media_machine.clone(), &ep)
.map_err(|err| error!("Error: {}", err))
.map_err(|_| error!("Could not determine Media State"))
.ok();
return glib::Continue(false)
}
}
}
glib::Continue(true)
});
gtk::timeout_add(250, callback);
lock.cancel_connect_clicked(clone!(prog, media_machine => move |_| { lock.cancel_connect_clicked(clone!(prog, media_machine => move |_| {
if let Ok(mut m) = prog.lock() { if let Ok(mut m) = prog.lock() {
m.cancel(); m.cancel();
} }
if let Ok(mut lock) = media_machine.try_borrow_mut() { if let Ok(mut lock) = media_machine.try_borrow_mut() {
take_mut::take(lock.deref_mut(), |media| { if let Ok(episode) = dbqueries::get_episode_widget_from_rowid(id) {
media.determine_state( take_mut::take(lock.deref_mut(), |media| {
episode.length(), media.determine_state(
false, episode.length(),
episode.local_uri().is_some(), false,
) episode.local_uri().is_some(),
}); )
});
}
} }
})); }));
drop(lock); drop(lock);
@ -221,12 +243,15 @@ fn determine_media_state(
} }
#[inline] #[inline]
fn on_download_clicked(ep: &EpisodeWidgetQuery, sender: Sender<Action>) -> Result<(), Error> { fn on_download_clicked(
ep: &EpisodeWidgetQuery,
sender: Sender<Action>,
) -> Result<(), Error> {
let pd = dbqueries::get_podcast_from_id(ep.podcast_id())?; let pd = dbqueries::get_podcast_from_id(ep.podcast_id())?;
let download_fold = get_download_folder(&pd.title())?; let download_fold = get_download_folder(&pd.title())?;
// Start a new download. // Start a new download.
manager::add(ep.rowid(), download_fold, sender.clone())?; manager::add(ep.rowid(), download_fold)?;
// Update Views // Update Views
sender.send(Action::RefreshEpisodesViewBGR)?; sender.send(Action::RefreshEpisodesViewBGR)?;