diff --git a/crates/lanspread-tauri-deno-ts/src/App.tsx b/crates/lanspread-tauri-deno-ts/src/App.tsx index 696131b..820f4a4 100644 --- a/crates/lanspread-tauri-deno-ts/src/App.tsx +++ b/crates/lanspread-tauri-deno-ts/src/App.tsx @@ -29,7 +29,7 @@ enum InstallStatus { type StatusLevel = 'info' | 'error'; -type GameFilter = 'all' | 'available' | 'installed'; +type GameFilter = 'all' | 'local' | 'installed'; interface Game { id: string; @@ -80,11 +80,41 @@ const GameThumbnail = ({ gameId, alt, getThumbnailUrl }: GameThumbnailProps) => return {alt}; }; +const IN_PROGRESS_INSTALL_STATUSES = new Set([ + InstallStatus.CheckingPeers, + InstallStatus.Downloading, + InstallStatus.Unpacking, +]); + +const isInProgressInstallStatus = (status: InstallStatus): boolean => { + return IN_PROGRESS_INSTALL_STATUSES.has(status); +}; + +const mergeGameUpdate = (game: Game, previous?: Game): Game => { + let installStatus = InstallStatus.NotInstalled; + if (game.installed) { + installStatus = InstallStatus.Installed; + } else if (previous && isInProgressInstallStatus(previous.install_status)) { + installStatus = previous.install_status; + } + + const localStateChanged = previous !== undefined + && (previous.installed !== game.installed || previous.downloaded !== game.downloaded); + + return { + ...game, + install_status: installStatus, + status_message: localStateChanged ? undefined : previous?.status_message, + status_level: localStateChanged ? undefined : previous?.status_level, + peer_count: game.peer_count ?? 0, + }; +}; + const App = () => { const [gameItems, setGameItems] = useState([]); const [searchTerm, setSearchTerm] = useState(''); const [gameDir, setGameDir] = useState(''); - const [currentFilter, setCurrentFilter] = useState('available'); + const [currentFilter, setCurrentFilter] = useState('local'); const [totalPeerCount, setTotalPeerCount] = useState(0); const checkingPeersTimeouts = useRef>>({}); const [thumbnails, setThumbnails] = useState>(new Map()); @@ -108,14 +138,15 @@ const App = () => { const getFilteredGames = (games: Game[], filter: GameFilter): Game[] => { switch (filter) { - case 'available': - // Show union of installed games and games with peers - return games.filter(game => game.installed || game.downloaded || game.peer_count > 0); - case 'installed': + case 'local': + // Games present on this machine, whether the archive is downloaded or already installed. return games.filter(game => game.installed || game.downloaded); + case 'installed': + return games.filter(game => game.installed); case 'all': default: - return games; + // Games reachable on the LAN: held on this machine or advertised by another peer. + return games.filter(game => game.installed || game.downloaded || game.peer_count > 0); } }; @@ -157,8 +188,6 @@ const App = () => { }, []); const getInitialGameDir = useCallback(async () => { - // update game directory from storage (if exists) - // only if it's not already set await new Promise(resolve => setTimeout(resolve, 1000)); const store = await load(FILE_STORAGE, STORE_OPTIONS); const savedGameDir = await store.get(GAME_DIR_KEY); @@ -321,18 +350,7 @@ const App = () => { console.log(`🎮 ${games.length} Games received`); setGameItems(prev => { const previousById = new Map(prev.map(item => [item.id, item])); - return games.map(game => { - const previous = previousById.get(game.id); - const installStatus = previous?.install_status - ?? (game.installed ? InstallStatus.Installed : InstallStatus.NotInstalled); - return { - ...game, - install_status: installStatus, - status_message: previous?.status_message, - status_level: previous?.status_level, - peer_count: game.peer_count ?? 0, // Ensure peer_count is always set - }; - }); + return games.map(game => mergeGameUpdate(game, previousById.get(game.id))); }); void getInitialGameDir(); }); @@ -535,7 +553,6 @@ const App = () => { } }; - // Rest of your component remains the same return (
@@ -554,21 +571,21 @@ const App = () => {