Implement FloatingGenerateBox component and update App layout

- Introduced the FloatingGenerateBox component for audio generation, enhancing user interaction with voice profiles.
- Updated App component to integrate FloatingGenerateBox and removed the GenerationForm component.
- Enhanced the layout for better responsiveness and added functionality to manage audio playback state.
- Updated UpdateStatus component to include new update handling logic and improved UI feedback for update readiness.
This commit is contained in:
Jamie Pine
2026-01-27 13:18:12 -08:00
parent 5f58c4dc3d
commit f1be633dca
11 changed files with 961 additions and 99 deletions
+43 -4
View File
@@ -8,12 +8,18 @@ export interface UpdateStatus {
version?: string;
downloading: boolean;
installing: boolean;
readyToInstall: boolean;
error?: string;
downloadProgress?: number; // 0-100 percentage
downloadedBytes?: number;
totalBytes?: number;
}
// Check if we're on Windows (NSIS installer handles restart automatically)
const isWindows = () => {
return navigator.userAgent.includes('Windows');
};
const isTauri = () => {
return '__TAURI_INTERNALS__' in window;
};
@@ -24,6 +30,7 @@ export function useAutoUpdater(checkOnMount = false) {
available: false,
downloading: false,
installing: false,
readyToInstall: false,
});
const [update, setUpdate] = useState<Update | null>(null);
@@ -46,6 +53,7 @@ export function useAutoUpdater(checkOnMount = false) {
version: foundUpdate.version,
downloading: false,
installing: false,
readyToInstall: false,
});
} else {
setStatus({
@@ -53,6 +61,7 @@ export function useAutoUpdater(checkOnMount = false) {
available: false,
downloading: false,
installing: false,
readyToInstall: false,
});
}
} catch (error) {
@@ -61,11 +70,13 @@ export function useAutoUpdater(checkOnMount = false) {
available: false,
downloading: false,
installing: false,
readyToInstall: false,
error: error instanceof Error ? error.message : 'Failed to check for updates',
});
}
}, []);
// Download the update (but don't install yet)
const downloadAndInstall = async () => {
if (!update || !isTauri()) return;
@@ -75,7 +86,8 @@ export function useAutoUpdater(checkOnMount = false) {
let downloadedBytes = 0;
let totalBytes = 0;
await update.downloadAndInstall((event) => {
// Just download the update
await update.download((event) => {
switch (event.event) {
case 'Started':
totalBytes = event.data.contentLength || 0;
@@ -104,22 +116,48 @@ export function useAutoUpdater(checkOnMount = false) {
setStatus((prev) => ({
...prev,
downloading: false,
installing: true,
readyToInstall: true,
downloadProgress: 100
}));
break;
}
});
await relaunch();
} catch (error) {
setStatus((prev) => ({
...prev,
downloading: false,
installing: false,
readyToInstall: false,
downloadProgress: undefined,
downloadedBytes: undefined,
totalBytes: undefined,
error: error instanceof Error ? error.message : 'Failed to download update',
}));
}
};
// Install the downloaded update and restart the app
const restartAndInstall = async () => {
if (!update || !isTauri()) return;
try {
setStatus((prev) => ({ ...prev, installing: true, error: undefined }));
// Install the update
await update.install();
// On Windows with NSIS, the installer handles the restart automatically.
// The process will be killed by the NSIS installer, so we won't reach here.
// On macOS/Linux, we need to manually relaunch.
if (!isWindows()) {
await relaunch();
}
// If we're on Windows and somehow still running, the NSIS installer
// should have already handled everything. Just wait for the process to end.
} catch (error) {
setStatus((prev) => ({
...prev,
installing: false,
error: error instanceof Error ? error.message : 'Failed to install update',
}));
}
@@ -135,5 +173,6 @@ export function useAutoUpdater(checkOnMount = false) {
status,
checkForUpdates,
downloadAndInstall,
restartAndInstall,
};
}