mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
0
fork

Configure Feed

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

at sys-log 217 lines 7.4 kB view raw
1import {useCallback} from 'react' 2import {View} from 'react-native' 3import Animated, { 4 FadeIn, 5 FadeOut, 6 LayoutAnimationConfig, 7 LinearTransition, 8 StretchOutY, 9} from 'react-native-reanimated' 10import {type ComAtprotoServerListAppPasswords} from '@atproto/api' 11import {msg, Trans} from '@lingui/macro' 12import {useLingui} from '@lingui/react' 13import {type NativeStackScreenProps} from '@react-navigation/native-stack' 14 15import {type CommonNavigatorParams} from '#/lib/routes/types' 16import {cleanError} from '#/lib/strings/errors' 17import {isWeb} from '#/platform/detection' 18import { 19 useAppPasswordDeleteMutation, 20 useAppPasswordsQuery, 21} from '#/state/queries/app-passwords' 22import {EmptyState} from '#/view/com/util/EmptyState' 23import {ErrorScreen} from '#/view/com/util/error/ErrorScreen' 24import * as Toast from '#/view/com/util/Toast' 25import {atoms as a, useTheme} from '#/alf' 26import {Admonition, colors} from '#/components/Admonition' 27import {Button, ButtonIcon, ButtonText} from '#/components/Button' 28import {useDialogControl} from '#/components/Dialog' 29import {PlusLarge_Stroke2_Corner0_Rounded as PlusIcon} from '#/components/icons/Plus' 30import {Trash_Stroke2_Corner0_Rounded as TrashIcon} from '#/components/icons/Trash' 31import {Warning_Stroke2_Corner0_Rounded as WarningIcon} from '#/components/icons/Warning' 32import * as Layout from '#/components/Layout' 33import {Loader} from '#/components/Loader' 34import * as Prompt from '#/components/Prompt' 35import {Text} from '#/components/Typography' 36import {AddAppPasswordDialog} from './components/AddAppPasswordDialog' 37import * as SettingsList from './components/SettingsList' 38 39type Props = NativeStackScreenProps<CommonNavigatorParams, 'AppPasswords'> 40export function AppPasswordsScreen({}: Props) { 41 const {_} = useLingui() 42 const {data: appPasswords, error} = useAppPasswordsQuery() 43 const createAppPasswordControl = useDialogControl() 44 45 return ( 46 <Layout.Screen testID="AppPasswordsScreen"> 47 <Layout.Header.Outer> 48 <Layout.Header.BackButton /> 49 <Layout.Header.Content> 50 <Layout.Header.TitleText> 51 <Trans>App Passwords</Trans> 52 </Layout.Header.TitleText> 53 </Layout.Header.Content> 54 <Layout.Header.Slot /> 55 </Layout.Header.Outer> 56 <Layout.Content> 57 {error ? ( 58 <ErrorScreen 59 title={_(msg`Oops!`)} 60 message={_(msg`There was an issue fetching your app passwords`)} 61 details={cleanError(error)} 62 /> 63 ) : ( 64 <SettingsList.Container> 65 <SettingsList.Item> 66 <Admonition type="tip" style={[a.flex_1]}> 67 <Trans> 68 Use app passwords to sign in to other Bluesky clients without 69 giving full access to your account or password. 70 </Trans> 71 </Admonition> 72 </SettingsList.Item> 73 <SettingsList.Item> 74 <Button 75 label={_(msg`Add App Password`)} 76 size="large" 77 color="primary" 78 variant="solid" 79 onPress={() => createAppPasswordControl.open()} 80 style={[a.flex_1]}> 81 <ButtonIcon icon={PlusIcon} /> 82 <ButtonText> 83 <Trans>Add App Password</Trans> 84 </ButtonText> 85 </Button> 86 </SettingsList.Item> 87 <SettingsList.Divider /> 88 <LayoutAnimationConfig skipEntering skipExiting> 89 {appPasswords ? ( 90 appPasswords.length > 0 ? ( 91 <View style={[a.overflow_hidden]}> 92 {appPasswords.map(appPassword => ( 93 <Animated.View 94 key={appPassword.name} 95 style={a.w_full} 96 entering={FadeIn} 97 exiting={isWeb ? FadeOut : StretchOutY} 98 layout={LinearTransition.delay(150)}> 99 <SettingsList.Item> 100 <AppPasswordCard appPassword={appPassword} /> 101 </SettingsList.Item> 102 </Animated.View> 103 ))} 104 </View> 105 ) : ( 106 <EmptyState 107 icon="growth" 108 message={_(msg`No app passwords yet`)} 109 /> 110 ) 111 ) : ( 112 <View 113 style={[ 114 a.flex_1, 115 a.justify_center, 116 a.align_center, 117 a.py_4xl, 118 ]}> 119 <Loader size="xl" /> 120 </View> 121 )} 122 </LayoutAnimationConfig> 123 </SettingsList.Container> 124 )} 125 </Layout.Content> 126 127 <AddAppPasswordDialog 128 control={createAppPasswordControl} 129 passwords={appPasswords?.map(p => p.name) || []} 130 /> 131 </Layout.Screen> 132 ) 133} 134 135function AppPasswordCard({ 136 appPassword, 137}: { 138 appPassword: ComAtprotoServerListAppPasswords.AppPassword 139}) { 140 const t = useTheme() 141 const {i18n, _} = useLingui() 142 const deleteControl = Prompt.usePromptControl() 143 const {mutateAsync: deleteMutation} = useAppPasswordDeleteMutation() 144 145 const onDelete = useCallback(async () => { 146 await deleteMutation({name: appPassword.name}) 147 Toast.show(_(msg({message: 'App password deleted', context: 'toast'}))) 148 }, [deleteMutation, appPassword.name, _]) 149 150 return ( 151 <View 152 style={[ 153 a.w_full, 154 a.border, 155 a.rounded_sm, 156 a.px_md, 157 a.py_sm, 158 t.atoms.bg_contrast_25, 159 t.atoms.border_contrast_low, 160 ]}> 161 <View 162 style={[ 163 a.flex_row, 164 a.justify_between, 165 a.align_start, 166 a.w_full, 167 a.gap_sm, 168 ]}> 169 <View style={[a.gap_xs]}> 170 <Text style={[t.atoms.text, a.text_md, a.font_bold]}> 171 {appPassword.name} 172 </Text> 173 <Text style={[t.atoms.text_contrast_medium]}> 174 <Trans> 175 Created{' '} 176 {i18n.date(appPassword.createdAt, { 177 year: 'numeric', 178 month: 'numeric', 179 day: 'numeric', 180 hour: '2-digit', 181 minute: '2-digit', 182 })} 183 </Trans> 184 </Text> 185 </View> 186 <Button 187 label={_(msg`Delete app password`)} 188 variant="ghost" 189 color="negative" 190 size="small" 191 style={[a.bg_transparent]} 192 onPress={() => deleteControl.open()}> 193 <ButtonIcon icon={TrashIcon} /> 194 </Button> 195 </View> 196 {appPassword.privileged && ( 197 <View style={[a.flex_row, a.gap_sm, a.align_center, a.mt_md]}> 198 <WarningIcon style={[{color: colors.warning[t.scheme]}]} /> 199 <Text style={t.atoms.text_contrast_high}> 200 <Trans>Allows access to direct messages</Trans> 201 </Text> 202 </View> 203 )} 204 205 <Prompt.Basic 206 control={deleteControl} 207 title={_(msg`Delete app password?`)} 208 description={_( 209 msg`Are you sure you want to delete the app password "${appPassword.name}"?`, 210 )} 211 onConfirm={onDelete} 212 confirmButtonCta={_(msg`Delete`)} 213 confirmButtonColor="negative" 214 /> 215 </View> 216 ) 217}