feat: 更新个人页面和活动热图组件
- 在个人页面中新增鱼干记录展示,优化用户界面 - 修改活动热图组件,增加信息弹窗,提供小鱼干使用说明 - 调整样式,提升整体视觉效果和用户体验 - 更新颜色常量,确保一致性
This commit is contained in:
@@ -264,6 +264,16 @@ export default function PersonalScreen() {
|
|||||||
>
|
>
|
||||||
<UserHeader />
|
<UserHeader />
|
||||||
<StatsSection />
|
<StatsSection />
|
||||||
|
<View style={styles.fishRecordContainer}>
|
||||||
|
{/* <Image
|
||||||
|
source={{ uri: 'https://plates-1251306435.cos.ap-guangzhou.myqcloud.com/images/icons/icon-profile-fish.png' }}
|
||||||
|
contentFit="cover"
|
||||||
|
style={{ width: 16, height: 16, marginLeft: 6 }}
|
||||||
|
transition={200}
|
||||||
|
cachePolicy="memory-disk"
|
||||||
|
/> */}
|
||||||
|
<Text style={styles.fishRecordText}>鱼干记录</Text>
|
||||||
|
</View>
|
||||||
<ActivityHeatMap />
|
<ActivityHeatMap />
|
||||||
{menuSections.map((section, index) => (
|
{menuSections.map((section, index) => (
|
||||||
<MenuSection key={index} title={section.title} items={section.items} />
|
<MenuSection key={index} title={section.title} items={section.items} />
|
||||||
@@ -277,7 +287,7 @@ export default function PersonalScreen() {
|
|||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
backgroundColor: '#FAFAFA',
|
backgroundColor: '#F0F9FF',
|
||||||
},
|
},
|
||||||
safeArea: {
|
safeArea: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
@@ -402,4 +412,16 @@ const styles = StyleSheet.create({
|
|||||||
switch: {
|
switch: {
|
||||||
transform: [{ scaleX: 0.8 }, { scaleY: 0.8 }],
|
transform: [{ scaleX: 0.8 }, { scaleY: 0.8 }],
|
||||||
},
|
},
|
||||||
|
fishRecordContainer: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'flex-start',
|
||||||
|
marginBottom: 10,
|
||||||
|
},
|
||||||
|
fishRecordText: {
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
color: '#2C3E50',
|
||||||
|
marginLeft: 4,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
|
import { IconSymbol } from '@/components/ui/IconSymbol';
|
||||||
import { Colors } from '@/constants/Colors';
|
import { Colors } from '@/constants/Colors';
|
||||||
import { useAppSelector } from '@/hooks/redux';
|
import { useAppSelector } from '@/hooks/redux';
|
||||||
import { useColorScheme } from '@/hooks/useColorScheme';
|
import { useColorScheme } from '@/hooks/useColorScheme';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import React, { useMemo } from 'react';
|
import React, { useMemo, useState } from 'react';
|
||||||
import { Dimensions, StyleSheet, Text, View } from 'react-native';
|
import { Dimensions, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
||||||
|
import Popover from 'react-native-popover-view';
|
||||||
|
|
||||||
|
|
||||||
const ActivityHeatMap = () => {
|
const ActivityHeatMap = () => {
|
||||||
const colorScheme = useColorScheme();
|
const colorScheme = useColorScheme();
|
||||||
const colors = Colors[colorScheme ?? 'light'];
|
const colors = Colors[colorScheme ?? 'light'];
|
||||||
|
const [showPopover, setShowPopover] = useState(false);
|
||||||
|
|
||||||
const activityData = useAppSelector(stat => stat.user.activityHistory);
|
const activityData = useAppSelector(stat => stat.user.activityHistory);
|
||||||
|
|
||||||
@@ -63,8 +66,8 @@ const ActivityHeatMap = () => {
|
|||||||
const getActivityColor = (level: number): string => {
|
const getActivityColor = (level: number): string => {
|
||||||
switch (level) {
|
switch (level) {
|
||||||
case 0:
|
case 0:
|
||||||
// 无活动:使用主题适配的背景色
|
// 无活动:使用淡蓝色,更有活力
|
||||||
return colors.separator;
|
return 'rgba(173, 216, 230, 0.3)'; // 淡蓝色,有活力但不突兀
|
||||||
case 1:
|
case 1:
|
||||||
// 低活动:使用主题主色的浅色版本
|
// 低活动:使用主题主色的浅色版本
|
||||||
return 'rgba(122, 90, 248, 0.15)'; // 浅色模式下的浅紫色
|
return 'rgba(122, 90, 248, 0.15)'; // 浅色模式下的浅紫色
|
||||||
@@ -159,12 +162,53 @@ const ActivityHeatMap = () => {
|
|||||||
<Text style={[styles.subtitle, { color: colors.textMuted }]}>
|
<Text style={[styles.subtitle, { color: colors.textMuted }]}>
|
||||||
最近6个月活跃 {activityStats.activeDays} 天
|
最近6个月活跃 {activityStats.activeDays} 天
|
||||||
</Text>
|
</Text>
|
||||||
<View style={[styles.statsBadge, {
|
<View style={styles.rightSection}>
|
||||||
backgroundColor: 'rgba(122, 90, 248, 0.1)'
|
<View style={[styles.statsBadge, {
|
||||||
}]}>
|
backgroundColor: 'rgba(122, 90, 248, 0.1)'
|
||||||
<Text style={[styles.statsText, { color: colors.primary }]}>
|
}]}>
|
||||||
{activityStats.activeRate}%
|
<Text style={[styles.statsText, { color: colors.primary }]}>
|
||||||
</Text>
|
{activityStats.activeRate}%
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<Popover
|
||||||
|
isVisible={showPopover}
|
||||||
|
onRequestClose={() => setShowPopover(false)}
|
||||||
|
from={(
|
||||||
|
<TouchableOpacity
|
||||||
|
style={styles.infoButton}
|
||||||
|
onPress={() => setShowPopover(true)}
|
||||||
|
>
|
||||||
|
<IconSymbol
|
||||||
|
name="info.circle"
|
||||||
|
size={16}
|
||||||
|
color={colors.textMuted}
|
||||||
|
/>
|
||||||
|
</TouchableOpacity>
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<View style={[styles.popoverContent, { backgroundColor: colors.card }]}>
|
||||||
|
<Text style={[styles.popoverTitle, { color: colors.text }]}>
|
||||||
|
小鱼干可以用来与小海豹进行对话
|
||||||
|
</Text>
|
||||||
|
<Text style={[styles.popoverSubtitle, { color: colors.text }]}>
|
||||||
|
获取说明
|
||||||
|
</Text>
|
||||||
|
<View style={styles.popoverList}>
|
||||||
|
<Text style={[styles.popoverItem, { color: colors.textMuted }]}>
|
||||||
|
1. 每日登录获得小鱼干+1
|
||||||
|
</Text>
|
||||||
|
<Text style={[styles.popoverItem, { color: colors.textMuted }]}>
|
||||||
|
2. 每日记录心情获得小鱼干+1
|
||||||
|
</Text>
|
||||||
|
<Text style={[styles.popoverItem, { color: colors.textMuted }]}>
|
||||||
|
3. 记饮食获得小鱼干+1
|
||||||
|
</Text>
|
||||||
|
<Text style={[styles.popoverItem, { color: colors.textMuted }]}>
|
||||||
|
4. 完成一次目标获得小鱼干+1
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</Popover>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
@@ -263,6 +307,15 @@ const styles = StyleSheet.create({
|
|||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
marginBottom: 6,
|
marginBottom: 6,
|
||||||
},
|
},
|
||||||
|
rightSection: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: 8,
|
||||||
|
},
|
||||||
|
infoButton: {
|
||||||
|
padding: 4,
|
||||||
|
borderRadius: 8,
|
||||||
|
},
|
||||||
title: {
|
title: {
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
fontWeight: 'bold',
|
fontWeight: 'bold',
|
||||||
@@ -332,6 +385,34 @@ const styles = StyleSheet.create({
|
|||||||
borderRadius: 2.5,
|
borderRadius: 2.5,
|
||||||
borderWidth: 0.5,
|
borderWidth: 0.5,
|
||||||
},
|
},
|
||||||
|
popoverContent: {
|
||||||
|
padding: 16,
|
||||||
|
borderRadius: 12,
|
||||||
|
maxWidth: 280,
|
||||||
|
shadowColor: '#000',
|
||||||
|
shadowOffset: { width: 0, height: 2 },
|
||||||
|
shadowOpacity: 0.1,
|
||||||
|
shadowRadius: 8,
|
||||||
|
elevation: 5,
|
||||||
|
},
|
||||||
|
popoverTitle: {
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: '600',
|
||||||
|
marginBottom: 12,
|
||||||
|
textAlign: 'center',
|
||||||
|
},
|
||||||
|
popoverSubtitle: {
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: '600',
|
||||||
|
marginBottom: 8,
|
||||||
|
},
|
||||||
|
popoverList: {
|
||||||
|
gap: 6,
|
||||||
|
},
|
||||||
|
popoverItem: {
|
||||||
|
fontSize: 14,
|
||||||
|
lineHeight: 20,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export default ActivityHeatMap;
|
export default ActivityHeatMap;
|
||||||
|
|||||||
@@ -122,8 +122,8 @@ const styles = StyleSheet.create({
|
|||||||
gap: 8,
|
gap: 8,
|
||||||
},
|
},
|
||||||
goalsIconButton: {
|
goalsIconButton: {
|
||||||
width: 24,
|
width: 18,
|
||||||
height: 24,
|
height: 18,
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ const MAPPING = {
|
|||||||
'person.fill': 'person',
|
'person.fill': 'person',
|
||||||
'person.3.fill': 'people',
|
'person.3.fill': 'people',
|
||||||
'message.fill': 'message',
|
'message.fill': 'message',
|
||||||
|
'info.circle': 'info',
|
||||||
} as IconMapping;
|
} as IconMapping;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ export const Colors = {
|
|||||||
textMuted: palette.gray[400], // 浅灰色用于静音文本
|
textMuted: palette.gray[400], // 浅灰色用于静音文本
|
||||||
background: palette.base.white,
|
background: palette.base.white,
|
||||||
surface: palette.base.white,
|
surface: palette.base.white,
|
||||||
card: palette.gray[25], // 最浅灰色用于卡片背景
|
card: '#ffffff', // 最浅灰色用于卡片背景
|
||||||
|
|
||||||
// 品牌与可交互主色
|
// 品牌与可交互主色
|
||||||
tint: tintColorLight,
|
tint: tintColorLight,
|
||||||
|
|||||||
Reference in New Issue
Block a user