diff --git a/apps/whispering/src-tauri/Cargo.toml b/apps/whispering/src-tauri/Cargo.toml index 09fc1d185c..14e5d63727 100644 --- a/apps/whispering/src-tauri/Cargo.toml +++ b/apps/whispering/src-tauri/Cargo.toml @@ -12,6 +12,10 @@ cargo-target-macos-version = "10.15" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[[bin]] +name = "whispering" +path = "src/main.rs" + [lib] # The `_lib` suffix may seem redundant but it is necessary # to make the lib name unique and wouldn't conflict with the bin name. diff --git a/apps/whispering/src-tauri/tauri.conf.json b/apps/whispering/src-tauri/tauri.conf.json index 17488314d7..03e586b7d1 100644 --- a/apps/whispering/src-tauri/tauri.conf.json +++ b/apps/whispering/src-tauri/tauri.conf.json @@ -21,9 +21,8 @@ "createUpdaterArtifacts": true, "macOS": { "entitlements": "entitlements.plist", - "hardenedRuntime": true, - "minimumSystemVersion": "10.15", - "signingIdentity": "Developer ID Application: Braden Wong (3C7J97QA5Z)" + "hardenedRuntime": false, + "minimumSystemVersion": "10.15" }, "linux": { "appimage": { diff --git a/apps/whispering/src/lib/commands.ts b/apps/whispering/src/lib/commands.ts index aaf9c02d20..ecbb67ebf7 100644 --- a/apps/whispering/src/lib/commands.ts +++ b/apps/whispering/src/lib/commands.ts @@ -1,61 +1,86 @@ import { rpc } from '$lib/query'; + import type { ShortcutTriggerState } from './services/_shortcut-trigger-state'; type SatisfiedCommand = { + callback: () => void; id: string; - title: string; on: ShortcutTriggerState; - callback: () => void; + title: string; }; export const commands = [ { - id: 'pushToTalk', title: 'Push to talk', - on: 'Both', callback: () => rpc.commands.toggleManualRecording.execute(undefined), + id: 'pushToTalk', + on: 'Both', }, { - id: 'toggleManualRecording', title: 'Toggle recording', - on: 'Pressed', callback: () => rpc.commands.toggleManualRecording.execute(undefined), + id: 'toggleManualRecording', + on: 'Pressed', }, { - id: 'startManualRecording', title: 'Start recording', - on: 'Pressed', callback: () => rpc.commands.startManualRecording.execute(undefined), + id: 'startManualRecording', + on: 'Pressed', }, { - id: 'stopManualRecording', title: 'Stop recording', - on: 'Pressed', callback: () => rpc.commands.stopManualRecording.execute(undefined), + id: 'stopManualRecording', + on: 'Pressed', }, { - id: 'cancelManualRecording', title: 'Cancel recording', - on: 'Pressed', callback: () => rpc.commands.cancelManualRecording.execute(undefined), + id: 'cancelManualRecording', + on: 'Pressed', }, { - id: 'startVadRecording', title: 'Start voice activated recording', - on: 'Pressed', callback: () => rpc.commands.startVadRecording.execute(undefined), + id: 'startVadRecording', + on: 'Pressed', }, { - id: 'stopVadRecording', title: 'Stop voice activated recording', - on: 'Pressed', callback: () => rpc.commands.stopVadRecording.execute(undefined), + id: 'stopVadRecording', + on: 'Pressed', }, { - id: 'toggleVadRecording', title: 'Toggle voice activated recording', - on: 'Pressed', callback: () => rpc.commands.toggleVadRecording.execute(undefined), + id: 'toggleVadRecording', + on: 'Pressed', + }, + { + title: 'Cycle through favorite output languages', + callback: () => rpc.commands.toggleOutputLanguage.execute(undefined), + id: 'toggleOutputLanguage', + on: 'Pressed', + }, + { + title: 'Switch to favorite language #1', + callback: () => rpc.commands.setOutputLanguageSlot.execute({ slot: 1 }), + id: 'setOutputLanguageSlot1', + on: 'Pressed', + }, + { + title: 'Switch to favorite language #2', + callback: () => rpc.commands.setOutputLanguageSlot.execute({ slot: 2 }), + id: 'setOutputLanguageSlot2', + on: 'Pressed', + }, + { + title: 'Switch to favorite language #3', + callback: () => rpc.commands.setOutputLanguageSlot.execute({ slot: 3 }), + id: 'setOutputLanguageSlot3', + on: 'Pressed', }, ] as const satisfies SatisfiedCommand[]; diff --git a/apps/whispering/src/lib/components/ConfirmationDialog.svelte b/apps/whispering/src/lib/components/ConfirmationDialog.svelte index 38bc4ad8c3..e70717cb77 100644 --- a/apps/whispering/src/lib/components/ConfirmationDialog.svelte +++ b/apps/whispering/src/lib/components/ConfirmationDialog.svelte @@ -8,29 +8,26 @@ let confirmText = $state(''); let onConfirm = () => {}; return { + close() { + isOpen = false; + }, + get confirmText() { + return confirmText; + }, get isOpen() { return isOpen; }, set isOpen(v) { isOpen = v; }, - get title() { - return title; - }, - get subtitle() { - return subtitle; - }, - get confirmText() { - return confirmText; - }, get onConfirm() { return onConfirm; }, open(dialog: { - title: string; - subtitle: string; confirmText: string; onConfirm: () => void; + subtitle: string; + title: string; }) { title = dialog.title; subtitle = dialog.subtitle; @@ -38,8 +35,11 @@ onConfirm = dialog.onConfirm; isOpen = true; }, - close() { - isOpen = false; + get subtitle() { + return subtitle; + }, + get title() { + return title; }, }; } diff --git a/apps/whispering/src/lib/components/MoreDetailsDialog.svelte b/apps/whispering/src/lib/components/MoreDetailsDialog.svelte index 129b0dee0c..107f0d30b0 100644 --- a/apps/whispering/src/lib/components/MoreDetailsDialog.svelte +++ b/apps/whispering/src/lib/components/MoreDetailsDialog.svelte @@ -13,17 +13,8 @@ >([]); return { - get isOpen() { - return isOpen; - }, - set isOpen(value: boolean) { - isOpen = value; - }, - get title() { - return title; - }, - get description() { - return description; + get buttons() { + return buttons; }, get content() { if (typeof content === 'string') { @@ -34,18 +25,24 @@ } return JSON.stringify(content, null, 2); }, - get buttons() { - return buttons; + get description() { + return description; + }, + get isOpen() { + return isOpen; + }, + set isOpen(value: boolean) { + isOpen = value; }, open: (payload: { - title: string; - description: string; - content: unknown; buttons?: { label: string; onClick: () => void; variant?: 'default' | 'destructive'; }[]; + content: unknown; + description: string; + title: string; }) => { title = payload.title; description = payload.description; @@ -53,13 +50,16 @@ buttons = payload.buttons ?? []; isOpen = true; }, + get title() { + return title; + }, }; })(); diff --git a/apps/whispering/src/lib/components/NavItems.svelte b/apps/whispering/src/lib/components/NavItems.svelte index 321e34cd62..a212e458dd 100644 --- a/apps/whispering/src/lib/components/NavItems.svelte +++ b/apps/whispering/src/lib/components/NavItems.svelte @@ -1,10 +1,7 @@ diff --git a/apps/whispering/src/lib/components/UpdateDialog.svelte b/apps/whispering/src/lib/components/UpdateDialog.svelte index b7cdbb7e05..d029caabb8 100644 --- a/apps/whispering/src/lib/components/UpdateDialog.svelte +++ b/apps/whispering/src/lib/components/UpdateDialog.svelte @@ -2,39 +2,36 @@ import type { Update } from '@tauri-apps/plugin-updater'; export const updateDialog = createUpdateDialog(); - export type UpdateInfo = Pick< + export type UpdateInfo = null | Pick< Update, - 'version' | 'date' | 'body' | 'downloadAndInstall' - > | null; + 'body' | 'date' | 'downloadAndInstall' | 'version' + >; function createUpdateDialog() { let isOpen = $state(false); - let update = $state(null); + let update = $state(null); let downloadProgress = $state(0); let downloadTotal = $state(0); - let error = $state(null); + let error = $state(null); return { - get isOpen() { - return isOpen; + close() { + isOpen = false; }, - set isOpen(v) { - isOpen = v; + get error() { + return error; }, - get update() { - return update; + get isDownloadComplete() { + return downloadTotal > 0 && downloadProgress >= downloadTotal && !error; }, get isDownloading() { return downloadTotal > 0 && downloadProgress < downloadTotal && !error; }, - get isDownloadComplete() { - return downloadTotal > 0 && downloadProgress >= downloadTotal && !error; - }, - get progressPercentage() { - return downloadTotal > 0 ? (downloadProgress / downloadTotal) * 100 : 0; + get isOpen() { + return isOpen; }, - get error() { - return error; + set isOpen(v) { + isOpen = v; }, open(newUpdate: UpdateInfo) { update = newUpdate; @@ -43,28 +40,31 @@ downloadTotal = 0; error = null; }, - close() { - isOpen = false; + get progressPercentage() { + return downloadTotal > 0 ? (downloadProgress / downloadTotal) * 100 : 0; + }, + setError(err: null | string) { + error = err; + downloadTotal = 0; + }, + get update() { + return update; }, updateProgress(progress: number, total: number) { downloadProgress = progress; downloadTotal = total; }, - setError(err: string | null) { - error = err; - downloadTotal = 0; - }, }; } - {#snippet trigger({ tooltipProps, tooltip })} + {#snippet trigger({ tooltip, tooltipProps })} + + {/each} + {/if} + + {#if (settings.value['transcription.favoriteLanguages'] ?? ['en', 'ja', 'zh']).length < 3} +
+ 💡 Tip: You can add more favorite languages by editing the settings manually +
+ {/if} + +
+
+

