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,7 +4,7 @@
|
||||
* 风格与现代整体UI保持一致
|
||||
*/
|
||||
|
||||
import React, { useCallback } from 'react';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import {
|
||||
View,
|
||||
TouchableOpacity,
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
Animated,
|
||||
} from 'react-native';
|
||||
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
||||
import { colors, spacing, fontSizes, borderRadius } from '../../theme';
|
||||
import { spacing, fontSizes, borderRadius, useAppColors, type AppColors } from '../../theme';
|
||||
import { VoteOptionDTO } from '../../types';
|
||||
import Text from '../common/Text';
|
||||
|
||||
@@ -28,6 +28,146 @@ interface VoteCardProps {
|
||||
compact?: boolean;
|
||||
}
|
||||
|
||||
function createVoteCardStyles(colors: AppColors) {
|
||||
return StyleSheet.create({
|
||||
container: {
|
||||
backgroundColor: colors.background.paper,
|
||||
borderRadius: borderRadius.lg,
|
||||
padding: spacing.md,
|
||||
marginVertical: spacing.sm,
|
||||
borderWidth: 1,
|
||||
borderColor: colors.divider,
|
||||
},
|
||||
containerCompact: {
|
||||
padding: spacing.sm,
|
||||
marginVertical: spacing.xs,
|
||||
},
|
||||
header: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginBottom: spacing.sm,
|
||||
},
|
||||
headerIcon: {
|
||||
width: 24,
|
||||
height: 24,
|
||||
borderRadius: borderRadius.sm,
|
||||
backgroundColor: colors.primary.light + '20',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginRight: spacing.sm,
|
||||
},
|
||||
headerTitle: {
|
||||
fontWeight: '600',
|
||||
color: colors.text.primary,
|
||||
},
|
||||
optionsList: {
|
||||
gap: spacing.sm,
|
||||
},
|
||||
optionContainer: {
|
||||
position: 'relative',
|
||||
borderRadius: borderRadius.md,
|
||||
overflow: 'hidden',
|
||||
},
|
||||
progressBar: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
bottom: 0,
|
||||
borderRadius: borderRadius.md,
|
||||
},
|
||||
optionButton: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingVertical: spacing.sm,
|
||||
paddingHorizontal: spacing.md,
|
||||
borderRadius: borderRadius.md,
|
||||
backgroundColor: colors.background.default,
|
||||
minHeight: 44,
|
||||
borderWidth: 1,
|
||||
borderColor: 'transparent',
|
||||
},
|
||||
optionButtonVoted: {
|
||||
borderColor: colors.primary.main,
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
optionIndicator: {
|
||||
width: 18,
|
||||
height: 18,
|
||||
borderRadius: borderRadius.full,
|
||||
borderWidth: 2,
|
||||
borderColor: colors.divider,
|
||||
marginRight: spacing.sm,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
optionIndicatorVoted: {
|
||||
backgroundColor: colors.primary.main,
|
||||
borderColor: colors.primary.main,
|
||||
},
|
||||
optionText: {
|
||||
flex: 1,
|
||||
fontSize: fontSizes.md,
|
||||
color: colors.text.primary,
|
||||
lineHeight: 20,
|
||||
},
|
||||
optionTextCompact: {
|
||||
fontSize: fontSizes.sm,
|
||||
lineHeight: 18,
|
||||
},
|
||||
resultContainer: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginLeft: spacing.sm,
|
||||
minWidth: 40,
|
||||
justifyContent: 'flex-end',
|
||||
},
|
||||
percentage: {
|
||||
color: colors.text.secondary,
|
||||
fontWeight: '500',
|
||||
},
|
||||
percentageVoted: {
|
||||
color: colors.primary.main,
|
||||
fontWeight: '700',
|
||||
},
|
||||
footer: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginTop: spacing.md,
|
||||
paddingTop: spacing.sm,
|
||||
borderTopWidth: StyleSheet.hairlineWidth,
|
||||
borderTopColor: colors.divider,
|
||||
},
|
||||
footerLeft: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: spacing.xs,
|
||||
},
|
||||
footerText: {
|
||||
fontSize: fontSizes.sm,
|
||||
},
|
||||
unvoteButton: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: spacing.xs,
|
||||
paddingVertical: spacing.xs,
|
||||
paddingHorizontal: spacing.sm,
|
||||
borderRadius: borderRadius.sm,
|
||||
backgroundColor: colors.background.default,
|
||||
},
|
||||
unvoteText: {
|
||||
fontSize: fontSizes.sm,
|
||||
},
|
||||
loadingOverlay: {
|
||||
...StyleSheet.absoluteFillObject,
|
||||
backgroundColor: colors.background.paper + 'CC',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
borderRadius: borderRadius.lg,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const VoteCard: React.FC<VoteCardProps> = ({
|
||||
options,
|
||||
totalVotes,
|
||||
@@ -38,7 +178,8 @@ const VoteCard: React.FC<VoteCardProps> = ({
|
||||
isLoading = false,
|
||||
compact = false,
|
||||
}) => {
|
||||
// 动画值
|
||||
const colors = useAppColors();
|
||||
const styles = useMemo(() => createVoteCardStyles(colors), [colors]);
|
||||
const progressAnim = React.useRef(new Animated.Value(0)).current;
|
||||
|
||||
React.useEffect(() => {
|
||||
@@ -151,7 +292,7 @@ const VoteCard: React.FC<VoteCardProps> = ({
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
);
|
||||
}, [hasVoted, votedOptionId, calculatePercentage, handleVote, isLoading, progressAnim, compact]);
|
||||
}, [hasVoted, votedOptionId, calculatePercentage, handleVote, isLoading, progressAnim, compact, colors, styles]);
|
||||
|
||||
// 排序后的选项(已投票的排在前面)
|
||||
const sortedOptions = React.useMemo(() => {
|
||||
@@ -229,142 +370,4 @@ const VoteCard: React.FC<VoteCardProps> = ({
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
backgroundColor: colors.background.paper,
|
||||
borderRadius: borderRadius.lg,
|
||||
padding: spacing.md,
|
||||
marginVertical: spacing.sm,
|
||||
borderWidth: 1,
|
||||
borderColor: colors.divider,
|
||||
},
|
||||
containerCompact: {
|
||||
padding: spacing.sm,
|
||||
marginVertical: spacing.xs,
|
||||
},
|
||||
header: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginBottom: spacing.sm,
|
||||
},
|
||||
headerIcon: {
|
||||
width: 24,
|
||||
height: 24,
|
||||
borderRadius: borderRadius.sm,
|
||||
backgroundColor: colors.primary.light + '20',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginRight: spacing.sm,
|
||||
},
|
||||
headerTitle: {
|
||||
fontWeight: '600',
|
||||
color: colors.text.primary,
|
||||
},
|
||||
optionsList: {
|
||||
gap: spacing.sm,
|
||||
},
|
||||
optionContainer: {
|
||||
position: 'relative',
|
||||
borderRadius: borderRadius.md,
|
||||
overflow: 'hidden',
|
||||
},
|
||||
progressBar: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
bottom: 0,
|
||||
borderRadius: borderRadius.md,
|
||||
},
|
||||
optionButton: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingVertical: spacing.sm,
|
||||
paddingHorizontal: spacing.md,
|
||||
borderRadius: borderRadius.md,
|
||||
backgroundColor: colors.background.default,
|
||||
minHeight: 44,
|
||||
borderWidth: 1,
|
||||
borderColor: 'transparent',
|
||||
},
|
||||
optionButtonVoted: {
|
||||
borderColor: colors.primary.main,
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
optionIndicator: {
|
||||
width: 18,
|
||||
height: 18,
|
||||
borderRadius: borderRadius.full,
|
||||
borderWidth: 2,
|
||||
borderColor: colors.divider,
|
||||
marginRight: spacing.sm,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
optionIndicatorVoted: {
|
||||
backgroundColor: colors.primary.main,
|
||||
borderColor: colors.primary.main,
|
||||
},
|
||||
optionText: {
|
||||
flex: 1,
|
||||
fontSize: fontSizes.md,
|
||||
color: colors.text.primary,
|
||||
lineHeight: 20,
|
||||
},
|
||||
optionTextCompact: {
|
||||
fontSize: fontSizes.sm,
|
||||
lineHeight: 18,
|
||||
},
|
||||
resultContainer: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginLeft: spacing.sm,
|
||||
minWidth: 40,
|
||||
justifyContent: 'flex-end',
|
||||
},
|
||||
percentage: {
|
||||
color: colors.text.secondary,
|
||||
fontWeight: '500',
|
||||
},
|
||||
percentageVoted: {
|
||||
color: colors.primary.main,
|
||||
fontWeight: '700',
|
||||
},
|
||||
footer: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginTop: spacing.md,
|
||||
paddingTop: spacing.sm,
|
||||
borderTopWidth: StyleSheet.hairlineWidth,
|
||||
borderTopColor: colors.divider,
|
||||
},
|
||||
footerLeft: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: spacing.xs,
|
||||
},
|
||||
footerText: {
|
||||
fontSize: fontSizes.sm,
|
||||
},
|
||||
unvoteButton: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: spacing.xs,
|
||||
paddingVertical: spacing.xs,
|
||||
paddingHorizontal: spacing.sm,
|
||||
borderRadius: borderRadius.sm,
|
||||
backgroundColor: colors.background.default,
|
||||
},
|
||||
unvoteText: {
|
||||
fontSize: fontSizes.sm,
|
||||
},
|
||||
loadingOverlay: {
|
||||
...StyleSheet.absoluteFillObject,
|
||||
backgroundColor: colors.background.paper + 'CC',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
borderRadius: borderRadius.lg,
|
||||
},
|
||||
});
|
||||
|
||||
export default VoteCard;
|
||||
|
||||
Reference in New Issue
Block a user