ListAddUser modal UX improvements (#1809)

* typo

* Add loading state to ListAddUser

* Improve UI/UX of ListAddUser
zio/stable
Paul Frazee 2023-11-03 16:44:00 -07:00 committed by GitHub
parent 4de852ded8
commit ebad6d2b1a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 27 additions and 20 deletions

View File

@ -10,7 +10,7 @@ export function useIsKeyboardVisible({
const [isKeyboardVisible, setKeyboardVisible] = useState(false) const [isKeyboardVisible, setKeyboardVisible] = useState(false)
// NOTE // NOTE
// only iOS suppose the "will" events // only iOS supports the "will" events
// -prf // -prf
const showEvent = const showEvent =
isIOS && iosUseWillEvents ? 'keyboardWillShow' : 'keyboardDidShow' isIOS && iosUseWillEvents ? 'keyboardWillShow' : 'keyboardDidShow'

View File

@ -48,6 +48,7 @@ export class UserAutocompleteModel {
// = // =
async setup() { async setup() {
this.isLoading = true
await this.rootStore.me.follows.syncIfNeeded() await this.rootStore.me.follows.syncIfNeeded()
runInAction(() => { runInAction(() => {
for (const did in this.rootStore.me.follows.byDid) { for (const did in this.rootStore.me.follows.byDid) {
@ -56,6 +57,7 @@ export class UserAutocompleteModel {
this.knownHandles.add(info.handle) this.knownHandles.add(info.handle)
} }
} }
this.isLoading = false
}) })
} }

View File

@ -21,9 +21,11 @@ import {s, colors} from 'lib/styles'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
import {isWeb} from 'platform/detection' import {isWeb} from 'platform/detection'
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
import {useIsKeyboardVisible} from 'lib/hooks/useIsKeyboardVisible'
import {cleanError} from 'lib/strings/errors' import {cleanError} from 'lib/strings/errors'
import {sanitizeDisplayName} from 'lib/strings/display-names' import {sanitizeDisplayName} from 'lib/strings/display-names'
import {sanitizeHandle} from 'lib/strings/handles' import {sanitizeHandle} from 'lib/strings/handles'
import {HITSLOP_20} from '#/lib/constants'
export const snapPoints = ['90%'] export const snapPoints = ['90%']
@ -42,6 +44,7 @@ export const Component = observer(function Component({
() => new UserAutocompleteModel(store), () => new UserAutocompleteModel(store),
[store], [store],
) )
const [isKeyboardVisible] = useIsKeyboardVisible()
// initial setup // initial setup
useEffect(() => { useEffect(() => {
@ -69,16 +72,7 @@ export const Component = observer(function Component({
<SafeAreaView <SafeAreaView
testID="listAddUserModal" testID="listAddUserModal"
style={[pal.view, isWeb ? styles.fixedHeight : s.flex1]}> style={[pal.view, isWeb ? styles.fixedHeight : s.flex1]}>
<View <View style={[s.flex1, isMobile && {paddingHorizontal: 18}]}>
style={[
s.flex1,
isMobile && {paddingHorizontal: 18, paddingBottom: 40},
]}>
<View style={styles.titleSection}>
<Text type="title-lg" style={[pal.text, styles.title]}>
Add User to List
</Text>
</View>
<View style={[styles.searchContainer, pal.border]}> <View style={[styles.searchContainer, pal.border]}>
<FontAwesomeIcon icon="search" size={16} /> <FontAwesomeIcon icon="search" size={16} />
<TextInput <TextInput
@ -91,9 +85,11 @@ export const Component = observer(function Component({
accessible={true} accessible={true}
accessibilityLabel="Search" accessibilityLabel="Search"
accessibilityHint="" accessibilityHint=""
autoFocus
autoCapitalize="none" autoCapitalize="none"
autoComplete="off" autoComplete="off"
autoCorrect={false} autoCorrect={false}
selectTextOnFocus
/> />
{query ? ( {query ? (
<Pressable <Pressable
@ -101,7 +97,8 @@ export const Component = observer(function Component({
accessibilityRole="button" accessibilityRole="button"
accessibilityLabel="Cancel search" accessibilityLabel="Cancel search"
accessibilityHint="Exits inputting search query" accessibilityHint="Exits inputting search query"
onAccessibilityEscape={onPressCancelSearch}> onAccessibilityEscape={onPressCancelSearch}
hitSlop={HITSLOP_20}>
<FontAwesomeIcon <FontAwesomeIcon
icon="xmark" icon="xmark"
size={16} size={16}
@ -110,8 +107,15 @@ export const Component = observer(function Component({
</Pressable> </Pressable>
) : undefined} ) : undefined}
</View> </View>
<ScrollView style={[s.flex1]}> <ScrollView
{autocompleteView.suggestions.length ? ( style={[s.flex1]}
keyboardDismissMode="none"
keyboardShouldPersistTaps="always">
{autocompleteView.isLoading ? (
<View style={{marginVertical: 20}}>
<ActivityIndicator />
</View>
) : autocompleteView.suggestions.length ? (
<> <>
{autocompleteView.suggestions.slice(0, 40).map((item, i) => ( {autocompleteView.suggestions.slice(0, 40).map((item, i) => (
<UserResult <UserResult
@ -134,10 +138,14 @@ export const Component = observer(function Component({
</Text> </Text>
)} )}
</ScrollView> </ScrollView>
<View style={[styles.btnContainer]}> <View
style={[
styles.btnContainer,
{paddingBottom: isKeyboardVisible ? 10 : 20},
]}>
<Button <Button
testID="doneBtn" testID="doneBtn"
type="primary" type="default"
onPress={() => store.shell.closeModal()} onPress={() => store.shell.closeModal()}
accessibilityLabel="Done" accessibilityLabel="Done"
accessibilityHint="" accessibilityHint=""
@ -188,16 +196,13 @@ function UserResult({
flexDirection: 'row', flexDirection: 'row',
alignItems: 'center', alignItems: 'center',
borderTopWidth: noBorder ? 0 : 1, borderTopWidth: noBorder ? 0 : 1,
paddingVertical: 8,
paddingHorizontal: 8, paddingHorizontal: 8,
}, },
]}> ]}>
<View <View
style={{ style={{
alignSelf: 'baseline',
width: 54, width: 54,
paddingLeft: 4, paddingLeft: 4,
paddingTop: 10,
}}> }}>
<UserAvatar size={40} avatar={profile.avatar} /> <UserAvatar size={40} avatar={profile.avatar} />
</View> </View>
@ -276,6 +281,6 @@ const styles = StyleSheet.create({
backgroundColor: colors.blue3, backgroundColor: colors.blue3,
}, },
btnContainer: { btnContainer: {
paddingTop: 20, paddingTop: 10,
}, },
}) })