From c74153f56a9a34094dddddca0cbca3bc79204e38 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Fri, 15 Dec 2017 18:42:49 +0200 Subject: [PATCH 01/16] Initial implementation of the new ShowWidget. --- hammond-gtk/resources/gtk/show_widget.ui | 255 ++++++++++------------- hammond-gtk/src/utils.rs | 5 + hammond-gtk/src/widgets/show.rs | 64 +++--- 3 files changed, 147 insertions(+), 177 deletions(-) diff --git a/hammond-gtk/resources/gtk/show_widget.ui b/hammond-gtk/resources/gtk/show_widget.ui index 6b30d01..cfb2207 100644 --- a/hammond-gtk/resources/gtk/show_widget.ui +++ b/hammond-gtk/resources/gtk/show_widget.ui @@ -2,191 +2,156 @@ - + True False + vertical - + True - False - center - center - 32 - 32 - 32 - 32 - 64 - 32 + True + in - + True False - center - center - vertical - 15 - - - True - False - center - start - 1 - 1 - 1 - 1 - - - False - False - 0 - - True False - center - center + vertical True False - center + center - - 50 + + True + False + 128 + image-x-generic-symbolic + + + False + True + 0 + + + + True False center - Foobar - True - center - True - 28 - False + center + vertical + + + True + False + The people behind The Intercept’s fearless reporting and incisive commentary—Jeremy Scahill, Glenn Greenwald, Betsy Reed and others—discuss the crucial issues of our time: national security, civil liberties, foreign policy, and criminal justice. Plus interviews with artists, thinkers, and newsmakers who challenge our preconceptions about the world we live in. + True + + + False + True + 5 + 0 + + + + + True + False + + + True + True + True + + + True + False + emblem-system-symbolic + + + + + False + True + 5 + 0 + + + + + Website + True + True + True + + + False + True + 5 + 1 + + + + + Unsubscribe + True + True + True + + + False + True + 5 + end + 2 + + + + + False + True + 5 + 1 + + True True - 0 + 5 + 1 False True - 5 - 1 + 10 + 0 - + True - True - True - center - center + False + vertical - - True - False - Unsubrscribe from this Podcast. -Warn: This will delete downloaded content associated with this Podcast. - user-trash-symbolic - + - False - False - 5 - end + True + True 1 - - - True - True - Mark all episodes as Played. - center - center - - - True - False - object-select-symbolic - - - - - False - False - 2 - - - - False - False - 1 - - - - - True - True - in - 200 - 200 - True - True - - - True - True - False - word-char - False - - - - - True - True - 2 - - - - - False - False - 0 - - - - - False - False - 1 - - - - - True - True - True - True - never - - - 400 - True - False - none - - @@ -194,7 +159,7 @@ Warn: This will delete downloaded content associated with this Podcast. True True - 2 + 0 diff --git a/hammond-gtk/src/utils.rs b/hammond-gtk/src/utils.rs index 7327854..56cdc56 100644 --- a/hammond-gtk/src/utils.rs +++ b/hammond-gtk/src/utils.rs @@ -70,6 +70,11 @@ pub fn get_pixbuf_from_path(pd: &Podcast) -> Option { Pixbuf::new_from_file_at_scale(&img_path, 256, 256, true).ok() } +pub fn get_pixbuf_from_path_128(pd: &Podcast) -> Option { + let img_path = downloader::cache_image(pd)?; + Pixbuf::new_from_file_at_scale(&img_path, 128, 128, true).ok() +} + #[cfg(test)] mod tests { use hammond_data::Source; diff --git a/hammond-gtk/src/widgets/show.rs b/hammond-gtk/src/widgets/show.rs index 99da2b8..5aaff1a 100644 --- a/hammond-gtk/src/widgets/show.rs +++ b/hammond-gtk/src/widgets/show.rs @@ -9,7 +9,7 @@ use hammond_data::Podcast; use hammond_downloader::downloader; use widgets::episode::episodes_listbox; -use utils::get_pixbuf_from_path; +use utils::get_pixbuf_from_path_128; use content::ShowStack; use headerbar::Header; @@ -19,34 +19,38 @@ use std::rc::Rc; pub struct ShowWidget { pub container: gtk::Box, cover: gtk::Image, - title: gtk::Label, - description: gtk::TextView, - view: gtk::Viewport, + description: gtk::Label, + link: gtk::Button, + settings: gtk::Button, unsub: gtk::Button, - played: gtk::Button, + episodes: gtk::Box, } impl ShowWidget { pub fn new() -> ShowWidget { // Adapted from gnome-music AlbumWidget let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/show_widget.ui"); - let container: gtk::Box = builder.get_object("podcast_widget").unwrap(); + let container: gtk::Box = builder.get_object("container").unwrap(); + let episodes: gtk::Box = builder.get_object("episodes").unwrap(); let cover: gtk::Image = builder.get_object("cover").unwrap(); - let title: gtk::Label = builder.get_object("title_label").unwrap(); - let description: gtk::TextView = builder.get_object("desc_text_view").unwrap(); - let view: gtk::Viewport = builder.get_object("view").unwrap(); + let description: gtk::Label = builder.get_object("description").unwrap(); let unsub: gtk::Button = builder.get_object("unsub_button").unwrap(); - let played: gtk::Button = builder.get_object("mark_all_played_button").unwrap(); + let link: gtk::Button = builder.get_object("link_button").unwrap(); + let settings: gtk::Button = builder.get_object("settings_button").unwrap(); + + unsub + .get_style_context() + .map(|c| c.add_class("destructive-action")); ShowWidget { container, cover, - title, description, - view, unsub, - played, + link, + settings, + episodes, } } @@ -65,38 +69,34 @@ impl ShowWidget { header.switch_to_normal(); })); - self.title.set_text(pd.title()); let listbox = episodes_listbox(pd); if let Ok(l) = listbox { - self.view.add(&l); + self.episodes.add(&l); } - { - let buff = self.description.get_buffer().unwrap(); - buff.set_text(pd.description()); - } + self.description.set_text(pd.description()); - let img = get_pixbuf_from_path(pd); + let img = get_pixbuf_from_path_128(pd); if let Some(i) = img { self.cover.set_from_pixbuf(&i); } - self.played.connect_clicked(clone!(shows, pd => move |_| { - on_played_button_clicked(shows.clone(), &pd); - })); + // self.played.connect_clicked(clone!(shows, pd => move |_| { + // on_played_button_clicked(shows.clone(), &pd); + // })); - self.show_played_button(pd); + // self.show_played_button(pd); } - fn show_played_button(&self, pd: &Podcast) { - let new_episodes = dbqueries::get_pd_unplayed_episodes(pd); + // fn show_played_button(&self, pd: &Podcast) { + // let new_episodes = dbqueries::get_pd_unplayed_episodes(pd); - if let Ok(n) = new_episodes { - if !n.is_empty() { - self.played.show() - } - } - } + // if let Ok(n) = new_episodes { + // if !n.is_empty() { + // self.played.show() + // } + // } + // } } fn on_unsub_button_clicked(shows: Rc, pd: &Podcast, unsub_button: >k::Button) { From 6614818418b4829b6dc41791bb629000ae8efeec Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Fri, 15 Dec 2017 19:55:13 +0200 Subject: [PATCH 02/16] Use Gtk::Frame to limit ShowWidget's size. --- hammond-gtk/resources/gtk/show_widget.ui | 310 ++++++++++++++--------- hammond-gtk/src/widgets/show.rs | 4 +- 2 files changed, 195 insertions(+), 119 deletions(-) diff --git a/hammond-gtk/resources/gtk/show_widget.ui b/hammond-gtk/resources/gtk/show_widget.ui index cfb2207..cac47f5 100644 --- a/hammond-gtk/resources/gtk/show_widget.ui +++ b/hammond-gtk/resources/gtk/show_widget.ui @@ -19,125 +19,9 @@ True False - vertical + center - True - False - center - - - True - False - 128 - image-x-generic-symbolic - - - False - True - 0 - - - - - True - False - center - center - vertical - - - True - False - The people behind The Intercept’s fearless reporting and incisive commentary—Jeremy Scahill, Glenn Greenwald, Betsy Reed and others—discuss the crucial issues of our time: national security, civil liberties, foreign policy, and criminal justice. Plus interviews with artists, thinkers, and newsmakers who challenge our preconceptions about the world we live in. - True - - - False - True - 5 - 0 - - - - - True - False - - - True - True - True - - - True - False - emblem-system-symbolic - - - - - False - True - 5 - 0 - - - - - Website - True - True - True - - - False - True - 5 - 1 - - - - - Unsubscribe - True - True - True - - - False - True - 5 - end - 2 - - - - - False - True - 5 - 1 - - - - - True - True - 5 - 1 - - - - - False - True - 10 - 0 - - - - True False vertical @@ -148,9 +32,201 @@ True True + 0 + + + + + True + False + center + vertical + + + True + False + 0 + none + + + True + False + vertical + + + True + False + center + + + True + False + 128 + image-x-generic-symbolic + + + False + False + 5 + 0 + + + + + True + False + center + vertical + + + True + False + start + center + A podcast about learning the Rust + True + 80 + 80 + False + + + False + False + 5 + 0 + + + + + True + False + + + True + True + True + + + True + False + emblem-system-symbolic + + + + + False + True + 5 + 0 + + + + + Website + True + True + True + + + False + True + 5 + 1 + + + + + Unsubscribe + True + True + True + + + False + True + 5 + end + 2 + + + + + False + False + 5 + 1 + + + + + False + False + 5 + 1 + + + + + False + False + 10 + 0 + + + + + + + + + + False + False + 5 + 0 + + + + + True + False + 0 + none + + + + + + + + + True + True + 1 + + + + + False + True 1 + + + True + False + vertical + + + + + + False + True + 2 + + diff --git a/hammond-gtk/src/widgets/show.rs b/hammond-gtk/src/widgets/show.rs index 5aaff1a..a8b9f83 100644 --- a/hammond-gtk/src/widgets/show.rs +++ b/hammond-gtk/src/widgets/show.rs @@ -23,7 +23,7 @@ pub struct ShowWidget { link: gtk::Button, settings: gtk::Button, unsub: gtk::Button, - episodes: gtk::Box, + episodes: gtk::Frame, } impl ShowWidget { @@ -31,7 +31,7 @@ impl ShowWidget { // Adapted from gnome-music AlbumWidget let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/show_widget.ui"); let container: gtk::Box = builder.get_object("container").unwrap(); - let episodes: gtk::Box = builder.get_object("episodes").unwrap(); + let episodes: gtk::Frame = builder.get_object("episodes").unwrap(); let cover: gtk::Image = builder.get_object("cover").unwrap(); let description: gtk::Label = builder.get_object("description").unwrap(); From b1af25e4c0af6a4787dd33ba2eb79225c7127d57 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Fri, 15 Dec 2017 20:38:39 +0200 Subject: [PATCH 03/16] ShowWidget: Wire the website button to open podcast homepage. --- hammond-gtk/src/widgets/show.rs | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/hammond-gtk/src/widgets/show.rs b/hammond-gtk/src/widgets/show.rs index a8b9f83..a9b27ba 100644 --- a/hammond-gtk/src/widgets/show.rs +++ b/hammond-gtk/src/widgets/show.rs @@ -1,6 +1,7 @@ use gtk::prelude::*; use gtk; use diesel::Identifiable; +use open; use std::fs; @@ -28,7 +29,6 @@ pub struct ShowWidget { impl ShowWidget { pub fn new() -> ShowWidget { - // Adapted from gnome-music AlbumWidget let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/show_widget.ui"); let container: gtk::Box = builder.get_object("container").unwrap(); let episodes: gtk::Frame = builder.get_object("episodes").unwrap(); @@ -81,22 +81,16 @@ impl ShowWidget { self.cover.set_from_pixbuf(&i); } + let link = pd.link().to_owned(); + self.link.connect_clicked(move |_| { + info!("Opening link: {}", &link); + let _ = open::that(&link); + }); + // self.played.connect_clicked(clone!(shows, pd => move |_| { // on_played_button_clicked(shows.clone(), &pd); // })); - - // self.show_played_button(pd); } - - // fn show_played_button(&self, pd: &Podcast) { - // let new_episodes = dbqueries::get_pd_unplayed_episodes(pd); - - // if let Ok(n) = new_episodes { - // if !n.is_empty() { - // self.played.show() - // } - // } - // } } fn on_unsub_button_clicked(shows: Rc, pd: &Podcast, unsub_button: >k::Button) { From 3c90e98d43f7be1b9649ee587510e0f92fdc9f7d Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Fri, 15 Dec 2017 20:46:55 +0200 Subject: [PATCH 04/16] ShowWidget: Make settings button a GtkMenuButton. --- hammond-gtk/resources/gtk/show_widget.ui | 9 +++++++-- hammond-gtk/src/widgets/show.rs | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/hammond-gtk/resources/gtk/show_widget.ui b/hammond-gtk/resources/gtk/show_widget.ui index cac47f5..3e0f918 100644 --- a/hammond-gtk/resources/gtk/show_widget.ui +++ b/hammond-gtk/resources/gtk/show_widget.ui @@ -101,7 +101,7 @@ True False - + True True True @@ -109,6 +109,8 @@ True False + center + center emblem-system-symbolic @@ -116,7 +118,6 @@ False True - 5 0 @@ -126,6 +127,8 @@ True True True + center + center False @@ -140,6 +143,8 @@ True True True + center + center False diff --git a/hammond-gtk/src/widgets/show.rs b/hammond-gtk/src/widgets/show.rs index a9b27ba..4d1f7ea 100644 --- a/hammond-gtk/src/widgets/show.rs +++ b/hammond-gtk/src/widgets/show.rs @@ -22,7 +22,7 @@ pub struct ShowWidget { cover: gtk::Image, description: gtk::Label, link: gtk::Button, - settings: gtk::Button, + settings: gtk::MenuButton, unsub: gtk::Button, episodes: gtk::Frame, } @@ -37,7 +37,7 @@ impl ShowWidget { let description: gtk::Label = builder.get_object("description").unwrap(); let unsub: gtk::Button = builder.get_object("unsub_button").unwrap(); let link: gtk::Button = builder.get_object("link_button").unwrap(); - let settings: gtk::Button = builder.get_object("settings_button").unwrap(); + let settings: gtk::MenuButton = builder.get_object("settings_button").unwrap(); unsub .get_style_context() From 4375c7f4ceecbb00a4af4e02baba3396a8d4ca82 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Fri, 15 Dec 2017 21:00:51 +0200 Subject: [PATCH 05/16] EpisodeWidget: Added a separator in each widget. This is a work around since list_box_set_header_func is not yet available in the gtk-rs bindings. --- hammond-gtk/resources/gtk/episode_widget.ui | 17 ++++++++++++++--- hammond-gtk/src/widgets/episode.rs | 3 ++- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/hammond-gtk/resources/gtk/episode_widget.ui b/hammond-gtk/resources/gtk/episode_widget.ui index cc2d9d5..527dee8 100644 --- a/hammond-gtk/resources/gtk/episode_widget.ui +++ b/hammond-gtk/resources/gtk/episode_widget.ui @@ -6,7 +6,17 @@ True False vertical - 5 + + + True + False + + + False + True + 0 + + True @@ -244,7 +254,8 @@ True True - 0 + 5 + 1 @@ -255,7 +266,7 @@ False True 5 - 1 + 2 diff --git a/hammond-gtk/src/widgets/episode.rs b/hammond-gtk/src/widgets/episode.rs index 921696f..fb166a3 100644 --- a/hammond-gtk/src/widgets/episode.rs +++ b/hammond-gtk/src/widgets/episode.rs @@ -273,7 +273,8 @@ pub fn episodes_listbox(pd: &Podcast) -> Result { let list = gtk::ListBox::new(); episodes.into_iter().for_each(|mut ep| { let widget = EpisodeWidget::new_initialized(&mut ep, pd); - list.add(&widget.container) + list.add(&widget.container); + list.add(>k::Separator::new(gtk::Orientation::Vertical)) }); list.set_vexpand(false); From 5989f4f54114b16f38e76c0b779dd5ad896bce7c Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Fri, 15 Dec 2017 21:15:20 +0200 Subject: [PATCH 06/16] ShowWidget: Set widget width to 600. --- hammond-gtk/resources/gtk/show_widget.ui | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hammond-gtk/resources/gtk/show_widget.ui b/hammond-gtk/resources/gtk/show_widget.ui index 3e0f918..2620800 100644 --- a/hammond-gtk/resources/gtk/show_widget.ui +++ b/hammond-gtk/resources/gtk/show_widget.ui @@ -37,6 +37,7 @@ + 600 True False center @@ -85,8 +86,7 @@ center A podcast about learning the Rust True - 80 - 80 + 60 False @@ -165,7 +165,7 @@ False - False + True 5 1 From dbe08f7deb1bc7dca622a7e2528cfc4b6d102cb0 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Sat, 16 Dec 2017 14:17:27 +0200 Subject: [PATCH 07/16] EpisodeListBox: Improve the separator workaround. --- hammond-gtk/resources/gtk/episode_widget.ui | 15 ++------------- hammond-gtk/resources/gtk/show_widget.ui | 2 +- hammond-gtk/src/widgets/episode.rs | 10 ++++++++-- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/hammond-gtk/resources/gtk/episode_widget.ui b/hammond-gtk/resources/gtk/episode_widget.ui index 527dee8..dc3cdf9 100644 --- a/hammond-gtk/resources/gtk/episode_widget.ui +++ b/hammond-gtk/resources/gtk/episode_widget.ui @@ -6,17 +6,6 @@ True False vertical - - - True - False - - - False - True - 0 - - True @@ -255,7 +244,7 @@ True True 5 - 1 + 0 @@ -266,7 +255,7 @@ False True 5 - 2 + 1 diff --git a/hammond-gtk/resources/gtk/show_widget.ui b/hammond-gtk/resources/gtk/show_widget.ui index 2620800..76a2b2a 100644 --- a/hammond-gtk/resources/gtk/show_widget.ui +++ b/hammond-gtk/resources/gtk/show_widget.ui @@ -196,7 +196,7 @@ True False 0 - none + in diff --git a/hammond-gtk/src/widgets/episode.rs b/hammond-gtk/src/widgets/episode.rs index fb166a3..35bfb02 100644 --- a/hammond-gtk/src/widgets/episode.rs +++ b/hammond-gtk/src/widgets/episode.rs @@ -269,12 +269,18 @@ fn receive() -> glib::Continue { pub fn episodes_listbox(pd: &Podcast) -> Result { let episodes = dbqueries::get_pd_episodeswidgets(pd)?; - // TODO: add a separator let list = gtk::ListBox::new(); + episodes.into_iter().for_each(|mut ep| { let widget = EpisodeWidget::new_initialized(&mut ep, pd); list.add(&widget.container); - list.add(>k::Separator::new(gtk::Orientation::Vertical)) + + let sep = gtk::Separator::new(gtk::Orientation::Vertical); + sep.set_sensitive(false); + sep.set_can_focus(false); + + list.add(&sep); + sep.show() }); list.set_vexpand(false); From 0653460fb2163fb2a1ca0aaa5b7a3df07c5c3763 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Sat, 16 Dec 2017 14:58:16 +0200 Subject: [PATCH 08/16] EpisodeWidget: prevent title label overflow. Set label's maximu character width to prevent it and elipsize instead. --- hammond-gtk/resources/gtk/episode_widget.ui | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hammond-gtk/resources/gtk/episode_widget.ui b/hammond-gtk/resources/gtk/episode_widget.ui index dc3cdf9..992a09b 100644 --- a/hammond-gtk/resources/gtk/episode_widget.ui +++ b/hammond-gtk/resources/gtk/episode_widget.ui @@ -27,8 +27,9 @@ False start Episode Title - True end + True + 70 False 1 From f8ae2dcffec3cc9f6d743a1c5cfeba797ffe2cb5 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Sat, 16 Dec 2017 18:22:35 +0200 Subject: [PATCH 09/16] Update rustfmt.toml and remove rustfmt warnings. --- hammond-gtk/src/main.rs | 4 +--- rustfmt.toml | 19 +++---------------- 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/hammond-gtk/src/main.rs b/hammond-gtk/src/main.rs index 5b1bac6..ef03853 100644 --- a/hammond-gtk/src/main.rs +++ b/hammond-gtk/src/main.rs @@ -52,9 +52,7 @@ mod content; mod utils; mod static_resource; -/* -THIS IS STILL A PROTOTYPE. -*/ +// THIS IS STILL A PROTOTYPE. fn build_ui(app: >k::Application) { let menu = gio::Menu::new(); diff --git a/rustfmt.toml b/rustfmt.toml index 7f1b8d9..c420ec1 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,26 +1,13 @@ unstable_features = true verbose = false -disable_all_formatting = false -skip_children = false max_width = 100 comment_width = 100 wrap_comments = true -error_on_line_overflow = true -error_on_line_overflow_comments = false tab_spaces = 4 -newline_style = "Unix" -fn_call_style = "Block" -report_todo = "Never" -report_fixme = "Never" -reorder_extern_crates = true -reorder_extern_crates_in_group = true -reorder_imports = false hard_tabs = false -spaces_within_parens = false +newline_style = "Unix" +reorder_imports = false write_mode = "Overwrite" -merge_derives = true condense_wildcard_suffixes = false format_strings = true -multiline_closure_forces_block = true -attributes_on_same_line_as_field = true -attributes_on_same_line_as_variant = true \ No newline at end of file +normalize_comments = true \ No newline at end of file From aca35c051318a83c2ad850e2809f6ee3b8bf3be9 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Sat, 16 Dec 2017 19:20:40 +0200 Subject: [PATCH 10/16] ShowWidget: Improve? description handling. --- hammond-gtk/resources/gtk/episode_widget.ui | 13 ++-- hammond-gtk/resources/gtk/show_widget.ui | 66 +++++++++++---------- 2 files changed, 41 insertions(+), 38 deletions(-) diff --git a/hammond-gtk/resources/gtk/episode_widget.ui b/hammond-gtk/resources/gtk/episode_widget.ui index 992a09b..c18c8a3 100644 --- a/hammond-gtk/resources/gtk/episode_widget.ui +++ b/hammond-gtk/resources/gtk/episode_widget.ui @@ -29,7 +29,7 @@ Episode Title end True - 70 + 60 False 1 @@ -41,7 +41,7 @@ - True + False True 0 @@ -135,14 +135,14 @@ - True + False True 1 - True + False True 5 0 @@ -162,7 +162,7 @@ False - True + False end 0 @@ -237,12 +237,13 @@ False True 5 + end 1 - True + False True 5 0 diff --git a/hammond-gtk/resources/gtk/show_widget.ui b/hammond-gtk/resources/gtk/show_widget.ui index 76a2b2a..cc3c9b4 100644 --- a/hammond-gtk/resources/gtk/show_widget.ui +++ b/hammond-gtk/resources/gtk/show_widget.ui @@ -31,7 +31,7 @@ True - True + False 0 @@ -58,6 +58,7 @@ True False center + 10 True @@ -67,8 +68,7 @@ False - False - 5 + True 0 @@ -76,30 +76,13 @@ True False - center vertical - - - True - False - start - center - A podcast about learning the Rust - True - 60 - False - - - False - False - 5 - 0 - - + 10 True False + 5 True @@ -158,23 +141,42 @@ False False - 5 + end + 0 + + + + + True + False + start + center + Show description + True + word-char + 55 + + + + + + True + True + end 1 - False + True True - 5 1 False - False - 10 + True 0 @@ -186,8 +188,8 @@ False - False - 5 + True + 25 0 @@ -205,7 +207,7 @@ - True + False True 1 @@ -227,8 +229,8 @@ - False - True + True + False 2 From f7af05a650116afe6e137ae54ca130fcaab2bd2c Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Sat, 16 Dec 2017 20:30:25 +0200 Subject: [PATCH 11/16] EpisodeWidget: Dim/Grey out widget if episode is played. --- hammond-data/src/dbqueries.rs | 2 +- hammond-gtk/src/widgets/episode.rs | 18 +++++++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/hammond-data/src/dbqueries.rs b/hammond-data/src/dbqueries.rs index f1bb8dd..7adb91c 100644 --- a/hammond-data/src/dbqueries.rs +++ b/hammond-data/src/dbqueries.rs @@ -50,7 +50,7 @@ pub fn get_played_episodes() -> Result> { Ok(episode.filter(played.is_not_null()).load::(&*con)?) } -pub fn get_episode_from_id(ep_id: i32) -> Result { +pub fn get_episode_from_rowid(ep_id: i32) -> Result { use schema::episode::dsl::*; let db = connection(); diff --git a/hammond-gtk/src/widgets/episode.rs b/hammond-gtk/src/widgets/episode.rs index 35bfb02..11e2fbc 100644 --- a/hammond-gtk/src/widgets/episode.rs +++ b/hammond-gtk/src/widgets/episode.rs @@ -109,6 +109,12 @@ impl EpisodeWidget { self.title.set_xalign(0.0); self.title.set_text(episode.title()); + if episode.played().is_some() { + self.title + .get_style_context() + .map(|c| c.add_class("dim-label")); + } + let progress = self.progress.clone(); timeout_add(200, move || { progress.pulse(); @@ -133,10 +139,16 @@ impl EpisodeWidget { self.delete.show(); } - self.play.connect_clicked(clone!(episode => move |_| { + let title = &self.title; + self.play + .connect_clicked(clone!(episode, title => move |_| { let mut episode = episode.clone(); on_play_bttn_clicked(episode.rowid()); - let _ = episode.set_played_now(); + if episode.set_played_now().is_ok() { + title + .get_style_context() + .map(|c| c.add_class("dim-label")); + }; })); let play = &self.play; @@ -234,7 +246,7 @@ fn on_play_bttn_clicked(episode_id: i32) { } fn on_delete_bttn_clicked(episode_id: i32) { - let mut ep = dbqueries::get_episode_from_id(episode_id).unwrap(); + let mut ep = dbqueries::get_episode_from_rowid(episode_id).unwrap(); let e = delete_local_content(&mut ep); if let Err(err) = e { From 440badf1ebb813bbc2b683eef4f8d4e4f61af3bd Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Sat, 16 Dec 2017 20:45:15 +0200 Subject: [PATCH 12/16] ShowWidget: Strip html tags from the description. --- hammond-downloader/src/downloader.rs | 2 +- hammond-gtk/src/widgets/show.rs | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/hammond-downloader/src/downloader.rs b/hammond-downloader/src/downloader.rs index 4343e91..e3a4a0c 100644 --- a/hammond-downloader/src/downloader.rs +++ b/hammond-downloader/src/downloader.rs @@ -8,7 +8,7 @@ use std::io::{BufWriter, Read, Write}; use std::path::Path; use errors::*; -use hammond_data::{Episode, EpisodeWidgetQuery, Podcast}; +use hammond_data::{EpisodeWidgetQuery, Podcast}; use hammond_data::xdg_dirs::{DL_DIR, HAMMOND_CACHE}; // TODO: Replace path that are of type &str with std::path. diff --git a/hammond-gtk/src/widgets/show.rs b/hammond-gtk/src/widgets/show.rs index 4d1f7ea..308964c 100644 --- a/hammond-gtk/src/widgets/show.rs +++ b/hammond-gtk/src/widgets/show.rs @@ -2,11 +2,11 @@ use gtk::prelude::*; use gtk; use diesel::Identifiable; use open; - -use std::fs; +use dissolve; use hammond_data::dbqueries; use hammond_data::Podcast; +use hammond_data::utils::replace_extra_spaces; use hammond_downloader::downloader; use widgets::episode::episodes_listbox; @@ -15,6 +15,7 @@ use content::ShowStack; use headerbar::Header; use std::rc::Rc; +use std::fs; #[derive(Debug, Clone)] pub struct ShowWidget { @@ -74,7 +75,9 @@ impl ShowWidget { self.episodes.add(&l); } - self.description.set_text(pd.description()); + // TODO: Temporary solution until we render html urls/bold/italic probably with markup. + let desc = dissolve::strip_html_tags(pd.description()).join(" "); + self.description.set_text(&replace_extra_spaces(&desc)); let img = get_pixbuf_from_path_128(pd); if let Some(i) = img { @@ -113,6 +116,7 @@ fn on_unsub_button_clicked(shows: Rc, pd: &Podcast, unsub_button: > shows.update_podcasts(); } +#[allow(dead_code)] fn on_played_button_clicked(shows: Rc, pd: &Podcast) { let _ = dbqueries::update_none_to_played_now(pd); From 75fe0f8ff5317ef47295e4a19f715e874d5f605c Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Sun, 17 Dec 2017 13:08:51 +0200 Subject: [PATCH 13/16] Use Default trait for creating Widget's that don't need arguments. --- hammond-gtk/src/content.rs | 8 ++--- hammond-gtk/src/headerbar.rs | 17 +++++++--- hammond-gtk/src/main.rs | 11 ++---- hammond-gtk/src/views/empty.rs | 10 ++++-- hammond-gtk/src/views/shows.rs | 54 ++++++++++++++++-------------- hammond-gtk/src/widgets/episode.rs | 12 ++++--- hammond-gtk/src/widgets/show.rs | 10 +++--- 7 files changed, 68 insertions(+), 54 deletions(-) diff --git a/hammond-gtk/src/content.rs b/hammond-gtk/src/content.rs index c87f88f..adc4cb6 100644 --- a/hammond-gtk/src/content.rs +++ b/hammond-gtk/src/content.rs @@ -60,8 +60,8 @@ impl ShowStack { header: header.clone(), }); - let pop = ShowsPopulated::new_initialized(show.clone(), header); - let widget = ShowWidget::new(); + let pop = ShowsPopulated::new(show.clone(), header); + let widget = ShowWidget::default(); let empty = EmptyView::new(); show.stack.add_named(&pop.container, "podcasts"); @@ -90,7 +90,7 @@ impl ShowStack { let vis = self.stack.get_visible_child_name().unwrap(); let old = self.stack.get_child_by_name("podcasts").unwrap(); - let pop = ShowsPopulated::new(); + let pop = ShowsPopulated::default(); pop.init(Rc::new(self.clone()), self.header.clone()); self.stack.remove(&old); @@ -109,7 +109,7 @@ impl ShowStack { pub fn replace_widget(&self, pd: &Podcast) { let old = self.stack.get_child_by_name("widget").unwrap(); - let new = ShowWidget::new_initialized(Rc::new(self.clone()), self.header.clone(), pd); + let new = ShowWidget::new(Rc::new(self.clone()), self.header.clone(), pd); self.stack.remove(&old); self.stack.add_named(&new.container, "widget"); diff --git a/hammond-gtk/src/headerbar.rs b/hammond-gtk/src/headerbar.rs index d683591..057957e 100644 --- a/hammond-gtk/src/headerbar.rs +++ b/hammond-gtk/src/headerbar.rs @@ -19,8 +19,8 @@ pub struct Header { show_title: gtk::Label, } -impl Header { - pub fn new() -> Rc
{ +impl Default for Header { + fn default() -> Header { let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/headerbar.ui"); let header: gtk::HeaderBar = builder.get_object("headerbar").unwrap(); @@ -33,14 +33,23 @@ impl Header { switch.set_halign(gtk::Align::Center); switch.show(); - Rc::new(Header { + Header { container: header, refresh, add_toggle, switch, back_button, show_title, - }) + } + } +} + +impl Header { + #[allow(dead_code)] + pub fn new(content: Rc) -> Rc
{ + let h = Header::default(); + h.init(content); + Rc::new(h) } pub fn init(&self, content: Rc) { diff --git a/hammond-gtk/src/main.rs b/hammond-gtk/src/main.rs index ef03853..dbe6c3a 100644 --- a/hammond-gtk/src/main.rs +++ b/hammond-gtk/src/main.rs @@ -24,6 +24,7 @@ use hammond_data::utils::checkup; use gtk::prelude::*; use gio::{ActionMapExt, ApplicationExt, MenuExt, SimpleActionExt}; +use std::rc::Rc; // http://gtk-rs.org/tuto/closures #[macro_export] @@ -52,8 +53,6 @@ mod content; mod utils; mod static_resource; -// THIS IS STILL A PROTOTYPE. - fn build_ui(app: >k::Application) { let menu = gio::Menu::new(); menu.append("Quit", "app.quit"); @@ -64,14 +63,8 @@ fn build_ui(app: >k::Application) { let window = gtk::ApplicationWindow::new(app); window.set_default_size(1150, 650); - // TODO: this will blow horribly - // let ct = content::ContentState::new().unwrap(); - // let stack = ct.get_stack(); - - // let ct = content::Content::new_initialized(); - // Get the headerbar - let header = headerbar::Header::new(); + let header = Rc::new(headerbar::Header::default()); let ct = content::Content::new(header.clone()); header.init(ct.clone()); window.set_titlebar(&header.container); diff --git a/hammond-gtk/src/views/empty.rs b/hammond-gtk/src/views/empty.rs index 1c93da7..ad3d152 100644 --- a/hammond-gtk/src/views/empty.rs +++ b/hammond-gtk/src/views/empty.rs @@ -5,11 +5,17 @@ pub struct EmptyView { pub container: gtk::Box, } -impl EmptyView { - pub fn new() -> EmptyView { +impl Default for EmptyView { + fn default() -> Self { let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/empty_view.ui"); let view: gtk::Box = builder.get_object("empty_view").unwrap(); EmptyView { container: view } } } + +impl EmptyView { + pub fn new() -> EmptyView { + EmptyView::default() + } +} diff --git a/hammond-gtk/src/views/shows.rs b/hammond-gtk/src/views/shows.rs index 981469b..327a9b8 100644 --- a/hammond-gtk/src/views/shows.rs +++ b/hammond-gtk/src/views/shows.rs @@ -19,18 +19,8 @@ pub struct ShowsPopulated { viewport: gtk::Viewport, } -#[derive(Debug)] -struct ShowsChild { - container: gtk::Box, - title: gtk::Label, - cover: gtk::Image, - banner: gtk::Image, - number: gtk::Label, - child: gtk::FlowBoxChild, -} - -impl ShowsPopulated { - pub fn new() -> ShowsPopulated { +impl Default for ShowsPopulated { + fn default() -> Self { let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/shows_view.ui"); let container: gtk::Box = builder.get_object("fb_parent").unwrap(); let flowbox: gtk::FlowBox = builder.get_object("flowbox").unwrap(); @@ -42,10 +32,11 @@ impl ShowsPopulated { viewport, } } +} - #[allow(dead_code)] - pub fn new_initialized(show: Rc, header: Rc
) -> ShowsPopulated { - let pop = ShowsPopulated::new(); +impl ShowsPopulated { + pub fn new(show: Rc, header: Rc
) -> ShowsPopulated { + let pop = ShowsPopulated::default(); pop.init(show, header); pop } @@ -74,7 +65,7 @@ impl ShowsPopulated { if let Ok(pds) = podcasts { pds.iter().for_each(|parent| { - let flowbox_child = ShowsChild::new_initialized(parent); + let flowbox_child = ShowsChild::new(parent); self.flowbox.add(&flowbox_child.child); }); self.flowbox.show_all(); @@ -86,11 +77,20 @@ impl ShowsPopulated { } } -impl ShowsChild { - fn new() -> ShowsChild { +#[derive(Debug)] +struct ShowsChild { + container: gtk::Box, + title: gtk::Label, + cover: gtk::Image, + banner: gtk::Image, + number: gtk::Label, + child: gtk::FlowBoxChild, +} + +impl Default for ShowsChild { + fn default() -> Self { let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/shows_child.ui"); - // Copy of gnome-music AlbumWidget let container: gtk::Box = builder.get_object("fb_child").unwrap(); let title: gtk::Label = builder.get_object("pd_title").unwrap(); let cover: gtk::Image = builder.get_object("pd_cover").unwrap(); @@ -109,6 +109,15 @@ impl ShowsChild { child, } } +} + +impl ShowsChild { + pub fn new(pd: &Podcast) -> ShowsChild { + let child = ShowsChild::default(); + child.init(pd); + + child + } fn init(&self, pd: &Podcast) { self.title.set_text(pd.title()); @@ -122,13 +131,6 @@ impl ShowsChild { self.configure_banner(pd); } - pub fn new_initialized(pd: &Podcast) -> ShowsChild { - let child = ShowsChild::new(); - child.init(pd); - - child - } - fn configure_banner(&self, pd: &Podcast) { let bann = Pixbuf::new_from_resource_at_scale("/org/gnome/hammond/banner.png", 256, 256, true); diff --git a/hammond-gtk/src/widgets/episode.rs b/hammond-gtk/src/widgets/episode.rs index 11e2fbc..9a9c673 100644 --- a/hammond-gtk/src/widgets/episode.rs +++ b/hammond-gtk/src/widgets/episode.rs @@ -47,8 +47,8 @@ struct EpisodeWidget { progress_label: gtk::Label, } -impl EpisodeWidget { - fn new() -> EpisodeWidget { +impl Default for EpisodeWidget { + fn default() -> Self { let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/episode_widget.ui"); let container: gtk::Box = builder.get_object("episode_container").unwrap(); @@ -95,9 +95,11 @@ impl EpisodeWidget { progress_label, } } +} - pub fn new_initialized(episode: &mut EpisodeWidgetQuery, pd: &Podcast) -> EpisodeWidget { - let widget = EpisodeWidget::new(); +impl EpisodeWidget { + pub fn new(episode: &mut EpisodeWidgetQuery, pd: &Podcast) -> EpisodeWidget { + let widget = EpisodeWidget::default(); widget.init(episode, pd); widget } @@ -284,7 +286,7 @@ pub fn episodes_listbox(pd: &Podcast) -> Result { let list = gtk::ListBox::new(); episodes.into_iter().for_each(|mut ep| { - let widget = EpisodeWidget::new_initialized(&mut ep, pd); + let widget = EpisodeWidget::new(&mut ep, pd); list.add(&widget.container); let sep = gtk::Separator::new(gtk::Orientation::Vertical); diff --git a/hammond-gtk/src/widgets/show.rs b/hammond-gtk/src/widgets/show.rs index 308964c..c232661 100644 --- a/hammond-gtk/src/widgets/show.rs +++ b/hammond-gtk/src/widgets/show.rs @@ -28,8 +28,8 @@ pub struct ShowWidget { episodes: gtk::Frame, } -impl ShowWidget { - pub fn new() -> ShowWidget { +impl Default for ShowWidget { + fn default() -> Self { let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/show_widget.ui"); let container: gtk::Box = builder.get_object("container").unwrap(); let episodes: gtk::Frame = builder.get_object("episodes").unwrap(); @@ -54,9 +54,11 @@ impl ShowWidget { episodes, } } +} - pub fn new_initialized(shows: Rc, header: Rc
, pd: &Podcast) -> ShowWidget { - let pdw = ShowWidget::new(); +impl ShowWidget { + pub fn new(shows: Rc, header: Rc
, pd: &Podcast) -> ShowWidget { + let pdw = ShowWidget::default(); pdw.init(shows, header, pd); pdw } From 35009e257432e5788e2dbfd93cc7f7ab8091a055 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Sun, 17 Dec 2017 13:44:00 +0200 Subject: [PATCH 14/16] Added an auto-updater that runs each hour. --- hammond-gtk/src/headerbar.rs | 4 ++-- hammond-gtk/src/main.rs | 22 ++++++++++++++++++---- hammond-gtk/src/utils.rs | 12 +++--------- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/hammond-gtk/src/headerbar.rs b/hammond-gtk/src/headerbar.rs index 057957e..4eb1a6d 100644 --- a/hammond-gtk/src/headerbar.rs +++ b/hammond-gtk/src/headerbar.rs @@ -75,7 +75,7 @@ impl Header { // FIXME: There appears to be a memmory leak here. self.refresh.connect_clicked(clone!(content => move |_| { - utils::refresh_feed(content.clone(), None, None); + utils::refresh_feed(content.clone(), None); })); let switch = &self.switch; @@ -120,7 +120,7 @@ fn on_add_bttn_clicked(content: Rc, entry: >k::Entry) { if let Ok(s) = source { info!("{:?} feed added", url); // update the db - utils::refresh_feed(content, Some(vec![s]), None); + utils::refresh_feed(content, Some(vec![s])); } else { error!("Feed probably already exists."); error!("Error: {:?}", source.unwrap_err()); diff --git a/hammond-gtk/src/main.rs b/hammond-gtk/src/main.rs index dbe6c3a..9e197e1 100644 --- a/hammond-gtk/src/main.rs +++ b/hammond-gtk/src/main.rs @@ -90,11 +90,25 @@ fn build_ui(app: >k::Application) { }); app.add_action(&check); - // queue a db update 1 minute after the startup. - gtk::idle_add(clone!(ct => move || { - utils::refresh_feed(ct.clone(), None, Some(60)); + // Update on startup + gtk::timeout_add_seconds( + 30, + clone!(ct => move || { + utils::refresh_feed(ct.clone(), None); glib::Continue(false) - })); + }), + ); + + // Auto-updater, runs every hour. + // TODO: expose the interval in which it run to a user setting. + // TODO: show notifications. + gtk::timeout_add_seconds( + 3600, + clone!(ct => move || { + utils::refresh_feed(ct.clone(), None); + glib::Continue(true) + }), + ); gtk::idle_add(move || { let _ = checkup(); diff --git a/hammond-gtk/src/utils.rs b/hammond-gtk/src/utils.rs index 56cdc56..c2f484d 100644 --- a/hammond-gtk/src/utils.rs +++ b/hammond-gtk/src/utils.rs @@ -5,14 +5,13 @@ use hammond_data::feed; use hammond_data::{Podcast, Source}; use hammond_downloader::downloader; -use std::{thread, time}; +use std::thread; use std::cell::RefCell; use std::sync::mpsc::{channel, Receiver}; +use std::rc::Rc; use content::Content; -use std::rc::Rc; - type Foo = RefCell, Receiver)>>; // Create a thread local storage that will store the arguments to be transfered. @@ -22,7 +21,7 @@ thread_local!(static GLOBAL: Foo = RefCell::new(None)); /// If `source` is None, Fetches all the `Source` entries in the database and updates them. /// `delay` represents the desired time in seconds for the thread to sleep before executing. /// When It's done,it queues up a `podcast_view` refresh. -pub fn refresh_feed(content: Rc, source: Option>, delay: Option) { +pub fn refresh_feed(content: Rc, source: Option>) { // Create a async channel. let (sender, receiver) = channel(); @@ -32,11 +31,6 @@ pub fn refresh_feed(content: Rc, source: Option>, delay: Op })); thread::spawn(move || { - if let Some(s) = delay { - let t = time::Duration::from_secs(s); - thread::sleep(t); - } - let feeds = { if let Some(vec) = source { Ok(feed::fetch(vec)) From 4c8c1f0013d11022ce48c898ce7f054a777703c3 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Sun, 17 Dec 2017 13:52:00 +0200 Subject: [PATCH 15/16] Add update option to the app menu. --- hammond-gtk/src/main.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hammond-gtk/src/main.rs b/hammond-gtk/src/main.rs index 9e197e1..d565154 100644 --- a/hammond-gtk/src/main.rs +++ b/hammond-gtk/src/main.rs @@ -57,6 +57,7 @@ fn build_ui(app: >k::Application) { let menu = gio::Menu::new(); menu.append("Quit", "app.quit"); menu.append("Checkup", "app.check"); + menu.append("Update feeds", "app.update"); app.set_app_menu(&menu); // Get the main window @@ -90,6 +91,13 @@ fn build_ui(app: >k::Application) { }); app.add_action(&check); + let update = gio::SimpleAction::new("update", None); + let ct_clone = ct.clone(); + update.connect_activate(move |_, _| { + utils::refresh_feed(ct_clone.clone(), None); + }); + app.add_action(&update); + // Update on startup gtk::timeout_add_seconds( 30, From 2eb58eae0069eae74ebafeb7ebe75efa6f1e24f1 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Sun, 17 Dec 2017 13:57:08 +0200 Subject: [PATCH 16/16] Headerbar: Remove refresh button. --- hammond-gtk/resources/gtk/headerbar.ui | 21 --------------------- hammond-gtk/src/headerbar.rs | 16 ++++------------ 2 files changed, 4 insertions(+), 33 deletions(-) diff --git a/hammond-gtk/resources/gtk/headerbar.ui b/hammond-gtk/resources/gtk/headerbar.ui index aa7d08e..91bb4f0 100644 --- a/hammond-gtk/resources/gtk/headerbar.ui +++ b/hammond-gtk/resources/gtk/headerbar.ui @@ -190,27 +190,6 @@ - - - True - True - True - center - True - True - - - True - False - view-refresh-symbolic - - - - - end - 1 - - True diff --git a/hammond-gtk/src/headerbar.rs b/hammond-gtk/src/headerbar.rs index 4eb1a6d..9d62773 100644 --- a/hammond-gtk/src/headerbar.rs +++ b/hammond-gtk/src/headerbar.rs @@ -12,7 +12,6 @@ use content::Content; #[derive(Debug)] pub struct Header { pub container: gtk::HeaderBar, - refresh: gtk::Button, add_toggle: gtk::MenuButton, switch: gtk::StackSwitcher, back_button: gtk::Button, @@ -24,7 +23,6 @@ impl Default for Header { let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/headerbar.ui"); let header: gtk::HeaderBar = builder.get_object("headerbar").unwrap(); - let refresh: gtk::Button = builder.get_object("ref_button").unwrap(); let add_toggle: gtk::MenuButton = builder.get_object("add_toggle_button").unwrap(); let switch: gtk::StackSwitcher = builder.get_object("switch").unwrap(); let back_button: gtk::Button = builder.get_object("back_button").unwrap(); @@ -35,7 +33,6 @@ impl Default for Header { Header { container: header, - refresh, add_toggle, switch, back_button, @@ -73,11 +70,6 @@ impl Header { })); self.add_toggle.set_popover(&add_popover); - // FIXME: There appears to be a memmory leak here. - self.refresh.connect_clicked(clone!(content => move |_| { - utils::refresh_feed(content.clone(), None); - })); - let switch = &self.switch; let add_toggle = &self.add_toggle; let show_title = &self.show_title; @@ -96,7 +88,7 @@ impl Header { self.switch.hide(); self.add_toggle.hide(); self.back_button.show(); - self.show_title.set_text(title); + self.set_show_title(title); self.show_title.show(); } @@ -107,9 +99,9 @@ impl Header { self.show_title.hide(); } - // pub fn set_show_title(&self, title: &str) { - // self.show_title.set_text(title) - // } + pub fn set_show_title(&self, title: &str) { + self.show_title.set_text(title) + } } fn on_add_bttn_clicked(content: Rc, entry: >k::Entry) {