diff --git a/components/inputs/PinInput.tsx b/components/inputs/PinInput.tsx new file mode 100644 index 00000000..a4885ceb --- /dev/null +++ b/components/inputs/PinInput.tsx @@ -0,0 +1,123 @@ +import { BottomSheetTextInput } from "@gorhom/bottom-sheet"; +import React, { useCallback, useImperativeHandle, useRef } from "react"; +import { StyleSheet, Text, type TextInputProps, View } from "react-native"; + +interface PinInputProps extends Omit { + value: string; + onChangeText: (text: string) => void; + length?: number; + autoFocus?: boolean; +} + +export interface PinInputRef { + focus: () => void; +} + +const PinInputComponent = React.forwardRef( + (props, ref) => { + const { + value, + onChangeText, + length = 6, + style, + autoFocus, + ...rest + } = props; + + const inputRef = useRef(null); + const activeIndex = value.length; + + const handlePress = useCallback(() => { + inputRef.current?.focus(); + }, []); + + useImperativeHandle( + ref, + () => ({ + focus: () => inputRef.current?.focus(), + }), + [], + ); + + return ( + + + + {Array(length) + .fill(0) + .map((_, i) => ( + + {value[i]} + {i === activeIndex && } + + ))} + + + ); + }, +); + +PinInputComponent.displayName = "PinInput"; + +export const PinInput = PinInputComponent; + +const styles = StyleSheet.create({ + container: { + width: "100%", + }, + hiddenInput: { + position: "absolute", + width: 1, + height: 1, + opacity: 0, + }, + cells: { + flexDirection: "row", + justifyContent: "space-between", + width: "100%", + }, + cell: { + width: 40, + height: 48, + borderWidth: 1, + borderColor: "#374151", + borderRadius: 8, + alignItems: "center", + justifyContent: "center", + backgroundColor: "#1F2937", + }, + activeCell: { + borderColor: "#6366F1", + }, + filledCell: { + borderColor: "#4B5563", + }, + digit: { + fontSize: 24, + color: "white", + fontWeight: "500", + }, + cursor: { + position: "absolute", + width: 2, + height: 24, + backgroundColor: "#6366F1", + animation: "blink 1s infinite", + }, +}); diff --git a/components/settings/QuickConnect.tsx b/components/settings/QuickConnect.tsx index b61500ce..d0cbf85e 100644 --- a/components/settings/QuickConnect.tsx +++ b/components/settings/QuickConnect.tsx @@ -2,7 +2,6 @@ import { BottomSheetBackdrop, type BottomSheetBackdropProps, BottomSheetModal, - BottomSheetTextInput, BottomSheetView, } from "@gorhom/bottom-sheet"; import { getQuickConnectApi } from "@jellyfin/sdk/lib/utils/api"; @@ -10,17 +9,19 @@ import { useAtom } from "jotai"; import type React from "react"; import { useCallback, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; -import { Alert, View, type ViewProps } from "react-native"; +import { Alert, Platform, View, type ViewProps } from "react-native"; import { useHaptic } from "@/hooks/useHaptic"; import { apiAtom, userAtom } from "@/providers/JellyfinProvider"; import { Button } from "../Button"; import { Text } from "../common/Text"; +import { PinInput } from "../inputs/PinInput"; import { ListGroup } from "../list/ListGroup"; import { ListItem } from "../list/ListItem"; interface Props extends ViewProps {} export const QuickConnect: React.FC = ({ ...props }) => { + const isTv = Platform.isTV; const [api] = useAtom(apiAtom); const [user] = useAtom(userAtom); const [quickConnectCode, setQuickConnectCode] = useState(); @@ -73,11 +74,17 @@ export const QuickConnect: React.FC = ({ ...props }) => { } }, [api, user, quickConnectCode]); + if (isTv) return null; + return ( bottomSheetModalRef?.current?.present()} + onPress={() => { + // Reset the code when opening the sheet + setQuickConnectCode(""); + bottomSheetModalRef?.current?.present(); + }} title={t("home.settings.quick_connect.authorize_button")} textColor='blue' /> @@ -93,6 +100,9 @@ export const QuickConnect: React.FC = ({ ...props }) => { backgroundColor: "#171717", }} backdropComponent={renderBackdrop} + keyboardBehavior='interactive' + keyboardBlurBehavior='restore' + android_keyboardInputMode='adjustResize' > @@ -102,16 +112,17 @@ export const QuickConnect: React.FC = ({ ...props }) => { - - + + {t( "home.settings.quick_connect.enter_the_quick_connect_code", )} - placeholderTextColor='#9CA3AF' - value={quickConnectCode} + +