From 5c68b550678601a9646e0c44e617069ee16db348 Mon Sep 17 00:00:00 2001 From: pml68 Date: Wed, 26 Feb 2025 23:23:52 +0100 Subject: feat: switch to personal `iced` fork, work on version info --- src/environment.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src/environment.rs') diff --git a/src/environment.rs b/src/environment.rs index 1ebb81b..70953a0 100644 --- a/src/environment.rs +++ b/src/environment.rs @@ -2,6 +2,16 @@ use std::env; use std::path::PathBuf; pub const CONFIG_FILE_NAME: &str = "config.toml"; +pub const VERSION: &str = env!("CARGO_PKG_VERSION"); +pub const GIT_HASH: Option<&str> = option_env!("GIT_HASH"); + +pub fn formatted_version() -> String { + let hash = GIT_HASH + .map(|hash| format!(" ({hash})")) + .unwrap_or_default(); + + format!("{}{hash}", VERSION) +} pub fn config_dir() -> PathBuf { portable_dir().unwrap_or_else(platform_specific_config_dir) -- cgit v1.2.3 From 13ec2282c914c076ff50ddc44bee1feeb7983ae8 Mon Sep 17 00:00:00 2001 From: pml68 Date: Sat, 1 Mar 2025 02:29:03 +0100 Subject: refactor: make config an `Arc` in `App` --- Cargo.lock | 14 ++++++- src/config.rs | 3 ++ src/dialogs.rs | 19 ++++++---- src/environment.rs | 3 ++ src/error.rs | 6 +-- src/main.rs | 101 ++++++++++++++++++++++++++++++++------------------- src/types/project.rs | 7 +++- 7 files changed, 102 insertions(+), 51 deletions(-) (limited to 'src/environment.rs') diff --git a/Cargo.lock b/Cargo.lock index 26a20ef..a4992bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2078,10 +2078,11 @@ dependencies = [ [[package]] name = "iced_custom_highlighter" version = "0.1.0" -source = "git+https://github.com/pml68/iced_custom_highlighter?branch=master#e4708bdb31a792918a4bc162aebbc296fce9ce85" +source = "git+https://github.com/pml68/iced_custom_highlighter?branch=master#aa5e7e024061a759fb89947185bb4969c3e21e66" dependencies = [ "iced_core", "syntect", + "two-face", ] [[package]] @@ -4866,6 +4867,17 @@ version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" +[[package]] +name = "two-face" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384eda438ddf62e2c6f39a174452d952d9d9df5a8ad5ade22198609f8dcaf852" +dependencies = [ + "once_cell", + "serde", + "syntect", +] + [[package]] name = "typenum" version = "1.18.0" diff --git a/src/config.rs b/src/config.rs index 975437f..1da1239 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,3 +1,6 @@ +// (c) 2022-2024 Cory Forsstrom, Casper Rogild Storm, Calvin Lee, Andrew Baldwin, Reza Alizadeh Majd +// (c) 2024-2025 Polesznyák Márk László + use std::path::PathBuf; use serde::Deserialize; diff --git a/src/dialogs.rs b/src/dialogs.rs index 2d916b1..5954ff5 100644 --- a/src/dialogs.rs +++ b/src/dialogs.rs @@ -1,21 +1,26 @@ -use rfd::{MessageButtons, MessageDialog, MessageDialogResult, MessageLevel}; +use rfd::{ + AsyncMessageDialog, MessageButtons, MessageDialog, MessageDialogResult, + MessageLevel, +}; -pub fn error_dialog(description: impl Into) { - let _ = MessageDialog::new() +pub async fn error_dialog(description: impl Into) { + let _ = AsyncMessageDialog::new() .set_level(MessageLevel::Error) .set_buttons(MessageButtons::Ok) .set_title("Oops! Something went wrong.") .set_description(description) - .show(); + .show() + .await; } -pub fn warning_dialog(description: impl Into) { - let _ = MessageDialog::new() +pub async fn warning_dialog(description: impl Into) { + let _ = AsyncMessageDialog::new() .set_level(MessageLevel::Warning) .set_buttons(MessageButtons::Ok) .set_title("Heads up!") .set_description(description) - .show(); + .show() + .await; } pub fn unsaved_changes_dialog(description: impl Into) -> bool { diff --git a/src/environment.rs b/src/environment.rs index 70953a0..8efc425 100644 --- a/src/environment.rs +++ b/src/environment.rs @@ -1,3 +1,6 @@ +// (c) 2023-2025 Cory Forsstrom, Casper Rogild Storm +// (c) 2024-2025 Polesznyák Márk László + use std::env; use std::path::PathBuf; diff --git a/src/error.rs b/src/error.rs index 002a1fc..9e1ee9d 100644 --- a/src/error.rs +++ b/src/error.rs @@ -7,16 +7,16 @@ use thiserror::Error; #[error(transparent)] pub enum Error { IO(Arc), - #[error("config does not exist")] + #[error("Config does not exist")] ConfigMissing, #[error("JSON parsing error: {0}")] SerdeJSON(Arc), #[error("TOML parsing error: {0}")] SerdeTOML(#[from] toml::de::Error), RustFmt(Arc), - #[error("the element tree contains no matching element")] + #[error("The element tree contains no matching element")] NonExistentElement, - #[error("the file dialog has been closed without selecting a valid option")] + #[error("The file dialog has been closed without selecting a valid option")] DialogClosed, #[error("{0}")] Other(String), diff --git a/src/main.rs b/src/main.rs index e7faea1..b645e80 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,6 +12,7 @@ mod values; mod widget; use std::path::PathBuf; +use std::sync::Arc; use config::Config; use dialogs::{error_dialog, unsaved_changes_dialog, warning_dialog}; @@ -60,7 +61,7 @@ struct App { is_loading: bool, project_path: Option, project: Project, - config: Config, + config: Arc, theme: Animated, pane_state: pane_grid::State, focus: Option, @@ -86,24 +87,25 @@ impl App { }, ); - let config = config_load.unwrap_or_default(); + let config = Arc::new(config_load.unwrap_or_default()); let theme = config.selected_theme(); - let mut task = Task::none(); - - if let Some(path) = config.last_project.clone() { + let task = if let Some(path) = config.last_project.clone() { if path.exists() && path.is_file() { - task = Task::perform( + Task::perform( Project::from_path(path, config.clone()), Message::FileOpened, - ); + ) } else { - warning_dialog(format!( + Task::future(warning_dialog(format!( "The file {} does not exist, or isn't a file.", path.to_string_lossy() - )); + ))) + .discard() } - } + } else { + Task::none() + }; ( Self { @@ -147,32 +149,37 @@ impl App { match message { Message::SwitchTheme(event) => { self.theme.update(event); + + Task::none() } - Message::CopyCode => { - return clipboard::write(self.editor_content.text()); + Message::CopyCode => clipboard::write(self.editor_content.text()), + Message::SwitchPage(page) => { + self.designer_page = page; + Task::none() } - Message::SwitchPage(page) => self.designer_page = page, Message::EditorAction(action) => { if let text_editor::Action::Scroll { lines: _ } = action { self.editor_content.perform(action); } + Task::none() } Message::RefreshEditorContent => { match self.project.app_code(&self.config) { Ok(code) => { self.editor_content = text_editor::Content::with_text(&code); + Task::none() } - Err(error) => error_dialog(error), + Err(error) => Task::future(error_dialog(error)).discard(), } } Message::DropNewElement(name, point, _) => { - return iced_drop::zones_on_point( + iced_drop::zones_on_point( move |zones| Message::HandleNew(name.clone(), zones), point, None, None, - ); + ) } Message::HandleNew(name, zones) => { let ids: Vec = zones.into_iter().map(|z| z.0).collect(); @@ -183,25 +190,29 @@ impl App { self.project.element_tree.as_mut(), action, ); + self.is_dirty = true; match result { Ok(Some(ref element)) => { self.project.element_tree = Some(element.clone()); } - Err(error) => error_dialog(error), + Err(error) => { + return Task::future(error_dialog(error)) + .map(|_| Message::RefreshEditorContent); + } _ => {} } - - self.is_dirty = true; - return Task::done(Message::RefreshEditorContent); + Task::done(Message::RefreshEditorContent) + } else { + Task::none() } } Message::MoveElement(element, point, _) => { - return iced_drop::zones_on_point( + iced_drop::zones_on_point( move |zones| Message::HandleMove(element.clone(), zones), point, None, None, - ); + ) } Message::HandleMove(element, zones) => { let ids: Vec = zones.into_iter().map(|z| z.0).collect(); @@ -217,26 +228,31 @@ impl App { action, ); if let Err(error) = result { - error_dialog(error); + return Task::future(error_dialog(error)).discard(); } self.is_dirty = true; - return Task::done(Message::RefreshEditorContent); + Task::done(Message::RefreshEditorContent) + } else { + Task::none() } } Message::PaneResized(pane_grid::ResizeEvent { split, ratio }) => { self.pane_state.resize(split, ratio); + Task::none() } Message::PaneClicked(pane) => { self.focus = Some(pane); + Task::none() } Message::PaneDragged(pane_grid::DragEvent::Dropped { pane, target, }) => { self.pane_state.drop(pane, target); + Task::none() } - Message::PaneDragged(_) => {} + Message::PaneDragged(_) => Task::none(), Message::NewFile => { if !self.is_loading { if !self.is_dirty { @@ -252,26 +268,32 @@ impl App { self.editor_content = text_editor::Content::new(); } } + + Task::none() } Message::OpenFile => { if !self.is_loading { if !self.is_dirty { self.is_loading = true; - return Task::perform( + Task::perform( Project::from_file(self.config.clone()), Message::FileOpened, - ); + ) } else if unsaved_changes_dialog( "You have unsaved changes. Do you wish to discard these and open another project?", ) { self.is_dirty = false; self.is_loading = true; - return Task::perform( + Task::perform( Project::from_file(self.config.clone()), Message::FileOpened, - ); + ) + } else { + Task::none() } + } else { + Task::none() } } Message::FileOpened(result) => { @@ -282,31 +304,35 @@ impl App { Ok((path, project)) => { self.project = project; self.project_path = Some(path); - return Task::done(Message::RefreshEditorContent); + Task::done(Message::RefreshEditorContent) } - Err(error) => error_dialog(error), + Err(error) => Task::future(error_dialog(error)).discard(), } } Message::SaveFile => { if !self.is_loading { self.is_loading = true; - return Task::perform( + Task::perform( self.project .clone() .write_to_file(self.project_path.clone()), Message::FileSaved, - ); + ) + } else { + Task::none() } } Message::SaveFileAs => { if !self.is_loading { self.is_loading = true; - return Task::perform( + Task::perform( self.project.clone().write_to_file(None), Message::FileSaved, - ); + ) + } else { + Task::none() } } Message::FileSaved(result) => { @@ -316,13 +342,12 @@ impl App { Ok(path) => { self.project_path = Some(path); self.is_dirty = false; + Task::none() } - Err(error) => error_dialog(error), + Err(error) => Task::future(error_dialog(error)).discard(), } } } - - Task::none() } fn subscription(&self) -> iced::Subscription { diff --git a/src/types/project.rs b/src/types/project.rs index e665d5e..721783e 100644 --- a/src/types/project.rs +++ b/src/types/project.rs @@ -1,4 +1,5 @@ use std::path::{Path, PathBuf}; +use std::sync::Arc; extern crate fxhash; use fxhash::FxHashMap; @@ -58,7 +59,7 @@ impl Project { pub async fn from_path( path: PathBuf, - config: Config, + config: Arc, ) -> Result<(PathBuf, Self), Error> { let contents = tokio::fs::read_to_string(&path).await?; let mut project: Self = serde_json::from_str(&contents)?; @@ -68,7 +69,9 @@ impl Project { Ok((path, project)) } - pub async fn from_file(config: Config) -> Result<(PathBuf, Self), Error> { + pub async fn from_file( + config: Arc, + ) -> Result<(PathBuf, Self), Error> { let picked_file = rfd::AsyncFileDialog::new() .set_title("Open a JSON file...") .add_filter("*.json, *.JSON", &["json", "JSON"]) -- cgit v1.2.3