Make subtitle's menu work on tv

This commit is contained in:
Zoe Roux 2023-01-26 18:55:09 +09:00
parent e45c595d6d
commit 1bba1eb02a
No known key found for this signature in database
GPG Key ID: B2AB52A2636E5C46
4 changed files with 40 additions and 49 deletions

View File

@ -21,8 +21,8 @@
import { Portal } from "@gorhom/portal"; import { Portal } from "@gorhom/portal";
import { ScrollView } from "moti"; import { ScrollView } from "moti";
import { ComponentType, createContext, ReactNode, useContext, useEffect, useState } from "react"; import { ComponentType, createContext, ReactNode, useContext, useEffect, useState } from "react";
import { StyleSheet, Pressable } from "react-native"; import { StyleSheet, Pressable, Platform, BackHandler } from "react-native";
import { percent, px, sm, useYoshiki, xl } from "yoshiki/native"; import { min, percent, px, sm, Theme, useYoshiki, vh, xl } from "yoshiki/native";
import Close from "@material-symbols/svg-400/rounded/close-fill.svg"; import Close from "@material-symbols/svg-400/rounded/close-fill.svg";
import { Icon, IconButton } from "./icons"; import { Icon, IconButton } from "./icons";
import { PressableFeedback } from "./links"; import { PressableFeedback } from "./links";
@ -52,6 +52,15 @@ const Menu = <AsProps,>({
else onMenuClose?.call(null); else onMenuClose?.call(null);
}, [isOpen, onMenuClose, onMenuOpen]); }, [isOpen, onMenuClose, onMenuOpen]);
useEffect(() => {
const handler = BackHandler.addEventListener("hardwareBackPress", () => {
if (!isOpen) return false;
setOpen(false);
return true;
});
return () => handler.remove();
}, [isOpen]);
return ( return (
<> <>
{/* @ts-ignore */} {/* @ts-ignore */}
@ -75,28 +84,26 @@ const Menu = <AsProps,>({
width: percent(100), width: percent(100),
alignSelf: "center", alignSelf: "center",
borderTopLeftRadius: px(26), borderTopLeftRadius: px(26),
borderTopRightRadius: { xs: px(26), xl: 0 }, borderTopRightRadius: px(26),
paddingTop: { xs: px(26), xl: 0 }, paddingTop: px(26),
marginTop: { xs: px(72), xl: 0 }, marginTop: px(72),
}, },
sm({ sm({
maxWidth: px(640), maxWidth: px(640),
marginHorizontal: px(56), marginHorizontal: px(56),
}), }),
xl({ Platform.isTV && {
top: 0, top: 0,
right: 0, right: 0,
marginRight: 0, marginRight: 0,
borderBottomLeftRadius: px(26), borderBottomLeftRadius: px(26),
}), maxWidth: min(px(640), vh(45)),
marginHorizontal: px(56),
borderTopRightRadius: 0,
marginTop: 0,
},
])} ])}
> >
<IconButton
icon={Close}
color={theme.colors.black}
onPress={() => setOpen(false)}
{...css({ alignSelf: "flex-end", display: { xs: "none", xl: "flex" } })}
/>
{children} {children}
</ScrollView> </ScrollView>
</MenuContext.Provider> </MenuContext.Provider>
@ -127,6 +134,7 @@ const MenuItem = ({
setOpen?.call(null, false); setOpen?.call(null, false);
onSelect?.call(null); onSelect?.call(null);
}} }}
hasTVPreferredFocus={selected}
{...css( {...css(
{ {
paddingHorizontal: ts(2), paddingHorizontal: ts(2),
@ -134,12 +142,20 @@ const MenuItem = ({
height: ts(5), height: ts(5),
alignItems: "center", alignItems: "center",
flexDirection: "row", flexDirection: "row",
focus: {
self: {
bg: (theme: Theme) => theme.alternate.accent,
},
// text: {
// color: (theme: Theme) => theme.alternate.contrast,
// },
},
}, },
props as any, props as any,
)} )}
> >
{selected && <Icon icon={Check} color={theme.paragraph} size={24} />} {selected && <Icon icon={Check} color={theme.paragraph} size={24} />}
<P {...css({ paddingLeft: ts(2) + +!selected * px(24) })}>{label}</P> <P {...css(["text", { paddingLeft: ts(2) + +!selected * px(24) }])}>{label}</P>
</PressableFeedback> </PressableFeedback>
); );
}; };

View File

@ -27,6 +27,7 @@ import { P } from "./text";
import { ContrastArea } from "./themes"; import { ContrastArea } from "./themes";
import { Icon } from "./icons"; import { Icon } from "./icons";
import Dot from "@material-symbols/svg-400/rounded/fiber_manual_record-fill.svg"; import Dot from "@material-symbols/svg-400/rounded/fiber_manual_record-fill.svg";
import { focusReset } from "./utils";
type YoshikiFunc<T> = (props: ReturnType<typeof useYoshiki>) => T; type YoshikiFunc<T> = (props: ReturnType<typeof useYoshiki>) => T;
const YoshikiProvider = ({ children }: { children: YoshikiFunc<ReactNode> }) => { const YoshikiProvider = ({ children }: { children: YoshikiFunc<ReactNode> }) => {
@ -115,18 +116,16 @@ const MenuItem = ({
<DropdownMenu.Item <DropdownMenu.Item
onSelect={onSelect} onSelect={onSelect}
{...css( {...css(
[ {
{ display: "flex",
display: "flex", alignItems: "center",
alignItems: "center", padding: "8px",
padding: "8px", height: "32px",
height: "32px", color: (theme) => theme.paragraph,
color: (theme) => theme.paragraph, focus: {
focus: { self: focusReset,
boxShadow: "none",
},
}, },
], },
props as any, props as any,
)} )}
> >

View File

@ -1,21 +0,0 @@
/*
* 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 "react-native/tvos-types.d";

View File

@ -28,11 +28,8 @@ import ClosedCaption from "@material-symbols/svg-400/rounded/closed_caption-fill
import Fullscreen from "@material-symbols/svg-400/rounded/fullscreen-fill.svg"; import Fullscreen from "@material-symbols/svg-400/rounded/fullscreen-fill.svg";
import FullscreenExit from "@material-symbols/svg-400/rounded/fullscreen_exit-fill.svg"; import FullscreenExit from "@material-symbols/svg-400/rounded/fullscreen_exit-fill.svg";
import { Stylable, useYoshiki } from "yoshiki/native"; import { Stylable, useYoshiki } from "yoshiki/native";
import { createParam } from "solito";
import { fullscreenAtom, subtitleAtom } from "../state"; import { fullscreenAtom, subtitleAtom } from "../state";
const { useParam } = createParam<{ subtitle?: string }>();
export const RightButtons = ({ export const RightButtons = ({
subtitles, subtitles,
fonts, fonts,