From e3230d49d369995f2a590a0e8c7c657daf40fae7 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 29 Aug 2026 11:19:15 -0400 Subject: [PATCH 1/6] Fixed sidebar --- src/App.tsx | 2 +- src/components/sidebar/MainPageSidebar.tsx | 107 +++++++++++---------- src/components/sidebar/ServerSidebar.tsx | 8 +- 3 files changed, 62 insertions(+), 55 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 52d1655..542ba27 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -49,7 +49,7 @@ export default function App() { minSize="4rem" groupResizeBehavior="preserve-pixel-size" > -
+
diff --git a/src/components/sidebar/MainPageSidebar.tsx b/src/components/sidebar/MainPageSidebar.tsx index 0b72932..f46aaaa 100644 --- a/src/components/sidebar/MainPageSidebar.tsx +++ b/src/components/sidebar/MainPageSidebar.tsx @@ -5,6 +5,7 @@ import { openUrl } from "@tauri-apps/plugin-opener"; import { Button } from "@/components/ui/button"; import { RefreshCw, Rss } from "lucide-react"; import { cn } from "@/lib/utils"; +import StatusCard from "../view/StatusCard"; function formatTime(publishedAt: number): string { if (!publishedAt) return ""; @@ -73,7 +74,9 @@ function StaticFallback() { ); } -export default function MainPageSidebar(_props: { +export default function MainPageSidebar({ + appRef, +}: { appRef: React.RefObject; }) { const [items, setItems] = useState(null); @@ -98,58 +101,62 @@ export default function MainPageSidebar(_props: { }, [load]); return ( -
-
-

- - Security News -

- -
+
+
+
+

+ + Security News +

+ +
-
- {loading && items === null && ( -

- Loading news… -

- )} +
+ {loading && items === null && ( +

+ Loading news… +

+ )} - {error && !loading && } + {error && !loading && } - {items && ( -
- {items.map((item) => ( - - ))} -
- )} -
+ {items && ( +
+ {items.map((item) => ( + + ))} +
+ )} +
+
+ +
); } diff --git a/src/components/sidebar/ServerSidebar.tsx b/src/components/sidebar/ServerSidebar.tsx index 3b20c19..45e6f48 100644 --- a/src/components/sidebar/ServerSidebar.tsx +++ b/src/components/sidebar/ServerSidebar.tsx @@ -156,20 +156,20 @@ export default function ServerSidebar({ appRef: React.RefObject; }) { return ( -
+
{appRef.current?.server?.meta && ( - <> +

{appRef.current.server.meta.name}

-
+
- +
)} From 11d271c5b736e6ad4971324afae9061fef9f1907 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 29 Aug 2026 11:27:15 -0400 Subject: [PATCH 2/6] Fixed mute and deafen --- src-tauri/src/commands/audio.rs | 19 +++++++++++++------ src-tauri/src/commands/config.rs | 6 ++---- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src-tauri/src/commands/audio.rs b/src-tauri/src/commands/audio.rs index 916ab3b..049a848 100644 --- a/src-tauri/src/commands/audio.rs +++ b/src-tauri/src/commands/audio.rs @@ -46,6 +46,7 @@ pub struct VoiceState { #[derive(Default)] pub struct VoiceStateInner { pub session: Mutex>, + pub backend_config: Arc>, } pub struct VoiceSession { @@ -532,10 +533,7 @@ pub fn connect_to_vc( producer_in: Arc::clone(&shared_producer_in), consumer_out: Arc::clone(&shared_consumer_out), - backend_config: Arc::new(Mutex::new(BackendConfig { - is_muted: false, - is_deaf: false, - })), + backend_config: Arc::clone(&voice_state.inner.backend_config), }; session.setup_input(config.input_device_name.clone(), Arc::clone(&state_inner))?; @@ -641,6 +639,7 @@ pub fn connect_to_vc( let shutdown = shutdown.clone(); let cipher = cipher.clone(); let backend_config = session.backend_config.clone(); + let consumer_out = session.consumer_out.clone(); thread::spawn(move || { let mut packets: BTreeMap> = BTreeMap::new(); @@ -651,9 +650,17 @@ pub fn connect_to_vc( let mut next_frame_time = Instant::now(); while !shutdown.load(Ordering::Relaxed) { - let is_deaf = { backend_config.lock().unwrap().is_deaf }; + let (is_muted, is_deaf) = { + let cfg = backend_config.lock().unwrap(); + (cfg.is_muted, cfg.is_deaf) + }; - if is_deaf { + if is_muted || is_deaf { + // Drop any audio already buffered for playback so that on + // unmute/undeafen we don't replay stale audio from the past. + if let Ok(mut cons) = consumer_out.lock() { + cons.clear(); + } packets.clear(); is_prebuffering = true; diff --git a/src-tauri/src/commands/config.rs b/src-tauri/src/commands/config.rs index c8d672f..5befd49 100644 --- a/src-tauri/src/commands/config.rs +++ b/src-tauri/src/commands/config.rs @@ -103,7 +103,7 @@ pub fn get_config(app: AppHandle, state: State) -> Result, config: BackendConfig, ) -> Result<(), String> { - if let Some(v) = &mut *voice_state.inner.session.lock().unwrap() { - *v.backend_config.lock().unwrap() = config - } + *voice_state.inner.backend_config.lock().unwrap() = config; Ok(()) } From 15aafeda580d5818bd63bca0ba3eb922d717ba53 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 29 Aug 2026 11:31:46 -0400 Subject: [PATCH 3/6] Fixed mute and deafen --- src-tauri/src/commands/audio.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src-tauri/src/commands/audio.rs b/src-tauri/src/commands/audio.rs index 049a848..e6fd85b 100644 --- a/src-tauri/src/commands/audio.rs +++ b/src-tauri/src/commands/audio.rs @@ -656,15 +656,22 @@ pub fn connect_to_vc( }; if is_muted || is_deaf { + // Keep draining the UDP socket while deafened/muted so stale + // packets don't accumulate in the OS buffer and get replayed + // when we undeafen/unmute. Decrypting and discarding here + // fully consumes the socket backlog. + if let Ok(len) = socket.recv(&mut udp_buffer) { + let _ = cipher.lock().unwrap().decrypt(&udp_buffer[..len]); + } // Drop any audio already buffered for playback so that on - // unmute/undeafen we don't replay stale audio from the past. + // unmute/undeafen we don't replay audio from the past. if let Ok(mut cons) = consumer_out.lock() { cons.clear(); } packets.clear(); is_prebuffering = true; - std::thread::sleep(Duration::from_secs(1)); + thread::sleep(Duration::from_millis(1)); continue; } From 0104c151ce96963dedda5bd4afcf19ee31037385 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 29 Aug 2026 11:33:46 -0400 Subject: [PATCH 4/6] A little more gap --- src/components/sidebar/ServerSidebar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/sidebar/ServerSidebar.tsx b/src/components/sidebar/ServerSidebar.tsx index 45e6f48..d18a6cc 100644 --- a/src/components/sidebar/ServerSidebar.tsx +++ b/src/components/sidebar/ServerSidebar.tsx @@ -64,7 +64,7 @@ export function RenderFeatures({ return ( users && ( -
+
{(isCurrentVc ? users : users.slice(0, 15)).map((pubkey) => { const user = appRef.current?.server?.users[pubkey]; if (!user) return null; From b950bb48167c1432b7aa22c5eb0fb3efd35537c2 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 29 Aug 2026 11:34:13 -0400 Subject: [PATCH 5/6] A little more gap --- src/components/sidebar/ServerSidebar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/sidebar/ServerSidebar.tsx b/src/components/sidebar/ServerSidebar.tsx index d18a6cc..9b0bbbd 100644 --- a/src/components/sidebar/ServerSidebar.tsx +++ b/src/components/sidebar/ServerSidebar.tsx @@ -64,7 +64,7 @@ export function RenderFeatures({ return ( users && ( -
+
{(isCurrentVc ? users : users.slice(0, 15)).map((pubkey) => { const user = appRef.current?.server?.users[pubkey]; if (!user) return null; From 78c1f07a3534e562ecd08f10d5ee813ce66eea13 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 29 Aug 2026 11:36:59 -0400 Subject: [PATCH 6/6] Fix muting also deaf --- src-tauri/src/commands/audio.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src-tauri/src/commands/audio.rs b/src-tauri/src/commands/audio.rs index e6fd85b..05f7ed1 100644 --- a/src-tauri/src/commands/audio.rs +++ b/src-tauri/src/commands/audio.rs @@ -650,12 +650,12 @@ pub fn connect_to_vc( let mut next_frame_time = Instant::now(); while !shutdown.load(Ordering::Relaxed) { - let (is_muted, is_deaf) = { + let is_deaf = { let cfg = backend_config.lock().unwrap(); - (cfg.is_muted, cfg.is_deaf) + cfg.is_deaf }; - if is_muted || is_deaf { + if is_deaf { // Keep draining the UDP socket while deafened/muted so stale // packets don't accumulate in the OS buffer and get replayed // when we undeafen/unmute. Decrypting and discarding here