feat(Theme): enhance theming and UI consistency across components
All checks were successful
Frontend CI / build-and-push-web (push) Successful in 8m15s
Frontend CI / ota-android (push) Successful in 10m56s
Frontend CI / build-android-apk (push) Successful in 1h3m22s

- Updated app.json to set userInterfaceStyle to automatic for improved theme adaptability.
- Refactored layout components to utilize useAppColors for dynamic theming, ensuring consistent color usage.
- Introduced SystemChrome component to manage system UI background color based on theme.
- Enhanced TabsLayout, ProfileStackLayout, and other components to leverage new theming structure.
- Improved QRCodeScanner, SearchBar, and CommentItem styles to align with the updated theme system.
- Consolidated styles in SystemMessageItem and TabBar for better maintainability and visual coherence.
This commit is contained in:
lafay
2026-03-25 05:16:54 +08:00
parent 90d834695f
commit 4ee3079b9f
86 changed files with 6777 additions and 5890 deletions

View File

@@ -3,10 +3,10 @@
* onPress 引用不参与比较,请配合父组件 ref + 按 id 查最新会话使用。
*/
import React, { memo, useEffect, useRef, useState } from 'react';
import React, { memo, useEffect, useMemo, useRef, useState } from 'react';
import { Animated, StyleSheet, TouchableOpacity, View } from 'react-native';
import { MaterialCommunityIcons } from '@expo/vector-icons';
import { colors, spacing, shadows } from '../../../theme';
import { spacing, shadows, useAppColors, type AppColors } from '../../../theme';
import {
ConversationResponse,
extractTextFromSegments,
@@ -150,6 +150,124 @@ function areConversationRowEqual(
return true;
}
function createConversationRowStyles(colors: AppColors) {
return StyleSheet.create({
conversationItem: {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: spacing.md,
paddingVertical: 14,
backgroundColor: colors.background.paper,
marginHorizontal: spacing.md,
marginTop: spacing.sm,
borderRadius: 12,
...shadows.sm,
},
conversationItemSelected: {
backgroundColor: colors.primary.light + '20',
borderColor: colors.primary.main,
borderWidth: 1,
},
avatarContainer: {
position: 'relative',
},
systemAvatar: {
width: 50,
height: 50,
borderRadius: 12,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: colors.primary.main,
},
conversationContent: {
flex: 1,
marginLeft: spacing.md,
},
conversationHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 4,
},
nameRow: {
flexDirection: 'row',
alignItems: 'center',
},
officialBadge: {
backgroundColor: colors.primary.main,
borderRadius: 4,
paddingHorizontal: 6,
paddingVertical: 2,
marginRight: spacing.xs,
},
officialBadgeText: {
color: colors.primary.contrast,
fontSize: 10,
fontWeight: '600',
},
userName: {
fontWeight: '600',
color: colors.text.primary,
fontSize: 16,
},
groupIcon: {
marginRight: 4,
},
memberCount: {
fontSize: 12,
color: colors.text.secondary,
marginLeft: 2,
},
pinnedIcon: {
marginLeft: 6,
},
groupAvatar: {
width: 50,
height: 50,
},
groupAvatarPlaceholder: {
width: 50,
height: 50,
borderRadius: 12,
backgroundColor: colors.primary.main,
alignItems: 'center',
justifyContent: 'center',
},
timeText: {
color: colors.text.secondary,
fontSize: 12,
},
messageRow: {
flexDirection: 'row',
alignItems: 'center',
},
messageText: {
flex: 1,
color: colors.text.secondary,
fontSize: 14,
},
unreadMessageText: {
color: colors.text.primary,
fontWeight: '500',
},
unreadBadge: {
minWidth: 20,
height: 20,
borderRadius: 10,
backgroundColor: colors.primary.main,
alignItems: 'center',
justifyContent: 'center',
marginLeft: spacing.sm,
paddingHorizontal: 6,
},
unreadBadgeText: {
color: colors.primary.contrast,
fontSize: 12,
fontWeight: '600',
},
});
}
const ConversationListRowInner: React.FC<ConversationListRowProps> = ({
item,
scale,
@@ -158,6 +276,8 @@ const ConversationListRowInner: React.FC<ConversationListRowProps> = ({
formatTime,
systemChannelId,
}) => {
const colors = useAppColors();
const styles = useMemo(() => createConversationRowStyles(colors), [colors]);
const isSystemChannel = item.id === systemChannelId;
const isGroupChat = !!(item.type === 'group' && item.group);
@@ -196,7 +316,7 @@ const ConversationListRowInner: React.FC<ConversationListRowProps> = ({
<View style={styles.avatarContainer}>
{isSystemChannel ? (
<View style={styles.systemAvatar}>
<MaterialCommunityIcons name="bell-ring" size={24} color="#FFF" />
<MaterialCommunityIcons name="bell-ring" size={24} color={colors.primary.contrast} />
</View>
) : isGroupChat ? (
<View style={styles.groupAvatar}>
@@ -204,7 +324,7 @@ const ConversationListRowInner: React.FC<ConversationListRowProps> = ({
<Avatar source={displayAvatar} size={50} name={displayName} />
) : (
<View style={styles.groupAvatarPlaceholder}>
<MaterialCommunityIcons name="account-group" size={28} color="#FFF" />
<MaterialCommunityIcons name="account-group" size={28} color={colors.primary.contrast} />
</View>
)}
</View>
@@ -271,119 +391,3 @@ const ConversationListRowInner: React.FC<ConversationListRowProps> = ({
ConversationListRowInner.displayName = 'ConversationListRow';
export const ConversationListRow = memo(ConversationListRowInner, areConversationRowEqual);
const styles = StyleSheet.create({
conversationItem: {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: spacing.md,
paddingVertical: 14,
backgroundColor: '#FFF',
marginHorizontal: spacing.md,
marginTop: spacing.sm,
borderRadius: 12,
...shadows.sm,
},
conversationItemSelected: {
backgroundColor: colors.primary.light + '20',
borderColor: colors.primary.main,
borderWidth: 1,
},
avatarContainer: {
position: 'relative',
},
systemAvatar: {
width: 50,
height: 50,
borderRadius: 12,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: colors.primary.main,
},
conversationContent: {
flex: 1,
marginLeft: spacing.md,
},
conversationHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 4,
},
nameRow: {
flexDirection: 'row',
alignItems: 'center',
},
officialBadge: {
backgroundColor: colors.primary.main,
borderRadius: 4,
paddingHorizontal: 6,
paddingVertical: 2,
marginRight: spacing.xs,
},
officialBadgeText: {
color: '#FFF',
fontSize: 10,
fontWeight: '600',
},
userName: {
fontWeight: '600',
color: '#333',
fontSize: 16,
},
groupIcon: {
marginRight: 4,
},
memberCount: {
fontSize: 12,
color: '#999',
marginLeft: 2,
},
pinnedIcon: {
marginLeft: 6,
},
groupAvatar: {
width: 50,
height: 50,
},
groupAvatarPlaceholder: {
width: 50,
height: 50,
borderRadius: 12,
backgroundColor: colors.primary.main,
alignItems: 'center',
justifyContent: 'center',
},
timeText: {
color: '#999',
fontSize: 12,
},
messageRow: {
flexDirection: 'row',
alignItems: 'center',
},
messageText: {
flex: 1,
color: '#888',
fontSize: 14,
},
unreadMessageText: {
color: '#333',
fontWeight: '500',
},
unreadBadge: {
minWidth: 20,
height: 20,
borderRadius: 10,
backgroundColor: colors.primary.main,
alignItems: 'center',
justifyContent: 'center',
marginLeft: spacing.sm,
paddingHorizontal: 6,
},
unreadBadgeText: {
color: '#FFF',
fontSize: 12,
fontWeight: '600',
},
});