Bluesky app fork with some witchin' additions 馃挮
0
fork

Configure Feed

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

at cope-settings-sync 209 lines 6.5 kB view raw
1import {useCallback, useImperativeHandle, useRef, useState} from 'react' 2import {View} from 'react-native' 3import {msg} from '@lingui/core/macro' 4import {useLingui} from '@lingui/react' 5import {Trans} from '@lingui/react/macro' 6 7import {BSKY_SERVICE} from '#/lib/constants' 8import * as persisted from '#/state/persisted' 9import {useSession} from '#/state/session' 10import {atoms as a, platform, useBreakpoints, useTheme, web} from '#/alf' 11import {Admonition} from '#/components/Admonition' 12import {Button, ButtonText} from '#/components/Button' 13import * as Dialog from '#/components/Dialog' 14import * as TextField from '#/components/forms/TextField' 15import {Globe_Stroke2_Corner0_Rounded as Globe} from '#/components/icons/Globe' 16import {InlineLinkText} from '#/components/Link' 17import {Text} from '#/components/Typography' 18import {useAnalytics} from '#/analytics' 19 20export function ServerInputDialog({ 21 control, 22 onSelect, 23}: { 24 control: Dialog.DialogOuterProps['control'] 25 onSelect: (url: string) => void 26}) { 27 const ax = useAnalytics() 28 const formRef = useRef<DialogInnerRef>(null) 29 30 // persist these options between dialog open/close 31 const [previousCustomAddress, setPreviousCustomAddress] = useState('') 32 33 const onClose = useCallback(() => { 34 const result = formRef.current?.getFormState() 35 if (result) { 36 onSelect(result) 37 if (result !== BSKY_SERVICE) { 38 setPreviousCustomAddress(result) 39 } 40 } 41 ax.metric('signin:hostingProviderPressed', { 42 hostingProviderDidChange: result !== BSKY_SERVICE, 43 }) 44 }, [ax, onSelect]) 45 46 return ( 47 <Dialog.Outer 48 control={control} 49 onClose={onClose} 50 nativeOptions={{preventExpansion: true}}> 51 <Dialog.Handle /> 52 <DialogInner 53 formRef={formRef} 54 initialCustomAddress={previousCustomAddress} 55 /> 56 </Dialog.Outer> 57 ) 58} 59 60type DialogInnerRef = {getFormState: () => string | null} 61 62function DialogInner({ 63 formRef, 64 initialCustomAddress, 65}: { 66 formRef: React.Ref<DialogInnerRef> 67 initialCustomAddress: string 68}) { 69 const control = Dialog.useDialogContext() 70 const {_} = useLingui() 71 const t = useTheme() 72 const {accounts} = useSession() 73 const {gtMobile} = useBreakpoints() 74 const [customAddress, setCustomAddress] = useState(initialCustomAddress) 75 const [pdsAddressHistory, setPdsAddressHistory] = useState<string[]>( 76 persisted.get('pdsAddressHistory') || [], 77 ) 78 79 useImperativeHandle( 80 formRef, 81 () => ({ 82 getFormState: () => { 83 let url = customAddress.trim().toLowerCase() 84 if (!url) { 85 return null 86 } 87 if (!url.startsWith('http://') && !url.startsWith('https://')) { 88 if (url === 'localhost' || url.startsWith('localhost:')) { 89 url = `http://${url}` 90 } else { 91 url = `https://${url}` 92 } 93 } 94 95 if (!pdsAddressHistory.includes(url)) { 96 const newHistory = [url, ...pdsAddressHistory.slice(0, 4)] 97 setPdsAddressHistory(newHistory) 98 persisted.write('pdsAddressHistory', newHistory) 99 } 100 101 return url 102 }, 103 }), 104 [customAddress, pdsAddressHistory], 105 ) 106 107 const isFirstTimeUser = accounts.length === 0 108 109 return ( 110 <Dialog.ScrollableInner 111 accessibilityDescribedBy="dialog-description" 112 accessibilityLabelledBy="dialog-title" 113 style={web({maxWidth: 500})}> 114 <View style={[a.relative, a.gap_md, a.w_full]}> 115 <Text nativeID="dialog-title" style={[a.text_2xl, a.font_bold]}> 116 <Trans>Choose your account provider</Trans> 117 </Text> 118 119 {isFirstTimeUser && ( 120 <Admonition type="tip"> 121 <Trans> 122 Bluesky is an open network where you can choose your own provider. 123 If you're new here, we recommend sticking with the default Bluesky 124 Social option. 125 </Trans> 126 </Admonition> 127 )} 128 129 <View 130 style={[ 131 a.border, 132 t.atoms.border_contrast_low, 133 a.rounded_sm, 134 a.px_md, 135 a.py_md, 136 ]}> 137 <TextField.LabelText nativeID="address-input-label"> 138 <Trans>Server address</Trans> 139 </TextField.LabelText> 140 <TextField.Root> 141 <TextField.Icon icon={Globe} /> 142 <Dialog.Input 143 testID="customServerTextInput" 144 value={customAddress} 145 onChangeText={setCustomAddress} 146 label="my-server.com" 147 accessibilityLabelledBy="address-input-label" 148 autoCapitalize="none" 149 keyboardType="url" 150 /> 151 </TextField.Root> 152 {pdsAddressHistory.length > 0 && ( 153 <View style={[a.flex_row, a.flex_wrap, a.mt_xs]}> 154 {pdsAddressHistory.map(uri => ( 155 <Button 156 key={uri} 157 variant="ghost" 158 color="primary" 159 label={uri} 160 style={[a.px_sm, a.py_xs, a.rounded_sm, a.gap_sm]} 161 onPress={() => setCustomAddress(uri)}> 162 <ButtonText>{uri}</ButtonText> 163 </Button> 164 ))} 165 </View> 166 )} 167 </View> 168 169 <View style={[a.py_xs]}> 170 <Text 171 style={[t.atoms.text_contrast_medium, a.text_sm, a.leading_snug]}> 172 {isFirstTimeUser ? ( 173 <Trans> 174 If you're a developer, you can host your own server. 175 </Trans> 176 ) : ( 177 <Trans> 178 Bluesky is an open network where you can choose your hosting 179 provider. If you're a developer, you can host your own server. 180 </Trans> 181 )}{' '} 182 <InlineLinkText 183 label={_(msg`Learn more about self hosting your PDS.`)} 184 to="https://atproto.com/guides/self-hosting"> 185 <Trans>Learn more.</Trans> 186 </InlineLinkText> 187 </Text> 188 </View> 189 190 <View style={gtMobile && [a.flex_row, a.justify_end]}> 191 <Button 192 testID="doneBtn" 193 variant="solid" 194 color="primary" 195 size={platform({ 196 native: 'large', 197 web: 'small', 198 })} 199 onPress={() => control.close()} 200 label={_(msg`Done`)}> 201 <ButtonText> 202 <Trans>Done</Trans> 203 </ButtonText> 204 </Button> 205 </View> 206 </View> 207 </Dialog.ScrollableInner> 208 ) 209}