Fix download button errors

This commit is contained in:
Zoe Roux 2023-12-18 13:54:12 +01:00
parent fb04daff9f
commit 7b035411c0
4 changed files with 68 additions and 29 deletions

View File

@ -27,21 +27,27 @@ import Download from "@material-symbols/svg-400/rounded/download.svg";
import { WatchStatusV, queryFn, useAccount } from "@kyoo/models"; import { WatchStatusV, queryFn, useAccount } from "@kyoo/models";
import { useMutation, useQueryClient } from "@tanstack/react-query"; import { useMutation, useQueryClient } from "@tanstack/react-query";
import { watchListIcon } from "./watchlist-info"; import { watchListIcon } from "./watchlist-info";
import { downloadFile } from "../downloads/state"; import { useDownloader } from "../downloads/state";
import { Platform } from "react-native";
import { useYoshiki } from "yoshiki/native";
export const EpisodesContext = ({ export const EpisodesContext = ({
type = "episode", type = "episode",
slug, slug,
showSlug, showSlug,
status, status,
force,
...props ...props
}: { }: {
type?: "show" | "movie" | "episode"; type?: "show" | "movie" | "episode";
showSlug?: string | null; showSlug?: string | null;
slug: string; slug: string;
status: WatchStatusV | null; status: WatchStatusV | null;
force?: boolean;
} & Partial<ComponentProps<typeof Menu<typeof IconButton>>>) => { } & Partial<ComponentProps<typeof Menu<typeof IconButton>>>) => {
const account = useAccount(); const account = useAccount();
const downloader = useDownloader();
const { css } = useYoshiki();
const { t } = useTranslation(); const { t } = useTranslation();
const queryClient = useQueryClient(); const queryClient = useQueryClient();
@ -55,7 +61,12 @@ export const EpisodesContext = ({
}); });
return ( return (
<Menu Trigger={IconButton} icon={MoreVert} {...tooltip(t("misc.more"))} {...(props as any)}> <Menu
Trigger={IconButton}
icon={MoreVert}
{...tooltip(t("misc.more"))}
{...(css([Platform.OS !== "web" && !force && { display: "none" }], props) as any)}
>
{showSlug && ( {showSlug && (
<Menu.Item label={t("home.episodeMore.goToShow")} icon={Info} href={`/show/${showSlug}`} /> <Menu.Item label={t("home.episodeMore.goToShow")} icon={Info} href={`/show/${showSlug}`} />
)} )}
@ -80,7 +91,7 @@ export const EpisodesContext = ({
<Menu.Item <Menu.Item
label={t("home.episodeMore.download")} label={t("home.episodeMore.download")}
icon={Download} icon={Download}
onSelect={() => downloadFile(type, slug)} onSelect={() => downloader(type, slug)}
/> />
)} )}
</Menu> </Menu>
@ -91,11 +102,22 @@ export const ItemContext = ({
type, type,
slug, slug,
status, status,
force,
...props ...props
}: { }: {
type: "movie" | "show"; type: "movie" | "show";
slug: string; slug: string;
status: WatchStatusV | null; status: WatchStatusV | null;
force?: boolean;
} & Partial<ComponentProps<typeof Menu<typeof IconButton>>>) => { } & Partial<ComponentProps<typeof Menu<typeof IconButton>>>) => {
return <EpisodesContext type={type} slug={slug} status={status} showSlug={null} {...props} />; return (
<EpisodesContext
type={type}
slug={slug}
status={status}
showSlug={null}
force={force}
{...props}
/>
);
}; };

View File

