Persistant Desktop settings #11

Merged
samuel127849 merged 3 commits from swarfield/desktop-settings into main 2026-01-10 23:26:22 +00:00
6 changed files with 86 additions and 4 deletions
+4
View File
@@ -0,0 +1,4 @@
{
"rust-analyzer.cargo.features": ["desktop","web"],
"rust-analyzer.cargo.noDefaultFeatures": false
}
Generated
+21
View File
@@ -2270,6 +2270,17 @@ dependencies = [
"xxhash-rust",
]
[[package]]
name = "etcetera"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26c7b13d0780cb82722fd59f6f57f925e143427e4a75313a6c77243bf5326ae6"
dependencies = [
"cfg-if",
"home",
"windows-sys 0.59.0",
]
[[package]]
name = "euclid"
version = "0.22.11"
@@ -3157,6 +3168,15 @@ version = "1.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad6880c8d4a9ebf39c6e8b77007ce223f646a4d21ce29d99f70cb16420545425"
[[package]]
name = "home"
version = "0.5.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d"
dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "html-purifier"
version = "0.3.0"
@@ -4261,6 +4281,7 @@ dependencies = [
"dioxus",
"dioxus-asset-resolver",
"dioxus-web",
"etcetera",
"futures",
"futures-channel",
"gloo-timers",
+2
View File
@@ -63,6 +63,7 @@ tokio-rustls = { version = "^0.26.0", optional = true }
opus = { version = "0.3.0", optional = true }
cpal = { version = "0.15.3", optional = true }
dasp_ring_buffer = { version = "0.11.0", optional = true }
etcetera = { version = "0.10.0", optional = true }
# Base Dependencies
# ================
@@ -130,4 +131,5 @@ desktop = [
"cpal",
"dasp_ring_buffer",
"rfd/xdg-portal",
"etcetera",
]
+4 -1
View File
@@ -558,7 +558,7 @@ pub fn LoginView(config: Resource<ClientConfig>) -> Element {
}
});
let mut address_input = use_signal(|| None::<String>);
let mut address_input = use_signal(|| imp::load_server_url());
let address = use_memo(move || {
if let Some(addr) = address_input() {
addr.clone()
@@ -575,6 +575,9 @@ pub fn LoginView(config: Resource<ClientConfig>) -> Element {
let do_connect = move |_| {
//let _ = set_default_username(&username.read());
let _ = imp::set_default_username(&username.read());
if config.read().as_ref().is_some_and(|cfg| cfg.any_server) {
imp::set_default_server(&address.read());
}
net.send(Connect {
address: address.read().clone(),
username: username.read().clone(),
+47 -3
View File
@@ -1,11 +1,13 @@
use crate::app::Command;
use crate::effects::{AudioProcessor, AudioProcessorSender};
use color_eyre::eyre::{bail, eyre, Context, Error};
use color_eyre::eyre::{bail, eyre, Error};
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait as _};
use dioxus::hooks::UnboundedReceiver;
use etcetera::{choose_app_strategy, AppStrategy, AppStrategyArgs};
use futures::io::{AsyncRead, AsyncWrite};
use mumble_protocol::control::ClientControlCodec;
use mumble_web2_common::{ClientConfig, ServerStatus};
use std::collections::HashMap;
use std::mem::replace;
use std::net::ToSocketAddrs;
use std::sync::Arc;
@@ -314,12 +316,54 @@ pub async fn network_connect(
crate::network_loop(username, event_rx, reader, writer).await
}
fn get_config_path() -> std::path::PathBuf {
let strategy = choose_app_strategy(AppStrategyArgs {
top_level_domain: "com".to_string(),
author: "Ohea Corp".to_string(),
app_name: "Mumble Web2".to_string(),
})
.expect("failed to choose app strategy");
strategy.config_dir().join("config.json")
}
fn load_config_map() -> HashMap<String, String> {
let config_path = get_config_path();
match std::fs::read_to_string(&config_path) {
Ok(contents) => serde_json::from_str(&contents).unwrap_or_default(),
Err(_) => HashMap::new(),
}
}
fn save_config_map(config: &HashMap<String, String>) -> color_eyre::Result<()> {
let config_path = get_config_path();
if let Some(parent) = config_path.parent() {
std::fs::create_dir_all(parent)?;
}
let contents = serde_json::to_string_pretty(config)?;
std::fs::write(&config_path, contents)?;
Ok(())
}
pub fn set_default_username(username: &str) -> Option<()> {
None
let mut config = load_config_map();
config.insert("username".to_string(), username.to_string());
save_config_map(&config).ok()
}
pub fn set_default_server(server: &str) -> Option<()> {
let mut config = load_config_map();
config.insert("server".to_string(), server.to_string());
save_config_map(&config).ok()
}
pub fn load_username() -> Option<String> {
return None;
let config = load_config_map();
config.get("username").cloned()
}
pub fn load_server_url() -> Option<String> {
let config = load_config_map();
Review

Load config should not change, because this is (confusingly) the server->client config, not really the user's own config. TBH we should rename it to "server_params" or something, but probably not in this PR.

Anyway, we should instead plumb the remembered last-used server address to the initial value of address_input of LoginView. That is, use it to pre-fill the field.

Load config should not change, because this is (confusingly) the server->client config, not really the user's own config. TBH we should rename it to "server_params" or something, but probably not in this PR. Anyway, we should instead plumb the remembered last-used server address to the initial value of address_input of LoginView. That is, use it to pre-fill the field.
config.get("server").cloned()
}
pub async fn load_config() -> color_eyre::Result<ClientConfig> {
+8
View File
@@ -399,6 +399,10 @@ pub fn set_default_username(username: &str) -> Option<()> {
.ok()
}
pub fn set_default_server(username: &str) -> Option<()> {
None
}
pub fn load_username() -> Option<String> {
web_sys::window()
.unwrap()
@@ -408,6 +412,10 @@ pub fn load_username() -> Option<String> {
.ok()?
}
pub fn load_server_url() -> Option<String> {
None
}
pub fn absolute_url(path: &str) -> Result<Url, Error> {
let window: web_sys::Window = web_sys::window().expect("no global `window` exists");
let location = window.location();