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.
This commit is contained in:
parent
211b36dfa3
commit
01310ee7fa
@ -1,318 +1,167 @@
|
|||||||
use gtk;
|
use gtk;
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
|
|
||||||
// use hammond_data::Podcast;
|
use hammond_data::Podcast;
|
||||||
use hammond_data::dbqueries;
|
use hammond_data::dbqueries;
|
||||||
|
|
||||||
use widgets::podcast::PodcastWidget;
|
|
||||||
use views::podcasts::PopulatedView;
|
use views::podcasts::PopulatedView;
|
||||||
use views::empty::EmptyView;
|
use views::empty::EmptyView;
|
||||||
|
use widgets::podcast::PodcastWidget;
|
||||||
|
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Content {
|
pub struct Content {
|
||||||
pub stack: gtk::Stack,
|
pub stack: gtk::Stack,
|
||||||
shows: ShowStateWrapper,
|
shows: Rc<ShowStack>,
|
||||||
episodes: EpisodeStateWrapper,
|
episodes: Rc<EpisodeStack>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Content {
|
impl Content {
|
||||||
pub fn new() -> Content {
|
pub fn new() -> Rc<Content> {
|
||||||
let stack = gtk::Stack::new();
|
let stack = gtk::Stack::new();
|
||||||
let shows = ShowStateWrapper::new();
|
let shows = ShowStack::new();
|
||||||
let episodes = EpisodeStateWrapper::new();
|
let episodes = EpisodeStack::new();
|
||||||
|
|
||||||
let shows_stack = shows.get_stack();
|
stack.add_titled(&episodes.stack, "episodes", "Episodes");
|
||||||
let ep_stack = episodes.get_stack();
|
stack.add_titled(&shows.stack, "shows", "Shows");
|
||||||
|
|
||||||
stack.add_titled(&ep_stack, "episodes", "Episodes");
|
Rc::new(Content {
|
||||||
stack.add_titled(&shows_stack, "shows", "Shows");
|
|
||||||
|
|
||||||
Content {
|
|
||||||
stack,
|
stack,
|
||||||
shows,
|
shows,
|
||||||
episodes,
|
episodes,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&mut self) {
|
pub fn update(&self) {
|
||||||
self.shows = self.shows.clone().update();
|
self.shows.update();
|
||||||
// FIXME: like above
|
|
||||||
self.episodes.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)]
|
#[derive(Debug, Clone)]
|
||||||
struct Populated;
|
pub struct ShowStack {
|
||||||
#[derive(Debug, Clone)]
|
pub stack: gtk::Stack,
|
||||||
struct Empty;
|
|
||||||
// struct Shows;
|
|
||||||
// struct Episodes;
|
|
||||||
|
|
||||||
// Thats probably too overengineered
|
|
||||||
// struct StackStateMachine<S, T> {
|
|
||||||
// shows: ShowsMachine<S>,
|
|
||||||
// episodes: EpisodesMachine<S>,
|
|
||||||
// stack: gtk::Stack,
|
|
||||||
// state: T,
|
|
||||||
// }
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
struct ShowsMachine<S> {
|
|
||||||
populated: ShowsPopulated,
|
|
||||||
empty: ShowsEmpty,
|
|
||||||
stack: gtk::Stack,
|
|
||||||
state: S,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> ShowsMachine<S> {
|
impl ShowStack {
|
||||||
fn new(state: S) -> ShowsMachine<S> {
|
fn new() -> Rc<ShowStack> {
|
||||||
let stack = gtk::Stack::new();
|
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();
|
let empty = EmptyView::new();
|
||||||
stack.add_named(&pop.container, "populated");
|
|
||||||
stack.add_named(&empty.container, "empty");
|
|
||||||
|
|
||||||
ShowsMachine {
|
show.stack.add_named(&pop.container, "podcasts");
|
||||||
empty,
|
show.stack.add_named(&widget.container, "widget");
|
||||||
populated: pop,
|
show.stack.add_named(&empty.container, "empty");
|
||||||
stack,
|
|
||||||
state,
|
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 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.remove(&old);
|
||||||
|
self.stack.add_named(&pop.container, "podcasts");
|
||||||
|
|
||||||
let pop = ShowsPopulated::new_initialized();
|
if pop.is_empty() {
|
||||||
self.populated = pop;
|
self.stack.set_visible_child_name("empty");
|
||||||
self.stack.add_named(&self.populated.container, "populated");
|
} else if vis != "empty" {
|
||||||
self.stack.set_visible_child_name(&vis);
|
self.stack.set_visible_child_name(&vis);
|
||||||
|
} else {
|
||||||
|
self.stack.set_visible_child_name("podcasts");
|
||||||
|
}
|
||||||
|
|
||||||
|
old.destroy();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
pub fn replace_widget(&self, pd: &Podcast) {
|
||||||
struct EpisodesMachine<S> {
|
let old = self.stack.get_child_by_name("widget").unwrap();
|
||||||
populated: EpisodesPopulated,
|
let new = PodcastWidget::new_initialized(Rc::new(self.clone()), pd);
|
||||||
empty: EpisodesEmpty,
|
|
||||||
stack: gtk::Stack,
|
|
||||||
state: S,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S> EpisodesMachine<S> {
|
self.stack.remove(&old);
|
||||||
// FIXME:
|
self.stack.add_named(&new.container, "widget");
|
||||||
fn update(&mut self) {
|
}
|
||||||
|
|
||||||
|
pub fn update_widget(&self) {
|
||||||
let vis = self.stack.get_visible_child_name().unwrap();
|
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();
|
let id = WidgetExt::get_name(&old).unwrap();
|
||||||
if id == "GtkBox" {
|
if id == "GtkBox" {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let pd = dbqueries::get_podcast_from_id(id.parse::<i32>().unwrap()).unwrap();
|
|
||||||
let pdw = EpisodesPopulated::new_initialized(&self.stack, &pd);
|
|
||||||
|
|
||||||
self.populated = pdw;
|
let pd = dbqueries::get_podcast_from_id(id.parse::<i32>().unwrap());
|
||||||
self.stack.remove(&old);
|
if let Ok(pd) = pd {
|
||||||
self.stack.add_named(&self.populated.container, "populated");
|
self.replace_widget(&pd);
|
||||||
self.stack.set_visible_child_name(&vis);
|
self.stack.set_visible_child_name(&vis);
|
||||||
}
|
old.destroy();
|
||||||
}
|
|
||||||
|
|
||||||
// impl Into<StackStateMachine<Populated, Shows>> for StackStateMachine<Populated, Episodes> {
|
|
||||||
// fn into(self) -> StackStateMachine<Populated, Shows> {
|
|
||||||
// self.stack.set_visible_child_name("shows");
|
|
||||||
|
|
||||||
// StackStateMachine {
|
|
||||||
// shows: self.shows,
|
|
||||||
// episodes: self.episodes,
|
|
||||||
// stack: self.stack,
|
|
||||||
// state: Shows {},
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// impl Into<StackStateMachine<Populated, Episodes>> for StackStateMachine<Populated, Shows> {
|
|
||||||
// fn into(self) -> StackStateMachine<Populated, Episodes> {
|
|
||||||
// self.stack.set_visible_child_name("episodes");
|
|
||||||
|
|
||||||
// StackStateMachine {
|
|
||||||
// shows: self.shows,
|
|
||||||
// episodes: self.episodes,
|
|
||||||
// stack: self.stack,
|
|
||||||
// state: Episodes {},
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TODO: Impl <From> instead of <Into>
|
|
||||||
impl Into<ShowsMachine<Populated>> for ShowsMachine<Empty> {
|
|
||||||
fn into(self) -> ShowsMachine<Populated> {
|
|
||||||
self.stack.set_visible_child_name("populated");
|
|
||||||
|
|
||||||
ShowsMachine {
|
|
||||||
populated: self.populated,
|
|
||||||
empty: self.empty,
|
|
||||||
stack: self.stack,
|
|
||||||
state: Populated {},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<ShowsMachine<Empty>> for ShowsMachine<Populated> {
|
pub fn switch_podcasts_animated(&self) {
|
||||||
fn into(self) -> ShowsMachine<Empty> {
|
self.stack
|
||||||
self.stack.set_visible_child_name("empty");
|
.set_visible_child_full("podcasts", gtk::StackTransitionType::SlideRight);
|
||||||
|
|
||||||
ShowsMachine {
|
|
||||||
populated: self.populated,
|
|
||||||
empty: self.empty,
|
|
||||||
stack: self.stack,
|
|
||||||
state: Empty {},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<EpisodesMachine<Populated>> for EpisodesMachine<Empty> {
|
pub fn switch_widget_animated(&self) {
|
||||||
fn into(self) -> EpisodesMachine<Populated> {
|
self.stack
|
||||||
self.stack.set_visible_child_name("populated");
|
.set_visible_child_full("widget", gtk::StackTransitionType::SlideLeft)
|
||||||
|
|
||||||
EpisodesMachine {
|
|
||||||
populated: self.populated,
|
|
||||||
empty: self.empty,
|
|
||||||
stack: self.stack,
|
|
||||||
state: Populated {},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<EpisodesMachine<Empty>> for EpisodesMachine<Populated> {
|
|
||||||
fn into(self) -> EpisodesMachine<Empty> {
|
|
||||||
self.stack.set_visible_child_name("empty");
|
|
||||||
|
|
||||||
EpisodesMachine {
|
|
||||||
populated: self.populated,
|
|
||||||
empty: self.empty,
|
|
||||||
stack: self.stack,
|
|
||||||
state: Empty {},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// enum StackStateWrapper<S> {
|
|
||||||
// Shows(StackStateMachine<S, Shows>),
|
|
||||||
// Episodes(StackStateMachine<S, Episodes>),
|
|
||||||
// }
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
enum ShowStateWrapper {
|
|
||||||
Populated(ShowsMachine<Populated>),
|
|
||||||
Empty(ShowsMachine<Empty>),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
enum EpisodeStateWrapper {
|
struct RecentEpisodes;
|
||||||
Populated(EpisodesMachine<Populated>),
|
|
||||||
Empty(EpisodesMachine<Empty>),
|
#[derive(Debug, Clone)]
|
||||||
|
struct EpisodeStack {
|
||||||
|
// populated: RecentEpisodes,
|
||||||
|
// empty: EmptyView,
|
||||||
|
stack: gtk::Stack,
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl <S>StackStateWrapper<S> {
|
impl EpisodeStack {
|
||||||
// fn switch(mut self) -> Self {
|
fn new() -> Rc<EpisodeStack> {
|
||||||
// match self {
|
let _pop = RecentEpisodes {};
|
||||||
// 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();
|
|
||||||
let empty = EmptyView::new();
|
let empty = EmptyView::new();
|
||||||
let stack = gtk::Stack::new();
|
let stack = gtk::Stack::new();
|
||||||
|
|
||||||
stack.add_named(&pop.container, "populated");
|
// stack.add_named(&pop.container, "populated");
|
||||||
stack.add_named(&empty.container, "empty");
|
stack.add_named(&empty.container, "empty");
|
||||||
|
// FIXME:
|
||||||
stack.set_visible_child_name("empty");
|
stack.set_visible_child_name("empty");
|
||||||
|
|
||||||
EpisodeStateWrapper::Empty(EpisodesMachine {
|
Rc::new(EpisodeStack {
|
||||||
empty,
|
// empty,
|
||||||
populated: pop,
|
// populated: pop,
|
||||||
stack,
|
stack,
|
||||||
state: Empty {},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self) {
|
fn update(&self) {
|
||||||
match *self {
|
// unimplemented!()
|
||||||
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(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,7 @@ use gtk::prelude::*;
|
|||||||
use hammond_data::Source;
|
use hammond_data::Source;
|
||||||
use hammond_data::utils::url_cleaner;
|
use hammond_data::utils::url_cleaner;
|
||||||
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::rc::Rc;
|
||||||
|
|
||||||
use utils;
|
use utils;
|
||||||
use content::Content;
|
use content::Content;
|
||||||
@ -36,23 +36,19 @@ impl Header {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_initialized(content: Arc<Mutex<Content>>) -> Header {
|
pub fn new_initialized(content: Rc<Content>) -> Header {
|
||||||
let header = Header::new();
|
let header = Header::new();
|
||||||
header.init(content);
|
header.init(content);
|
||||||
header
|
header
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init(&self, content: Arc<Mutex<Content>>) {
|
fn init(&self, content: Rc<Content>) {
|
||||||
let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/headerbar.ui");
|
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 add_popover: gtk::Popover = builder.get_object("add-popover").unwrap();
|
||||||
let new_url: gtk::Entry = builder.get_object("new-url").unwrap();
|
let new_url: gtk::Entry = builder.get_object("new-url").unwrap();
|
||||||
let add_button: gtk::Button = builder.get_object("add-button").unwrap();
|
let add_button: gtk::Button = builder.get_object("add-button").unwrap();
|
||||||
|
self.switch.set_stack(&content.stack);
|
||||||
{
|
|
||||||
let cont = content.lock().unwrap();
|
|
||||||
self.switch.set_stack(&cont.stack);
|
|
||||||
}
|
|
||||||
|
|
||||||
new_url.connect_changed(move |url| {
|
new_url.connect_changed(move |url| {
|
||||||
println!("{:?}", url.get_text());
|
println!("{:?}", url.get_text());
|
||||||
@ -68,14 +64,13 @@ impl Header {
|
|||||||
self.add_toggle.set_popover(&add_popover);
|
self.add_toggle.set_popover(&add_popover);
|
||||||
|
|
||||||
// FIXME: There appears to be a memmory leak here.
|
// FIXME: There appears to be a memmory leak here.
|
||||||
let cont = content.clone();
|
|
||||||
self.refresh.connect_clicked(move |_| {
|
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<Mutex<Content>>, entry: >k::Entry) {
|
fn on_add_bttn_clicked(content: Rc<Content>, entry: >k::Entry) {
|
||||||
let url = entry.get_text().unwrap_or_default();
|
let url = entry.get_text().unwrap_or_default();
|
||||||
let url = url_cleaner(&url);
|
let url = url_cleaner(&url);
|
||||||
let source = Source::from_url(&url);
|
let source = Source::from_url(&url);
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
#![cfg_attr(feature = "cargo-clippy", allow(clone_on_ref_ptr))]
|
||||||
|
|
||||||
extern crate gdk;
|
extern crate gdk;
|
||||||
extern crate gdk_pixbuf;
|
extern crate gdk_pixbuf;
|
||||||
extern crate gio;
|
extern crate gio;
|
||||||
@ -22,8 +24,6 @@ use hammond_data::utils::checkup;
|
|||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
use gio::{ActionMapExt, ApplicationExt, MenuExt, SimpleActionExt};
|
use gio::{ActionMapExt, ApplicationExt, MenuExt, SimpleActionExt};
|
||||||
|
|
||||||
use std::sync::{Arc, Mutex};
|
|
||||||
|
|
||||||
// http://gtk-rs.org/tuto/closures
|
// http://gtk-rs.org/tuto/closures
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! clone {
|
macro_rules! clone {
|
||||||
@ -72,7 +72,6 @@ fn build_ui(app: >k::Application) {
|
|||||||
// let ct = content::Content::new_initialized();
|
// let ct = content::Content::new_initialized();
|
||||||
let ct = content::Content::new();
|
let ct = content::Content::new();
|
||||||
let stack = ct.stack.clone();
|
let stack = ct.stack.clone();
|
||||||
let ct = Arc::new(Mutex::new(ct));
|
|
||||||
window.add(&stack);
|
window.add(&stack);
|
||||||
|
|
||||||
window.connect_delete_event(|w, _| {
|
window.connect_delete_event(|w, _| {
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
use glib;
|
use glib;
|
||||||
use gtk;
|
|
||||||
use gdk_pixbuf::Pixbuf;
|
use gdk_pixbuf::Pixbuf;
|
||||||
|
|
||||||
use hammond_data::feed;
|
use hammond_data::feed;
|
||||||
@ -9,14 +8,12 @@ use hammond_downloader::downloader;
|
|||||||
use std::{thread, time};
|
use std::{thread, time};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::sync::mpsc::{channel, Receiver};
|
use std::sync::mpsc::{channel, Receiver};
|
||||||
use std::borrow::Cow;
|
|
||||||
|
|
||||||
use content::Content;
|
use content::Content;
|
||||||
use regex::Regex;
|
|
||||||
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::rc::Rc;
|
||||||
|
|
||||||
type Foo = RefCell<Option<(Arc<Mutex<Content>>, Receiver<bool>)>>;
|
type Foo = RefCell<Option<(Rc<Content>, Receiver<bool>)>>;
|
||||||
|
|
||||||
// Create a thread local storage that will store the arguments to be transfered.
|
// Create a thread local storage that will store the arguments to be transfered.
|
||||||
thread_local!(static GLOBAL: Foo = RefCell::new(None));
|
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.
|
/// 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.
|
/// `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.
|
/// When It's done,it queues up a `podcast_view` refresh.
|
||||||
pub fn refresh_feed(content: Arc<Mutex<Content>>, source: Option<Vec<Source>>, delay: Option<u64>) {
|
pub fn refresh_feed(content: Rc<Content>, source: Option<Vec<Source>>, delay: Option<u64>) {
|
||||||
// Create a async channel.
|
// Create a async channel.
|
||||||
let (sender, receiver) = channel();
|
let (sender, receiver) = channel();
|
||||||
|
|
||||||
// Pass the desired arguments into the Local Thread Storage.
|
// Pass the desired arguments into the Local Thread Storage.
|
||||||
GLOBAL.with(clone!(content => move |global| {
|
GLOBAL.with(clone!(content => move |global| {
|
||||||
*global.borrow_mut() = Some((content, receiver));
|
*global.borrow_mut() = Some((content.clone(), receiver));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
@ -61,7 +58,6 @@ fn refresh_podcasts_view() -> glib::Continue {
|
|||||||
GLOBAL.with(|global| {
|
GLOBAL.with(|global| {
|
||||||
if let Some((ref content, ref reciever)) = *global.borrow() {
|
if let Some((ref content, ref reciever)) = *global.borrow() {
|
||||||
if reciever.try_recv().is_ok() {
|
if reciever.try_recv().is_ok() {
|
||||||
let mut content = content.lock().unwrap();
|
|
||||||
content.update();
|
content.update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -74,18 +70,6 @@ pub fn get_pixbuf_from_path(pd: &Podcast) -> Option<Pixbuf> {
|
|||||||
Pixbuf::new_from_file_at_scale(&img_path, 256, 256, true).ok()
|
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<str> {
|
|
||||||
s.trim();
|
|
||||||
s.replace('&', "&");
|
|
||||||
s.replace('<', "<");
|
|
||||||
s.replace('>', ">");
|
|
||||||
|
|
||||||
let re = Regex::new("(?P<url>https?://[^\\s&,)(\"]+(&\\w=[\\w._-]?)*(#[\\w._-]+)?)").unwrap();
|
|
||||||
re.replace_all(s, "<a href=\"$url\">$url</a>")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use hammond_data::Source;
|
use hammond_data::Source;
|
||||||
|
|||||||
@ -7,8 +7,9 @@ use hammond_data::dbqueries;
|
|||||||
use hammond_data::Podcast;
|
use hammond_data::Podcast;
|
||||||
|
|
||||||
use utils::get_pixbuf_from_path;
|
use utils::get_pixbuf_from_path;
|
||||||
|
use content::ShowStack;
|
||||||
|
|
||||||
// use content;
|
use std::rc::Rc;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct PopulatedView {
|
pub struct PopulatedView {
|
||||||
@ -42,25 +43,29 @@ impl PopulatedView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn new_initialized() -> PopulatedView {
|
pub fn new_initialized(show: Rc<ShowStack>) -> PopulatedView {
|
||||||
let pop = PopulatedView::new();
|
let pop = PopulatedView::new();
|
||||||
pop.init();
|
pop.init(show);
|
||||||
pop
|
pop
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(&self) {
|
pub fn init(&self, show: Rc<ShowStack>) {
|
||||||
// pub fn init(&self, stack: >k::Stack) {
|
use gtk::WidgetExt;
|
||||||
// use gtk::WidgetExt;
|
|
||||||
|
|
||||||
// // TODO: handle unwraps.
|
// TODO: handle unwraps.
|
||||||
// self.flowbox
|
// Note: flowbox_activation always adds "widnget" into the stack and switch to it,
|
||||||
// .connect_child_activated(clone!(stack => move |_, child| {
|
// TODO: implement back button.
|
||||||
// // This is such an ugly hack...
|
// so back button should always remove "widget" and destroy it.
|
||||||
// // let id = child.get_name().unwrap().parse::<i32>().unwrap();
|
let show = show.clone();
|
||||||
// let id = WidgetExt::get_name(child).unwrap().parse::<i32>().unwrap();
|
self.flowbox
|
||||||
// let parent = dbqueries::get_podcast_from_id(id).unwrap();
|
.connect_child_activated(clone!(show => move |_, child| {
|
||||||
// on_flowbox_child_activate(&stack, &parent);
|
// This is such an ugly hack...
|
||||||
// }));
|
let id = WidgetExt::get_name(child).unwrap().parse::<i32>().unwrap();
|
||||||
|
let pd = dbqueries::get_podcast_from_id(id).unwrap();
|
||||||
|
|
||||||
|
show.replace_widget(&pd);
|
||||||
|
show.switch_widget_animated();
|
||||||
|
}));
|
||||||
// Populate the flowbox with the Podcasts.
|
// Populate the flowbox with the Podcasts.
|
||||||
self.populate_flowbox();
|
self.populate_flowbox();
|
||||||
}
|
}
|
||||||
@ -76,6 +81,10 @@ impl PopulatedView {
|
|||||||
self.flowbox.show_all();
|
self.flowbox.show_all();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.flowbox.get_children().is_empty()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PodcastChild {
|
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)
|
|
||||||
// }
|
|
||||||
|
|||||||
@ -10,7 +10,8 @@ use hammond_downloader::downloader;
|
|||||||
|
|
||||||
use widgets::episode::episodes_listbox;
|
use widgets::episode::episodes_listbox;
|
||||||
use utils::get_pixbuf_from_path;
|
use utils::get_pixbuf_from_path;
|
||||||
// use content;
|
use content::ShowStack;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct PodcastWidget {
|
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<ShowStack>, pd: &Podcast) -> PodcastWidget {
|
||||||
let pdw = PodcastWidget::new();
|
let pdw = PodcastWidget::new();
|
||||||
pdw.init(stack, pd);
|
pdw.init(shows, pd);
|
||||||
pdw
|
pdw
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(&self, stack: >k::Stack, pd: &Podcast) {
|
pub fn init(&self, shows: Rc<ShowStack>, pd: &Podcast) {
|
||||||
WidgetExt::set_name(&self.container, &pd.id().to_string());
|
WidgetExt::set_name(&self.container, &pd.id().to_string());
|
||||||
|
|
||||||
// TODO: should spawn a thread to avoid locking the UI probably.
|
// TODO: should spawn a thread to avoid locking the UI probably.
|
||||||
self.unsub.connect_clicked(clone!(stack, pd => move |bttn| {
|
self.unsub.connect_clicked(clone!(shows, pd => move |bttn| {
|
||||||
on_unsub_button_clicked(&stack, &pd, bttn);
|
on_unsub_button_clicked(shows.clone(), &pd, bttn);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
self.title.set_text(pd.title());
|
self.title.set_text(pd.title());
|
||||||
@ -77,8 +78,8 @@ impl PodcastWidget {
|
|||||||
self.cover.set_from_pixbuf(&i);
|
self.cover.set_from_pixbuf(&i);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.played.connect_clicked(clone!(stack, pd => move |_| {
|
self.played.connect_clicked(clone!(shows, pd => move |_| {
|
||||||
on_played_button_clicked(&stack, &pd);
|
on_played_button_clicked(shows.clone(), &pd);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
self.show_played_button(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<ShowStack>, pd: &Podcast, unsub_button: >k::Button) {
|
||||||
let res = dbqueries::remove_feed(pd);
|
let res = dbqueries::remove_feed(pd);
|
||||||
if res.is_ok() {
|
if res.is_ok() {
|
||||||
info!("{} was removed succesfully.", pd.title());
|
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<ShowStack>, pd: &Podcast) {
|
||||||
let _ = dbqueries::update_none_to_played_now(pd);
|
let _ = dbqueries::update_none_to_played_now(pd);
|
||||||
|
|
||||||
// content::update_widget_preserve_vis(stack, pd);
|
shows.update_widget();
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user