diff --git a/src/@types/app.d.ts b/src/@types/app.d.ts index 212f28b9..38e5113f 100644 --- a/src/@types/app.d.ts +++ b/src/@types/app.d.ts @@ -17,39 +17,20 @@ declare namespace App { } declare namespace QueryKey { - type Account = [ - 'Account', - { - id: Mastodon.Account['id'] - } - ] + type Account = ['Account', { id: Mastodon.Account['id'] }] - type Announcements = [ - 'Announcements', - { - showAll?: boolean - } - ] + type Announcements = ['Announcements', { showAll?: boolean }] - type Application = [ - 'Application', - { - instanceDomain: string - } - ] + type Application = ['Application', { instanceDomain: string }] - type Instance = [ - 'Instance', - { - instanceDomain: string - } - ] + type Instance = ['Instance', { instanceDomain: string }] - type Relationship = [ - 'Relationship', - { - id: Mastodon.Account['id'] - } + type Relationship = ['Relationship', { id: Mastodon.Account['id'] }] + + type Relationships = [ + 'Relationships', + 'following' | 'followers', + { id: Mastodon.Account['id'] } ] type Search = [ diff --git a/src/components/Account.tsx b/src/components/Account.tsx new file mode 100644 index 00000000..2b7dee0b --- /dev/null +++ b/src/components/Account.tsx @@ -0,0 +1,66 @@ +import { ParseEmojis } from '@components/Parse' +import { useNavigation } from '@react-navigation/native' +import { StyleConstants } from '@utils/styles/constants' +import { useTheme } from '@utils/styles/ThemeManager' +import React from 'react' +import { Image, Pressable, StyleSheet, Text, View } from 'react-native' + +export interface Props { + account: Mastodon.Account +} + +const ComponentAccount: React.FC = ({ account }) => { + const navigation = useNavigation() + const { theme } = useTheme() + + return ( + { + navigation.push('Screen-Shared-Account', { account }) + }} + > + + + + + + + @{account.acct} + + + + ) +} + +const styles = StyleSheet.create({ + itemDefault: { + paddingHorizontal: StyleConstants.Spacing.Global.PagePadding, + paddingVertical: StyleConstants.Spacing.M + }, + itemAccount: { + flexDirection: 'row', + alignItems: 'center' + }, + itemAccountAvatar: { + alignSelf: 'flex-start', + width: StyleConstants.Avatar.S, + height: StyleConstants.Avatar.S, + borderRadius: 6, + marginRight: StyleConstants.Spacing.S + }, + itemAccountAcct: { marginTop: StyleConstants.Spacing.XS } +}) + +export default ComponentAccount diff --git a/src/components/Parse/HTML.tsx b/src/components/Parse/HTML.tsx index 9c10019d..dd1592e6 100644 --- a/src/components/Parse/HTML.tsx +++ b/src/components/Parse/HTML.tsx @@ -27,7 +27,8 @@ const renderNode = ({ navigation, mentions, tags, - showFullLink + showFullLink, + disableDetails }: { theme: any node: any @@ -37,6 +38,7 @@ const renderNode = ({ mentions?: Mastodon.Mention[] tags?: Mastodon.Tag[] showFullLink: boolean + disableDetails: boolean }) => { if (node.name == 'a') { const classes = node.attribs.class @@ -52,9 +54,10 @@ const renderNode = ({ }} onPress={() => { const tag = href.split(new RegExp(/\/tag\/(.*)|\/tags\/(.*)/)) - navigation.push('Screen-Shared-Hashtag', { - hashtag: tag[1] || tag[2] - }) + !disableDetails && + navigation.push('Screen-Shared-Hashtag', { + hashtag: tag[1] || tag[2] + }) }} > {node.children[0].data} @@ -72,6 +75,7 @@ const renderNode = ({ }} onPress={() => { accountIndex !== -1 && + !disableDetails && navigation.push('Screen-Shared-Account', { account: mentions[accountIndex] }) @@ -96,7 +100,7 @@ const renderNode = ({ ...StyleConstants.FontStyle[size] }} onPress={async () => - !shouldBeTag + !disableDetails && !shouldBeTag ? await openLink(href) : navigation.push('Screen-Shared-Hashtag', { hashtag: content.substring(1) @@ -132,6 +136,7 @@ export interface Props { showFullLink?: boolean numberOfLines?: number expandHint?: string + disableDetails?: boolean } const ParseHTML: React.FC = ({ @@ -142,7 +147,8 @@ const ParseHTML: React.FC = ({ tags, showFullLink = false, numberOfLines = 10, - expandHint = '全文' + expandHint = '全文', + disableDetails = false }) => { const navigation = useNavigation() const { theme } = useTheme() @@ -157,7 +163,8 @@ const ParseHTML: React.FC = ({ navigation, mentions, tags, - showFullLink + showFullLink, + disableDetails }), [] ) diff --git a/src/components/Relationship/Incoming.tsx b/src/components/Relationship/Incoming.tsx index f013302c..9aa89e61 100644 --- a/src/components/Relationship/Incoming.tsx +++ b/src/components/Relationship/Incoming.tsx @@ -15,7 +15,7 @@ export interface Props { const RelationshipIncoming: React.FC = ({ id }) => { const { t } = useTranslation() - const relationshipQueryKey = ['Relationship', { id }] + const relationshipQueryKey: QueryKey.Relationship = ['Relationship', { id }] const queryClient = useQueryClient() const fireMutation = useCallback( diff --git a/src/components/Relationship/Outgoing.tsx b/src/components/Relationship/Outgoing.tsx index bfd891c4..8ff96ca0 100644 --- a/src/components/Relationship/Outgoing.tsx +++ b/src/components/Relationship/Outgoing.tsx @@ -14,7 +14,7 @@ export interface Props { const RelationshipOutgoing: React.FC = ({ id }) => { const { t } = useTranslation() - const relationshipQueryKey = ['Relationship', { id }] + const relationshipQueryKey: QueryKey.Relationship = ['Relationship', { id }] const query = useQuery(relationshipQueryKey, relationshipFetch) const queryClient = useQueryClient() diff --git a/src/components/Separator.tsx b/src/components/Separator.tsx new file mode 100644 index 00000000..d2f7a0a3 --- /dev/null +++ b/src/components/Separator.tsx @@ -0,0 +1,31 @@ +import { StyleConstants } from '@utils/styles/constants' +import { useTheme } from '@utils/styles/ThemeManager' +import React from 'react' +import { StyleSheet, View } from 'react-native' + +export interface Props { + extraMarginLeft?: number + extraMarginRight?: number +} + +const ComponentSeparator = React.memo( + ({ extraMarginLeft = 0, extraMarginRight = 0 }: Props) => { + const { theme } = useTheme() + + return ( + + ) + }, + () => true +) + +export default ComponentSeparator diff --git a/src/components/Timelines/Timeline.tsx b/src/components/Timelines/Timeline.tsx index b4688a6f..1ef4c9e0 100644 --- a/src/components/Timelines/Timeline.tsx +++ b/src/components/Timelines/Timeline.tsx @@ -1,18 +1,18 @@ +import ComponentSeparator from '@components/Separator' +import TimelineConversation from '@components/Timelines/Timeline/Conversation' +import TimelineDefault from '@components/Timelines/Timeline/Default' +import TimelineEmpty from '@components/Timelines/Timeline/Empty' +import TimelineEnd from '@root/components/Timelines/Timeline/End' +import TimelineNotifications from '@components/Timelines/Timeline/Notifications' +import { useScrollToTop } from '@react-navigation/native' +import { timelineFetch } from '@utils/fetches/timelineFetch' +import { updateNotification } from '@utils/slices/instancesSlice' +import { StyleConstants } from '@utils/styles/constants' import React, { useCallback, useEffect, useMemo, useRef } from 'react' import { RefreshControl, StyleSheet } from 'react-native' -import { InfiniteData, useInfiniteQuery } from 'react-query' - -import TimelineNotifications from '@components/Timelines/Timeline/Notifications' -import TimelineDefault from '@components/Timelines/Timeline/Default' -import TimelineConversation from '@components/Timelines/Timeline/Conversation' -import { timelineFetch } from '@utils/fetches/timelineFetch' -import TimelineSeparator from '@components/Timelines/Timeline/Separator' -import TimelineEmpty from '@components/Timelines/Timeline/Empty' -import TimelineEnd from '@components/Timelines/Timeline/Shared/End' -import { useScrollToTop } from '@react-navigation/native' import { FlatList } from 'react-native-gesture-handler' +import { InfiniteData, useInfiniteQuery } from 'react-query' import { useDispatch } from 'react-redux' -import { updateNotification } from '@root/utils/slices/instancesSlice' export type TimelineData = | InfiniteData<{ @@ -130,6 +130,10 @@ const Timeline: React.FC = ({ item={item} queryKey={queryKey} index={index} + {...(queryKey[0] === 'RemotePublic' && { + disableDetails: true, + disableOnPress: true + })} {...(flattenPinnedLength && flattenPinnedLength[0] && { pinnedLength: flattenPinnedLength[0] @@ -143,8 +147,13 @@ const Timeline: React.FC = ({ ) const ItemSeparatorComponent = useCallback( ({ leadingItem }) => ( - ), [] diff --git a/src/components/Timelines/Timeline/Default.tsx b/src/components/Timelines/Timeline/Default.tsx index 0f9ce205..5a15ce96 100644 --- a/src/components/Timelines/Timeline/Default.tsx +++ b/src/components/Timelines/Timeline/Default.tsx @@ -15,10 +15,12 @@ import { useSelector } from 'react-redux' export interface Props { item: Mastodon.Status - queryKey: QueryKey.Timeline + queryKey?: QueryKey.Timeline index: number pinnedLength?: number highlighted?: boolean + disableDetails?: boolean + disableOnPress?: boolean } // When the poll is long @@ -27,17 +29,18 @@ const TimelineDefault: React.FC = ({ queryKey, index, pinnedLength, - highlighted = false + highlighted = false, + disableDetails = false, + disableOnPress = false }) => { const localAccountId = useSelector(getLocalAccountId) - const isRemotePublic = queryKey[0] === 'RemotePublic' const navigation = useNavigation() let actualStatus = item.reblog ? item.reblog : item const onPress = useCallback( () => - !isRemotePublic && + !disableOnPress && !highlighted && navigation.push('Screen-Shared-Toot', { toot: actualStatus @@ -55,11 +58,11 @@ const TimelineDefault: React.FC = ({ @@ -74,9 +77,13 @@ const TimelineDefault: React.FC = ({ }} > {actualStatus.content.length > 0 && ( - + )} - {actualStatus.poll && ( + {queryKey && actualStatus.poll && ( = ({ sameAccount={actualStatus.account.id === localAccountId} /> )} - {actualStatus.media_attachments.length > 0 && ( + {!disableDetails && actualStatus.media_attachments.length > 0 && ( )} - {actualStatus.card && } + {!disableDetails && actualStatus.card && ( + + )} - {!isRemotePublic && ( + {queryKey && !disableDetails && ( = ({ hasNextPage }) => { i18nKey='timeline:shared.end.message' // optional -> fallbacks to defaults if not provided components={[ = ({ highlighted = false }) => { - const { theme } = useTheme() - - return ( - - ) -} - -const styles = StyleSheet.create({ - base: { - borderTopWidth: StyleSheet.hairlineWidth, - marginRight: StyleConstants.Spacing.Global.PagePadding - } -}) - -export default TimelineSeparator diff --git a/src/components/Timelines/Timeline/Shared/Content.tsx b/src/components/Timelines/Timeline/Shared/Content.tsx index 3f1fa69c..8ac4f632 100644 --- a/src/components/Timelines/Timeline/Shared/Content.tsx +++ b/src/components/Timelines/Timeline/Shared/Content.tsx @@ -8,12 +8,14 @@ export interface Props { status: Mastodon.Status numberOfLines?: number highlighted?: boolean + disableDetails?: boolean } const TimelineContent: React.FC = ({ status, numberOfLines, - highlighted = false + highlighted = false, + disableDetails = false }) => { const { t } = useTranslation('timeline') @@ -29,6 +31,7 @@ const TimelineContent: React.FC = ({ mentions={status.mentions} tags={status.tags} numberOfLines={999} + disableDetails={disableDetails} /> = ({ tags={status.tags} numberOfLines={0} expandHint={t('shared.content.expandHint')} + disableDetails={disableDetails} /> ) : ( @@ -49,6 +53,7 @@ const TimelineContent: React.FC = ({ mentions={status.mentions} tags={status.tags} numberOfLines={numberOfLines} + disableDetails={disableDetails} /> )} diff --git a/src/components/Timelines/Timeline/Shared/HeaderConversation.tsx b/src/components/Timelines/Timeline/Shared/HeaderConversation.tsx index d08552a7..6edf9739 100644 --- a/src/components/Timelines/Timeline/Shared/HeaderConversation.tsx +++ b/src/components/Timelines/Timeline/Shared/HeaderConversation.tsx @@ -1,9 +1,11 @@ import client from '@api/client' import haptics from '@components/haptics' import Icon from '@components/Icon' +import { TimelineData } from '@components/Timelines/Timeline' import { toast } from '@components/toast' import { StyleConstants } from '@utils/styles/constants' import { useTheme } from '@utils/styles/ThemeManager' +import { findIndex } from 'lodash' import React, { useCallback, useMemo } from 'react' import { useTranslation } from 'react-i18next' import { Pressable, StyleSheet, View } from 'react-native' @@ -33,14 +35,24 @@ const HeaderConversation: React.FC = ({ queryKey, conversation }) => { const oldData = queryClient.getQueryData(queryKey) haptics('Success') - queryClient.setQueryData(queryKey, (old: any) => - old.pages.map((paging: any) => ({ - toots: paging.toots.filter( - (toot: Mastodon.Conversation) => toot.id !== conversation.id - ), - pointer: paging.pointer - })) - ) + queryClient.setQueryData(queryKey, old => { + let tootIndex = -1 + const pageIndex = findIndex(old?.pages, page => { + const tempIndex = findIndex(page.toots, ['id', conversation.id]) + if (tempIndex >= 0) { + tootIndex = tempIndex + return true + } else { + return false + } + }) + + if (pageIndex >= 0 && tootIndex >= 0) { + old!.pages[pageIndex].toots.splice(tootIndex, 1) + } + + return old + }) return oldData }, diff --git a/src/i18n/zh/screens/sharedAccount.ts b/src/i18n/zh/screens/sharedAccount.ts index 50a8b129..f1fda9a4 100644 --- a/src/i18n/zh/screens/sharedAccount.ts +++ b/src/i18n/zh/screens/sharedAccount.ts @@ -7,8 +7,8 @@ export default { created_at: '加入时间:{{date}}', summary: { statuses_count: '{{count}} 条嘟文', - followers_count: '关注 {{count}} 人', - following_count: '被 {{count}} 人关注' + following_count: '关注 {{count}} 人', + followers_count: '被 {{count}} 人关注' }, segments: { left: '所有嘟嘟', diff --git a/src/screens/Shared/Account/Information/Stats.tsx b/src/screens/Shared/Account/Information/Stats.tsx index 4efad66a..bc6b1aa9 100644 --- a/src/screens/Shared/Account/Information/Stats.tsx +++ b/src/screens/Shared/Account/Information/Stats.tsx @@ -1,3 +1,4 @@ +import { useNavigation } from '@react-navigation/native' import { StyleConstants } from '@root/utils/styles/constants' import { useTheme } from '@root/utils/styles/ThemeManager' import { LinearGradient } from 'expo-linear-gradient' @@ -13,6 +14,7 @@ export interface Props { } const AccountInformationStats = forwardRef(({ account }, ref) => { + const navigation = useNavigation() const { theme } = useTheme() const { t } = useTranslation('sharedAccount') const ShimmerPlaceholder = createShimmerPlaceholder(LinearGradient) @@ -55,10 +57,17 @@ const AccountInformationStats = forwardRef(({ account }, ref) => { shimmerColors={theme.shimmer} > + account && + navigation.push('Screen-Shared-Relationships', { + account, + initialType: 'following' + }) + } > - {t('content.summary.followers_count', { - count: account?.followers_count || 0 + {t('content.summary.following_count', { + count: account?.following_count || 0 })} @@ -70,10 +79,17 @@ const AccountInformationStats = forwardRef(({ account }, ref) => { shimmerColors={theme.shimmer} > + account && + navigation.push('Screen-Shared-Relationships', { + account, + initialType: 'followers' + }) + } > - {t('content.summary.following_count', { - count: account?.following_count || 0 + {t('content.summary.followers_count', { + count: account?.followers_count || 0 })} diff --git a/src/screens/Shared/Compose/Reply.tsx b/src/screens/Shared/Compose/Reply.tsx index 0407d57f..624cddaa 100644 --- a/src/screens/Shared/Compose/Reply.tsx +++ b/src/screens/Shared/Compose/Reply.tsx @@ -1,13 +1,8 @@ -import TimelineAttachment from '@components/Timelines/Timeline/Shared/Attachment' -import TimelineAvatar from '@components/Timelines/Timeline/Shared/Avatar' -import TimelineCard from '@components/Timelines/Timeline/Shared/Card' -import TimelineContent from '@components/Timelines/Timeline/Shared/Content' -import TimelineHeaderDefault from '@components/Timelines/Timeline/Shared/HeaderDefault' -import { StyleConstants } from '@utils/styles/constants' import { useTheme } from '@utils/styles/ThemeManager' import ComposeContext from './utils/createContext' import React, { useContext } from 'react' import { StyleSheet, View } from 'react-native' +import TimelineDefault from '@root/components/Timelines/Timeline/Default' const ComposeReply: React.FC = () => { const { @@ -16,32 +11,20 @@ const ComposeReply: React.FC = () => { const { theme } = useTheme() return ( - - - - - {replyToStatus!.content.length > 0 && ( - - )} - {replyToStatus!.media_attachments.length > 0 && ( - - )} - {replyToStatus!.card && } - + + ) } const styles = StyleSheet.create({ - status: { - flex: 1, - flexDirection: 'row', - borderTopWidth: StyleSheet.hairlineWidth, - paddingTop: StyleConstants.Spacing.Global.PagePadding, - margin: StyleConstants.Spacing.Global.PagePadding - }, - details: { - flex: 1 + base: { + borderTopWidth: StyleSheet.hairlineWidth } }) diff --git a/src/screens/Shared/Relationships.tsx b/src/screens/Shared/Relationships.tsx new file mode 100644 index 00000000..5f4d6e2b --- /dev/null +++ b/src/screens/Shared/Relationships.tsx @@ -0,0 +1,81 @@ +import SegmentedControl from '@react-native-community/segmented-control' +import { useNavigation } from '@react-navigation/native' +import { useTheme } from '@utils/styles/ThemeManager' +import React, { useEffect, useState } from 'react' +import { Dimensions, StyleSheet, View } from 'react-native' +import { TabView } from 'react-native-tab-view' +import RelationshipsList from './Relationships/List' + +export interface Props { + route: { + params: { + account: Mastodon.Account + initialType: 'following' | 'followers' + } + } +} + +const ScreenSharedRelationships: React.FC = ({ + route: { + params: { account, initialType } + } +}) => { + console.log(account.id) + const { mode } = useTheme() + const navigation = useNavigation() + + const [segment, setSegment] = useState(initialType === 'following' ? 0 : 1) + useEffect(() => { + const updateHeaderRight = () => + navigation.setOptions({ + headerCenter: () => ( + + + setSegment(nativeEvent.selectedSegmentIndex) + } + /> + + ) + }) + return updateHeaderRight() + }, []) + + const routes: { key: Props['route']['params']['initialType'] }[] = [ + { key: 'following' }, + { key: 'followers' } + ] + + const renderScene = ({ + route + }: { + route: { + key: Props['route']['params']['initialType'] + } + }) => { + return + } + + return ( + null} + initialLayout={{ width: Dimensions.get('window').width }} + navigationState={{ index: segment, routes }} + onIndexChange={index => setSegment(index)} + /> + ) +} + +const styles = StyleSheet.create({ + segmentsContainer: { + flexBasis: '60%' + } +}) + +export default React.memo(ScreenSharedRelationships, () => true) diff --git a/src/screens/Shared/Relationships/List.tsx b/src/screens/Shared/Relationships/List.tsx new file mode 100644 index 00000000..86667a9f --- /dev/null +++ b/src/screens/Shared/Relationships/List.tsx @@ -0,0 +1,98 @@ +import ComponentAccount from '@components/Account' +import ComponentSeparator from '@components/Separator' +import TimelineEmpty from '@components/Timelines/Timeline/Empty' +import TimelineEnd from '@root/components/Timelines/Timeline/End' +import { useScrollToTop } from '@react-navigation/native' +import { relationshipsFetch } from '@utils/fetches/relationshipsFetch' +import React, { useCallback, useMemo, useRef } from 'react' +import { RefreshControl, StyleSheet } from 'react-native' +import { FlatList } from 'react-native-gesture-handler' +import { useInfiniteQuery } from 'react-query' + +export interface Props { + id: Mastodon.Account['id'] + type: 'following' | 'followers' +} + +const RelationshipsList: React.FC = ({ id, type }) => { + const queryKey: QueryKey.Relationships = ['Relationships', type, { id }] + + const { + status, + data, + isFetching, + refetch, + hasNextPage, + fetchNextPage, + isFetchingNextPage + } = useInfiniteQuery(queryKey, relationshipsFetch, { + getNextPageParam: lastPage => { + return lastPage.length + ? { + direction: 'next', + id: lastPage[lastPage.length - 1].id + } + : undefined + } + }) + const flattenData = data?.pages ? data.pages.flatMap(d => [...d]) : [] + + const flRef = useRef>(null) + + const keyExtractor = useCallback(({ id }) => id, []) + const renderItem = useCallback( + ({ item }) => , + [] + ) + const flItemEmptyComponent = useMemo( + () => , + [status] + ) + const onEndReached = useCallback( + () => !isFetchingNextPage && fetchNextPage(), + [isFetchingNextPage] + ) + const ListFooterComponent = useCallback( + () => , + [hasNextPage] + ) + const refreshControl = useMemo( + () => ( + refetch()} /> + ), + [isFetching] + ) + + useScrollToTop(flRef) + + return ( + + ) +} + +const styles = StyleSheet.create({ + flatList: { + minHeight: '100%' + } +}) + +export default RelationshipsList diff --git a/src/screens/Shared/Search.tsx b/src/screens/Shared/Search.tsx index 556ef17f..64369b52 100644 --- a/src/screens/Shared/Search.tsx +++ b/src/screens/Shared/Search.tsx @@ -1,24 +1,22 @@ -import { HeaderRight } from '@components/Header' -import Icon from '@components/Icon' -import { ParseEmojis, ParseHTML } from '@components/Parse' import { useNavigation } from '@react-navigation/native' +import ComponentAccount from '@root/components/Account' +import ComponentSeparator from '@root/components/Separator' +import TimelineDefault from '@root/components/Timelines/Timeline/Default' import { searchFetch } from '@utils/fetches/searchFetch' import { StyleConstants } from '@utils/styles/constants' import { useTheme } from '@utils/styles/ThemeManager' import { debounce } from 'lodash' import React, { useCallback, useEffect, useMemo, useState } from 'react' import { - Image, KeyboardAvoidingView, Pressable, SectionList, StyleSheet, Text, - TextInput, View } from 'react-native' import { Chase } from 'react-native-animated-spinkit' -import { SafeAreaView } from 'react-native-safe-area-context' +import { TextInput } from 'react-native-gesture-handler' import { useQuery } from 'react-query' const ScreenSharedSearch: React.FC = () => { @@ -31,6 +29,42 @@ const ScreenSharedSearch: React.FC = () => { { enabled: false } ) + useEffect(() => { + const updateHeaderRight = () => + navigation.setOptions({ + headerCenter: () => ( + + + 搜索 + + + setSearchTerm(text) + } + placeholder={'些什么'} + placeholderTextColor={theme.secondary} + returnKeyType='go' + /> + + ) + }) + return updateHeaderRight() + }, []) + const [setctionData, setSectionData] = useState< { title: string; data: any }[] >([]) @@ -74,48 +108,50 @@ const ScreenSharedSearch: React.FC = () => { const listEmpty = useMemo( () => ( - {status === 'loading' ? ( - - - - ) : ( - <> - - 输入关键词搜索用户、 - 话题标签或者 - 嘟文 - - - 高级搜索格式 - - - @username@domain - {' '} - 搜索用户 - - - #example - {' '}搜索话题标签 - - - URL - {' '}搜索指定嘟文 - - - URL - {' '}搜索指定用户 - - - )} + + {status === 'loading' ? ( + + + + ) : ( + <> + + 输入关键词搜索用户、 + 话题标签或者 + 嘟文 + + + 高级搜索格式 + + + @username@domain + {' '} + 搜索用户 + + + #example + {' '}搜索话题标签 + + + URL + {' '}搜索指定嘟文 + + + URL + {' '}搜索指定用户 + + + )} + ), [status] @@ -123,10 +159,7 @@ const ScreenSharedSearch: React.FC = () => { const sectionHeader = useCallback( ({ section: { title } }) => ( {title} @@ -152,43 +185,10 @@ const ScreenSharedSearch: React.FC = () => { ) : null, [searchTerm] ) - const listItem = useCallback(({ item, section }) => { + const listItem = useCallback(({ item, section, index }) => { switch (section.title) { case 'accounts': - return ( - { - navigation.goBack() - navigation.push('Screen-Shared-Account', { account: item }) - }} - > - - - - - - - @{item.acct} - - - - ) + return case 'hashtags': return ( { ) case 'statuses': - return ( - { - navigation.goBack() - navigation.push('Screen-Shared-Toot', { toot: item }) - }} - > - - - - - - - @{item.account.acct} - - {item.content && ( - - - - )} - - - ) + return default: return null } @@ -257,100 +214,42 @@ const ScreenSharedSearch: React.FC = () => { return ( - - - - - - setSearchTerm(text) - } - placeholder={'搜索些什么'} - placeholderTextColor={theme.secondary} - returnKeyType='go' - /> - - - navigation.goBack()} - /> - - - item + index} - /> - + item + index} + SectionSeparatorComponent={ComponentSeparator} + ItemSeparatorComponent={ComponentSeparator} + /> ) } const styles = StyleSheet.create({ base: { - flex: 1, - padding: StyleConstants.Spacing.Global.PagePadding, - paddingTop: 0 + minHeight: '100%' }, searchBar: { - padding: StyleConstants.Spacing.Global.PagePadding, - paddingBottom: 0, + flexBasis: '80%', flexDirection: 'row', alignItems: 'center' }, - searchField: { - flex: 1, - flexDirection: 'row', - alignItems: 'center', - borderBottomWidth: 1.25 - }, - searchIcon: { - marginLeft: StyleConstants.Spacing.S - }, - searchCancel: { - paddingHorizontal: StyleConstants.Spacing.S, - marginLeft: StyleConstants.Spacing.S - }, textInput: { - flex: 1, - padding: StyleConstants.Spacing.S, ...StyleConstants.FontStyle.M, - marginRight: StyleConstants.Spacing.S + paddingLeft: StyleConstants.Spacing.XS, + marginBottom: + (StyleConstants.Font.LineHeight.M - StyleConstants.Font.Size.M) / 2 }, - emptyBase: { - marginTop: StyleConstants.Spacing.M, - marginLeft: - StyleConstants.Spacing.S + - StyleConstants.Spacing.M + - StyleConstants.Spacing.S + marginVertical: StyleConstants.Spacing.Global.PagePadding, + // paddingHorizontal: StyleConstants.Spacing.Global.PagePadding + alignItems: 'center' }, loading: { flex: 1, alignItems: 'center' }, emptyFontSize: { ...StyleConstants.FontStyle.S }, @@ -364,8 +263,7 @@ const styles = StyleSheet.create({ marginBottom: StyleConstants.Spacing.S }, sectionHeader: { - padding: StyleConstants.Spacing.M, - borderBottomWidth: StyleSheet.hairlineWidth + padding: StyleConstants.Spacing.M }, sectionHeaderText: { ...StyleConstants.FontStyle.M, @@ -383,23 +281,8 @@ const styles = StyleSheet.create({ padding: StyleConstants.Spacing.S * 1.5, borderBottomWidth: StyleSheet.hairlineWidth }, - itemAccount: { - flexDirection: 'row', - alignItems: 'center' - }, - itemAccountAvatar: { - alignSelf: 'flex-start', - width: StyleConstants.Avatar.S, - height: StyleConstants.Avatar.S, - borderRadius: 6, - marginRight: StyleConstants.Spacing.S - }, - itemAccountAcct: { marginTop: StyleConstants.Spacing.XS }, itemHashtag: { ...StyleConstants.FontStyle.M - }, - itemStatus: { - marginTop: StyleConstants.Spacing.S } }) diff --git a/src/screens/Shared/sharedScreens.tsx b/src/screens/Shared/sharedScreens.tsx index d3bcf7ad..1c97f385 100644 --- a/src/screens/Shared/sharedScreens.tsx +++ b/src/screens/Shared/sharedScreens.tsx @@ -1,15 +1,15 @@ -import { HeaderLeft } from '@root/components/Header' +import { HeaderLeft, HeaderRight } from '@components/Header' import ScreenSharedAccount from '@screens/Shared/Account' -import ScreenSharedAnnouncements from '@root/screens/Shared/Announcements' +import ScreenSharedAnnouncements from '@screens/Shared/Announcements' import ScreenSharedHashtag from '@screens/Shared/Hashtag' +import ScreenSharedImagesViewer from '@screens/Shared/ImagesViewer' +import ScreenSharedRelationships from '@screens/Shared/Relationships' import ScreenSharedToot from '@screens/Shared/Toot' import Compose from '@screens/Shared/Compose' -import ComposeEditAttachment from '@screens/Shared/Compose/EditAttachment' import ScreenSharedSearch from '@screens/Shared/Search' import React from 'react' -import { Text } from 'react-native' import { useTranslation } from 'react-i18next' -import ScreenSharedImagesViewer from './ImagesViewer' +import { View } from 'react-native' const sharedScreens = (Stack: any) => { const { t } = useTranslation() @@ -60,9 +60,9 @@ const sharedScreens = (Stack: any) => { key='Screen-Shared-Search' name='Screen-Shared-Search' component={ScreenSharedSearch} - options={{ - stackPresentation: 'modal' - }} + options={({ navigation }: any) => ({ + headerLeft: () => navigation.goBack()} /> + })} />, { stackPresentation: 'transparentModal', stackAnimation: 'none' }} + />, + ({ + title: route.params.account.display_name || route.params.account.name, + headerLeft: () => navigation.goBack()} /> + })} /> ] } diff --git a/src/utils/fetches/relationshipsFetch.ts b/src/utils/fetches/relationshipsFetch.ts new file mode 100644 index 00000000..4277569d --- /dev/null +++ b/src/utils/fetches/relationshipsFetch.ts @@ -0,0 +1,28 @@ +import client from '@api/client' + +export const relationshipsFetch = async ({ + queryKey, + pageParam +}: { + queryKey: QueryKey.Relationships + pageParam?: { direction: 'next'; id: Mastodon.Status['id'] } +}): Promise => { + const [_, type, { id }] = queryKey + let params: { [key: string]: string } = {} + + if (pageParam) { + switch (pageParam.direction) { + case 'next': + params.max_id = pageParam.id + break + } + } + + const res = await client({ + method: 'get', + instance: 'local', + url: `accounts/${id}/${type}`, + params + }) + return Promise.resolve(res.body) +} diff --git a/src/utils/styles/constants.ts b/src/utils/styles/constants.ts index 36616719..dfe33032 100644 --- a/src/utils/styles/constants.ts +++ b/src/utils/styles/constants.ts @@ -3,7 +3,7 @@ const Base = 4 export const StyleConstants = { Font: { Size: { S: 14, M: 16, L: 18 }, - LineHeight: { S: 18, M: 22, L: 30 }, + LineHeight: { S: 18, M: 22, L: 26 }, Weight: { Bold: '600' as '600' } }, FontStyle: { @@ -21,5 +21,5 @@ export const StyleConstants = { Global: { PagePadding: Base * 4 } }, - Avatar: { S: 36, M: 52, L: 104 } + Avatar: { S: 40, M: 52, L: 104 } }