+58
-24
src/components/AccountList.tsx
+58
-24
src/components/AccountList.tsx
···
5
5
import {useLingui} from '@lingui/react'
6
6
7
7
import {useActorStatus} from '#/lib/actor-status'
8
+
import {isJwtExpired} from '#/lib/jwt'
8
9
import {sanitizeDisplayName} from '#/lib/strings/display-names'
9
10
import {sanitizeHandle} from '#/lib/strings/handles'
10
11
import {useProfilesQuery} from '#/state/queries/profile'
11
12
import {type SessionAccount, useSession} from '#/state/session'
12
13
import {UserAvatar} from '#/view/com/util/UserAvatar'
13
14
import {atoms as a, useTheme} from '#/alf'
14
-
import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check'
15
-
import {ChevronRight_Stroke2_Corner0_Rounded as Chevron} from '#/components/icons/Chevron'
15
+
import {Button} from '#/components/Button'
16
+
import {CheckThick_Stroke2_Corner0_Rounded as CheckIcon} from '#/components/icons/Check'
17
+
import {ChevronRight_Stroke2_Corner0_Rounded as ChevronIcon} from '#/components/icons/Chevron'
18
+
import {PlusLarge_Stroke2_Corner0_Rounded as PlusIcon} from '#/components/icons/Plus'
19
+
import {Text} from '#/components/Typography'
16
20
import {useSimpleVerificationState} from '#/components/verification'
17
21
import {VerificationCheck} from '#/components/verification/VerificationCheck'
18
-
import {Button} from './Button'
19
-
import {Text} from './Typography'
20
22
21
23
export function AccountList({
22
24
onSelectAccount,
···
44
46
<View
45
47
pointerEvents={pendingDid ? 'none' : 'auto'}
46
48
style={[
47
-
a.rounded_md,
49
+
a.rounded_lg,
48
50
a.overflow_hidden,
49
-
{borderWidth: 1},
51
+
a.border,
50
52
t.atoms.border_contrast_low,
51
53
]}>
52
54
{accounts.map(account => (
···
58
60
isCurrentAccount={account.did === currentAccount?.did}
59
61
isPendingAccount={account.did === pendingDid}
60
62
/>
61
-
<View style={[{borderBottomWidth: 1}, t.atoms.border_contrast_low]} />
63
+
<View style={[a.border_b, t.atoms.border_contrast_low]} />
62
64
</React.Fragment>
63
65
))}
64
66
<Button
···
72
74
a.flex_1,
73
75
a.flex_row,
74
76
a.align_center,
75
-
{height: 48},
77
+
a.p_lg,
78
+
a.gap_sm,
76
79
(hovered || pressed) && t.atoms.bg_contrast_25,
77
80
]}>
78
-
<Text
81
+
<View
79
82
style={[
80
-
a.font_semi_bold,
81
-
a.flex_1,
82
-
a.flex_row,
83
-
a.py_sm,
84
-
a.leading_tight,
85
-
t.atoms.text_contrast_medium,
86
-
{paddingLeft: 56},
83
+
t.atoms.bg_contrast_25,
84
+
a.rounded_full,
85
+
{width: 48, height: 48},
86
+
a.justify_center,
87
+
a.align_center,
88
+
(hovered || pressed) && t.atoms.bg_contrast_50,
87
89
]}>
90
+
<PlusIcon style={[t.atoms.text_contrast_low]} size="md" />
91
+
</View>
92
+
<Text style={[a.flex_1, a.leading_tight, a.text_md, a.font_medium]}>
88
93
{otherLabel ?? <Trans>Other account</Trans>}
89
94
</Text>
90
-
<Chevron size="sm" style={[t.atoms.text, a.mr_md]} />
95
+
<ChevronIcon size="md" style={[t.atoms.text_contrast_low]} />
91
96
</View>
92
97
)}
93
98
</Button>
···
116
121
const onPress = useCallback(() => {
117
122
onSelect(account)
118
123
}, [account, onSelect])
124
+
125
+
const isLoggedOut = !account.refreshJwt || isJwtExpired(account.refreshJwt)
119
126
120
127
return (
121
128
<Button
···
134
141
a.flex_1,
135
142
a.flex_row,
136
143
a.align_center,
137
-
a.px_md,
144
+
a.p_lg,
138
145
a.gap_sm,
139
-
{height: 56},
140
146
(hovered || pressed || isPendingAccount) && t.atoms.bg_contrast_25,
141
147
]}>
142
148
<UserAvatar
143
149
avatar={profile?.avatar}
144
-
size={36}
150
+
size={48}
145
151
type={profile?.associated?.labeler ? 'labeler' : 'user'}
146
152
live={live}
147
153
hideLiveBadge
···
151
157
<View style={[a.flex_row, a.align_center, a.gap_xs]}>
152
158
<Text
153
159
emoji
154
-
style={[a.font_semi_bold, a.leading_tight]}
160
+
style={[a.font_medium, a.leading_tight, a.text_md]}
155
161
numberOfLines={1}>
156
162
{sanitizeDisplayName(
157
163
profile?.displayName || profile?.handle || account.handle,
···
166
172
</View>
167
173
)}
168
174
</View>
169
-
<Text style={[a.leading_tight, t.atoms.text_contrast_medium]}>
175
+
<Text
176
+
style={[
177
+
a.leading_tight,
178
+
t.atoms.text_contrast_medium,
179
+
a.text_sm,
180
+
]}>
170
181
{sanitizeHandle(account.handle, '@')}
171
182
</Text>
183
+
{isLoggedOut && (
184
+
<Text
185
+
style={[
186
+
a.leading_tight,
187
+
a.text_xs,
188
+
a.italic,
189
+
t.atoms.text_contrast_medium,
190
+
]}>
191
+
<Trans>Logged out</Trans>
192
+
</Text>
193
+
)}
172
194
</View>
173
195
174
196
{isCurrentAccount ? (
175
-
<Check size="sm" style={[{color: t.palette.positive_500}]} />
197
+
<View
198
+
style={[
199
+
{
200
+
width: 20,
201
+
height: 20,
202
+
backgroundColor: t.palette.positive_500,
203
+
},
204
+
a.rounded_full,
205
+
a.justify_center,
206
+
a.align_center,
207
+
]}>
208
+
<CheckIcon size="xs" style={[{color: t.palette.white}]} />
209
+
</View>
176
210
) : (
177
-
<Chevron size="sm" style={[t.atoms.text]} />
211
+
<ChevronIcon size="md" style={[t.atoms.text_contrast_low]} />
178
212
)}
179
213
</View>
180
214
)}
+3
-6
src/components/Button.tsx
+3
-6
src/components/Button.tsx
···
435
435
436
436
if (shape === 'default') {
437
437
if (size === 'large') {
438
-
baseStyles.push({
438
+
baseStyles.push(a.rounded_full, {
439
439
paddingVertical: 12,
440
440
paddingHorizontal: 25,
441
-
borderRadius: 10,
442
441
gap: 3,
443
442
})
444
443
} else if (size === 'small') {
445
-
baseStyles.push({
444
+
baseStyles.push(a.rounded_full, {
446
445
paddingVertical: 8,
447
446
paddingHorizontal: 13,
448
-
borderRadius: 8,
449
447
gap: 3,
450
448
})
451
449
} else if (size === 'tiny') {
452
-
baseStyles.push({
450
+
baseStyles.push(a.rounded_full, {
453
451
paddingVertical: 5,
454
452
paddingHorizontal: 9,
455
-
borderRadius: 6,
456
453
gap: 2,
457
454
})
458
455
}
-1
src/components/Layout/Header/index.tsx
-1
src/components/Layout/Header/index.tsx
+1
-2
src/components/PostControls/RepostButton.tsx
+1
-2
src/components/PostControls/RepostButton.tsx
+2
-2
src/components/ageAssurance/AgeAssuranceAppealDialog.tsx
+2
-2
src/components/ageAssurance/AgeAssuranceAppealDialog.tsx
···
1
1
import React from 'react'
2
2
import {View} from 'react-native'
3
-
import {ComAtprotoModerationDefs} from '@atproto/api'
3
+
import {ToolsOzoneReportDefs} from '@atproto/api'
4
4
import {msg, Trans} from '@lingui/macro'
5
5
import {useLingui} from '@lingui/react'
6
6
import {useMutation} from '@tanstack/react-query'
···
50
50
51
51
await agent.createModerationReport(
52
52
{
53
-
reasonType: ComAtprotoModerationDefs.REASONAPPEAL,
53
+
reasonType: ToolsOzoneReportDefs.REASONAPPEAL,
54
54
subject: {
55
55
$type: 'com.atproto.admin.defs#repoRef',
56
56
did: currentAccount?.did,
+1
-1
src/components/dialogs/SwitchAccount.tsx
+1
-1
src/components/dialogs/SwitchAccount.tsx
+2
-2
src/components/dms/AfterReportDialog.tsx
+2
-2
src/components/dms/AfterReportDialog.tsx
···
46
46
<Dialog.Handle />
47
47
<Dialog.ScrollableInner
48
48
label={_(
49
-
msg`Would you like to block this account or delete this conversation?`,
49
+
msg`Would you like to block this user and/or delete this conversation?`,
50
50
)}
51
51
style={[web({maxWidth: 400})]}>
52
52
<DialogInner params={params} currentScreen={currentScreen} />
···
177
177
</Text>
178
178
</View>
179
179
<Toggle.Group
180
-
label={_(msg`Block and/or delete this conversation`)}
180
+
label={_(msg`Block user and/or delete this conversation`)}
181
181
values={actions}
182
182
onChange={setActions}>
183
183
<View style={[a.gap_md]}>
+2
-2
src/components/moderation/LabelsOnMeDialog.tsx
+2
-2
src/components/moderation/LabelsOnMeDialog.tsx
···
1
1
import React, {useState} from 'react'
2
2
import {View} from 'react-native'
3
-
import {type ComAtprotoLabelDefs, ComAtprotoModerationDefs} from '@atproto/api'
3
+
import {type ComAtprotoLabelDefs, ToolsOzoneReportDefs} from '@atproto/api'
4
4
import {XRPCError} from '@atproto/xrpc'
5
5
import {msg, Trans} from '@lingui/macro'
6
6
import {useLingui} from '@lingui/react'
···
239
239
: 'com.atproto.admin.defs#repoRef'
240
240
await agent.createModerationReport(
241
241
{
242
-
reasonType: ComAtprotoModerationDefs.REASONAPPEAL,
242
+
reasonType: ToolsOzoneReportDefs.REASONAPPEAL,
243
243
subject: {
244
244
$type,
245
245
...subject,
+23
src/lib/jwt.ts
+23
src/lib/jwt.ts
···
1
+
import {jwtDecode} from 'jwt-decode'
2
+
3
+
import {logger} from '#/logger'
4
+
5
+
/**
6
+
* Simple check if a JWT token has expired. Does *not* validate the token or check for revocation status,
7
+
* just checks the expiration time.
8
+
*
9
+
* @param token The JWT token to check.
10
+
* @returns `true` if the token has expired, `false` otherwise.
11
+
*/
12
+
export function isJwtExpired(token: string) {
13
+
try {
14
+
const payload = jwtDecode(token)
15
+
16
+
if (!payload.exp) return true
17
+
const now = Math.floor(Date.now() / 1000)
18
+
return now >= payload.exp
19
+
} catch {
20
+
logger.error(`session: could not decode jwt`)
21
+
return true // invalid token or parse error
22
+
}
23
+
}
-122
src/lib/moderation/useReportOptions.ts
-122
src/lib/moderation/useReportOptions.ts
···
1
-
import {useMemo} from 'react'
2
-
import {ComAtprotoModerationDefs} from '@atproto/api'
3
-
import {msg} from '@lingui/macro'
4
-
import {useLingui} from '@lingui/react'
5
-
6
-
export interface ReportOption {
7
-
reason: string
8
-
title: string
9
-
description: string
10
-
}
11
-
12
-
interface ReportOptions {
13
-
account: ReportOption[]
14
-
post: ReportOption[]
15
-
list: ReportOption[]
16
-
starterpack: ReportOption[]
17
-
feedgen: ReportOption[]
18
-
other: ReportOption[]
19
-
convoMessage: ReportOption[]
20
-
}
21
-
22
-
export function useReportOptions(): ReportOptions {
23
-
const {_} = useLingui()
24
-
return useMemo(() => {
25
-
const other = {
26
-
reason: ComAtprotoModerationDefs.REASONOTHER,
27
-
title: _(msg`Other`),
28
-
description: _(msg`An issue not included in these options`),
29
-
}
30
-
const common = [
31
-
{
32
-
reason: ComAtprotoModerationDefs.REASONRUDE,
33
-
title: _(msg`Anti-Social Behavior`),
34
-
description: _(msg`Harassment, trolling, or intolerance`),
35
-
},
36
-
{
37
-
reason: ComAtprotoModerationDefs.REASONVIOLATION,
38
-
title: _(msg`Illegal and Urgent`),
39
-
description: _(msg`Glaring violations of law or terms of service`),
40
-
},
41
-
other,
42
-
]
43
-
return {
44
-
account: [
45
-
{
46
-
reason: ComAtprotoModerationDefs.REASONMISLEADING,
47
-
title: _(msg`Misleading Account`),
48
-
description: _(
49
-
msg`Impersonation or false claims about identity or affiliation`,
50
-
),
51
-
},
52
-
{
53
-
reason: ComAtprotoModerationDefs.REASONSPAM,
54
-
title: _(msg`Frequently Posts Unwanted Content`),
55
-
description: _(msg`Spam; excessive mentions or replies`),
56
-
},
57
-
{
58
-
reason: ComAtprotoModerationDefs.REASONVIOLATION,
59
-
title: _(msg`Name or Description Violates Community Standards`),
60
-
description: _(msg`Terms used violate community standards`),
61
-
},
62
-
other,
63
-
],
64
-
post: [
65
-
{
66
-
reason: ComAtprotoModerationDefs.REASONMISLEADING,
67
-
title: _(msg`Misleading Post`),
68
-
description: _(msg`Impersonation, misinformation, or false claims`),
69
-
},
70
-
{
71
-
reason: ComAtprotoModerationDefs.REASONSPAM,
72
-
title: _(msg`Spam`),
73
-
description: _(msg`Excessive mentions or replies`),
74
-
},
75
-
{
76
-
reason: ComAtprotoModerationDefs.REASONSEXUAL,
77
-
title: _(msg`Unwanted Sexual Content`),
78
-
description: _(msg`Nudity or adult content not labeled as such`),
79
-
},
80
-
...common,
81
-
],
82
-
convoMessage: [
83
-
{
84
-
reason: ComAtprotoModerationDefs.REASONSPAM,
85
-
title: _(msg`Spam`),
86
-
description: _(msg`Excessive or unwanted messages`),
87
-
},
88
-
{
89
-
reason: ComAtprotoModerationDefs.REASONSEXUAL,
90
-
title: _(msg`Unwanted Sexual Content`),
91
-
description: _(msg`Inappropriate messages or explicit links`),
92
-
},
93
-
...common,
94
-
],
95
-
list: [
96
-
{
97
-
reason: ComAtprotoModerationDefs.REASONVIOLATION,
98
-
title: _(msg`Name or Description Violates Community Standards`),
99
-
description: _(msg`Terms used violate community standards`),
100
-
},
101
-
...common,
102
-
],
103
-
starterpack: [
104
-
{
105
-
reason: ComAtprotoModerationDefs.REASONVIOLATION,
106
-
title: _(msg`Name or Description Violates Community Standards`),
107
-
description: _(msg`Terms used violate community standards`),
108
-
},
109
-
...common,
110
-
],
111
-
feedgen: [
112
-
{
113
-
reason: ComAtprotoModerationDefs.REASONVIOLATION,
114
-
title: _(msg`Name or Description Violates Community Standards`),
115
-
description: _(msg`Terms used violate community standards`),
116
-
},
117
-
...common,
118
-
],
119
-
other: common,
120
-
}
121
-
}, [_])
122
-
}
+89
-181
src/locale/locales/en/messages.po
+89
-181
src/locale/locales/en/messages.po
···
1047
1047
msgstr ""
1048
1048
1049
1049
#: src/components/moderation/ReportDialog/utils/useReportOptions.ts:239
1050
-
#: src/lib/moderation/useReportOptions.ts:28
1051
1050
msgid "An issue not included in these options"
1052
1051
msgstr ""
1053
1052
···
1063
1062
#: src/components/hooks/useFollowMethods.ts:50
1064
1063
#: src/components/ProfileCard.tsx:484
1065
1064
#: src/components/ProfileCard.tsx:505
1066
-
#: src/view/com/profile/FollowButton.tsx:38
1067
-
#: src/view/com/profile/FollowButton.tsx:48
1068
1065
msgid "An issue occurred, please try again."
1069
1066
msgstr ""
1070
1067
···
1105
1102
1106
1103
#: src/components/dialogs/nuxs/InitialVerificationAnnouncement.tsx:37
1107
1104
msgid "Announcing verification on Bluesky"
1108
-
msgstr ""
1109
-
1110
-
#: src/lib/moderation/useReportOptions.ts:33
1111
-
msgid "Anti-Social Behavior"
1112
1105
msgstr ""
1113
1106
1114
1107
#: src/view/com/composer/threadgate/ThreadgateBtn.tsx:48
···
1304
1297
1305
1298
#: src/components/moderation/LabelsOnMeDialog.tsx:333
1306
1299
#: src/components/moderation/LabelsOnMeDialog.tsx:334
1307
-
#: src/screens/Login/ChooseAccountForm.tsx:90
1308
-
#: src/screens/Login/ChooseAccountForm.tsx:95
1300
+
#: src/screens/Login/ChooseAccountForm.tsx:91
1301
+
#: src/screens/Login/ChooseAccountForm.tsx:96
1309
1302
#: src/screens/Login/ForgotPasswordForm.tsx:123
1310
1303
#: src/screens/Login/ForgotPasswordForm.tsx:129
1311
1304
#: src/screens/Login/LoginForm.tsx:310
···
1412
1405
msgid "Block and Delete"
1413
1406
msgstr ""
1414
1407
1415
-
#: src/components/dms/AfterReportDialog.tsx:180
1416
-
msgid "Block and/or delete this conversation"
1417
-
msgstr ""
1418
-
1419
1408
#: src/screens/ProfileList/components/SubscribeMenu.tsx:125
1420
1409
msgid "Block list"
1421
1410
msgstr ""
···
1437
1426
msgid "Block User"
1438
1427
msgstr ""
1439
1428
1429
+
#: src/components/dms/AfterReportDialog.tsx:180
1430
+
msgid "Block user and/or delete this conversation"
1431
+
msgstr ""
1432
+
1440
1433
#: src/components/Post/Embed/index.tsx:186
1441
1434
msgid "Blocked"
1442
1435
msgstr ""
···
1592
1585
#: src/components/LabelingServiceCard/index.tsx:62
1593
1586
#: src/components/moderation/ReportDialog/index.tsx:834
1594
1587
#: src/screens/Search/components/StarterPackCard.tsx:106
1595
-
#: src/screens/Search/Explore.tsx:937
1588
+
#: src/screens/Search/Explore.tsx:936
1596
1589
msgid "By {0}"
1597
1590
msgstr ""
1598
1591
1599
-
#: src/screens/Profile/components/ProfileFeedHeader.tsx:451
1592
+
#: src/screens/Profile/components/ProfileFeedHeader.tsx:453
1600
1593
msgid "By <0>{0}</0>"
1601
1594
msgstr ""
1602
1595
···
1642
1635
#: src/components/live/GoLiveDialog.tsx:244
1643
1636
#: src/components/live/GoLiveDialog.tsx:250
1644
1637
#: src/components/Menu/index.tsx:350
1645
-
#: src/components/PostControls/RepostButton.tsx:210
1638
+
#: src/components/PostControls/RepostButton.tsx:209
1646
1639
#: src/components/Prompt.tsx:144
1647
1640
#: src/components/Prompt.tsx:146
1648
1641
#: src/screens/Deactivated.tsx:158
···
2260
2253
msgid "Continue"
2261
2254
msgstr ""
2262
2255
2263
-
#: src/components/AccountList.tsx:128
2256
+
#: src/components/AccountList.tsx:135
2264
2257
msgid "Continue as {0} (currently signed in)"
2265
2258
msgstr ""
2266
2259
···
2839
2832
msgid "Discover new custom feeds"
2840
2833
msgstr ""
2841
2834
2842
-
#: src/screens/Search/Explore.tsx:432
2835
+
#: src/screens/Search/Explore.tsx:431
2843
2836
#: src/view/screens/Feeds.tsx:730
2844
2837
msgid "Discover New Feeds"
2845
2838
msgstr ""
···
2951
2944
msgid "Double tap to close the dialog"
2952
2945
msgstr ""
2953
2946
2954
-
#: src/screens/VideoFeed/index.tsx:1087
2947
+
#: src/screens/VideoFeed/index.tsx:1101
2955
2948
msgid "Double tap to like"
2956
2949
msgstr ""
2957
2950
···
3351
3344
msgid "Everything else"
3352
3345
msgstr ""
3353
3346
3354
-
#: src/lib/moderation/useReportOptions.ts:73
3355
-
msgid "Excessive mentions or replies"
3356
-
msgstr ""
3357
-
3358
-
#: src/lib/moderation/useReportOptions.ts:86
3359
-
msgid "Excessive or unwanted messages"
3360
-
msgstr ""
3361
-
3362
3347
#: src/components/dialogs/MutedWords.tsx:316
3363
3348
msgid "Exclude users you follow"
3364
3349
msgstr ""
···
3395
3380
msgid "Expand post text"
3396
3381
msgstr ""
3397
3382
3398
-
#: src/screens/VideoFeed/index.tsx:972
3383
+
#: src/screens/VideoFeed/index.tsx:973
3399
3384
msgid "Expands or collapses post text"
3400
3385
msgstr ""
3401
3386
···
3536
3521
msgid "Failed to load conversations"
3537
3522
msgstr ""
3538
3523
3539
-
#: src/screens/Search/Explore.tsx:468
3540
-
#: src/screens/Search/Explore.tsx:520
3541
-
#: src/screens/Search/Explore.tsx:558
3542
-
#: src/screens/Search/Explore.tsx:597
3524
+
#: src/screens/Search/Explore.tsx:467
3525
+
#: src/screens/Search/Explore.tsx:519
3526
+
#: src/screens/Search/Explore.tsx:557
3527
+
#: src/screens/Search/Explore.tsx:596
3543
3528
msgid "Failed to load feeds preferences"
3544
3529
msgstr ""
3545
3530
···
3569
3554
msgid "Failed to load preference."
3570
3555
msgstr ""
3571
3556
3572
-
#: src/screens/Search/Explore.tsx:461
3573
-
#: src/screens/Search/Explore.tsx:513
3574
-
#: src/screens/Search/Explore.tsx:551
3575
-
#: src/screens/Search/Explore.tsx:590
3557
+
#: src/screens/Search/Explore.tsx:460
3558
+
#: src/screens/Search/Explore.tsx:512
3559
+
#: src/screens/Search/Explore.tsx:550
3560
+
#: src/screens/Search/Explore.tsx:589
3576
3561
msgid "Failed to load suggested feeds"
3577
3562
msgstr ""
3578
3563
3579
-
#: src/screens/Search/Explore.tsx:371
3564
+
#: src/screens/Search/Explore.tsx:370
3580
3565
msgid "Failed to load suggested follows"
3581
3566
msgstr ""
3582
3567
···
3703
3688
msgid "Feed identifier"
3704
3689
msgstr ""
3705
3690
3706
-
#: src/screens/Profile/components/ProfileFeedHeader.tsx:354
3691
+
#: src/screens/Profile/components/ProfileFeedHeader.tsx:355
3707
3692
msgid "Feed menu"
3708
3693
msgstr ""
3709
3694
···
3846
3831
#: src/components/ProfileHoverCard/index.web.tsx:507
3847
3832
#: src/screens/PostThread/components/ThreadItemAnchorFollowButton.tsx:131
3848
3833
#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:258
3849
-
#: src/screens/VideoFeed/index.tsx:856
3850
-
msgid "Follow"
3851
-
msgstr ""
3852
-
3853
-
#: src/view/com/profile/FollowButton.tsx:72
3854
-
msgctxt "action"
3834
+
#: src/screens/VideoFeed/index.tsx:857
3855
3835
msgid "Follow"
3856
3836
msgstr ""
3857
3837
···
3860
3840
msgid "Follow {0}"
3861
3841
msgstr ""
3862
3842
3863
-
#: src/screens/VideoFeed/index.tsx:833
3843
+
#: src/screens/VideoFeed/index.tsx:834
3864
3844
msgid "Follow {handle}"
3865
3845
msgstr ""
3866
3846
···
3897
3877
msgid "Follow back"
3898
3878
msgstr ""
3899
3879
3900
-
#: src/view/com/profile/FollowButton.tsx:81
3901
-
msgctxt "action"
3902
-
msgid "Follow back"
3903
-
msgstr ""
3904
-
3905
3880
#: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:113
3906
3881
msgid "Followed all accounts!"
3907
3882
msgstr ""
···
3937
3912
#: src/components/ProfileHoverCard/index.web.tsx:506
3938
3913
#: src/screens/PostThread/components/ThreadItemAnchorFollowButton.tsx:134
3939
3914
#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:254
3940
-
#: src/screens/VideoFeed/index.tsx:854
3915
+
#: src/screens/VideoFeed/index.tsx:855
3941
3916
msgid "Following"
3942
3917
msgstr ""
3943
3918
···
3952
3927
msgid "Following {0}"
3953
3928
msgstr ""
3954
3929
3955
-
#: src/screens/VideoFeed/index.tsx:832
3930
+
#: src/screens/VideoFeed/index.tsx:833
3956
3931
msgid "Following {handle}"
3957
3932
msgstr ""
3958
3933
···
4031
4006
4032
4007
#: src/screens/Onboarding/StepFinished/ValuePropositionPager.shared.tsx:12
4033
4008
msgid "Free your feed"
4034
-
msgstr ""
4035
-
4036
-
#: src/lib/moderation/useReportOptions.ts:54
4037
-
msgid "Frequently Posts Unwanted Content"
4038
4009
msgstr ""
4039
4010
4040
4011
#: src/screens/Settings/NotificationSettings/components/PreferenceControls.tsx:157
···
4131
4102
msgid "Give your profile a face"
4132
4103
msgstr ""
4133
4104
4134
-
#: src/lib/moderation/useReportOptions.ts:39
4135
-
msgid "Glaring violations of law or terms of service"
4136
-
msgstr ""
4137
-
4138
4105
#: src/components/moderation/ReportDialog/utils/useReportOptions.ts:142
4139
4106
msgid "Glorification of violence"
4140
4107
msgstr ""
···
4149
4116
#: src/screens/ProfileList/components/ErrorScreen.tsx:34
4150
4117
#: src/screens/ProfileList/components/ErrorScreen.tsx:40
4151
4118
#: src/screens/VideoFeed/components/Header.tsx:163
4152
-
#: src/screens/VideoFeed/index.tsx:1148
4153
-
#: src/screens/VideoFeed/index.tsx:1152
4119
+
#: src/screens/VideoFeed/index.tsx:1162
4120
+
#: src/screens/VideoFeed/index.tsx:1166
4154
4121
#: src/view/com/auth/LoggedOut.tsx:72
4155
4122
#: src/view/screens/NotFound.tsx:57
4156
4123
msgid "Go back"
···
4285
4252
msgid "Harassment or hate"
4286
4253
msgstr ""
4287
4254
4288
-
#: src/lib/moderation/useReportOptions.ts:34
4289
-
msgid "Harassment, trolling, or intolerance"
4290
-
msgstr ""
4291
-
4292
4255
#: src/components/moderation/ReportDialog/utils/useReportOptions.ts:189
4293
4256
msgid "Harmful or high-risk activities"
4294
4257
msgstr ""
···
4344
4307
msgid "Hidden"
4345
4308
msgstr ""
4346
4309
4347
-
#: src/screens/VideoFeed/index.tsx:630
4310
+
#: src/screens/VideoFeed/index.tsx:631
4348
4311
msgid "Hidden by your moderation settings."
4349
4312
msgstr ""
4350
4313
···
4553
4516
msgid "If you're trying to change your handle or email, do so before you deactivate."
4554
4517
msgstr ""
4555
4518
4556
-
#: src/lib/moderation/useReportOptions.ts:38
4557
-
msgid "Illegal and Urgent"
4558
-
msgstr ""
4559
-
4560
4519
#: src/view/com/util/images/Gallery.tsx:75
4561
4520
msgid "Image"
4562
4521
msgstr ""
···
4583
4542
msgid "Impersonation"
4584
4543
msgstr ""
4585
4544
4586
-
#: src/lib/moderation/useReportOptions.ts:49
4587
-
msgid "Impersonation or false claims about identity or affiliation"
4588
-
msgstr ""
4589
-
4590
-
#: src/lib/moderation/useReportOptions.ts:68
4591
-
msgid "Impersonation, misinformation, or false claims"
4592
-
msgstr ""
4593
-
4594
4545
#: src/screens/Settings/NotificationSettings/index.tsx:284
4595
4546
msgid "In-app"
4596
4547
msgstr ""
···
4617
4568
4618
4569
#: src/screens/Settings/NotificationSettings/index.tsx:273
4619
4570
msgid "In-app, Push, People you follow"
4620
-
msgstr ""
4621
-
4622
-
#: src/lib/moderation/useReportOptions.ts:91
4623
-
msgid "Inappropriate messages or explicit links"
4624
4571
msgstr ""
4625
4572
4626
4573
#. Title message shown in chat requests inbox when it's empty
···
4944
4891
msgid "Light"
4945
4892
msgstr ""
4946
4893
4947
-
#: src/screens/Profile/components/ProfileFeedHeader.tsx:518
4894
+
#: src/screens/Profile/components/ProfileFeedHeader.tsx:515
4948
4895
msgid "Like"
4949
4896
msgstr ""
4950
4897
···
4966
4913
msgid "Like notifications"
4967
4914
msgstr ""
4968
4915
4969
-
#: src/screens/Profile/components/ProfileFeedHeader.tsx:505
4916
+
#: src/screens/Profile/components/ProfileFeedHeader.tsx:502
4970
4917
msgid "Like this feed"
4971
4918
msgstr ""
4972
4919
···
4991
4938
msgstr ""
4992
4939
4993
4940
#: src/components/LabelingServiceCard/index.tsx:96
4994
-
#: src/screens/Profile/components/ProfileFeedHeader.tsx:493
4941
+
#: src/screens/Profile/components/ProfileFeedHeader.tsx:490
4995
4942
#: src/screens/Profile/Header/ProfileHeaderLabeler.tsx:290
4996
4943
#: src/screens/Profile/Header/ProfileHeaderLabeler.tsx:304
4997
4944
msgid "Liked by {likeCount, plural, one {# user} other {# users}}"
···
5132
5079
msgid "Live link"
5133
5080
msgstr ""
5134
5081
5135
-
#: src/screens/Search/Explore.tsx:84
5082
+
#: src/screens/Search/Explore.tsx:83
5136
5083
msgid "Load more"
5137
5084
msgstr ""
5138
5085
5139
-
#: src/screens/Search/Explore.tsx:502
5140
-
#: src/screens/Search/Explore.tsx:579
5086
+
#: src/screens/Search/Explore.tsx:501
5087
+
#: src/screens/Search/Explore.tsx:578
5141
5088
msgid "Load more suggested feeds"
5142
5089
msgstr ""
5143
5090
···
5158
5105
5159
5106
#: src/Navigation.tsx:321
5160
5107
msgid "Log"
5108
+
msgstr ""
5109
+
5110
+
#: src/components/AccountList.tsx:191
5111
+
msgid "Logged out"
5161
5112
msgstr ""
5162
5113
5163
5114
#: src/screens/Settings/PrivacyAndSecuritySettings.tsx:106
···
5325
5276
msgid "Misleading"
5326
5277
msgstr ""
5327
5278
5328
-
#: src/lib/moderation/useReportOptions.ts:47
5329
-
msgid "Misleading Account"
5330
-
msgstr ""
5331
-
5332
-
#: src/lib/moderation/useReportOptions.ts:67
5333
-
msgid "Misleading Post"
5334
-
msgstr ""
5335
-
5336
5279
#: src/Navigation.tsx:177
5337
5280
#: src/screens/Moderation/index.tsx:100
5338
5281
#: src/screens/Settings/Settings.tsx:188
···
5536
5479
5537
5480
#: src/components/dialogs/lists/CreateOrEditListDialog.tsx:399
5538
5481
msgid "Name"
5539
-
msgstr ""
5540
-
5541
-
#: src/lib/moderation/useReportOptions.ts:59
5542
-
#: src/lib/moderation/useReportOptions.ts:98
5543
-
#: src/lib/moderation/useReportOptions.ts:106
5544
-
#: src/lib/moderation/useReportOptions.ts:114
5545
-
msgid "Name or Description Violates Community Standards"
5546
5482
msgstr ""
5547
5483
5548
5484
#: src/lib/interests.ts:66
···
5585
5521
msgid "New"
5586
5522
msgstr ""
5587
5523
5588
-
#: src/view/screens/Lists.tsx:79
5524
+
#: src/view/screens/Lists.tsx:78
5589
5525
#: src/view/screens/ModerationModlists.tsx:79
5590
5526
msgctxt "action"
5591
5527
msgid "New"
···
5805
5741
msgid "No results"
5806
5742
msgstr ""
5807
5743
5808
-
#: src/screens/Search/Explore.tsx:794
5744
+
#: src/screens/Search/Explore.tsx:793
5809
5745
msgid "No results for \"{0}\"."
5810
5746
msgstr ""
5811
5747
···
5823
5759
msgid "No results found for {query}"
5824
5760
msgstr ""
5825
5761
5826
-
#: src/screens/Search/Explore.tsx:798
5762
+
#: src/screens/Search/Explore.tsx:797
5827
5763
msgid "No results."
5828
5764
msgstr ""
5829
5765
···
5956
5892
msgid "Nudity"
5957
5893
msgstr ""
5958
5894
5959
-
#: src/lib/moderation/useReportOptions.ts:78
5960
-
msgid "Nudity or adult content not labeled as such"
5961
-
msgstr ""
5962
-
5963
5895
#: src/lib/moderation/useLabelBehaviorDescription.ts:14
5964
5896
#: src/screens/Settings/NotificationSettings/index.tsx:291
5965
5897
msgid "Off"
···
6067
5999
msgid "Open conversation options"
6068
6000
msgstr ""
6069
6001
6070
-
#: src/components/Layout/Header/index.tsx:160
6002
+
#: src/components/Layout/Header/index.tsx:159
6071
6003
msgid "Open drawer menu"
6072
6004
msgstr ""
6073
6005
···
6080
6012
msgid "Open feed info screen"
6081
6013
msgstr ""
6082
6014
6083
-
#: src/screens/Profile/components/ProfileFeedHeader.tsx:291
6084
-
#: src/screens/Profile/components/ProfileFeedHeader.tsx:296
6015
+
#: src/screens/Profile/components/ProfileFeedHeader.tsx:292
6016
+
#: src/screens/Profile/components/ProfileFeedHeader.tsx:297
6085
6017
msgid "Open feed options menu"
6086
6018
msgstr ""
6087
6019
···
6249
6181
6250
6182
#: src/components/moderation/ReportDialog/utils/useReportOptions.ts:238
6251
6183
#: src/components/moderation/ReportDialog/utils/useReportOptions.ts:242
6252
-
#: src/lib/moderation/useReportOptions.ts:27
6253
6184
#: src/view/com/composer/labels/LabelsBtn.tsx:185
6254
6185
msgid "Other"
6255
6186
msgstr ""
6256
6187
6257
-
#: src/components/AccountList.tsx:88
6188
+
#: src/components/AccountList.tsx:93
6258
6189
msgid "Other account"
6259
6190
msgstr ""
6260
6191
···
6383
6314
msgid "Pictures meant for adults."
6384
6315
msgstr ""
6385
6316
6386
-
#: src/screens/Profile/components/ProfileFeedHeader.tsx:523
6387
-
#: src/screens/Profile/components/ProfileFeedHeader.tsx:530
6317
+
#: src/screens/Profile/components/ProfileFeedHeader.tsx:520
6318
+
#: src/screens/Profile/components/ProfileFeedHeader.tsx:527
6388
6319
#: src/screens/SavedFeeds.tsx:351
6389
6320
msgid "Pin feed"
6390
6321
msgstr ""
···
6398
6329
msgid "Pin to home"
6399
6330
msgstr ""
6400
6331
6401
-
#: src/screens/Profile/components/ProfileFeedHeader.tsx:337
6332
+
#: src/screens/Profile/components/ProfileFeedHeader.tsx:338
6402
6333
msgid "Pin to Home"
6403
6334
msgstr ""
6404
6335
···
6647
6578
#: src/screens/PostThread/components/ThreadItemAnchor.tsx:134
6648
6579
#: src/screens/PostThread/components/ThreadItemPost.tsx:112
6649
6580
#: src/screens/PostThread/components/ThreadItemTreePost.tsx:108
6650
-
#: src/screens/VideoFeed/index.tsx:534
6581
+
#: src/screens/VideoFeed/index.tsx:535
6651
6582
msgid "Post has been deleted"
6652
6583
msgstr ""
6653
6584
···
6940
6871
msgid "Read blog post"
6941
6872
msgstr ""
6942
6873
6943
-
#: src/screens/VideoFeed/index.tsx:973
6874
+
#: src/screens/VideoFeed/index.tsx:974
6944
6875
msgid "Read less"
6945
6876
msgstr ""
6946
6877
6947
-
#: src/screens/VideoFeed/index.tsx:973
6878
+
#: src/screens/VideoFeed/index.tsx:974
6948
6879
msgid "Read more"
6949
6880
msgstr ""
6950
6881
···
7077
7008
msgid "Remove feed?"
7078
7009
msgstr ""
7079
7010
7080
-
#: src/screens/Profile/components/ProfileFeedHeader.tsx:319
7081
-
#: src/screens/Profile/components/ProfileFeedHeader.tsx:325
7011
+
#: src/screens/Profile/components/ProfileFeedHeader.tsx:320
7012
+
#: src/screens/Profile/components/ProfileFeedHeader.tsx:326
7082
7013
#: src/screens/ProfileList/components/MoreOptionsMenu.tsx:181
7083
7014
#: src/screens/ProfileList/components/MoreOptionsMenu.tsx:184
7084
7015
#: src/screens/SavedFeeds.tsx:340
···
7296
7227
msgid "Report dialog"
7297
7228
msgstr ""
7298
7229
7299
-
#: src/screens/Profile/components/ProfileFeedHeader.tsx:546
7300
-
#: src/screens/Profile/components/ProfileFeedHeader.tsx:552
7230
+
#: src/screens/Profile/components/ProfileFeedHeader.tsx:543
7231
+
#: src/screens/Profile/components/ProfileFeedHeader.tsx:549
7301
7232
msgid "Report feed"
7302
7233
msgstr ""
7303
7234
···
7523
7454
#: src/screens/Profile/ProfileFeed/index.tsx:93
7524
7455
#: src/screens/ProfileList/components/ErrorScreen.tsx:35
7525
7456
#: src/screens/Settings/components/ChangeHandleDialog.tsx:569
7526
-
#: src/screens/VideoFeed/index.tsx:1149
7457
+
#: src/screens/VideoFeed/index.tsx:1163
7527
7458
#: src/view/screens/NotFound.tsx:60
7528
7459
msgid "Returns to previous page"
7529
7460
msgstr ""
···
7582
7513
msgid "Save QR code"
7583
7514
msgstr ""
7584
7515
7585
-
#: src/screens/Profile/components/ProfileFeedHeader.tsx:320
7586
-
#: src/screens/Profile/components/ProfileFeedHeader.tsx:326
7516
+
#: src/screens/Profile/components/ProfileFeedHeader.tsx:321
7517
+
#: src/screens/Profile/components/ProfileFeedHeader.tsx:327
7587
7518
msgid "Save to my feeds"
7588
7519
msgstr ""
7589
7520
···
7680
7611
msgid "Search for feeds that you want to suggest to others."
7681
7612
msgstr ""
7682
7613
7683
-
#: src/screens/Search/Explore.tsx:358
7614
+
#: src/screens/Search/Explore.tsx:357
7684
7615
msgid "Search for more accounts"
7685
7616
msgstr ""
7686
7617
7687
-
#: src/screens/Search/Explore.tsx:435
7618
+
#: src/screens/Search/Explore.tsx:434
7688
7619
msgid "Search for more feeds"
7689
7620
msgstr ""
7690
7621
···
8112
8043
msgid "Share QR code"
8113
8044
msgstr ""
8114
8045
8115
-
#: src/screens/Profile/components/ProfileFeedHeader.tsx:474
8046
+
#: src/screens/Profile/components/ProfileFeedHeader.tsx:471
8116
8047
msgid "Share this feed"
8117
8048
msgstr ""
8118
8049
···
8156
8087
#: src/components/moderation/ScreenHider.tsx:178
8157
8088
#: src/components/moderation/ScreenHider.tsx:181
8158
8089
#: src/screens/List/ListHiddenScreen.tsx:190
8159
-
#: src/screens/VideoFeed/index.tsx:633
8160
-
#: src/screens/VideoFeed/index.tsx:639
8090
+
#: src/screens/VideoFeed/index.tsx:634
8091
+
#: src/screens/VideoFeed/index.tsx:640
8161
8092
msgid "Show anyway"
8162
8093
msgstr ""
8163
8094
···
8272
8203
msgid "Sign in"
8273
8204
msgstr ""
8274
8205
8275
-
#: src/components/AccountList.tsx:129
8206
+
#: src/components/AccountList.tsx:136
8276
8207
msgid "Sign in as {0}"
8277
8208
msgstr ""
8278
8209
8279
-
#: src/screens/Login/ChooseAccountForm.tsx:80
8210
+
#: src/screens/Login/ChooseAccountForm.tsx:81
8280
8211
msgid "Sign in as..."
8281
8212
msgstr ""
8282
8213
···
8289
8220
msgid "Sign in or create your account to join the conversation!"
8290
8221
msgstr ""
8291
8222
8292
-
#: src/components/AccountList.tsx:68
8223
+
#: src/components/AccountList.tsx:70
8293
8224
msgid "Sign in to account that is not listed"
8294
8225
msgstr ""
8295
8226
···
8425
8356
msgid "Something went wrong. Please try again."
8426
8357
msgstr ""
8427
8358
8428
-
#: src/screens/Profile/components/ProfileFeedHeader.tsx:542
8359
+
#: src/screens/Profile/components/ProfileFeedHeader.tsx:539
8429
8360
msgid "Something wrong? Let us know."
8430
8361
msgstr ""
8431
8362
···
8456
8387
msgstr ""
8457
8388
8458
8389
#: src/components/moderation/ReportDialog/utils/useReportOptions.ts:39
8459
-
#: src/lib/moderation/useReportOptions.ts:72
8460
-
#: src/lib/moderation/useReportOptions.ts:85
8461
8390
msgid "Spam"
8462
8391
msgstr ""
8463
8392
···
8465
8394
msgid "Spam or other inauthentic behavior or deception"
8466
8395
msgstr ""
8467
8396
8468
-
#: src/lib/moderation/useReportOptions.ts:55
8469
-
msgid "Spam; excessive mentions or replies"
8470
-
msgstr ""
8471
-
8472
8397
#: src/lib/interests.ts:72
8473
8398
#: src/screens/Onboarding/index.tsx:58
8474
8399
#: src/screens/Search/modules/ExploreTrendingTopics.tsx:230
···
8520
8445
msgid "Starter pack is invalid"
8521
8446
msgstr ""
8522
8447
8523
-
#: src/screens/Search/Explore.tsx:626
8448
+
#: src/screens/Search/Explore.tsx:625
8524
8449
#: src/view/screens/Profile.tsx:231
8525
8450
msgid "Starter Packs"
8526
8451
msgstr ""
···
8607
8532
msgid "Successfully verified"
8608
8533
msgstr ""
8609
8534
8610
-
#: src/screens/Search/Explore.tsx:355
8535
+
#: src/screens/Search/Explore.tsx:354
8611
8536
msgid "Suggested Accounts"
8612
8537
msgstr ""
8613
8538
···
8754
8679
msgid "Terms of Service"
8755
8680
msgstr ""
8756
8681
8757
-
#: src/lib/moderation/useReportOptions.ts:60
8758
-
#: src/lib/moderation/useReportOptions.ts:99
8759
-
#: src/lib/moderation/useReportOptions.ts:107
8760
-
#: src/lib/moderation/useReportOptions.ts:115
8761
-
msgid "Terms used violate community standards"
8762
-
msgstr ""
8763
-
8764
8682
#: src/components/dialogs/MutedWords.tsx:271
8765
8683
msgid "Text & tags"
8766
8684
msgstr ""
···
8804
8722
msgid "That's all, folks!"
8805
8723
msgstr ""
8806
8724
8807
-
#: src/screens/VideoFeed/index.tsx:1121
8725
+
#: src/screens/VideoFeed/index.tsx:1135
8808
8726
msgid "That's everything!"
8809
8727
msgstr ""
8810
8728
···
8932
8850
msgid "There was an issue contacting the server"
8933
8851
msgstr ""
8934
8852
8935
-
#: src/screens/Profile/components/ProfileFeedHeader.tsx:418
8853
+
#: src/screens/Profile/components/ProfileFeedHeader.tsx:419
8936
8854
#: src/screens/Profile/Header/ProfileHeaderLabeler.tsx:109
8937
8855
msgid "There was an issue contacting the server, please check your internet connection and try again."
8938
8856
msgstr ""
···
8941
8859
msgid "There was an issue fetching notifications. Tap here to try again."
8942
8860
msgstr ""
8943
8861
8944
-
#: src/screens/Search/Explore.tsx:993
8862
+
#: src/screens/Search/Explore.tsx:992
8945
8863
#: src/view/com/posts/PostFeed.tsx:712
8946
8864
msgid "There was an issue fetching posts. Tap here to try again."
8947
8865
msgstr ""
···
9473
9391
msgid "Undo repost ({0, plural, one {# repost} other {# reposts}})"
9474
9392
msgstr ""
9475
9393
9476
-
#: src/view/com/profile/FollowButton.tsx:63
9477
-
msgctxt "action"
9478
-
msgid "Unfollow"
9479
-
msgstr ""
9480
-
9481
9394
#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:242
9482
9395
msgid "Unfollow {0}"
9483
9396
msgstr ""
···
9487
9400
msgid "Unfollow account"
9488
9401
msgstr ""
9489
9402
9490
-
#: src/screens/VideoFeed/index.tsx:837
9403
+
#: src/screens/VideoFeed/index.tsx:838
9491
9404
msgid "Unfollows the user"
9492
9405
msgstr ""
9493
9406
···
9511
9424
msgid "Unlabeled, abusive, or non-consensual adult content"
9512
9425
msgstr ""
9513
9426
9514
-
#: src/screens/Profile/components/ProfileFeedHeader.tsx:518
9427
+
#: src/screens/Profile/components/ProfileFeedHeader.tsx:515
9515
9428
msgid "Unlike"
9516
9429
msgstr ""
9517
9430
···
9566
9479
msgid "Unpin"
9567
9480
msgstr ""
9568
9481
9569
-
#: src/screens/Profile/components/ProfileFeedHeader.tsx:523
9570
-
#: src/screens/Profile/components/ProfileFeedHeader.tsx:530
9482
+
#: src/screens/Profile/components/ProfileFeedHeader.tsx:520
9483
+
#: src/screens/Profile/components/ProfileFeedHeader.tsx:527
9571
9484
#: src/screens/SavedFeeds.tsx:351
9572
9485
msgid "Unpin feed"
9573
9486
msgstr ""
···
9576
9489
msgid "Unpin Feed"
9577
9490
msgstr ""
9578
9491
9579
-
#: src/screens/Profile/components/ProfileFeedHeader.tsx:310
9580
-
#: src/screens/Profile/components/ProfileFeedHeader.tsx:312
9492
+
#: src/screens/Profile/components/ProfileFeedHeader.tsx:311
9493
+
#: src/screens/Profile/components/ProfileFeedHeader.tsx:313
9581
9494
msgid "Unpin from home"
9582
9495
msgstr ""
9583
9496
···
9627
9540
9628
9541
#: src/view/com/composer/Composer.tsx:895
9629
9542
msgid "Unsupported video type: {mimeType}"
9630
-
msgstr ""
9631
-
9632
-
#: src/lib/moderation/useReportOptions.ts:77
9633
-
#: src/lib/moderation/useReportOptions.ts:90
9634
-
msgid "Unwanted Sexual Content"
9635
9543
msgstr ""
9636
9544
9637
9545
#: src/screens/Settings/components/OTAInfo.tsx:58
···
9951
9859
msgid "Video Games"
9952
9860
msgstr ""
9953
9861
9954
-
#: src/screens/VideoFeed/index.tsx:1079
9862
+
#: src/screens/VideoFeed/index.tsx:1093
9955
9863
msgid "Video is paused"
9956
9864
msgstr ""
9957
9865
9958
-
#: src/screens/VideoFeed/index.tsx:1079
9866
+
#: src/screens/VideoFeed/index.tsx:1093
9959
9867
msgid "Video is playing"
9960
9868
msgstr ""
9961
9869
···
9993
9901
msgstr ""
9994
9902
9995
9903
#: src/components/ProfileCard.tsx:124
9996
-
#: src/screens/Profile/components/ProfileFeedHeader.tsx:454
9904
+
#: src/screens/Profile/components/ProfileFeedHeader.tsx:456
9997
9905
#: src/screens/Search/components/SearchProfileCard.tsx:36
9998
-
#: src/screens/VideoFeed/index.tsx:796
9906
+
#: src/screens/VideoFeed/index.tsx:797
9999
9907
#: src/view/com/notifications/NotificationFeedItem.tsx:599
10000
9908
msgid "View {0}'s profile"
10001
9909
msgstr ""
···
10016
9924
msgid "View debug entry"
10017
9925
msgstr ""
10018
9926
10019
-
#: src/screens/VideoFeed/index.tsx:661
10020
-
#: src/screens/VideoFeed/index.tsx:679
9927
+
#: src/screens/VideoFeed/index.tsx:662
9928
+
#: src/screens/VideoFeed/index.tsx:680
10021
9929
msgid "View details"
10022
9930
msgstr ""
10023
9931
···
10065
9973
msgid "View this user's verifications"
10066
9974
msgstr ""
10067
9975
10068
-
#: src/screens/Profile/components/ProfileFeedHeader.tsx:489
9976
+
#: src/screens/Profile/components/ProfileFeedHeader.tsx:486
10069
9977
msgid "View users who like this feed"
10070
9978
msgstr ""
10071
9979
···
10391
10299
msgstr ""
10392
10300
10393
10301
#: src/components/dms/AfterReportDialog.tsx:49
10394
-
msgid "Would you like to block this account or delete this conversation?"
10302
+
msgid "Would you like to block this user and/or delete this conversation?"
10395
10303
msgstr ""
10396
10304
10397
10305
#: src/screens/Messages/components/MessageInput.tsx:154
···
10861
10769
msgid "You've reached your daily limit for video uploads (too many videos)"
10862
10770
msgstr ""
10863
10771
10864
-
#: src/screens/VideoFeed/index.tsx:1130
10772
+
#: src/screens/VideoFeed/index.tsx:1144
10865
10773
msgid "You've run out of videos to watch. Maybe it's a good time to take a break?"
10866
10774
msgstr ""
10867
10775
+3
-2
src/screens/Login/ChooseAccountForm.tsx
+3
-2
src/screens/Login/ChooseAccountForm.tsx
···
8
8
import {type SessionAccount, useSession, useSessionApi} from '#/state/session'
9
9
import {useLoggedOutViewControls} from '#/state/shell/logged-out'
10
10
import * as Toast from '#/view/com/util/Toast'
11
-
import {atoms as a} from '#/alf'
11
+
import {atoms as a, web} from '#/alf'
12
12
import {AccountList} from '#/components/AccountList'
13
13
import {Button, ButtonText} from '#/components/Button'
14
14
import * as TextField from '#/components/forms/TextField'
···
74
74
return (
75
75
<FormContainer
76
76
testID="chooseAccountForm"
77
-
titleText={<Trans>Select account</Trans>}>
77
+
titleText={<Trans>Select account</Trans>}
78
+
style={web([a.py_2xl])}>
78
79
<View>
79
80
<TextField.LabelText>
80
81
<Trans>Sign in as...</Trans>
+2
-2
src/screens/Messages/components/ChatDisabled.tsx
+2
-2
src/screens/Messages/components/ChatDisabled.tsx
···
1
1
import {useCallback, useState} from 'react'
2
2
import {View} from 'react-native'
3
-
import {ComAtprotoModerationDefs} from '@atproto/api'
3
+
import {ToolsOzoneReportDefs} from '@atproto/api'
4
4
import {msg, Trans} from '@lingui/macro'
5
5
import {useLingui} from '@lingui/react'
6
6
import {useMutation} from '@tanstack/react-query'
···
81
81
throw new Error('No current account, should be unreachable')
82
82
await agent.createModerationReport(
83
83
{
84
-
reasonType: ComAtprotoModerationDefs.REASONAPPEAL,
84
+
reasonType: ToolsOzoneReportDefs.REASONAPPEAL,
85
85
subject: {
86
86
$type: 'com.atproto.admin.defs#repoRef',
87
87
did: currentAccount.did,
+4
-4
src/screens/Profile/Header/Shell.tsx
+4
-4
src/screens/Profile/Header/Shell.tsx
···
9
9
} from 'react-native-reanimated'
10
10
import {useSafeAreaInsets} from 'react-native-safe-area-context'
11
11
import {type AppBskyActorDefs, type ModerationDecision} from '@atproto/api'
12
+
import {utils} from '@bsky.app/alf'
12
13
import {msg} from '@lingui/macro'
13
14
import {useLingui} from '@lingui/react'
14
15
import {useNavigation} from '@react-navigation/native'
···
26
27
import {UserAvatar} from '#/view/com/util/UserAvatar'
27
28
import {UserBanner} from '#/view/com/util/UserBanner'
28
29
import {atoms as a, platform, useTheme} from '#/alf'
29
-
import {transparentifyColor} from '#/alf/util/colorGeneration'
30
30
import {Button} from '#/components/Button'
31
31
import {useDialogControl} from '#/components/Dialog'
32
32
import {ArrowLeft_Stroke2_Corner0_Rounded as ArrowLeftIcon} from '#/components/icons/Arrow'
···
175
175
style={[
176
176
a.align_center,
177
177
a.justify_center,
178
-
a.rounded_sm,
178
+
a.rounded_full,
179
179
{
180
180
width: 31,
181
181
height: 31,
182
-
backgroundColor: transparentifyColor('#000', 0.5),
182
+
backgroundColor: utils.alpha('#000', 0.5),
183
183
},
184
184
hovered && {
185
-
backgroundColor: transparentifyColor('#000', 0.75),
185
+
backgroundColor: utils.alpha('#000', 0.75),
186
186
},
187
187
]}>
188
188
<ArrowLeftIcon size="lg" fill="white" />
+1
-2
src/screens/Search/Explore.tsx
+1
-2
src/screens/Search/Explore.tsx
···
15
15
import {sanitizeHandle} from '#/lib/strings/handles'
16
16
import {logger} from '#/logger'
17
17
import {type MetricEvents} from '#/logger/metrics'
18
-
import {isNative} from '#/platform/detection'
19
18
import {useLanguagePrefs} from '#/state/preferences/languages'
20
19
import {useModerationOpts} from '#/state/preferences/moderation-opts'
21
20
import {RQKEY_ROOT_PAGINATED as useActorSearchPaginatedQueryKeyRoot} from '#/state/queries/actor-search'
···
924
923
}
925
924
case 'preview:header': {
926
925
return (
927
-
<ModuleHeader.Container style={[a.pt_xs]} bottomBorder={isNative}>
926
+
<ModuleHeader.Container style={[a.pt_xs]} bottomBorder>
928
927
{/* Very non-scientific way to avoid small gap on scroll */}
929
928
<View style={[a.absolute, a.inset_0, t.atoms.bg, {top: -2}]} />
930
929
<ModuleHeader.FeedLink feed={item.feed}>
+1
-1
src/screens/Search/Shell.tsx
+1
-1
src/screens/Search/Shell.tsx
+1
-1
src/screens/Search/modules/ExploreTrendingTopics.tsx
+1
-1
src/screens/Search/modules/ExploreTrendingTopics.tsx
···
97
97
PressableComponent={Pressable}>
98
98
{({hovered, pressed}) => (
99
99
<>
100
-
<SubtleHover hover={hovered || pressed} />
100
+
<SubtleHover hover={hovered || pressed} native />
101
101
<View style={[gutters, a.w_full, a.py_lg, a.flex_row, a.gap_2xs]}>
102
102
<View style={[a.flex_1, a.gap_xs]}>
103
103
<View style={[a.flex_row]}>
+1
-1
src/screens/Settings/components/SettingsList.tsx
+1
-1
src/screens/Settings/components/SettingsList.tsx
+2
-2
src/screens/Takendown.tsx
+2
-2
src/screens/Takendown.tsx
···
3
3
import {SystemBars} from 'react-native-edge-to-edge'
4
4
import {KeyboardAwareScrollView} from 'react-native-keyboard-controller'
5
5
import {useSafeAreaInsets} from 'react-native-safe-area-context'
6
-
import {type ComAtprotoAdminDefs, ComAtprotoModerationDefs} from '@atproto/api'
6
+
import {type ComAtprotoAdminDefs, ToolsOzoneReportDefs} from '@atproto/api'
7
7
import {msg, Trans} from '@lingui/macro'
8
8
import {useLingui} from '@lingui/react'
9
9
import {useMutation} from '@tanstack/react-query'
···
54
54
if (!currentAccount) throw new Error('No session')
55
55
await agent.com.atproto.moderation.createReport(
56
56
{
57
-
reasonType: ComAtprotoModerationDefs.REASONAPPEAL,
57
+
reasonType: ToolsOzoneReportDefs.REASONAPPEAL,
58
58
subject: {
59
59
$type: 'com.atproto.admin.defs#repoRef',
60
60
did: currentAccount.did,
+22
-8
src/screens/VideoFeed/index.tsx
+22
-8
src/screens/VideoFeed/index.tsx
···
57
57
import {sanitizeDisplayName} from '#/lib/strings/display-names'
58
58
import {cleanError} from '#/lib/strings/errors'
59
59
import {sanitizeHandle} from '#/lib/strings/handles'
60
+
import {logger} from '#/logger'
60
61
import {isAndroid} from '#/platform/detection'
61
62
import {useA11y} from '#/state/a11y'
62
63
import {
···
204
205
}, [params])
205
206
const feedUri = params.type === 'feedgen' ? params.uri : undefined
206
207
const {data: feedInfo} = useFeedInfo(feedUri)
207
-
const feedFeedback = useFeedFeedback(feedInfo, hasSession)
208
+
const feedFeedback = useFeedFeedback(feedInfo ?? undefined, hasSession)
208
209
const {data, error, hasNextPage, isFetchingNextPage, fetchNextPage} =
209
210
usePostFeedQuery(
210
211
feedDesc,
···
1044
1045
const {isPlaying} = useEvent(player, 'playingChange', {
1045
1046
isPlaying: player.playing,
1046
1047
})
1048
+
const isMounted = useRef(false)
1047
1049
1048
-
const togglePlayPause = () => {
1049
-
if (!player) return
1050
+
useEffect(() => {
1051
+
isMounted.current = true
1052
+
return () => {
1053
+
isMounted.current = false
1054
+
}
1055
+
}, [])
1056
+
1057
+
const togglePlayPause = useNonReactiveCallback(() => {
1058
+
// gets called after a timeout, so guard against being called after unmount -sfn
1059
+
if (!player || !isMounted.current) return
1050
1060
doubleTapRef.current = null
1051
-
if (player.playing) {
1052
-
player.pause()
1053
-
} else {
1054
-
player.play()
1061
+
try {
1062
+
if (player.playing) {
1063
+
player.pause()
1064
+
} else {
1065
+
player.play()
1066
+
}
1067
+
} catch (err) {
1068
+
logger.error('Could not toggle play/pause', {safeMessage: err})
1055
1069
}
1056
-
}
1070
+
})
1057
1071
1058
1072
const onPress = () => {
1059
1073
if (doubleTapRef.current) {
+1
-1
src/state/queries/feed.ts
+1
-1
src/state/queries/feed.ts
+5
-12
src/state/session/util.ts
+5
-12
src/state/session/util.ts
···
1
1
import {jwtDecode} from 'jwt-decode'
2
2
3
+
import {isJwtExpired} from '#/lib/jwt'
3
4
import {hasProp} from '#/lib/type-guards'
4
-
import {logger} from '#/logger'
5
5
import * as persisted from '#/state/persisted'
6
6
import {type SessionAccount} from './types'
7
7
···
22
22
}
23
23
24
24
export function isSessionExpired(account: SessionAccount) {
25
-
try {
26
-
if (account.accessJwt) {
27
-
const decoded = jwtDecode(account.accessJwt)
28
-
if (decoded.exp) {
29
-
const didExpire = Date.now() >= decoded.exp * 1000
30
-
return didExpire
31
-
}
32
-
}
33
-
} catch (e) {
34
-
logger.error(`session: could not decode jwt`)
25
+
if (account.accessJwt) {
26
+
return isJwtExpired(account.accessJwt)
27
+
} else {
28
+
return true
35
29
}
36
-
return true
37
30
}
-85
src/view/com/profile/FollowButton.tsx
-85
src/view/com/profile/FollowButton.tsx
···
1
-
import {type StyleProp, type TextStyle, View} from 'react-native'
2
-
import {msg} from '@lingui/macro'
3
-
import {useLingui} from '@lingui/react'
4
-
5
-
import {type Shadow} from '#/state/cache/types'
6
-
import {useProfileFollowMutationQueue} from '#/state/queries/profile'
7
-
import type * as bsky from '#/types/bsky'
8
-
import {Button, type ButtonType} from '../util/forms/Button'
9
-
import * as Toast from '../util/Toast'
10
-
11
-
export function FollowButton({
12
-
unfollowedType = 'inverted',
13
-
followedType = 'default',
14
-
profile,
15
-
labelStyle,
16
-
logContext,
17
-
onFollow,
18
-
}: {
19
-
unfollowedType?: ButtonType
20
-
followedType?: ButtonType
21
-
profile: Shadow<bsky.profile.AnyProfileView>
22
-
labelStyle?: StyleProp<TextStyle>
23
-
logContext: 'ProfileCard' | 'StarterPackProfilesList'
24
-
onFollow?: () => void
25
-
}) {
26
-
const [queueFollow, queueUnfollow] = useProfileFollowMutationQueue(
27
-
profile,
28
-
logContext,
29
-
)
30
-
const {_} = useLingui()
31
-
32
-
const onPressFollow = async () => {
33
-
try {
34
-
await queueFollow()
35
-
onFollow?.()
36
-
} catch (e: any) {
37
-
if (e?.name !== 'AbortError') {
38
-
Toast.show(_(msg`An issue occurred, please try again.`), 'xmark')
39
-
}
40
-
}
41
-
}
42
-
43
-
const onPressUnfollow = async () => {
44
-
try {
45
-
await queueUnfollow()
46
-
} catch (e: any) {
47
-
if (e?.name !== 'AbortError') {
48
-
Toast.show(_(msg`An issue occurred, please try again.`), 'xmark')
49
-
}
50
-
}
51
-
}
52
-
53
-
if (!profile.viewer) {
54
-
return <View />
55
-
}
56
-
57
-
if (profile.viewer.following) {
58
-
return (
59
-
<Button
60
-
type={followedType}
61
-
labelStyle={labelStyle}
62
-
onPress={onPressUnfollow}
63
-
label={_(msg({message: 'Unfollow', context: 'action'}))}
64
-
/>
65
-
)
66
-
} else if (!profile.viewer.followedBy) {
67
-
return (
68
-
<Button
69
-
type={unfollowedType}
70
-
labelStyle={labelStyle}
71
-
onPress={onPressFollow}
72
-
label={_(msg({message: 'Follow', context: 'action'}))}
73
-
/>
74
-
)
75
-
} else {
76
-
return (
77
-
<Button
78
-
type={unfollowedType}
79
-
labelStyle={labelStyle}
80
-
onPress={onPressFollow}
81
-
label={_(msg({message: 'Follow back', context: 'action'}))}
82
-
/>
83
-
)
84
-
}
85
-
}
-88
src/view/com/util/EmptyStateWithButton.tsx
-88
src/view/com/util/EmptyStateWithButton.tsx
···
1
-
import {StyleSheet, View} from 'react-native'
2
-
import {type IconProp} from '@fortawesome/fontawesome-svg-core'
3
-
import {
4
-
FontAwesomeIcon,
5
-
type FontAwesomeIconStyle,
6
-
} from '@fortawesome/react-native-fontawesome'
7
-
8
-
import {usePalette} from '#/lib/hooks/usePalette'
9
-
import {s} from '#/lib/styles'
10
-
import {Button} from './forms/Button'
11
-
import {Text} from './text/Text'
12
-
13
-
interface Props {
14
-
testID?: string
15
-
icon: IconProp
16
-
message: string
17
-
buttonLabel: string
18
-
onPress: () => void
19
-
}
20
-
21
-
export function EmptyStateWithButton(props: Props) {
22
-
const pal = usePalette('default')
23
-
const palInverted = usePalette('inverted')
24
-
25
-
return (
26
-
<View testID={props.testID} style={styles.container}>
27
-
<View style={styles.iconContainer}>
28
-
<FontAwesomeIcon
29
-
icon={props.icon}
30
-
style={[styles.icon, pal.text]}
31
-
size={62}
32
-
/>
33
-
</View>
34
-
<Text type="xl-medium" style={[s.textCenter, pal.text]}>
35
-
{props.message}
36
-
</Text>
37
-
<View style={styles.btns}>
38
-
<Button
39
-
testID={props.testID ? `${props.testID}-button` : undefined}
40
-
type="inverted"
41
-
style={styles.btn}
42
-
onPress={props.onPress}>
43
-
<FontAwesomeIcon
44
-
icon="plus"
45
-
style={palInverted.text as FontAwesomeIconStyle}
46
-
size={14}
47
-
/>
48
-
<Text type="lg-medium" style={palInverted.text}>
49
-
{props.buttonLabel}
50
-
</Text>
51
-
</Button>
52
-
</View>
53
-
</View>
54
-
)
55
-
}
56
-
const styles = StyleSheet.create({
57
-
container: {
58
-
height: '100%',
59
-
paddingVertical: 40,
60
-
paddingHorizontal: 30,
61
-
},
62
-
iconContainer: {
63
-
marginBottom: 16,
64
-
},
65
-
icon: {
66
-
marginLeft: 'auto',
67
-
marginRight: 'auto',
68
-
},
69
-
btns: {
70
-
flexDirection: 'row',
71
-
justifyContent: 'center',
72
-
},
73
-
btn: {
74
-
gap: 10,
75
-
marginVertical: 20,
76
-
flexDirection: 'row',
77
-
alignItems: 'center',
78
-
paddingVertical: 14,
79
-
paddingHorizontal: 24,
80
-
borderRadius: 30,
81
-
},
82
-
notice: {
83
-
borderRadius: 12,
84
-
paddingHorizontal: 12,
85
-
paddingVertical: 10,
86
-
marginHorizontal: 30,
87
-
},
88
-
})