Enhance update status display and audio sample components

- Improved the UpdateStatus component to show download progress and total bytes downloaded during updates.
- Refactored AudioSampleRecording and AudioSampleSystem components for cleaner button rendering and consistent layout.
- Updated import order in SampleUpload component for better organization.
This commit is contained in:
Jamie Pine
2026-01-26 19:22:43 -08:00
parent cd77b80b4f
commit 8b67faf96d
5 changed files with 60 additions and 45 deletions
@@ -71,11 +71,23 @@ export function UpdateStatus() {
{status.downloading && (
<div className="space-y-2">
<div className="flex items-center gap-2 text-sm">
<Download className="h-4 w-4" />
Downloading update...
<div className="flex items-center justify-between text-sm">
<div className="flex items-center gap-2">
<Download className="h-4 w-4" />
Downloading update...
</div>
{status.downloadProgress !== undefined && (
<span className="text-muted-foreground">
{status.downloadProgress}%
</span>
)}
</div>
<Progress />
<Progress value={status.downloadProgress} />
{status.downloadedBytes !== undefined && status.totalBytes !== undefined && status.totalBytes > 0 && (
<div className="text-xs text-muted-foreground">
{(status.downloadedBytes / 1024 / 1024).toFixed(1)} MB / {(status.totalBytes / 1024 / 1024).toFixed(1)} MB
</div>
)}
</div>
)}
@@ -1,4 +1,4 @@
import { Mic, Square, Play, Pause } from 'lucide-react';
import { Mic, Pause, Play, Square } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { FormControl, FormItem, FormLabel, FormMessage } from '@/components/ui/form';
import { formatAudioDuration } from '@/lib/utils/audio';
@@ -35,12 +35,7 @@ export function AudioSampleRecording({
<div className="space-y-4">
{!isRecording && !file && (
<div className="flex flex-col items-center justify-center gap-4 p-4 border-2 border-dashed rounded-lg min-h-[180px]">
<Button
type="button"
onClick={onStart}
size="lg"
className="flex items-center gap-2"
>
<Button type="button" onClick={onStart} size="lg" className="flex items-center gap-2">
<Mic className="h-5 w-5" />
Start Recording
</Button>
@@ -81,16 +76,9 @@ export function AudioSampleRecording({
<Mic className="h-5 w-5 text-primary" />
<span className="font-medium">Recording complete</span>
</div>
<p className="text-sm text-muted-foreground text-center">
File: {file.name}
</p>
<p className="text-sm text-muted-foreground text-center">File: {file.name}</p>
<div className="flex gap-2">
<Button
type="button"
size="icon"
variant="outline"
onClick={onPlayPause}
>
<Button type="button" size="icon" variant="outline" onClick={onPlayPause}>
{isPlaying ? <Pause className="h-4 w-4" /> : <Play className="h-4 w-4" />}
</Button>
<Button
@@ -1,4 +1,4 @@
import { Monitor, Square, Play, Pause, Mic } from 'lucide-react';
import { Mic, Monitor, Pause, Play, Square } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { FormControl, FormItem, FormLabel, FormMessage } from '@/components/ui/form';
import { formatAudioDuration } from '@/lib/utils/audio';
@@ -35,12 +35,7 @@ export function AudioSampleSystem({
<div className="space-y-4">
{!isRecording && !file && (
<div className="flex flex-col items-center justify-center gap-4 p-4 border-2 border-dashed rounded-lg min-h-[180px]">
<Button
type="button"
onClick={onStart}
size="lg"
className="flex items-center gap-2"
>
<Button type="button" onClick={onStart} size="lg" className="flex items-center gap-2">
<Monitor className="h-5 w-5" />
Start Capture
</Button>
@@ -81,16 +76,9 @@ export function AudioSampleSystem({
<Monitor className="h-5 w-5 text-primary" />
<span className="font-medium">Capture complete</span>
</div>
<p className="text-sm text-muted-foreground text-center">
File: {file.name}
</p>
<p className="text-sm text-muted-foreground text-center">File: {file.name}</p>
<div className="flex gap-2">
<Button
type="button"
size="icon"
variant="outline"
onClick={onPlayPause}
>
<Button type="button" size="icon" variant="outline" onClick={onPlayPause}>
{isPlaying ? <Pause className="h-4 w-4" /> : <Play className="h-4 w-4" />}
</Button>
<Button
@@ -22,15 +22,15 @@ import {
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { Textarea } from '@/components/ui/textarea';
import { useToast } from '@/components/ui/use-toast';
import { useAudioRecording } from '@/lib/hooks/useAudioRecording';
import { useAudioPlayer } from '@/lib/hooks/useAudioPlayer';
import { useAudioRecording } from '@/lib/hooks/useAudioRecording';
import { useAddSample, useProfile } from '@/lib/hooks/useProfiles';
import { useSystemAudioCapture } from '@/lib/hooks/useSystemAudioCapture';
import { useTranscription } from '@/lib/hooks/useTranscription';
import { isTauri } from '@/lib/tauri';
import { AudioSampleUpload } from './AudioSampleUpload';
import { AudioSampleRecording } from './AudioSampleRecording';
import { AudioSampleSystem } from './AudioSampleSystem';
import { AudioSampleUpload } from './AudioSampleUpload';
const sampleSchema = z.object({
file: z.instanceof(File, { message: 'Please select an audio file' }),
+34 -7
View File
@@ -1,4 +1,4 @@
import { useEffect, useState } from 'react';
import { useCallback, useEffect, useState } from 'react';
import { check, type Update } from '@tauri-apps/plugin-updater';
import { relaunch } from '@tauri-apps/plugin-process';
@@ -9,6 +9,9 @@ export interface UpdateStatus {
downloading: boolean;
installing: boolean;
error?: string;
downloadProgress?: number; // 0-100 percentage
downloadedBytes?: number;
totalBytes?: number;
}
const isTauri = () => {
@@ -25,7 +28,7 @@ export function useAutoUpdater(checkOnMount = false) {
const [update, setUpdate] = useState<Update | null>(null);
const checkForUpdates = async () => {
const checkForUpdates = useCallback(async () => {
if (!isTauri()) {
return;
}
@@ -61,7 +64,7 @@ export function useAutoUpdater(checkOnMount = false) {
error: error instanceof Error ? error.message : 'Failed to check for updates',
});
}
};
}, []);
const downloadAndInstall = async () => {
if (!update || !isTauri()) return;
@@ -69,19 +72,40 @@ export function useAutoUpdater(checkOnMount = false) {
try {
setStatus((prev) => ({ ...prev, downloading: true, error: undefined }));
let downloadedBytes = 0;
let totalBytes = 0;
await update.downloadAndInstall((event) => {
switch (event.event) {
case 'Started':
setStatus((prev) => ({ ...prev, downloading: true }));
totalBytes = event.data.contentLength || 0;
downloadedBytes = 0;
setStatus((prev) => ({
...prev,
downloading: true,
totalBytes,
downloadedBytes: 0,
downloadProgress: 0
}));
break;
case 'Progress':
console.log(`Downloaded ${event.data.chunkLength} bytes`);
case 'Progress': {
downloadedBytes += event.data.chunkLength;
const progress = totalBytes > 0
? Math.round((downloadedBytes / totalBytes) * 100)
: undefined;
setStatus((prev) => ({
...prev,
downloadedBytes,
downloadProgress: progress
}));
break;
}
case 'Finished':
setStatus((prev) => ({
...prev,
downloading: false,
installing: true,
downloadProgress: 100
}));
break;
}
@@ -93,6 +117,9 @@ export function useAutoUpdater(checkOnMount = false) {
...prev,
downloading: false,
installing: false,
downloadProgress: undefined,
downloadedBytes: undefined,
totalBytes: undefined,
error: error instanceof Error ? error.message : 'Failed to install update',
}));
}
@@ -102,7 +129,7 @@ export function useAutoUpdater(checkOnMount = false) {
if (checkOnMount && isTauri()) {
checkForUpdates();
}
}, [checkOnMount]);
}, [checkOnMount, checkForUpdates]);
return {
status,