Search is done

This commit is contained in:
Zhiyuan Zheng 2020-12-19 01:57:57 +01:00
parent 7491478176
commit 54799aabb8
No known key found for this signature in database
GPG Key ID: 078A93AB607D85E0
13 changed files with 250 additions and 109 deletions

View File

@ -120,10 +120,11 @@ const Timeline: React.FC<Props> = ({
() => !disableRefresh && fetchPreviousPage(),
[]
)
const flOnEndReach = useCallback(() => fetchNextPage(), [])
const flFooter = useCallback(() => {
return <TimelineEnd hasNextPage={hasNextPage} />
}, [hasNextPage])
const flOnEndReach = useCallback(() => !disableRefresh && fetchNextPage(), [])
const flFooter = useCallback(
() => (!disableRefresh ? <TimelineEnd hasNextPage={hasNextPage} /> : null),
[hasNextPage]
)
const onScrollToIndexFailed = useCallback(error => {
const offset = error.averageItemLength * error.index
flRef.current?.scrollToOffset({ offset })

View File

@ -38,7 +38,7 @@ const TimelineConversation: React.FC<Props> = ({
paddingTop: highlighted ? StyleConstants.Spacing.S : 0,
paddingLeft: highlighted
? 0
: StyleConstants.Avatar.S + StyleConstants.Spacing.S
: StyleConstants.Avatar.M + StyleConstants.Spacing.S
}}
>
<TimelineContent
@ -71,7 +71,7 @@ const TimelineConversation: React.FC<Props> = ({
style={{
paddingLeft: highlighted
? 0
: StyleConstants.Avatar.S + StyleConstants.Spacing.S
: StyleConstants.Avatar.M + StyleConstants.Spacing.S
}}
>
<TimelineActions queryKey={queryKey} status={item.last_status!} />

View File

@ -38,7 +38,7 @@ const TimelineDefault: React.FC<Props> = ({
StyleConstants.Spacing.Global.PagePadding * 2 // Global page padding on both sides
: Dimensions.get('window').width -
StyleConstants.Spacing.Global.PagePadding * 2 - // Global page padding on both sides
StyleConstants.Avatar.S - // Avatar width
StyleConstants.Avatar.M - // Avatar width
StyleConstants.Spacing.S // Avatar margin to the right
const tootOnPress = useCallback(
@ -56,7 +56,7 @@ const TimelineDefault: React.FC<Props> = ({
paddingTop: highlighted ? StyleConstants.Spacing.S : 0,
paddingLeft: highlighted
? 0
: StyleConstants.Avatar.S + StyleConstants.Spacing.S
: StyleConstants.Avatar.M + StyleConstants.Spacing.S
}}
>
{actualStatus.content.length > 0 && (
@ -100,7 +100,7 @@ const TimelineDefault: React.FC<Props> = ({
style={{
paddingLeft: highlighted
? 0
: StyleConstants.Avatar.S + StyleConstants.Spacing.S
: StyleConstants.Avatar.M + StyleConstants.Spacing.S
}}
>
<TimelineActions queryKey={queryKey} status={actualStatus} />

View File

@ -33,7 +33,7 @@ const TimelineNotifications: React.FC<Props> = ({
StyleConstants.Spacing.Global.PagePadding * 2 // Global page padding on both sides
: Dimensions.get('window').width -
StyleConstants.Spacing.Global.PagePadding * 2 - // Global page padding on both sides
StyleConstants.Avatar.S - // Avatar width
StyleConstants.Avatar.M - // Avatar width
StyleConstants.Spacing.S // Avatar margin to the right
const tootOnPress = useCallback(
@ -51,7 +51,7 @@ const TimelineNotifications: React.FC<Props> = ({
paddingTop: highlighted ? StyleConstants.Spacing.S : 0,
paddingLeft: highlighted
? 0
: StyleConstants.Avatar.S + StyleConstants.Spacing.S
: StyleConstants.Avatar.M + StyleConstants.Spacing.S
}}
>
{notification.status.content.length > 0 && (
@ -97,7 +97,7 @@ const TimelineNotifications: React.FC<Props> = ({
style={{
paddingLeft: highlighted
? 0
: StyleConstants.Avatar.S + StyleConstants.Spacing.S
: StyleConstants.Avatar.M + StyleConstants.Spacing.S
}}
>
<TimelineActions queryKey={queryKey} status={notification.status} />

View File

@ -20,7 +20,7 @@ const TimelineSeparator: React.FC<Props> = ({ highlighted = false }) => {
marginLeft: highlighted
? StyleConstants.Spacing.Global.PagePadding
: StyleConstants.Spacing.Global.PagePadding +
StyleConstants.Avatar.S +
StyleConstants.Avatar.M +
StyleConstants.Spacing.S
}
]}

View File

@ -107,7 +107,7 @@ const styles = StyleSheet.create({
marginBottom: StyleConstants.Spacing.S
},
icon: {
marginLeft: StyleConstants.Avatar.S - StyleConstants.Font.Size.S,
marginLeft: StyleConstants.Avatar.M - StyleConstants.Font.Size.S,
marginRight: StyleConstants.Spacing.S
},
content: {

View File

@ -27,8 +27,8 @@ const TimelineAvatar: React.FC<Props> = ({ queryKey, account }) => {
const styles = StyleSheet.create({
avatar: {
flexBasis: StyleConstants.Avatar.S,
height: StyleConstants.Avatar.S,
flexBasis: StyleConstants.Avatar.M,
height: StyleConstants.Avatar.M,
marginRight: StyleConstants.Spacing.S
},
image: {

View File

@ -42,20 +42,14 @@ const Login: React.FC = () => {
const instanceQuery = useQuery(
['Instance', { instanceDomain }],
instanceFetch,
{
enabled: false,
retry: false
}
{ enabled: false, retry: false }
)
const applicationQuery = useQuery(
['Application', { instanceDomain }],
applicationFetch,
{
enabled: false,
retry: false
}
{ enabled: false, retry: false }
)
useEffect(() => {
if (
applicationQuery.data?.client_id.length &&
@ -115,9 +109,6 @@ const Login: React.FC = () => {
text => {
setInstanceDomain(text)
setApplicationData(undefined)
if (text) {
instanceQuery.refetch()
}
},
1000,
{
@ -126,6 +117,11 @@ const Login: React.FC = () => {
),
[]
)
useEffect(() => {
if (instanceDomain) {
instanceQuery.refetch()
}
}, [instanceDomain])
const instanceInfo = useCallback(
({
@ -191,12 +187,19 @@ const Login: React.FC = () => {
clearButtonMode='never'
keyboardType='url'
textContentType='URL'
onSubmitEditing={() =>
instanceQuery.isSuccess &&
instanceQuery.data &&
instanceQuery.data.uri &&
applicationQuery.refetch()
}
onSubmitEditing={({ nativeEvent: { text } }) => {
if (
text === instanceDomain &&
instanceQuery.isSuccess &&
instanceQuery.data &&
instanceQuery.data.uri
) {
applicationQuery.refetch()
} else {
setInstanceDomain(text)
setApplicationData(undefined)
}
}}
placeholder={t('content.login.server.placeholder')}
placeholderTextColor={theme.secondary}
returnKeyType='go'

View File

@ -19,7 +19,7 @@ const ComposeReply: React.FC = () => {
const contentWidth =
Dimensions.get('window').width -
StyleConstants.Spacing.Global.PagePadding * 2 - // Global page padding on both sides
StyleConstants.Avatar.S - // Avatar width
StyleConstants.Avatar.M - // Avatar width
StyleConstants.Spacing.S // Avatar margin to the right
return (

View File

@ -227,7 +227,7 @@ const styles = StyleSheet.create({
width: StyleConstants.Font.LineHeight.M * 2,
height: StyleConstants.Font.LineHeight.M * 2,
marginRight: StyleConstants.Spacing.S,
borderRadius: StyleConstants.Avatar.S
borderRadius: StyleConstants.Avatar.M
},
accountName: {
fontSize: StyleConstants.Font.Size.S,

View File

@ -1,27 +1,42 @@
import { Feather } from '@expo/vector-icons'
import { useNavigation } from '@react-navigation/native'
import { HeaderRight } from '@root/components/Header'
import { MenuHeader, MenuRow } from '@root/components/Menu'
import Emojis from '@root/components/Timelines/Timeline/Shared/Emojis'
import { searchFetch } from '@root/utils/fetches/searchFetch'
import { StyleConstants } from '@root/utils/styles/constants'
import { useTheme } from '@root/utils/styles/ThemeManager'
import { debounce } from 'lodash'
import React, { useCallback, useMemo, useState } from 'react'
import { SectionList, StyleSheet, Text, TextInput, View } from 'react-native'
import React, { useCallback, useEffect, useMemo, useState } from 'react'
import {
Image,
Pressable,
SectionList,
StyleSheet,
Text,
TextInput,
View
} from 'react-native'
import { SafeAreaView } from 'react-native-safe-area-context'
import { useQuery } from 'react-query'
const ScreenSharedSearch: React.FC = () => {
const navigation = useNavigation()
const { theme } = useTheme()
const [searchTerm, setSearchTerm] = useState<string | undefined>()
const { isFetching, data, refetch } = useQuery(
const { status, data, refetch } = useQuery(
['Search', { term: searchTerm }],
searchFetch,
{ enabled: false }
)
const transformData = () => {
return data
? Object.keys(data as Mastodon.Results)
const [setctionData, setSectionData] = useState<
{ title: string; data: any }[]
>([])
useEffect(
() =>
data &&
setSectionData(
Object.keys(data as Mastodon.Results)
.map(key => ({
title: key,
// @ts-ignore
@ -36,24 +51,23 @@ const ScreenSharedSearch: React.FC = () => {
return 0
}
})
: []
}
),
[data]
)
const onChangeText = useCallback(
debounce(
text => {
setSearchTerm(text)
if (text) {
refetch()
}
},
1000,
{
trailing: true
}
),
debounce(text => setSearchTerm(text), 1000, {
trailing: true
}),
[]
)
useEffect(() => {
if (searchTerm) {
refetch()
} else {
setSectionData([])
}
}, [searchTerm])
const listEmpty = useMemo(
() => (
@ -93,9 +107,107 @@ const ScreenSharedSearch: React.FC = () => {
),
[]
)
const sectionHeader = useCallback(
({ section: { title } }) => (
<View
style={[
styles.sectionHeader,
{ borderBottomColor: theme.border, backgroundColor: theme.background }
]}
>
<Text style={[styles.sectionHeaderText, { color: theme.primary }]}>
{title}
</Text>
</View>
),
[]
)
const sectionFooter = useCallback(
({ section: { data, title } }) =>
!data.length ? (
<View
style={[styles.sectionFooter, { backgroundColor: theme.background }]}
>
<Text style={[styles.sectionFooterText, { color: theme.secondary }]}>
{' '}
<Text style={{ fontWeight: StyleConstants.Font.Weight.Bold }}>
{searchTerm}
</Text>{' '}
{title}
</Text>
</View>
) : null,
[searchTerm]
)
const listItem = useCallback(({ item, section }) => {
switch (section.title) {
case 'accounts':
return (
<Pressable
style={[
styles.itemDefault,
styles.itemAccount,
{ borderBottomColor: theme.border }
]}
onPress={() => {
navigation.goBack()
navigation.push('Screen-Shared-Account', {
id: item.id
})
}}
>
<Image
source={{ uri: item.avatar_static }}
style={styles.itemAccountAvatar}
/>
<View>
{item.emojis?.length ? (
<Emojis
content={item.display_name || item.username}
emojis={item.emojis}
size={StyleConstants.Font.Size.S}
fontBold={true}
/>
) : (
<Text
style={[styles.nameWithoutEmoji, { color: theme.primary }]}
>
{item.display_name || item.username}
</Text>
)}
<Text
style={[styles.itemAccountAcct, { color: theme.secondary }]}
>
@{item.acct}
</Text>
</View>
</Pressable>
)
case 'hashtags':
return (
<Pressable
style={[styles.itemDefault, { borderBottomColor: theme.border }]}
onPress={() => {
navigation.goBack()
navigation.push('Screen-Shared-Hashtag', {
hashtag: item.name
})
}}
>
<Text style={[styles.itemHashtag, { color: theme.primary }]}>
#{item.name}
</Text>
</Pressable>
)
case 'statuses':
return <Text>{item.id || 'empty'}</Text>
default:
return null
}
}, [])
return (
<>
<SafeAreaView style={{ flex: 1 }} edges={['bottom']}>
<View style={styles.searchBar}>
<View
style={[styles.searchField, { borderBottomColor: theme.secondary }]}
@ -119,12 +231,7 @@ const ScreenSharedSearch: React.FC = () => {
autoCorrect={false}
clearButtonMode='never'
keyboardType='web-search'
// onSubmitEditing={() =>
// instanceQuery.isSuccess &&
// instanceQuery.data &&
// instanceQuery.data.uri &&
// applicationQuery.refetch()
// }
onSubmitEditing={({ nativeEvent: { text } }) => setSearchTerm(text)}
placeholder={'搜索些什么'}
placeholderTextColor={theme.secondary}
returnKeyType='go'
@ -135,36 +242,26 @@ const ScreenSharedSearch: React.FC = () => {
</View>
</View>
<SectionList
ListEmptyComponent={listEmpty}
style={styles.base}
sections={transformData()}
refreshing={isFetching}
keyExtractor={(item, index) => item + index}
renderSectionHeader={({ section: { title } }) => (
<MenuHeader heading={title} />
)}
renderItem={({ item, section }) => {
switch (section.title) {
case 'accounts':
return <Text>{item.display_name || item.username}</Text>
case 'statuses':
return <Text>{item.id || 'empty'}</Text>
case 'hashtags':
return <MenuRow title={item.name} />
default:
return null
}
}}
renderItem={listItem}
stickySectionHeadersEnabled
sections={setctionData}
ListEmptyComponent={listEmpty}
refreshing={status === 'loading'}
keyboardShouldPersistTaps='always'
renderSectionHeader={sectionHeader}
renderSectionFooter={sectionFooter}
keyExtractor={(item, index) => item + index}
/>
</>
</SafeAreaView>
)
}
const styles = StyleSheet.create({
base: {
flex: 1,
padding: StyleConstants.Spacing.Global.PagePadding
padding: StyleConstants.Spacing.Global.PagePadding,
paddingTop: 0
},
searchBar: {
padding: StyleConstants.Spacing.Global.PagePadding,
@ -193,7 +290,7 @@ const styles = StyleSheet.create({
},
emptyBase: {
marginTop: StyleConstants.Spacing.S,
marginTop: StyleConstants.Spacing.M,
marginLeft:
StyleConstants.Spacing.S +
StyleConstants.Spacing.M +
@ -208,6 +305,44 @@ const styles = StyleSheet.create({
},
emptyAdvanced: {
marginBottom: StyleConstants.Spacing.S
},
sectionHeader: {
padding: StyleConstants.Spacing.M,
borderBottomWidth: StyleSheet.hairlineWidth
},
sectionHeaderText: {
fontSize: StyleConstants.Font.Size.M,
fontWeight: StyleConstants.Font.Weight.Bold,
textAlign: 'center'
},
sectionFooter: {
padding: StyleConstants.Spacing.S
},
sectionFooterText: {
fontSize: StyleConstants.Font.Size.S,
textAlign: 'center'
},
itemDefault: {
padding: StyleConstants.Spacing.S * 1.5,
borderBottomWidth: StyleSheet.hairlineWidth
},
itemAccount: {
flexDirection: 'row',
alignItems: 'center'
},
itemAccountAvatar: {
width: StyleConstants.Avatar.S,
height: StyleConstants.Avatar.S,
borderRadius: 6,
marginRight: StyleConstants.Spacing.S
},
nameWithoutEmoji: {
fontSize: StyleConstants.Font.Size.S,
fontWeight: StyleConstants.Font.Weight.Bold
},
itemAccountAcct: { marginTop: StyleConstants.Spacing.XS },
itemHashtag: {
fontSize: StyleConstants.Font.Size.M
}
})

View File

@ -77,28 +77,29 @@ export const timelineFetch = async ({
case 'Account_Default':
if (pageParam) {
if (pageParam.direction === 'prev') {
res = await client({
method: 'get',
instance: 'local',
url: `accounts/${account}/statuses`,
params: {
pinned: 'true',
...params
}
})
return Promise.resolve({ toots: res.body })
} else {
res = await client({
method: 'get',
instance: 'local',
url: `accounts/${account}/statuses`,
params: {
exclude_replies: 'true',
...params
}
})
return Promise.resolve({ toots: res.body })
switch (pageParam.direction) {
case 'prev':
res = await client({
method: 'get',
instance: 'local',
url: `accounts/${account}/statuses`,
params: {
pinned: 'true',
...params
}
})
return Promise.resolve({ toots: res.body })
case 'next':
res = await client({
method: 'get',
instance: 'local',
url: `accounts/${account}/statuses`,
params: {
exclude_replies: 'true',
...params
}
})
return Promise.resolve({ toots: res.body })
}
} else {
res = await client({

View File

@ -25,7 +25,8 @@ export const StyleConstants = {
},
Avatar: {
S: 52,
S: 36,
M: 52,
L: 104
}
}