ci: showing new badge in repack-modal

This commit is contained in:
Moyasee
2025-10-31 23:17:06 +02:00
parent 4dd3c9de76
commit efab242c74
13 changed files with 253 additions and 84 deletions

View File

@@ -214,6 +214,8 @@ declare global {
) => Promise<void>;
getDownloadSources: () => Promise<DownloadSource[]>;
syncDownloadSources: () => Promise<void>;
getDownloadSourcesCheckBaseline: () => Promise<string | null>;
getDownloadSourcesSinceValue: () => Promise<string | null>;
/* Hardware */
getDiskFreeSpace: (path: string) => Promise<DiskUsage>;

View File

@@ -8,9 +8,9 @@ export function useDownloadOptionsListener() {
useEffect(() => {
const unsubscribe = window.electron.onNewDownloadOptions(
(gamesWithNewOptions) => {
gamesWithNewOptions.forEach(({ gameId, count }) => {
for (const { gameId, count } of gamesWithNewOptions) {
dispatch(updateGameNewDownloadOptions({ gameId, count }));
});
}
}
);

View File

@@ -45,12 +45,27 @@
&__repack-title {
color: globals.$muted-color;
word-break: break-word;
display: flex;
align-items: center;
gap: calc(globals.$spacing-unit * 1);
}
&__repack-info {
font-size: globals.$small-font-size;
}
&__new-badge {
background-color: rgba(255, 255, 255, 0.1);
color: rgba(255, 255, 255, 0.7);
padding: 4px 8px;
border-radius: 6px;
font-size: 12px;
font-weight: 600;
min-width: 24px;
text-align: center;
flex-shrink: 0;
}
&__no-results {
width: 100%;
padding: calc(globals.$spacing-unit * 4) 0;

View File

@@ -15,8 +15,7 @@ import {
TextField,
CheckboxField,
} from "@renderer/components";
import type { DownloadSource } from "@types";
import type { GameRepack } from "@types";
import type { DownloadSource, GameRepack } from "@types";
import { DownloadSettingsModal } from "./download-settings-modal";
import { gameDetailsContext } from "@renderer/context";
@@ -53,6 +52,10 @@ export function RepacksModal({
const [hashesInDebrid, setHashesInDebrid] = useState<Record<string, boolean>>(
{}
);
const [lastCheckTimestamp, setLastCheckTimestamp] = useState<string | null>(
null
);
const [isLoadingTimestamp, setIsLoadingTimestamp] = useState(true);
const { game, repacks } = useContext(gameDetailsContext);
@@ -66,8 +69,8 @@ export function RepacksModal({
return null;
}
const hashRegex = /xt=urn:btih:([a-zA-Z0-9]+)/i;
const match = magnet.match(hashRegex);
const hashRegex = /xt=urn:btih:([a-f0-9]+)/i;
const match = hashRegex.exec(magnet);
return match ? match[1].toLowerCase() : null;
};
@@ -97,6 +100,21 @@ export function RepacksModal({
fetchDownloadSources();
}, []);
useEffect(() => {
const fetchLastCheckTimestamp = async () => {
setIsLoadingTimestamp(true);
const timestamp = await window.electron.getDownloadSourcesSinceValue();
setLastCheckTimestamp(timestamp);
setIsLoadingTimestamp(false);
};
if (visible) {
fetchLastCheckTimestamp();
}
}, [visible, repacks]);
const sortedRepacks = useMemo(() => {
return orderBy(
repacks,
@@ -158,6 +176,19 @@ export function RepacksModal({
return repack.uris.some((uri) => uri.includes(game.download!.uri));
};
const isNewRepack = (repack: GameRepack): boolean => {
// Don't show badge while loading timestamp
if (isLoadingTimestamp) return false;
if (!lastCheckTimestamp || !repack.createdAt) {
return false;
}
const lastCheckUtc = new Date(lastCheckTimestamp).toISOString();
return repack.createdAt > lastCheckUtc;
};
const [isFilterDrawerOpen, setIsFilterDrawerOpen] = useState(false);
useEffect(() => {
@@ -273,7 +304,14 @@ export function RepacksModal({
onClick={() => handleRepackClick(repack)}
className="repacks-modal__repack-button"
>
<p className="repacks-modal__repack-title">{repack.title}</p>
<p className="repacks-modal__repack-title">
{repack.title}
{isNewRepack(repack) && (
<span className="repacks-modal__new-badge">
{t("new_download_option")}
</span>
)}
</p>
{isLastDownloadedOption && (
<Badge>{t("last_downloaded_option")}</Badge>