mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-09 03:04:20 -04:00
Create a usePopup to simplify popup creation
This commit is contained in:
parent
d9f4a6ff8d
commit
53ac4a2050
@ -18,10 +18,10 @@
|
||||
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { ReactNode } from "react";
|
||||
import { ReactElement, ReactNode, useCallback, useEffect, useState } from "react";
|
||||
import { Container } from "./container";
|
||||
import { Portal } from "@gorhom/portal";
|
||||
import { SwitchVariant, YoshikiFunc } from "./themes";
|
||||
import { Portal, usePortal } from "@gorhom/portal";
|
||||
import { ContrastArea, SwitchVariant, YoshikiFunc } from "./themes";
|
||||
import { View } from "react-native";
|
||||
import { imageBorderRadius } from "./constants";
|
||||
import { px } from "yoshiki/native";
|
||||
@ -29,7 +29,7 @@ import { ts } from "./utils";
|
||||
|
||||
export const Popup = ({ children, ...props }: { children: ReactNode | YoshikiFunc<ReactNode> }) => {
|
||||
return (
|
||||
<Portal>
|
||||
<ContrastArea mode="user">
|
||||
<SwitchVariant>
|
||||
{({ css, theme }) => (
|
||||
<View
|
||||
@ -60,6 +60,19 @@ export const Popup = ({ children, ...props }: { children: ReactNode | YoshikiFun
|
||||
</View>
|
||||
)}
|
||||
</SwitchVariant>
|
||||
</Portal>
|
||||
</ContrastArea>
|
||||
);
|
||||
};
|
||||
|
||||
export const usePopup = () => {
|
||||
const { addPortal, removePortal } = usePortal();
|
||||
const [current, setPopup] = useState<ReactNode>();
|
||||
const close = useCallback(() => setPopup(undefined), []);
|
||||
|
||||
useEffect(() => {
|
||||
addPortal("popup", current);
|
||||
return () => removePortal("popup");
|
||||
}, [current, addPortal, removePortal]);
|
||||
|
||||
return [setPopup, close];
|
||||
};
|
||||
|
@ -18,7 +18,7 @@
|
||||
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { IconButton, Menu, tooltip } from "@kyoo/primitives";
|
||||
import { IconButton, Menu, tooltip, usePopup } from "@kyoo/primitives";
|
||||
import { ComponentProps, ReactElement, useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import MoreVert from "@material-symbols/svg-400/rounded/more_vert.svg";
|
||||
@ -51,7 +51,7 @@ export const EpisodesContext = ({
|
||||
const downloader = useDownloader();
|
||||
const { css } = useYoshiki();
|
||||
const { t } = useTranslation();
|
||||
const [popup, setPopup] = useState<ReactElement | undefined>(undefined);
|
||||
const [setPopup, close] = usePopup();
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
const mutation = useMutation({
|
||||
@ -109,19 +109,12 @@ export const EpisodesContext = ({
|
||||
label={t("home.episodeMore.mediainfo")}
|
||||
icon={MovieInfo}
|
||||
onSelect={() =>
|
||||
setPopup(
|
||||
<MediaInfoPopup
|
||||
mediaType={type}
|
||||
mediaSlug={slug}
|
||||
close={() => setPopup(undefined)}
|
||||
/>,
|
||||
)
|
||||
setPopup(<MediaInfoPopup mediaType={type} mediaSlug={slug} close={close} />)
|
||||
}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</Menu>
|
||||
{popup}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -47,9 +47,9 @@ import {
|
||||
ts,
|
||||
Chip,
|
||||
DottedSeparator,
|
||||
focusReset,
|
||||
usePopup,
|
||||
} from "@kyoo/primitives";
|
||||
import { Fragment, ReactElement, useState } from "react";
|
||||
import { Fragment } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import MovieInfo from "@material-symbols/svg-400/rounded/movie_info.svg";
|
||||
import { ImageStyle, Platform, View } from "react-native";
|
||||
@ -112,7 +112,7 @@ export const TitleLine = ({
|
||||
const { css, theme } = useYoshiki();
|
||||
const { t } = useTranslation();
|
||||
const downloader = useDownloader();
|
||||
const [popup, setPopup] = useState<ReactElement | undefined>(undefined);
|
||||
const [setPopup, close] = usePopup();
|
||||
|
||||
return (
|
||||
<Container
|
||||
@ -246,30 +246,22 @@ export const TitleLine = ({
|
||||
/>
|
||||
)}
|
||||
{type === "movie" && slug && (
|
||||
<IconButton
|
||||
icon={Download}
|
||||
onPress={() => downloader(type, slug)}
|
||||
color={{ xs: theme.user.contrast, md: theme.colors.white }}
|
||||
{...tooltip(t("home.episodeMore.download"))}
|
||||
/>
|
||||
<>
|
||||
<IconButton
|
||||
icon={Download}
|
||||
onPress={() => downloader(type, slug)}
|
||||
color={{ xs: theme.user.contrast, md: theme.colors.white }}
|
||||
{...tooltip(t("home.episodeMore.download"))}
|
||||
/>
|
||||
<IconButton
|
||||
icon={MovieInfo}
|
||||
color={{ xs: theme.user.contrast, md: theme.colors.white }}
|
||||
onPress={() =>
|
||||
setPopup(<MediaInfoPopup mediaType={"movie"} mediaSlug={slug!} close={close} />)
|
||||
}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{type === "movie" && (
|
||||
<IconButton
|
||||
icon={MovieInfo}
|
||||
color={{ xs: theme.user.contrast, md: theme.colors.white }}
|
||||
onPress={() =>
|
||||
slug &&
|
||||
setPopup(
|
||||
<MediaInfoPopup
|
||||
mediaType={type}
|
||||
mediaSlug={slug}
|
||||
close={() => setPopup(undefined)}
|
||||
/>,
|
||||
)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{popup}
|
||||
{rating !== null && (
|
||||
<>
|
||||
<DottedSeparator
|
||||
|
@ -45,6 +45,7 @@ import {
|
||||
SwitchVariant,
|
||||
imageBorderRadius,
|
||||
ts,
|
||||
usePopup,
|
||||
} from "@kyoo/primitives";
|
||||
import { DefaultLayout } from "../layout";
|
||||
import { Children, ComponentProps, ReactElement, ReactNode, useState } from "react";
|
||||
@ -257,10 +258,11 @@ const ChangePasswordPopup = ({
|
||||
);
|
||||
};
|
||||
|
||||
const AccountSettings = ({ setPopup }: { setPopup: (e?: ReactElement) => void }) => {
|
||||
const AccountSettings = () => {
|
||||
const account = useAccount();
|
||||
const { css, theme } = useYoshiki();
|
||||
const { t } = useTranslation();
|
||||
const [setPopup, close] = usePopup();
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
const { mutateAsync } = useMutation({
|
||||
@ -335,7 +337,7 @@ const AccountSettings = ({ setPopup }: { setPopup: (e?: ReactElement) => void })
|
||||
label={t("settings.account.username.label")}
|
||||
inital={account.username}
|
||||
apply={async (v) => await mutateAsync({ username: v })}
|
||||
close={() => setPopup(undefined)}
|
||||
close={close}
|
||||
/>,
|
||||
)
|
||||
}
|
||||
@ -356,7 +358,7 @@ const AccountSettings = ({ setPopup }: { setPopup: (e?: ReactElement) => void })
|
||||
label={t("settings.account.email.label")}
|
||||
inital={account.email}
|
||||
apply={async (v) => await mutateAsync({ email: v })}
|
||||
close={() => setPopup(undefined)}
|
||||
close={close}
|
||||
/>,
|
||||
)
|
||||
}
|
||||
@ -375,7 +377,7 @@ const AccountSettings = ({ setPopup }: { setPopup: (e?: ReactElement) => void })
|
||||
icon={Password}
|
||||
label={t("settings.account.password.label")}
|
||||
apply={async (op, np) => await editPassword({ oldPassword: op, newPassword: np })}
|
||||
close={() => setPopup(undefined)}
|
||||
close={close}
|
||||
/>,
|
||||
)
|
||||
}
|
||||
@ -389,67 +391,63 @@ const AccountSettings = ({ setPopup }: { setPopup: (e?: ReactElement) => void })
|
||||
export const SettingsPage: QueryPage = () => {
|
||||
const { t, i18n } = useTranslation();
|
||||
const languages = new Intl.DisplayNames([i18n.language ?? "en"], { type: "language" });
|
||||
const [popup, setPopup] = useState<ReactElement | undefined>(undefined);
|
||||
|
||||
const theme = useUserTheme("auto");
|
||||
return (
|
||||
<>
|
||||
<ScrollView contentContainerStyle={{ gap: ts(4), paddingBottom: ts(4) }}>
|
||||
<SettingsContainer title={t("settings.general.label")}>
|
||||
<Preference
|
||||
icon={Theme}
|
||||
<ScrollView contentContainerStyle={{ gap: ts(4), paddingBottom: ts(4) }}>
|
||||
<SettingsContainer title={t("settings.general.label")}>
|
||||
<Preference
|
||||
icon={Theme}
|
||||
label={t("settings.general.theme.label")}
|
||||
description={t("settings.general.theme.description")}
|
||||
>
|
||||
<Select
|
||||
label={t("settings.general.theme.label")}
|
||||
description={t("settings.general.theme.description")}
|
||||
>
|
||||
<Select
|
||||
label={t("settings.general.theme.label")}
|
||||
value={theme}
|
||||
onValueChange={(value) => setUserTheme(value)}
|
||||
values={["auto", "light", "dark"]}
|
||||
getLabel={(key) => t(`settings.general.theme.${key}`)}
|
||||
/>
|
||||
</Preference>
|
||||
<Preference
|
||||
icon={Language}
|
||||
value={theme}
|
||||
onValueChange={(value) => setUserTheme(value)}
|
||||
values={["auto", "light", "dark"]}
|
||||
getLabel={(key) => t(`settings.general.theme.${key}`)}
|
||||
/>
|
||||
</Preference>
|
||||
<Preference
|
||||
icon={Language}
|
||||
label={t("settings.general.language.label")}
|
||||
description={t("settings.general.language.description")}
|
||||
>
|
||||
<Select
|
||||
label={t("settings.general.language.label")}
|
||||
description={t("settings.general.language.description")}
|
||||
>
|
||||
<Select
|
||||
label={t("settings.general.language.label")}
|
||||
value={i18n.resolvedLanguage!}
|
||||
onValueChange={(value) =>
|
||||
i18n.changeLanguage(value !== "system" ? value : (i18n.options.lng as string))
|
||||
}
|
||||
values={["system", ...Object.keys(i18n.options.resources!)]}
|
||||
getLabel={(key) =>
|
||||
key === "system" ? t("settings.general.language.system") : languages.of(key) ?? key
|
||||
}
|
||||
/>
|
||||
</Preference>
|
||||
</SettingsContainer>
|
||||
<AccountSettings setPopup={setPopup} />
|
||||
<SettingsContainer title={t("settings.about.label")}>
|
||||
<Link
|
||||
href="https://github.com/zoriya/kyoo/releases/latest/download/kyoo.apk"
|
||||
target="_blank"
|
||||
>
|
||||
<Preference
|
||||
icon={Android}
|
||||
label={t("settings.about.android-app.label")}
|
||||
description={t("settings.about.android-app.description")}
|
||||
/>
|
||||
</Link>
|
||||
<Link href="https://github.com/zoriya/kyoo" target="_blank">
|
||||
<Preference
|
||||
icon={Public}
|
||||
label={t("settings.about.git.label")}
|
||||
description={t("settings.about.git.description")}
|
||||
/>
|
||||
</Link>
|
||||
</SettingsContainer>
|
||||
</ScrollView>
|
||||
{popup}
|
||||
</>
|
||||
value={i18n.resolvedLanguage!}
|
||||
onValueChange={(value) =>
|
||||
i18n.changeLanguage(value !== "system" ? value : (i18n.options.lng as string))
|
||||
}
|
||||
values={["system", ...Object.keys(i18n.options.resources!)]}
|
||||
getLabel={(key) =>
|
||||
key === "system" ? t("settings.general.language.system") : languages.of(key) ?? key
|
||||
}
|
||||
/>
|
||||
</Preference>
|
||||
</SettingsContainer>
|
||||
<AccountSettings />
|
||||
<SettingsContainer title={t("settings.about.label")}>
|
||||
<Link
|
||||
href="https://github.com/zoriya/kyoo/releases/latest/download/kyoo.apk"
|
||||
target="_blank"
|
||||
>
|
||||
<Preference
|
||||
icon={Android}
|
||||
label={t("settings.about.android-app.label")}
|
||||
description={t("settings.about.android-app.description")}
|
||||
/>
|
||||
</Link>
|
||||
<Link href="https://github.com/zoriya/kyoo" target="_blank">
|
||||
<Preference
|
||||
icon={Public}
|
||||
label={t("settings.about.git.label")}
|
||||
description={t("settings.about.git.description")}
|
||||
/>
|
||||
</Link>
|
||||
</SettingsContainer>
|
||||
</ScrollView>
|
||||
);
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user