diff --git a/client/app/(app)/home.tsx b/client/app/(app)/home.tsx index c0fb964..8758129 100644 --- a/client/app/(app)/home.tsx +++ b/client/app/(app)/home.tsx @@ -1,5 +1,5 @@ import { useEffect, useLayoutEffect, useMemo, useState, useCallback, useRef } from 'react'; -import { StyleSheet, View, Dimensions, Text, Pressable, PanResponder, Animated as RNAnimated } from 'react-native'; +import { StyleSheet, View, Dimensions, Text, Pressable, PanResponder, Animated as RNAnimated, ImageBackground } from 'react-native'; import { useTranslation } from 'react-i18next'; import { useNavigation, useFocusEffect } from 'expo-router'; import Animated, { @@ -31,6 +31,40 @@ import LikeIcon from '@/assets/images/icon/like_icon.svg'; const { height: SCREEN_HEIGHT } = Dimensions.get('window'); +// 预定义风景图列表 +const NATURE_IMAGES = [ + require('@/assets/theme/nature/1.png'), + require('@/assets/theme/nature/2.png'), + require('@/assets/theme/nature/3.png'), + require('@/assets/theme/nature/4.png'), + require('@/assets/theme/nature/5.png'), + require('@/assets/theme/nature/6.png'), + require('@/assets/theme/nature/7.png'), + require('@/assets/theme/nature/8.png'), + require('@/assets/theme/nature/9.png'), + require('@/assets/theme/nature/10.png'), + require('@/assets/theme/nature/11.png'), + require('@/assets/theme/nature/12.png'), + require('@/assets/theme/nature/13.png'), + require('@/assets/theme/nature/14.png'), + require('@/assets/theme/nature/15.png'), + require('@/assets/theme/nature/17.png'), + require('@/assets/theme/nature/18.png'), + require('@/assets/theme/nature/19.png'), + require('@/assets/theme/nature/20.png'), + require('@/assets/theme/nature/22.png'), +]; + +// 预定义颜色列表 +const THEME_COLORS = [ + '#F7D9BF', + '#CBF2D8', + '#F5CDDE', + '#F2ECCB', + '#E2CBF2', + '#CBD9F2', +]; + export default function HomeScreen() { const { t } = useTranslation(); const navigation = useNavigation(); @@ -66,12 +100,26 @@ export default function HomeScreen() { }, []) ); - const backgroundColor = themeMode === 'color' ? '#F3D0E1' : '#F4D6C2'; + const backgroundColor = useMemo(() => { + if (themeMode === 'color') { + const colorIndex = Math.floor(index / 10) % THEME_COLORS.length; + return THEME_COLORS[colorIndex]; + } + return '#F4D6C2'; // 风景模式下的默认底色(图片加载前显示) + }, [themeMode, index]); + + // 计算当前应该显示的风景图索引(滑动 10 次切换一张) + const natureImageIndex = useMemo(() => { + return Math.floor(index / 10) % NATURE_IMAGES.length; + }, [index]); + + const currentNatureImage = NATURE_IMAGES[natureImageIndex]; useLayoutEffect(() => { navigation.setOptions({ headerShadowVisible: false, - headerStyle: { backgroundColor }, + headerStyle: { backgroundColor: themeMode === 'scenery' ? 'transparent' : backgroundColor }, + headerTransparent: themeMode === 'scenery', headerRight: () => ( ), }); - }, [backgroundColor, navigation, t]); + }, [backgroundColor, themeMode, navigation, t]); const textAnimatedStyle = useAnimatedStyle(() => ({ transform: [{ translateY: translateY.value }], @@ -176,10 +224,11 @@ export default function HomeScreen() { // 2. 保存到收藏夹,包含当前背景信息 await addFavorite({ + favId: String(Date.now()), // 生成唯一 ID id: item.id, date: dateStr, themeMode: themeMode, - background: backgroundColor, // 目前存储的是颜色值 + background: themeMode === 'scenery' ? String(natureImageIndex) : backgroundColor, }); // 3. 爱心缩放动画 @@ -202,8 +251,15 @@ export default function HomeScreen() { return ( - - {item.text} + {themeMode === 'scenery' && ( + + )} + + {item.text} @@ -216,9 +272,13 @@ export default function HomeScreen() { style={styles.reactionInner} > {likeFilled ? ( - + ) : ( - + )} @@ -277,9 +337,15 @@ const styles = StyleSheet.create({ justifyContent: 'center', }, card: { - paddingHorizontal: 30, - alignItems: 'center', + position: 'absolute', + top: 0, + left: 0, + right: 0, + bottom: 0, justifyContent: 'center', + alignItems: 'center', + paddingHorizontal: 30, + zIndex: 5, // 降低层级,防止遮挡底部按钮 }, text: { fontSize: 22, @@ -288,6 +354,16 @@ const styles = StyleSheet.create({ fontWeight: '700', textAlign: 'center', }, + sceneryCard: { + // 风景模式下稍微收窄文案宽度,增加呼吸感 + paddingHorizontal: 50, + }, + sceneryText: { + color: '#FFFFFF', + textShadowColor: 'rgba(0, 0, 0, 0.5)', + textShadowOffset: { width: 0, height: 1 }, + textShadowRadius: 4, + }, actions: { position: 'absolute', bottom: SCREEN_HEIGHT * 0.16, @@ -295,6 +371,7 @@ const styles = StyleSheet.create({ right: 0, flexDirection: 'row', justifyContent: 'center', + zIndex: 20, // 提升层级,确保在最顶层可点击 }, reactionButton: { alignItems: 'center', diff --git a/client/assets/images/home/like_filled.svg b/client/assets/images/home/like_filled.svg index f8749df..cb3c2c1 100644 --- a/client/assets/images/home/like_filled.svg +++ b/client/assets/images/home/like_filled.svg @@ -1,4 +1,4 @@ - + diff --git a/client/assets/images/icon/like_icon.svg b/client/assets/images/icon/like_icon.svg index a52fe32..bd94d57 100644 --- a/client/assets/images/icon/like_icon.svg +++ b/client/assets/images/icon/like_icon.svg @@ -1,3 +1,3 @@ - + diff --git a/client/assets/theme/nature/1.png b/client/assets/theme/nature/1.png new file mode 100644 index 0000000..65e98a2 Binary files /dev/null and b/client/assets/theme/nature/1.png differ diff --git a/client/assets/theme/nature/10.png b/client/assets/theme/nature/10.png new file mode 100644 index 0000000..a460796 Binary files /dev/null and b/client/assets/theme/nature/10.png differ diff --git a/client/assets/theme/nature/11.png b/client/assets/theme/nature/11.png new file mode 100644 index 0000000..1a66767 Binary files /dev/null and b/client/assets/theme/nature/11.png differ diff --git a/client/assets/theme/nature/12.png b/client/assets/theme/nature/12.png new file mode 100644 index 0000000..f32f373 Binary files /dev/null and b/client/assets/theme/nature/12.png differ diff --git a/client/assets/theme/nature/13.png b/client/assets/theme/nature/13.png new file mode 100644 index 0000000..b4613cf Binary files /dev/null and b/client/assets/theme/nature/13.png differ diff --git a/client/assets/theme/nature/14.png b/client/assets/theme/nature/14.png new file mode 100644 index 0000000..a8e1de6 Binary files /dev/null and b/client/assets/theme/nature/14.png differ diff --git a/client/assets/theme/nature/15.png b/client/assets/theme/nature/15.png new file mode 100644 index 0000000..d84c28f Binary files /dev/null and b/client/assets/theme/nature/15.png differ diff --git a/client/assets/theme/nature/17.png b/client/assets/theme/nature/17.png new file mode 100644 index 0000000..86c003f Binary files /dev/null and b/client/assets/theme/nature/17.png differ diff --git a/client/assets/theme/nature/18.png b/client/assets/theme/nature/18.png new file mode 100644 index 0000000..e945639 Binary files /dev/null and b/client/assets/theme/nature/18.png differ diff --git a/client/assets/theme/nature/19.png b/client/assets/theme/nature/19.png new file mode 100644 index 0000000..a3bda43 Binary files /dev/null and b/client/assets/theme/nature/19.png differ diff --git a/client/assets/theme/nature/2.png b/client/assets/theme/nature/2.png new file mode 100644 index 0000000..21bac6a Binary files /dev/null and b/client/assets/theme/nature/2.png differ diff --git a/client/assets/theme/nature/20.png b/client/assets/theme/nature/20.png new file mode 100644 index 0000000..59be818 Binary files /dev/null and b/client/assets/theme/nature/20.png differ diff --git a/client/assets/theme/nature/22.png b/client/assets/theme/nature/22.png new file mode 100644 index 0000000..7e9c2a9 Binary files /dev/null and b/client/assets/theme/nature/22.png differ diff --git a/client/assets/theme/nature/3.png b/client/assets/theme/nature/3.png new file mode 100644 index 0000000..4a1f8ab Binary files /dev/null and b/client/assets/theme/nature/3.png differ diff --git a/client/assets/theme/nature/4.png b/client/assets/theme/nature/4.png new file mode 100644 index 0000000..9837d09 Binary files /dev/null and b/client/assets/theme/nature/4.png differ diff --git a/client/assets/theme/nature/5.png b/client/assets/theme/nature/5.png new file mode 100644 index 0000000..f7d8cb1 Binary files /dev/null and b/client/assets/theme/nature/5.png differ diff --git a/client/assets/theme/nature/6.png b/client/assets/theme/nature/6.png new file mode 100644 index 0000000..457e4a3 Binary files /dev/null and b/client/assets/theme/nature/6.png differ diff --git a/client/assets/theme/nature/7.png b/client/assets/theme/nature/7.png new file mode 100644 index 0000000..ed2cd1d Binary files /dev/null and b/client/assets/theme/nature/7.png differ diff --git a/client/assets/theme/nature/8.png b/client/assets/theme/nature/8.png new file mode 100644 index 0000000..8e6e7b9 Binary files /dev/null and b/client/assets/theme/nature/8.png differ diff --git a/client/assets/theme/nature/9.png b/client/assets/theme/nature/9.png new file mode 100644 index 0000000..9d47eb0 Binary files /dev/null and b/client/assets/theme/nature/9.png differ diff --git a/client/components/home/.ProfileModal.tsx.swp b/client/components/home/.ProfileModal.tsx.swp deleted file mode 100644 index 9e07e56..0000000 Binary files a/client/components/home/.ProfileModal.tsx.swp and /dev/null differ diff --git a/client/components/home/ProfileModal.tsx b/client/components/home/ProfileModal.tsx index e657e3f..9381112 100644 --- a/client/components/home/ProfileModal.tsx +++ b/client/components/home/ProfileModal.tsx @@ -50,6 +50,29 @@ type Props = { type Page = 'root' | 'favorites' | 'dailyReminder' | 'widget' | 'language' | 'widgetHowTo'; type NavDirection = 'forward' | 'back'; +const NATURE_IMAGES = [ + require('@/assets/theme/nature/1.png'), + require('@/assets/theme/nature/2.png'), + require('@/assets/theme/nature/3.png'), + require('@/assets/theme/nature/4.png'), + require('@/assets/theme/nature/5.png'), + require('@/assets/theme/nature/6.png'), + require('@/assets/theme/nature/7.png'), + require('@/assets/theme/nature/8.png'), + require('@/assets/theme/nature/9.png'), + require('@/assets/theme/nature/10.png'), + require('@/assets/theme/nature/11.png'), + require('@/assets/theme/nature/12.png'), + require('@/assets/theme/nature/13.png'), + require('@/assets/theme/nature/14.png'), + require('@/assets/theme/nature/15.png'), + require('@/assets/theme/nature/17.png'), + require('@/assets/theme/nature/18.png'), + require('@/assets/theme/nature/19.png'), + require('@/assets/theme/nature/20.png'), + require('@/assets/theme/nature/22.png'), +]; + export default function ProfileModal({ visible, name: propName, onClose }: Props) { const { t } = useTranslation(); @@ -260,11 +283,11 @@ function FavoritesPage({ visible, page }: { visible: boolean; page: Page }) { setFavorites(list); } - async function handleRemove(id: string) { + async function handleRemove(favId: string) { // 1. 调用存储层移除收藏 - await removeFavorite(id); + await removeFavorite(favId); // 2. 更新本地状态 - setFavorites(prev => prev.filter(item => item.id !== id)); + setFavorites(prev => prev.filter(item => item.favId !== favId)); } return ( @@ -274,7 +297,7 @@ function FavoritesPage({ visible, page }: { visible: boolean; page: Page }) { ) : ( it.id} + keyExtractor={(it) => it.favId} contentContainerStyle={styles.favList} showsVerticalScrollIndicator={false} renderItem={({ item }) => ( @@ -290,11 +313,30 @@ function FavoritesPage({ visible, page }: { visible: boolean; page: Page }) { - {item.text} + {item.themeMode === 'scenery' ? ( + + + + ) : null} + + {item.text} + handleRemove(item.id)} + onPress={() => handleRemove(item.favId)} style={styles.favRemoveBtn} hitSlop={10} > @@ -765,6 +807,7 @@ const styles = StyleSheet.create({ position: 'relative', borderWidth: 1, borderColor: 'rgba(119, 47, 0, 0.05)', + overflow: 'hidden', }, favThumbText: { fontSize: 15, diff --git a/client/components/ui/.SheetModal.tsx.swp b/client/components/ui/.SheetModal.tsx.swp deleted file mode 100644 index e0c938d..0000000 Binary files a/client/components/ui/.SheetModal.tsx.swp and /dev/null differ diff --git a/client/src/storage/appStorage.ts b/client/src/storage/appStorage.ts index 455038a..fefc4b6 100644 --- a/client/src/storage/appStorage.ts +++ b/client/src/storage/appStorage.ts @@ -70,6 +70,7 @@ export async function setReaction(contentId: string, reaction: Reaction): Promis } export type FavoriteItem = { + favId: string; // 唯一标识,支持重复点赞同一文案 id: string; date: string; themeMode: ThemeMode; @@ -82,15 +83,15 @@ export async function getFavorites(): Promise { export async function addFavorite(item: FavoriteItem): Promise { const list = await getFavorites(); - if (list.some(i => i.id === item.id)) return; + // 允许重复点赞,不再根据 id 去重 const newList = [item, ...list]; console.log('Adding to favorites, new list size:', newList.length); await setJson(KEY_FAVORITES_ITEMS, newList); } -export async function removeFavorite(contentId: string): Promise { +export async function removeFavorite(favId: string): Promise { const list = await getFavorites(); - const next = list.filter(item => item.id !== contentId); + const next = list.filter(item => item.favId !== favId); await setJson(KEY_FAVORITES_ITEMS, next); }