use web_sys::HtmlInputElement; use web_sys::HtmlSelectElement; use yew::prelude::*; use crate::api; use crate::types::{AppConfig, SubsonicPasswordStatus, YtAuthStatus}; #[function_component(SettingsPage)] pub fn settings_page() -> Html { let config = use_state(|| None::); let error = use_state(|| None::); let message = use_state(|| None::); let ytauth = use_state(|| None::); let ytauth_loading = use_state(|| false); let subsonic_status = use_state(|| None::); let subsonic_password = use_state(String::new); let subsonic_saving = use_state(|| false); { let config = config.clone(); let error = error.clone(); let ytauth = ytauth.clone(); let subsonic_status = subsonic_status.clone(); use_effect_with((), move |_| { wasm_bindgen_futures::spawn_local(async move { match api::get_config().await { Ok(c) => config.set(Some(c)), Err(e) => error.set(Some(e.0)), } }); wasm_bindgen_futures::spawn_local(async move { if let Ok(status) = api::get_ytauth_status().await { ytauth.set(Some(status)); } }); wasm_bindgen_futures::spawn_local(async move { if let Ok(status) = api::get_subsonic_password_status().await { subsonic_status.set(Some(status)); } }); }); } let on_save = { let config = config.clone(); let message = message.clone(); let error = error.clone(); Callback::from(move |e: SubmitEvent| { e.prevent_default(); let config = config.clone(); let message = message.clone(); let error = error.clone(); if let Some(ref c) = *config { let c = c.clone(); wasm_bindgen_futures::spawn_local(async move { match api::save_config(&c).await { Ok(updated) => { config.set(Some(updated)); message.set(Some("Settings saved".to_string())); error.set(None); } Err(e) => error.set(Some(e.0)), } }); } }) }; // Helper to update a field in config state macro_rules! field_setter { ($config:expr, $field:ident, $val:expr) => {{ let mut c = (*$config).clone().unwrap(); c.$field = $val; $config.set(Some(c)); }}; } if let Some(ref err) = *error { if config.is_none() { return html! {
{ format!("Error: {err}") }
}; } } let Some(ref c) = *config else { return html! {

{ "Loading configuration..." }

}; }; // Build YouTube auth card HTML outside the main html! macro let ytauth_html = { let ytauth = ytauth.clone(); let ytauth_loading = ytauth_loading.clone(); let message = message.clone(); let error = error.clone(); if let Some(ref status) = *ytauth { if status.login_session_active { let vnc_url = status.vnc_url.clone().unwrap_or_default(); let on_done = { let ytauth = ytauth.clone(); let ytauth_loading = ytauth_loading.clone(); let message = message.clone(); let error = error.clone(); Callback::from(move |_: MouseEvent| { let ytauth = ytauth.clone(); let ytauth_loading = ytauth_loading.clone(); let message = message.clone(); let error = error.clone(); ytauth_loading.set(true); wasm_bindgen_futures::spawn_local(async move { match api::ytauth_login_stop().await { Ok(_) => { message.set(Some( "YouTube login complete! Cookies exported.".into(), )); if let Ok(s) = api::get_ytauth_status().await { ytauth.set(Some(s)); } } Err(e) => error.set(Some(e.0)), } ytauth_loading.set(false); }); }) }; html! { <>

{ "Log into YouTube in the browser below, then click Done." }

if !vnc_url.is_empty() {

{ "Open login window" }