Merge branch 'episode_widget_redisgn' into 'master'
Episode widget redisgn See merge request alatiera/Hammond!5
This commit is contained in:
commit
6284c8828b
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -601,6 +601,7 @@ dependencies = [
|
|||||||
name = "hammond-gtk"
|
name = "hammond-gtk"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"diesel 0.99.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"diesel 0.99.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"dissolve 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"dissolve 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"gdk 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"gdk 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
use diesel;
|
use diesel;
|
||||||
use models::queryables::{Episode, Podcast, Source};
|
use models::queryables::{Episode, EpisodeWidgetQuery, Podcast, Source};
|
||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
use errors::*;
|
use errors::*;
|
||||||
|
|
||||||
@ -103,6 +103,21 @@ pub fn get_pd_episodes(parent: &Podcast) -> Result<Vec<Episode>> {
|
|||||||
.load::<Episode>(&*con)?)
|
.load::<Episode>(&*con)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_pd_episodeswidgets(parent: &Podcast) -> Result<Vec<EpisodeWidgetQuery>> {
|
||||||
|
use schema::episode::dsl::*;
|
||||||
|
|
||||||
|
let db = connection();
|
||||||
|
let con = db.get()?;
|
||||||
|
|
||||||
|
Ok(
|
||||||
|
episode.select((rowid, title, uri, local_uri, epoch, length, played, podcast_id))
|
||||||
|
.filter(podcast_id.eq(parent.id()))
|
||||||
|
// .group_by(epoch)
|
||||||
|
.order(epoch.desc())
|
||||||
|
.load::<EpisodeWidgetQuery>(&*con)?,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_pd_unplayed_episodes(parent: &Podcast) -> Result<Vec<Episode>> {
|
pub fn get_pd_unplayed_episodes(parent: &Podcast) -> Result<Vec<Episode>> {
|
||||||
use schema::episode::dsl::*;
|
use schema::episode::dsl::*;
|
||||||
|
|
||||||
|
|||||||
@ -61,7 +61,7 @@ pub(crate) mod models;
|
|||||||
mod parser;
|
mod parser;
|
||||||
mod schema;
|
mod schema;
|
||||||
|
|
||||||
pub use models::queryables::{Episode, Podcast, Source};
|
pub use models::queryables::{Episode, EpisodeWidgetQuery, Podcast, Source};
|
||||||
|
|
||||||
/// [XDG Base Direcotory](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html) Paths.
|
/// [XDG Base Direcotory](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html) Paths.
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
|
use diesel::prelude::*;
|
||||||
|
use diesel;
|
||||||
|
|
||||||
use reqwest;
|
use reqwest;
|
||||||
use diesel::SaveChangesDsl;
|
use diesel::SaveChangesDsl;
|
||||||
@ -189,6 +191,135 @@ impl Episode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Queryable, AsChangeset, PartialEq)]
|
||||||
|
#[table_name = "episode"]
|
||||||
|
#[changeset_options(treat_none_as_null = "true")]
|
||||||
|
#[primary_key(title, podcast_id)]
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
/// Diesel Model to be used for constructing `EpisodeWidgets`.
|
||||||
|
pub struct EpisodeWidgetQuery {
|
||||||
|
rowid: i32,
|
||||||
|
title: String,
|
||||||
|
uri: Option<String>,
|
||||||
|
local_uri: Option<String>,
|
||||||
|
epoch: i32,
|
||||||
|
length: Option<i32>,
|
||||||
|
played: Option<i32>,
|
||||||
|
// favorite: bool,
|
||||||
|
// archive: bool,
|
||||||
|
podcast_id: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EpisodeWidgetQuery {
|
||||||
|
/// Get the value of the sqlite's `ROW_ID`
|
||||||
|
pub fn rowid(&self) -> i32 {
|
||||||
|
self.rowid
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the value of the `title` field.
|
||||||
|
pub fn title(&self) -> &str {
|
||||||
|
&self.title
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the value of the `uri`.
|
||||||
|
///
|
||||||
|
/// Represents the url(usually) that the media file will be located at.
|
||||||
|
pub fn uri(&self) -> Option<&str> {
|
||||||
|
self.uri.as_ref().map(|s| s.as_str())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the value of the `local_uri`.
|
||||||
|
///
|
||||||
|
/// Represents the local uri,usually filesystem path,
|
||||||
|
/// that the media file will be located at.
|
||||||
|
pub fn local_uri(&self) -> Option<&str> {
|
||||||
|
self.local_uri.as_ref().map(|s| s.as_str())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the `local_uri`.
|
||||||
|
pub fn set_local_uri(&mut self, value: Option<&str>) {
|
||||||
|
self.local_uri = value.map(|x| x.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the `epoch` value.
|
||||||
|
///
|
||||||
|
/// Retrieved from the rss Item publish date.
|
||||||
|
/// Value is set to Utc whenever possible.
|
||||||
|
pub fn epoch(&self) -> i32 {
|
||||||
|
self.epoch
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the `length`.
|
||||||
|
pub fn length(&self) -> Option<i32> {
|
||||||
|
self.length
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the `length`.
|
||||||
|
pub fn set_length(&mut self, value: Option<i32>) {
|
||||||
|
self.length = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Epoch representation of the last time the episode was played.
|
||||||
|
///
|
||||||
|
/// None/Null for unplayed.
|
||||||
|
pub fn played(&self) -> Option<i32> {
|
||||||
|
self.played
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the `played` value.
|
||||||
|
pub fn set_played(&mut self, value: Option<i32>) {
|
||||||
|
self.played = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// /// Represents the archiving policy for the episode.
|
||||||
|
// pub fn archive(&self) -> bool {
|
||||||
|
// self.archive
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /// Set the `archive` policy.
|
||||||
|
// ///
|
||||||
|
// /// If true, the download cleanr will ignore the episode
|
||||||
|
// /// and the corresponding media value will never be automaticly deleted.
|
||||||
|
// pub fn set_archive(&mut self, b: bool) {
|
||||||
|
// self.archive = b
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /// Get the `favorite` status of the `Episode`.
|
||||||
|
// pub fn favorite(&self) -> bool {
|
||||||
|
// self.favorite
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /// Set `favorite` status.
|
||||||
|
// pub fn set_favorite(&mut self, b: bool) {
|
||||||
|
// self.favorite = b
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// `Podcast` table foreign key.
|
||||||
|
pub fn podcast_id(&self) -> i32 {
|
||||||
|
self.podcast_id
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the `played` value with the current `epoch` timestap and save it.
|
||||||
|
pub fn set_played_now(&mut self) -> Result<()> {
|
||||||
|
let epoch = Utc::now().timestamp() as i32;
|
||||||
|
self.set_played(Some(epoch));
|
||||||
|
self.save()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper method to easily save/"sync" current state of self to the Database.
|
||||||
|
pub fn save(&self) -> Result<usize> {
|
||||||
|
use schema::episode::dsl::*;
|
||||||
|
|
||||||
|
let db = connection();
|
||||||
|
let tempdb = db.get()?;
|
||||||
|
|
||||||
|
Ok(diesel::update(episode.filter(rowid.eq(self.rowid)))
|
||||||
|
.set(self)
|
||||||
|
.execute(&*tempdb)?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Queryable, Identifiable, AsChangeset, Associations, PartialEq)]
|
#[derive(Queryable, Identifiable, AsChangeset, Associations, PartialEq)]
|
||||||
#[belongs_to(Source, foreign_key = "source_id")]
|
#[belongs_to(Source, foreign_key = "source_id")]
|
||||||
#[changeset_options(treat_none_as_null = "true")]
|
#[changeset_options(treat_none_as_null = "true")]
|
||||||
|
|||||||
@ -33,6 +33,7 @@ pub(crate) fn new_podcast(chan: &Channel, source_id: i32) -> NewPodcast {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Parses an `rss::Item` into a `NewEpisode` Struct.
|
/// Parses an `rss::Item` into a `NewEpisode` Struct.
|
||||||
|
// TODO: parse itunes duration extension.
|
||||||
pub(crate) fn new_episode(item: &Item, parent_id: i32) -> Result<NewEpisode> {
|
pub(crate) fn new_episode(item: &Item, parent_id: i32) -> Result<NewEpisode> {
|
||||||
if item.title().is_none() {
|
if item.title().is_none() {
|
||||||
bail!("No title specified for the item.")
|
bail!("No title specified for the item.")
|
||||||
|
|||||||
@ -8,7 +8,7 @@ use std::io::{BufWriter, Read, Write};
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use errors::*;
|
use errors::*;
|
||||||
use hammond_data::{Episode, Podcast};
|
use hammond_data::{Episode, EpisodeWidgetQuery, Podcast};
|
||||||
use hammond_data::xdg_dirs::{DL_DIR, HAMMOND_CACHE};
|
use hammond_data::xdg_dirs::{DL_DIR, HAMMOND_CACHE};
|
||||||
|
|
||||||
// TODO: Replace path that are of type &str with std::path.
|
// TODO: Replace path that are of type &str with std::path.
|
||||||
@ -106,7 +106,7 @@ pub fn get_download_folder(pd_title: &str) -> Result<String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Refactor
|
// TODO: Refactor
|
||||||
pub fn get_episode(ep: &mut Episode, download_folder: &str) -> Result<()> {
|
pub fn get_episode(ep: &mut EpisodeWidgetQuery, download_folder: &str) -> Result<()> {
|
||||||
// Check if its alrdy downloaded
|
// Check if its alrdy downloaded
|
||||||
if ep.local_uri().is_some() {
|
if ep.local_uri().is_some() {
|
||||||
if Path::new(ep.local_uri().unwrap()).exists() {
|
if Path::new(ep.local_uri().unwrap()).exists() {
|
||||||
|
|||||||
@ -6,6 +6,7 @@ version = "0.1.0"
|
|||||||
workspace = "../"
|
workspace = "../"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
chrono = "0.4.0"
|
||||||
dissolve = "0.2.2"
|
dissolve = "0.2.2"
|
||||||
gdk = "0.7.0"
|
gdk = "0.7.0"
|
||||||
gdk-pixbuf = "0.3.0"
|
gdk-pixbuf = "0.3.0"
|
||||||
|
|||||||
@ -2,190 +2,241 @@
|
|||||||
<!-- Generated with glade 3.20.2 -->
|
<!-- Generated with glade 3.20.2 -->
|
||||||
<interface>
|
<interface>
|
||||||
<requires lib="gtk+" version="3.20"/>
|
<requires lib="gtk+" version="3.20"/>
|
||||||
<object class="GtkBox" id="episode_box">
|
<object class="GtkBox" id="episode_container">
|
||||||
<property name="width_request">100</property>
|
|
||||||
<property name="height_request">25</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="margin_top">5</property>
|
<property name="orientation">vertical</property>
|
||||||
<property name="margin_bottom">5</property>
|
|
||||||
<property name="spacing">5</property>
|
<property name="spacing">5</property>
|
||||||
<child>
|
|
||||||
<object class="GtkButton" id="play_button">
|
|
||||||
<property name="can_focus">True</property>
|
|
||||||
<property name="receives_default">True</property>
|
|
||||||
<property name="halign">end</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">media-playback-start-symbolic</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">False</property>
|
|
||||||
<property name="padding">5</property>
|
|
||||||
<property name="pack_type">end</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="halign">end</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">document-save-symbolic</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">False</property>
|
|
||||||
<property name="padding">5</property>
|
|
||||||
<property name="pack_type">end</property>
|
|
||||||
<property name="position">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkButton" id="delete_button">
|
|
||||||
<property name="name">delete_button</property>
|
|
||||||
<property name="can_focus">True</property>
|
|
||||||
<property name="receives_default">True</property>
|
|
||||||
<property name="halign">end</property>
|
|
||||||
<property name="valign">center</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkImage">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">False</property>
|
|
||||||
<property name="icon_name">user-trash-symbolic</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">False</property>
|
|
||||||
<property name="pack_type">end</property>
|
|
||||||
<property name="position">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkButton" id="mark_unplayed_button">
|
|
||||||
<property name="can_focus">True</property>
|
|
||||||
<property name="receives_default">True</property>
|
|
||||||
<property name="tooltip_text" translatable="yes">Mark episode as Unplayed.</property>
|
|
||||||
<property name="halign">end</property>
|
|
||||||
<property name="valign">center</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkImage">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">False</property>
|
|
||||||
<property name="icon_name">edit-undo-symbolic</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">False</property>
|
|
||||||
<property name="pack_type">end</property>
|
|
||||||
<property name="position">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkButton" id="mark_played_button">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">True</property>
|
|
||||||
<property name="receives_default">True</property>
|
|
||||||
<property name="tooltip_text" translatable="yes">Mark episode as played.</property>
|
|
||||||
<property name="halign">end</property>
|
|
||||||
<property name="valign">center</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkImage">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">False</property>
|
|
||||||
<property name="icon_name">object-select-symbolic</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">False</property>
|
|
||||||
<property name="pack_type">end</property>
|
|
||||||
<property name="position">2</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
<child>
|
||||||
<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="orientation">vertical</property>
|
<property name="spacing">5</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkLabel" id="title_label">
|
<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">start</property>
|
<property name="orientation">vertical</property>
|
||||||
<property name="valign">center</property>
|
<property name="spacing">5</property>
|
||||||
<property name="use_markup">True</property>
|
<child>
|
||||||
<property name="wrap">True</property>
|
<object class="GtkBox">
|
||||||
<property name="ellipsize">end</property>
|
<property name="visible">True</property>
|
||||||
<property name="lines">1</property>
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="title_label">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="halign">start</property>
|
||||||
|
<property name="label" translatable="yes">Episode Title</property>
|
||||||
|
<property name="wrap">True</property>
|
||||||
|
<property name="ellipsize">end</property>
|
||||||
|
<property name="track_visited_links">False</property>
|
||||||
|
<property name="lines">1</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="spacing">5</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="date_label">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">1970/01/01</property>
|
||||||
|
<property name="single_line_mode">True</property>
|
||||||
|
<property name="track_visited_links">False</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="seperator1">
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="no_show_all">True</property>
|
||||||
|
<property name="label" translatable="yes">·</property>
|
||||||
|
<property name="track_visited_links">False</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="duration_label">
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="no_show_all">True</property>
|
||||||
|
<property name="label" translatable="yes">42 min</property>
|
||||||
|
<property name="single_line_mode">True</property>
|
||||||
|
<property name="track_visited_links">False</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="seperator2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">·</property>
|
||||||
|
<property name="track_visited_links">False</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="size_label">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">42 MB</property>
|
||||||
|
<property name="single_line_mode">True</property>
|
||||||
|
<property name="track_visited_links">False</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">4</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="progress_label">
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="no_show_all">True</property>
|
||||||
|
<property name="label" translatable="yes">12 MB / 42 MB</property>
|
||||||
|
<property name="single_line_mode">True</property>
|
||||||
|
<property name="track_visited_links">False</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">5</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">True</property>
|
||||||
<property name="fill">False</property>
|
<property name="fill">True</property>
|
||||||
|
<property name="padding">5</property>
|
||||||
<property name="position">0</property>
|
<property name="position">0</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkExpander" id="expand_desc">
|
<object class="GtkBox">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="label_fill">True</property>
|
<property name="spacing">5</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkScrolledWindow">
|
<object class="GtkButton" id="cancel_button">
|
||||||
<property name="visible">True</property>
|
<property name="label" translatable="yes">Cancel</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="shadow_type">in</property>
|
<property name="receives_default">True</property>
|
||||||
<property name="min_content_height">100</property>
|
<property name="valign">center</property>
|
||||||
<property name="max_content_height">600</property>
|
</object>
|
||||||
<property name="propagate_natural_width">True</property>
|
<packing>
|
||||||
<property name="propagate_natural_height">True</property>
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="pack_type">end</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="delete_button">
|
||||||
|
<property name="name">delete_button</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<property name="halign">end</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkTextView" id="desc_text_view">
|
<object class="GtkImage">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="margin_bottom">5</property>
|
<property name="icon_name">user-trash-symbolic</property>
|
||||||
<property name="editable">False</property>
|
|
||||||
<property name="wrap_mode">word-char</property>
|
|
||||||
<property name="cursor_visible">False</property>
|
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="pack_type">end</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child type="label">
|
<child>
|
||||||
<object class="GtkLabel">
|
<object class="GtkButton" id="download_button">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="label" translatable="yes">Description:</property>
|
<property name="receives_default">True</property>
|
||||||
|
<property name="halign">end</property>
|
||||||
|
<property name="valign">center</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">document-save-symbolic</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="pack_type">end</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="play_button">
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="icon_name">media-playback-start-symbolic</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="pack_type">end</property>
|
||||||
|
<property name="position">3</property>
|
||||||
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
<property name="fill">True</property>
|
<property name="fill">True</property>
|
||||||
|
<property name="padding">5</property>
|
||||||
<property name="position">1</property>
|
<property name="position">1</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
@ -193,7 +244,18 @@
|
|||||||
<packing>
|
<packing>
|
||||||
<property name="expand">True</property>
|
<property name="expand">True</property>
|
||||||
<property name="fill">True</property>
|
<property name="fill">True</property>
|
||||||
<property name="position">3</property>
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkProgressBar" id="progress_bar">
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="padding">5</property>
|
||||||
|
<property name="position">1</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
|||||||
@ -6,6 +6,7 @@ extern crate gio;
|
|||||||
extern crate glib;
|
extern crate glib;
|
||||||
extern crate gtk;
|
extern crate gtk;
|
||||||
|
|
||||||
|
extern crate chrono;
|
||||||
extern crate diesel;
|
extern crate diesel;
|
||||||
extern crate dissolve;
|
extern crate dissolve;
|
||||||
extern crate hammond_data;
|
extern crate hammond_data;
|
||||||
|
|||||||
@ -1,101 +1,129 @@
|
|||||||
use glib;
|
use glib;
|
||||||
use gtk;
|
use gtk;
|
||||||
|
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
use gtk::{ContainerExt, TextBufferExt};
|
use chrono::prelude::*;
|
||||||
|
|
||||||
use open;
|
use open;
|
||||||
use dissolve::strip_html_tags;
|
|
||||||
|
|
||||||
use hammond_data::dbqueries;
|
use hammond_data::dbqueries;
|
||||||
use hammond_data::{Episode, Podcast};
|
use hammond_data::{EpisodeWidgetQuery, Podcast};
|
||||||
use hammond_downloader::downloader;
|
|
||||||
use hammond_data::utils::*;
|
use hammond_data::utils::*;
|
||||||
use hammond_data::errors::*;
|
use hammond_data::errors::*;
|
||||||
use hammond_data::utils::replace_extra_spaces;
|
use hammond_downloader::downloader;
|
||||||
|
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::sync::mpsc::{channel, Receiver};
|
use std::sync::mpsc::{channel, Receiver};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
type Foo = RefCell<Option<(gtk::Button, gtk::Button, gtk::Button, Receiver<bool>)>>;
|
type Foo = RefCell<
|
||||||
|
Option<
|
||||||
|
(
|
||||||
|
gtk::Button,
|
||||||
|
gtk::Button,
|
||||||
|
gtk::Button,
|
||||||
|
gtk::Button,
|
||||||
|
gtk::ProgressBar,
|
||||||
|
Receiver<bool>,
|
||||||
|
),
|
||||||
|
>,
|
||||||
|
>;
|
||||||
|
|
||||||
thread_local!(static GLOBAL: Foo = RefCell::new(None));
|
thread_local!(static GLOBAL: Foo = RefCell::new(None));
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct EpisodeWidget {
|
struct EpisodeWidget {
|
||||||
container: gtk::Box,
|
container: gtk::Box,
|
||||||
download: gtk::Button,
|
|
||||||
play: gtk::Button,
|
play: gtk::Button,
|
||||||
delete: gtk::Button,
|
delete: gtk::Button,
|
||||||
played: gtk::Button,
|
download: gtk::Button,
|
||||||
unplayed: gtk::Button,
|
cancel: gtk::Button,
|
||||||
title: gtk::Label,
|
title: gtk::Label,
|
||||||
description: gtk::TextView,
|
date: gtk::Label,
|
||||||
// description: gtk::Label,
|
duration: gtk::Label,
|
||||||
expander: gtk::Expander,
|
size: gtk::Label,
|
||||||
|
progress: gtk::ProgressBar,
|
||||||
|
progress_label: gtk::Label,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EpisodeWidget {
|
impl EpisodeWidget {
|
||||||
fn new() -> EpisodeWidget {
|
fn new() -> EpisodeWidget {
|
||||||
// This is just a prototype and will be reworked probably.
|
|
||||||
let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/episode_widget.ui");
|
let builder = gtk::Builder::new_from_resource("/org/gnome/hammond/gtk/episode_widget.ui");
|
||||||
|
|
||||||
let container: gtk::Box = builder.get_object("episode_box").unwrap();
|
let container: gtk::Box = builder.get_object("episode_container").unwrap();
|
||||||
|
let progress: gtk::ProgressBar = builder.get_object("progress_bar").unwrap();
|
||||||
|
|
||||||
let download: gtk::Button = builder.get_object("download_button").unwrap();
|
let download: gtk::Button = builder.get_object("download_button").unwrap();
|
||||||
let play: gtk::Button = builder.get_object("play_button").unwrap();
|
let play: gtk::Button = builder.get_object("play_button").unwrap();
|
||||||
let delete: gtk::Button = builder.get_object("delete_button").unwrap();
|
let delete: gtk::Button = builder.get_object("delete_button").unwrap();
|
||||||
let played: gtk::Button = builder.get_object("mark_played_button").unwrap();
|
let cancel: gtk::Button = builder.get_object("cancel_button").unwrap();
|
||||||
let unplayed: gtk::Button = builder.get_object("mark_unplayed_button").unwrap();
|
|
||||||
|
|
||||||
let title: gtk::Label = builder.get_object("title_label").unwrap();
|
let title: gtk::Label = builder.get_object("title_label").unwrap();
|
||||||
let expander: gtk::Expander = builder.get_object("expand_desc").unwrap();
|
let date: gtk::Label = builder.get_object("date_label").unwrap();
|
||||||
let description: gtk::TextView = builder.get_object("desc_text_view").unwrap();
|
let duration: gtk::Label = builder.get_object("duration_label").unwrap();
|
||||||
// let description: gtk::Label = builder.get_object("desc_text").unwrap();
|
let size: gtk::Label = builder.get_object("size_label").unwrap();
|
||||||
|
let progress_label: gtk::Label = builder.get_object("progress_label").unwrap();
|
||||||
|
|
||||||
|
let sep1: gtk::Label = builder.get_object("seperator1").unwrap();
|
||||||
|
let sep2: gtk::Label = builder.get_object("seperator2").unwrap();
|
||||||
|
|
||||||
|
// Dim(grey out) the labels.
|
||||||
|
// If it's possible through glade, feel free to open a PR.
|
||||||
|
duration
|
||||||
|
.get_style_context()
|
||||||
|
.map(|c| c.add_class("dim-label"));
|
||||||
|
progress_label
|
||||||
|
.get_style_context()
|
||||||
|
.map(|c| c.add_class("dim-label"));
|
||||||
|
date.get_style_context().map(|c| c.add_class("dim-label"));
|
||||||
|
size.get_style_context().map(|c| c.add_class("dim-label"));
|
||||||
|
sep1.get_style_context().map(|c| c.add_class("dim-label"));
|
||||||
|
sep2.get_style_context().map(|c| c.add_class("dim-label"));
|
||||||
|
|
||||||
EpisodeWidget {
|
EpisodeWidget {
|
||||||
container,
|
container,
|
||||||
|
progress,
|
||||||
download,
|
download,
|
||||||
play,
|
play,
|
||||||
|
cancel,
|
||||||
delete,
|
delete,
|
||||||
played,
|
|
||||||
unplayed,
|
|
||||||
title,
|
title,
|
||||||
expander,
|
duration,
|
||||||
description,
|
size,
|
||||||
|
date,
|
||||||
|
progress_label,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_initialized(episode: &mut Episode, pd: &Podcast) -> EpisodeWidget {
|
pub fn new_initialized(episode: &mut EpisodeWidgetQuery, pd: &Podcast) -> EpisodeWidget {
|
||||||
let widget = EpisodeWidget::new();
|
let widget = EpisodeWidget::new();
|
||||||
widget.init(episode, pd);
|
widget.init(episode, pd);
|
||||||
widget
|
widget
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init(&self, episode: &mut Episode, pd: &Podcast) {
|
// TODO: calculate lenght.
|
||||||
|
// TODO: wire the progress_bar to the downloader.
|
||||||
|
// TODO: wire the cancel button.
|
||||||
|
fn init(&self, episode: &mut EpisodeWidgetQuery, pd: &Podcast) {
|
||||||
self.title.set_xalign(0.0);
|
self.title.set_xalign(0.0);
|
||||||
self.title.set_text(episode.title());
|
self.title.set_text(episode.title());
|
||||||
|
|
||||||
if episode.description().is_some() {
|
let progress = self.progress.clone();
|
||||||
let text = episode.description().unwrap().to_owned();
|
timeout_add(200, move || {
|
||||||
let description = &self.description;
|
progress.pulse();
|
||||||
self.expander
|
glib::Continue(true)
|
||||||
.connect_activate(clone!(description, text => move |_| {
|
});
|
||||||
// let mut text = text.clone();
|
|
||||||
// html_to_markup(&mut text);
|
|
||||||
// description.set_markup(&text)
|
|
||||||
|
|
||||||
let plain_text = strip_html_tags(&text).join(" ");
|
if let Some(size) = episode.length() {
|
||||||
// TODO: handle unwrap
|
let megabytes = size / 1024 / 1024; // episode.length represents bytes
|
||||||
let buff = description.get_buffer().unwrap();
|
self.size.set_text(&format!("{} MB", megabytes))
|
||||||
buff.set_text(&replace_extra_spaces(&plain_text));
|
};
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
if episode.played().is_some() {
|
let date = Utc.timestamp(i64::from(episode.epoch()), 0)
|
||||||
self.unplayed.show();
|
.format("%b %e")
|
||||||
self.played.hide();
|
.to_string();
|
||||||
}
|
self.date.set_text(&date);
|
||||||
|
|
||||||
// Show or hide the play/delete/download buttons upon widget initialization.
|
// Show or hide the play/delete/download buttons upon widget initialization.
|
||||||
let local_uri = episode.local_uri();
|
let local_uri = episode.local_uri();
|
||||||
@ -105,15 +133,10 @@ impl EpisodeWidget {
|
|||||||
self.delete.show();
|
self.delete.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
let played = &self.played;
|
self.play.connect_clicked(clone!(episode => move |_| {
|
||||||
let unplayed = &self.unplayed;
|
|
||||||
self.play
|
|
||||||
.connect_clicked(clone!(episode, played, unplayed => move |_| {
|
|
||||||
let mut episode = episode.clone();
|
let mut episode = episode.clone();
|
||||||
on_play_bttn_clicked(episode.rowid());
|
on_play_bttn_clicked(episode.rowid());
|
||||||
let _ = episode.set_played_now();
|
let _ = episode.set_played_now();
|
||||||
played.hide();
|
|
||||||
unplayed.show();
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let play = &self.play;
|
let play = &self.play;
|
||||||
@ -126,59 +149,58 @@ impl EpisodeWidget {
|
|||||||
download.show();
|
download.show();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let unplayed = &self.unplayed;
|
|
||||||
self.played
|
|
||||||
.connect_clicked(clone!(episode, unplayed => move |played| {
|
|
||||||
let mut episode = episode.clone();
|
|
||||||
let _ = episode.set_played_now();
|
|
||||||
played.hide();
|
|
||||||
unplayed.show();
|
|
||||||
}));
|
|
||||||
|
|
||||||
let played = &self.played;
|
|
||||||
self.unplayed
|
|
||||||
.connect_clicked(clone!(episode, played => move |un| {
|
|
||||||
let mut episode = episode.clone();
|
|
||||||
episode.set_played(None);
|
|
||||||
let _ = episode.save();
|
|
||||||
un.hide();
|
|
||||||
played.show();
|
|
||||||
}));
|
|
||||||
|
|
||||||
let pd_title = pd.title().to_owned();
|
let pd_title = pd.title().to_owned();
|
||||||
let play = &self.play;
|
let play = &self.play;
|
||||||
let delete = &self.delete;
|
let delete = &self.delete;
|
||||||
self.download
|
let cancel = &self.cancel;
|
||||||
.connect_clicked(clone!(play, delete, episode => move |dl| {
|
let progress = &self.progress;
|
||||||
|
self.download.connect_clicked(
|
||||||
|
clone!(play, delete, episode, cancel, progress => move |dl| {
|
||||||
on_download_clicked(
|
on_download_clicked(
|
||||||
&pd_title,
|
&pd_title,
|
||||||
&mut episode.clone(),
|
&mut episode.clone(),
|
||||||
dl,
|
dl,
|
||||||
&play,
|
&play,
|
||||||
&delete,
|
&delete,
|
||||||
|
&cancel,
|
||||||
|
&progress
|
||||||
);
|
);
|
||||||
}));
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: show notification when dl is finished.
|
// TODO: show notification when dl is finished.
|
||||||
fn on_download_clicked(
|
fn on_download_clicked(
|
||||||
pd_title: &str,
|
pd_title: &str,
|
||||||
ep: &mut Episode,
|
ep: &mut EpisodeWidgetQuery,
|
||||||
download_bttn: >k::Button,
|
download_bttn: >k::Button,
|
||||||
play_bttn: >k::Button,
|
play_bttn: >k::Button,
|
||||||
del_bttn: >k::Button,
|
del_bttn: >k::Button,
|
||||||
|
cancel_bttn: >k::Button,
|
||||||
|
progress_bar: >k::ProgressBar,
|
||||||
) {
|
) {
|
||||||
// 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!(download_bttn, play_bttn, del_bttn => move |global| {
|
GLOBAL.with(
|
||||||
*global.borrow_mut() = Some((download_bttn, play_bttn, del_bttn, receiver));
|
clone!(download_bttn, play_bttn, del_bttn, cancel_bttn, progress_bar => move |global| {
|
||||||
}));
|
*global.borrow_mut() = Some((
|
||||||
|
download_bttn,
|
||||||
|
play_bttn,
|
||||||
|
del_bttn,
|
||||||
|
cancel_bttn,
|
||||||
|
progress_bar,
|
||||||
|
receiver));
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
let pd_title = pd_title.to_owned();
|
let pd_title = pd_title.to_owned();
|
||||||
let mut ep = ep.clone();
|
let mut ep = ep.clone();
|
||||||
|
cancel_bttn.show();
|
||||||
|
progress_bar.show();
|
||||||
|
download_bttn.hide();
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let download_fold = downloader::get_download_folder(&pd_title).unwrap();
|
let download_fold = downloader::get_download_folder(&pd_title).unwrap();
|
||||||
let e = downloader::get_episode(&mut ep, download_fold.as_str());
|
let e = downloader::get_episode(&mut ep, download_fold.as_str());
|
||||||
@ -223,13 +245,21 @@ fn on_delete_bttn_clicked(episode_id: i32) {
|
|||||||
|
|
||||||
fn receive() -> glib::Continue {
|
fn receive() -> glib::Continue {
|
||||||
GLOBAL.with(|global| {
|
GLOBAL.with(|global| {
|
||||||
if let Some((ref download_bttn, ref play_bttn, ref del_bttn, ref reciever)) =
|
if let Some((
|
||||||
*global.borrow()
|
ref download_bttn,
|
||||||
|
ref play_bttn,
|
||||||
|
ref del_bttn,
|
||||||
|
ref cancel_bttn,
|
||||||
|
ref progress_bar,
|
||||||
|
ref reciever,
|
||||||
|
)) = *global.borrow()
|
||||||
{
|
{
|
||||||
if reciever.try_recv().is_ok() {
|
if reciever.try_recv().is_ok() {
|
||||||
download_bttn.hide();
|
download_bttn.hide();
|
||||||
play_bttn.show();
|
play_bttn.show();
|
||||||
del_bttn.show();
|
del_bttn.show();
|
||||||
|
cancel_bttn.hide();
|
||||||
|
progress_bar.hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -237,11 +267,10 @@ fn receive() -> glib::Continue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn episodes_listbox(pd: &Podcast) -> Result<gtk::ListBox> {
|
pub fn episodes_listbox(pd: &Podcast) -> Result<gtk::ListBox> {
|
||||||
let episodes = dbqueries::get_pd_episodes(pd)?;
|
let episodes = dbqueries::get_pd_episodeswidgets(pd)?;
|
||||||
|
|
||||||
let list = gtk::ListBox::new();
|
let list = gtk::ListBox::new();
|
||||||
episodes.into_iter().for_each(|mut ep| {
|
episodes.into_iter().for_each(|mut ep| {
|
||||||
// let w = epidose_widget(&mut ep, pd.title());
|
|
||||||
let widget = EpisodeWidget::new_initialized(&mut ep, pd);
|
let widget = EpisodeWidget::new_initialized(&mut ep, pd);
|
||||||
list.add(&widget.container)
|
list.add(&widget.container)
|
||||||
});
|
});
|
||||||
|
|||||||
@ -35,5 +35,5 @@ cp -rf vendor $DIST/
|
|||||||
|
|
||||||
# packaging
|
# packaging
|
||||||
cd $DEST/dist
|
cd $DEST/dist
|
||||||
tar -czvf $VERSION.tar.gz $VERSION
|
tar -cJvf $VERSION.tar.xz $VERSION
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user