aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/ui/src
diff options
context:
space:
mode:
Diffstat (limited to 'ui/src')
-rw-r--r--ui/src/App.svelte27
-rw-r--r--ui/src/lib/DownloadMonitor.svelte92
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}