aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--src-tauri/src/main.rs37
-rw-r--r--ui/src/components/BottomBar.svelte7
-rw-r--r--ui/src/stores/game.svelte.ts30
3 files changed, 68 insertions, 6 deletions
diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs
index d7ae9a4..bf7504d 100644
--- a/src-tauri/src/main.rs
+++ b/src-tauri/src/main.rs
@@ -587,6 +587,42 @@ async fn get_versions() -> Result<Vec<core::manifest::Version>, String> {
}
#[tauri::command]
+async fn get_installed_versions(app_handle: tauri::AppHandle) -> Result<Vec<String>, String> {
+ let game_dir = app_handle
+ .path()
+ .app_data_dir()
+ .map_err(|e| format!("Failed to get app data dir: {}", e))?;
+
+ let versions_dir = game_dir.join("versions");
+
+ if !versions_dir.exists() {
+ return Ok(Vec::new());
+ }
+
+ let mut installed_versions = Vec::new();
+
+ if let Ok(entries) = std::fs::read_dir(versions_dir) {
+ for entry in entries {
+ if let Ok(entry) = entry {
+ if let Ok(file_type) = entry.file_type() {
+ if file_type.is_dir() {
+ if let Ok(file_name) = entry.file_name().into_string() {
+ // Optionally verify if {version_id}.json exists inside
+ let json_path = entry.path().join(format!("{}.json", file_name));
+ if json_path.exists() {
+ installed_versions.push(file_name);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ Ok(installed_versions)
+}
+
+#[tauri::command]
async fn login_offline(
window: Window,
state: State<'_, core::auth::AccountState>,
@@ -784,6 +820,7 @@ fn main() {
.invoke_handler(tauri::generate_handler![
start_game,
get_versions,
+ get_installed_versions,
login_offline,
get_active_account,
logout,
diff --git a/ui/src/components/BottomBar.svelte b/ui/src/components/BottomBar.svelte
index dcad9e8..a96b086 100644
--- a/ui/src/components/BottomBar.svelte
+++ b/ui/src/components/BottomBar.svelte
@@ -65,10 +65,13 @@
>
{#if gameState.versions.length === 0}
<option>Loading...</option>
+ {:else if gameState.installedVersionIds.length === 0}
+ <option disabled>No installed versions</option>
{:else}
{#each gameState.versions as version}
- <option value={version.id}>{version.id} ({version.type})</option
- >
+ {#if gameState.installedVersionIds.includes(version.id)}
+ <option value={version.id}>{version.id} ({version.type})</option>
+ {/if}
{/each}
{/if}
</select>
diff --git a/ui/src/stores/game.svelte.ts b/ui/src/stores/game.svelte.ts
index 0af3daf..3128cc6 100644
--- a/ui/src/stores/game.svelte.ts
+++ b/ui/src/stores/game.svelte.ts
@@ -5,14 +5,36 @@ import { authState } from "./auth.svelte";
export class GameState {
versions = $state<Version[]>([]);
+ installedVersionIds = $state<string[]>([]);
selectedVersion = $state("");
async loadVersions() {
try {
- this.versions = await invoke<Version[]>("get_versions");
- if (this.versions.length > 0) {
- const latest = this.versions.find((v) => v.type === "release");
- this.selectedVersion = latest ? latest.id : this.versions[0].id;
+ // Fetch both full version list and installed versions
+ const [allVersions, installedIds] = await Promise.all([
+ invoke<Version[]>("get_versions"),
+ invoke<string[]>("get_installed_versions")
+ ]);
+
+ this.versions = allVersions;
+ this.installedVersionIds = installedIds;
+
+ if (this.installedVersionIds.length > 0) {
+ // Find the first installed version that appears in our manifest (preserving order)
+ // Usually we want the latest release that is installed
+ const installedVersions = this.versions.filter(v => this.installedVersionIds.includes(v.id));
+
+ // Try to find latest release among installed
+ const latestInstalledRelease = installedVersions.find(v => v.type === "release");
+
+ if (latestInstalledRelease) {
+ this.selectedVersion = latestInstalledRelease.id;
+ } else if (installedVersions.length > 0) {
+ this.selectedVersion = installedVersions[0].id;
+ } else {
+ // Fallback to just the first ID if not in manifest
+ this.selectedVersion = this.installedVersionIds[0];
+ }
}
} catch (e) {
console.error("Failed to fetch versions:", e);