mirror of
https://github.com/BrenBroZAYT/gameyfin.git
synced 2026-06-13 16:40:01 +00:00
Add download button to GameView
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
import {useEffect, useState} from "react";
|
||||
import {
|
||||
Button,
|
||||
ButtonGroup,
|
||||
Dropdown,
|
||||
DropdownItem,
|
||||
DropdownMenu,
|
||||
DropdownTrigger,
|
||||
SharedSelection
|
||||
} from "@heroui/react";
|
||||
import {CaretDown} from "@phosphor-icons/react";
|
||||
import {UserPreferenceService} from "Frontend/util/user-preference-service";
|
||||
|
||||
export interface ComboButtonOption {
|
||||
label: string;
|
||||
description: string;
|
||||
action: () => void;
|
||||
isDisabled?: boolean;
|
||||
}
|
||||
|
||||
export interface ComboButtonProps {
|
||||
options: Record<string, ComboButtonOption>;
|
||||
preferredOptionKey?: string;
|
||||
}
|
||||
|
||||
export default function ComboButton({options, preferredOptionKey}: ComboButtonProps) {
|
||||
const [selectedOption, setSelectedOption] = useState(new Set([Object.keys(options)[0]]));
|
||||
const [disabledOptions] = useState<string[]>(getDisabledKeys(options));
|
||||
const selectedOptionValue = Array.from(selectedOption)[0];
|
||||
|
||||
useEffect(() => {
|
||||
if (!preferredOptionKey) return;
|
||||
|
||||
UserPreferenceService.get(preferredOptionKey).then((key) => {
|
||||
if (key && options[key]) {
|
||||
setSelectedOption(new Set([key]));
|
||||
} else {
|
||||
setSelectedOption(new Set([Object.keys(options)[0]]));
|
||||
}
|
||||
})
|
||||
}, []);
|
||||
|
||||
async function onSelectionChange(keys: SharedSelection) {
|
||||
if (!keys.currentKey) return;
|
||||
|
||||
if (preferredOptionKey) {
|
||||
await UserPreferenceService.set(preferredOptionKey, keys.currentKey);
|
||||
}
|
||||
|
||||
setSelectedOption(new Set([keys.currentKey]));
|
||||
}
|
||||
|
||||
function getDisabledKeys(options: Record<string, ComboButtonOption>): string[] {
|
||||
return Object.keys(options).filter(key => options[key].isDisabled);
|
||||
}
|
||||
|
||||
return (
|
||||
<ButtonGroup className="gap-[1px]">
|
||||
<Button color="primary" className="font-semibold w-52"
|
||||
onPress={options[selectedOptionValue].action}>{options[selectedOptionValue].label}
|
||||
</Button>
|
||||
<Dropdown placement="bottom-end">
|
||||
<DropdownTrigger>
|
||||
<Button isIconOnly color="primary">
|
||||
<CaretDown/>
|
||||
</Button>
|
||||
</DropdownTrigger>
|
||||
<DropdownMenu
|
||||
disallowEmptySelection
|
||||
aria-label="Merge options"
|
||||
selectedKeys={selectedOption}
|
||||
disabledKeys={disabledOptions}
|
||||
selectionMode="single"
|
||||
/*@ts-ignore*/
|
||||
onSelectionChange={onSelectionChange}
|
||||
className="w-60"
|
||||
>
|
||||
{Object.entries(options).map(([key, option]) => (
|
||||
<DropdownItem key={key} description={option.description}>
|
||||
{option.label}
|
||||
</DropdownItem>
|
||||
))}
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
</ButtonGroup>
|
||||
);
|
||||
}
|
||||
@@ -3,11 +3,31 @@ import GameDto from "Frontend/generated/de/grimsi/gameyfin/games/dto/GameDto";
|
||||
import {GameEndpoint} from "Frontend/generated/endpoints";
|
||||
import {useParams} from "react-router";
|
||||
import {GameCover} from "Frontend/components/general/covers/GameCover";
|
||||
import ComboButton, {ComboButtonOption} from "Frontend/components/general/input/ComboButton";
|
||||
|
||||
export default function GameView() {
|
||||
const {gameId} = useParams();
|
||||
|
||||
const [game, setGame] = useState<GameDto>();
|
||||
const [selectedDownloadOption, setSelectedDownloadOption] = useState<string | null>(null);
|
||||
|
||||
const downloadOptions: Record<string, ComboButtonOption> = {
|
||||
browser: {
|
||||
label: "Direct Download",
|
||||
description: "Download the game in this browser",
|
||||
action: () => {
|
||||
alert("Direct download not yet implemented")
|
||||
}
|
||||
},
|
||||
torrent: {
|
||||
label: "Torrent Download",
|
||||
description: "Download the game as a torrent",
|
||||
action: () => {
|
||||
alert("Torrent download not yet implemented")
|
||||
},
|
||||
isDisabled: true
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (gameId) {
|
||||
@@ -24,14 +44,17 @@ export default function GameView() {
|
||||
</div>
|
||||
}
|
||||
<div className="flex flex-col gap-4 mx-24">
|
||||
<div className="flex flex-row gap-4">
|
||||
<div className="mt-[-16.25rem]">
|
||||
<GameCover game={game} size={320} radius="none"/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<p className="font-semibold text-3xl">{game.title}</p>
|
||||
<p className="text-foreground/60">{game.release !== undefined ? new Date(game.release).getFullYear() : "unknown"}</p>
|
||||
<div className="flex flex-row justify-between">
|
||||
<div className="flex flex-row gap-4">
|
||||
<div className="mt-[-16.25rem]">
|
||||
<GameCover game={game} size={320} radius="none"/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<p className="font-semibold text-3xl">{game.title}</p>
|
||||
<p className="text-foreground/60">{game.release !== undefined ? new Date(game.release).getFullYear() : "unknown"}</p>
|
||||
</div>
|
||||
</div>
|
||||
<ComboButton options={downloadOptions} preferredOptionKey="preferred-download-method"/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<p className="text-foreground/60">Summary</p>
|
||||
|
||||
Reference in New Issue
Block a user