feat(Theme): enhance theming and UI consistency across components
- 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:
@@ -4,12 +4,12 @@
|
||||
* 采用卡片式设计,符合胡萝卜BBS整体风格
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { View, TouchableOpacity, StyleSheet, Animated } from 'react-native';
|
||||
import React, { useMemo } from 'react';
|
||||
import { View, TouchableOpacity, StyleSheet } from 'react-native';
|
||||
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
||||
import { formatDistanceToNow } from 'date-fns';
|
||||
import { zhCN } from 'date-fns/locale';
|
||||
import { colors, spacing, borderRadius, shadows, fontSizes } from '../../theme';
|
||||
import { spacing, borderRadius, shadows, fontSizes, useAppColors, type AppColors } from '../../theme';
|
||||
import { SystemMessageResponse, SystemMessageType } from '../../types/dto';
|
||||
import Text from '../common/Text';
|
||||
import Avatar from '../common/Avatar';
|
||||
@@ -23,9 +23,9 @@ interface SystemMessageItemProps {
|
||||
index?: number; // 用于交错动画
|
||||
}
|
||||
|
||||
// 系统消息类型到图标和颜色的映射
|
||||
const getSystemMessageIcon = (
|
||||
systemType: SystemMessageType
|
||||
systemType: SystemMessageType,
|
||||
colors: AppColors
|
||||
): { icon: keyof typeof MaterialCommunityIcons.glyphMap; color: string; bgColor: string; gradient: string[] } => {
|
||||
switch (systemType) {
|
||||
case 'like_post':
|
||||
@@ -119,6 +119,155 @@ const getSystemMessageIcon = (
|
||||
}
|
||||
};
|
||||
|
||||
function createSystemMessageStyles(colors: AppColors) {
|
||||
return StyleSheet.create({
|
||||
container: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'flex-start',
|
||||
padding: spacing.md,
|
||||
backgroundColor: colors.background.paper,
|
||||
borderRadius: borderRadius.lg,
|
||||
marginHorizontal: spacing.md,
|
||||
marginBottom: spacing.sm,
|
||||
...shadows.sm,
|
||||
},
|
||||
unreadContainer: {
|
||||
backgroundColor: colors.primary.light + '08',
|
||||
borderLeftWidth: 3,
|
||||
borderLeftColor: colors.primary.main,
|
||||
},
|
||||
unreadIndicator: {
|
||||
position: 'absolute',
|
||||
left: 6,
|
||||
top: '50%',
|
||||
marginTop: -4,
|
||||
width: 8,
|
||||
height: 8,
|
||||
borderRadius: borderRadius.full,
|
||||
backgroundColor: colors.primary.main,
|
||||
},
|
||||
iconContainer: {
|
||||
marginRight: spacing.md,
|
||||
},
|
||||
avatarWrapper: {
|
||||
position: 'relative',
|
||||
},
|
||||
iconWrapper: {
|
||||
width: 48,
|
||||
height: 48,
|
||||
borderRadius: borderRadius.lg,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
typeIconBadge: {
|
||||
position: 'absolute',
|
||||
bottom: -2,
|
||||
right: -2,
|
||||
width: 20,
|
||||
height: 20,
|
||||
borderRadius: borderRadius.full,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
borderWidth: 2,
|
||||
borderColor: colors.background.paper,
|
||||
},
|
||||
content: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
minWidth: 0,
|
||||
},
|
||||
titleRow: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginBottom: spacing.xs,
|
||||
},
|
||||
titleLeft: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
flex: 1,
|
||||
marginRight: spacing.sm,
|
||||
},
|
||||
title: {
|
||||
fontWeight: '500',
|
||||
fontSize: fontSizes.md,
|
||||
color: colors.text.primary,
|
||||
},
|
||||
unreadTitle: {
|
||||
fontWeight: '600',
|
||||
color: colors.text.primary,
|
||||
},
|
||||
statusBadge: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: spacing.xs,
|
||||
paddingVertical: 2,
|
||||
borderRadius: borderRadius.sm,
|
||||
marginLeft: spacing.xs,
|
||||
},
|
||||
statusText: {
|
||||
fontSize: 10,
|
||||
fontWeight: '500',
|
||||
marginLeft: 2,
|
||||
},
|
||||
time: {
|
||||
fontSize: fontSizes.sm,
|
||||
flexShrink: 0,
|
||||
},
|
||||
messageContent: {
|
||||
lineHeight: 20,
|
||||
fontSize: fontSizes.sm,
|
||||
},
|
||||
extraInfo: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginTop: spacing.xs,
|
||||
backgroundColor: colors.primary.light + '12',
|
||||
paddingHorizontal: spacing.sm,
|
||||
paddingVertical: spacing.xs,
|
||||
borderRadius: borderRadius.md,
|
||||
alignSelf: 'flex-start',
|
||||
},
|
||||
extraText: {
|
||||
marginLeft: spacing.xs,
|
||||
flex: 1,
|
||||
fontWeight: '500',
|
||||
},
|
||||
actionsRow: {
|
||||
flexDirection: 'row',
|
||||
marginTop: spacing.sm,
|
||||
gap: spacing.sm,
|
||||
},
|
||||
actionBtn: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingVertical: spacing.xs,
|
||||
paddingHorizontal: spacing.md,
|
||||
borderRadius: borderRadius.md,
|
||||
borderWidth: 1,
|
||||
gap: spacing.xs,
|
||||
},
|
||||
rejectBtn: {
|
||||
borderColor: `${colors.error.main}55`,
|
||||
backgroundColor: `${colors.error.main}18`,
|
||||
},
|
||||
approveBtn: {
|
||||
borderColor: `${colors.success.main}55`,
|
||||
backgroundColor: `${colors.success.main}18`,
|
||||
},
|
||||
actionBtnText: {
|
||||
fontWeight: '500',
|
||||
},
|
||||
arrowContainer: {
|
||||
marginLeft: spacing.sm,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
height: 20,
|
||||
width: 20,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// 获取系统消息标题
|
||||
const getSystemMessageTitle = (message: SystemMessageResponse): string => {
|
||||
const { system_type, extra_data } = message;
|
||||
@@ -177,6 +326,9 @@ const SystemMessageItem: React.FC<SystemMessageItemProps> = ({
|
||||
requestActionLoading = false,
|
||||
index = 0,
|
||||
}) => {
|
||||
const colors = useAppColors();
|
||||
const styles = useMemo(() => createSystemMessageStyles(colors), [colors]);
|
||||
|
||||
// 格式化时间
|
||||
const formatTime = (dateString: string): string => {
|
||||
try {
|
||||
@@ -189,7 +341,7 @@ const SystemMessageItem: React.FC<SystemMessageItemProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
const { icon, color, bgColor } = getSystemMessageIcon(message.system_type);
|
||||
const { icon, color, bgColor } = getSystemMessageIcon(message.system_type, colors);
|
||||
const title = getSystemMessageTitle(message);
|
||||
const { extra_data } = message;
|
||||
const operatorName = extra_data?.actor_name || extra_data?.operator_name;
|
||||
@@ -212,17 +364,17 @@ const SystemMessageItem: React.FC<SystemMessageItemProps> = ({
|
||||
const getStatusBadge = () => {
|
||||
if (requestStatus === 'accepted') {
|
||||
return (
|
||||
<View style={[styles.statusBadge, { backgroundColor: '#E8F5E9' }]}>
|
||||
<MaterialCommunityIcons name="check" size={10} color="#4CAF50" />
|
||||
<Text variant="caption" color="#4CAF50" style={styles.statusText}>已同意</Text>
|
||||
<View style={[styles.statusBadge, { backgroundColor: `${colors.success.main}22` }]}>
|
||||
<MaterialCommunityIcons name="check" size={10} color={colors.success.main} />
|
||||
<Text variant="caption" color={colors.success.main} style={styles.statusText}>已同意</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
if (requestStatus === 'rejected') {
|
||||
return (
|
||||
<View style={[styles.statusBadge, { backgroundColor: '#FFEBEE' }]}>
|
||||
<MaterialCommunityIcons name="close" size={10} color="#F44336" />
|
||||
<Text variant="caption" color="#F44336" style={styles.statusText}>已拒绝</Text>
|
||||
<View style={[styles.statusBadge, { backgroundColor: `${colors.error.main}22` }]}>
|
||||
<MaterialCommunityIcons name="close" size={10} color={colors.error.main} />
|
||||
<Text variant="caption" color={colors.error.main} style={styles.statusText}>已拒绝</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -328,16 +480,16 @@ const SystemMessageItem: React.FC<SystemMessageItemProps> = ({
|
||||
onPress={() => onRequestAction?.(false)}
|
||||
disabled={requestActionLoading}
|
||||
>
|
||||
<MaterialCommunityIcons name="close" size={14} color="#F44336" />
|
||||
<Text variant="caption" color="#F44336" style={styles.actionBtnText}>拒绝</Text>
|
||||
<MaterialCommunityIcons name="close" size={14} color={colors.error.main} />
|
||||
<Text variant="caption" color={colors.error.main} style={styles.actionBtnText}>拒绝</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={[styles.actionBtn, styles.approveBtn]}
|
||||
onPress={() => onRequestAction?.(true)}
|
||||
disabled={requestActionLoading}
|
||||
>
|
||||
<MaterialCommunityIcons name="check" size={14} color="#4CAF50" />
|
||||
<Text variant="caption" color="#4CAF50" style={styles.actionBtnText}>同意</Text>
|
||||
<MaterialCommunityIcons name="check" size={14} color={colors.success.main} />
|
||||
<Text variant="caption" color={colors.success.main} style={styles.actionBtnText}>同意</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
)}
|
||||
@@ -353,151 +505,4 @@ const SystemMessageItem: React.FC<SystemMessageItemProps> = ({
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'flex-start',
|
||||
padding: spacing.md,
|
||||
backgroundColor: colors.background.paper,
|
||||
borderRadius: borderRadius.lg,
|
||||
marginHorizontal: spacing.md,
|
||||
marginBottom: spacing.sm,
|
||||
...shadows.sm,
|
||||
},
|
||||
unreadContainer: {
|
||||
backgroundColor: colors.primary.light + '08',
|
||||
borderLeftWidth: 3,
|
||||
borderLeftColor: colors.primary.main,
|
||||
},
|
||||
unreadIndicator: {
|
||||
position: 'absolute',
|
||||
left: 6,
|
||||
top: '50%',
|
||||
marginTop: -4,
|
||||
width: 8,
|
||||
height: 8,
|
||||
borderRadius: borderRadius.full,
|
||||
backgroundColor: colors.primary.main,
|
||||
},
|
||||
iconContainer: {
|
||||
marginRight: spacing.md,
|
||||
},
|
||||
avatarWrapper: {
|
||||
position: 'relative',
|
||||
},
|
||||
iconWrapper: {
|
||||
width: 48,
|
||||
height: 48,
|
||||
borderRadius: borderRadius.lg,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
typeIconBadge: {
|
||||
position: 'absolute',
|
||||
bottom: -2,
|
||||
right: -2,
|
||||
width: 20,
|
||||
height: 20,
|
||||
borderRadius: borderRadius.full,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
borderWidth: 2,
|
||||
borderColor: colors.background.paper,
|
||||
},
|
||||
content: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
minWidth: 0,
|
||||
},
|
||||
titleRow: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginBottom: spacing.xs,
|
||||
},
|
||||
titleLeft: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
flex: 1,
|
||||
marginRight: spacing.sm,
|
||||
},
|
||||
title: {
|
||||
fontWeight: '500',
|
||||
fontSize: fontSizes.md,
|
||||
color: colors.text.primary,
|
||||
},
|
||||
unreadTitle: {
|
||||
fontWeight: '600',
|
||||
color: colors.text.primary,
|
||||
},
|
||||
statusBadge: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: spacing.xs,
|
||||
paddingVertical: 2,
|
||||
borderRadius: borderRadius.sm,
|
||||
marginLeft: spacing.xs,
|
||||
},
|
||||
statusText: {
|
||||
fontSize: 10,
|
||||
fontWeight: '500',
|
||||
marginLeft: 2,
|
||||
},
|
||||
time: {
|
||||
fontSize: fontSizes.sm,
|
||||
flexShrink: 0,
|
||||
},
|
||||
messageContent: {
|
||||
lineHeight: 20,
|
||||
fontSize: fontSizes.sm,
|
||||
},
|
||||
extraInfo: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginTop: spacing.xs,
|
||||
backgroundColor: colors.primary.light + '12',
|
||||
paddingHorizontal: spacing.sm,
|
||||
paddingVertical: spacing.xs,
|
||||
borderRadius: borderRadius.md,
|
||||
alignSelf: 'flex-start',
|
||||
},
|
||||
extraText: {
|
||||
marginLeft: spacing.xs,
|
||||
flex: 1,
|
||||
fontWeight: '500',
|
||||
},
|
||||
actionsRow: {
|
||||
flexDirection: 'row',
|
||||
marginTop: spacing.sm,
|
||||
gap: spacing.sm,
|
||||
},
|
||||
actionBtn: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingVertical: spacing.xs,
|
||||
paddingHorizontal: spacing.md,
|
||||
borderRadius: borderRadius.md,
|
||||
borderWidth: 1,
|
||||
gap: spacing.xs,
|
||||
},
|
||||
rejectBtn: {
|
||||
borderColor: '#FFCDD2',
|
||||
backgroundColor: '#FFEBEE',
|
||||
},
|
||||
approveBtn: {
|
||||
borderColor: '#C8E6C9',
|
||||
backgroundColor: '#E8F5E9',
|
||||
},
|
||||
actionBtnText: {
|
||||
fontWeight: '500',
|
||||
},
|
||||
arrowContainer: {
|
||||
marginLeft: spacing.sm,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
height: 20,
|
||||
width: 20,
|
||||
},
|
||||
});
|
||||
|
||||
export default SystemMessageItem;
|
||||
|
||||
Reference in New Issue
Block a user