mirror of
https://github.com/tooot-app/app
synced 2025-06-05 22:19:13 +02:00
Using react-query 3
This commit is contained in:
14
App.tsx
14
App.tsx
@ -1,7 +1,7 @@
|
|||||||
import * as SplashScreen from 'expo-splash-screen'
|
import * as SplashScreen from 'expo-splash-screen'
|
||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import { AppearanceProvider } from 'react-native-appearance'
|
import { AppearanceProvider } from 'react-native-appearance'
|
||||||
import { QueryCache, ReactQueryCacheProvider, setConsole } from 'react-query'
|
import { QueryClient, QueryClientProvider } from 'react-query'
|
||||||
import { Provider } from 'react-redux'
|
import { Provider } from 'react-redux'
|
||||||
import { PersistGate } from 'redux-persist/integration/react'
|
import { PersistGate } from 'redux-persist/integration/react'
|
||||||
|
|
||||||
@ -9,13 +9,7 @@ import { Index } from '@root/Index'
|
|||||||
import { persistor, store } from '@root/store'
|
import { persistor, store } from '@root/store'
|
||||||
import ThemeManager from '@utils/styles/ThemeManager'
|
import ThemeManager from '@utils/styles/ThemeManager'
|
||||||
|
|
||||||
const queryCache = new QueryCache()
|
const queryClient = new QueryClient()
|
||||||
|
|
||||||
setConsole({
|
|
||||||
log: console.log,
|
|
||||||
warn: console.warn,
|
|
||||||
error: console.warn
|
|
||||||
})
|
|
||||||
|
|
||||||
// if (__DEV__) {
|
// if (__DEV__) {
|
||||||
// const whyDidYouRender = require('@welldone-software/why-did-you-render')
|
// const whyDidYouRender = require('@welldone-software/why-did-you-render')
|
||||||
@ -53,7 +47,7 @@ const App: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<AppearanceProvider>
|
<AppearanceProvider>
|
||||||
<ReactQueryCacheProvider queryCache={queryCache}>
|
<QueryClientProvider client={queryClient}>
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<PersistGate
|
<PersistGate
|
||||||
persistor={persistor}
|
persistor={persistor}
|
||||||
@ -73,7 +67,7 @@ const App: React.FC = () => {
|
|||||||
}}
|
}}
|
||||||
</PersistGate>
|
</PersistGate>
|
||||||
</Provider>
|
</Provider>
|
||||||
</ReactQueryCacheProvider>
|
</QueryClientProvider>
|
||||||
</AppearanceProvider>
|
</AppearanceProvider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
16
package.json
16
package.json
@ -11,9 +11,9 @@
|
|||||||
"@expo/vector-icons": "^12.0.0",
|
"@expo/vector-icons": "^12.0.0",
|
||||||
"@react-native-community/masked-view": "0.1.10",
|
"@react-native-community/masked-view": "0.1.10",
|
||||||
"@react-native-community/segmented-control": "2.2.1",
|
"@react-native-community/segmented-control": "2.2.1",
|
||||||
"@react-navigation/bottom-tabs": "^5.10.6",
|
"@react-navigation/bottom-tabs": "^5.11.2",
|
||||||
"@react-navigation/native": "^5.8.6",
|
"@react-navigation/native": "^5.8.10",
|
||||||
"@reduxjs/toolkit": "^1.4.0",
|
"@reduxjs/toolkit": "^1.5.0",
|
||||||
"axios": "^0.21.0",
|
"axios": "^0.21.0",
|
||||||
"crypto-js": "^3.3.0",
|
"crypto-js": "^3.3.0",
|
||||||
"expo": "^40.0.0",
|
"expo": "^40.0.0",
|
||||||
@ -32,7 +32,7 @@
|
|||||||
"lodash": "^4.17.20",
|
"lodash": "^4.17.20",
|
||||||
"react": "16.13.1",
|
"react": "16.13.1",
|
||||||
"react-dom": "16.13.1",
|
"react-dom": "16.13.1",
|
||||||
"react-i18next": "^11.7.3",
|
"react-i18next": "^11.8.4",
|
||||||
"react-native": "https://github.com/expo/react-native/archive/sdk-40.0.0.tar.gz",
|
"react-native": "https://github.com/expo/react-native/archive/sdk-40.0.0.tar.gz",
|
||||||
"react-native-appearance": "~0.3.3",
|
"react-native-appearance": "~0.3.3",
|
||||||
"react-native-collapsible": "^1.5.3",
|
"react-native-collapsible": "^1.5.3",
|
||||||
@ -48,7 +48,7 @@
|
|||||||
"react-native-toast-message": "^1.3.4",
|
"react-native-toast-message": "^1.3.4",
|
||||||
"react-native-webview": "11.0.0",
|
"react-native-webview": "11.0.0",
|
||||||
"react-navigation": "^4.4.3",
|
"react-navigation": "^4.4.3",
|
||||||
"react-query": "^2.26.2",
|
"react-query": "^3.3.2",
|
||||||
"react-redux": "^7.2.2",
|
"react-redux": "^7.2.2",
|
||||||
"redux-persist": "^6.0.0",
|
"redux-persist": "^6.0.0",
|
||||||
"redux-persist-expo-securestore": "^2.0.0",
|
"redux-persist-expo-securestore": "^2.0.0",
|
||||||
@ -65,9 +65,9 @@
|
|||||||
"@types/react-dom": "~16.9.8",
|
"@types/react-dom": "~16.9.8",
|
||||||
"@types/react-native": "~0.63.2",
|
"@types/react-native": "~0.63.2",
|
||||||
"@types/react-navigation": "^3.4.0",
|
"@types/react-navigation": "^3.4.0",
|
||||||
"@types/react-redux": "^7.1.11",
|
"@types/react-redux": "^7.1.12",
|
||||||
"@welldone-software/why-did-you-render": "^6.0.0-rc.1",
|
"@welldone-software/why-did-you-render": "^6.0.3",
|
||||||
"babel-plugin-module-resolver": "^4.0.0",
|
"babel-plugin-module-resolver": "^4.1.0",
|
||||||
"typescript": "~4.0.0"
|
"typescript": "~4.0.0"
|
||||||
},
|
},
|
||||||
"private": true
|
"private": true
|
||||||
|
41
src/@types/app.d.ts
vendored
41
src/@types/app.d.ts
vendored
@ -14,8 +14,47 @@ declare namespace App {
|
|||||||
| 'Conversations'
|
| 'Conversations'
|
||||||
| 'Bookmarks'
|
| 'Bookmarks'
|
||||||
| 'Favourites'
|
| 'Favourites'
|
||||||
|
}
|
||||||
|
|
||||||
type QueryKey = [
|
declare namespace QueryKey {
|
||||||
|
type Account = [
|
||||||
|
'Account',
|
||||||
|
{
|
||||||
|
id: Mastodon.Account['id']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
type Application = [
|
||||||
|
'Application',
|
||||||
|
{
|
||||||
|
instanceDomain: string
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
type Instance = [
|
||||||
|
'Instance',
|
||||||
|
{
|
||||||
|
instanceDomain: string
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
type Relationship = [
|
||||||
|
'Relationship',
|
||||||
|
{
|
||||||
|
id: Mastodon.Account['id']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
type Search = [
|
||||||
|
'Search',
|
||||||
|
{
|
||||||
|
type?: 'accounts' | 'hashtags' | 'statuses'
|
||||||
|
term: string
|
||||||
|
limit?: number
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
type Timeline = [
|
||||||
Pages,
|
Pages,
|
||||||
{
|
{
|
||||||
page: Pages
|
page: Pages
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { useCallback, useEffect, useMemo, useRef } from 'react'
|
import React, { useCallback, useEffect, useMemo, useRef } from 'react'
|
||||||
import { AppState, StyleSheet } from 'react-native'
|
import { StyleSheet } from 'react-native'
|
||||||
import { setFocusHandler, useInfiniteQuery } from 'react-query'
|
import { useInfiniteQuery } from 'react-query'
|
||||||
|
|
||||||
import TimelineNotifications from '@components/Timelines/Timeline/Notifications'
|
import TimelineNotifications from '@components/Timelines/Timeline/Notifications'
|
||||||
import TimelineDefault from '@components/Timelines/Timeline/Default'
|
import TimelineDefault from '@components/Timelines/Timeline/Default'
|
||||||
@ -29,17 +29,7 @@ const Timeline: React.FC<Props> = ({
|
|||||||
account,
|
account,
|
||||||
disableRefresh = false
|
disableRefresh = false
|
||||||
}) => {
|
}) => {
|
||||||
setFocusHandler(handleFocus => {
|
const queryKey: QueryKey.Timeline = [
|
||||||
const handleAppStateChange = (appState: string) => {
|
|
||||||
if (appState === 'active') {
|
|
||||||
handleFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AppState.addEventListener('change', handleAppStateChange)
|
|
||||||
return () => AppState.removeEventListener('change', handleAppStateChange)
|
|
||||||
})
|
|
||||||
|
|
||||||
const queryKey: App.QueryKey = [
|
|
||||||
page,
|
page,
|
||||||
{
|
{
|
||||||
page,
|
page,
|
||||||
@ -51,24 +41,38 @@ const Timeline: React.FC<Props> = ({
|
|||||||
]
|
]
|
||||||
const {
|
const {
|
||||||
status,
|
status,
|
||||||
isSuccess,
|
|
||||||
isLoading,
|
|
||||||
isError,
|
|
||||||
isFetchingMore,
|
|
||||||
canFetchMore,
|
|
||||||
data,
|
data,
|
||||||
fetchMore,
|
refetch,
|
||||||
refetch
|
hasPreviousPage,
|
||||||
|
fetchPreviousPage,
|
||||||
|
isFetchingPreviousPage,
|
||||||
|
hasNextPage,
|
||||||
|
fetchNextPage,
|
||||||
|
isFetchingNextPage
|
||||||
} = useInfiniteQuery(queryKey, timelineFetch, {
|
} = useInfiniteQuery(queryKey, timelineFetch, {
|
||||||
getFetchMore: last => last?.toots.length > 0
|
getPreviousPageParam: firstPage => ({
|
||||||
|
direction: 'prev',
|
||||||
|
id: firstPage.toots[0].id
|
||||||
|
}),
|
||||||
|
getNextPageParam: lastPage =>
|
||||||
|
lastPage.toots.length
|
||||||
|
? {
|
||||||
|
direction: 'next',
|
||||||
|
id: lastPage.toots[lastPage.toots.length - 1].id
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
})
|
})
|
||||||
const flattenData = data ? data.flatMap(d => [...d?.toots]) : []
|
const flattenData = data?.pages ? data.pages.flatMap(d => [...d?.toots]) : []
|
||||||
const flattenPointer = data ? data.flatMap(d => [d?.pointer]) : []
|
const flattenPointer = data?.pages
|
||||||
const flattenPinnedLength = data ? data.flatMap(d => [d?.pinnedLength]) : []
|
? data.pages.flatMap(d => [d?.pointer])
|
||||||
|
: []
|
||||||
|
const flattenPinnedLength = data?.pages
|
||||||
|
? data.pages.flatMap(d => [d?.pinnedLength])
|
||||||
|
: []
|
||||||
|
|
||||||
const flRef = useRef<FlatList<any>>(null)
|
const flRef = useRef<FlatList<any>>(null)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (toot && isSuccess) {
|
if (toot && status === 'success') {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
flRef.current?.scrollToIndex({
|
flRef.current?.scrollToIndex({
|
||||||
index: flattenPointer[0]!,
|
index: flattenPointer[0]!,
|
||||||
@ -76,7 +80,7 @@ const Timeline: React.FC<Props> = ({
|
|||||||
})
|
})
|
||||||
}, 500)
|
}, 500)
|
||||||
}
|
}
|
||||||
}, [isSuccess])
|
}, [status])
|
||||||
|
|
||||||
const flKeyExtrator = useCallback(({ id }) => id, [])
|
const flKeyExtrator = useCallback(({ id }) => id, [])
|
||||||
const flRenderItem = useCallback(({ item, index }) => {
|
const flRenderItem = useCallback(({ item, index }) => {
|
||||||
@ -110,33 +114,16 @@ const Timeline: React.FC<Props> = ({
|
|||||||
)
|
)
|
||||||
const flItemEmptyComponent = useMemo(
|
const flItemEmptyComponent = useMemo(
|
||||||
() => <TimelineEmpty status={status} refetch={refetch} />,
|
() => <TimelineEmpty status={status} refetch={refetch} />,
|
||||||
[isLoading, isError, isSuccess]
|
[status]
|
||||||
)
|
)
|
||||||
const flOnRefresh = useCallback(
|
const flOnRefresh = useCallback(
|
||||||
() =>
|
() => !disableRefresh && fetchPreviousPage(),
|
||||||
!disableRefresh &&
|
[]
|
||||||
fetchMore(
|
|
||||||
{
|
|
||||||
direction: 'prev',
|
|
||||||
id: flattenData.length ? flattenData[0].id : null
|
|
||||||
},
|
|
||||||
{ previous: true }
|
|
||||||
),
|
|
||||||
[flattenData]
|
|
||||||
)
|
|
||||||
const flOnEndReach = useCallback(
|
|
||||||
() =>
|
|
||||||
!disableRefresh &&
|
|
||||||
canFetchMore &&
|
|
||||||
fetchMore({
|
|
||||||
direction: 'next',
|
|
||||||
id: flattenData[flattenData.length - 1].id
|
|
||||||
}),
|
|
||||||
[flattenData]
|
|
||||||
)
|
)
|
||||||
|
const flOnEndReach = useCallback(() => fetchNextPage(), [])
|
||||||
const flFooter = useCallback(() => {
|
const flFooter = useCallback(() => {
|
||||||
return <TimelineEnd isFetchingMore={isFetchingMore} />
|
return <TimelineEnd hasNextPage={hasNextPage} />
|
||||||
}, [isFetchingMore])
|
}, [hasNextPage])
|
||||||
const onScrollToIndexFailed = useCallback(error => {
|
const onScrollToIndexFailed = useCallback(error => {
|
||||||
const offset = error.averageItemLength * error.index
|
const offset = error.averageItemLength * error.index
|
||||||
flRef.current?.scrollToOffset({ offset })
|
flRef.current?.scrollToOffset({ offset })
|
||||||
@ -159,11 +146,11 @@ const Timeline: React.FC<Props> = ({
|
|||||||
onEndReached={flOnEndReach}
|
onEndReached={flOnEndReach}
|
||||||
keyExtractor={flKeyExtrator}
|
keyExtractor={flKeyExtrator}
|
||||||
ListFooterComponent={flFooter}
|
ListFooterComponent={flFooter}
|
||||||
|
refreshing={isFetchingPreviousPage}
|
||||||
ListEmptyComponent={flItemEmptyComponent}
|
ListEmptyComponent={flItemEmptyComponent}
|
||||||
ItemSeparatorComponent={flItemSeparatorComponent}
|
ItemSeparatorComponent={flItemSeparatorComponent}
|
||||||
onEndReachedThreshold={!disableRefresh ? 0.75 : null}
|
onEndReachedThreshold={!disableRefresh ? 0.75 : null}
|
||||||
refreshing={!disableRefresh && isLoading && flattenData.length > 0}
|
{...(toot && status === 'success' && { onScrollToIndexFailed })}
|
||||||
{...(toot && isSuccess && { onScrollToIndexFailed })}
|
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ import TimelineActions from '@components/Timelines/Timeline/Shared/Actions'
|
|||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
item: Mastodon.Conversation
|
item: Mastodon.Conversation
|
||||||
queryKey: App.QueryKey
|
queryKey: QueryKey.Timeline
|
||||||
highlighted?: boolean
|
highlighted?: boolean
|
||||||
}
|
}
|
||||||
// Unread and mark as unread
|
// Unread and mark as unread
|
||||||
|
@ -15,7 +15,7 @@ import { StyleConstants } from '@utils/styles/constants'
|
|||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
item: Mastodon.Status
|
item: Mastodon.Status
|
||||||
queryKey: App.QueryKey
|
queryKey: QueryKey.Timeline
|
||||||
index: number
|
index: number
|
||||||
pinnedLength?: number
|
pinnedLength?: number
|
||||||
highlighted?: boolean
|
highlighted?: boolean
|
||||||
|
@ -15,7 +15,7 @@ import { StyleConstants } from '@utils/styles/constants'
|
|||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
notification: Mastodon.Notification
|
notification: Mastodon.Notification
|
||||||
queryKey: App.QueryKey
|
queryKey: QueryKey.Timeline
|
||||||
highlighted?: boolean
|
highlighted?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { useCallback, useMemo } from 'react'
|
import React, { useCallback, useMemo } from 'react'
|
||||||
import { ActionSheetIOS, Pressable, StyleSheet, Text, View } from 'react-native'
|
import { ActionSheetIOS, Pressable, StyleSheet, Text, View } from 'react-native'
|
||||||
import { useMutation, useQueryCache } from 'react-query'
|
import { useMutation, useQueryClient } from 'react-query'
|
||||||
import { Feather } from '@expo/vector-icons'
|
import { Feather } from '@expo/vector-icons'
|
||||||
|
|
||||||
import client from '@api/client'
|
import client from '@api/client'
|
||||||
@ -44,7 +44,7 @@ const fireMutation = async ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
queryKey: App.QueryKey
|
queryKey: QueryKey.Timeline
|
||||||
status: Mastodon.Status
|
status: Mastodon.Status
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,20 +55,21 @@ const TimelineActions: React.FC<Props> = ({ queryKey, status }) => {
|
|||||||
const iconColorAction = (state: boolean) =>
|
const iconColorAction = (state: boolean) =>
|
||||||
state ? theme.primary : theme.secondary
|
state ? theme.primary : theme.secondary
|
||||||
|
|
||||||
const queryCache = useQueryCache()
|
const queryClient = useQueryClient()
|
||||||
const [mutateAction] = useMutation(fireMutation, {
|
const { mutate } = useMutation(fireMutation, {
|
||||||
onMutate: ({ id, type, stateKey, prevState }) => {
|
onMutate: ({ id, type, stateKey, prevState }) => {
|
||||||
queryCache.cancelQueries(queryKey)
|
queryClient.cancelQueries(queryKey)
|
||||||
const oldData = queryCache.getQueryData(queryKey)
|
const oldData = queryClient.getQueryData(queryKey)
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'favourite':
|
case 'favourite':
|
||||||
case 'reblog':
|
case 'reblog':
|
||||||
case 'bookmark':
|
case 'bookmark':
|
||||||
queryCache.setQueryData(queryKey, old =>
|
queryClient.setQueryData(queryKey, (old: any) => {
|
||||||
(old as {}[]).map((paging: any) => ({
|
old.pages.map((paging: any) => ({
|
||||||
toots: paging.toots.map((toot: any) => {
|
toots: paging.toots.map((toot: any) => {
|
||||||
if (toot.id === id) {
|
if (toot.id === id) {
|
||||||
|
console.log(toot[stateKey])
|
||||||
toot[stateKey] =
|
toot[stateKey] =
|
||||||
typeof prevState === 'boolean' ? !prevState : true
|
typeof prevState === 'boolean' ? !prevState : true
|
||||||
}
|
}
|
||||||
@ -76,7 +77,8 @@ const TimelineActions: React.FC<Props> = ({ queryKey, status }) => {
|
|||||||
}),
|
}),
|
||||||
pointer: paging.pointer
|
pointer: paging.pointer
|
||||||
}))
|
}))
|
||||||
)
|
return old
|
||||||
|
})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,7 +86,7 @@ const TimelineActions: React.FC<Props> = ({ queryKey, status }) => {
|
|||||||
},
|
},
|
||||||
onError: (err, _, oldData) => {
|
onError: (err, _, oldData) => {
|
||||||
toast({ type: 'error', content: '请重试' })
|
toast({ type: 'error', content: '请重试' })
|
||||||
queryCache.setQueryData(queryKey, oldData)
|
queryClient.setQueryData(queryKey, oldData)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -99,7 +101,7 @@ const TimelineActions: React.FC<Props> = ({ queryKey, status }) => {
|
|||||||
}, [])
|
}, [])
|
||||||
const onPressReblog = useCallback(
|
const onPressReblog = useCallback(
|
||||||
() =>
|
() =>
|
||||||
mutateAction({
|
mutate({
|
||||||
id: status.id,
|
id: status.id,
|
||||||
type: 'reblog',
|
type: 'reblog',
|
||||||
stateKey: 'reblogged',
|
stateKey: 'reblogged',
|
||||||
@ -109,7 +111,7 @@ const TimelineActions: React.FC<Props> = ({ queryKey, status }) => {
|
|||||||
)
|
)
|
||||||
const onPressFavourite = useCallback(
|
const onPressFavourite = useCallback(
|
||||||
() =>
|
() =>
|
||||||
mutateAction({
|
mutate({
|
||||||
id: status.id,
|
id: status.id,
|
||||||
type: 'favourite',
|
type: 'favourite',
|
||||||
stateKey: 'favourited',
|
stateKey: 'favourited',
|
||||||
@ -119,7 +121,7 @@ const TimelineActions: React.FC<Props> = ({ queryKey, status }) => {
|
|||||||
)
|
)
|
||||||
const onPressBookmark = useCallback(
|
const onPressBookmark = useCallback(
|
||||||
() =>
|
() =>
|
||||||
mutateAction({
|
mutate({
|
||||||
id: status.id,
|
id: status.id,
|
||||||
type: 'bookmark',
|
type: 'bookmark',
|
||||||
stateKey: 'bookmarked',
|
stateKey: 'bookmarked',
|
||||||
|
@ -4,7 +4,7 @@ import { Video } from 'expo-av'
|
|||||||
import { ButtonRound } from '@components/Button'
|
import { ButtonRound } from '@components/Button'
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
media_attachments: Mastodon.AttachmentVideo[]
|
media_attachments: Mastodon.Attachment[]
|
||||||
width: number
|
width: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import { StyleConstants } from '@utils/styles/constants'
|
|||||||
import { useNavigation } from '@react-navigation/native'
|
import { useNavigation } from '@react-navigation/native'
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
queryKey?: App.QueryKey
|
queryKey?: QueryKey.Timeline
|
||||||
account: Mastodon.Account
|
account: Mastodon.Account
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,15 +5,15 @@ import { StyleConstants } from '@utils/styles/constants'
|
|||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
isFetchingMore: false | 'previous' | 'next' | undefined
|
hasNextPage?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const TimelineEnd: React.FC<Props> = ({ isFetchingMore }) => {
|
const TimelineEnd: React.FC<Props> = ({ hasNextPage }) => {
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.base}>
|
<View style={styles.base}>
|
||||||
{isFetchingMore ? (
|
{hasNextPage ? (
|
||||||
<ActivityIndicator />
|
<ActivityIndicator />
|
||||||
) : (
|
) : (
|
||||||
<Text style={[styles.text, { color: theme.secondary }]}>
|
<Text style={[styles.text, { color: theme.secondary }]}>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Feather } from '@expo/vector-icons'
|
import { Feather } from '@expo/vector-icons'
|
||||||
import React, { useCallback, useMemo } from 'react'
|
import React, { useCallback, useMemo } from 'react'
|
||||||
import { Pressable, StyleSheet, Text, View } from 'react-native'
|
import { Pressable, StyleSheet, Text, View } from 'react-native'
|
||||||
import { useMutation, useQueryCache } from 'react-query'
|
import { useMutation, useQueryClient } from 'react-query'
|
||||||
import client from '@api/client'
|
import client from '@api/client'
|
||||||
import { toast } from '@components/toast'
|
import { toast } from '@components/toast'
|
||||||
|
|
||||||
@ -11,7 +11,7 @@ import { useTheme } from '@utils/styles/ThemeManager'
|
|||||||
import Emojis from '@components/Timelines/Timeline/Shared/Emojis'
|
import Emojis from '@components/Timelines/Timeline/Shared/Emojis'
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
queryKey: App.QueryKey
|
queryKey: QueryKey.Timeline
|
||||||
id: string
|
id: string
|
||||||
account: Mastodon.Account
|
account: Mastodon.Account
|
||||||
created_at?: Mastodon.Status['created_at']
|
created_at?: Mastodon.Status['created_at']
|
||||||
@ -43,14 +43,14 @@ const HeaderConversation: React.FC<Props> = ({
|
|||||||
account,
|
account,
|
||||||
created_at
|
created_at
|
||||||
}) => {
|
}) => {
|
||||||
const queryCache = useQueryCache()
|
const queryClient = useQueryClient()
|
||||||
const [mutateAction] = useMutation(fireMutation, {
|
const { mutate } = useMutation(fireMutation, {
|
||||||
onMutate: () => {
|
onMutate: () => {
|
||||||
queryCache.cancelQueries(queryKey)
|
queryClient.cancelQueries(queryKey)
|
||||||
const oldData = queryCache.getQueryData(queryKey)
|
const oldData = queryClient.getQueryData(queryKey)
|
||||||
|
|
||||||
queryCache.setQueryData(queryKey, old =>
|
queryClient.setQueryData(queryKey, (old: any) =>
|
||||||
(old as {}[]).map((paging: any) => ({
|
old.pages.map((paging: any) => ({
|
||||||
toots: paging.toots.filter((toot: any) => toot.id !== id),
|
toots: paging.toots.filter((toot: any) => toot.id !== id),
|
||||||
pointer: paging.pointer
|
pointer: paging.pointer
|
||||||
}))
|
}))
|
||||||
@ -60,16 +60,13 @@ const HeaderConversation: React.FC<Props> = ({
|
|||||||
},
|
},
|
||||||
onError: (err, _, oldData) => {
|
onError: (err, _, oldData) => {
|
||||||
toast({ type: 'error', content: '请重试', autoHide: false })
|
toast({ type: 'error', content: '请重试', autoHide: false })
|
||||||
queryCache.setQueryData(queryKey, oldData)
|
queryClient.setQueryData(queryKey, oldData)
|
||||||
},
|
|
||||||
onSettled: () => {
|
|
||||||
queryCache.invalidateQueries(queryKey)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
|
|
||||||
const actionOnPress = useCallback(() => mutateAction({ id }), [])
|
const actionOnPress = useCallback(() => mutate({ id }), [])
|
||||||
|
|
||||||
const actionChildren = useMemo(
|
const actionChildren = useMemo(
|
||||||
() => (
|
() => (
|
||||||
|
@ -15,7 +15,7 @@ import HeaderDefaultActionsStatus from '@components/Timelines/Timeline/Shared/He
|
|||||||
import HeaderDefaultActionsDomain from '@components/Timelines/Timeline/Shared/HeaderDefault/ActionsDomain'
|
import HeaderDefaultActionsDomain from '@components/Timelines/Timeline/Shared/HeaderDefault/ActionsDomain'
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
queryKey?: App.QueryKey
|
queryKey?: QueryKey.Timeline
|
||||||
status: Mastodon.Status
|
status: Mastodon.Status
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { useMutation, useQueryCache } from 'react-query'
|
import { useMutation, useQueryClient } from 'react-query'
|
||||||
import client from '@api/client'
|
import client from '@api/client'
|
||||||
import { MenuContainer, MenuHeader, MenuRow } from '@components/Menu'
|
import { MenuContainer, MenuHeader, MenuRow } from '@components/Menu'
|
||||||
import { toast } from '@components/toast'
|
import { toast } from '@components/toast'
|
||||||
@ -56,7 +56,7 @@ const fireMutation = async ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
queryKey: App.QueryKey
|
queryKey: QueryKey.Timeline
|
||||||
accountId: string
|
accountId: string
|
||||||
account: string
|
account: string
|
||||||
setBottomSheetVisible: React.Dispatch<React.SetStateAction<boolean>>
|
setBottomSheetVisible: React.Dispatch<React.SetStateAction<boolean>>
|
||||||
@ -68,19 +68,16 @@ const HeaderDefaultActionsAccount: React.FC<Props> = ({
|
|||||||
account,
|
account,
|
||||||
setBottomSheetVisible
|
setBottomSheetVisible
|
||||||
}) => {
|
}) => {
|
||||||
const queryCache = useQueryCache()
|
const queryClient = useQueryClient()
|
||||||
const [mutateAction] = useMutation(fireMutation, {
|
const { mutate } = useMutation(fireMutation, {
|
||||||
onMutate: () => {
|
onMutate: () => {
|
||||||
queryCache.cancelQueries(queryKey)
|
queryClient.cancelQueries(queryKey)
|
||||||
const oldData = queryCache.getQueryData(queryKey)
|
const oldData = queryClient.getQueryData(queryKey)
|
||||||
return oldData
|
return oldData
|
||||||
},
|
},
|
||||||
onError: (err, _, oldData) => {
|
onError: (err, _, oldData) => {
|
||||||
toast({ type: 'error', content: '请重试', autoHide: false })
|
toast({ type: 'error', content: '请重试', autoHide: false })
|
||||||
queryCache.setQueryData(queryKey, oldData)
|
queryClient.setQueryData(queryKey, oldData)
|
||||||
},
|
|
||||||
onSettled: () => {
|
|
||||||
queryCache.invalidateQueries(queryKey)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -90,7 +87,7 @@ const HeaderDefaultActionsAccount: React.FC<Props> = ({
|
|||||||
<MenuRow
|
<MenuRow
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
setBottomSheetVisible(false)
|
setBottomSheetVisible(false)
|
||||||
mutateAction({
|
mutate({
|
||||||
type: 'mute',
|
type: 'mute',
|
||||||
id: accountId,
|
id: accountId,
|
||||||
stateKey: 'muting'
|
stateKey: 'muting'
|
||||||
@ -102,7 +99,7 @@ const HeaderDefaultActionsAccount: React.FC<Props> = ({
|
|||||||
<MenuRow
|
<MenuRow
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
setBottomSheetVisible(false)
|
setBottomSheetVisible(false)
|
||||||
mutateAction({
|
mutate({
|
||||||
type: 'block',
|
type: 'block',
|
||||||
id: accountId,
|
id: accountId,
|
||||||
stateKey: 'blocking'
|
stateKey: 'blocking'
|
||||||
@ -114,7 +111,7 @@ const HeaderDefaultActionsAccount: React.FC<Props> = ({
|
|||||||
<MenuRow
|
<MenuRow
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
setBottomSheetVisible(false)
|
setBottomSheetVisible(false)
|
||||||
mutateAction({
|
mutate({
|
||||||
type: 'reports',
|
type: 'reports',
|
||||||
id: accountId
|
id: accountId
|
||||||
})
|
})
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { useMutation, useQueryCache } from 'react-query'
|
import { useMutation, useQueryClient } from 'react-query'
|
||||||
import client from '@api/client'
|
import client from '@api/client'
|
||||||
import MenuContainer from '@components/Menu/Container'
|
import MenuContainer from '@components/Menu/Container'
|
||||||
import MenuHeader from '@components/Menu/Header'
|
import MenuHeader from '@components/Menu/Header'
|
||||||
@ -30,7 +30,7 @@ const fireMutation = async ({ domain }: { domain: string }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
queryKey: App.QueryKey
|
queryKey: QueryKey.Timeline
|
||||||
domain: string
|
domain: string
|
||||||
setBottomSheetVisible: React.Dispatch<React.SetStateAction<boolean>>
|
setBottomSheetVisible: React.Dispatch<React.SetStateAction<boolean>>
|
||||||
}
|
}
|
||||||
@ -40,19 +40,19 @@ const HeaderDefaultActionsDomain: React.FC<Props> = ({
|
|||||||
domain,
|
domain,
|
||||||
setBottomSheetVisible
|
setBottomSheetVisible
|
||||||
}) => {
|
}) => {
|
||||||
const queryCache = useQueryCache()
|
const queryClient = useQueryClient()
|
||||||
const [mutateAction] = useMutation(fireMutation, {
|
const { mutate } = useMutation(fireMutation, {
|
||||||
onMutate: () => {
|
onMutate: () => {
|
||||||
queryCache.cancelQueries(queryKey)
|
queryClient.cancelQueries(queryKey)
|
||||||
const oldData = queryCache.getQueryData(queryKey)
|
const oldData = queryClient.getQueryData(queryKey)
|
||||||
return oldData
|
return oldData
|
||||||
},
|
},
|
||||||
onError: (err, _, oldData) => {
|
onError: (err, _, oldData) => {
|
||||||
toast({ type: 'error', content: '请重试', autoHide: false })
|
toast({ type: 'error', content: '请重试', autoHide: false })
|
||||||
queryCache.setQueryData(queryKey, oldData)
|
queryClient.setQueryData(queryKey, oldData)
|
||||||
},
|
},
|
||||||
onSettled: () => {
|
onSettled: () => {
|
||||||
queryCache.invalidateQueries(queryKey)
|
queryClient.invalidateQueries(queryKey)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ const HeaderDefaultActionsDomain: React.FC<Props> = ({
|
|||||||
<MenuRow
|
<MenuRow
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
setBottomSheetVisible(false)
|
setBottomSheetVisible(false)
|
||||||
mutateAction({ domain })
|
mutate({ domain })
|
||||||
}}
|
}}
|
||||||
iconFront='cloud-off'
|
iconFront='cloud-off'
|
||||||
title={`屏蔽域名 ${domain}`}
|
title={`屏蔽域名 ${domain}`}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { useNavigation } from '@react-navigation/native'
|
import { useNavigation } from '@react-navigation/native'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { Alert } from 'react-native'
|
import { Alert } from 'react-native'
|
||||||
import { useMutation, useQueryCache } from 'react-query'
|
import { useMutation, useQueryClient } from 'react-query'
|
||||||
import client from '@api/client'
|
import client from '@api/client'
|
||||||
import { MenuContainer, MenuHeader, MenuRow } from '@components/Menu'
|
import { MenuContainer, MenuHeader, MenuRow } from '@components/Menu'
|
||||||
import { toast } from '@components/toast'
|
import { toast } from '@components/toast'
|
||||||
@ -55,7 +55,7 @@ const fireMutation = async ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
queryKey: App.QueryKey
|
queryKey: QueryKey.Timeline
|
||||||
status: Mastodon.Status
|
status: Mastodon.Status
|
||||||
setBottomSheetVisible: React.Dispatch<React.SetStateAction<boolean>>
|
setBottomSheetVisible: React.Dispatch<React.SetStateAction<boolean>>
|
||||||
}
|
}
|
||||||
@ -66,17 +66,17 @@ const HeaderDefaultActionsStatus: React.FC<Props> = ({
|
|||||||
setBottomSheetVisible
|
setBottomSheetVisible
|
||||||
}) => {
|
}) => {
|
||||||
const navigation = useNavigation()
|
const navigation = useNavigation()
|
||||||
const queryCache = useQueryCache()
|
const queryClient = useQueryClient()
|
||||||
const [mutateAction] = useMutation(fireMutation, {
|
const { mutate } = useMutation(fireMutation, {
|
||||||
onMutate: ({ id, type, stateKey, prevState }) => {
|
onMutate: ({ id, type, stateKey, prevState }) => {
|
||||||
queryCache.cancelQueries(queryKey)
|
queryClient.cancelQueries(queryKey)
|
||||||
const oldData = queryCache.getQueryData(queryKey)
|
const oldData = queryClient.getQueryData(queryKey)
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'mute':
|
case 'mute':
|
||||||
case 'pin':
|
case 'pin':
|
||||||
queryCache.setQueryData(queryKey, old =>
|
queryClient.setQueryData(queryKey, (old: any) =>
|
||||||
(old as {}[]).map((paging: any) => ({
|
old.pages.map((paging: any) => ({
|
||||||
toots: paging.toots.map((toot: any) => {
|
toots: paging.toots.map((toot: any) => {
|
||||||
if (toot.id === id) {
|
if (toot.id === id) {
|
||||||
toot[stateKey] =
|
toot[stateKey] =
|
||||||
@ -89,8 +89,8 @@ const HeaderDefaultActionsStatus: React.FC<Props> = ({
|
|||||||
)
|
)
|
||||||
break
|
break
|
||||||
case 'delete':
|
case 'delete':
|
||||||
queryCache.setQueryData(queryKey, old =>
|
queryClient.setQueryData(queryKey, (old: any) =>
|
||||||
(old as {}[]).map((paging: any) => ({
|
old.pages.map((paging: any) => ({
|
||||||
toots: paging.toots.filter((toot: any) => toot.id !== id),
|
toots: paging.toots.filter((toot: any) => toot.id !== id),
|
||||||
pointer: paging.pointer
|
pointer: paging.pointer
|
||||||
}))
|
}))
|
||||||
@ -102,7 +102,7 @@ const HeaderDefaultActionsStatus: React.FC<Props> = ({
|
|||||||
},
|
},
|
||||||
onError: (err, _, oldData) => {
|
onError: (err, _, oldData) => {
|
||||||
toast({ type: 'error', content: '请重试' })
|
toast({ type: 'error', content: '请重试' })
|
||||||
queryCache.setQueryData(queryKey, oldData)
|
queryClient.setQueryData(queryKey, oldData)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -112,7 +112,7 @@ const HeaderDefaultActionsStatus: React.FC<Props> = ({
|
|||||||
<MenuRow
|
<MenuRow
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
setBottomSheetVisible(false)
|
setBottomSheetVisible(false)
|
||||||
mutateAction({
|
mutate({
|
||||||
type: 'delete',
|
type: 'delete',
|
||||||
id: status.id,
|
id: status.id,
|
||||||
stateKey: 'id'
|
stateKey: 'id'
|
||||||
@ -138,7 +138,7 @@ const HeaderDefaultActionsStatus: React.FC<Props> = ({
|
|||||||
url: `statuses/${status.id}`
|
url: `statuses/${status.id}`
|
||||||
})
|
})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
queryCache.invalidateQueries(queryKey)
|
queryClient.invalidateQueries(queryKey)
|
||||||
setBottomSheetVisible(false)
|
setBottomSheetVisible(false)
|
||||||
navigation.navigate(getCurrentTab(navigation), {
|
navigation.navigate(getCurrentTab(navigation), {
|
||||||
screen: 'Screen-Shared-Compose',
|
screen: 'Screen-Shared-Compose',
|
||||||
@ -159,7 +159,7 @@ const HeaderDefaultActionsStatus: React.FC<Props> = ({
|
|||||||
<MenuRow
|
<MenuRow
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
setBottomSheetVisible(false)
|
setBottomSheetVisible(false)
|
||||||
mutateAction({
|
mutate({
|
||||||
type: 'mute',
|
type: 'mute',
|
||||||
id: status.id,
|
id: status.id,
|
||||||
stateKey: 'muted',
|
stateKey: 'muted',
|
||||||
@ -174,7 +174,7 @@ const HeaderDefaultActionsStatus: React.FC<Props> = ({
|
|||||||
<MenuRow
|
<MenuRow
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
setBottomSheetVisible(false)
|
setBottomSheetVisible(false)
|
||||||
mutateAction({
|
mutate({
|
||||||
type: 'pin',
|
type: 'pin',
|
||||||
id: status.id,
|
id: status.id,
|
||||||
stateKey: 'pinned',
|
stateKey: 'pinned',
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Feather } from '@expo/vector-icons'
|
import { Feather } from '@expo/vector-icons'
|
||||||
import React, { useMemo, useState } from 'react'
|
import React, { useMemo, useState } from 'react'
|
||||||
import { Pressable, StyleSheet, Text, View } from 'react-native'
|
import { Pressable, StyleSheet, Text, View } from 'react-native'
|
||||||
import { useMutation, useQueryCache } from 'react-query'
|
import { useMutation, useQueryClient } from 'react-query'
|
||||||
import client from '@api/client'
|
import client from '@api/client'
|
||||||
import { ButtonRow } from '@components/Button'
|
import { ButtonRow } from '@components/Button'
|
||||||
import { toast } from '@components/toast'
|
import { toast } from '@components/toast'
|
||||||
@ -47,21 +47,21 @@ const fireMutation = async ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
queryKey: App.QueryKey
|
queryKey: QueryKey.Timeline
|
||||||
status: Mastodon.Status
|
status: Required<Mastodon.Status, 'poll'>
|
||||||
}
|
}
|
||||||
|
|
||||||
const TimelinePoll: React.FC<Props> = ({ queryKey, status: { poll } }) => {
|
const TimelinePoll: React.FC<Props> = ({ queryKey, status: { poll } }) => {
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
|
|
||||||
const queryCache = useQueryCache()
|
const queryClient = useQueryClient()
|
||||||
const [mutateAction] = useMutation(fireMutation, {
|
const { mutate } = useMutation(fireMutation, {
|
||||||
onMutate: ({ id, options }) => {
|
onMutate: ({ id, options }) => {
|
||||||
queryCache.cancelQueries(queryKey)
|
queryClient.cancelQueries(queryKey)
|
||||||
const oldData = queryCache.getQueryData(queryKey)
|
const oldData = queryClient.getQueryData(queryKey)
|
||||||
|
|
||||||
queryCache.setQueryData(queryKey, old =>
|
queryClient.setQueryData(queryKey, (old: any) =>
|
||||||
(old as {}[]).map((paging: any) => ({
|
old.pages.map((paging: any) => ({
|
||||||
toots: paging.toots.map((toot: any) => {
|
toots: paging.toots.map((toot: any) => {
|
||||||
if (toot.poll?.id === id) {
|
if (toot.poll?.id === id) {
|
||||||
const poll = toot.poll
|
const poll = toot.poll
|
||||||
@ -98,13 +98,13 @@ const TimelinePoll: React.FC<Props> = ({ queryKey, status: { poll } }) => {
|
|||||||
},
|
},
|
||||||
onError: (err, _, oldData) => {
|
onError: (err, _, oldData) => {
|
||||||
toast({ type: 'error', content: '请重试' })
|
toast({ type: 'error', content: '请重试' })
|
||||||
queryCache.setQueryData(queryKey, oldData)
|
queryClient.setQueryData(queryKey, oldData)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const pollExpiration = useMemo(() => {
|
const pollExpiration = useMemo(() => {
|
||||||
// how many voted
|
// 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 }]}>
|
||||||
投票已结束
|
投票已结束
|
||||||
@ -113,20 +113,20 @@ const TimelinePoll: React.FC<Props> = ({ queryKey, status: { poll } }) => {
|
|||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<Text style={[styles.expiration, { color: theme.secondary }]}>
|
<Text style={[styles.expiration, { color: theme.secondary }]}>
|
||||||
{relativeTime(poll!.expires_at)}截止
|
{relativeTime(poll.expires_at)}截止
|
||||||
</Text>
|
</Text>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const [singleOptions, setSingleOptions] = useState({
|
const [singleOptions, setSingleOptions] = useState({
|
||||||
...[false, false, false, false].slice(0, poll!.options.length)
|
...[false, false, false, false].slice(0, poll.options.length)
|
||||||
})
|
})
|
||||||
const [multipleOptions, setMultipleOptions] = useState({
|
const [multipleOptions, setMultipleOptions] = useState({
|
||||||
...[false, false, false, false].slice(0, poll!.options.length)
|
...[false, false, false, false].slice(0, poll.options.length)
|
||||||
})
|
})
|
||||||
const isSelected = (index: number) => {
|
const isSelected = (index: number) => {
|
||||||
if (poll!.multiple) {
|
if (poll.multiple) {
|
||||||
return multipleOptions[index] ? 'check-square' : 'square'
|
return multipleOptions[index] ? 'check-square' : 'square'
|
||||||
} else {
|
} else {
|
||||||
return singleOptions[index] ? 'check-circle' : 'circle'
|
return singleOptions[index] ? 'check-circle' : 'circle'
|
||||||
@ -135,28 +135,28 @@ const TimelinePoll: React.FC<Props> = ({ queryKey, status: { poll } }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.base}>
|
<View style={styles.base}>
|
||||||
{poll!.options.map((option, index) =>
|
{poll.options.map((option, index) =>
|
||||||
poll!.voted ? (
|
poll.voted ? (
|
||||||
<View key={index} style={styles.poll}>
|
<View key={index} style={styles.poll}>
|
||||||
<View style={styles.optionSelected}>
|
<View style={styles.optionSelected}>
|
||||||
<View style={styles.contentSelected}>
|
<View style={styles.contentSelected}>
|
||||||
<Emojis
|
<Emojis
|
||||||
content={option.title}
|
content={option.title}
|
||||||
emojis={poll!.emojis}
|
emojis={poll.emojis}
|
||||||
size={StyleConstants.Font.Size.M}
|
size={StyleConstants.Font.Size.M}
|
||||||
numberOfLines={1}
|
numberOfLines={1}
|
||||||
/>
|
/>
|
||||||
{poll!.own_votes!.includes(index) && (
|
{poll.own_votes!.includes(index) && (
|
||||||
<Feather
|
<Feather
|
||||||
style={styles.voted}
|
style={styles.voted}
|
||||||
name={poll!.multiple ? 'check-square' : 'check-circle'}
|
name={poll.multiple ? 'check-square' : 'check-circle'}
|
||||||
size={StyleConstants.Font.Size.M}
|
size={StyleConstants.Font.Size.M}
|
||||||
color={theme.primary}
|
color={theme.primary}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</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)}%
|
{Math.round((option.votes_count / poll.votes_count) * 100)}%
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
@ -165,7 +165,7 @@ const TimelinePoll: React.FC<Props> = ({ queryKey, status: { poll } }) => {
|
|||||||
styles.background,
|
styles.background,
|
||||||
{
|
{
|
||||||
width: `${Math.round(
|
width: `${Math.round(
|
||||||
(option.votes_count / poll!.votes_count) * 100
|
(option.votes_count / poll.votes_count) * 100
|
||||||
)}%`,
|
)}%`,
|
||||||
backgroundColor: theme.border
|
backgroundColor: theme.border
|
||||||
}
|
}
|
||||||
@ -177,7 +177,7 @@ const TimelinePoll: React.FC<Props> = ({ queryKey, status: { poll } }) => {
|
|||||||
<Pressable
|
<Pressable
|
||||||
style={[styles.optionUnselected]}
|
style={[styles.optionUnselected]}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
if (poll!.multiple) {
|
if (poll.multiple) {
|
||||||
setMultipleOptions({
|
setMultipleOptions({
|
||||||
...multipleOptions,
|
...multipleOptions,
|
||||||
[index]: !multipleOptions[index]
|
[index]: !multipleOptions[index]
|
||||||
@ -189,7 +189,7 @@ const TimelinePoll: React.FC<Props> = ({ queryKey, status: { poll } }) => {
|
|||||||
index === 1,
|
index === 1,
|
||||||
index === 2,
|
index === 2,
|
||||||
index === 3
|
index === 3
|
||||||
].slice(0, poll!.options.length)
|
].slice(0, poll.options.length)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
@ -203,7 +203,7 @@ const TimelinePoll: React.FC<Props> = ({ queryKey, status: { poll } }) => {
|
|||||||
<View style={styles.contentUnselected}>
|
<View style={styles.contentUnselected}>
|
||||||
<Emojis
|
<Emojis
|
||||||
content={option.title}
|
content={option.title}
|
||||||
emojis={poll!.emojis}
|
emojis={poll.emojis}
|
||||||
size={StyleConstants.Font.Size.M}
|
size={StyleConstants.Font.Size.M}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
@ -217,9 +217,9 @@ const TimelinePoll: React.FC<Props> = ({ queryKey, status: { poll } }) => {
|
|||||||
<ButtonRow
|
<ButtonRow
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
if (poll.multiple) {
|
if (poll.multiple) {
|
||||||
mutateAction({ id: poll.id, options: multipleOptions })
|
mutate({ id: poll.id, options: multipleOptions })
|
||||||
} else {
|
} else {
|
||||||
mutateAction({ id: poll.id, options: singleOptions })
|
mutate({ id: poll.id, options: singleOptions })
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
text='投票'
|
text='投票'
|
||||||
|
@ -6,13 +6,13 @@ import MenuButton from '@components/Menu/Button'
|
|||||||
import { MenuContainer } from '@components/Menu'
|
import { MenuContainer } from '@components/Menu'
|
||||||
import { useNavigation } from '@react-navigation/native'
|
import { useNavigation } from '@react-navigation/native'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useQueryCache } from 'react-query'
|
import { useQueryClient } from 'react-query'
|
||||||
|
|
||||||
const Logout: React.FC = () => {
|
const Logout: React.FC = () => {
|
||||||
const { t } = useTranslation('meRoot')
|
const { t } = useTranslation('meRoot')
|
||||||
const dispatch = useDispatch()
|
const dispatch = useDispatch()
|
||||||
const navigation = useNavigation()
|
const navigation = useNavigation()
|
||||||
const queryCache = useQueryCache()
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
const alertOption = {
|
const alertOption = {
|
||||||
title: t('content.logout.alert.title'),
|
title: t('content.logout.alert.title'),
|
||||||
@ -22,7 +22,7 @@ const Logout: React.FC = () => {
|
|||||||
text: t('content.logout.alert.buttons.logout'),
|
text: t('content.logout.alert.buttons.logout'),
|
||||||
style: 'destructive' as const,
|
style: 'destructive' as const,
|
||||||
onPress: () => {
|
onPress: () => {
|
||||||
queryCache.clear()
|
queryClient.clear()
|
||||||
dispatch(updateLocal({}))
|
dispatch(updateLocal({}))
|
||||||
navigation.navigate('Screen-Public', {
|
navigation.navigate('Screen-Public', {
|
||||||
screen: 'Screen-Public-Root',
|
screen: 'Screen-Public-Root',
|
||||||
|
@ -22,7 +22,7 @@ const ScreenMeSettings: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<MenuContainer marginTop={true}>
|
<MenuContainer>
|
||||||
<MenuRow
|
<MenuRow
|
||||||
title={t('content.language.heading')}
|
title={t('content.language.heading')}
|
||||||
content={t(`content.language.options.${settingsLanguage}`)}
|
content={t(`content.language.options.${settingsLanguage}`)}
|
||||||
|
@ -25,7 +25,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 { PanGestureHandler } from 'react-native-gesture-handler'
|
import { PanGestureHandler } from 'react-native-gesture-handler'
|
||||||
import { PostAction } from '@screens/Shared/Compose'
|
import { ComposeAction } from '@screens/Shared/Compose'
|
||||||
import client from '@api/client'
|
import client from '@api/client'
|
||||||
import AttachmentVideo from '@components/Timelines/Timeline/Shared/Attachment/AttachmentVideo'
|
import AttachmentVideo from '@components/Timelines/Timeline/Shared/Attachment/AttachmentVideo'
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ export interface Props {
|
|||||||
route: {
|
route: {
|
||||||
params: {
|
params: {
|
||||||
attachment: Mastodon.Attachment & { local_url: string }
|
attachment: Mastodon.Attachment & { local_url: string }
|
||||||
composeDispatch: Dispatch<PostAction>
|
composeDispatch: Dispatch<ComposeAction>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
navigation: any
|
navigation: any
|
||||||
|
@ -26,7 +26,7 @@ import { searchFetch } from '@utils/fetches/searchFetch'
|
|||||||
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 {
|
import {
|
||||||
PostAction,
|
ComposeAction,
|
||||||
ComposeState,
|
ComposeState,
|
||||||
ComposeContext
|
ComposeContext
|
||||||
} from '@screens/Shared/Compose'
|
} from '@screens/Shared/Compose'
|
||||||
@ -45,7 +45,7 @@ const ListItem = React.memo(
|
|||||||
}: {
|
}: {
|
||||||
item: Mastodon.Account & Mastodon.Tag
|
item: Mastodon.Account & Mastodon.Tag
|
||||||
composeState: ComposeState
|
composeState: ComposeState
|
||||||
composeDispatch: Dispatch<PostAction>
|
composeDispatch: Dispatch<ComposeAction>
|
||||||
textInputRef: RefObject<TextInput>
|
textInputRef: RefObject<TextInput>
|
||||||
}) => {
|
}) => {
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
|
@ -12,7 +12,7 @@ export interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ComposeRootFooter: React.FC<Props> = ({ textInputRef }) => {
|
const ComposeRootFooter: React.FC<Props> = ({ textInputRef }) => {
|
||||||
const { composeState, composeDispatch } = useContext(ComposeContext)
|
const { composeState } = useContext(ComposeContext)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -2,7 +2,7 @@ import { Dispatch } from 'react'
|
|||||||
import { ActionSheetIOS, Alert } from 'react-native'
|
import { ActionSheetIOS, Alert } from 'react-native'
|
||||||
import * as ImagePicker from 'expo-image-picker'
|
import * as ImagePicker from 'expo-image-picker'
|
||||||
|
|
||||||
import { PostAction, ComposeState } from '@screens/Shared/Compose'
|
import { ComposeAction, ComposeState } from '@screens/Shared/Compose'
|
||||||
import client from '@api/client'
|
import client from '@api/client'
|
||||||
import { ImageInfo } from 'expo-image-picker/build/ImagePicker.types'
|
import { ImageInfo } from 'expo-image-picker/build/ImagePicker.types'
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ const uploadAttachment = async ({
|
|||||||
}: {
|
}: {
|
||||||
result: NonNullable<ImageInfo>
|
result: NonNullable<ImageInfo>
|
||||||
composeState: ComposeState
|
composeState: ComposeState
|
||||||
composeDispatch: Dispatch<PostAction>
|
composeDispatch: Dispatch<ComposeAction>
|
||||||
}) => {
|
}) => {
|
||||||
const formData = new FormData()
|
const formData = new FormData()
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@ -84,7 +84,7 @@ const addAttachments = async ({
|
|||||||
...params
|
...params
|
||||||
}: {
|
}: {
|
||||||
composeState: ComposeState
|
composeState: ComposeState
|
||||||
composeDispatch: Dispatch<PostAction>
|
composeDispatch: Dispatch<ComposeAction>
|
||||||
}): Promise<any> => {
|
}): Promise<any> => {
|
||||||
ActionSheetIOS.showActionSheetWithOptions(
|
ActionSheetIOS.showActionSheetWithOptions(
|
||||||
{
|
{
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
import { debounce, differenceWith, isEqual } from 'lodash'
|
import { debounce, differenceWith, isEqual } from 'lodash'
|
||||||
import React, { createElement, Dispatch } from 'react'
|
import React, { createElement, Dispatch } from 'react'
|
||||||
import { Text } from 'react-native'
|
import { Text } from 'react-native'
|
||||||
import { RefetchOptions } from 'react-query/types/core/query'
|
import { FetchOptions } from 'react-query/types/core/query'
|
||||||
import Autolinker from '@root/modules/autolinker'
|
import Autolinker from '@root/modules/autolinker'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import { PostAction, ComposeState } from '@screens/Shared/Compose'
|
import { ComposeAction, ComposeState } from '@screens/Shared/Compose'
|
||||||
|
|
||||||
export interface Params {
|
export interface Params {
|
||||||
textInput: ComposeState['textInputFocus']['current']
|
textInput: ComposeState['textInputFocus']['current']
|
||||||
composeDispatch: Dispatch<PostAction>
|
composeDispatch: Dispatch<ComposeAction>
|
||||||
content: string
|
content: string
|
||||||
refetch?: (options?: RefetchOptions | undefined) => Promise<any>
|
refetch?: (options?: FetchOptions | undefined) => Promise<any>
|
||||||
disableDebounce?: boolean
|
disableDebounce?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Dispatch } from 'react'
|
import { Dispatch } from 'react'
|
||||||
import { PostAction, ComposeState } from '@screens/Shared/Compose'
|
import { ComposeAction, ComposeState } from '@screens/Shared/Compose'
|
||||||
import formatText from './formatText'
|
import formatText from './formatText'
|
||||||
|
|
||||||
const updateText = ({
|
const updateText = ({
|
||||||
@ -9,7 +9,7 @@ const updateText = ({
|
|||||||
type
|
type
|
||||||
}: {
|
}: {
|
||||||
composeState: ComposeState
|
composeState: ComposeState
|
||||||
composeDispatch: Dispatch<PostAction>
|
composeDispatch: Dispatch<ComposeAction>
|
||||||
newText: string
|
newText: string
|
||||||
type: 'emoji' | 'suggestion'
|
type: 'emoji' | 'suggestion'
|
||||||
}) => {
|
}) => {
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
import client from '@api/client'
|
import client from '@api/client'
|
||||||
|
|
||||||
export const accountFetch = async (
|
export const accountFetch = async ({
|
||||||
key: string,
|
queryKey
|
||||||
{ id }: { id: string }
|
}: {
|
||||||
): Promise<Mastodon.Account> => {
|
queryKey: QueryKey.Account
|
||||||
|
}): Promise<Mastodon.Account> => {
|
||||||
|
const [_, { id }] = queryKey
|
||||||
|
|
||||||
const res = await client({
|
const res = await client({
|
||||||
method: 'get',
|
method: 'get',
|
||||||
instance: 'local',
|
instance: 'local',
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
import client from '@api/client'
|
import client from '@api/client'
|
||||||
|
|
||||||
export const applicationFetch = async (
|
export const applicationFetch = async ({
|
||||||
key: string,
|
queryKey
|
||||||
{ instanceDomain }: { instanceDomain: string }
|
}: {
|
||||||
): Promise<Mastodon.AppOauth> => {
|
queryKey: QueryKey.Application
|
||||||
|
}): Promise<Mastodon.AppOauth> => {
|
||||||
|
const [_, { instanceDomain }] = queryKey
|
||||||
|
|
||||||
const formData = new FormData()
|
const formData = new FormData()
|
||||||
formData.append('client_name', 'test_dudu')
|
formData.append('client_name', 'test_dudu')
|
||||||
formData.append('redirect_uris', 'exp://127.0.0.1:19000')
|
formData.append('redirect_uris', 'exp://127.0.0.1:19000')
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
import client from '@api/client'
|
import client from '@api/client'
|
||||||
|
|
||||||
export const instanceFetch = async (
|
export const instanceFetch = async ({
|
||||||
key: string,
|
queryKey
|
||||||
{ instanceDomain }: { instanceDomain: string }
|
}: {
|
||||||
): Promise<Mastodon.Instance> => {
|
queryKey: QueryKey.Instance
|
||||||
|
}): Promise<Mastodon.Instance> => {
|
||||||
|
const [_, { instanceDomain }] = queryKey
|
||||||
|
|
||||||
const res = await client({
|
const res = await client({
|
||||||
method: 'get',
|
method: 'get',
|
||||||
instance: 'remote',
|
instance: 'remote',
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
import client from '@api/client'
|
import client from '@api/client'
|
||||||
|
|
||||||
export const relationshipFetch = async (
|
export const relationshipFetch = async ({
|
||||||
key: string,
|
queryKey
|
||||||
{ id }: { id: string }
|
}: {
|
||||||
): Promise<Mastodon.Relationship> => {
|
queryKey: QueryKey.Relationship
|
||||||
|
}): Promise<Mastodon.Relationship> => {
|
||||||
|
const [_, { id }] = queryKey
|
||||||
|
|
||||||
const res = await client({
|
const res = await client({
|
||||||
method: 'get',
|
method: 'get',
|
||||||
instance: 'local',
|
instance: 'local',
|
||||||
|
@ -1,17 +1,10 @@
|
|||||||
import client from '@api/client'
|
import client from '@api/client'
|
||||||
|
|
||||||
export const searchFetch = async (
|
export const searchFetch = async ({
|
||||||
{} = {},
|
queryKey
|
||||||
{
|
}: {
|
||||||
type,
|
queryKey: QueryKey.Search
|
||||||
term,
|
}): Promise<
|
||||||
limit = 20
|
|
||||||
}: {
|
|
||||||
type?: 'accounts' | 'hashtags' | 'statuses'
|
|
||||||
term: string
|
|
||||||
limit?: number
|
|
||||||
}
|
|
||||||
): Promise<
|
|
||||||
| Mastodon.Account[]
|
| Mastodon.Account[]
|
||||||
| Mastodon.Tag[]
|
| Mastodon.Tag[]
|
||||||
| Mastodon.Status[]
|
| Mastodon.Status[]
|
||||||
@ -21,6 +14,7 @@ export const searchFetch = async (
|
|||||||
statuses: Mastodon.Status[]
|
statuses: Mastodon.Status[]
|
||||||
}
|
}
|
||||||
> => {
|
> => {
|
||||||
|
const [_, { type, term, limit = 20 }] = queryKey
|
||||||
const res = await client({
|
const res = await client({
|
||||||
version: 'v2',
|
version: 'v2',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
|
@ -2,43 +2,28 @@ import { uniqBy } from 'lodash'
|
|||||||
|
|
||||||
import client from '@api/client'
|
import client from '@api/client'
|
||||||
|
|
||||||
export const timelineFetch = async (
|
export const timelineFetch = async ({
|
||||||
key: string,
|
queryKey,
|
||||||
{
|
pageParam
|
||||||
page,
|
}: {
|
||||||
params = {},
|
queryKey: QueryKey.Timeline
|
||||||
account,
|
pageParam?: { direction: 'prev' | 'next'; id: Mastodon.Status['id'] }
|
||||||
hashtag,
|
}): Promise<{
|
||||||
list,
|
|
||||||
toot
|
|
||||||
}: {
|
|
||||||
page: App.Pages
|
|
||||||
params?: {
|
|
||||||
[key: string]: string | number | boolean
|
|
||||||
}
|
|
||||||
hashtag?: Mastodon.Tag['name']
|
|
||||||
list?: Mastodon.List['id']
|
|
||||||
toot?: Mastodon.Status
|
|
||||||
account?: Mastodon.Account['id']
|
|
||||||
},
|
|
||||||
pagination: {
|
|
||||||
direction: 'prev' | 'next'
|
|
||||||
id: string
|
|
||||||
}
|
|
||||||
): Promise<{
|
|
||||||
toots: Mastodon.Status[]
|
toots: Mastodon.Status[]
|
||||||
pointer?: number
|
pointer?: number
|
||||||
pinnedLength?: number
|
pinnedLength?: number
|
||||||
}> => {
|
}> => {
|
||||||
|
const [page, { account, hashtag, list, toot }] = queryKey
|
||||||
let res
|
let res
|
||||||
|
let params: { [key: string]: string } = {}
|
||||||
|
|
||||||
if (pagination && pagination.id) {
|
if (pageParam) {
|
||||||
switch (pagination.direction) {
|
switch (pageParam.direction) {
|
||||||
case 'prev':
|
case 'prev':
|
||||||
params.min_id = pagination.id
|
params.min_id = pageParam.id
|
||||||
break
|
break
|
||||||
case 'next':
|
case 'next':
|
||||||
params.max_id = pagination.id
|
params.max_id = pageParam.id
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -91,8 +76,8 @@ export const timelineFetch = async (
|
|||||||
return Promise.resolve({ toots: res.body })
|
return Promise.resolve({ toots: res.body })
|
||||||
|
|
||||||
case 'Account_Default':
|
case 'Account_Default':
|
||||||
if (pagination && pagination.id) {
|
if (pageParam) {
|
||||||
if (pagination.direction === 'prev') {
|
if (pageParam.direction === 'prev') {
|
||||||
res = await client({
|
res = await client({
|
||||||
method: 'get',
|
method: 'get',
|
||||||
instance: 'local',
|
instance: 'local',
|
||||||
@ -175,10 +160,10 @@ export const timelineFetch = async (
|
|||||||
url: `conversations`,
|
url: `conversations`,
|
||||||
params
|
params
|
||||||
})
|
})
|
||||||
if (pagination) {
|
if (pageParam) {
|
||||||
// Bug in pull to refresh in conversations
|
// Bug in pull to refresh in conversations
|
||||||
res.body = res.body.filter(
|
res.body = res.body.filter(
|
||||||
(b: Mastodon.Conversation) => b.id !== pagination.id
|
(b: Mastodon.Conversation) => b.id !== pageParam.id
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return Promise.resolve({ toots: res.body })
|
return Promise.resolve({ toots: res.body })
|
||||||
@ -220,5 +205,7 @@ export const timelineFetch = async (
|
|||||||
toots: [...res.body.ancestors, toot, ...res.body.descendants],
|
toots: [...res.body.ancestors, toot, ...res.body.descendants],
|
||||||
pointer: res.body.ancestors.length
|
pointer: res.body.ancestors.length
|
||||||
})
|
})
|
||||||
|
default:
|
||||||
|
return Promise.reject()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
50
yarn.lock
50
yarn.lock
@ -978,7 +978,7 @@
|
|||||||
pirates "^4.0.0"
|
pirates "^4.0.0"
|
||||||
source-map-support "^0.5.16"
|
source-map-support "^0.5.16"
|
||||||
|
|
||||||
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.1", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4":
|
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4":
|
||||||
version "7.12.5"
|
version "7.12.5"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e"
|
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e"
|
||||||
integrity sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==
|
integrity sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==
|
||||||
@ -1348,7 +1348,7 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@react-native-community/segmented-control/-/segmented-control-2.2.1.tgz#5ca418d78c5f6051353c9586918458713b88a83c"
|
resolved "https://registry.yarnpkg.com/@react-native-community/segmented-control/-/segmented-control-2.2.1.tgz#5ca418d78c5f6051353c9586918458713b88a83c"
|
||||||
integrity sha512-BzxFbI9Iqv+31yVqEvCTzJYmwb8jOMTf/UPuC4Hj176tmEPqBpuDaGH+rkAFg1miOco3/43RQxiAZO+mkY40Fg==
|
integrity sha512-BzxFbI9Iqv+31yVqEvCTzJYmwb8jOMTf/UPuC4Hj176tmEPqBpuDaGH+rkAFg1miOco3/43RQxiAZO+mkY40Fg==
|
||||||
|
|
||||||
"@react-navigation/bottom-tabs@^5.10.6":
|
"@react-navigation/bottom-tabs@^5.11.2":
|
||||||
version "5.11.2"
|
version "5.11.2"
|
||||||
resolved "https://registry.yarnpkg.com/@react-navigation/bottom-tabs/-/bottom-tabs-5.11.2.tgz#5b541612fcecdea2a5024a4028da35e4a727bde6"
|
resolved "https://registry.yarnpkg.com/@react-navigation/bottom-tabs/-/bottom-tabs-5.11.2.tgz#5b541612fcecdea2a5024a4028da35e4a727bde6"
|
||||||
integrity sha512-7+hH00N9Ze74VcX8uYWVyXFXZ0Fwid+lG+SSLtmnJjk1Y6oIQpQ17EPqKO0UZlKKjhsvMlAnL5fdgFtoqnSjcA==
|
integrity sha512-7+hH00N9Ze74VcX8uYWVyXFXZ0Fwid+lG+SSLtmnJjk1Y6oIQpQ17EPqKO0UZlKKjhsvMlAnL5fdgFtoqnSjcA==
|
||||||
@ -1385,7 +1385,7 @@
|
|||||||
hoist-non-react-statics "^3.3.2"
|
hoist-non-react-statics "^3.3.2"
|
||||||
react-native-safe-area-view "^0.14.9"
|
react-native-safe-area-view "^0.14.9"
|
||||||
|
|
||||||
"@react-navigation/native@^5.8.6":
|
"@react-navigation/native@^5.8.10":
|
||||||
version "5.8.10"
|
version "5.8.10"
|
||||||
resolved "https://registry.yarnpkg.com/@react-navigation/native/-/native-5.8.10.tgz#3fe806abff9efb085bcf595212803dd05a1347ca"
|
resolved "https://registry.yarnpkg.com/@react-navigation/native/-/native-5.8.10.tgz#3fe806abff9efb085bcf595212803dd05a1347ca"
|
||||||
integrity sha512-OUgD1o+y7PwmhRIRqQxN0SQvVU/SHic/ek/qMvBZX8nu5/WlBNxmNRMHVxONgHlG3AQZh27NUs9ynntL7ek1zQ==
|
integrity sha512-OUgD1o+y7PwmhRIRqQxN0SQvVU/SHic/ek/qMvBZX8nu5/WlBNxmNRMHVxONgHlG3AQZh27NUs9ynntL7ek1zQ==
|
||||||
@ -1401,7 +1401,7 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
nanoid "^3.1.15"
|
nanoid "^3.1.15"
|
||||||
|
|
||||||
"@reduxjs/toolkit@^1.4.0":
|
"@reduxjs/toolkit@^1.5.0":
|
||||||
version "1.5.0"
|
version "1.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.5.0.tgz#1025c1ccb224d1fc06d8d98a61f6717d57e6d477"
|
resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.5.0.tgz#1025c1ccb224d1fc06d8d98a61f6717d57e6d477"
|
||||||
integrity sha512-E/FUraRx+8guw9Hlg/Ja8jI/hwCrmIKed8Annt9YsZw3BQp+F24t5I5b2OWR6pkEHY4hn1BgP08FrTZFRKsdaQ==
|
integrity sha512-E/FUraRx+8guw9Hlg/Ja8jI/hwCrmIKed8Annt9YsZw3BQp+F24t5I5b2OWR6pkEHY4hn1BgP08FrTZFRKsdaQ==
|
||||||
@ -1492,7 +1492,7 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
react-navigation "*"
|
react-navigation "*"
|
||||||
|
|
||||||
"@types/react-redux@^7.1.11":
|
"@types/react-redux@^7.1.12":
|
||||||
version "7.1.12"
|
version "7.1.12"
|
||||||
resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.12.tgz#148f2c768687346b556e29a322ca44cfa28cc3ac"
|
resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.12.tgz#148f2c768687346b556e29a322ca44cfa28cc3ac"
|
||||||
integrity sha512-xZj4/8oRZP5RlJPlC5XPnawPtMn+T2bV4Hxi38AcuoZzXlN/Il/ZPfgXuIq3WG37wVL6FP7suVfmE4BopuqtTg==
|
integrity sha512-xZj4/8oRZP5RlJPlC5XPnawPtMn+T2bV4Hxi38AcuoZzXlN/Il/ZPfgXuIq3WG37wVL6FP7suVfmE4BopuqtTg==
|
||||||
@ -1565,7 +1565,7 @@
|
|||||||
invariant "^2.2.4"
|
invariant "^2.2.4"
|
||||||
lodash "^4.5.0"
|
lodash "^4.5.0"
|
||||||
|
|
||||||
"@welldone-software/why-did-you-render@^6.0.0-rc.1":
|
"@welldone-software/why-did-you-render@^6.0.3":
|
||||||
version "6.0.3"
|
version "6.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/@welldone-software/why-did-you-render/-/why-did-you-render-6.0.3.tgz#99c58ea8e3f2ea8c042fb1d58ebf147d345fff26"
|
resolved "https://registry.yarnpkg.com/@welldone-software/why-did-you-render/-/why-did-you-render-6.0.3.tgz#99c58ea8e3f2ea8c042fb1d58ebf147d345fff26"
|
||||||
integrity sha512-9HskvqZrCVEnKur2WIZ2Jm36u+1bCbb1c+iHa8QljjHmEVOA2US1qKq3HeUcwsjgKZRo5xucV6td2FeJP8agmQ==
|
integrity sha512-9HskvqZrCVEnKur2WIZ2Jm36u+1bCbb1c+iHa8QljjHmEVOA2US1qKq3HeUcwsjgKZRo5xucV6td2FeJP8agmQ==
|
||||||
@ -1815,10 +1815,10 @@ babel-plugin-module-resolver@^3.2.0:
|
|||||||
reselect "^3.0.1"
|
reselect "^3.0.1"
|
||||||
resolve "^1.4.0"
|
resolve "^1.4.0"
|
||||||
|
|
||||||
babel-plugin-module-resolver@^4.0.0:
|
babel-plugin-module-resolver@^4.1.0:
|
||||||
version "4.0.0"
|
version "4.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/babel-plugin-module-resolver/-/babel-plugin-module-resolver-4.0.0.tgz#8f3a3d9d48287dc1d3b0d5595113adabd36a847f"
|
resolved "https://registry.yarnpkg.com/babel-plugin-module-resolver/-/babel-plugin-module-resolver-4.1.0.tgz#22a4f32f7441727ec1fbf4967b863e1e3e9f33e2"
|
||||||
integrity sha512-3pdEq3PXALilSJ6dnC4wMWr0AZixHRM4utpdpBR9g5QG7B7JwWyukQv7a9hVxkbGFl+nQbrHDqqQOIBtTXTP/Q==
|
integrity sha512-MlX10UDheRr3lb3P0WcaIdtCSRlxdQsB1sBqL7W0raF070bGl1HQQq5K3T2vf2XAYie+ww+5AKC/WrkjRO2knA==
|
||||||
dependencies:
|
dependencies:
|
||||||
find-babel-config "^1.2.0"
|
find-babel-config "^1.2.0"
|
||||||
glob "^7.1.6"
|
glob "^7.1.6"
|
||||||
@ -4169,6 +4169,14 @@ map-visit@^1.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
object-visit "^1.0.0"
|
object-visit "^1.0.0"
|
||||||
|
|
||||||
|
match-sorter@^6.0.2:
|
||||||
|
version "6.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/match-sorter/-/match-sorter-6.0.2.tgz#91bbab14c28a87f4a67755b7a194c0d11dedc080"
|
||||||
|
integrity sha512-SDRLNlWof9GnAUEyhKP0O5525MMGXUGt+ep4MrrqQ2StAh3zjvICVZseiwg7Zijn3GazpJDiwuRr/mFDHd92NQ==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.12.5"
|
||||||
|
remove-accents "0.4.2"
|
||||||
|
|
||||||
md5-file@^3.2.3:
|
md5-file@^3.2.3:
|
||||||
version "3.2.3"
|
version "3.2.3"
|
||||||
resolved "https://registry.yarnpkg.com/md5-file/-/md5-file-3.2.3.tgz#f9bceb941eca2214a4c0727f5e700314e770f06f"
|
resolved "https://registry.yarnpkg.com/md5-file/-/md5-file-3.2.3.tgz#f9bceb941eca2214a4c0727f5e700314e770f06f"
|
||||||
@ -5192,10 +5200,10 @@ react-dom@16.13.1:
|
|||||||
prop-types "^15.6.2"
|
prop-types "^15.6.2"
|
||||||
scheduler "^0.19.1"
|
scheduler "^0.19.1"
|
||||||
|
|
||||||
react-i18next@^11.7.3:
|
react-i18next@^11.8.4:
|
||||||
version "11.8.3"
|
version "11.8.4"
|
||||||
resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.8.3.tgz#d365586a537f759a1bff75e01054f6a5fc71e4f5"
|
resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.8.4.tgz#5407d2edcaa704c38e4034e7ac06413914ed6e6d"
|
||||||
integrity sha512-E5LjGmM3Kgje4M0oSkHFNAxiU1BM+P1J9QPfF7+Agm4sa1YS18GhQNJCZD3o9ofZLjq8ocQfGUuYweYGfrj0RQ==
|
integrity sha512-QlPJfX+Roi+jEQ6frBSsLHHH+VWbUoCl6wZDT8XHMd6PsSgepjgD2sZf/h7F46JnHeuy0U+SxY3TtrJF+aDIyg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime" "^7.3.1"
|
"@babel/runtime" "^7.3.1"
|
||||||
html-parse-stringify2 "2.0.1"
|
html-parse-stringify2 "2.0.1"
|
||||||
@ -5359,12 +5367,13 @@ react-navigation@*, react-navigation@^4.4.3:
|
|||||||
"@react-navigation/core" "^3.7.9"
|
"@react-navigation/core" "^3.7.9"
|
||||||
"@react-navigation/native" "^3.8.3"
|
"@react-navigation/native" "^3.8.3"
|
||||||
|
|
||||||
react-query@^2.26.2:
|
react-query@^3.3.2:
|
||||||
version "2.26.4"
|
version "3.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/react-query/-/react-query-2.26.4.tgz#18239b4c0b61d0b744f0d4a91f566b294fa9f752"
|
resolved "https://registry.yarnpkg.com/react-query/-/react-query-3.3.2.tgz#9cc75962ec8f6f3b4468a46d1b0ef160b97ef37d"
|
||||||
integrity sha512-sXGG0gh1ah11AcfptYOCRpGDoYMnssq6riQUpQaLSM2EOodVkexp3zNLk1MFDgfRGuXQst40Tnu17oNwni66aA==
|
integrity sha512-SeAtekP/D3Eaf/715LmAnneSufn9Q4eGQkuOzOQ08/UtCQ58P4pkAevHu/WIBwCjtffZDTHMJRMeCeeUyouubg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime" "^7.5.5"
|
"@babel/runtime" "^7.5.5"
|
||||||
|
match-sorter "^6.0.2"
|
||||||
|
|
||||||
react-redux@^7.2.2:
|
react-redux@^7.2.2:
|
||||||
version "7.2.2"
|
version "7.2.2"
|
||||||
@ -5491,6 +5500,11 @@ regjsparser@^0.6.4:
|
|||||||
dependencies:
|
dependencies:
|
||||||
jsesc "~0.5.0"
|
jsesc "~0.5.0"
|
||||||
|
|
||||||
|
remove-accents@0.4.2:
|
||||||
|
version "0.4.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/remove-accents/-/remove-accents-0.4.2.tgz#0a43d3aaae1e80db919e07ae254b285d9e1c7bb5"
|
||||||
|
integrity sha1-CkPTqq4egNuRngeuJUsoXZ4ce7U=
|
||||||
|
|
||||||
remove-trailing-separator@^1.0.1:
|
remove-trailing-separator@^1.0.1:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
|
resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
|
||||||
|
Reference in New Issue
Block a user