Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

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

Focus the text input on tap during the composer

+146 -136
+146 -136
src/view/com/composer/ComposePost.tsx
··· 9 9 StyleSheet, 10 10 TextInput, 11 11 TouchableOpacity, 12 + TouchableWithoutFeedback, 12 13 View, 13 14 } from 'react-native' 14 15 import LinearGradient from 'react-native-linear-gradient' ··· 88 89 } 89 90 }, []) 90 91 92 + const onPressContainer = () => { 93 + textInput.current?.focus() 94 + } 91 95 const onPressSelectPhotos = () => { 92 96 if (isSelectingPhotos) { 93 97 setIsSelectingPhotos(false) ··· 183 187 testID="composePostView" 184 188 behavior={Platform.OS === 'ios' ? 'padding' : 'height'} 185 189 style={[pal.view, styles.outer]}> 186 - <SafeAreaView style={s.flex1}> 187 - <View style={styles.topbar}> 188 - <TouchableOpacity 189 - testID="composerCancelButton" 190 - onPress={onPressCancel}> 191 - <Text style={[pal.link, s.f18]}>Cancel</Text> 192 - </TouchableOpacity> 193 - <View style={s.flex1} /> 190 + <TouchableWithoutFeedback onPressIn={onPressContainer}> 191 + <SafeAreaView style={s.flex1}> 192 + <View style={styles.topbar}> 193 + <TouchableOpacity 194 + testID="composerCancelButton" 195 + onPress={onPressCancel}> 196 + <Text style={[pal.link, s.f18]}>Cancel</Text> 197 + </TouchableOpacity> 198 + <View style={s.flex1} /> 199 + {isProcessing ? ( 200 + <View style={styles.postBtn}> 201 + <ActivityIndicator /> 202 + </View> 203 + ) : canPost ? ( 204 + <TouchableOpacity 205 + testID="composerPublishButton" 206 + onPress={onPressPublish}> 207 + <LinearGradient 208 + colors={[gradients.blueLight.start, gradients.blueLight.end]} 209 + start={{x: 0, y: 0}} 210 + end={{x: 1, y: 1}} 211 + style={styles.postBtn}> 212 + <Text style={[s.white, s.f16, s.bold]}> 213 + {replyTo ? 'Reply' : 'Post'} 214 + </Text> 215 + </LinearGradient> 216 + </TouchableOpacity> 217 + ) : ( 218 + <View style={[styles.postBtn, pal.btn]}> 219 + <Text style={[pal.textLight, s.f16, s.bold]}>Post</Text> 220 + </View> 221 + )} 222 + </View> 194 223 {isProcessing ? ( 195 - <View style={styles.postBtn}> 196 - <ActivityIndicator /> 224 + <View style={[pal.btn, styles.processingLine]}> 225 + <Text style={s.black}>{processingState}</Text> 197 226 </View> 198 - ) : canPost ? ( 199 - <TouchableOpacity 200 - testID="composerPublishButton" 201 - onPress={onPressPublish}> 202 - <LinearGradient 203 - colors={[gradients.blueLight.start, gradients.blueLight.end]} 204 - start={{x: 0, y: 0}} 205 - end={{x: 1, y: 1}} 206 - style={styles.postBtn}> 207 - <Text style={[s.white, s.f16, s.bold]}> 208 - {replyTo ? 'Reply' : 'Post'} 209 - </Text> 210 - </LinearGradient> 211 - </TouchableOpacity> 212 - ) : ( 213 - <View style={[styles.postBtn, pal.btn]}> 214 - <Text style={[pal.textLight, s.f16, s.bold]}>Post</Text> 227 + ) : undefined} 228 + {error !== '' && ( 229 + <View style={styles.errorLine}> 230 + <View style={styles.errorIcon}> 231 + <FontAwesomeIcon 232 + icon="exclamation" 233 + style={{color: colors.red4}} 234 + size={10} 235 + /> 236 + </View> 237 + <Text style={[s.red4, s.flex1]}>{error}</Text> 215 238 </View> 216 239 )} 217 - </View> 218 - {isProcessing ? ( 219 - <View style={[pal.btn, styles.processingLine]}> 220 - <Text style={s.black}>{processingState}</Text> 221 - </View> 222 - ) : undefined} 223 - {error !== '' && ( 224 - <View style={styles.errorLine}> 225 - <View style={styles.errorIcon}> 226 - <FontAwesomeIcon 227 - icon="exclamation" 228 - style={{color: colors.red4}} 229 - size={10} 230 - /> 231 - </View> 232 - <Text style={[s.red4, s.flex1]}>{error}</Text> 233 - </View> 234 - )} 235 - <ScrollView style={s.flex1}> 236 - {replyTo ? ( 237 - <View style={[pal.border, styles.replyToLayout]}> 240 + <ScrollView style={s.flex1}> 241 + {replyTo ? ( 242 + <View style={[pal.border, styles.replyToLayout]}> 243 + <UserAvatar 244 + handle={replyTo.author.handle} 245 + displayName={replyTo.author.displayName} 246 + avatar={replyTo.author.avatar} 247 + size={50} 248 + /> 249 + <View style={styles.replyToPost}> 250 + <TextLink 251 + type="xl-medium" 252 + href={`/profile/${replyTo.author.handle}`} 253 + text={replyTo.author.displayName || replyTo.author.handle} 254 + style={[pal.text]} 255 + /> 256 + <Text type="post-text" style={pal.text} numberOfLines={6}> 257 + {replyTo.text} 258 + </Text> 259 + </View> 260 + </View> 261 + ) : undefined} 262 + <View 263 + style={[ 264 + pal.border, 265 + styles.textInputLayout, 266 + selectTextInputLayout, 267 + ]}> 238 268 <UserAvatar 239 - handle={replyTo.author.handle} 240 - displayName={replyTo.author.displayName} 241 - avatar={replyTo.author.avatar} 269 + handle={store.me.handle || ''} 270 + displayName={store.me.displayName} 271 + avatar={store.me.avatar} 242 272 size={50} 243 273 /> 244 - <View style={styles.replyToPost}> 245 - <TextLink 246 - type="xl-medium" 247 - href={`/profile/${replyTo.author.handle}`} 248 - text={replyTo.author.displayName || replyTo.author.handle} 249 - style={[pal.text]} 250 - /> 251 - <Text type="post-text" style={pal.text} numberOfLines={6}> 252 - {replyTo.text} 253 - </Text> 254 - </View> 274 + <TextInput 275 + testID="composerTextInput" 276 + ref={textInput} 277 + multiline 278 + scrollEnabled 279 + onChangeText={(text: string) => onChangeText(text)} 280 + placeholder={selectTextInputPlaceholder} 281 + placeholderTextColor={pal.colors.textLight} 282 + style={[pal.text, styles.textInput]}> 283 + {textDecorated} 284 + </TextInput> 255 285 </View> 256 - ) : undefined} 257 - <View 258 - style={[pal.border, styles.textInputLayout, selectTextInputLayout]}> 259 - <UserAvatar 260 - handle={store.me.handle || ''} 261 - displayName={store.me.displayName} 262 - avatar={store.me.avatar} 263 - size={50} 264 - /> 265 - <TextInput 266 - testID="composerTextInput" 267 - ref={textInput} 268 - multiline 269 - scrollEnabled 270 - onChangeText={(text: string) => onChangeText(text)} 271 - placeholder={selectTextInputPlaceholder} 272 - placeholderTextColor={pal.colors.textLight} 273 - style={[pal.text, styles.textInput]}> 274 - {textDecorated} 275 - </TextInput> 276 - </View> 277 - <SelectedPhoto 278 - selectedPhotos={selectedPhotos} 279 - onSelectPhotos={onSelectPhotos} 280 - /> 281 - </ScrollView> 282 - {isSelectingPhotos && 283 - localPhotos.photos != null && 284 - selectedPhotos.length < 4 && ( 285 - <PhotoCarouselPicker 286 + <SelectedPhoto 286 287 selectedPhotos={selectedPhotos} 287 288 onSelectPhotos={onSelectPhotos} 288 - localPhotos={localPhotos} 289 289 /> 290 - )} 291 - <View style={[pal.border, styles.bottomBar]}> 292 - <TouchableOpacity 293 - testID="composerSelectPhotosButton" 294 - onPress={onPressSelectPhotos} 295 - style={[s.pl5]} 296 - hitSlop={HITSLOP}> 297 - <FontAwesomeIcon 298 - icon={['far', 'image']} 299 - style={selectedPhotos.length < 4 ? pal.link : pal.textLight} 300 - size={24} 301 - /> 302 - </TouchableOpacity> 303 - <View style={s.flex1} /> 304 - <Text style={[s.mr10, {color: progressColor}]}> 305 - {MAX_TEXT_LENGTH - text.length} 306 - </Text> 307 - <View> 308 - {text.length > DANGER_TEXT_LENGTH ? ( 309 - <ProgressPie 310 - size={30} 311 - borderWidth={4} 312 - borderColor={progressColor} 313 - color={progressColor} 314 - progress={Math.min( 315 - (text.length - MAX_TEXT_LENGTH) / MAX_TEXT_LENGTH, 316 - 1, 317 - )} 290 + </ScrollView> 291 + {isSelectingPhotos && 292 + localPhotos.photos != null && 293 + selectedPhotos.length < 4 && ( 294 + <PhotoCarouselPicker 295 + selectedPhotos={selectedPhotos} 296 + onSelectPhotos={onSelectPhotos} 297 + localPhotos={localPhotos} 318 298 /> 319 - ) : ( 320 - <ProgressCircle 321 - size={30} 322 - borderWidth={1} 323 - borderColor={colors.gray2} 324 - color={progressColor} 325 - progress={text.length / MAX_TEXT_LENGTH} 299 + )} 300 + <View style={[pal.border, styles.bottomBar]}> 301 + <TouchableOpacity 302 + testID="composerSelectPhotosButton" 303 + onPress={onPressSelectPhotos} 304 + style={[s.pl5]} 305 + hitSlop={HITSLOP}> 306 + <FontAwesomeIcon 307 + icon={['far', 'image']} 308 + style={selectedPhotos.length < 4 ? pal.link : pal.textLight} 309 + size={24} 326 310 /> 327 - )} 311 + </TouchableOpacity> 312 + <View style={s.flex1} /> 313 + <Text style={[s.mr10, {color: progressColor}]}> 314 + {MAX_TEXT_LENGTH - text.length} 315 + </Text> 316 + <View> 317 + {text.length > DANGER_TEXT_LENGTH ? ( 318 + <ProgressPie 319 + size={30} 320 + borderWidth={4} 321 + borderColor={progressColor} 322 + color={progressColor} 323 + progress={Math.min( 324 + (text.length - MAX_TEXT_LENGTH) / MAX_TEXT_LENGTH, 325 + 1, 326 + )} 327 + /> 328 + ) : ( 329 + <ProgressCircle 330 + size={30} 331 + borderWidth={1} 332 + borderColor={colors.gray2} 333 + color={progressColor} 334 + progress={text.length / MAX_TEXT_LENGTH} 335 + /> 336 + )} 337 + </View> 328 338 </View> 329 - </View> 330 - <Autocomplete 331 - active={autocompleteView.isActive} 332 - items={autocompleteView.suggestions} 333 - onSelect={onSelectAutocompleteItem} 334 - /> 335 - </SafeAreaView> 339 + <Autocomplete 340 + active={autocompleteView.isActive} 341 + items={autocompleteView.suggestions} 342 + onSelect={onSelectAutocompleteItem} 343 + /> 344 + </SafeAreaView> 345 + </TouchableWithoutFeedback> 336 346 </KeyboardAvoidingView> 337 347 ) 338 348 })