Files
club-launcher/src/hooks/useGames.ts
T
houseassassin 9a4c4fa943 feat: icon extraction from .exe files
- electron/main.ts: extractExeIcon() via app.getFileIcon(), saves PNG to
  userData/icons/{md5}.png; IPC icon:extract; scanner:import now auto-extracts
- electron/preload.ts: expose extractIcon()
- AdminPanel: Scan button next to image field — extracts icon from current exe
  (shows animated pulse while loading, error if no exe selected or extraction fails)
- GameCard: isExtractedIcon() detects icons/ path; renders centered 64x64 icon
  on gradient background instead of stretched cover

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 13:09:46 +00:00

65 lines
2.3 KiB
TypeScript

import { useState, useEffect, useCallback } from 'react'
import type { AppEntry, CustomGame, Game } from '../types'
interface ScannedExe { name: string; exe: string }
interface AppSettings { steamPath: string | null; gameFolders: string[] }
declare global {
interface Window {
launcher: {
getGames: () => Promise<Game[]>
launchGame: (id: string) => Promise<{ ok: boolean; error?: string; recent?: string[] }>
// Custom games
addCustomGame: (g: Omit<CustomGame, 'id' | 'source'>) => Promise<CustomGame>
removeGame: (id: string) => Promise<{ ok: boolean }>
updateGame: (g: CustomGame) => Promise<{ ok: boolean }>
// App entries
addApp: (a: Omit<AppEntry, 'id' | 'source'>) => Promise<AppEntry>
removeApp: (id: string) => Promise<{ ok: boolean }>
updateApp: (a: AppEntry) => Promise<{ ok: boolean }>
// Dialogs
pickExe: () => Promise<string | null>
pickImage: () => Promise<string | null>
pickFolder: (title?: string) => Promise<string | null>
// Settings
getSettings: () => Promise<AppSettings & { resolvedSteamPath: string | null }>
setSteamPath: (path: string | null) => Promise<AppSettings>
addGameFolder: (folder: string) => Promise<AppSettings>
removeGameFolder: (folder: string) => Promise<AppSettings>
// Icon extraction
extractIcon: (exePath: string) => Promise<string>
// Scanner
scanFolder: (folder: string) => Promise<ScannedExe[]>
importScanned: (exes: ScannedExe[]) => Promise<CustomGame[]>
// Favorites / recent
getFavorites: () => Promise<string[]>
toggleFavorite: (id: string) => Promise<string[]>
getRecent: () => Promise<string[]>
// Events
onAdminOpen: (cb: () => void) => () => void
}
}
}
export function useGames() {
const [games, setGames] = useState<Game[]>([])
const [loading, setLoading] = useState(true)
const [error, setError] = useState<string | null>(null)
const load = useCallback(async () => {
setLoading(true)
setError(null)
try {
setGames(await window.launcher.getGames())
} catch (e) {
setError(String(e))
} finally {
setLoading(false)
}
}, [])
useEffect(() => { load() }, [load])
return { games, loading, error, reload: load }
}