1
0
mirror of https://github.com/tooot-app/app synced 2025-06-05 22:19:13 +02:00
This commit is contained in:
Zhiyuan Zheng
2020-12-20 17:53:24 +01:00
parent 98a60df9d1
commit 09b960d368
15 changed files with 228 additions and 158 deletions

1
src/@types/app.d.ts vendored
View File

@ -57,7 +57,6 @@ declare namespace QueryKey {
type Timeline = [ type Timeline = [
Pages, Pages,
{ {
page: Pages
hashtag?: Mastodon.Tag['name'] hashtag?: Mastodon.Tag['name']
list?: Mastodon.List['id'] list?: Mastodon.List['id']
toot?: Mastodon.Status toot?: Mastodon.Status

View File

@ -84,8 +84,7 @@ const renderNode = ({
}} }}
onPress={() => { onPress={() => {
navigation.navigate('Screen-Shared-Webview', { navigation.navigate('Screen-Shared-Webview', {
uri: href, uri: href
domain: domain[1]
}) })
}} }}
> >

View File

@ -39,7 +39,12 @@ const Timelines: React.FC<Props> = ({ name, content }) => {
}) })
}, []) }, [])
const [routes] = useState(content.map(p => ({ key: p.page }))) const routes = content
.filter(p =>
localRegistered ? p : p.page === 'RemotePublic' ? p : undefined
)
.map(p => ({ key: p.page }))
const renderScene = ({ const renderScene = ({
route route
}: { }: {
@ -47,7 +52,11 @@ const Timelines: React.FC<Props> = ({ name, content }) => {
key: App.Pages key: App.Pages
} }
}) => { }) => {
return <Timeline page={route.key} /> return (
(localRegistered || route.key === 'RemotePublic') && (
<Timeline page={route.key} />
)
)
} }
return ( return (

View File

@ -40,7 +40,6 @@ const Timeline: React.FC<Props> = ({
const queryKey: QueryKey.Timeline = [ const queryKey: QueryKey.Timeline = [
page, page,
{ {
page,
...(hashtag && { hashtag }), ...(hashtag && { hashtag }),
...(list && { list }), ...(list && { list }),
...(toot && { toot }), ...(toot && { toot }),
@ -91,27 +90,32 @@ const Timeline: React.FC<Props> = ({
}, [status]) }, [status])
const flKeyExtrator = useCallback(({ id }) => id, []) const flKeyExtrator = useCallback(({ id }) => id, [])
const flRenderItem = useCallback(({ item, index }) => { const flRenderItem = useCallback(
switch (page) { ({ item, index }) => {
case 'Conversations': switch (page) {
return <TimelineConversation item={item} queryKey={queryKey} /> case 'Conversations':
case 'Notifications': return <TimelineConversation item={item} queryKey={queryKey} />
return <TimelineNotifications notification={item} queryKey={queryKey} /> case 'Notifications':
default: return (
return ( <TimelineNotifications notification={item} queryKey={queryKey} />
<TimelineDefault )
item={item} default:
queryKey={queryKey} return (
index={index} <TimelineDefault
{...(flattenPinnedLength && item={item}
flattenPinnedLength[0] && { queryKey={queryKey}
pinnedLength: flattenPinnedLength[0] index={index}
})} {...(flattenPinnedLength &&
{...(toot && toot.id === item.id && { highlighted: true })} flattenPinnedLength[0] && {
/> pinnedLength: flattenPinnedLength[0]
) })}
} {...(toot && toot.id === item.id && { highlighted: true })}
}, []) />
)
}
},
[flattenPinnedLength[0]]
)
const flItemSeparatorComponent = useCallback( const flItemSeparatorComponent = useCallback(
({ leadingItem }) => ( ({ leadingItem }) => (
<TimelineSeparator <TimelineSeparator

View File

@ -74,7 +74,12 @@ const TimelineConversation: React.FC<Props> = ({
: StyleConstants.Avatar.M + StyleConstants.Spacing.S : StyleConstants.Avatar.M + StyleConstants.Spacing.S
}} }}
> >
<TimelineActions queryKey={queryKey} status={item.last_status!} /> <TimelineActions
queryKey={queryKey}
status={item.last_status!}
reblog={false}
sameAccountRoot={false}
/>
</View> </View>
</View> </View>
) )

View File

@ -12,6 +12,8 @@ import TimelineHeaderDefault from '@components/Timelines/Timeline/Shared/HeaderD
import TimelinePoll from '@components/Timelines/Timeline/Shared/Poll' import TimelinePoll from '@components/Timelines/Timeline/Shared/Poll'
import { StyleConstants } from '@utils/styles/constants' import { StyleConstants } from '@utils/styles/constants'
import { useSelector } from 'react-redux'
import { getLocalAccountId } from '@root/utils/slices/instancesSlice'
export interface Props { export interface Props {
item: Mastodon.Status item: Mastodon.Status
@ -29,6 +31,7 @@ const TimelineDefault: React.FC<Props> = ({
pinnedLength, pinnedLength,
highlighted = false highlighted = false
}) => { }) => {
const localAccountId = useSelector(getLocalAccountId)
const isRemotePublic = queryKey[0] === 'RemotePublic' const isRemotePublic = queryKey[0] === 'RemotePublic'
const navigation = useNavigation() const navigation = useNavigation()
@ -68,6 +71,7 @@ const TimelineDefault: React.FC<Props> = ({
queryKey={queryKey} queryKey={queryKey}
poll={actualStatus.poll} poll={actualStatus.poll}
reblog={item.reblog ? true : false} reblog={item.reblog ? true : false}
sameAccount={actualStatus.account.id === localAccountId}
/> />
)} )}
{actualStatus.media_attachments.length > 0 && ( {actualStatus.media_attachments.length > 0 && (
@ -76,7 +80,7 @@ const TimelineDefault: React.FC<Props> = ({
{actualStatus.card && <TimelineCard card={actualStatus.card} />} {actualStatus.card && <TimelineCard card={actualStatus.card} />}
</View> </View>
), ),
[actualStatus.poll?.voted] [actualStatus.poll]
) )
return ( return (
@ -95,6 +99,7 @@ const TimelineDefault: React.FC<Props> = ({
<TimelineHeaderDefault <TimelineHeaderDefault
{...(!isRemotePublic && { queryKey })} {...(!isRemotePublic && { queryKey })}
status={actualStatus} status={actualStatus}
sameAccount={actualStatus.account.id === localAccountId}
/> />
</View> </View>
@ -112,6 +117,7 @@ const TimelineDefault: React.FC<Props> = ({
queryKey={queryKey} queryKey={queryKey}
status={actualStatus} status={actualStatus}
reblog={item.reblog ? true : false} reblog={item.reblog ? true : false}
sameAccountRoot={item.account.id === localAccountId}
/> />
</View> </View>
)} )}

View File

@ -12,6 +12,8 @@ import TimelineHeaderNotification from '@components/Timelines/Timeline/Shared/He
import TimelinePoll from '@components/Timelines/Timeline/Shared/Poll' import TimelinePoll from '@components/Timelines/Timeline/Shared/Poll'
import { StyleConstants } from '@utils/styles/constants' import { StyleConstants } from '@utils/styles/constants'
import { useSelector } from 'react-redux'
import { getLocalAccountId } from '@root/utils/slices/instancesSlice'
export interface Props { export interface Props {
notification: Mastodon.Notification notification: Mastodon.Notification
@ -24,6 +26,7 @@ const TimelineNotifications: React.FC<Props> = ({
queryKey, queryKey,
highlighted = false highlighted = false
}) => { }) => {
const localAccountId = useSelector(getLocalAccountId)
const navigation = useNavigation() const navigation = useNavigation()
const actualAccount = notification.status const actualAccount = notification.status
? notification.status.account ? notification.status.account
@ -61,7 +64,12 @@ const TimelineNotifications: React.FC<Props> = ({
/> />
)} )}
{notification.status.poll && ( {notification.status.poll && (
<TimelinePoll queryKey={queryKey} status={notification.status} /> <TimelinePoll
queryKey={queryKey}
poll={notification.status.poll}
reblog={false}
sameAccount={notification.account.id === localAccountId}
/>
)} )}
{notification.status.media_attachments.length > 0 && ( {notification.status.media_attachments.length > 0 && (
<TimelineAttachment <TimelineAttachment
@ -100,7 +108,12 @@ const TimelineNotifications: React.FC<Props> = ({
: StyleConstants.Avatar.M + StyleConstants.Spacing.S : StyleConstants.Avatar.M + StyleConstants.Spacing.S
}} }}
> >
<TimelineActions queryKey={queryKey} status={notification.status} /> <TimelineActions
queryKey={queryKey}
status={notification.status}
reblog={false}
sameAccountRoot={notification.account.id === localAccountId}
/>
</View> </View>
)} )}
</View> </View>

View File

@ -11,6 +11,8 @@ import { useNavigation } from '@react-navigation/native'
import getCurrentTab from '@utils/getCurrentTab' import getCurrentTab from '@utils/getCurrentTab'
import { findIndex } from 'lodash' import { findIndex } from 'lodash'
import { TimelineData } from '../../Timeline' import { TimelineData } from '../../Timeline'
import { useSelector } from 'react-redux'
import { getLocalAccountId } from '@root/utils/slices/instancesSlice'
const fireMutation = async ({ const fireMutation = async ({
id, id,
@ -49,9 +51,15 @@ export interface Props {
queryKey: QueryKey.Timeline queryKey: QueryKey.Timeline
status: Mastodon.Status status: Mastodon.Status
reblog: boolean reblog: boolean
sameAccountRoot: boolean
} }
const TimelineActions: React.FC<Props> = ({ queryKey, status, reblog }) => { const TimelineActions: React.FC<Props> = ({
queryKey,
status,
reblog,
sameAccountRoot
}) => {
const navigation = useNavigation() const navigation = useNavigation()
const { theme } = useTheme() const { theme } = useTheme()
const iconColor = theme.secondary const iconColor = theme.secondary
@ -65,9 +73,28 @@ const TimelineActions: React.FC<Props> = ({ queryKey, status, reblog }) => {
const oldData = queryClient.getQueryData(queryKey) const oldData = queryClient.getQueryData(queryKey)
switch (type) { switch (type) {
// Update each specific page
case 'favourite': case 'favourite':
case 'reblog': case 'reblog':
case 'bookmark': case 'bookmark':
if (type === 'favourite' && queryKey[0] === 'Favourites') {
queryClient.invalidateQueries(['Favourites'])
break
}
if (
type === 'reblog' &&
queryKey[0] === 'Following' &&
prevState === true &&
sameAccountRoot
) {
queryClient.invalidateQueries(['Following'])
break
}
if (type === 'bookmark' && queryKey[0] === 'Bookmarks') {
queryClient.invalidateQueries(['Bookmarks'])
break
}
queryClient.setQueryData<TimelineData>(queryKey, old => { queryClient.setQueryData<TimelineData>(queryKey, old => {
let tootIndex = -1 let tootIndex = -1
const pageIndex = findIndex(old?.pages, page => { const pageIndex = findIndex(old?.pages, page => {

View File

@ -23,7 +23,7 @@ const fireMutation = async ({ id }: { id: string }) => {
instance: 'local', instance: 'local',
url: `conversations/${id}` url: `conversations/${id}`
}) })
console.log(res)
if (!res.body.error) { if (!res.body.error) {
toast({ type: 'success', content: '删除私信成功' }) toast({ type: 'success', content: '删除私信成功' })
return Promise.resolve() return Promise.resolve()

View File

@ -5,7 +5,7 @@ import { Feather } from '@expo/vector-icons'
import Emojis from '@components/Timelines/Timeline/Shared/Emojis' import Emojis from '@components/Timelines/Timeline/Shared/Emojis'
import relativeTime from '@utils/relativeTime' import relativeTime from '@utils/relativeTime'
import { getLocalAccountId, getLocalUrl } from '@utils/slices/instancesSlice' import { getLocalUrl } from '@utils/slices/instancesSlice'
import { useTheme } from '@utils/styles/ThemeManager' import { useTheme } from '@utils/styles/ThemeManager'
import BottomSheet from '@components/BottomSheet' import BottomSheet from '@components/BottomSheet'
import { useSelector } from 'react-redux' import { useSelector } from 'react-redux'
@ -17,9 +17,14 @@ import HeaderDefaultActionsDomain from '@components/Timelines/Timeline/Shared/He
export interface Props { export interface Props {
queryKey?: QueryKey.Timeline queryKey?: QueryKey.Timeline
status: Mastodon.Status status: Mastodon.Status
sameAccount: boolean
} }
const TimelineHeaderDefault: React.FC<Props> = ({ queryKey, status }) => { const TimelineHeaderDefault: React.FC<Props> = ({
queryKey,
status,
sameAccount
}) => {
const domain = status.uri const domain = status.uri
? status.uri.split(new RegExp(/\/\/(.*?)\//))[1] ? status.uri.split(new RegExp(/\/\/(.*?)\//))[1]
: '' : ''
@ -29,7 +34,6 @@ const TimelineHeaderDefault: React.FC<Props> = ({ queryKey, status }) => {
const { theme } = useTheme() const { theme } = useTheme()
const navigation = useNavigation() const navigation = useNavigation()
const localAccountId = useSelector(getLocalAccountId)
const localDomain = useSelector(getLocalUrl) const localDomain = useSelector(getLocalUrl)
const [since, setSince] = useState(relativeTime(status.created_at)) const [since, setSince] = useState(relativeTime(status.created_at))
const [modalVisible, setBottomSheetVisible] = useState(false) const [modalVisible, setBottomSheetVisible] = useState(false)
@ -46,9 +50,10 @@ const TimelineHeaderDefault: React.FC<Props> = ({ queryKey, status }) => {
const onPressAction = useCallback(() => setBottomSheetVisible(true), []) const onPressAction = useCallback(() => setBottomSheetVisible(true), [])
const onPressApplication = useCallback(() => { const onPressApplication = useCallback(() => {
navigation.navigate('Screen-Shared-Webview', { status.application!.website &&
uri: status.application!.website navigation.navigate('Screen-Shared-Webview', {
}) uri: status.application!.website
})
}, []) }, [])
const pressableAction = useMemo( const pressableAction = useMemo(
@ -128,7 +133,7 @@ const TimelineHeaderDefault: React.FC<Props> = ({ queryKey, status }) => {
visible={modalVisible} visible={modalVisible}
handleDismiss={() => setBottomSheetVisible(false)} handleDismiss={() => setBottomSheetVisible(false)}
> >
{status.account.id !== localAccountId && ( {!sameAccount && (
<HeaderDefaultActionsAccount <HeaderDefaultActionsAccount
queryKey={queryKey} queryKey={queryKey}
accountId={status.account.id} accountId={status.account.id}
@ -137,7 +142,7 @@ const TimelineHeaderDefault: React.FC<Props> = ({ queryKey, status }) => {
/> />
)} )}
{status.account.id === localAccountId && ( {sameAccount && (
<HeaderDefaultActionsStatus <HeaderDefaultActionsStatus
queryKey={queryKey} queryKey={queryKey}
status={status} status={status}

View File

@ -99,7 +99,6 @@ const HeaderDefaultActionsStatus: React.FC<Props> = ({
}) })
break break
case 'delete': case 'delete':
console.log('deleting toot')
queryClient.setQueryData<TimelineData>( queryClient.setQueryData<TimelineData>(
queryKey, queryKey,
old => old =>

View File

@ -18,26 +18,26 @@ const fireMutation = async ({
options options
}: { }: {
id: string id: string
options: { [key: number]: boolean } options?: { [key: number]: boolean }
}) => { }) => {
const formData = new FormData() const formData = new FormData()
Object.keys(options).forEach(option => { options &&
// @ts-ignore Object.keys(options).forEach(option => {
if (options[option]) { // @ts-ignore
formData.append('choices[]', option) if (options[option]) {
} formData.append('choices[]', option)
}) }
})
const res = await client({ const res = await client({
method: 'post', method: options ? 'post' : 'get',
instance: 'local', instance: 'local',
url: `polls/${id}/votes`, url: options ? `polls/${id}/votes` : `polls/${id}`,
body: formData ...(options && { body: formData })
}) })
if (res.body.id === id) { if (res.body.id === id) {
toast({ type: 'success', content: '投票成功成功' }) return Promise.resolve(res.body as Mastodon.Poll)
return Promise.resolve()
} else { } else {
toast({ toast({
type: 'error', type: 'error',
@ -52,40 +52,20 @@ export interface Props {
queryKey: QueryKey.Timeline queryKey: QueryKey.Timeline
poll: NonNullable<Mastodon.Status['poll']> poll: NonNullable<Mastodon.Status['poll']>
reblog: boolean reblog: boolean
sameAccount: boolean
} }
const TimelinePoll: React.FC<Props> = ({ queryKey, poll, reblog }) => { const TimelinePoll: React.FC<Props> = ({
queryKey,
poll,
reblog,
sameAccount
}) => {
const { theme } = useTheme() const { theme } = useTheme()
const queryClient = useQueryClient() const queryClient = useQueryClient()
const { mutate } = useMutation(fireMutation, { const mutation = useMutation(fireMutation, {
onMutate: ({ id, options }) => { onSuccess: (data, { id }) => {
queryClient.cancelQueries(queryKey) queryClient.cancelQueries(queryKey)
const oldData = queryClient.getQueryData(queryKey)
const updatePoll = (poll: Mastodon.Poll): Mastodon.Poll => {
const myVotes = Object.keys(options).filter(
// @ts-ignore
option => options[option]
)
const myVotesInt = myVotes.map(option => parseInt(option))
return {
...poll,
votes_count: poll.votes_count
? poll.votes_count + myVotes.length
: myVotes.length,
voters_count: poll.voters_count ? poll.voters_count + 1 : 1,
voted: true,
own_votes: myVotesInt,
options: poll.options.map((o, i) => {
if (myVotesInt.includes(i)) {
o.votes_count = o.votes_count + 1
}
return o
})
}
}
queryClient.setQueryData<TimelineData>(queryKey, old => { queryClient.setQueryData<TimelineData>(queryKey, old => {
let tootIndex = -1 let tootIndex = -1
@ -104,28 +84,49 @@ const TimelinePoll: React.FC<Props> = ({ queryKey, poll, reblog }) => {
if (pageIndex >= 0 && tootIndex >= 0) { if (pageIndex >= 0 && tootIndex >= 0) {
if (reblog) { if (reblog) {
old!.pages[pageIndex].toots[tootIndex].reblog!.poll = updatePoll( old!.pages[pageIndex].toots[tootIndex].reblog!.poll = data
old!.pages[pageIndex].toots[tootIndex].reblog!.poll!
)
} else { } else {
old!.pages[pageIndex].toots[tootIndex].poll = updatePoll( old!.pages[pageIndex].toots[tootIndex].poll = data
old!.pages[pageIndex].toots[tootIndex].poll!
)
} }
} }
return old return old
}) })
return oldData
},
onError: (err, _, oldData) => {
toast({ type: 'error', content: '请重试' })
queryClient.setQueryData(queryKey, oldData)
} }
}) })
const pollButton = () => {
if (!poll.expired) {
if (!sameAccount && !poll.voted) {
return (
<View style={styles.button}>
<ButtonRow
onPress={() => {
if (poll.multiple) {
mutation.mutate({ id: poll.id, options: multipleOptions })
} else {
mutation.mutate({ id: poll.id, options: singleOptions })
}
}}
{...(mutation.isLoading ? { icon: 'loader' } : { text: '投票' })}
disabled={mutation.isLoading}
/>
</View>
)
} else {
return (
<View style={styles.button}>
<ButtonRow
onPress={() => mutation.mutate({ id: poll.id })}
{...(mutation.isLoading ? { icon: 'loader' } : { text: '刷新' })}
disabled={mutation.isLoading}
/>
</View>
)
}
}
}
const pollExpiration = useMemo(() => { const pollExpiration = useMemo(() => {
// how many voted
if (poll.expired) { if (poll.expired) {
return ( return (
<Text style={[styles.expiration, { color: theme.secondary }]}> <Text style={[styles.expiration, { color: theme.secondary }]}>
@ -178,7 +179,10 @@ const TimelinePoll: React.FC<Props> = ({ queryKey, poll, reblog }) => {
)} )}
</View> </View>
<Text style={[styles.percentage, { color: theme.primary }]}> <Text style={[styles.percentage, { color: theme.primary }]}>
{Math.round((option.votes_count / poll.votes_count) * 100)}% {poll.votes_count
? Math.round((option.votes_count / poll.voters_count) * 100)
: 0}
%
</Text> </Text>
</View> </View>
@ -187,7 +191,7 @@ const TimelinePoll: React.FC<Props> = ({ queryKey, poll, reblog }) => {
styles.background, styles.background,
{ {
width: `${Math.round( width: `${Math.round(
(option.votes_count / poll.votes_count) * 100 (option.votes_count / poll.voters_count) * 100
)}%`, )}%`,
backgroundColor: theme.border backgroundColor: theme.border
} }
@ -234,20 +238,7 @@ const TimelinePoll: React.FC<Props> = ({ queryKey, poll, reblog }) => {
) )
)} )}
<View style={styles.meta}> <View style={styles.meta}>
{!poll.expired && !poll.own_votes?.length && ( {pollButton()}
<View style={styles.button}>
<ButtonRow
onPress={() => {
if (poll.multiple) {
mutate({ id: poll.id, options: multipleOptions })
} else {
mutate({ id: poll.id, options: singleOptions })
}
}}
text='投票'
/>
</View>
)}
<Text style={[styles.votes, { color: theme.secondary }]}> <Text style={[styles.votes, { color: theme.secondary }]}>
{poll.voters_count || 0}{' • '} {poll.voters_count || 0}{' • '}
</Text> </Text>
@ -299,7 +290,7 @@ const styles = StyleSheet.create({
top: 0, top: 0,
left: 0, left: 0,
height: '100%', height: '100%',
minWidth: 1, minWidth: 2,
borderTopRightRadius: 6, borderTopRightRadius: 6,
borderBottomRightRadius: 6 borderBottomRightRadius: 6
}, },
@ -320,7 +311,4 @@ const styles = StyleSheet.create({
} }
}) })
export default React.memo( export default TimelinePoll
TimelinePoll,
(prev, next) => prev.poll.voted === next.poll.voted
)

View File

@ -29,6 +29,7 @@ import { HeaderLeft, HeaderRight } from '@components/Header'
import { StyleConstants } from '@utils/styles/constants' import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager' import { useTheme } from '@utils/styles/ThemeManager'
import formatText from '@screens/Shared/Compose/formatText' import formatText from '@screens/Shared/Compose/formatText'
import { useQueryClient } from 'react-query'
const Stack = createNativeStackNavigator() const Stack = createNativeStackNavigator()
@ -316,6 +317,7 @@ export interface Props {
const Compose: React.FC<Props> = ({ route: { params }, navigation }) => { const Compose: React.FC<Props> = ({ route: { params }, navigation }) => {
const { theme } = useTheme() const { theme } = useTheme()
const queryClient = useQueryClient()
const [hasKeyboard, setHasKeyboard] = useState(false) const [hasKeyboard, setHasKeyboard] = useState(false)
useEffect(() => { useEffect(() => {
@ -449,7 +451,8 @@ const Compose: React.FC<Props> = ({ route: { params }, navigation }) => {
composeState.poll.expire + composeState.poll.expire +
composeState.attachments.sensitive + composeState.attachments.sensitive +
composeState.attachments.uploads.map(upload => upload.id) + composeState.attachments.uploads.map(upload => upload.id) +
composeState.visibility composeState.visibility +
(params?.type === 'edit' ? Math.random() : '')
).toString() ).toString()
}, },
body: formData body: formData
@ -462,7 +465,7 @@ const Compose: React.FC<Props> = ({ route: { params }, navigation }) => {
{ {
text: '好的', text: '好的',
onPress: () => { onPress: () => {
// clear homepage cache queryClient.invalidateQueries(['Following'])
navigation.goBack() navigation.goBack()
} }
} }

View File

@ -8,6 +8,7 @@ import { useTheme } from '@root/utils/styles/ThemeManager'
import { debounce } from 'lodash' import { debounce } from 'lodash'
import React, { useCallback, useEffect, useMemo, useState } from 'react' import React, { useCallback, useEffect, useMemo, useState } from 'react'
import { import {
ActivityIndicator,
Image, Image,
Pressable, Pressable,
SectionList, SectionList,
@ -70,42 +71,47 @@ const ScreenSharedSearch: React.FC = () => {
}, [searchTerm]) }, [searchTerm])
const listEmpty = useMemo( const listEmpty = useMemo(
() => ( () =>
<View style={styles.emptyBase}> status === 'loading' ? (
<Text <View style={styles.emptyBase}>
style={[ <ActivityIndicator />
styles.emptyDefault, </View>
styles.emptyFontSize, ) : (
{ color: theme.primary } <View style={styles.emptyBase}>
]} <Text
> style={[
<Text style={styles.emptyFontBold}></Text> styles.emptyDefault,
<Text style={styles.emptyFontBold}></Text> styles.emptyFontSize,
<Text style={styles.emptyFontBold}></Text> { color: theme.primary }
</Text> ]}
<Text style={[styles.emptyAdvanced, { color: theme.primary }]}> >
<Text style={styles.emptyFontBold}></Text>
</Text> <Text style={styles.emptyFontBold}></Text>
<Text style={[styles.emptyAdvanced, { color: theme.primary }]}> <Text style={styles.emptyFontBold}></Text>
<Text style={{ color: theme.secondary }}>@username@domain</Text> </Text>
{' '} <Text style={[styles.emptyAdvanced, { color: theme.primary }]}>
</Text> </Text>
<Text style={[styles.emptyAdvanced, { color: theme.primary }]}> <Text style={[styles.emptyAdvanced, { color: theme.primary }]}>
<Text style={{ color: theme.secondary }}>#example</Text> <Text style={{ color: theme.secondary }}>@username@domain</Text>
{' '} {' '}
</Text>
<Text style={[styles.emptyAdvanced, { color: theme.primary }]}> </Text>
<Text style={{ color: theme.secondary }}>URL</Text> <Text style={[styles.emptyAdvanced, { color: theme.primary }]}>
{' '} <Text style={{ color: theme.secondary }}>#example</Text>
</Text> {' '}
<Text style={[styles.emptyAdvanced, { color: theme.primary }]}> </Text>
<Text style={{ color: theme.secondary }}>URL</Text> <Text style={[styles.emptyAdvanced, { color: theme.primary }]}>
{' '} <Text style={{ color: theme.secondary }}>URL</Text>
</Text> {' '}
</View> </Text>
), <Text style={[styles.emptyAdvanced, { color: theme.primary }]}>
[] <Text style={{ color: theme.secondary }}>URL</Text>
{' '}
</Text>
</View>
),
[status]
) )
const sectionHeader = useCallback( const sectionHeader = useCallback(
({ section: { title } }) => ( ({ section: { title } }) => (
@ -247,7 +253,6 @@ const ScreenSharedSearch: React.FC = () => {
stickySectionHeadersEnabled stickySectionHeadersEnabled
sections={setctionData} sections={setctionData}
ListEmptyComponent={listEmpty} ListEmptyComponent={listEmpty}
refreshing={status === 'loading'}
keyboardShouldPersistTaps='always' keyboardShouldPersistTaps='always'
renderSectionHeader={sectionHeader} renderSectionHeader={sectionHeader}
renderSectionFooter={sectionFooter} renderSectionFooter={sectionFooter}

View File

@ -20,10 +20,18 @@ export const timelineFetch = async ({
if (pageParam) { if (pageParam) {
switch (pageParam.direction) { switch (pageParam.direction) {
case 'prev': case 'prev':
params.min_id = pageParam.id if (page === 'Bookmarks' || page === 'Favourites') {
params.max_id = pageParam.id
} else {
params.min_id = pageParam.id
}
break break
case 'next': case 'next':
params.max_id = pageParam.id if (page === 'Bookmarks' || page === 'Favourites') {
params.min_id = pageParam.id
} else {
params.max_id = pageParam.id
}
break break
} }
} }