Prototype of an Episode List widget.
This commit is contained in:
parent
90c252b34e
commit
31ad416c25
@ -7,9 +7,9 @@ use errors::*;
|
|||||||
// TODO: look into how bad-utf8 is handled in rss crate,
|
// TODO: look into how bad-utf8 is handled in rss crate,
|
||||||
// and figure if there is a need for checking before parsing.
|
// and figure if there is a need for checking before parsing.
|
||||||
pub fn parse_podcast(chan: &Channel, source_id: i32) -> Result<models::NewPodcast> {
|
pub fn parse_podcast(chan: &Channel, source_id: i32) -> Result<models::NewPodcast> {
|
||||||
let title = chan.title().to_owned();
|
let title = chan.title().trim().to_owned();
|
||||||
let link = chan.link().to_owned();
|
let link = chan.link().to_owned();
|
||||||
let description = chan.description().to_owned();
|
let description = chan.description().trim().to_owned();
|
||||||
// Some feeds miss baseurl and/or http://
|
// Some feeds miss baseurl and/or http://
|
||||||
// TODO: Sanitize the url,
|
// TODO: Sanitize the url,
|
||||||
// could also be reuse to sanitize the new-url gui entrybox.
|
// could also be reuse to sanitize the new-url gui entrybox.
|
||||||
@ -26,12 +26,12 @@ pub fn parse_podcast(chan: &Channel, source_id: i32) -> Result<models::NewPodcas
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_episode(item: &Item, parent_id: i32) -> Result<models::NewEpisode> {
|
pub fn parse_episode(item: &Item, parent_id: i32) -> Result<models::NewEpisode> {
|
||||||
let title = item.title();
|
let title = item.title().map(|s| s.trim());
|
||||||
let description = item.description();
|
let description = item.description().map(|s| s.trim());
|
||||||
let guid = item.guid().map(|x| x.value());
|
let guid = item.guid().map(|x| x.value().trim());
|
||||||
let local_uri = None;
|
let local_uri = None;
|
||||||
|
|
||||||
let mut uri = item.enclosure().map(|x| x.url());
|
let mut uri = item.enclosure().map(|x| x.url().trim());
|
||||||
if uri == None {
|
if uri == None {
|
||||||
uri = item.link();
|
uri = item.link();
|
||||||
}
|
}
|
||||||
@ -200,10 +200,8 @@ mod tests {
|
|||||||
let channel = Channel::read_from(BufReader::new(file)).unwrap();
|
let channel = Channel::read_from(BufReader::new(file)).unwrap();
|
||||||
|
|
||||||
let firstitem = channel.items().first().unwrap();
|
let firstitem = channel.items().first().unwrap();
|
||||||
let descr = "\n \
|
let descr = "<p>A reporter finds that homes meant to replace New York’s troubled \
|
||||||
<p>A reporter finds that homes meant to replace New York’s troubled \
|
psychiatric hospitals might be just as bad.</p>";
|
||||||
psychiatric hospitals might be just as bad.</p>\
|
|
||||||
\n \n ";
|
|
||||||
let i = parse_episode(&firstitem, 0).unwrap();
|
let i = parse_episode(&firstitem, 0).unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -231,11 +229,9 @@ mod tests {
|
|||||||
|
|
||||||
let second = channel.items().iter().nth(1).unwrap();
|
let second = channel.items().iter().nth(1).unwrap();
|
||||||
let i2 = parse_episode(&second, 0).unwrap();
|
let i2 = parse_episode(&second, 0).unwrap();
|
||||||
let descr2 = "\n \
|
let descr2 = "<p>Jonathan Allen and Amie Parnes didn’t know their \
|
||||||
<p>Jonathan Allen and Amie Parnes didn’t know their \
|
|
||||||
book would be called ‘Shattered,’ or that their extraordinary access would \
|
book would be called ‘Shattered,’ or that their extraordinary access would \
|
||||||
let them chronicle the mounting signs of a doomed campaign.</p>\
|
let them chronicle the mounting signs of a doomed campaign.</p>";
|
||||||
\n \n ";
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
i2.title,
|
i2.title,
|
||||||
|
|||||||
109
hammond-gtk/gtk/EpisodeWidget.ui
Normal file
109
hammond-gtk/gtk/EpisodeWidget.ui
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Generated with glade 3.20.1 -->
|
||||||
|
<interface>
|
||||||
|
<requires lib="gtk+" version="3.20"/>
|
||||||
|
<object class="GtkBox" id="episode_box">
|
||||||
|
<property name="width_request">100</property>
|
||||||
|
<property name="height_request">25</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="margin_top">5</property>
|
||||||
|
<property name="margin_bottom">5</property>
|
||||||
|
<property name="spacing">5</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="title_label">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="use_markup">True</property>
|
||||||
|
<property name="wrap">True</property>
|
||||||
|
<property name="ellipsize">end</property>
|
||||||
|
<property name="lines">1</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="desc_label">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="use_markup">True</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="wrap">True</property>
|
||||||
|
<property name="ellipsize">end</property>
|
||||||
|
<property name="lines">3</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="padding">5</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="download_button">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="margin_top">5</property>
|
||||||
|
<property name="margin_bottom">5</property>
|
||||||
|
<property name="always_show_image">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="icon_name">gtk-save</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="padding">5</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="play_button">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="margin_top">5</property>
|
||||||
|
<property name="margin_bottom">5</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="icon_name">gtk-media-play</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="padding">5</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</interface>
|
||||||
@ -41,6 +41,7 @@
|
|||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="label" translatable="yes">label</property>
|
<property name="label" translatable="yes">label</property>
|
||||||
|
<property name="use_markup">True</property>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
|
|||||||
@ -9,18 +9,18 @@
|
|||||||
<object class="GtkBox">
|
<object class="GtkBox">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="halign">end</property>
|
<property name="halign">center</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
<property name="margin_left">32</property>
|
<property name="margin_left">32</property>
|
||||||
<property name="margin_right">32</property>
|
<property name="margin_right">32</property>
|
||||||
<property name="margin_start">32</property>
|
<property name="margin_start">32</property>
|
||||||
<property name="margin_end">32</property>
|
<property name="margin_end">32</property>
|
||||||
<property name="margin_top">64</property>
|
<property name="margin_top">64</property>
|
||||||
<property name="margin_bottom">32</property>
|
<property name="margin_bottom">32</property>
|
||||||
<property name="vexpand">True</property>
|
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkBox">
|
<object class="GtkBox">
|
||||||
<property name="width_request">100</property>
|
<property name="width_request">50</property>
|
||||||
<property name="height_request">100</property>
|
<property name="height_request">50</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="halign">center</property>
|
<property name="halign">center</property>
|
||||||
@ -52,18 +52,14 @@
|
|||||||
<property name="halign">center</property>
|
<property name="halign">center</property>
|
||||||
<property name="valign">start</property>
|
<property name="valign">start</property>
|
||||||
<property name="orientation">vertical</property>
|
<property name="orientation">vertical</property>
|
||||||
<property name="spacing">3</property>
|
<property name="spacing">2</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkLabel" id="title_label">
|
<object class="GtkLabel" id="title_label">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="halign">center</property>
|
<property name="halign">center</property>
|
||||||
<property name="justify">center</property>
|
<property name="use_markup">True</property>
|
||||||
<property name="ellipsize">middle</property>
|
<property name="ellipsize">end</property>
|
||||||
<attributes>
|
|
||||||
<attribute name="weight" value="bold"/>
|
|
||||||
<attribute name="scale" value="1.2"/>
|
|
||||||
</attributes>
|
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
@ -75,9 +71,12 @@
|
|||||||
<object class="GtkLabel" id="description_label">
|
<object class="GtkLabel" id="description_label">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
|
<property name="use_markup">True</property>
|
||||||
<property name="wrap">True</property>
|
<property name="wrap">True</property>
|
||||||
|
<property name="wrap_mode">word-char</property>
|
||||||
<property name="selectable">True</property>
|
<property name="selectable">True</property>
|
||||||
<property name="ellipsize">end</property>
|
<property name="ellipsize">end</property>
|
||||||
|
<property name="max_width_chars">30</property>
|
||||||
<property name="lines">5</property>
|
<property name="lines">5</property>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
@ -119,8 +118,8 @@
|
|||||||
<property name="width_request">400</property>
|
<property name="width_request">400</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="halign">start</property>
|
|
||||||
<property name="hexpand">True</property>
|
<property name="hexpand">True</property>
|
||||||
|
<property name="vexpand">True</property>
|
||||||
<property name="shadow_type">none</property>
|
<property name="shadow_type">none</property>
|
||||||
<child>
|
<child>
|
||||||
<placeholder/>
|
<placeholder/>
|
||||||
|
|||||||
@ -15,6 +15,7 @@ extern crate loggerv;
|
|||||||
use log::LogLevel;
|
use log::LogLevel;
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
use hammond_data::dbqueries;
|
use hammond_data::dbqueries;
|
||||||
|
use std::rc;
|
||||||
|
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
use gio::ApplicationExt;
|
use gio::ApplicationExt;
|
||||||
@ -73,6 +74,7 @@ fn create_and_fill_list_store(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn podcast_widget(
|
fn podcast_widget(
|
||||||
|
connection: &SqliteConnection,
|
||||||
title: Option<&str>,
|
title: Option<&str>,
|
||||||
description: Option<&str>,
|
description: Option<&str>,
|
||||||
image: Option<Pixbuf>,
|
image: Option<Pixbuf>,
|
||||||
@ -85,9 +87,12 @@ fn podcast_widget(
|
|||||||
let cover: gtk::Image = pd_widget_buidler.get_object("cover").unwrap();
|
let cover: gtk::Image = pd_widget_buidler.get_object("cover").unwrap();
|
||||||
let title_label: gtk::Label = pd_widget_buidler.get_object("title_label").unwrap();
|
let title_label: gtk::Label = pd_widget_buidler.get_object("title_label").unwrap();
|
||||||
let desc_label: gtk::Label = pd_widget_buidler.get_object("description_label").unwrap();
|
let desc_label: gtk::Label = pd_widget_buidler.get_object("description_label").unwrap();
|
||||||
|
let view: gtk::Viewport = pd_widget_buidler.get_object("view").unwrap();
|
||||||
|
|
||||||
if let Some(t) = title {
|
if let Some(t) = title {
|
||||||
title_label.set_text(t);
|
title_label.set_text(t);
|
||||||
|
let listbox = episodes_listbox(connection, t);
|
||||||
|
view.add(&listbox);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(d) = description {
|
if let Some(d) = description {
|
||||||
@ -102,6 +107,50 @@ fn podcast_widget(
|
|||||||
pd_widget
|
pd_widget
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn epidose_widget(title: Option<&str>, description: Option<&str>) -> gtk::Box {
|
||||||
|
// This is just a prototype and will be reworked probably.
|
||||||
|
let builder = include_str!("../gtk/EpisodeWidget.ui");
|
||||||
|
let builder = gtk::Builder::new_from_string(builder);
|
||||||
|
|
||||||
|
let ep: gtk::Box = builder.get_object("episode_box").unwrap();
|
||||||
|
let _dl_button: gtk::Button = builder.get_object("download_button").unwrap();
|
||||||
|
let _play_button: gtk::Button = builder.get_object("play_button").unwrap();
|
||||||
|
|
||||||
|
let title_label: gtk::Label = builder.get_object("title_label").unwrap();
|
||||||
|
let desc_label: gtk::Label = builder.get_object("desc_label").unwrap();
|
||||||
|
|
||||||
|
title_label.set_xalign(0.0);
|
||||||
|
desc_label.set_xalign(0.0);
|
||||||
|
|
||||||
|
if let Some(t) = title {
|
||||||
|
title_label.set_text(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(d) = description {
|
||||||
|
desc_label.set_text(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
ep
|
||||||
|
}
|
||||||
|
|
||||||
|
fn episodes_listbox(connection: &SqliteConnection, pd_title: &str) -> gtk::ListBox {
|
||||||
|
let pd = dbqueries::load_podcast(connection, pd_title).unwrap();
|
||||||
|
let episodes = dbqueries::get_pd_episodes(connection, &pd).unwrap();
|
||||||
|
|
||||||
|
let list = gtk::ListBox::new();
|
||||||
|
episodes.iter().for_each(|ep| {
|
||||||
|
let w = epidose_widget(ep.title(), ep.description());
|
||||||
|
list.add(&w)
|
||||||
|
});
|
||||||
|
|
||||||
|
list.set_vexpand(true);
|
||||||
|
list.set_hexpand(true);
|
||||||
|
list.set_visible(true);
|
||||||
|
list
|
||||||
|
}
|
||||||
|
|
||||||
|
// I am sorry about the spaghetti code.
|
||||||
|
// Gonna clean it up when the GUI is a bit usuable.
|
||||||
fn build_ui() {
|
fn build_ui() {
|
||||||
let glade_src = include_str!("../gtk/foo.ui");
|
let glade_src = include_str!("../gtk/foo.ui");
|
||||||
let header_src = include_str!("../gtk/headerbar.ui");
|
let header_src = include_str!("../gtk/headerbar.ui");
|
||||||
@ -113,7 +162,8 @@ fn build_ui() {
|
|||||||
// Get the Stack
|
// Get the Stack
|
||||||
let stack: gtk::Stack = builder.get_object("stack1").unwrap();
|
let stack: gtk::Stack = builder.get_object("stack1").unwrap();
|
||||||
|
|
||||||
let pd_widget = podcast_widget(None, None, None);
|
let db = hammond_data::establish_connection();
|
||||||
|
let pd_widget = podcast_widget(&db, None, None, None);
|
||||||
stack.add_named(&pd_widget, "pdw");
|
stack.add_named(&pd_widget, "pdw");
|
||||||
// Get the headerbar
|
// Get the headerbar
|
||||||
let header: gtk::HeaderBar = header_build.get_object("headerbar1").unwrap();
|
let header: gtk::HeaderBar = header_build.get_object("headerbar1").unwrap();
|
||||||
@ -166,11 +216,11 @@ fn build_ui() {
|
|||||||
hammond_data::index_feed::index_loop(db, false).unwrap();
|
hammond_data::index_feed::index_loop(db, false).unwrap();
|
||||||
});
|
});
|
||||||
|
|
||||||
let db = hammond_data::establish_connection();
|
|
||||||
// let pd_model = create_and_fill_tree_store(&db, &builder);
|
// let pd_model = create_and_fill_tree_store(&db, &builder);
|
||||||
let pd_model = create_and_fill_list_store(&db, &builder);
|
let pd_model = create_and_fill_list_store(&db, &builder);
|
||||||
|
|
||||||
let iter = pd_model.get_iter_first().unwrap();
|
let iter = pd_model.get_iter_first().unwrap();
|
||||||
|
let db = rc::Rc::new(db);
|
||||||
// this will iterate over the episodes.
|
// this will iterate over the episodes.
|
||||||
// let iter = pd_model.iter_children(&iter).unwrap();
|
// let iter = pd_model.iter_children(&iter).unwrap();
|
||||||
loop {
|
loop {
|
||||||
@ -191,10 +241,12 @@ fn build_ui() {
|
|||||||
|
|
||||||
let f = create_flowbox_child(&title, pixbuf.clone());
|
let f = create_flowbox_child(&title, pixbuf.clone());
|
||||||
let stack_clone = stack.clone();
|
let stack_clone = stack.clone();
|
||||||
|
let db_clone = db.clone();
|
||||||
f.connect_activate(move |_| {
|
f.connect_activate(move |_| {
|
||||||
let pdw = stack_clone.get_child_by_name("pdw").unwrap();
|
let pdw = stack_clone.get_child_by_name("pdw").unwrap();
|
||||||
stack_clone.remove(&pdw);
|
stack_clone.remove(&pdw);
|
||||||
let pdw = podcast_widget(
|
let pdw = podcast_widget(
|
||||||
|
&db_clone,
|
||||||
Some(title.as_str()),
|
Some(title.as_str()),
|
||||||
Some(description.as_str()),
|
Some(description.as_str()),
|
||||||
pixbuf.clone(),
|
pixbuf.clone(),
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user