From ad7f5013f3459b81da88e40d104c5ce8ece26919 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Mon, 11 Dec 2017 11:15:54 +0200 Subject: [PATCH 01/12] Extend ShowsMachine functionality. --- hammond-data/src/parser.rs | 1 - hammond-gtk/src/content.rs | 114 ++++++++++++++++--------------------- 2 files changed, 49 insertions(+), 66 deletions(-) diff --git a/hammond-data/src/parser.rs b/hammond-data/src/parser.rs index 1be8064..393ac54 100644 --- a/hammond-data/src/parser.rs +++ b/hammond-data/src/parser.rs @@ -81,7 +81,6 @@ pub(crate) fn new_episode(item: &Item, parent_id: i32) -> Result { .unwrap()) } - #[cfg(test)] mod tests { use std::fs::File; diff --git a/hammond-gtk/src/content.rs b/hammond-gtk/src/content.rs index be7a491..64063cc 100644 --- a/hammond-gtk/src/content.rs +++ b/hammond-gtk/src/content.rs @@ -97,69 +97,6 @@ pub struct PodcastsView {} #[derive(Debug)] pub struct WidgetsView {} -impl Into> for ContentState { - fn into(self) -> ContentState { - self.content.stack.set_visible_child_name("podcasts"); - - ContentState { - content: self.content, - state: PodcastsView {}, - } - } -} - -impl UpdateView for ContentState { - fn update(&mut self) {} -} - -impl Into> for ContentState { - fn into(self) -> ContentState { - self.content.stack.set_visible_child_name("empty"); - ContentState { - content: self.content, - state: Empty {}, - } - } -} - -impl Into> for ContentState { - fn into(self) -> ContentState { - self.content.stack.set_visible_child_name("widget"); - - ContentState { - content: self.content, - state: WidgetsView {}, - } - } -} - -impl UpdateView for ContentState { - fn update(&mut self) { - let pop = PopulatedView::new_initialized(&self.content.stack); - self.content.replace_podcasts(pop) - } -} - -impl Into> for ContentState { - fn into(self) -> ContentState { - self.content.stack.set_visible_child_name("podcasts"); - ContentState { - content: self.content, - state: PodcastsView {}, - } - } -} - -impl Into> for ContentState { - fn into(self) -> ContentState { - self.content.stack.set_visible_child_name("empty"); - ContentState { - content: self.content, - state: Empty {}, - } - } -} - impl UpdateView for ContentState { fn update(&mut self) { let old = self.content.stack.get_child_by_name("widget").unwrap(); @@ -286,6 +223,20 @@ struct ShowsMachine { state: S, } +impl ShowsMachine { + fn update(&mut self) { + let vis = self.stack.get_visible_child_name().unwrap(); + let old = self.stack.get_child_by_name("shows").unwrap(); + self.stack.remove(&old); + + let pop = ShowsPopulated::new_initialized(&self.stack); + self.populated = pop; + self.stack + .add_titled(&self.populated.container, "shows", "Shows"); + self.stack.set_visible_child_name(&vis); + } +} + #[derive(Debug)] struct EpisodesMachine { populated: EpisodesPopulated, @@ -320,6 +271,7 @@ struct EpisodesMachine { // } // } +// TODO: Impl instead of impl Into> for ShowsMachine { fn into(self) -> ShowsMachine { self.stack.set_visible_child_name("populated"); @@ -378,8 +330,8 @@ impl Into> for EpisodesMachine { // } enum ShowStateWrapper { - Populated(EpisodesMachine), - Empty(EpisodesMachine), + Populated(ShowsMachine), + Empty(ShowsMachine), } enum EpisodeStateWrapper { @@ -397,12 +349,44 @@ enum EpisodeStateWrapper { // } impl ShowStateWrapper { + fn new() -> Self { + let stack = gtk::Stack::new(); + let pop = ShowsPopulated::new_initialized(&stack); + let empty = EmptyView::new(); + + if pop.flowbox.get_children().is_empty() { + stack.set_visible_child_name("empty"); + ShowStateWrapper::Empty(ShowsMachine { + empty, + populated: pop, + stack, + state: Empty {}, + }) + } else { + stack.set_visible_child_name("shows"); + + ShowStateWrapper::Populated(ShowsMachine { + empty, + populated: pop, + stack, + state: Populated {}, + }) + } + } + fn switch(self) -> Self { match self { ShowStateWrapper::Populated(val) => ShowStateWrapper::Empty(val.into()), ShowStateWrapper::Empty(val) => ShowStateWrapper::Populated(val.into()), } } + + fn update(&mut self) { + match *self { + ShowStateWrapper::Populated(ref mut val) => val.update(), + ShowStateWrapper::Empty(ref mut val) => val.update(), + } + } } impl EpisodeStateWrapper { From fa33138d66d81a1028b3f6ab7f137d24410baa5f Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Mon, 11 Dec 2017 11:53:29 +0200 Subject: [PATCH 02/12] Start switching to the new stack architecture. --- hammond-gtk/src/content.rs | 184 ++++++++++++----------------- hammond-gtk/src/main.rs | 3 +- hammond-gtk/src/views/podcasts.rs | 35 +++--- hammond-gtk/src/widgets/podcast.rs | 1 - 4 files changed, 97 insertions(+), 126 deletions(-) diff --git a/hammond-gtk/src/content.rs b/hammond-gtk/src/content.rs index 64063cc..c75d4a1 100644 --- a/hammond-gtk/src/content.rs +++ b/hammond-gtk/src/content.rs @@ -8,78 +8,60 @@ use widgets::podcast::PodcastWidget; use views::podcasts::PopulatedView; use views::empty::EmptyView; -#[derive(Debug)] pub struct Content { pub stack: gtk::Stack, - pub widget: PodcastWidget, - pub podcasts: PopulatedView, - pub empty: EmptyView, + shows: ShowStateWrapper, + episodes: EpisodeStateWrapper, } impl Content { pub fn new() -> Content { let stack = gtk::Stack::new(); + let shows = ShowStateWrapper::new(); + let episodes = EpisodeStateWrapper::new(); - let widget = PodcastWidget::new(); - let podcasts = PopulatedView::new(); - let empty = EmptyView::new(); + let shows_stack = shows.get_stack(); + let ep_stack = episodes.get_stack(); - stack.add_titled(&widget.container, "widget", "Episodes"); - stack.add_titled(&podcasts.container, "podcasts", "Shows"); - stack.add_named(&empty.container, "empty"); + stack.add_titled(&ep_stack, "episodes", "Episodes"); + stack.add_titled(&shows_stack, "shows", "Shows"); Content { stack, - widget, - empty, - podcasts, + shows, + episodes, } } - pub fn new_initialized() -> Content { - let ct = Content::new(); - ct.init(); - ct - } + // pub fn new_initialized() -> Content { + // let ct = Content::new(); + // ct.init(); + // ct + // } - pub fn init(&self) { - self.podcasts.init(&self.stack); - if self.podcasts.flowbox.get_children().is_empty() { - self.stack.set_visible_child_name("empty"); - return; - } + // pub fn init(&self) { + // self.podcasts.init(); + // if self.podcasts.flowbox.get_children().is_empty() { + // self.stack.set_visible_child_name("empty"); + // return; + // } - self.stack.set_visible_child_name("podcasts"); - } + // self.stack.set_visible_child_name("podcasts"); + // } - fn replace_widget(&mut self, pdw: PodcastWidget) { - let vis = self.stack.get_visible_child_name().unwrap(); - let old = self.stack.get_child_by_name("widget").unwrap(); - self.stack.remove(&old); + // fn replace_widget(&mut self, pdw: PodcastWidget) { + // let vis = self.stack.get_visible_child_name().unwrap(); + // let old = self.stack.get_child_by_name("widget").unwrap(); + // self.stack.remove(&old); - self.widget = pdw; - self.stack - .add_titled(&self.widget.container, "widget", "Episodes"); - self.stack.set_visible_child_name(&vis); - old.destroy(); - } - - fn replace_podcasts(&mut self, pop: PopulatedView) { - let vis = self.stack.get_visible_child_name().unwrap(); - let old = self.stack.get_child_by_name("podcasts").unwrap(); - self.stack.remove(&old); - - self.podcasts = pop; - self.stack - .add_titled(&self.podcasts.container, "podcasts", "Shows"); - self.stack.set_visible_child_name(&vis); - old.destroy(); - } + // self.widget = pdw; + // self.stack + // .add_titled(&self.widget.container, "widget", "Episodes"); + // self.stack.set_visible_child_name(&vis); + // old.destroy(); + // } } -#[derive(Debug)] -// Experiementing with Wrapping gtk::Stack into a State machine. -// Gonna revist it when TryInto trais is stabilized. pub struct ContentState { content: Content, state: S, @@ -89,8 +71,6 @@ pub trait UpdateView { fn update(&mut self); } -pub struct Empty; - #[derive(Debug)] pub struct PodcastsView {} @@ -104,34 +84,7 @@ impl UpdateView for ContentState { let pd = dbqueries::get_podcast_from_id(id.parse::().unwrap()).unwrap(); let pdw = PodcastWidget::new_initialized(&self.content.stack, &pd); - self.content.replace_widget(pdw); - } -} - -impl ContentState { - #[allow(dead_code)] - pub fn new() -> Result, ContentState> { - let content = Content::new(); - - content.podcasts.init(&content.stack); - if content.podcasts.flowbox.get_children().is_empty() { - content.stack.set_visible_child_name("empty"); - return Err(ContentState { - content, - state: Empty {}, - }); - } - - content.stack.set_visible_child_name("podcasts"); - Ok(ContentState { - content, - state: PodcastsView {}, - }) - } - - #[allow(dead_code)] - pub fn get_stack(&self) -> gtk::Stack { - self.content.stack.clone() + // self.content.replace_widget(pdw); } } @@ -149,25 +102,8 @@ fn replace_podcasts(stack: >k::Stack, pop: &PopulatedView) { old.destroy(); } -#[allow(dead_code)] -pub fn show_widget(stack: >k::Stack) { - stack.set_visible_child_name("widget") -} - -pub fn show_podcasts(stack: >k::Stack) { - stack.set_visible_child_name("podcasts") -} - -pub fn show_empty(stack: >k::Stack) { - stack.set_visible_child_name("empty") -} - pub fn update_podcasts(stack: >k::Stack) { - let pods = PopulatedView::new_initialized(stack); - - if pods.flowbox.get_children().is_empty() { - show_empty(stack) - } + let pods = PopulatedView::new_initialized(); replace_podcasts(stack, &pods); } @@ -191,10 +127,10 @@ pub fn update_widget_preserve_vis(stack: >k::Stack, pd: &Podcast) { stack.set_visible_child_name(&vis) } -pub fn on_podcasts_child_activate(stack: >k::Stack, pd: &Podcast) { - update_widget(stack, pd); - stack.set_visible_child_full("widget", gtk::StackTransitionType::SlideLeft); -} +// pub fn on_podcasts_child_activate(stack: >k::Stack, pd: &Podcast) { +// update_widget(stack, pd); +// stack.set_visible_child_full("widget", gtk::StackTransitionType::SlideLeft); +// } // FIXME: Rename and remove aliases type ShowsPopulated = PopulatedView; @@ -203,7 +139,7 @@ type EpisodesPopulated = PodcastWidget; type EpisodesEmpty = EmptyView; struct Populated; -// struct Empty; +struct Empty; // struct Shows; // struct Episodes; @@ -229,7 +165,7 @@ impl ShowsMachine { let old = self.stack.get_child_by_name("shows").unwrap(); self.stack.remove(&old); - let pop = ShowsPopulated::new_initialized(&self.stack); + let pop = ShowsPopulated::new_initialized(); self.populated = pop; self.stack .add_titled(&self.populated.container, "shows", "Shows"); @@ -351,8 +287,10 @@ enum EpisodeStateWrapper { impl ShowStateWrapper { fn new() -> Self { let stack = gtk::Stack::new(); - let pop = ShowsPopulated::new_initialized(&stack); + let pop = ShowsPopulated::new_initialized(); let empty = EmptyView::new(); + stack.add_named(&pop.container, "populated"); + stack.add_named(&empty.container, "empty"); if pop.flowbox.get_children().is_empty() { stack.set_visible_child_name("empty"); @@ -363,7 +301,7 @@ impl ShowStateWrapper { state: Empty {}, }) } else { - stack.set_visible_child_name("shows"); + stack.set_visible_child_name("populated"); ShowStateWrapper::Populated(ShowsMachine { empty, @@ -387,13 +325,45 @@ impl ShowStateWrapper { ShowStateWrapper::Empty(ref mut val) => val.update(), } } + + fn get_stack(&self) -> gtk::Stack { + match *self { + ShowStateWrapper::Populated(ref val) => val.stack.clone(), + ShowStateWrapper::Empty(ref val) => val.stack.clone(), + } + } } impl EpisodeStateWrapper { + // FIXME: + fn new() -> Self { + let pop = PodcastWidget::new(); + let empty = EmptyView::new(); + let stack = gtk::Stack::new(); + + stack.add_named(&pop.container, "populated"); + stack.add_named(&empty.container, "empty"); + stack.set_visible_child_name("empty"); + + EpisodeStateWrapper::Empty(EpisodesMachine { + empty, + populated: pop, + stack, + state: Empty {}, + }) + } + fn switch(self) -> Self { match self { EpisodeStateWrapper::Populated(val) => EpisodeStateWrapper::Empty(val.into()), EpisodeStateWrapper::Empty(val) => EpisodeStateWrapper::Populated(val.into()), } } + + fn get_stack(&self) -> gtk::Stack { + match *self { + EpisodeStateWrapper::Populated(ref val) => val.stack.clone(), + EpisodeStateWrapper::Empty(ref val) => val.stack.clone(), + } + } } diff --git a/hammond-gtk/src/main.rs b/hammond-gtk/src/main.rs index f4fd89b..0cf43dd 100644 --- a/hammond-gtk/src/main.rs +++ b/hammond-gtk/src/main.rs @@ -67,7 +67,8 @@ fn build_ui(app: >k::Application) { // let ct = content::ContentState::new().unwrap(); // let stack = ct.get_stack(); - let ct = content::Content::new_initialized(); + // let ct = content::Content::new_initialized(); + let ct = content::Content::new(); let stack = ct.stack; window.add(&stack); diff --git a/hammond-gtk/src/views/podcasts.rs b/hammond-gtk/src/views/podcasts.rs index 711be87..0767d72 100644 --- a/hammond-gtk/src/views/podcasts.rs +++ b/hammond-gtk/src/views/podcasts.rs @@ -8,7 +8,7 @@ use hammond_data::Podcast; use utils::get_pixbuf_from_path; -use content; +// use content; #[derive(Debug, Clone)] pub struct PopulatedView { @@ -42,24 +42,25 @@ impl PopulatedView { } #[allow(dead_code)] - pub fn new_initialized(stack: >k::Stack) -> PopulatedView { + pub fn new_initialized() -> PopulatedView { let pop = PopulatedView::new(); - pop.init(stack); + pop.init(); pop } - pub fn init(&self, stack: >k::Stack) { - use gtk::WidgetExt; + pub fn init(&self) { + // pub fn init(&self, stack: >k::Stack) { + // use gtk::WidgetExt; - // TODO: handle unwraps. - self.flowbox - .connect_child_activated(clone!(stack => move |_, child| { - // This is such an ugly hack... - // let id = child.get_name().unwrap().parse::().unwrap(); - let id = WidgetExt::get_name(child).unwrap().parse::().unwrap(); - let parent = dbqueries::get_podcast_from_id(id).unwrap(); - on_flowbox_child_activate(&stack, &parent); - })); + // // TODO: handle unwraps. + // self.flowbox + // .connect_child_activated(clone!(stack => move |_, child| { + // // This is such an ugly hack... + // // let id = child.get_name().unwrap().parse::().unwrap(); + // let id = WidgetExt::get_name(child).unwrap().parse::().unwrap(); + // let parent = dbqueries::get_podcast_from_id(id).unwrap(); + // on_flowbox_child_activate(&stack, &parent); + // })); // Populate the flowbox with the Podcasts. self.populate_flowbox(); } @@ -139,6 +140,6 @@ impl PodcastChild { } } -fn on_flowbox_child_activate(stack: >k::Stack, parent: &Podcast) { - content::on_podcasts_child_activate(stack, parent) -} +// fn on_flowbox_child_activate(stack: >k::Stack, parent: &Podcast) { +// content::on_podcasts_child_activate(stack, parent) +// } diff --git a/hammond-gtk/src/widgets/podcast.rs b/hammond-gtk/src/widgets/podcast.rs index 206ffd9..b447384 100644 --- a/hammond-gtk/src/widgets/podcast.rs +++ b/hammond-gtk/src/widgets/podcast.rs @@ -112,7 +112,6 @@ fn on_unsub_button_clicked(stack: >k::Stack, pd: &Podcast, unsub_button: >k: }; } content::update_podcasts(stack); - content::show_podcasts(stack); } fn on_played_button_clicked(stack: >k::Stack, pd: &Podcast) { From ddb195db3c816d9b77a0382126fcc8f80f0ba3e5 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Mon, 11 Dec 2017 13:51:16 +0200 Subject: [PATCH 03/12] Wired up refresh button. --- hammond-gtk/src/content.rs | 87 +++++++++++++----------------------- hammond-gtk/src/headerbar.rs | 30 ++++++++----- hammond-gtk/src/main.rs | 11 +++-- hammond-gtk/src/utils.rs | 17 ++++--- 4 files changed, 68 insertions(+), 77 deletions(-) diff --git a/hammond-gtk/src/content.rs b/hammond-gtk/src/content.rs index c75d4a1..1001dce 100644 --- a/hammond-gtk/src/content.rs +++ b/hammond-gtk/src/content.rs @@ -33,58 +33,9 @@ impl Content { } } - // pub fn new_initialized() -> Content { - // let ct = Content::new(); - // ct.init(); - // ct - // } - - // pub fn init(&self) { - // self.podcasts.init(); - // if self.podcasts.flowbox.get_children().is_empty() { - // self.stack.set_visible_child_name("empty"); - // return; - // } - - // self.stack.set_visible_child_name("podcasts"); - // } - - // fn replace_widget(&mut self, pdw: PodcastWidget) { - // let vis = self.stack.get_visible_child_name().unwrap(); - // let old = self.stack.get_child_by_name("widget").unwrap(); - // self.stack.remove(&old); - - // self.widget = pdw; - // self.stack - // .add_titled(&self.widget.container, "widget", "Episodes"); - // self.stack.set_visible_child_name(&vis); - // old.destroy(); - // } -} - -pub struct ContentState { - content: Content, - state: S, -} - -pub trait UpdateView { - fn update(&mut self); -} - -#[derive(Debug)] -pub struct PodcastsView {} - -#[derive(Debug)] -pub struct WidgetsView {} - -impl UpdateView for ContentState { - fn update(&mut self) { - let old = self.content.stack.get_child_by_name("widget").unwrap(); - let id = WidgetExt::get_name(&old).unwrap(); - let pd = dbqueries::get_podcast_from_id(id.parse::().unwrap()).unwrap(); - - let pdw = PodcastWidget::new_initialized(&self.content.stack, &pd); - // self.content.replace_widget(pdw); + pub fn update(&mut self) { + self.shows.update(); + self.episodes.update(); } } @@ -162,13 +113,12 @@ struct ShowsMachine { impl ShowsMachine { fn update(&mut self) { let vis = self.stack.get_visible_child_name().unwrap(); - let old = self.stack.get_child_by_name("shows").unwrap(); + let old = self.stack.get_child_by_name("populated").unwrap(); self.stack.remove(&old); let pop = ShowsPopulated::new_initialized(); self.populated = pop; - self.stack - .add_titled(&self.populated.container, "shows", "Shows"); + self.stack.add_named(&self.populated.container, "populated"); self.stack.set_visible_child_name(&vis); } } @@ -181,6 +131,26 @@ struct EpisodesMachine { state: S, } +impl EpisodesMachine { + // FIXME: + fn update(&mut self) { + let vis = self.stack.get_visible_child_name().unwrap(); + let old = self.stack.get_child_by_name("populated").unwrap(); + + let id = WidgetExt::get_name(&old).unwrap(); + if id == "GtkBox" { + return; + } + let pd = dbqueries::get_podcast_from_id(id.parse::().unwrap()).unwrap(); + let pdw = EpisodesPopulated::new_initialized(&self.stack, &pd); + + self.populated = pdw; + self.stack.remove(&old); + self.stack.add_named(&self.populated.container, "populated"); + self.stack.set_visible_child_name(&vis); + } +} + // impl Into> for StackStateMachine { // fn into(self) -> StackStateMachine { // self.stack.set_visible_child_name("shows"); @@ -353,6 +323,13 @@ impl EpisodeStateWrapper { }) } + fn update(&mut self) { + match *self { + EpisodeStateWrapper::Populated(ref mut val) => val.update(), + EpisodeStateWrapper::Empty(ref mut val) => val.update(), + } + } + fn switch(self) -> Self { match self { EpisodeStateWrapper::Populated(val) => EpisodeStateWrapper::Empty(val.into()), diff --git a/hammond-gtk/src/headerbar.rs b/hammond-gtk/src/headerbar.rs index 7bcd41e..34c8087 100644 --- a/hammond-gtk/src/headerbar.rs +++ b/hammond-gtk/src/headerbar.rs @@ -4,8 +4,10 @@ use gtk::prelude::*; use hammond_data::Source; use hammond_data::utils::url_cleaner; +use std::sync::{Arc, Mutex}; + use utils; -// use content; +use content::Content; #[derive(Debug)] pub struct Header { @@ -34,26 +36,31 @@ impl Header { } } - pub fn new_initialized(stack: >k::Stack) -> Header { + pub fn new_initialized(content: Arc>) -> Header { let header = Header::new(); - header.init(stack); + header.init(content); header } - fn init(&self, stack: >k::Stack) { + fn init(&self, content: Arc>) { let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/headerbar.ui"); let add_popover: gtk::Popover = builder.get_object("add-popover").unwrap(); let new_url: gtk::Entry = builder.get_object("new-url").unwrap(); let add_button: gtk::Button = builder.get_object("add-button").unwrap(); - self.switch.set_stack(stack); + + { + let cont = content.lock().unwrap(); + self.switch.set_stack(&cont.stack); + } new_url.connect_changed(move |url| { println!("{:?}", url.get_text()); }); - add_button.connect_clicked(clone!(stack, add_popover, new_url => move |_| { - on_add_bttn_clicked(&stack, &new_url); + let cont = content.clone(); + add_button.connect_clicked(clone!(cont, add_popover, new_url => move |_| { + on_add_bttn_clicked(cont.clone(), &new_url); // TODO: lock the button instead of hiding and add notification of feed added. // TODO: map the spinner @@ -62,13 +69,14 @@ impl Header { self.add_toggle.set_popover(&add_popover); // FIXME: There appears to be a memmory leak here. - self.refresh.connect_clicked(clone!(stack => move |_| { - utils::refresh_feed(&stack, None, None); + let cont = content.clone(); + self.refresh.connect_clicked(clone!(cont => move |_| { + utils::refresh_feed(cont.clone(), None, None); })); } } -fn on_add_bttn_clicked(stack: >k::Stack, entry: >k::Entry) { +fn on_add_bttn_clicked(content: Arc>, entry: >k::Entry) { let url = entry.get_text().unwrap_or_default(); let url = url_cleaner(&url); let source = Source::from_url(&url); @@ -76,7 +84,7 @@ fn on_add_bttn_clicked(stack: >k::Stack, entry: >k::Entry) { if let Ok(s) = source { info!("{:?} feed added", url); // update the db - utils::refresh_feed(stack, Some(vec![s]), None); + utils::refresh_feed(content, Some(vec![s]), None); } 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 0cf43dd..9f4a4b4 100644 --- a/hammond-gtk/src/main.rs +++ b/hammond-gtk/src/main.rs @@ -22,6 +22,8 @@ use hammond_data::utils::checkup; use gtk::prelude::*; use gio::{ActionMapExt, ApplicationExt, MenuExt, SimpleActionExt}; +use std::sync::{Arc, Mutex}; + // http://gtk-rs.org/tuto/closures #[macro_export] macro_rules! clone { @@ -69,7 +71,8 @@ fn build_ui(app: >k::Application) { // let ct = content::Content::new_initialized(); let ct = content::Content::new(); - let stack = ct.stack; + let stack = ct.stack.clone(); + let ct = Arc::new(Mutex::new(ct)); window.add(&stack); window.connect_delete_event(|w, _| { @@ -93,8 +96,8 @@ fn build_ui(app: >k::Application) { app.add_action(&check); // queue a db update 1 minute after the startup. - gtk::idle_add(clone!(stack => move || { - utils::refresh_feed(&stack, None, Some(60)); + gtk::idle_add(clone!(ct => move || { + utils::refresh_feed(ct.clone(), None, Some(60)); glib::Continue(false) })); @@ -104,7 +107,7 @@ fn build_ui(app: >k::Application) { }); // Get the headerbar - let header = headerbar::Header::new_initialized(&stack); + let header = headerbar::Header::new_initialized(ct.clone()); window.set_titlebar(&header.container); window.show_all(); diff --git a/hammond-gtk/src/utils.rs b/hammond-gtk/src/utils.rs index 5402b90..0a6a5c2 100644 --- a/hammond-gtk/src/utils.rs +++ b/hammond-gtk/src/utils.rs @@ -11,10 +11,12 @@ use std::cell::RefCell; use std::sync::mpsc::{channel, Receiver}; use std::borrow::Cow; -use content; +use content::Content; use regex::Regex; -type Foo = RefCell)>>; +use std::sync::{Arc, Mutex}; + +type Foo = RefCell>, Receiver)>>; // Create a thread local storage that will store the arguments to be transfered. thread_local!(static GLOBAL: Foo = RefCell::new(None)); @@ -23,13 +25,13 @@ 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(stack: >k::Stack, source: Option>, delay: Option) { +pub fn refresh_feed(content: Arc>, source: Option>, delay: Option) { // Create a async channel. let (sender, receiver) = channel(); // Pass the desired arguments into the Local Thread Storage. - GLOBAL.with(clone!(stack => move |global| { - *global.borrow_mut() = Some((stack, receiver)); + GLOBAL.with(clone!(content => move |global| { + *global.borrow_mut() = Some((content, receiver)); })); thread::spawn(move || { @@ -57,9 +59,10 @@ pub fn refresh_feed(stack: >k::Stack, source: Option>, delay: Opti fn refresh_podcasts_view() -> glib::Continue { GLOBAL.with(|global| { - if let Some((ref stack, ref reciever)) = *global.borrow() { + if let Some((ref content, ref reciever)) = *global.borrow() { if reciever.try_recv().is_ok() { - content::update_podcasts_preserve_vis(stack); + let mut content = content.lock().unwrap(); + content.update(); } } }); From 211b36dfa37a0cec8c5ef4172da32f479438de98 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Mon, 11 Dec 2017 16:14:43 +0200 Subject: [PATCH 04/12] Fix showmachine updating. --- hammond-gtk/src/content.rs | 128 +++++++++++------------------ hammond-gtk/src/headerbar.rs | 9 +- hammond-gtk/src/widgets/podcast.rs | 8 +- 3 files changed, 58 insertions(+), 87 deletions(-) diff --git a/hammond-gtk/src/content.rs b/hammond-gtk/src/content.rs index 1001dce..4b7d32a 100644 --- a/hammond-gtk/src/content.rs +++ b/hammond-gtk/src/content.rs @@ -1,13 +1,14 @@ use gtk; use gtk::prelude::*; -use hammond_data::Podcast; +// use hammond_data::Podcast; use hammond_data::dbqueries; use widgets::podcast::PodcastWidget; use views::podcasts::PopulatedView; use views::empty::EmptyView; +#[derive(Debug, Clone)] pub struct Content { pub stack: gtk::Stack, shows: ShowStateWrapper, @@ -34,50 +35,12 @@ impl Content { } pub fn update(&mut self) { - self.shows.update(); + self.shows = self.shows.clone().update(); + // FIXME: like above self.episodes.update(); } } -fn replace_widget(stack: >k::Stack, pdw: &PodcastWidget) { - let old = stack.get_child_by_name("widget").unwrap(); - stack.remove(&old); - stack.add_titled(&pdw.container, "widget", "Episode"); - old.destroy(); -} - -fn replace_podcasts(stack: >k::Stack, pop: &PopulatedView) { - let old = stack.get_child_by_name("podcasts").unwrap(); - stack.remove(&old); - stack.add_titled(&pop.container, "podcasts", "Shows"); - old.destroy(); -} - -pub fn update_podcasts(stack: >k::Stack) { - let pods = PopulatedView::new_initialized(); - - replace_podcasts(stack, &pods); -} - -pub fn update_widget(stack: >k::Stack, pd: &Podcast) { - let pdw = PodcastWidget::new_initialized(stack, pd); - replace_widget(stack, &pdw); -} - -pub fn update_podcasts_preserve_vis(stack: >k::Stack) { - let vis = stack.get_visible_child_name().unwrap(); - update_podcasts(stack); - if vis != "empty" { - stack.set_visible_child_name(&vis) - } -} - -pub fn update_widget_preserve_vis(stack: >k::Stack, pd: &Podcast) { - let vis = stack.get_visible_child_name().unwrap(); - update_widget(stack, pd); - stack.set_visible_child_name(&vis) -} - // pub fn on_podcasts_child_activate(stack: >k::Stack, pd: &Podcast) { // update_widget(stack, pd); // stack.set_visible_child_full("widget", gtk::StackTransitionType::SlideLeft); @@ -89,7 +52,9 @@ type ShowsEmpty = EmptyView; type EpisodesPopulated = PodcastWidget; type EpisodesEmpty = EmptyView; +#[derive(Debug, Clone)] struct Populated; +#[derive(Debug, Clone)] struct Empty; // struct Shows; // struct Episodes; @@ -111,6 +76,21 @@ struct ShowsMachine { } impl ShowsMachine { + fn new(state: S) -> ShowsMachine { + let stack = gtk::Stack::new(); + let pop = ShowsPopulated::new_initialized(); + let empty = EmptyView::new(); + stack.add_named(&pop.container, "populated"); + stack.add_named(&empty.container, "empty"); + + ShowsMachine { + empty, + populated: pop, + stack, + state, + } + } + fn update(&mut self) { let vis = self.stack.get_visible_child_name().unwrap(); let old = self.stack.get_child_by_name("populated").unwrap(); @@ -123,7 +103,7 @@ impl ShowsMachine { } } -#[derive(Debug)] +#[derive(Debug, Clone)] struct EpisodesMachine { populated: EpisodesPopulated, empty: EpisodesEmpty, @@ -235,11 +215,13 @@ impl Into> for EpisodesMachine { // Episodes(StackStateMachine), // } +#[derive(Debug, Clone)] enum ShowStateWrapper { Populated(ShowsMachine), Empty(ShowsMachine), } +#[derive(Debug, Clone)] enum EpisodeStateWrapper { Populated(EpisodesMachine), Empty(EpisodesMachine), @@ -256,44 +238,34 @@ enum EpisodeStateWrapper { impl ShowStateWrapper { fn new() -> Self { - let stack = gtk::Stack::new(); - let pop = ShowsPopulated::new_initialized(); - let empty = EmptyView::new(); - stack.add_named(&pop.container, "populated"); - stack.add_named(&empty.container, "empty"); + let machine = ShowsMachine::new(Populated {}); - if pop.flowbox.get_children().is_empty() { - stack.set_visible_child_name("empty"); - ShowStateWrapper::Empty(ShowsMachine { - empty, - populated: pop, - stack, - state: Empty {}, - }) + if machine.populated.flowbox.get_children().is_empty() { + machine.stack.set_visible_child_name("empty"); + ShowStateWrapper::Empty(machine.into()) } else { - stack.set_visible_child_name("populated"); - - ShowStateWrapper::Populated(ShowsMachine { - empty, - populated: pop, - stack, - state: Populated {}, - }) + machine.stack.set_visible_child_name("populated"); + ShowStateWrapper::Populated(machine) } } - fn switch(self) -> Self { + fn update(mut self) -> Self { match self { - ShowStateWrapper::Populated(val) => ShowStateWrapper::Empty(val.into()), - ShowStateWrapper::Empty(val) => ShowStateWrapper::Populated(val.into()), - } - } - - fn update(&mut self) { - match *self { ShowStateWrapper::Populated(ref mut val) => val.update(), ShowStateWrapper::Empty(ref mut val) => val.update(), } + + if self.is_empty() { + match self { + ShowStateWrapper::Populated(val) => ShowStateWrapper::Empty(val.into()), + _ => self, + } + } else { + match self { + ShowStateWrapper::Empty(val) => ShowStateWrapper::Populated(val.into()), + _ => self, + } + } } fn get_stack(&self) -> gtk::Stack { @@ -302,6 +274,13 @@ impl ShowStateWrapper { ShowStateWrapper::Empty(ref val) => val.stack.clone(), } } + + fn is_empty(&self) -> bool { + match *self { + ShowStateWrapper::Populated(ref val) => val.populated.flowbox.get_children().is_empty(), + ShowStateWrapper::Empty(ref val) => val.populated.flowbox.get_children().is_empty(), + } + } } impl EpisodeStateWrapper { @@ -330,13 +309,6 @@ impl EpisodeStateWrapper { } } - fn switch(self) -> Self { - match self { - EpisodeStateWrapper::Populated(val) => EpisodeStateWrapper::Empty(val.into()), - EpisodeStateWrapper::Empty(val) => EpisodeStateWrapper::Populated(val.into()), - } - } - fn get_stack(&self) -> gtk::Stack { match *self { EpisodeStateWrapper::Populated(ref val) => val.stack.clone(), diff --git a/hammond-gtk/src/headerbar.rs b/hammond-gtk/src/headerbar.rs index 34c8087..956e040 100644 --- a/hammond-gtk/src/headerbar.rs +++ b/hammond-gtk/src/headerbar.rs @@ -58,9 +58,8 @@ impl Header { println!("{:?}", url.get_text()); }); - let cont = content.clone(); - add_button.connect_clicked(clone!(cont, add_popover, new_url => move |_| { - on_add_bttn_clicked(cont.clone(), &new_url); + add_button.connect_clicked(clone!(content, add_popover, new_url => move |_| { + on_add_bttn_clicked(content.clone(), &new_url); // TODO: lock the button instead of hiding and add notification of feed added. // TODO: map the spinner @@ -70,9 +69,9 @@ impl Header { // FIXME: There appears to be a memmory leak here. let cont = content.clone(); - self.refresh.connect_clicked(clone!(cont => move |_| { + self.refresh.connect_clicked(move |_| { utils::refresh_feed(cont.clone(), None, None); - })); + }); } } diff --git a/hammond-gtk/src/widgets/podcast.rs b/hammond-gtk/src/widgets/podcast.rs index b447384..c0d4c34 100644 --- a/hammond-gtk/src/widgets/podcast.rs +++ b/hammond-gtk/src/widgets/podcast.rs @@ -10,9 +10,9 @@ use hammond_downloader::downloader; use widgets::episode::episodes_listbox; use utils::get_pixbuf_from_path; -use content; +// use content; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct PodcastWidget { pub container: gtk::Box, cover: gtk::Image, @@ -111,11 +111,11 @@ fn on_unsub_button_clicked(stack: >k::Stack, pd: &Podcast, unsub_button: >k: } }; } - content::update_podcasts(stack); + // content::update_podcasts(stack); } fn on_played_button_clicked(stack: >k::Stack, pd: &Podcast) { let _ = dbqueries::update_none_to_played_now(pd); - content::update_widget_preserve_vis(stack, pd); + // content::update_widget_preserve_vis(stack, pd); } From 01310ee7fa0abec74706748ca1d8bbd1a2458fbb Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Tue, 12 Dec 2017 16:01:19 +0200 Subject: [PATCH 05/12] Working non-state machine stack implementation. Removed the stack state-machines. It was confusing trying to both implement statemachines and re-design the stack architecture at the same time. --- hammond-gtk/src/content.rs | 343 ++++++++--------------------- hammond-gtk/src/headerbar.rs | 17 +- hammond-gtk/src/main.rs | 5 +- hammond-gtk/src/utils.rs | 24 +- hammond-gtk/src/views/podcasts.rs | 43 ++-- hammond-gtk/src/widgets/podcast.rs | 26 ++- 6 files changed, 146 insertions(+), 312 deletions(-) diff --git a/hammond-gtk/src/content.rs b/hammond-gtk/src/content.rs index 4b7d32a..8214ab9 100644 --- a/hammond-gtk/src/content.rs +++ b/hammond-gtk/src/content.rs @@ -1,318 +1,167 @@ use gtk; use gtk::prelude::*; -// use hammond_data::Podcast; +use hammond_data::Podcast; use hammond_data::dbqueries; -use widgets::podcast::PodcastWidget; use views::podcasts::PopulatedView; use views::empty::EmptyView; +use widgets::podcast::PodcastWidget; + +use std::rc::Rc; #[derive(Debug, Clone)] pub struct Content { pub stack: gtk::Stack, - shows: ShowStateWrapper, - episodes: EpisodeStateWrapper, + shows: Rc, + episodes: Rc, } impl Content { - pub fn new() -> Content { + pub fn new() -> Rc { let stack = gtk::Stack::new(); - let shows = ShowStateWrapper::new(); - let episodes = EpisodeStateWrapper::new(); + let shows = ShowStack::new(); + let episodes = EpisodeStack::new(); - let shows_stack = shows.get_stack(); - let ep_stack = episodes.get_stack(); + stack.add_titled(&episodes.stack, "episodes", "Episodes"); + stack.add_titled(&shows.stack, "shows", "Shows"); - stack.add_titled(&ep_stack, "episodes", "Episodes"); - stack.add_titled(&shows_stack, "shows", "Shows"); - - Content { + Rc::new(Content { stack, shows, episodes, - } + }) } - pub fn update(&mut self) { - self.shows = self.shows.clone().update(); - // FIXME: like above + pub fn update(&self) { + self.shows.update(); self.episodes.update(); } } -// pub fn on_podcasts_child_activate(stack: >k::Stack, pd: &Podcast) { -// update_widget(stack, pd); -// stack.set_visible_child_full("widget", gtk::StackTransitionType::SlideLeft); -// } - -// FIXME: Rename and remove aliases -type ShowsPopulated = PopulatedView; -type ShowsEmpty = EmptyView; -type EpisodesPopulated = PodcastWidget; -type EpisodesEmpty = EmptyView; - #[derive(Debug, Clone)] -struct Populated; -#[derive(Debug, Clone)] -struct Empty; -// struct Shows; -// struct Episodes; - -// Thats probably too overengineered -// struct StackStateMachine { -// shows: ShowsMachine, -// episodes: EpisodesMachine, -// stack: gtk::Stack, -// state: T, -// } - -#[derive(Debug, Clone)] -struct ShowsMachine { - populated: ShowsPopulated, - empty: ShowsEmpty, - stack: gtk::Stack, - state: S, +pub struct ShowStack { + pub stack: gtk::Stack, } -impl ShowsMachine { - fn new(state: S) -> ShowsMachine { +impl ShowStack { + fn new() -> Rc { let stack = gtk::Stack::new(); - let pop = ShowsPopulated::new_initialized(); + + let show = Rc::new(ShowStack { stack }); + + let pop = PopulatedView::new_initialized(show.clone()); + let widget = PodcastWidget::new(); let empty = EmptyView::new(); - stack.add_named(&pop.container, "populated"); - stack.add_named(&empty.container, "empty"); - ShowsMachine { - empty, - populated: pop, - stack, - state, + show.stack.add_named(&pop.container, "podcasts"); + show.stack.add_named(&widget.container, "widget"); + show.stack.add_named(&empty.container, "empty"); + + if pop.is_empty() { + show.stack.set_visible_child_name("empty") + } else { + show.stack.set_visible_child_name("podcasts") } + + show } - fn update(&mut self) { + // fn is_empty(&self) -> bool { + // self.podcasts.is_empty() + // } + + pub fn update(&self) { + self.update_podcasts(); + self.update_widget(); + } + + pub fn update_podcasts(&self) { let vis = self.stack.get_visible_child_name().unwrap(); - let old = self.stack.get_child_by_name("populated").unwrap(); + let old = self.stack.get_child_by_name("podcasts").unwrap(); + + let pop = PopulatedView::new(); + pop.init(Rc::new(self.clone())); + self.stack.remove(&old); + self.stack.add_named(&pop.container, "podcasts"); - let pop = ShowsPopulated::new_initialized(); - self.populated = pop; - self.stack.add_named(&self.populated.container, "populated"); - self.stack.set_visible_child_name(&vis); + if pop.is_empty() { + self.stack.set_visible_child_name("empty"); + } else if vis != "empty" { + self.stack.set_visible_child_name(&vis); + } else { + self.stack.set_visible_child_name("podcasts"); + } + + old.destroy(); } -} -#[derive(Debug, Clone)] -struct EpisodesMachine { - populated: EpisodesPopulated, - empty: EpisodesEmpty, - stack: gtk::Stack, - state: S, -} + pub fn replace_widget(&self, pd: &Podcast) { + let old = self.stack.get_child_by_name("widget").unwrap(); + let new = PodcastWidget::new_initialized(Rc::new(self.clone()), pd); -impl EpisodesMachine { - // FIXME: - fn update(&mut self) { + self.stack.remove(&old); + self.stack.add_named(&new.container, "widget"); + } + + pub fn update_widget(&self) { let vis = self.stack.get_visible_child_name().unwrap(); - let old = self.stack.get_child_by_name("populated").unwrap(); + let old = self.stack.get_child_by_name("widget").unwrap(); let id = WidgetExt::get_name(&old).unwrap(); if id == "GtkBox" { return; } - let pd = dbqueries::get_podcast_from_id(id.parse::().unwrap()).unwrap(); - let pdw = EpisodesPopulated::new_initialized(&self.stack, &pd); - self.populated = pdw; - self.stack.remove(&old); - self.stack.add_named(&self.populated.container, "populated"); - self.stack.set_visible_child_name(&vis); - } -} - -// impl Into> for StackStateMachine { -// fn into(self) -> StackStateMachine { -// self.stack.set_visible_child_name("shows"); - -// StackStateMachine { -// shows: self.shows, -// episodes: self.episodes, -// stack: self.stack, -// state: Shows {}, -// } -// } -// } - -// impl Into> for StackStateMachine { -// fn into(self) -> StackStateMachine { -// self.stack.set_visible_child_name("episodes"); - -// StackStateMachine { -// shows: self.shows, -// episodes: self.episodes, -// stack: self.stack, -// state: Episodes {}, -// } -// } -// } - -// TODO: Impl instead of -impl Into> for ShowsMachine { - fn into(self) -> ShowsMachine { - self.stack.set_visible_child_name("populated"); - - ShowsMachine { - populated: self.populated, - empty: self.empty, - stack: self.stack, - state: Populated {}, + let pd = dbqueries::get_podcast_from_id(id.parse::().unwrap()); + if let Ok(pd) = pd { + self.replace_widget(&pd); + self.stack.set_visible_child_name(&vis); + old.destroy(); } } -} -impl Into> for ShowsMachine { - fn into(self) -> ShowsMachine { - self.stack.set_visible_child_name("empty"); - - ShowsMachine { - populated: self.populated, - empty: self.empty, - stack: self.stack, - state: Empty {}, - } + pub fn switch_podcasts_animated(&self) { + self.stack + .set_visible_child_full("podcasts", gtk::StackTransitionType::SlideRight); } -} -impl Into> for EpisodesMachine { - fn into(self) -> EpisodesMachine { - self.stack.set_visible_child_name("populated"); - - EpisodesMachine { - populated: self.populated, - empty: self.empty, - stack: self.stack, - state: Populated {}, - } + pub fn switch_widget_animated(&self) { + self.stack + .set_visible_child_full("widget", gtk::StackTransitionType::SlideLeft) } } -impl Into> for EpisodesMachine { - fn into(self) -> EpisodesMachine { - self.stack.set_visible_child_name("empty"); - - EpisodesMachine { - populated: self.populated, - empty: self.empty, - stack: self.stack, - state: Empty {}, - } - } -} - -// enum StackStateWrapper { -// Shows(StackStateMachine), -// Episodes(StackStateMachine), -// } - -#[derive(Debug, Clone)] -enum ShowStateWrapper { - Populated(ShowsMachine), - Empty(ShowsMachine), -} - #[derive(Debug, Clone)] -enum EpisodeStateWrapper { - Populated(EpisodesMachine), - Empty(EpisodesMachine), +struct RecentEpisodes; + +#[derive(Debug, Clone)] +struct EpisodeStack { + // populated: RecentEpisodes, + // empty: EmptyView, + stack: gtk::Stack, } -// impl StackStateWrapper { -// fn switch(mut self) -> Self { -// match self { -// StackStateWrapper::Shows(val) => StackStateWrapper::Episodes(val.into()), -// StackStateWrapper::Episodes(val) => StackStateWrapper::Shows(val.into()) -// } -// } -// } - -impl ShowStateWrapper { - fn new() -> Self { - let machine = ShowsMachine::new(Populated {}); - - if machine.populated.flowbox.get_children().is_empty() { - machine.stack.set_visible_child_name("empty"); - ShowStateWrapper::Empty(machine.into()) - } else { - machine.stack.set_visible_child_name("populated"); - ShowStateWrapper::Populated(machine) - } - } - - fn update(mut self) -> Self { - match self { - ShowStateWrapper::Populated(ref mut val) => val.update(), - ShowStateWrapper::Empty(ref mut val) => val.update(), - } - - if self.is_empty() { - match self { - ShowStateWrapper::Populated(val) => ShowStateWrapper::Empty(val.into()), - _ => self, - } - } else { - match self { - ShowStateWrapper::Empty(val) => ShowStateWrapper::Populated(val.into()), - _ => self, - } - } - } - - fn get_stack(&self) -> gtk::Stack { - match *self { - ShowStateWrapper::Populated(ref val) => val.stack.clone(), - ShowStateWrapper::Empty(ref val) => val.stack.clone(), - } - } - - fn is_empty(&self) -> bool { - match *self { - ShowStateWrapper::Populated(ref val) => val.populated.flowbox.get_children().is_empty(), - ShowStateWrapper::Empty(ref val) => val.populated.flowbox.get_children().is_empty(), - } - } -} - -impl EpisodeStateWrapper { - // FIXME: - fn new() -> Self { - let pop = PodcastWidget::new(); +impl EpisodeStack { + fn new() -> Rc { + let _pop = RecentEpisodes {}; let empty = EmptyView::new(); let stack = gtk::Stack::new(); - stack.add_named(&pop.container, "populated"); + // stack.add_named(&pop.container, "populated"); stack.add_named(&empty.container, "empty"); + // FIXME: stack.set_visible_child_name("empty"); - EpisodeStateWrapper::Empty(EpisodesMachine { - empty, - populated: pop, + Rc::new(EpisodeStack { + // empty, + // populated: pop, stack, - state: Empty {}, }) } - fn update(&mut self) { - match *self { - EpisodeStateWrapper::Populated(ref mut val) => val.update(), - EpisodeStateWrapper::Empty(ref mut val) => val.update(), - } - } - - fn get_stack(&self) -> gtk::Stack { - match *self { - EpisodeStateWrapper::Populated(ref val) => val.stack.clone(), - EpisodeStateWrapper::Empty(ref val) => val.stack.clone(), - } + fn update(&self) { + // unimplemented!() } } diff --git a/hammond-gtk/src/headerbar.rs b/hammond-gtk/src/headerbar.rs index 956e040..140eac2 100644 --- a/hammond-gtk/src/headerbar.rs +++ b/hammond-gtk/src/headerbar.rs @@ -4,7 +4,7 @@ use gtk::prelude::*; use hammond_data::Source; use hammond_data::utils::url_cleaner; -use std::sync::{Arc, Mutex}; +use std::rc::Rc; use utils; use content::Content; @@ -36,23 +36,19 @@ impl Header { } } - pub fn new_initialized(content: Arc>) -> Header { + pub fn new_initialized(content: Rc) -> Header { let header = Header::new(); header.init(content); header } - fn init(&self, content: Arc>) { + fn init(&self, content: Rc) { let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/headerbar.ui"); let add_popover: gtk::Popover = builder.get_object("add-popover").unwrap(); let new_url: gtk::Entry = builder.get_object("new-url").unwrap(); let add_button: gtk::Button = builder.get_object("add-button").unwrap(); - - { - let cont = content.lock().unwrap(); - self.switch.set_stack(&cont.stack); - } + self.switch.set_stack(&content.stack); new_url.connect_changed(move |url| { println!("{:?}", url.get_text()); @@ -68,14 +64,13 @@ impl Header { self.add_toggle.set_popover(&add_popover); // FIXME: There appears to be a memmory leak here. - let cont = content.clone(); self.refresh.connect_clicked(move |_| { - utils::refresh_feed(cont.clone(), None, None); + utils::refresh_feed(content.clone(), None, None); }); } } -fn on_add_bttn_clicked(content: Arc>, entry: >k::Entry) { +fn on_add_bttn_clicked(content: Rc, entry: >k::Entry) { let url = entry.get_text().unwrap_or_default(); let url = url_cleaner(&url); let source = Source::from_url(&url); diff --git a/hammond-gtk/src/main.rs b/hammond-gtk/src/main.rs index 9f4a4b4..77bd430 100644 --- a/hammond-gtk/src/main.rs +++ b/hammond-gtk/src/main.rs @@ -1,3 +1,5 @@ +#![cfg_attr(feature = "cargo-clippy", allow(clone_on_ref_ptr))] + extern crate gdk; extern crate gdk_pixbuf; extern crate gio; @@ -22,8 +24,6 @@ use hammond_data::utils::checkup; use gtk::prelude::*; use gio::{ActionMapExt, ApplicationExt, MenuExt, SimpleActionExt}; -use std::sync::{Arc, Mutex}; - // http://gtk-rs.org/tuto/closures #[macro_export] macro_rules! clone { @@ -72,7 +72,6 @@ fn build_ui(app: >k::Application) { // let ct = content::Content::new_initialized(); let ct = content::Content::new(); let stack = ct.stack.clone(); - let ct = Arc::new(Mutex::new(ct)); window.add(&stack); window.connect_delete_event(|w, _| { diff --git a/hammond-gtk/src/utils.rs b/hammond-gtk/src/utils.rs index 0a6a5c2..7327854 100644 --- a/hammond-gtk/src/utils.rs +++ b/hammond-gtk/src/utils.rs @@ -1,5 +1,4 @@ use glib; -use gtk; use gdk_pixbuf::Pixbuf; use hammond_data::feed; @@ -9,14 +8,12 @@ use hammond_downloader::downloader; use std::{thread, time}; use std::cell::RefCell; use std::sync::mpsc::{channel, Receiver}; -use std::borrow::Cow; use content::Content; -use regex::Regex; -use std::sync::{Arc, Mutex}; +use std::rc::Rc; -type Foo = RefCell>, Receiver)>>; +type Foo = RefCell, Receiver)>>; // Create a thread local storage that will store the arguments to be transfered. thread_local!(static GLOBAL: Foo = RefCell::new(None)); @@ -25,13 +22,13 @@ 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: Arc>, source: Option>, delay: Option) { +pub fn refresh_feed(content: Rc, source: Option>, delay: Option) { // Create a async channel. let (sender, receiver) = channel(); // Pass the desired arguments into the Local Thread Storage. GLOBAL.with(clone!(content => move |global| { - *global.borrow_mut() = Some((content, receiver)); + *global.borrow_mut() = Some((content.clone(), receiver)); })); thread::spawn(move || { @@ -61,7 +58,6 @@ fn refresh_podcasts_view() -> glib::Continue { GLOBAL.with(|global| { if let Some((ref content, ref reciever)) = *global.borrow() { if reciever.try_recv().is_ok() { - let mut content = content.lock().unwrap(); content.update(); } } @@ -74,18 +70,6 @@ pub fn get_pixbuf_from_path(pd: &Podcast) -> Option { Pixbuf::new_from_file_at_scale(&img_path, 256, 256, true).ok() } -#[allow(dead_code)] -// WIP: parse html to markup -pub fn html_to_markup(s: &mut str) -> Cow { - s.trim(); - s.replace('&', "&"); - s.replace('<', "<"); - s.replace('>', ">"); - - let re = Regex::new("(?Phttps?://[^\\s&,)(\"]+(&\\w=[\\w._-]?)*(#[\\w._-]+)?)").unwrap(); - re.replace_all(s, "$url") -} - #[cfg(test)] mod tests { use hammond_data::Source; diff --git a/hammond-gtk/src/views/podcasts.rs b/hammond-gtk/src/views/podcasts.rs index 0767d72..58c5f14 100644 --- a/hammond-gtk/src/views/podcasts.rs +++ b/hammond-gtk/src/views/podcasts.rs @@ -7,8 +7,9 @@ use hammond_data::dbqueries; use hammond_data::Podcast; use utils::get_pixbuf_from_path; +use content::ShowStack; -// use content; +use std::rc::Rc; #[derive(Debug, Clone)] pub struct PopulatedView { @@ -42,25 +43,29 @@ impl PopulatedView { } #[allow(dead_code)] - pub fn new_initialized() -> PopulatedView { + pub fn new_initialized(show: Rc) -> PopulatedView { let pop = PopulatedView::new(); - pop.init(); + pop.init(show); pop } - pub fn init(&self) { - // pub fn init(&self, stack: >k::Stack) { - // use gtk::WidgetExt; + pub fn init(&self, show: Rc) { + use gtk::WidgetExt; - // // TODO: handle unwraps. - // self.flowbox - // .connect_child_activated(clone!(stack => move |_, child| { - // // This is such an ugly hack... - // // let id = child.get_name().unwrap().parse::().unwrap(); - // let id = WidgetExt::get_name(child).unwrap().parse::().unwrap(); - // let parent = dbqueries::get_podcast_from_id(id).unwrap(); - // on_flowbox_child_activate(&stack, &parent); - // })); + // TODO: handle unwraps. + // Note: flowbox_activation always adds "widnget" into the stack and switch to it, + // TODO: implement back button. + // so back button should always remove "widget" and destroy it. + let show = show.clone(); + self.flowbox + .connect_child_activated(clone!(show => move |_, child| { + // This is such an ugly hack... + let id = WidgetExt::get_name(child).unwrap().parse::().unwrap(); + let pd = dbqueries::get_podcast_from_id(id).unwrap(); + + show.replace_widget(&pd); + show.switch_widget_animated(); + })); // Populate the flowbox with the Podcasts. self.populate_flowbox(); } @@ -76,6 +81,10 @@ impl PopulatedView { self.flowbox.show_all(); } } + + pub fn is_empty(&self) -> bool { + self.flowbox.get_children().is_empty() + } } impl PodcastChild { @@ -139,7 +148,3 @@ impl PodcastChild { } } } - -// fn on_flowbox_child_activate(stack: >k::Stack, parent: &Podcast) { -// content::on_podcasts_child_activate(stack, parent) -// } diff --git a/hammond-gtk/src/widgets/podcast.rs b/hammond-gtk/src/widgets/podcast.rs index c0d4c34..1d7f91b 100644 --- a/hammond-gtk/src/widgets/podcast.rs +++ b/hammond-gtk/src/widgets/podcast.rs @@ -10,7 +10,8 @@ use hammond_downloader::downloader; use widgets::episode::episodes_listbox; use utils::get_pixbuf_from_path; -// use content; +use content::ShowStack; +use std::rc::Rc; #[derive(Debug, Clone)] pub struct PodcastWidget { @@ -47,18 +48,18 @@ impl PodcastWidget { } } - pub fn new_initialized(stack: >k::Stack, pd: &Podcast) -> PodcastWidget { + pub fn new_initialized(shows: Rc, pd: &Podcast) -> PodcastWidget { let pdw = PodcastWidget::new(); - pdw.init(stack, pd); + pdw.init(shows, pd); pdw } - pub fn init(&self, stack: >k::Stack, pd: &Podcast) { + pub fn init(&self, shows: Rc, pd: &Podcast) { WidgetExt::set_name(&self.container, &pd.id().to_string()); // TODO: should spawn a thread to avoid locking the UI probably. - self.unsub.connect_clicked(clone!(stack, pd => move |bttn| { - on_unsub_button_clicked(&stack, &pd, bttn); + self.unsub.connect_clicked(clone!(shows, pd => move |bttn| { + on_unsub_button_clicked(shows.clone(), &pd, bttn); })); self.title.set_text(pd.title()); @@ -77,8 +78,8 @@ impl PodcastWidget { self.cover.set_from_pixbuf(&i); } - self.played.connect_clicked(clone!(stack, pd => move |_| { - on_played_button_clicked(&stack, &pd); + self.played.connect_clicked(clone!(shows, pd => move |_| { + on_played_button_clicked(shows.clone(), &pd); })); self.show_played_button(pd); @@ -95,7 +96,7 @@ impl PodcastWidget { } } -fn on_unsub_button_clicked(stack: >k::Stack, pd: &Podcast, unsub_button: >k::Button) { +fn on_unsub_button_clicked(shows: Rc, pd: &Podcast, unsub_button: >k::Button) { let res = dbqueries::remove_feed(pd); if res.is_ok() { info!("{} was removed succesfully.", pd.title()); @@ -111,11 +112,12 @@ fn on_unsub_button_clicked(stack: >k::Stack, pd: &Podcast, unsub_button: >k: } }; } - // content::update_podcasts(stack); + shows.switch_podcasts_animated(); + shows.update_podcasts(); } -fn on_played_button_clicked(stack: >k::Stack, pd: &Podcast) { +fn on_played_button_clicked(shows: Rc, pd: &Podcast) { let _ = dbqueries::update_none_to_played_now(pd); - // content::update_widget_preserve_vis(stack, pd); + shows.update_widget(); } From d5d55d4ef30cc2dc6cd7a5c13bc4aa5bf6420707 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Tue, 12 Dec 2017 16:51:24 +0200 Subject: [PATCH 06/12] Update dependancies. --- Cargo.lock | 78 +++++++++++++++++------------------ hammond-downloader/Cargo.toml | 4 +- 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 910f55f..95d51b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -91,7 +91,7 @@ dependencies = [ [[package]] name = "base64" -version = "0.6.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -590,7 +590,7 @@ dependencies = [ "diesel 0.99.0 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "hammond-data 0.1.0", - "hyper 0.11.7 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.11.9 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "mime_guess 1.8.3 (registry+https://github.com/rust-lang/crates.io-index)", "reqwest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -636,10 +636,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "hyper" -version = "0.11.7" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -650,7 +650,7 @@ dependencies = [ "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "relay 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -663,9 +663,9 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.11.7 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.11.9 (registry+https://github.com/rust-lang/crates.io-index)", "native-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-tls 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -897,8 +897,8 @@ name = "native-tls" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "openssl 0.9.22 (registry+https://github.com/rust-lang/crates.io-index)", - "schannel 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl 0.9.23 (registry+https://github.com/rust-lang/crates.io-index)", + "schannel 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "security-framework 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "security-framework-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -963,19 +963,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "openssl" -version = "0.9.22" +version = "0.9.23" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.22 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.23 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "openssl-sys" -version = "0.9.22" +version = "0.9.23" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1144,7 +1144,7 @@ dependencies = [ "aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1168,16 +1168,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.11.7 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.11.9 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "libflate 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "mime_guess 2.0.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)", "native-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "serde_urlencoded 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-tls 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1220,13 +1220,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "schannel" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "crypt32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "secur32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1281,18 +1281,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_json" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1302,7 +1302,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1335,7 +1335,7 @@ dependencies = [ "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", "precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache_codegen 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1409,10 +1409,10 @@ dependencies = [ [[package]] name = "thread_local" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1429,7 +1429,7 @@ dependencies = [ [[package]] name = "tokio-core" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1464,7 +1464,7 @@ dependencies = [ "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1484,7 +1484,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "native-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1619,7 +1619,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum atty 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "21e50800ec991574876040fff8ee46b136a53e985286fbe6a3bdfe6421b78860" "checksum backtrace 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8709cc7ec06f6f0ae6c2c7e12f6ed41540781f72b488d83734978295ceae182e" "checksum backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "44585761d6161b0f57afc49482ab6bd067e4edef48c12a152c237eb0203f7661" -"checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9" +"checksum base64 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c4a342b450b268e1be8036311e2c613d7f8a7ed31214dff1cc3b60852a3168d" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" @@ -1672,7 +1672,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum gtk-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "905fcfbaaad1b44ec0b4bba9e4d527d728284c62bc2ba41fccedace2b096766f" "checksum html5ever 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba3a1fd1857a714d410c191364c5d7bf8a6487c0ab5575146d37dd7eb17ef523" "checksum httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "af2f2dd97457e8fb1ae7c5a420db346af389926e36f43768b96f101546b04a07" -"checksum hyper 0.11.7 (registry+https://github.com/rust-lang/crates.io-index)" = "4959ca95f55df4265bff2ad63066147255e6fa733682cf6d1cb5eaff6e53324b" +"checksum hyper 0.11.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e0594792d2109069d0caffd176f674d770a84adf024c5bb48e686b1ee5ac7659" "checksum hyper-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c81fa95203e2a6087242c38691a0210f23e9f3f8f944350bd676522132e2985" "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" "checksum iovec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b6e8b9c2247fcf6c6a1151f1156932be5606c9fd6f55a2d7f9fc1cb29386b2f7" @@ -1709,8 +1709,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "cacfcab5eb48250ee7d0c7896b51a2c5eec99c1feea5f32025635f5ae4b00070" "checksum num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "514f0d73e64be53ff320680ca671b64fe3fb91da01e1ae2ddc99eb51d453b20d" "checksum open 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c281318d992e4432cfa799969467003d05921582a7489a8325e37f8a450d5113" -"checksum openssl 0.9.22 (registry+https://github.com/rust-lang/crates.io-index)" = "419ef26bb651d72b6c5a603bcc4e4856a362460e62352dfffa53de91d2e81181" -"checksum openssl-sys 0.9.22 (registry+https://github.com/rust-lang/crates.io-index)" = "5483bdc56756041ba6aa37c9cb59cc2219f012a2a1377d97ad35556ac6676ee7" +"checksum openssl 0.9.23 (registry+https://github.com/rust-lang/crates.io-index)" = "169a4b9160baf9b9b1ab975418c673686638995ba921683a7f1e01470dcb8854" +"checksum openssl-sys 0.9.23 (registry+https://github.com/rust-lang/crates.io-index)" = "2200ffec628e3f14c39fc0131a301db214f1a7d584e36507ee8700b0c7fb7a46" "checksum pango 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e81c404ab81ea7ea2fc2431a0a7672507b80e4b8bf4b41eac3fc83cc665104e" "checksum pango-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34f34a1be107fe16abb2744e0e206bee4b3b07460b5fddd3009a6aaf60bd69ab" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" @@ -1738,15 +1738,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" -"checksum schannel 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7554288337c1110e34d7a2433518d889374c1de1a45f856b7bcddb03702131fc" +"checksum schannel 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "4330c2e874379fbd28fa67ba43239dbe8c7fb00662ceb1078bd37474f08bf5ce" "checksum scheduled-thread-pool 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a2ff3fc5223829be817806c6441279c676e454cc7da608faf03b0ccc09d3889" "checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum secur32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f412dfa83308d893101dd59c10d6fda8283465976c28c287c5c855bf8d216bc" "checksum security-framework 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "dfa44ee9c54ce5eecc9de7d5acbad112ee58755239381f687e564004ba4a2332" "checksum security-framework-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "5421621e836278a0b139268f36eee0dc7e389b784dc3f79d8f11aabadf41bead" -"checksum serde 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)" = "6a7c37d7f192f00041e8a613e936717923a71bc0c9051fc4425a49b104140f05" -"checksum serde_json 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ea28ea0cca944668919bec6af209864a8dfe769fd2b0b723f36b22e20c1bf69f" +"checksum serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "1c57ab4ec5fa85d08aaf8ed9245899d9bbdd66768945b21113b84d5f595cb6a1" +"checksum serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7cf5b0b5b4bd22eeecb7e01ac2e1225c7ef5e4272b79ee28a8392a8c8489c839" "checksum serde_urlencoded 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce0fd303af908732989354c6f02e05e2e6d597152870f2c6990efb0577137480" "checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537" "checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23" @@ -1761,9 +1761,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6" "checksum tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9de21546595a0873061940d994bbbc5c35f024ae4fd61ec5c5b159115684f508" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" -"checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14" +"checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963" "checksum time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d788d3aa77bc0ef3e9621256885555368b47bd495c13dd2e7413c89f845520" -"checksum tokio-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "c843a027f7c1df5f81e7734a0df3f67bf329411781ebf36393ce67beef6071e3" +"checksum tokio-core 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c87c27560184212c9dc45cd8f38623f37918248aad5b58fb65303b5d07a98c6e" "checksum tokio-io 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "514aae203178929dbf03318ad7c683126672d4d96eccb77b29603d33c9e25743" "checksum tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fbb47ae81353c63c487030659494b295f6cb6576242f907f203473b191b0389" "checksum tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24da22d077e0f15f55162bdbdc661228c1581892f52074fb242678d015b45162" diff --git a/hammond-downloader/Cargo.toml b/hammond-downloader/Cargo.toml index f063adc..ed50616 100644 --- a/hammond-downloader/Cargo.toml +++ b/hammond-downloader/Cargo.toml @@ -6,7 +6,7 @@ workspace = "../" [dependencies] error-chain = "0.11.0" -hyper = "0.11.7" +hyper = "0.11.9" log = "0.3.8" mime_guess = "1.8.3" reqwest = "0.8.1" @@ -14,7 +14,7 @@ tempdir = "0.3.5" [dependencies.diesel] features = ["sqlite"] -version = "0.99" +version = "0.99.0" [dependencies.hammond-data] path = "../hammond-data" From 5defb5867a2b429b07b3c40339aa5bc98641f63d Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Wed, 13 Dec 2017 11:35:17 +0200 Subject: [PATCH 07/12] Move and rename stuff. --- hammond-gtk/src/content.rs | 13 +++++----- hammond-gtk/src/views/episodes.rs | 1 + hammond-gtk/src/views/mod.rs | 3 ++- .../src/views/{podcasts.rs => shows.rs} | 26 +++++++++---------- hammond-gtk/src/widgets/episode.rs | 2 -- hammond-gtk/src/widgets/mod.rs | 2 +- .../src/widgets/{podcast.rs => show.rs} | 12 ++++----- 7 files changed, 30 insertions(+), 29 deletions(-) create mode 100644 hammond-gtk/src/views/episodes.rs rename hammond-gtk/src/views/{podcasts.rs => shows.rs} (88%) rename hammond-gtk/src/widgets/{podcast.rs => show.rs} (95%) diff --git a/hammond-gtk/src/content.rs b/hammond-gtk/src/content.rs index 8214ab9..4e71505 100644 --- a/hammond-gtk/src/content.rs +++ b/hammond-gtk/src/content.rs @@ -4,9 +4,10 @@ use gtk::prelude::*; use hammond_data::Podcast; use hammond_data::dbqueries; -use views::podcasts::PopulatedView; +use views::shows::ShowsPopulated; use views::empty::EmptyView; -use widgets::podcast::PodcastWidget; + +use widgets::show::ShowWidget; use std::rc::Rc; @@ -50,8 +51,8 @@ impl ShowStack { let show = Rc::new(ShowStack { stack }); - let pop = PopulatedView::new_initialized(show.clone()); - let widget = PodcastWidget::new(); + let pop = ShowsPopulated::new_initialized(show.clone()); + let widget = ShowWidget::new(); let empty = EmptyView::new(); show.stack.add_named(&pop.container, "podcasts"); @@ -80,7 +81,7 @@ impl ShowStack { let vis = self.stack.get_visible_child_name().unwrap(); let old = self.stack.get_child_by_name("podcasts").unwrap(); - let pop = PopulatedView::new(); + let pop = ShowsPopulated::new(); pop.init(Rc::new(self.clone())); self.stack.remove(&old); @@ -99,7 +100,7 @@ impl ShowStack { pub fn replace_widget(&self, pd: &Podcast) { let old = self.stack.get_child_by_name("widget").unwrap(); - let new = PodcastWidget::new_initialized(Rc::new(self.clone()), pd); + let new = ShowWidget::new_initialized(Rc::new(self.clone()), pd); self.stack.remove(&old); self.stack.add_named(&new.container, "widget"); diff --git a/hammond-gtk/src/views/episodes.rs b/hammond-gtk/src/views/episodes.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/hammond-gtk/src/views/episodes.rs @@ -0,0 +1 @@ + diff --git a/hammond-gtk/src/views/mod.rs b/hammond-gtk/src/views/mod.rs index 9c47e7d..a9ea1bf 100644 --- a/hammond-gtk/src/views/mod.rs +++ b/hammond-gtk/src/views/mod.rs @@ -1,2 +1,3 @@ -pub mod podcasts; +pub mod shows; +pub mod episodes; pub mod empty; diff --git a/hammond-gtk/src/views/podcasts.rs b/hammond-gtk/src/views/shows.rs similarity index 88% rename from hammond-gtk/src/views/podcasts.rs rename to hammond-gtk/src/views/shows.rs index 58c5f14..5b2ee98 100644 --- a/hammond-gtk/src/views/podcasts.rs +++ b/hammond-gtk/src/views/shows.rs @@ -12,14 +12,14 @@ use content::ShowStack; use std::rc::Rc; #[derive(Debug, Clone)] -pub struct PopulatedView { +pub struct ShowsPopulated { pub container: gtk::Box, pub flowbox: gtk::FlowBox, viewport: gtk::Viewport, } #[derive(Debug)] -struct PodcastChild { +struct ShowsChild { container: gtk::Box, title: gtk::Label, cover: gtk::Image, @@ -28,14 +28,14 @@ struct PodcastChild { child: gtk::FlowBoxChild, } -impl PopulatedView { - pub fn new() -> PopulatedView { +impl ShowsPopulated { + pub fn new() -> ShowsPopulated { let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/podcasts_view.ui"); let container: gtk::Box = builder.get_object("fb_parent").unwrap(); let flowbox: gtk::FlowBox = builder.get_object("flowbox").unwrap(); let viewport: gtk::Viewport = builder.get_object("viewport").unwrap(); - PopulatedView { + ShowsPopulated { container, flowbox, viewport, @@ -43,8 +43,8 @@ impl PopulatedView { } #[allow(dead_code)] - pub fn new_initialized(show: Rc) -> PopulatedView { - let pop = PopulatedView::new(); + pub fn new_initialized(show: Rc) -> ShowsPopulated { + let pop = ShowsPopulated::new(); pop.init(show); pop } @@ -75,7 +75,7 @@ impl PopulatedView { if let Ok(pds) = podcasts { pds.iter().for_each(|parent| { - let flowbox_child = PodcastChild::new_initialized(parent); + let flowbox_child = ShowsChild::new_initialized(parent); self.flowbox.add(&flowbox_child.child); }); self.flowbox.show_all(); @@ -87,8 +87,8 @@ impl PopulatedView { } } -impl PodcastChild { - fn new() -> PodcastChild { +impl ShowsChild { + fn new() -> ShowsChild { let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/podcasts_child.ui"); // Copy of gnome-music AlbumWidget @@ -101,7 +101,7 @@ impl PodcastChild { let child = gtk::FlowBoxChild::new(); child.add(&container); - PodcastChild { + ShowsChild { container, title, cover, @@ -123,8 +123,8 @@ impl PodcastChild { self.configure_banner(pd); } - pub fn new_initialized(pd: &Podcast) -> PodcastChild { - let child = PodcastChild::new(); + pub fn new_initialized(pd: &Podcast) -> ShowsChild { + let child = ShowsChild::new(); child.init(pd); child diff --git a/hammond-gtk/src/widgets/episode.rs b/hammond-gtk/src/widgets/episode.rs index 7166d0c..e69efd1 100644 --- a/hammond-gtk/src/widgets/episode.rs +++ b/hammond-gtk/src/widgets/episode.rs @@ -13,8 +13,6 @@ use hammond_data::utils::*; use hammond_data::errors::*; use hammond_data::utils::replace_extra_spaces; -// use utils::html_to_markup; - use std::thread; use std::cell::RefCell; use std::sync::mpsc::{channel, Receiver}; diff --git a/hammond-gtk/src/widgets/mod.rs b/hammond-gtk/src/widgets/mod.rs index 5752aa3..d33f990 100644 --- a/hammond-gtk/src/widgets/mod.rs +++ b/hammond-gtk/src/widgets/mod.rs @@ -1,2 +1,2 @@ -pub mod podcast; +pub mod show; pub mod episode; diff --git a/hammond-gtk/src/widgets/podcast.rs b/hammond-gtk/src/widgets/show.rs similarity index 95% rename from hammond-gtk/src/widgets/podcast.rs rename to hammond-gtk/src/widgets/show.rs index 1d7f91b..b21bb06 100644 --- a/hammond-gtk/src/widgets/podcast.rs +++ b/hammond-gtk/src/widgets/show.rs @@ -14,7 +14,7 @@ use content::ShowStack; use std::rc::Rc; #[derive(Debug, Clone)] -pub struct PodcastWidget { +pub struct ShowWidget { pub container: gtk::Box, cover: gtk::Image, title: gtk::Label, @@ -24,8 +24,8 @@ pub struct PodcastWidget { played: gtk::Button, } -impl PodcastWidget { - pub fn new() -> PodcastWidget { +impl ShowWidget { + pub fn new() -> ShowWidget { // Adapted from gnome-music AlbumWidget let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/podcast_widget.ui"); let container: gtk::Box = builder.get_object("podcast_widget").unwrap(); @@ -37,7 +37,7 @@ impl PodcastWidget { let unsub: gtk::Button = builder.get_object("unsub_button").unwrap(); let played: gtk::Button = builder.get_object("mark_all_played_button").unwrap(); - PodcastWidget { + ShowWidget { container, cover, title, @@ -48,8 +48,8 @@ impl PodcastWidget { } } - pub fn new_initialized(shows: Rc, pd: &Podcast) -> PodcastWidget { - let pdw = PodcastWidget::new(); + pub fn new_initialized(shows: Rc, pd: &Podcast) -> ShowWidget { + let pdw = ShowWidget::new(); pdw.init(shows, pd); pdw } From 82a59d80dd73376a527475cd39f134134253fc23 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Wed, 13 Dec 2017 11:53:56 +0200 Subject: [PATCH 08/12] Update README.md and CONTRIBUTING.md --- CONTRIBUTING.md | 14 +++++++++++--- README.md | 11 +---------- hammond-gtk/src/views/shows.rs | 2 +- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f1f3d07..2e46fdc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,6 +20,12 @@ It is recommended to add a pre-commit hook to run cargo test and cargo fmt cargo test -- --test-threads=1 && cargo fmt --all -- --write-mode=diff ``` +## Running the test suite + +The test suite sets a temporary sqlite database in the /tmp folder. Due to that it's not possible to run them in parrallel. + +In order to run the test suite use the following: `cargo test -- --test-threads=1` + # Issues, issues and more issues! There are many ways you can contribute to Hammond, and all of them involve creating issues @@ -67,8 +73,10 @@ Steps to reproduce: ## Pull Request Process 1. Ensure your code compiles. Run `make` before creating the pull request. -2. If you're adding new API, it must be properly documented. -3. The commit message is formatted as follows: +2. Ensure the test suit passes. Run `cargo test -- --test-threads=1`. +3. Ensure your code is properly formated. Run `cargo fmt --all`. +4. If you're adding new API, it must be properly documented. +5. The commit message is formatted as follows: ``` component: @@ -78,7 +86,7 @@ Steps to reproduce: ``` -4. You may merge the pull request in once you have the sign-off of the maintainers, or if you +6. You may merge the pull request in once you have the sign-off of the maintainers, or if you do not have permission to do that, you may request the second reviewer to merge it for you. ## Code of Conduct diff --git a/README.md b/README.md index 89a8a06..4d25ca6 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,7 @@ This is a prototype of a podcast client written in Rust. ![podcast_widget](./assets/podcast_widget.png) ## Getting in Touch -If you have any questions regarding the -use or development of Hammond, want to discuss design or simply hang out, please join us in [#hammond on irc.gnome.org.](irc://irc.gnome.org/#hammond) +If you have any questions regarding the use or development of Hammond, want to discuss design or simply hang out, please join us in [#hammond on irc.gnome.org.](irc://irc.gnome.org/#hammond) Sidenote: @@ -70,14 +69,6 @@ cd Hammond/ cargo build --all ``` -## Call for designers - -Currently there no design plans or mockups. They are highly needed in order to advance the Gtk Client. - -There is the will for a complete client re-write if a someone contributes the mockups. - -If you happen to be a designer and want to contribute please hope on [#hammond](irc://irc.gnome.org/#hammond) and get in touch with us. - ## Contributing There alot of thins yet to be done. diff --git a/hammond-gtk/src/views/shows.rs b/hammond-gtk/src/views/shows.rs index 5b2ee98..bd9cf62 100644 --- a/hammond-gtk/src/views/shows.rs +++ b/hammond-gtk/src/views/shows.rs @@ -14,7 +14,7 @@ use std::rc::Rc; #[derive(Debug, Clone)] pub struct ShowsPopulated { pub container: gtk::Box, - pub flowbox: gtk::FlowBox, + flowbox: gtk::FlowBox, viewport: gtk::Viewport, } From 0a52f87f3a852e08804a6632bf94e9d30900ee51 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Wed, 13 Dec 2017 12:21:34 +0200 Subject: [PATCH 09/12] Rename glade files. --- .../resources/gtk/{podcast_widget.ui => show_widget.ui} | 0 .../resources/gtk/{podcasts_child.ui => shows_child.ui} | 0 .../resources/gtk/{podcasts_view.ui => shows_view.ui} | 0 hammond-gtk/resources/resources.xml | 6 +++--- hammond-gtk/src/views/shows.rs | 7 ++----- hammond-gtk/src/widgets/show.rs | 2 +- 6 files changed, 6 insertions(+), 9 deletions(-) rename hammond-gtk/resources/gtk/{podcast_widget.ui => show_widget.ui} (100%) rename hammond-gtk/resources/gtk/{podcasts_child.ui => shows_child.ui} (100%) rename hammond-gtk/resources/gtk/{podcasts_view.ui => shows_view.ui} (100%) diff --git a/hammond-gtk/resources/gtk/podcast_widget.ui b/hammond-gtk/resources/gtk/show_widget.ui similarity index 100% rename from hammond-gtk/resources/gtk/podcast_widget.ui rename to hammond-gtk/resources/gtk/show_widget.ui diff --git a/hammond-gtk/resources/gtk/podcasts_child.ui b/hammond-gtk/resources/gtk/shows_child.ui similarity index 100% rename from hammond-gtk/resources/gtk/podcasts_child.ui rename to hammond-gtk/resources/gtk/shows_child.ui diff --git a/hammond-gtk/resources/gtk/podcasts_view.ui b/hammond-gtk/resources/gtk/shows_view.ui similarity index 100% rename from hammond-gtk/resources/gtk/podcasts_view.ui rename to hammond-gtk/resources/gtk/shows_view.ui diff --git a/hammond-gtk/resources/resources.xml b/hammond-gtk/resources/resources.xml index df3f3cd..e8bdc73 100644 --- a/hammond-gtk/resources/resources.xml +++ b/hammond-gtk/resources/resources.xml @@ -3,10 +3,10 @@ banner.png gtk/episode_widget.ui - gtk/podcast_widget.ui + gtk/show_widget.ui gtk/empty_view.ui - gtk/podcasts_view.ui - gtk/podcasts_child.ui + gtk/shows_view.ui + gtk/shows_child.ui gtk/headerbar.ui diff --git a/hammond-gtk/src/views/shows.rs b/hammond-gtk/src/views/shows.rs index bd9cf62..8e7b802 100644 --- a/hammond-gtk/src/views/shows.rs +++ b/hammond-gtk/src/views/shows.rs @@ -30,7 +30,7 @@ struct ShowsChild { impl ShowsPopulated { pub fn new() -> ShowsPopulated { - let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/podcasts_view.ui"); + 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(); let viewport: gtk::Viewport = builder.get_object("viewport").unwrap(); @@ -53,10 +53,7 @@ impl ShowsPopulated { use gtk::WidgetExt; // TODO: handle unwraps. - // Note: flowbox_activation always adds "widnget" into the stack and switch to it, // TODO: implement back button. - // so back button should always remove "widget" and destroy it. - let show = show.clone(); self.flowbox .connect_child_activated(clone!(show => move |_, child| { // This is such an ugly hack... @@ -89,7 +86,7 @@ impl ShowsPopulated { impl ShowsChild { fn new() -> ShowsChild { - let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/podcasts_child.ui"); + 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(); diff --git a/hammond-gtk/src/widgets/show.rs b/hammond-gtk/src/widgets/show.rs index b21bb06..1adcc3d 100644 --- a/hammond-gtk/src/widgets/show.rs +++ b/hammond-gtk/src/widgets/show.rs @@ -27,7 +27,7 @@ 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/podcast_widget.ui"); + 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 cover: gtk::Image = builder.get_object("cover").unwrap(); From 0bb0035f3c3c1bcf2c3aa8fcb9b4e57611d282ec Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Wed, 13 Dec 2017 13:53:15 +0200 Subject: [PATCH 10/12] Rework of the Headerbar. Added a stack to switch between a normal and a BackButton view. Also added a centered stack switcher and removed the Home button. Backbutton is not wired yet. --- hammond-gtk/resources/gtk/headerbar.ui | 113 ++++++++++++++++++++++--- hammond-gtk/src/headerbar.rs | 15 +++- 2 files changed, 113 insertions(+), 15 deletions(-) diff --git a/hammond-gtk/resources/gtk/headerbar.ui b/hammond-gtk/resources/gtk/headerbar.ui index fc17ce5..0946f21 100644 --- a/hammond-gtk/resources/gtk/headerbar.ui +++ b/hammond-gtk/resources/gtk/headerbar.ui @@ -1,5 +1,5 @@ - + @@ -109,20 +109,70 @@ - + True False - False - True - + + True + True + True + + + True + False + go-previous-symbolic + + + + + False + False + 0 + + + + + True + False + Show Title + + + + + + True + True + 1 + + + + + False + True + + + True + False + True + + + + + + + + True + False + 5 + + True True False Add a new feed - center - + True False gtk-add @@ -135,26 +185,63 @@ - 1 + False + False + 0 - + True False center True + 0 + False + True + 4 + + + + + True + True + True + + + True + False + open-menu-symbolic + + + + + False + False + end 2 - + + True + False + vertical + + + False + True + end + 3 + + + + True True True - center True True @@ -167,8 +254,10 @@ + False + False end - -1 + 3 diff --git a/hammond-gtk/src/headerbar.rs b/hammond-gtk/src/headerbar.rs index 140eac2..1a8d6b4 100644 --- a/hammond-gtk/src/headerbar.rs +++ b/hammond-gtk/src/headerbar.rs @@ -15,24 +15,33 @@ pub struct Header { refresh: gtk::Button, add_toggle: gtk::MenuButton, switch: gtk::StackSwitcher, + stack: gtk::Stack, } impl Header { pub fn new() -> Header { let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/headerbar.ui"); - let header: gtk::HeaderBar = builder.get_object("headerbar1").unwrap(); - let refresh: gtk::Button = builder.get_object("refbutton").unwrap(); - let add_toggle: gtk::MenuButton = builder.get_object("add-toggle-button").unwrap(); + 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 stack: gtk::Stack = builder.get_object("headerbar_stack").unwrap(); + let normal_view: gtk::Box = builder.get_object("normal_view").unwrap(); + let back_view: gtk::Box = builder.get_object("back_view").unwrap(); switch.set_halign(gtk::Align::Center); switch.show(); + stack.add_named(&normal_view, "normal_view"); + stack.add_named(&back_view, "back_view"); + stack.set_visible_child_name("normal_view"); + Header { container: header, refresh, add_toggle, switch, + stack, } } From d74aa9c625546a9dc9605511fef03a8741f0d01b Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Wed, 13 Dec 2017 16:36:40 +0200 Subject: [PATCH 11/12] Wire Headerbar back button and change initialiazation order. --- hammond-gtk/resources/gtk/headerbar.ui | 101 ++++++++++++++----------- hammond-gtk/src/content.rs | 25 ++++-- hammond-gtk/src/headerbar.rs | 54 ++++++++++--- hammond-gtk/src/main.rs | 14 ++-- hammond-gtk/src/views/shows.rs | 9 ++- hammond-gtk/src/widgets/show.rs | 9 ++- 6 files changed, 136 insertions(+), 76 deletions(-) diff --git a/hammond-gtk/resources/gtk/headerbar.ui b/hammond-gtk/resources/gtk/headerbar.ui index 0946f21..2c53892 100644 --- a/hammond-gtk/resources/gtk/headerbar.ui +++ b/hammond-gtk/resources/gtk/headerbar.ui @@ -146,6 +146,19 @@ 1 + + + True + False + vertical + + + False + True + end + 2 + + False @@ -166,42 +179,16 @@ False 5 - - True - True - False - Add a new feed - - - True - False - gtk-add - True - 1 - - - - - - False - False - 0 - - - - + True False - center - True - 0 + vertical False True - 4 + end + 0 @@ -221,20 +208,7 @@ False False end - 2 - - - - - True - False - vertical - - - False - True - end - 3 + 1 @@ -257,8 +231,47 @@ False False end + 2 + + + + + True + True + False + Add a new feed + + + True + False + gtk-add + True + 1 + + + + + + False + False 3 + + + True + False + center + True + 0 + + + False + True + 4 + + diff --git a/hammond-gtk/src/content.rs b/hammond-gtk/src/content.rs index 4e71505..c87f88f 100644 --- a/hammond-gtk/src/content.rs +++ b/hammond-gtk/src/content.rs @@ -8,20 +8,21 @@ use views::shows::ShowsPopulated; use views::empty::EmptyView; use widgets::show::ShowWidget; +use headerbar::Header; use std::rc::Rc; #[derive(Debug, Clone)] pub struct Content { pub stack: gtk::Stack, - shows: Rc, + pub shows: Rc, episodes: Rc, } impl Content { - pub fn new() -> Rc { + pub fn new(header: Rc
) -> Rc { let stack = gtk::Stack::new(); - let shows = ShowStack::new(); + let shows = ShowStack::new(header); let episodes = EpisodeStack::new(); stack.add_titled(&episodes.stack, "episodes", "Episodes"); @@ -38,20 +39,28 @@ impl Content { self.shows.update(); self.episodes.update(); } + + pub fn get_stack(&self) -> gtk::Stack { + self.stack.clone() + } } #[derive(Debug, Clone)] pub struct ShowStack { pub stack: gtk::Stack, + header: Rc
, } impl ShowStack { - fn new() -> Rc { + fn new(header: Rc
) -> Rc { let stack = gtk::Stack::new(); - let show = Rc::new(ShowStack { stack }); + let show = Rc::new(ShowStack { + stack, + header: header.clone(), + }); - let pop = ShowsPopulated::new_initialized(show.clone()); + let pop = ShowsPopulated::new_initialized(show.clone(), header); let widget = ShowWidget::new(); let empty = EmptyView::new(); @@ -82,7 +91,7 @@ impl ShowStack { let old = self.stack.get_child_by_name("podcasts").unwrap(); let pop = ShowsPopulated::new(); - pop.init(Rc::new(self.clone())); + pop.init(Rc::new(self.clone()), self.header.clone()); self.stack.remove(&old); self.stack.add_named(&pop.container, "podcasts"); @@ -100,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()), pd); + let new = ShowWidget::new_initialized(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 1a8d6b4..0aa98a9 100644 --- a/hammond-gtk/src/headerbar.rs +++ b/hammond-gtk/src/headerbar.rs @@ -16,10 +16,12 @@ pub struct Header { add_toggle: gtk::MenuButton, switch: gtk::StackSwitcher, stack: gtk::Stack, + back_button: gtk::Button, + show_title: gtk::Label, } impl Header { - pub fn new() -> Header { + pub fn new() -> Rc
{ let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/headerbar.ui"); let header: gtk::HeaderBar = builder.get_object("headerbar").unwrap(); @@ -29,29 +31,40 @@ impl Header { let stack: gtk::Stack = builder.get_object("headerbar_stack").unwrap(); let normal_view: gtk::Box = builder.get_object("normal_view").unwrap(); let back_view: gtk::Box = builder.get_object("back_view").unwrap(); + let back_button: gtk::Button = builder.get_object("back_button").unwrap(); + let show_title: gtk::Label = builder.get_object("show_title").unwrap(); + + let stack = stack.clone(); + back_button.connect_clicked(clone!(stack => move |_| { + stack.set_visible_child_name("normal_view"); + })); + switch.set_halign(gtk::Align::Center); switch.show(); stack.add_named(&normal_view, "normal_view"); stack.add_named(&back_view, "back_view"); + stack.set_transition_type(gtk::StackTransitionType::Crossfade); stack.set_visible_child_name("normal_view"); - Header { + Rc::new(Header { container: header, refresh, add_toggle, switch, stack, - } + back_button, + show_title, + }) } - pub fn new_initialized(content: Rc) -> Header { - let header = Header::new(); - header.init(content); - header - } + // pub fn new_initialized(content: Rc) -> Rc
{ + // let header = Header::new(); + // header.init(content); + // header + // } - fn init(&self, content: Rc) { + pub fn init(&self, content: Rc) { let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/headerbar.ui"); let add_popover: gtk::Popover = builder.get_object("add-popover").unwrap(); @@ -73,9 +86,28 @@ impl Header { self.add_toggle.set_popover(&add_popover); // FIXME: There appears to be a memmory leak here. - self.refresh.connect_clicked(move |_| { + self.refresh.connect_clicked(clone!(content => move |_| { utils::refresh_feed(content.clone(), None, None); - }); + })); + + let stack = self.stack.clone(); + self.back_button + .connect_clicked(clone!(content => move |_| { + content.shows.stack.set_visible_child_full("podcasts", gtk::StackTransitionType::SlideLeft); + stack.set_visible_child_name("normal_view") + })); + } + + pub fn switch_to_normal(&self) { + self.stack.set_visible_child_name("normal_view") + } + + pub fn switch_to_back(&self) { + self.stack.set_visible_child_name("back_view") + } + + pub fn set_show_title(&self, title: &str) { + self.show_title.set_text(title) } } diff --git a/hammond-gtk/src/main.rs b/hammond-gtk/src/main.rs index 77bd430..0c594b9 100644 --- a/hammond-gtk/src/main.rs +++ b/hammond-gtk/src/main.rs @@ -70,9 +70,13 @@ fn build_ui(app: >k::Application) { // let stack = ct.get_stack(); // let ct = content::Content::new_initialized(); - let ct = content::Content::new(); - let stack = ct.stack.clone(); - window.add(&stack); + + // Get the headerbar + let header = headerbar::Header::new(); + let ct = content::Content::new(header.clone()); + header.init(ct.clone()); + window.set_titlebar(&header.container); + window.add(&ct.get_stack()); window.connect_delete_event(|w, _| { w.destroy(); @@ -105,10 +109,6 @@ fn build_ui(app: >k::Application) { glib::Continue(false) }); - // Get the headerbar - let header = headerbar::Header::new_initialized(ct.clone()); - window.set_titlebar(&header.container); - window.show_all(); window.activate(); app.connect_activate(move |_| ()); diff --git a/hammond-gtk/src/views/shows.rs b/hammond-gtk/src/views/shows.rs index 8e7b802..affbb15 100644 --- a/hammond-gtk/src/views/shows.rs +++ b/hammond-gtk/src/views/shows.rs @@ -8,6 +8,7 @@ use hammond_data::Podcast; use utils::get_pixbuf_from_path; use content::ShowStack; +use headerbar::Header; use std::rc::Rc; @@ -43,13 +44,13 @@ impl ShowsPopulated { } #[allow(dead_code)] - pub fn new_initialized(show: Rc) -> ShowsPopulated { + pub fn new_initialized(show: Rc, header: Rc
) -> ShowsPopulated { let pop = ShowsPopulated::new(); - pop.init(show); + pop.init(show, header); pop } - pub fn init(&self, show: Rc) { + pub fn init(&self, show: Rc, header: Rc
) { use gtk::WidgetExt; // TODO: handle unwraps. @@ -61,6 +62,8 @@ impl ShowsPopulated { let pd = dbqueries::get_podcast_from_id(id).unwrap(); show.replace_widget(&pd); + header.set_show_title(pd.title()); + header.switch_to_back(); show.switch_widget_animated(); })); // Populate the flowbox with the Podcasts. diff --git a/hammond-gtk/src/widgets/show.rs b/hammond-gtk/src/widgets/show.rs index 1adcc3d..99da2b8 100644 --- a/hammond-gtk/src/widgets/show.rs +++ b/hammond-gtk/src/widgets/show.rs @@ -11,6 +11,8 @@ use hammond_downloader::downloader; use widgets::episode::episodes_listbox; use utils::get_pixbuf_from_path; use content::ShowStack; +use headerbar::Header; + use std::rc::Rc; #[derive(Debug, Clone)] @@ -48,18 +50,19 @@ impl ShowWidget { } } - pub fn new_initialized(shows: Rc, pd: &Podcast) -> ShowWidget { + pub fn new_initialized(shows: Rc, header: Rc
, pd: &Podcast) -> ShowWidget { let pdw = ShowWidget::new(); - pdw.init(shows, pd); + pdw.init(shows, header, pd); pdw } - pub fn init(&self, shows: Rc, pd: &Podcast) { + pub fn init(&self, shows: Rc, header: Rc
, pd: &Podcast) { WidgetExt::set_name(&self.container, &pd.id().to_string()); // TODO: should spawn a thread to avoid locking the UI probably. self.unsub.connect_clicked(clone!(shows, pd => move |bttn| { on_unsub_button_clicked(shows.clone(), &pd, bttn); + header.switch_to_normal(); })); self.title.set_text(pd.title()); From f0de6bfb1b272a1477769fc8025b71cfba6d711e Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Wed, 13 Dec 2017 17:58:55 +0200 Subject: [PATCH 12/12] Use symbolic icons instead. --- hammond-gtk/resources/gtk/episode_widget.ui | 26 ++++++++++----------- hammond-gtk/resources/gtk/headerbar.ui | 6 ++--- hammond-gtk/resources/gtk/show_widget.ui | 8 +++---- 3 files changed, 17 insertions(+), 23 deletions(-) diff --git a/hammond-gtk/resources/gtk/episode_widget.ui b/hammond-gtk/resources/gtk/episode_widget.ui index fdfacf7..6b85d48 100644 --- a/hammond-gtk/resources/gtk/episode_widget.ui +++ b/hammond-gtk/resources/gtk/episode_widget.ui @@ -1,5 +1,5 @@ - + @@ -11,26 +11,23 @@ 5 5 - + + delete_button True True end center - 5 - 5 True False - gtk-media-play - True + edit-delete-symbolic False False - 5 end 0 @@ -49,8 +46,7 @@ True False - gtk-save - True + document-save-symbolic @@ -63,23 +59,25 @@ - - delete_button + True True end center + 5 + 5 True False - gtk-delete + media-playback-start-symbolic False False + 5 end 0 @@ -95,7 +93,7 @@ True False - gtk-undo + edit-undo-symbolic @@ -118,7 +116,7 @@ True False - gtk-apply + object-select-symbolic diff --git a/hammond-gtk/resources/gtk/headerbar.ui b/hammond-gtk/resources/gtk/headerbar.ui index 2c53892..b06d65e 100644 --- a/hammond-gtk/resources/gtk/headerbar.ui +++ b/hammond-gtk/resources/gtk/headerbar.ui @@ -222,8 +222,7 @@ True False - gtk-refresh - True + view-refresh-symbolic
@@ -244,8 +243,7 @@ True False - gtk-add - True + list-add-symbolic 1
diff --git a/hammond-gtk/resources/gtk/show_widget.ui b/hammond-gtk/resources/gtk/show_widget.ui index 0241f05..9fd63c6 100644 --- a/hammond-gtk/resources/gtk/show_widget.ui +++ b/hammond-gtk/resources/gtk/show_widget.ui @@ -1,5 +1,5 @@ - + @@ -35,8 +35,6 @@ 1 1 1 - gtk-missing-image - True False @@ -95,7 +93,7 @@ False Unsubrscribe from this Podcast. Warn: This will delete downloaded content associated with this Podcast. - gtk-delete + edit-delete-symbolic
@@ -118,7 +116,7 @@ Warn: This will delete downloaded content associated with this Podcast. True False - gtk-apply + object-select-symbolic