feat(library): Reactive library updating

Signed-off-by: quexeky <git@quexeky.dev>
This commit is contained in:
quexeky
2025-02-12 09:29:03 +11:00
parent 1dddd4bf92
commit 73fbf2e0be
6 changed files with 57 additions and 45 deletions
+2 -2
View File
@@ -11,7 +11,7 @@
v-for="(nav, navIdx) in navigation" v-for="(nav, navIdx) in navigation"
:class="[ :class="[
'transition uppercase font-display font-semibold text-md', 'transition uppercase font-display font-semibold text-md',
navIdx === currentPageIndex navIdx === currentNavigation
? 'text-zinc-100' ? 'text-zinc-100'
: 'text-zinc-400 hover:text-zinc-200', : 'text-zinc-400 hover:text-zinc-200',
]" ]"
@@ -78,7 +78,7 @@ const navigation: Array<NavigationItem> = [
}, },
]; ];
const currentPageIndex = useCurrentNavigationIndex(navigation); const {currentNavigation} = useCurrentNavigationIndex(navigation);
const quickActions: Array<QuickActionNav> = [ const quickActions: Array<QuickActionNav> = [
{ {
+3 -1
View File
@@ -26,5 +26,7 @@ export const useCurrentNavigationIndex = (
currentNavigation.value = calculateCurrentNavIndex(to); currentNavigation.value = calculateCurrentNavIndex(to);
}); });
return currentNavigation; return {currentNavigation, recalculateNavigation: () => {
currentNavigation.value = calculateCurrentNavIndex(route);
}};
}; };
+42 -32
View File
@@ -1,28 +1,17 @@
<template> <template>
<div class="flex flex-row h-full"> <div class="flex flex-row h-full">
<div <div class="flex-none max-h-full overflow-y-auto w-64 bg-zinc-950 px-2 py-1">
class="flex-none max-h-full overflow-y-auto w-64 bg-zinc-950 px-2 py-1"
>
<ul class="flex flex-col gap-y-1"> <ul class="flex flex-col gap-y-1">
<NuxtLink <NuxtLink v-for="(nav, navIdx) in navigation" :key="nav.route" :class="[
v-for="(nav, navIdx) in navigation" 'transition-all duration-200 rounded-lg flex items-center py-1.5 px-3',
:key="nav.route" navIdx === currentNavigation
:class="[ ? 'bg-zinc-800 text-zinc-100'
'transition-all duration-200 rounded-lg flex items-center py-1.5 px-3', : nav.isInstalled.value
navIdx === currentNavigationIndex
? 'bg-zinc-800 text-zinc-100'
: nav.isInstalled.value
? 'text-zinc-300 hover:bg-zinc-800/90 hover:text-zinc-200' ? 'text-zinc-300 hover:bg-zinc-800/90 hover:text-zinc-200'
: 'text-zinc-500 hover:bg-zinc-800/70 hover:text-zinc-300', : 'text-zinc-500 hover:bg-zinc-800/70 hover:text-zinc-300',
]" ]" :href="nav.route">
:href="nav.route"
>
<div class="flex items-center w-full gap-x-3"> <div class="flex items-center w-full gap-x-3">
<img <img class="size-6 flex-none object-cover bg-zinc-900 rounded" :src="icons[nav.id]" alt="" />
class="size-6 flex-none object-cover bg-zinc-900 rounded"
:src="icons[navIdx]"
alt=""
/>
<p class="truncate text-sm font-display leading-6 flex-1"> <p class="truncate text-sm font-display leading-6 flex-1">
{{ nav.label }} {{ nav.label }}
</p> </p>
@@ -31,35 +20,47 @@
</ul> </ul>
</div> </div>
<div class="grow overflow-y-auto"> <div class="grow overflow-y-auto">
<NuxtPage :libraryDownloadError = "libraryDownloadError" /> <NuxtPage :libraryDownloadError="libraryDownloadError" />
</div> </div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { invoke } from "@tauri-apps/api/core"; import { invoke } from "@tauri-apps/api/core";
import { GameStatusEnum, type Game, type NavigationItem } from "~/types"; import { listen } from "@tauri-apps/api/event";
import { GameStatusEnum, type Game, type GameStatus, type NavigationItem } from "~/types";
let libraryDownloadError = false; let libraryDownloadError = false;
async function calculateGames(): Promise<Game[]> { const games: { [key: string]: { game: Game, status: Ref<GameStatus, GameStatus> } } = {};
const icons: { [key: string]: string } = {};
const rawGames: Ref<Game[], Game[]> = ref([])
async function calculateGames() {
try { try {
return await invoke("fetch_library"); rawGames.value = await invoke("fetch_library");
for (const game of rawGames.value) {
if (games[game.id]) continue;
games[game.id] = await useGame(game.id);
}
for (const game of rawGames.value) {
if (icons[game.id]) continue;
icons[game.id] = await useObject(game.mIconId);
}
} }
catch(e) { catch (e) {
console.log(e) console.log(e)
libraryDownloadError = true; libraryDownloadError = true;
return new Array(); return new Array();
} }
} }
const rawGames: Array<Game> = await calculateGames(); await calculateGames();
const games = await Promise.all(rawGames.map((e) => useGame(e.id)));
const icons = await Promise.all( const navigation = computed(() => rawGames.value.map((game) => {
games.map(({ game, status }) => useObject(game.mIconId)) const status = games[game.id].status;
);
const navigation = games.map(({ game, status }) => {
const isInstalled = computed( const isInstalled = computed(
() => () =>
status.value.type == GameStatusEnum.Installed || status.value.type == GameStatusEnum.Installed ||
@@ -71,9 +72,18 @@ const navigation = games.map(({ game, status }) => {
route: `/library/${game.id}`, route: `/library/${game.id}`,
prefix: `/library/${game.id}`, prefix: `/library/${game.id}`,
isInstalled, isInstalled,
id: game.id,
}; };
return item; return item;
}); })
);
const { currentNavigation, recalculateNavigation } = useCurrentNavigationIndex(navigation.value);
listen("update_library", async (event) => {
console.log("Updating library");
await calculateGames()
recalculateNavigation();
})
const currentNavigationIndex = useCurrentNavigationIndex(navigation);
</script> </script>
+4 -4
View File
@@ -10,13 +10,13 @@
<ul role="list" class="-mx-2 space-y-1"> <ul role="list" class="-mx-2 space-y-1">
<li v-for="(item, itemIdx) in navigation" :key="item.prefix"> <li v-for="(item, itemIdx) in navigation" :key="item.prefix">
<NuxtLink :href="item.route" :class="[ <NuxtLink :href="item.route" :class="[
itemIdx === currentPageIndex itemIdx === currentNavigation
? 'bg-zinc-800/50 text-zinc-100' ? 'bg-zinc-800/50 text-zinc-100'
: 'text-zinc-400 hover:bg-zinc-800/30 hover:text-zinc-200', : 'text-zinc-400 hover:bg-zinc-800/30 hover:text-zinc-200',
'transition group flex gap-x-3 rounded-md p-2 pr-12 text-sm font-semibold leading-6', 'transition group flex gap-x-3 rounded-md p-2 pr-12 text-sm font-semibold leading-6',
]"> ]">
<component :is="item.icon" :class="[ <component :is="item.icon" :class="[
itemIdx === currentPageIndex itemIdx === currentNavigation
? 'text-zinc-100' ? 'text-zinc-100'
: 'text-zinc-400 group-hover:text-zinc-200', : 'text-zinc-400 group-hover:text-zinc-200',
'transition h-6 w-6 shrink-0', 'transition h-6 w-6 shrink-0',
@@ -112,10 +112,10 @@ const navigation = computed(() => [
const currentPlatform = platform(); const currentPlatform = platform();
// Use .value to unwrap the computed ref // Use .value to unwrap the computed ref
const currentPageIndex = useCurrentNavigationIndex(navigation.value); const {currentNavigation} = useCurrentNavigationIndex(navigation.value);
// Watch for navigation changes and update currentPageIndex // Watch for navigation changes and update currentPageIndex
watch(navigation, (newNav) => { watch(navigation, (newNav) => {
currentPageIndex.value = useCurrentNavigationIndex(newNav).value; currentNavigation.value = useCurrentNavigationIndex(newNav).currentNavigation.value;
}); });
</script> </script>
-1
View File
@@ -38,7 +38,6 @@ pub fn uninstall_game(game_id: String, app_handle: AppHandle) -> Result<(), Libr
Some(data) => data, Some(data) => data,
None => return Err(LibraryError::MetaNotFound(game_id)), None => return Err(LibraryError::MetaNotFound(game_id)),
}; };
println!("{:?}", meta);
uninstall_game_logic(meta, &app_handle); uninstall_game_logic(meta, &app_handle);
Ok(()) Ok(())
+5 -4
View File
@@ -103,7 +103,6 @@ pub fn fetch_library_logic(
drop(db_handle); drop(db_handle);
cache_object("library", &games)?; cache_object("library", &games)?;
Ok(games) Ok(games)
} }
pub fn fetch_library_logic_offline( pub fn fetch_library_logic_offline(
@@ -137,7 +136,6 @@ pub fn fetch_game_logic(
status, status,
}; };
cache_object(id, &data)?; cache_object(id, &data)?;
return Ok(data); return Ok(data);
@@ -261,8 +259,6 @@ pub fn uninstall_game_logic(meta: DownloadableMetadata, app_handle: &AppHandle)
.entry(meta.clone()) .entry(meta.clone())
.and_modify(|v| *v = ApplicationTransientStatus::Uninstalling {}); .and_modify(|v| *v = ApplicationTransientStatus::Uninstalling {});
db_handle.applications.installed_game_version.remove(&meta.id);
drop(db_handle); drop(db_handle);
let app_handle = app_handle.clone(); let app_handle = app_handle.clone();
@@ -273,6 +269,10 @@ pub fn uninstall_game_logic(meta: DownloadableMetadata, app_handle: &AppHandle)
Ok(_) => { Ok(_) => {
let mut db_handle = borrow_db_mut_checked(); let mut db_handle = borrow_db_mut_checked();
db_handle.applications.transient_statuses.remove(&meta); db_handle.applications.transient_statuses.remove(&meta);
db_handle
.applications
.installed_game_version
.remove(&meta.id);
db_handle db_handle
.applications .applications
.game_statuses .game_statuses
@@ -282,6 +282,7 @@ pub fn uninstall_game_logic(meta: DownloadableMetadata, app_handle: &AppHandle)
save_db(); save_db();
debug!("uninstalled game id {}", &meta.id); debug!("uninstalled game id {}", &meta.id);
app_handle.emit("update_library", {}).unwrap();
push_game_update( push_game_update(
&app_handle, &app_handle,