refactor(mobile): enhance header components and layout

- Introduced `NavigationBlurEffectHeaderView` for improved header rendering in various settings screens.
- Updated `SafeNavigationScrollView` to accept a `Header` prop for better layout flexibility.
- Refactored existing screens to utilize the new header component, enhancing consistency across the app.
- Adjusted styles for header text to improve visual hierarchy.

Signed-off-by: Innei <tukon479@gmail.com>
This commit is contained in:
Innei 2025-04-07 21:23:12 +08:00
parent cd024e45d3
commit bb7fa92d45
No known key found for this signature in database
GPG Key ID: 0F62D33977F021F7
21 changed files with 258 additions and 179 deletions

View File

@ -90,7 +90,7 @@ export const HeaderSubmitTextButton = ({
)}
<Text
className={cn(
"text-accent text-base font-semibold",
"text-accent text-base font-bold",
!isValid && "text-secondary-label",
isLoading && "opacity-0",
)}

View File

@ -43,6 +43,8 @@ type SafeNavigationScrollViewProps = Omit<ScrollViewProps, "onScroll"> & {
contentViewStyle?: StyleProp<ViewStyle>
contentViewClassName?: string
Header?: React.ReactNode
} & PropsWithChildren
export const SafeNavigationScrollView = forwardRef<ScrollView, SafeNavigationScrollViewProps>(
@ -55,6 +57,7 @@ export const SafeNavigationScrollView = forwardRef<ScrollView, SafeNavigationScr
reanimatedScrollY,
contentViewClassName,
contentViewStyle,
Header,
...props
},
forwardedRef,
@ -95,6 +98,7 @@ export const SafeNavigationScrollView = forwardRef<ScrollView, SafeNavigationScr
return (
<NavigationHeaderHeightContext.Provider value={headerHeight}>
<SetNavigationHeaderHeightContext.Provider value={setHeaderHeight}>
{Header}
<ReAnimatedScrollView
ref={ref}
onScroll={scrollHandler}
@ -131,6 +135,35 @@ export const SafeNavigationScrollView = forwardRef<ScrollView, SafeNavigationScr
},
)
export const NavigationBlurEffectHeaderView = ({
headerHideableBottom,
headerHideableBottomHeight,
headerTitleAbsolute,
...props
}: InternalNavigationHeaderProps & {
blurThreshold?: number
headerHideableBottom?: () => React.ReactNode
headerHideableBottomHeight?: number
headerTitleAbsolute?: boolean
}) => {
const hideableBottom = headerHideableBottom?.()
return (
<View className="absolute inset-x-0 top-0 z-[99]">
<InternalNavigationHeader
title={props.title}
headerRight={props.headerRight}
headerLeft={props.headerLeft}
hideableBottom={hideableBottom}
hideableBottomHeight={headerHideableBottomHeight}
headerTitleAbsolute={headerTitleAbsolute}
headerTitle={props.headerTitle}
promptBeforeLeave={props.promptBeforeLeave}
isLoading={props.isLoading}
/>
</View>
)
}
export const NavigationBlurEffectHeader = ({
headerHideableBottom,
headerHideableBottomHeight,

View File

@ -2,7 +2,7 @@ import { isUndefined } from "es-toolkit/compat"
import type { PrimitiveAtom } from "jotai"
import { atom, useAtomValue, useSetAtom } from "jotai"
import type { FC, ReactNode } from "react"
import { memo, useCallback, useContext, useMemo } from "react"
import { memo, useCallback, useContext, useMemo, useRef } from "react"
import type { NativeSyntheticEvent } from "react-native"
import { StyleSheet, View } from "react-native"
import { useSharedValue } from "react-native-reanimated"
@ -124,6 +124,9 @@ export const WrappedScreenItem: FC<
},
[navigation, screenId],
)
const ref = useRef<View>(null)
return (
<ScreenItemContext.Provider value={ctxValue}>
<ScreenOptionsContext.Provider value={screenOptionsCtxValue}>
@ -133,8 +136,10 @@ export const WrappedScreenItem: FC<
...defaultHeaderConfig,
...headerConfig,
}}
nativeID=""
key={screenId}
screenId={screenId}
ref={ref}
stackPresentation={stackPresentation}
style={[
StyleSheet.absoluteFill,

View File

@ -128,19 +128,20 @@ function FollowImpl(props: { feedId: string }) {
className="bg-system-grouped-background"
contentViewClassName="gap-y-4 mt-2"
contentContainerStyle={{ paddingBottom: insets.bottom }}
Header={
<NavigationBlurEffectHeader
title={`${isSubscribed ? "Edit" : "Follow"} - ${feed?.title}`}
headerRight={
<HeaderSubmitTextButton
isValid={isValid}
onPress={form.handleSubmit(submit)}
isLoading={isLoading}
label={isSubscribed ? "Save" : "Follow"}
/>
}
/>
}
>
<NavigationBlurEffectHeader
title={`${isSubscribed ? "Edit" : "Follow"} - ${feed?.title}`}
headerRight={
<HeaderSubmitTextButton
isValid={isValid}
onPress={form.handleSubmit(submit)}
isLoading={isLoading}
label={isSubscribed ? "Save" : "Follow"}
/>
}
/>
{/* Group 1 */}
<GroupedInsetListCard className="px-5 py-4">
<View className="flex flex-row gap-4">

View File

@ -5,7 +5,7 @@ import type { OtpInputRef } from "react-native-otp-entry"
import { OtpInput } from "react-native-otp-entry"
import {
NavigationBlurEffectHeader,
NavigationBlurEffectHeaderView,
SafeNavigationScrollView,
} from "@/src/components/layouts/views/SafeNavigationScrollView"
import { QRCode } from "@/src/components/ui/qrcode/QRCode"
@ -45,9 +45,7 @@ export const TwoFASetting: NavigationControllerView<{ totpURI: string }> = ({ to
return (
<KeyboardAvoidingView behavior="padding">
<SafeNavigationScrollView>
<NavigationBlurEffectHeader title="Setting 2FA" />
<SafeNavigationScrollView Header={<NavigationBlurEffectHeaderView title="Setting 2FA" />}>
<View className="my-8 items-center justify-center">
<QRCode
data={totpURI}

View File

@ -4,7 +4,7 @@ import { Linking, Text, View } from "react-native"
import { Link } from "@/src/components/common/Link"
import {
NavigationBlurEffectHeader,
NavigationBlurEffectHeaderView,
SafeNavigationScrollView,
} from "@/src/components/layouts/views/SafeNavigationScrollView"
import {
@ -49,9 +49,11 @@ export const AboutScreen = () => {
const appVersion = nativeApplicationVersion
return (
<SafeNavigationScrollView className="bg-system-grouped-background" contentViewClassName="pt-6">
<NavigationBlurEffectHeader title={t("titles.about")} />
<SafeNavigationScrollView
Header={<NavigationBlurEffectHeaderView title={t("titles.about")} />}
className="bg-system-grouped-background"
contentViewClassName="pt-6"
>
<GroupedInsetListCard>
<GroupedInsetListBaseCell className="flex-col py-6">
<View className="flex-1 items-center justify-center">

View File

@ -6,7 +6,7 @@ import { useTranslation } from "react-i18next"
import { Alert, Text, View } from "react-native"
import {
NavigationBlurEffectHeader,
NavigationBlurEffectHeaderView,
SafeNavigationScrollView,
} from "@/src/components/layouts/views/SafeNavigationScrollView"
import { GroupedInsetListCardItemStyle } from "@/src/components/ui/grouped/GroupedInsetListCardItemStyle"
@ -70,9 +70,10 @@ const useAccount = () => {
export const AccountScreen = () => {
const { t } = useTranslation("settings")
return (
<SafeNavigationScrollView className="bg-system-grouped-background">
<NavigationBlurEffectHeader title={t("titles.account")} />
<SafeNavigationScrollView
className="bg-system-grouped-background"
Header={<NavigationBlurEffectHeaderView title={t("titles.account")} />}
>
<AuthenticationSection />
<SecuritySection />

View File

@ -8,7 +8,7 @@ import { useColors } from "react-native-uikit-colors"
import { SwipeableGroupProvider, SwipeableItem } from "@/src/components/common/SwipeableItem"
import { HeaderSubmitTextButton } from "@/src/components/layouts/header/HeaderElements"
import {
NavigationBlurEffectHeader,
NavigationBlurEffectHeaderView,
SafeNavigationScrollView,
} from "@/src/components/layouts/views/SafeNavigationScrollView"
import {
@ -39,18 +39,22 @@ export const ActionsScreen = () => {
const isDirty = useIsActionDataDirty()
return (
<SafeNavigationScrollView nestedScrollEnabled className="bg-system-grouped-background">
<NavigationBlurEffectHeader
title={t("titles.actions")}
headerRight={useCallback(
() => (
<SaveRuleButton disabled={!isDirty} />
),
[isDirty],
)}
promptBeforeLeave={isDirty}
/>
<SafeNavigationScrollView
Header={
<NavigationBlurEffectHeaderView
title={t("titles.actions")}
headerRight={useCallback(
() => (
<SaveRuleButton disabled={!isDirty} />
),
[isDirty],
)}
promptBeforeLeave={isDirty}
/>
}
nestedScrollEnabled
className="bg-system-grouped-background"
>
<View className="mt-6">
<GroupedInsetListCard>
<GroupedInformationCell

View File

@ -4,7 +4,7 @@ import { useColorScheme, View } from "react-native"
import { setUISetting, useUISettingKey } from "@/src/atoms/settings/ui"
import {
NavigationBlurEffectHeader,
NavigationBlurEffectHeaderView,
SafeNavigationScrollView,
} from "@/src/components/layouts/views/SafeNavigationScrollView"
import { Select } from "@/src/components/ui/form/Select"
@ -29,10 +29,11 @@ export const AppearanceScreen = () => {
const hideRecentReader = useUISettingKey("hideRecentReader")
return (
<SafeNavigationScrollView className="bg-system-grouped-background">
<NavigationBlurEffectHeader title={t("appearance.title")} />
<GroupedInsetListSectionHeader label={t("appearance.subscriptions")} />
<SafeNavigationScrollView
className="bg-system-grouped-background"
Header={<NavigationBlurEffectHeaderView title={t("appearance.title")} />}
>
<GroupedInsetListSectionHeader label={t("appearance.subscriptions")} marginSize="small" />
<GroupedInsetListCard>
<GroupedInsetListCell
label={t("appearance.show_unread_count.label")}

View File

@ -4,7 +4,7 @@ import { Alert } from "react-native"
import { setDataSetting, useDataSettingKey } from "@/src/atoms/settings/data"
import {
NavigationBlurEffectHeader,
NavigationBlurEffectHeaderView,
SafeNavigationScrollView,
} from "@/src/components/layouts/views/SafeNavigationScrollView"
import {
@ -23,10 +23,11 @@ export const DataScreen = () => {
const { t } = useTranslation("settings")
const sendAnonymousData = useDataSettingKey("sendAnonymousData")
return (
<SafeNavigationScrollView className="bg-system-grouped-background">
<NavigationBlurEffectHeader title={t("titles.data_control")} />
<GroupedInsetListSectionHeader label={t("general.privacy")} />
<SafeNavigationScrollView
className="bg-system-grouped-background"
Header={<NavigationBlurEffectHeaderView title={t("titles.data_control")} />}
>
<GroupedInsetListSectionHeader label={t("general.privacy")} marginSize="small" />
<GroupedInsetListCard>
<GroupedInsetListCell

View File

@ -2,7 +2,7 @@ import { useTranslation } from "react-i18next"
import { Text, View } from "react-native"
import {
NavigationBlurEffectHeader,
NavigationBlurEffectHeaderView,
SafeNavigationScrollView,
} from "@/src/components/layouts/views/SafeNavigationScrollView"
import { Select } from "@/src/components/ui/form/Select"
@ -28,9 +28,10 @@ export const EditConditionScreen: NavigationControllerView<{
}> = (params) => {
const { t } = useTranslation("settings")
return (
<SafeNavigationScrollView className="bg-system-grouped-background">
<NavigationBlurEffectHeader title={t("actions.edit_condition")} />
<SafeNavigationScrollView
className="bg-system-grouped-background"
Header={<NavigationBlurEffectHeaderView title={t("actions.edit_condition")} />}
>
<ConditionForm index={params} />
</SafeNavigationScrollView>
)

View File

@ -8,6 +8,7 @@ import { KeyboardController } from "react-native-keyboard-controller"
import { HeaderSubmitTextButton } from "@/src/components/layouts/header/HeaderElements"
import {
NavigationBlurEffectHeader,
NavigationBlurEffectHeaderView,
SafeNavigationScrollView,
} from "@/src/components/layouts/views/SafeNavigationScrollView"
import { UserAvatar } from "@/src/components/ui/avatar/UserAvatar"
@ -35,6 +36,19 @@ import { setAvatar } from "../utils"
export const EditProfileScreen = () => {
const whoami = useWhoami()
const { t } = useTranslation("settings")
const [dirtyFields, setDirtyFields] = useState<Partial<UserProfileEditable>>({})
const { mutateAsync: updateProfile, isPending } = useMutation({
mutationFn: async () => {
await userSyncService.updateProfile(dirtyFields)
},
onSuccess: () => {
toast.success("Profile updated")
},
onError: (error) => {
toast.error(error.message)
},
})
if (!whoami) {
return (
@ -45,10 +59,26 @@ export const EditProfileScreen = () => {
}
return (
<SafeNavigationScrollView className="bg-system-grouped-background">
<SafeNavigationScrollView
Header={
<NavigationBlurEffectHeaderView
headerRight={
<HeaderSubmitTextButton
label={t("words.save", { ns: "common" })}
isValid={isPending || Object.keys(dirtyFields).length === 0}
onPress={() => {
updateProfile()
}}
/>
}
title={t("profile.edit_profile")}
/>
}
className="bg-system-grouped-background"
>
<NavigationBlurEffectHeader title={t("profile.edit_profile")} />
<AvatarSection whoami={whoami} />
<ProfileForm whoami={whoami} />
<ProfileForm whoami={whoami} dirtyFields={dirtyFields} setDirtyFields={setDirtyFields} />
</SafeNavigationScrollView>
)
}
@ -75,39 +105,14 @@ const AvatarSection: FC<{
const ProfileForm: FC<{
whoami: MeModel
}> = ({ whoami }) => {
dirtyFields: Partial<UserProfileEditable>
setDirtyFields: (dirtyFields: Partial<UserProfileEditable>) => void
}> = ({ whoami, dirtyFields, setDirtyFields }) => {
const { t } = useTranslation("settings")
const [dirtyFields, setDirtyFields] = useState<Partial<UserProfileEditable>>({})
const { mutateAsync: updateProfile, isPending } = useMutation({
mutationFn: async () => {
await userSyncService.updateProfile(dirtyFields)
},
onSuccess: () => {
toast.success("Profile updated")
},
onError: (error) => {
toast.error(error.message)
},
})
const navigation = useNavigation()
return (
<View className="mt-4">
<NavigationBlurEffectHeader
headerRight={
<HeaderSubmitTextButton
label={t("words.save", { ns: "common" })}
isValid={isPending || Object.keys(dirtyFields).length === 0}
onPress={() => {
updateProfile()
}}
/>
}
title={t("profile.edit_profile")}
/>
<TouchableWithoutFeedback
onPress={() => {
KeyboardController.dismiss()

View File

@ -2,7 +2,7 @@ import { useTranslation } from "react-i18next"
import { Text } from "react-native"
import {
NavigationBlurEffectHeader,
NavigationBlurEffectHeaderView,
SafeNavigationScrollView,
} from "@/src/components/layouts/views/SafeNavigationScrollView"
import { PlainTextField } from "@/src/components/ui/form/TextField"
@ -21,8 +21,10 @@ export const EditRewriteRulesScreen: NavigationControllerView<{ index: number }>
const rule = useActionRule(index)
return (
<SafeNavigationScrollView className="bg-system-grouped-background">
<NavigationBlurEffectHeader title={t("actions.edit_rewrite_rule")} />
<SafeNavigationScrollView
className="bg-system-grouped-background"
Header={<NavigationBlurEffectHeaderView title={t("actions.edit_rewrite_rule")} />}
>
<GroupedInsetListSectionHeader
label={t("actions.action_card.rewrite_rules")}
marginSize="small"

View File

@ -4,7 +4,7 @@ import * as DropdownMenu from "zeego/dropdown-menu"
import { SwipeableItem } from "@/src/components/common/SwipeableItem"
import {
NavigationBlurEffectHeader,
NavigationBlurEffectHeaderView,
SafeNavigationScrollView,
} from "@/src/components/layouts/views/SafeNavigationScrollView"
import { PlainTextField } from "@/src/components/ui/form/TextField"
@ -35,10 +35,12 @@ export const EditRuleScreen: NavigationControllerView<{ index: number }> = ({ in
<SafeNavigationScrollView
className="bg-system-grouped-background"
contentContainerClassName="mt-6"
Header={
<NavigationBlurEffectHeaderView
title={`${t("actions.edit_rule")}${rule?.name ? ` - ${rule.name}` : ""}`}
/>
}
>
<NavigationBlurEffectHeader
title={`${t("actions.edit_rule")}${rule?.name ? ` - ${rule.name}` : ""}`}
/>
<RuleImpl index={index} />
</SafeNavigationScrollView>
)

View File

@ -2,7 +2,7 @@ import { useTranslation } from "react-i18next"
import { Text } from "react-native"
import {
NavigationBlurEffectHeader,
NavigationBlurEffectHeaderView,
SafeNavigationScrollView,
} from "@/src/components/layouts/views/SafeNavigationScrollView"
import { PlainTextField } from "@/src/components/ui/form/TextField"
@ -21,8 +21,10 @@ export const EditWebhooksScreen: NavigationControllerView<{ index: number }> = (
const rule = useActionRule(index)
return (
<SafeNavigationScrollView className="bg-system-grouped-background">
<NavigationBlurEffectHeader title={t("actions.edit_webhook")} />
<SafeNavigationScrollView
className="bg-system-grouped-background"
Header={<NavigationBlurEffectHeaderView title={t("actions.edit_webhook")} />}
>
<GroupedInsetListSectionHeader label={t("actions.action_card.webhooks")} marginSize="small" />
<GroupedInsetListCard>
{rule?.result.webhooks?.map((webhook, webhookIndex) => (

View File

@ -8,7 +8,7 @@ import type { MobileSupportedLanguages } from "@/src/@types/constants"
import { currentSupportedLanguages } from "@/src/@types/constants"
import { setGeneralSetting, useGeneralSettingKey } from "@/src/atoms/settings/general"
import {
NavigationBlurEffectHeader,
NavigationBlurEffectHeaderView,
SafeNavigationScrollView,
} from "@/src/components/layouts/views/SafeNavigationScrollView"
import { Select } from "@/src/components/ui/form/Select"
@ -80,11 +80,13 @@ export const GeneralScreen: NavigationControllerView = () => {
const openLinksInApp = useGeneralSettingKey("openLinksInApp")
return (
<SafeNavigationScrollView className="bg-system-grouped-background">
<NavigationBlurEffectHeader title={t("titles.general")} />
<SafeNavigationScrollView
className="bg-system-grouped-background"
Header={<NavigationBlurEffectHeaderView title={t("titles.general")} />}
>
{/* Language */}
<GroupedInsetListSectionHeader label={t("general.language")} />
<GroupedInsetListSectionHeader label={t("general.language")} marginSize="small" />
<GroupedInsetListCard>
<LanguageSelect settingKey="language" />
</GroupedInsetListCard>

View File

@ -8,7 +8,7 @@ import { Pressable, Text, View } from "react-native"
import { useServerConfigs } from "@/src/atoms/server-configs"
import { UINavigationHeaderActionButton } from "@/src/components/layouts/header/NavigationHeader"
import {
NavigationBlurEffectHeader,
NavigationBlurEffectHeaderView,
SafeNavigationScrollView,
} from "@/src/components/layouts/views/SafeNavigationScrollView"
import { UserAvatar } from "@/src/components/ui/avatar/UserAvatar"
@ -61,11 +61,15 @@ export const InvitationsScreen: NavigationControllerView = () => {
toast.success("Copied to clipboard")
}
return (
<SafeNavigationScrollView className="bg-system-grouped-background">
<NavigationBlurEffectHeader
title={t("titles.invitations")}
headerRight={<GenerateButton />}
/>
<SafeNavigationScrollView
className="bg-system-grouped-background"
Header={
<NavigationBlurEffectHeaderView
title={t("titles.invitations")}
headerRight={<GenerateButton />}
/>
}
>
<View className="mt-6">
<GroupedInsetListCard>
<GroupedInformationCell

View File

@ -8,7 +8,7 @@ import { useColor, useColors } from "react-native-uikit-colors"
import { Balance } from "@/src/components/common/Balance"
import { UINavigationHeaderActionButton } from "@/src/components/layouts/header/NavigationHeader"
import {
NavigationBlurEffectHeader,
NavigationBlurEffectHeaderView,
SafeNavigationScrollView,
} from "@/src/components/layouts/views/SafeNavigationScrollView"
import {
@ -41,17 +41,21 @@ export const ListsScreen = () => {
const lists = useOwnedLists()
return (
<SafeNavigationScrollView nestedScrollEnabled className="bg-system-grouped-background">
<NavigationBlurEffectHeader
title={t("titles.lists")}
headerRight={useCallback(
() => (
<AddListButton />
),
[],
)}
/>
<SafeNavigationScrollView
nestedScrollEnabled
className="bg-system-grouped-background"
Header={
<NavigationBlurEffectHeaderView
title={t("titles.lists")}
headerRight={useCallback(
() => (
<AddListButton />
),
[],
)}
/>
}
>
<View className="mt-6">
<GroupedInsetListCard>
<GroupedInformationCell

View File

@ -4,10 +4,11 @@ import { createContext, useContext, useEffect, useMemo, useRef, useState } from
import { useTranslation } from "react-i18next"
import { PixelRatio, StyleSheet, Text, View } from "react-native"
import { HeaderSubmitButton } from "@/src/components/layouts/header/HeaderElements"
import { UINavigationHeaderActionButton } from "@/src/components/layouts/header/NavigationHeader"
import {
NavigationBlurEffectHeader,
HeaderSubmitTextButton,
} from "@/src/components/layouts/header/HeaderElements"
import {
NavigationBlurEffectHeaderView,
SafeNavigationScrollView,
} from "@/src/components/layouts/views/SafeNavigationScrollView"
import {
@ -39,25 +40,7 @@ const ManageListContext = createContext<{
export const ManageListScreen: NavigationControllerView<{ id: string }> = ({ id }) => {
usePrefetchOwnedLists()
const list = useList(id)
return (
<SafeNavigationScrollView
className="bg-system-grouped-background"
contentContainerClassName="mt-6"
>
{!!list && <ListImpl id={list.id} />}
</SafeNavigationScrollView>
)
}
const ListImpl: React.FC<{ id: string }> = ({ id }) => {
const { t } = useTranslation("settings")
const list = useList(id)!
usePrefetchSubscription(list.view)
const subscriptionIds = useFeedSubscriptionByView(list.view)
const sortedSubscriptionIds = useSortedFeedSubscriptionByAlphabet(subscriptionIds)
const nextSelectedFeedIdRef = useRef(new Set<string>())
const ctxValue = useMemo(() => ({ nextSelectedFeedIdRef }), [nextSelectedFeedIdRef])
@ -68,8 +51,8 @@ const ListImpl: React.FC<{ id: string }> = ({ id }) => {
if (initOnceRef.current) return
initOnceRef.current = true
nextSelectedFeedIdRef.current = new Set(list.feedIds)
}, [list.feedIds])
nextSelectedFeedIdRef.current = new Set(list?.feedIds ?? [])
}, [list?.feedIds])
const addFeedsToFeedListMutation = useMutation({
mutationFn: () =>
@ -80,12 +63,14 @@ const ListImpl: React.FC<{ id: string }> = ({ id }) => {
})
const navigation = useNavigation()
return (
<ManageListContext.Provider value={ctxValue}>
<NavigationBlurEffectHeader
title={`${t("lists.manage_list")} - ${list?.title}`}
headerRight={() => (
<UINavigationHeaderActionButton>
<HeaderSubmitButton
<SafeNavigationScrollView
className="bg-system-grouped-background"
Header={
<NavigationBlurEffectHeaderView
title={`${t("lists.manage_list")} - ${list?.title}`}
headerRight={() => (
<HeaderSubmitTextButton
label={t("words.save", { ns: "common" })}
isLoading={addFeedsToFeedListMutation.isPending}
isValid
onPress={() => {
@ -100,16 +85,37 @@ const ListImpl: React.FC<{ id: string }> = ({ id }) => {
})
}}
/>
</UINavigationHeaderActionButton>
)}
/>
)}
/>
}
>
{!!list && (
<ManageListContext.Provider value={ctxValue}>
<ListImpl id={list.id} />
</ManageListContext.Provider>
)}
</SafeNavigationScrollView>
)
}
const ListImpl: React.FC<{ id: string }> = ({ id }) => {
const { t } = useTranslation("settings")
const list = useList(id)!
usePrefetchSubscription(list.view)
const subscriptionIds = useFeedSubscriptionByView(list.view)
const sortedSubscriptionIds = useSortedFeedSubscriptionByAlphabet(subscriptionIds)
return (
<>
<GroupedInsetListSectionHeader label={t("lists.select_feeds")} />
<GroupedInsetListCard SeparatorComponent={SeparatorComponent}>
{sortedSubscriptionIds.map((id) => (
<FeedCell key={id} feedId={id} isSelected={list.feedIds.includes(id)} />
))}
</GroupedInsetListCard>
</ManageListContext.Provider>
</>
)
}

View File

@ -1,7 +1,7 @@
import { useTranslation } from "react-i18next"
import {
NavigationBlurEffectHeader,
NavigationBlurEffectHeaderView,
SafeNavigationScrollView,
} from "@/src/components/layouts/views/SafeNavigationScrollView"
import {
@ -15,8 +15,10 @@ export const PrivacyScreen = () => {
const { t } = useTranslation("settings")
const { pushControllerView } = useNavigation()
return (
<SafeNavigationScrollView className="bg-system-grouped-background">
<NavigationBlurEffectHeader title={t("titles.privacy")} />
<SafeNavigationScrollView
className="bg-system-grouped-background"
Header={<NavigationBlurEffectHeaderView title={t("titles.privacy")} />}
>
<GroupedInsetListCard className="mt-4">
<GroupedInsetListNavigationLink
label={t("privacy.terms")}

View File

@ -3,7 +3,7 @@ import { useCallback, useState } from "react"
import { useColor } from "react-native-uikit-colors"
import {
NavigationBlurEffectHeader,
NavigationBlurEffectHeaderView,
SafeNavigationScrollView,
} from "@/src/components/layouts/views/SafeNavigationScrollView"
import { UIBarButton } from "@/src/components/ui/button/UIBarButton"
@ -39,33 +39,36 @@ export const ResetPassword = () => {
}, [changePasswordAsync])
return (
<SafeNavigationScrollView className="bg-system-grouped-background flex-1">
<NavigationBlurEffectHeader
title="Reset Password"
headerRight={useCallback(
() => (
<UIBarButton
label="Save"
normalIcon={
isPending ? (
<PlatformActivityIndicator size="small" color={labelColor} />
) : (
<CheckLineIcon height={18} width={18} color={labelColor} />
)
}
disabled={
!currentPassword ||
!newPassword ||
!confirmNewPassword ||
newPassword !== confirmNewPassword
}
onPress={handleSave}
/>
),
[confirmNewPassword, currentPassword, handleSave, isPending, labelColor, newPassword],
)}
/>
<SafeNavigationScrollView
className="bg-system-grouped-background flex-1"
Header={
<NavigationBlurEffectHeaderView
title="Reset Password"
headerRight={useCallback(
() => (
<UIBarButton
label="Save"
normalIcon={
isPending ? (
<PlatformActivityIndicator size="small" color={labelColor} />
) : (
<CheckLineIcon height={18} width={18} color={labelColor} />
)
}
disabled={
!currentPassword ||
!newPassword ||
!confirmNewPassword ||
newPassword !== confirmNewPassword
}
onPress={handleSave}
/>
),
[confirmNewPassword, currentPassword, handleSave, isPending, labelColor, newPassword],
)}
/>
}
>
<GroupedInsetListSectionHeader label="Current Password" />
<GroupedInsetListCard>
<GroupedInsetListBaseCell className="py-3">