-
Notifications
You must be signed in to change notification settings - Fork 537
Overlay floating control [Improvements to #892] #907
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -11,6 +11,7 @@ import { | |||||||||||||||||||||||||||||||||||||||
| VolumeOffIcon, | ||||||||||||||||||||||||||||||||||||||||
| } from "lucide-react"; | ||||||||||||||||||||||||||||||||||||||||
| import { useEffect, useState } from "react"; | ||||||||||||||||||||||||||||||||||||||||
| import { emit, listen } from "@tauri-apps/api/event"; | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| import SoundIndicator from "@/components/sound-indicator"; | ||||||||||||||||||||||||||||||||||||||||
| import { useHypr } from "@/contexts"; | ||||||||||||||||||||||||||||||||||||||||
|
|
@@ -227,7 +228,8 @@ export function WhenActive() { | |||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||||||||||||||||||||
| if (showConsent) { | ||||||||||||||||||||||||||||||||||||||||
| listenerCommands.setSpeakerMuted(true).then(() => { | ||||||||||||||||||||||||||||||||||||||||
| listenerCommands.setSpeakerMuted(true).then(async () => { | ||||||||||||||||||||||||||||||||||||||||
| await emit("audio-speaker-state-changed", { muted: true }); | ||||||||||||||||||||||||||||||||||||||||
| audioControls.refetchSpeakerMuted(); | ||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
@@ -237,9 +239,12 @@ export function WhenActive() { | |||||||||||||||||||||||||||||||||||||||
| mutationFn: async (recordEveryone: boolean) => { | ||||||||||||||||||||||||||||||||||||||||
| if (recordEveryone) { | ||||||||||||||||||||||||||||||||||||||||
| await listenerCommands.setSpeakerMuted(false); | ||||||||||||||||||||||||||||||||||||||||
| await emit("audio-speaker-state-changed", { muted: false }); | ||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||
| await listenerCommands.setSpeakerMuted(true); | ||||||||||||||||||||||||||||||||||||||||
| await listenerCommands.setMicMuted(false); | ||||||||||||||||||||||||||||||||||||||||
| await emit("audio-speaker-state-changed", { muted: true }); | ||||||||||||||||||||||||||||||||||||||||
| await emit("audio-mic-state-changed", { muted: false }); | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| setHasShownConsent(true); | ||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||
|
|
@@ -438,13 +443,43 @@ function useAudioControls() { | |||||||||||||||||||||||||||||||||||||||
| queryFn: () => listenerCommands.getSpeakerMuted(), | ||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| // Listen for audio state changes from other windows | ||||||||||||||||||||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||||||||||||||||||||
| const unsubscribeMicState = listen<{ muted: boolean }>("audio-mic-state-changed", ({ payload }) => { | ||||||||||||||||||||||||||||||||||||||||
| console.log(`[Main Window] Received mic state change:`, payload); | ||||||||||||||||||||||||||||||||||||||||
| refetchMicMuted(); | ||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| const unsubscribeSpeakerState = listen<{ muted: boolean }>("audio-speaker-state-changed", ({ payload }) => { | ||||||||||||||||||||||||||||||||||||||||
| console.log(`[Main Window] Received speaker state change:`, payload); | ||||||||||||||||||||||||||||||||||||||||
| refetchSpeakerMuted(); | ||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| return () => { | ||||||||||||||||||||||||||||||||||||||||
| unsubscribeMicState.then(unlisten => unlisten()); | ||||||||||||||||||||||||||||||||||||||||
| unsubscribeSpeakerState.then(unlisten => unlisten()); | ||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||
| }, [refetchMicMuted, refetchSpeakerMuted]); | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| const toggleMicMuted = useMutation({ | ||||||||||||||||||||||||||||||||||||||||
| mutationFn: () => listenerCommands.setMicMuted(!isMicMuted), | ||||||||||||||||||||||||||||||||||||||||
| mutationFn: async () => { | ||||||||||||||||||||||||||||||||||||||||
| const newMuted = !isMicMuted; | ||||||||||||||||||||||||||||||||||||||||
| await listenerCommands.setMicMuted(newMuted); | ||||||||||||||||||||||||||||||||||||||||
| // Emit event to synchronize with other windows | ||||||||||||||||||||||||||||||||||||||||
| await emit("audio-mic-state-changed", { muted: newMuted }); | ||||||||||||||||||||||||||||||||||||||||
| return newMuted; | ||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||
| onSuccess: () => refetchMicMuted(), | ||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+465
to
472
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Undefined state can flip mic unintentionally
- const newMuted = !isMicMuted;
+ if (isMicMuted === undefined) {
+ return; // or disable the button until loaded
+ }
+ const newMuted = !isMicMuted;The same applies to 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| const toggleSpeakerMuted = useMutation({ | ||||||||||||||||||||||||||||||||||||||||
| mutationFn: () => listenerCommands.setSpeakerMuted(!isSpeakerMuted), | ||||||||||||||||||||||||||||||||||||||||
| mutationFn: async () => { | ||||||||||||||||||||||||||||||||||||||||
| const newMuted = !isSpeakerMuted; | ||||||||||||||||||||||||||||||||||||||||
| await listenerCommands.setSpeakerMuted(newMuted); | ||||||||||||||||||||||||||||||||||||||||
| // Emit event to synchronize with other windows | ||||||||||||||||||||||||||||||||||||||||
| await emit("audio-speaker-state-changed", { muted: newMuted }); | ||||||||||||||||||||||||||||||||||||||||
| return newMuted; | ||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||
| onSuccess: () => refetchSpeakerMuted(), | ||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Potential memory-leak & race in event listener cleanup
listenreturnsPromise<UnlistenFn>.Storing the promise and later calling
.then(unlisten => unlisten())inside the cleanup works, but if the promise rejects (e.g. window closed) the.catch()branch is swallowed and the listener may linger.A safer pattern is:
useEffect(() => { - const unsub = listen<Payload>("evt", handler); + let unlisten: (() => void) | undefined; + const unsubPromise = listen<Payload>("evt", handler) + .then(fn => (unlisten = fn)) + .catch(console.error); return () => { - unsub.then(u => u()).catch(console.error); + if (unlisten) unlisten(); }; }, []);This guarantees that the actual
unlistenfunction is called or the error is surfaced.🤖 Prompt for AI Agents