From 00e747eb5facf03436b25b295941ab7168dfc540 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Sat, 12 May 2018 22:55:35 +0300 Subject: [PATCH] h-gtk: Wire the import_shows button on the hamburger menu to the the opml import. --- hammond-data/src/opml.rs | 24 ++++++++++- hammond-gtk/resources/gtk/headerbar.ui | 3 +- hammond-gtk/src/headerbar.rs | 58 +++++++++++++++++++++++--- 3 files changed, 76 insertions(+), 9 deletions(-) diff --git a/hammond-data/src/opml.rs b/hammond-data/src/opml.rs index 675d32b..618c290 100644 --- a/hammond-data/src/opml.rs +++ b/hammond-data/src/opml.rs @@ -7,7 +7,9 @@ use models::Source; use xml::reader; use std::collections::HashSet; +use std::fs; use std::io::Read; +use std::path::Path; // use std::fs::{File, OpenOptions}; // use std::io::BufReader; @@ -25,15 +27,35 @@ pub struct Opml { } /// Import feed url's from a `R` into the `Source` table. -pub fn opml_import(reader: R) -> Result>, reader::Error> { +// TODO: Write test +pub fn import_to_db(reader: R) -> Result, reader::Error> { let feeds = extract_sources(reader)? .iter() .map(|opml| Source::from_url(&opml.url)) + .filter_map(|s| { + if let Err(ref err) = s { + let txt = "If you think this might be a bug please consider filling a report over \ + at https://gitlab.gnome.org/World/hammond/issues/new"; + + error!("Failed to import a Show: {}", err); + error!("{}", txt); + } + + s.ok() + }) .collect(); Ok(feeds) } +/// Open a File from `P`, try to parse the OPML then insert the Feeds in the database and +/// return the new `Source`s +// TODO: Write test +pub fn import_from_file>(path: P) -> Result, DataError> { + let content = fs::read_to_string(path)?; + import_to_db(content.as_bytes()).map_err(From::from) +} + /// Extracts the `outline` elemnts from a reader `R` and returns a `HashSet` of `Opml` structs. pub fn extract_sources(reader: R) -> Result, reader::Error> { let mut list = HashSet::new(); diff --git a/hammond-gtk/resources/gtk/headerbar.ui b/hammond-gtk/resources/gtk/headerbar.ui index 3290921..291502c 100644 --- a/hammond-gtk/resources/gtk/headerbar.ui +++ b/hammond-gtk/resources/gtk/headerbar.ui @@ -323,9 +323,8 @@ Tobias Bernard True - False True - False + True Import Shows diff --git a/hammond-gtk/src/headerbar.rs b/hammond-gtk/src/headerbar.rs index fd7f7b8..7e442da 100644 --- a/hammond-gtk/src/headerbar.rs +++ b/hammond-gtk/src/headerbar.rs @@ -4,16 +4,16 @@ use gtk::prelude::*; use failure::Error; use failure::ResultExt; +use rayon; use url::Url; -use hammond_data::dbqueries; -use hammond_data::Source; +use hammond_data::{dbqueries, opml, Source}; use std::sync::mpsc::Sender; use app::Action; use stacks::Content; -use utils::{itunes_to_rss, refresh}; +use utils::{self, itunes_to_rss, refresh}; #[derive(Debug, Clone)] // TODO: split this into smaller @@ -107,9 +107,12 @@ impl Header { })); })); - self.about.connect_clicked(clone!(window => move |_| { - about_dialog(&window); - })); + self.about + .connect_clicked(clone!(window => move |_| about_dialog(&window))); + + self.import.connect_clicked( + clone!(window, sender => move |_| on_import_clicked(&window, &sender)), + ); // Add the Headerbar to the window. window.set_titlebar(&self.container); @@ -226,6 +229,49 @@ fn on_url_change( } } +fn on_import_clicked(window: >k::Window, sender: &Sender) { + use glib::translate::ToGlib; + use gtk::{FileChooserAction, FileChooserDialog, ResponseType}; + + // let dialog = FileChooserDialog::new(title, Some(&window), FileChooserAction::Open); + // TODO: It might be better to use a FileChooserNative widget. + // Create the FileChooser Dialog + let dialog = FileChooserDialog::with_buttons( + Some("Select the file from which to you want to Import Shows."), + Some(window), + FileChooserAction::Open, + &[ + ("_Cancel", ResponseType::Cancel), + ("_Open", ResponseType::Accept), + ], + ); + + dialog.connect_response(clone!(sender => move |dialog, resp| { + debug!("Dialong Response {}", resp); + if resp == ResponseType::Accept.to_glib() { + // TODO: Show an in-app notifictaion if the file can not be accessed + if let Some(filename) = dialog.get_filename() { + debug!("File selected: {:?}", filename); + + rayon::spawn(clone!(sender => move || { + // Parse the file and import the feeds + if let Ok(sources) = opml::import_from_file(filename) { + // Refresh the succesfully parsed feeds to index them + utils::refresh(Some(sources), sender) + } else { + // TODO: Show an in-app notification if file can not be parsed + error!("Failed to parse the Import file") + } + })) + } + } + + dialog.destroy(); + })); + + dialog.run(); +} + // Totally copied it from fractal. // https://gitlab.gnome.org/danigm/fractal/blob/503e311e22b9d7540089d735b92af8e8f93560c5/fractal-gtk/src/app.rs#L1883-1912 fn about_dialog(window: >k::Window) {