refactor(database): migrate to new modular database layer and unify data access
- Remove legacy database.ts, LocalDataSource.ts, and MessageRepository.ts - Create new src/database/ module with messageRepository, userCacheRepository, conversationRepository, and groupCacheRepository - Update all consumers to import from @/database instead of services/database - Add web platform blur handling for modal components to fix focus issues - Flatten SystemMessageItem and NotificationsScreen styles for consistent design - Add draggable slider in ChatSettingsScreen and dynamic font size support - Introduce 9 new chat color themes - Add profile screens for about, terms, and privacy policy with navigation routes - Add policy links to login and registration screens - Fix post share URL format from /posts/ to /post/
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import React, { useState, useEffect, useCallback, useMemo } from 'react';
|
||||
import { View, TouchableOpacity, ActivityIndicator, Modal, Alert, Dimensions, StyleSheet, FlatList, ListRenderItem, ScrollView } from 'react-native';
|
||||
import { View, TouchableOpacity, ActivityIndicator, Modal, Alert, Dimensions, StyleSheet, FlatList, ListRenderItem, ScrollView, Platform } from 'react-native';
|
||||
import { Image as ExpoImage } from 'expo-image';
|
||||
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
||||
import * as ImagePicker from 'expo-image-picker';
|
||||
@@ -18,6 +18,12 @@ import { useAppColors, spacing } from '../../../../theme';
|
||||
|
||||
const { height: SCREEN_HEIGHT } = Dimensions.get('window');
|
||||
|
||||
const blurActiveElementOnWeb = () => {
|
||||
if (Platform.OS !== 'web') return;
|
||||
const active = (globalThis as any)?.document?.activeElement as { blur?: () => void } | undefined;
|
||||
active?.blur?.();
|
||||
};
|
||||
|
||||
// 表情尺寸配置 - 固定宽度 40px,使用 flex 布局
|
||||
const EMOJI_SIZES = {
|
||||
mobile: { size: 24, itemWidth: 40, itemHeight: 40 },
|
||||
@@ -176,6 +182,7 @@ export const EmojiPanel: React.FC<EmojiPanelProps> = ({
|
||||
|
||||
// 打开管理界面
|
||||
const handleOpenManage = () => {
|
||||
blurActiveElementOnWeb();
|
||||
setShowManageModal(true);
|
||||
setManageMode(false);
|
||||
setSelectedStickers(new Set());
|
||||
|
||||
@@ -33,6 +33,7 @@ import {
|
||||
} from '../../../../types/dto';
|
||||
import { spacing, useAppColors, type AppColors } from '../../../../theme';
|
||||
import { SenderInfo } from './types';
|
||||
import { useChatSettingsStore } from '../../../../stores/chatSettingsStore';
|
||||
|
||||
const IMAGE_MAX_WIDTH = 200;
|
||||
const IMAGE_MAX_HEIGHT = 260;
|
||||
@@ -617,7 +618,8 @@ export const ReplyPreviewSegment: React.FC<ReplyPreviewSegmentProps> = ({
|
||||
getSenderInfo,
|
||||
}) => {
|
||||
const themeColors = useAppColors();
|
||||
const styles = useMemo(() => createSegmentStyles(themeColors), [themeColors]);
|
||||
const fontSize = useChatSettingsStore((s) => s.fontSize);
|
||||
const styles = useMemo(() => createSegmentStyles(themeColors, fontSize), [themeColors, fontSize]);
|
||||
|
||||
if (!replyMessage) {
|
||||
// 如果没有引用消息详情,只显示引用ID
|
||||
@@ -729,7 +731,8 @@ export const MessageSegmentsRenderer: React.FC<{
|
||||
getSenderInfo,
|
||||
}) => {
|
||||
const themeColors = useAppColors();
|
||||
const segStyles = useMemo(() => createSegmentStyles(themeColors), [themeColors]);
|
||||
const fontSize = useChatSettingsStore((s) => s.fontSize);
|
||||
const segStyles = useMemo(() => createSegmentStyles(themeColors, fontSize), [themeColors, fontSize]);
|
||||
|
||||
const replySegment = segments.find(s => s.type === 'reply');
|
||||
const otherSegments = segments.filter(s => s.type !== 'reply');
|
||||
@@ -815,7 +818,7 @@ const formatDuration = (seconds: number): string => {
|
||||
return mins > 0 ? `${mins}:${secs.toString().padStart(2, '0')}` : `0:${secs.toString().padStart(2, '0')}`;
|
||||
};
|
||||
|
||||
function createSegmentStyles(colors: AppColors) {
|
||||
function createSegmentStyles(colors: AppColors, fontSize: number = 16) {
|
||||
return StyleSheet.create({
|
||||
// 容器
|
||||
segmentsContainer: {
|
||||
@@ -847,10 +850,10 @@ function createSegmentStyles(colors: AppColors) {
|
||||
marginTop: 2,
|
||||
},
|
||||
|
||||
// 文本 - 适配暗色模式
|
||||
// 文本 - 适配暗色模式,支持动态字号
|
||||
textContent: {
|
||||
fontSize: 17.5,
|
||||
lineHeight: 25,
|
||||
fontSize,
|
||||
lineHeight: Math.round(fontSize * 1.43),
|
||||
letterSpacing: 0.1,
|
||||
fontWeight: '400',
|
||||
},
|
||||
@@ -861,10 +864,10 @@ function createSegmentStyles(colors: AppColors) {
|
||||
color: colors.chat.textPrimary,
|
||||
},
|
||||
|
||||
// @提及 - 微信/QQ 风格:更精致的高亮
|
||||
// @提及 - 微信/QQ 风格:更精致的高亮,支持动态字号
|
||||
atText: {
|
||||
fontSize: 16,
|
||||
lineHeight: 22,
|
||||
fontSize,
|
||||
lineHeight: Math.round(fontSize * 1.4),
|
||||
fontWeight: '500',
|
||||
},
|
||||
atTextMe: {
|
||||
@@ -904,7 +907,7 @@ function createSegmentStyles(colors: AppColors) {
|
||||
height: 28,
|
||||
},
|
||||
faceText: {
|
||||
fontSize: 16,
|
||||
fontSize,
|
||||
color: '#666',
|
||||
},
|
||||
|
||||
@@ -930,7 +933,7 @@ function createSegmentStyles(colors: AppColors) {
|
||||
},
|
||||
voiceDuration: {
|
||||
marginLeft: spacing.sm,
|
||||
fontSize: 15,
|
||||
fontSize: fontSize - 1,
|
||||
fontWeight: '500',
|
||||
},
|
||||
|
||||
@@ -1113,14 +1116,14 @@ function createSegmentStyles(colors: AppColors) {
|
||||
minWidth: 0,
|
||||
},
|
||||
replySender: {
|
||||
fontSize: 13,
|
||||
fontSize: fontSize - 3,
|
||||
fontWeight: '600',
|
||||
color: colors.chat.link,
|
||||
marginRight: 6,
|
||||
flexShrink: 0,
|
||||
},
|
||||
replyText: {
|
||||
fontSize: 13,
|
||||
fontSize: fontSize - 3,
|
||||
color: colors.chat.textTertiary,
|
||||
flex: 1,
|
||||
flexShrink: 1,
|
||||
|
||||
@@ -42,10 +42,7 @@ import {
|
||||
PendingChatAttachment,
|
||||
} from './types';
|
||||
import { TIME_SEPARATOR_INTERVAL, MEMBERS_PAGE_SIZE, MAX_PENDING_CHAT_IMAGES } from './constants';
|
||||
import {
|
||||
deleteMessage as deleteMessageFromDb,
|
||||
clearConversationMessages,
|
||||
} from '../../../../services/database';
|
||||
import { messageRepository } from '@/database';
|
||||
|
||||
export const useChatScreen = () => {
|
||||
const getSendErrorMessage = useCallback((error: unknown, fallback: string) => {
|
||||
@@ -1209,7 +1206,7 @@ export const useChatScreen = () => {
|
||||
const updatedMessages = messages.filter(m => m.id !== messageId);
|
||||
// 注意:这里我们依赖 MessageManager 的数据,所以需要通过其他方式刷新
|
||||
// 暂时只删除本地数据库
|
||||
await deleteMessageFromDb(messageId);
|
||||
await messageRepository.delete(messageId);
|
||||
} catch (error) {
|
||||
console.error('删除消息失败:', error);
|
||||
Alert.alert('删除失败', '无法删除消息');
|
||||
@@ -1224,7 +1221,7 @@ export const useChatScreen = () => {
|
||||
setLastSeq(0);
|
||||
setFirstSeq(0);
|
||||
setHasMoreHistory(true);
|
||||
await clearConversationMessages(conversationId);
|
||||
await messageRepository.clearConversation(conversationId);
|
||||
// 刷新消息列表
|
||||
await refreshMessages();
|
||||
} catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user