diff --git a/plugin-network/Cargo.toml b/plugin-network/Cargo.toml index 9e4624c..416de91 100644 --- a/plugin-network/Cargo.toml +++ b/plugin-network/Cargo.toml @@ -9,9 +9,9 @@ edition = "2021" anyhow = "1.0.86" async-std = "1.12.0" clap = { version = "4.5.4", features = ["derive"] } -dioxus = "0.5.1" +dioxus = { version = "0.5.1", features = ["desktop"] } dioxus-desktop = "0.5.1" -dioxus-free-icons = { version = "0.8.5", features = ["font-awesome-regular"] } +dioxus-free-icons = { version = "0.8.6", features = ["font-awesome-regular"] } dioxus-html = "0.5.1" env_logger = "0.11.3" futures-channel = "0.3.30" diff --git a/plugin-network/src/gui.rs b/plugin-network/src/gui.rs index 61ab1bf..f3a8891 100644 --- a/plugin-network/src/gui.rs +++ b/plugin-network/src/gui.rs @@ -15,8 +15,8 @@ static SPINNER_HTML: &'static str = include_str!("../public/spinner.html"); static DEFAULT_CSS_CONTENT: &'static str = include_str!("../public/default.css"); /// Run GUI Application -pub fn run_app(ssid: &str, timeout: u32) { - let builder = dioxus_desktop::WindowBuilder::new() +pub fn run(ssid: String, timeout: u32) { + let window = dioxus_desktop::WindowBuilder::new() .with_title("RMenu - Network Login") .with_inner_size(LogicalSize { width: 400, @@ -25,14 +25,12 @@ pub fn run_app(ssid: &str, timeout: u32) { .with_focused(true) .with_decorations(false) .with_always_on_top(true); - dioxus_desktop::launch_with_props( - App, - AppProp { - ssid: ssid.to_owned(), - timeout, - }, - dioxus_desktop::Config::new().with_window(builder), - ); + let config = dioxus_desktop::Config::new().with_window(window); + let context = Context { ssid, timeout }; + LaunchBuilder::desktop() + .with_cfg(config) + .with_context(context) + .launch(gui_main); } /// Message to send to GUI @@ -45,12 +43,13 @@ pub enum UserMessage { impl UserMessage { /// Retrieve CSS-Class to use on UserMessage - fn css_class(&self) -> &str { + fn css_class(&self) -> String { match self { Self::Error(_) => "error", Self::Success(_) => "success", Self::Nothing => "none", } + .to_owned() } /// Retrieve Message Value fn message(&self) -> Option { @@ -62,22 +61,14 @@ impl UserMessage { } } -#[derive(Debug, PartialEq, Props)] -struct AppProp { +#[derive(Debug, Clone)] +struct Context { ssid: String, timeout: u32, } //TODO: add auth timeout -/// Set Cursor/Keyboard Focus onto Input -#[inline] -fn focus(cx: Scope) { - let eval = use_eval(cx); - let js = "document.getElementById(`secret`).focus()"; - let _ = eval(&js); -} - /// Complete Network Connection/Authentication Attempt async fn connect_async(ssid: String, timeout: u32, secret: &str) -> Result<()> { // retrieve access-point from manager @@ -92,31 +83,30 @@ async fn connect_async(ssid: String, timeout: u32, secret: &str) -> Result<()> { manager.connect(&access_point, Some(secret)).await } -/// Simple Login GUI Application -fn App(cx: Scope) -> Element { - let secret = use_state(cx, || String::new()); - let message = use_state(cx, || UserMessage::Nothing); - let show_secret = use_state(cx, || false); - let loading = use_state(cx, || false); +fn gui_main() -> Element { + let ctx = use_context::(); + let mut message = use_signal(|| UserMessage::Nothing); + let mut loading = use_signal(|| false); + let mut secret = use_signal(String::new); + let mut show_secret = use_signal(|| false); - // always ensure focus - focus(cx); + // refocus on input + let js = format!("setTimeout(() => {{ document.getElementById('secret').focus() }}, 100)"); + eval(&js); // build keyboard actions event handler let keyboard_controls = move |e: KeyboardEvent| match e.code() { Code::Escape => std::process::exit(0), Code::Enter => { - let ssid = cx.props.ssid.to_owned(); - let timeout = cx.props.timeout.to_owned(); - let secret = secret.get().to_owned(); - let message = message.to_owned(); - let loading = loading.to_owned(); + let timeout = ctx.timeout.to_owned(); loading.set(true); message.set(UserMessage::Nothing); - cx.spawn(async move { + spawn(async move { + let ctx = use_context::(); + let ssid = ctx.ssid.to_owned(); log::info!("connecting to ssid: {ssid:?}"); - let result = connect_async(ssid, timeout, &secret).await; + let result = connect_async(ssid, timeout, &secret()).await; log::info!("connection result: {result:?}"); match result { Ok(_) => { @@ -139,27 +129,27 @@ fn App(cx: Scope) -> Element { }; // retrieve message details / set input-type / get loading css-class - let msg_css = message.css_class(); - let msg_str = message.message(); - let input_type = match show_secret.get() { + let msg_css = message.with(|msg| msg.css_class()); + let msg_str = message.with(|msg| msg.message()); + let input_type = match show_secret() { true => "text", false => "password", }; - let blackout_css = match loading.get() { + let blackout_css = match loading() { true => "active", false => "", }; // complete final rendering - cx.render(rsx! { - style { DEFAULT_CSS_CONTENT } - style { SPINNER_CSS } + rsx! { + style { "{DEFAULT_CSS_CONTENT}" } + style { "{SPINNER_CSS}" } div { onkeydown: keyboard_controls, label { id: "header", "for": "secret", - "Wi-Fi Network {cx.props.ssid:?} Requires a Password" + "Wi-Fi Network {ctx.ssid:?} Requires a Password" } div { id: "controls", @@ -167,36 +157,36 @@ fn App(cx: Scope) -> Element { id: "secret", value: "{secret}", placeholder: "Password", - oninput: move |e| secret.set(e.value.clone()), + oninput: move |e| secret.set(e.value()), "type": "{input_type}" } button { id: "icon", - onclick: |_| show_secret.modify(|v| !v), - match show_secret.get() { - true => cx.render(rsx! { + onclick: move |_| show_secret.toggle(), + {match show_secret() { + true => rsx! { Icon { fill: "black", icon: FaEye, } - }), - false => cx.render(rsx! { + }, + false => rsx! { Icon { fill: "black", icon: FaEyeSlash, } - }) - } + } + }} } } if let Some(msg) = msg_str { - cx.render(rsx! { + {rsx! { div { id: "message", class: "{msg_css}", "{msg}" } - }) + }} } div { id: "blackout", @@ -207,5 +197,5 @@ fn App(cx: Scope) -> Element { } } } - }) + } } diff --git a/plugin-network/src/main.rs b/plugin-network/src/main.rs index 8ec59ae..b046fcf 100644 --- a/plugin-network/src/main.rs +++ b/plugin-network/src/main.rs @@ -97,7 +97,7 @@ fn main() -> Result<()> { let connected = context.block_on(try_connect_ap(ssid.clone(), timeout))?; if !connected { log::info!("Spawning GUI to complete AP Login"); - gui::run_app(&ssid, timeout.unwrap_or(30)); + gui::run(ssid, timeout.unwrap_or(30)); } } } diff --git a/plugin-network/src/network.rs b/plugin-network/src/network.rs index 12a8ccf..6c5d78d 100644 --- a/plugin-network/src/network.rs +++ b/plugin-network/src/network.rs @@ -26,7 +26,6 @@ pub struct Manager { /// AccessPoint Information #[derive(Debug)] pub struct AccessPoint { - pub in_use: bool, pub ssid: String, pub rate: u32, pub signal: u8, @@ -267,7 +266,6 @@ impl Manager { access.insert( ssid.to_owned(), AccessPoint { - in_use: is_active, ssid, rate, signal,