feat: 优化架构
Some checks failed
Frontend CI / build-and-push-web (push) Successful in 2m39s
Frontend CI / ota-android (push) Successful in 10m22s
Frontend CI / build-android-apk (push) Has been cancelled

This commit is contained in:
lafay
2026-04-13 01:30:37 +08:00
parent 2adc9360a5
commit fe6a03da5d
93 changed files with 386 additions and 211 deletions

View File

@@ -9,9 +9,9 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import * as Notifications from 'expo-notifications'; import * as Notifications from 'expo-notifications';
import * as SystemUI from 'expo-system-ui'; import * as SystemUI from 'expo-system-ui';
import { registerNotificationPresentationHandler } from '../src/services/notificationPreferences'; import { registerNotificationPresentationHandler } from '@/services/notification';
import { api } from '../src/services/api'; import { api } from '@/services/core';
import { wsService } from '../src/services/wsService'; import { wsService } from '@/services/core';
import { EventSubscriber } from '../src/infrastructure/EventSubscriber'; import { EventSubscriber } from '../src/infrastructure/EventSubscriber';
import { import {
ThemeBootstrap, ThemeBootstrap,
@@ -22,9 +22,9 @@ import {
import { AppBackButton } from '../src/components/common'; import { AppBackButton } from '../src/components/common';
import AppPromptBar from '../src/components/common/AppPromptBar'; import AppPromptBar from '../src/components/common/AppPromptBar';
import AppDialogHost from '../src/components/common/AppDialogHost'; import AppDialogHost from '../src/components/common/AppDialogHost';
import { installAlertOverride } from '../src/services/alertOverride'; import { installAlertOverride } from '@/services/ui';
import { useAuthStore } from '../src/stores'; import { useAuthStore } from '../src/stores';
import { checkForAPKUpdate } from '../src/services/apkUpdateService'; import { checkForAPKUpdate } from '@/services/platform';
import { CallScreen, IncomingCallModal, FloatingCallWindow } from '../src/components/call'; import { CallScreen, IncomingCallModal, FloatingCallWindow } from '../src/components/call';
registerNotificationPresentationHandler(); registerNotificationPresentationHandler();
@@ -122,11 +122,11 @@ function NotificationBootstrap() {
useEffect(() => { useEffect(() => {
const initNotifications = async () => { const initNotifications = async () => {
const { loadNotificationPreferences } = await import('../src/services/notificationPreferences'); const { loadNotificationPreferences } = await import('@/services/notification');
await loadNotificationPreferences(); await loadNotificationPreferences();
const { systemNotificationService } = await import('../src/services/systemNotificationService'); const { systemNotificationService } = await import('@/services/notification');
await systemNotificationService.initialize(); await systemNotificationService.initialize();
const { initBackgroundService } = await import('../src/services/backgroundService'); const { initBackgroundService } = await import('@/services/background');
await initBackgroundService(); await initBackgroundService();
const subscription = AppState.addEventListener('change', (nextAppState) => { const subscription = AppState.addEventListener('change', (nextAppState) => {

View File

@@ -1,5 +1,6 @@
/** @type {import('expo/metro-config').MetroConfig} */ /** @type {import('expo/metro-config').MetroConfig} */
const { getDefaultConfig } = require('expo/metro-config'); const { getDefaultConfig } = require('expo/metro-config');
const path = require('path');
const config = getDefaultConfig(__dirname); const config = getDefaultConfig(__dirname);
@@ -10,6 +11,11 @@ config.resolver.assetExts.push('wasm');
// The package doesn't properly export "./index" in its exports field // The package doesn't properly export "./index" in its exports field
config.resolver.unstable_enablePackageExports = false; config.resolver.unstable_enablePackageExports = false;
// Support TypeScript path aliases (@/ -> ./src/)
config.resolver.alias = {
'@': path.resolve(__dirname, 'src'),
};
// NOTE: enhanceMiddleware is marked as deprecated in Metro's types, // NOTE: enhanceMiddleware is marked as deprecated in Metro's types,
// but there's currently no official alternative for custom dev server headers. // but there's currently no official alternative for custom dev server headers.
// For production, configure COEP/COOP headers on your hosting platform. // For production, configure COEP/COOP headers on your hosting platform.

View File

@@ -20,7 +20,7 @@ import {
import { MaterialCommunityIcons } from '@expo/vector-icons'; import { MaterialCommunityIcons } from '@expo/vector-icons';
import { useAppColors } from '../../../theme'; import { useAppColors } from '../../../theme';
import { spacing, borderRadius, fontSizes, shadows } from '../../../theme'; import { spacing, borderRadius, fontSizes, shadows } from '../../../theme';
import reportService, { ReportReason, ReportTargetType, REPORT_REASONS } from '../../../services/reportService'; import { reportService, ReportReason, ReportTargetType, REPORT_REASONS } from '@/services/post';
import { blurActiveElement } from '../../../infrastructure/platform'; import { blurActiveElement } from '../../../infrastructure/platform';
import Text from '../../common/Text'; import Text from '../../common/Text';

View File

@@ -4,7 +4,7 @@ import type { AlertButton } from 'react-native';
import { MaterialCommunityIcons } from '@expo/vector-icons'; import { MaterialCommunityIcons } from '@expo/vector-icons';
import { LinearGradient } from 'expo-linear-gradient'; import { LinearGradient } from 'expo-linear-gradient';
import { bindDialogListener, DialogPayload } from '../../services/dialogService'; import { bindDialogListener, DialogPayload } from '@/services/ui';
import { borderRadius, shadows, spacing, useAppColors, type AppColors } from '../../theme'; import { borderRadius, shadows, spacing, useAppColors, type AppColors } from '../../theme';
import { blurActiveElement } from '../../infrastructure/platform'; import { blurActiveElement } from '../../infrastructure/platform';

View File

@@ -3,7 +3,7 @@ import { Animated, StyleSheet, Text, TouchableOpacity, View } from 'react-native
import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { MaterialCommunityIcons } from '@expo/vector-icons'; import { MaterialCommunityIcons } from '@expo/vector-icons';
import { bindPromptListener, PromptPayload, PromptType } from '../../services/promptService'; import { bindPromptListener, PromptPayload, PromptType } from '@/services/ui';
import { borderRadius, shadows, spacing, useAppColors, type AppColors } from '../../theme'; import { borderRadius, shadows, spacing, useAppColors, type AppColors } from '../../theme';
interface PromptState extends PromptPayload { interface PromptState extends PromptPayload {

View File

@@ -3,7 +3,7 @@
* 封装所有 API 调用,统一错误处理和请求拦截 * 封装所有 API 调用,统一错误处理和请求拦截
*/ */
import { api, ApiResponse, ApiError } from '../../services/api'; import { api, ApiResponse, ApiError } from '@/services/core';
import { IApiDataSource, DataSourceError } from './interfaces'; import { IApiDataSource, DataSourceError } from './interfaces';
export class ApiDataSource implements IApiDataSource { export class ApiDataSource implements IApiDataSource {

View File

@@ -14,7 +14,7 @@ import {
WSGroupTypingMessage, WSGroupTypingMessage,
WSGroupNoticeMessage, WSGroupNoticeMessage,
WSMessageType, WSMessageType,
} from '../../services/wsService'; } from '@/services/core';
// 事件处理器类型 // 事件处理器类型
type EventHandler<T> = (data: T) => void; type EventHandler<T> = (data: T) => void;

View File

@@ -7,7 +7,7 @@ import type {
MaterialFile, MaterialFile,
MaterialFileType, MaterialFileType,
} from '../../types/material'; } from '../../types/material';
import { api } from '../../services/api'; import { api } from '@/services/core';
// ==================== 接口定义 ==================== // ==================== 接口定义 ====================

View File

@@ -14,8 +14,8 @@ import {
PostBatcherOptions, PostBatcherOptions,
createPostUpdateBatcher, createPostUpdateBatcher,
} from '../infrastructure/diff/PostUpdateBatcher'; } from '../infrastructure/diff/PostUpdateBatcher';
import { postSyncService } from '../services/post/PostSyncService'; import { postSyncService } from '@/services/post';
import type { PostsState } from '../services/post/PostSyncService'; import type { PostsState } from '@/services/post';
import { usePostListStore } from '../stores/post/postListStore'; import { usePostListStore } from '../stores/post/postListStore';
import type { Post } from '../core/entities/Post'; import type { Post } from '../core/entities/Post';

View File

@@ -27,8 +27,8 @@ import { SafeAreaView } from 'react-native-safe-area-context';
import { useRouter } from 'expo-router'; import { useRouter } from 'expo-router';
import { MaterialCommunityIcons } from '@expo/vector-icons'; import { MaterialCommunityIcons } from '@expo/vector-icons';
import { useAppColors, useResolvedColorScheme, type AppColors } from '../../theme'; import { useAppColors, useResolvedColorScheme, type AppColors } from '../../theme';
import { authService, resolveAuthApiError } from '../../services/authService'; import { authService, resolveAuthApiError } from '@/services/auth';
import { showPrompt } from '../../services/promptService'; import { showPrompt } from '@/services/ui';
export const ForgotPasswordScreen: React.FC = () => { export const ForgotPasswordScreen: React.FC = () => {
const colors = useAppColors(); const colors = useAppColors();

View File

@@ -30,7 +30,7 @@ import { useAppColors, useResolvedColorScheme, type AppColors } from '../../them
import { useAuthStore } from '../../stores'; import { useAuthStore } from '../../stores';
import * as hrefs from '../../navigation/hrefs'; import * as hrefs from '../../navigation/hrefs';
import { useResponsive } from '../../hooks'; import { useResponsive } from '../../hooks';
import { showPrompt } from '../../services/promptService'; import { showPrompt } from '@/services/ui';

View File

@@ -11,7 +11,7 @@ import {
import { SafeAreaView } from 'react-native-safe-area-context'; import { SafeAreaView } from 'react-native-safe-area-context';
import { MaterialCommunityIcons } from '@expo/vector-icons'; import { MaterialCommunityIcons } from '@expo/vector-icons';
import { useRouter, useLocalSearchParams } from 'expo-router'; import { useRouter, useLocalSearchParams } from 'expo-router';
import { qrcodeApi } from '../../services/authService'; import { qrcodeApi } from '@/services/auth';
import { spacing, fontSizes, borderRadius, useAppColors, type AppColors } from '../../theme'; import { spacing, fontSizes, borderRadius, useAppColors, type AppColors } from '../../theme';
import { AppBackButton } from '../../components/common'; import { AppBackButton } from '../../components/common';

View File

@@ -26,7 +26,7 @@ import { SafeAreaView } from 'react-native-safe-area-context';
import { useRouter } from 'expo-router'; import { useRouter } from 'expo-router';
import { MaterialCommunityIcons } from '@expo/vector-icons'; import { MaterialCommunityIcons } from '@expo/vector-icons';
import { useAppColors, useResolvedColorScheme, type AppColors } from '../../theme'; import { useAppColors, useResolvedColorScheme, type AppColors } from '../../theme';
import { authService, resolveAuthApiError } from '../../services/authService'; import { authService, resolveAuthApiError } from '@/services/auth';
import { useAuthStore } from '../../stores'; import { useAuthStore } from '../../stores';
import { import {
useRegisterStore, useRegisterStore,
@@ -35,7 +35,7 @@ import {
useRegisterCountdown, useRegisterCountdown,
} from '../../stores/registerStore'; } from '../../stores/registerStore';
import * as hrefs from '../../navigation/hrefs'; import * as hrefs from '../../navigation/hrefs';
import { showPrompt } from '../../services/promptService'; import { showPrompt } from '@/services/ui';
import { RegisterStepIndicator } from '../../components/common'; import { RegisterStepIndicator } from '../../components/common';
import { RegisterStepProps, RegisterStep } from './types'; import { RegisterStepProps, RegisterStep } from './types';
import { RegisterStep1Email } from './RegisterStep1Email'; import { RegisterStep1Email } from './RegisterStep1Email';

View File

@@ -22,8 +22,8 @@ import { MaterialCommunityIcons } from '@expo/vector-icons';
import * as ImagePicker from 'expo-image-picker'; import * as ImagePicker from 'expo-image-picker';
import { useAppColors, type AppColors } from '../../theme'; import { useAppColors, type AppColors } from '../../theme';
import { useVerificationStore } from '../../stores/verificationStore'; import { useVerificationStore } from '../../stores/verificationStore';
import { showPrompt } from '../../services/promptService'; import { showPrompt } from '@/services/ui';
import { uploadService } from '../../services/uploadService'; import { uploadService } from '@/services/upload';
import type { UserIdentity } from '../../types/dto'; import type { UserIdentity } from '../../types/dto';
const IDENTITY_CONFIG: Record<string, { title: string; idField: string; idLabel: string }> = { const IDENTITY_CONFIG: Record<string, { title: string; idField: string; idLabel: string }> = {

View File

@@ -35,8 +35,8 @@ import {
} from '../../theme'; } from '../../theme';
import { Text, ResponsiveContainer } from '../../components/common'; import { Text, ResponsiveContainer } from '../../components/common';
import { channelService, postService, showPrompt, voteService } from '../../services'; import { channelService, postService, showPrompt, voteService } from '../../services';
import { ApiError } from '../../services/api'; import { ApiError } from '@/services/core';
import { uploadService } from '../../services/uploadService'; import { uploadService } from '@/services/upload';
import VoteEditor from '../../components/business/VoteEditor'; import VoteEditor from '../../components/business/VoteEditor';
import { useResponsive, useResponsiveValue } from '../../hooks'; import { useResponsive, useResponsiveValue } from '../../hooks';
import * as hrefs from '../../navigation/hrefs'; import * as hrefs from '../../navigation/hrefs';

View File

@@ -34,7 +34,7 @@ import type { PostCardAction } from '../../components/business/PostCard';
import { Loading, EmptyState, Text, ImageGallery, ImageGridItem, ResponsiveGrid } from '../../components/common'; import { Loading, EmptyState, Text, ImageGallery, ImageGridItem, ResponsiveGrid } from '../../components/common';
import { useResponsive, useResponsiveSpacing } from '../../hooks/useResponsive'; import { useResponsive, useResponsiveSpacing } from '../../hooks/useResponsive';
import { useDifferentialPosts } from '../../hooks/useDifferentialPosts'; import { useDifferentialPosts } from '../../hooks/useDifferentialPosts';
import { postSyncService } from '../../services/post/PostSyncService'; import { postSyncService } from '@/services/post';
import { SearchScreen } from './SearchScreen'; import { SearchScreen } from './SearchScreen';
import { CreatePostScreen } from '../create/CreatePostScreen'; import { CreatePostScreen } from '../create/CreatePostScreen';
import * as hrefs from '../../navigation/hrefs'; import * as hrefs from '../../navigation/hrefs';

View File

@@ -37,12 +37,12 @@ import { Post, Comment, VoteResultDTO, VoteOptionDTO } from '../../types';
import { useUserStore } from '../../stores'; import { useUserStore } from '../../stores';
import { useCurrentUser } from '../../stores/authStore'; import { useCurrentUser } from '../../stores/authStore';
import { postService, commentService, uploadService, authService, showPrompt, voteService } from '../../services'; import { postService, commentService, uploadService, authService, showPrompt, voteService } from '../../services';
import { postSyncService } from '../../services/post/PostSyncService'; import { postSyncService } from '@/services/post';
import { useCursorPagination } from '../../hooks/useCursorPagination'; import { useCursorPagination } from '../../hooks/useCursorPagination';
import { CommentItem, VoteCard, ReportDialog } from '../../components/business'; import { CommentItem, VoteCard, ReportDialog } from '../../components/business';
import { Avatar, Button, Loading, EmptyState, Text, ImageGallery, ImageGrid, ImageGridItem, AdaptiveLayout, AppBackButton } from '../../components/common'; import { Avatar, Button, Loading, EmptyState, Text, ImageGallery, ImageGrid, ImageGridItem, AdaptiveLayout, AppBackButton } from '../../components/common';
import { useResponsive, useResponsiveValue, useResponsiveSpacing } from '../../hooks/useResponsive'; import { useResponsive, useResponsiveValue, useResponsiveSpacing } from '../../hooks/useResponsive';
import { handleError } from '../../services/errorHandler'; import { handleError } from '@/services/core';
import * as hrefs from '../../navigation/hrefs'; import * as hrefs from '../../navigation/hrefs';
function togglePostField( function togglePostField(

View File

@@ -20,7 +20,7 @@ import { spacing, fontSizes, borderRadius, useAppColors, type AppColors } from '
import { Post, User } from '../../types'; import { Post, User } from '../../types';
import { useUserStore } from '../../stores'; import { useUserStore } from '../../stores';
import { postService, authService } from '../../services'; import { postService, authService } from '../../services';
import { postSyncService } from '../../services/post/PostSyncService'; import { postSyncService } from '@/services/post';
import { PostCard, TabBar, SearchBar } from '../../components/business'; import { PostCard, TabBar, SearchBar } from '../../components/business';
import type { PostCardAction } from '../../components/business/PostCard'; import type { PostCardAction } from '../../components/business/PostCard';
import { Avatar, EmptyState, Text, ResponsiveGrid, Loading } from '../../components/common'; import { Avatar, EmptyState, Text, ResponsiveGrid, Loading } from '../../components/common';

View File

@@ -22,8 +22,8 @@ import { MaterialCommunityIcons } from '@expo/vector-icons';
import { blurActiveElement } from '../../infrastructure/platform'; import { blurActiveElement } from '../../infrastructure/platform';
import * as ImagePicker from 'expo-image-picker'; import * as ImagePicker from 'expo-image-picker';
import { spacing, fontSizes, borderRadius, shadows, useAppColors, type AppColors } from '../../theme'; import { spacing, fontSizes, borderRadius, shadows, useAppColors, type AppColors } from '../../theme';
import { groupService } from '../../services/groupService'; import { groupService } from '@/services/message';
import { uploadService } from '../../services/uploadService'; import { uploadService } from '@/services/upload';
import { Avatar, Text, Button, Loading } from '../../components/common'; import { Avatar, Text, Button, Loading } from '../../components/common';
import { User } from '../../types'; import { User } from '../../types';
import MutualFollowSelectorModal from './components/MutualFollowSelectorModal'; import MutualFollowSelectorModal from './components/MutualFollowSelectorModal';

View File

@@ -34,9 +34,9 @@ import {
type AppColors, type AppColors,
} from '../../theme'; } from '../../theme';
import { useAuthStore } from '../../stores'; import { useAuthStore } from '../../stores';
import { groupService } from '../../services/groupService'; import { groupService } from '@/services/message';
import { uploadService } from '../../services/uploadService'; import { uploadService } from '@/services/upload';
import { messageService } from '../../services/messageService'; import { messageService } from '@/services/message';
import { Avatar, Text, Button, Loading, Divider } from '../../components/common'; import { Avatar, Text, Button, Loading, Divider } from '../../components/common';
import { useResponsive, useBreakpointGTE } from '../../hooks/useResponsive'; import { useResponsive, useBreakpointGTE } from '../../hooks/useResponsive';
import { import {

View File

@@ -6,7 +6,7 @@ import { MaterialCommunityIcons } from '@expo/vector-icons';
import { spacing, borderRadius, fontSizes, useAppColors, type AppColors } from '../../theme'; import { spacing, borderRadius, fontSizes, useAppColors, type AppColors } from '../../theme';
import { Avatar, Text } from '../../components/common'; import { Avatar, Text } from '../../components/common';
import { routePayloadCache } from '../../stores/routePayloadCache'; import { routePayloadCache } from '../../stores/routePayloadCache';
import { groupService } from '../../services/groupService'; import { groupService } from '@/services/message';
import { groupManager } from '../../stores/groupManager'; import { groupManager } from '../../stores/groupManager';
import { GroupMemberResponse } from '../../types/dto'; import { GroupMemberResponse } from '../../types/dto';
import { GroupInfoSummaryCard, DecisionFooter } from './components/GroupRequestShared'; import { GroupInfoSummaryCard, DecisionFooter } from './components/GroupRequestShared';

View File

@@ -25,7 +25,7 @@ import { MaterialCommunityIcons } from '@expo/vector-icons';
import { blurActiveElement } from '../../infrastructure/platform'; import { blurActiveElement } from '../../infrastructure/platform';
import { spacing, fontSizes, borderRadius, useAppColors, type AppColors } from '../../theme'; import { spacing, fontSizes, borderRadius, useAppColors, type AppColors } from '../../theme';
import { useAuthStore } from '../../stores'; import { useAuthStore } from '../../stores';
import { groupService } from '../../services/groupService'; import { groupService } from '@/services/message';
import { import {
createRemoteGroupMemberListSource, createRemoteGroupMemberListSource,
GroupMemberListSourceKind, GroupMemberListSourceKind,

View File

@@ -8,7 +8,7 @@ import { spacing, borderRadius, shadows, useAppColors, type AppColors } from '..
import { Avatar, Text } from '../../components/common'; import { Avatar, Text } from '../../components/common';
import * as hrefs from '../../navigation/hrefs'; import * as hrefs from '../../navigation/hrefs';
import { routePayloadCache } from '../../stores/routePayloadCache'; import { routePayloadCache } from '../../stores/routePayloadCache';
import { groupService } from '../../services/groupService'; import { groupService } from '@/services/message';
import { groupManager } from '../../stores/groupManager'; import { groupManager } from '../../stores/groupManager';
import { userManager } from '../../stores/userManager'; import { userManager } from '../../stores/userManager';
import { GroupInfoSummaryCard, DecisionFooter } from './components/GroupRequestShared'; import { GroupInfoSummaryCard, DecisionFooter } from './components/GroupRequestShared';

View File

@@ -16,7 +16,7 @@ import { MaterialCommunityIcons } from '@expo/vector-icons';
import { spacing, borderRadius, fontSizes, useAppColors, type AppColors } from '../../theme'; import { spacing, borderRadius, fontSizes, useAppColors, type AppColors } from '../../theme';
import Avatar from '../../components/common/Avatar'; import Avatar from '../../components/common/Avatar';
import Text from '../../components/common/Text'; import Text from '../../components/common/Text';
import { groupService } from '../../services/groupService'; import { groupService } from '@/services/message';
import { groupManager } from '../../stores/groupManager'; import { groupManager } from '../../stores/groupManager';
import { GroupResponse, JoinType } from '../../types/dto'; import { GroupResponse, JoinType } from '../../types/dto';
import { useCursorPagination } from '../../hooks/useCursorPagination'; import { useCursorPagination } from '../../hooks/useCursorPagination';

View File

@@ -30,8 +30,8 @@ import { useRouter } from 'expo-router';
import { MaterialCommunityIcons } from '@expo/vector-icons'; import { MaterialCommunityIcons } from '@expo/vector-icons';
import { spacing, borderRadius, useAppColors, useResolvedColorScheme, type AppColors } from '../../theme'; import { spacing, borderRadius, useAppColors, useResolvedColorScheme, type AppColors } from '../../theme';
import { SystemMessageResponse } from '../../types/dto'; import { SystemMessageResponse } from '../../types/dto';
import { messageService } from '../../services/messageService'; import { messageService } from '@/services/message';
import { commentService } from '../../services/commentService'; import { commentService } from '@/services/post';
import { SystemMessageItem } from '../../components/business'; import { SystemMessageItem } from '../../components/business';
import { Text, ResponsiveContainer } from '../../components/common'; import { Text, ResponsiveContainer } from '../../components/common';
import { useCursorPagination } from '../../hooks/useCursorPagination'; import { useCursorPagination } from '../../hooks/useCursorPagination';

View File

@@ -18,9 +18,9 @@ import { useRouter, useLocalSearchParams } from 'expo-router';
import { MaterialCommunityIcons } from '@expo/vector-icons'; import { MaterialCommunityIcons } from '@expo/vector-icons';
import { spacing, borderRadius, shadows, useAppColors, type AppColors } from '../../theme'; import { spacing, borderRadius, shadows, useAppColors, type AppColors } from '../../theme';
import { useAuthStore } from '../../stores'; import { useAuthStore } from '../../stores';
import { authService } from '../../services/authService'; import { authService } from '@/services/auth';
import { messageService } from '../../services/messageService'; import { messageService } from '@/services/message';
import { ApiError } from '../../services/api'; import { ApiError } from '@/services/core';
import { messageRepository, conversationRepository } from '@/database'; import { messageRepository, conversationRepository } from '@/database';
import { messageManager } from '../../stores/messageManager'; import { messageManager } from '../../stores/messageManager';
import { userManager } from '../../stores/userManager'; import { userManager } from '../../stores/userManager';

View File

@@ -13,7 +13,7 @@ import { Text } from '../../../../components/common';
import { useChatScreenStyles } from './styles'; import { useChatScreenStyles } from './styles';
import { useResponsive, useBreakpointGTE } from '../../../../hooks/useResponsive'; import { useResponsive, useBreakpointGTE } from '../../../../hooks/useResponsive';
import { EMOJIS } from './constants'; import { EMOJIS } from './constants';
import { CustomSticker, getCustomStickers, batchDeleteStickers, addStickerFromUrl } from '../../../../services/stickerService'; import { CustomSticker, getCustomStickers, batchDeleteStickers, addStickerFromUrl } from '@/services/message';
import { useAppColors, spacing } from '../../../../theme'; import { useAppColors, spacing } from '../../../../theme';
import { blurActiveElement } from '../../../../infrastructure/platform'; import { blurActiveElement } from '../../../../infrastructure/platform';

View File

@@ -21,7 +21,7 @@ import { useAppColors, spacing, fontSizes, shadows, type AppColors } from '../..
import { GroupMemberResponse, GroupResponse, GroupAnnouncementResponse } from '../../../../types/dto'; import { GroupMemberResponse, GroupResponse, GroupAnnouncementResponse } from '../../../../types/dto';
import { useBreakpointGTE } from '../../../../hooks/useResponsive'; import { useBreakpointGTE } from '../../../../hooks/useResponsive';
import { groupManager } from '../../../../stores/groupManager'; import { groupManager } from '../../../../stores/groupManager';
import { groupService } from '../../../../services/groupService'; import { groupService } from '@/services/message';
const { width: screenWidth } = Dimensions.get('window'); const { width: screenWidth } = Dimensions.get('window');
const PANEL_WIDTH = 360; const PANEL_WIDTH = 360;

View File

@@ -21,7 +21,7 @@ import { useAppColors, spacing, fontSizes, shadows, borderRadius, type AppColors
import { GroupMemberResponse, GroupResponse, GroupAnnouncementResponse } from '../../../../types/dto'; import { GroupMemberResponse, GroupResponse, GroupAnnouncementResponse } from '../../../../types/dto';
import { useBreakpointGTE } from '../../../../hooks/useResponsive'; import { useBreakpointGTE } from '../../../../hooks/useResponsive';
import { groupManager } from '../../../../stores/groupManager'; import { groupManager } from '../../../../stores/groupManager';
import { groupService } from '../../../../services/groupService'; import { groupService } from '@/services/message';
const { width: screenWidth } = Dimensions.get('window'); const { width: screenWidth } = Dimensions.get('window');
const PANEL_WIDTH = 360; const PANEL_WIDTH = 360;

View File

@@ -19,7 +19,7 @@ import { useChatScreenStyles } from './styles';
import { LongPressMenuProps } from './types'; import { LongPressMenuProps } from './types';
import { RECALL_TIME_LIMIT } from './constants'; import { RECALL_TIME_LIMIT } from './constants';
import { extractTextFromSegments, ImageSegmentData } from '../../../../types/dto'; import { extractTextFromSegments, ImageSegmentData } from '../../../../types/dto';
import { isStickerExists, addStickerFromUrl } from '../../../../services/stickerService'; import { isStickerExists, addStickerFromUrl } from '@/services/message';
import { blurActiveElement } from '../../../../infrastructure/platform'; import { blurActiveElement } from '../../../../infrastructure/platform';
const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } = Dimensions.get('window'); const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } = Dimensions.get('window');

View File

@@ -22,12 +22,12 @@ import { formatDistanceToNow } from 'date-fns';
import { zhCN } from 'date-fns/locale'; import { zhCN } from 'date-fns/locale';
import * as ImagePicker from 'expo-image-picker'; import * as ImagePicker from 'expo-image-picker';
import { GroupMemberResponse, MessageSegment, TextSegmentData, ImageSegmentData, AtSegmentData, ReplySegmentData, MessageStatus } from '../../../../types/dto'; import { GroupMemberResponse, MessageSegment, TextSegmentData, ImageSegmentData, AtSegmentData, ReplySegmentData, MessageStatus } from '../../../../types/dto';
import { messageService } from '../../../../services/messageService'; import { messageService } from '@/services/message';
import { uploadService } from '../../../../services/uploadService'; import { uploadService } from '@/services/upload';
import { ApiError } from '../../../../services/api'; import { ApiError } from '@/services/core';
// 【新架构】使用 MessageManager // 【新架构】使用 MessageManager
import { useChat, useGroupTyping, useGroupMuted, messageManager, callStore } from '../../../../stores'; import { useChat, useGroupTyping, useGroupMuted, messageManager, callStore } from '../../../../stores';
import { groupService } from '../../../../services/groupService'; import { groupService } from '@/services/message';
import { userManager } from '../../../../stores/userManager'; import { userManager } from '../../../../stores/userManager';
import { groupManager } from '../../../../stores/groupManager'; import { groupManager } from '../../../../stores/groupManager';
import * as hrefs from '../../../../navigation/hrefs'; import * as hrefs from '../../../../navigation/hrefs';

View File

@@ -13,7 +13,7 @@ import {
import { MaterialCommunityIcons } from '@expo/vector-icons'; import { MaterialCommunityIcons } from '@expo/vector-icons';
import { spacing, fontSizes, borderRadius, useAppColors, type AppColors } from '../../../theme'; import { spacing, fontSizes, borderRadius, useAppColors, type AppColors } from '../../../theme';
import { authService } from '../../../services/authService'; import { authService } from '@/services/auth';
import { useAuthStore } from '../../../stores'; import { useAuthStore } from '../../../stores';
import { Avatar, EmptyState, Loading, Text } from '../../../components/common'; import { Avatar, EmptyState, Loading, Text } from '../../../components/common';
import { blurActiveElement } from '../../../infrastructure/platform'; import { blurActiveElement } from '../../../infrastructure/platform';

View File

@@ -28,7 +28,7 @@ import {
} from '../../theme'; } from '../../theme';
import { Text } from '../../components/common'; import { Text } from '../../components/common';
import { useResponsive, useResponsiveSpacing } from '../../hooks'; import { useResponsive, useResponsiveSpacing } from '../../hooks';
import { checkForAPKUpdate, type VersionCheckResult } from '../../services/apkUpdateService'; import { checkForAPKUpdate, type VersionCheckResult } from '@/services/platform';
import * as hrefs from '../../navigation/hrefs'; import * as hrefs from '../../navigation/hrefs';
const CONTENT_MAX_WIDTH = 720; const CONTENT_MAX_WIDTH = 720;

View File

@@ -16,8 +16,8 @@ import { useResponsive, useResponsiveSpacing } from '../../hooks';
// 内容最大宽度 // 内容最大宽度
const CONTENT_MAX_WIDTH = 720; const CONTENT_MAX_WIDTH = 720;
import { authService, resolveAuthApiError } from '../../services/authService'; import { authService, resolveAuthApiError } from '@/services/auth';
import { showPrompt } from '../../services/promptService'; import { showPrompt } from '@/services/ui';
import { useAuthStore } from '../../stores'; import { useAuthStore } from '../../stores';
export const AccountSecurityScreen: React.FC = () => { export const AccountSecurityScreen: React.FC = () => {

View File

@@ -22,9 +22,9 @@ import {
setPushNotificationsPreference, setPushNotificationsPreference,
setSoundPreference, setSoundPreference,
setVibrationPreference, setVibrationPreference,
} from '../../services/notificationPreferences'; } from '@/services/notification';
import { useResponsive, useResponsiveSpacing } from '../../hooks'; import { useResponsive, useResponsiveSpacing } from '../../hooks';
import { backgroundSyncManager, BackgroundSyncMode } from '../../services/BackgroundSyncManager'; import { backgroundSyncManager, BackgroundSyncMode } from '@/services/background';
// 内容最大宽度 // 内容最大宽度
const CONTENT_MAX_WIDTH = 720; const CONTENT_MAX_WIDTH = 720;

View File

@@ -23,7 +23,7 @@ import {
useVerificationStatus, useVerificationStatus,
useVerificationLoading, useVerificationLoading,
} from '../../stores/verificationStore'; } from '../../stores/verificationStore';
import { showPrompt } from '../../services/promptService'; import { showPrompt } from '@/services/ui';
import * as hrefs from '../../navigation/hrefs'; import * as hrefs from '../../navigation/hrefs';
const STATUS_CONFIG = { const STATUS_CONFIG = {

View File

@@ -12,7 +12,7 @@ import { Post, User } from '../../types';
import { useUserStore } from '../../stores'; import { useUserStore } from '../../stores';
import { useCurrentUser } from '../../stores/authStore'; import { useCurrentUser } from '../../stores/authStore';
import { postService, authService, messageService } from '../../services'; import { postService, authService, messageService } from '../../services';
import { postSyncService } from '../../services/post/PostSyncService'; import { postSyncService } from '@/services/post';
import { userManager } from '../../stores/userManager'; import { userManager } from '../../stores/userManager';
import * as hrefs from '../../navigation/hrefs'; import * as hrefs from '../../navigation/hrefs';
import { PostCardAction } from '../../components/business/PostCard'; import { PostCardAction } from '../../components/business/PostCard';

View File

@@ -6,7 +6,7 @@ import { MaterialCommunityIcons } from '@expo/vector-icons';
import { spacing, borderRadius, fontSizes, shadows, useAppColors, type AppColors } from '../../theme'; import { spacing, borderRadius, fontSizes, shadows, useAppColors, type AppColors } from '../../theme';
import { routePayloadCache } from '../../stores/routePayloadCache'; import { routePayloadCache } from '../../stores/routePayloadCache';
import { scheduleService } from '../../services/scheduleService'; import { scheduleService } from '@/services/platform';
const WEEKDAY_NAMES = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']; const WEEKDAY_NAMES = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];
const getMergedSectionIndex = (section: number) => Math.ceil(section / 2); const getMergedSectionIndex = (section: number) => Math.ceil(section / 2);

View File

@@ -43,7 +43,7 @@ import {
} from '../../types/schedule'; } from '../../types/schedule';
import * as hrefs from '../../navigation/hrefs'; import * as hrefs from '../../navigation/hrefs';
import { routePayloadCache } from '../../stores/routePayloadCache'; import { routePayloadCache } from '../../stores/routePayloadCache';
import { scheduleService } from '../../services/scheduleService'; import { scheduleService } from '@/services/platform';
const { width: SCREEN_WIDTH } = Dimensions.get('window'); const { width: SCREEN_WIDTH } = Dimensions.get('window');

View File

@@ -3,8 +3,9 @@
* *
*/ */
import { api } from './api'; import { api } from '../core/api';
import { User } from '../types'; import { User } from '@/types';
import type { PrivacySettingsDTO, PrivacySettingsRequestDTO, DeletionStatusDTO } from '@/types/dto';
export function resolveAuthApiError(error: any, fallback = '操作失败,请稍后重试'): string { export function resolveAuthApiError(error: any, fallback = '操作失败,请稍后重试'): string {
const code: number = error?.code ?? 0; const code: number = error?.code ?? 0;
@@ -160,6 +161,7 @@ class AuthService {
if (refreshToken) { if (refreshToken) {
await api.setRefreshToken(refreshToken); await api.setRefreshToken(refreshToken);
} }
api.resetAuthState();
return response.data; return response.data;
} }
@@ -178,6 +180,7 @@ class AuthService {
if (refreshToken) { if (refreshToken) {
await api.setRefreshToken(refreshToken); await api.setRefreshToken(refreshToken);
} }
api.resetAuthState();
return response.data; return response.data;
} }
@@ -457,9 +460,9 @@ class AuthService {
} }
// 隐私设置 // 隐私设置
async getPrivacySettings(): Promise<import('../types/dto').PrivacySettingsDTO | null> { async getPrivacySettings(): Promise<PrivacySettingsDTO | null> {
try { try {
const response = await api.get<import('../types/dto').PrivacySettingsDTO>('/users/me/privacy'); const response = await api.get<PrivacySettingsDTO>('/users/me/privacy');
return response.data; return response.data;
} catch (error) { } catch (error) {
console.error('获取隐私设置失败:', error); console.error('获取隐私设置失败:', error);
@@ -467,7 +470,7 @@ class AuthService {
} }
} }
async updatePrivacySettings(settings: import('../types/dto').PrivacySettingsRequestDTO): Promise<boolean> { async updatePrivacySettings(settings: PrivacySettingsRequestDTO): Promise<boolean> {
try { try {
await api.put('/users/me/privacy', settings); await api.put('/users/me/privacy', settings);
return true; return true;
@@ -478,9 +481,9 @@ class AuthService {
} }
// 账号注销 // 账号注销
async requestAccountDeletion(password: string): Promise<import('../types/dto').DeletionStatusDTO | null> { async requestAccountDeletion(password: string): Promise<DeletionStatusDTO | null> {
try { try {
const response = await api.post<import('../types/dto').DeletionStatusDTO>('/users/me/deactivate', { const response = await api.post<DeletionStatusDTO>('/users/me/deactivate', {
password, password,
}); });
return response.data; return response.data;
@@ -500,9 +503,9 @@ class AuthService {
} }
} }
async getDeletionStatus(): Promise<import('../types/dto').DeletionStatusDTO | null> { async getDeletionStatus(): Promise<DeletionStatusDTO | null> {
try { try {
const response = await api.get<import('../types/dto').DeletionStatusDTO>('/users/me/deletion-status'); const response = await api.get<DeletionStatusDTO>('/users/me/deletion-status');
return response.data; return response.data;
} catch (error) { } catch (error) {
console.error('获取注销状态失败:', error); console.error('获取注销状态失败:', error);

View File

@@ -0,0 +1,18 @@
export { authService, resolveAuthApiError, qrcodeApi } from './authService';
export type {
LoginRequest,
RegisterRequest,
SendEmailCodeRequest,
ResetPasswordRequest,
VerifyCurrentUserEmailRequest,
AuthResponse,
RefreshTokenResponse,
UpdateUserRequest,
BlockedUserListResponse,
BlockStatusResponse,
QRCodeSession,
ScanResponse,
} from './authService';
export { verificationService } from './verificationService';
export type { SubmitVerificationResponse } from './verificationService';

View File

@@ -3,13 +3,13 @@
* *
*/ */
import { api } from './api'; import { api } from '../core/api';
import { import {
VerificationStatusDTO, VerificationStatusDTO,
VerificationRecordDTO, VerificationRecordDTO,
SubmitVerificationRequest, SubmitVerificationRequest,
PaginatedData, PaginatedData,
} from '../types/dto'; } from '@/types/dto';
// 提交认证响应 // 提交认证响应
export interface SubmitVerificationResponse { export interface SubmitVerificationResponse {

View File

@@ -7,7 +7,7 @@
import { AppState, AppStateStatus, Platform } from 'react-native'; import { AppState, AppStateStatus, Platform } from 'react-native';
import { ForegroundServiceModule } from './ForegroundServiceModule'; import { ForegroundServiceModule } from './ForegroundServiceModule';
import { wsService } from './wsService'; import { wsService } from '../core/wsService';
import AsyncStorage from '@react-native-async-storage/async-storage'; import AsyncStorage from '@react-native-async-storage/async-storage';
/** /**

View File

@@ -15,8 +15,8 @@ import {
backgroundSyncManager, backgroundSyncManager,
BackgroundSyncMode, BackgroundSyncMode,
} from './BackgroundSyncManager'; } from './BackgroundSyncManager';
import { messageService } from './messageService'; import { messageService } from '../message/messageService';
import { api } from './api'; import { api } from '../core/api';
// 后台任务名称 // 后台任务名称
const BACKGROUND_SYNC_TASK = 'background-sync-task'; const BACKGROUND_SYNC_TASK = 'background-sync-task';
@@ -215,7 +215,7 @@ export {
setVibrationConfig, setVibrationConfig,
getVibrationConfig, getVibrationConfig,
setVibrationEnabled, setVibrationEnabled,
} from './messageVibrationService'; } from '../platform/messageVibrationService';
// 重新导出类型 // 重新导出类型
export { BackgroundSyncMode }; export { BackgroundSyncMode };
@@ -230,7 +230,7 @@ export const backgroundService = {
checkStatus: checkBackgroundStatus, checkStatus: checkBackgroundStatus,
// 震动相关 // 震动相关
vibrate: async () => { vibrate: async () => {
const { triggerVibration } = await import('./messageVibrationService'); const { triggerVibration } = await import('../platform/messageVibrationService');
triggerVibration(); triggerVibration();
}, },
}; };

View File

@@ -0,0 +1,19 @@
export {
backgroundService,
initBackgroundService,
stopBackgroundService,
triggerVibration,
vibrateOnMessage,
setVibrationConfig,
getVibrationConfig,
setVibrationEnabled,
checkBackgroundStatus,
setBackgroundSyncMode,
getBackgroundSyncMode,
syncNow,
} from './backgroundService';
export { BackgroundSyncMode, backgroundSyncManager } from './BackgroundSyncManager';
export { ForegroundServiceModule } from './ForegroundServiceModule';
export type { ForegroundServiceOptions } from './ForegroundServiceModule';

View File

@@ -75,6 +75,7 @@ class ApiClient {
private baseUrl: string; private baseUrl: string;
private verificationModalShown = false; private verificationModalShown = false;
private refreshLock: Promise<boolean> | null = null; private refreshLock: Promise<boolean> | null = null;
private isAuthFailed = false; // 全局认证失败标志,防止无限重试
constructor(baseUrl: string) { constructor(baseUrl: string) {
this.baseUrl = baseUrl; this.baseUrl = baseUrl;
@@ -90,10 +91,17 @@ class ApiClient {
} }
private navigateToLogin() { private navigateToLogin() {
this.isAuthFailed = true; // 设置全局失败标志
eventBus.emit({ type: 'NAVIGATE', payload: { path: '/(auth)/login' } }); eventBus.emit({ type: 'NAVIGATE', payload: { path: '/(auth)/login' } });
eventBus.emit({ type: 'AUTH_LOGOUT' }); eventBus.emit({ type: 'AUTH_LOGOUT' });
} }
// 重置认证状态(登录成功后调用)
resetAuthState() {
this.isAuthFailed = false;
this.refreshLock = null;
}
private parseJwt(token: string): JwtPayload | null { private parseJwt(token: string): JwtPayload | null {
try { try {
const parts = token.split('.'); const parts = token.split('.');
@@ -167,13 +175,22 @@ class ApiClient {
} }
} }
// 不需要认证的路径前缀
private static PUBLIC_PATHS = ['/auth/login', '/auth/register', '/auth/password/', '/auth/check-username', '/auth/qrcode', '/auth/refresh'];
// 统一请求方法 // 统一请求方法
private async request<T>( private async request<T>(
method: string, method: string,
path: string, path: string,
params?: Record<string, any>, params?: Record<string, any>,
body?: any body?: any,
_retryCount = 0,
): Promise<ApiResponse<T>> { ): Promise<ApiResponse<T>> {
// 认证已失败,仅放行公开路径(登录、注册等)
if (this.isAuthFailed && !ApiClient.PUBLIC_PATHS.some(p => path.startsWith(p))) {
throw new ApiError(401, '登录已过期,请重新登录');
}
const url = new URL(`${this.baseUrl}${path}`); const url = new URL(`${this.baseUrl}${path}`);
// 添加查询参数 // 添加查询参数
@@ -226,6 +243,11 @@ class ApiClient {
// 处理 401 未授权 // 处理 401 未授权
if (response.status === 401) { if (response.status === 401) {
if (_retryCount >= 1) {
await this.clearToken();
this.navigateToLogin();
throw new ApiError(401, '登录已过期,请重新登录');
}
const refreshed = await this.refreshToken(); const refreshed = await this.refreshToken();
if (!refreshed) { if (!refreshed) {
await this.clearToken(); await this.clearToken();
@@ -233,7 +255,7 @@ class ApiClient {
throw new ApiError(401, '登录已过期,请重新登录'); throw new ApiError(401, '登录已过期,请重新登录');
} }
return this.request(method, path, params, body); return this.request(method, path, params, body, _retryCount + 1);
} }
// 解析响应(兼容非 JSON 返回,避免 SyntaxError 被误判为网络错误) // 解析响应(兼容非 JSON 返回,避免 SyntaxError 被误判为网络错误)

View File

@@ -10,7 +10,7 @@
* console.error + Alert * console.error + Alert
*/ */
import { showPrompt } from './promptService'; import { showPrompt } from '../ui/promptService';
export enum AppErrorCode { export enum AppErrorCode {
NETWORK_ERROR = 'NETWORK_ERROR', NETWORK_ERROR = 'NETWORK_ERROR',

View File

@@ -0,0 +1,39 @@
export { api, WS_URL, TOKEN_KEY, REFRESH_TOKEN_KEY } from './api';
export { ApiError } from './api';
export type { ApiResponse, PaginatedData } from './api';
export { wsService } from './wsService';
export type {
WSMessage,
WSMessageType,
WSChatMessage,
WSReadMessage,
WSTypingMessage,
WSRecallMessage,
WSNotificationMessage,
WSAnnouncementMessage,
WSGroupChatMessage,
WSGroupTypingMessage,
GroupNoticeType,
WSGroupNoticeMessage,
WSGroupMentionMessage,
WSGroupReadMessage,
WSGroupRecallMessage,
WSCallIncomingMessage,
WSCallAcceptedMessage,
WSCallRejectedMessage,
WSCallBusyMessage,
WSCallEndedMessage,
WSCallSDPMessage,
WSCallICEMessage,
WSCallPeerMutedMessage,
WSCallInvitedMessage,
WSCallAnsweredElsewhereMessage,
WSErrorMessage,
WSServerMessage,
ICEServerConfig,
} from './wsService';
export { handleError, createErrorHandler, safeAsync, createAppError } from './errorHandler';
export type { AppError, ErrorHandlerOptions } from './errorHandler';
export { AppErrorCode } from './errorHandler';

View File

@@ -2,8 +2,8 @@ import { AppState, AppStateStatus } from 'react-native';
import { api, WS_URL } from './api'; import { api, WS_URL } from './api';
import { eventBus } from '@/core/events/EventBus'; import { eventBus } from '@/core/events/EventBus';
import { MessageCategory, SystemMessageType, SystemMessageExtraData, MessageSegment } from '../types/dto'; import { MessageCategory, SystemMessageType, SystemMessageExtraData, MessageSegment } from '@/types/dto';
import { systemNotificationService } from './systemNotificationService'; import { systemNotificationService } from '../notification/systemNotificationService';
export type WSMessageType = export type WSMessageType =
| 'chat' | 'chat'

View File

@@ -1,54 +1,6 @@
/** export { api, WS_URL, TOKEN_KEY, REFRESH_TOKEN_KEY, ApiError } from './core';
* 服务导出 export type { ApiResponse, PaginatedData } from './core';
* 统一导出所有API服务 export { wsService } from './core';
*/
// API 客户端
export { api, WS_URL, TOKEN_KEY, REFRESH_TOKEN_KEY } from './api';
export type { ApiResponse, PaginatedData, ApiError } from './api';
// 认证服务
export { authService } from './authService';
export { resolveAuthApiError } from './authService';
export type {
LoginRequest,
RegisterRequest,
SendEmailCodeRequest,
ResetPasswordRequest,
VerifyCurrentUserEmailRequest,
AuthResponse,
RefreshTokenResponse,
UpdateUserRequest,
BlockedUserListResponse,
BlockStatusResponse,
} from './authService';
// 帖子服务
export { postService } from './postService';
// 评论服务
export { commentService } from './commentService';
// 消息服务
export { messageService } from './messageService';
// 通知服务
export { notificationService } from './notificationService';
// 文件上传服务
export { uploadService } from './uploadService';
export type { UploadResponse } from './uploadService';
// 推送服务
export { pushService, registerDevice, getDevices, unregisterDevice, updateDeviceToken, getPushRecords } from './pushService';
// 投票服务
export { voteService } from './voteService';
export { channelService } from './channelService';
export type { ChannelItem } from './channelService';
// WebSocket 实时服务
export { wsService } from './wsService';
export type { export type {
WSMessage, WSMessage,
WSMessageType, WSMessageType,
@@ -64,15 +16,32 @@ export type {
WSGroupNoticeMessage, WSGroupNoticeMessage,
WSGroupMentionMessage, WSGroupMentionMessage,
WSGroupReadMessage, WSGroupReadMessage,
WSGroupRecallMessage WSGroupRecallMessage,
} from './wsService'; } from './core';
export { handleError, createErrorHandler, safeAsync, createAppError, AppErrorCode } from './core';
export type { AppError, ErrorHandlerOptions } from './core';
// 系统通知服务 export { authService, resolveAuthApiError } from './auth';
export { systemNotificationService, getNotificationTitle } from './systemNotificationService'; export type {
export type { AppNotificationType } from './systemNotificationService'; LoginRequest,
RegisterRequest,
SendEmailCodeRequest,
ResetPasswordRequest,
VerifyCurrentUserEmailRequest,
AuthResponse,
RefreshTokenResponse,
UpdateUserRequest,
BlockedUserListResponse,
BlockStatusResponse,
} from './auth';
export { verificationService } from './auth';
export type { SubmitVerificationResponse } from './auth';
// 群组服务 export { postService, commentService, voteService, channelService, reportService } from './post';
export { groupService } from './groupService'; export type { ChannelItem } from './post';
export { messageService } from './message';
export { groupService } from './message';
export type { export type {
GroupResponse, GroupResponse,
GroupMemberResponse, GroupMemberResponse,
@@ -88,13 +57,16 @@ export type {
SetMuteAllRequest, SetMuteAllRequest,
SetJoinTypeRequest, SetJoinTypeRequest,
CreateAnnouncementRequest, CreateAnnouncementRequest,
} from './groupService'; } from './message';
// 课表服务 export { notificationService } from './notification';
export { scheduleService } from './scheduleService'; export { systemNotificationService, getNotificationTitle } from './notification';
export type { CreateScheduleCourseRequest } from './scheduleService'; export type { AppNotificationType } from './notification';
export { pushService, registerDevice, getDevices, unregisterDevice, updateDeviceToken, getPushRecords } from './notification';
export { uploadService } from './upload';
export type { UploadResponse } from './upload';
// 后台保活服务
export { export {
backgroundService, backgroundService,
initBackgroundService, initBackgroundService,
@@ -105,21 +77,12 @@ export {
getVibrationConfig, getVibrationConfig,
setVibrationEnabled, setVibrationEnabled,
checkBackgroundStatus, checkBackgroundStatus,
} from './backgroundService'; } from './background';
// 统一提示/弹窗服务 export { showPrompt } from './ui';
export { showPrompt } from './promptService'; export { showConfirm } from './ui';
export { showConfirm } from './dialogService';
// 统一错误处理服务 export { apkUpdateService, checkForAPKUpdate, manualCheckForUpdate } from './platform';
export { handleError, createErrorHandler, safeAsync, createAppError } from './errorHandler'; export type { APKVersionInfo, VersionCheckResult } from './platform';
export type { AppError, ErrorHandlerOptions } from './errorHandler'; export { scheduleService } from './platform';
export { AppErrorCode } from './errorHandler'; export type { CreateScheduleCourseRequest } from './platform';
// APK 更新检查服务
export { apkUpdateService, checkForAPKUpdate, manualCheckForUpdate } from './apkUpdateService';
export type { APKVersionInfo, VersionCheckResult } from './apkUpdateService';
// 身份认证服务
export { verificationService } from './verificationService';
export type { SubmitVerificationResponse } from './verificationService';

View File

@@ -4,7 +4,7 @@
* 使 RESTful API: /api/v1/groups * 使 RESTful API: /api/v1/groups
*/ */
import { api } from './api'; import { api } from '../core/api';
import { import {
GroupResponse, GroupResponse,
GroupMemberResponse, GroupMemberResponse,
@@ -25,7 +25,7 @@ import {
HandleGroupRequestAction, HandleGroupRequestAction,
CursorPaginationRequest, CursorPaginationRequest,
CursorPaginationResponse, CursorPaginationResponse,
} from '../types/dto'; } from '@/types/dto';
function asGroupId(raw: unknown): string { function asGroupId(raw: unknown): string {
return String(raw); return String(raw);

View File

@@ -0,0 +1,42 @@
export { messageService } from './messageService';
export type { RemoteConversationListPageResult } from './messageService';
export type {
ConversationListResponse,
ConversationResponse,
ConversationDetailResponse,
MessageListResponse,
MessageResponse,
SendMessageRequest,
UnreadCountResponse,
ConversationUnreadCountResponse,
SystemMessageListResponse,
SystemUnreadCountResponse,
} from './messageService';
export { groupService } from './groupService';
export type {
GroupResponse,
GroupMemberResponse,
GroupAnnouncementResponse,
GroupListResponse,
GroupMemberListResponse,
GroupAnnouncementListResponse,
CreateGroupRequest,
InviteMembersRequest,
TransferOwnerRequest,
SetRoleRequest,
SetNicknameRequest,
SetMuteAllRequest,
SetJoinTypeRequest,
CreateAnnouncementRequest,
} from './groupService';
export type { CustomSticker } from './stickerService';
export {
getCustomStickers,
addStickerFromUrl,
deleteSticker,
isStickerExists,
reorderStickers,
batchDeleteStickers,
} from './stickerService';

View File

@@ -4,8 +4,8 @@
* 使 API : /api/v1/conversations (RESTful action ) * 使 API : /api/v1/conversations (RESTful action )
*/ */
import { api } from './api'; import { api } from '../core/api';
import { wsService } from './wsService'; import { wsService } from '../core/wsService';
import { import {
ConversationListResponse, ConversationListResponse,
ConversationResponse, ConversationResponse,
@@ -21,7 +21,7 @@ import {
MessageSegment, MessageSegment,
CursorPaginationRequest, CursorPaginationRequest,
CursorPaginationResponse, CursorPaginationResponse,
} from '../types/dto'; } from '@/types/dto';
import { conversationRepository, userCacheRepository } from '@/database'; import { conversationRepository, userCacheRepository } from '@/database';
/** 远端会话列表分页offset / cursor统一结果拉取成功后均已执行本地缓存同步 */ /** 远端会话列表分页offset / cursor统一结果拉取成功后均已执行本地缓存同步 */

View File

@@ -3,8 +3,8 @@
* *
*/ */
import { api } from './api'; import { api } from '../core/api';
import { uploadService } from './uploadService'; import { uploadService } from '../upload/uploadService';
// 自定义表情类型 // 自定义表情类型
export interface CustomSticker { export interface CustomSticker {

View File

@@ -0,0 +1,17 @@
export { notificationService } from './notificationService';
export { systemNotificationService, getNotificationTitle } from './systemNotificationService';
export type { AppNotificationType } from './systemNotificationService';
export {
NOTIFICATION_PREF_KEYS,
getNotificationPreferencesSync,
loadNotificationPreferences,
setVibrationPreference,
setPushNotificationsPreference,
setSoundPreference,
registerNotificationPresentationHandler,
} from './notificationPreferences';
export type { NotificationPrefs } from './notificationPreferences';
export { pushService, registerDevice, getDevices, unregisterDevice, updateDeviceToken, getPushRecords } from './pushService';

View File

@@ -5,7 +5,7 @@
import AsyncStorage from '@react-native-async-storage/async-storage'; import AsyncStorage from '@react-native-async-storage/async-storage';
import * as Notifications from 'expo-notifications'; import * as Notifications from 'expo-notifications';
import { setVibrationEnabled } from './messageVibrationService'; import { setVibrationEnabled } from '../platform/messageVibrationService';
export const NOTIFICATION_PREF_KEYS = { export const NOTIFICATION_PREF_KEYS = {
/** 与历史版本保持一致 */ /** 与历史版本保持一致 */

View File

@@ -3,9 +3,9 @@
* *
*/ */
import { api, PaginatedData } from './api'; import { api, PaginatedData } from '../core/api';
import { Notification, NotificationBadge, NotificationType } from '../types'; import { Notification, NotificationBadge, NotificationType } from '@/types';
import { CursorPaginationRequest, CursorPaginationResponse } from '../types/dto'; import { CursorPaginationRequest, CursorPaginationResponse } from '@/types/dto';
// 通知列表响应 // 通知列表响应
interface NotificationListResponse { interface NotificationListResponse {

View File

@@ -2,12 +2,12 @@
* - Token和推送记录 * - Token和推送记录
*/ */
import { api } from './api'; import { api } from '../core/api';
import { import {
DeviceTokenResponse, DeviceTokenResponse,
RegisterDeviceRequest, RegisterDeviceRequest,
PushRecordResponse PushRecordResponse
} from '../types/dto'; } from '@/types/dto';
// 推送服务类 // 推送服务类
class PushService { class PushService {

View File

@@ -6,10 +6,10 @@
import * as Notifications from 'expo-notifications'; import * as Notifications from 'expo-notifications';
import { Platform, AppState, AppStateStatus } from 'react-native'; import { Platform, AppState, AppStateStatus } from 'react-native';
import type { WSChatMessage, WSNotificationMessage, WSAnnouncementMessage } from './wsService'; import type { WSChatMessage, WSNotificationMessage, WSAnnouncementMessage } from '../core/wsService';
import { extractTextFromSegments } from '../types/dto'; import { extractTextFromSegments } from '@/types/dto';
import { getNotificationPreferencesSync } from './notificationPreferences'; import { getNotificationPreferencesSync } from './notificationPreferences';
import { vibrateOnMessage } from './messageVibrationService'; import { vibrateOnMessage } from '../platform/messageVibrationService';
// 通知渠道配置 // 通知渠道配置
const CHANNEL_ID = 'default'; const CHANNEL_ID = 'default';

View File

@@ -6,7 +6,7 @@
import { Platform, Linking, Alert } from 'react-native'; import { Platform, Linking, Alert } from 'react-native';
import Constants from 'expo-constants'; import Constants from 'expo-constants';
import AsyncStorage from '@react-native-async-storage/async-storage'; import AsyncStorage from '@react-native-async-storage/async-storage';
import { showConfirm } from './dialogService'; import { showConfirm } from '../ui/dialogService';
// 条件导入原生模块(仅在 Android 上可用) // 条件导入原生模块(仅在 Android 上可用)
// eslint-disable-next-line @typescript-eslint/no-var-requires // eslint-disable-next-line @typescript-eslint/no-var-requires

View File

@@ -0,0 +1,13 @@
export { apkUpdateService, checkForAPKUpdate, manualCheckForUpdate } from './apkUpdateService';
export type { APKVersionInfo, VersionCheckResult } from './apkUpdateService';
export { scheduleService } from './scheduleService';
export type { CreateScheduleCourseRequest, SyncScheduleRequest } from './scheduleService';
export {
triggerVibration,
vibrateOnMessage,
setVibrationConfig,
getVibrationConfig,
setVibrationEnabled,
} from './messageVibrationService';

View File

@@ -1,5 +1,5 @@
import { api } from './api'; import { api } from '../core/api';
import { Course } from '../types/schedule'; import { Course } from '@/types/schedule';
interface ScheduleCourseDTO { interface ScheduleCourseDTO {
id: string; id: string;

View File

@@ -1,4 +1,4 @@
import { api } from './api'; import { api } from '../core/api';
export interface ChannelItem { export interface ChannelItem {
id: string; id: string;

View File

@@ -3,9 +3,9 @@
* *
*/ */
import { api, PaginatedData } from './api'; import { api, PaginatedData } from '../core/api';
import { Comment, CreateCommentInput } from '../types'; import { Comment, CreateCommentInput } from '@/types';
import { CursorPaginationRequest, CursorPaginationResponse, CommentDTO } from '../types/dto'; import { CursorPaginationRequest, CursorPaginationResponse, CommentDTO } from '@/types/dto';
// 评论列表响应 // 评论列表响应
interface CommentListResponse { interface CommentListResponse {

View File

@@ -0,0 +1,15 @@
export { postService } from './postService';
export { commentService } from './commentService';
export { voteService } from './voteService';
export { channelService } from './channelService';
export type { ChannelItem } from './channelService';
export { reportService, REPORT_REASONS } from './reportService';
export type { ReportReason, ReportTargetType, ReportResponse } from './reportService';
export { postSyncService } from './PostSyncService';
export type { PostDetailState, PostsState } from './PostSyncService';
export { mergePostListWithFastPath, mergeRefreshWindow } from './postMerge';

View File

@@ -3,9 +3,9 @@
* 使 postSyncService * 使 postSyncService
*/ */
import { api, PaginatedData } from './api'; import { api, PaginatedData } from '../core/api';
import { Post, CreatePostInput } from '../types'; import { Post, CreatePostInput } from '@/types';
import { CursorPaginationRequest, CursorPaginationResponse } from '../types/dto'; import { CursorPaginationRequest, CursorPaginationResponse } from '@/types/dto';
// 帖子列表响应 // 帖子列表响应
interface PostListResponse { interface PostListResponse {

View File

@@ -3,7 +3,7 @@
* *
*/ */
import { api } from './api'; import { api } from '../core/api';
// 举报原因类型 // 举报原因类型
export type ReportReason = 'spam' | 'inappropriate' | 'harassment' | 'misinformation' | 'other'; export type ReportReason = 'spam' | 'inappropriate' | 'harassment' | 'misinformation' | 'other';

View File

@@ -3,8 +3,8 @@
* API调用 * API调用
*/ */
import { api } from './api'; import { api } from '../core/api';
import { Post, VoteResultDTO, CreateVotePostRequest } from '../types'; import { Post, VoteResultDTO, CreateVotePostRequest } from '@/types';
// 投票响应 // 投票响应
interface VoteResponse { interface VoteResponse {

16
src/services/ui/index.ts Normal file
View File

@@ -0,0 +1,16 @@
export {
showPrompt,
bindPromptListener,
PromptType,
PromptPayload,
} from './promptService';
export {
showDialog,
bindDialogListener,
showConfirm,
DialogPayload,
ConfirmOptions,
} from './dialogService';
export { installAlertOverride } from './alertOverride';

View File

@@ -0,0 +1,2 @@
export { uploadService } from './uploadService';
export type { UploadResponse } from './uploadService';

View File

@@ -3,7 +3,7 @@
* *
*/ */
import { api } from './api'; import { api } from '../core/api';
/** /**
* URI mimeType * URI mimeType

View File

@@ -14,7 +14,7 @@ import AsyncStorage from '@react-native-async-storage/async-storage';
import { create } from 'zustand'; import { create } from 'zustand';
import { User } from '../types'; import { User } from '../types';
import { authService, resolveAuthApiError, LoginRequest, RegisterRequest } from '../services'; import { authService, resolveAuthApiError, LoginRequest, RegisterRequest } from '../services';
import { wsService } from '../services/wsService'; import { wsService } from '@/services/core';
import { callStore } from './callStore'; import { callStore } from './callStore';
import { useSessionStore } from './sessionStore'; import { useSessionStore } from './sessionStore';
import { import {

View File

@@ -6,8 +6,8 @@ import {
WSCallSDPMessage, WSCallSDPMessage,
WSCallICEMessage, WSCallICEMessage,
WSErrorMessage, WSErrorMessage,
} from '../services/wsService'; } from '@/services/core';
import { webrtcManager, ICEServer } from '../services/webrtc'; import { webrtcManager, ICEServer } from '@/services/webrtc';
import { getCurrentUserId } from './sessionStore'; import { getCurrentUserId } from './sessionStore';
import { useUserStore } from './userStore'; import { useUserStore } from './userStore';
import { userManager } from './userManager'; import { userManager } from './userManager';

View File

@@ -3,7 +3,7 @@
*/ */
import { ConversationResponse } from '../types/dto'; import { ConversationResponse } from '../types/dto';
import { messageService } from '../services/messageService'; import { messageService } from '@/services/message';
import { conversationRepository } from '@/database'; import { conversationRepository } from '@/database';
export const CONVERSATION_LIST_PAGE_SIZE = 20; export const CONVERSATION_LIST_PAGE_SIZE = 20;

View File

@@ -4,7 +4,7 @@ import type {
GroupMemberResponse, GroupMemberResponse,
GroupResponse, GroupResponse,
} from '../../types/dto'; } from '../../types/dto';
import { groupService } from '../../services/groupService'; import { groupService } from '@/services/message';
import { groupCacheRepository, userCacheRepository } from '@/database'; import { groupCacheRepository, userCacheRepository } from '@/database';
import { useGroupManagerStore } from './groupStore'; import { useGroupManagerStore } from './groupStore';
import { createCacheEntry, isCacheExpired, DEFAULT_TTL } from '../utils/cache'; import { createCacheEntry, isCacheExpired, DEFAULT_TTL } from '../utils/cache';

View File

@@ -9,7 +9,7 @@ import {
GroupMemberListResponse, GroupMemberListResponse,
CursorPaginationRequest, CursorPaginationRequest,
} from '../types/dto'; } from '../types/dto';
import { groupService } from '../services/groupService'; import { groupService } from '@/services/message';
import { groupCacheRepository } from '@/database'; import { groupCacheRepository } from '@/database';
export const GROUP_LIST_PAGE_SIZE = 20; export const GROUP_LIST_PAGE_SIZE = 20;

View File

@@ -1,4 +1,4 @@
import { groupService } from '../services/groupService'; import { groupService } from '@/services/message';
import { CursorPaginationResponse, GroupMemberResponse } from '../types/dto'; import { CursorPaginationResponse, GroupMemberResponse } from '../types/dto';
export const GROUP_MEMBER_LIST_PAGE_SIZE = 50; export const GROUP_MEMBER_LIST_PAGE_SIZE = 50;

View File

@@ -8,7 +8,7 @@
*/ */
import type { ConversationResponse } from '../../../types/dto'; import type { ConversationResponse } from '../../../types/dto';
import { messageService } from '../../../services/messageService'; import { messageService } from '@/services/message';
import { conversationRepository } from '@/database'; import { conversationRepository } from '@/database';
import type { IConversationOperations } from '../types'; import type { IConversationOperations } from '../types';
import { useMessageStore, normalizeConversationId } from '../store'; import { useMessageStore, normalizeConversationId } from '../store';

View File

@@ -8,7 +8,7 @@
*/ */
import type { MessageResponse, MessageSegment, ConversationResponse } from '../../../types/dto'; import type { MessageResponse, MessageSegment, ConversationResponse } from '../../../types/dto';
import { messageService } from '../../../services/messageService'; import { messageService } from '@/services/message';
import { messageRepository } from '@/database'; import { messageRepository } from '@/database';
import type { IMessageSendService } from '../types'; import type { IMessageSendService } from '../types';
import { useMessageStore, mergeMessagesById } from '../store'; import { useMessageStore, mergeMessagesById } from '../store';

View File

@@ -8,7 +8,7 @@
*/ */
import type { ConversationResponse, MessageResponse } from '../../../types/dto'; import type { ConversationResponse, MessageResponse } from '../../../types/dto';
import { messageService } from '../../../services/messageService'; import { messageService } from '@/services/message';
import { messageRepository, conversationRepository } from '@/database'; import { messageRepository, conversationRepository } from '@/database';
import { MessageMapper } from '@/data/mappers'; import { MessageMapper } from '@/data/mappers';
import { import {

View File

@@ -8,7 +8,7 @@
*/ */
import type { ConversationResponse } from '../../../types/dto'; import type { ConversationResponse } from '../../../types/dto';
import { messageService } from '../../../services/messageService'; import { messageService } from '@/services/message';
import { messageRepository, conversationRepository } from '@/database'; import { messageRepository, conversationRepository } from '@/database';
import type { ReadStateRecord, IReadReceiptManager } from '../types'; import type { ReadStateRecord, IReadReceiptManager } from '../types';
import { READ_STATE_PROTECTION_DELAY } from '../constants'; import { READ_STATE_PROTECTION_DELAY } from '../constants';

View File

@@ -4,7 +4,7 @@
*/ */
import type { MessageResponse, UserDTO } from '../../../types/dto'; import type { MessageResponse, UserDTO } from '../../../types/dto';
import { api } from '../../../services/api'; import { api } from '@/services/core';
import { userCacheRepository } from '@/database'; import { userCacheRepository } from '@/database';
import type { IUserCacheService } from '../types'; import type { IUserCacheService } from '../types';

View File

@@ -16,8 +16,8 @@ import type {
WSGroupRecallMessage, WSGroupRecallMessage,
WSGroupTypingMessage, WSGroupTypingMessage,
WSGroupNoticeMessage, WSGroupNoticeMessage,
} from '../../../services/wsService'; } from '@/services/core';
import { wsService, GroupNoticeType } from '../../../services/wsService'; import { wsService, GroupNoticeType } from '@/services/core';
import { eventBus } from '@/core/events/EventBus'; import { eventBus } from '@/core/events/EventBus';
import { messageRepository } from '@/database'; import { messageRepository } from '@/database';
import type { MessageResponse, ConversationResponse } from '../../../types/dto'; import type { MessageResponse, ConversationResponse } from '../../../types/dto';

View File

@@ -6,7 +6,7 @@
*/ */
import type { Post } from '../../types'; import type { Post } from '../../types';
import { postService } from '../../services/postService'; import { postService } from '@/services/post';
import { usePostManagerStore } from './postStore'; import { usePostManagerStore } from './postStore';
import { createCacheEntry, isCacheExpired, DEFAULT_TTL } from '../utils/cache'; import { createCacheEntry, isCacheExpired, DEFAULT_TTL } from '../utils/cache';
import { createDedupe } from '../utils/requestDedupe'; import { createDedupe } from '../utils/requestDedupe';

View File

@@ -3,7 +3,7 @@
*/ */
import { Post } from '../types'; import { Post } from '../types';
import { postService } from '../services/postService'; import { postService } from '@/services/post';
import type { CursorPaginationRequest } from '../types/dto'; import type { CursorPaginationRequest } from '../types/dto';
export const POST_LIST_PAGE_SIZE = 20; export const POST_LIST_PAGE_SIZE = 20;

View File

@@ -6,7 +6,7 @@
*/ */
import type { UserDTO } from '../../types/dto'; import type { UserDTO } from '../../types/dto';
import { authService } from '../../services/authService'; import { authService } from '@/services/auth';
import { userCacheRepository } from '@/database'; import { userCacheRepository } from '@/database';
import { useUserManagerStore } from './userStore'; import { useUserManagerStore } from './userStore';
import { createCacheEntry, isCacheExpired, DEFAULT_TTL } from '../utils/cache'; import { createCacheEntry, isCacheExpired, DEFAULT_TTL } from '../utils/cache';

View File

@@ -6,7 +6,7 @@
import { create } from 'zustand'; import { create } from 'zustand';
import { User, Post, Notification, NotificationBadge } from '../types'; import { User, Post, Notification, NotificationBadge } from '../types';
import { PaginatedData } from '../services/api'; import { PaginatedData } from '@/services/core';
import { import {
authService, authService,
postService, postService,

View File

@@ -4,7 +4,7 @@
*/ */
import { create } from 'zustand'; import { create } from 'zustand';
import { verificationService } from '../services/verificationService'; import { verificationService } from '@/services/auth';
import { import {
VerificationStatusDTO, VerificationStatusDTO,
VerificationRecordDTO, VerificationRecordDTO,