Activity notification settings (#8485)

Co-authored-by: Eric Bailey <git@esb.lol>
Co-authored-by: Samuel Newman <mozzius@protonmail.com>
Co-authored-by: hailey <me@haileyok.com>
This commit is contained in:
Samuel Newman
2025-07-02 00:36:04 +03:00
committed by GitHub
parent 8f9a8ddce0
commit bc072570d2
53 changed files with 1810 additions and 288 deletions
+6 -6
View File
@@ -1,20 +1,20 @@
import {
AppBskyFeedDefs,
AppBskyFeedGetListFeed as GetListFeed,
BskyAgent,
type Agent,
type AppBskyFeedDefs,
type AppBskyFeedGetListFeed as GetListFeed,
} from '@atproto/api'
import {FeedAPI, FeedAPIResponse} from './types'
import {type FeedAPI, type FeedAPIResponse} from './types'
export class ListFeedAPI implements FeedAPI {
agent: BskyAgent
agent: Agent
params: GetListFeed.QueryParams
constructor({
agent,
feedParams,
}: {
agent: BskyAgent
agent: Agent
feedParams: GetListFeed.QueryParams
}) {
this.agent = agent
+52
View File
@@ -0,0 +1,52 @@
import {
type Agent,
type AppBskyFeedDefs,
type AppBskyFeedGetPosts,
} from '@atproto/api'
import {logger} from '#/logger'
import {type FeedAPI, type FeedAPIResponse} from './types'
export class PostListFeedAPI implements FeedAPI {
agent: Agent
params: AppBskyFeedGetPosts.QueryParams
peek: AppBskyFeedDefs.FeedViewPost | null = null
constructor({
agent,
feedParams,
}: {
agent: Agent
feedParams: AppBskyFeedGetPosts.QueryParams
}) {
this.agent = agent
if (feedParams.uris.length > 25) {
logger.warn(
`Too many URIs provided - expected 25, got ${feedParams.uris.length}`,
)
}
this.params = {
uris: feedParams.uris.slice(0, 25),
}
}
async peekLatest(): Promise<AppBskyFeedDefs.FeedViewPost> {
if (this.peek) return this.peek
throw new Error('Has not fetched yet')
}
async fetch({}: {}): Promise<FeedAPIResponse> {
const res = await this.agent.app.bsky.feed.getPosts({
...this.params,
})
if (res.success) {
this.peek = {post: res.data.posts[0]}
return {
feed: res.data.posts.map(post => ({post})),
}
}
return {
feed: [],
}
}
}
+35 -9
View File
@@ -1,6 +1,6 @@
import {useEffect} from 'react'
import * as Notifications from 'expo-notifications'
import {type AppBskyNotificationListNotifications} from '@atproto/api'
import {AtUri} from '@atproto/api'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {CommonActions, useNavigation} from '@react-navigation/native'
@@ -32,6 +32,7 @@ export type NotificationReason =
| 'repost-via-repost'
| 'verified'
| 'unverified'
| 'subscribed-post'
/**
* Manually overridden type, but retains the possibility of
@@ -112,61 +113,68 @@ export function useNotificationsHandler() {
})
Notifications.setNotificationChannelAsync(
'like' satisfies AppBskyNotificationListNotifications.Notification['reason'],
'like' satisfies NotificationReason,
{
name: _(msg`Likes`),
importance: Notifications.AndroidImportance.HIGH,
},
)
Notifications.setNotificationChannelAsync(
'repost' satisfies AppBskyNotificationListNotifications.Notification['reason'],
'repost' satisfies NotificationReason,
{
name: _(msg`Reposts`),
importance: Notifications.AndroidImportance.HIGH,
},
)
Notifications.setNotificationChannelAsync(
'reply' satisfies AppBskyNotificationListNotifications.Notification['reason'],
'reply' satisfies NotificationReason,
{
name: _(msg`Replies`),
importance: Notifications.AndroidImportance.HIGH,
},
)
Notifications.setNotificationChannelAsync(
'mention' satisfies AppBskyNotificationListNotifications.Notification['reason'],
'mention' satisfies NotificationReason,
{
name: _(msg`Mentions`),
importance: Notifications.AndroidImportance.HIGH,
},
)
Notifications.setNotificationChannelAsync(
'quote' satisfies AppBskyNotificationListNotifications.Notification['reason'],
'quote' satisfies NotificationReason,
{
name: _(msg`Quotes`),
importance: Notifications.AndroidImportance.HIGH,
},
)
Notifications.setNotificationChannelAsync(
'follow' satisfies AppBskyNotificationListNotifications.Notification['reason'],
'follow' satisfies NotificationReason,
{
name: _(msg`New followers`),
importance: Notifications.AndroidImportance.HIGH,
},
)
Notifications.setNotificationChannelAsync(
'like-via-repost' satisfies AppBskyNotificationListNotifications.Notification['reason'],
'like-via-repost' satisfies NotificationReason,
{
name: _(msg`Likes of your reposts`),
importance: Notifications.AndroidImportance.HIGH,
},
)
Notifications.setNotificationChannelAsync(
'repost-via-repost' satisfies AppBskyNotificationListNotifications.Notification['reason'],
'repost-via-repost' satisfies NotificationReason,
{
name: _(msg`Reposts of your reposts`),
importance: Notifications.AndroidImportance.HIGH,
},
)
Notifications.setNotificationChannelAsync(
'subscribed-post' satisfies NotificationReason,
{
name: _(msg`Activity from others`),
importance: Notifications.AndroidImportance.HIGH,
},
)
}, [_])
useEffect(() => {
@@ -220,6 +228,23 @@ export function useNotificationsHandler() {
}
} else {
switch (payload.reason) {
case 'subscribed-post':
const urip = new AtUri(payload.uri)
if (urip.collection === 'app.bsky.feed.post') {
setTimeout(() => {
// @ts-expect-error types are weird here
navigation.navigate('HomeTab', {
screen: 'PostThread',
params: {
name: urip.host,
rkey: urip.rkey,
},
})
}, 500)
} else {
resetToTab('NotificationsTab')
}
break
case 'like':
case 'repost':
case 'follow':
@@ -231,6 +256,7 @@ export function useNotificationsHandler() {
case 'repost-via-repost':
case 'verified':
case 'unverified':
default:
resetToTab('NotificationsTab')
break
// TODO implement these after we have an idea of how to handle each individual case
@@ -1,12 +1,9 @@
import {AppBskyActorDefs} from '@atproto/api'
import {sanitizeDisplayName} from '#/lib/strings/display-names'
import {sanitizeHandle} from '#/lib/strings/handles'
import type * as bsky from '#/types/bsky'
export function createSanitizedDisplayName(
profile:
| AppBskyActorDefs.ProfileViewBasic
| AppBskyActorDefs.ProfileViewDetailed,
profile: bsky.profile.AnyProfileView,
noAt = false,
) {
if (profile.displayName != null && profile.displayName !== '') {
+2
View File
@@ -51,6 +51,7 @@ export type CommonNavigatorParams = {
AppearanceSettings: undefined
AccountSettings: undefined
PrivacyAndSecuritySettings: undefined
ActivityPrivacySettings: undefined
ContentAndMediaSettings: undefined
NotificationSettings: undefined
ReplyNotificationSettings: undefined
@@ -72,6 +73,7 @@ export type CommonNavigatorParams = {
MessagesConversation: {conversation: string; embed?: string; accept?: true}
MessagesSettings: undefined
MessagesInbox: undefined
NotificationsActivityList: {posts: string}
LegacyNotificationSettings: undefined
Feeds: undefined
Start: {name: string; rkey: string}
-1
View File
@@ -7,7 +7,6 @@ export type Gate =
| 'old_postonboarding'
| 'onboarding_add_video_feed'
| 'post_threads_v2_unspecced'
| 'reengagement_features'
| 'remove_show_latest_button'
| 'test_gate_1'
| 'test_gate_2'