diff --git a/Cargo.lock b/Cargo.lock index 4c65f7d..85805bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -418,6 +418,7 @@ version = "0.0.0" dependencies = [ "chipbox-common", "color-eyre", + "cowstr", "cpal", "gen_value", "home", @@ -436,6 +437,7 @@ name = "chipbox-common" version = "0.1.0" dependencies = [ "chrono", + "cowstr", "cssparser 0.33.0", "cssparser-color", "derive_more", @@ -472,6 +474,7 @@ dependencies = [ "chipbox-ui-panel", "chipbox-ui-spinner", "const_format", + "cowstr", "futures", "serde", "tauri-sys", @@ -557,6 +560,35 @@ dependencies = [ "objc", ] +[[package]] +name = "code-product" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9feea482d196b435bb8857c2ec1274926993bc3342953515620eb9641337ee01" +dependencies = [ + "code-product-lib", + "code-product-macro", +] + +[[package]] +name = "code-product-lib" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5938681371198e7a690aa008843d39bd3b3b65f17b0101518c388f453c0aaf4e" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "code-product-macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0371403e32bb895fc60f96b3b76a46a17b99a9ff85b3dbff0e1c5ff0f1ec8e13" +dependencies = [ + "code-product-lib", + "proc-macro2", +] + [[package]] name = "color-eyre" version = "0.6.3" @@ -631,6 +663,12 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "constptr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f6b816ec3d57d4febea032f3ce2bf9dca119f999a865f9f24d7020d9eb5167e" + [[package]] name = "convert_case" version = "0.4.0" @@ -697,6 +735,19 @@ dependencies = [ "bindgen", ] +[[package]] +name = "cowstr" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613de46416b29f30c0c581b5f4cd7dfc01991f59c416b30aa85a0a82af7c791e" +dependencies = [ + "code-product", + "constptr", + "mutants", + "serde", + "serde_test", +] + [[package]] name = "cpal" version = "0.15.3" @@ -2502,6 +2553,12 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "mutants" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc0287524726960e07b119cebd01678f852f147742ae0d925e6a520dca956126" + [[package]] name = "ndk" version = "0.6.0" @@ -3521,6 +3578,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_test" +version = "1.0.176" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a2f49ace1498612d14f7e0b8245519584db8299541dfe31a06374a828d620ab" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" diff --git a/Cargo.toml b/Cargo.toml index a57f97a..156897d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ once_cell = "1.19" chrono = { version = "0.4", features = ["serde"] } rb = { version = "0.4" } derive_more = { version = "0.99", features = ["nightly"] } +cowstr = { version = "1.3", features = ["serde"] } ## tracing tracing = "0.1" tracing-subscriber = { version = "0.3" } diff --git a/backend/lib/Cargo.toml b/backend/lib/Cargo.toml index 3a031d5..b8fc022 100644 --- a/backend/lib/Cargo.toml +++ b/backend/lib/Cargo.toml @@ -21,3 +21,4 @@ gen_value = { workspace = true } once_cell = { workspace = true } rb = { workspace = true } tauri = { workspace = true } +cowstr.workspace = true diff --git a/backend/lib/src/app_data.rs b/backend/lib/src/app_data.rs index 718b6ad..a62a049 100644 --- a/backend/lib/src/app_data.rs +++ b/backend/lib/src/app_data.rs @@ -1,8 +1,7 @@ -use self::app_state::AppState; -use crate::{common, AppThread, ThreadMsg}; -use common::app::{BackendMsg, BackendResponse, FrontendMsg, FrontendRequest}; +pub mod msg; mod app_state; +use self::app_state::AppState; /// All data required for managing the application. /// @@ -25,96 +24,4 @@ impl AppData { pub fn tauri_app(&self) -> &tauri::AppHandle { &self.tauri_app } - - /// Handles a message from the parent thread. - /// Returns `true` if the app should quit. - pub fn handle_msg(&mut self, msg: ThreadMsg) -> bool { - match msg { - // Handle frontend message. - ThreadMsg::Frontend(msg) => self.handle_frontend_msg(msg), - // Quit. - ThreadMsg::Exit => return true, - }; - false - } - - /// Handles messages from the frontend. - fn handle_frontend_msg(&mut self, msg: FrontendMsg) { - match msg { - FrontendMsg::Request(request) => { - self.handle_frontend_request(request) - } - } - } - - /// Handles the request and sends a response to the frontend. - fn handle_frontend_request(&mut self, request: FrontendRequest) { - // Handle request and prepare response. - let response = match request { - FrontendRequest::BackendAppState => { - self.backend_app_state_response() - } - FrontendRequest::Settings => self.backend_settings_response(), - FrontendRequest::UseDefaultSettings => { - self.use_default_settings_response() - } - }; - - // Send response. - AppThread::send_message( - &self.tauri_app, - BackendMsg::Response(response), - ); - } - - /// Reply with current state. - fn backend_app_state_response(&mut self) -> BackendResponse { - // Get state and convert it to `BackendAppState`. - let app_state = (&self.state).into(); - - // Prepare response. - BackendResponse::BackendAppState(app_state) - } - - /// Reply with current settings. - fn backend_settings_response(&mut self) -> BackendResponse { - // Get settings. - let settings_opt = match self.state { - AppState::Idle { ref settings } => Some(settings.clone()), - _ => None, - }; - - // Prepare response. - BackendResponse::Settings(settings_opt) - } - - /// Set default settings and reply with a copy. - pub fn use_default_settings_response(&mut self) -> BackendResponse { - // Apply and return settings. - match self.state { - // Fail gracefully if in the middle of reading settings. - AppState::ReadingSettings => { - tracing::error!("Frontend attempted to set settings to default while backend was still reading config."); - } - // Change state to idle if awaiting config. - AppState::AwaitConfig { .. } => { - self.state = AppState::Idle { - settings: Default::default(), - }; - } - // Modify if idle. - AppState::Idle { ref mut settings } => { - *settings = Default::default(); - } - // Modify if editing a project. - AppState::Edit { - ref mut settings, .. - } => { - *settings = Default::default(); - } - } - - // Prepare response. - BackendResponse::UseDefaultSettings(Default::default()) - } } diff --git a/backend/lib/src/app_data/app_state.rs b/backend/lib/src/app_data/app_state.rs index 08d1598..d55cbfe 100644 --- a/backend/lib/src/app_data/app_state.rs +++ b/backend/lib/src/app_data/app_state.rs @@ -40,7 +40,9 @@ impl From<&AppState> for BackendAppState { match app { AppState::ReadingSettings => BackendAppState::ReadingSettings, AppState::AwaitConfig { ref reason } => { - BackendAppState::AwaitConfig { reason: *reason } + BackendAppState::AwaitConfig { + reason: reason.clone(), + } } AppState::Idle { .. } => BackendAppState::Idle, AppState::Edit { .. } => BackendAppState::Editor, diff --git a/backend/lib/src/app_data/app_state/edit_state/audio_engine/host_id.rs b/backend/lib/src/app_data/app_state/edit_state/audio_engine/host_id.rs index c0b5797..0e77181 100644 --- a/backend/lib/src/app_data/app_state/edit_state/audio_engine/host_id.rs +++ b/backend/lib/src/app_data/app_state/edit_state/audio_engine/host_id.rs @@ -1,4 +1,5 @@ use chipbox_common as common; +use cowstr::CowStr; use std::str::FromStr; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -13,20 +14,20 @@ impl From for cpal::HostId { #[derive(Debug)] pub enum ParseError { - Invalid(String), - WrongPlatform(String), + Invalid { value: CowStr }, + WrongPlatform { value: CowStr }, } impl std::fmt::Display for ParseError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - ParseError::Invalid(s) => { - write!(f, "`{s}` is not convertible to a valid host id") + ParseError::Invalid { value } => { + write!(f, "`{value}` is not convertible to a valid host id") } - ParseError::WrongPlatform(s) => { + ParseError::WrongPlatform { value } => { write!( f, - "host `{s}` is not supported on this platform ({platform})", + "host `{value}` is not supported on this platform ({platform})", platform = std::env::consts::OS ) } @@ -38,7 +39,7 @@ impl std::error::Error for ParseError {} impl FromStr for HostId { type Err = ParseError; - fn from_str(s: &str) -> Result { + fn from_str(value: &str) -> Result { const WASAPI: &str = "wasapi"; const ASIO: &str = "asio"; const JACK: &str = "jack"; @@ -53,7 +54,7 @@ impl FromStr for HostId { NULL, ]; - match s.to_lowercase().as_str() { + match value.to_lowercase().as_str() { #[cfg(target_os = "windows")] WASAPI => Ok(Self(cpal::HostId::Wasapi)), #[cfg(target_os = "windows")] @@ -94,10 +95,14 @@ impl FromStr for HostId { )))] NULL => Ok(Self(cpal::HostId::Null)), _ => { - if SUPPORTED_BACKENDS.contains(&s) { - Err(ParseError::WrongPlatform(s.into())) + if SUPPORTED_BACKENDS.contains(&value) { + Err(ParseError::WrongPlatform { + value: value.into(), + }) } else { - Err(ParseError::Invalid(s.into())) + Err(ParseError::Invalid { + value: value.into(), + }) } } } diff --git a/backend/lib/src/app_data/msg.rs b/backend/lib/src/app_data/msg.rs new file mode 100644 index 0000000..a1b5043 --- /dev/null +++ b/backend/lib/src/app_data/msg.rs @@ -0,0 +1,27 @@ +use self::request::handle_frontend_request; + +use super::AppData; +use crate::{common, ThreadMsg}; +use common::app::msg::FrontendMsg; +mod request; + +/// Handles a message from the parent thread. +/// Returns `true` if the app should quit. +pub fn handle_thread_msg(app_data: &mut AppData, msg: ThreadMsg) -> bool { + match msg { + // Handle frontend message. + ThreadMsg::Frontend(msg) => handle_frontend_msg(app_data, msg), + // Quit. + ThreadMsg::Exit => return true, + }; + false +} + +/// Handles messages from the frontend. +fn handle_frontend_msg(app_data: &mut AppData, msg: FrontendMsg) { + match msg { + FrontendMsg::Request(request) => { + handle_frontend_request(app_data, request) + } + } +} diff --git a/backend/lib/src/app_data/msg/request.rs b/backend/lib/src/app_data/msg/request.rs new file mode 100644 index 0000000..75c4297 --- /dev/null +++ b/backend/lib/src/app_data/msg/request.rs @@ -0,0 +1,27 @@ +use crate::app_data::AppData; +use crate::{common, AppThread}; +use common::app::msg::request::FrontendRequest; +use common::app::msg::BackendMsg; + +mod backend_response; + +/// Handles the request and sends a response to the frontend. +pub(super) fn handle_frontend_request( + app_data: &mut AppData, + request: FrontendRequest, +) { + // Handle request and prepare response. + let response = match request { + FrontendRequest::AppState => backend_response::app_state(app_data), + FrontendRequest::Settings => backend_response::settings(app_data), + FrontendRequest::UseDefaultSettings => { + backend_response::use_default_settings(app_data) + } + }; + + // Send response. + AppThread::send_message( + &app_data.tauri_app, + BackendMsg::Response(response), + ); +} diff --git a/backend/lib/src/app_data/msg/request/backend_response.rs b/backend/lib/src/app_data/msg/request/backend_response.rs new file mode 100644 index 0000000..df94834 --- /dev/null +++ b/backend/lib/src/app_data/msg/request/backend_response.rs @@ -0,0 +1,55 @@ +use crate::app_data::app_state::AppState; +use crate::app_data::AppData; +use crate::common; +use common::app::msg::request::BackendResponse; + +/// Reply with current state. +pub(super) fn app_state(app_data: &mut AppData) -> BackendResponse { + // Get state and convert it to `BackendAppState`. + let app_state = (&app_data.state).into(); + + // Prepare response. + BackendResponse::BackendAppState(app_state) +} + +/// Reply with current settings. +pub(super) fn settings(app_data: &mut AppData) -> BackendResponse { + // Get settings. + let settings_opt = match app_data.state { + AppState::Idle { ref settings } => Some(settings.clone()), + _ => None, + }; + + // Prepare response. + BackendResponse::Settings(settings_opt) +} + +/// Set default settings and reply with a copy. +pub(super) fn use_default_settings(app_data: &mut AppData) -> BackendResponse { + // Apply and return settings. + match app_data.state { + // Fail gracefully if in the middle of reading settings. + AppState::ReadingSettings => { + tracing::error!("Frontend attempted to set settings to default while backend was still reading config."); + } + // Change state to idle if awaiting config. + AppState::AwaitConfig { .. } => { + app_data.state = AppState::Idle { + settings: Default::default(), + }; + } + // Modify if idle. + AppState::Idle { ref mut settings } => { + *settings = Default::default(); + } + // Modify if editing a project. + AppState::Edit { + ref mut settings, .. + } => { + *settings = Default::default(); + } + } + + // Prepare response. + BackendResponse::UseDefaultSettings(Default::default()) +} diff --git a/backend/lib/src/lib.rs b/backend/lib/src/lib.rs index f5f87e7..ab9cc47 100644 --- a/backend/lib/src/lib.rs +++ b/backend/lib/src/lib.rs @@ -6,7 +6,10 @@ pub use chipbox_common as common; pub mod dir; -use app_data::AppData; +use app_data::{msg, AppData}; +use common::app::msg::cmd::BackendCmd; +use common::app::msg::{BackendMsg, FrontendMsg}; +use common::app::AwaitConfigReason; use settings::SettingsExt as _; use tauri::{async_runtime, Manager as _}; mod app_data; @@ -18,7 +21,7 @@ mod settings; /// Messages received by the app thread. pub enum ThreadMsg { /// Tauri forwarded a message from the frontend. - Frontend(common::app::FrontendMsg), + Frontend(FrontendMsg), /// Main requested to exit. /// Immediatelly closes the app thread. Exit, @@ -55,7 +58,7 @@ impl AppThread { // Read settings. tracing::trace!("Reading settings."); - let result = read_settings().await; + let result = Self::read_settings().await; // Handle the result. match result { @@ -63,11 +66,14 @@ impl AppThread { Ok(settings_opt) => { tracing::trace!("Settings ok."); + // Prepare settings update message. + let msg = BackendCmd::UpdateSettings(match settings_opt { + Some(ref settings) => Ok(settings.clone()), + None => Err(AwaitConfigReason::NoConfig), + }); + // Send message to client. - Self::send_message( - self.data.tauri_app(), - common::app::BackendMsg::ReadingSettings, - ); + Self::send_message(self.data.tauri_app(), msg.into()); // Update state based on whether there was a valid config. self.data.state = settings_opt.into(); @@ -77,13 +83,21 @@ impl AppThread { } // Something went wrong while reading settings. Err(err) => { - tracing::error!("Settings read failed: {}", err); + // Prepare error message. + let err_msg = format!("Settings read failed: {}", err); + tracing::error!(err_msg); + + // Send message to client. + let msg = BackendCmd::UpdateSettings(Err( + AwaitConfigReason::Error(err_msg.into()), + )); + Self::send_message(self.data.tauri_app(), msg.into()); // Wait for exit message. self.poll_until_exit_message() .await; } - } + }; // Exit. tracing::trace!("App thread finished."); @@ -153,7 +167,7 @@ impl AppThread { /// Polls messages from the channel in a loop. async fn poll_messages(&mut self) { Self::poll_message_until(&mut self.rx, |msg| { - match self.data.handle_msg(msg) { + match msg::handle_thread_msg(&mut self.data, msg) { true => Some(()), false => None, } @@ -164,34 +178,31 @@ impl AppThread { } /// Send an `AppMessage` to the client window. - fn send_message( - tauri_app: &tauri::AppHandle, - msg: common::app::BackendMsg, - ) { + fn send_message(tauri_app: &tauri::AppHandle, msg: BackendMsg) { tracing::trace!("Sending message to frontend: {:?}", msg); tauri_app - .emit_all(common::app::BackendMsg::event_name(), msg) + .emit_all(BackendMsg::event_name(), msg) .unwrap_or_else(|err| { tracing::error!("Failed to send message to frontend: {}", err); }) } -} -/// Read settings from the config file. -/// Returns `Ok(None)` if the config file does not exist. -pub async fn read_settings( -) -> Result, settings::SettingsError> { - match common::Settings::read().await { - // Settings found. - Ok(settings) => Ok(Some(settings)), - // We catch `std::io::ErrorKind::NotFound`. - // Not having a config file is a valid state. - Err(settings::SettingsError::Io(ref e)) - if e.err.kind() == std::io::ErrorKind::NotFound => - { - Ok(None) + /// Read settings from the config file. + /// Returns `Ok(None)` if the config file does not exist. + async fn read_settings( + ) -> Result, settings::SettingsError> { + match common::Settings::read().await { + // Settings found. + Ok(settings) => Ok(Some(settings)), + // We catch `std::io::ErrorKind::NotFound`. + // Not having a config file is a valid state. + Err(settings::SettingsError::Io(ref e)) + if e.err.kind() == std::io::ErrorKind::NotFound => + { + Ok(None) + } + // Something else went wrong. + Err(err) => Err(err), } - // Something else went wrong. - Err(err) => Err(err), } } diff --git a/common/Cargo.toml b/common/Cargo.toml index 468c0c3..bb10c52 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -10,3 +10,4 @@ once_cell = { workspace = true } cssparser = { workspace = true } derive_more = { workspace = true } cssparser-color = { workspace = true } +cowstr = { workspace = true } diff --git a/common/src/app.rs b/common/src/app.rs index eb9ddab..b3580e2 100644 --- a/common/src/app.rs +++ b/common/src/app.rs @@ -1,63 +1,37 @@ -use crate::Settings; -use serde::{Deserialize, Serialize}; - -/// Messages sent by the backend app thread. -#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] -pub enum BackendMsg { - /// Backend app is currently reading user config. - ReadingSettings, - /// Response to a frontend request. - Response(BackendResponse), -} - -impl BackendMsg { - /// JS Event name used by the frontend. - pub const fn event_name() -> &'static str { - "chipbox-app-message" - } -} - -/// Messages sent by the backend app thread in response to frontend queries. -#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] -pub enum BackendResponse { - /// Respond with current `BackendAppState`. - BackendAppState(BackendAppState), - /// Respond with current `Settings`. - Settings(Option), - /// Respond with default `Settings`. - UseDefaultSettings(Settings), -} +pub mod msg; -/// Messages sent by the frontend app thread. -#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] -pub enum FrontendMsg { - /// Query information from the backend. - Request(FrontendRequest), -} - -/// Messages sent by the frontend app thread requesting information from the backend. -#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] -pub enum FrontendRequest { - /// Query current `BackendAppState`. - BackendAppState, - /// Query current `Settings`. - Settings, - /// Use default settings and query a copy from the backend. - UseDefaultSettings, -} +use cowstr::CowStr; +use serde::{Deserialize, Serialize}; /// The reason why the user config is not ready. -#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Copy, Default)] +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Default)] pub enum AwaitConfigReason { #[default] /// This is the first time the application has been started. /// /// The user has not yet configured the application. NoConfig, + /// An error occurred while reading the user config. + Error(CowStr), +} + +impl std::error::Error for AwaitConfigReason {} + +impl std::fmt::Display for AwaitConfigReason { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + AwaitConfigReason::NoConfig => { + write!(f, "No user configuration found") + } + AwaitConfigReason::Error(err) => { + write!(f, "Error reading user configuration: {}", err) + } + } + } } /// Minimal description of the current state of the backend. -#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Copy, Default)] +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Default)] pub enum BackendAppState { /// Backend is currently reading user config. #[default] diff --git a/common/src/app/msg.rs b/common/src/app/msg.rs new file mode 100644 index 0000000..35f3b46 --- /dev/null +++ b/common/src/app/msg.rs @@ -0,0 +1,48 @@ +pub mod cmd; +pub mod request; + +use self::cmd::BackendCmd; +use self::request::{BackendResponse, FrontendRequest}; +use super::BackendAppState; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +/// Messages sent by the backend app thread. +pub enum BackendMsg { + /// Send a command from the backend. + Cmd(BackendCmd), + /// Response to a frontend request. + Response(BackendResponse), +} + +impl BackendMsg { + /// JS Event name used by the frontend. + pub const fn event_name() -> &'static str { + "chipbox-app-message" + } +} + +impl From for BackendMsg { + fn from(cmd: BackendCmd) -> Self { + Self::Cmd(cmd) + } +} + +impl From for BackendMsg { + fn from(response: BackendResponse) -> Self { + Self::Response(response) + } +} + +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +/// Messages sent by the frontend app thread. +pub enum FrontendMsg { + /// Query information from the backend. + Request(FrontendRequest), +} + +impl From for FrontendMsg { + fn from(request: FrontendRequest) -> Self { + Self::Request(request) + } +} diff --git a/common/src/app/msg/cmd.rs b/common/src/app/msg/cmd.rs new file mode 100644 index 0000000..d4e44f2 --- /dev/null +++ b/common/src/app/msg/cmd.rs @@ -0,0 +1,12 @@ +use crate::app::AwaitConfigReason; +use crate::Settings; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub enum BackendCmd { + /// Inform the frontend that the backend app + /// is currently reading user config. + ReadingSettings, + /// Update the config of the frontend app. + UpdateSettings(Result), +} diff --git a/common/src/app/msg/request.rs b/common/src/app/msg/request.rs new file mode 100644 index 0000000..353860a --- /dev/null +++ b/common/src/app/msg/request.rs @@ -0,0 +1,26 @@ +use super::BackendAppState; +use crate::Settings; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +/// Messages sent by the backend app thread +/// in response to frontend queries. +pub enum BackendResponse { + /// Respond with current `BackendAppState`. + BackendAppState(BackendAppState), + /// Respond with current `Settings`. + Settings(Option), + /// Respond with default `Settings`. + UseDefaultSettings(Settings), +} + +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +/// Messages sent by the frontend app thread requesting information from the backend. +pub enum FrontendRequest { + /// Query current `BackendAppState`. + AppState, + /// Query current `Settings`. + Settings, + /// Use default settings and query a copy from the backend. + UseDefaultSettings, +} diff --git a/glue/src/msg.rs b/glue/src/msg.rs index 14b9a6f..bab8cdb 100644 --- a/glue/src/msg.rs +++ b/glue/src/msg.rs @@ -1,5 +1,5 @@ use crate::common; -use common::app::FrontendMsg; +use common::app::msg::FrontendMsg; #[cfg(feature = "backend")] use {crate::backend_lib::ThreadMsg, tauri::async_runtime::Sender}; diff --git a/ui/app/Cargo.toml b/ui/app/Cargo.toml index bcec54a..8d1fb7c 100644 --- a/ui/app/Cargo.toml +++ b/ui/app/Cargo.toml @@ -14,11 +14,12 @@ chipbox-ui-panel = { workspace = true } tracing = { workspace = true } ## concurrency futures = { workspace = true } -tokio = { version = "1.37", features = [], default-features = false } +tokio = { version = "*", features = [], default-features = false } ## serde serde = { workspace = true } ## utils const_format = { workspace = true } +cowstr = { workspace = true } ## wasm frontend yew = { workspace = true } web-sys = { workspace = true } diff --git a/ui/app/src/app.rs b/ui/app/src/app.rs index 03e3425..2270948 100644 --- a/ui/app/src/app.rs +++ b/ui/app/src/app.rs @@ -12,9 +12,11 @@ mod state; #[function_component] pub fn App() -> yew::Html { - // App state. + // Initial state of the application. + // Rerender on state change. let app_state = use_state_eq(AppState::default); - // After rendering, query the backend. + + // After each render, query the backend. use_effect({ let app_state = app_state.clone(); move || query_backend_app_state(app_state) @@ -25,7 +27,7 @@ pub fn App() -> yew::Html { }, AppState::Setup(ref setup_state) => html! { - + }, AppState::Home(ref home_state) => html! { diff --git a/ui/app/src/app/backend_query.rs b/ui/app/src/app/backend_query.rs index afae7cc..f111d70 100644 --- a/ui/app/src/app/backend_query.rs +++ b/ui/app/src/app/backend_query.rs @@ -4,17 +4,17 @@ use yew::prelude::*; #[derive(PartialEq, Default, Clone, Copy)] pub(super) enum BackendQueryState { #[default] - WaitingForBackend, - ReadingSettings, - QueryingSettings, + WaitForBackend, + ReadSettings, + QuerySettings, } impl AsRef for BackendQueryState { fn as_ref(&self) -> &str { match self { - Self::WaitingForBackend => "Waiting for backend...", - Self::ReadingSettings => "Reading settings...", - Self::QueryingSettings => "Querying settings...", + Self::WaitForBackend => "Waiting for backend...", + Self::ReadSettings => "Reading settings...", + Self::QuerySettings => "Querying settings...", } } } diff --git a/ui/app/src/app/home.rs b/ui/app/src/app/home.rs index 434fc2f..524f859 100644 --- a/ui/app/src/app/home.rs +++ b/ui/app/src/app/home.rs @@ -21,7 +21,7 @@ pub(super) fn Home(props: &Props) -> yew::Html { fn html_querying_settings() -> yew::Html { html! { - + } } diff --git a/ui/app/src/app/setup.rs b/ui/app/src/app/setup.rs index 4d75938..2db5b28 100644 --- a/ui/app/src/app/setup.rs +++ b/ui/app/src/app/setup.rs @@ -1,8 +1,10 @@ +use cowstr::CowStr; use yew::prelude::*; -#[derive(PartialEq, Clone, Copy)] +#[derive(PartialEq, Clone)] pub(super) enum SetupState { First, + Error(CowStr), } #[derive(Properties, PartialEq)] @@ -14,6 +16,7 @@ pub(super) struct Props { pub(super) fn Setup(props: &Props) -> yew::Html { match props.state { SetupState::First => html_first(), + SetupState::Error(ref _err) => todo!(), } } diff --git a/ui/app/src/app/state.rs b/ui/app/src/app/state.rs index 468ffed..adb92a7 100644 --- a/ui/app/src/app/state.rs +++ b/ui/app/src/app/state.rs @@ -8,10 +8,13 @@ impl From for AppState { fn from(value: BackendAppState) -> Self { match value { BackendAppState::ReadingSettings => { - Self::BackendQuery(BackendQueryState::ReadingSettings) + Self::BackendQuery(BackendQueryState::ReadSettings) } BackendAppState::AwaitConfig { reason } => match reason { AwaitConfigReason::NoConfig => Self::Setup(SetupState::First), + AwaitConfigReason::Error(err) => { + Self::Setup(SetupState::Error(err)) + } }, BackendAppState::Idle => Self::Home(HomeState::Welcome), BackendAppState::Editor => todo!(),