h-gtk: Wire the import_shows button on the hamburger menu to the the opml import.
This commit is contained in:
parent
2d8164cf0a
commit
00e747eb5f
@ -7,7 +7,9 @@ use models::Source;
|
|||||||
use xml::reader;
|
use xml::reader;
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
use std::fs;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
// use std::fs::{File, OpenOptions};
|
// use std::fs::{File, OpenOptions};
|
||||||
// use std::io::BufReader;
|
// use std::io::BufReader;
|
||||||
@ -25,15 +27,35 @@ pub struct Opml {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Import feed url's from a `R` into the `Source` table.
|
/// Import feed url's from a `R` into the `Source` table.
|
||||||
pub fn opml_import<R: Read>(reader: R) -> Result<Vec<Result<Source, DataError>>, reader::Error> {
|
// TODO: Write test
|
||||||
|
pub fn import_to_db<R: Read>(reader: R) -> Result<Vec<Source>, reader::Error> {
|
||||||
let feeds = extract_sources(reader)?
|
let feeds = extract_sources(reader)?
|
||||||
.iter()
|
.iter()
|
||||||
.map(|opml| Source::from_url(&opml.url))
|
.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();
|
.collect();
|
||||||
|
|
||||||
Ok(feeds)
|
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<P: AsRef<Path>>(path: P) -> Result<Vec<Source>, 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.
|
/// Extracts the `outline` elemnts from a reader `R` and returns a `HashSet` of `Opml` structs.
|
||||||
pub fn extract_sources<R: Read>(reader: R) -> Result<HashSet<Opml>, reader::Error> {
|
pub fn extract_sources<R: Read>(reader: R) -> Result<HashSet<Opml>, reader::Error> {
|
||||||
let mut list = HashSet::new();
|
let mut list = HashSet::new();
|
||||||
|
|||||||
@ -323,9 +323,8 @@ Tobias Bernard
|
|||||||
<child>
|
<child>
|
||||||
<object class="GtkModelButton" id="import">
|
<object class="GtkModelButton" id="import">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="sensitive">False</property>
|
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="receives_default">False</property>
|
<property name="receives_default">True</property>
|
||||||
<property name="text" translatable="yes">Import Shows</property>
|
<property name="text" translatable="yes">Import Shows</property>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
|
|||||||
@ -4,16 +4,16 @@ use gtk::prelude::*;
|
|||||||
|
|
||||||
use failure::Error;
|
use failure::Error;
|
||||||
use failure::ResultExt;
|
use failure::ResultExt;
|
||||||
|
use rayon;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use hammond_data::dbqueries;
|
use hammond_data::{dbqueries, opml, Source};
|
||||||
use hammond_data::Source;
|
|
||||||
|
|
||||||
use std::sync::mpsc::Sender;
|
use std::sync::mpsc::Sender;
|
||||||
|
|
||||||
use app::Action;
|
use app::Action;
|
||||||
use stacks::Content;
|
use stacks::Content;
|
||||||
use utils::{itunes_to_rss, refresh};
|
use utils::{self, itunes_to_rss, refresh};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
// TODO: split this into smaller
|
// TODO: split this into smaller
|
||||||
@ -107,9 +107,12 @@ impl Header {
|
|||||||
}));
|
}));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
self.about.connect_clicked(clone!(window => move |_| {
|
self.about
|
||||||
about_dialog(&window);
|
.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.
|
// Add the Headerbar to the window.
|
||||||
window.set_titlebar(&self.container);
|
window.set_titlebar(&self.container);
|
||||||
@ -226,6 +229,49 @@ fn on_url_change(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn on_import_clicked(window: >k::Window, sender: &Sender<Action>) {
|
||||||
|
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.
|
// Totally copied it from fractal.
|
||||||
// https://gitlab.gnome.org/danigm/fractal/blob/503e311e22b9d7540089d735b92af8e8f93560c5/fractal-gtk/src/app.rs#L1883-1912
|
// https://gitlab.gnome.org/danigm/fractal/blob/503e311e22b9d7540089d735b92af8e8f93560c5/fractal-gtk/src/app.rs#L1883-1912
|
||||||
fn about_dialog(window: >k::Window) {
|
fn about_dialog(window: >k::Window) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user