Redesign login view with server card list, add/edit/delete modals,
and per-server ping status display. Rename ProxyOverrides to ClientConfig,
remove ConfigSystemInterface in favor of direct platform methods
(load_config, load_username, set_default_username, load_server_url),
remove SharedState threading in favor of global STATE, simplify
network_loop and audio setup, update proxy endpoint from /overrides
to /config, and clean up desktop launch configuration.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add ServerEntry model, load_servers/save_servers/set_default_server
to PlatformInterface with implementations for desktop (etcetera config),
web (localStorage), mobile (stub), and stub platforms. Implement
mumble_udp_ping protocol on desktop for direct server status queries.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously the model state was in a `static STATE` to make it accessible to all the various subsystems. This moves it into an Arc and plumbs the reference around via function arguments. That allows us to do non-static initialization, eg based on user config. I also moved some things into dioxus context.
Co-authored-by: Sam Sartor <me@samsartor.com>
Co-committed-by: Sam Sartor <me@samsartor.com>
This change migrates the config logic to a new generic key+value abstraction. This allows config parameters to be get and set with arbitrary string keys. Config value types can be anything that serde knows how to serialize / deserialize.
Implementations:
Desktop:
Uses a json file in a platform specific directory (pulled from etcetera). This is mostly the same as the existing code. Implemented in `native_config.rs`
Android:
Uses the same mechanism as desktop, with a different path selection that calls out to the android apis (via jni) to get the correct directory.
Web:
Uses browser local storage. Values are stored as strings instead of actual json objects to keep things simple for now. We might want to update this at some point.
Desktop support:

```
% cat ~/.config/mumble-web2/config.json
{
"username": "restitux-test",
"server_url": "voip.ohea.xyz"
}%
```
Web support:

Android support:

```
root@c053bdd1b4da:/# adb shell
tokay:/ $ run-as xyz.ohea.mumble_web_2
tokay:/data/user/0/xyz.ohea.mumble_web_2 $ ls
app_textures app_webview cache code_cache files no_backup shared_prefs
tokay:/data/user/0/xyz.ohea.mumble_web_2 $ ls files
config.json oat permission_manager.dex
tokay:/data/user/0/xyz.ohea.mumble_web_2 $ cat files/config.json
{
"server_url": "voip.ohea.xyz",
"username": "test"
}tokay:/data/user/0/xyz.ohea.mumble_web_2 $
```
Reviewed-on: #25
Reviewed-by: Sam Sartor <cap@samsartor.com>
# Summary
Introduces a trait-based platform abstraction layer that makes the boundary
between platform-specific and shared code explicit and compile-time verified.
The TLDR version of this new trait stuff works:
1. Define a `PlatformInterface` trait.
2. Each platform defines a zero-sized struct implementing the trait (ex `WebPlatform`).
3. Create an ifdef'd type alias on those structs:
```rust
#[cfg(feature = "web")]
pub type Platform = web::WebPlatform;
#[cfg(all(feature = "desktop"))]
pub type Platform = desktop::DesktopPlatform;
#[cfg(all(feature = "mobile", not(feature = "web")))]
pub type Platform = mobile::MobilePlatform;
```
5. Add a compile time assertion that `Platform` implements `PlatformInterface`.
# Motivation
Previously, platform code used a mix of pub use re-exports and #[cfg] blocks
that made it difficult to understand what each platform must implement. The
new trait-based approach provides:
- Clear documentation of the platform contract
- Compile-time verification that all platforms implement required
functionality
- Ability to cargo check without feature flags (via stub platform)
# Changes
New traits in imp/mod.rs:
- PlatformInterface - logging, permissions, network, config, storage. Overall this the trait that platforms must satify to compile.
- AudioSystemInterface - audio system initialization and recording
- AudioPlayerInterface - opus audio playback
Type aliases:
- Platform, AudioSystem, AudioPlayer resolve to the correct types based on
feature flags
Call site updates:
- Changed from imp::function() to Platform::function() syntax
- Removed ImpRead/ImpWrite helper traits in favor of direct bounds
# Testing
Manual testing reveals that Web and Desktop still work, I (Liam) have not tested the mobile version beyond compilation.
Co-authored-by: Liam Warfield <liam.warfield@gmail.com>
Reviewed-on: #18
Co-authored-by: Sam Sartor <me@samsartor.com>
Co-committed-by: Sam Sartor <me@samsartor.com>