Move import
This commit is contained in:
parent
c6ce888cc7
commit
ac6ac42860
@ -326,6 +326,7 @@ Tobias Bernard
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="text" translatable="yes">Import Shows</property>
|
||||
<property name="action-name">app.import</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
|
||||
@ -2,6 +2,20 @@
|
||||
<interface>
|
||||
<!-- interface-requires gtk+ 3.0 -->
|
||||
<menu id="app-menu">
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_Check for new episodes</attribute>
|
||||
<attribute name="action">app.refresh</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_Import Shows</attribute>
|
||||
<attribute name="action">app.import</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_Export Shows</attribute>
|
||||
<attribute name="action">app.export</attribute>
|
||||
</item>
|
||||
</section>
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_Preferences</attribute>
|
||||
|
||||
@ -7,6 +7,7 @@ use gtk::prelude::*;
|
||||
use gtk::SettingsExt as GtkSettingsExt;
|
||||
|
||||
use hammond_data::Podcast;
|
||||
use hammond_data::{opml};
|
||||
|
||||
use appnotif::{InAppNotification, UndoState};
|
||||
use headerbar::Header;
|
||||
@ -19,6 +20,8 @@ use std::rc::Rc;
|
||||
use std::sync::mpsc::{channel, Receiver, Sender};
|
||||
use std::sync::Arc;
|
||||
|
||||
use rayon;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Action {
|
||||
RefreshAllViews,
|
||||
@ -67,9 +70,21 @@ impl App {
|
||||
let window = gtk::Window::new(gtk::WindowType::Toplevel);
|
||||
window.set_title("Hammond");
|
||||
|
||||
let (sender, receiver) = channel();
|
||||
|
||||
window.connect_delete_event(clone!(application, settings, window => move |_, _| {
|
||||
WindowGeometry::from_window(&window).write(&settings);
|
||||
application.quit();
|
||||
Inhibit(false)
|
||||
}));
|
||||
|
||||
// Ideally a lot more than actions would happen in startup & window
|
||||
// creation would be in activate
|
||||
application.connect_startup(clone!(window => move |app| {
|
||||
application.connect_startup(clone!(window, sender => move |app| {
|
||||
let import = SimpleAction::new("import", None);
|
||||
import.connect_activate(clone!(window, sender => move |_, _| on_import_clicked(&window, &sender)));
|
||||
app.add_action(&import);
|
||||
|
||||
let about = SimpleAction::new("about", None);
|
||||
// Should investigate use of active_window here
|
||||
about.connect_activate(clone!(window => move |_, _| about_dialog(&window)));
|
||||
@ -80,14 +95,6 @@ impl App {
|
||||
app.add_action(&quit);
|
||||
}));
|
||||
|
||||
window.connect_delete_event(clone!(application, settings, window => move |_, _| {
|
||||
WindowGeometry::from_window(&window).write(&settings);
|
||||
application.quit();
|
||||
Inhibit(false)
|
||||
}));
|
||||
|
||||
let (sender, receiver) = channel();
|
||||
|
||||
// Create a content instance
|
||||
let content =
|
||||
Rc::new(Content::new(sender.clone()).expect("Content Initialization failed."));
|
||||
@ -274,3 +281,63 @@ fn about_dialog(window: >k::Window) {
|
||||
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
fn on_import_clicked(window: >k::Window, sender: &Sender<Action>) {
|
||||
use glib::translate::ToGlib;
|
||||
use gtk::{FileChooserAction, FileChooserDialog, FileFilter, 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),
|
||||
],
|
||||
);
|
||||
|
||||
// Do not show hidden(.thing) files
|
||||
dialog.set_show_hidden(false);
|
||||
|
||||
// Set a filter to show only xml files
|
||||
let filter = FileFilter::new();
|
||||
FileFilterExt::set_name(&filter, Some("OPML file"));
|
||||
filter.add_mime_type("application/xml");
|
||||
filter.add_mime_type("text/xml");
|
||||
dialog.add_filter(&filter);
|
||||
|
||||
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 {
|
||||
let text = String::from("Failed to parse the Imported file");
|
||||
sender.send(Action::ErrorNotification(text))
|
||||
.map_err(|err| error!("Action Sender: {}", err))
|
||||
.ok();
|
||||
}
|
||||
}))
|
||||
} else {
|
||||
let text = String::from("Selected File could not be accessed.");
|
||||
sender.send(Action::ErrorNotification(text))
|
||||
.map_err(|err| error!("Action Sender: {}", err))
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
|
||||
dialog.destroy();
|
||||
}));
|
||||
|
||||
dialog.run();
|
||||
}
|
||||
|
||||
@ -4,16 +4,15 @@ use gtk::prelude::*;
|
||||
|
||||
use failure::Error;
|
||||
use failure::ResultExt;
|
||||
use rayon;
|
||||
use url::Url;
|
||||
|
||||
use hammond_data::{dbqueries, opml, Source};
|
||||
use hammond_data::{dbqueries, Source};
|
||||
|
||||
use std::sync::mpsc::Sender;
|
||||
|
||||
use app::Action;
|
||||
use stacks::Content;
|
||||
use utils::{self, itunes_to_rss, refresh};
|
||||
use utils::{itunes_to_rss, refresh};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
// TODO: split this into smaller
|
||||
@ -23,7 +22,6 @@ pub struct Header {
|
||||
switch: gtk::StackSwitcher,
|
||||
back: gtk::Button,
|
||||
show_title: gtk::Label,
|
||||
import: gtk::ModelButton,
|
||||
export: gtk::ModelButton,
|
||||
update_button: gtk::ModelButton,
|
||||
update_box: gtk::Box,
|
||||
@ -40,7 +38,6 @@ impl Default for Header {
|
||||
let switch = builder.get_object("switch").unwrap();
|
||||
let back = builder.get_object("back").unwrap();
|
||||
let show_title = builder.get_object("show_title").unwrap();
|
||||
let import = builder.get_object("import").unwrap();
|
||||
let export = builder.get_object("export").unwrap();
|
||||
let update_button = builder.get_object("update_button").unwrap();
|
||||
let update_box = builder.get_object("update_notification").unwrap();
|
||||
@ -53,7 +50,6 @@ impl Default for Header {
|
||||
switch,
|
||||
back,
|
||||
show_title,
|
||||
import,
|
||||
export,
|
||||
update_button,
|
||||
update_box,
|
||||
@ -104,10 +100,6 @@ impl Header {
|
||||
}));
|
||||
}));
|
||||
|
||||
self.import.connect_clicked(
|
||||
clone!(window, sender => move |_| on_import_clicked(&window, &sender)),
|
||||
);
|
||||
|
||||
// Add the Headerbar to the window.
|
||||
window.set_titlebar(&self.container);
|
||||
|
||||
@ -222,63 +214,3 @@ fn on_url_change(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn on_import_clicked(window: >k::Window, sender: &Sender<Action>) {
|
||||
use glib::translate::ToGlib;
|
||||
use gtk::{FileChooserAction, FileChooserDialog, FileFilter, 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),
|
||||
],
|
||||
);
|
||||
|
||||
// Do not show hidden(.thing) files
|
||||
dialog.set_show_hidden(false);
|
||||
|
||||
// Set a filter to show only xml files
|
||||
let filter = FileFilter::new();
|
||||
FileFilterExt::set_name(&filter, Some("OPML file"));
|
||||
filter.add_mime_type("application/xml");
|
||||
filter.add_mime_type("text/xml");
|
||||
dialog.add_filter(&filter);
|
||||
|
||||
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 {
|
||||
let text = String::from("Failed to parse the Imported file");
|
||||
sender.send(Action::ErrorNotification(text))
|
||||
.map_err(|err| error!("Action Sender: {}", err))
|
||||
.ok();
|
||||
}
|
||||
}))
|
||||
} else {
|
||||
let text = String::from("Selected File could not be accessed.");
|
||||
sender.send(Action::ErrorNotification(text))
|
||||
.map_err(|err| error!("Action Sender: {}", err))
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
|
||||
dialog.destroy();
|
||||
}));
|
||||
|
||||
dialog.run();
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user