EpisodeWidget: Implement API to update the progress bar.

This commit is contained in:
Jordan Petridis 2018-01-08 05:11:37 +02:00
parent 5c333291e1
commit eef83fc98c
No known key found for this signature in database
GPG Key ID: CEABAD9F5683B9A6
7 changed files with 86 additions and 71 deletions

View File

@ -257,6 +257,7 @@
<object class="GtkProgressBar" id="progress_bar"> <object class="GtkProgressBar" id="progress_bar">
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="no_show_all">True</property> <property name="no_show_all">True</property>
<property name="pulse_step">0</property>
</object> </object>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>

View File

@ -17,8 +17,10 @@ use std::sync::mpsc::{channel, Receiver, Sender};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum Action { pub enum Action {
UpdateSources(Option<Source>), UpdateSources(Option<Source>),
RefreshViews, RefreshAllViews,
RefreshEpisodesView,
RefreshEpisodesViewBGR, RefreshEpisodesViewBGR,
RefreshWidget,
HeaderBarShowTile(String), HeaderBarShowTile(String),
HeaderBarNormal, HeaderBarNormal,
HeaderBarHideUpdateIndicator, HeaderBarHideUpdateIndicator,
@ -134,12 +136,14 @@ impl App {
utils::refresh_feed(headerbar.clone(), Some(vec![s]), sender.clone()) utils::refresh_feed(headerbar.clone(), Some(vec![s]), sender.clone())
} }
} }
Ok(Action::RefreshViews) => content.update(), Ok(Action::RefreshAllViews) => content.update(),
Ok(Action::RefreshWidget) => content.update_widget(),
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::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::HeaderBarHideUpdateIndicator) => headerbar.hide_update_notification(), Ok(Action::HeaderBarHideUpdateIndicator) => headerbar.hide_update_notification(),
_ => (), Err(_) => (),
} }
Continue(true) Continue(true)

View File

