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 <tukon479@gmail.com>
This commit is contained in:
Innei 2025-02-11 15:42:27 +08:00
parent f5618ddb3a
commit ebea9d824f
No known key found for this signature in database
GPG Key ID: 0F62D33977F021F7
4 changed files with 56 additions and 55 deletions

View File

@ -143,6 +143,7 @@ export const NavigationBlurEffectHeader = ({
}))
const hideableBottom = headerHideableBottom?.()
const { headerLeft, ...rest } = props
return (
<Stack.Screen
@ -154,13 +155,15 @@ export const NavigationBlurEffectHeader = ({
),
headerTransparent: true,
headerLeft: canBack
? () => (
<TouchableOpacity hitSlop={10} onPress={() => router.back()}>
<MingcuteLeftLineIcon height={20} width={20} color={label} />
</TouchableOpacity>
)
: undefined,
headerLeft:
headerLeft ??
(canBack
? () => (
<TouchableOpacity hitSlop={10} onPress={() => router.back()}>
<MingcuteLeftLineIcon height={20} width={20} color={label} />
</TouchableOpacity>
)
: undefined),
header: headerHideableBottom
? ({ options }) => {
@ -176,7 +179,7 @@ export const NavigationBlurEffectHeader = ({
}
: undefined,
...props,
...rest,
}}
/>
)

View File

@ -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 (
<NavigationContext.Provider value={useMemo(() => ({ scrollY }), [scrollY])}>
<NavigationBlurEffectHeader
headerBackTitle={screenType === "feed" ? "Subscriptions" : undefined}
headerBackTitle={isFeed ? "Subscriptions" : undefined}
headerShown
headerTitle={viewTitle}
headerLeft={useCallback(
() => (screenType === "timeline" ? <LeftAction /> : null),
[screenType],
)}
headerRight={useCallback(
() => (screenType === "timeline" ? <RightAction /> : null),
[screenType],
)}
headerHideableBottomHeight={
screenType === "timeline" ? headerHideableBottomHeight : undefined
}
headerHideableBottom={screenType === "timeline" ? ViewSelector : undefined}
headerLeft={useMemo(() => (isTimeline ? () => <LeftAction /> : undefined), [isTimeline])}
headerRight={useMemo(() => (isTimeline ? () => <RightAction /> : undefined), [isTimeline])}
headerHideableBottomHeight={isTimeline ? headerHideableBottomHeight : undefined}
headerHideableBottom={isTimeline ? ViewSelector : undefined}
/>
{view === FeedViewType.Pictures || view === FeedViewType.Videos ? (
<EntryListContentGrid entryIds={entryIds} />
@ -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 (
<BottomTabBarHeightContext.Consumer>
{(tabBarHeight) => (
<FlashList
onScroll={onScroll}
data={entryIds}
renderItem={renderItem}
keyExtractor={(id) => 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 ? <EntryItemSkeleton /> : null}
/>
)}
</BottomTabBarHeightContext.Consumer>
<FlashList
onScroll={onScroll}
data={entryIds}
renderItem={renderItem}
keyExtractor={(id) => 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 ? <EntryItemSkeleton /> : null}
/>
)
}

View File

@ -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 = () => {
<ContextMenu.Root>
<ContextMenu.Trigger className="overflow-hidden rounded-full">
<ThemedText className="text-secondary-label text-sm">
I agree to the Terms of Service and Privacy Policy
I agree to the{" "}
<Link href="/terms" className="text-primary-label">
Terms of Service
</Link>{" "}
and Privacy Policy
</ThemedText>
</ContextMenu.Trigger>

View File

@ -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 (
<EntryListContext.Provider value={useMemo(() => ({ type: "feed" }), [])}>
<EntryListScreen
entryIds={entryIdsByFeedId.length > 0 ? entryIdsByFeedId : entryIdsByCategory}
/>
<BottomTabBarHeightContext.Provider value={0}>
<EntryListScreen
entryIds={entryIdsByFeedId.length > 0 ? entryIdsByFeedId : entryIdsByCategory}
/>
</BottomTabBarHeightContext.Provider>
</EntryListContext.Provider>
)
}