import { listen, type UnlistenFn } from "@tauri-apps/api/event"; import { Play, User, XIcon } from "lucide-react"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { toast } from "sonner"; import { listInstalledVersions, startGame } from "@/client"; import { cn } from "@/lib/utils"; import { useAuthStore } from "@/models/auth"; import { useInstanceStore } from "@/models/instance"; import { LoginModal } from "./login-modal"; import { Button } from "./ui/button"; import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue, } from "./ui/select"; import { Spinner } from "./ui/spinner"; interface InstalledVersion { id: string; type: string; } export function BottomBar() { const authStore = useAuthStore(); const instancesStore = useInstanceStore(); const [isLaunched, setIsLaunched] = useState(false); const gameUnlisten = useRef(null); const [isLaunching, setIsLaunching] = useState(false); const [selectedVersion, setSelectedVersion] = useState(null); const [installedVersions, setInstalledVersions] = useState< InstalledVersion[] >([]); const [isLoadingVersions, setIsLoadingVersions] = useState(true); const [showLoginModal, setShowLoginModal] = useState(false); const loadInstalledVersions = useCallback(async () => { if (!instancesStore.activeInstance) { setInstalledVersions([]); setIsLoadingVersions(false); return; } setIsLoadingVersions(true); try { const versions = await listInstalledVersions( instancesStore.activeInstance.id, ); setInstalledVersions(versions); // If no version is selected but we have installed versions, select the first one if (!selectedVersion && versions.length > 0) { setSelectedVersion(versions[0].id); } } catch (error) { console.error("Failed to load installed versions:", error); } finally { setIsLoadingVersions(false); } }, [instancesStore.activeInstance, selectedVersion]); useEffect(() => { loadInstalledVersions(); // Listen for backend events that should refresh installed versions. let unlistenDownload: UnlistenFn | null = null; let unlistenVersionDeleted: UnlistenFn | null = null; (async () => { try { unlistenDownload = await listen("download-complete", () => { loadInstalledVersions(); }); } catch (err) { // best-effort: do not break UI if listening fails // eslint-disable-next-line no-console console.warn("Failed to attach download-complete listener:", err); } try { unlistenVersionDeleted = await listen("version-deleted", () => { loadInstalledVersions(); }); } catch (err) { // eslint-disable-next-line no-console console.warn("Failed to attach version-deleted listener:", err); } })(); return () => { try { if (unlistenDownload) unlistenDownload(); } catch { // ignore } try { if (unlistenVersionDeleted) unlistenVersionDeleted(); } catch { // ignore } }; }, [loadInstalledVersions]); const handleStartGame = async () => { if (!selectedVersion) { toast.info("Please select a version!"); return; } if (!instancesStore.activeInstance) { toast.info("Please select an instance first!"); return; } try { gameUnlisten.current = await listen("game-exited", () => { setIsLaunched(false); }); } catch (error) { toast.warning(`Failed to listen to game-exited event: ${error}`); } setIsLaunching(true); try { await startGame(instancesStore.activeInstance?.id, selectedVersion); setIsLaunched(true); } catch (error) { console.error(`Failed to start game: ${error}`); toast.error(`Failed to start game: ${error}`); } finally { setIsLaunching(false); } }; const getVersionTypeColor = (type: string) => { switch (type) { case "release": return "bg-emerald-500"; case "snapshot": return "bg-amber-500"; case "old_beta": return "bg-rose-500"; case "old_alpha": return "bg-violet-500"; default: return "bg-gray-500"; } }; const versionOptions = useMemo( () => installedVersions.map((v) => ({ label: `${v.id}${v.type !== "release" ? ` (${v.type})` : ""}`, value: v.id, type: v.type, })), [installedVersions], ); const renderButton = () => { if (!authStore.account) { return ( ); } return isLaunched ? ( ) : ( ); }; return (
Active Instance {instancesStore.activeInstance?.name || "No instance selected"}
{renderButton()}
setShowLoginModal(false)} />
); }