Puts the denoise bool into an AudioSettings struct in the model state, and persists changes to user state.
Co-authored-by: Sam Sartor <me@samsartor.com>
Co-committed-by: Sam Sartor <me@samsartor.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>
# 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>
# Summary
Channel ordering is currently broken as described in #17. This change makes sorting work correctly and cleans up the logic a bit.
# Changes
- creates a `ChannelsState` wrapper struct to handle this behavior
- moves the logic for handling `ChannelState` processing, including data update and parent-child tree sorting, into the impl for `ChannelsState`
- moves the logic for handling `ChannelRemove` into this impl
Parent child sorting properly applies the position values, which are arbitrary integers that are supposed to be sorted in numerical order. Lexicographical sorting is use for tiebreaking, which lines up (at least in my testing) with the official client's behavior. We may handle some lexicographical edge cases differently (spaces, symbols, etc) but 1. the Desktop client compliance is best effort and 2. users should use the position fields instead of relying on text sort order. Some compatibility is still helpful for matching temporary channel positioning, especially for servers with automated channel creation workflows.
This code is a bit complicated, as the mumble protocol makes no guarantees which order the channels will be sent. It ended up being simpler to just bulk recreate the children anytime any channel update is sent. I don't expect this to ever have performance issues, though maybe someday some server with 10,000 channels will send us a bug report 😆
# Testing
I tested this change by creating a bunch of channel with various sort orders and names. I compared the behavior with the official desktop client and our client seemed to follow along.
Reviewed-on: #20
(Turns out not) Pretty simple, if the average amplitude is under a certain value clear
out the buffer! The value I chose (.001) was an arbitrary value I got
from printf debugging. I was able to show that this worked pretty well
on the desktop session. Hopefully we'll add this to the settings page at
some point.
Once the app has been under that threshold for more than 200ms, we stop transmitting and send a terminator packet.
Reviewed-on: #13
Reviewed-by: restitux <restitux@ohea.xyz>
I noticed our BRB and AFK rooms were borked and made a change to fix that. I've attached a photo showing the result.
Overview:
- Add suppress field to UserState struct
- Process suppress field from UserState protobuf messages
- Update UI to show suppressed users with blacked out styling and muted icon
- Disable mute toggle button when user is suppressed
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Reviewed-on: #16
This adds android builds to the CI infrastructure. These builds generate an `apk` file that you can download and install.
- Adds a new container build job that builds a container with all the required android dependencies
- Adds a new release build that builds an android apk
- Updated the imp module to split out mobile and desktop behavior
- Adds logic to request microphone permissions
- Added a custom android manifest that declares the required permissions
Reviewed-on: #9