From fa099bb55f133d46d6d2bdd0341e9bd649ea4bf0 Mon Sep 17 00:00:00 2001 From: Cory Date: Sat, 24 Jul 2021 11:08:57 -0700 Subject: [PATCH 01/12] Add share module for addon import / export --- Cargo.lock | 2 - crates/core/src/error.rs | 2 + crates/core/src/lib.rs | 1 + crates/core/src/share.rs | 92 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 crates/core/src/share.rs diff --git a/Cargo.lock b/Cargo.lock index 8de1a060..acfb8476 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,7 +1,5 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 - [[package]] name = "ab_glyph" version = "0.2.10" diff --git a/crates/core/src/error.rs b/crates/core/src/error.rs index 8d55b739..8e6033af 100644 --- a/crates/core/src/error.rs +++ b/crates/core/src/error.rs @@ -21,6 +21,8 @@ pub enum FilesystemError { NormalizingPathSlash { path: PathBuf }, #[error("Could not strip prefix {prefix:?} from {from:?}")] StripPrefix { prefix: String, from: String }, + #[error(transparent)] + SerdeJson(#[from] serde_json::Error), } #[derive(thiserror::Error, Debug)] diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index 6bd5b643..2e748b87 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -9,6 +9,7 @@ pub mod murmur2; pub mod network; pub mod parse; pub mod repository; +pub mod share; #[cfg(feature = "gui")] pub mod theme; pub mod utility; diff --git a/crates/core/src/share.rs b/crates/core/src/share.rs new file mode 100644 index 00000000..5f44685a --- /dev/null +++ b/crates/core/src/share.rs @@ -0,0 +1,92 @@ +use std::{collections::HashMap, convert::TryFrom, fs, path::Path}; + +use serde::{Deserialize, Serialize}; + +use crate::{addon::Addon, config::Flavor, error, repository::RepositoryKind}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct Data { + pub flavor: Flavor, + pub repo_kind: RepositoryKind, + pub id: String, + pub name: String, +} + +impl TryFrom<(Flavor, Addon)> for Data { + type Error = (); + + fn try_from((flavor, addon): (Flavor, Addon)) -> Result { + let name = addon.title().to_string(); + let repository = addon.repository.ok_or(())?; + let repo_kind = repository.kind; + let id = repository.id; + + Ok(Self { + flavor, + repo_kind, + id, + name, + }) + } +} + +pub fn export( + addons: HashMap>, + output_dir: impl AsRef, +) -> Result<(), error::FilesystemError> { + let data = addons + .into_iter() + .map(|(flavor, addons)| { + ( + flavor, + addons + .into_iter() + .map(|a| Data::try_from((flavor, a))) + .flatten() + .collect::>(), + ) + }) + .collect::>>(); + + let file = output_dir.as_ref().join("ajour-addons.json"); + + let contents = serde_json::to_string(&data)?; + + fs::write(file, contents)?; + + Ok(()) +} + +pub fn parse_only_needed( + existing_addons: HashMap>, + import_string: String, +) -> Result>, serde_json::Error> { + let data = serde_json::from_str::>>(&import_string)?; + + Ok(data + .into_iter() + .map(|(flavor, data)| { + ( + flavor, + data.into_iter() + .filter(|data| { + if let Some(existing) = existing_addons.get(&flavor) { + !existing.iter().any(|a| { + if let Some(existing_repo) = a.repository() { + let kind = data.repo_kind; + + existing_repo.id == data.id && existing_repo.kind == kind + } else { + false + } + }) + } else { + true + } + }) + .collect::>(), + ) + }) + .filter(|(_, data)| !data.is_empty()) + .collect()) +} From 3064266e0f2406c238754bfb28b1a52e9e3c3035 Mon Sep 17 00:00:00 2001 From: Cory Date: Sat, 24 Jul 2021 11:12:19 -0700 Subject: [PATCH 02/12] Change to yml --- crates/core/src/error.rs | 2 -- crates/core/src/share.rs | 8 ++++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/crates/core/src/error.rs b/crates/core/src/error.rs index 8e6033af..8d55b739 100644 --- a/crates/core/src/error.rs +++ b/crates/core/src/error.rs @@ -21,8 +21,6 @@ pub enum FilesystemError { NormalizingPathSlash { path: PathBuf }, #[error("Could not strip prefix {prefix:?} from {from:?}")] StripPrefix { prefix: String, from: String }, - #[error(transparent)] - SerdeJson(#[from] serde_json::Error), } #[derive(thiserror::Error, Debug)] diff --git a/crates/core/src/share.rs b/crates/core/src/share.rs index 5f44685a..e55c712a 100644 --- a/crates/core/src/share.rs +++ b/crates/core/src/share.rs @@ -48,9 +48,9 @@ pub fn export( }) .collect::>>(); - let file = output_dir.as_ref().join("ajour-addons.json"); + let file = output_dir.as_ref().join("ajour-addons.yml"); - let contents = serde_json::to_string(&data)?; + let contents = serde_yaml::to_string(&data)?; fs::write(file, contents)?; @@ -60,8 +60,8 @@ pub fn export( pub fn parse_only_needed( existing_addons: HashMap>, import_string: String, -) -> Result>, serde_json::Error> { - let data = serde_json::from_str::>>(&import_string)?; +) -> Result>, serde_yaml::Error> { + let data = serde_yaml::from_str::>>(&import_string)?; Ok(data .into_iter() From 939f908079bf75684f5d1c5040081613a6bb5896 Mon Sep 17 00:00:00 2001 From: Cory Date: Sat, 24 Jul 2021 11:29:14 -0700 Subject: [PATCH 03/12] Pass a file path instead of string --- crates/core/src/share.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/core/src/share.rs b/crates/core/src/share.rs index e55c712a..fae074fb 100644 --- a/crates/core/src/share.rs +++ b/crates/core/src/share.rs @@ -59,9 +59,10 @@ pub fn export( pub fn parse_only_needed( existing_addons: HashMap>, - import_string: String, -) -> Result>, serde_yaml::Error> { - let data = serde_yaml::from_str::>>(&import_string)?; + path: impl AsRef, +) -> Result>, error::FilesystemError> { + let file = fs::File::open(&path)?; + let data = serde_yaml::from_reader::<_, HashMap>>(file)?; Ok(data .into_iter() From b6de9a4545a516a518f0a7ce82ab111ea5a2b9f6 Mon Sep 17 00:00:00 2001 From: Cory Date: Sat, 24 Jul 2021 11:34:44 -0700 Subject: [PATCH 04/12] Store ignored metadata --- crates/core/src/share.rs | 51 +++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/crates/core/src/share.rs b/crates/core/src/share.rs index fae074fb..4aad1559 100644 --- a/crates/core/src/share.rs +++ b/crates/core/src/share.rs @@ -57,37 +57,50 @@ pub fn export( Ok(()) } +pub struct Parsed { + pub data: Vec, + pub ignored: usize, +} + pub fn parse_only_needed( existing_addons: HashMap>, path: impl AsRef, -) -> Result>, error::FilesystemError> { +) -> Result, error::FilesystemError> { let file = fs::File::open(&path)?; let data = serde_yaml::from_reader::<_, HashMap>>(file)?; Ok(data .into_iter() .map(|(flavor, data)| { + let original_len = data.len(); + let needed = data + .into_iter() + .filter(|data| { + if let Some(existing) = existing_addons.get(&flavor) { + !existing.iter().any(|a| { + if let Some(existing_repo) = a.repository() { + let kind = data.repo_kind; + + existing_repo.id == data.id && existing_repo.kind == kind + } else { + false + } + }) + } else { + true + } + }) + .collect::>(); + + let ignored = original_len - needed.len(); + ( flavor, - data.into_iter() - .filter(|data| { - if let Some(existing) = existing_addons.get(&flavor) { - !existing.iter().any(|a| { - if let Some(existing_repo) = a.repository() { - let kind = data.repo_kind; - - existing_repo.id == data.id && existing_repo.kind == kind - } else { - false - } - }) - } else { - true - } - }) - .collect::>(), + Parsed { + data: needed, + ignored, + }, ) }) - .filter(|(_, data)| !data.is_empty()) .collect()) } From dfc035f6392f61c3f9027af82df169ffd0e5825a Mon Sep 17 00:00:00 2001 From: Casper Rogild Storm Date: Sun, 25 Jul 2021 14:24:12 +0200 Subject: [PATCH 05/12] initial gui for import/export --- locale/en.json | 7 ++++-- src/gui/element/settings.rs | 46 +++++++++++++++++++++++++++++++++++-- src/gui/mod.rs | 11 +++++++++ src/gui/update.rs | 6 +++++ 4 files changed, 66 insertions(+), 4 deletions(-) diff --git a/locale/en.json b/locale/en.json index 69f5d968..3c7d3cfb 100644 --- a/locale/en.json +++ b/locale/en.json @@ -145,5 +145,8 @@ "delete-addon": "Delete {addon}", "confirm-deletion": "Confirm deletion", "paste-url": "Paste URL here...", - "all-sources": "All Sources" -} \ No newline at end of file + "all-sources": "All Sources", + "share-addons-title": "Export and import something something something..", + "share-addons-import": "Import", + "share-addons-export": "Export" +} diff --git a/src/gui/element/settings.rs b/src/gui/element/settings.rs index 1a88ab54..af974eef 100644 --- a/src/gui/element/settings.rs +++ b/src/gui/element/settings.rs @@ -7,7 +7,7 @@ use { crate::gui::{ style, BackupFolderKind, BackupState, CatalogColumnKey, CatalogColumnSettings, ColumnKey, ColumnSettings, GlobalReleaseChannel, Interaction, Language, Message, ScaleState, - SelfUpdateChannelState, ThemeState, WowDirectoryState, + SelfUpdateChannelState, ShareState, ThemeState, WowDirectoryState, }, crate::localization::localized_string, ajour_core::{config::Config, theme::ColorPalette}, @@ -40,6 +40,7 @@ pub fn data_container<'a, 'b>( reset_columns_button_state: &'a mut button::State, localization_picklist_state: &'a mut pick_list::State, wow_directories: &'a mut Vec, + share_state: &'a mut ShareState, ) -> Container<'a, Message> { let mut scrollable = Scrollable::new(scrollable_state) .spacing(1) @@ -603,6 +604,45 @@ pub fn data_container<'a, 'b>( .push(data_row) }; + let share_column = { + let description = Text::new(localized_string("share-addons-title")).size(DEFAULT_FONT_SIZE); + let import_button_title_container = Container::new( + Text::new(localized_string("share-addons-import")).size(DEFAULT_FONT_SIZE), + ) + .center_x() + .align_x(Align::Center); + let import_button: Element = Button::new( + &mut share_state.import_btn_state, + import_button_title_container, + ) + .style(style::DefaultBoxedButton(color_palette)) + .on_press(Interaction::ImportAddons) + .into(); + + let export_button_title_container = Container::new( + Text::new(localized_string("share-addons-export")).size(DEFAULT_FONT_SIZE), + ) + .center_x() + .align_x(Align::Center); + let export_button: Element = Button::new( + &mut share_state.export_btn_state, + export_button_title_container, + ) + .style(style::DefaultBoxedButton(color_palette)) + .on_press(Interaction::ExportAddons) + .into(); + + let row = Row::new() + .push(import_button.map(Message::Interaction)) + .push(Space::new(Length::Units(5), Length::Units(0))) + .push(export_button.map(Message::Interaction)); + + Column::new() + .push(description) + .push(Space::new(Length::Units(0), Length::Units(5))) + .push(row) + }; + let config_column = { let config_dir = ajour_core::fs::config_dir(); let config_dir_string = config_dir.as_path().display().to_string(); @@ -864,7 +904,9 @@ pub fn data_container<'a, 'b>( .push(Space::new(Length::Units(0), Length::Units(10))) .push(hide_addons_column) .push(Space::new(Length::Units(0), Length::Units(10))) - .push(delete_saved_variables_column); + .push(delete_saved_variables_column) + .push(Space::new(Length::Units(0), Length::Units(10))) + .push(share_column); let columns_title_text = Text::new(localized_string("columns")).size(DEFAULT_HEADER_FONT_SIZE); let columns_title_text_container = diff --git a/src/gui/mod.rs b/src/gui/mod.rs index ff5412d5..0ad9ad67 100644 --- a/src/gui/mod.rs +++ b/src/gui/mod.rs @@ -173,6 +173,8 @@ pub enum Interaction { ThemeUrlInput(String), ImportTheme, CompressionLevelChanged(i32), + ExportAddons, + ImportAddons, } #[derive(Debug)] @@ -273,6 +275,7 @@ pub struct Ajour { default_backup_compression_format: pick_list::State, pending_confirmation: Option, zstd_compression_level_slider_state: slider::State, + share_state: ShareState, } impl Default for Ajour { @@ -340,6 +343,7 @@ impl Default for Ajour { default_backup_compression_format: Default::default(), pending_confirmation: None, zstd_compression_level_slider_state: Default::default(), + share_state: Default::default(), } } } @@ -1015,6 +1019,7 @@ impl Application for Ajour { &mut self.reset_columns_btn_state, &mut self.localization_picklist_state, &mut self.wow_directories, + &mut self.share_state, ); content = content.push(settings_container) @@ -2051,6 +2056,12 @@ impl Default for ScaleState { } } +#[derive(Default)] +pub struct ShareState { + import_btn_state: button::State, + export_btn_state: button::State, +} + #[allow(clippy::upper_case_acronyms)] #[derive(Debug, Clone)] pub enum BackupFolderKind { diff --git a/src/gui/update.rs b/src/gui/update.rs index 53f1d9e7..20f928c5 100644 --- a/src/gui/update.rs +++ b/src/gui/update.rs @@ -2298,6 +2298,12 @@ pub fn handle_message(ajour: &mut Ajour, message: Message) -> Result { + log::debug!("Interaction::ExportAddons"); + } + Message::Interaction(Interaction::ImportAddons) => { + log::debug!("Interaction::ImportAddons"); + } Message::Interaction(Interaction::CompressionLevelChanged(level)) => { ajour.config.zstd_compression_level = level; let _ = ajour.config.save(); From 1e6efd1bcb3dc3acceebf7fe7f533c20e71b740b Mon Sep 17 00:00:00 2001 From: Cory Date: Sun, 25 Jul 2021 16:02:08 -0700 Subject: [PATCH 06/12] Hook up import / export buttons --- Cargo.lock | 26 ++++------ Cargo.toml | 2 +- crates/core/src/share.rs | 9 ++-- src/gui/mod.rs | 7 +++ src/gui/update.rs | 108 ++++++++++++++++++++++++++++++++++++--- 5 files changed, 124 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index acfb8476..a9d26260 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "ab_glyph" version = "0.2.10" @@ -2515,12 +2517,17 @@ dependencies = [ [[package]] name = "native-dialog" -version = "0.4.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5b69bf2d8a7adddb64521426df8c3125d27ca8da25db97efc7425d8b07c92f3" +checksum = "d689b01017db3e350e0e9798d233cca9ad3bf810e7c02b9b55ec06b9ee7dbd8a" dependencies = [ - "osascript", - "serde", + "cocoa 0.24.0", + "dirs-next", + "objc", + "objc-foundation", + "objc_id", + "once_cell", + "raw-window-handle", "thiserror", "wfd", "which", @@ -2825,17 +2832,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "osascript" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38731fa859ef679f1aec66ca9562165926b442f298467f76f5990f431efe87dc" -dependencies = [ - "serde", - "serde_derive", - "serde_json", -] - [[package]] name = "osmesa-sys" version = "0.1.2" diff --git a/Cargo.toml b/Cargo.toml index 37df3000..68a11ab1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ iced_native = { version = "0.4.0" } async-std = "1.6.2" isahc = { version = "0.9.6", features = ["json"] } image = "0.23.8" -native-dialog = "0.4.2" +native-dialog = "0.5.5" opener = "0.4.1" chrono = { version = "0.4", features = ['serde'] } log = "0.4" diff --git a/crates/core/src/share.rs b/crates/core/src/share.rs index 4aad1559..b668bb8d 100644 --- a/crates/core/src/share.rs +++ b/crates/core/src/share.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; use crate::{addon::Addon, config::Flavor, error, repository::RepositoryKind}; -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct Data { pub flavor: Flavor, pub repo_kind: RepositoryKind, @@ -32,7 +32,7 @@ impl TryFrom<(Flavor, Addon)> for Data { pub fn export( addons: HashMap>, - output_dir: impl AsRef, + output_file: impl AsRef, ) -> Result<(), error::FilesystemError> { let data = addons .into_iter() @@ -48,15 +48,14 @@ pub fn export( }) .collect::>>(); - let file = output_dir.as_ref().join("ajour-addons.yml"); - let contents = serde_yaml::to_string(&data)?; - fs::write(file, contents)?; + fs::write(output_file.as_ref(), contents)?; Ok(()) } +#[derive(Debug, Clone)] pub struct Parsed { pub data: Vec, pub ignored: usize, diff --git a/src/gui/mod.rs b/src/gui/mod.rs index 0ad9ad67..59e39486 100644 --- a/src/gui/mod.rs +++ b/src/gui/mod.rs @@ -5,6 +5,8 @@ mod update; use crate::cli::Opts; use crate::localization::{localized_string, LANG}; use crate::Result; +use ajour_core::repository::RepositoryKind; +use ajour_core::share; use ajour_core::{ addon::{Addon, AddonFolder, AddonState}, cache::catalog_download_latest_or_use_cache, @@ -222,6 +224,10 @@ pub enum Message { CheckRepositoryUpdates(Instant), RepositoryPackagesFetched((Flavor, Result, DownloadError>)), ThemeImported(Result<(String, Vec), ThemeError>), + ExportAddons(Option), + AddonsExported(Result<(), FilesystemError>), + ImportAddons(Option), + ImportParsed(Result, FilesystemError>), } pub struct Ajour { @@ -1910,6 +1916,7 @@ pub enum InstallStatus { pub enum InstallKind { Catalog { source: catalog::Source }, Source, + Import { repo_kind: RepositoryKind }, } #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] diff --git a/src/gui/update.rs b/src/gui/update.rs index 20f928c5..fc51883c 100644 --- a/src/gui/update.rs +++ b/src/gui/update.rs @@ -36,7 +36,7 @@ use { }, iced::{Command, Length}, isahc::http::Uri, - native_dialog::*, + native_dialog::FileDialog, std::collections::{hash_map::DefaultHasher, HashMap}, std::convert::TryFrom, std::hash::Hasher, @@ -44,6 +44,8 @@ use { strfmt::strfmt, }; +use ajour_core::share; + use crate::gui::Confirm; #[cfg(target_os = "windows")] use crate::tray::{TrayMessage, SHOULD_EXIT, TRAY_SENDER}; @@ -1799,7 +1801,9 @@ pub fn handle_message(ajour: &mut Ajour, message: Message) -> Result !(id == a.id && a.kind == kind), + InstallKind::Catalog { .. } | InstallKind::Import { .. } => { + !(id == a.id && a.kind == kind) + } InstallKind::Source => a.kind != kind, }); @@ -1902,7 +1906,7 @@ pub fn handle_message(ajour: &mut Ajour, message: Message) -> Result { install_addon.status = InstallStatus::Unavailable; } - InstallKind::Source => { + InstallKind::Source | InstallKind::Import { .. } => { install_addon.status = InstallStatus::Error(error.to_string()); } } @@ -2300,10 +2304,83 @@ pub fn handle_message(ajour: &mut Ajour, message: Message) -> Result { log::debug!("Interaction::ExportAddons"); + + return Ok(Command::perform( + select_export_file(), + Message::ExportAddons, + )); } + Message::ExportAddons(path) => { + if let Some(path) = path { + log::debug!("Message::ExportAddons({:?})", &path); + + let addons = ajour.addons.clone(); + + return Ok(Command::perform( + async { share::export(addons, path) }, + Message::AddonsExported, + )); + } + } + Message::AddonsExported(result) => match result.context("Failed to export addons") { + Ok(_) => { + log::debug!("Message::AddonsExported"); + } + Err(error) => { + log_error(&error); + + ajour.error = Some(error); + } + }, Message::Interaction(Interaction::ImportAddons) => { log::debug!("Interaction::ImportAddons"); + + return Ok(Command::perform( + select_import_file(), + Message::ImportAddons, + )); + } + Message::ImportAddons(path) => { + if let Some(path) = path { + log::debug!("Message::ImportAddons({:?})", &path); + + let current_addons = ajour.addons.clone(); + + return Ok(Command::perform( + async { share::parse_only_needed(current_addons, path) }, + Message::ImportParsed, + )); + } } + Message::ImportParsed(result) => match result.context("Failed to import addons") { + Ok(parsed) => { + log::debug!("Message::ImportParsed"); + + let mut commands = vec![]; + + for (flavor, parsed) in parsed.into_iter() { + for data in parsed.data { + let id = data.id.clone(); + let repo_kind = data.repo_kind; + let install_kind = InstallKind::Import { repo_kind }; + + let command = Command::perform( + async move { (flavor, id, install_kind) }, + |(a, b, c)| Message::Interaction(Interaction::InstallAddon(a, b, c)), + ); + + commands.push(command); + } + } + + return Ok(Command::batch(commands)); + } + Err(error) => { + log_error(&error); + + ajour.error = Some(error); + } + }, Message::Interaction(Interaction::CompressionLevelChanged(level)) => { ajour.config.zstd_compression_level = level; let _ = ajour.config.save(); @@ -2508,8 +2585,8 @@ pub fn handle_message(ajour: &mut Ajour, message: Message) -> Result Option { - let dialog = OpenSingleDir { dir: None }; - if let Ok(show) = dialog.show() { + let dialog = FileDialog::new(); + if let Ok(show) = dialog.show_open_single_dir() { return show; } @@ -2517,14 +2594,28 @@ async fn select_directory() -> Option { } async fn select_wow_directory(flavor: Option) -> (Option, Option) { - let dialog = OpenSingleDir { dir: None }; - if let Ok(show) = dialog.show() { + let dialog = FileDialog::new(); + if let Ok(show) = dialog.show_open_single_dir() { return (show, flavor); } (None, flavor) } +async fn select_export_file() -> Option { + let dialog = FileDialog::new() + .add_filter("YML File", &["yml"]) + .set_filename("ajour-addons.yml"); + + dialog.show_save_single_file().ok().flatten() +} + +async fn select_import_file() -> Option { + let dialog = FileDialog::new().add_filter("YML File", &["yml"]); + + dialog.show_open_single_file().ok().flatten() +} + async fn perform_read_addon_directory( addon_cache: Option>>, fingerprint_cache: Option>>, @@ -2625,6 +2716,9 @@ async fn perform_fetch_latest_addon( RepositoryPackage::from_source_url(flavor, url)? } + InstallKind::Import { repo_kind } => { + RepositoryPackage::from_repo_id(flavor, repo_kind, id)? + } }; repo_package.resolve_metadata().await?; From 15883b128e70b896f50bbcaafab46cc387551fc3 Mon Sep 17 00:00:00 2001 From: Cory Date: Sun, 25 Jul 2021 16:03:55 -0700 Subject: [PATCH 07/12] Use full name --- crates/core/src/share.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/core/src/share.rs b/crates/core/src/share.rs index b668bb8d..ede1f211 100644 --- a/crates/core/src/share.rs +++ b/crates/core/src/share.rs @@ -41,7 +41,7 @@ pub fn export( flavor, addons .into_iter() - .map(|a| Data::try_from((flavor, a))) + .map(|addon| Data::try_from((flavor, addon))) .flatten() .collect::>(), ) @@ -76,8 +76,8 @@ pub fn parse_only_needed( .into_iter() .filter(|data| { if let Some(existing) = existing_addons.get(&flavor) { - !existing.iter().any(|a| { - if let Some(existing_repo) = a.repository() { + !existing.iter().any(|addon| { + if let Some(existing_repo) = addon.repository() { let kind = data.repo_kind; existing_repo.id == data.id && existing_repo.kind == kind From bbd84aedcbb7c041dd8777e920e276a8d44bf60a Mon Sep 17 00:00:00 2001 From: Cory Date: Sun, 25 Jul 2021 16:09:27 -0700 Subject: [PATCH 08/12] fix import --- src/gui/update.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/gui/update.rs b/src/gui/update.rs index fc51883c..33e0d4f5 100644 --- a/src/gui/update.rs +++ b/src/gui/update.rs @@ -23,6 +23,7 @@ use { repository::{ batch_refresh_repository_packages, Changelog, RepositoryKind, RepositoryPackage, }, + share, utility::{download_update_to_temp_file, get_latest_release, wow_path_resolution}, }, ajour_weak_auras::{Aura, AuraStatus}, @@ -44,8 +45,6 @@ use { strfmt::strfmt, }; -use ajour_core::share; - use crate::gui::Confirm; #[cfg(target_os = "windows")] use crate::tray::{TrayMessage, SHOULD_EXIT, TRAY_SENDER}; From 0e16ad7638f9686317f4189800ee1a5f6eca978f Mon Sep 17 00:00:00 2001 From: Cory Date: Sun, 25 Jul 2021 16:10:06 -0700 Subject: [PATCH 09/12] Fix error message --- src/gui/update.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/update.rs b/src/gui/update.rs index 33e0d4f5..02c36a5a 100644 --- a/src/gui/update.rs +++ b/src/gui/update.rs @@ -2351,7 +2351,7 @@ pub fn handle_message(ajour: &mut Ajour, message: Message) -> Result match result.context("Failed to import addons") { + Message::ImportParsed(result) => match result.context("Failed to parse import file") { Ok(parsed) => { log::debug!("Message::ImportParsed"); From d7dd2b5913e3302de5c04f83db3f5cadb021b4f5 Mon Sep 17 00:00:00 2001 From: Cory Date: Sat, 31 Jul 2021 13:44:23 -0700 Subject: [PATCH 10/12] Use rfd crate to prevent panic on macos --- Cargo.lock | 221 +++++++++++++++++++++++++++++++++++++--------- Cargo.toml | 2 +- src/gui/update.rs | 18 ++-- 3 files changed, 190 insertions(+), 51 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a9d26260..831cc1db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -71,17 +71,17 @@ dependencies = [ "json-gettext", "log", "log-panics", - "native-dialog", "num-format", "once_cell", "open", "opener", + "rfd", "serde", "serde_json", "strfmt", "structopt", "timeago", - "version-compare", + "version-compare 0.0.11", "winapi 0.3.9", ] @@ -362,6 +362,18 @@ dependencies = [ "syn", ] +[[package]] +name = "atk-sys" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f530e4af131d94cc4fa15c5c9d0348f0ef28bac64ba660b6b2a1cf2605dedfce" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + [[package]] name = "atomic-waker" version = "1.0.0" @@ -549,6 +561,16 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba" +[[package]] +name = "cairo-sys-rs" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ed2639b9ad5f1d6efa76de95558e11339e7318426d84ac4890b86c03e828ca7" +dependencies = [ + "libc", + "system-deps", +] + [[package]] name = "calloop" version = "0.6.5" @@ -1482,6 +1504,36 @@ dependencies = [ "byteorder", ] +[[package]] +name = "gdk-pixbuf-sys" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bfe468a7f43e97b8d193a762b6c5cf67a7d36cacbc0b9291dbcae24bfea1e8f" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gdk-sys" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a9653cfc500fd268015b1ac055ddbc3df7a5c9ea3f4ccef147b3957bd140d69" +dependencies = [ + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "pkg-config", + "system-deps", +] + [[package]] name = "generator" version = "0.6.24" @@ -1689,6 +1741,19 @@ version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" +[[package]] +name = "gio-sys" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e24fb752f8f5d2cf6bbc2c606fd2bc989c81c5e2fe321ab974d54f8b6344eac" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", + "winapi 0.3.9", +] + [[package]] name = "gl_generator" version = "0.14.0" @@ -1709,6 +1774,16 @@ dependencies = [ "version_check", ] +[[package]] +name = "glib-sys" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e9b997a66e9a23d073f2b1abb4dbfc3925e0b8952f67efd8d9b6e168e4cdc1" +dependencies = [ + "libc", + "system-deps", +] + [[package]] name = "glob" version = "0.3.0" @@ -1863,6 +1938,35 @@ dependencies = [ "xi-unicode", ] +[[package]] +name = "gobject-sys" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "952133b60c318a62bf82ee75b93acc7e84028a093e06b9e27981c2b6fe68218c" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gtk-sys" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89acda6f084863307d948ba64a4b1ef674e8527dddab147ee4cdcc194c880457" +dependencies = [ + "atk-sys", + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "system-deps", +] + [[package]] name = "guillotiere" version = "0.6.0" @@ -2515,25 +2619,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "native-dialog" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d689b01017db3e350e0e9798d233cca9ad3bf810e7c02b9b55ec06b9ee7dbd8a" -dependencies = [ - "cocoa 0.24.0", - "dirs-next", - "objc", - "objc-foundation", - "objc_id", - "once_cell", - "raw-window-handle", - "thiserror", - "wfd", - "which", - "winapi 0.3.9", -] - [[package]] name = "nb-connect" version = "1.0.3" @@ -2859,6 +2944,18 @@ dependencies = [ "ttf-parser 0.12.0", ] +[[package]] +name = "pango-sys" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d2650c8b62d116c020abd0cea26a4ed96526afda89b1c4ea567131fdefc890" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + [[package]] name = "parking" version = "2.0.0" @@ -3399,6 +3496,29 @@ dependencies = [ "rand 0.7.3", ] +[[package]] +name = "rfd" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1084e570d9ce1890734b33edd8c1a7b7276076f9610fa23a48aa955587da141" +dependencies = [ + "block", + "dispatch", + "glib-sys", + "gobject-sys", + "gtk-sys", + "js-sys", + "lazy_static", + "objc", + "objc-foundation", + "objc_id", + "raw-window-handle", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winapi 0.3.9", +] + [[package]] name = "rust-argon2" version = "0.8.3" @@ -3779,6 +3899,24 @@ dependencies = [ "syn", ] +[[package]] +name = "strum" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57bd81eb48f4c437cadc685403cad539345bf703d78e63707418431cecd4522b" + +[[package]] +name = "strum_macros" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "svg_fmt" version = "0.4.1" @@ -3808,6 +3946,21 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "system-deps" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3ecc17269a19353b3558b313bba738b25d82993e30d62a18406a24aba4649b" +dependencies = [ + "heck", + "pkg-config", + "strum", + "strum_macros", + "thiserror", + "toml", + "version-compare 0.0.10", +] + [[package]] name = "tar" version = "0.4.33" @@ -4085,6 +4238,12 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" +[[package]] +name = "version-compare" +version = "0.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d63556a25bae6ea31b52e640d7c41d1ab27faba4ccb600013837a3d0b3994ca1" + [[package]] name = "version-compare" version = "0.0.11" @@ -4320,16 +4479,6 @@ dependencies = [ "cc", ] -[[package]] -name = "wfd" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e713040b67aae5bf1a0ae3e1ebba8cc29ab2b90da9aa1bff6e09031a8a41d7a8" -dependencies = [ - "libc", - "winapi 0.3.9", -] - [[package]] name = "wgpu" version = "0.6.2" @@ -4401,16 +4550,6 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "which" -version = "4.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87c14ef7e1b8b8ecfc75d5eca37949410046e66f15d185c01d70824f1f8111ef" -dependencies = [ - "libc", - "thiserror", -] - [[package]] name = "winapi" version = "0.2.8" diff --git a/Cargo.toml b/Cargo.toml index 68a11ab1..c4d85201 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ iced_native = { version = "0.4.0" } async-std = "1.6.2" isahc = { version = "0.9.6", features = ["json"] } image = "0.23.8" -native-dialog = "0.5.5" +rfd = "0.4.0" opener = "0.4.1" chrono = { version = "0.4", features = ['serde'] } log = "0.4" diff --git a/src/gui/update.rs b/src/gui/update.rs index 02c36a5a..b006d5bd 100644 --- a/src/gui/update.rs +++ b/src/gui/update.rs @@ -37,7 +37,7 @@ use { }, iced::{Command, Length}, isahc::http::Uri, - native_dialog::FileDialog, + rfd::FileDialog, std::collections::{hash_map::DefaultHasher, HashMap}, std::convert::TryFrom, std::hash::Hasher, @@ -2585,8 +2585,8 @@ pub fn handle_message(ajour: &mut Ajour, message: Message) -> Result Option { let dialog = FileDialog::new(); - if let Ok(show) = dialog.show_open_single_dir() { - return show; + if let Some(show) = dialog.pick_folder() { + return Some(show); } None @@ -2594,8 +2594,8 @@ async fn select_directory() -> Option { async fn select_wow_directory(flavor: Option) -> (Option, Option) { let dialog = FileDialog::new(); - if let Ok(show) = dialog.show_open_single_dir() { - return (show, flavor); + if let Some(show) = dialog.pick_folder() { + return (Some(show), flavor); } (None, flavor) @@ -2603,16 +2603,16 @@ async fn select_wow_directory(flavor: Option) -> (Option, Optio async fn select_export_file() -> Option { let dialog = FileDialog::new() - .add_filter("YML File", &["yml"]) - .set_filename("ajour-addons.yml"); + .set_file_name("ajour-addons.yml") + .add_filter("YML File", &["yml"]); - dialog.show_save_single_file().ok().flatten() + dialog.save_file() } async fn select_import_file() -> Option { let dialog = FileDialog::new().add_filter("YML File", &["yml"]); - dialog.show_open_single_file().ok().flatten() + dialog.pick_file() } async fn perform_read_addon_directory( From 25e4d587e7115d01e1d2fff8115218d3479b76d8 Mon Sep 17 00:00:00 2001 From: Cory Date: Sat, 31 Jul 2021 14:06:31 -0700 Subject: [PATCH 11/12] Use async version of dialog --- src/gui/update.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/gui/update.rs b/src/gui/update.rs index b006d5bd..4efa94bd 100644 --- a/src/gui/update.rs +++ b/src/gui/update.rs @@ -37,7 +37,7 @@ use { }, iced::{Command, Length}, isahc::http::Uri, - rfd::FileDialog, + rfd::AsyncFileDialog, std::collections::{hash_map::DefaultHasher, HashMap}, std::convert::TryFrom, std::hash::Hasher, @@ -2584,35 +2584,35 @@ pub fn handle_message(ajour: &mut Ajour, message: Message) -> Result Option { - let dialog = FileDialog::new(); - if let Some(show) = dialog.pick_folder() { - return Some(show); + let dialog = AsyncFileDialog::new(); + if let Some(show) = dialog.pick_folder().await { + return Some(show.path().to_path_buf()); } None } async fn select_wow_directory(flavor: Option) -> (Option, Option) { - let dialog = FileDialog::new(); - if let Some(show) = dialog.pick_folder() { - return (Some(show), flavor); + let dialog = AsyncFileDialog::new(); + if let Some(show) = dialog.pick_folder().await { + return (Some(show.path().to_path_buf()), flavor); } (None, flavor) } async fn select_export_file() -> Option { - let dialog = FileDialog::new() + let dialog = AsyncFileDialog::new() .set_file_name("ajour-addons.yml") .add_filter("YML File", &["yml"]); - dialog.save_file() + dialog.save_file().await.map(|f| f.path().to_path_buf()) } async fn select_import_file() -> Option { - let dialog = FileDialog::new().add_filter("YML File", &["yml"]); + let dialog = AsyncFileDialog::new().add_filter("YML File", &["yml"]); - dialog.pick_file() + dialog.pick_file().await.map(|f| f.path().to_path_buf()) } async fn perform_read_addon_directory( From b316e4b109c4c99349429cc55a4fe2ee73f85b13 Mon Sep 17 00:00:00 2001 From: Cory Date: Sat, 31 Jul 2021 14:14:35 -0700 Subject: [PATCH 12/12] Switch to my addons after importing file --- src/gui/update.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/update.rs b/src/gui/update.rs index 4efa94bd..a3c0269d 100644 --- a/src/gui/update.rs +++ b/src/gui/update.rs @@ -2345,6 +2345,8 @@ pub fn handle_message(ajour: &mut Ajour, message: Message) -> Result