/** * 聊天设置页 ChatSettingsScreen * 胡萝卜BBS - 聊天个性化设置 */ import React, { useMemo, useCallback, useRef } from 'react'; import { View, StyleSheet, TouchableOpacity, ScrollView, Dimensions, PanResponder, } from 'react-native'; import { SafeAreaView } from 'react-native-safe-area-context'; import { useAppColors, spacing, fontSizes, borderRadius, type AppColors, } from '../../theme'; import { Text } from '../../components/common'; import { useResponsiveSpacing } from '../../hooks'; import { useChatSettingsStore, useChatSettingsActions, CHAT_THEMES, } from '../../stores/chatSettingsStore'; const { width: SCREEN_WIDTH } = Dimensions.get('window'); const CARD_MAX_WIDTH = 720; interface SliderProps { value: number; min: number; max: number; onValueChange: (value: number) => void; leftLabel?: string; rightLabel?: string; showValue?: boolean; } // 自定义滑块组件(支持拖动) const Slider: React.FC = ({ value, min, max, onValueChange, leftLabel, rightLabel, showValue = true, }) => { const colors = useAppColors(); const styles = useMemo(() => createSliderStyles(colors), [colors]); const trackWidthRef = useRef(0); const percentage = isNaN(value) ? 0 : ((value - min) / (max - min)) * 100; const updateValue = useCallback((locationX: number) => { const width = trackWidthRef.current; if (width <= 0) return; const newPercentage = Math.max(0, Math.min(100, (locationX / width) * 100)); const newValue = Math.round(min + (newPercentage / 100) * (max - min)); onValueChange(newValue); }, [min, max, onValueChange]); const panResponder = useMemo(() => PanResponder.create({ onStartShouldSetPanResponder: () => true, onMoveShouldSetPanResponder: () => true, onPanResponderGrant: (evt) => { updateValue(evt.nativeEvent.locationX); }, onPanResponderMove: (evt) => { updateValue(evt.nativeEvent.locationX); }, }), [updateValue]); const handleLayout = useCallback((event: any) => { trackWidthRef.current = event.nativeEvent.layout.width; }, []); return ( {leftLabel && {leftLabel}} {showValue && {isNaN(value) ? 0 : value}} {rightLabel && {rightLabel}} ); }; function createSliderStyles(colors: AppColors) { return StyleSheet.create({ container: { marginVertical: spacing.sm, }, labelRow: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: spacing.xs, }, label: { fontSize: fontSizes.sm, color: colors.text.secondary, }, value: { fontSize: fontSizes.md, fontWeight: '600', color: colors.primary.main, }, trackContainer: { height: 24, justifyContent: 'center', }, track: { height: 4, backgroundColor: colors.divider, borderRadius: 2, }, fill: { height: '100%', borderRadius: 2, }, thumb: { position: 'absolute', width: 20, height: 20, borderRadius: 10, marginLeft: -10, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.2, shadowRadius: 2, elevation: 3, }, }); } function createStyles(colors: AppColors) { return StyleSheet.create({ container: { flex: 1, backgroundColor: colors.background.paper, }, scrollContent: { paddingVertical: spacing.lg, }, section: { marginBottom: spacing['2xl'], maxWidth: CARD_MAX_WIDTH, alignSelf: 'center', width: '100%', paddingHorizontal: spacing['2xl'], }, sectionTitle: { fontSize: fontSizes.sm, fontWeight: '600', color: colors.text.secondary, marginBottom: spacing.sm, marginTop: spacing.sm, textTransform: 'uppercase', letterSpacing: 0.5, }, // 聊天预览样式 previewContainer: { backgroundColor: colors.primary.light + '20', borderRadius: 14, padding: spacing.md, minHeight: 140, }, previewMessage: { backgroundColor: '#FFFFFF', padding: spacing.sm, marginBottom: spacing.sm, maxWidth: '80%', alignSelf: 'flex-start', minWidth: 44, shadowColor: '#000', shadowOffset: { width: 0, height: 1 }, shadowOpacity: 0.06, shadowRadius: 2, elevation: 1, }, previewReply: { padding: spacing.sm, maxWidth: '80%', alignSelf: 'flex-end', minWidth: 44, shadowColor: '#000', shadowOffset: { width: 0, height: 1 }, shadowOpacity: 0.06, shadowRadius: 2, elevation: 1, }, previewText: { color: colors.text.primary, }, // 主题选择样式 themeList: { flexDirection: 'row', gap: spacing.sm, }, themeItem: { width: 70, height: 90, borderRadius: borderRadius.md, borderWidth: 2, borderColor: 'transparent', overflow: 'hidden', padding: spacing.xs, }, themeItemActive: { borderColor: colors.primary.main, }, themePreview: { flex: 1, justifyContent: 'center', gap: 4, }, themeBubble1: { height: 12, borderRadius: 6, width: '70%', }, themeBubble2: { height: 12, borderRadius: 6, width: '50%', alignSelf: 'flex-end', }, themeIcon: { position: 'absolute', bottom: 4, right: 4, width: 18, height: 18, borderRadius: 9, justifyContent: 'center', alignItems: 'center', }, themeName: { fontSize: fontSizes.xs, textAlign: 'center', marginTop: 4, color: colors.text.secondary, }, sliderContainer: { paddingVertical: 8, }, }); } export const ChatSettingsScreen: React.FC = () => { const colors = useAppColors(); const styles = useMemo(() => createStyles(colors), [colors]); const responsivePadding = useResponsiveSpacing({ xs: 8, sm: 12, md: 16, lg: 24, xl: 32 }); // 从 store 获取状态 const fontSize = useChatSettingsStore((s) => s.fontSize); const messageRadius = useChatSettingsStore((s) => s.messageRadius); const themeIndex = useChatSettingsStore((s) => s.themeIndex); const { setFontSize, setMessageRadius, setTheme } = useChatSettingsActions(); const currentTheme = CHAT_THEMES[themeIndex]; // 渲染聊天预览 const renderChatPreview = () => ( 预览 早上好!👋 你知道现在几点吗? 现在是威海的早晨😎 ); // 渲染字号滑块 const renderFontSizeSlider = () => ( 消息字号 ); // 渲染主题颜色选择 const renderThemeColors = () => ( 主题颜色 {CHAT_THEMES.map((theme, index) => ( setTheme(index)} activeOpacity={0.8} > {theme.icon} ))} ); // 渲染圆角滑块 const renderRadiusSlider = () => ( 消息圆角 ); return ( {renderFontSizeSlider()} {renderChatPreview()} {renderThemeColors()} {renderRadiusSlider()} ); }; export default ChatSettingsScreen;