mirror of
https://github.com/zimplexing/OrionTV.git
synced 2026-02-14 03:34:44 +08:00
- Hide live streaming tab in mobile navigation components - Hide remote input and live stream configurations in settings - Hide API configuration description text on mobile - Disable HTTP server startup on mobile devices to save resources This streamlines the mobile interface while preserving full functionality on tablet and TV platforms.
139 lines
4.0 KiB
TypeScript
139 lines
4.0 KiB
TypeScript
import React, { useState, useRef, useImperativeHandle, forwardRef } from "react";
|
||
import { View, TextInput, StyleSheet, Animated } 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";
|
||
|
||
interface APIConfigSectionProps {
|
||
onChanged: () => void;
|
||
onFocus?: () => void;
|
||
onBlur?: () => void;
|
||
hideDescription?: boolean;
|
||
}
|
||
|
||
export interface APIConfigSectionRef {
|
||
setInputValue: (value: string) => void;
|
||
}
|
||
|
||
export const APIConfigSection = forwardRef<APIConfigSectionRef, APIConfigSectionProps>(
|
||
({ onChanged, onFocus, onBlur, hideDescription = false }, ref) => {
|
||
const { apiBaseUrl, setApiBaseUrl, remoteInputEnabled } = useSettingsStore();
|
||
const { serverUrl } = useRemoteControlStore();
|
||
const [isInputFocused, setIsInputFocused] = useState(false);
|
||
const [isSectionFocused, setIsSectionFocused] = useState(false);
|
||
const inputRef = useRef<TextInput>(null);
|
||
const inputAnimationStyle = useButtonAnimation(isSectionFocused, 1.01);
|
||
|
||
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]
|
||
);
|
||
|
||
useTVEventHandler(handleTVEvent);
|
||
|
||
return (
|
||
<SettingsSection focusable onFocus={handleSectionFocus} onBlur={handleSectionBlur}>
|
||
<View style={styles.inputContainer}>
|
||
<View style={styles.titleContainer}>
|
||
<ThemedText style={styles.sectionTitle}>API 地址</ThemedText>
|
||
{!hideDescription && remoteInputEnabled && serverUrl && (
|
||
<ThemedText style={styles.subtitle}>用手机访问 {serverUrl},可远程输入</ThemedText>
|
||
)}
|
||
</View>
|
||
<Animated.View style={inputAnimationStyle}>
|
||
<TextInput
|
||
ref={inputRef}
|
||
style={[styles.input, isInputFocused && styles.inputFocused]}
|
||
value={apiBaseUrl}
|
||
onChangeText={handleUrlChange}
|
||
placeholder="输入服务器地址"
|
||
placeholderTextColor="#888"
|
||
autoCapitalize="none"
|
||
autoCorrect={false}
|
||
onFocus={() => setIsInputFocused(true)}
|
||
onBlur={() => setIsInputFocused(false)}
|
||
/>
|
||
</Animated.View>
|
||
</View>
|
||
</SettingsSection>
|
||
);
|
||
}
|
||
);
|
||
|
||
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,
|
||
},
|
||
});
|