mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-02-02 16:23:48 +03:00
feat: debrid token input component
This commit is contained in:
parent
b1dde446b2
commit
8761302384
@ -280,7 +280,8 @@
|
|||||||
"launch_minimized": "Launch Hydra minimized",
|
"launch_minimized": "Launch Hydra minimized",
|
||||||
"disable_nsfw_alert": "Disable NSFW alert",
|
"disable_nsfw_alert": "Disable NSFW alert",
|
||||||
"seed_after_download_complete": "Seed after download complete",
|
"seed_after_download_complete": "Seed after download complete",
|
||||||
"show_hidden_achievement_description": "Show hidden achievements description before unlocking them"
|
"show_hidden_achievement_description": "Show hidden achievements description before unlocking them",
|
||||||
|
"debrid_services": "Debrid Services"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"download_complete": "Download complete",
|
"download_complete": "Download complete",
|
||||||
|
@ -268,7 +268,8 @@
|
|||||||
"launch_minimized": "Iniciar o Hydra minimizado",
|
"launch_minimized": "Iniciar o Hydra minimizado",
|
||||||
"disable_nsfw_alert": "Desativar alerta de conteúdo inapropriado",
|
"disable_nsfw_alert": "Desativar alerta de conteúdo inapropriado",
|
||||||
"seed_after_download_complete": "Semear após a conclusão do download",
|
"seed_after_download_complete": "Semear após a conclusão do download",
|
||||||
"show_hidden_achievement_description": "Mostrar descrição de conquistas ocultas antes de debloqueá-las"
|
"show_hidden_achievement_description": "Mostrar descrição de conquistas ocultas antes de debloqueá-las",
|
||||||
|
"debrid_services": "Serviços Debrid"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"download_complete": "Download concluído",
|
"download_complete": "Download concluído",
|
||||||
|
186
src/renderer/src/pages/settings/settings-debrid-input.tsx
Normal file
186
src/renderer/src/pages/settings/settings-debrid-input.tsx
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
import { useContext, useEffect, useMemo, useState } from "react";
|
||||||
|
import { Trans, useTranslation } from "react-i18next";
|
||||||
|
import { Button, CheckboxField, Link, TextField } from "@renderer/components";
|
||||||
|
import * as styles from "./settings-debrid.css";
|
||||||
|
import { useAppSelector, useToast } from "@renderer/hooks";
|
||||||
|
import { SPACING_UNIT } from "@renderer/theme.css";
|
||||||
|
import { settingsContext } from "@renderer/context";
|
||||||
|
import { DebridServices } from "@types";
|
||||||
|
|
||||||
|
const REAL_DEBRID_API_TOKEN_URL = "https://real-debrid.com/apitoken";
|
||||||
|
const TORBOX_API_TOKEN_URL = "https://torbox.app/settings";
|
||||||
|
|
||||||
|
interface SettingsDebridForm {
|
||||||
|
useRealDebrid: boolean;
|
||||||
|
realDebridApiToken: string | null;
|
||||||
|
useTorBox: boolean;
|
||||||
|
torBoxApiToken: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SettingsDebridProps {
|
||||||
|
service: DebridServices;
|
||||||
|
form: SettingsDebridForm;
|
||||||
|
setForm: (SettingsDebridForm) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SettingsDebridInput({
|
||||||
|
service,
|
||||||
|
form,
|
||||||
|
setForm,
|
||||||
|
}: SettingsDebridProps) {
|
||||||
|
const userPreferences = useAppSelector(
|
||||||
|
(state) => state.userPreferences.value
|
||||||
|
);
|
||||||
|
|
||||||
|
const { updateUserPreferences } = useContext(settingsContext);
|
||||||
|
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
|
const { showSuccessToast, showErrorToast } = useToast();
|
||||||
|
|
||||||
|
const { t } = useTranslation("settings");
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (userPreferences) {
|
||||||
|
setForm({
|
||||||
|
useRealDebrid: Boolean(userPreferences.realDebridApiToken),
|
||||||
|
realDebridApiToken: userPreferences.realDebridApiToken ?? null,
|
||||||
|
useTorBox: Boolean(userPreferences.torBoxApiToken),
|
||||||
|
torBoxApiToken: userPreferences.torBoxApiToken ?? null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [userPreferences]);
|
||||||
|
|
||||||
|
const handleFormSubmit: React.FormEventHandler<HTMLFormElement> = async (
|
||||||
|
event
|
||||||
|
) => {
|
||||||
|
setIsLoading(true);
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (form.useRealDebrid) {
|
||||||
|
const user = await window.electron.authenticateRealDebrid(
|
||||||
|
form.realDebridApiToken!
|
||||||
|
);
|
||||||
|
|
||||||
|
if (user.type === "free") {
|
||||||
|
showErrorToast(
|
||||||
|
t("real_debrid_free_account_error", { username: user.username })
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
showSuccessToast(
|
||||||
|
t("real_debrid_linked_message", { username: user.username })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
showSuccessToast(t("changes_saved"));
|
||||||
|
}
|
||||||
|
|
||||||
|
updateUserPreferences({
|
||||||
|
realDebridApiToken: form.useRealDebrid ? form.realDebridApiToken : null,
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
showErrorToast(t("real_debrid_invalid_token"));
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const useDebridService = useMemo(() => {
|
||||||
|
if (service === "RealDebrid") {
|
||||||
|
return form.useRealDebrid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (service === "TorBox") {
|
||||||
|
return form.useTorBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}, [form, service]);
|
||||||
|
|
||||||
|
const debridApiToken = useMemo(() => {
|
||||||
|
if (service === "RealDebrid") {
|
||||||
|
return form.realDebridApiToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (service === "TorBox") {
|
||||||
|
return form.torBoxApiToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}, [form, service]);
|
||||||
|
|
||||||
|
const onChangeCheckbox = () => {
|
||||||
|
if (service === "RealDebrid") {
|
||||||
|
setForm((prev) => ({
|
||||||
|
...prev,
|
||||||
|
useRealDebrid: !form.useRealDebrid,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (service === "TorBox") {
|
||||||
|
setForm((prev) => ({
|
||||||
|
...prev,
|
||||||
|
useTorBox: !form.useTorBox,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onChangeInput = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
if (service === "RealDebrid") {
|
||||||
|
setForm((prev) => ({
|
||||||
|
...prev,
|
||||||
|
realDebridApiToken: event.target.value,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (service === "TorBox") {
|
||||||
|
setForm((prev) => ({
|
||||||
|
...prev,
|
||||||
|
torBoxApiToken: event.target.value,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const isButtonDisabled =
|
||||||
|
(form.useRealDebrid && !form.realDebridApiToken) || isLoading;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form className={styles.form} onSubmit={handleFormSubmit}>
|
||||||
|
<CheckboxField
|
||||||
|
label={t("enable_real_debrid")}
|
||||||
|
checked={useDebridService}
|
||||||
|
onChange={onChangeCheckbox}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{useDebridService && (
|
||||||
|
<TextField
|
||||||
|
label={t("real_debrid_api_token")}
|
||||||
|
value={debridApiToken ?? ""}
|
||||||
|
type="password"
|
||||||
|
onChange={onChangeInput}
|
||||||
|
placeholder="API Token"
|
||||||
|
containerProps={{ style: { marginTop: `${SPACING_UNIT}px` } }}
|
||||||
|
rightContent={
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
style={{
|
||||||
|
alignSelf: "flex-end",
|
||||||
|
}}
|
||||||
|
disabled={isButtonDisabled}
|
||||||
|
>
|
||||||
|
{t("save")}
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
hint={
|
||||||
|
<Trans i18nKey="real_debrid_api_token_hint" ns="settings">
|
||||||
|
<Link to={REAL_DEBRID_API_TOKEN_URL} />
|
||||||
|
</Trans>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
@ -2,7 +2,7 @@ import { useContext, useEffect, useState } from "react";
|
|||||||
import { Trans, useTranslation } from "react-i18next";
|
import { Trans, useTranslation } from "react-i18next";
|
||||||
|
|
||||||
import { Button, CheckboxField, Link, TextField } from "@renderer/components";
|
import { Button, CheckboxField, Link, TextField } from "@renderer/components";
|
||||||
import * as styles from "./settings-real-debrid.css";
|
import * as styles from "./settings-debrid.css";
|
||||||
|
|
||||||
import { useAppSelector, useToast } from "@renderer/hooks";
|
import { useAppSelector, useToast } from "@renderer/hooks";
|
||||||
|
|
||||||
@ -10,8 +10,9 @@ import { SPACING_UNIT } from "@renderer/theme.css";
|
|||||||
import { settingsContext } from "@renderer/context";
|
import { settingsContext } from "@renderer/context";
|
||||||
|
|
||||||
const REAL_DEBRID_API_TOKEN_URL = "https://real-debrid.com/apitoken";
|
const REAL_DEBRID_API_TOKEN_URL = "https://real-debrid.com/apitoken";
|
||||||
|
const TORBOX_API_TOKEN_URL = "https://torbox.app/settings";
|
||||||
|
|
||||||
export function SettingsRealDebrid() {
|
export function SettingsDebrid() {
|
||||||
const userPreferences = useAppSelector(
|
const userPreferences = useAppSelector(
|
||||||
(state) => state.userPreferences.value
|
(state) => state.userPreferences.value
|
||||||
);
|
);
|
||||||
@ -22,6 +23,8 @@ export function SettingsRealDebrid() {
|
|||||||
const [form, setForm] = useState({
|
const [form, setForm] = useState({
|
||||||
useRealDebrid: false,
|
useRealDebrid: false,
|
||||||
realDebridApiToken: null as string | null,
|
realDebridApiToken: null as string | null,
|
||||||
|
useTorBox: false,
|
||||||
|
torBoxApiToken: null as string | null,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { showSuccessToast, showErrorToast } = useToast();
|
const { showSuccessToast, showErrorToast } = useToast();
|
||||||
@ -33,6 +36,8 @@ export function SettingsRealDebrid() {
|
|||||||
setForm({
|
setForm({
|
||||||
useRealDebrid: Boolean(userPreferences.realDebridApiToken),
|
useRealDebrid: Boolean(userPreferences.realDebridApiToken),
|
||||||
realDebridApiToken: userPreferences.realDebridApiToken ?? null,
|
realDebridApiToken: userPreferences.realDebridApiToken ?? null,
|
||||||
|
useTorBox: Boolean(userPreferences.torBoxApiToken),
|
||||||
|
torBoxApiToken: userPreferences.torBoxApiToken ?? null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [userPreferences]);
|
}, [userPreferences]);
|
||||||
@ -102,6 +107,17 @@ export function SettingsRealDebrid() {
|
|||||||
}
|
}
|
||||||
placeholder="API Token"
|
placeholder="API Token"
|
||||||
containerProps={{ style: { marginTop: `${SPACING_UNIT}px` } }}
|
containerProps={{ style: { marginTop: `${SPACING_UNIT}px` } }}
|
||||||
|
rightContent={
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
style={{
|
||||||
|
alignSelf: "flex-end",
|
||||||
|
}}
|
||||||
|
disabled={isButtonDisabled}
|
||||||
|
>
|
||||||
|
{t("save")}
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
hint={
|
hint={
|
||||||
<Trans i18nKey="real_debrid_api_token_hint" ns="settings">
|
<Trans i18nKey="real_debrid_api_token_hint" ns="settings">
|
||||||
<Link to={REAL_DEBRID_API_TOKEN_URL} />
|
<Link to={REAL_DEBRID_API_TOKEN_URL} />
|
||||||
@ -110,13 +126,45 @@ export function SettingsRealDebrid() {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Button
|
<CheckboxField
|
||||||
type="submit"
|
label={t("enable_torbox")}
|
||||||
style={{ alignSelf: "flex-end", marginTop: `${SPACING_UNIT * 2}px` }}
|
checked={form.useTorBox}
|
||||||
disabled={isButtonDisabled}
|
onChange={() =>
|
||||||
>
|
setForm((prev) => ({
|
||||||
{t("save_changes")}
|
...prev,
|
||||||
</Button>
|
useTorBox: !form.useTorBox,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{form.useTorBox && (
|
||||||
|
<TextField
|
||||||
|
label={t("real_debrid_api_token")}
|
||||||
|
value={form.torBoxApiToken ?? ""}
|
||||||
|
type="password"
|
||||||
|
onChange={(event) =>
|
||||||
|
setForm({ ...form, torBoxApiToken: event.target.value })
|
||||||
|
}
|
||||||
|
placeholder="API Token"
|
||||||
|
containerProps={{ style: { marginTop: `${SPACING_UNIT}px` } }}
|
||||||
|
rightContent={
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
style={{
|
||||||
|
alignSelf: "flex-end",
|
||||||
|
}}
|
||||||
|
disabled={isButtonDisabled}
|
||||||
|
>
|
||||||
|
{t("save")}
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
hint={
|
||||||
|
<Trans i18nKey="real_debrid_api_token_hint" ns="settings">
|
||||||
|
<Link to={TORBOX_API_TOKEN_URL} />
|
||||||
|
</Trans>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
}
|
@ -2,7 +2,7 @@ import { Button } from "@renderer/components";
|
|||||||
|
|
||||||
import * as styles from "./settings.css";
|
import * as styles from "./settings.css";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { SettingsRealDebrid } from "./settings-real-debrid";
|
import { SettingsDebrid } from "./settings-debrid";
|
||||||
import { SettingsGeneral } from "./settings-general";
|
import { SettingsGeneral } from "./settings-general";
|
||||||
import { SettingsBehavior } from "./settings-behavior";
|
import { SettingsBehavior } from "./settings-behavior";
|
||||||
|
|
||||||
@ -25,7 +25,7 @@ export default function Settings() {
|
|||||||
t("general"),
|
t("general"),
|
||||||
t("behavior"),
|
t("behavior"),
|
||||||
t("download_sources"),
|
t("download_sources"),
|
||||||
"Real-Debrid",
|
t("debrid_services"),
|
||||||
];
|
];
|
||||||
|
|
||||||
if (userDetails) return [...categories, t("privacy")];
|
if (userDetails) return [...categories, t("privacy")];
|
||||||
@ -50,7 +50,7 @@ export default function Settings() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (currentCategoryIndex === 3) {
|
if (currentCategoryIndex === 3) {
|
||||||
return <SettingsRealDebrid />;
|
return <SettingsDebrid />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <SettingsPrivacy />;
|
return <SettingsPrivacy />;
|
||||||
|
@ -19,6 +19,8 @@ export type HydraCloudFeature =
|
|||||||
| "backup"
|
| "backup"
|
||||||
| "achievements-points";
|
| "achievements-points";
|
||||||
|
|
||||||
|
export type DebridServices = "RealDebrid" | "TorBox";
|
||||||
|
|
||||||
export interface GameRepack {
|
export interface GameRepack {
|
||||||
id: number;
|
id: number;
|
||||||
title: string;
|
title: string;
|
||||||
|
Loading…
Reference in New Issue
Block a user