/* * 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 . */ import { Page, QueryIdentifier, useFetch, KyooErrors } from "@kyoo/models"; import { Breakpoint, P } from "@kyoo/primitives"; import { ComponentType, ReactElement, isValidElement } from "react"; import { useTranslation } from "react-i18next"; import { View } from "react-native"; import { useYoshiki } from "yoshiki/native"; export type Layout = { numColumns: Breakpoint; size: Breakpoint; gap: Breakpoint; layout: "grid" | "horizontal" | "vertical"; }; export type WithLoading = | (Item & { isLoading: false }) | (Partial & { isLoading: true }); const isPage = (obj: unknown): obj is Page => (typeof obj === "object" && obj && "items" in obj) || false; export const Fetch = ({ query, placeholderCount = 1, children, }: { query: QueryIdentifier; placeholderCount?: number; children: ( item: Data extends Page ? WithLoading : WithLoading, i: number, ) => JSX.Element | null; }): JSX.Element | null => { const { data, isPaused, error } = useFetch(query); if (error) return ; if (isPaused) return ; if (!data) { const placeholders = [...Array(placeholderCount)].map((_, i) => children({ isLoading: true } as any, i), ); return <>{placeholderCount === 1 ? placeholders[0] : placeholders}; } if (!isPage(data)) return children(data ? { ...data, isLoading: false } : ({ isLoading: true } as any), 0); return <>{data.items.map((item, i) => children({ ...item, isLoading: false } as any, i))}; }; export const OfflineView = () => { const { css } = useYoshiki(); const { t } = useTranslation(); return (

theme.colors.white })}>{t("errors.offline")}

); }; export const ErrorView = ({ error }: { error: KyooErrors }) => { const { css } = useYoshiki(); return ( theme.colors.red, flexGrow: 1, flexShrink: 1, justifyContent: "center", alignItems: "center", })} > {error.errors.map((x, i) => (

theme.colors.white })}> {x}

))}
); }; export const EmptyView = ({ message }: { message: string }) => { const { css } = useYoshiki(); return (

theme.heading })}>{message}

); }; export const addHeader = ( Header: ComponentType<{ children: JSX.Element } & Props> | ReactElement | undefined, children: ReactElement, headerProps?: Props, ) => { if (!Header) return children; return !isValidElement(Header) ? ( // @ts-ignore
{children}
) : ( <> {Header} {children} ); };