From fbbb2520e046fff848565866ab268516513d8086 Mon Sep 17 00:00:00 2001 From: Moyasee Date: Mon, 19 Jan 2026 17:57:49 +0200 Subject: [PATCH] feat: enhance game scanning notifications and UI updates --- src/locales/en/translation.json | 6 +++- .../events/library/scan-installed-games.ts | 33 +++++++++++++++++-- .../src/components/header/header.scss | 9 +++-- src/renderer/src/components/header/header.tsx | 11 ++++++- .../notifications/local-notification-item.tsx | 2 ++ src/types/index.ts | 3 +- 6 files changed, 56 insertions(+), 8 deletions(-) diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 9a97423b..833685d7 100755 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -629,7 +629,11 @@ "game_extracted": "{{title}} extracted successfully", "friend_started_playing_game": "{{displayName}} started playing a game", "test_achievement_notification_title": "This is a test notification", - "test_achievement_notification_description": "Pretty cool, huh?" + "test_achievement_notification_description": "Pretty cool, huh?", + "scan_games_complete_title": "Scanning for games finished successfully", + "scan_games_complete_description": "Found {{count}} games without executable path set", + "scan_games_no_results_title": "Scanning for games finished", + "scan_games_no_results_description": "No installed games were found" }, "system_tray": { "open": "Open Hydra", diff --git a/src/main/events/library/scan-installed-games.ts b/src/main/events/library/scan-installed-games.ts index cb123ee9..0bdc818c 100644 --- a/src/main/events/library/scan-installed-games.ts +++ b/src/main/events/library/scan-installed-games.ts @@ -1,8 +1,14 @@ import path from "node:path"; import fs from "node:fs"; +import { t } from "i18next"; import { registerEvent } from "../register-event"; import { gamesSublevel } from "@main/level"; -import { GameExecutables, logger, WindowManager } from "@main/services"; +import { + GameExecutables, + LocalNotificationManager, + logger, + WindowManager, +} from "@main/services"; const SCAN_DIRECTORIES = [ String.raw`C:\Games`, @@ -88,9 +94,32 @@ const scanInstalledGames = async ( WindowManager.mainWindow?.webContents.send("on-library-batch-complete"); + const total = games.filter((g) => !g.game.executablePath).length; + + const hasFoundGames = foundGames.length > 0; + + await LocalNotificationManager.createNotification( + "SCAN_GAMES_COMPLETE", + t( + hasFoundGames + ? "scan_games_complete_title" + : "scan_games_no_results_title", + { ns: "notifications" } + ), + t( + hasFoundGames + ? "scan_games_complete_description" + : "scan_games_no_results_description", + { ns: "notifications", count: foundGames.length } + ), + { + url: "/library?openScanModal=true", + } + ); + return { foundGames, - total: games.filter((g) => !g.game.executablePath).length, + total, }; }; diff --git a/src/renderer/src/components/header/header.scss b/src/renderer/src/components/header/header.scss index 0debe0fc..35148ee1 100644 --- a/src/renderer/src/components/header/header.scss +++ b/src/renderer/src/components/header/header.scss @@ -61,22 +61,25 @@ cursor: pointer; transition: all ease 0.2s; padding: globals.$spacing-unit; + display: flex; + align-items: center; + justify-content: center; &:hover { color: #dadbe1; } - &--scanning { + &--scanning svg { animation: spin 2s linear infinite; } } @keyframes spin { from { - transform: rotate(-0deg); + transform: rotate(0deg); } to { - transform: rotate(-360deg); + transform: rotate(360deg); } } diff --git a/src/renderer/src/components/header/header.tsx b/src/renderer/src/components/header/header.tsx index faf60a1e..b84a6dba 100644 --- a/src/renderer/src/components/header/header.tsx +++ b/src/renderer/src/components/header/header.tsx @@ -1,6 +1,6 @@ import { useTranslation } from "react-i18next"; import { useEffect, useId, useMemo, useRef, useState } from "react"; -import { useLocation, useNavigate } from "react-router-dom"; +import { useLocation, useNavigate, useSearchParams } from "react-router-dom"; import { ArrowLeftIcon, SearchIcon, @@ -40,6 +40,7 @@ export function Header() { const navigate = useNavigate(); const location = useLocation(); + const [searchParams, setSearchParams] = useSearchParams(); const { headerTitle, draggingDisabled } = useAppSelector( (state) => state.window @@ -268,6 +269,14 @@ export function Header() { return () => window.removeEventListener("resize", handleResize); }, [isDropdownVisible]); + useEffect(() => { + if (searchParams.get("openScanModal") === "true") { + setShowScanModal(true); + searchParams.delete("openScanModal"); + setSearchParams(searchParams, { replace: true }); + } + }, [searchParams, setSearchParams]); + return ( <>
; case "ACHIEVEMENT_UNLOCKED": return ; + case "SCAN_GAMES_COMPLETE": + return ; default: return ; } diff --git a/src/types/index.ts b/src/types/index.ts index 3ddd660c..39fd0791 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -330,7 +330,8 @@ export type LocalNotificationType = | "EXTRACTION_COMPLETE" | "DOWNLOAD_COMPLETE" | "UPDATE_AVAILABLE" - | "ACHIEVEMENT_UNLOCKED"; + | "ACHIEVEMENT_UNLOCKED" + | "SCAN_GAMES_COMPLETE"; export interface Notification { id: string;