mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-03-09 15:40:26 +00:00
feat: adding proper path for real debrid downloads
This commit is contained in:
commit
5ec56bda5b
16 changed files with 279 additions and 214 deletions
|
@ -66,7 +66,7 @@ export function Downloads() {
|
|||
};
|
||||
|
||||
const downloaderName = {
|
||||
[Downloader.Http]: t("real_debrid"),
|
||||
[Downloader.RealDebrid]: t("real_debrid"),
|
||||
[Downloader.Torrent]: t("torrent"),
|
||||
};
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { useEffect, useRef, useState } from "react";
|
||||
import { ShopDetails, SteamMovies, SteamScreenshot } from "@types";
|
||||
import { ChevronRightIcon, ChevronLeftIcon } from "@primer/octicons-react";
|
||||
import * as styles from "./game-details.css";
|
||||
import * as styles from "./gallery-slider.css";
|
||||
|
||||
export interface GallerySliderProps {
|
||||
gameDetails: ShopDetails | null;
|
||||
|
@ -22,6 +22,7 @@ export function GallerySlider({ gameDetails }: GallerySliderProps) {
|
|||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
const [mediaIndex, setMediaIndex] = useState<number>(0);
|
||||
const [arrowShow, setArrowShow] = useState(false);
|
||||
|
||||
|
@ -41,6 +42,10 @@ export function GallerySlider({ gameDetails }: GallerySliderProps) {
|
|||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setMediaIndex(0);
|
||||
}, [gameDetails]);
|
||||
|
||||
useEffect(() => {
|
||||
if (scrollContainerRef.current) {
|
||||
const container = scrollContainerRef.current;
|
||||
|
@ -49,10 +54,10 @@ export function GallerySlider({ gameDetails }: GallerySliderProps) {
|
|||
const scrollLeft = mediaIndex * itemWidth;
|
||||
container.scrollLeft = scrollLeft;
|
||||
}
|
||||
}, [mediaIndex, mediaCount]);
|
||||
}, [gameDetails, mediaIndex, mediaCount]);
|
||||
|
||||
const hasScreenshots = gameDetails && gameDetails.screenshots.length > 0;
|
||||
const hasMovies = gameDetails && gameDetails.movies.length > 0;
|
||||
const hasScreenshots = gameDetails && gameDetails.screenshots.length;
|
||||
const hasMovies = gameDetails && gameDetails.movies?.length;
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -72,6 +77,7 @@ export function GallerySlider({ gameDetails }: GallerySliderProps) {
|
|||
poster={video.thumbnail}
|
||||
style={{ translate: `${-100 * mediaIndex}%` }}
|
||||
autoPlay
|
||||
loop
|
||||
muted
|
||||
>
|
||||
<source src={video.webm.max.replace("http", "https")} />
|
||||
|
@ -112,7 +118,7 @@ export function GallerySlider({ gameDetails }: GallerySliderProps) {
|
|||
|
||||
<div className={styles.gallerySliderPreview} ref={scrollContainerRef}>
|
||||
{hasMovies &&
|
||||
gameDetails.movies.map((video: SteamMovies, i: number) => (
|
||||
gameDetails.movies?.map((video: SteamMovies, i: number) => (
|
||||
<img
|
||||
key={video.id}
|
||||
onClick={() => setMediaIndex(i)}
|
||||
|
|
|
@ -79,95 +79,6 @@ export const descriptionContent = style({
|
|||
height: "100%",
|
||||
});
|
||||
|
||||
export const gallerySliderContainer = style({
|
||||
padding: `${SPACING_UNIT * 3}px ${SPACING_UNIT * 2}px`,
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
});
|
||||
|
||||
export const gallerySliderMedia = style({
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
display: "block",
|
||||
flexShrink: 0,
|
||||
flexGrow: "0",
|
||||
transition: "translate 0.3s ease-in-out",
|
||||
borderRadius: "4px",
|
||||
});
|
||||
|
||||
export const gallerySliderAnimationContainer = style({
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
display: "flex",
|
||||
position: "relative",
|
||||
overflow: "hidden",
|
||||
"@media": {
|
||||
"(min-width: 1280px)": {
|
||||
width: "60%",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const gallerySliderPreview = style({
|
||||
width: "100%",
|
||||
paddingTop: "0.5rem",
|
||||
height: "100%",
|
||||
display: "flex",
|
||||
position: "relative",
|
||||
overflowX: "auto",
|
||||
overflowY: "hidden",
|
||||
"@media": {
|
||||
"(min-width: 1280px)": {
|
||||
width: "60%",
|
||||
},
|
||||
},
|
||||
"::-webkit-scrollbar-thumb": {
|
||||
width: "20%",
|
||||
},
|
||||
});
|
||||
|
||||
export const gallerySliderMediaPreview = style({
|
||||
cursor: "pointer",
|
||||
width: "20%",
|
||||
height: "20%",
|
||||
display: "block",
|
||||
flexShrink: 0,
|
||||
flexGrow: 0,
|
||||
opacity: 0.3,
|
||||
paddingRight: "5px",
|
||||
transition: "translate 300ms ease-in-out",
|
||||
borderRadius: "4px",
|
||||
":hover": {
|
||||
opacity: 1,
|
||||
},
|
||||
});
|
||||
|
||||
export const gallerySliderMediaPreviewActive = style({
|
||||
opacity: 1,
|
||||
});
|
||||
|
||||
export const gallerySliderButton = style({
|
||||
all: "unset",
|
||||
display: "block",
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
padding: "1rem",
|
||||
cursor: "pointer",
|
||||
transition: "background-color 100ms ease-in-out",
|
||||
":hover": {
|
||||
backgroundColor: "rgb(0, 0, 0, 0.2)",
|
||||
},
|
||||
});
|
||||
|
||||
export const gallerySliderIcons = style({
|
||||
fill: vars.color.muted,
|
||||
width: "2rem",
|
||||
height: "2rem",
|
||||
});
|
||||
|
||||
export const contentSidebar = style({
|
||||
borderLeft: `solid 1px ${vars.color.border};`,
|
||||
width: "100%",
|
||||
|
|
|
@ -257,6 +257,13 @@ export function GameDetails() {
|
|||
}}
|
||||
className={styles.description}
|
||||
/>
|
||||
|
||||
<small>
|
||||
All screenshots and movies displayed on this page are the
|
||||
property of Steam and/or their respective owners. We do not
|
||||
claim ownership of any content unless otherwise stated. All
|
||||
content is used for informational and promotional purposes only.
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div className={styles.contentSidebar}>
|
||||
|
|
|
@ -24,3 +24,8 @@ export const downloadsPathField = style({
|
|||
display: "flex",
|
||||
gap: `${SPACING_UNIT}px`,
|
||||
});
|
||||
|
||||
export const settingsCategories = style({
|
||||
display: "flex",
|
||||
gap: `${SPACING_UNIT}px`,
|
||||
});
|
||||
|
|
|
@ -5,7 +5,11 @@ import * as styles from "./settings.css";
|
|||
import { useTranslation } from "react-i18next";
|
||||
import { UserPreferences } from "@types";
|
||||
|
||||
const categories = ["general", "behavior", "real_debrid"];
|
||||
|
||||
export function Settings() {
|
||||
const [currentCategory, setCurrentCategory] = useState(categories.at(0)!);
|
||||
|
||||
const [form, setForm] = useState({
|
||||
downloadsPath: "",
|
||||
downloadNotificationsEnabled: false,
|
||||
|
@ -61,62 +65,80 @@ export function Settings() {
|
|||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<section className={styles.container}>
|
||||
<div className={styles.content}>
|
||||
<div className={styles.downloadsPathField}>
|
||||
<TextField
|
||||
label={t("downloads_path")}
|
||||
value={form.downloadsPath}
|
||||
readOnly
|
||||
disabled
|
||||
const renderCategory = () => {
|
||||
if (currentCategory === "general") {
|
||||
return (
|
||||
<>
|
||||
<div className={styles.downloadsPathField}>
|
||||
<TextField
|
||||
label={t("downloads_path")}
|
||||
value={form.downloadsPath}
|
||||
readOnly
|
||||
disabled
|
||||
/>
|
||||
|
||||
<Button
|
||||
style={{ alignSelf: "flex-end" }}
|
||||
theme="outline"
|
||||
onClick={handleChooseDownloadsPath}
|
||||
>
|
||||
{t("change")}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<h3>{t("notifications")}</h3>
|
||||
|
||||
<CheckboxField
|
||||
label={t("enable_download_notifications")}
|
||||
checked={form.downloadNotificationsEnabled}
|
||||
onChange={() =>
|
||||
updateUserPreferences(
|
||||
"downloadNotificationsEnabled",
|
||||
!form.downloadNotificationsEnabled
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
||||
<Button
|
||||
style={{ alignSelf: "flex-end" }}
|
||||
theme="outline"
|
||||
onClick={handleChooseDownloadsPath}
|
||||
>
|
||||
{t("change")}
|
||||
</Button>
|
||||
</div>
|
||||
<CheckboxField
|
||||
label={t("enable_repack_list_notifications")}
|
||||
checked={form.repackUpdatesNotificationsEnabled}
|
||||
onChange={() =>
|
||||
updateUserPreferences(
|
||||
"repackUpdatesNotificationsEnabled",
|
||||
!form.repackUpdatesNotificationsEnabled
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
||||
<h3>{t("notifications")}</h3>
|
||||
<h3>{t("telemetry")}</h3>
|
||||
|
||||
<CheckboxField
|
||||
label={t("enable_download_notifications")}
|
||||
checked={form.downloadNotificationsEnabled}
|
||||
onChange={() =>
|
||||
updateUserPreferences(
|
||||
"downloadNotificationsEnabled",
|
||||
!form.downloadNotificationsEnabled
|
||||
)
|
||||
}
|
||||
<CheckboxField
|
||||
label={t("telemetry_description")}
|
||||
checked={form.telemetryEnabled}
|
||||
onChange={() =>
|
||||
updateUserPreferences("telemetryEnabled", !form.telemetryEnabled)
|
||||
}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
if (currentCategory === "real_debrid") {
|
||||
return (
|
||||
<TextField
|
||||
label={t("real_debrid_api_token_description")}
|
||||
value={form.realDebridApiToken ?? ""}
|
||||
type="password"
|
||||
onChange={(event) => {
|
||||
updateUserPreferences("realDebridApiToken", event.target.value);
|
||||
}}
|
||||
placeholder="API Token"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
<CheckboxField
|
||||
label={t("enable_repack_list_notifications")}
|
||||
checked={form.repackUpdatesNotificationsEnabled}
|
||||
onChange={() =>
|
||||
updateUserPreferences(
|
||||
"repackUpdatesNotificationsEnabled",
|
||||
!form.repackUpdatesNotificationsEnabled
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
||||
<h3>{t("telemetry")}</h3>
|
||||
|
||||
<CheckboxField
|
||||
label={t("telemetry_description")}
|
||||
checked={form.telemetryEnabled}
|
||||
onChange={() =>
|
||||
updateUserPreferences("telemetryEnabled", !form.telemetryEnabled)
|
||||
}
|
||||
/>
|
||||
|
||||
<h3>{t("behavior")}</h3>
|
||||
|
||||
return (
|
||||
<>
|
||||
<CheckboxField
|
||||
label={t("quit_app_instead_hiding")}
|
||||
checked={form.preferQuitInsteadOfHiding}
|
||||
|
@ -128,15 +150,6 @@ export function Settings() {
|
|||
}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
label={t("real_debrid_api_token_description")}
|
||||
value={form.realDebridApiToken ?? ""}
|
||||
type="password"
|
||||
onChange={(event) => {
|
||||
updateUserPreferences("realDebridApiToken", event.target.value);
|
||||
}}
|
||||
/>
|
||||
|
||||
<CheckboxField
|
||||
label={t("launch_with_system")}
|
||||
onChange={() => {
|
||||
|
@ -145,6 +158,27 @@ export function Settings() {
|
|||
}}
|
||||
checked={form.runAtStartup}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<section className={styles.container}>
|
||||
<div className={styles.content}>
|
||||
<section className={styles.settingsCategories}>
|
||||
{categories.map((category) => (
|
||||
<Button
|
||||
key={category}
|
||||
theme={currentCategory === category ? "primary" : "outline"}
|
||||
onClick={() => setCurrentCategory(category)}
|
||||
>
|
||||
{t(category)}
|
||||
</Button>
|
||||
))}
|
||||
</section>
|
||||
|
||||
<h3>{t(currentCategory)}</h3>
|
||||
{renderCategory()}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue