主要改动: 1. 创建乐观更新工具函数 (optimisticUpdate.ts) - 消除 userStore.ts 中的重复代码 2. 拆分 useResponsive.ts (485行 -> 12个专注模块) - useBreakpoint: 断点检测 - useOrientation: 方向检测 - usePlatform: 平台检测 - useScreenSize: 屏幕尺寸 - useResponsiveValue: 响应式值 - useResponsiveStyle: 响应式样式 - useMediaQuery: 媒体查询 - useColumnCount: 列数计算 - useResponsiveSpacing: 响应式间距 3. 整理数据层 (Repository 层) - ApiDataSource: API数据源 - LocalDataSource: 本地数据源 - CacheDataSource: 缓存数据源 - MessageRepository: 消息仓库 4. 重构 messageManager.ts (2194行 -> 4个模块) - MessageStateManager: 状态管理 - WebSocketMessageHandler: WebSocket处理 - MessageSyncService: 消息同步 - ReadReceiptManager: 已读管理 5. 导航解耦 (MainNavigator.tsx: 1118行 -> 100行) - 创建 NavigationService 解耦层 - 拆分多个 Navigator 组件 架构改进: - 单一职责原则: 每个模块职责明确 - 依赖倒置: 通过接口解耦 - 代码复用: 工具函数可被多处使用 - 可测试性: 各模块可独立测试
92 lines
2.5 KiB
TypeScript
92 lines
2.5 KiB
TypeScript
/**
|
|
* 已读回执管理器
|
|
* 负责处理消息已读状态的同步
|
|
*/
|
|
|
|
import { messageService } from '../../services/messageService';
|
|
import { messageRepository } from '../../data/repositories/MessageRepository';
|
|
import type { MessageStateManager } from './MessageStateManager';
|
|
|
|
export interface ReadReceiptResult {
|
|
conversationId: string;
|
|
lastReadSeq: number;
|
|
success: boolean;
|
|
}
|
|
|
|
export class ReadReceiptManager {
|
|
private pendingOperations: Map<string, Promise<void>> = new Map();
|
|
private stateManager: MessageStateManager | null = null;
|
|
|
|
setStateManager(manager: MessageStateManager): void {
|
|
this.stateManager = manager;
|
|
}
|
|
|
|
async markAsRead(
|
|
conversationId: string,
|
|
lastSeq: number
|
|
): Promise<ReadReceiptResult> {
|
|
const existing = this.pendingOperations.get(conversationId);
|
|
if (existing) {
|
|
await existing;
|
|
}
|
|
|
|
if (!this.stateManager) {
|
|
throw new Error('StateManager not set');
|
|
}
|
|
|
|
const version = this.stateManager.beginReadOperation(conversationId);
|
|
|
|
const promise = this.executeMarkAsRead(conversationId, lastSeq, version);
|
|
this.pendingOperations.set(conversationId, promise);
|
|
|
|
try {
|
|
await promise;
|
|
return { conversationId, lastReadSeq: lastSeq, success: true };
|
|
} catch (error) {
|
|
console.error('[ReadReceiptManager] Failed to mark as read:', error);
|
|
return { conversationId, lastReadSeq: lastSeq, success: false };
|
|
} finally {
|
|
this.pendingOperations.delete(conversationId);
|
|
this.stateManager.endReadOperation(conversationId);
|
|
}
|
|
}
|
|
|
|
private async executeMarkAsRead(
|
|
conversationId: string,
|
|
lastSeq: number,
|
|
version: number
|
|
): Promise<void> {
|
|
await messageService.markAsRead(conversationId, lastSeq);
|
|
|
|
await messageRepository.markConversationAsRead(conversationId);
|
|
|
|
if (this.stateManager) {
|
|
this.stateManager.updateConversation(conversationId, {
|
|
unreadCount: 0,
|
|
});
|
|
}
|
|
}
|
|
|
|
async markAllAsRead(): Promise<void> {
|
|
if (!this.stateManager) return;
|
|
|
|
const conversations = this.stateManager.getConversations();
|
|
const unreadConversations = conversations.filter(c => c.unreadCount > 0);
|
|
|
|
await Promise.all(
|
|
unreadConversations.map(conv =>
|
|
this.markAsRead(conv.id, conv.lastSeq)
|
|
)
|
|
);
|
|
}
|
|
|
|
isPending(conversationId: string): boolean {
|
|
return this.pendingOperations.has(conversationId);
|
|
}
|
|
|
|
reset(): void {
|
|
this.pendingOperations.clear();
|
|
}
|
|
}
|
|
|
|
export const readReceiptManager = new ReadReceiptManager(); |