ListAddUser modal UX improvements (#1809)
* typo * Add loading state to ListAddUser * Improve UI/UX of ListAddUserzio/stable
parent
4de852ded8
commit
ebad6d2b1a
|
@ -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'
|
||||||
|
|
|
@ -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
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue