feat(ui): unify design system to Twitter/X style across screens and improve message handling
Some checks failed
Frontend CI / build-and-push-web (push) Failing after 3m9s
Frontend CI / ota-android (push) Successful in 10m29s
Frontend CI / build-android-apk (push) Successful in 43m4s

Redesign multiple screens and components from card-based responsive design to Twitter/X flat design:
- UserProfileHeader: adopt Twitter/X style with larger icons, simplified buttons, and block functionality
- AppBackButton: update to chevron-left icon with larger size, remove background styling
- Update SettingsScreen, EditProfileScreen, and UserProfileScreen with flat layout approach
- ConversationListRow: convert from bordered cards to flat list rows with updated typography

Improve message system with WebSocket notification handling:
- Add real-time system unread count updates via WebSocket
- Track lastSystemMessageAt for accurate system message timestamps
- Add notification deduplication and read-status filtering
- Combine system and conversation unread counts in background sync
- Clear system notifications from notification center on mark as read
This commit is contained in:
lafay
2026-04-25 00:39:40 +08:00
parent e0d28535f4
commit ad19bc2af7
26 changed files with 950 additions and 1121 deletions

View File

@@ -49,6 +49,7 @@ import {
useUnreadCount,
useMarkAsRead,
useMessageManagerConversations,
useMessageStore,
} from '../../stores';
import { Avatar, Text, EmptyState, ResponsiveContainer, AppBackButton } from '../../components/common';
import { useResponsive, useBreakpointGTE } from '../../hooks/useResponsive';
@@ -113,6 +114,7 @@ export const MessageListScreen: React.FC = () => {
// 使用 MessageManager 获取未读数和系统通知数
const { totalUnreadCount, systemUnreadCount } = useUnreadCount();
const lastSystemMessageAt = useMessageStore(state => state.lastSystemMessageAt);
const { markAllAsRead, isMarking } = useMarkAsRead(null);
// 【新架构】使用MessageManager的hook创建会话
@@ -160,14 +162,14 @@ export const MessageListScreen: React.FC = () => {
seq: 0,
segments: [{ type: 'text', data: { text: '系统通知' } }],
status: 'normal',
created_at: new Date().toISOString(),
created_at: lastSystemMessageAt || new Date().toISOString(),
},
last_message_at: new Date().toISOString(),
last_message_at: lastSystemMessageAt || new Date().toISOString(),
unread_count: systemUnreadCount,
participants: [],
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
}), [systemUnreadCount]);
created_at: lastSystemMessageAt || new Date().toISOString(),
updated_at: lastSystemMessageAt || new Date().toISOString(),
}), [systemUnreadCount, lastSystemMessageAt]);
// 动画值
const [scaleAnims] = useState(() =>
@@ -451,6 +453,7 @@ export const MessageListScreen: React.FC = () => {
// 创建系统通知会话项
const createSystemMessageItem = (): ConversationResponse => {
const noticeContent = systemUnreadCount > 0 ? `您有 ${systemUnreadCount} 条未读通知` : '暂无新通知';
const lastTime = lastSystemMessageAt || new Date().toISOString();
return {
id: SYSTEM_MESSAGE_CHANNEL_ID,
type: 'private',
@@ -462,13 +465,13 @@ export const MessageListScreen: React.FC = () => {
seq: 0,
segments: [{ type: 'text', data: { text: noticeContent } }],
status: 'normal',
created_at: new Date().toISOString(),
created_at: lastTime,
},
last_message_at: new Date().toISOString(),
last_message_at: lastTime,
unread_count: systemUnreadCount,
participants: [],
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
created_at: lastTime,
updated_at: lastTime,
};
};
@@ -936,7 +939,8 @@ function createMessageListStyles(colors: AppColors) {
paddingHorizontal: spacing.md,
paddingVertical: spacing.md,
backgroundColor: colors.background.default,
...shadows.sm,
borderBottomWidth: StyleSheet.hairlineWidth,
borderBottomColor: colors.divider + '60',
},
headerWide: {
paddingHorizontal: spacing.lg,
@@ -949,7 +953,7 @@ function createMessageListStyles(colors: AppColors) {
paddingHorizontal: spacing.lg,
},
listContentWide: {
paddingHorizontal: spacing.lg,
paddingHorizontal: spacing.xs,
},
headerLeft: {
width: 44,
@@ -1028,6 +1032,7 @@ function createMessageListStyles(colors: AppColors) {
listContent: {
flexGrow: 1,
backgroundColor: colors.background.default,
paddingHorizontal: spacing.xs,
},
loadingContainer: {
flex: 1,
@@ -1086,11 +1091,9 @@ function createMessageListStyles(colors: AppColors) {
flexDirection: 'row',
alignItems: 'center',
padding: spacing.md,
backgroundColor: colors.background.paper,
borderRadius: borderRadius.lg,
marginBottom: spacing.sm,
borderWidth: StyleSheet.hairlineWidth,
borderColor: `${colors.divider}50`,
backgroundColor: colors.background.default,
borderBottomWidth: StyleSheet.hairlineWidth,
borderBottomColor: `${colors.divider}50`,
},
searchResultContent: {
flex: 1,