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
8 changes: 3 additions & 5 deletions apps/desktop/src/components/editor-area/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -199,11 +199,11 @@ export default function EditorArea({

const handleEnhanceWithTemplate = useCallback((templateId: string) => {
const targetTemplateId = templateId === "auto" ? null : templateId;
enhance.mutate({ templateId: targetTemplateId, triggerType: "template" });
enhance.mutate({ templateId: targetTemplateId });
}, [enhance]);

const handleClickEnhance = useCallback(() => {
enhance.mutate({ triggerType: "manual" });
enhance.mutate({});
}, [enhance]);

const safelyFocusEditor = useCallback(() => {
Expand Down Expand Up @@ -403,12 +403,10 @@ export function useEnhanceMutation({
const enhance = useMutation({
mutationKey: ["enhance", sessionId],
mutationFn: async ({
triggerType,
templateId,
}: {
triggerType: "manual" | "template" | "auto";
templateId?: string | null;
} = { triggerType: "manual" }) => {
}) => {
setIsCancelled(false);
originalContentRef.current = getCurrentEnhancedContent;
const abortController = new AbortController();
Expand Down
197 changes: 16 additions & 181 deletions apps/desktop/src/components/editor-area/note-header/listen-button.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { zodResolver } from "@hookform/resolvers/zod";
import { Trans } from "@lingui/react/macro";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { useMutation, useQuery } from "@tanstack/react-query";
import {
CheckIcon,
ChevronDownIcon,
MicIcon,
MicOffIcon,
PauseIcon,
PlayIcon,
StopCircleIcon,
Volume2Icon,
Expand All @@ -19,18 +18,12 @@ import { z } from "zod";
import SoundIndicator from "@/components/sound-indicator";
import { useHypr } from "@/contexts";
import { useEnhancePendingState } from "@/hooks/enhance-pending";
import { TemplateService } from "@/utils/template-service";
import { commands as analyticsCommands } from "@hypr/plugin-analytics";
import { commands as dbCommands } from "@hypr/plugin-db";
import { commands as listenerCommands } from "@hypr/plugin-listener";
import { commands as localSttCommands } from "@hypr/plugin-local-stt";
import { commands as miscCommands } from "@hypr/plugin-misc";
import { Button } from "@hypr/ui/components/ui/button";
import { Form, FormControl, FormField, FormItem, FormLabel } from "@hypr/ui/components/ui/form";
import { Popover, PopoverContent, PopoverTrigger } from "@hypr/ui/components/ui/popover";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@hypr/ui/components/ui/select";
import { Spinner } from "@hypr/ui/components/ui/spinner";
import { Switch } from "@hypr/ui/components/ui/switch";
import { sonnerToast, toast } from "@hypr/ui/components/ui/toast";
import { Tooltip, TooltipContent, TooltipTrigger } from "@hypr/ui/components/ui/tooltip";
import { cn } from "@hypr/ui/lib/utils";
Expand Down Expand Up @@ -63,8 +56,6 @@ export default function ListenButton({ sessionId, isCompact = false }: { session
const ongoingSessionId = useOngoingSession((s) => s.sessionId);
const ongoingSessionStore = useOngoingSession((s) => ({
start: s.start,
resume: s.resume,
pause: s.pause,
stop: s.stop,
loading: s.loading,
}));
Expand Down Expand Up @@ -112,10 +103,6 @@ export default function ListenButton({ sessionId, isCompact = false }: { session
}
};

const handleResumeSession = () => {
ongoingSessionStore.resume();
};

if (ongoingSessionStore.loading) {
return (
<div className="w-9 h-9 flex items-center justify-center">
Expand All @@ -124,24 +111,6 @@ export default function ListenButton({ sessionId, isCompact = false }: { session
);
}

if (ongoingSessionStatus === "running_paused" && sessionId === ongoingSessionId) {
return (
<button
disabled={!modelDownloaded.data}
onClick={handleResumeSession}
className={cn(
`${
isCompact ? "w-16" : "w-16"
} h-9 rounded-full transition-all hover:scale-95 cursor-pointer outline-none p-0 flex items-center justify-center text-xs font-medium`,
"bg-red-100 border-2 border-red-400 text-red-600",
"shadow-[0_0_0_2px_rgba(255,255,255,0.8)_inset]",
)}
>
<Trans>{isCompact ? "Resume" : "Resume"}</Trans>
</button>
);
}

if (ongoingSessionStatus === "inactive") {
const buttonProps = {
disabled: isOnboarding
Expand Down Expand Up @@ -267,23 +236,13 @@ function WhenInactiveAndMeetingEndedOnboarding({ disabled, onClick }: { disabled
function WhenActive({ sessionId }: { sessionId: string }) {
const ongoingSessionId = useOngoingSession((s) => s.sessionId);
const ongoingSessionStore = useOngoingSession((s) => ({
pause: s.pause,
stop: s.stop,
setAutoEnhanceTemplate: s.setAutoEnhanceTemplate,
}));
const sessionWords = useSession(ongoingSessionId!, (s) => s.session.words);
const [isPopoverOpen, setIsPopoverOpen] = useState(false);

const handlePauseSession = () => {
ongoingSessionStore.pause();
setIsPopoverOpen(false);
};

const handleStopSession = (templateId?: string | null) => {
if (templateId !== undefined) {
ongoingSessionStore.setAutoEnhanceTemplate(templateId);
}

const handleStopSession = () => {
ongoingSessionStore.stop();
setIsPopoverOpen(false);

Expand All @@ -308,7 +267,6 @@ function WhenActive({ sessionId }: { sessionId: string }) {
<PopoverContent className="w-64" align="end">
<RecordingControls
sessionId={sessionId}
onPause={handlePauseSession}
onStop={handleStopSession}
/>
</PopoverContent>
Expand All @@ -318,12 +276,10 @@ function WhenActive({ sessionId }: { sessionId: string }) {

function RecordingControls({
sessionId,
onPause,
onStop,
}: {
sessionId: string;
onPause: () => void;
onStop: (templateId?: string | null) => void;
onStop: () => void;
}) {
const { onboardingSessionId } = useHypr();
const ongoingSessionMuted = useOngoingSession((s) => ({
Expand Down Expand Up @@ -353,20 +309,7 @@ function RecordingControls({
/>
</div>

<div className="flex gap-2">
<Button
variant="outline"
onClick={onPause}
className="flex-1 justify-center text-xs text-gray-700"
>
<PauseIcon className="w-4 h-4" />
<Trans>Pause</Trans>
</Button>
<StopButton
sessionId={sessionId}
onStop={onStop}
/>
</div>
<StopButton onStop={onStop} />
</>
);
}
Expand All @@ -378,22 +321,7 @@ const stopButtonSchema = z.object({

type StopButtonFormData = z.infer<typeof stopButtonSchema>;

function StopButton({ sessionId, onStop }: { sessionId: string; onStop: (templateId: string | null) => void }) {
const [isOpen, setIsOpen] = useState(false);
const { userId } = useHypr();

useEffect(() => {
if (isOpen) {
analyticsCommands.event({
event: "stop_button_dropdown_opened",
distinct_id: userId,
session_id: sessionId,
});
}
}, [isOpen]);

const queryClient = useQueryClient();

function StopButton({ onStop }: { onStop: (templateId: string | null) => void }) {
const defaultTemplateQuery = useQuery({
queryKey: ["config"],
queryFn: () => dbCommands.getConfig().then((config) => config.general.selected_template_id),
Expand All @@ -406,19 +334,6 @@ function StopButton({ sessionId, onStop }: { sessionId: string; onStop: (templat
refetchOnWindowFocus: true,
});

const templatesQuery = useQuery({
queryKey: ["templates"],
queryFn: () =>
TemplateService.getAllTemplates().then((templates) =>
templates.map((template) => {
const title = template.title || "Untitled";
const truncatedTitle = title.length > 20 ? title.substring(0, 20) + "..." : title;
return { id: template.id, title: truncatedTitle };
})
),
refetchOnWindowFocus: true,
});

const form = useForm<StopButtonFormData>({
resolver: zodResolver(stopButtonSchema),
defaultValues: {
Expand All @@ -439,98 +354,18 @@ function StopButton({ sessionId, onStop }: { sessionId: string; onStop: (templat
}
}, [saveRecordingsQuery.data, form]);

const handleSubmit = (data: StopButtonFormData) => {
const actualTemplateId = data.selectedTemplate === "auto" ? null : data.selectedTemplate;
if (!data.saveAudio) {
miscCommands.audioDelete(sessionId);
}
onStop(actualTemplateId);
queryClient.invalidateQueries({ predicate: (query) => query.queryKey[0] === "audio" });
};

return (
<Popover open={isOpen} onOpenChange={setIsOpen}>
<Form {...form}>
<form onSubmit={form.handleSubmit(handleSubmit)} className="flex flex-1">
<Button
type="submit"
variant="destructive"
className="flex-1 rounded-r-none justify-center w-[90px] text-xs"
>
<StopCircleIcon
color="white"
className="w-4 h-4"
/>
<Trans>Stop</Trans>
</Button>
<PopoverTrigger asChild>
<Button
type="button"
variant="destructive"
className="rounded-l-none px-2 flex-shrink-0 transition-all border-l border-red-600"
>
<ChevronDownIcon className="w-4 h-4 text-white" />
</Button>
</PopoverTrigger>
</form>
</Form>

<PopoverContent className="w-96">
<Form {...form}>
<div className="space-y-3">
<FormField
control={form.control}
name="saveAudio"
render={({ field }) => (
<FormItem className="flex items-center justify-between space-y-0">
<FormLabel className="text-sm font-medium">
<Trans>Save current recording</Trans>
</FormLabel>
<FormControl>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
className="data-[state=checked]:bg-primary"
/>
</FormControl>
</FormItem>
)}
/>

<div className="border-t border-gray-200" />

<FormField
control={form.control}
name="selectedTemplate"
render={({ field }) => (
<FormItem className="flex flex-row gap-4 items-center space-y-0">
<FormLabel className="text-sm font-medium whitespace-nowrap">
<Trans>Template</Trans>
</FormLabel>
<FormControl>
<Select value={field.value} onValueChange={field.onChange}>
<SelectTrigger className="w-full text-sm">
<SelectValue placeholder="Select template..." />
</SelectTrigger>
<SelectContent className="max-h-44 overflow-y-auto w-[var(--radix-select-trigger-width)]">
<SelectItem value="auto">
<Trans>No Template (Default)</Trans>
</SelectItem>
{templatesQuery.data?.map((template) => (
<SelectItem key={template.id} value={template.id} className="whitespace-nowrap">
{template.title}
</SelectItem>
))}
</SelectContent>
</Select>
</FormControl>
</FormItem>
)}
/>
</div>
</Form>
</PopoverContent>
</Popover>
<Button
variant="destructive"
className="w-full flex-1 justify-center text-xs"
onClick={() => onStop(null)}
>
<StopCircleIcon
color="white"
className="w-4 h-4"
/>
<Trans>Stop</Trans>
</Button>
);
}

Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src/components/left-sidebar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export default function LeftSidebar() {
const isInOngoingNoteMain = activeSessionId === ongoingSessionId;
const isInOngoingNoteSub = activeSessionId === ongoingSessionId;
const isInOngoingNote = isInOngoingNoteMain || isInOngoingNoteSub;
const isMeetingRunning = status === "running_active" || status === "running_paused";
const isMeetingRunning = status === "running_active";
const inMeetingAndNotInNote = isMeetingRunning
&& ongoingSessionId !== null
&& !isInOngoingNote;
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src/components/toast/ota.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export default function OtaNotification() {
}

// Don't show update notifications during active meetings
if (ongoingSession.status === "running_active" || ongoingSession.status === "running_paused") {
if (ongoingSession.status === "running_active") {
return;
}

Expand Down
Loading
Loading