mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-03-09 15:40:26 +00:00
Merge branch 'feature/custom-themes' of https://github.com/hydralauncher/hydra into feature/custom-themes
This commit is contained in:
commit
3f6315f043
5 changed files with 96 additions and 73 deletions
|
@ -327,7 +327,8 @@
|
||||||
"enable_torbox": "Enable Torbox",
|
"enable_torbox": "Enable Torbox",
|
||||||
"torbox_description": "TorBox is your premium seedbox service rivaling even the best servers on the market.",
|
"torbox_description": "TorBox is your premium seedbox service rivaling even the best servers on the market.",
|
||||||
"torbox_account_linked": "TorBox account linked",
|
"torbox_account_linked": "TorBox account linked",
|
||||||
"real_debrid_account_linked": "Real-Debrid account linked"
|
"real_debrid_account_linked": "Real-Debrid account linked",
|
||||||
|
"name_min_length": "Theme name must be at least 3 characters long"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"download_complete": "Download complete",
|
"download_complete": "Download complete",
|
||||||
|
|
|
@ -317,7 +317,8 @@
|
||||||
"enable_torbox": "Habilitar Torbox",
|
"enable_torbox": "Habilitar Torbox",
|
||||||
"torbox_description": "TorBox é o seu serviço de seedbox premium que rivaliza até com os melhores servidores do mercado.",
|
"torbox_description": "TorBox é o seu serviço de seedbox premium que rivaliza até com os melhores servidores do mercado.",
|
||||||
"torbox_account_linked": "Conta do TorBox vinculada",
|
"torbox_account_linked": "Conta do TorBox vinculada",
|
||||||
"real_debrid_account_linked": "Conta Real-Debrid associada"
|
"real_debrid_account_linked": "Conta Real-Debrid associada",
|
||||||
|
"name_min_length": "O nome do tema deve ter pelo menos 3 caracteres"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"download_complete": "Download concluído",
|
"download_complete": "Download concluído",
|
||||||
|
|
|
@ -230,14 +230,17 @@ export class DownloadManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
static async cancelDownload(downloadKey = this.downloadingGameId) {
|
static async cancelDownload(downloadKey = this.downloadingGameId) {
|
||||||
await PythonRPC.rpc.post("/action", {
|
await PythonRPC.rpc
|
||||||
|
.post("/action", {
|
||||||
action: "cancel",
|
action: "cancel",
|
||||||
game_id: downloadKey,
|
game_id: downloadKey,
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
logger.error("Failed to cancel game download", err);
|
||||||
});
|
});
|
||||||
|
|
||||||
WindowManager.mainWindow?.setProgressBar(-1);
|
|
||||||
|
|
||||||
if (downloadKey === this.downloadingGameId) {
|
if (downloadKey === this.downloadingGameId) {
|
||||||
|
WindowManager.mainWindow?.setProgressBar(-1);
|
||||||
WindowManager.mainWindow?.webContents.send("on-download-progress", null);
|
WindowManager.mainWindow?.webContents.send("on-download-progress", null);
|
||||||
this.downloadingGameId = null;
|
this.downloadingGameId = null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,10 +44,9 @@ export function DownloadSettingsModal({
|
||||||
(state) => state.userPreferences.value
|
(state) => state.userPreferences.value
|
||||||
);
|
);
|
||||||
|
|
||||||
const getDiskFreeSpace = (path: string) => {
|
const getDiskFreeSpace = async (path: string) => {
|
||||||
window.electron.getDiskFreeSpace(path).then((result) => {
|
const result = await window.electron.getDiskFreeSpace(path);
|
||||||
setDiskFreeSpace(result.free);
|
setDiskFreeSpace(result.free);
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const checkFolderWritePermission = useCallback(
|
const checkFolderWritePermission = useCallback(
|
||||||
|
@ -100,6 +99,7 @@ export function DownloadSettingsModal({
|
||||||
userPreferences?.downloadsPath,
|
userPreferences?.downloadsPath,
|
||||||
downloaders,
|
downloaders,
|
||||||
userPreferences?.realDebridApiToken,
|
userPreferences?.realDebridApiToken,
|
||||||
|
userPreferences?.torBoxApiToken,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const handleChooseDownloadsPath = async () => {
|
const handleChooseDownloadsPath = async () => {
|
||||||
|
@ -155,19 +155,21 @@ export function DownloadSettingsModal({
|
||||||
<span>{t("downloader")}</span>
|
<span>{t("downloader")}</span>
|
||||||
|
|
||||||
<div className="download-settings-modal__downloaders">
|
<div className="download-settings-modal__downloaders">
|
||||||
{downloaders.map((downloader) => (
|
{downloaders.map((downloader) => {
|
||||||
|
const shouldDisableButton =
|
||||||
|
(downloader === Downloader.RealDebrid &&
|
||||||
|
!userPreferences?.realDebridApiToken) ||
|
||||||
|
(downloader === Downloader.TorBox &&
|
||||||
|
!userPreferences?.torBoxApiToken);
|
||||||
|
|
||||||
|
return (
|
||||||
<Button
|
<Button
|
||||||
key={downloader}
|
key={downloader}
|
||||||
className="download-settings-modal__downloader-option"
|
className="download-settings-modal__downloader-option"
|
||||||
theme={
|
theme={
|
||||||
selectedDownloader === downloader ? "primary" : "outline"
|
selectedDownloader === downloader ? "primary" : "outline"
|
||||||
}
|
}
|
||||||
disabled={
|
disabled={shouldDisableButton}
|
||||||
(downloader === Downloader.RealDebrid &&
|
|
||||||
!userPreferences?.realDebridApiToken) ||
|
|
||||||
(downloader === Downloader.TorBox &&
|
|
||||||
!userPreferences?.torBoxApiToken)
|
|
||||||
}
|
|
||||||
onClick={() => setSelectedDownloader(downloader)}
|
onClick={() => setSelectedDownloader(downloader)}
|
||||||
>
|
>
|
||||||
{selectedDownloader === downloader && (
|
{selectedDownloader === downloader && (
|
||||||
|
@ -175,7 +177,8 @@ export function DownloadSettingsModal({
|
||||||
)}
|
)}
|
||||||
{DOWNLOADER_NAME[downloader]}
|
{DOWNLOADER_NAME[downloader]}
|
||||||
</Button>
|
</Button>
|
||||||
))}
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,14 @@ import { Modal } from "@renderer/components/modal/modal";
|
||||||
import { TextField } from "@renderer/components/text-field/text-field";
|
import { TextField } from "@renderer/components/text-field/text-field";
|
||||||
import { Button } from "@renderer/components/button/button";
|
import { Button } from "@renderer/components/button/button";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useState } from "react";
|
|
||||||
import "./modals.scss";
|
import "./modals.scss";
|
||||||
import { useUserDetails } from "@renderer/hooks";
|
import { useUserDetails } from "@renderer/hooks";
|
||||||
import { Theme } from "@types";
|
import { Theme } from "@types";
|
||||||
|
import { useForm } from "react-hook-form";
|
||||||
|
|
||||||
|
import * as yup from "yup";
|
||||||
|
import { yupResolver } from "@hookform/resolvers/yup";
|
||||||
|
import { useCallback } from "react";
|
||||||
|
|
||||||
interface AddThemeModalProps {
|
interface AddThemeModalProps {
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
|
@ -13,45 +17,54 @@ interface AddThemeModalProps {
|
||||||
onThemeAdded: () => void;
|
onThemeAdded: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AddThemeModal = ({
|
interface FormValues {
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function AddThemeModal({
|
||||||
visible,
|
visible,
|
||||||
onClose,
|
onClose,
|
||||||
onThemeAdded,
|
onThemeAdded,
|
||||||
}: AddThemeModalProps) => {
|
}: Readonly<AddThemeModalProps>) {
|
||||||
const { t } = useTranslation("settings");
|
const { t } = useTranslation("settings");
|
||||||
const { userDetails } = useUserDetails();
|
const { userDetails } = useUserDetails();
|
||||||
const [name, setName] = useState("");
|
|
||||||
const [error, setError] = useState("");
|
|
||||||
|
|
||||||
const handleKeyDown = (event: React.KeyboardEvent) => {
|
const schema = yup.object({
|
||||||
if (event.key === "Enter") {
|
name: yup
|
||||||
handleSubmit();
|
.string()
|
||||||
}
|
.required(t("required_field"))
|
||||||
};
|
.min(3, t("name_min_length")),
|
||||||
|
});
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const {
|
||||||
if (!name || name.length < 3) {
|
register,
|
||||||
setError(t("theme_name_error_hint"));
|
handleSubmit,
|
||||||
return;
|
reset,
|
||||||
}
|
formState: { isSubmitting, errors },
|
||||||
|
} = useForm<FormValues>({
|
||||||
|
resolver: yupResolver(schema),
|
||||||
|
});
|
||||||
|
|
||||||
|
const onSubmit = useCallback(
|
||||||
|
async (values: FormValues) => {
|
||||||
const theme: Theme = {
|
const theme: Theme = {
|
||||||
id: crypto.randomUUID(),
|
id: crypto.randomUUID(),
|
||||||
name,
|
name: values.name,
|
||||||
isActive: false,
|
isActive: false,
|
||||||
author: userDetails?.id || undefined,
|
author: userDetails?.id,
|
||||||
authorName: userDetails?.username || undefined,
|
authorName: userDetails?.username,
|
||||||
code: "",
|
code: "",
|
||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
updatedAt: new Date(),
|
updatedAt: new Date(),
|
||||||
};
|
};
|
||||||
|
|
||||||
await window.electron.addCustomTheme(theme);
|
await window.electron.addCustomTheme(theme);
|
||||||
setName("");
|
|
||||||
setError("");
|
|
||||||
onThemeAdded();
|
onThemeAdded();
|
||||||
onClose();
|
onClose();
|
||||||
};
|
reset();
|
||||||
|
},
|
||||||
|
[onClose, onThemeAdded, userDetails?.id, userDetails?.username, reset]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
|
@ -60,21 +73,23 @@ export const AddThemeModal = ({
|
||||||
description={t("create_theme_modal_description")}
|
description={t("create_theme_modal_description")}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
>
|
>
|
||||||
<div className="add-theme-modal__container">
|
<form className="add-theme-modal__container">
|
||||||
<TextField
|
<TextField
|
||||||
|
{...register("name")}
|
||||||
label={t("theme_name")}
|
label={t("theme_name")}
|
||||||
placeholder={t("insert_theme_name")}
|
placeholder={t("insert_theme_name")}
|
||||||
value={name}
|
hint={errors.name?.message}
|
||||||
onChange={(e) => setName(e.target.value)}
|
error={errors.name?.message}
|
||||||
hint={error}
|
|
||||||
error={!!error}
|
|
||||||
onKeyDown={handleKeyDown}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Button theme="primary" onClick={handleSubmit}>
|
<Button
|
||||||
|
theme="primary"
|
||||||
|
onClick={handleSubmit(onSubmit)}
|
||||||
|
disabled={isSubmitting}
|
||||||
|
>
|
||||||
{t("create_theme")}
|
{t("create_theme")}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</form>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue