Hammond-gtk: Use Atomic Refference counting to reduce cloning of Podcast.

This commit is contained in:
Jordan Petridis 2018-02-07 06:28:16 +02:00
parent df02054b29
commit 67af85e347
No known key found for this signature in database
GPG Key ID: CEABAD9F5683B9A6
5 changed files with 45 additions and 26 deletions

View File

@ -5,6 +5,8 @@ use errors::DataError;
use models::{Save, Source}; use models::{Save, Source};
use schema::podcast; use schema::podcast;
use std::sync::Arc;
#[derive(Queryable, Identifiable, AsChangeset, Associations, PartialEq)] #[derive(Queryable, Identifiable, AsChangeset, Associations, PartialEq)]
#[belongs_to(Source, foreign_key = "source_id")] #[belongs_to(Source, foreign_key = "source_id")]
#[changeset_options(treat_none_as_null = "true")] #[changeset_options(treat_none_as_null = "true")]
@ -138,6 +140,16 @@ impl From<Podcast> for PodcastCoverQuery {
} }
} }
impl From<Arc<Podcast>> for PodcastCoverQuery {
fn from(p: Arc<Podcast>) -> PodcastCoverQuery {
PodcastCoverQuery {
id: p.id(),
title: p.title.clone(),
image_uri: p.image_uri.clone(),
}
}
}
impl PodcastCoverQuery { impl PodcastCoverQuery {
/// Get the Feed `id`. /// Get the Feed `id`.
pub fn id(&self) -> i32 { pub fn id(&self) -> i32 {

View File

@ -135,8 +135,8 @@ impl App {
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(ref pd)) => { Ok(Action::ReplaceWidget(pd)) => {
if let Err(err) = content.get_shows().replace_widget(pd) { if let Err(err) = content.get_shows().replace_widget(Arc::new(pd)) {
error!("Something went wrong while trying to update the ShowWidget."); error!("Something went wrong while trying to update the ShowWidget.");
error!("Error: {}", err); error!("Error: {}", err);
} }

View File

@ -12,6 +12,7 @@ use views::{EmptyView, ShowsPopulated};
use app::Action; use app::Action;
use widgets::ShowWidget; use widgets::ShowWidget;
use std::sync::Arc;
use std::sync::mpsc::Sender; use std::sync::mpsc::Sender;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -93,7 +94,7 @@ impl ShowStack {
Ok(()) Ok(())
} }
pub fn replace_widget(&self, pd: &Podcast) -> Result<(), Error> { pub fn replace_widget(&self, pd: Arc<Podcast>) -> Result<(), Error> {
let old = self.stack let old = self.stack
.get_child_by_name("widget") .get_child_by_name("widget")
.ok_or_else(|| format_err!("Faild to get \"widget\" child from the stack."))? .ok_or_else(|| format_err!("Faild to get \"widget\" child from the stack."))?
@ -144,7 +145,7 @@ impl ShowStack {
let id = id.ok_or_else(|| format_err!("Failed to get widget's name."))?; let id = id.ok_or_else(|| format_err!("Failed to get widget's name."))?;
let pd = dbqueries::get_podcast_from_id(id.parse::<i32>()?)?; let pd = dbqueries::get_podcast_from_id(id.parse::<i32>()?)?;
self.replace_widget(&pd)?; self.replace_widget(Arc::new(pd))?;
self.stack.set_visible_child_name(&vis); self.stack.set_visible_child_name(&vis);
old.destroy(); old.destroy();
Ok(()) Ok(())

View File

@ -8,6 +8,7 @@ use hammond_data::dbqueries;
use app::Action; use app::Action;
use utils::get_pixbuf_from_path; use utils::get_pixbuf_from_path;
use std::sync::Arc;
use std::sync::mpsc::Sender; use std::sync::mpsc::Sender;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -55,7 +56,10 @@ impl ShowsPopulated {
fn populate_flowbox(&self) -> Result<(), Error> { fn populate_flowbox(&self) -> Result<(), Error> {
let podcasts = dbqueries::get_podcasts()?; let podcasts = dbqueries::get_podcasts()?;
podcasts.iter().for_each(|parent| { podcasts
.into_iter()
.map(|pd| Arc::new(pd))
.for_each(|parent| {
let flowbox_child = ShowsChild::new(parent); let flowbox_child = ShowsChild::new(parent);
self.flowbox.add(&flowbox_child.child); self.flowbox.add(&flowbox_child.child);
}); });
@ -114,23 +118,23 @@ impl Default for ShowsChild {
} }
impl ShowsChild { impl ShowsChild {
pub fn new(pd: &Podcast) -> ShowsChild { pub fn new(pd: Arc<Podcast>) -> ShowsChild {
let child = ShowsChild::default(); let child = ShowsChild::default();
child.init(pd); child.init(pd);
child child
} }
fn init(&self, pd: &Podcast) { fn init(&self, pd: Arc<Podcast>) {
self.container.set_tooltip_text(pd.title()); self.container.set_tooltip_text(pd.title());
if let Err(err) = self.set_cover(pd) { if let Err(err) = self.set_cover(pd.clone()) {
error!("Failed to set a cover: {}", err) error!("Failed to set a cover: {}", err)
} }
WidgetExt::set_name(&self.child, &pd.id().to_string()); WidgetExt::set_name(&self.child, &pd.id().to_string());
} }
fn set_cover(&self, pd: &Podcast) -> Result<(), Error> { fn set_cover(&self, pd: Arc<Podcast>) -> Result<(), Error> {
let image = get_pixbuf_from_path(&pd.clone().into(), 256)?; let image = get_pixbuf_from_path(&pd.clone().into(), 256)?;
self.cover.set_from_pixbuf(&image); self.cover.set_from_pixbuf(&image);
Ok(()) Ok(())

View File

@ -12,6 +12,7 @@ use app::Action;
use utils::get_pixbuf_from_path; use utils::get_pixbuf_from_path;
use widgets::episode::episodes_listbox; use widgets::episode::episodes_listbox;
use std::sync::Arc;
use std::sync::mpsc::Sender; use std::sync::mpsc::Sender;
use std::thread; use std::thread;
@ -54,27 +55,27 @@ impl Default for ShowWidget {
} }
impl ShowWidget { impl ShowWidget {
pub fn new(pd: &Podcast, sender: Sender<Action>) -> ShowWidget { pub fn new(pd: Arc<Podcast>, sender: Sender<Action>) -> ShowWidget {
let pdw = ShowWidget::default(); let pdw = ShowWidget::default();
pdw.init(pd, sender); pdw.init(pd, sender);
pdw pdw
} }
pub fn init(&self, pd: &Podcast, sender: Sender<Action>) { pub fn init(&self, pd: Arc<Podcast>, sender: Sender<Action>) {
// Hacky workaround so the pd.id() can be retrieved from the `ShowStack`. // Hacky workaround so the pd.id() can be retrieved from the `ShowStack`.
WidgetExt::set_name(&self.container, &pd.id().to_string()); WidgetExt::set_name(&self.container, &pd.id().to_string());
self.unsub self.unsub
.connect_clicked(clone!(pd, sender => move |bttn| { .connect_clicked(clone!(pd, sender => move |bttn| {
if let Err(err) = on_unsub_button_clicked(&pd, bttn, sender.clone()) { if let Err(err) = on_unsub_button_clicked(pd.clone(), bttn, sender.clone()) {
error!("Error: {}", err); error!("Error: {}", err);
} }
})); }));
self.setup_listbox(pd, sender.clone()); self.setup_listbox(pd.clone(), sender.clone());
self.set_description(pd.description()); self.set_description(pd.description());
if let Err(err) = self.set_cover(pd) { if let Err(err) = self.set_cover(pd.clone()) {
error!("Failed to set a cover: {}", err) error!("Failed to set a cover: {}", err)
} }
@ -90,13 +91,14 @@ impl ShowWidget {
} }
/// Populate the listbox with the shows episodes. /// Populate the listbox with the shows episodes.
fn setup_listbox(&self, pd: &Podcast, sender: Sender<Action>) { fn setup_listbox(&self, pd: Arc<Podcast>, sender: Sender<Action>) {
let listbox = episodes_listbox(pd, sender.clone()); let listbox = episodes_listbox(&pd, sender.clone());
listbox.ok().map(|l| self.episodes.add(&l)); listbox.ok().map(|l| self.episodes.add(&l));
} }
/// Set the show cover. /// Set the show cover.
fn set_cover(&self, pd: &Podcast) -> Result<(), Error> { fn set_cover(&self, pd: Arc<Podcast>) -> Result<(), Error> {
let image = get_pixbuf_from_path(&pd.clone().into(), 128)?; let image = get_pixbuf_from_path(&pd.into(), 128)?;
self.cover.set_from_pixbuf(&image); self.cover.set_from_pixbuf(&image);
Ok(()) Ok(())
} }
@ -115,7 +117,7 @@ impl ShowWidget {
} }
fn on_unsub_button_clicked( fn on_unsub_button_clicked(
pd: &Podcast, pd: Arc<Podcast>,
unsub_button: &gtk::Button, unsub_button: &gtk::Button,
sender: Sender<Action>, sender: Sender<Action>,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -123,12 +125,12 @@ fn on_unsub_button_clicked(
// if pressed twice would panic. // if pressed twice would panic.
unsub_button.hide(); unsub_button.hide();
// Spawn a thread so it won't block the ui. // Spawn a thread so it won't block the ui.
thread::spawn(clone!(pd => move || { thread::spawn(move || {
if let Err(err) = delete_show(&pd) { if let Err(err) = delete_show(&pd) {
error!("Something went wrong trying to remove {}", pd.title()); error!("Something went wrong trying to remove {}", pd.title());
error!("Error: {}", err); error!("Error: {}", err);
} }
})); });
sender.send(Action::HeaderBarNormal)?; sender.send(Action::HeaderBarNormal)?;
sender.send(Action::ShowShowsAnimated)?; sender.send(Action::ShowShowsAnimated)?;
@ -140,8 +142,8 @@ fn on_unsub_button_clicked(
} }
#[allow(dead_code)] #[allow(dead_code)]
fn on_played_button_clicked(pd: &Podcast, sender: Sender<Action>) -> Result<(), Error> { fn on_played_button_clicked(pd: Arc<Podcast>, sender: Sender<Action>) -> Result<(), Error> {
dbqueries::update_none_to_played_now(pd)?; dbqueries::update_none_to_played_now(&pd)?;
sender.send(Action::RefreshWidget)?; sender.send(Action::RefreshWidget)?;
Ok(()) Ok(())
} }