Skip to content

Commit ee3e083

Browse files
authored
Restore quick language select (#8981)
* restore quick language select * rm showCancel * rm margin from thread button * alf composer icons * stop hiding keyboard * use trans
1 parent 0f08906 commit ee3e083

File tree

4 files changed

+154
-90
lines changed

4 files changed

+154
-90
lines changed

src/state/persisted/schema.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ const schema = z.object({
7878
postLanguage: z.string(),
7979
/**
8080
* 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.
8383
*
8484
* BCP-47 2-letter language codes without region.
8585
*/

src/view/com/composer/Composer.tsx

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,6 @@ import {LabelsBtn} from '#/view/com/composer/labels/LabelsBtn'
110110
import {Gallery} from '#/view/com/composer/photos/Gallery'
111111
import {OpenCameraBtn} from '#/view/com/composer/photos/OpenCameraBtn'
112112
import {SelectGifBtn} from '#/view/com/composer/photos/SelectGifBtn'
113-
import {SelectPostLanguagesBtn} from '#/view/com/composer/select-language/SelectPostLanguagesDialog'
114113
import {SuggestedLanguage} from '#/view/com/composer/select-language/SuggestedLanguage'
115114
// TODO: Prevent naming components that coincide with RN primitives
116115
// due to linting false positives
@@ -123,14 +122,16 @@ import {Text} from '#/view/com/util/text/Text'
123122
import {UserAvatar} from '#/view/com/util/UserAvatar'
124123
import {atoms as a, native, useTheme, web} from '#/alf'
125124
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'
129129
import {LazyQuoteEmbed} from '#/components/Post/Embed/LazyQuoteEmbed'
130130
import * as Prompt from '#/components/Prompt'
131131
import * as Toast from '#/components/Toast'
132132
import {Text as NewText} from '#/components/Typography'
133133
import {BottomSheetPortalProvider} from '../../../../modules/bottom-sheet'
134+
import {PostLanguageSelect} from './select-language/PostLanguageSelect'
134135
import {
135136
type AssetType,
136137
SelectMediaButton,
@@ -941,7 +942,7 @@ let ComposerPost = React.memo(function ComposerPost({
941942
})
942943
}
943944
}}>
944-
<ButtonIcon icon={X} />
945+
<ButtonIcon icon={XIcon} />
945946
</Button>
946947
<Prompt.Basic
947948
control={discardPromptControl}
@@ -1430,7 +1431,7 @@ function ComposerFooter({
14301431
variant="ghost"
14311432
shape="round"
14321433
color="primary">
1433-
<EmojiSmile size="lg" />
1434+
<EmojiSmileIcon size="lg" />
14341435
</Button>
14351436
) : null}
14361437
</ToolbarWrapper>
@@ -1440,20 +1441,16 @@ function ComposerFooter({
14401441
<View style={[a.flex_row, a.align_center, a.justify_between]}>
14411442
{showAddButton && (
14421443
<Button
1443-
label={_(msg`Add new post`)}
1444+
label={_(msg`Add another post to thread`)}
14441445
onPress={onAddPost}
1445-
style={[a.p_sm, a.m_2xs]}
1446+
style={[a.p_sm]}
14461447
variant="ghost"
14471448
shape="round"
14481449
color="primary">
1449-
<FontAwesomeIcon
1450-
icon="add"
1451-
size={20}
1452-
color={t.palette.primary_500}
1453-
/>
1450+
<PlusIcon size="lg" />
14541451
</Button>
14551452
)}
1456-
<SelectPostLanguagesBtn />
1453+
<PostLanguageSelect />
14571454
<CharProgress
14581455
count={post.shortenedGraphemeLength}
14591456
style={{width: 65}}
@@ -1753,7 +1750,7 @@ function ErrorBanner({
17531750
t.atoms.bg_contrast_25,
17541751
]}>
17551752
<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} />
17571754
<NewText style={[a.flex_1, a.leading_snug, {paddingTop: 1}]}>
17581755
{error}
17591756
</NewText>
@@ -1765,7 +1762,7 @@ function ErrorBanner({
17651762
shape="round"
17661763
style={[a.absolute, {top: 0, right: 0}]}
17671764
onPress={onClearError}>
1768-
<ButtonIcon icon={X} />
1765+
<ButtonIcon icon={XIcon} />
17691766
</Button>
17701767
</View>
17711768
{videoError && videoState.jobId && (
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
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+
}

src/view/com/composer/select-language/SelectPostLanguagesDialog.tsx renamed to src/view/com/composer/select-language/PostLanguageSelectDialog.tsx

Lines changed: 8 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
11
import {useCallback, useMemo, useState} from 'react'
2-
import {Keyboard, useWindowDimensions, View} from 'react-native'
2+
import {useWindowDimensions, View} from 'react-native'
33
import {useSafeAreaInsets} from 'react-native-safe-area-context'
44
import {msg, Trans} from '@lingui/macro'
55
import {useLingui} from '@lingui/react'
66

7-
import {LANG_DROPDOWN_HITSLOP} from '#/lib/constants'
87
import {languageName} from '#/locale/helpers'
9-
import {codeToLanguageName} from '#/locale/helpers'
108
import {type Language, LANGUAGES, LANGUAGES_MAP_CODE2} from '#/locale/languages'
119
import {isNative, isWeb} from '#/platform/detection'
1210
import {
13-
toPostLanguages,
1411
useLanguagePrefs,
1512
useLanguagePrefsApi,
1613
} from '#/state/preferences/languages'
@@ -21,75 +18,14 @@ import {Button, ButtonIcon, ButtonText} from '#/components/Button'
2118
import * as Dialog from '#/components/Dialog'
2219
import {SearchInput} from '#/components/forms/SearchInput'
2320
import * as Toggle from '#/components/forms/Toggle'
24-
import {Globe_Stroke2_Corner0_Rounded as GlobeIcon} from '#/components/icons/Globe'
2521
import {TimesLarge_Stroke2_Corner0_Rounded as XIcon} from '#/components/icons/Times'
2622
import {Text} from '#/components/Typography'
2723

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+
}) {
9329
const {height} = useWindowDimensions()
9430
const insets = useSafeAreaInsets()
9531

@@ -104,13 +40,13 @@ function LanguageDialog({control}: {control: Dialog.DialogControlProps}) {
10440
nativeOptions={{minHeight: height - insets.top}}>
10541
<Dialog.Handle />
10642
<ErrorBoundary renderError={renderErrorBoundary}>
107-
<PostLanguagesSettingsDialogInner />
43+
<DialogInner />
10844
</ErrorBoundary>
10945
</Dialog.Outer>
11046
)
11147
}
11248

113-
export function PostLanguagesSettingsDialogInner() {
49+
export function DialogInner() {
11450
const control = Dialog.useDialogContext()
11551
const [headerHeight, setHeaderHeight] = useState(0)
11652

0 commit comments

Comments
 (0)