Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

174 changes: 147 additions & 27 deletions apps/desktop/src/components/editor-area/note-header/listen-button.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
import { Trans } from "@lingui/react/macro";
import { useMutation, useQuery } from "@tanstack/react-query";
import { MicIcon, MicOffIcon, PauseIcon, PlayIcon, StopCircleIcon, Volume2Icon, VolumeOffIcon } from "lucide-react";
import {
CheckIcon,
ChevronDownIcon,
MicIcon,
MicOffIcon,
PauseIcon,
PlayIcon,
StopCircleIcon,
Volume2Icon,
VolumeOffIcon,
} from "lucide-react";
import { useEffect, useState } from "react";

import SoundIndicator from "@/components/sound-indicator";
Expand Down Expand Up @@ -319,16 +329,14 @@ function RecordingControls({

return (
<>
<div className="flex w-full justify-between mb-3">
<AudioControlButton
<div className="flex gap-2 w-full justify-between mb-3">
<MicrophoneSelector
isMuted={ongoingSessionMuted.micMuted}
onClick={() => toggleMicMuted.mutate()}
type="mic"
onToggleMuted={() => toggleMicMuted.mutate()}
/>
<AudioControlButton
<SpeakerButton
isMuted={ongoingSessionMuted.speakerMuted}
onClick={() => toggleSpeakerMuted.mutate()}
type="speaker"
/>
</div>

Expand Down Expand Up @@ -377,35 +385,147 @@ function RecordingControls({
);
}

function AudioControlButton({
type,
function MicrophoneSelector({
isMuted,
onToggleMuted,
disabled,
}: {
isMuted?: boolean;
onToggleMuted: () => void;
disabled?: boolean;
}) {
const [isOpen, setIsOpen] = useState(false);

const allDevicesQuery = useQuery({
queryKey: ["microphone", "devices"],
queryFn: () => listenerCommands.listMicrophoneDevices(),
});

const currentDeviceQuery = useQuery({
queryKey: ["microphone", "current-device"],
queryFn: () => listenerCommands.getCurrentMicrophoneDevice(),
});

const handleSelectDevice = (device: string) => {
listenerCommands.setMicrophoneDevice(device).then(() => {
currentDeviceQuery.refetch();
});
};

useEffect(() => {
console.log("currentDeviceQuery.data", currentDeviceQuery.data);
console.log("allDevicesQuery.data", allDevicesQuery.data);
}, [currentDeviceQuery.data, allDevicesQuery.data]);
Comment on lines +415 to +418
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Remove debugging console.log statements

These appear to be debugging statements that should not be in production code.

-  useEffect(() => {
-    console.log("currentDeviceQuery.data", currentDeviceQuery.data);
-    console.log("allDevicesQuery.data", allDevicesQuery.data);
-  }, [currentDeviceQuery.data, allDevicesQuery.data]);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
useEffect(() => {
console.log("currentDeviceQuery.data", currentDeviceQuery.data);
console.log("allDevicesQuery.data", allDevicesQuery.data);
}, [currentDeviceQuery.data, allDevicesQuery.data]);
🤖 Prompt for AI Agents
In apps/desktop/src/components/editor-area/note-header/listen-button.tsx around
lines 415 to 418, remove the console.log statements used for debugging
currentDeviceQuery.data and allDevicesQuery.data to clean up the production
code.


const Icon = isMuted ? MicOffIcon : MicIcon;

return (
<div className="flex-1 min-w-0">
<Popover open={isOpen} onOpenChange={setIsOpen}>
<div className="flex -space-x-px">
<Button
variant="outline"
className="rounded-r-none flex-1 min-w-0 h-10"
disabled={disabled}
onClick={onToggleMuted}
>
<Icon
className={cn(
"w-4 h-4 flex-shrink-0",
isMuted ? "text-neutral-500" : "",
disabled && "text-neutral-300",
)}
/>
{!disabled && <SoundIndicator input="mic" size="long" />}
</Button>

<PopoverTrigger asChild>
<Button
variant="outline"
className="rounded-l-none px-0.5 flex-shrink-0"
disabled={disabled}
>
<ChevronDownIcon className="w-4 h-4" />
</Button>
</PopoverTrigger>
</div>

<PopoverContent className="w-64 p-0" align="end">
<div className="p-2">
<div className="mb-2 px-2">
<span className="text-sm font-medium">Microphone</span>
</div>

{allDevicesQuery.isLoading
? (
<div className="p-4 text-center">
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-neutral-600 mx-auto"></div>
<p className="text-sm text-neutral-500 mt-2">Loading devices...</p>
</div>
)
: allDevicesQuery.data?.length === 0
? (
<div className="p-4 text-center">
<p className="text-sm text-neutral-500">No microphones found</p>
</div>
)
: (
<div className="space-y-1">
{allDevicesQuery.data?.map((device) => {
const isSelected = device === currentDeviceQuery.data;
return (
<Button
key={device}
variant="ghost"
className={cn(
"w-full justify-start text-left h-8 px-2",
isSelected && "bg-neutral-100",
)}
onClick={() => {
handleSelectDevice(device);
setIsOpen(false);
}}
>
<Icon className="w-3 h-3 mr-2 flex-shrink-0" />
<span className="text-sm truncate flex-1">{device}</span>
{isSelected && <CheckIcon className="w-3 h-3 ml-auto flex-shrink-0 text-green-600" />}
</Button>
);
})}
</div>
)}
</div>
</PopoverContent>
</Popover>
</div>
);
}

function SpeakerButton({
isMuted,
onClick,
disabled,
}: {
type: "mic" | "speaker";
isMuted?: boolean;
onClick: () => void;
disabled?: boolean;
}) {
const Icon = type === "mic"
? isMuted
? MicOffIcon
: MicIcon
: isMuted
? VolumeOffIcon
: Volume2Icon;
const Icon = isMuted ? VolumeOffIcon : Volume2Icon;

return (
<Button
variant="ghost"
size="icon"
onClick={onClick}
className="w-full"
disabled={disabled}
>
<Icon className={cn(isMuted ? "text-neutral-500" : "", disabled && "text-neutral-300")} size={20} />
{!disabled && <SoundIndicator input={type} size="long" />}
</Button>
<div className="flex-1 min-w-0">
<Button
variant="outline"
onClick={onClick}
className="w-full h-10"
disabled={disabled}
>
<Icon
className={cn("flex-shrink-0", isMuted ? "text-neutral-500" : "", disabled && "text-neutral-300")}
size={16}
/>
{!disabled && <SoundIndicator input="speaker" size="long" />}
</Button>
</div>
);
}
16 changes: 8 additions & 8 deletions apps/desktop/src/locales/en/messages.po
Original file line number Diff line number Diff line change
Expand Up @@ -256,8 +256,8 @@ msgstr "(Beta) Upcoming meeting notifications"
#. placeholder {0}: disabled ? "Wait..." : isHovered ? "Resume" : "Ended"
#: src/components/settings/views/templates.tsx:194
#: src/components/settings/components/wer-modal.tsx:116
#: src/components/editor-area/note-header/listen-button.tsx:179
#: src/components/editor-area/note-header/listen-button.tsx:218
#: src/components/editor-area/note-header/listen-button.tsx:189
#: src/components/editor-area/note-header/listen-button.tsx:228
msgid "{0}"
msgstr "{0}"

Expand Down Expand Up @@ -887,7 +887,7 @@ msgstr "No speech-to-text models available or failed to load."
#~ msgid "No Template"
#~ msgstr "No Template"

#: src/components/editor-area/note-header/listen-button.tsx:342
#: src/components/editor-area/note-header/listen-button.tsx:350
msgid "No Template (Default)"
msgstr "No Template (Default)"

Expand Down Expand Up @@ -955,7 +955,7 @@ msgstr "Optional for participant suggestions"
msgid "Owner"
msgstr "Owner"

#: src/components/editor-area/note-header/listen-button.tsx:365
#: src/components/editor-area/note-header/listen-button.tsx:373
msgid "Pause"
msgstr "Pause"

Expand All @@ -967,7 +967,7 @@ msgstr "people"
msgid "Performance difference between languages"
msgstr "Performance difference between languages"

#: src/components/editor-area/note-header/listen-button.tsx:198
#: src/components/editor-area/note-header/listen-button.tsx:208
msgid "Play video"
msgstr "Play video"

Expand Down Expand Up @@ -1011,7 +1011,7 @@ msgstr "Required to transcribe other people's voice during meetings"
msgid "Required to transcribe your voice during meetings"
msgstr "Required to transcribe your voice during meetings"

#: src/components/editor-area/note-header/listen-button.tsx:107
#: src/components/editor-area/note-header/listen-button.tsx:117
msgid "Resume"
msgstr "Resume"

Expand Down Expand Up @@ -1109,11 +1109,11 @@ msgstr "Start Annual Plan"
msgid "Start Monthly Plan"
msgstr "Start Monthly Plan"

#: src/components/editor-area/note-header/listen-button.tsx:154
#: src/components/editor-area/note-header/listen-button.tsx:164
msgid "Start recording"
msgstr "Start recording"

#: src/components/editor-area/note-header/listen-button.tsx:373
#: src/components/editor-area/note-header/listen-button.tsx:381
msgid "Stop"
msgstr "Stop"

Expand Down
16 changes: 8 additions & 8 deletions apps/desktop/src/locales/ko/messages.po
Original file line number Diff line number Diff line change
Expand Up @@ -256,8 +256,8 @@ msgstr ""
#. placeholder {0}: disabled ? "Wait..." : isHovered ? "Resume" : "Ended"
#: src/components/settings/views/templates.tsx:194
#: src/components/settings/components/wer-modal.tsx:116
#: src/components/editor-area/note-header/listen-button.tsx:179
#: src/components/editor-area/note-header/listen-button.tsx:218
#: src/components/editor-area/note-header/listen-button.tsx:189
#: src/components/editor-area/note-header/listen-button.tsx:228
msgid "{0}"
msgstr ""

Expand Down Expand Up @@ -887,7 +887,7 @@ msgstr ""
#~ msgid "No Template"
#~ msgstr ""

#: src/components/editor-area/note-header/listen-button.tsx:342
#: src/components/editor-area/note-header/listen-button.tsx:350
msgid "No Template (Default)"
msgstr ""

Expand Down Expand Up @@ -955,7 +955,7 @@ msgstr ""
msgid "Owner"
msgstr ""

#: src/components/editor-area/note-header/listen-button.tsx:365
#: src/components/editor-area/note-header/listen-button.tsx:373
msgid "Pause"
msgstr ""

Expand All @@ -967,7 +967,7 @@ msgstr ""
msgid "Performance difference between languages"
msgstr ""

#: src/components/editor-area/note-header/listen-button.tsx:198
#: src/components/editor-area/note-header/listen-button.tsx:208
msgid "Play video"
msgstr ""

Expand Down Expand Up @@ -1011,7 +1011,7 @@ msgstr ""
msgid "Required to transcribe your voice during meetings"
msgstr ""

#: src/components/editor-area/note-header/listen-button.tsx:107
#: src/components/editor-area/note-header/listen-button.tsx:117
msgid "Resume"
msgstr ""

Expand Down Expand Up @@ -1109,11 +1109,11 @@ msgstr ""
msgid "Start Monthly Plan"
msgstr ""

#: src/components/editor-area/note-header/listen-button.tsx:154
#: src/components/editor-area/note-header/listen-button.tsx:164
msgid "Start recording"
msgstr ""

#: src/components/editor-area/note-header/listen-button.tsx:373
#: src/components/editor-area/note-header/listen-button.tsx:381
msgid "Stop"
msgstr ""

Expand Down
6 changes: 0 additions & 6 deletions apps/desktop/src/utils/broadcast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,6 @@ export function broadcastQueryClient(queryClient: QueryClient) {

const keys = event.payload.queryKey as string[];

if (keys.some((key) => key?.includes("extension"))) {
queryClient.invalidateQueries({
predicate: (query) => query.queryKey.some((key) => typeof key === "string" && key.includes("extension")),
});
}

if (keys.some((key) => key?.includes("flags"))) {
queryClient.invalidateQueries({
predicate: (query) => query.queryKey.some((key) => typeof key === "string" && key.includes("flags")),
Expand Down
1 change: 1 addition & 0 deletions crates/audio/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ futures-util = { workspace = true }
tokio = { workspace = true, features = ["rt", "macros"] }

cpal = { workspace = true }
dasp = { workspace = true }
rodio = { workspace = true }

ebur128 = "0.1.10"
Expand Down
Loading
Loading