The client now handles being suppressed correctly (#16)
Build Mumble Web 2 / linux_build (push) Successful in 1m25s
Build Mumble Web 2 / windows_build (push) Successful in 2m38s
Build Mumble Web 2 / android_build (push) Successful in 5m56s

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 commit was merged in pull request #16.
This commit is contained in:
2026-01-19 19:12:57 +00:00
parent d7b88874df
commit c8119d0efa
2 changed files with 20 additions and 10 deletions
+17 -10
View File
@@ -68,16 +68,21 @@ pub struct UserState {
pub channel: ChannelId, pub channel: ChannelId,
pub deaf: bool, pub deaf: bool,
pub mute: bool, pub mute: bool,
pub suppress: bool,
pub self_deaf: bool, pub self_deaf: bool,
pub self_mute: bool, pub self_mute: bool,
} }
impl UserState { impl UserState {
pub fn icon(&self) -> UserIcon { pub fn icon(&self) -> UserIcon {
match (self.mute || self.self_mute, self.deaf || self.self_deaf) { if self.deaf || self.self_deaf {
(false, false) => UserIcon::Normal, UserIcon::Deafened
(true, false) => UserIcon::Muted, } else if self.mute || self.self_mute {
(_, true) => UserIcon::Deafened, UserIcon::Muted
} else if self.suppress {
UserIcon::Suppressed
} else {
UserIcon::Normal
} }
} }
} }
@@ -117,6 +122,7 @@ pub enum UserIcon {
Normal, Normal,
Muted, Muted,
Deafened, Deafened,
Suppressed,
None, None,
} }
@@ -128,7 +134,7 @@ impl UserIcon {
use UserIcon::*; use UserIcon::*;
Some(match self { Some(match self {
Normal => asset!("assets/mic-svgrepo-com.svg"), Normal => asset!("assets/mic-svgrepo-com.svg"),
Muted => asset!("assets/mic-off-svgrepo-com.svg"), Muted | Suppressed => asset!("assets/mic-off-svgrepo-com.svg"),
Deafened => asset!("assets/speaker-muted-svgrepo-com.svg"), Deafened => asset!("assets/speaker-muted-svgrepo-com.svg"),
None => return Option::None, None => return Option::None,
}) })
@@ -140,7 +146,7 @@ pub fn UserPill(name: String, icon: UserIcon, isself: bool) -> Element {
let color = match icon { let color = match icon {
UserIcon::Normal => "var(--accent-normal)", UserIcon::Normal => "var(--accent-normal)",
UserIcon::Muted => "var(--accent-muted)", UserIcon::Muted => "var(--accent-muted)",
UserIcon::Deafened => "var(--accent-deafened)", UserIcon::Suppressed | UserIcon::Deafened => "var(--accent-deafened)",
UserIcon::None => "var(--accent-normal)", UserIcon::None => "var(--accent-normal)",
}; };
@@ -320,6 +326,7 @@ pub fn ControlView(config: Resource<ClientConfig>) -> Element {
deaf, deaf,
self_deaf, self_deaf,
mute, mute,
suppress,
self_mute, self_mute,
ref name, ref name,
channel, channel,
@@ -470,15 +477,15 @@ pub fn ControlView(config: Resource<ClientConfig>) -> Element {
} }
} }
button { button {
class: match mute || self_mute { class: match mute || suppress || self_mute {
true => "toggle_button is_on", true => "toggle_button is_on",
false => "toggle_button", false => "toggle_button",
}, },
role: "switch", role: "switch",
aria_checked: mute || self_mute, aria_checked: mute || suppress || self_mute,
disabled: mute, disabled: mute || suppress,
onclick: move |_| net.send(SetMute { mute: !self_mute }), onclick: move |_| net.send(SetMute { mute: !self_mute }),
match mute || self_mute { match mute || suppress || self_mute {
true => rsx!(span { class: "material-symbols-outlined", "mic_off"}), true => rsx!(span { class: "material-symbols-outlined", "mic_off"}),
false => rsx!(span { class: "material-symbols-outlined", "mic"}), false => rsx!(span { class: "material-symbols-outlined", "mic"}),
} }
+3
View File
@@ -404,6 +404,9 @@ fn accept_packet(
if u.has_deaf() { if u.has_deaf() {
state.deaf = u.get_deaf(); state.deaf = u.get_deaf();
} }
if u.has_suppress() {
state.suppress = u.get_suppress();
}
if u.has_self_mute() { if u.has_self_mute() {
state.self_mute = u.get_self_mute(); state.self_mute = u.get_self_mute();
} }