diff options
Diffstat (limited to 'ui/src')
| -rw-r--r-- | ui/src/App.svelte | 27 | ||||
| -rw-r--r-- | ui/src/lib/DownloadMonitor.svelte | 92 |
2 files changed, 114 insertions, 5 deletions
diff --git a/ui/src/App.svelte b/ui/src/App.svelte index 18ef5e5..0e14cb0 100644 --- a/ui/src/App.svelte +++ b/ui/src/App.svelte @@ -1,6 +1,7 @@ <script lang="ts"> import { invoke } from "@tauri-apps/api/core"; import { onMount } from "svelte"; + import DownloadMonitor from "./lib/DownloadMonitor.svelte"; let status = "Ready"; @@ -48,8 +49,12 @@ async function login() { if (currentAccount) { if (confirm("Logout " + currentAccount.username + "?")) { - currentAccount = null; - // Note: Backend state persists until restarted or overwritten. + try { + await invoke("logout"); + currentAccount = null; + } catch(e) { + console.error("Logout failed:", e); + } } return; } @@ -64,10 +69,21 @@ } async function startGame() { - status = "Launching (Simulated)..."; - console.log("Invoking start_game..."); + if (!currentAccount) { + alert("Please login first!"); + login(); + return; + } + + if (!selectedVersion) { + alert("Please select a version!"); + return; + } + + status = "Preparing to launch " + selectedVersion + "..."; + console.log("Invoking start_game for version:", selectedVersion); try { - const msg = await invoke("start_game"); + const msg = await invoke("start_game", { versionId: selectedVersion }); console.log("Response:", msg); status = msg as string; } catch (e) { @@ -110,6 +126,7 @@ <!-- Main Content --> <main class="flex-1 flex flex-col relative min-w-0"> + <DownloadMonitor /> <!-- Top Bar (Window Controls Placeholder) --> <div class="h-8 w-full bg-zinc-900/50 absolute top-0 left-0 z-50 drag-region" data-tauri-drag-region> <!-- Windows/macOS controls would go here or be handled by OS --> diff --git a/ui/src/lib/DownloadMonitor.svelte b/ui/src/lib/DownloadMonitor.svelte new file mode 100644 index 0000000..b2751fe --- /dev/null +++ b/ui/src/lib/DownloadMonitor.svelte @@ -0,0 +1,92 @@ +<script lang="ts"> + import { listen } from "@tauri-apps/api/event"; + import { onMount, onDestroy } from "svelte"; + + export let visible = false; + + interface DownloadEvent { + file: string; + downloaded: number; // in bytes + total: number; // in bytes + status: string; + } + + let currentFile = ""; + let progress = 0; // percentage 0-100 + let totalFiles = 0; + let statusText = "Preparing..."; + let unlistenProgress: () => void; + let unlistenStart: () => void; + let unlistenComplete: () => void; + let downloadedBytes = 0; + let totalBytes = 0; + + onMount(async () => { + unlistenStart = await listen<number>("download-start", (event) => { + visible = true; + totalFiles = event.payload; + progress = 0; + statusText = "Starting download..."; + currentFile = ""; + }); + + unlistenProgress = await listen<DownloadEvent>("download-progress", (event) => { + const payload = event.payload; + currentFile = payload.file; + + // Simple file progress for now. Global progress would require tracking all files. + // For single file (Client jar), this is accurate. + downloadedBytes = payload.downloaded; + totalBytes = payload.total; + + statusText = payload.status; + + if (payload.total > 0) { + progress = (payload.downloaded / payload.total) * 100; + } + }); + + unlistenComplete = await listen("download-complete", () => { + statusText = "Done!"; + progress = 100; + setTimeout(() => { visible = false; }, 2000); + }); + }); + + onDestroy(() => { + if (unlistenProgress) unlistenProgress(); + if (unlistenStart) unlistenStart(); + if (unlistenComplete) unlistenComplete(); + }); + + function formatBytes(bytes: number) { + if (bytes === 0) return '0 B'; + const k = 1024; + const sizes = ['B', 'KB', 'MB', 'GB']; + const i = Math.floor(Math.log(bytes) / Math.log(k)); + return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; + } +</script> + +{#if visible} +<div class="fixed bottom-28 right-8 z-50 w-80 bg-zinc-900/90 backdrop-blur-md border border-zinc-700 rounded-lg shadow-2xl p-4 animate-in slide-in-from-right-10 fade-in duration-300"> + <div class="flex items-center justify-between mb-2"> + <h3 class="text-white font-bold text-sm">Downloads</h3> + <span class="text-xs text-zinc-400">{statusText}</span> + </div> + + <div class="text-xs text-zinc-300 truncate mb-1" title={currentFile}> + {currentFile || "Waiting..."} + </div> + + <!-- Progress Bar --> + <div class="w-full bg-zinc-800 rounded-full h-2 mb-2 overflow-hidden"> + <div class="bg-gradient-to-r from-green-500 to-emerald-400 h-2 rounded-full transition-all duration-200" style="width: {progress}%"></div> + </div> + + <div class="flex justify-between text-[10px] text-zinc-500 font-mono"> + <span>{formatBytes(downloadedBytes)} / {formatBytes(totalBytes)}</span> + <span>{Math.round(progress)}%</span> + </div> +</div> +{/if} |