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:
parent
cd024e45d3
commit
bb7fa92d45
|
|
@ -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",
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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 />
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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")}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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) => (
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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")}
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
Loading…
Reference in New Issue