mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-02-03 00:33:49 +03:00
feat: change selectFolderModal to a section inside repacksModal
This commit is contained in:
parent
5db7b97090
commit
433e00bb50
@ -1,10 +1,9 @@
|
|||||||
import checkDiskSpace from "check-disk-space";
|
import checkDiskSpace from "check-disk-space";
|
||||||
|
|
||||||
import { registerEvent } from "../register-event";
|
import { registerEvent } from "../register-event";
|
||||||
import { getDownloadsPath } from "../helpers/get-downloads-path";
|
|
||||||
|
|
||||||
const getDiskFreeSpace = async (_event: Electron.IpcMainInvokeEvent) =>
|
const getDiskFreeSpace = async (_event: Electron.IpcMainInvokeEvent, path: string) =>
|
||||||
checkDiskSpace(await getDownloadsPath());
|
checkDiskSpace(path);
|
||||||
|
|
||||||
registerEvent(getDiskFreeSpace, {
|
registerEvent(getDiskFreeSpace, {
|
||||||
name: "getDiskFreeSpace",
|
name: "getDiskFreeSpace",
|
||||||
|
@ -99,7 +99,7 @@ contextBridge.exposeInMainWorld("electron", {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/* Hardware */
|
/* Hardware */
|
||||||
getDiskFreeSpace: () => ipcRenderer.invoke("getDiskFreeSpace"),
|
getDiskFreeSpace: (path: string) => ipcRenderer.invoke("getDiskFreeSpace", path),
|
||||||
|
|
||||||
/* Misc */
|
/* Misc */
|
||||||
getOrCacheImage: (url: string) => ipcRenderer.invoke("getOrCacheImage", url),
|
getOrCacheImage: (url: string) => ipcRenderer.invoke("getOrCacheImage", url),
|
||||||
|
2
src/renderer/declaration.d.ts
vendored
2
src/renderer/declaration.d.ts
vendored
@ -76,7 +76,7 @@ declare global {
|
|||||||
) => Promise<void>;
|
) => Promise<void>;
|
||||||
|
|
||||||
/* Hardware */
|
/* Hardware */
|
||||||
getDiskFreeSpace: () => Promise<DiskSpace>;
|
getDiskFreeSpace: (path: string) => Promise<DiskSpace>;
|
||||||
|
|
||||||
/* Misc */
|
/* Misc */
|
||||||
getOrCacheImage: (url: string) => Promise<string>;
|
getOrCacheImage: (url: string) => Promise<string>;
|
||||||
|
@ -51,7 +51,6 @@ export function GameDetails() {
|
|||||||
const { t, i18n } = useTranslation("game_details");
|
const { t, i18n } = useTranslation("game_details");
|
||||||
|
|
||||||
const [showRepacksModal, setShowRepacksModal] = useState(false);
|
const [showRepacksModal, setShowRepacksModal] = useState(false);
|
||||||
const [showSelectFolderModal, setShowSelectFolderModal] = useState(false);
|
|
||||||
|
|
||||||
const randomGameObjectID = useRef<string | null>(null);
|
const randomGameObjectID = useRef<string | null>(null);
|
||||||
|
|
||||||
@ -154,7 +153,6 @@ export function GameDetails() {
|
|||||||
).then(() => {
|
).then(() => {
|
||||||
getGame();
|
getGame();
|
||||||
setShowRepacksModal(false);
|
setShowRepacksModal(false);
|
||||||
setShowSelectFolderModal(false);
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -179,8 +177,6 @@ export function GameDetails() {
|
|||||||
visible={showRepacksModal}
|
visible={showRepacksModal}
|
||||||
gameDetails={gameDetails}
|
gameDetails={gameDetails}
|
||||||
startDownload={handleStartDownload}
|
startDownload={handleStartDownload}
|
||||||
showSelectFolderModal={showSelectFolderModal}
|
|
||||||
setShowSelectFolderModal={setShowSelectFolderModal}
|
|
||||||
onClose={() => setShowRepacksModal(false)}
|
onClose={() => setShowRepacksModal(false)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -16,3 +16,23 @@ export const repackButton = style({
|
|||||||
color: vars.color.bodyText,
|
color: vars.color.bodyText,
|
||||||
padding: `${SPACING_UNIT * 2}px`,
|
padding: `${SPACING_UNIT * 2}px`,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const container = style({
|
||||||
|
width: "100%",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
gap: `${SPACING_UNIT * 2}px`,
|
||||||
|
marginBottom: SPACING_UNIT * 2,
|
||||||
|
paddingBottom: SPACING_UNIT * 2,
|
||||||
|
borderBottom: `solid 1px ${vars.color.borderColor}`,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const downloadsPathField = style({
|
||||||
|
display: "flex",
|
||||||
|
gap: `${SPACING_UNIT * 2}px`,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const hintText = style({
|
||||||
|
fontSize: 12,
|
||||||
|
color: vars.color.bodyText,
|
||||||
|
});
|
@ -6,18 +6,16 @@ import type { GameRepack, ShopDetails } from "@types";
|
|||||||
|
|
||||||
import * as styles from "./repacks-modal.css";
|
import * as styles from "./repacks-modal.css";
|
||||||
|
|
||||||
import type { DiskSpace } from "check-disk-space";
|
import { useAppSelector } from "@renderer/hooks";
|
||||||
import { format } from "date-fns";
|
|
||||||
import { SPACING_UNIT } from "@renderer/theme.css";
|
import { SPACING_UNIT } from "@renderer/theme.css";
|
||||||
import { formatBytes } from "@renderer/utils";
|
import { formatBytes } from "@renderer/utils";
|
||||||
import { useAppSelector } from "@renderer/hooks";
|
import type { DiskSpace } from "check-disk-space";
|
||||||
import { SelectFolderModal } from "./select-folder-modal";
|
import { format } from "date-fns";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
export interface RepacksModalProps {
|
export interface RepacksModalProps {
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
gameDetails: ShopDetails;
|
gameDetails: ShopDetails;
|
||||||
showSelectFolderModal: boolean;
|
|
||||||
setShowSelectFolderModal: (value: boolean) => void;
|
|
||||||
startDownload: (repackId: number, downloadPath: string) => Promise<void>;
|
startDownload: (repackId: number, downloadPath: string) => Promise<void>;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
}
|
}
|
||||||
@ -25,18 +23,13 @@ export interface RepacksModalProps {
|
|||||||
export function RepacksModal({
|
export function RepacksModal({
|
||||||
visible,
|
visible,
|
||||||
gameDetails,
|
gameDetails,
|
||||||
showSelectFolderModal,
|
|
||||||
setShowSelectFolderModal,
|
|
||||||
startDownload,
|
startDownload,
|
||||||
onClose,
|
onClose,
|
||||||
}: RepacksModalProps) {
|
}: RepacksModalProps) {
|
||||||
const [diskFreeSpace, setDiskFreeSpace] = useState<DiskSpace>(null);
|
const [diskFreeSpace, setDiskFreeSpace] = useState<DiskSpace>(null);
|
||||||
const [filteredRepacks, setFilteredRepacks] = useState<GameRepack[]>([]);
|
const [filteredRepacks, setFilteredRepacks] = useState<GameRepack[]>([]);
|
||||||
const [repack, setRepack] = useState<GameRepack>(null);
|
const [selectedPath, setSelectedPath] = useState("");
|
||||||
|
const [downloadStarting, setDownloadStarting] = useState(false);
|
||||||
const repackersFriendlyNames = useAppSelector(
|
|
||||||
(state) => state.repackersFriendlyNames.value
|
|
||||||
);
|
|
||||||
|
|
||||||
const { t } = useTranslation("game_details");
|
const { t } = useTranslation("game_details");
|
||||||
|
|
||||||
@ -44,20 +37,22 @@ export function RepacksModal({
|
|||||||
setFilteredRepacks(gameDetails.repacks);
|
setFilteredRepacks(gameDetails.repacks);
|
||||||
}, [gameDetails.repacks]);
|
}, [gameDetails.repacks]);
|
||||||
|
|
||||||
const getDiskFreeSpace = () => {
|
useEffect(() => {
|
||||||
window.electron.getDiskFreeSpace().then((result) => {
|
visible && getDiskFreeSpace(selectedPath);
|
||||||
setDiskFreeSpace(result);
|
}, [selectedPath, visible]);
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getDiskFreeSpace();
|
Promise.all([
|
||||||
}, [visible]);
|
window.electron.getDefaultDownloadsPath(),
|
||||||
|
window.electron.getUserPreferences(),
|
||||||
|
]).then(([path, userPreferences]) => {
|
||||||
|
setSelectedPath(userPreferences?.downloadsPath || path);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
const handleRepackClick = (repack: GameRepack) => {
|
const repackersFriendlyNames = useAppSelector(
|
||||||
setRepack(repack);
|
(state) => state.repackersFriendlyNames.value
|
||||||
setShowSelectFolderModal(true);
|
);
|
||||||
};
|
|
||||||
|
|
||||||
const handleFilter: React.ChangeEventHandler<HTMLInputElement> = (event) => {
|
const handleFilter: React.ChangeEventHandler<HTMLInputElement> = (event) => {
|
||||||
setFilteredRepacks(
|
setFilteredRepacks(
|
||||||
@ -69,6 +64,32 @@ export function RepacksModal({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleChooseDownloadsPath = async () => {
|
||||||
|
const { filePaths } = await window.electron.showOpenDialog({
|
||||||
|
defaultPath: selectedPath,
|
||||||
|
properties: ["openDirectory"],
|
||||||
|
});
|
||||||
|
|
||||||
|
if (filePaths && filePaths.length > 0) {
|
||||||
|
const path = filePaths[0];
|
||||||
|
setSelectedPath(path);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRepackClick = (repack: GameRepack) => {
|
||||||
|
setDownloadStarting(true);
|
||||||
|
startDownload(repack.id, selectedPath).finally(() => {
|
||||||
|
setDownloadStarting(false);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDiskFreeSpace = (path: string) => {
|
||||||
|
window.electron.getDiskFreeSpace(path).then((result) => {
|
||||||
|
setDiskFreeSpace(result);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
visible={visible}
|
visible={visible}
|
||||||
@ -78,13 +99,37 @@ export function RepacksModal({
|
|||||||
})}
|
})}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
>
|
>
|
||||||
<SelectFolderModal
|
<div className={styles.container}>
|
||||||
visible={showSelectFolderModal}
|
<div className={styles.downloadsPathField}>
|
||||||
onClose={() => setShowSelectFolderModal(false)}
|
<TextField
|
||||||
gameDetails={gameDetails}
|
label={t("downloads_path")}
|
||||||
startDownload={startDownload}
|
value={selectedPath}
|
||||||
repack={repack}
|
readOnly
|
||||||
/>
|
disabled
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
style={{ alignSelf: "flex-end" }}
|
||||||
|
theme="outline"
|
||||||
|
onClick={handleChooseDownloadsPath}
|
||||||
|
disabled={downloadStarting}
|
||||||
|
>
|
||||||
|
{t("change")}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<p className={styles.hintText}>
|
||||||
|
{t("select_folder_hint")}{" "}
|
||||||
|
<Link
|
||||||
|
to="/settings"
|
||||||
|
style={{
|
||||||
|
textDecoration: "none",
|
||||||
|
color: "#C0C1C7",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("hydra_settings")}
|
||||||
|
</Link>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
<div style={{ marginBottom: `${SPACING_UNIT * 2}px` }}>
|
<div style={{ marginBottom: `${SPACING_UNIT * 2}px` }}>
|
||||||
<TextField placeholder={t("filter")} onChange={handleFilter} />
|
<TextField placeholder={t("filter")} onChange={handleFilter} />
|
||||||
</div>
|
</div>
|
||||||
@ -96,6 +141,7 @@ export function RepacksModal({
|
|||||||
theme="dark"
|
theme="dark"
|
||||||
onClick={() => handleRepackClick(repack)}
|
onClick={() => handleRepackClick(repack)}
|
||||||
className={styles.repackButton}
|
className={styles.repackButton}
|
||||||
|
disabled={downloadStarting}
|
||||||
>
|
>
|
||||||
<p style={{ color: "#DADBE1" }}>{repack.title}</p>
|
<p style={{ color: "#DADBE1" }}>{repack.title}</p>
|
||||||
<p style={{ fontSize: "12px" }}>
|
<p style={{ fontSize: "12px" }}>
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
import { style } from "@vanilla-extract/css";
|
|
||||||
import { SPACING_UNIT, vars } from "@renderer/theme.css";
|
|
||||||
|
|
||||||
export const container = style({
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
gap: `${SPACING_UNIT * 2}px`,
|
|
||||||
width: "100%",
|
|
||||||
});
|
|
||||||
|
|
||||||
export const downloadsPathField = style({
|
|
||||||
display: "flex",
|
|
||||||
gap: `${SPACING_UNIT * 2}px`,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const hintText = style({
|
|
||||||
fontSize: 12,
|
|
||||||
color: vars.color.bodyText,
|
|
||||||
});
|
|
@ -1,99 +0,0 @@
|
|||||||
import { Button, Modal, TextField } from "@renderer/components";
|
|
||||||
import { GameRepack, ShopDetails } from "@types";
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
|
|
||||||
import * as styles from "./select-folder-modal.css";
|
|
||||||
import { Link } from "react-router-dom";
|
|
||||||
|
|
||||||
export interface SelectFolderModalProps {
|
|
||||||
visible: boolean;
|
|
||||||
gameDetails: ShopDetails;
|
|
||||||
onClose: () => void;
|
|
||||||
startDownload: (repackId: number, downloadPath: string) => Promise<void>;
|
|
||||||
repack: GameRepack;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function SelectFolderModal({
|
|
||||||
visible,
|
|
||||||
gameDetails,
|
|
||||||
onClose,
|
|
||||||
startDownload,
|
|
||||||
repack,
|
|
||||||
}: SelectFolderModalProps) {
|
|
||||||
const { t } = useTranslation("game_details");
|
|
||||||
|
|
||||||
const [selectedPath, setSelectedPath] = useState("");
|
|
||||||
const [downloadStarting, setDownloadStarting] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
Promise.all([
|
|
||||||
window.electron.getDefaultDownloadsPath(),
|
|
||||||
window.electron.getUserPreferences(),
|
|
||||||
]).then(([path, userPreferences]) => {
|
|
||||||
setSelectedPath(userPreferences?.downloadsPath || path);
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleChooseDownloadsPath = async () => {
|
|
||||||
const { filePaths } = await window.electron.showOpenDialog({
|
|
||||||
defaultPath: selectedPath,
|
|
||||||
properties: ["openDirectory"],
|
|
||||||
});
|
|
||||||
|
|
||||||
if (filePaths && filePaths.length > 0) {
|
|
||||||
const path = filePaths[0];
|
|
||||||
setSelectedPath(path);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleStartClick = () => {
|
|
||||||
setDownloadStarting(true);
|
|
||||||
startDownload(repack.id, selectedPath).finally(() => {
|
|
||||||
setDownloadStarting(false);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Modal
|
|
||||||
visible={visible}
|
|
||||||
title={`${gameDetails.name} Installation folder`}
|
|
||||||
description={t("select_folder_description")}
|
|
||||||
onClose={onClose}
|
|
||||||
>
|
|
||||||
<div className={styles.container}>
|
|
||||||
<div className={styles.downloadsPathField}>
|
|
||||||
<TextField
|
|
||||||
label={t("downloads_path")}
|
|
||||||
value={selectedPath}
|
|
||||||
readOnly
|
|
||||||
disabled
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
style={{ alignSelf: "flex-end" }}
|
|
||||||
theme="outline"
|
|
||||||
onClick={handleChooseDownloadsPath}
|
|
||||||
>
|
|
||||||
{t("change")}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
<p className={styles.hintText}>
|
|
||||||
{t("select_folder_hint")}{" "}
|
|
||||||
<Link
|
|
||||||
to="/settings"
|
|
||||||
style={{
|
|
||||||
textDecoration: "none",
|
|
||||||
color: "#C0C1C7",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t("hydra_settings")}
|
|
||||||
</Link>
|
|
||||||
</p>
|
|
||||||
<Button onClick={handleStartClick} disabled={downloadStarting}>
|
|
||||||
{t("download_now")}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user