this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at e28f6d2f370b4e882ed6f23d08ca0f8d94dbac5f 202 lines 7.0 kB view raw
1import {View} from 'react-native' 2import {type $Typed, ComAtprotoLabelDefs} from '@atproto/api' 3import {Trans, useLingui} from '@lingui/react/macro' 4import {type NativeStackScreenProps} from '@react-navigation/native-stack' 5import {useQueryClient} from '@tanstack/react-query' 6 7import {type CommonNavigatorParams} from '#/lib/routes/types' 8import {RQKEY_ROOT as POST_FEED_RQKEY_ROOT} from '#/state/queries/post-feed' 9import { 10 useProfileQuery, 11 useProfileUpdateMutation, 12} from '#/state/queries/profile' 13import {postThreadQueryKeyRoot} from '#/state/queries/usePostThread/types' 14import {useSession} from '#/state/session' 15import {UserAvatar} from '#/view/com/util/UserAvatar' 16import {atoms as a, platform, useTheme} from '#/alf' 17import {BotBadge} from '#/components/BotBadge' 18import * as Toggle from '#/components/forms/Toggle' 19import {Bot_Filled as RobotIcon} from '#/components/icons/Bot' 20import * as Layout from '#/components/Layout' 21import {Text} from '#/components/Typography' 22import {useSimpleVerificationState} from '#/components/verification' 23import {VerificationCheck} from '#/components/verification/VerificationCheck' 24import {useAnalytics} from '#/analytics' 25import * as bsky from '#/types/bsky' 26 27type Props = NativeStackScreenProps< 28 CommonNavigatorParams, 29 'AutomationLabelSettings' 30> 31export function AutomationLabelSettingsScreen({}: Props) { 32 const t = useTheme() 33 const ax = useAnalytics() 34 const {t: l} = useLingui() 35 const queryClient = useQueryClient() 36 const {currentAccount} = useSession() 37 const {data: profile} = useProfileQuery({did: currentAccount?.did}) 38 const updateProfile = useProfileUpdateMutation() 39 const verification = useSimpleVerificationState({profile}) 40 41 const isBotLabeled = 42 profile?.labels?.some(l => l.val === 'bot' && l.src === profile.did) ?? 43 false 44 const canToggle = profile && !updateProfile.isPending 45 46 const onToggle = () => { 47 if (!profile) { 48 return 49 } 50 let wasAdded = false 51 ax.metric('bot:label:toggle', {state: isBotLabeled ? 'remove' : 'add'}) 52 updateProfile.mutate( 53 { 54 profile, 55 updates: existing => { 56 const labels: $Typed<ComAtprotoLabelDefs.SelfLabels> = bsky.validate( 57 existing.labels, 58 ComAtprotoLabelDefs.validateSelfLabels, 59 ) 60 ? existing.labels 61 : { 62 $type: 'com.atproto.label.defs#selfLabels', 63 values: [], 64 } 65 66 const hasLabel = labels.values.some(l => l.val === 'bot') 67 if (hasLabel) { 68 wasAdded = false 69 labels.values = labels.values.filter(l => l.val !== 'bot') 70 } else { 71 wasAdded = true 72 labels.values.push({val: 'bot'}) 73 } 74 75 if (labels.values.length === 0) { 76 delete existing.labels 77 } else { 78 existing.labels = labels 79 } 80 81 return existing 82 }, 83 checkCommitted: res => { 84 const exists = !!res.data.labels?.some(l => l.val === 'bot') 85 return exists === wasAdded 86 }, 87 }, 88 { 89 onSuccess() { 90 queryClient.invalidateQueries({queryKey: [POST_FEED_RQKEY_ROOT]}) 91 queryClient.invalidateQueries({queryKey: [postThreadQueryKeyRoot]}) 92 }, 93 }, 94 ) 95 } 96 97 return ( 98 <Layout.Screen> 99 <Layout.Header.Outer> 100 <Layout.Header.BackButton /> 101 <Layout.Header.Content> 102 <Layout.Header.TitleText> 103 <Trans>Automation Label</Trans> 104 </Layout.Header.TitleText> 105 </Layout.Header.Content> 106 <Layout.Header.Slot /> 107 </Layout.Header.Outer> 108 <Layout.Content> 109 <View style={[a.p_xl, a.gap_xl]}> 110 {profile && ( 111 <View 112 style={[ 113 a.flex_row, 114 a.justify_center, 115 a.align_center, 116 a.gap_sm, 117 a.rounded_lg, 118 a.border, 119 t.atoms.bg_contrast_50, 120 t.atoms.border_contrast_low, 121 { 122 height: 160, 123 paddingRight: 20, // helps visually center 124 }, 125 ]}> 126 <UserAvatar size={42} avatar={profile.avatar} type="user" /> 127 <View> 128 <View style={[a.flex_row, a.align_baseline]}> 129 <View style={[a.flex_row, a.align_center, a.gap_xs]}> 130 <Text 131 emoji 132 style={[ 133 a.text_xl, 134 a.font_semi_bold, 135 a.flex_shrink, 136 a.leading_tight, 137 ]} 138 numberOfLines={1}> 139 {profile.displayName || profile.handle} 140 </Text> 141 {verification.isVerified && ( 142 <VerificationCheck 143 verifier={verification.role === 'verifier'} 144 size="sm" 145 /> 146 )} 147 <View style={{top: platform({ios: -1})}}> 148 <BotBadge profile={profile} alwaysShow width={17} /> 149 </View> 150 </View> 151 </View> 152 <Text 153 style={[ 154 a.text_md, 155 a.leading_snug, 156 t.atoms.text_contrast_medium, 157 ]} 158 numberOfLines={1}> 159 @{profile.handle} 160 </Text> 161 </View> 162 </View> 163 )} 164 <View style={[a.gap_sm]}> 165 <Text style={[a.text_2xl, a.font_bold]}> 166 <Trans>Add automation label to account</Trans> 167 </Text> 168 <Text style={[a.text_md, a.leading_snug]}> 169 <Trans> 170 This label lets the world know that this account is automated. 171 If turned on, this label appears next to the account's name on 172 their profile and posts. It can be turned on or off at any time. 173 </Trans> 174 </Text> 175 </View> 176 <Toggle.Item 177 name="automation_label" 178 disabled={!canToggle || updateProfile.isPending} 179 value={isBotLabeled} 180 onChange={onToggle} 181 label={l`Show automation label`} 182 style={[ 183 a.w_full, 184 a.p_md, 185 a.rounded_lg, 186 a.border, 187 t.atoms.border_contrast_low, 188 t.atoms.bg_contrast_50, 189 ]}> 190 <View style={[a.pr_xs]}> 191 <RobotIcon width={24} fill={t.atoms.text_contrast_medium.color} /> 192 </View> 193 <Toggle.LabelText style={[a.flex_1, a.text_md, a.font_medium]}> 194 <Trans>Show automation label</Trans> 195 </Toggle.LabelText> 196 <Toggle.Platform /> 197 </Toggle.Item> 198 </View> 199 </Layout.Content> 200 </Layout.Screen> 201 ) 202}