+9
-1
.github/workflows/bundle-deploy-eas-update.yml
+9
-1
.github/workflows/bundle-deploy-eas-update.yml
···
5
5
push:
6
6
branches:
7
7
- main
8
+
- hailey/eas-fab
8
9
workflow_dispatch:
9
10
inputs:
10
11
channel:
···
118
119
119
120
- name: 🏗️ Create Bundle
120
121
if: ${{ !steps.fingerprint.outputs.includes-changes }}
121
-
run: SENTRY_DIST=${{ steps.sentry.outputs.SENTRY_DIST }} SENTRY_RELEASE=${{ steps.sentry.outputs.SENTRY_RELEASE }} SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }} SENTRY_DSN=${{ secrets.SENTRY_DSN }} EXPO_PUBLIC_ENV="${{ inputs.channel || 'testflight' }}" yarn export
122
+
run: |
123
+
SENTRY_DIST=${{ steps.sentry.outputs.SENTRY_DIST }} SENTRY_RELEASE=${{ steps.sentry.outputs.SENTRY_RELEASE }} SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }} SENTRY_DSN=${{ secrets.SENTRY_DSN }} EXPO_PUBLIC_ENV="${{ inputs.channel || 'testflight' }}" yarn export-ios
124
+
mv ./dist ./ios-dist
125
+
sed -i 's/"react-native-mmkv": "\^2\.12\.2"/"react-native-mmkv": "^3.3.0"/' package.json
126
+
yarn install
127
+
SENTRY_DIST=${{ steps.sentry.outputs.SENTRY_DIST }} SENTRY_RELEASE=${{ steps.sentry.outputs.SENTRY_RELEASE }} SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }} SENTRY_DSN=${{ secrets.SENTRY_DSN }} EXPO_PUBLIC_ENV="${{ inputs.channel || 'testflight' }}" yarn export-android
128
+
mv ./dist ./android-dist
129
+
122
130
123
131
- name: 📦 Package Bundle and 🚀 Deploy
124
132
if: ${{ !steps.fingerprint.outputs.includes-changes }}
+15
modules/expo-background-notification-handler/android/src/main/java/expo/modules/backgroundnotificationhandler/BackgroundNotificationHandler.kt
+15
modules/expo-background-notification-handler/android/src/main/java/expo/modules/backgroundnotificationhandler/BackgroundNotificationHandler.kt
···
15
15
16
16
if (remoteMessage.data["reason"] == "chat-message") {
17
17
mutateWithChatMessage(remoteMessage)
18
+
} else {
19
+
mutateWithOtherReason(remoteMessage)
18
20
}
19
21
20
22
notifInterface.showMessage(remoteMessage)
···
38
40
39
41
// TODO - Remove this once we have more backend capability
40
42
remoteMessage.data["badge"] = null
43
+
}
44
+
45
+
private fun mutateWithOtherReason(remoteMessage: RemoteMessage) {
46
+
// If oreo or higher
47
+
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
48
+
// If one of "like", "repost", "follow", "mention", "reply", "quote", "like-via-repost", "repost-via-repost"
49
+
// assign to it's eponymous channel. otherwise do nothing, let expo handle it
50
+
when (remoteMessage.data["reason"]) {
51
+
"like", "repost", "follow", "mention", "reply", "quote", "like-via-repost", "repost-via-repost" -> {
52
+
remoteMessage.data["channelId"] = remoteMessage.data["reason"]
53
+
}
54
+
}
55
+
}
41
56
}
42
57
}
+3
-2
package.json
+3
-2
package.json
···
61
61
"intl:push": "crowdin push translations --verbose -b main",
62
62
"nuke": "rm -rf ./node_modules && rm -rf ./ios && rm -rf ./android",
63
63
"update-extensions": "bash scripts/updateExtensions.sh",
64
-
"export": "npx expo export --dump-sourcemap && yarn upload-native-sourcemaps",
64
+
"export-ios": "npx expo export --platform ios --dump-sourcemap && yarn upload-native-sourcemaps",
65
+
"export-android": "npx expo export --platform android --dump-sourcemap && yarn upload-native-sourcemaps",
65
66
"upload-native-sourcemaps": "npx sentry-expo-upload-sourcemaps dist",
66
67
"make-deploy-bundle": "bash scripts/bundleUpdate.sh",
67
68
"generate-webpack-stats-file": "EXPO_PUBLIC_GENERATE_STATS=1 yarn build-web",
···
190
191
"react-native-gesture-handler": "2.25.0",
191
192
"react-native-get-random-values": "~1.11.0",
192
193
"react-native-ios-context-menu": "^1.15.3",
193
-
"react-native-keyboard-controller": "^1.17.1",
194
+
"react-native-keyboard-controller": "^1.17.5",
194
195
"react-native-mmkv": "^2.12.2",
195
196
"react-native-pager-view": "^6.7.1",
196
197
"react-native-progress": "bluesky-social/react-native-progress",
+17
-9
scripts/bundleUpdate.js
+17
-9
scripts/bundleUpdate.js
···
3
3
const fsp = fs.promises
4
4
const path = require('path')
5
5
6
-
const DIST_DIR = './dist'
6
+
const IOS_DIST_DIR = './ios-dist'
7
+
const ANDROID_DIST_DIR = './android-dist'
8
+
7
9
const BUNDLES_DIR = '/_expo/static/js'
8
-
const IOS_BUNDLE_DIR = path.join(DIST_DIR, BUNDLES_DIR, '/ios')
9
-
const ANDROID_BUNDLE_DIR = path.join(DIST_DIR, BUNDLES_DIR, '/android')
10
-
const METADATA_PATH = path.join(DIST_DIR, '/metadata.json')
10
+
11
+
const IOS_BUNDLE_DIR = path.join(IOS_DIST_DIR, BUNDLES_DIR, '/ios')
12
+
const ANDROID_BUNDLE_DIR = path.join(ANDROID_DIST_DIR, BUNDLES_DIR, '/android')
13
+
14
+
const IOS_METADATA_PATH = path.join(IOS_DIST_DIR, '/metadata.json')
15
+
const ANDROID_METADATA_PATH = path.join(ANDROID_DIST_DIR, '/metadata.json')
16
+
11
17
const DEST_DIR = './bundleTempDir'
12
18
13
19
// Weird, don't feel like figuring out _why_ it wants this
14
-
const METADATA = require(`../${METADATA_PATH}`)
15
-
const IOS_METADATA_ASSETS = METADATA.fileMetadata.ios.assets
16
-
const ANDROID_METADATA_ASSETS = METADATA.fileMetadata.android.assets
20
+
const IOS_METADATA = require(`../${IOS_METADATA_PATH}`)
21
+
const ANDROID_METADATA = require(`../${ANDROID_METADATA_PATH}`)
22
+
23
+
const IOS_METADATA_ASSETS = IOS_METADATA.fileMetadata.ios.assets
24
+
const ANDROID_METADATA_ASSETS = ANDROID_METADATA.fileMetadata.android.assets
17
25
18
26
const getMd5 = async path => {
19
27
return new Promise(res => {
···
60
68
61
69
console.log('Getting ios asset md5s and moving them...')
62
70
for (const asset of IOS_METADATA_ASSETS) {
63
-
const currPath = path.join(DIST_DIR, asset.path)
71
+
const currPath = path.join(IOS_DIST_DIR, asset.path)
64
72
const md5 = await getMd5(currPath)
65
73
const withExtPath = `assets/${md5}.${asset.ext}`
66
74
iosAssets.push(withExtPath)
···
69
77
70
78
console.log('Getting android asset md5s and moving them...')
71
79
for (const asset of ANDROID_METADATA_ASSETS) {
72
-
const currPath = path.join(DIST_DIR, asset.path)
80
+
const currPath = path.join(ANDROID_DIST_DIR, asset.path)
73
81
const md5 = await getMd5(currPath)
74
82
const withExtPath = `assets/${md5}.${asset.ext}`
75
83
androidAssets.push(withExtPath)
+2
src/App.native.tsx
+2
src/App.native.tsx
···
64
64
import {ThemeProvider as Alf} from '#/alf'
65
65
import {useColorModeTheme} from '#/alf/util/useColorModeTheme'
66
66
import {Provider as ContextMenuProvider} from '#/components/ContextMenu'
67
+
import {NuxDialogs} from '#/components/dialogs/nuxs'
67
68
import {useStarterPackEntry} from '#/components/hooks/useStarterPackEntry'
68
69
import {Provider as IntentDialogProvider} from '#/components/intents/IntentDialogs'
69
70
import {Provider as PortalProvider} from '#/components/Portal'
···
156
157
<IntentDialogProvider>
157
158
<TestCtrls />
158
159
<Shell />
160
+
<NuxDialogs />
159
161
</IntentDialogProvider>
160
162
</GestureHandlerRootView>
161
163
</HideBottomBarBorderProvider>
+2
src/App.web.tsx
+2
src/App.web.tsx
···
54
54
import {ThemeProvider as Alf} from '#/alf'
55
55
import {useColorModeTheme} from '#/alf/util/useColorModeTheme'
56
56
import {Provider as ContextMenuProvider} from '#/components/ContextMenu'
57
+
import {NuxDialogs} from '#/components/dialogs/nuxs'
57
58
import {useStarterPackEntry} from '#/components/hooks/useStarterPackEntry'
58
59
import {Provider as IntentDialogProvider} from '#/components/intents/IntentDialogs'
59
60
import {Provider as PortalProvider} from '#/components/Portal'
···
134
135
<HideBottomBarBorderProvider>
135
136
<IntentDialogProvider>
136
137
<Shell />
138
+
<NuxDialogs />
137
139
</IntentDialogProvider>
138
140
</HideBottomBarBorderProvider>
139
141
</ServiceConfigProvider>
+16
-3
src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/utils.tsx
+16
-3
src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/utils.tsx
···
1
1
import {type RefObject, useCallback, useEffect, useRef, useState} from 'react'
2
2
3
3
import {isSafari} from '#/lib/browser'
4
+
import {logger} from '#/logger'
4
5
import {useVideoVolumeState} from '#/components/Post/Embed/VideoEmbed/VideoVolumeContext'
5
6
6
7
export function useVideoElement(ref: RefObject<HTMLVideoElement>) {
···
79
80
await ref.current.play()
80
81
} catch (e: any) {
81
82
if (
82
-
!e.message?.includes(`The request is not allowed by the user agent`)
83
+
!e.message?.includes(
84
+
`The request is not allowed by the user agent`,
85
+
) &&
86
+
!e.message?.includes(
87
+
`The play() request was interrupted by a call to pause()`,
88
+
)
83
89
) {
84
90
throw e
85
91
}
···
176
182
} else {
177
183
const promise = ref.current.play()
178
184
if (promise !== undefined) {
179
-
promise.catch(err => {
180
-
console.error('Error playing video:', err)
185
+
promise.catch((err: any) => {
186
+
if (
187
+
// ignore this common error. it's fine
188
+
!err.message?.includes(
189
+
`The play() request was interrupted by a call to pause()`,
190
+
)
191
+
) {
192
+
logger.error('Error playing video:', {message: err})
193
+
}
181
194
})
182
195
}
183
196
}
+1
-1
src/components/ProfileHoverCard/index.web.tsx
+1
-1
src/components/ProfileHoverCard/index.web.tsx
+4
-2
src/components/ProfileHoverCard/types.ts
+4
-2
src/components/ProfileHoverCard/types.ts
+9
-4
src/components/dialogs/PostInteractionSettingsDialog.tsx
+9
-4
src/components/dialogs/PostInteractionSettingsDialog.tsx
···
1
1
import React from 'react'
2
-
import {StyleProp, View, ViewStyle} from 'react-native'
3
-
import {AppBskyFeedDefs, AppBskyFeedPostgate, AtUri} from '@atproto/api'
2
+
import {type StyleProp, View, type ViewStyle} from 'react-native'
3
+
import {
4
+
type AppBskyFeedDefs,
5
+
type AppBskyFeedPostgate,
6
+
AtUri,
7
+
} from '@atproto/api'
4
8
import {msg, Trans} from '@lingui/macro'
5
9
import {useLingui} from '@lingui/react'
6
10
import {useQueryClient} from '@tanstack/react-query'
···
22
26
import {
23
27
createThreadgateViewQueryKey,
24
28
getThreadgateView,
25
-
ThreadgateAllowUISetting,
29
+
type ThreadgateAllowUISetting,
26
30
threadgateViewToAllowUISetting,
27
31
useSetThreadgateAllowMutation,
28
32
useThreadgateViewQuery,
···
558
562
await Promise.all([
559
563
queryClient.prefetchQuery({
560
564
queryKey: createPostgateQueryKey(postUri),
561
-
queryFn: () => getPostgateRecord({agent, postUri}),
565
+
queryFn: () =>
566
+
getPostgateRecord({agent, postUri}).then(res => res ?? null),
562
567
staleTime: STALE.SECONDS.THIRTY,
563
568
}),
564
569
queryClient.prefetchQuery({
+100
-8
src/lib/hooks/useNotificationHandler.ts
+100
-8
src/lib/hooks/useNotificationHandler.ts
···
1
-
import React from 'react'
1
+
import {useEffect} from 'react'
2
2
import * as Notifications from 'expo-notifications'
3
+
import {type AppBskyNotificationListNotifications} from '@atproto/api'
4
+
import {msg} from '@lingui/macro'
5
+
import {useLingui} from '@lingui/react'
3
6
import {CommonActions, useNavigation} from '@react-navigation/native'
4
7
import {useQueryClient} from '@tanstack/react-query'
5
8
···
25
28
| 'quote'
26
29
| 'chat-message'
27
30
| 'starterpack-joined'
31
+
| 'like-via-repost'
32
+
| 'repost-via-repost'
33
+
| 'verified'
34
+
| 'unverified'
28
35
29
36
/**
30
37
* Manually overridden type, but retains the possibility of
···
66
73
const {currentConvoId} = useCurrentConvoId()
67
74
const {setShowLoggedOut} = useLoggedOutViewControls()
68
75
const closeAllActiveElements = useCloseAllActiveElements()
76
+
const {_} = useLingui()
69
77
70
78
// On Android, we cannot control which sound is used for a notification on Android
71
79
// 28 or higher. Instead, we have to configure a notification channel ahead of time
72
80
// which has the sounds we want in the configuration for that channel. These two
73
81
// channels allow for the mute/unmute functionality we want for the background
74
82
// handler.
75
-
React.useEffect(() => {
83
+
useEffect(() => {
76
84
if (!isAndroid) return
85
+
// assign both chat notifications to a group
86
+
// NOTE: I don't think that it will retroactively move them into the group
87
+
// if the channels already exist. no big deal imo -sfn
88
+
const CHAT_GROUP = 'chat'
89
+
Notifications.setNotificationChannelGroupAsync(CHAT_GROUP, {
90
+
name: _(msg`Chat`),
91
+
description: _(
92
+
msg`You can choose whether chat notifications have sound in the chat settings within the app`,
93
+
),
94
+
})
77
95
Notifications.setNotificationChannelAsync('chat-messages', {
78
-
name: 'Chat',
96
+
name: _(msg`Chat messages - sound`),
97
+
groupId: CHAT_GROUP,
79
98
importance: Notifications.AndroidImportance.MAX,
80
99
sound: 'dm.mp3',
81
100
showBadge: true,
82
101
vibrationPattern: [250],
83
102
lockscreenVisibility: Notifications.AndroidNotificationVisibility.PRIVATE,
84
103
})
85
-
86
104
Notifications.setNotificationChannelAsync('chat-messages-muted', {
87
-
name: 'Chat - Muted',
105
+
name: _(msg`Chat messages - silent`),
106
+
groupId: CHAT_GROUP,
88
107
importance: Notifications.AndroidImportance.MAX,
89
108
sound: null,
90
109
showBadge: true,
91
110
vibrationPattern: [250],
92
111
lockscreenVisibility: Notifications.AndroidNotificationVisibility.PRIVATE,
93
112
})
94
-
}, [])
95
113
96
-
React.useEffect(() => {
114
+
Notifications.setNotificationChannelAsync(
115
+
'like' satisfies AppBskyNotificationListNotifications.Notification['reason'],
116
+
{
117
+
name: _(msg`Likes`),
118
+
importance: Notifications.AndroidImportance.HIGH,
119
+
},
120
+
)
121
+
Notifications.setNotificationChannelAsync(
122
+
'repost' satisfies AppBskyNotificationListNotifications.Notification['reason'],
123
+
{
124
+
name: _(msg`Reposts`),
125
+
importance: Notifications.AndroidImportance.HIGH,
126
+
},
127
+
)
128
+
Notifications.setNotificationChannelAsync(
129
+
'reply' satisfies AppBskyNotificationListNotifications.Notification['reason'],
130
+
{
131
+
name: _(msg`Replies`),
132
+
importance: Notifications.AndroidImportance.HIGH,
133
+
},
134
+
)
135
+
Notifications.setNotificationChannelAsync(
136
+
'mention' satisfies AppBskyNotificationListNotifications.Notification['reason'],
137
+
{
138
+
name: _(msg`Mentions`),
139
+
importance: Notifications.AndroidImportance.HIGH,
140
+
},
141
+
)
142
+
Notifications.setNotificationChannelAsync(
143
+
'quote' satisfies AppBskyNotificationListNotifications.Notification['reason'],
144
+
{
145
+
name: _(msg`Quotes`),
146
+
importance: Notifications.AndroidImportance.HIGH,
147
+
},
148
+
)
149
+
Notifications.setNotificationChannelAsync(
150
+
'follow' satisfies AppBskyNotificationListNotifications.Notification['reason'],
151
+
{
152
+
name: _(msg`New followers`),
153
+
importance: Notifications.AndroidImportance.HIGH,
154
+
},
155
+
)
156
+
Notifications.setNotificationChannelAsync(
157
+
'like-via-repost' satisfies AppBskyNotificationListNotifications.Notification['reason'],
158
+
{
159
+
name: _(msg`Likes of your reposts`),
160
+
importance: Notifications.AndroidImportance.HIGH,
161
+
},
162
+
)
163
+
Notifications.setNotificationChannelAsync(
164
+
'repost-via-repost' satisfies AppBskyNotificationListNotifications.Notification['reason'],
165
+
{
166
+
name: _(msg`Reposts of your reposts`),
167
+
importance: Notifications.AndroidImportance.HIGH,
168
+
},
169
+
)
170
+
}, [_])
171
+
172
+
useEffect(() => {
97
173
const handleNotification = (payload?: NotificationPayload) => {
98
174
if (!payload) return
99
175
···
151
227
case 'quote':
152
228
case 'reply':
153
229
case 'starterpack-joined':
230
+
case 'like-via-repost':
231
+
case 'repost-via-repost':
232
+
case 'verified':
233
+
case 'unverified':
154
234
resetToTab('NotificationsTab')
155
235
break
156
236
// TODO implement these after we have an idea of how to handle each individual case
···
242
322
const payload = e.notification.request.trigger
243
323
.payload as NotificationPayload
244
324
245
-
if (!payload) return
325
+
if (!payload) {
326
+
logger.error('useNotificationsHandler: received no payload', {
327
+
identifier: e.notification.request.identifier,
328
+
})
329
+
return
330
+
}
331
+
if (!payload.reason) {
332
+
logger.error('useNotificationsHandler: received unknown payload', {
333
+
payload,
334
+
identifier: e.notification.request.identifier,
335
+
})
336
+
return
337
+
}
246
338
247
339
logger.debug(
248
340
'User pressed a notification, opening notifications tab',
+5
src/lib/hooks/useOpenLink.ts
+5
src/lib/hooks/useOpenLink.ts
···
11
11
isRelativeUrl,
12
12
toNiceDomain,
13
13
} from '#/lib/strings/url-helpers'
14
+
import {logger} from '#/logger'
14
15
import {isNative} from '#/platform/detection'
15
16
import {useInAppBrowser} from '#/state/preferences/in-app-browser'
16
17
import {useTheme} from '#/alf'
···
64
65
toolbarColor: t.atoms.bg.backgroundColor,
65
66
controlsColor: t.palette.primary_500,
66
67
createTask: false,
68
+
}).catch(err => {
69
+
if (__DEV__)
70
+
logger.error('Could not open web browser', {message: err})
71
+
Linking.openURL(url)
67
72
}),
68
73
)
69
74
return
+1
src/lib/statsig/gates.ts
+1
src/lib/statsig/gates.ts
+190
-155
src/locale/locales/en/messages.po
+190
-155
src/locale/locales/en/messages.po
···
95
95
msgid "{0, plural, one {following} other {following}}"
96
96
msgstr ""
97
97
98
-
#: src/screens/PostThread/components/ThreadItemAnchor.tsx:474
98
+
#: src/screens/PostThread/components/ThreadItemAnchor.tsx:468
99
99
#: src/view/com/post-thread/PostThreadItem.tsx:541
100
100
msgid "{0, plural, one {like} other {likes}}"
101
101
msgstr ""
···
104
104
msgid "{0, plural, one {post} other {posts}}"
105
105
msgstr ""
106
106
107
-
#: src/screens/PostThread/components/ThreadItemAnchor.tsx:458
107
+
#: src/screens/PostThread/components/ThreadItemAnchor.tsx:452
108
108
#: src/view/com/post-thread/PostThreadItem.tsx:525
109
109
msgid "{0, plural, one {quote} other {quotes}}"
110
110
msgstr ""
111
111
112
-
#: src/screens/PostThread/components/ThreadItemAnchor.tsx:440
112
+
#: src/screens/PostThread/components/ThreadItemAnchor.tsx:434
113
113
#: src/view/com/post-thread/PostThreadItem.tsx:507
114
114
msgid "{0, plural, one {repost} other {reposts}}"
115
115
msgstr ""
···
499
499
500
500
#: src/Navigation.tsx:490
501
501
#: src/screens/Settings/AboutSettings.tsx:75
502
-
#: src/screens/Settings/Settings.tsx:234
503
-
#: src/screens/Settings/Settings.tsx:237
502
+
#: src/screens/Settings/Settings.tsx:238
503
+
#: src/screens/Settings/Settings.tsx:241
504
504
msgid "About"
505
505
msgstr ""
506
506
···
519
519
msgstr ""
520
520
521
521
#: src/screens/Settings/AccessibilitySettings.tsx:46
522
-
#: src/screens/Settings/Settings.tsx:210
523
-
#: src/screens/Settings/Settings.tsx:213
522
+
#: src/screens/Settings/Settings.tsx:214
523
+
#: src/screens/Settings/Settings.tsx:217
524
524
msgid "Accessibility"
525
525
msgstr ""
526
526
···
531
531
#: src/Navigation.tsx:381
532
532
#: src/screens/Login/LoginForm.tsx:194
533
533
#: src/screens/Settings/AccountSettings.tsx:48
534
-
#: src/screens/Settings/Settings.tsx:164
535
-
#: src/screens/Settings/Settings.tsx:167
534
+
#: src/screens/Settings/Settings.tsx:166
535
+
#: src/screens/Settings/Settings.tsx:169
536
536
msgid "Account"
537
537
msgstr ""
538
538
···
563
563
msgid "Account Muted by List"
564
564
msgstr ""
565
565
566
-
#: src/screens/Settings/Settings.tsx:514
566
+
#: src/screens/Settings/Settings.tsx:518
567
567
msgid "Account options"
568
568
msgstr ""
569
569
570
-
#: src/screens/Settings/Settings.tsx:550
570
+
#: src/screens/Settings/Settings.tsx:554
571
571
msgid "Account removed from quick access"
572
572
msgstr ""
573
573
···
639
639
msgid "Add alt text (optional)"
640
640
msgstr ""
641
641
642
-
#: src/screens/Settings/Settings.tsx:454
643
-
#: src/screens/Settings/Settings.tsx:457
642
+
#: src/screens/Settings/Settings.tsx:458
643
+
#: src/screens/Settings/Settings.tsx:461
644
644
#: src/view/shell/desktop/LeftNav.tsx:260
645
645
#: src/view/shell/desktop/LeftNav.tsx:264
646
646
msgid "Add another account"
···
772
772
msgid "alice@example.com"
773
773
msgstr ""
774
774
775
-
#: src/view/screens/Notifications.tsx:86
775
+
#: src/view/screens/Notifications.tsx:88
776
776
msgid "All"
777
777
msgstr ""
778
778
···
800
800
msgid "Allow new messages from"
801
801
msgstr ""
802
802
803
-
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:344
803
+
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:348
804
804
msgid "Allow quote posts"
805
805
msgstr ""
806
806
807
-
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:389
807
+
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:393
808
808
msgid "Allow replies from:"
809
809
msgstr ""
810
810
···
1040
1040
1041
1041
#: src/Navigation.tsx:373
1042
1042
#: src/screens/Settings/AppearanceSettings.tsx:85
1043
-
#: src/screens/Settings/Settings.tsx:202
1044
-
#: src/screens/Settings/Settings.tsx:205
1043
+
#: src/screens/Settings/Settings.tsx:206
1044
+
#: src/screens/Settings/Settings.tsx:209
1045
1045
msgid "Appearance"
1046
1046
msgstr ""
1047
1047
···
1050
1050
msgid "Apply default recommended feeds"
1051
1051
msgstr ""
1052
1052
1053
-
#: src/screens/PostThread/components/ThreadItemAnchor.tsx:640
1053
+
#: src/screens/PostThread/components/ThreadItemAnchor.tsx:634
1054
1054
#: src/view/com/post-thread/PostThreadItem.tsx:955
1055
1055
msgid "Archived from {0}"
1056
1056
msgstr ""
1057
1057
1058
-
#: src/screens/PostThread/components/ThreadItemAnchor.tsx:609
1059
-
#: src/screens/PostThread/components/ThreadItemAnchor.tsx:648
1058
+
#: src/screens/PostThread/components/ThreadItemAnchor.tsx:603
1059
+
#: src/screens/PostThread/components/ThreadItemAnchor.tsx:642
1060
1060
#: src/view/com/post-thread/PostThreadItem.tsx:924
1061
1061
#: src/view/com/post-thread/PostThreadItem.tsx:963
1062
1062
msgid "Archived post"
···
1297
1297
msgid "Bluesky"
1298
1298
msgstr ""
1299
1299
1300
-
#: src/screens/PostThread/components/ThreadItemAnchor.tsx:665
1300
+
#: src/screens/PostThread/components/ThreadItemAnchor.tsx:659
1301
1301
#: src/view/com/post-thread/PostThreadItem.tsx:980
1302
1302
msgid "Bluesky cannot confirm the authenticity of the claimed date."
1303
1303
msgstr ""
···
1455
1455
#: src/screens/Settings/AppIconSettings/index.tsx:225
1456
1456
#: src/screens/Settings/components/ChangeHandleDialog.tsx:78
1457
1457
#: src/screens/Settings/components/ChangeHandleDialog.tsx:85
1458
-
#: src/screens/Settings/Settings.tsx:279
1458
+
#: src/screens/Settings/Settings.tsx:283
1459
1459
#: src/screens/Takendown.tsx:99
1460
1460
#: src/screens/Takendown.tsx:102
1461
1461
#: src/view/com/composer/Composer.tsx:960
···
1466
1466
#: src/view/com/modals/ChangePassword.tsx:282
1467
1467
#: src/view/com/modals/CreateOrEditList.tsx:333
1468
1468
#: src/view/com/modals/CropImage.web.tsx:97
1469
-
#: src/view/com/modals/LinkWarning.tsx:105
1470
-
#: src/view/com/modals/LinkWarning.tsx:107
1471
1469
#: src/view/shell/desktop/LeftNav.tsx:213
1472
1470
msgid "Cancel"
1473
1471
msgstr ""
···
1498
1496
1499
1497
#: src/screens/Search/Shell.tsx:341
1500
1498
msgid "Cancel search"
1501
-
msgstr ""
1502
-
1503
-
#: src/view/com/modals/LinkWarning.tsx:106
1504
-
msgid "Cancels opening the linked website"
1505
1499
msgstr ""
1506
1500
1507
1501
#: src/components/PostControls/index.tsx:101
···
1567
1561
msgid "Changes hosting provider"
1568
1562
msgstr ""
1569
1563
1564
+
#: src/lib/hooks/useNotificationHandler.ts:90
1570
1565
#: src/Navigation.tsx:515
1571
1566
#: src/view/shell/bottom-bar/BottomBar.tsx:221
1572
1567
#: src/view/shell/desktop/LeftNav.tsx:553
···
1580
1575
msgid "Chat deleted"
1581
1576
msgstr ""
1582
1577
1578
+
#: src/lib/hooks/useNotificationHandler.ts:105
1579
+
msgid "Chat messages - silent"
1580
+
msgstr ""
1581
+
1582
+
#: src/lib/hooks/useNotificationHandler.ts:96
1583
+
msgid "Chat messages - sound"
1584
+
msgstr ""
1585
+
1583
1586
#: src/components/dms/ConvoMenu.tsx:176
1584
1587
msgctxt "toast"
1585
1588
msgid "Chat muted"
···
1668
1671
msgid "Choose your username"
1669
1672
msgstr ""
1670
1673
1671
-
#: src/screens/Settings/Settings.tsx:432
1674
+
#: src/screens/Settings/Settings.tsx:436
1672
1675
msgid "Clear all storage data"
1673
1676
msgstr ""
1674
1677
1675
-
#: src/screens/Settings/Settings.tsx:434
1678
+
#: src/screens/Settings/Settings.tsx:438
1676
1679
msgid "Clear all storage data (restart after this)"
1677
1680
msgstr ""
1678
1681
···
1697
1700
msgid "Click here to update your email"
1698
1701
msgstr ""
1699
1702
1700
-
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:337
1703
+
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:341
1701
1704
msgid "Click to disable quote posts of this post."
1702
1705
msgstr ""
1703
1706
1704
-
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:338
1707
+
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:342
1705
1708
msgid "Click to enable quote posts of this post."
1706
1709
msgstr ""
1707
1710
···
1762
1765
msgid "Close dialog"
1763
1766
msgstr ""
1764
1767
1765
-
#: src/view/shell/index.web.tsx:85
1768
+
#: src/view/shell/index.web.tsx:87
1766
1769
msgid "Close drawer menu"
1767
1770
msgstr ""
1768
1771
···
1920
1923
msgstr ""
1921
1924
1922
1925
#: src/screens/Settings/AccessibilitySettings.tsx:109
1923
-
#: src/screens/Settings/Settings.tsx:194
1924
-
#: src/screens/Settings/Settings.tsx:197
1926
+
#: src/screens/Settings/Settings.tsx:198
1927
+
#: src/screens/Settings/Settings.tsx:201
1925
1928
msgid "Content and media"
1926
1929
msgstr ""
1927
1930
···
2142
2145
msgid "Could not process your video"
2143
2146
msgstr ""
2144
2147
2145
-
#: src/state/queries/notifications/settings.ts:47
2148
+
#: src/state/queries/notifications/settings.ts:50
2146
2149
msgid "Could not update notification settings"
2147
2150
msgstr ""
2148
2151
···
2229
2232
msgid "Customization options"
2230
2233
msgstr ""
2231
2234
2232
-
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:103
2235
+
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:107
2233
2236
msgid "Customize who can interact with this post."
2234
2237
msgstr ""
2235
2238
···
2267
2270
msgid "Deactivate account"
2268
2271
msgstr ""
2269
2272
2270
-
#: src/screens/Settings/Settings.tsx:406
2273
+
#: src/screens/Settings/Settings.tsx:410
2271
2274
msgid "Debug Moderation"
2272
2275
msgstr ""
2273
2276
···
2316
2319
msgid "Delete chat"
2317
2320
msgstr ""
2318
2321
2319
-
#: src/screens/Settings/Settings.tsx:413
2322
+
#: src/screens/Settings/Settings.tsx:417
2320
2323
msgid "Delete chat declaration record"
2321
2324
msgstr ""
2322
2325
···
2425
2428
msgid "Developer mode enabled"
2426
2429
msgstr ""
2427
2430
2428
-
#: src/screens/Settings/Settings.tsx:261
2429
-
#: src/screens/Settings/Settings.tsx:264
2431
+
#: src/screens/Settings/Settings.tsx:265
2432
+
#: src/screens/Settings/Settings.tsx:268
2430
2433
msgid "Developer options"
2431
2434
msgstr ""
2432
2435
···
2731
2734
msgid "Edit People"
2732
2735
msgstr ""
2733
2736
2734
-
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:69
2735
-
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:239
2737
+
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:73
2738
+
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:243
2736
2739
msgid "Edit post interaction settings"
2737
2740
msgstr ""
2738
2741
···
2977
2980
msgid "Error: {error}"
2978
2981
msgstr ""
2979
2982
2980
-
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:394
2983
+
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:398
2981
2984
msgid "Everybody"
2982
2985
msgstr ""
2983
2986
···
2991
2994
2992
2995
#: src/screens/Messages/Settings.tsx:83
2993
2996
#: src/screens/Messages/Settings.tsx:86
2994
-
#: src/screens/Settings/NotificationSettings/components/PreferenceControls.tsx:153
2995
-
#: src/screens/Settings/NotificationSettings/components/PreferenceControls.tsx:167
2997
+
#: src/screens/Settings/NotificationSettings/components/PreferenceControls.tsx:160
2998
+
#: src/screens/Settings/NotificationSettings/components/PreferenceControls.tsx:174
2996
2999
msgid "Everyone"
2997
3000
msgstr ""
2998
3001
···
3245
3248
msgid "Failed to save settings. Please try again."
3246
3249
msgstr ""
3247
3250
3248
-
#: src/screens/Settings/InterestsSettings.tsx:136
3251
+
#: src/screens/Settings/InterestsSettings.tsx:132
3249
3252
msgctxt "toast"
3250
3253
msgid "Failed to save your interests."
3251
3254
msgstr ""
···
3372
3375
3373
3376
#: src/screens/Search/components/SearchLanguageDropdown.tsx:70
3374
3377
msgid "Filter search by language (currently: {currentLanguageLabel})"
3378
+
msgstr ""
3379
+
3380
+
#: src/screens/Settings/NotificationSettings/components/PreferenceControls.tsx:154
3381
+
msgid "Filter who you receive notifications from"
3375
3382
msgstr ""
3376
3383
3377
3384
#: src/screens/Onboarding/StepFinished.tsx:314
···
3589
3596
msgid "Frequently Posts Unwanted Content"
3590
3597
msgstr ""
3591
3598
3599
+
#: src/screens/Settings/NotificationSettings/components/PreferenceControls.tsx:150
3600
+
msgid "From"
3601
+
msgstr ""
3602
+
3592
3603
#: src/screens/Hashtag.tsx:120
3593
3604
msgid "From @{sanitizedAuthor}"
3594
3605
msgstr ""
···
3664
3675
msgid "Glaring violations of law or terms of service"
3665
3676
msgstr ""
3666
3677
3678
+
#: src/components/dialogs/LinkWarning.tsx:111
3679
+
#: src/components/dialogs/LinkWarning.tsx:117
3667
3680
#: src/components/Layout/Header/index.tsx:127
3668
3681
#: src/components/moderation/ScreenHider.tsx:154
3669
3682
#: src/components/moderation/ScreenHider.tsx:163
···
3799
3812
msgid "Having trouble?"
3800
3813
msgstr ""
3801
3814
3802
-
#: src/screens/Settings/Settings.tsx:226
3803
3815
#: src/screens/Settings/Settings.tsx:230
3816
+
#: src/screens/Settings/Settings.tsx:234
3804
3817
#: src/view/shell/desktop/RightNav.tsx:120
3805
3818
#: src/view/shell/desktop/RightNav.tsx:121
3806
3819
#: src/view/shell/Drawer.tsx:370
···
4067
4080
msgid "In-app"
4068
4081
msgstr ""
4069
4082
4070
-
#: src/screens/Settings/NotificationSettings/components/PreferenceControls.tsx:134
4083
+
#: src/screens/Settings/NotificationSettings/components/PreferenceControls.tsx:139
4071
4084
msgid "In-app notifications"
4072
4085
msgstr ""
4073
4086
···
4258
4271
msgstr ""
4259
4272
4260
4273
#: src/screens/Settings/LanguageSettings.tsx:78
4261
-
#: src/screens/Settings/Settings.tsx:218
4262
-
#: src/screens/Settings/Settings.tsx:221
4274
+
#: src/screens/Settings/Settings.tsx:222
4275
+
#: src/screens/Settings/Settings.tsx:225
4263
4276
msgid "Languages"
4264
4277
msgstr ""
4265
4278
···
4346
4359
msgid "Leave them all unchecked to see any language."
4347
4360
msgstr ""
4348
4361
4349
-
#: src/view/com/modals/LinkWarning.tsx:65
4362
+
#: src/components/dialogs/LinkWarning.tsx:67
4363
+
#: src/components/dialogs/LinkWarning.tsx:75
4350
4364
msgid "Leaving Bluesky"
4351
4365
msgstr ""
4352
4366
···
4431
4445
msgid "Liked by {likeCount, plural, one {# user} other {# users}}"
4432
4446
msgstr ""
4433
4447
4434
-
#: src/screens/Settings/NotificationSettings/index.tsx:159
4448
+
#: src/lib/hooks/useNotificationHandler.ts:117
4449
+
#: src/screens/Settings/NotificationSettings/index.tsx:126
4435
4450
#: src/screens/Settings/NotificationSettings/LikeNotificationSettings.tsx:41
4436
4451
#: src/view/screens/Profile.tsx:229
4437
4452
msgid "Likes"
4438
4453
msgstr ""
4439
4454
4455
+
#: src/lib/hooks/useNotificationHandler.ts:159
4440
4456
#: src/screens/Settings/NotificationSettings/index.tsx:208
4441
4457
#: src/screens/Settings/NotificationSettings/LikesOnRepostsNotificationSettings.tsx:41
4442
4458
msgid "Likes of your reposts"
···
4446
4462
msgid "Likes of your reposts notifications"
4447
4463
msgstr ""
4448
4464
4449
-
#: src/screens/PostThread/components/ThreadItemAnchor.tsx:467
4465
+
#: src/screens/PostThread/components/ThreadItemAnchor.tsx:461
4450
4466
#: src/view/com/post-thread/PostThreadItem.tsx:243
4451
4467
msgid "Likes on this post"
4452
4468
msgstr ""
···
4554
4570
msgid "Load more suggested feeds"
4555
4571
msgstr ""
4556
4572
4557
-
#: src/view/screens/Notifications.tsx:270
4573
+
#: src/view/screens/Notifications.tsx:278
4558
4574
msgid "Load new notifications"
4559
4575
msgstr ""
4560
4576
···
4614
4630
msgid "Make one for me"
4615
4631
msgstr ""
4616
4632
4617
-
#: src/view/com/modals/LinkWarning.tsx:79
4633
+
#: src/components/dialogs/LinkWarning.tsx:85
4618
4634
msgid "Make sure this is where you intend to go!"
4619
4635
msgstr ""
4620
4636
···
4668
4684
msgid "mentioned users"
4669
4685
msgstr ""
4670
4686
4671
-
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:423
4687
+
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:427
4672
4688
msgid "Mentioned users"
4673
4689
msgstr ""
4674
4690
4675
-
#: src/screens/Settings/NotificationSettings/index.tsx:137
4691
+
#: src/lib/hooks/useNotificationHandler.ts:138
4692
+
#: src/screens/Settings/NotificationSettings/index.tsx:159
4676
4693
#: src/screens/Settings/NotificationSettings/MentionNotificationSettings.tsx:41
4677
-
#: src/view/screens/Notifications.tsx:99
4694
+
#: src/view/screens/Notifications.tsx:101
4678
4695
msgid "Mentions"
4679
4696
msgstr ""
4680
4697
···
4741
4758
4742
4759
#: src/Navigation.tsx:159
4743
4760
#: src/screens/Moderation/index.tsx:93
4744
-
#: src/screens/Settings/Settings.tsx:178
4745
-
#: src/screens/Settings/Settings.tsx:181
4761
+
#: src/screens/Settings/Settings.tsx:180
4762
+
#: src/screens/Settings/Settings.tsx:183
4746
4763
msgid "Moderation"
4747
4764
msgstr ""
4748
4765
···
5024
5041
msgid "New follower notifications"
5025
5042
msgstr ""
5026
5043
5027
-
#: src/screens/Settings/NotificationSettings/index.tsx:181
5044
+
#: src/lib/hooks/useNotificationHandler.ts:152
5045
+
#: src/screens/Settings/NotificationSettings/index.tsx:137
5028
5046
#: src/screens/Settings/NotificationSettings/NewFollowerNotificationSettings.tsx:41
5029
5047
msgid "New followers"
5030
5048
msgstr ""
···
5059
5077
5060
5078
#: src/screens/Profile/ProfileFeed/index.tsx:241
5061
5079
#: src/view/screens/Feeds.tsx:552
5062
-
#: src/view/screens/Notifications.tsx:165
5080
+
#: src/view/screens/Notifications.tsx:167
5063
5081
#: src/view/screens/Profile.tsx:510
5064
5082
#: src/view/screens/ProfileList.tsx:250
5065
5083
#: src/view/screens/ProfileList.tsx:288
···
5232
5250
msgid "No thanks"
5233
5251
msgstr ""
5234
5252
5235
-
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:405
5253
+
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:409
5236
5254
msgid "Nobody"
5237
5255
msgstr ""
5238
5256
···
5284
5302
5285
5303
#: src/Navigation.tsx:396
5286
5304
#: src/Navigation.tsx:530
5287
-
#: src/view/screens/Notifications.tsx:134
5305
+
#: src/view/screens/Notifications.tsx:136
5288
5306
msgid "Notification settings"
5289
5307
msgstr ""
5290
5308
···
5307
5325
#: src/screens/Settings/NotificationSettings/ReplyNotificationSettings.tsx:30
5308
5326
#: src/screens/Settings/NotificationSettings/RepostNotificationSettings.tsx:30
5309
5327
#: src/screens/Settings/NotificationSettings/RepostsOnRepostsNotificationSettings.tsx:30
5310
-
#: src/screens/Settings/Settings.tsx:186
5311
5328
#: src/screens/Settings/Settings.tsx:189
5312
-
#: src/view/screens/Notifications.tsx:128
5329
+
#: src/screens/Settings/Settings.tsx:192
5330
+
#: src/view/screens/Notifications.tsx:130
5313
5331
#: src/view/shell/bottom-bar/BottomBar.tsx:252
5314
5332
#: src/view/shell/desktop/LeftNav.tsx:654
5315
5333
#: src/view/shell/Drawer.tsx:482
···
5361
5379
msgstr ""
5362
5380
5363
5381
#: src/screens/Login/PasswordUpdatedForm.tsx:37
5364
-
#: src/screens/PostThread/components/ThreadItemAnchor.tsx:670
5382
+
#: src/screens/PostThread/components/ThreadItemAnchor.tsx:664
5365
5383
#: src/view/com/post-thread/PostThreadItem.tsx:985
5366
5384
msgid "Okay"
5367
5385
msgstr ""
···
5381
5399
msgid "on<0><1/><2><3/></2></0>"
5382
5400
msgstr ""
5383
5401
5384
-
#: src/screens/Settings/Settings.tsx:367
5402
+
#: src/screens/Settings/Settings.tsx:371
5385
5403
msgid "Onboarding reset"
5386
5404
msgstr ""
5387
5405
···
5473
5491
msgid "Open message options"
5474
5492
msgstr ""
5475
5493
5476
-
#: src/screens/Settings/Settings.tsx:404
5494
+
#: src/screens/Settings/Settings.tsx:408
5477
5495
msgid "Open moderation debug page"
5478
5496
msgstr ""
5479
5497
···
5502
5520
msgid "Open starter pack menu"
5503
5521
msgstr ""
5504
5522
5505
-
#: src/screens/Settings/Settings.tsx:397
5506
-
#: src/screens/Settings/Settings.tsx:411
5523
+
#: src/screens/Settings/Settings.tsx:401
5524
+
#: src/screens/Settings/Settings.tsx:415
5507
5525
msgid "Open storybook page"
5508
5526
msgstr ""
5509
5527
5510
-
#: src/screens/Settings/Settings.tsx:390
5528
+
#: src/screens/Settings/Settings.tsx:394
5511
5529
msgid "Open system log"
5512
5530
msgstr ""
5513
5531
···
5569
5587
msgid "Opens GIF select dialog"
5570
5588
msgstr ""
5571
5589
5572
-
#: src/screens/Settings/Settings.tsx:227
5590
+
#: src/screens/Settings/Settings.tsx:231
5573
5591
msgid "Opens helpdesk in browser"
5592
+
msgstr ""
5593
+
5594
+
#: src/components/dialogs/LinkWarning.tsx:97
5595
+
msgid "Opens link {0}"
5574
5596
msgstr ""
5575
5597
5576
5598
#: src/view/com/modals/InviteCodes.tsx:173
···
5585
5607
msgid "Opens password reset form"
5586
5608
msgstr ""
5587
5609
5588
-
#: src/view/com/modals/LinkWarning.tsx:93
5589
-
msgid "Opens the linked website"
5590
-
msgstr ""
5591
-
5592
5610
#: src/view/com/notifications/NotificationFeedItem.tsx:850
5593
5611
#: src/view/com/util/UserAvatar.tsx:581
5594
5612
msgid "Opens this profile"
···
5607
5625
msgid "Options:"
5608
5626
msgstr ""
5609
5627
5610
-
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:418
5628
+
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:422
5611
5629
msgid "Or combine these options:"
5612
5630
msgstr ""
5613
5631
···
5715
5733
msgid "People following @{0}"
5716
5734
msgstr ""
5717
5735
5718
-
#: src/screens/Settings/NotificationSettings/components/PreferenceControls.tsx:171
5719
-
#: src/screens/Settings/NotificationSettings/components/PreferenceControls.tsx:185
5736
+
#: src/screens/Settings/NotificationSettings/components/PreferenceControls.tsx:178
5737
+
#: src/screens/Settings/NotificationSettings/components/PreferenceControls.tsx:192
5720
5738
msgid "People I follow"
5721
5739
msgstr ""
5722
5740
···
5934
5952
msgid "Porn"
5935
5953
msgstr ""
5936
5954
5937
-
#: src/screens/PostThread/index.tsx:490
5955
+
#: src/screens/PostThread/index.tsx:495
5938
5956
#: src/view/com/post-thread/PostThread.tsx:561
5939
5957
msgctxt "description"
5940
5958
msgid "Post"
···
5995
6013
msgid "Post Hidden by You"
5996
6014
msgstr ""
5997
6015
5998
-
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:100
6016
+
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:104
5999
6017
msgid "Post interaction settings"
6000
6018
msgstr ""
6001
6019
···
6043
6061
msgid "Posts hidden"
6044
6062
msgstr ""
6045
6063
6046
-
#: src/view/com/modals/LinkWarning.tsx:60
6047
-
msgid "Potentially Misleading Link"
6064
+
#: src/components/dialogs/LinkWarning.tsx:73
6065
+
msgid "Potentially misleading link"
6066
+
msgstr ""
6067
+
6068
+
#: src/components/dialogs/LinkWarning.tsx:66
6069
+
msgid "Potentially misleading link warning"
6048
6070
msgstr ""
6049
6071
6050
6072
#: src/screens/Messages/components/MessageListError.tsx:19
···
6082
6104
msgid "Privacy"
6083
6105
msgstr ""
6084
6106
6085
-
#: src/screens/Settings/Settings.tsx:172
6086
-
#: src/screens/Settings/Settings.tsx:175
6107
+
#: src/screens/Settings/Settings.tsx:174
6108
+
#: src/screens/Settings/Settings.tsx:177
6087
6109
msgid "Privacy and security"
6088
6110
msgstr ""
6089
6111
···
6163
6185
msgid "Push"
6164
6186
msgstr ""
6165
6187
6166
-
#: src/screens/Settings/NotificationSettings/components/PreferenceControls.tsx:117
6188
+
#: src/screens/Settings/NotificationSettings/components/PreferenceControls.tsx:122
6167
6189
msgid "Push notifications"
6168
6190
msgstr ""
6169
6191
···
6213
6235
msgid "Quote posts disabled"
6214
6236
msgstr ""
6215
6237
6216
-
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:329
6238
+
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:333
6217
6239
msgid "Quote settings"
6218
6240
msgstr ""
6219
6241
6242
+
#: src/lib/hooks/useNotificationHandler.ts:145
6220
6243
#: src/screens/Post/PostQuotes.tsx:38
6221
-
#: src/screens/Settings/NotificationSettings/index.tsx:148
6244
+
#: src/screens/Settings/NotificationSettings/index.tsx:170
6222
6245
#: src/screens/Settings/NotificationSettings/QuoteNotificationSettings.tsx:41
6223
6246
msgid "Quotes"
6224
6247
msgstr ""
6225
6248
6226
-
#: src/screens/PostThread/components/ThreadItemAnchor.tsx:451
6249
+
#: src/screens/PostThread/components/ThreadItemAnchor.tsx:445
6227
6250
#: src/view/com/post-thread/PostThreadItem.tsx:269
6228
6251
msgid "Quotes of this post"
6229
6252
msgstr ""
···
6296
6319
msgid "Reason:"
6297
6320
msgstr ""
6298
6321
6299
-
#: src/screens/Settings/NotificationSettings/components/PreferenceControls.tsx:123
6322
+
#: src/screens/Settings/NotificationSettings/components/PreferenceControls.tsx:128
6300
6323
msgid "Receive in-app notifications"
6301
6324
msgstr ""
6302
6325
6303
-
#: src/screens/Settings/NotificationSettings/components/PreferenceControls.tsx:106
6326
+
#: src/screens/Settings/NotificationSettings/components/PreferenceControls.tsx:111
6304
6327
msgid "Receive push notifications"
6305
6328
msgstr ""
6306
6329
···
6335
6358
#: src/components/FeedCard.tsx:343
6336
6359
#: src/components/StarterPack/Wizard/WizardListCard.tsx:102
6337
6360
#: src/components/StarterPack/Wizard/WizardListCard.tsx:109
6338
-
#: src/screens/Settings/Settings.tsx:552
6361
+
#: src/screens/Settings/Settings.tsx:556
6339
6362
#: src/view/com/feeds/FeedSourceCard.tsx:322
6340
6363
#: src/view/com/modals/UserAddRemoveLists.tsx:235
6341
6364
#: src/view/com/posts/PostFeedErrorMessage.tsx:213
···
6350
6373
msgid "Remove {historyItem}"
6351
6374
msgstr ""
6352
6375
6353
-
#: src/screens/Settings/Settings.tsx:531
6354
-
#: src/screens/Settings/Settings.tsx:534
6376
+
#: src/screens/Settings/Settings.tsx:535
6377
+
#: src/screens/Settings/Settings.tsx:538
6355
6378
msgid "Remove account"
6356
6379
msgstr ""
6357
6380
···
6392
6415
msgid "Remove from my feeds"
6393
6416
msgstr ""
6394
6417
6395
-
#: src/screens/Settings/Settings.tsx:544
6418
+
#: src/screens/Settings/Settings.tsx:548
6396
6419
msgid "Remove from quick access?"
6397
6420
msgstr ""
6398
6421
···
6487
6510
msgid "Replace with Discover"
6488
6511
msgstr ""
6489
6512
6490
-
#: src/screens/Settings/NotificationSettings/index.tsx:126
6513
+
#: src/lib/hooks/useNotificationHandler.ts:131
6514
+
#: src/screens/Settings/NotificationSettings/index.tsx:148
6491
6515
#: src/screens/Settings/NotificationSettings/ReplyNotificationSettings.tsx:41
6492
6516
#: src/view/screens/Profile.tsx:226
6493
6517
msgid "Replies"
···
6525
6549
msgid "Reply notifications"
6526
6550
msgstr ""
6527
6551
6528
-
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:385
6552
+
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:389
6529
6553
msgid "Reply settings"
6530
6554
msgstr ""
6531
6555
6532
-
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:370
6556
+
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:374
6533
6557
msgid "Reply settings are chosen by the author of the thread"
6534
6558
msgstr ""
6535
6559
···
6701
6725
msgid "Reposted by you"
6702
6726
msgstr ""
6703
6727
6704
-
#: src/screens/Settings/NotificationSettings/index.tsx:170
6728
+
#: src/lib/hooks/useNotificationHandler.ts:124
6729
+
#: src/screens/Settings/NotificationSettings/index.tsx:181
6705
6730
#: src/screens/Settings/NotificationSettings/RepostNotificationSettings.tsx:41
6706
6731
msgid "Reposts"
6707
6732
msgstr ""
6708
6733
6709
-
#: src/screens/PostThread/components/ThreadItemAnchor.tsx:433
6734
+
#: src/screens/PostThread/components/ThreadItemAnchor.tsx:427
6710
6735
#: src/view/com/post-thread/PostThreadItem.tsx:248
6711
6736
msgid "Reposts of this post"
6712
6737
msgstr ""
6713
6738
6739
+
#: src/lib/hooks/useNotificationHandler.ts:166
6714
6740
#: src/screens/Settings/NotificationSettings/index.tsx:223
6715
6741
#: src/screens/Settings/NotificationSettings/RepostsOnRepostsNotificationSettings.tsx:41
6716
6742
msgid "Reposts of your reposts"
···
6768
6794
msgid "Reset Code"
6769
6795
msgstr ""
6770
6796
6771
-
#: src/screens/Settings/Settings.tsx:418
6772
-
#: src/screens/Settings/Settings.tsx:420
6797
+
#: src/screens/Settings/Settings.tsx:422
6798
+
#: src/screens/Settings/Settings.tsx:424
6773
6799
msgid "Reset onboarding state"
6774
6800
msgstr ""
6775
6801
···
6835
6861
msgstr ""
6836
6862
6837
6863
#: src/components/dialogs/BirthDateSettings.tsx:121
6838
-
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:479
6839
-
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:485
6864
+
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:483
6865
+
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:489
6840
6866
#: src/components/live/EditLiveDialog.tsx:216
6841
6867
#: src/components/live/EditLiveDialog.tsx:223
6842
6868
#: src/components/StarterPack/QrCodeDialog.tsx:192
···
7140
7166
msgstr ""
7141
7167
7142
7168
#: src/screens/Onboarding/StepInterests/index.tsx:192
7143
-
#: src/screens/Settings/InterestsSettings.tsx:165
7169
+
#: src/screens/Settings/InterestsSettings.tsx:161
7144
7170
msgid "Select your interests from the options below"
7145
7171
msgstr ""
7146
7172
7147
7173
#: src/screens/Settings/LanguageSettings.tsx:124
7148
7174
msgid "Select your preferred language for translations in your feed."
7175
+
msgstr ""
7176
+
7177
+
#: src/screens/Settings/NotificationSettings/components/PreferenceControls.tsx:106
7178
+
msgid "Select your preferred notification channels"
7149
7179
msgstr ""
7150
7180
7151
7181
#: src/view/com/util/forms/DropdownButton.tsx:297
···
7242
7272
msgstr ""
7243
7273
7244
7274
#: src/Navigation.tsx:195
7245
-
#: src/screens/Settings/Settings.tsx:91
7275
+
#: src/screens/Settings/Settings.tsx:93
7246
7276
#: src/view/shell/desktop/LeftNav.tsx:727
7247
7277
#: src/view/shell/Drawer.tsx:572
7248
7278
msgid "Settings"
7249
7279
msgstr ""
7250
7280
7251
-
#: src/screens/Settings/NotificationSettings/index.tsx:154
7281
+
#: src/screens/Settings/NotificationSettings/index.tsx:121
7252
7282
msgid "Settings for like notifications"
7253
7283
msgstr ""
7254
7284
7255
-
#: src/screens/Settings/NotificationSettings/index.tsx:132
7285
+
#: src/screens/Settings/NotificationSettings/index.tsx:154
7256
7286
msgid "Settings for mention notifications"
7257
7287
msgstr ""
7258
7288
7259
-
#: src/screens/Settings/NotificationSettings/index.tsx:176
7289
+
#: src/screens/Settings/NotificationSettings/index.tsx:132
7260
7290
msgid "Settings for new follower notifications"
7261
7291
msgstr ""
7262
7292
···
7272
7302
msgid "Settings for notifications for reposts of your reposts"
7273
7303
msgstr ""
7274
7304
7275
-
#: src/screens/Settings/NotificationSettings/index.tsx:143
7305
+
#: src/screens/Settings/NotificationSettings/index.tsx:165
7276
7306
msgid "Settings for quote notifications"
7277
7307
msgstr ""
7278
7308
7279
-
#: src/screens/Settings/NotificationSettings/index.tsx:121
7309
+
#: src/screens/Settings/NotificationSettings/index.tsx:143
7280
7310
msgid "Settings for reply notifications"
7281
7311
msgstr ""
7282
7312
7283
-
#: src/screens/Settings/NotificationSettings/index.tsx:165
7313
+
#: src/screens/Settings/NotificationSettings/index.tsx:176
7284
7314
msgid "Settings for repost notifications"
7285
7315
msgstr ""
7286
7316
···
7327
7357
msgid "Share author DID"
7328
7358
msgstr ""
7329
7359
7360
+
#: src/components/dialogs/LinkWarning.tsx:96
7361
+
#: src/components/dialogs/LinkWarning.tsx:104
7330
7362
#: src/components/StarterPack/ShareDialog.tsx:104
7331
7363
#: src/components/StarterPack/ShareDialog.tsx:111
7332
7364
msgid "Share link"
7333
7365
msgstr ""
7334
7366
7335
-
#: src/view/com/modals/LinkWarning.tsx:89
7336
-
#: src/view/com/modals/LinkWarning.tsx:95
7337
-
msgid "Share Link"
7338
-
msgstr ""
7339
-
7340
7367
#: src/components/StarterPack/ShareDialog.tsx:68
7341
7368
msgid "Share link dialog"
7342
7369
msgstr ""
···
7380
7407
msgid "Shared Preferences Tester"
7381
7408
msgstr ""
7382
7409
7383
-
#: src/view/com/modals/LinkWarning.tsx:92
7384
-
msgid "Shares the linked website"
7385
-
msgstr ""
7386
-
7387
7410
#: src/components/moderation/ContentHider.tsx:200
7388
7411
#: src/components/moderation/LabelPreference.tsx:137
7389
7412
#: src/components/moderation/PostHider.tsx:134
···
7496
7519
msgid "Show warning and filter from feeds"
7497
7520
msgstr ""
7498
7521
7499
-
#: src/screens/PostThread/components/ThreadItemAnchor.tsx:611
7522
+
#: src/screens/PostThread/components/ThreadItemAnchor.tsx:605
7500
7523
#: src/view/com/post-thread/PostThreadItem.tsx:926
7501
7524
msgid "Shows information about when this post was created"
7502
7525
msgstr ""
7503
7526
7504
-
#: src/screens/Settings/Settings.tsx:115
7527
+
#: src/screens/Settings/Settings.tsx:117
7505
7528
msgid "Shows other accounts you can switch to"
7506
7529
msgstr ""
7507
7530
···
7558
7581
msgid "Sign in to view post"
7559
7582
msgstr ""
7560
7583
7561
-
#: src/screens/Settings/Settings.tsx:244
7562
-
#: src/screens/Settings/Settings.tsx:246
7563
-
#: src/screens/Settings/Settings.tsx:278
7584
+
#: src/screens/Settings/Settings.tsx:248
7585
+
#: src/screens/Settings/Settings.tsx:250
7586
+
#: src/screens/Settings/Settings.tsx:282
7564
7587
#: src/screens/SignupQueued.tsx:93
7565
7588
#: src/screens/SignupQueued.tsx:96
7566
7589
#: src/screens/Takendown.tsx:85
···
7574
7597
msgid "Sign Out"
7575
7598
msgstr ""
7576
7599
7577
-
#: src/screens/Settings/Settings.tsx:275
7600
+
#: src/screens/Settings/Settings.tsx:279
7578
7601
#: src/view/shell/desktop/LeftNav.tsx:209
7579
7602
msgid "Sign out?"
7580
7603
msgstr ""
···
7777
7800
msgid "Step {0} of {1}"
7778
7801
msgstr ""
7779
7802
7780
-
#: src/screens/Settings/Settings.tsx:372
7803
+
#: src/screens/Settings/Settings.tsx:376
7781
7804
msgid "Storage cleared, you need to restart the app now."
7782
7805
msgstr ""
7783
7806
7784
7807
#: src/Navigation.tsx:288
7785
-
#: src/screens/Settings/Settings.tsx:399
7808
+
#: src/screens/Settings/Settings.tsx:403
7786
7809
msgid "Storybook"
7787
7810
msgstr ""
7788
7811
···
7864
7887
msgid "Support"
7865
7888
msgstr ""
7866
7889
7867
-
#: src/screens/Settings/Settings.tsx:113
7868
-
#: src/screens/Settings/Settings.tsx:127
7869
-
#: src/screens/Settings/Settings.tsx:494
7890
+
#: src/screens/Settings/Settings.tsx:115
7891
+
#: src/screens/Settings/Settings.tsx:129
7892
+
#: src/screens/Settings/Settings.tsx:498
7870
7893
#: src/view/shell/desktop/LeftNav.tsx:246
7871
7894
msgid "Switch account"
7872
7895
msgstr ""
···
7893
7916
7894
7917
#: src/screens/Settings/AboutSettings.tsx:107
7895
7918
#: src/screens/Settings/AboutSettings.tsx:110
7896
-
#: src/screens/Settings/Settings.tsx:392
7919
+
#: src/screens/Settings/Settings.tsx:396
7897
7920
msgid "System log"
7898
7921
msgstr ""
7899
7922
···
8195
8218
msgid "There was an issue! {0}"
8196
8219
msgstr ""
8197
8220
8198
-
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:217
8221
+
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:221
8199
8222
#: src/screens/List/ListHiddenScreen.tsx:63
8200
8223
#: src/screens/List/ListHiddenScreen.tsx:77
8201
8224
#: src/screens/List/ListHiddenScreen.tsx:99
···
8339
8362
msgid "This labeler hasn't declared what labels it publishes, and may not be active."
8340
8363
msgstr ""
8341
8364
8342
-
#: src/view/com/modals/LinkWarning.tsx:72
8365
+
#: src/components/dialogs/LinkWarning.tsx:79
8343
8366
msgid "This link is taking you to the following website:"
8344
8367
msgstr ""
8345
8368
···
8359
8382
msgid "This moderation service is unavailable. See below for more details. If this issue persists, contact us."
8360
8383
msgstr ""
8361
8384
8362
-
#: src/screens/PostThread/components/ThreadItemAnchor.tsx:651
8385
+
#: src/screens/PostThread/components/ThreadItemAnchor.tsx:645
8363
8386
#: src/view/com/post-thread/PostThreadItem.tsx:966
8364
8387
msgid "This post claims to have been created on <0>{0}</0>, but was first seen by Bluesky on <1>{1}</1>."
8365
8388
msgstr ""
···
8441
8464
msgid "This will delete \"{0}\" from your muted words. You can always add it back later."
8442
8465
msgstr ""
8443
8466
8444
-
#: src/screens/Settings/Settings.tsx:546
8467
+
#: src/screens/Settings/Settings.tsx:550
8445
8468
msgid "This will remove @{0} from the quick access list."
8446
8469
msgstr ""
8447
8470
···
8539
8562
#: src/components/dms/MessageContextMenu.tsx:145
8540
8563
#: src/components/PostControls/PostMenu/PostMenuItems.tsx:444
8541
8564
#: src/components/PostControls/PostMenu/PostMenuItems.tsx:446
8542
-
#: src/screens/PostThread/components/ThreadItemAnchor.tsx:573
8543
-
#: src/screens/PostThread/components/ThreadItemAnchor.tsx:576
8565
+
#: src/screens/PostThread/components/ThreadItemAnchor.tsx:567
8566
+
#: src/screens/PostThread/components/ThreadItemAnchor.tsx:570
8544
8567
#: src/view/com/post-thread/PostThreadItem.tsx:888
8545
8568
#: src/view/com/post-thread/PostThreadItem.tsx:891
8546
8569
msgid "Translate"
···
8758
8781
msgid "Unpinned from your feeds"
8759
8782
msgstr ""
8760
8783
8761
-
#: src/screens/Settings/Settings.tsx:425
8762
-
#: src/screens/Settings/Settings.tsx:427
8784
+
#: src/screens/Settings/Settings.tsx:429
8785
+
#: src/screens/Settings/Settings.tsx:431
8763
8786
msgid "Unsnooze email reminder"
8764
8787
msgstr ""
8765
8788
···
8974
8997
msgid "Users I follow"
8975
8998
msgstr ""
8976
8999
8977
-
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:456
9000
+
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:460
8978
9001
msgid "Users in \"{0}\""
8979
9002
msgstr ""
8980
9003
8981
-
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:433
9004
+
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:437
8982
9005
msgid "Users you follow"
8983
9006
msgstr ""
8984
9007
···
9225
9248
msgid "Views video in immersive mode"
9226
9249
msgstr ""
9227
9250
9228
-
#: src/view/com/modals/LinkWarning.tsx:89
9229
-
#: src/view/com/modals/LinkWarning.tsx:95
9230
-
msgid "Visit Site"
9251
+
#: src/components/dialogs/LinkWarning.tsx:96
9252
+
#: src/components/dialogs/LinkWarning.tsx:106
9253
+
msgid "Visit site"
9254
+
msgstr ""
9255
+
9256
+
#: src/view/screens/Notifications.tsx:303
9257
+
msgid "Visit your notification settings"
9231
9258
msgstr ""
9232
9259
9233
9260
#: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VolumeControl.tsx:81
···
9281
9308
msgid "We ran out of posts from your follows. Here's the latest from <0/>."
9282
9309
msgstr ""
9283
9310
9284
-
#: src/screens/Settings/InterestsSettings.tsx:158
9311
+
#: src/screens/Settings/InterestsSettings.tsx:154
9285
9312
msgid "We recommend selecting at least two interests."
9286
9313
msgstr ""
9287
9314
···
9573
9600
msgid "You can also temporarily deactivate your account instead, and reactivate it at any time."
9574
9601
msgstr ""
9575
9602
9603
+
#: src/lib/hooks/useNotificationHandler.ts:92
9604
+
msgid "You can choose whether chat notifications have sound in the chat settings within the app"
9605
+
msgstr ""
9606
+
9576
9607
#: src/screens/Messages/Settings.tsx:111
9577
9608
msgid "You can continue ongoing conversations regardless of which setting you choose."
9578
9609
msgstr ""
···
9586
9617
msgid "You can reactivate your account to continue logging in. Your profile and posts will be visible to other users."
9587
9618
msgstr ""
9588
9619
9589
-
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:81
9620
+
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:85
9590
9621
msgid "You can set default interaction settings in <0>Settings → Moderation → Interaction settings</0>."
9591
9622
msgstr ""
9592
9623
···
9634
9665
msgid "You have blocked this user. You cannot view their content."
9635
9666
msgstr ""
9636
9667
9668
+
#: src/view/screens/Notifications.tsx:298
9669
+
msgid "You have completely disabled reply, quote, and mention notifications, so this tab will no longer update. To adjust this, visit your <0>notification settings</0>."
9670
+
msgstr ""
9671
+
9637
9672
#: src/screens/Login/SetNewPasswordForm.tsx:49
9638
9673
#: src/screens/Login/SetNewPasswordForm.tsx:95
9639
9674
#: src/view/com/modals/ChangePassword.tsx:87
···
9753
9788
msgid "You previously deactivated @{0}."
9754
9789
msgstr ""
9755
9790
9756
-
#: src/screens/Settings/Settings.tsx:383
9791
+
#: src/screens/Settings/Settings.tsx:387
9757
9792
msgid "You probably want to restart the app now."
9758
9793
msgstr ""
9759
9794
···
9765
9800
msgid "You reacted {0} to {1}"
9766
9801
msgstr ""
9767
9802
9768
-
#: src/screens/Settings/Settings.tsx:276
9803
+
#: src/screens/Settings/Settings.tsx:280
9769
9804
#: src/view/shell/desktop/LeftNav.tsx:210
9770
9805
msgid "You will be signed out of all your accounts."
9771
9806
msgstr ""
···
9919
9954
msgid "Your first like!"
9920
9955
msgstr ""
9921
9956
9922
-
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:443
9957
+
#: src/components/dialogs/PostInteractionSettingsDialog.tsx:447
9923
9958
msgid "Your followers"
9924
9959
msgstr ""
9925
9960
···
9943
9978
msgid "Your interests"
9944
9979
msgstr ""
9945
9980
9946
-
#: src/screens/Settings/InterestsSettings.tsx:127
9981
+
#: src/screens/Settings/InterestsSettings.tsx:123
9947
9982
msgctxt "toast"
9948
9983
msgid "Your interests have been updated!"
9949
9984
msgstr ""
+5
-3
src/logger/__tests__/logger.test.ts
+5
-3
src/logger/__tests__/logger.test.ts
···
110
110
const timestamp = Date.now()
111
111
const sentryTimestamp = timestamp / 1000
112
112
113
+
/*
113
114
sentryTransport(
114
115
LogLevel.Debug,
115
116
Logger.Context.Default,
···
125
126
level: LogLevel.Debug,
126
127
timestamp: sentryTimestamp,
127
128
})
129
+
*/
128
130
129
131
sentryTransport(
130
132
LogLevel.Info,
···
154
156
message,
155
157
data: {__context__: 'logger'},
156
158
type: 'default',
157
-
level: 'debug', // Sentry bug, log becomes debug
159
+
level: 'log',
158
160
timestamp: sentryTimestamp,
159
161
})
160
162
jest.runAllTimers()
···
220
222
const sentryTimestamp = timestamp / 1000
221
223
222
224
sentryTransport(
223
-
LogLevel.Debug,
225
+
LogLevel.Info,
224
226
undefined,
225
227
message,
226
228
{error: new Error('foo')},
···
230
232
message,
231
233
data: {error: 'Error: foo'},
232
234
type: 'default',
233
-
level: LogLevel.Debug,
235
+
level: LogLevel.Info,
234
236
timestamp: sentryTimestamp,
235
237
})
236
238
})
+4
-1
src/logger/transports/sentry.ts
+4
-1
src/logger/transports/sentry.ts
···
1
1
import {isNetworkError} from '#/lib/strings/errors'
2
2
import {Sentry} from '#/logger/sentry/lib'
3
-
import {LogLevel, Transport} from '#/logger/types'
3
+
import {LogLevel, type Transport} from '#/logger/types'
4
4
import {prepareMetadata} from '#/logger/util'
5
5
6
6
export const sentryTransport: Transport = (
···
10
10
{type, tags, ...metadata},
11
11
timestamp,
12
12
) => {
13
+
// Skip debug messages entirely for now - esb
14
+
if (level === LogLevel.Debug) return
15
+
13
16
const meta = {
14
17
__context__: context,
15
18
...prepareMetadata(metadata),
+44
-52
src/screens/PostThread/components/ThreadItemAnchor.tsx
+44
-52
src/screens/PostThread/components/ThreadItemAnchor.tsx
···
311
311
isRoot && [a.pt_lg],
312
312
]}>
313
313
<View style={[a.flex_row, a.gap_md, a.pb_md]}>
314
-
<PreviewableUserAvatar
315
-
size={42}
316
-
profile={post.author}
317
-
moderation={moderation.ui('avatar')}
318
-
type={post.author.associated?.labeler ? 'labeler' : 'user'}
319
-
live={live}
320
-
onBeforePress={onOpenAuthor}
321
-
/>
322
-
<View style={[a.flex_1, a.align_start]}>
323
-
<ProfileHoverCard did={post.author.did}>
324
-
<View style={[a.flex_1]}>
314
+
<View collapsable={false}>
315
+
<PreviewableUserAvatar
316
+
size={42}
317
+
profile={post.author}
318
+
moderation={moderation.ui('avatar')}
319
+
type={post.author.associated?.labeler ? 'labeler' : 'user'}
320
+
live={live}
321
+
onBeforePress={onOpenAuthor}
322
+
/>
323
+
</View>
324
+
<Link
325
+
to={authorHref}
326
+
style={[a.flex_1]}
327
+
label={sanitizeDisplayName(
328
+
post.author.displayName || sanitizeHandle(post.author.handle),
329
+
moderation.ui('displayName'),
330
+
)}
331
+
onPress={onOpenAuthor}>
332
+
<View style={[a.flex_1, a.align_start]}>
333
+
<ProfileHoverCard did={post.author.did} style={[a.w_full]}>
325
334
<View style={[a.flex_row, a.align_center]}>
326
-
<Link
327
-
to={authorHref}
328
-
style={[a.flex_shrink]}
329
-
label={sanitizeDisplayName(
335
+
<Text
336
+
emoji
337
+
style={[
338
+
a.flex_shrink,
339
+
a.text_lg,
340
+
a.font_bold,
341
+
a.leading_snug,
342
+
]}
343
+
numberOfLines={1}>
344
+
{sanitizeDisplayName(
330
345
post.author.displayName ||
331
346
sanitizeHandle(post.author.handle),
332
347
moderation.ui('displayName'),
333
348
)}
334
-
onPress={onOpenAuthor}>
335
-
<Text
336
-
emoji
337
-
style={[
338
-
a.text_lg,
339
-
a.font_bold,
340
-
a.leading_snug,
341
-
a.self_start,
342
-
]}
343
-
numberOfLines={1}>
344
-
{sanitizeDisplayName(
345
-
post.author.displayName ||
346
-
sanitizeHandle(post.author.handle),
347
-
moderation.ui('displayName'),
348
-
)}
349
-
</Text>
350
-
</Link>
349
+
</Text>
351
350
352
351
<View style={[{paddingLeft: 3, top: -1}]}>
353
352
<VerificationCheckButton profile={authorShadow} size="md" />
354
353
</View>
355
354
</View>
356
-
<View style={[a.align_start]}>
357
-
<Link
358
-
style={[a.flex_shrink]}
359
-
to={authorHref}
360
-
label={sanitizeHandle(post.author.handle, '@')}>
361
-
<Text
362
-
style={[
363
-
a.text_md,
364
-
a.leading_snug,
365
-
t.atoms.text_contrast_medium,
366
-
]}
367
-
numberOfLines={1}>
368
-
{sanitizeHandle(post.author.handle, '@')}
369
-
</Text>
370
-
</Link>
371
-
</View>
372
-
</View>
373
-
</ProfileHoverCard>
374
-
</View>
355
+
<Text
356
+
style={[
357
+
a.text_md,
358
+
a.leading_snug,
359
+
t.atoms.text_contrast_medium,
360
+
]}
361
+
numberOfLines={1}>
362
+
{sanitizeHandle(post.author.handle, '@')}
363
+
</Text>
364
+
</ProfileHoverCard>
365
+
</View>
366
+
</Link>
375
367
{showFollowButton && (
376
-
<View>
368
+
<View collapsable={false}>
377
369
<PostThreadFollowBtn did={post.author.did} />
378
370
</View>
379
371
)}
+12
-5
src/screens/PostThread/index.tsx
+12
-5
src/screens/PostThread/index.tsx
···
54
54
* One query to rule them all
55
55
*/
56
56
const thread = usePostThread({anchor: uri})
57
-
const anchor = useMemo(() => {
57
+
const {anchor, hasParents} = useMemo(() => {
58
+
// eslint-disable-next-line @typescript-eslint/no-shadow
59
+
let hasParents = false
58
60
for (const item of thread.data.items) {
59
61
if (item.type === 'threadPost' && item.depth === 0) {
60
-
return item
62
+
return {anchor: item, hasParents}
61
63
}
64
+
hasParents = true
62
65
}
63
-
return
66
+
return {hasParents}
64
67
}, [thread.data.items])
65
68
66
69
const {openComposer} = useOpenComposer()
···
481
484
],
482
485
)
483
486
487
+
const defaultListFooterHeight = hasParents ? windowHeight - 200 : undefined
488
+
484
489
return (
485
490
<>
486
491
<Layout.Header.Outer headerRef={headerRef}>
···
537
542
* back to the top of the screen when handling scroll.
538
543
*/
539
544
height={platform({
540
-
web: windowHeight - 200,
541
-
default: deferParents ? windowHeight * 2 : windowHeight - 200,
545
+
web: defaultListFooterHeight,
546
+
default: deferParents
547
+
? windowHeight * 2
548
+
: defaultListFooterHeight,
542
549
})}
543
550
style={isTombstoneView ? {borderTopWidth: 0} : undefined}
544
551
/>
+1
-5
src/screens/Settings/NotificationSettings/ReplyNotificationSettings.tsx
+1
-5
src/screens/Settings/NotificationSettings/ReplyNotificationSettings.tsx
···
53
53
</Admonition>
54
54
</View>
55
55
) : (
56
-
<PreferenceControls
57
-
name="reply"
58
-
preference={preferences?.reply}
59
-
allowDisableInApp={false}
60
-
/>
56
+
<PreferenceControls name="reply" preference={preferences?.reply} />
61
57
)}
62
58
</SettingsList.Container>
63
59
</Layout.Content>
+5
src/screens/Settings/NotificationSettings/components/PreferenceControls.tsx
+5
src/screens/Settings/NotificationSettings/components/PreferenceControls.tsx
···
5
5
import {msg, Trans} from '@lingui/macro'
6
6
import {useLingui} from '@lingui/react'
7
7
8
+
import {useGate} from '#/lib/statsig/statsig'
8
9
import {useNotificationSettingsUpdateMutation} from '#/state/queries/notifications/settings'
9
10
import {atoms as a, platform, useTheme} from '#/alf'
10
11
import * as Toggle from '#/components/forms/Toggle'
···
27
28
preference?: AppBskyNotificationDefs.Preference | FilterablePreference
28
29
allowDisableInApp?: boolean
29
30
}) {
31
+
const gate = useGate()
32
+
33
+
if (!gate('reengagement_features')) return null
34
+
30
35
if (!preference)
31
36
return (
32
37
<View style={[a.w_full, a.pt_5xl, a.align_center]}>
+12
-8
src/screens/Settings/Settings.tsx
+12
-8
src/screens/Settings/Settings.tsx
···
16
16
type CommonNavigatorParams,
17
17
type NavigationProp,
18
18
} from '#/lib/routes/types'
19
+
import {useGate} from '#/lib/statsig/statsig'
19
20
import {sanitizeDisplayName} from '#/lib/strings/display-names'
20
21
import {sanitizeHandle} from '#/lib/strings/handles'
21
22
import {useProfileShadow} from '#/state/cache/profile-shadow'
···
82
83
const {pendingDid, onPressSwitchAccount} = useAccountSwitcher()
83
84
const [showAccounts, setShowAccounts] = useState(false)
84
85
const [showDevOptions, setShowDevOptions] = useState(false)
86
+
const gate = useGate()
85
87
86
88
return (
87
89
<Layout.Screen>
···
182
184
<Trans>Moderation</Trans>
183
185
</SettingsList.ItemText>
184
186
</SettingsList.LinkItem>
185
-
<SettingsList.LinkItem
186
-
to="/settings/notifications"
187
-
label={_(msg`Notifications`)}>
188
-
<SettingsList.ItemIcon icon={NotificationIcon} />
189
-
<SettingsList.ItemText>
190
-
<Trans>Notifications</Trans>
191
-
</SettingsList.ItemText>
192
-
</SettingsList.LinkItem>
187
+
{gate('reengagement_features') && (
188
+
<SettingsList.LinkItem
189
+
to="/settings/notifications"
190
+
label={_(msg`Notifications`)}>
191
+
<SettingsList.ItemIcon icon={NotificationIcon} />
192
+
<SettingsList.ItemText>
193
+
<Trans>Notifications</Trans>
194
+
</SettingsList.ItemText>
195
+
</SettingsList.LinkItem>
196
+
)}
193
197
<SettingsList.LinkItem
194
198
to="/settings/content-and-media"
195
199
label={_(msg`Content and media`)}>
+44
-30
src/state/messages/convo/agent.ts
+44
-30
src/state/messages/convo/agent.ts
···
10
10
import {nanoid} from 'nanoid/non-secure'
11
11
12
12
import {networkRetry} from '#/lib/async/retry'
13
+
import {isNetworkError} from '#/lib/strings/errors'
13
14
import {Logger} from '#/logger'
14
15
import {isNative} from '#/platform/detection'
15
16
import {
···
130
131
131
132
getSnapshot(): ConvoState {
132
133
if (!this.snapshot) this.snapshot = this.generateSnapshot()
133
-
// logger.debug('Convo: snapshotted', {})
134
+
// logger.debug('snapshotted', {})
134
135
return this.snapshot
135
136
}
136
137
···
392
393
break
393
394
}
394
395
395
-
logger.debug(`Convo: dispatch '${action.event}'`, {
396
+
logger.debug(`dispatch '${action.event}'`, {
396
397
id: this.id,
397
398
prev: prevStatus,
398
399
next: this.status,
···
467
468
* Some validation prior to `Ready` status
468
469
*/
469
470
if (!this.convo) {
470
-
throw new Error('Convo: could not find convo')
471
+
throw new Error('could not find convo')
471
472
}
472
473
if (!this.sender) {
473
-
throw new Error('Convo: could not find sender in convo')
474
+
throw new Error('could not find sender in convo')
474
475
}
475
476
if (!this.recipients) {
476
-
throw new Error('Convo: could not find recipients in convo')
477
+
throw new Error('could not find recipients in convo')
477
478
}
478
479
479
480
const userIsDisabled = Boolean(this.sender.chatDisabled)
···
484
485
this.dispatch({event: ConvoDispatchEvent.Ready})
485
486
}
486
487
} catch (e: any) {
487
-
logger.error(e, {message: 'Convo: setup failed'})
488
+
if (!isNetworkError(e)) {
489
+
logger.error('setup failed', {
490
+
safeMessage: e.message,
491
+
})
492
+
}
488
493
489
494
this.dispatch({
490
495
event: ConvoDispatchEvent.Error,
···
589
594
this.sender = sender || this.sender
590
595
this.recipients = recipients || this.recipients
591
596
} catch (e: any) {
592
-
logger.error(e, {message: `Convo: failed to refresh convo`})
597
+
if (!isNetworkError(e)) {
598
+
logger.error(`failed to refresh convo`, {
599
+
safeMessage: e.message,
600
+
})
601
+
}
593
602
}
594
603
}
595
604
···
599
608
}
600
609
| undefined
601
610
async fetchMessageHistory() {
602
-
logger.debug('Convo: fetch message history', {})
611
+
logger.debug('fetch message history', {})
603
612
604
613
/*
605
614
* If oldestRev is null, we've fetched all history.
···
653
662
}
654
663
}
655
664
} catch (e: any) {
656
-
logger.error('Convo: failed to fetch message history')
665
+
if (!isNetworkError(e)) {
666
+
logger.error('failed to fetch message history', {
667
+
safeMessage: e.message,
668
+
})
669
+
}
657
670
658
671
this.fetchMessageHistoryError = {
659
672
retry: () => {
···
802
815
// Ignore empty messages for now since they have no other purpose atm
803
816
if (!message.text.trim() && !message.embed) return
804
817
805
-
logger.debug('Convo: send message', {})
818
+
logger.debug('send message', {})
806
819
807
820
const tempId = nanoid()
808
821
···
836
849
837
850
async processPendingMessages() {
838
851
logger.debug(
839
-
`Convo: processing messages (${this.pendingMessages.size} remaining)`,
852
+
`processing messages (${this.pendingMessages.size} remaining)`,
840
853
{},
841
854
)
842
855
···
881
894
// continue queue processing
882
895
await this.processPendingMessages()
883
896
} catch (e: any) {
884
-
logger.error(e, {message: `Convo: failed to send message`})
885
897
this.handleSendMessageFailure(e)
886
898
this.isProcessingPendingMessages = false
887
899
}
···
914
926
case 'recipient has disabled incoming messages':
915
927
break
916
928
default:
917
-
logger.warn(
918
-
`Convo handleSendMessageFailure could not handle error`,
919
-
{
929
+
if (!isNetworkError(e)) {
930
+
logger.warn(`handleSendMessageFailure could not handle error`, {
920
931
status: e.status,
921
932
message: e.message,
922
-
},
923
-
)
933
+
})
934
+
}
924
935
break
925
936
}
926
937
}
927
938
} else {
928
939
this.pendingMessageFailure = 'unrecoverable'
929
-
logger.error(e, {
930
-
message: `Convo handleSendMessageFailure received unknown error`,
931
-
})
940
+
941
+
if (!isNetworkError(e)) {
942
+
logger.error(`handleSendMessageFailure received unknown error`, {
943
+
safeMessage: e.message,
944
+
})
945
+
}
932
946
}
933
947
934
948
this.commit()
···
944
958
this.commit()
945
959
946
960
logger.debug(
947
-
`Convo: batch retrying ${this.pendingMessages.size} pending messages`,
961
+
`batch retrying ${this.pendingMessages.size} pending messages`,
948
962
{},
949
963
)
950
964
···
977
991
978
992
this.commit()
979
993
980
-
logger.debug(
981
-
`Convo: sent ${this.pendingMessages.size} pending messages`,
982
-
{},
983
-
)
994
+
logger.debug(`sent ${this.pendingMessages.size} pending messages`, {})
984
995
} catch (e: any) {
985
-
logger.error(e, {message: `Convo: failed to batch retry messages`})
986
996
this.handleSendMessageFailure(e)
987
997
}
988
998
}
989
999
990
1000
async deleteMessage(messageId: string) {
991
-
logger.debug('Convo: delete message', {})
1001
+
logger.debug('delete message', {})
992
1002
993
1003
this.deletedMessages.add(messageId)
994
1004
this.commit()
···
1004
1014
)
1005
1015
})
1006
1016
} catch (e: any) {
1007
-
logger.error(e, {message: `Convo: failed to delete message`})
1017
+
if (!isNetworkError(e)) {
1018
+
logger.error(`failed to delete message`, {
1019
+
safeMessage: e.message,
1020
+
})
1021
+
}
1008
1022
this.deletedMessages.delete(messageId)
1009
1023
this.commit()
1010
1024
throw e
···
1232
1246
}
1233
1247
1234
1248
try {
1235
-
logger.info(`Adding reaction ${emoji} to message ${messageId}`)
1249
+
logger.debug(`Adding reaction ${emoji} to message ${messageId}`)
1236
1250
const {data} = await this.agent.chat.bsky.convo.addReaction(
1237
1251
{messageId, value: emoji, convoId: this.convoId},
1238
1252
{encoding: 'application/json', headers: DM_SERVICE_HEADERS},
···
1297
1311
}
1298
1312
1299
1313
try {
1300
-
logger.info(`Removing reaction ${emoji} from message ${messageId}`)
1314
+
logger.debug(`Removing reaction ${emoji} from message ${messageId}`)
1301
1315
await this.agent.chat.bsky.convo.removeReaction(
1302
1316
{messageId, value: emoji, convoId: this.convoId},
1303
1317
{encoding: 'application/json', headers: DM_SERVICE_HEADERS},
+18
-18
src/state/messages/events/agent.ts
+18
-18
src/state/messages/events/agent.ts
···
3
3
import {nanoid} from 'nanoid/non-secure'
4
4
5
5
import {networkRetry} from '#/lib/async/retry'
6
+
import {isNetworkError} from '#/lib/strings/errors'
6
7
import {Logger} from '#/logger'
7
8
import {
8
9
BACKGROUND_POLL_INTERVAL,
···
18
19
} from '#/state/messages/events/types'
19
20
import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const'
20
21
21
-
const LOGGER_CONTEXT = 'MessagesEventBus'
22
22
const logger = Logger.create(Logger.Context.DMsAgent)
23
23
24
24
export class MessagesEventBus {
···
91
91
}
92
92
93
93
background() {
94
-
logger.debug(`${LOGGER_CONTEXT}: background`, {})
94
+
logger.debug(`background`, {})
95
95
this.dispatch({event: MessagesEventBusDispatchEvent.Background})
96
96
}
97
97
98
98
suspend() {
99
-
logger.debug(`${LOGGER_CONTEXT}: suspend`, {})
99
+
logger.debug(`suspend`, {})
100
100
this.dispatch({event: MessagesEventBusDispatchEvent.Suspend})
101
101
}
102
102
103
103
resume() {
104
-
logger.debug(`${LOGGER_CONTEXT}: resume`, {})
104
+
logger.debug(`resume`, {})
105
105
this.dispatch({event: MessagesEventBusDispatchEvent.Resume})
106
106
}
107
107
···
228
228
break
229
229
}
230
230
231
-
logger.debug(`${LOGGER_CONTEXT}: dispatch '${action.event}'`, {
231
+
logger.debug(`dispatch '${action.event}'`, {
232
232
id: this.id,
233
233
prev: prevStatus,
234
234
next: this.status,
···
236
236
}
237
237
238
238
private async init() {
239
-
logger.debug(`${LOGGER_CONTEXT}: init`, {})
239
+
logger.debug(`init`, {})
240
240
241
241
try {
242
242
const response = await networkRetry(2, () => {
···
260
260
261
261
this.dispatch({event: MessagesEventBusDispatchEvent.Ready})
262
262
} catch (e: any) {
263
-
logger.error(e, {
264
-
message: `${LOGGER_CONTEXT}: init failed`,
265
-
})
263
+
if (!isNetworkError(e)) {
264
+
logger.error(`init failed`, {
265
+
safeMessage: e.message,
266
+
})
267
+
}
266
268
267
269
this.dispatch({
268
270
event: MessagesEventBusDispatchEvent.Error,
···
324
326
this.isPolling = true
325
327
326
328
// logger.debug(
327
-
// `${LOGGER_CONTEXT}: poll`,
329
+
// `poll`,
328
330
// {
329
331
// requestedPollIntervals: Array.from(
330
332
// this.requestedPollIntervals.values(),
···
370
372
}
371
373
372
374
if (needsEmit) {
373
-
try {
374
-
this.emitter.emit('event', {type: 'logs', logs: batch})
375
-
} catch (e: any) {
376
-
logger.error(e, {
377
-
message: `${LOGGER_CONTEXT}: process latest events`,
378
-
})
379
-
}
375
+
this.emitter.emit('event', {type: 'logs', logs: batch})
380
376
}
381
377
} catch (e: any) {
382
-
logger.error(e, {message: `${LOGGER_CONTEXT}: poll events failed`})
378
+
if (!isNetworkError(e)) {
379
+
logger.error(`poll events failed`, {
380
+
safeMessage: e.message,
381
+
})
382
+
}
383
383
384
384
this.dispatch({
385
385
event: MessagesEventBusDispatchEvent.Error,
+4
-1
src/state/queries/notifications/settings.ts
+4
-1
src/state/queries/notifications/settings.ts
···
14
14
const RQKEY_ROOT = 'notification-settings'
15
15
const RQKEY = [RQKEY_ROOT]
16
16
17
-
export function useNotificationSettingsQuery() {
17
+
export function useNotificationSettingsQuery({
18
+
enabled,
19
+
}: {enabled?: boolean} = {}) {
18
20
const agent = useAgent()
19
21
20
22
return useQuery({
···
23
25
const response = await agent.app.bsky.notification.getPreferences()
24
26
return response.data.preferences
25
27
},
28
+
enabled,
26
29
})
27
30
}
28
31
export function useNotificationSettingsUpdateMutation() {
+3
-3
src/state/queries/postgate/index.ts
+3
-3
src/state/queries/postgate/index.ts
···
2
2
import {
3
3
AppBskyEmbedRecord,
4
4
AppBskyEmbedRecordWithMedia,
5
-
AppBskyFeedDefs,
5
+
type AppBskyFeedDefs,
6
6
AppBskyFeedPostgate,
7
7
AtUri,
8
-
BskyAgent,
8
+
type BskyAgent,
9
9
} from '@atproto/api'
10
10
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'
11
11
···
139
139
staleTime: STALE.SECONDS.THIRTY,
140
140
queryKey: createPostgateQueryKey(postUri),
141
141
async queryFn() {
142
-
return (await getPostgateRecord({agent, postUri})) ?? null
142
+
return await getPostgateRecord({agent, postUri}).then(res => res ?? null)
143
143
},
144
144
})
145
145
}
+2
-2
src/view/com/notifications/NotificationFeed.tsx
+2
-2
src/view/com/notifications/NotificationFeed.tsx
···
16
16
import {useNotificationFeedQuery} from '#/state/queries/notifications/feed'
17
17
import {EmptyState} from '#/view/com/util/EmptyState'
18
18
import {ErrorMessage} from '#/view/com/util/error/ErrorMessage'
19
-
import {List, type ListRef} from '#/view/com/util/List'
19
+
import {List, type ListProps, type ListRef} from '#/view/com/util/List'
20
20
import {NotificationFeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder'
21
21
import {LoadMoreRetryBtn} from '#/view/com/util/LoadMoreRetryBtn'
22
22
import {NotificationFeedItem} from './NotificationFeedItem'
···
39
39
scrollElRef?: ListRef
40
40
onPressTryAgain?: () => void
41
41
onScrolledDownChange: (isScrolledDown: boolean) => void
42
-
ListHeaderComponent?: () => JSX.Element
42
+
ListHeaderComponent?: ListProps['ListHeaderComponent']
43
43
refreshNotifications: () => Promise<void>
44
44
}) {
45
45
const initialNumToRender = useInitialNumToRender()
+4
-4
src/view/com/util/List.tsx
+4
-4
src/view/com/util/List.tsx
···
1
1
import React, {memo} from 'react'
2
-
import {RefreshControl, ViewToken} from 'react-native'
2
+
import {RefreshControl, type ViewToken} from 'react-native'
3
3
import {
4
-
FlatListPropsWithLayout,
4
+
type FlatListPropsWithLayout,
5
5
runOnJS,
6
6
useSharedValue,
7
7
} from 'react-native-reanimated'
···
11
11
import {useDedupe} from '#/lib/hooks/useDedupe'
12
12
import {useScrollHandlers} from '#/lib/ScrollContext'
13
13
import {addStyle} from '#/lib/styles'
14
-
import {isAndroid, isIOS} from '#/platform/detection'
14
+
import {isIOS} from '#/platform/detection'
15
15
import {useLightbox} from '#/state/lightbox'
16
16
import {useTheme} from '#/alf'
17
17
import {FlatList_INTERNAL} from './Views'
···
152
152
153
153
return (
154
154
<FlatList_INTERNAL
155
-
showsVerticalScrollIndicator={!isAndroid} // overridable
155
+
showsVerticalScrollIndicator // overridable
156
156
onViewableItemsChanged={onViewableItemsChanged}
157
157
viewabilityConfig={viewabilityConfig}
158
158
{...props}
+54
-15
src/view/screens/Notifications.tsx
+54
-15
src/view/screens/Notifications.tsx
···
1
-
import React from 'react'
1
+
import {useCallback, useEffect, useMemo, useRef, useState} from 'react'
2
2
import {View} from 'react-native'
3
3
import {msg, Trans} from '@lingui/macro'
4
4
import {useLingui} from '@lingui/react'
···
17
17
import {isNative} from '#/platform/detection'
18
18
import {emitSoftReset, listenSoftReset} from '#/state/events'
19
19
import {RQKEY as NOTIFS_RQKEY} from '#/state/queries/notifications/feed'
20
+
import {useNotificationSettingsQuery} from '#/state/queries/notifications/settings'
20
21
import {
21
22
useUnreadNotifications,
22
23
useUnreadNotificationsApi,
···
30
31
import {type ListMethods} from '#/view/com/util/List'
31
32
import {LoadLatestBtn} from '#/view/com/util/load-latest/LoadLatestBtn'
32
33
import {MainScrollProvider} from '#/view/com/util/MainScrollProvider'
33
-
import {atoms as a} from '#/alf'
34
+
import {atoms as a, useTheme} from '#/alf'
34
35
import {web} from '#/alf'
36
+
import {Admonition} from '#/components/Admonition'
35
37
import {ButtonIcon} from '#/components/Button'
36
38
import {SettingsGear2_Stroke2_Corner0_Rounded as SettingsIcon} from '#/components/icons/SettingsGear2'
37
39
import * as Layout from '#/components/Layout'
38
-
import {Link} from '#/components/Link'
40
+
import {InlineLinkText, Link} from '#/components/Link'
39
41
import {Loader} from '#/components/Loader'
40
42
41
43
// We don't currently persist this across reloads since
···
53
55
const unreadNotifs = useUnreadNotifications()
54
56
const hasNew = !!unreadNotifs
55
57
const {checkUnread: checkUnreadAll} = useUnreadNotificationsApi()
56
-
const [isLoadingAll, setIsLoadingAll] = React.useState(false)
57
-
const [isLoadingMentions, setIsLoadingMentions] = React.useState(false)
58
+
const [isLoadingAll, setIsLoadingAll] = useState(false)
59
+
const [isLoadingMentions, setIsLoadingMentions] = useState(false)
58
60
const initialActiveTab = lastActiveTab
59
-
const [activeTab, setActiveTab] = React.useState(initialActiveTab)
61
+
const [activeTab, setActiveTab] = useState(initialActiveTab)
60
62
const isLoading = activeTab === 0 ? isLoadingAll : isLoadingMentions
61
63
62
-
const onPageSelected = React.useCallback(
64
+
const onPageSelected = useCallback(
63
65
(index: number) => {
64
66
setActiveTab(index)
65
67
lastActiveTab = index
···
68
70
)
69
71
70
72
const queryClient = useQueryClient()
71
-
const checkUnreadMentions = React.useCallback(
73
+
const checkUnreadMentions = useCallback(
72
74
async ({invalidate}: {invalidate: boolean}) => {
73
75
if (invalidate) {
74
76
return truncateAndInvalidate(queryClient, NOTIFS_RQKEY('mentions'))
···
80
82
[queryClient],
81
83
)
82
84
83
-
const sections = React.useMemo(() => {
85
+
const sections = useMemo(() => {
84
86
return [
85
87
{
86
88
title: _(msg`All`),
···
186
188
}) {
187
189
const {_} = useLingui()
188
190
const setMinimalShellMode = useSetMinimalShellMode()
189
-
const [isScrolledDown, setIsScrolledDown] = React.useState(false)
190
-
const scrollElRef = React.useRef<ListMethods>(null)
191
+
const [isScrolledDown, setIsScrolledDown] = useState(false)
192
+
const scrollElRef = useRef<ListMethods>(null)
191
193
const queryClient = useQueryClient()
192
194
const isScreenFocused = useIsFocused()
193
195
const isFocusedAndActive = isScreenFocused && isActive
194
196
195
197
// event handlers
196
198
// =
197
-
const scrollToTop = React.useCallback(() => {
199
+
const scrollToTop = useCallback(() => {
198
200
scrollElRef.current?.scrollToOffset({animated: isNative, offset: 0})
199
201
setMinimalShellMode(false)
200
202
}, [scrollElRef, setMinimalShellMode])
201
203
202
-
const onPressLoadLatest = React.useCallback(() => {
204
+
const onPressLoadLatest = useCallback(() => {
203
205
scrollToTop()
204
206
if (hasNew) {
205
207
// render what we have now
···
238
240
// on-visible setup
239
241
// =
240
242
useFocusEffect(
241
-
React.useCallback(() => {
243
+
useCallback(() => {
242
244
if (isFocusedAndActive) {
243
245
setMinimalShellMode(false)
244
246
logger.debug('NotificationsScreen: Focus')
···
246
248
}
247
249
}, [setMinimalShellMode, onFocusCheckLatest, isFocusedAndActive]),
248
250
)
249
-
React.useEffect(() => {
251
+
252
+
useEffect(() => {
250
253
if (!isFocusedAndActive) {
251
254
return
252
255
}
···
262
265
refreshNotifications={() => checkUnread({invalidate: true})}
263
266
onScrolledDownChange={setIsScrolledDown}
264
267
scrollElRef={scrollElRef}
268
+
ListHeaderComponent={
269
+
filter === 'mentions' ? (
270
+
<DisabledNotificationsWarning active={isFocusedAndActive} />
271
+
) : null
272
+
}
265
273
/>
266
274
</MainScrollProvider>
267
275
{(isScrolledDown || hasNew) && (
···
274
282
</>
275
283
)
276
284
}
285
+
286
+
function DisabledNotificationsWarning({active}: {active: boolean}) {
287
+
const t = useTheme()
288
+
const {_} = useLingui()
289
+
const {data} = useNotificationSettingsQuery({enabled: active})
290
+
291
+
if (!data) return null
292
+
293
+
if (!data.reply.list && !data.quote.list && !data.mention.list) {
294
+
// mention tab notifications are disabled
295
+
return (
296
+
<View style={[a.py_md, a.px_lg, a.border_b, t.atoms.border_contrast_low]}>
297
+
<Admonition type="warning">
298
+
<Trans>
299
+
You have completely disabled reply, quote, and mention
300
+
notifications, so this tab will no longer update. To adjust this,
301
+
visit your{' '}
302
+
<InlineLinkText
303
+
label={_(msg`Visit your notification settings`)}
304
+
to={{screen: 'NotificationSettings'}}>
305
+
notification settings
306
+
</InlineLinkText>
307
+
.
308
+
</Trans>
309
+
</Admonition>
310
+
</View>
311
+
)
312
+
}
313
+
314
+
return null
315
+
}
+14
src/view/shell/index.tsx
+14
src/view/shell/index.tsx
···
25
25
import {ErrorBoundary} from '#/view/com/util/ErrorBoundary'
26
26
import {atoms as a, select, useTheme} from '#/alf'
27
27
import {setSystemUITheme} from '#/alf/util/systemUI'
28
+
import {EmailDialog} from '#/components/dialogs/EmailDialog'
29
+
import {InAppBrowserConsentDialog} from '#/components/dialogs/InAppBrowserConsent'
30
+
import {LinkWarningDialog} from '#/components/dialogs/LinkWarning'
31
+
import {MutedWordsDialog} from '#/components/dialogs/MutedWords'
32
+
import {SigninDialog} from '#/components/dialogs/Signin'
33
+
import {Outlet as PortalOutlet} from '#/components/Portal'
28
34
import {RoutesContainer, TabsNavigator} from '#/Navigation'
35
+
import {BottomSheetOutlet} from '../../../modules/bottom-sheet'
29
36
import {updateActiveViewAsync} from '../../../modules/expo-bluesky-swiss-army/src/VisibilityView'
30
37
import {Composer} from './Composer'
31
38
import {DrawerContent} from './Drawer'
···
145
152
</View>
146
153
<Composer winHeight={winDim.height} />
147
154
<ModalsContainer />
155
+
<MutedWordsDialog />
156
+
<SigninDialog />
157
+
<EmailDialog />
158
+
<InAppBrowserConsentDialog />
159
+
<LinkWarningDialog />
148
160
<Lightbox />
161
+
<PortalOutlet />
162
+
<BottomSheetOutlet />
149
163
</>
150
164
)
151
165
}
+10
src/view/shell/index.web.tsx
+10
src/view/shell/index.web.tsx
···
17
17
import {ModalsContainer} from '#/view/com/modals/Modal'
18
18
import {ErrorBoundary} from '#/view/com/util/ErrorBoundary'
19
19
import {atoms as a, select, useTheme} from '#/alf'
20
+
import {EmailDialog} from '#/components/dialogs/EmailDialog'
21
+
import {LinkWarningDialog} from '#/components/dialogs/LinkWarning'
22
+
import {MutedWordsDialog} from '#/components/dialogs/MutedWords'
23
+
import {SigninDialog} from '#/components/dialogs/Signin'
24
+
import {Outlet as PortalOutlet} from '#/components/Portal'
20
25
import {FlatNavigator, RoutesContainer} from '#/Navigation'
21
26
import {Composer} from './Composer.web'
22
27
import {DrawerContent} from './Drawer'
···
62
67
</ErrorBoundary>
63
68
<Composer winHeight={0} />
64
69
<ModalsContainer />
70
+
<MutedWordsDialog />
71
+
<SigninDialog />
72
+
<EmailDialog />
73
+
<LinkWarningDialog />
65
74
<Lightbox />
75
+
<PortalOutlet />
66
76
67
77
{showDrawerDelayedExit && (
68
78
<>
+4
-4
yarn.lock
+4
-4
yarn.lock
···
16843
16843
resolved "https://registry.yarnpkg.com/react-native-is-edge-to-edge/-/react-native-is-edge-to-edge-1.1.6.tgz#69ec13f70d76e9245e275eed4140d0873a78f902"
16844
16844
integrity sha512-1pHnFTlBahins6UAajXUqeCOHew9l9C2C8tErnpGC3IyLJzvxD+TpYAixnCbrVS52f7+NvMttbiSI290XfwN0w==
16845
16845
16846
-
react-native-keyboard-controller@^1.17.1:
16847
-
version "1.17.1"
16848
-
resolved "https://registry.yarnpkg.com/react-native-keyboard-controller/-/react-native-keyboard-controller-1.17.1.tgz#46efe148c1bdd0ee22094dcb2660f70f81e6544e"
16849
-
integrity sha512-YM3GYvtkuWimCKkZFURn5hIb1WiKOQqi2DijdwZSF5QSSzGqfqwzEEC3bm1xCN8HGHAEIXAaWIBUsc3Xp5L+Ng==
16846
+
react-native-keyboard-controller@^1.17.5:
16847
+
version "1.17.5"
16848
+
resolved "https://registry.yarnpkg.com/react-native-keyboard-controller/-/react-native-keyboard-controller-1.17.5.tgz#a517f0d42f73e69a03e768379934a3bb705595f5"
16849
+
integrity sha512-2bZi4uH/beAcHiQ7nv6sxW03/UpNcnNAPpaSnQtg0cbU3ySThPRETMqr0ZupFLUSZovolyFhyFJLjxmQ7cavJg==
16850
16850
dependencies:
16851
16851
react-native-is-edge-to-edge "^1.1.6"
16852
16852