From 365a8143ff410b3c6d9f283527ceadbae12084eb Mon Sep 17 00:00:00 2001 From: neoapps-dev Date: Thu, 30 Apr 2026 19:02:34 +0300 Subject: [PATCH] feat: enhanced update checker for game and launcher --- src/context/LauncherContext.tsx | 9 +++--- src/hooks/useUpdateCheck.ts | 50 +++++++++++++++++++++++++++------ src/pages/App.tsx | 3 +- 3 files changed, 48 insertions(+), 14 deletions(-) diff --git a/src/context/LauncherContext.tsx b/src/context/LauncherContext.tsx index 67f8cbf..989c991 100644 --- a/src/context/LauncherContext.tsx +++ b/src/context/LauncherContext.tsx @@ -26,15 +26,14 @@ interface UIContextType { onNavigateToMenu: () => void; connected: boolean; updateMessage: string | null; + updateUrl: string | null; clearUpdateMessage: () => void; } const UIContext = createContext(undefined); - export const ConfigContext = createContext | undefined>(undefined); export const AudioContext = createContext | undefined>(undefined); export const GameContext = createContext | undefined>(undefined); export const SkinContext = createContext | undefined>(undefined); - export function LauncherProvider({ children }: { children: React.ReactNode }) { const [showIntro, setShowIntro] = useState(true); const [logoAnimDone, setLogoAnimDone] = useState(false); @@ -44,7 +43,7 @@ export function LauncherProvider({ children }: { children: React.ReactNode }) { const [showCredits, setShowCredits] = useState(false); const [focusSection, setFocusSection] = useState<"menu" | "skin">("menu"); - const { updateMessage, clearUpdateMessage } = useUpdateCheck(); + const { updateMessage, updateUrl, clearUpdateMessage } = useUpdateCheck(); const configRaw = useAppConfig(); const gameRaw = useGameManager({ @@ -181,8 +180,8 @@ export function LauncherProvider({ children }: { children: React.ReactNode }) { isWindowVisible, showCredits, setShowCredits, focusSection, setFocusSection, onNavigateToSkin, onNavigateToMenu, connected, - updateMessage, clearUpdateMessage - }), [activeView, showIntro, logoAnimDone, isUiHidden, isWindowVisible, showCredits, focusSection, onNavigateToSkin, onNavigateToMenu, connected, updateMessage, clearUpdateMessage]); + updateMessage, updateUrl, clearUpdateMessage + }), [activeView, showIntro, logoAnimDone, isUiHidden, isWindowVisible, showCredits, focusSection, onNavigateToSkin, onNavigateToMenu, connected, updateMessage, updateUrl, clearUpdateMessage]); return ( diff --git a/src/hooks/useUpdateCheck.ts b/src/hooks/useUpdateCheck.ts index 5856823..74750e0 100644 --- a/src/hooks/useUpdateCheck.ts +++ b/src/hooks/useUpdateCheck.ts @@ -1,18 +1,51 @@ import { useState, useEffect, useCallback } from "react"; declare const __BUILD_DATE__: string; -const REPO_URL = "https://api.github.com/repos/LCE-Hub/LCE-Emerald-Launcher/releases/latest"; +const LATEST_URL = "https://api.github.com/repos/LCE-Hub/LCE-Emerald-Launcher/releases/latest"; +const NIGHTLY_URL = "https://api.github.com/repos/LCE-Hub/LCE-Emerald-Launcher/releases/tags/nightly"; export function useUpdateCheck() { const [updateMessage, setUpdateMessage] = useState(null); + const [updateUrl, setUpdateUrl] = useState(null); const checkUpdates = useCallback(async () => { try { - const response = await fetch(REPO_URL); - if (!response.ok) return; - const data = await response.json(); - const latestDate = new Date(data.published_at); const buildDate = new Date(__BUILD_DATE__); - if (latestDate > buildDate) { - setUpdateMessage(`Version ${data.tag_name} is now available!`); - } 9 + let isNightly = false; + let latestData = null; + let latestDate = new Date(0); + try { + const latestResponse = await fetch(LATEST_URL); + if (latestResponse.ok) { + latestData = await latestResponse.json(); + latestDate = new Date(latestData.published_at); + if (buildDate > latestDate) { + isNightly = true; + } + } else { + isNightly = true; + } + } catch (e) { + isNightly = true; + } + + if (isNightly) { + const nightlyResponse = await fetch(NIGHTLY_URL); + if (!nightlyResponse.ok) return; + const nightlyData = await nightlyResponse.json(); + let releaseDate = new Date(nightlyData.published_at || nightlyData.updated_at); + if (nightlyData.assets && nightlyData.assets.length > 0) { + const assetDate = new Date(nightlyData.assets[0].updated_at); + if (assetDate > releaseDate) releaseDate = assetDate; + } + + if (releaseDate > buildDate) { + setUpdateMessage(`A new Nightly build is available!`); + setUpdateUrl("https://github.com/LCE-Hub/LCE-Emerald-Launcher/releases/tag/nightly"); + } + } else { + if (latestDate > buildDate && latestData) { + setUpdateMessage(`Version ${latestData.tag_name} is now available!`); + setUpdateUrl(latestData.html_url || LATEST_URL); + } + } } catch (e) { console.error("Failed to check for updates:", e); } @@ -24,6 +57,7 @@ export function useUpdateCheck() { return { updateMessage, + updateUrl, clearUpdateMessage: () => setUpdateMessage(null), }; } diff --git a/src/pages/App.tsx b/src/pages/App.tsx index 95ab13b..16e2903 100644 --- a/src/pages/App.tsx +++ b/src/pages/App.tsx @@ -45,6 +45,7 @@ export default function App() { focusSection, onNavigateToMenu, updateMessage, + updateUrl, clearUpdateMessage, } = useUI(); const config = useConfig(); @@ -159,7 +160,7 @@ export default function App() { message={updateMessage} onClose={clearUpdateMessage} onClick={() => - TauriService.openUrl("https://github.com/LCE-Hub/LCE-Emerald-Launcher/releases/latest") + TauriService.openUrl(updateUrl || "https://github.com/LCE-Hub/LCE-Emerald-Launcher/releases/latest") } title="Update Available!" variant="update"