import React, { useState, useRef, useImperativeHandle, forwardRef } from "react"; import { View, TextInput, StyleSheet, Animated, Platform } from "react-native"; import { useTVEventHandler } from "react-native"; import { ThemedText } from "@/components/ThemedText"; import { SettingsSection } from "./SettingsSection"; import { useSettingsStore } from "@/stores/settingsStore"; import { useRemoteControlStore } from "@/stores/remoteControlStore"; import { useButtonAnimation } from "@/hooks/useAnimation"; import { Colors } from "@/constants/Colors"; import { useResponsiveLayout } from "@/hooks/useResponsiveLayout"; interface APIConfigSectionProps { onChanged: () => void; onFocus?: () => void; onBlur?: () => void; onPress?: () => void; hideDescription?: boolean; } export interface APIConfigSectionRef { setInputValue: (value: string) => void; } export const APIConfigSection = forwardRef( ({ onChanged, onFocus, onBlur, onPress, hideDescription = false }, ref) => { const { apiBaseUrl, setApiBaseUrl, remoteInputEnabled } = useSettingsStore(); const { serverUrl } = useRemoteControlStore(); const [isInputFocused, setIsInputFocused] = useState(false); const [isSectionFocused, setIsSectionFocused] = useState(false); const inputRef = useRef(null); const inputAnimationStyle = useButtonAnimation(isSectionFocused, 1.01); const deviceType = useResponsiveLayout().deviceType; const handleUrlChange = (url: string) => { setApiBaseUrl(url); onChanged(); }; useImperativeHandle(ref, () => ({ setInputValue: (value: string) => { setApiBaseUrl(value); onChanged(); }, })); const handleSectionFocus = () => { setIsSectionFocused(true); onFocus?.(); }; const handleSectionBlur = () => { setIsSectionFocused(false); onBlur?.(); }; // TV遥控器事件处理 const handleTVEvent = React.useCallback( (event: any) => { if (isSectionFocused && event.eventType === "select") { inputRef.current?.focus(); } }, [isSectionFocused] ); const handlePress = () => { inputRef.current?.focus(); onPress?.(); } useTVEventHandler(handleTVEvent); const [selection, setSelection] = useState<{ start: number; end: number }>({ start: 0, end: 0, }); // 当用户手动移动光标或选中文本时,同步到 state(可选) const onSelectionChange = ({ nativeEvent: { selection }, }: any) => { setSelection(selection); }; return ( API 地址 {!hideDescription && remoteInputEnabled && serverUrl && ( 用手机访问 {serverUrl},可远程输入 )} { setIsInputFocused(true); // 将光标移动到文本末尾 const end = apiBaseUrl.length; setSelection({ start: end, end: end }); // 有时需要延迟一下,让系统先完成 focus 再设置 selection //(在 Android 上更可靠) setTimeout(() => { // 对于受控的 selection 已经生效,这里仅作保险 inputRef.current?.setNativeProps({ selection: { start: end, end: end } }); }, 0); }} selection={selection} onSelectionChange={onSelectionChange} // 可选 onBlur={() => setIsInputFocused(false)} /> ); } ); APIConfigSection.displayName = "APIConfigSection"; const styles = StyleSheet.create({ titleContainer: { flexDirection: "row", alignItems: "center", marginBottom: 8, }, sectionTitle: { fontSize: 16, fontWeight: "bold", marginRight: 12, }, subtitle: { fontSize: 12, color: "#888", fontStyle: "italic", }, inputContainer: { marginBottom: 12, }, label: { fontSize: 16, marginBottom: 8, color: "#ccc", }, input: { height: 50, borderWidth: 2, borderRadius: 8, paddingHorizontal: 15, fontSize: 16, backgroundColor: "#3a3a3c", color: "white", borderColor: "transparent", }, inputFocused: { borderColor: Colors.dark.primary, shadowColor: Colors.dark.primary, shadowOffset: { width: 0, height: 0 }, shadowOpacity: 0.8, shadowRadius: 10, elevation: 5, }, });