From ebea9d824f9e624885eb9b03bf1cdc7ae2bde53a Mon Sep 17 00:00:00 2001 From: Innei Date: Tue, 11 Feb 2025 15:42:27 +0800 Subject: [PATCH] refactor: improve navigation and component rendering in mobile app - Update SafeNavigationScrollView to support custom headerLeft prop - Optimize EntryListScreen with memoized header actions and simplified conditions - Simplify EntryListContent by removing BottomTabBarHeightContext.Consumer - Add Link to Terms of Service in login screen - Wrap Feed screen with BottomTabBarHeightContext.Provider Signed-off-by: Innei --- .../common/SafeNavigationScrollView.tsx | 19 +++-- .../src/modules/entry-list/entry-list.tsx | 75 ++++++++----------- apps/mobile/src/modules/login/index.tsx | 8 +- .../screens/(stack)/feeds/[feedId]/index.tsx | 9 ++- 4 files changed, 56 insertions(+), 55 deletions(-) diff --git a/apps/mobile/src/components/common/SafeNavigationScrollView.tsx b/apps/mobile/src/components/common/SafeNavigationScrollView.tsx index 1dbb9861a..298cd8406 100644 --- a/apps/mobile/src/components/common/SafeNavigationScrollView.tsx +++ b/apps/mobile/src/components/common/SafeNavigationScrollView.tsx @@ -143,6 +143,7 @@ export const NavigationBlurEffectHeader = ({ })) const hideableBottom = headerHideableBottom?.() + const { headerLeft, ...rest } = props return ( ( - router.back()}> - - - ) - : undefined, + headerLeft: + headerLeft ?? + (canBack + ? () => ( + router.back()}> + + + ) + : undefined), header: headerHideableBottom ? ({ options }) => { @@ -176,7 +179,7 @@ export const NavigationBlurEffectHeader = ({ } : undefined, - ...props, + ...rest, }} /> ) diff --git a/apps/mobile/src/modules/entry-list/entry-list.tsx b/apps/mobile/src/modules/entry-list/entry-list.tsx index 4d4218881..0df6e98c6 100644 --- a/apps/mobile/src/modules/entry-list/entry-list.tsx +++ b/apps/mobile/src/modules/entry-list/entry-list.tsx @@ -1,5 +1,5 @@ import { FeedViewType } from "@follow/constants" -import { BottomTabBarHeightContext } from "@react-navigation/bottom-tabs" +import { useBottomTabBarHeight } from "@react-navigation/bottom-tabs" import type { ListRenderItemInfo } from "@shopify/flash-list" import { FlashList } from "@shopify/flash-list" import { Image } from "expo-image" @@ -38,24 +38,18 @@ export function EntryListScreen({ entryIds }: { entryIds: string[] }) { const viewTitle = useSelectedFeedTitle() const screenType = useEntryListContext().type + const isFeed = screenType === "feed" + const isTimeline = screenType === "timeline" return ( ({ scrollY }), [scrollY])}> (screenType === "timeline" ? : null), - [screenType], - )} - headerRight={useCallback( - () => (screenType === "timeline" ? : null), - [screenType], - )} - headerHideableBottomHeight={ - screenType === "timeline" ? headerHideableBottomHeight : undefined - } - headerHideableBottom={screenType === "timeline" ? ViewSelector : undefined} + headerLeft={useMemo(() => (isTimeline ? () => : undefined), [isTimeline])} + headerRight={useMemo(() => (isTimeline ? () => : undefined), [isTimeline])} + headerHideableBottomHeight={isTimeline ? headerHideableBottomHeight : undefined} + headerHideableBottom={isTimeline ? ViewSelector : undefined} /> {view === FeedViewType.Pictures || view === FeedViewType.Videos ? ( @@ -66,7 +60,7 @@ export function EntryListScreen({ entryIds }: { entryIds: string[] }) { ) } -export function EntryListContent({ entryIds }: { entryIds: string[] }) { +function EntryListContent({ entryIds }: { entryIds: string[] }) { const screenType = useEntryListContext().type const insets = useSafeAreaInsets() @@ -92,34 +86,31 @@ export function EntryListContent({ entryIds }: { entryIds: string[] }) { [], ) + const tabBarHeight = useBottomTabBarHeight() return ( - - {(tabBarHeight) => ( - id} - onEndReached={() => { - fetchNextPage() - }} - onViewableItemsChanged={({ viewableItems }) => { - debouncedFetchEntryContentByStream(viewableItems.map((item) => item.key)) - }} - scrollIndicatorInsets={{ - top: headerHeight - insets.top, - bottom: tabBarHeight ? tabBarHeight - insets.bottom : undefined, - }} - estimatedItemSize={100} - contentContainerStyle={{ - paddingTop: headerHeight, - paddingBottom: tabBarHeight, - }} - ItemSeparatorComponent={ItemSeparator} - ListFooterComponent={isFetchingNextPage ? : null} - /> - )} - + id} + onEndReached={() => { + fetchNextPage() + }} + onViewableItemsChanged={({ viewableItems }) => { + debouncedFetchEntryContentByStream(viewableItems.map((item) => item.key)) + }} + scrollIndicatorInsets={{ + top: headerHeight - insets.top, + bottom: tabBarHeight ? tabBarHeight - insets.bottom : undefined, + }} + estimatedItemSize={100} + contentContainerStyle={{ + paddingTop: headerHeight, + paddingBottom: tabBarHeight, + }} + ItemSeparatorComponent={ItemSeparator} + ListFooterComponent={isFetchingNextPage ? : null} + /> ) } diff --git a/apps/mobile/src/modules/login/index.tsx b/apps/mobile/src/modules/login/index.tsx index dfe7a4a51..92f96c097 100644 --- a/apps/mobile/src/modules/login/index.tsx +++ b/apps/mobile/src/modules/login/index.tsx @@ -1,4 +1,4 @@ -import { router } from "expo-router" +import { Link, router } from "expo-router" import { forwardRef, useCallback, useImperativeHandle, useRef, useState } from "react" import { TouchableWithoutFeedback, View } from "react-native" import BouncyCheckbox from "react-native-bouncy-checkbox" @@ -128,7 +128,11 @@ const TermsText = () => { - I agree to the Terms of Service and Privacy Policy + I agree to the{" "} + + Terms of Service + {" "} + and Privacy Policy diff --git a/apps/mobile/src/screens/(stack)/feeds/[feedId]/index.tsx b/apps/mobile/src/screens/(stack)/feeds/[feedId]/index.tsx index 67ed5045c..24b496c70 100644 --- a/apps/mobile/src/screens/(stack)/feeds/[feedId]/index.tsx +++ b/apps/mobile/src/screens/(stack)/feeds/[feedId]/index.tsx @@ -1,3 +1,4 @@ +import { BottomTabBarHeightContext } from "@react-navigation/bottom-tabs" import { useLocalSearchParams } from "expo-router" import { useMemo } from "react" @@ -11,9 +12,11 @@ export default function Feed() { const entryIdsByCategory = useEntryIdsByCategory(feedIdOrCategory as string) return ( ({ type: "feed" }), [])}> - 0 ? entryIdsByFeedId : entryIdsByCategory} - /> + + 0 ? entryIdsByFeedId : entryIdsByCategory} + /> + ) }