Keyboard shortcuts:

+
    +
  • Toggle between languages: Configure in Settings → Shortcuts
  • +
  • Jump to Slot 1/2/3: Configure in Settings → Shortcuts
  • +
+
+ +
+ + + diff --git a/apps/whispering/src/routes/(config)/transformations/+page.svelte b/apps/whispering/src/routes/(config)/transformations/+page.svelte index e16deae4ee..440500ec6f 100644 --- a/apps/whispering/src/routes/(config)/transformations/+page.svelte +++ b/apps/whispering/src/routes/(config)/transformations/+page.svelte @@ -1,7 +1,17 @@ @@ -68,6 +68,13 @@ type="submit" onclick={() => createTransformation.mutate($state.snapshot(transformation), { + onError: (error) => { + rpc.notify.error.execute({ + title: 'Failed to create transformation!', + description: 'Your transformation could not be created.', + action: { error, type: 'more-details' }, + }); + }, onSuccess: () => { isDialogOpen = false; transformation = generateDefaultTransformation(); @@ -77,13 +84,6 @@ 'Your transformation has been created successfully.', }); }, - onError: (error) => { - rpc.notify.error.execute({ - title: 'Failed to create transformation!', - description: 'Your transformation could not be created.', - action: { type: 'more-details', error }, - }); - }, })} > Create diff --git a/apps/whispering/src/routes/(config)/transformations/EditTransformationModal.svelte b/apps/whispering/src/routes/(config)/transformations/EditTransformationModal.svelte index 35c9ab9e34..ad381833e6 100644 --- a/apps/whispering/src/routes/(config)/transformations/EditTransformationModal.svelte +++ b/apps/whispering/src/routes/(config)/transformations/EditTransformationModal.svelte @@ -1,15 +1,17 @@ @@ -141,10 +143,16 @@ onclick={() => { confirmationDialog.open({ title: 'Delete transformation', - subtitle: 'Are you sure? This action cannot be undone.', confirmText: 'Delete', onConfirm: () => { deleteTransformation.mutate($state.snapshot(transformation), { + onError: (error) => { + rpc.notify.error.execute({ + title: 'Failed to delete transformation!', + description: 'Your transformation could not be deleted.', + action: { error, type: 'more-details' }, + }); + }, onSuccess: () => { isDialogOpen = false; rpc.notify.success.execute({ @@ -153,15 +161,9 @@ 'Your transformation has been deleted successfully.', }); }, - onError: (error) => { - rpc.notify.error.execute({ - title: 'Failed to delete transformation!', - description: 'Your transformation could not be deleted.', - action: { type: 'more-details', error }, - }); - }, }); }, + subtitle: 'Are you sure? This action cannot be undone.', }); }} variant="destructive" @@ -182,6 +184,13 @@