@ -22,6 +22,7 @@ import { useAtomValue } from "jotai";
import { downloadAtom } from "./state"; import { downloadAtom } from "./state";
import { FlashList } from "@shopify/flash-list"; import { FlashList } from "@shopify/flash-list";
import { View } from "react-native"; import { View } from "react-native";
import { P } from "@kyoo/primitives";
export const DownloadPage = () => { export const DownloadPage = () => {
const downloads = useAtomValue(downloadAtom); const downloads = useAtomValue(downloadAtom);
@ -29,9 +30,7 @@ export const DownloadPage = () => {
return ( return (
<FlashList <FlashList
data={downloads} data={downloads}
renderItem={({ item }) => { renderItem={({ item }) => <P>{item.data.name}</P>}
<View>{item.data.name}</View>;
}}
keyExtractor={(x) => x.data.id} keyExtractor={(x) => x.data.id}
numColumns={1} numColumns={1}
/> />

View File

@ -35,6 +35,7 @@ import { Player } from "../player";
import { atom, useSetAtom, PrimitiveAtom, useStore } from "jotai"; import { atom, useSetAtom, PrimitiveAtom, useStore } from "jotai";
import { getCurrentAccount, storage } from "@kyoo/models/src/account-internal"; import { getCurrentAccount, storage } from "@kyoo/models/src/account-internal";
import { ReactNode, useEffect } from "react"; import { ReactNode, useEffect } from "react";
import { Platform, ToastAndroid } from "react-native";
type State = { type State = {
status: "DOWNLOADING" | "PAUSED" | "DONE" | "FAILED" | "STOPPED"; status: "DOWNLOADING" | "PAUSED" | "DONE" | "FAILED" | "STOPPED";
@ -111,9 +112,13 @@ const setupDownloadTask = (
update((x) => ({ ...x, percent: 100, status: "DONE" })); update((x) => ({ ...x, percent: 100, status: "DONE" }));
// apparently this is needed for ios /shrug i'm totaly gona forget this // apparently this is needed for ios /shrug i'm totaly gona forget this
// if i ever implement ios so keeping this here // if i ever implement ios so keeping this here
RNBackgroundDownloader.completeHandler(task.id); if (Platform.OS === "ios") RNBackgroundDownloader.completeHandler(task.id);
}) })
.error((error) => update((x) => ({ ...x, status: "FAILED", error }))); .error((error) => {
update((x) => ({ ...x, status: "FAILED", error }));
console.error(`Error downloading ${state.data.slug}`, error);
ToastAndroid.show(`Error downloading ${state.data.slug}`, ToastAndroid.LONG);
});
return { data: state.data, info: state.info, path: state.path, state: stateAtom }; return { data: state.data, info: state.info, path: state.path, state: stateAtom };
}; };
@ -146,6 +151,7 @@ export const useDownloader = () => {
const store = useStore(); const store = useStore();
return async (type: "episode" | "movie", slug: string) => { return async (type: "episode" | "movie", slug: string) => {
try {
const account = getCurrentAccount()!; const account = getCurrentAccount()!;
const [data, info] = await Promise.all([ const [data, info] = await Promise.all([
query(Player.query(type, slug), account), query(Player.query(type, slug), account),
@ -157,7 +163,7 @@ export const useDownloader = () => {
const task = RNBackgroundDownloader.download({ const task = RNBackgroundDownloader.download({
id: data.id, id: data.id,
// TODO: support variant qualities // TODO: support variant qualities
url: `${account.apiUrl}/api/video/${type}/${slug}/direct`, url: `${account.apiUrl}/video/${type}/${slug}/direct`,
destination: path, destination: path,
headers: { headers: {
Authorization: account.token.access_token, Authorization: account.token.access_token,
@ -165,8 +171,13 @@ export const useDownloader = () => {
// TODO: Implement only wifi // TODO: Implement only wifi
// network: Network.ALL, // network: Network.ALL,
}); });
console.log("Starting download", path);
setDownloads((x) => [...x, setupDownloadTask({ data, info, path }, task, store)]); setDownloads((x) => [...x, setupDownloadTask({ data, info, path }, task, store)]);
} catch (e) {
console.error("download error", e);
ToastAndroid.show(`Error downloading ${slug}`, ToastAndroid.LONG);
}
}; };
}; };

View File

@ -157,7 +157,13 @@ export const ItemDetails = ({
<View <View
{...css({ flexShrink: 1, flexGrow: 1, justifyContent: "flex-end", marginBottom: px(50) })} {...css({ flexShrink: 1, flexGrow: 1, justifyContent: "flex-end", marginBottom: px(50) })}
> >
<View {...css({ flexDirection: "row-reverse", justifyContent: "space-between" })}> <View
{...css({
flexDirection: "row-reverse",
justifyContent: "space-between",
alignContent: "flex-start",
})}
>
{slug && type && type !== "collection" && watchStatus !== undefined && ( {slug && type && type !== "collection" && watchStatus !== undefined && (
<ItemContext <ItemContext
type={type} type={type}
@ -165,6 +171,7 @@ export const ItemDetails = ({
status={watchStatus} status={watchStatus}
isOpen={moreOpened} isOpen={moreOpened}
setOpen={(v) => setMoreOpened(v)} setOpen={(v) => setMoreOpened(v)}
force
/> />
)} )}
{(isLoading || tagline) && ( {(isLoading || tagline) && (