Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

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

Restore quick language select (#8981)

* restore quick language select

* rm showCancel

* rm margin from thread button

* alf composer icons

* stop hiding keyboard

* use trans

authored by samuel.fm and committed by

GitHub ee3e0839 0f089060

+154 -90
+2 -2
src/state/persisted/schema.ts
··· 78 78 postLanguage: z.string(), 79 79 /** 80 80 * The user's post language history, used to pre-populate the post language 81 - * selector in the composer. Within each value, multiple languages are 82 - * separated by values. 81 + * selector in the composer. Within each value, multiple languages are separated 82 + * by commas. 83 83 * 84 84 * BCP-47 2-letter language codes without region. 85 85 */
+13 -16
src/view/com/composer/Composer.tsx
··· 110 110 import {Gallery} from '#/view/com/composer/photos/Gallery' 111 111 import {OpenCameraBtn} from '#/view/com/composer/photos/OpenCameraBtn' 112 112 import {SelectGifBtn} from '#/view/com/composer/photos/SelectGifBtn' 113 - import {SelectPostLanguagesBtn} from '#/view/com/composer/select-language/SelectPostLanguagesDialog' 114 113 import {SuggestedLanguage} from '#/view/com/composer/select-language/SuggestedLanguage' 115 114 // TODO: Prevent naming components that coincide with RN primitives 116 115 // due to linting false positives ··· 123 122 import {UserAvatar} from '#/view/com/util/UserAvatar' 124 123 import {atoms as a, native, useTheme, web} from '#/alf' 125 124 import {Button, ButtonIcon, ButtonText} from '#/components/Button' 126 - import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo' 127 - import {EmojiArc_Stroke2_Corner0_Rounded as EmojiSmile} from '#/components/icons/Emoji' 128 - import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times' 125 + import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfoIcon} from '#/components/icons/CircleInfo' 126 + import {EmojiArc_Stroke2_Corner0_Rounded as EmojiSmileIcon} from '#/components/icons/Emoji' 127 + import {PlusLarge_Stroke2_Corner0_Rounded as PlusIcon} from '#/components/icons/Plus' 128 + import {TimesLarge_Stroke2_Corner0_Rounded as XIcon} from '#/components/icons/Times' 129 129 import {LazyQuoteEmbed} from '#/components/Post/Embed/LazyQuoteEmbed' 130 130 import * as Prompt from '#/components/Prompt' 131 131 import * as Toast from '#/components/Toast' 132 132 import {Text as NewText} from '#/components/Typography' 133 133 import {BottomSheetPortalProvider} from '../../../../modules/bottom-sheet' 134 + import {PostLanguageSelect} from './select-language/PostLanguageSelect' 134 135 import { 135 136 type AssetType, 136 137 SelectMediaButton, ··· 941 942 }) 942 943 } 943 944 }}> 944 - <ButtonIcon icon={X} /> 945 + <ButtonIcon icon={XIcon} /> 945 946 </Button> 946 947 <Prompt.Basic 947 948 control={discardPromptControl} ··· 1430 1431 variant="ghost" 1431 1432 shape="round" 1432 1433 color="primary"> 1433 - <EmojiSmile size="lg" /> 1434 + <EmojiSmileIcon size="lg" /> 1434 1435 </Button> 1435 1436 ) : null} 1436 1437 </ToolbarWrapper> ··· 1440 1441 <View style={[a.flex_row, a.align_center, a.justify_between]}> 1441 1442 {showAddButton && ( 1442 1443 <Button 1443 - label={_(msg`Add new post`)} 1444 + label={_(msg`Add another post to thread`)} 1444 1445 onPress={onAddPost} 1445 - style={[a.p_sm, a.m_2xs]} 1446 + style={[a.p_sm]} 1446 1447 variant="ghost" 1447 1448 shape="round" 1448 1449 color="primary"> 1449 - <FontAwesomeIcon 1450 - icon="add" 1451 - size={20} 1452 - color={t.palette.primary_500} 1453 - /> 1450 + <PlusIcon size="lg" /> 1454 1451 </Button> 1455 1452 )} 1456 - <SelectPostLanguagesBtn /> 1453 + <PostLanguageSelect /> 1457 1454 <CharProgress 1458 1455 count={post.shortenedGraphemeLength} 1459 1456 style={{width: 65}} ··· 1753 1750 t.atoms.bg_contrast_25, 1754 1751 ]}> 1755 1752 <View style={[a.relative, a.flex_row, a.gap_sm, {paddingRight: 48}]}> 1756 - <CircleInfo fill={t.palette.negative_400} /> 1753 + <CircleInfoIcon fill={t.palette.negative_400} /> 1757 1754 <NewText style={[a.flex_1, a.leading_snug, {paddingTop: 1}]}> 1758 1755 {error} 1759 1756 </NewText> ··· 1765 1762 shape="round" 1766 1763 style={[a.absolute, {top: 0, right: 0}]} 1767 1764 onPress={onClearError}> 1768 - <ButtonIcon icon={X} /> 1765 + <ButtonIcon icon={XIcon} /> 1769 1766 </Button> 1770 1767 </View> 1771 1768 {videoError && videoState.jobId && (
+131
src/view/com/composer/select-language/PostLanguageSelect.tsx
··· 1 + import {msg, Trans} from '@lingui/macro' 2 + import {useLingui} from '@lingui/react' 3 + 4 + import {LANG_DROPDOWN_HITSLOP} from '#/lib/constants' 5 + import {codeToLanguageName} from '#/locale/helpers' 6 + import { 7 + toPostLanguages, 8 + useLanguagePrefs, 9 + useLanguagePrefsApi, 10 + } from '#/state/preferences/languages' 11 + import {atoms as a, useTheme} from '#/alf' 12 + import {Button, type ButtonProps} from '#/components/Button' 13 + import * as Dialog from '#/components/Dialog' 14 + import {ChevronRight_Stroke2_Corner0_Rounded as ChevronRightIcon} from '#/components/icons/Chevron' 15 + import {Globe_Stroke2_Corner0_Rounded as GlobeIcon} from '#/components/icons/Globe' 16 + import * as Menu from '#/components/Menu' 17 + import {Text} from '#/components/Typography' 18 + import {PostLanguageSelectDialog} from './PostLanguageSelectDialog' 19 + 20 + export function PostLanguageSelect() { 21 + const {_} = useLingui() 22 + const langPrefs = useLanguagePrefs() 23 + const setLangPrefs = useLanguagePrefsApi() 24 + const languageDialogControl = Dialog.useDialogControl() 25 + 26 + const dedupedHistory = Array.from( 27 + new Set([...langPrefs.postLanguageHistory, langPrefs.postLanguage]), 28 + ) 29 + 30 + if ( 31 + dedupedHistory.length === 1 && 32 + dedupedHistory[0] === langPrefs.postLanguage 33 + ) { 34 + return ( 35 + <> 36 + <LanguageBtn onPress={languageDialogControl.open} /> 37 + <PostLanguageSelectDialog control={languageDialogControl} /> 38 + </> 39 + ) 40 + } 41 + 42 + return ( 43 + <> 44 + <Menu.Root> 45 + <Menu.Trigger label={_(msg`Select post language`)}> 46 + {({props}) => <LanguageBtn {...props} />} 47 + </Menu.Trigger> 48 + <Menu.Outer> 49 + <Menu.Group> 50 + {dedupedHistory.map(historyItem => { 51 + const langCodes = historyItem.split(',') 52 + const langName = langCodes 53 + .map(code => codeToLanguageName(code, langPrefs.appLanguage)) 54 + .join(' + ') 55 + return ( 56 + <Menu.Item 57 + key={historyItem} 58 + label={_(msg`Select ${langName}`)} 59 + onPress={() => setLangPrefs.setPostLanguage(historyItem)}> 60 + <Menu.ItemText>{langName}</Menu.ItemText> 61 + <Menu.ItemRadio 62 + selected={historyItem === langPrefs.postLanguage} 63 + /> 64 + </Menu.Item> 65 + ) 66 + })} 67 + </Menu.Group> 68 + <Menu.Divider /> 69 + <Menu.Item 70 + label={_(msg`More languages...`)} 71 + onPress={languageDialogControl.open}> 72 + <Menu.ItemText> 73 + <Trans>More languages...</Trans> 74 + </Menu.ItemText> 75 + <Menu.ItemIcon icon={ChevronRightIcon} /> 76 + </Menu.Item> 77 + </Menu.Outer> 78 + </Menu.Root> 79 + 80 + <PostLanguageSelectDialog control={languageDialogControl} /> 81 + </> 82 + ) 83 + } 84 + 85 + function LanguageBtn(props: Omit<ButtonProps, 'label' | 'children'>) { 86 + const {_} = useLingui() 87 + const langPrefs = useLanguagePrefs() 88 + const t = useTheme() 89 + 90 + const postLanguagesPref = toPostLanguages(langPrefs.postLanguage) 91 + 92 + return ( 93 + <Button 94 + testID="selectLangBtn" 95 + size="small" 96 + hitSlop={LANG_DROPDOWN_HITSLOP} 97 + label={_( 98 + msg({ 99 + message: `Post language selection`, 100 + comment: `Accessibility label for button that opens dialog to choose post language settings`, 101 + }), 102 + )} 103 + accessibilityHint={_(msg`Opens post language settings`)} 104 + style={[a.mr_xs]} 105 + {...props}> 106 + {({pressed, hovered}) => { 107 + const color = 108 + pressed || hovered ? t.palette.primary_300 : t.palette.primary_500 109 + if (postLanguagesPref.length > 0) { 110 + return ( 111 + <Text 112 + style={[ 113 + {color}, 114 + a.font_bold, 115 + a.text_sm, 116 + a.leading_snug, 117 + {maxWidth: 100}, 118 + ]} 119 + numberOfLines={1}> 120 + {postLanguagesPref 121 + .map(lang => codeToLanguageName(lang, langPrefs.appLanguage)) 122 + .join(', ')} 123 + </Text> 124 + ) 125 + } else { 126 + return <GlobeIcon size="xs" style={{color}} /> 127 + } 128 + }} 129 + </Button> 130 + ) 131 + }
+8 -72
src/view/com/composer/select-language/SelectPostLanguagesDialog.tsx src/view/com/composer/select-language/PostLanguageSelectDialog.tsx
··· 1 1 import {useCallback, useMemo, useState} from 'react' 2 - import {Keyboard, useWindowDimensions, View} from 'react-native' 2 + import {useWindowDimensions, View} from 'react-native' 3 3 import {useSafeAreaInsets} from 'react-native-safe-area-context' 4 4 import {msg, Trans} from '@lingui/macro' 5 5 import {useLingui} from '@lingui/react' 6 6 7 - import {LANG_DROPDOWN_HITSLOP} from '#/lib/constants' 8 7 import {languageName} from '#/locale/helpers' 9 - import {codeToLanguageName} from '#/locale/helpers' 10 8 import {type Language, LANGUAGES, LANGUAGES_MAP_CODE2} from '#/locale/languages' 11 9 import {isNative, isWeb} from '#/platform/detection' 12 10 import { 13 - toPostLanguages, 14 11 useLanguagePrefs, 15 12 useLanguagePrefsApi, 16 13 } from '#/state/preferences/languages' ··· 21 18 import * as Dialog from '#/components/Dialog' 22 19 import {SearchInput} from '#/components/forms/SearchInput' 23 20 import * as Toggle from '#/components/forms/Toggle' 24 - import {Globe_Stroke2_Corner0_Rounded as GlobeIcon} from '#/components/icons/Globe' 25 21 import {TimesLarge_Stroke2_Corner0_Rounded as XIcon} from '#/components/icons/Times' 26 22 import {Text} from '#/components/Typography' 27 23 28 - export function SelectPostLanguagesBtn() { 29 - const {_} = useLingui() 30 - const langPrefs = useLanguagePrefs() 31 - const t = useTheme() 32 - const control = Dialog.useDialogControl() 33 - 34 - const onPressMore = useCallback(async () => { 35 - if (isNative) { 36 - if (Keyboard.isVisible()) { 37 - Keyboard.dismiss() 38 - } 39 - } 40 - control.open() 41 - }, [control]) 42 - 43 - const postLanguagesPref = toPostLanguages(langPrefs.postLanguage) 44 - 45 - return ( 46 - <> 47 - <Button 48 - testID="selectLangBtn" 49 - onPress={onPressMore} 50 - size="small" 51 - hitSlop={LANG_DROPDOWN_HITSLOP} 52 - label={_( 53 - msg({ 54 - message: `Post language selection`, 55 - comment: `Accessibility label for button that opens dialog to choose post language settings`, 56 - }), 57 - )} 58 - accessibilityHint={_(msg`Opens post language settings`)} 59 - style={[a.mx_md]}> 60 - {({pressed, hovered, focused}) => { 61 - const color = 62 - pressed || hovered || focused 63 - ? t.palette.primary_300 64 - : t.palette.primary_500 65 - if (postLanguagesPref.length > 0) { 66 - return ( 67 - <Text 68 - style={[ 69 - {color}, 70 - a.font_bold, 71 - a.text_sm, 72 - a.leading_snug, 73 - {maxWidth: 100}, 74 - ]} 75 - numberOfLines={1}> 76 - {postLanguagesPref 77 - .map(lang => codeToLanguageName(lang, langPrefs.appLanguage)) 78 - .join(', ')} 79 - </Text> 80 - ) 81 - } else { 82 - return <GlobeIcon size="xs" style={{color}} /> 83 - } 84 - }} 85 - </Button> 86 - 87 - <LanguageDialog control={control} /> 88 - </> 89 - ) 90 - } 91 - 92 - function LanguageDialog({control}: {control: Dialog.DialogControlProps}) { 24 + export function PostLanguageSelectDialog({ 25 + control, 26 + }: { 27 + control: Dialog.DialogControlProps 28 + }) { 93 29 const {height} = useWindowDimensions() 94 30 const insets = useSafeAreaInsets() 95 31 ··· 104 40 nativeOptions={{minHeight: height - insets.top}}> 105 41 <Dialog.Handle /> 106 42 <ErrorBoundary renderError={renderErrorBoundary}> 107 - <PostLanguagesSettingsDialogInner /> 43 + <DialogInner /> 108 44 </ErrorBoundary> 109 45 </Dialog.Outer> 110 46 ) 111 47 } 112 48 113 - export function PostLanguagesSettingsDialogInner() { 49 + export function DialogInner() { 114 50 const control = Dialog.useDialogContext() 115 51 const [headerHeight, setHeaderHeight] = useState(0) 116 52