mirror of
https://github.com/hydralauncher/hydra.git
synced 2026-01-20 17:53:55 +00:00
chore: adding download sorting
This commit is contained in:
@@ -282,6 +282,7 @@ export function App() {
|
||||
message={toast.message}
|
||||
type={toast.type}
|
||||
onClose={handleToastClose}
|
||||
duration={toast.duration}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
4
src/renderer/src/declaration.d.ts
vendored
4
src/renderer/src/declaration.d.ts
vendored
@@ -40,7 +40,9 @@ declare global {
|
||||
|
||||
interface Electron {
|
||||
/* Torrenting */
|
||||
startGameDownload: (payload: StartGameDownloadPayload) => Promise<void>;
|
||||
startGameDownload: (
|
||||
payload: StartGameDownloadPayload
|
||||
) => Promise<{ ok: boolean; error?: string }>;
|
||||
cancelGameDownload: (shop: GameShop, objectId: string) => Promise<void>;
|
||||
pauseGameDownload: (shop: GameShop, objectId: string) => Promise<void>;
|
||||
resumeGameDownload: (shop: GameShop, objectId: string) => Promise<void>;
|
||||
|
||||
@@ -6,6 +6,7 @@ export interface ToastState {
|
||||
title: string;
|
||||
message?: string;
|
||||
type: ToastProps["type"];
|
||||
duration?: number;
|
||||
visible: boolean;
|
||||
}
|
||||
|
||||
@@ -13,6 +14,7 @@ const initialState: ToastState = {
|
||||
title: "",
|
||||
message: "",
|
||||
type: "success",
|
||||
duration: 5000,
|
||||
visible: false,
|
||||
};
|
||||
|
||||
@@ -24,6 +26,7 @@ export const toastSlice = createSlice({
|
||||
state.title = action.payload.title;
|
||||
state.message = action.payload.message;
|
||||
state.type = action.payload.type;
|
||||
state.duration = action.payload.duration ?? 5000;
|
||||
state.visible = true;
|
||||
},
|
||||
closeToast: (state) => {
|
||||
|
||||
@@ -29,10 +29,11 @@ export function useDownload() {
|
||||
const startDownload = async (payload: StartGameDownloadPayload) => {
|
||||
dispatch(clearDownload());
|
||||
|
||||
const game = await window.electron.startGameDownload(payload);
|
||||
const response = await window.electron.startGameDownload(payload);
|
||||
|
||||
await updateLibrary();
|
||||
return game;
|
||||
if (response.ok) updateLibrary();
|
||||
|
||||
return response;
|
||||
};
|
||||
|
||||
const pauseDownload = async (shop: GameShop, objectId: string) => {
|
||||
|
||||
@@ -6,12 +6,13 @@ export function useToast() {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const showSuccessToast = useCallback(
|
||||
(title: string, message?: string) => {
|
||||
(title: string, message?: string, duration?: number) => {
|
||||
dispatch(
|
||||
showToast({
|
||||
title,
|
||||
message,
|
||||
type: "success",
|
||||
duration,
|
||||
})
|
||||
);
|
||||
},
|
||||
@@ -19,12 +20,13 @@ export function useToast() {
|
||||
);
|
||||
|
||||
const showErrorToast = useCallback(
|
||||
(title: string, message?: string) => {
|
||||
(title: string, message?: string, duration?: number) => {
|
||||
dispatch(
|
||||
showToast({
|
||||
title,
|
||||
message,
|
||||
type: "error",
|
||||
duration,
|
||||
})
|
||||
);
|
||||
},
|
||||
@@ -32,12 +34,13 @@ export function useToast() {
|
||||
);
|
||||
|
||||
const showWarningToast = useCallback(
|
||||
(title: string, message?: string) => {
|
||||
(title: string, message?: string, duration?: number) => {
|
||||
dispatch(
|
||||
showToast({
|
||||
title,
|
||||
message,
|
||||
type: "warning",
|
||||
duration,
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
@@ -8,7 +8,7 @@ import * as styles from "./downloads.css";
|
||||
import { DeleteGameModal } from "./delete-game-modal";
|
||||
import { DownloadGroup } from "./download-group";
|
||||
import type { GameShop, LibraryGame, SeedingStatus } from "@types";
|
||||
import { orderBy } from "lodash-es";
|
||||
import { orderBy, sortBy } from "lodash-es";
|
||||
import { ArrowDownIcon } from "@primer/octicons-react";
|
||||
|
||||
export default function Downloads() {
|
||||
@@ -58,21 +58,24 @@ export default function Downloads() {
|
||||
complete: [],
|
||||
};
|
||||
|
||||
const result = library.reduce((prev, next) => {
|
||||
/* Game has been manually added to the library or has been canceled */
|
||||
if (!next.download?.status || next.download?.status === "removed")
|
||||
return prev;
|
||||
const result = sortBy(library, (game) => game.download?.timestamp).reduce(
|
||||
(prev, next) => {
|
||||
/* Game has been manually added to the library or has been canceled */
|
||||
if (!next.download?.status || next.download?.status === "removed")
|
||||
return prev;
|
||||
|
||||
/* Is downloading */
|
||||
if (lastPacket?.gameId === next.id)
|
||||
return { ...prev, downloading: [...prev.downloading, next] };
|
||||
/* Is downloading */
|
||||
if (lastPacket?.gameId === next.id)
|
||||
return { ...prev, downloading: [...prev.downloading, next] };
|
||||
|
||||
/* Is either queued or paused */
|
||||
if (next.download.queued || next.download?.status === "paused")
|
||||
return { ...prev, queued: [...prev.queued, next] };
|
||||
/* Is either queued or paused */
|
||||
if (next.download.queued || next.download?.status === "paused")
|
||||
return { ...prev, queued: [...prev.queued, next] };
|
||||
|
||||
return { ...prev, complete: [...prev.complete, next] };
|
||||
}, initialValue);
|
||||
return { ...prev, complete: [...prev.complete, next] };
|
||||
},
|
||||
initialValue
|
||||
);
|
||||
|
||||
const queued = orderBy(result.queued, (game) => game.download?.timestamp, [
|
||||
"desc",
|
||||
|
||||
@@ -102,19 +102,23 @@ export default function GameDetails() {
|
||||
downloader: Downloader,
|
||||
downloadPath: string
|
||||
) => {
|
||||
await startDownload({
|
||||
const response = await startDownload({
|
||||
repackId: repack.id,
|
||||
objectId: objectId!,
|
||||
title: gameTitle,
|
||||
downloader,
|
||||
shop: shop as GameShop,
|
||||
shop,
|
||||
downloadPath,
|
||||
uri: selectRepackUri(repack, downloader),
|
||||
});
|
||||
|
||||
await updateGame();
|
||||
setShowRepacksModal(false);
|
||||
setShowGameOptionsModal(false);
|
||||
if (response.ok) {
|
||||
await updateGame();
|
||||
setShowRepacksModal(false);
|
||||
setShowGameOptionsModal(false);
|
||||
}
|
||||
|
||||
return response;
|
||||
};
|
||||
|
||||
const handleNSFWContentRefuse = () => {
|
||||
@@ -123,10 +127,7 @@ export default function GameDetails() {
|
||||
};
|
||||
|
||||
return (
|
||||
<CloudSyncContextProvider
|
||||
objectId={objectId!}
|
||||
shop={shop! as GameShop}
|
||||
>
|
||||
<CloudSyncContextProvider objectId={objectId!} shop={shop}>
|
||||
<CloudSyncContextConsumer>
|
||||
{({
|
||||
showCloudSyncModal,
|
||||
|
||||
@@ -18,7 +18,7 @@ export interface DownloadSettingsModalProps {
|
||||
repack: GameRepack,
|
||||
downloader: Downloader,
|
||||
downloadPath: string
|
||||
) => Promise<void>;
|
||||
) => Promise<{ ok: boolean; error?: string }>;
|
||||
repack: GameRepack | null;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ export function DownloadSettingsModal({
|
||||
onClose,
|
||||
startDownload,
|
||||
repack,
|
||||
}: DownloadSettingsModalProps) {
|
||||
}: Readonly<DownloadSettingsModalProps>) {
|
||||
const { t } = useTranslation("game_details");
|
||||
|
||||
const { showErrorToast } = useToast();
|
||||
@@ -117,20 +117,30 @@ export function DownloadSettingsModal({
|
||||
}
|
||||
};
|
||||
|
||||
const handleStartClick = () => {
|
||||
const handleStartClick = async () => {
|
||||
if (repack) {
|
||||
setDownloadStarting(true);
|
||||
|
||||
startDownload(repack, selectedDownloader!, selectedPath)
|
||||
.then(() => {
|
||||
try {
|
||||
const response = await startDownload(
|
||||
repack,
|
||||
selectedDownloader!,
|
||||
selectedPath
|
||||
);
|
||||
|
||||
if (response.ok) {
|
||||
onClose();
|
||||
})
|
||||
.catch((error) => {
|
||||
showErrorToast(t("download_error"), error.message);
|
||||
})
|
||||
.finally(() => {
|
||||
setDownloadStarting(false);
|
||||
});
|
||||
return;
|
||||
} else if (response.error) {
|
||||
showErrorToast(t("download_error"), t(response.error), 4_000);
|
||||
}
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
showErrorToast(t("download_error"), error.message, 4_000);
|
||||
}
|
||||
} finally {
|
||||
setDownloadStarting(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ export interface RepacksModalProps {
|
||||
repack: GameRepack,
|
||||
downloader: Downloader,
|
||||
downloadPath: string
|
||||
) => Promise<void>;
|
||||
) => Promise<{ ok: boolean; error?: string }>;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ export function RepacksModal({
|
||||
visible,
|
||||
startDownload,
|
||||
onClose,
|
||||
}: RepacksModalProps) {
|
||||
}: Readonly<RepacksModalProps>) {
|
||||
const [filteredRepacks, setFilteredRepacks] = useState<GameRepack[]>([]);
|
||||
const [repack, setRepack] = useState<GameRepack | null>(null);
|
||||
const [showSelectFolderModal, setShowSelectFolderModal] = useState(false);
|
||||
@@ -111,7 +111,7 @@ export function RepacksModal({
|
||||
|
||||
<p style={{ fontSize: "12px" }}>
|
||||
{repack.fileSize} - {repack.repacker} -{" "}
|
||||
{repack.uploadDate ? formatDate(repack.uploadDate!) : ""}
|
||||
{repack.uploadDate ? formatDate(repack.uploadDate) : ""}
|
||||
</p>
|
||||
</Button>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user