feat(Apps): introduce Apps tab and related screens for enhanced navigation
- Added a new "Apps" tab in the TabsLayout, providing users with access to various applications. - Created AppsScreen to display app entries, including a schedule feature with a calendar icon. - Implemented routing for the schedule and course screens under the new Apps tab structure. - Updated navigation hrefs to reflect the new Apps section, improving overall user experience. - Refactored HomeScreen to manage bottom tab visibility based on scroll events, enhancing usability.
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
* 支持列表和多列网格模式(响应式布局)
|
||||
*/
|
||||
|
||||
import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react';
|
||||
import React, { useState, useEffect, useLayoutEffect, useCallback, useMemo, useRef } from 'react';
|
||||
import {
|
||||
View,
|
||||
FlatList,
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
StatusBar,
|
||||
TouchableOpacity,
|
||||
NativeSyntheticEvent,
|
||||
NativeScrollEvent,
|
||||
Alert,
|
||||
Clipboard,
|
||||
Modal,
|
||||
@@ -92,6 +93,24 @@ export const HomeScreen: React.FC = () => {
|
||||
|
||||
const isLoadingMoreRef = useRef(false);
|
||||
|
||||
/** 横向胶囊条滚动位置:切换频道刷新列表时不重置 */
|
||||
const capsuleHScrollRef = useRef<ScrollView | null>(null);
|
||||
const capsuleScrollXRef = useRef(0);
|
||||
|
||||
const restoreCapsuleStripScroll = useCallback(() => {
|
||||
const x = capsuleScrollXRef.current;
|
||||
if (x <= 0) return;
|
||||
const scroll = () => capsuleHScrollRef.current?.scrollTo({ x, animated: false });
|
||||
scroll();
|
||||
requestAnimationFrame(() => {
|
||||
requestAnimationFrame(scroll);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const onCapsuleHorizontalScroll = useCallback((e: NativeSyntheticEvent<NativeScrollEvent>) => {
|
||||
capsuleScrollXRef.current = e.nativeEvent.contentOffset.x;
|
||||
}, []);
|
||||
|
||||
// 构建一个以 postId 为 key 的 map,用于快速查找
|
||||
const postsMap = useMemo(() => {
|
||||
const map = new Map<string, Post>();
|
||||
@@ -114,6 +133,11 @@ export const HomeScreen: React.FC = () => {
|
||||
const isLatestTab = activeIndex === 1;
|
||||
const currentChannelId = isLatestTab && activeCapsuleId ? activeCapsuleId : undefined;
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (!isLatestTab) return;
|
||||
restoreCapsuleStripScroll();
|
||||
}, [isLatestTab, activeCapsuleId, latestCapsules.length, restoreCapsuleStripScroll]);
|
||||
|
||||
// 使用差异更新 Hook 获取帖子列表
|
||||
const listKey = useMemo(
|
||||
() => `home_${getPostType()}_${currentChannelId || 'all'}`,
|
||||
@@ -453,7 +477,15 @@ export const HomeScreen: React.FC = () => {
|
||||
|
||||
return (
|
||||
<View style={[styles.capsuleWrapper, { paddingHorizontal: responsivePadding }]}>
|
||||
<ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={styles.capsuleList}>
|
||||
<ScrollView
|
||||
ref={capsuleHScrollRef}
|
||||
horizontal
|
||||
showsHorizontalScrollIndicator={false}
|
||||
contentContainerStyle={styles.capsuleList}
|
||||
onScroll={onCapsuleHorizontalScroll}
|
||||
scrollEventThrottle={16}
|
||||
onContentSizeChange={restoreCapsuleStripScroll}
|
||||
>
|
||||
{latestCapsules.map((item) => {
|
||||
const isActive = item.id === activeCapsuleId;
|
||||
return (
|
||||
|
||||
@@ -2054,30 +2054,23 @@ const styles = StyleSheet.create({
|
||||
paddingVertical: spacing.xs,
|
||||
borderRadius: borderRadius.md,
|
||||
},
|
||||
// 空评论状态样式
|
||||
// 空评论状态样式(与平铺评论区一致,无卡片气泡)
|
||||
emptyCommentsContainer: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginHorizontal: spacing.lg,
|
||||
marginTop: spacing.lg,
|
||||
marginBottom: spacing.md,
|
||||
paddingVertical: spacing.xl + spacing.md,
|
||||
paddingHorizontal: spacing.lg,
|
||||
borderRadius: borderRadius.lg,
|
||||
backgroundColor: colors.background.paper,
|
||||
borderWidth: StyleSheet.hairlineWidth,
|
||||
borderColor: colors.divider,
|
||||
marginHorizontal: spacing.md,
|
||||
marginTop: spacing.md,
|
||||
marginBottom: spacing.lg,
|
||||
paddingVertical: spacing.xl,
|
||||
paddingHorizontal: spacing.md,
|
||||
},
|
||||
emptyCommentsIconWrapper: {
|
||||
width: 44,
|
||||
height: 44,
|
||||
borderRadius: 22,
|
||||
backgroundColor: colors.background.default,
|
||||
borderWidth: StyleSheet.hairlineWidth,
|
||||
borderColor: colors.divider,
|
||||
width: 40,
|
||||
height: 40,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginBottom: spacing.sm,
|
||||
opacity: 0.85,
|
||||
},
|
||||
emptyCommentsTitle: {
|
||||
fontSize: fontSizes.md,
|
||||
|
||||
Reference in New Issue
Block a user