From 54799aabb896887a15fea5abbde6e2c188cd8389 Mon Sep 17 00:00:00 2001 From: Zhiyuan Zheng Date: Sat, 19 Dec 2020 01:57:57 +0100 Subject: [PATCH] Search is done --- src/components/Timelines/Timeline.tsx | 9 +- .../Timelines/Timeline/Conversation.tsx | 4 +- src/components/Timelines/Timeline/Default.tsx | 6 +- .../Timelines/Timeline/Notifications.tsx | 6 +- .../Timelines/Timeline/Separator.tsx | 2 +- .../Timelines/Timeline/Shared/Actioned.tsx | 2 +- .../Timelines/Timeline/Shared/Avatar.tsx | 4 +- src/screens/Me/Root/Login.tsx | 39 +-- src/screens/Shared/Compose/Reply.tsx | 2 +- src/screens/Shared/Compose/Root.tsx | 2 +- src/screens/Shared/Search.tsx | 235 ++++++++++++++---- src/utils/fetches/timelineFetch.ts | 45 ++-- src/utils/styles/constants.ts | 3 +- 13 files changed, 250 insertions(+), 109 deletions(-) diff --git a/src/components/Timelines/Timeline.tsx b/src/components/Timelines/Timeline.tsx index 1f9afbb4..94bf1cf4 100644 --- a/src/components/Timelines/Timeline.tsx +++ b/src/components/Timelines/Timeline.tsx @@ -120,10 +120,11 @@ const Timeline: React.FC = ({ () => !disableRefresh && fetchPreviousPage(), [] ) - const flOnEndReach = useCallback(() => fetchNextPage(), []) - const flFooter = useCallback(() => { - return - }, [hasNextPage]) + const flOnEndReach = useCallback(() => !disableRefresh && fetchNextPage(), []) + const flFooter = useCallback( + () => (!disableRefresh ? : null), + [hasNextPage] + ) const onScrollToIndexFailed = useCallback(error => { const offset = error.averageItemLength * error.index flRef.current?.scrollToOffset({ offset }) diff --git a/src/components/Timelines/Timeline/Conversation.tsx b/src/components/Timelines/Timeline/Conversation.tsx index 31ce66f7..6901dde0 100644 --- a/src/components/Timelines/Timeline/Conversation.tsx +++ b/src/components/Timelines/Timeline/Conversation.tsx @@ -38,7 +38,7 @@ const TimelineConversation: React.FC = ({ paddingTop: highlighted ? StyleConstants.Spacing.S : 0, paddingLeft: highlighted ? 0 - : StyleConstants.Avatar.S + StyleConstants.Spacing.S + : StyleConstants.Avatar.M + StyleConstants.Spacing.S }} > = ({ style={{ paddingLeft: highlighted ? 0 - : StyleConstants.Avatar.S + StyleConstants.Spacing.S + : StyleConstants.Avatar.M + StyleConstants.Spacing.S }} > diff --git a/src/components/Timelines/Timeline/Default.tsx b/src/components/Timelines/Timeline/Default.tsx index 2eb366d1..8aed403e 100644 --- a/src/components/Timelines/Timeline/Default.tsx +++ b/src/components/Timelines/Timeline/Default.tsx @@ -38,7 +38,7 @@ const TimelineDefault: React.FC = ({ 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 = ({ 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 = ({ style={{ paddingLeft: highlighted ? 0 - : StyleConstants.Avatar.S + StyleConstants.Spacing.S + : StyleConstants.Avatar.M + StyleConstants.Spacing.S }} > diff --git a/src/components/Timelines/Timeline/Notifications.tsx b/src/components/Timelines/Timeline/Notifications.tsx index 16fbe0b4..cb678a2b 100644 --- a/src/components/Timelines/Timeline/Notifications.tsx +++ b/src/components/Timelines/Timeline/Notifications.tsx @@ -33,7 +33,7 @@ const TimelineNotifications: React.FC = ({ 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 = ({ 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 = ({ style={{ paddingLeft: highlighted ? 0 - : StyleConstants.Avatar.S + StyleConstants.Spacing.S + : StyleConstants.Avatar.M + StyleConstants.Spacing.S }} > diff --git a/src/components/Timelines/Timeline/Separator.tsx b/src/components/Timelines/Timeline/Separator.tsx index 4b88fb41..796c3ab4 100644 --- a/src/components/Timelines/Timeline/Separator.tsx +++ b/src/components/Timelines/Timeline/Separator.tsx @@ -20,7 +20,7 @@ const TimelineSeparator: React.FC = ({ highlighted = false }) => { marginLeft: highlighted ? StyleConstants.Spacing.Global.PagePadding : StyleConstants.Spacing.Global.PagePadding + - StyleConstants.Avatar.S + + StyleConstants.Avatar.M + StyleConstants.Spacing.S } ]} diff --git a/src/components/Timelines/Timeline/Shared/Actioned.tsx b/src/components/Timelines/Timeline/Shared/Actioned.tsx index 5e1543e0..8c1e8d0c 100644 --- a/src/components/Timelines/Timeline/Shared/Actioned.tsx +++ b/src/components/Timelines/Timeline/Shared/Actioned.tsx @@ -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: { diff --git a/src/components/Timelines/Timeline/Shared/Avatar.tsx b/src/components/Timelines/Timeline/Shared/Avatar.tsx index 762ea0b9..3775e742 100644 --- a/src/components/Timelines/Timeline/Shared/Avatar.tsx +++ b/src/components/Timelines/Timeline/Shared/Avatar.tsx @@ -27,8 +27,8 @@ const TimelineAvatar: React.FC = ({ 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: { diff --git a/src/screens/Me/Root/Login.tsx b/src/screens/Me/Root/Login.tsx index f624f453..60409dde 100644 --- a/src/screens/Me/Root/Login.tsx +++ b/src/screens/Me/Root/Login.tsx @@ -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' diff --git a/src/screens/Shared/Compose/Reply.tsx b/src/screens/Shared/Compose/Reply.tsx index ba4b0b73..1b6afcb7 100644 --- a/src/screens/Shared/Compose/Reply.tsx +++ b/src/screens/Shared/Compose/Reply.tsx @@ -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 ( diff --git a/src/screens/Shared/Compose/Root.tsx b/src/screens/Shared/Compose/Root.tsx index 74f2debd..fe8faac6 100644 --- a/src/screens/Shared/Compose/Root.tsx +++ b/src/screens/Shared/Compose/Root.tsx @@ -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, diff --git a/src/screens/Shared/Search.tsx b/src/screens/Shared/Search.tsx index 5896e96c..81687480 100644 --- a/src/screens/Shared/Search.tsx +++ b/src/screens/Shared/Search.tsx @@ -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() - 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 } }) => ( + + + {title} + + + ), + [] + ) + const sectionFooter = useCallback( + ({ section: { data, title } }) => + !data.length ? ( + + + 找不到{' '} + + {searchTerm} + {' '} + 相关的{title} + + + ) : null, + [searchTerm] + ) + const listItem = useCallback(({ item, section }) => { + switch (section.title) { + case 'accounts': + return ( + { + navigation.goBack() + navigation.push('Screen-Shared-Account', { + id: item.id + }) + }} + > + + + {item.emojis?.length ? ( + + ) : ( + + {item.display_name || item.username} + + )} + + @{item.acct} + + + + ) + case 'hashtags': + return ( + { + navigation.goBack() + navigation.push('Screen-Shared-Hashtag', { + hashtag: item.name + }) + }} + > + + #{item.name} + + + ) + case 'statuses': + return {item.id || 'empty'} + default: + return null + } + }, []) return ( - <> + { 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 = () => { item + index} - renderSectionHeader={({ section: { title } }) => ( - - )} - renderItem={({ item, section }) => { - switch (section.title) { - case 'accounts': - return {item.display_name || item.username} - case 'statuses': - return {item.id || 'empty'} - case 'hashtags': - return - default: - return null - } - }} + renderItem={listItem} stickySectionHeadersEnabled + sections={setctionData} + ListEmptyComponent={listEmpty} + refreshing={status === 'loading'} + keyboardShouldPersistTaps='always' + renderSectionHeader={sectionHeader} + renderSectionFooter={sectionFooter} + keyExtractor={(item, index) => item + index} /> - + ) } 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 } }) diff --git a/src/utils/fetches/timelineFetch.ts b/src/utils/fetches/timelineFetch.ts index 73ce05e5..7dc471be 100644 --- a/src/utils/fetches/timelineFetch.ts +++ b/src/utils/fetches/timelineFetch.ts @@ -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({ diff --git a/src/utils/styles/constants.ts b/src/utils/styles/constants.ts index 0d46fd37..af6efcde 100644 --- a/src/utils/styles/constants.ts +++ b/src/utils/styles/constants.ts @@ -25,7 +25,8 @@ export const StyleConstants = { }, Avatar: { - S: 52, + S: 36, + M: 52, L: 104 } }