feat: cleaner UI for version detection

This commit is contained in:
neoapps-dev
2026-04-30 18:35:39 +03:00
parent b589e43d3e
commit 1ecc47c32f
6 changed files with 58 additions and 26 deletions

View File

@@ -1282,7 +1282,7 @@ async fn check_game_update(app: AppHandle, instance_id: String, url: String) ->
let local_timestamp = fs::read_to_string(&timestamp_file).unwrap_or_default();
if local_timestamp.is_empty() {
return Ok(false);
return Ok(true);
}
let response = reqwest::Client::new().head(&url).send().await.map_err(|e| e.to_string())?;

View File

@@ -20,6 +20,7 @@ const HomeView = memo(function HomeView() {
downloadingId,
isGameRunning,
stopGame,
updatesAvailable,
} = useGame();
const isFocusedSection = focusSection === "menu";
@@ -54,10 +55,10 @@ const HomeView = memo(function HomeView() {
isDanger: isGameRunning,
disabled: isDownloading,
},
{ label: "Help & Options", action: () => setActiveView("settings"), disabled: false },
{ label: "Versions", action: () => setActiveView("versions"), disabled: false },
{ label: "Workshop", action: () => setActiveView("workshop"), disabled: false },
{ label: "Developer Tools", action: () => setActiveView("devtools"), disabled: false },
{ label: "Help & Options", action: () => setActiveView("settings"), disabled: false, id: "settings" },
{ label: "Versions", action: () => setActiveView("versions"), disabled: false, id: "versions" },
{ label: "Workshop", action: () => setActiveView("workshop"), disabled: false, id: "workshop" },
{ label: "Developer Tools", action: () => setActiveView("devtools"), disabled: false, id: "devtools" },
],
[
isDownloading,
@@ -131,7 +132,16 @@ const HomeView = memo(function HomeView() {
opacity: btn.disabled ? 0.5 : 1,
}}
>
<span className="w-full text-center">{btn.label}</span>
<div className="w-full h-full flex items-center justify-center relative">
<span>{btn.label}</span>
{btn.id === "versions" && Object.values(updatesAvailable || {}).some((v) => v) && (
<img
src="/images/Update_Icon.png"
className="absolute right-4 w-6 h-6 object-contain"
style={{ imageRendering: "pixelated", filter: "drop-shadow(0 0 2px rgba(255, 255, 0, 0.8)) sepia(100%) saturate(500%) hue-rotate(5deg) brightness(1.2)" }}
/>
)}
</div>
</button>
</div>
))}

View File

@@ -61,6 +61,7 @@ const VersionsView = memo(function VersionsView() {
updateCustomEdition: onUpdateEdition,
downloadingId,
downloadProgress,
updatesAvailable,
} = useGame();
const [focusIndex, setFocusIndex] = useState<number>(0);
const [focusBtn, setFocusBtn] = useState<number>(0);
@@ -488,7 +489,10 @@ const VersionsView = memo(function VersionsView() {
src="/images/Update_Icon.png"
alt="Update"
className="w-6 h-6 object-contain"
style={{ imageRendering: "pixelated" }}
style={{
imageRendering: "pixelated",
filter: updatesAvailable?.[edition.id] ? "brightness(1.5) sepia(1) saturate(5) hue-rotate(15deg) drop-shadow(0 0 4px rgba(255,255,0,0.8))" : "none"
}}
/>
</button>
<button

View File

@@ -73,7 +73,8 @@ export function LauncherProvider({ children }: { children: React.ReactNode }) {
gameRaw.installs, gameRaw.isGameRunning, gameRaw.downloadProgress,
gameRaw.downloadingId, gameRaw.editions, gameRaw.isRunnerDownloading,
gameRaw.runnerDownloadProgress, gameRaw.error, gameRaw.updateCustomEdition,
gameRaw.handleUninstall, gameRaw.handleCancelDownload, gameRaw.gameUpdateMessage, configRaw.profile
gameRaw.handleUninstall, gameRaw.handleCancelDownload, gameRaw.gameUpdateMessage, configRaw.profile,
gameRaw.updatesAvailable
]);
const audio = useMemo(() => audioRaw, [

View File

@@ -43,7 +43,7 @@ const PARTNERSHIP_SERVERS = [
{
name: "Kowhaifans Clubhouse",
ip: "lce.kowhaifan.net",
port: 1026,
port: 25565,
},
];
@@ -86,26 +86,42 @@ export function useGameManager({
setInstalls(results.filter((id): id is string => id !== null));
}, [editions]);
const [updatesAvailable, setUpdatesAvailable] = useState<Record<string, boolean>>({});
const checkForGameUpdates = useCallback(async () => {
if (!profile) return;
const edition = editions.find(e => e.id === profile);
if (!edition) return;
try {
const isUpdate = await TauriService.checkGameUpdate(profile, edition.url);
if (isUpdate) {
setGameUpdateMessage(`An update is available for ${edition.name}!`);
} else {
setGameUpdateMessage(null);
}
} catch (e) {
console.error(e);
const checks = await Promise.all(
editions.map(async (edition) => {
if (!installs.includes(edition.id)) return [edition.id, false] as const;
try {
const isUpdate = await TauriService.checkGameUpdate(edition.id, edition.url);
return [edition.id, isUpdate] as const;
} catch (e) {
console.error(e);
return [edition.id, false] as const;
}
})
);
const newUpdates: Record<string, boolean> = {};
for (const [id, hasUpdate] of checks) {
newUpdates[id as string] = hasUpdate as boolean;
}
}, [profile, editions]);
setUpdatesAvailable(newUpdates);
const updatedGames = editions.filter(e => newUpdates[e.id]);
if (updatedGames.length > 0) {
if (updatedGames.length === 1) {
setGameUpdateMessage(`An update is available for ${updatedGames[0].name}!`);
} else {
setGameUpdateMessage(`Updates are available for ${updatedGames.length} versions!`);
}
} else {
setGameUpdateMessage(null);
}
}, [editions, installs]);
useEffect(() => {
if (installs.includes(profile)) {
checkForGameUpdates();
}
checkForGameUpdates();
}, [profile, installs, checkForGameUpdates]);
useEffect(() => {
@@ -270,5 +286,6 @@ export function useGameManager({
checkInstalls,
gameUpdateMessage,
setGameUpdateMessage,
updatesAvailable,
};
}

View File

@@ -170,7 +170,7 @@ export default function App() {
onClose={() => game.setGameUpdateMessage(null)}
onClick={() => {
game.setGameUpdateMessage(null);
game.toggleInstall(config.profile);
setActiveView("versions");
}}
title="Game Update Available!"
variant="update"