mirror of
https://github.com/tooot-app/app
synced 2025-06-05 22:19:13 +02:00
Believe #638 can be closed now!
This commit is contained in:
@ -1,10 +1,19 @@
|
||||
import { BottomTabScreenProps } from '@react-navigation/bottom-tabs'
|
||||
import { NavigatorScreenParams } from '@react-navigation/native'
|
||||
import { NavigatorScreenParams, useNavigationState } from '@react-navigation/native'
|
||||
import { NativeStackScreenProps } from '@react-navigation/native-stack'
|
||||
import { StackNavigationProp } from '@react-navigation/stack'
|
||||
import { ComposeState } from '@screens/Compose/utils/types'
|
||||
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
||||
|
||||
export const useNavState = () =>
|
||||
useNavigationState(state =>
|
||||
state.routes.map(
|
||||
route => (route.params as { queryKey?: QueryKeyTimeline } | undefined)?.queryKey
|
||||
)
|
||||
)
|
||||
.filter(key => key?.[0] === 'Timeline')
|
||||
.reverse()
|
||||
|
||||
export type RootStackParamList = {
|
||||
'Screen-Tabs': NavigatorScreenParams<ScreenTabsStackParamList>
|
||||
'Screen-Announcements': { showAll: boolean }
|
||||
@ -13,20 +22,19 @@ export type RootStackParamList = {
|
||||
type: 'edit'
|
||||
incomingStatus: Mastodon.Status
|
||||
replyToStatus?: Mastodon.Status
|
||||
queryKey?: QueryKeyTimeline
|
||||
rootQueryKey?: QueryKeyTimeline
|
||||
navigationState: (QueryKeyTimeline | undefined)[]
|
||||
}
|
||||
| {
|
||||
type: 'deleteEdit'
|
||||
incomingStatus: Mastodon.Status
|
||||
replyToStatus?: Mastodon.Status
|
||||
queryKey?: QueryKeyTimeline
|
||||
navigationState: (QueryKeyTimeline | undefined)[]
|
||||
}
|
||||
| {
|
||||
type: 'reply'
|
||||
incomingStatus: Mastodon.Status
|
||||
accts: Mastodon.Account['acct'][]
|
||||
queryKey?: QueryKeyTimeline
|
||||
navigationState: (QueryKeyTimeline | undefined)[]
|
||||
}
|
||||
| {
|
||||
type: 'conversation'
|
||||
@ -85,27 +93,18 @@ export type ScreenTabsScreenProps<T extends keyof ScreenTabsStackParamList> = Bo
|
||||
export type TabSharedStackParamList = {
|
||||
'Tab-Shared-Account': {
|
||||
account: Pick<Mastodon.Account, 'id' | 'username' | 'acct' | 'url' | '_remote'>
|
||||
queryKey?: QueryKeyTimeline
|
||||
}
|
||||
'Tab-Shared-Account-In-Lists': {
|
||||
account: Pick<Mastodon.Account, 'id' | 'username'>
|
||||
}
|
||||
'Tab-Shared-Attachments': { account: Mastodon.Account }
|
||||
'Tab-Shared-Hashtag': {
|
||||
hashtag: Mastodon.Tag['name']
|
||||
}
|
||||
'Tab-Shared-History': {
|
||||
status: Mastodon.Status
|
||||
detectedLanguage: string
|
||||
}
|
||||
'Tab-Shared-Account-In-Lists': { account: Pick<Mastodon.Account, 'id' | 'username'> }
|
||||
'Tab-Shared-Attachments': { account: Mastodon.Account; queryKey?: QueryKeyTimeline }
|
||||
'Tab-Shared-Hashtag': { hashtag: Mastodon.Tag['name']; queryKey?: QueryKeyTimeline }
|
||||
'Tab-Shared-History': { status: Mastodon.Status; detectedLanguage: string }
|
||||
'Tab-Shared-Report': {
|
||||
account: Pick<Mastodon.Account, 'id' | 'acct' | 'username' | 'url'>
|
||||
status?: Pick<Mastodon.Status, 'id' | '_remote' | 'uri'>
|
||||
}
|
||||
'Tab-Shared-Search': undefined
|
||||
'Tab-Shared-Toot': {
|
||||
toot: Mastodon.Status
|
||||
rootQueryKey?: QueryKeyTimeline
|
||||
}
|
||||
'Tab-Shared-Toot': { toot: Mastodon.Status; queryKey?: QueryKeyTimeline }
|
||||
'Tab-Shared-Users':
|
||||
| {
|
||||
reference: 'accounts'
|
||||
@ -124,15 +123,15 @@ export type TabSharedStackScreenProps<T extends keyof TabSharedStackParamList> =
|
||||
NativeStackScreenProps<TabSharedStackParamList, T>
|
||||
|
||||
export type TabLocalStackParamList = {
|
||||
'Tab-Local-Root': undefined
|
||||
'Tab-Local-Root': { queryKey?: QueryKeyTimeline }
|
||||
} & TabSharedStackParamList
|
||||
|
||||
export type TabPublicStackParamList = {
|
||||
'Tab-Public-Root': undefined
|
||||
'Tab-Public-Root': { queryKey?: QueryKeyTimeline }
|
||||
} & TabSharedStackParamList
|
||||
|
||||
export type TabNotificationsStackParamList = {
|
||||
'Tab-Notifications-Root': undefined
|
||||
'Tab-Notifications-Root': { queryKey?: QueryKeyTimeline }
|
||||
'Tab-Notifications-Filters': undefined
|
||||
} & TabSharedStackParamList
|
||||
export type TabNotificationsStackScreenProps<T extends keyof TabNotificationsStackParamList> =
|
||||
@ -140,11 +139,11 @@ export type TabNotificationsStackScreenProps<T extends keyof TabNotificationsSta
|
||||
|
||||
export type TabMeStackParamList = {
|
||||
'Tab-Me-Root': undefined
|
||||
'Tab-Me-Bookmarks': undefined
|
||||
'Tab-Me-Conversations': undefined
|
||||
'Tab-Me-Favourites': undefined
|
||||
'Tab-Me-Bookmarks': { queryKey?: QueryKeyTimeline }
|
||||
'Tab-Me-Conversations': { queryKey?: QueryKeyTimeline }
|
||||
'Tab-Me-Favourites': { queryKey?: QueryKeyTimeline }
|
||||
'Tab-Me-FollowedTags': undefined
|
||||
'Tab-Me-List': Mastodon.List
|
||||
'Tab-Me-List': { list: Mastodon.List; queryKey?: QueryKeyTimeline }
|
||||
'Tab-Me-List-Accounts': Omit<Mastodon.List, 'replies_policy'>
|
||||
'Tab-Me-List-Edit':
|
||||
| {
|
||||
|
@ -4,9 +4,7 @@ import navigationRef from '@utils/navigation/navigationRef'
|
||||
const pushUseNavigate = (id?: Mastodon.Notification['id']) => {
|
||||
navigationRef.navigate('Screen-Tabs', {
|
||||
screen: 'Tab-Notifications',
|
||||
params: {
|
||||
screen: 'Tab-Notifications-Root'
|
||||
}
|
||||
params: { screen: 'Tab-Notifications-Root', params: {} }
|
||||
})
|
||||
|
||||
if (!id) {
|
||||
|
@ -9,13 +9,13 @@ import {
|
||||
import { PagedResponse } from '@utils/api/helpers'
|
||||
import apiInstance from '@utils/api/instance'
|
||||
import { featureCheck } from '@utils/helpers/featureCheck'
|
||||
import { useNavState } from '@utils/navigation/navigators'
|
||||
import { queryClient } from '@utils/queryHooks'
|
||||
import { getAccountStorage } from '@utils/storage/actions'
|
||||
import { AxiosError } from 'axios'
|
||||
import { uniqBy } from 'lodash'
|
||||
import { searchLocalStatus } from './search'
|
||||
import deleteItem from './timeline/deleteItem'
|
||||
import editItem from './timeline/editItem'
|
||||
import updateStatusProperty from './timeline/updateStatusProperty'
|
||||
|
||||
export type QueryKeyTimeline = [
|
||||
@ -248,8 +248,6 @@ enum MapPropertyToUrl {
|
||||
export type MutationVarsTimelineUpdateStatusProperty = {
|
||||
// This is status in general, including "status" inside conversation and notification
|
||||
type: 'updateStatusProperty'
|
||||
queryKey: QueryKeyTimeline
|
||||
rootQueryKey?: QueryKeyTimeline
|
||||
status: Mastodon.Status
|
||||
payload:
|
||||
| {
|
||||
@ -279,7 +277,6 @@ export type MutationVarsTimelineUpdateStatusProperty = {
|
||||
export type MutationVarsTimelineUpdateAccountProperty = {
|
||||
// This is status in general, including "status" inside conversation and notification
|
||||
type: 'updateAccountProperty'
|
||||
queryKey?: QueryKeyTimeline
|
||||
id: Mastodon.Account['id']
|
||||
payload: {
|
||||
property: 'mute' | 'block' | 'reports'
|
||||
@ -287,34 +284,22 @@ export type MutationVarsTimelineUpdateAccountProperty = {
|
||||
}
|
||||
}
|
||||
|
||||
export type MutationVarsTimelineEditItem = {
|
||||
// This is for editing status
|
||||
type: 'editItem'
|
||||
queryKey?: QueryKeyTimeline
|
||||
rootQueryKey?: QueryKeyTimeline
|
||||
status: Mastodon.Status
|
||||
}
|
||||
|
||||
export type MutationVarsTimelineDeleteItem = {
|
||||
// This is for deleting status and conversation
|
||||
type: 'deleteItem'
|
||||
source: 'statuses' | 'conversations'
|
||||
queryKey?: QueryKeyTimeline
|
||||
rootQueryKey?: QueryKeyTimeline
|
||||
id: Mastodon.Status['id']
|
||||
}
|
||||
|
||||
export type MutationVarsTimelineDomainBlock = {
|
||||
// This is for deleting status and conversation
|
||||
type: 'domainBlock'
|
||||
queryKey: QueryKeyTimeline
|
||||
domain: string
|
||||
}
|
||||
|
||||
export type MutationVarsTimeline =
|
||||
| MutationVarsTimelineUpdateStatusProperty
|
||||
| MutationVarsTimelineUpdateAccountProperty
|
||||
| MutationVarsTimelineEditItem
|
||||
| MutationVarsTimelineDeleteItem
|
||||
| MutationVarsTimelineDomainBlock
|
||||
|
||||
@ -380,8 +365,6 @@ const mutationFunction = async (params: MutationVarsTimeline) => {
|
||||
}
|
||||
})
|
||||
}
|
||||
case 'editItem':
|
||||
return { body: params.status }
|
||||
case 'deleteItem':
|
||||
return apiInstance<Mastodon.Conversation>({
|
||||
method: 'delete',
|
||||
@ -415,6 +398,8 @@ const useTimelineMutation = ({
|
||||
onSettled?: MutationOptionsTimeline['onSettled']
|
||||
onSuccess?: MutationOptionsTimeline['onSuccess']
|
||||
}) => {
|
||||
const navigationState = useNavState()
|
||||
|
||||
return useMutation<
|
||||
{ body: Mastodon.Conversation | Mastodon.Notification | Mastodon.Status },
|
||||
AxiosError,
|
||||
@ -425,19 +410,16 @@ const useTimelineMutation = ({
|
||||
onSuccess,
|
||||
...(onMutate && {
|
||||
onMutate: params => {
|
||||
queryClient.cancelQueries(params.queryKey)
|
||||
const oldData = params.queryKey && queryClient.getQueryData(params.queryKey)
|
||||
queryClient.cancelQueries(navigationState[0])
|
||||
const oldData = navigationState[0] && queryClient.getQueryData(navigationState[0])
|
||||
|
||||
haptics('Light')
|
||||
switch (params.type) {
|
||||
case 'updateStatusProperty':
|
||||
updateStatusProperty(params)
|
||||
break
|
||||
case 'editItem':
|
||||
editItem(params)
|
||||
updateStatusProperty(params, navigationState)
|
||||
break
|
||||
case 'deleteItem':
|
||||
deleteItem(params)
|
||||
deleteItem(params, navigationState)
|
||||
break
|
||||
}
|
||||
return oldData
|
||||
|
@ -1,29 +1,31 @@
|
||||
import { InfiniteData } from '@tanstack/react-query'
|
||||
import { queryClient } from '@utils/queryHooks'
|
||||
import { MutationVarsTimelineDeleteItem } from '../timeline'
|
||||
import { MutationVarsTimelineDeleteItem, QueryKeyTimeline, TimelineData } from '../timeline'
|
||||
|
||||
const deleteItem = ({ queryKey, rootQueryKey, id }: MutationVarsTimelineDeleteItem) => {
|
||||
queryKey &&
|
||||
queryClient.setQueryData<InfiniteData<any> | undefined>(queryKey, old => {
|
||||
const deleteItem = (
|
||||
{ id }: MutationVarsTimelineDeleteItem,
|
||||
navigationState: (QueryKeyTimeline | undefined)[]
|
||||
) => {
|
||||
for (const key of navigationState) {
|
||||
if (!key) continue
|
||||
|
||||
queryClient.setQueryData<InfiniteData<TimelineData> | undefined>(key, old => {
|
||||
if (old) {
|
||||
let foundToot: boolean = false
|
||||
old.pages = old.pages.map(page => {
|
||||
page.body = page.body.filter((item: Mastodon.Status) => item.id !== id)
|
||||
if (foundToot) return page
|
||||
|
||||
page.body = (page.body as Mastodon.Status[]).filter(
|
||||
(item: Mastodon.Status) => item.id !== id
|
||||
)
|
||||
|
||||
return page
|
||||
})
|
||||
return old
|
||||
}
|
||||
})
|
||||
|
||||
rootQueryKey &&
|
||||
queryClient.setQueryData<InfiniteData<any> | undefined>(rootQueryKey, old => {
|
||||
if (old) {
|
||||
old.pages = old.pages.map(page => {
|
||||
page.body = page.body.filter((item: Mastodon.Status) => item.id !== id)
|
||||
return page
|
||||
})
|
||||
return old
|
||||
}
|
||||
return old
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default deleteItem
|
||||
|
@ -1,39 +0,0 @@
|
||||
import { InfiniteData } from '@tanstack/react-query'
|
||||
import { queryClient } from '@utils/queryHooks'
|
||||
import { MutationVarsTimelineEditItem } from '../timeline'
|
||||
|
||||
const editItem = ({ queryKey, rootQueryKey, status }: MutationVarsTimelineEditItem) => {
|
||||
queryKey &&
|
||||
queryClient.setQueryData<InfiniteData<any> | undefined>(queryKey, old => {
|
||||
if (old) {
|
||||
old.pages = old.pages.map(page => {
|
||||
page.body = page.body.map((item: Mastodon.Status) => {
|
||||
if (item.id === status.id) {
|
||||
item = status
|
||||
}
|
||||
return item
|
||||
})
|
||||
return page
|
||||
})
|
||||
return old
|
||||
}
|
||||
})
|
||||
|
||||
rootQueryKey &&
|
||||
queryClient.setQueryData<InfiniteData<any> | undefined>(rootQueryKey, old => {
|
||||
if (old) {
|
||||
old.pages = old.pages.map(page => {
|
||||
page.body = page.body.map((item: Mastodon.Status) => {
|
||||
if (item.id === status.id) {
|
||||
item = status
|
||||
}
|
||||
return item
|
||||
})
|
||||
return page
|
||||
})
|
||||
return old
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export default editItem
|
@ -1,72 +1,78 @@
|
||||
import { InfiniteData } from '@tanstack/react-query'
|
||||
import { queryClient } from '@utils/queryHooks'
|
||||
import { MutationVarsTimelineUpdateStatusProperty, TimelineData } from '../timeline'
|
||||
import {
|
||||
MutationVarsTimelineUpdateStatusProperty,
|
||||
QueryKeyTimeline,
|
||||
TimelineData
|
||||
} from '../timeline'
|
||||
|
||||
const updateStatusProperty = ({
|
||||
queryKey,
|
||||
rootQueryKey,
|
||||
status,
|
||||
payload,
|
||||
poll
|
||||
}: MutationVarsTimelineUpdateStatusProperty & { poll?: Mastodon.Poll }) => {
|
||||
for (const key of [queryKey, rootQueryKey]) {
|
||||
const updateStatusProperty = (
|
||||
{ status, payload, poll }: MutationVarsTimelineUpdateStatusProperty & { poll?: Mastodon.Poll },
|
||||
navigationState: (QueryKeyTimeline | undefined)[]
|
||||
) => {
|
||||
const update = (to?: Mastodon.Status): boolean => {
|
||||
if (!to) return false
|
||||
enum MapPropertyToCount {
|
||||
favourited = 'favourites_count',
|
||||
reblogged = 'reblogs_count'
|
||||
}
|
||||
switch (payload.type) {
|
||||
case 'poll':
|
||||
to.poll = poll
|
||||
return true
|
||||
default:
|
||||
to[payload.type] = payload.to
|
||||
switch (payload.type) {
|
||||
case 'favourited':
|
||||
case 'reblogged':
|
||||
if (payload.to) {
|
||||
to[MapPropertyToCount[payload.type]]++
|
||||
} else {
|
||||
to[MapPropertyToCount[payload.type]]--
|
||||
}
|
||||
break
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
for (const key of navigationState) {
|
||||
if (!key) continue
|
||||
|
||||
queryClient.setQueryData<InfiniteData<TimelineData> | undefined>(key, old => {
|
||||
if (old) {
|
||||
let foundToot: Mastodon.Status | undefined = undefined
|
||||
let updated: boolean = false
|
||||
old.pages = old.pages.map(page => {
|
||||
if (foundToot) {
|
||||
return page
|
||||
} else {
|
||||
if (typeof (page.body as Mastodon.Conversation[])[0].unread === 'boolean') {
|
||||
foundToot = (page.body as Mastodon.Conversation[]).find(({ last_status }) =>
|
||||
last_status?.reblog
|
||||
? last_status.reblog.id === status.id
|
||||
: last_status?.id === status.id
|
||||
)?.last_status
|
||||
} else if (typeof (page.body as Mastodon.Notification[])[0].type === 'string') {
|
||||
foundToot = (page.body as Mastodon.Notification[]).find(no =>
|
||||
no.status?.reblog ? no.status.reblog.id === status.id : no.status?.id === status.id
|
||||
)?.status
|
||||
} else {
|
||||
foundToot = (page.body as Mastodon.Status[]).find(toot =>
|
||||
toot.reblog ? toot.reblog.id === status.id : toot.id === status.id
|
||||
)
|
||||
}
|
||||
if (updated) return page
|
||||
|
||||
return page
|
||||
}
|
||||
})
|
||||
|
||||
if (foundToot) {
|
||||
const toot = foundToot as Mastodon.Status
|
||||
enum MapPropertyToCount {
|
||||
favourited = 'favourites_count',
|
||||
reblogged = 'reblogs_count'
|
||||
}
|
||||
|
||||
switch (payload.type) {
|
||||
case 'poll':
|
||||
toot.poll = poll
|
||||
break
|
||||
default:
|
||||
toot[payload.type] = payload.to
|
||||
switch (payload.type) {
|
||||
case 'favourited':
|
||||
case 'reblogged':
|
||||
if (payload.to) {
|
||||
toot[MapPropertyToCount[payload.type]]++
|
||||
} else {
|
||||
toot[MapPropertyToCount[payload.type]]--
|
||||
}
|
||||
break
|
||||
if (typeof (page.body as Mastodon.Conversation[])[0].unread === 'boolean') {
|
||||
;(page.body as Mastodon.Conversation[]).forEach(({ last_status }) => {
|
||||
if (last_status?.reblog?.id === status.id) {
|
||||
updated = update(last_status.reblog)
|
||||
} else if (last_status?.id === status.id) {
|
||||
updated = update(last_status)
|
||||
}
|
||||
break
|
||||
})
|
||||
} else if (typeof (page.body as Mastodon.Notification[])[0].type === 'string') {
|
||||
;(page.body as Mastodon.Notification[]).forEach(no => {
|
||||
if (no.status?.reblog?.id === status.id) {
|
||||
updated = update(no.status.reblog)
|
||||
} else if (no.status?.id === status.id) {
|
||||
updated = update(no.status)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
;(page.body as Mastodon.Status[]).forEach(toot => {
|
||||
if (toot.reblog?.id === status.id) {
|
||||
updated = update(toot.reblog)
|
||||
} else if (toot.id === status.id) {
|
||||
updated = update(toot)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
return page
|
||||
})
|
||||
}
|
||||
|
||||
return old
|
||||
})
|
||||
}
|
||||
|
@ -5,8 +5,8 @@ export const dev = () => {
|
||||
if (__DEV__) {
|
||||
log('log', 'dev', 'loading tools')
|
||||
// @ts-ignore
|
||||
import('react-query-native-devtools').then(({ addPlugin }) => {
|
||||
addPlugin({ queryClient })
|
||||
})
|
||||
// import('react-query-native-devtools').then(({ addPlugin }) => {
|
||||
// addPlugin({ queryClient })
|
||||
// })
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user