mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-31 20:24:27 -04:00
Add a downloads tab
This commit is contained in:
parent
f1cc396bfc
commit
71d29a303f
@ -22,6 +22,7 @@ import { Icon } from "@kyoo/primitives";
|
|||||||
import { Tabs } from "expo-router";
|
import { Tabs } from "expo-router";
|
||||||
import Home from "@material-symbols/svg-400/rounded/home-fill.svg";
|
import Home from "@material-symbols/svg-400/rounded/home-fill.svg";
|
||||||
import Browse from "@material-symbols/svg-400/rounded/browse-fill.svg";
|
import Browse from "@material-symbols/svg-400/rounded/browse-fill.svg";
|
||||||
|
import Downloading from "@material-symbols/svg-400/rounded/downloading-fill.svg";
|
||||||
|
|
||||||
export default function TabsLayout() {
|
export default function TabsLayout() {
|
||||||
return (
|
return (
|
||||||
@ -44,6 +45,13 @@ export default function TabsLayout() {
|
|||||||
tabBarIcon: ({ color, size }) => <Icon icon={Browse} color={color} size={size} />,
|
tabBarIcon: ({ color, size }) => <Icon icon={Browse} color={color} size={size} />,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
<Tabs.Screen
|
||||||
|
name="downloads"
|
||||||
|
options={{
|
||||||
|
tabBarLabel: "Downloads",
|
||||||
|
tabBarIcon: ({ color, size }) => <Icon icon={Downloading} color={color} size={size} />,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
23
front/apps/mobile/app/(app)/(tabs)/downloads.tsx
Normal file
23
front/apps/mobile/app/(app)/(tabs)/downloads.tsx
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Kyoo - A portable and vast media library solution.
|
||||||
|
* Copyright (c) Kyoo.
|
||||||
|
*
|
||||||
|
* See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||||
|
*
|
||||||
|
* Kyoo is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* Kyoo is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { DownloadPage } from "@kyoo/ui";
|
||||||
|
|
||||||
|
export default DownloadPage;
|
@ -48,6 +48,7 @@ import "@formatjs/intl-displaynames/locale-data/fr";
|
|||||||
import en from "../../../translations/en.json";
|
import en from "../../../translations/en.json";
|
||||||
import fr from "../../../translations/fr.json";
|
import fr from "../../../translations/fr.json";
|
||||||
import { useTheme } from "yoshiki/native";
|
import { useTheme } from "yoshiki/native";
|
||||||
|
import { DownloadProvider } from "@kyoo/ui";
|
||||||
|
|
||||||
i18next.use(initReactI18next).init({
|
i18next.use(initReactI18next).init({
|
||||||
interpolation: {
|
interpolation: {
|
||||||
@ -103,9 +104,11 @@ export default function Root() {
|
|||||||
>
|
>
|
||||||
<PortalProvider>
|
<PortalProvider>
|
||||||
<AccountProvider>
|
<AccountProvider>
|
||||||
<NavigationThemeProvider>
|
<DownloadProvider>
|
||||||
<Slot />
|
<NavigationThemeProvider>
|
||||||
</NavigationThemeProvider>
|
<Slot />
|
||||||
|
</NavigationThemeProvider>
|
||||||
|
</DownloadProvider>
|
||||||
</AccountProvider>
|
</AccountProvider>
|
||||||
</PortalProvider>
|
</PortalProvider>
|
||||||
</ThemeSelector>
|
</ThemeSelector>
|
||||||
|
@ -52,6 +52,7 @@ const styleText = (
|
|||||||
{
|
{
|
||||||
marginVertical: rem(0.5),
|
marginVertical: rem(0.5),
|
||||||
color: type === "header" ? theme.heading : theme.paragraph,
|
color: type === "header" ? theme.heading : theme.paragraph,
|
||||||
|
flexShrink: 1,
|
||||||
fontSize: rem(1),
|
fontSize: rem(1),
|
||||||
fontFamily: theme.font.normal,
|
fontFamily: theme.font.normal,
|
||||||
},
|
},
|
||||||
|
@ -27,7 +27,7 @@ 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/download";
|
import { downloadFile } from "../downloads/state";
|
||||||
|
|
||||||
export const EpisodesContext = ({
|
export const EpisodesContext = ({
|
||||||
type = "episode",
|
type = "episode",
|
||||||
|
22
front/packages/ui/src/downloads/index.tsx
Normal file
22
front/packages/ui/src/downloads/index.tsx
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Kyoo - A portable and vast media library solution.
|
||||||
|
* Copyright (c) Kyoo.
|
||||||
|
*
|
||||||
|
* See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||||
|
*
|
||||||
|
* Kyoo is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* Kyoo is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export { DownloadPage } from "./page";
|
||||||
|
export { DownloadProvider } from "./state";
|
39
front/packages/ui/src/downloads/page.tsx
Normal file
39
front/packages/ui/src/downloads/page.tsx
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Kyoo - A portable and vast media library solution.
|
||||||
|
* Copyright (c) Kyoo.
|
||||||
|
*
|
||||||
|
* See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||||
|
*
|
||||||
|
* Kyoo is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* Kyoo is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { useAtomValue } from "jotai";
|
||||||
|
import { downloadAtom } from "./state";
|
||||||
|
import { FlashList } from "@shopify/flash-list";
|
||||||
|
import { View } from "react-native";
|
||||||
|
|
||||||
|
export const DownloadPage = () => {
|
||||||
|
const downloads = useAtomValue(downloadAtom);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FlashList
|
||||||
|
data={downloads}
|
||||||
|
renderItem={({ item }) => {
|
||||||
|
<View>{item.data.name}</View>;
|
||||||
|
}}
|
||||||
|
keyExtractor={(x) => x.data.id}
|
||||||
|
numColumns={1}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
@ -18,13 +18,8 @@
|
|||||||
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import RNBackgroundDownloader, {
|
||||||
download,
|
type DownloadTask,
|
||||||
completeHandler,
|
|
||||||
directories,
|
|
||||||
DownloadTask,
|
|
||||||
checkForExistingDownloads,
|
|
||||||
ensureDownloadsAreRunning,
|
|
||||||
} from "@kesha-antonov/react-native-background-downloader";
|
} from "@kesha-antonov/react-native-background-downloader";
|
||||||
import { deleteAsync } from "expo-file-system";
|
import { deleteAsync } from "expo-file-system";
|
||||||
import {
|
import {
|
||||||
@ -39,7 +34,7 @@ import {
|
|||||||
import { Player } from "../player";
|
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 { useEffect } from "react";
|
import { ReactNode, useEffect } from "react";
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
status: "DOWNLOADING" | "PAUSED" | "DONE" | "FAILED" | "STOPPED";
|
status: "DOWNLOADING" | "PAUSED" | "DONE" | "FAILED" | "STOPPED";
|
||||||
@ -53,7 +48,7 @@ type State = {
|
|||||||
play: () => void;
|
play: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const downloadAtom = atom<
|
export const downloadAtom = atom<
|
||||||
{
|
{
|
||||||
data: Episode | Movie;
|
data: Episode | Movie;
|
||||||
info: WatchInfo;
|
info: WatchInfo;
|
||||||
@ -116,7 +111,7 @@ 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
|
||||||
completeHandler(task.id);
|
RNBackgroundDownloader.completeHandler(task.id);
|
||||||
})
|
})
|
||||||
.error((error) => update((x) => ({ ...x, status: "FAILED", error })));
|
.error((error) => update((x) => ({ ...x, status: "FAILED", error })));
|
||||||
|
|
||||||
@ -158,8 +153,8 @@ export const useDownloader = () => {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
// TODO: support custom paths
|
// TODO: support custom paths
|
||||||
const path = `${directories.documents}/${slug}-${data.id}.${info.extension}`;
|
const path = `${RNBackgroundDownloader.directories.documents}/${slug}-${data.id}.${info.extension}`;
|
||||||
const task = 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}/api/video/${type}/${slug}/direct`,
|
||||||
@ -175,14 +170,14 @@ export const useDownloader = () => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DownloadProvider = () => {
|
export const DownloadProvider = ({ children }: { children: ReactNode }) => {
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function run() {
|
async function run() {
|
||||||
if (store.get(downloadAtom).length) return;
|
if (store.get(downloadAtom).length) return;
|
||||||
|
|
||||||
const tasks = await checkForExistingDownloads();
|
const tasks = await RNBackgroundDownloader.checkForExistingDownloads();
|
||||||
const dls: { data: Episode | Movie; info: WatchInfo; path: string; state: State }[] =
|
const dls: { data: Episode | Movie; info: WatchInfo; path: string; state: State }[] =
|
||||||
JSON.parse(storage.getString("downloads") ?? "[]");
|
JSON.parse(storage.getString("downloads") ?? "[]");
|
||||||
const downloads = dls.map((dl) => {
|
const downloads = dls.map((dl) => {
|
||||||
@ -214,8 +209,10 @@ export const DownloadProvider = () => {
|
|||||||
for (const t of tasks) {
|
for (const t of tasks) {
|
||||||
if (!downloads.find((x) => x.data.id === t.id)) t.stop();
|
if (!downloads.find((x) => x.data.id === t.id)) t.stop();
|
||||||
}
|
}
|
||||||
ensureDownloadsAreRunning();
|
RNBackgroundDownloader.ensureDownloadsAreRunning();
|
||||||
}
|
}
|
||||||
run();
|
run();
|
||||||
}, [store]);
|
}, [store]);
|
||||||
|
|
||||||
|
return children;
|
||||||
};
|
};
|
@ -26,3 +26,4 @@ export { CollectionPage } from "./collection";
|
|||||||
export { Player } from "./player";
|
export { Player } from "./player";
|
||||||
export { SearchPage } from "./search";
|
export { SearchPage } from "./search";
|
||||||
export { LoginPage, RegisterPage } from "./login";
|
export { LoginPage, RegisterPage } from "./login";
|
||||||
|
export { DownloadPage, DownloadProvider } from "./downloads";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user