refactor(database): migrate to new modular database layer and unify data access
All checks were successful
Frontend CI / build-and-push-web (push) Successful in 2m44s
Frontend CI / ota-android (push) Successful in 12m51s
Frontend CI / build-android-apk (push) Successful in 1h1m26s

- 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:
lafay
2026-04-04 08:01:45 +08:00
parent 189b977fac
commit 82c2970a85
76 changed files with 3382 additions and 2000 deletions

View File

@@ -15,6 +15,7 @@ import {
Modal,
Pressable,
Dimensions,
Platform,
} from 'react-native';
import {
useResponsive,
@@ -159,6 +160,10 @@ export function AdaptiveLayout({
// 抽屉动画
useEffect(() => {
if (isDrawerOpen) {
if (Platform.OS === 'web') {
const active = (globalThis as any)?.document?.activeElement as { blur?: () => void } | undefined;
active?.blur?.();
}
Animated.parallel([
Animated.timing(slideAnim, {
toValue: 1,

View File

@@ -1,5 +1,5 @@
import React, { useEffect, useMemo, useState } from 'react';
import { Modal, Pressable, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import { Modal, Pressable, StyleSheet, Text, TouchableOpacity, View, Platform } from 'react-native';
import type { AlertButton } from 'react-native';
import { MaterialCommunityIcons } from '@expo/vector-icons';
import { LinearGradient } from 'expo-linear-gradient';
@@ -93,6 +93,12 @@ function createDialogHostStyles(colors: AppColors) {
});
}
const blurActiveElementOnWeb = () => {
if (Platform.OS !== 'web') return;
const active = (globalThis as any)?.document?.activeElement as { blur?: () => void } | undefined;
active?.blur?.();
};
const AppDialogHost: React.FC = () => {
const [dialog, setDialog] = useState<DialogPayload | null>(null);
const colors = useAppColors();
@@ -105,6 +111,12 @@ const AppDialogHost: React.FC = () => {
return unbind;
}, []);
useEffect(() => {
if (dialog) {
blurActiveElementOnWeb();
}
}, [dialog]);
const actions = useMemo<AlertButton[]>(() => {
if (!dialog?.actions?.length) return [{ text: '确定' }];
return dialog.actions;

View File

@@ -14,6 +14,7 @@ import {
Text,
StatusBar,
Alert,
Platform,
} from 'react-native';
import { Image as ExpoImage } from 'expo-image';
import {
@@ -126,6 +127,10 @@ export const ImageGallery: React.FC<ImageGalleryProps> = ({
// 打开/关闭时重置状态
useEffect(() => {
if (visible) {
if (Platform.OS === 'web') {
const active = (globalThis as any)?.document?.activeElement as { blur?: () => void } | undefined;
active?.blur?.();
}
setCurrentIndex(initialIndex);
setShowControls(true);
setError(false);

View File

@@ -3,7 +3,7 @@
* 全屏模态播放视频,基于 expo-video
*/
import React, { useCallback } from 'react';
import React, { useCallback, useEffect } from 'react';
import {
Modal,
View,
@@ -12,6 +12,7 @@ import {
TouchableOpacity,
Text,
StatusBar,
Platform,
} from 'react-native';
import { VideoView, useVideoPlayer } from 'expo-video';
import { MaterialCommunityIcons } from '@expo/vector-icons';
@@ -79,6 +80,13 @@ export const VideoPlayerModal: React.FC<VideoPlayerModalProps> = ({
url,
onClose,
}) => {
useEffect(() => {
if (visible && Platform.OS === 'web') {
const active = (globalThis as any)?.document?.activeElement as { blur?: () => void } | undefined;
active?.blur?.();
}
}, [visible]);
return (
<Modal
visible={visible}