Skip to content

Commit

Permalink
Merge branch 'feature/custom-themes' of https://github.com/hydralaunc…
Browse files Browse the repository at this point in the history
…her/hydra into feature/custom-themes
  • Loading branch information
Hachi-R committed Feb 16, 2025
2 parents bf3905f + 22e5674 commit 3f6315f
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 73 deletions.
3 changes: 2 additions & 1 deletion src/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,8 @@
"enable_torbox": "Enable Torbox",
"torbox_description": "TorBox is your premium seedbox service rivaling even the best servers on the market.",
"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": {
"download_complete": "Download complete",
Expand Down
3 changes: 2 additions & 1 deletion src/locales/pt-BR/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,8 @@
"enable_torbox": "Habilitar Torbox",
"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",
"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": {
"download_complete": "Download concluído",
Expand Down
15 changes: 9 additions & 6 deletions src/main/services/download/download-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,14 +230,17 @@ export class DownloadManager {
}

static async cancelDownload(downloadKey = this.downloadingGameId) {
await PythonRPC.rpc.post("/action", {
action: "cancel",
game_id: downloadKey,
});

WindowManager.mainWindow?.setProgressBar(-1);
await PythonRPC.rpc
.post("/action", {
action: "cancel",
game_id: downloadKey,
})
.catch((err) => {
logger.error("Failed to cancel game download", err);
});

if (downloadKey === this.downloadingGameId) {
WindowManager.mainWindow?.setProgressBar(-1);
WindowManager.mainWindow?.webContents.send("on-download-progress", null);
this.downloadingGameId = null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,9 @@ export function DownloadSettingsModal({
(state) => state.userPreferences.value
);

const getDiskFreeSpace = (path: string) => {
window.electron.getDiskFreeSpace(path).then((result) => {
setDiskFreeSpace(result.free);
});
const getDiskFreeSpace = async (path: string) => {
const result = await window.electron.getDiskFreeSpace(path);
setDiskFreeSpace(result.free);
};

const checkFolderWritePermission = useCallback(
Expand Down Expand Up @@ -100,6 +99,7 @@ export function DownloadSettingsModal({
userPreferences?.downloadsPath,
downloaders,
userPreferences?.realDebridApiToken,
userPreferences?.torBoxApiToken,
]);

const handleChooseDownloadsPath = async () => {
Expand Down Expand Up @@ -155,27 +155,30 @@ export function DownloadSettingsModal({
<span>{t("downloader")}</span>

<div className="download-settings-modal__downloaders">
{downloaders.map((downloader) => (
<Button
key={downloader}
className="download-settings-modal__downloader-option"
theme={
selectedDownloader === downloader ? "primary" : "outline"
}
disabled={
(downloader === Downloader.RealDebrid &&
!userPreferences?.realDebridApiToken) ||
(downloader === Downloader.TorBox &&
!userPreferences?.torBoxApiToken)
}
onClick={() => setSelectedDownloader(downloader)}
>
{selectedDownloader === downloader && (
<CheckCircleFillIcon className="download-settings-modal__downloader-icon" />
)}
{DOWNLOADER_NAME[downloader]}
</Button>
))}
{downloaders.map((downloader) => {
const shouldDisableButton =
(downloader === Downloader.RealDebrid &&
!userPreferences?.realDebridApiToken) ||
(downloader === Downloader.TorBox &&
!userPreferences?.torBoxApiToken);

return (
<Button
key={downloader}
className="download-settings-modal__downloader-option"
theme={
selectedDownloader === downloader ? "primary" : "outline"
}
disabled={shouldDisableButton}
onClick={() => setSelectedDownloader(downloader)}
>
{selectedDownloader === downloader && (
<CheckCircleFillIcon className="download-settings-modal__downloader-icon" />
)}
{DOWNLOADER_NAME[downloader]}
</Button>
);
})}
</div>
</div>

Expand Down
95 changes: 55 additions & 40 deletions src/renderer/src/pages/settings/aparence/modals/add-theme-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,56 +2,69 @@ import { Modal } from "@renderer/components/modal/modal";
import { TextField } from "@renderer/components/text-field/text-field";
import { Button } from "@renderer/components/button/button";
import { useTranslation } from "react-i18next";
import { useState } from "react";
import "./modals.scss";
import { useUserDetails } from "@renderer/hooks";
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 {
visible: boolean;
onClose: () => void;
onThemeAdded: () => void;
}

export const AddThemeModal = ({
interface FormValues {
name: string;
}

export function AddThemeModal({
visible,
onClose,
onThemeAdded,
}: AddThemeModalProps) => {
}: Readonly<AddThemeModalProps>) {
const { t } = useTranslation("settings");
const { userDetails } = useUserDetails();
const [name, setName] = useState("");
const [error, setError] = useState("");

const handleKeyDown = (event: React.KeyboardEvent) => {
if (event.key === "Enter") {
handleSubmit();
}
};
const schema = yup.object({
name: yup
.string()
.required(t("required_field"))
.min(3, t("name_min_length")),
});

const handleSubmit = async () => {
if (!name || name.length < 3) {
setError(t("theme_name_error_hint"));
return;
}
const {
register,
handleSubmit,
reset,
formState: { isSubmitting, errors },
} = useForm<FormValues>({
resolver: yupResolver(schema),
});

const theme: Theme = {
id: crypto.randomUUID(),
name,
isActive: false,
author: userDetails?.id || undefined,
authorName: userDetails?.username || undefined,
code: "",
createdAt: new Date(),
updatedAt: new Date(),
};
const onSubmit = useCallback(
async (values: FormValues) => {
const theme: Theme = {
id: crypto.randomUUID(),
name: values.name,
isActive: false,
author: userDetails?.id,
authorName: userDetails?.username,
code: "",
createdAt: new Date(),
updatedAt: new Date(),
};

await window.electron.addCustomTheme(theme);
setName("");
setError("");
onThemeAdded();
onClose();
};
await window.electron.addCustomTheme(theme);
onThemeAdded();
onClose();
reset();
},
[onClose, onThemeAdded, userDetails?.id, userDetails?.username, reset]
);

return (
<Modal
Expand All @@ -60,21 +73,23 @@ export const AddThemeModal = ({
description={t("create_theme_modal_description")}
onClose={onClose}
>
<div className="add-theme-modal__container">
<form className="add-theme-modal__container">
<TextField
{...register("name")}
label={t("theme_name")}
placeholder={t("insert_theme_name")}
value={name}
onChange={(e) => setName(e.target.value)}
hint={error}
error={!!error}
onKeyDown={handleKeyDown}
hint={errors.name?.message}
error={errors.name?.message}
/>

<Button theme="primary" onClick={handleSubmit}>
<Button
theme="primary"
onClick={handleSubmit(onSubmit)}
disabled={isSubmitting}
>
{t("create_theme")}
</Button>
</div>
</form>
</Modal>
);
};
}

0 comments on commit 3f6315f

Please sign in to comment.