[backup] games from server with images

This commit is contained in:
2024-11-13 23:51:28 +01:00
parent 5d45c4ce4b
commit a6ed6e04fe
13 changed files with 214 additions and 113 deletions
+100 -83
View File
@@ -1,95 +1,112 @@
// types.ts
interface Game {
id: string;
name: string;
description: string;
size: number;
}
interface RunGameArgs {
id: string;
}
// App.tsx
import { useEffect, useState } from 'react';
import { invoke } from '@tauri-apps/api/core';
import { listen } from '@tauri-apps/api/event';
import {useEffect, useState} from 'react';
import {invoke} from '@tauri-apps/api/core';
import {listen} from '@tauri-apps/api/event';
import "./App.css";
interface Game {
id: string;
name: string;
description: string;
size: number;
thumbnail: Uint8Array;
}
const App = () => {
const [gameItems, setGameItems] = useState<Game[]>([]);
const [gameItems, setGameItems] = useState<Game[]>([]);
const [searchTerm, setSearchTerm] = useState('');
useEffect(() => {
// Listen for games list updates
const setupEventListener = async () => {
try {
const unlisten = await listen('games-list-updated', (event) => {
console.log('Received games-list-updated event');
const games = event.payload as Game[];
games.forEach(game => {
console.log(`game: ${JSON.stringify(game)}`);
});
setGameItems(games);
});
const filteredGames = gameItems.filter(item =>
item.name.toLowerCase().includes(searchTerm.toLowerCase())
);
// Cleanup listener on component unmount
return () => {
unlisten();
useEffect(() => {
console.log('🔵 Effect starting - setting up listener and requesting games');
let isSubscribed = true; // For tracking if component is still mounted
const setupEventListener = async () => {
try {
const unlisten = await listen('games-list-updated', (event) => {
if (!isSubscribed) return; // Don't update state if unmounted
console.log('📥 Received games-list-updated event');
const games = event.payload as Game[];
games.forEach(game => {
console.log(`🎮 game: ${JSON.stringify(game.id)}`);
});
setGameItems(games);
});
// Initial request for games
console.log('📤 Requesting initial games list');
await invoke('request_games');
// Cleanup function
return () => {
console.log('🧹 Cleaning up - removing listener');
isSubscribed = false;
unlisten();
};
} catch (error) {
console.error('❌ Error in setup:', error);
}
};
} catch (error) {
console.error('Error setting up event listener:', error);
}
setupEventListener();
// Cleanup
return () => {
console.log('🚫 Effect cleanup - component unmounting');
isSubscribed = false;
};
}, []); // Empty dependency array means this runs once on mount
const runGame = async (id: string) => {
console.log(`🎯 Running game with id=${id}`);
try {
const result = await invoke('run_game_backend', {id});
console.log(`✅ Game started, result=${result}`);
} catch (error) {
console.error('❌ Error running game:', error);
}
};
setupEventListener();
// Uncomment if you want to request games on mount
// const requestGames = async () => {
// try {
// await invoke('request_games');
// } catch (error) {
// console.error('Error requesting games:', error);
// }
// };
// requestGames();
}, []);
const runGame = async (id: string) => {
console.log(`id=${id}`);
try {
const result = await invoke('run_game_backend', { id });
console.log(`id=${result}`);
} catch (error) {
console.error('Error running game:', error);
}
};
return (
<main className="container">
<h1 className="align-center">SoftLAN Launcher</h1>
<div className="main-header">HEADER</div>
<div className="grid-container">
{gameItems.map((item) => (
<div
key={item.id}
className="item"
onClick={() => runGame(item.id)}
>
<img
src="https://via.placeholder.com/200x150"
alt="Item Image"
/>
<div className="item-name">{item.name}</div>
<div className="description">
<span className="desc-text">{item.description}</span>
<span className="size-text">{item.size.toString()}</span>
// Rest of your component remains the same
return (
<main className="container">
<h1 className="align-center">SoftLAN Launcher</h1>
<div className="main-header">
{/* Search input */}
<div className="search-container">
<input
type="text"
placeholder="Search games..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="search-input"
/>
</div></div>
<div className="grid-container">
{filteredGames.map((item) => {
// Convert the thumbnail bytes to base64
const uint8Array = new Uint8Array(item.thumbnail);
const binaryString = uint8Array.reduce((acc, byte) => acc + String.fromCharCode(byte), '');
const thumbnailUrl = `data:image/jpeg;base64,${btoa(binaryString)}`;
return (
<div key={item.id} className="item" onClick={() => runGame(item.id)}>
<img src={thumbnailUrl} alt={`${item.name} thumbnail`} />
<div className="item-name">{item.name}</div>
<div className="description">
<span className="desc-text">{item.description.slice(0, 10)}</span>
<span className="size-text">{item.size.toString()}</span>
</div>
<div className="play-button">Play</div>
</div>
);
})}
</div>
<div className="play-button">Play</div>
</div>
))}
</div>
</main>
);
</main>
);
};
export default App;