feat(message): implement incremental sync and atomic unread updates
Refactor the messaging system to improve synchronization efficiency and state consistency. - Implement incremental message synchronization using sequence numbers (seq) to reduce payload size. - Add `markAllAsRead` batch API support to optimize read receipt processing. - Introduce atomic state updates in `useMessageStore` to prevent inconsistent UI rendering during unread count changes. - Implement notification deduplication in `WSMessageHandler` to prevent duplicate unread increments during reconnection. - Optimize `MessageSyncService` to prioritize incremental sync over full snapshots when local data exists. - Refactor `ReadReceiptManager` to use optimistic updates with proper rollback mechanisms. - Fix minor UI issues in `SettingsScreen` and `PrivacySettingsScreen` related to theme picker z-index and style application.
This commit is contained in:
@@ -100,6 +100,14 @@ export interface MessageActions {
|
||||
setNotificationMuted: (conversationId: string, notificationMuted: boolean) => void;
|
||||
setInitialized: (initialized: boolean) => void;
|
||||
|
||||
// 原子性更新(避免中间渲染状态)
|
||||
updateConversationWithUnread: (
|
||||
conversation: ConversationResponse,
|
||||
totalUnread: number,
|
||||
systemUnread: number,
|
||||
) => void;
|
||||
incrementUnreadAtomic: (conversationId: string) => void;
|
||||
|
||||
// 重置
|
||||
reset: () => void;
|
||||
}
|
||||
@@ -439,6 +447,53 @@ export const useMessageStore = create<MessageStore>((set, get) => ({
|
||||
set({ isInitialized: initialized });
|
||||
},
|
||||
|
||||
updateConversationWithUnread: (
|
||||
conversation: ConversationResponse,
|
||||
totalUnread: number,
|
||||
systemUnread: number,
|
||||
) => {
|
||||
const id = normalizeConversationId(conversation.id);
|
||||
set(state => {
|
||||
const newConversations = new Map(state.conversations);
|
||||
newConversations.set(id, { ...conversation, id });
|
||||
const conversationList = sortConversationList(newConversations);
|
||||
const newNotificationMutedMap = new Map(state.notificationMutedMap);
|
||||
if (conversation.notification_muted) {
|
||||
newNotificationMutedMap.set(id, true);
|
||||
} else {
|
||||
newNotificationMutedMap.delete(id);
|
||||
}
|
||||
return {
|
||||
conversations: newConversations,
|
||||
conversationList,
|
||||
notificationMutedMap: newNotificationMutedMap,
|
||||
totalUnreadCount: totalUnread,
|
||||
systemUnreadCount: systemUnread,
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
incrementUnreadAtomic: (conversationId: string) => {
|
||||
const normalizedId = normalizeConversationId(conversationId);
|
||||
set(state => {
|
||||
const conversation = state.conversations.get(normalizedId);
|
||||
if (!conversation) return state;
|
||||
|
||||
const newConversations = new Map(state.conversations);
|
||||
newConversations.set(normalizedId, {
|
||||
...conversation,
|
||||
unread_count: (conversation.unread_count || 0) + 1,
|
||||
});
|
||||
const conversationList = sortConversationList(newConversations);
|
||||
|
||||
return {
|
||||
conversations: newConversations,
|
||||
conversationList,
|
||||
totalUnreadCount: state.totalUnreadCount + 1,
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
// ==================== 重置 ====================
|
||||
|
||||
reset: () => {
|
||||
|
||||
Reference in New Issue
Block a user