@ -41,8 +41,9 @@ impl Content {
} }
pub fn update(&self) { pub fn update(&self) {
self.update_shows_view();
self.update_episode_view(); self.update_episode_view();
self.update_shows_view();
self.update_widget()
} }
pub fn update_episode_view(&self) { pub fn update_episode_view(&self) {
@ -56,7 +57,11 @@ impl Content {
} }
pub fn update_shows_view(&self) { pub fn update_shows_view(&self) {
self.shows.update(); self.shows.update_podcasts();
}
pub fn update_widget(&self) {
self.shows.update_widget();
} }
pub fn get_stack(&self) -> gtk::Stack { pub fn get_stack(&self) -> gtk::Stack {
@ -100,15 +105,11 @@ impl ShowStack {
show show
} }
// fn is_empty(&self) -> bool { // pub fn update(&self) {
// self.podcasts.is_empty() // self.update_widget();
// self.update_podcasts();
// } // }
pub fn update(&self) {
self.update_podcasts();
self.update_widget();
}
pub fn update_podcasts(&self) { pub fn update_podcasts(&self) {
let vis = self.stack.get_visible_child_name().unwrap(); let vis = self.stack.get_visible_child_name().unwrap();

View File

@ -4,7 +4,7 @@ use hammond_downloader::downloader::get_episode;
use app::Action; use app::Action;
use std::collections::{HashMap, HashSet}; use std::collections::HashMap;
use std::sync::{Arc, Mutex, RwLock}; use std::sync::{Arc, Mutex, RwLock};
use std::sync::mpsc::Sender; use std::sync::mpsc::Sender;
// use std::sync::atomic::AtomicUsize; // use std::sync::atomic::AtomicUsize;
@ -24,26 +24,27 @@ impl Progress {
downloaded_bytes: 0, downloaded_bytes: 0,
} }
} }
pub fn get_fraction(&self) -> f64 {
self.downloaded_bytes as f64 / self.total_bytes as f64
}
} }
lazy_static! { lazy_static! {
pub static ref ACTIVE_DOWNLOADS: Arc<RwLock<HashSet<i32>>> = { pub static ref ACTIVE_DOWNLOADS: Arc<RwLock<HashMap<i32, Arc<Mutex<Progress>>>>> = {
Arc::new(RwLock::new(HashSet::new()))
};
pub static ref ACTIVE_PROGRESS: Arc<RwLock<HashMap<i32, Mutex<Progress>>>> = {
Arc::new(RwLock::new(HashMap::new())) Arc::new(RwLock::new(HashMap::new()))
}; };
} }
pub fn add(id: i32, directory: &str, sender: Sender<Action>) { pub fn add(id: i32, directory: &str, sender: Sender<Action>, prog: Arc<Mutex<Progress>>) {
{ {
let mut m = ACTIVE_DOWNLOADS.write().unwrap(); let mut m = ACTIVE_DOWNLOADS.write().unwrap();
m.insert(id); m.insert(id, prog.clone());
} }
let dir = directory.to_owned(); let dir = directory.to_owned();
thread::spawn(move || { thread::spawn(move || {
info!("{:?}", prog); // just checking that it compiles
let episode = dbqueries::get_episode_from_rowid(id).unwrap(); let episode = dbqueries::get_episode_from_rowid(id).unwrap();
let e = get_episode(&mut episode.into(), dir.as_str()); let e = get_episode(&mut episode.into(), dir.as_str());
if let Err(err) = e { if let Err(err) = e {
@ -54,7 +55,9 @@ pub fn add(id: i32, directory: &str, sender: Sender<Action>) {
let mut m = ACTIVE_DOWNLOADS.write().unwrap(); let mut m = ACTIVE_DOWNLOADS.write().unwrap();
m.remove(&id); m.remove(&id);
} }
sender.send(Action::RefreshViews).unwrap();
sender.send(Action::RefreshEpisodesView).unwrap();
sender.send(Action::RefreshWidget).unwrap();
}); });
} }
@ -102,9 +105,10 @@ mod tests {
}; };
let (sender, _rx) = channel(); let (sender, _rx) = channel();
let prog = Arc::new(Mutex::new(Progress::new(42)));
let download_fold = downloader::get_download_folder(&pd.title()).unwrap(); let download_fold = downloader::get_download_folder(&pd.title()).unwrap();
add(episode.rowid(), download_fold.as_str(), sender); add(episode.rowid(), download_fold.as_str(), sender, prog);
// Give it soem time to download the file // Give it soem time to download the file
thread::sleep(time::Duration::from_secs(40)); thread::sleep(time::Duration::from_secs(40));

View File

@ -30,7 +30,7 @@ pub fn refresh_feed(headerbar: Arc<Header>, source: Option<Vec<Source>>, sender:
}; };
sender.send(Action::HeaderBarHideUpdateIndicator).unwrap(); sender.send(Action::HeaderBarHideUpdateIndicator).unwrap();
sender.send(Action::RefreshViews).unwrap(); sender.send(Action::RefreshAllViews).unwrap();
}); });
} }

View File

