Add new chat notification preferences (#10972)
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
import {Trans} from '@lingui/react/macro'
|
||||
|
||||
import type * as Dialog from '#/components/Dialog'
|
||||
import {NotificationSettingsDialog} from '#/components/dialogs/NotificationSettingsDialog'
|
||||
import {Envelope_Stroke2_Corner2_Rounded as EnvelopeIcon} from '#/components/icons/Envelope'
|
||||
import {Message_Stroke2_Corner0_Rounded as MessageIcon} from '#/components/icons/Message'
|
||||
|
||||
export function ChatNotificationDialogs({
|
||||
chatControl,
|
||||
chatRequestControl,
|
||||
}: {
|
||||
chatControl: Dialog.DialogControlProps
|
||||
chatRequestControl: Dialog.DialogControlProps
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
<NotificationSettingsDialog
|
||||
control={chatControl}
|
||||
name="chat"
|
||||
icon={MessageIcon}
|
||||
titleText={<Trans>New messages</Trans>}
|
||||
subtitleText={
|
||||
<Trans>Get notifications when people send you messages.</Trans>
|
||||
}
|
||||
allowDisableInApp={false}
|
||||
/>
|
||||
<NotificationSettingsDialog
|
||||
control={chatRequestControl}
|
||||
name="chatRequest"
|
||||
icon={EnvelopeIcon}
|
||||
titleText={<Trans>New message requests</Trans>}
|
||||
subtitleText={
|
||||
<Trans>
|
||||
Get notifications when people send you message requests.
|
||||
</Trans>
|
||||
}
|
||||
allowDisableInApp={false}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,9 +1,12 @@
|
||||
import {useMemo} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {type AppBskyNotificationDefs} from '@atproto/api'
|
||||
import {Trans, useLingui} from '@lingui/react/macro'
|
||||
|
||||
import {useNotificationSettingsUpdateMutation} from '#/state/queries/notifications/settings'
|
||||
import {
|
||||
type NotificationSettingsPreference,
|
||||
type NotificationSettingsPreferenceName,
|
||||
useNotificationSettingsUpdateMutation,
|
||||
} from '#/state/queries/notifications/settings'
|
||||
import {atoms as a, platform, useTheme} from '#/alf'
|
||||
import * as Toggle from '#/components/forms/Toggle'
|
||||
import {Loader} from '#/components/Loader'
|
||||
@@ -17,16 +20,13 @@ export function PreferenceControls({
|
||||
preference,
|
||||
allowDisableInApp = true,
|
||||
}: {
|
||||
name: Exclude<keyof AppBskyNotificationDefs.Preferences, '$type'>
|
||||
name: NotificationSettingsPreferenceName
|
||||
/**
|
||||
* Keep other prefs in sync with `name`. For use in the "everything else" category
|
||||
* which groups starterpack joins + verified + unverified notifications into a single toggle.
|
||||
*/
|
||||
syncOthers?: Exclude<keyof AppBskyNotificationDefs.Preferences, '$type'>[]
|
||||
preference?:
|
||||
| AppBskyNotificationDefs.Preference
|
||||
| AppBskyNotificationDefs.FilterablePreference
|
||||
| AppBskyNotificationDefs.ChatPreference
|
||||
syncOthers?: NotificationSettingsPreferenceName[]
|
||||
preference?: NotificationSettingsPreference
|
||||
allowDisableInApp?: boolean
|
||||
}) {
|
||||
if (!preference)
|
||||
@@ -52,12 +52,9 @@ export function Inner({
|
||||
preference,
|
||||
allowDisableInApp,
|
||||
}: {
|
||||
name: Exclude<keyof AppBskyNotificationDefs.Preferences, '$type'>
|
||||
syncOthers?: Exclude<keyof AppBskyNotificationDefs.Preferences, '$type'>[]
|
||||
preference:
|
||||
| AppBskyNotificationDefs.Preference
|
||||
| AppBskyNotificationDefs.FilterablePreference
|
||||
| AppBskyNotificationDefs.ChatPreference
|
||||
name: NotificationSettingsPreferenceName
|
||||
syncOthers?: NotificationSettingsPreferenceName[]
|
||||
preference: NotificationSettingsPreference
|
||||
allowDisableInApp: boolean
|
||||
}) {
|
||||
const t = useTheme()
|
||||
@@ -95,7 +92,7 @@ export function Inner({
|
||||
}
|
||||
|
||||
const onChangeFilter = ([change]: string[]) => {
|
||||
if (change !== 'all' && change !== 'follows' && change !== 'accepted')
|
||||
if (change !== 'all' && change !== 'follows')
|
||||
throw new Error('Invalid filter')
|
||||
|
||||
const newPreference = {
|
||||
@@ -135,7 +132,7 @@ export function Inner({
|
||||
</Toggle.LabelText>
|
||||
<Toggle.Platform />
|
||||
</Toggle.Item>
|
||||
{allowDisableInApp && (
|
||||
{allowDisableInApp && 'list' in preference && (
|
||||
<Toggle.Item
|
||||
label={l`Receive in-app notifications`}
|
||||
name="list"
|
||||
@@ -176,31 +173,17 @@ export function Inner({
|
||||
/>
|
||||
)}
|
||||
</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>
|
||||
)}
|
||||
<Toggle.Item
|
||||
highlightRow
|
||||
label={l`People I follow`}
|
||||
name="follows">
|
||||
{({selected}) => (
|
||||
<Toggle.RadioWithLabel
|
||||
label={l`People I follow`}
|
||||
selected={selected}
|
||||
/>
|
||||
)}
|
||||
</Toggle.Item>
|
||||
</View>
|
||||
</Toggle.Group>
|
||||
</>
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import {useLingui} from '@lingui/react/macro'
|
||||
|
||||
import {type NotificationSettingsPreference} from '#/state/queries/notifications/settings'
|
||||
|
||||
export function SettingPreview({
|
||||
preference,
|
||||
}: {
|
||||
preference?: NotificationSettingsPreference
|
||||
}) {
|
||||
const {t: l} = useLingui()
|
||||
|
||||
if (!preference) {
|
||||
return null
|
||||
}
|
||||
|
||||
if ('include' in preference) {
|
||||
const list = 'list' in preference && preference.list
|
||||
|
||||
if (preference.include === 'all') {
|
||||
if (list && preference.push) return l`In-app, push, everyone`
|
||||
if (list) return l`In-app, everyone`
|
||||
if (preference.push) return l`Push, everyone`
|
||||
} else if (preference.include === 'follows') {
|
||||
if (list && preference.push) return l`In-app, push, people you follow`
|
||||
if (list) return l`In-app, people you follow`
|
||||
if (preference.push) return l`Push, people you follow`
|
||||
}
|
||||
} else {
|
||||
if (preference.list && preference.push) return l`In-app, push`
|
||||
if (preference.list) return l`In-app`
|
||||
if (preference.push) return l`Push`
|
||||
}
|
||||
|
||||
return l`Off`
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
import {useEffect} from 'react'
|
||||
import {Linking, View} from 'react-native'
|
||||
import * as Notification from 'expo-notifications'
|
||||
import {type AppBskyNotificationDefs} from '@atproto/api'
|
||||
import {Trans, useLingui} from '@lingui/react/macro'
|
||||
import {useQuery, useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
@@ -10,7 +9,10 @@ import {
|
||||
type AllNavigatorParams,
|
||||
type NativeStackScreenProps,
|
||||
} from '#/lib/routes/types'
|
||||
import {useNotificationSettingsQuery} from '#/state/queries/notifications/settings'
|
||||
import {
|
||||
useChatNotificationSettingsQuery,
|
||||
useNotificationSettingsQuery,
|
||||
} from '#/state/queries/notifications/settings'
|
||||
import {atoms as a} from '#/alf'
|
||||
import {Admonition} from '#/components/Admonition'
|
||||
import * as Dialog from '#/components/Dialog'
|
||||
@@ -18,11 +20,13 @@ import {NotificationSettingsDialog} from '#/components/dialogs/NotificationSetti
|
||||
import {At_Stroke2_Corner2_Rounded as AtIcon} from '#/components/icons/At'
|
||||
import {BellRinging_Stroke2_Corner0_Rounded as BellRingingIcon} from '#/components/icons/BellRinging'
|
||||
import {Bubble_Stroke2_Corner2_Rounded as BubbleIcon} from '#/components/icons/Bubble'
|
||||
import {Envelope_Stroke2_Corner2_Rounded as EnvelopeIcon} from '#/components/icons/Envelope'
|
||||
import {Haptic_Stroke2_Corner2_Rounded as HapticIcon} from '#/components/icons/Haptic'
|
||||
import {
|
||||
Heart2_Stroke2_Corner0_Rounded as HeartIcon,
|
||||
LikeRepost_Stroke2_Corner2_Rounded as LikeRepostIcon,
|
||||
} from '#/components/icons/Heart2'
|
||||
import {Message_Stroke2_Corner0_Rounded as MessageIcon} from '#/components/icons/Message'
|
||||
import {PersonPlus_Stroke2_Corner2_Rounded as PersonPlusIcon} from '#/components/icons/Person'
|
||||
import {CloseQuote_Stroke2_Corner0_Rounded as CloseQuoteIcon} from '#/components/icons/Quote'
|
||||
import {
|
||||
@@ -33,7 +37,9 @@ import {Shapes_Stroke2_Corner0_Rounded as ShapesIcon} from '#/components/icons/S
|
||||
import * as Layout from '#/components/Layout'
|
||||
import {IS_ANDROID, IS_IOS, IS_WEB} from '#/env'
|
||||
import * as SettingsList from '../components/SettingsList'
|
||||
import {ChatNotificationDialogs} from './components/ChatNotificationDialogs'
|
||||
import {ItemTextWithSubtitle} from './components/ItemTextWithSubtitle'
|
||||
import {SettingPreview} from './components/SettingPreview'
|
||||
|
||||
const RQKEY = ['notification-permissions']
|
||||
|
||||
@@ -42,6 +48,8 @@ export function NotificationSettingsScreen({}: Props) {
|
||||
const {t: l} = useLingui()
|
||||
const queryClient = useQueryClient()
|
||||
const {data: settings, isError} = useNotificationSettingsQuery()
|
||||
const {data: chatSettings, isError: chatError} =
|
||||
useChatNotificationSettingsQuery()
|
||||
|
||||
const likeDialogControl = Dialog.useDialogControl()
|
||||
const followDialogControl = Dialog.useDialogControl()
|
||||
@@ -52,6 +60,8 @@ export function NotificationSettingsScreen({}: Props) {
|
||||
const activityDialogControl = Dialog.useDialogControl()
|
||||
const likeRepostDialogControl = Dialog.useDialogControl()
|
||||
const repostRepostDialogControl = Dialog.useDialogControl()
|
||||
const chatDialogControl = Dialog.useDialogControl()
|
||||
const chatRequestDialogControl = Dialog.useDialogControl()
|
||||
const miscDialogControl = Dialog.useDialogControl()
|
||||
|
||||
const {data: permissions, refetch} = useQuery({
|
||||
@@ -234,6 +244,40 @@ export function NotificationSettingsScreen({}: Props) {
|
||||
showSkeleton={!settings}
|
||||
/>
|
||||
</SettingsList.PressableItem>
|
||||
<SettingsList.PressableItem
|
||||
label={l`Settings for notifications for new messages`}
|
||||
onPress={chatDialogControl.open}
|
||||
contentContainerStyle={[a.align_start]}>
|
||||
<SettingsList.ItemIcon icon={MessageIcon} />
|
||||
<ItemTextWithSubtitle
|
||||
titleText={<Trans>New messages</Trans>}
|
||||
subtitleText={
|
||||
chatError ? (
|
||||
<Trans>Failed to load notification settings.</Trans>
|
||||
) : (
|
||||
<SettingPreview preference={chatSettings?.chat} />
|
||||
)
|
||||
}
|
||||
showSkeleton={!chatSettings && !chatError}
|
||||
/>
|
||||
</SettingsList.PressableItem>
|
||||
<SettingsList.PressableItem
|
||||
label={l`Settings for notifications for new message requests`}
|
||||
onPress={chatRequestDialogControl.open}
|
||||
contentContainerStyle={[a.align_start]}>
|
||||
<SettingsList.ItemIcon icon={EnvelopeIcon} />
|
||||
<ItemTextWithSubtitle
|
||||
titleText={<Trans>New message requests</Trans>}
|
||||
subtitleText={
|
||||
chatError ? (
|
||||
<Trans>Failed to load notification settings.</Trans>
|
||||
) : (
|
||||
<SettingPreview preference={chatSettings?.chatRequest} />
|
||||
)
|
||||
}
|
||||
showSkeleton={!chatSettings && !chatError}
|
||||
/>
|
||||
</SettingsList.PressableItem>
|
||||
<SettingsList.PressableItem
|
||||
label={l`Settings for notifications for everything else`}
|
||||
onPress={miscDialogControl.open}
|
||||
@@ -333,6 +377,10 @@ export function NotificationSettingsScreen({}: Props) {
|
||||
<Trans>Get notifications when people repost your reposts.</Trans>
|
||||
}
|
||||
/>
|
||||
<ChatNotificationDialogs
|
||||
chatControl={chatDialogControl}
|
||||
chatRequestControl={chatRequestDialogControl}
|
||||
/>
|
||||
<NotificationSettingsDialog
|
||||
control={miscDialogControl}
|
||||
name="starterpackJoined"
|
||||
@@ -350,46 +398,3 @@ export function NotificationSettingsScreen({}: Props) {
|
||||
</Layout.Screen>
|
||||
)
|
||||
}
|
||||
|
||||
function SettingPreview({
|
||||
preference,
|
||||
}: {
|
||||
preference?:
|
||||
| AppBskyNotificationDefs.Preference
|
||||
| AppBskyNotificationDefs.FilterablePreference
|
||||
}) {
|
||||
const {t: l} = useLingui()
|
||||
if (!preference) {
|
||||
return null
|
||||
} else {
|
||||
if ('include' in preference) {
|
||||
if (preference.include === 'all') {
|
||||
if (preference.list && preference.push) {
|
||||
return l`In-app, push, everyone`
|
||||
} else if (preference.list) {
|
||||
return l`In-app, everyone`
|
||||
} else if (preference.push) {
|
||||
return l`Push, everyone`
|
||||
}
|
||||
} else if (preference.include === 'follows') {
|
||||
if (preference.list && preference.push) {
|
||||
return l`In-app, push, people you follow`
|
||||
} else if (preference.list) {
|
||||
return l`In-app, people you follow`
|
||||
} else if (preference.push) {
|
||||
return l`Push, people you follow`
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (preference.list && preference.push) {
|
||||
return l`In-app, push`
|
||||
} else if (preference.list) {
|
||||
return l`In-app`
|
||||
} else if (preference.push) {
|
||||
return l`Push`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return l`Off`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user