Refactor notification settings as dialogs (#10646)
Co-authored-by: Samuel Newman <mozzius@protonmail.com>
This commit is contained in:
@@ -308,16 +308,6 @@ func serve(cctx *cli.Context) error {
|
|||||||
e.GET("/settings/interests", server.WebGeneric)
|
e.GET("/settings/interests", server.WebGeneric)
|
||||||
e.GET("/settings/about", server.WebGeneric)
|
e.GET("/settings/about", server.WebGeneric)
|
||||||
e.GET("/settings/notifications", server.WebGeneric)
|
e.GET("/settings/notifications", server.WebGeneric)
|
||||||
e.GET("/settings/notifications/replies", server.WebGeneric)
|
|
||||||
e.GET("/settings/notifications/mentions", server.WebGeneric)
|
|
||||||
e.GET("/settings/notifications/quotes", server.WebGeneric)
|
|
||||||
e.GET("/settings/notifications/likes", server.WebGeneric)
|
|
||||||
e.GET("/settings/notifications/reposts", server.WebGeneric)
|
|
||||||
e.GET("/settings/notifications/new-followers", server.WebGeneric)
|
|
||||||
e.GET("/settings/notifications/likes-on-reposts", server.WebGeneric)
|
|
||||||
e.GET("/settings/notifications/reposts-on-reposts", server.WebGeneric)
|
|
||||||
e.GET("/settings/notifications/activity", server.WebGeneric)
|
|
||||||
e.GET("/settings/notifications/miscellaneous", server.WebGeneric)
|
|
||||||
e.GET("/sys/debug", server.WebGeneric)
|
e.GET("/sys/debug", server.WebGeneric)
|
||||||
e.GET("/sys/debug-mod", server.WebGeneric)
|
e.GET("/sys/debug-mod", server.WebGeneric)
|
||||||
e.GET("/sys/log", server.WebGeneric)
|
e.GET("/sys/log", server.WebGeneric)
|
||||||
|
|||||||
+6
-95
@@ -114,16 +114,6 @@ import {InterestsSettingsScreen} from '#/screens/Settings/InterestsSettings'
|
|||||||
import {LanguageSettingsScreen} from '#/screens/Settings/LanguageSettings'
|
import {LanguageSettingsScreen} from '#/screens/Settings/LanguageSettings'
|
||||||
import {LegacyNotificationSettingsScreen} from '#/screens/Settings/LegacyNotificationSettings'
|
import {LegacyNotificationSettingsScreen} from '#/screens/Settings/LegacyNotificationSettings'
|
||||||
import {NotificationSettingsScreen} from '#/screens/Settings/NotificationSettings'
|
import {NotificationSettingsScreen} from '#/screens/Settings/NotificationSettings'
|
||||||
import {ActivityNotificationSettingsScreen} from '#/screens/Settings/NotificationSettings/ActivityNotificationSettings'
|
|
||||||
import {LikeNotificationSettingsScreen} from '#/screens/Settings/NotificationSettings/LikeNotificationSettings'
|
|
||||||
import {LikesOnRepostsNotificationSettingsScreen} from '#/screens/Settings/NotificationSettings/LikesOnRepostsNotificationSettings'
|
|
||||||
import {MentionNotificationSettingsScreen} from '#/screens/Settings/NotificationSettings/MentionNotificationSettings'
|
|
||||||
import {MiscellaneousNotificationSettingsScreen} from '#/screens/Settings/NotificationSettings/MiscellaneousNotificationSettings'
|
|
||||||
import {NewFollowerNotificationSettingsScreen} from '#/screens/Settings/NotificationSettings/NewFollowerNotificationSettings'
|
|
||||||
import {QuoteNotificationSettingsScreen} from '#/screens/Settings/NotificationSettings/QuoteNotificationSettings'
|
|
||||||
import {ReplyNotificationSettingsScreen} from '#/screens/Settings/NotificationSettings/ReplyNotificationSettings'
|
|
||||||
import {RepostNotificationSettingsScreen} from '#/screens/Settings/NotificationSettings/RepostNotificationSettings'
|
|
||||||
import {RepostsOnRepostsNotificationSettingsScreen} from '#/screens/Settings/NotificationSettings/RepostsOnRepostsNotificationSettings'
|
|
||||||
import {PrivacyAndSecuritySettingsScreen} from '#/screens/Settings/PrivacyAndSecuritySettings'
|
import {PrivacyAndSecuritySettingsScreen} from '#/screens/Settings/PrivacyAndSecuritySettings'
|
||||||
import {SettingsScreen} from '#/screens/Settings/Settings'
|
import {SettingsScreen} from '#/screens/Settings/Settings'
|
||||||
import {ThreadPreferencesScreen} from '#/screens/Settings/ThreadPreferences'
|
import {ThreadPreferencesScreen} from '#/screens/Settings/ThreadPreferences'
|
||||||
@@ -444,86 +434,6 @@ function commonScreens(Stack: typeof Flat, unreadCountLabel?: string) {
|
|||||||
getComponent={() => NotificationSettingsScreen}
|
getComponent={() => NotificationSettingsScreen}
|
||||||
options={{title: title(msg`Notification settings`), requireAuth: true}}
|
options={{title: title(msg`Notification settings`), requireAuth: true}}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
|
||||||
name="ReplyNotificationSettings"
|
|
||||||
getComponent={() => ReplyNotificationSettingsScreen}
|
|
||||||
options={{
|
|
||||||
title: title(msg`Reply notifications`),
|
|
||||||
requireAuth: true,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Stack.Screen
|
|
||||||
name="MentionNotificationSettings"
|
|
||||||
getComponent={() => MentionNotificationSettingsScreen}
|
|
||||||
options={{
|
|
||||||
title: title(msg`Mention notifications`),
|
|
||||||
requireAuth: true,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Stack.Screen
|
|
||||||
name="QuoteNotificationSettings"
|
|
||||||
getComponent={() => QuoteNotificationSettingsScreen}
|
|
||||||
options={{
|
|
||||||
title: title(msg`Quote notifications`),
|
|
||||||
requireAuth: true,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Stack.Screen
|
|
||||||
name="LikeNotificationSettings"
|
|
||||||
getComponent={() => LikeNotificationSettingsScreen}
|
|
||||||
options={{
|
|
||||||
title: title(msg`Like notifications`),
|
|
||||||
requireAuth: true,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Stack.Screen
|
|
||||||
name="RepostNotificationSettings"
|
|
||||||
getComponent={() => RepostNotificationSettingsScreen}
|
|
||||||
options={{
|
|
||||||
title: title(msg`Repost notifications`),
|
|
||||||
requireAuth: true,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Stack.Screen
|
|
||||||
name="NewFollowerNotificationSettings"
|
|
||||||
getComponent={() => NewFollowerNotificationSettingsScreen}
|
|
||||||
options={{
|
|
||||||
title: title(msg`New follower notifications`),
|
|
||||||
requireAuth: true,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Stack.Screen
|
|
||||||
name="LikesOnRepostsNotificationSettings"
|
|
||||||
getComponent={() => LikesOnRepostsNotificationSettingsScreen}
|
|
||||||
options={{
|
|
||||||
title: title(msg`Likes of your reposts notifications`),
|
|
||||||
requireAuth: true,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Stack.Screen
|
|
||||||
name="RepostsOnRepostsNotificationSettings"
|
|
||||||
getComponent={() => RepostsOnRepostsNotificationSettingsScreen}
|
|
||||||
options={{
|
|
||||||
title: title(msg`Reposts of your reposts notifications`),
|
|
||||||
requireAuth: true,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Stack.Screen
|
|
||||||
name="ActivityNotificationSettings"
|
|
||||||
getComponent={() => ActivityNotificationSettingsScreen}
|
|
||||||
options={{
|
|
||||||
title: title(msg`Activity notifications`),
|
|
||||||
requireAuth: true,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Stack.Screen
|
|
||||||
name="MiscellaneousNotificationSettings"
|
|
||||||
getComponent={() => MiscellaneousNotificationSettingsScreen}
|
|
||||||
options={{
|
|
||||||
title: title(msg`Miscellaneous notifications`),
|
|
||||||
requireAuth: true,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="ContentAndMediaSettings"
|
name="ContentAndMediaSettings"
|
||||||
getComponent={() => ContentAndMediaSettingsScreen}
|
getComponent={() => ContentAndMediaSettingsScreen}
|
||||||
@@ -916,6 +826,7 @@ const LINKING = {
|
|||||||
|
|
||||||
function RoutesContainer({children}: React.PropsWithChildren<{}>) {
|
function RoutesContainer({children}: React.PropsWithChildren<{}>) {
|
||||||
const ax = useAnalytics()
|
const ax = useAnalytics()
|
||||||
|
// eslint-disable-next-line react-compiler/react-compiler
|
||||||
const notyLogger = ax.logger.useChild(ax.logger.Context.Notifications)
|
const notyLogger = ax.logger.useChild(ax.logger.Context.Notifications)
|
||||||
const theme = useColorSchemeStyle(DefaultTheme, DarkTheme)
|
const theme = useColorSchemeStyle(DefaultTheme, DarkTheme)
|
||||||
const {currentAccount, accounts} = useSession()
|
const {currentAccount, accounts} = useSession()
|
||||||
@@ -943,7 +854,7 @@ function RoutesContainer({children}: React.PropsWithChildren<{}>) {
|
|||||||
|
|
||||||
const account = accounts.find(a => a.did === payload.recipientDid)
|
const account = accounts.find(a => a.did === payload.recipientDid)
|
||||||
if (account) {
|
if (account) {
|
||||||
onPressSwitchAccount(account, 'Notification')
|
void onPressSwitchAccount(account, 'Notification')
|
||||||
} else {
|
} else {
|
||||||
setShowLoggedOut(true)
|
setShowLoggedOut(true)
|
||||||
}
|
}
|
||||||
@@ -955,7 +866,7 @@ function RoutesContainer({children}: React.PropsWithChildren<{}>) {
|
|||||||
// chat-added-to-group routes to the convo because the recipient was
|
// chat-added-to-group routes to the convo because the recipient was
|
||||||
// just added and now has access.
|
// just added and now has access.
|
||||||
// @ts-expect-error nested navigators aren't typed -sfn
|
// @ts-expect-error nested navigators aren't typed -sfn
|
||||||
navigate('MessagesTab', {
|
void navigate('MessagesTab', {
|
||||||
screen: 'Messages',
|
screen: 'Messages',
|
||||||
params: {
|
params: {
|
||||||
pushToConversation: payload.convoId,
|
pushToConversation: payload.convoId,
|
||||||
@@ -1012,7 +923,7 @@ function RoutesContainer({children}: React.PropsWithChildren<{}>) {
|
|||||||
} else if (path) {
|
} else if (path) {
|
||||||
const [screen, params] = router.matchPath(path)
|
const [screen, params] = router.matchPath(path)
|
||||||
// @ts-expect-error nested navigators aren't typed -sfn
|
// @ts-expect-error nested navigators aren't typed -sfn
|
||||||
navigate('HomeTab', {screen, params})
|
void navigate('HomeTab', {screen, params})
|
||||||
notyLogger.debug(`handlePushNotificationEntry: navigate`, {
|
notyLogger.debug(`handlePushNotificationEntry: navigate`, {
|
||||||
screen,
|
screen,
|
||||||
params,
|
params,
|
||||||
@@ -1118,7 +1029,7 @@ function navigate<K extends keyof AllNavigatorParams>(
|
|||||||
}
|
}
|
||||||
navigationRef.addListener('state', handler)
|
navigationRef.addListener('state', handler)
|
||||||
|
|
||||||
// @ts-ignore I dont know what would make typescript happy but I have a life -prf
|
// @ts-ignore I don't know what would make typescript happy but I have a life -prf
|
||||||
navigationRef.navigate(name, params)
|
navigationRef.navigate(name, params)
|
||||||
}),
|
}),
|
||||||
timeout(1e3),
|
timeout(1e3),
|
||||||
@@ -1131,7 +1042,7 @@ function resetToTab(
|
|||||||
tabName: 'HomeTab' | 'SearchTab' | 'MessagesTab' | 'NotificationsTab',
|
tabName: 'HomeTab' | 'SearchTab' | 'MessagesTab' | 'NotificationsTab',
|
||||||
) {
|
) {
|
||||||
if (navigationRef.isReady()) {
|
if (navigationRef.isReady()) {
|
||||||
navigate(tabName)
|
void navigate(tabName)
|
||||||
if (navigationRef.canGoBack()) {
|
if (navigationRef.canGoBack()) {
|
||||||
navigationRef.dispatch(StackActions.popToTop()) //we need to check .canGoBack() before calling it
|
navigationRef.dispatch(StackActions.popToTop()) //we need to check .canGoBack() before calling it
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1017,7 +1017,7 @@ export type Events = {
|
|||||||
'activityPreference:changeChannels': {
|
'activityPreference:changeChannels': {
|
||||||
name: string
|
name: string
|
||||||
push: boolean
|
push: boolean
|
||||||
list: boolean
|
list?: boolean
|
||||||
}
|
}
|
||||||
'activityPreference:changeFilter': {
|
'activityPreference:changeFilter': {
|
||||||
name: string
|
name: string
|
||||||
|
|||||||
@@ -0,0 +1,105 @@
|
|||||||
|
import {View} from 'react-native'
|
||||||
|
import {type AppBskyNotificationDefs} from '@atproto/api'
|
||||||
|
import {Trans, useLingui} from '@lingui/react/macro'
|
||||||
|
|
||||||
|
import {useNotificationSettingsQuery} from '#/state/queries/notifications/settings'
|
||||||
|
import * as SettingsList from '#/screens/Settings/components/SettingsList'
|
||||||
|
import {PreferenceControls} from '#/screens/Settings/NotificationSettings/components/PreferenceControls'
|
||||||
|
import {atoms as a, useTheme, web} from '#/alf'
|
||||||
|
import {Admonition} from '#/components/Admonition'
|
||||||
|
import {Button, ButtonText} from '#/components/Button'
|
||||||
|
import * as Dialog from '#/components/Dialog'
|
||||||
|
import {type Props as SVGIconProps} from '#/components/icons/common'
|
||||||
|
import {Text} from '#/components/Typography'
|
||||||
|
import {IS_NATIVE} from '#/env'
|
||||||
|
|
||||||
|
type NotificationSettingsDialogProps = {
|
||||||
|
control: Dialog.DialogControlProps
|
||||||
|
name: Exclude<keyof AppBskyNotificationDefs.Preferences, '$type'>
|
||||||
|
syncOthers?: Exclude<keyof AppBskyNotificationDefs.Preferences, '$type'>[]
|
||||||
|
icon: React.ComponentType<SVGIconProps>
|
||||||
|
titleText: React.ReactNode
|
||||||
|
subtitleText: React.ReactNode
|
||||||
|
allowDisableInApp?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export function NotificationSettingsDialog({
|
||||||
|
control,
|
||||||
|
name,
|
||||||
|
syncOthers,
|
||||||
|
titleText,
|
||||||
|
subtitleText,
|
||||||
|
allowDisableInApp = true,
|
||||||
|
}: NotificationSettingsDialogProps) {
|
||||||
|
return (
|
||||||
|
<Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}>
|
||||||
|
<NotificationSettingsDialogInner
|
||||||
|
control={control}
|
||||||
|
name={name}
|
||||||
|
syncOthers={syncOthers}
|
||||||
|
titleText={titleText}
|
||||||
|
subtitleText={subtitleText}
|
||||||
|
allowDisableInApp={allowDisableInApp}
|
||||||
|
/>
|
||||||
|
</Dialog.Outer>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function NotificationSettingsDialogInner({
|
||||||
|
control,
|
||||||
|
name,
|
||||||
|
syncOthers,
|
||||||
|
titleText,
|
||||||
|
subtitleText,
|
||||||
|
allowDisableInApp,
|
||||||
|
}: Omit<NotificationSettingsDialogProps, 'icon'>) {
|
||||||
|
const t = useTheme()
|
||||||
|
const {t: l} = useLingui()
|
||||||
|
const {data: preferences, isError} = useNotificationSettingsQuery()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Dialog.Handle />
|
||||||
|
<Dialog.ScrollableInner
|
||||||
|
label={l`Notification settings`}
|
||||||
|
style={web({maxWidth: 400})}>
|
||||||
|
<SettingsList.Container>
|
||||||
|
<View style={[a.flex_1, a.gap_xs, a.mb_md]}>
|
||||||
|
<Text style={[a.font_semi_bold, a.text_lg]}>{titleText}</Text>
|
||||||
|
<Text
|
||||||
|
style={[a.text_sm, t.atoms.text_contrast_medium, a.leading_snug]}>
|
||||||
|
{subtitleText}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
{isError ? (
|
||||||
|
<View style={[a.mt_md]}>
|
||||||
|
<Admonition type="error">
|
||||||
|
<Trans>Failed to load notification settings.</Trans>
|
||||||
|
</Admonition>
|
||||||
|
</View>
|
||||||
|
) : (
|
||||||
|
<PreferenceControls
|
||||||
|
name={name}
|
||||||
|
syncOthers={syncOthers}
|
||||||
|
preference={preferences?.[name]}
|
||||||
|
allowDisableInApp={allowDisableInApp}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</SettingsList.Container>
|
||||||
|
<Dialog.Close />
|
||||||
|
{IS_NATIVE && (
|
||||||
|
<Button
|
||||||
|
color="secondary"
|
||||||
|
size="large"
|
||||||
|
label={l`Close dialog`}
|
||||||
|
onPress={() => control.close()}
|
||||||
|
style={[a.mt_md]}>
|
||||||
|
<ButtonText>
|
||||||
|
<Trans>Done</Trans>
|
||||||
|
</ButtonText>
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</Dialog.ScrollableInner>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -55,16 +55,6 @@ export type CommonNavigatorParams = {
|
|||||||
ActivityPrivacySettings: undefined
|
ActivityPrivacySettings: undefined
|
||||||
ContentAndMediaSettings: undefined
|
ContentAndMediaSettings: undefined
|
||||||
NotificationSettings: undefined
|
NotificationSettings: undefined
|
||||||
ReplyNotificationSettings: undefined
|
|
||||||
MentionNotificationSettings: undefined
|
|
||||||
QuoteNotificationSettings: undefined
|
|
||||||
LikeNotificationSettings: undefined
|
|
||||||
RepostNotificationSettings: undefined
|
|
||||||
NewFollowerNotificationSettings: undefined
|
|
||||||
LikesOnRepostsNotificationSettings: undefined
|
|
||||||
RepostsOnRepostsNotificationSettings: undefined
|
|
||||||
ActivityNotificationSettings: undefined
|
|
||||||
MiscellaneousNotificationSettings: undefined
|
|
||||||
InterestsSettings: undefined
|
InterestsSettings: undefined
|
||||||
AboutSettings: undefined
|
AboutSettings: undefined
|
||||||
AppIconSettings: undefined
|
AppIconSettings: undefined
|
||||||
|
|||||||
@@ -58,18 +58,6 @@ export const router = new Router<AllNavigatableRoutes>({
|
|||||||
AboutSettings: '/settings/about',
|
AboutSettings: '/settings/about',
|
||||||
AppIconSettings: '/settings/app-icon',
|
AppIconSettings: '/settings/app-icon',
|
||||||
NotificationSettings: '/settings/notifications',
|
NotificationSettings: '/settings/notifications',
|
||||||
ReplyNotificationSettings: '/settings/notifications/replies',
|
|
||||||
MentionNotificationSettings: '/settings/notifications/mentions',
|
|
||||||
QuoteNotificationSettings: '/settings/notifications/quotes',
|
|
||||||
LikeNotificationSettings: '/settings/notifications/likes',
|
|
||||||
RepostNotificationSettings: '/settings/notifications/reposts',
|
|
||||||
NewFollowerNotificationSettings: '/settings/notifications/new-followers',
|
|
||||||
LikesOnRepostsNotificationSettings:
|
|
||||||
'/settings/notifications/likes-on-reposts',
|
|
||||||
RepostsOnRepostsNotificationSettings:
|
|
||||||
'/settings/notifications/reposts-on-reposts',
|
|
||||||
ActivityNotificationSettings: '/settings/notifications/activity',
|
|
||||||
MiscellaneousNotificationSettings: '/settings/notifications/miscellaneous',
|
|
||||||
FindContactsSettings: '/settings/find-contacts',
|
FindContactsSettings: '/settings/find-contacts',
|
||||||
// support
|
// support
|
||||||
Support: '/support',
|
Support: '/support',
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ export function MessagesSettingsScreenInner({}: Props) {
|
|||||||
did: currentAccount!.did,
|
did: currentAccount!.did,
|
||||||
})
|
})
|
||||||
const {preferences, setPref} = useBackgroundNotificationPreferences()
|
const {preferences, setPref} = useBackgroundNotificationPreferences()
|
||||||
|
|
||||||
const exportCarControl = Dialog.useDialogControl()
|
const exportCarControl = Dialog.useDialogControl()
|
||||||
|
|
||||||
const isGroupChatEnabled = ax.features.enabled(ax.features.GroupChatsEnable)
|
const isGroupChatEnabled = ax.features.enabled(ax.features.GroupChatsEnable)
|
||||||
@@ -233,7 +234,7 @@ export function MessagesSettingsScreenInner({}: Props) {
|
|||||||
value={preferences.playSoundChat}
|
value={preferences.playSoundChat}
|
||||||
style={[a.flex_row, a.align_center, a.justify_between]}
|
style={[a.flex_row, a.align_center, a.justify_between]}
|
||||||
onChange={onSelectSoundSetting}>
|
onChange={onSelectSoundSetting}>
|
||||||
<BellIcon style={[a.mr_2xs, t.atoms.text]} size="md" />
|
<BellIcon style={[a.mr_2xs, t.atoms.text]} size="lg" />
|
||||||
<Text
|
<Text
|
||||||
style={[
|
style={[
|
||||||
a.flex_1,
|
a.flex_1,
|
||||||
@@ -251,19 +252,19 @@ export function MessagesSettingsScreenInner({}: Props) {
|
|||||||
)}
|
)}
|
||||||
<View style={[a.px_xl]}>
|
<View style={[a.px_xl]}>
|
||||||
<Toggle.Item
|
<Toggle.Item
|
||||||
label={l`Export chat data`}
|
label={l`Export my chat data`}
|
||||||
name="playSoundChat"
|
name="playSoundChat"
|
||||||
value={preferences.playSoundChat}
|
value={preferences.playSoundChat}
|
||||||
style={[a.flex_row, a.align_center, a.justify_between]}
|
style={[a.flex_row, a.align_center, a.justify_between]}
|
||||||
onChange={() => {
|
onChange={() => {
|
||||||
exportCarControl.open()
|
exportCarControl.open()
|
||||||
}}>
|
}}>
|
||||||
<CarIcon style={[a.mr_2xs, t.atoms.text]} size="md" />
|
<CarIcon style={[a.mr_2xs, t.atoms.text]} size="lg" />
|
||||||
<Text
|
<Text
|
||||||
style={[a.flex_1, a.text_md, a.font_semi_bold, t.atoms.text]}>
|
style={[a.flex_1, a.text_md, a.font_semi_bold, t.atoms.text]}>
|
||||||
<Trans>Export chat data</Trans>
|
<Trans>Export my chat data</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
<ChevronRightIcon style={[a.ml_2xs, t.atoms.text]} size="md" />
|
<ChevronRightIcon style={[a.ml_2xs, t.atoms.text]} size="lg" />
|
||||||
</Toggle.Item>
|
</Toggle.Item>
|
||||||
</View>
|
</View>
|
||||||
<Divider style={{marginVertical: 10}} />
|
<Divider style={{marginVertical: 10}} />
|
||||||
|
|||||||
@@ -1,269 +0,0 @@
|
|||||||
import {useCallback, useMemo} from 'react'
|
|
||||||
import {type ListRenderItemInfo, Text as RNText, View} from 'react-native'
|
|
||||||
import {type ModerationOpts} from '@atproto/api'
|
|
||||||
import {msg} from '@lingui/core/macro'
|
|
||||||
import {useLingui} from '@lingui/react'
|
|
||||||
import {Trans} from '@lingui/react/macro'
|
|
||||||
|
|
||||||
import {createSanitizedDisplayName} from '#/lib/moderation/create-sanitized-display-name'
|
|
||||||
import {
|
|
||||||
type AllNavigatorParams,
|
|
||||||
type NativeStackScreenProps,
|
|
||||||
} from '#/lib/routes/types'
|
|
||||||
import {cleanError} from '#/lib/strings/errors'
|
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {useProfileShadow} from '#/state/cache/profile-shadow'
|
|
||||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
|
||||||
import {useActivitySubscriptionsQuery} from '#/state/queries/activity-subscriptions'
|
|
||||||
import {useNotificationSettingsQuery} from '#/state/queries/notifications/settings'
|
|
||||||
import {List} from '#/view/com/util/List'
|
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
|
||||||
import {SubscribeProfileDialog} from '#/components/activity-notifications/SubscribeProfileDialog'
|
|
||||||
import * as Admonition from '#/components/Admonition'
|
|
||||||
import {Button, ButtonText} from '#/components/Button'
|
|
||||||
import {useDialogControl} from '#/components/Dialog'
|
|
||||||
import {
|
|
||||||
BellRinging_Filled_Corner0_Rounded as BellRingingFilledIcon,
|
|
||||||
BellRinging_Stroke2_Corner0_Rounded as BellRingingIcon,
|
|
||||||
} from '#/components/icons/BellRinging'
|
|
||||||
import * as Layout from '#/components/Layout'
|
|
||||||
import {InlineLinkText} from '#/components/Link'
|
|
||||||
import {ListFooter} from '#/components/Lists'
|
|
||||||
import {Loader} from '#/components/Loader'
|
|
||||||
import * as ProfileCard from '#/components/ProfileCard'
|
|
||||||
import {Text} from '#/components/Typography'
|
|
||||||
import type * as bsky from '#/types/bsky'
|
|
||||||
import * as SettingsList from '../components/SettingsList'
|
|
||||||
import {ItemTextWithSubtitle} from './components/ItemTextWithSubtitle'
|
|
||||||
import {PreferenceControls} from './components/PreferenceControls'
|
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<
|
|
||||||
AllNavigatorParams,
|
|
||||||
'ActivityNotificationSettings'
|
|
||||||
>
|
|
||||||
export function ActivityNotificationSettingsScreen({}: Props) {
|
|
||||||
const t = useTheme()
|
|
||||||
const {_} = useLingui()
|
|
||||||
const {data: preferences, isError} = useNotificationSettingsQuery()
|
|
||||||
|
|
||||||
const moderationOpts = useModerationOpts()
|
|
||||||
|
|
||||||
const {
|
|
||||||
data: subscriptions,
|
|
||||||
isPending,
|
|
||||||
error,
|
|
||||||
isFetchingNextPage,
|
|
||||||
fetchNextPage,
|
|
||||||
hasNextPage,
|
|
||||||
} = useActivitySubscriptionsQuery()
|
|
||||||
|
|
||||||
const items = useMemo(() => {
|
|
||||||
if (!subscriptions) return []
|
|
||||||
return subscriptions?.pages.flatMap(page => page.subscriptions)
|
|
||||||
}, [subscriptions])
|
|
||||||
|
|
||||||
const renderItem = useCallback(
|
|
||||||
({item}: ListRenderItemInfo<bsky.profile.AnyProfileView>) => {
|
|
||||||
if (!moderationOpts) return null
|
|
||||||
return (
|
|
||||||
<ActivitySubscriptionCard
|
|
||||||
profile={item}
|
|
||||||
moderationOpts={moderationOpts}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
[moderationOpts],
|
|
||||||
)
|
|
||||||
|
|
||||||
const onEndReached = useCallback(async () => {
|
|
||||||
if (isFetchingNextPage || !hasNextPage || isError) return
|
|
||||||
try {
|
|
||||||
await fetchNextPage()
|
|
||||||
} catch (err) {
|
|
||||||
logger.error('Failed to load more likes', {message: err})
|
|
||||||
}
|
|
||||||
}, [isFetchingNextPage, hasNextPage, isError, fetchNextPage])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Layout.Screen>
|
|
||||||
<Layout.Header.Outer>
|
|
||||||
<Layout.Header.BackButton />
|
|
||||||
<Layout.Header.Content>
|
|
||||||
<Layout.Header.TitleText>
|
|
||||||
<Trans>Notifications</Trans>
|
|
||||||
</Layout.Header.TitleText>
|
|
||||||
</Layout.Header.Content>
|
|
||||||
<Layout.Header.Slot />
|
|
||||||
</Layout.Header.Outer>
|
|
||||||
<List
|
|
||||||
ListHeaderComponent={
|
|
||||||
<SettingsList.Container>
|
|
||||||
<SettingsList.Item style={[a.align_start]}>
|
|
||||||
<SettingsList.ItemIcon icon={BellRingingIcon} />
|
|
||||||
<ItemTextWithSubtitle
|
|
||||||
bold
|
|
||||||
titleText={<Trans>Activity from others</Trans>}
|
|
||||||
subtitleText={
|
|
||||||
<Trans>
|
|
||||||
Get notified about posts and replies from accounts you
|
|
||||||
choose.
|
|
||||||
</Trans>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</SettingsList.Item>
|
|
||||||
{isError ? (
|
|
||||||
<View style={[a.px_lg, a.pt_md]}>
|
|
||||||
<Admonition.Admonition type="error">
|
|
||||||
<Trans>Failed to load notification settings.</Trans>
|
|
||||||
</Admonition.Admonition>
|
|
||||||
</View>
|
|
||||||
) : (
|
|
||||||
<PreferenceControls
|
|
||||||
name="subscribedPost"
|
|
||||||
preference={preferences?.subscribedPost}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</SettingsList.Container>
|
|
||||||
}
|
|
||||||
data={items}
|
|
||||||
keyExtractor={keyExtractor}
|
|
||||||
renderItem={renderItem}
|
|
||||||
onEndReached={onEndReached}
|
|
||||||
onEndReachedThreshold={4}
|
|
||||||
ListEmptyComponent={
|
|
||||||
error ? null : (
|
|
||||||
<View style={[a.px_xl, a.py_md]}>
|
|
||||||
{!isPending ? (
|
|
||||||
<Admonition.Outer type="tip">
|
|
||||||
<Admonition.Row>
|
|
||||||
<Admonition.Icon />
|
|
||||||
<Admonition.Content>
|
|
||||||
<Admonition.Text>
|
|
||||||
<Trans>
|
|
||||||
Enable notifications for an account by visiting their
|
|
||||||
profile and pressing the{' '}
|
|
||||||
<RNText
|
|
||||||
style={[
|
|
||||||
a.font_semi_bold,
|
|
||||||
t.atoms.text_contrast_high,
|
|
||||||
]}>
|
|
||||||
bell icon
|
|
||||||
</RNText>{' '}
|
|
||||||
<BellRingingFilledIcon
|
|
||||||
size="xs"
|
|
||||||
style={t.atoms.text_contrast_high}
|
|
||||||
/>
|
|
||||||
.
|
|
||||||
</Trans>
|
|
||||||
</Admonition.Text>
|
|
||||||
<Admonition.Text>
|
|
||||||
<Trans>
|
|
||||||
If you want to restrict who can receive notifications
|
|
||||||
for your account's activity, you can change this in{' '}
|
|
||||||
<InlineLinkText
|
|
||||||
label={_(msg`Privacy and Security settings`)}
|
|
||||||
to={{screen: 'ActivityPrivacySettings'}}
|
|
||||||
style={[a.font_semi_bold]}>
|
|
||||||
Settings → Privacy and Security
|
|
||||||
</InlineLinkText>
|
|
||||||
.
|
|
||||||
</Trans>
|
|
||||||
</Admonition.Text>
|
|
||||||
</Admonition.Content>
|
|
||||||
</Admonition.Row>
|
|
||||||
</Admonition.Outer>
|
|
||||||
) : (
|
|
||||||
<View style={[a.flex_1, a.align_center, a.pt_xl]}>
|
|
||||||
<Loader size="lg" />
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
ListFooterComponent={
|
|
||||||
<ListFooter
|
|
||||||
style={[items.length === 0 && a.border_transparent]}
|
|
||||||
isFetchingNextPage={isFetchingNextPage}
|
|
||||||
error={cleanError(error)}
|
|
||||||
onRetry={fetchNextPage}
|
|
||||||
hasNextPage={hasNextPage}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
windowSize={11}
|
|
||||||
/>
|
|
||||||
</Layout.Screen>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function keyExtractor(item: bsky.profile.AnyProfileView) {
|
|
||||||
return item.did
|
|
||||||
}
|
|
||||||
|
|
||||||
function ActivitySubscriptionCard({
|
|
||||||
profile: profileUnshadowed,
|
|
||||||
moderationOpts,
|
|
||||||
}: {
|
|
||||||
profile: bsky.profile.AnyProfileView
|
|
||||||
moderationOpts: ModerationOpts
|
|
||||||
}) {
|
|
||||||
const profile = useProfileShadow(profileUnshadowed)
|
|
||||||
const control = useDialogControl()
|
|
||||||
const {_} = useLingui()
|
|
||||||
const t = useTheme()
|
|
||||||
|
|
||||||
const preview = useMemo(() => {
|
|
||||||
const actSub = profile.viewer?.activitySubscription
|
|
||||||
if (actSub?.post && actSub?.reply) {
|
|
||||||
return _(msg`Posts, Replies`)
|
|
||||||
} else if (actSub?.post) {
|
|
||||||
return _(msg`Posts`)
|
|
||||||
} else if (actSub?.reply) {
|
|
||||||
return _(msg`Replies`)
|
|
||||||
}
|
|
||||||
return _(msg`None`)
|
|
||||||
}, [_, profile.viewer?.activitySubscription])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={[a.py_md, a.px_xl, a.border_t, t.atoms.border_contrast_low]}>
|
|
||||||
<ProfileCard.Outer>
|
|
||||||
<ProfileCard.Header>
|
|
||||||
<ProfileCard.Avatar
|
|
||||||
profile={profile}
|
|
||||||
moderationOpts={moderationOpts}
|
|
||||||
/>
|
|
||||||
<View style={[a.flex_1, a.gap_2xs]}>
|
|
||||||
<ProfileCard.NameAndHandle
|
|
||||||
profile={profile}
|
|
||||||
moderationOpts={moderationOpts}
|
|
||||||
inline
|
|
||||||
/>
|
|
||||||
<Text style={[a.leading_snug, t.atoms.text_contrast_medium]}>
|
|
||||||
{preview}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
<Button
|
|
||||||
label={_(
|
|
||||||
msg`Edit notifications from ${createSanitizedDisplayName(
|
|
||||||
profile,
|
|
||||||
)}`,
|
|
||||||
)}
|
|
||||||
size="small"
|
|
||||||
color="primary"
|
|
||||||
variant="solid"
|
|
||||||
onPress={control.open}>
|
|
||||||
<ButtonText>
|
|
||||||
<Trans>Edit</Trans>
|
|
||||||
</ButtonText>
|
|
||||||
</Button>
|
|
||||||
</ProfileCard.Header>
|
|
||||||
</ProfileCard.Outer>
|
|
||||||
|
|
||||||
<SubscribeProfileDialog
|
|
||||||
control={control}
|
|
||||||
profile={profile}
|
|
||||||
moderationOpts={moderationOpts}
|
|
||||||
includeProfile
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
import {View} from 'react-native'
|
|
||||||
import {Trans} from '@lingui/react/macro'
|
|
||||||
|
|
||||||
import {
|
|
||||||
type AllNavigatorParams,
|
|
||||||
type NativeStackScreenProps,
|
|
||||||
} from '#/lib/routes/types'
|
|
||||||
import {useNotificationSettingsQuery} from '#/state/queries/notifications/settings'
|
|
||||||
import {atoms as a} from '#/alf'
|
|
||||||
import {Admonition} from '#/components/Admonition'
|
|
||||||
import {Heart2_Stroke2_Corner0_Rounded as HeartIcon} from '#/components/icons/Heart2'
|
|
||||||
import * as Layout from '#/components/Layout'
|
|
||||||
import * as SettingsList from '../components/SettingsList'
|
|
||||||
import {ItemTextWithSubtitle} from './components/ItemTextWithSubtitle'
|
|
||||||
import {PreferenceControls} from './components/PreferenceControls'
|
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<
|
|
||||||
AllNavigatorParams,
|
|
||||||
'LikeNotificationSettings'
|
|
||||||
>
|
|
||||||
export function LikeNotificationSettingsScreen({}: Props) {
|
|
||||||
const {data: preferences, isError} = useNotificationSettingsQuery()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Layout.Screen>
|
|
||||||
<Layout.Header.Outer>
|
|
||||||
<Layout.Header.BackButton />
|
|
||||||
<Layout.Header.Content>
|
|
||||||
<Layout.Header.TitleText>
|
|
||||||
<Trans>Notifications</Trans>
|
|
||||||
</Layout.Header.TitleText>
|
|
||||||
</Layout.Header.Content>
|
|
||||||
<Layout.Header.Slot />
|
|
||||||
</Layout.Header.Outer>
|
|
||||||
<Layout.Content>
|
|
||||||
<SettingsList.Container>
|
|
||||||
<SettingsList.Item style={[a.align_start]}>
|
|
||||||
<SettingsList.ItemIcon icon={HeartIcon} />
|
|
||||||
<ItemTextWithSubtitle
|
|
||||||
bold
|
|
||||||
titleText={<Trans>Likes</Trans>}
|
|
||||||
subtitleText={
|
|
||||||
<Trans>Get notifications when people like your posts.</Trans>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</SettingsList.Item>
|
|
||||||
{isError ? (
|
|
||||||
<View style={[a.px_lg, a.pt_md]}>
|
|
||||||
<Admonition type="error">
|
|
||||||
<Trans>Failed to load notification settings.</Trans>
|
|
||||||
</Admonition>
|
|
||||||
</View>
|
|
||||||
) : (
|
|
||||||
<PreferenceControls name="like" preference={preferences?.like} />
|
|
||||||
)}
|
|
||||||
</SettingsList.Container>
|
|
||||||
</Layout.Content>
|
|
||||||
</Layout.Screen>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
import {View} from 'react-native'
|
|
||||||
import {Trans} from '@lingui/react/macro'
|
|
||||||
|
|
||||||
import {
|
|
||||||
type AllNavigatorParams,
|
|
||||||
type NativeStackScreenProps,
|
|
||||||
} from '#/lib/routes/types'
|
|
||||||
import {useNotificationSettingsQuery} from '#/state/queries/notifications/settings'
|
|
||||||
import {atoms as a} from '#/alf'
|
|
||||||
import {Admonition} from '#/components/Admonition'
|
|
||||||
import {LikeRepost_Stroke2_Corner2_Rounded as LikeRepostIcon} from '#/components/icons/Heart2'
|
|
||||||
import * as Layout from '#/components/Layout'
|
|
||||||
import * as SettingsList from '../components/SettingsList'
|
|
||||||
import {ItemTextWithSubtitle} from './components/ItemTextWithSubtitle'
|
|
||||||
import {PreferenceControls} from './components/PreferenceControls'
|
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<
|
|
||||||
AllNavigatorParams,
|
|
||||||
'LikesOnRepostsNotificationSettings'
|
|
||||||
>
|
|
||||||
export function LikesOnRepostsNotificationSettingsScreen({}: Props) {
|
|
||||||
const {data: preferences, isError} = useNotificationSettingsQuery()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Layout.Screen>
|
|
||||||
<Layout.Header.Outer>
|
|
||||||
<Layout.Header.BackButton />
|
|
||||||
<Layout.Header.Content>
|
|
||||||
<Layout.Header.TitleText>
|
|
||||||
<Trans>Notifications</Trans>
|
|
||||||
</Layout.Header.TitleText>
|
|
||||||
</Layout.Header.Content>
|
|
||||||
<Layout.Header.Slot />
|
|
||||||
</Layout.Header.Outer>
|
|
||||||
<Layout.Content>
|
|
||||||
<SettingsList.Container>
|
|
||||||
<SettingsList.Item style={[a.align_start]}>
|
|
||||||
<SettingsList.ItemIcon icon={LikeRepostIcon} />
|
|
||||||
<ItemTextWithSubtitle
|
|
||||||
bold
|
|
||||||
titleText={<Trans>Likes of your reposts</Trans>}
|
|
||||||
subtitleText={
|
|
||||||
<Trans>
|
|
||||||
Get notifications when people like posts that you've reposted.
|
|
||||||
</Trans>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</SettingsList.Item>
|
|
||||||
{isError ? (
|
|
||||||
<View style={[a.px_lg, a.pt_md]}>
|
|
||||||
<Admonition type="error">
|
|
||||||
<Trans>Failed to load notification settings.</Trans>
|
|
||||||
</Admonition>
|
|
||||||
</View>
|
|
||||||
) : (
|
|
||||||
<PreferenceControls
|
|
||||||
name="likeViaRepost"
|
|
||||||
preference={preferences?.likeViaRepost}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</SettingsList.Container>
|
|
||||||
</Layout.Content>
|
|
||||||
</Layout.Screen>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
import {View} from 'react-native'
|
|
||||||
import {Trans} from '@lingui/react/macro'
|
|
||||||
|
|
||||||
import {
|
|
||||||
type AllNavigatorParams,
|
|
||||||
type NativeStackScreenProps,
|
|
||||||
} from '#/lib/routes/types'
|
|
||||||
import {useNotificationSettingsQuery} from '#/state/queries/notifications/settings'
|
|
||||||
import {atoms as a} from '#/alf'
|
|
||||||
import {Admonition} from '#/components/Admonition'
|
|
||||||
import {At_Stroke2_Corner2_Rounded as AtIcon} from '#/components/icons/At'
|
|
||||||
import * as Layout from '#/components/Layout'
|
|
||||||
import * as SettingsList from '../components/SettingsList'
|
|
||||||
import {ItemTextWithSubtitle} from './components/ItemTextWithSubtitle'
|
|
||||||
import {PreferenceControls} from './components/PreferenceControls'
|
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<
|
|
||||||
AllNavigatorParams,
|
|
||||||
'MentionNotificationSettings'
|
|
||||||
>
|
|
||||||
export function MentionNotificationSettingsScreen({}: Props) {
|
|
||||||
const {data: preferences, isError} = useNotificationSettingsQuery()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Layout.Screen>
|
|
||||||
<Layout.Header.Outer>
|
|
||||||
<Layout.Header.BackButton />
|
|
||||||
<Layout.Header.Content>
|
|
||||||
<Layout.Header.TitleText>
|
|
||||||
<Trans>Notifications</Trans>
|
|
||||||
</Layout.Header.TitleText>
|
|
||||||
</Layout.Header.Content>
|
|
||||||
<Layout.Header.Slot />
|
|
||||||
</Layout.Header.Outer>
|
|
||||||
<Layout.Content>
|
|
||||||
<SettingsList.Container>
|
|
||||||
<SettingsList.Item style={[a.align_start]}>
|
|
||||||
<SettingsList.ItemIcon icon={AtIcon} />
|
|
||||||
<ItemTextWithSubtitle
|
|
||||||
bold
|
|
||||||
titleText={<Trans>Mentions</Trans>}
|
|
||||||
subtitleText={
|
|
||||||
<Trans>Get notifications when people mention you.</Trans>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</SettingsList.Item>
|
|
||||||
{isError ? (
|
|
||||||
<View style={[a.px_lg, a.pt_md]}>
|
|
||||||
<Admonition type="error">
|
|
||||||
<Trans>Failed to load notification settings.</Trans>
|
|
||||||
</Admonition>
|
|
||||||
</View>
|
|
||||||
) : (
|
|
||||||
<PreferenceControls
|
|
||||||
name="mention"
|
|
||||||
preference={preferences?.mention}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</SettingsList.Container>
|
|
||||||
</Layout.Content>
|
|
||||||
</Layout.Screen>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
import {View} from 'react-native'
|
|
||||||
import {Trans} from '@lingui/react/macro'
|
|
||||||
|
|
||||||
import {
|
|
||||||
type AllNavigatorParams,
|
|
||||||
type NativeStackScreenProps,
|
|
||||||
} from '#/lib/routes/types'
|
|
||||||
import {useNotificationSettingsQuery} from '#/state/queries/notifications/settings'
|
|
||||||
import {atoms as a} from '#/alf'
|
|
||||||
import {Admonition} from '#/components/Admonition'
|
|
||||||
import {Shapes_Stroke2_Corner0_Rounded as ShapesIcon} from '#/components/icons/Shapes'
|
|
||||||
import * as Layout from '#/components/Layout'
|
|
||||||
import * as SettingsList from '../components/SettingsList'
|
|
||||||
import {ItemTextWithSubtitle} from './components/ItemTextWithSubtitle'
|
|
||||||
import {PreferenceControls} from './components/PreferenceControls'
|
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<
|
|
||||||
AllNavigatorParams,
|
|
||||||
'MiscellaneousNotificationSettings'
|
|
||||||
>
|
|
||||||
export function MiscellaneousNotificationSettingsScreen({}: Props) {
|
|
||||||
const {data: preferences, isError} = useNotificationSettingsQuery()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Layout.Screen>
|
|
||||||
<Layout.Header.Outer>
|
|
||||||
<Layout.Header.BackButton />
|
|
||||||
<Layout.Header.Content>
|
|
||||||
<Layout.Header.TitleText>
|
|
||||||
<Trans>Notifications</Trans>
|
|
||||||
</Layout.Header.TitleText>
|
|
||||||
</Layout.Header.Content>
|
|
||||||
<Layout.Header.Slot />
|
|
||||||
</Layout.Header.Outer>
|
|
||||||
<Layout.Content>
|
|
||||||
<SettingsList.Container>
|
|
||||||
<SettingsList.Item style={[a.align_start]}>
|
|
||||||
<SettingsList.ItemIcon icon={ShapesIcon} />
|
|
||||||
<ItemTextWithSubtitle
|
|
||||||
bold
|
|
||||||
titleText={<Trans>Everything else</Trans>}
|
|
||||||
subtitleText={
|
|
||||||
<Trans>
|
|
||||||
Notifications for everything else, such as when someone joins
|
|
||||||
via one of your starter packs.
|
|
||||||
</Trans>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</SettingsList.Item>
|
|
||||||
{isError ? (
|
|
||||||
<View style={[a.px_lg, a.pt_md]}>
|
|
||||||
<Admonition type="error">
|
|
||||||
<Trans>Failed to load notification settings.</Trans>
|
|
||||||
</Admonition>
|
|
||||||
</View>
|
|
||||||
) : (
|
|
||||||
<PreferenceControls
|
|
||||||
name="starterpackJoined"
|
|
||||||
preference={preferences?.starterpackJoined}
|
|
||||||
syncOthers={['verified', 'unverified']}
|
|
||||||
allowDisableInApp={false}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</SettingsList.Container>
|
|
||||||
</Layout.Content>
|
|
||||||
</Layout.Screen>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
import {View} from 'react-native'
|
|
||||||
import {Trans} from '@lingui/react/macro'
|
|
||||||
|
|
||||||
import {
|
|
||||||
type AllNavigatorParams,
|
|
||||||
type NativeStackScreenProps,
|
|
||||||
} from '#/lib/routes/types'
|
|
||||||
import {useNotificationSettingsQuery} from '#/state/queries/notifications/settings'
|
|
||||||
import {atoms as a} from '#/alf'
|
|
||||||
import {Admonition} from '#/components/Admonition'
|
|
||||||
import {PersonPlus_Stroke2_Corner2_Rounded as PersonPlusIcon} from '#/components/icons/Person'
|
|
||||||
import * as Layout from '#/components/Layout'
|
|
||||||
import * as SettingsList from '../components/SettingsList'
|
|
||||||
import {ItemTextWithSubtitle} from './components/ItemTextWithSubtitle'
|
|
||||||
import {PreferenceControls} from './components/PreferenceControls'
|
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<
|
|
||||||
AllNavigatorParams,
|
|
||||||
'NewFollowerNotificationSettings'
|
|
||||||
>
|
|
||||||
export function NewFollowerNotificationSettingsScreen({}: Props) {
|
|
||||||
const {data: preferences, isError} = useNotificationSettingsQuery()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Layout.Screen>
|
|
||||||
<Layout.Header.Outer>
|
|
||||||
<Layout.Header.BackButton />
|
|
||||||
<Layout.Header.Content>
|
|
||||||
<Layout.Header.TitleText>
|
|
||||||
<Trans>Notifications</Trans>
|
|
||||||
</Layout.Header.TitleText>
|
|
||||||
</Layout.Header.Content>
|
|
||||||
<Layout.Header.Slot />
|
|
||||||
</Layout.Header.Outer>
|
|
||||||
<Layout.Content>
|
|
||||||
<SettingsList.Container>
|
|
||||||
<SettingsList.Item style={[a.align_start]}>
|
|
||||||
<SettingsList.ItemIcon icon={PersonPlusIcon} />
|
|
||||||
<ItemTextWithSubtitle
|
|
||||||
bold
|
|
||||||
titleText={<Trans>New followers</Trans>}
|
|
||||||
subtitleText={
|
|
||||||
<Trans>Get notifications when people follow you.</Trans>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</SettingsList.Item>
|
|
||||||
{isError ? (
|
|
||||||
<View style={[a.px_lg, a.pt_md]}>
|
|
||||||
<Admonition type="error">
|
|
||||||
<Trans>Failed to load notification settings.</Trans>
|
|
||||||
</Admonition>
|
|
||||||
</View>
|
|
||||||
) : (
|
|
||||||
<PreferenceControls
|
|
||||||
name="follow"
|
|
||||||
preference={preferences?.follow}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</SettingsList.Container>
|
|
||||||
</Layout.Content>
|
|
||||||
</Layout.Screen>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
import {View} from 'react-native'
|
|
||||||
import {Trans} from '@lingui/react/macro'
|
|
||||||
|
|
||||||
import {
|
|
||||||
type AllNavigatorParams,
|
|
||||||
type NativeStackScreenProps,
|
|
||||||
} from '#/lib/routes/types'
|
|
||||||
import {useNotificationSettingsQuery} from '#/state/queries/notifications/settings'
|
|
||||||
import {atoms as a} from '#/alf'
|
|
||||||
import {Admonition} from '#/components/Admonition'
|
|
||||||
import {CloseQuote_Stroke2_Corner0_Rounded as CloseQuoteIcon} from '#/components/icons/Quote'
|
|
||||||
import * as Layout from '#/components/Layout'
|
|
||||||
import * as SettingsList from '../components/SettingsList'
|
|
||||||
import {ItemTextWithSubtitle} from './components/ItemTextWithSubtitle'
|
|
||||||
import {PreferenceControls} from './components/PreferenceControls'
|
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<
|
|
||||||
AllNavigatorParams,
|
|
||||||
'QuoteNotificationSettings'
|
|
||||||
>
|
|
||||||
export function QuoteNotificationSettingsScreen({}: Props) {
|
|
||||||
const {data: preferences, isError} = useNotificationSettingsQuery()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Layout.Screen>
|
|
||||||
<Layout.Header.Outer>
|
|
||||||
<Layout.Header.BackButton />
|
|
||||||
<Layout.Header.Content>
|
|
||||||
<Layout.Header.TitleText>
|
|
||||||
<Trans>Notifications</Trans>
|
|
||||||
</Layout.Header.TitleText>
|
|
||||||
</Layout.Header.Content>
|
|
||||||
<Layout.Header.Slot />
|
|
||||||
</Layout.Header.Outer>
|
|
||||||
<Layout.Content>
|
|
||||||
<SettingsList.Container>
|
|
||||||
<SettingsList.Item style={[a.align_start]}>
|
|
||||||
<SettingsList.ItemIcon icon={CloseQuoteIcon} />
|
|
||||||
<ItemTextWithSubtitle
|
|
||||||
bold
|
|
||||||
titleText={<Trans>Quotes</Trans>}
|
|
||||||
subtitleText={
|
|
||||||
<Trans>Get notifications when people quote your posts.</Trans>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</SettingsList.Item>
|
|
||||||
{isError ? (
|
|
||||||
<View style={[a.px_lg, a.pt_md]}>
|
|
||||||
<Admonition type="error">
|
|
||||||
<Trans>Failed to load notification settings.</Trans>
|
|
||||||
</Admonition>
|
|
||||||
</View>
|
|
||||||
) : (
|
|
||||||
<PreferenceControls name="quote" preference={preferences?.quote} />
|
|
||||||
)}
|
|
||||||
</SettingsList.Container>
|
|
||||||
</Layout.Content>
|
|
||||||
</Layout.Screen>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
import {View} from 'react-native'
|
|
||||||
import {Trans} from '@lingui/react/macro'
|
|
||||||
|
|
||||||
import {
|
|
||||||
type AllNavigatorParams,
|
|
||||||
type NativeStackScreenProps,
|
|
||||||
} from '#/lib/routes/types'
|
|
||||||
import {useNotificationSettingsQuery} from '#/state/queries/notifications/settings'
|
|
||||||
import {atoms as a} from '#/alf'
|
|
||||||
import {Admonition} from '#/components/Admonition'
|
|
||||||
import {Bubble_Stroke2_Corner2_Rounded as BubbleIcon} from '#/components/icons/Bubble'
|
|
||||||
import * as Layout from '#/components/Layout'
|
|
||||||
import * as SettingsList from '../components/SettingsList'
|
|
||||||
import {ItemTextWithSubtitle} from './components/ItemTextWithSubtitle'
|
|
||||||
import {PreferenceControls} from './components/PreferenceControls'
|
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<
|
|
||||||
AllNavigatorParams,
|
|
||||||
'ReplyNotificationSettings'
|
|
||||||
>
|
|
||||||
export function ReplyNotificationSettingsScreen({}: Props) {
|
|
||||||
const {data: preferences, isError} = useNotificationSettingsQuery()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Layout.Screen>
|
|
||||||
<Layout.Header.Outer>
|
|
||||||
<Layout.Header.BackButton />
|
|
||||||
<Layout.Header.Content>
|
|
||||||
<Layout.Header.TitleText>
|
|
||||||
<Trans>Notifications</Trans>
|
|
||||||
</Layout.Header.TitleText>
|
|
||||||
</Layout.Header.Content>
|
|
||||||
<Layout.Header.Slot />
|
|
||||||
</Layout.Header.Outer>
|
|
||||||
<Layout.Content>
|
|
||||||
<SettingsList.Container>
|
|
||||||
<SettingsList.Item style={[a.align_start]}>
|
|
||||||
<SettingsList.ItemIcon icon={BubbleIcon} />
|
|
||||||
<ItemTextWithSubtitle
|
|
||||||
bold
|
|
||||||
titleText={<Trans>Replies</Trans>}
|
|
||||||
subtitleText={
|
|
||||||
<Trans>
|
|
||||||
Get notifications when people reply to your posts.
|
|
||||||
</Trans>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</SettingsList.Item>
|
|
||||||
{isError ? (
|
|
||||||
<View style={[a.px_lg, a.pt_md]}>
|
|
||||||
<Admonition type="error">
|
|
||||||
<Trans>Failed to load notification settings.</Trans>
|
|
||||||
</Admonition>
|
|
||||||
</View>
|
|
||||||
) : (
|
|
||||||
<PreferenceControls name="reply" preference={preferences?.reply} />
|
|
||||||
)}
|
|
||||||
</SettingsList.Container>
|
|
||||||
</Layout.Content>
|
|
||||||
</Layout.Screen>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
import {View} from 'react-native'
|
|
||||||
import {Trans} from '@lingui/react/macro'
|
|
||||||
|
|
||||||
import {
|
|
||||||
type AllNavigatorParams,
|
|
||||||
type NativeStackScreenProps,
|
|
||||||
} from '#/lib/routes/types'
|
|
||||||
import {useNotificationSettingsQuery} from '#/state/queries/notifications/settings'
|
|
||||||
import {atoms as a} from '#/alf'
|
|
||||||
import {Admonition} from '#/components/Admonition'
|
|
||||||
import {Repost_Stroke2_Corner2_Rounded as RepostIcon} from '#/components/icons/Repost'
|
|
||||||
import * as Layout from '#/components/Layout'
|
|
||||||
import * as SettingsList from '../components/SettingsList'
|
|
||||||
import {ItemTextWithSubtitle} from './components/ItemTextWithSubtitle'
|
|
||||||
import {PreferenceControls} from './components/PreferenceControls'
|
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<
|
|
||||||
AllNavigatorParams,
|
|
||||||
'RepostNotificationSettings'
|
|
||||||
>
|
|
||||||
export function RepostNotificationSettingsScreen({}: Props) {
|
|
||||||
const {data: preferences, isError} = useNotificationSettingsQuery()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Layout.Screen>
|
|
||||||
<Layout.Header.Outer>
|
|
||||||
<Layout.Header.BackButton />
|
|
||||||
<Layout.Header.Content>
|
|
||||||
<Layout.Header.TitleText>
|
|
||||||
<Trans>Notifications</Trans>
|
|
||||||
</Layout.Header.TitleText>
|
|
||||||
</Layout.Header.Content>
|
|
||||||
<Layout.Header.Slot />
|
|
||||||
</Layout.Header.Outer>
|
|
||||||
<Layout.Content>
|
|
||||||
<SettingsList.Container>
|
|
||||||
<SettingsList.Item style={[a.align_start]}>
|
|
||||||
<SettingsList.ItemIcon icon={RepostIcon} />
|
|
||||||
<ItemTextWithSubtitle
|
|
||||||
bold
|
|
||||||
titleText={<Trans>Reposts</Trans>}
|
|
||||||
subtitleText={
|
|
||||||
<Trans>Get notifications when people repost your posts.</Trans>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</SettingsList.Item>
|
|
||||||
{isError ? (
|
|
||||||
<View style={[a.px_lg, a.pt_md]}>
|
|
||||||
<Admonition type="error">
|
|
||||||
<Trans>Failed to load notification settings.</Trans>
|
|
||||||
</Admonition>
|
|
||||||
</View>
|
|
||||||
) : (
|
|
||||||
<PreferenceControls
|
|
||||||
name="repost"
|
|
||||||
preference={preferences?.repost}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</SettingsList.Container>
|
|
||||||
</Layout.Content>
|
|
||||||
</Layout.Screen>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
import {View} from 'react-native'
|
|
||||||
import {Trans} from '@lingui/react/macro'
|
|
||||||
|
|
||||||
import {
|
|
||||||
type AllNavigatorParams,
|
|
||||||
type NativeStackScreenProps,
|
|
||||||
} from '#/lib/routes/types'
|
|
||||||
import {useNotificationSettingsQuery} from '#/state/queries/notifications/settings'
|
|
||||||
import {atoms as a} from '#/alf'
|
|
||||||
import {Admonition} from '#/components/Admonition'
|
|
||||||
import {RepostRepost_Stroke2_Corner2_Rounded as RepostRepostIcon} from '#/components/icons/Repost'
|
|
||||||
import * as Layout from '#/components/Layout'
|
|
||||||
import * as SettingsList from '../components/SettingsList'
|
|
||||||
import {ItemTextWithSubtitle} from './components/ItemTextWithSubtitle'
|
|
||||||
import {PreferenceControls} from './components/PreferenceControls'
|
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<
|
|
||||||
AllNavigatorParams,
|
|
||||||
'RepostsOnRepostsNotificationSettings'
|
|
||||||
>
|
|
||||||
export function RepostsOnRepostsNotificationSettingsScreen({}: Props) {
|
|
||||||
const {data: preferences, isError} = useNotificationSettingsQuery()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Layout.Screen>
|
|
||||||
<Layout.Header.Outer>
|
|
||||||
<Layout.Header.BackButton />
|
|
||||||
<Layout.Header.Content>
|
|
||||||
<Layout.Header.TitleText>
|
|
||||||
<Trans>Notifications</Trans>
|
|
||||||
</Layout.Header.TitleText>
|
|
||||||
</Layout.Header.Content>
|
|
||||||
<Layout.Header.Slot />
|
|
||||||
</Layout.Header.Outer>
|
|
||||||
<Layout.Content>
|
|
||||||
<SettingsList.Container>
|
|
||||||
<SettingsList.Item style={[a.align_start]}>
|
|
||||||
<SettingsList.ItemIcon icon={RepostRepostIcon} />
|
|
||||||
<ItemTextWithSubtitle
|
|
||||||
bold
|
|
||||||
titleText={<Trans>Reposts of your reposts</Trans>}
|
|
||||||
subtitleText={
|
|
||||||
<Trans>
|
|
||||||
Get notifications when people repost posts that you've
|
|
||||||
reposted.
|
|
||||||
</Trans>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</SettingsList.Item>
|
|
||||||
{isError ? (
|
|
||||||
<View style={[a.px_lg, a.pt_md]}>
|
|
||||||
<Admonition type="error">
|
|
||||||
<Trans>Failed to load notification settings.</Trans>
|
|
||||||
</Admonition>
|
|
||||||
</View>
|
|
||||||
) : (
|
|
||||||
<PreferenceControls
|
|
||||||
name="repostViaRepost"
|
|
||||||
preference={preferences?.repostViaRepost}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</SettingsList.Container>
|
|
||||||
</Layout.Content>
|
|
||||||
</Layout.Screen>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,7 @@
|
|||||||
import {useMemo} from 'react'
|
import {useMemo} from 'react'
|
||||||
import {View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
import {type AppBskyNotificationDefs} from '@atproto/api'
|
import {type AppBskyNotificationDefs} from '@atproto/api'
|
||||||
import {msg} from '@lingui/core/macro'
|
import {Trans, useLingui} from '@lingui/react/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
|
||||||
import {Trans} from '@lingui/react/macro'
|
|
||||||
|
|
||||||
import {useNotificationSettingsUpdateMutation} from '#/state/queries/notifications/settings'
|
import {useNotificationSettingsUpdateMutation} from '#/state/queries/notifications/settings'
|
||||||
import {atoms as a, platform, useTheme} from '#/alf'
|
import {atoms as a, platform, useTheme} from '#/alf'
|
||||||
@@ -28,6 +26,7 @@ export function PreferenceControls({
|
|||||||
preference?:
|
preference?:
|
||||||
| AppBskyNotificationDefs.Preference
|
| AppBskyNotificationDefs.Preference
|
||||||
| AppBskyNotificationDefs.FilterablePreference
|
| AppBskyNotificationDefs.FilterablePreference
|
||||||
|
| AppBskyNotificationDefs.ChatPreference
|
||||||
allowDisableInApp?: boolean
|
allowDisableInApp?: boolean
|
||||||
}) {
|
}) {
|
||||||
if (!preference)
|
if (!preference)
|
||||||
@@ -58,16 +57,17 @@ export function Inner({
|
|||||||
preference:
|
preference:
|
||||||
| AppBskyNotificationDefs.Preference
|
| AppBskyNotificationDefs.Preference
|
||||||
| AppBskyNotificationDefs.FilterablePreference
|
| AppBskyNotificationDefs.FilterablePreference
|
||||||
|
| AppBskyNotificationDefs.ChatPreference
|
||||||
allowDisableInApp: boolean
|
allowDisableInApp: boolean
|
||||||
}) {
|
}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {_} = useLingui()
|
const {t: l} = useLingui()
|
||||||
const ax = useAnalytics()
|
const ax = useAnalytics()
|
||||||
const {mutate} = useNotificationSettingsUpdateMutation()
|
const {mutate} = useNotificationSettingsUpdateMutation()
|
||||||
|
|
||||||
const channels = useMemo(() => {
|
const channels = useMemo(() => {
|
||||||
const arr = []
|
const arr = []
|
||||||
if (preference.list) arr.push('list')
|
if ('list' in preference && preference.list) arr.push('list')
|
||||||
if (preference.push) arr.push('push')
|
if (preference.push) arr.push('push')
|
||||||
return arr
|
return arr
|
||||||
}, [preference])
|
}, [preference])
|
||||||
@@ -75,15 +75,18 @@ export function Inner({
|
|||||||
const onChangeChannels = (change: string[]) => {
|
const onChangeChannels = (change: string[]) => {
|
||||||
const newPreference = {
|
const newPreference = {
|
||||||
...preference,
|
...preference,
|
||||||
list: change.includes('list'),
|
...('list' in preference ? {list: change.includes('list')} : {}),
|
||||||
push: change.includes('push'),
|
push: change.includes('push'),
|
||||||
} satisfies typeof preference
|
} as typeof preference
|
||||||
|
|
||||||
ax.metric('activityPreference:changeChannels', {
|
const metrics: {name: string; push: boolean; list?: boolean} = {
|
||||||
name,
|
name,
|
||||||
push: newPreference.push,
|
push: newPreference.push,
|
||||||
list: newPreference.list,
|
}
|
||||||
})
|
if ('list' in newPreference) {
|
||||||
|
metrics.list = newPreference.list
|
||||||
|
}
|
||||||
|
ax.metric('activityPreference:changeChannels', metrics)
|
||||||
|
|
||||||
mutate({
|
mutate({
|
||||||
[name]: newPreference,
|
[name]: newPreference,
|
||||||
@@ -92,7 +95,7 @@ export function Inner({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const onChangeFilter = ([change]: string[]) => {
|
const onChangeFilter = ([change]: string[]) => {
|
||||||
if (change !== 'all' && change !== 'follows')
|
if (change !== 'all' && change !== 'follows' && change !== 'accepted')
|
||||||
throw new Error('Invalid filter')
|
throw new Error('Invalid filter')
|
||||||
|
|
||||||
const newPreference = {
|
const newPreference = {
|
||||||
@@ -109,15 +112,15 @@ export function Inner({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={[a.px_xl, a.pt_md, a.gap_sm]}>
|
<View style={[a.gap_sm]}>
|
||||||
<Toggle.Group
|
<Toggle.Group
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
label={_(msg`Select your preferred notification channels`)}
|
label={l`Select your preferred notification channels`}
|
||||||
values={channels}
|
values={channels}
|
||||||
onChange={onChangeChannels}>
|
onChange={onChangeChannels}>
|
||||||
<View style={[a.gap_sm]}>
|
<View style={[a.gap_sm]}>
|
||||||
<Toggle.Item
|
<Toggle.Item
|
||||||
label={_(msg`Receive push notifications`)}
|
label={l`Receive push notifications`}
|
||||||
name="push"
|
name="push"
|
||||||
style={[
|
style={[
|
||||||
a.py_xs,
|
a.py_xs,
|
||||||
@@ -134,7 +137,7 @@ export function Inner({
|
|||||||
</Toggle.Item>
|
</Toggle.Item>
|
||||||
{allowDisableInApp && (
|
{allowDisableInApp && (
|
||||||
<Toggle.Item
|
<Toggle.Item
|
||||||
label={_(msg`Receive in-app notifications`)}
|
label={l`Receive in-app notifications`}
|
||||||
name="list"
|
name="list"
|
||||||
style={[
|
style={[
|
||||||
a.py_xs,
|
a.py_xs,
|
||||||
@@ -160,39 +163,44 @@ export function Inner({
|
|||||||
</Text>
|
</Text>
|
||||||
<Toggle.Group
|
<Toggle.Group
|
||||||
type="radio"
|
type="radio"
|
||||||
label={_(msg`Filter who you receive notifications from`)}
|
label={l`Filter who you receive notifications from`}
|
||||||
values={[preference.include]}
|
values={[preference.include]}
|
||||||
onChange={onChangeFilter}
|
onChange={onChangeFilter}
|
||||||
disabled={channels.length === 0}>
|
disabled={channels.length === 0}>
|
||||||
<View style={[a.gap_sm]}>
|
<View style={[a.gap_sm]}>
|
||||||
<Toggle.Item
|
<Toggle.Item highlightRow label={l`Everyone`} name="all">
|
||||||
label={_(msg`Everyone`)}
|
{({selected}) => (
|
||||||
name="all"
|
<Toggle.RadioWithLabel
|
||||||
style={[a.flex_row, a.py_xs, a.gap_sm]}>
|
label={l`Everyone`}
|
||||||
<Toggle.Radio />
|
selected={selected}
|
||||||
<Toggle.LabelText
|
/>
|
||||||
style={[
|
)}
|
||||||
channels.length > 0 && t.atoms.text,
|
|
||||||
a.font_normal,
|
|
||||||
a.text_md,
|
|
||||||
]}>
|
|
||||||
<Trans>Everyone</Trans>
|
|
||||||
</Toggle.LabelText>
|
|
||||||
</Toggle.Item>
|
|
||||||
<Toggle.Item
|
|
||||||
label={_(msg`People I follow`)}
|
|
||||||
name="follows"
|
|
||||||
style={[a.flex_row, a.py_xs, a.gap_sm]}>
|
|
||||||
<Toggle.Radio />
|
|
||||||
<Toggle.LabelText
|
|
||||||
style={[
|
|
||||||
channels.length > 0 && t.atoms.text,
|
|
||||||
a.font_normal,
|
|
||||||
a.text_md,
|
|
||||||
]}>
|
|
||||||
<Trans>People I follow</Trans>
|
|
||||||
</Toggle.LabelText>
|
|
||||||
</Toggle.Item>
|
</Toggle.Item>
|
||||||
|
{name === 'chat' ? (
|
||||||
|
<Toggle.Item
|
||||||
|
highlightRow
|
||||||
|
label={l`Accepted conversations`}
|
||||||
|
name="accepted">
|
||||||
|
{({selected}) => (
|
||||||
|
<Toggle.RadioWithLabel
|
||||||
|
label={l`Accepted conversations`}
|
||||||
|
selected={selected}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Toggle.Item>
|
||||||
|
) : (
|
||||||
|
<Toggle.Item
|
||||||
|
highlightRow
|
||||||
|
label={l`People I follow`}
|
||||||
|
name="follows">
|
||||||
|
{({selected}) => (
|
||||||
|
<Toggle.RadioWithLabel
|
||||||
|
label={l`People I follow`}
|
||||||
|
selected={selected}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Toggle.Item>
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
</Toggle.Group>
|
</Toggle.Group>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -2,9 +2,7 @@ import {useEffect} from 'react'
|
|||||||
import {Linking, View} from 'react-native'
|
import {Linking, View} from 'react-native'
|
||||||
import * as Notification from 'expo-notifications'
|
import * as Notification from 'expo-notifications'
|
||||||
import {type AppBskyNotificationDefs} from '@atproto/api'
|
import {type AppBskyNotificationDefs} from '@atproto/api'
|
||||||
import {msg} from '@lingui/core/macro'
|
import {Trans, useLingui} from '@lingui/react/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
|
||||||
import {Trans} from '@lingui/react/macro'
|
|
||||||
import {useQuery, useQueryClient} from '@tanstack/react-query'
|
import {useQuery, useQueryClient} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {useAppState} from '#/lib/appState'
|
import {useAppState} from '#/lib/appState'
|
||||||
@@ -15,6 +13,8 @@ import {
|
|||||||
import {useNotificationSettingsQuery} from '#/state/queries/notifications/settings'
|
import {useNotificationSettingsQuery} from '#/state/queries/notifications/settings'
|
||||||
import {atoms as a} from '#/alf'
|
import {atoms as a} from '#/alf'
|
||||||
import {Admonition} from '#/components/Admonition'
|
import {Admonition} from '#/components/Admonition'
|
||||||
|
import * as Dialog from '#/components/Dialog'
|
||||||
|
import {NotificationSettingsDialog} from '#/components/dialogs/NotificationSettingsDialog'
|
||||||
import {At_Stroke2_Corner2_Rounded as AtIcon} from '#/components/icons/At'
|
import {At_Stroke2_Corner2_Rounded as AtIcon} from '#/components/icons/At'
|
||||||
import {BellRinging_Stroke2_Corner0_Rounded as BellRingingIcon} from '#/components/icons/BellRinging'
|
import {BellRinging_Stroke2_Corner0_Rounded as BellRingingIcon} from '#/components/icons/BellRinging'
|
||||||
import {Bubble_Stroke2_Corner2_Rounded as BubbleIcon} from '#/components/icons/Bubble'
|
import {Bubble_Stroke2_Corner2_Rounded as BubbleIcon} from '#/components/icons/Bubble'
|
||||||
@@ -39,10 +39,21 @@ const RQKEY = ['notification-permissions']
|
|||||||
|
|
||||||
type Props = NativeStackScreenProps<AllNavigatorParams, 'NotificationSettings'>
|
type Props = NativeStackScreenProps<AllNavigatorParams, 'NotificationSettings'>
|
||||||
export function NotificationSettingsScreen({}: Props) {
|
export function NotificationSettingsScreen({}: Props) {
|
||||||
const {_} = useLingui()
|
const {t: l} = useLingui()
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const {data: settings, isError} = useNotificationSettingsQuery()
|
const {data: settings, isError} = useNotificationSettingsQuery()
|
||||||
|
|
||||||
|
const likeDialogControl = Dialog.useDialogControl()
|
||||||
|
const followDialogControl = Dialog.useDialogControl()
|
||||||
|
const replyDialogControl = Dialog.useDialogControl()
|
||||||
|
const mentionDialogControl = Dialog.useDialogControl()
|
||||||
|
const quoteDialogControl = Dialog.useDialogControl()
|
||||||
|
const repostDialogControl = Dialog.useDialogControl()
|
||||||
|
const activityDialogControl = Dialog.useDialogControl()
|
||||||
|
const likeRepostDialogControl = Dialog.useDialogControl()
|
||||||
|
const repostRepostDialogControl = Dialog.useDialogControl()
|
||||||
|
const miscDialogControl = Dialog.useDialogControl()
|
||||||
|
|
||||||
const {data: permissions, refetch} = useQuery({
|
const {data: permissions, refetch} = useQuery({
|
||||||
queryKey: RQKEY,
|
queryKey: RQKEY,
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
@@ -54,7 +65,7 @@ export function NotificationSettingsScreen({}: Props) {
|
|||||||
const appState = useAppState()
|
const appState = useAppState()
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (appState === 'active') {
|
if (appState === 'active') {
|
||||||
refetch()
|
void refetch()
|
||||||
}
|
}
|
||||||
}, [appState, refetch])
|
}, [appState, refetch])
|
||||||
|
|
||||||
@@ -76,10 +87,10 @@ export function NotificationSettingsScreen({}: Props) {
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
} catch {
|
} catch {
|
||||||
Linking.openSettings()
|
void Linking.openSettings()
|
||||||
}
|
}
|
||||||
} else if (IS_IOS) {
|
} else if (IS_IOS) {
|
||||||
Linking.openSettings()
|
void Linking.openSettings()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -100,8 +111,8 @@ export function NotificationSettingsScreen({}: Props) {
|
|||||||
{permissions && !permissions.granted && (
|
{permissions && !permissions.granted && (
|
||||||
<>
|
<>
|
||||||
<SettingsList.PressableItem
|
<SettingsList.PressableItem
|
||||||
label={_(msg`Enable push notifications`)}
|
label={l`Enable push notifications`}
|
||||||
onPress={onRequestPermissions}>
|
onPress={() => void onRequestPermissions()}>
|
||||||
<SettingsList.ItemIcon icon={HapticIcon} />
|
<SettingsList.ItemIcon icon={HapticIcon} />
|
||||||
<SettingsList.ItemText>
|
<SettingsList.ItemText>
|
||||||
<Trans>Enable push notifications</Trans>
|
<Trans>Enable push notifications</Trans>
|
||||||
@@ -118,9 +129,9 @@ export function NotificationSettingsScreen({}: Props) {
|
|||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
<View style={[a.gap_sm]}>
|
<View style={[a.gap_sm]}>
|
||||||
<SettingsList.LinkItem
|
<SettingsList.PressableItem
|
||||||
label={_(msg`Settings for like notifications`)}
|
label={l`Settings for like notifications`}
|
||||||
to={{screen: 'LikeNotificationSettings'}}
|
onPress={likeDialogControl.open}
|
||||||
contentContainerStyle={[a.align_start]}>
|
contentContainerStyle={[a.align_start]}>
|
||||||
<SettingsList.ItemIcon icon={HeartIcon} />
|
<SettingsList.ItemIcon icon={HeartIcon} />
|
||||||
<ItemTextWithSubtitle
|
<ItemTextWithSubtitle
|
||||||
@@ -128,10 +139,10 @@ export function NotificationSettingsScreen({}: Props) {
|
|||||||
subtitleText={<SettingPreview preference={settings?.like} />}
|
subtitleText={<SettingPreview preference={settings?.like} />}
|
||||||
showSkeleton={!settings}
|
showSkeleton={!settings}
|
||||||
/>
|
/>
|
||||||
</SettingsList.LinkItem>
|
</SettingsList.PressableItem>
|
||||||
<SettingsList.LinkItem
|
<SettingsList.PressableItem
|
||||||
label={_(msg`Settings for new follower notifications`)}
|
label={l`Settings for new follower notifications`}
|
||||||
to={{screen: 'NewFollowerNotificationSettings'}}
|
onPress={followDialogControl.open}
|
||||||
contentContainerStyle={[a.align_start]}>
|
contentContainerStyle={[a.align_start]}>
|
||||||
<SettingsList.ItemIcon icon={PersonPlusIcon} />
|
<SettingsList.ItemIcon icon={PersonPlusIcon} />
|
||||||
<ItemTextWithSubtitle
|
<ItemTextWithSubtitle
|
||||||
@@ -139,10 +150,10 @@ export function NotificationSettingsScreen({}: Props) {
|
|||||||
subtitleText={<SettingPreview preference={settings?.follow} />}
|
subtitleText={<SettingPreview preference={settings?.follow} />}
|
||||||
showSkeleton={!settings}
|
showSkeleton={!settings}
|
||||||
/>
|
/>
|
||||||
</SettingsList.LinkItem>
|
</SettingsList.PressableItem>
|
||||||
<SettingsList.LinkItem
|
<SettingsList.PressableItem
|
||||||
label={_(msg`Settings for reply notifications`)}
|
label={l`Settings for reply notifications`}
|
||||||
to={{screen: 'ReplyNotificationSettings'}}
|
onPress={replyDialogControl.open}
|
||||||
contentContainerStyle={[a.align_start]}>
|
contentContainerStyle={[a.align_start]}>
|
||||||
<SettingsList.ItemIcon icon={BubbleIcon} />
|
<SettingsList.ItemIcon icon={BubbleIcon} />
|
||||||
<ItemTextWithSubtitle
|
<ItemTextWithSubtitle
|
||||||
@@ -150,10 +161,10 @@ export function NotificationSettingsScreen({}: Props) {
|
|||||||
subtitleText={<SettingPreview preference={settings?.reply} />}
|
subtitleText={<SettingPreview preference={settings?.reply} />}
|
||||||
showSkeleton={!settings}
|
showSkeleton={!settings}
|
||||||
/>
|
/>
|
||||||
</SettingsList.LinkItem>
|
</SettingsList.PressableItem>
|
||||||
<SettingsList.LinkItem
|
<SettingsList.PressableItem
|
||||||
label={_(msg`Settings for mention notifications`)}
|
label={l`Settings for mention notifications`}
|
||||||
to={{screen: 'MentionNotificationSettings'}}
|
onPress={mentionDialogControl.open}
|
||||||
contentContainerStyle={[a.align_start]}>
|
contentContainerStyle={[a.align_start]}>
|
||||||
<SettingsList.ItemIcon icon={AtIcon} />
|
<SettingsList.ItemIcon icon={AtIcon} />
|
||||||
<ItemTextWithSubtitle
|
<ItemTextWithSubtitle
|
||||||
@@ -161,10 +172,10 @@ export function NotificationSettingsScreen({}: Props) {
|
|||||||
subtitleText={<SettingPreview preference={settings?.mention} />}
|
subtitleText={<SettingPreview preference={settings?.mention} />}
|
||||||
showSkeleton={!settings}
|
showSkeleton={!settings}
|
||||||
/>
|
/>
|
||||||
</SettingsList.LinkItem>
|
</SettingsList.PressableItem>
|
||||||
<SettingsList.LinkItem
|
<SettingsList.PressableItem
|
||||||
label={_(msg`Settings for quote notifications`)}
|
label={l`Settings for quote notifications`}
|
||||||
to={{screen: 'QuoteNotificationSettings'}}
|
onPress={quoteDialogControl.open}
|
||||||
contentContainerStyle={[a.align_start]}>
|
contentContainerStyle={[a.align_start]}>
|
||||||
<SettingsList.ItemIcon icon={CloseQuoteIcon} />
|
<SettingsList.ItemIcon icon={CloseQuoteIcon} />
|
||||||
<ItemTextWithSubtitle
|
<ItemTextWithSubtitle
|
||||||
@@ -172,10 +183,10 @@ export function NotificationSettingsScreen({}: Props) {
|
|||||||
subtitleText={<SettingPreview preference={settings?.quote} />}
|
subtitleText={<SettingPreview preference={settings?.quote} />}
|
||||||
showSkeleton={!settings}
|
showSkeleton={!settings}
|
||||||
/>
|
/>
|
||||||
</SettingsList.LinkItem>
|
</SettingsList.PressableItem>
|
||||||
<SettingsList.LinkItem
|
<SettingsList.PressableItem
|
||||||
label={_(msg`Settings for repost notifications`)}
|
label={l`Settings for repost notifications`}
|
||||||
to={{screen: 'RepostNotificationSettings'}}
|
onPress={repostDialogControl.open}
|
||||||
contentContainerStyle={[a.align_start]}>
|
contentContainerStyle={[a.align_start]}>
|
||||||
<SettingsList.ItemIcon icon={RepostIcon} />
|
<SettingsList.ItemIcon icon={RepostIcon} />
|
||||||
<ItemTextWithSubtitle
|
<ItemTextWithSubtitle
|
||||||
@@ -183,10 +194,10 @@ export function NotificationSettingsScreen({}: Props) {
|
|||||||
subtitleText={<SettingPreview preference={settings?.repost} />}
|
subtitleText={<SettingPreview preference={settings?.repost} />}
|
||||||
showSkeleton={!settings}
|
showSkeleton={!settings}
|
||||||
/>
|
/>
|
||||||
</SettingsList.LinkItem>
|
</SettingsList.PressableItem>
|
||||||
<SettingsList.LinkItem
|
<SettingsList.PressableItem
|
||||||
label={_(msg`Settings for activity from others`)}
|
label={l`Settings for activity from others`}
|
||||||
to={{screen: 'ActivityNotificationSettings'}}
|
onPress={activityDialogControl.open}
|
||||||
contentContainerStyle={[a.align_start]}>
|
contentContainerStyle={[a.align_start]}>
|
||||||
<SettingsList.ItemIcon icon={BellRingingIcon} />
|
<SettingsList.ItemIcon icon={BellRingingIcon} />
|
||||||
<ItemTextWithSubtitle
|
<ItemTextWithSubtitle
|
||||||
@@ -196,12 +207,10 @@ export function NotificationSettingsScreen({}: Props) {
|
|||||||
}
|
}
|
||||||
showSkeleton={!settings}
|
showSkeleton={!settings}
|
||||||
/>
|
/>
|
||||||
</SettingsList.LinkItem>
|
</SettingsList.PressableItem>
|
||||||
<SettingsList.LinkItem
|
<SettingsList.PressableItem
|
||||||
label={_(
|
label={l`Settings for notifications for likes of your reposts`}
|
||||||
msg`Settings for notifications for likes of your reposts`,
|
onPress={likeRepostDialogControl.open}
|
||||||
)}
|
|
||||||
to={{screen: 'LikesOnRepostsNotificationSettings'}}
|
|
||||||
contentContainerStyle={[a.align_start]}>
|
contentContainerStyle={[a.align_start]}>
|
||||||
<SettingsList.ItemIcon icon={LikeRepostIcon} />
|
<SettingsList.ItemIcon icon={LikeRepostIcon} />
|
||||||
<ItemTextWithSubtitle
|
<ItemTextWithSubtitle
|
||||||
@@ -211,12 +220,10 @@ export function NotificationSettingsScreen({}: Props) {
|
|||||||
}
|
}
|
||||||
showSkeleton={!settings}
|
showSkeleton={!settings}
|
||||||
/>
|
/>
|
||||||
</SettingsList.LinkItem>
|
</SettingsList.PressableItem>
|
||||||
<SettingsList.LinkItem
|
<SettingsList.PressableItem
|
||||||
label={_(
|
label={l`Settings for notifications for reposts of your reposts`}
|
||||||
msg`Settings for notifications for reposts of your reposts`,
|
onPress={repostRepostDialogControl.open}
|
||||||
)}
|
|
||||||
to={{screen: 'RepostsOnRepostsNotificationSettings'}}
|
|
||||||
contentContainerStyle={[a.align_start]}>
|
contentContainerStyle={[a.align_start]}>
|
||||||
<SettingsList.ItemIcon icon={RepostRepostIcon} />
|
<SettingsList.ItemIcon icon={RepostRepostIcon} />
|
||||||
<ItemTextWithSubtitle
|
<ItemTextWithSubtitle
|
||||||
@@ -226,10 +233,10 @@ export function NotificationSettingsScreen({}: Props) {
|
|||||||
}
|
}
|
||||||
showSkeleton={!settings}
|
showSkeleton={!settings}
|
||||||
/>
|
/>
|
||||||
</SettingsList.LinkItem>
|
</SettingsList.PressableItem>
|
||||||
<SettingsList.LinkItem
|
<SettingsList.PressableItem
|
||||||
label={_(msg`Settings for notifications for everything else`)}
|
label={l`Settings for notifications for everything else`}
|
||||||
to={{screen: 'MiscellaneousNotificationSettings'}}
|
onPress={miscDialogControl.open}
|
||||||
contentContainerStyle={[a.align_start]}>
|
contentContainerStyle={[a.align_start]}>
|
||||||
<SettingsList.ItemIcon icon={ShapesIcon} />
|
<SettingsList.ItemIcon icon={ShapesIcon} />
|
||||||
<ItemTextWithSubtitle
|
<ItemTextWithSubtitle
|
||||||
@@ -241,10 +248,105 @@ export function NotificationSettingsScreen({}: Props) {
|
|||||||
}
|
}
|
||||||
showSkeleton={!settings}
|
showSkeleton={!settings}
|
||||||
/>
|
/>
|
||||||
</SettingsList.LinkItem>
|
</SettingsList.PressableItem>
|
||||||
</View>
|
</View>
|
||||||
</SettingsList.Container>
|
</SettingsList.Container>
|
||||||
</Layout.Content>
|
</Layout.Content>
|
||||||
|
<NotificationSettingsDialog
|
||||||
|
control={likeDialogControl}
|
||||||
|
name="like"
|
||||||
|
icon={HeartIcon}
|
||||||
|
titleText={<Trans>Likes</Trans>}
|
||||||
|
subtitleText={
|
||||||
|
<Trans>Get notifications when people like your posts.</Trans>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<NotificationSettingsDialog
|
||||||
|
control={followDialogControl}
|
||||||
|
name="follow"
|
||||||
|
icon={PersonPlusIcon}
|
||||||
|
titleText={<Trans>New followers</Trans>}
|
||||||
|
subtitleText={<Trans>Get notifications when people follow you.</Trans>}
|
||||||
|
/>
|
||||||
|
<NotificationSettingsDialog
|
||||||
|
control={replyDialogControl}
|
||||||
|
name="reply"
|
||||||
|
icon={BubbleIcon}
|
||||||
|
titleText={<Trans>Replies</Trans>}
|
||||||
|
subtitleText={
|
||||||
|
<Trans>Get notifications when people reply to your posts.</Trans>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<NotificationSettingsDialog
|
||||||
|
control={mentionDialogControl}
|
||||||
|
name="mention"
|
||||||
|
icon={AtIcon}
|
||||||
|
titleText={<Trans>Mentions</Trans>}
|
||||||
|
subtitleText={<Trans>Get notifications when people mention you.</Trans>}
|
||||||
|
/>
|
||||||
|
<NotificationSettingsDialog
|
||||||
|
control={quoteDialogControl}
|
||||||
|
name="quote"
|
||||||
|
icon={CloseQuoteIcon}
|
||||||
|
titleText={<Trans>Quotes</Trans>}
|
||||||
|
subtitleText={
|
||||||
|
<Trans>Get notifications when people quote your posts.</Trans>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<NotificationSettingsDialog
|
||||||
|
control={repostDialogControl}
|
||||||
|
name="repost"
|
||||||
|
icon={RepostIcon}
|
||||||
|
titleText={<Trans>Reposts</Trans>}
|
||||||
|
subtitleText={
|
||||||
|
<Trans>Get notifications when people repost your posts.</Trans>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<NotificationSettingsDialog
|
||||||
|
control={activityDialogControl}
|
||||||
|
name="subscribedPost"
|
||||||
|
icon={BellRingingIcon}
|
||||||
|
titleText={<Trans>Activity from others</Trans>}
|
||||||
|
subtitleText={
|
||||||
|
<Trans>
|
||||||
|
Get notifications when there's activity on posts you're subscribed
|
||||||
|
to.
|
||||||
|
</Trans>
|
||||||
|
}
|
||||||
|
allowDisableInApp={false}
|
||||||
|
/>
|
||||||
|
<NotificationSettingsDialog
|
||||||
|
control={likeRepostDialogControl}
|
||||||
|
name="likeViaRepost"
|
||||||
|
icon={LikeRepostIcon}
|
||||||
|
titleText={<Trans>Likes of your reposts</Trans>}
|
||||||
|
subtitleText={
|
||||||
|
<Trans>Get notifications when people like your reposts.</Trans>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<NotificationSettingsDialog
|
||||||
|
control={repostRepostDialogControl}
|
||||||
|
name="repostViaRepost"
|
||||||
|
icon={RepostRepostIcon}
|
||||||
|
titleText={<Trans>Reposts of your reposts</Trans>}
|
||||||
|
subtitleText={
|
||||||
|
<Trans>Get notifications when people repost your reposts.</Trans>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<NotificationSettingsDialog
|
||||||
|
control={miscDialogControl}
|
||||||
|
name="starterpackJoined"
|
||||||
|
syncOthers={['verified', 'unverified']}
|
||||||
|
icon={ShapesIcon}
|
||||||
|
titleText={<Trans>Everything else</Trans>}
|
||||||
|
subtitleText={
|
||||||
|
<Trans>
|
||||||
|
Get notifications for starter pack joins, verification, and other
|
||||||
|
activity.
|
||||||
|
</Trans>
|
||||||
|
}
|
||||||
|
allowDisableInApp={false}
|
||||||
|
/>
|
||||||
</Layout.Screen>
|
</Layout.Screen>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -256,38 +358,38 @@ function SettingPreview({
|
|||||||
| AppBskyNotificationDefs.Preference
|
| AppBskyNotificationDefs.Preference
|
||||||
| AppBskyNotificationDefs.FilterablePreference
|
| AppBskyNotificationDefs.FilterablePreference
|
||||||
}) {
|
}) {
|
||||||
const {_} = useLingui()
|
const {t: l} = useLingui()
|
||||||
if (!preference) {
|
if (!preference) {
|
||||||
return null
|
return null
|
||||||
} else {
|
} else {
|
||||||
if ('include' in preference) {
|
if ('include' in preference) {
|
||||||
if (preference.include === 'all') {
|
if (preference.include === 'all') {
|
||||||
if (preference.list && preference.push) {
|
if (preference.list && preference.push) {
|
||||||
return _(msg`In-app, Push, Everyone`)
|
return l`In-app, push, everyone`
|
||||||
} else if (preference.list) {
|
} else if (preference.list) {
|
||||||
return _(msg`In-app, Everyone`)
|
return l`In-app, everyone`
|
||||||
} else if (preference.push) {
|
} else if (preference.push) {
|
||||||
return _(msg`Push, Everyone`)
|
return l`Push, everyone`
|
||||||
}
|
}
|
||||||
} else if (preference.include === 'follows') {
|
} else if (preference.include === 'follows') {
|
||||||
if (preference.list && preference.push) {
|
if (preference.list && preference.push) {
|
||||||
return _(msg`In-app, Push, People you follow`)
|
return l`In-app, push, people you follow`
|
||||||
} else if (preference.list) {
|
} else if (preference.list) {
|
||||||
return _(msg`In-app, People you follow`)
|
return l`In-app, people you follow`
|
||||||
} else if (preference.push) {
|
} else if (preference.push) {
|
||||||
return _(msg`Push, People you follow`)
|
return l`Push, people you follow`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (preference.list && preference.push) {
|
if (preference.list && preference.push) {
|
||||||
return _(msg`In-app, Push`)
|
return l`In-app, push`
|
||||||
} else if (preference.list) {
|
} else if (preference.list) {
|
||||||
return _(msg`In-app`)
|
return l`In-app`
|
||||||
} else if (preference.push) {
|
} else if (preference.push) {
|
||||||
return _(msg`Push`)
|
return l`Push`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return _(msg`Off`)
|
return l`Off`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,12 +115,12 @@ export function ExportCarDialog({
|
|||||||
<Button
|
<Button
|
||||||
color="primary"
|
color="primary"
|
||||||
size="large"
|
size="large"
|
||||||
label={l`Download CAR file`}
|
label={l`Download profile data`}
|
||||||
disabled={!!loading}
|
disabled={!!loading}
|
||||||
onPress={() => void download()}>
|
onPress={() => void download()}>
|
||||||
<ButtonIcon icon={loading === 'repo' ? Loader : DownloadIcon} />
|
<ButtonIcon icon={loading === 'repo' ? Loader : DownloadIcon} />
|
||||||
<ButtonText>
|
<ButtonText>
|
||||||
<Trans context="button">Download CAR file</Trans>
|
<Trans context="button">Download profile data</Trans>
|
||||||
</ButtonText>
|
</ButtonText>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ export function useNotificationSettingsUpdateMutation() {
|
|||||||
},
|
},
|
||||||
onError: e => {
|
onError: e => {
|
||||||
logger.error('Could not update notification settings', {message: e})
|
logger.error('Could not update notification settings', {message: e})
|
||||||
queryClient.invalidateQueries({queryKey: RQKEY})
|
void queryClient.invalidateQueries({queryKey: RQKEY})
|
||||||
Toast.show(t`Could not update notification settings`, {
|
Toast.show(t`Could not update notification settings`, {
|
||||||
type: 'error',
|
type: 'error',
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user