@ -17,6 +17,7 @@ use app::Action;
use manager; use manager;
use std::sync::mpsc::Sender; use std::sync::mpsc::Sender;
use std::sync::{Arc, Mutex};
use std::path::Path; use std::path::Path;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -83,6 +84,8 @@ impl EpisodeWidget {
// TODO: wire the progress_bar to the downloader. // TODO: wire the progress_bar to the downloader.
// TODO: wire the cancel button. // TODO: wire the cancel button.
fn init(&self, episode: &mut EpisodeWidgetQuery, sender: Sender<Action>) { fn init(&self, episode: &mut EpisodeWidgetQuery, sender: Sender<Action>) {
WidgetExt::set_name(&self.container, &episode.rowid().to_string());
// Set the title label state. // Set the title label state.
self.set_title(episode); self.set_title(episode);
@ -98,12 +101,8 @@ impl EpisodeWidget {
// Show or hide the play/delete/download buttons upon widget initialization. // Show or hide the play/delete/download buttons upon widget initialization.
self.show_buttons(episode.local_uri()); self.show_buttons(episode.local_uri());
{ // Determine what the state of the progress bar should be.
let m = manager::ACTIVE_DOWNLOADS.read().unwrap(); self.determine_progess_bar();
if m.contains(&episode.rowid()) {
self.show_progess_bar()
};
}
let title = &self.title; let title = &self.title;
self.play self.play
@ -118,17 +117,10 @@ impl EpisodeWidget {
}; };
})); }));
let cancel = &self.cancel;
let progress = self.progress.clone();
self.download self.download
.connect_clicked(clone!(episode, cancel, progress, sender => move |dl| { .connect_clicked(clone!(episode, sender => move |dl| {
on_download_clicked( dl.set_sensitive(false);
&mut episode.clone(), on_download_clicked(&mut episode.clone(), sender.clone());
dl,
&cancel,
progress.clone(),
sender.clone()
);
})); }));
} }
@ -202,43 +194,56 @@ impl EpisodeWidget {
}; };
} }
fn show_progess_bar(&self) { fn determine_progess_bar(&self) {
let progress_bar = self.progress.clone(); let id = WidgetExt::get_name(&self.container)
timeout_add(200, move || { .unwrap()
progress_bar.pulse(); .parse::<i32>()
glib::Continue(true) .unwrap();
});
self.progress.show(); let m = manager::ACTIVE_DOWNLOADS.read().unwrap();
self.download.hide(); if !m.contains_key(&id) {
self.cancel.show(); return;
};
let progress_bar = self.progress.clone();
if let Some(prog) = m.get(&id) {
self.progress.show();
self.download.hide();
self.cancel.show();
timeout_add(
400,
clone!(prog => move || {
let fraction = {
let m = prog.lock().unwrap();
m.get_fraction()
};
progress_bar.set_fraction(fraction);
// info!("Fraction: {}", progress_bar.get_fraction());
if fraction != 1.0{
glib::Continue(true)
} else {
glib::Continue(false)
}
}),
);
}
} }
} }
fn on_download_clicked( fn on_download_clicked(ep: &EpisodeWidgetQuery, sender: Sender<Action>) {
ep: &EpisodeWidgetQuery,
download_bttn: &gtk::Button,
cancel_bttn: &gtk::Button,
progress_bar: gtk::ProgressBar,
sender: Sender<Action>,
) {
let progress = progress_bar.clone();
// Start the proggress_bar pulse.
timeout_add(200, move || {
progress_bar.pulse();
glib::Continue(true)
});
let pd = dbqueries::get_podcast_from_id(ep.podcast_id()).unwrap(); let pd = dbqueries::get_podcast_from_id(ep.podcast_id()).unwrap();
let pd_title = pd.title().to_owned(); let download_fold = downloader::get_download_folder(&pd.title().to_owned()).unwrap();
cancel_bttn.show();
progress.show();
download_bttn.hide();
let download_fold = downloader::get_download_folder(&pd_title).unwrap();
manager::add(ep.rowid(), &download_fold, sender.clone()); // Create a new `Progress` struct to keep track of dl progress.
sender.send(Action::RefreshEpisodesViewBGR).unwrap(); let prog = Arc::new(Mutex::new(manager::Progress::new(42)));
// Start a new download.
manager::add(ep.rowid(), &download_fold, sender.clone(), prog.clone());
// Update Views
sender.send(Action::RefreshEpisodesView).unwrap();
sender.send(Action::RefreshWidget).unwrap();
} }
fn on_play_bttn_clicked(episode_id: i32) { fn on_play_bttn_clicked(episode_id: i32) {

View File

@ -142,7 +142,7 @@ fn on_unsub_button_clicked(
})); }));
shows.switch_podcasts_animated(); shows.switch_podcasts_animated();
// Queue a refresh after the switch to avoid blocking the db. // Queue a refresh after the switch to avoid blocking the db.
sender.send(Action::RefreshViews).unwrap(); sender.send(Action::RefreshAllViews).unwrap();
} }
#[allow(dead_code)] #[allow(dead_code)]