This commit is contained in:
Zhiyuan Zheng 2021-12-18 19:59:38 +01:00
parent ad6c6a98b6
commit 8c9dfb839b
23 changed files with 126 additions and 112 deletions

View File

@ -16,6 +16,7 @@ import * as SplashScreen from 'expo-splash-screen'
import React, { useCallback, useEffect, useState } from 'react'
import { AppState, LogBox, Platform } from 'react-native'
import { GestureHandlerRootView } from 'react-native-gesture-handler'
import { enableFreeze } from 'react-native-screens'
import { QueryClientProvider } from 'react-query'
import { Provider } from 'react-redux'
import { PersistGate } from 'redux-persist/integration/react'
@ -29,6 +30,7 @@ dev()
sentry()
audio()
push()
enableFreeze()
const App: React.FC = () => {
log('log', 'App', 'rendering App')

View File

@ -136,7 +136,7 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
}
if (previousRoute?.name !== currentRoute?.name) {
Analytics.setCurrentScreen(currentRoute?.name)
Analytics.logEvent('screen_view', { screen_name: currentRoute?.name })
Sentry.Native.setContext('page', {
previous: previousRoute,
current: currentRoute

View File

@ -21,6 +21,11 @@ export type Params = {
>
}
export type InstanceResponse<T = unknown> = {
body: T
links: { prev?: string; next?: string }
}
const apiInstance = async <T = unknown>({
method,
version = 'v1',
@ -29,7 +34,7 @@ const apiInstance = async <T = unknown>({
headers,
body,
extras
}: Params): Promise<{ body: T; links: { prev?: string; next?: string } }> => {
}: Params): Promise<InstanceResponse<T>> => {
const { store } = require('@root/store')
const state = store.getState() as RootState
const instanceActive = state.instances.instances.findIndex(

View File

@ -47,7 +47,6 @@ const TimelineTranslate = React.memo(
const [enabled, setEnabled] = useState(false)
const { refetch, data, isLoading, isSuccess, isError } = useTranslateQuery({
uri: status.uri,
source: status.language,
target: settingsLanguage,
text,

View File

@ -31,7 +31,7 @@ const Tab = createBottomTabNavigator<ScreenTabsStackParamList>()
const ScreenTabs = React.memo(
({ navigation }: RootStackScreenProps<'Screen-Tabs'>) => {
const { mode, theme } = useTheme()
const { theme } = useTheme()
const instanceActive = useSelector(getInstanceActive)
const instanceAccount = useSelector(

View File

@ -10,9 +10,11 @@ import { Alert, StyleSheet } from 'react-native'
import FlashMessage from 'react-native-flash-message'
import { ScrollView } from 'react-native-gesture-handler'
const TabMeProfileName: React.FC<TabMeProfileStackScreenProps<
'Tab-Me-Profile-Name'
> & { messageRef: RefObject<FlashMessage> }> = ({
const TabMeProfileName: React.FC<
TabMeProfileStackScreenProps<'Tab-Me-Profile-Name'> & {
messageRef: RefObject<FlashMessage>
}
> = ({
messageRef,
route: {
params: { display_name }
@ -91,7 +93,8 @@ const TabMeProfileName: React.FC<TabMeProfileStackScreenProps<
options={{
maxLength: 30,
autoCapitalize: 'none',
autoCompleteType: 'username',
autoComplete: 'username',
textContentType: 'username',
autoCorrect: false
}}
/>

View File

@ -64,6 +64,7 @@ const SettingsApp: React.FC = () => {
cancelButtonIndex: options.length - 1
},
buttonIndex => {
if (!buttonIndex) return
if (buttonIndex < options.length - 1) {
analytics('settings_language_press', {
current: i18n.language,

View File

@ -32,9 +32,9 @@ export const mapFontsizeToName = (size: SettingsState['fontsize']) => {
}
}
const TabMeSettingsFontsize: React.FC<TabMeStackScreenProps<
'Tab-Me-Settings-Fontsize'
>> = () => {
const TabMeSettingsFontsize: React.FC<
TabMeStackScreenProps<'Tab-Me-Settings-Fontsize'>
> = () => {
const { mode, theme } = useTheme()
const { t } = useTranslation('screenTabs')
const initialSize = useSelector(getSettingsFontsize)
@ -113,7 +113,12 @@ const TabMeSettingsFontsize: React.FC<TabMeStackScreenProps<
extraMarginLeft={-StyleConstants.Spacing.Global.PagePadding}
extraMarginRight={-StyleConstants.Spacing.Global.PagePadding}
/>
<TimelineDefault item={item} disableDetails disableOnPress />
<TimelineDefault
// @ts-ignore
item={item}
disableDetails
disableOnPress
/>
<ComponentSeparator
extraMarginLeft={-StyleConstants.Spacing.Global.PagePadding}
extraMarginRight={-StyleConstants.Spacing.Global.PagePadding}

View File

@ -18,9 +18,9 @@ import {
} from 'react-native'
import { Circle } from 'react-native-animated-spinkit'
const TabSharedSearch: React.FC<TabSharedStackScreenProps<
'Tab-Shared-Search'
>> = ({
const TabSharedSearch: React.FC<
TabSharedStackScreenProps<'Tab-Shared-Search'>
> = ({
route: {
params: { text }
}
@ -33,7 +33,13 @@ const TabSharedSearch: React.FC<TabSharedStackScreenProps<
hashtags: t('shared.search.sections.hashtags'),
statuses: t('shared.search.sections.statuses')
}
const { status, data } = useSearchQuery({
const { status, data } = useSearchQuery<
{
title: string
translation: string
data: any[]
}[]
>({
term: text,
options: {
enabled: text !== undefined,

View File

@ -33,24 +33,18 @@ const AccessibilityManager: React.FC = ({ children }) => {
useEffect(() => {
loadAccessibilityInfo()
AccessibilityInfo.addEventListener(
const reduceMotionSubscription = AccessibilityInfo.addEventListener(
'reduceMotionChanged',
handleReduceMotionChanged
)
AccessibilityInfo.addEventListener(
const screenReaderSubscription = AccessibilityInfo.addEventListener(
'screenReaderChanged',
handleScreenReaderEnabled
)
return () => {
AccessibilityInfo.removeEventListener(
'reduceMotionChanged',
handleReduceMotionChanged
)
AccessibilityInfo.removeEventListener(
'screenReaderChanged',
handleScreenReaderEnabled
)
reduceMotionSubscription.remove()
screenReaderSubscription.remove()
}
}, [])

View File

@ -1,10 +1,10 @@
import apiInstance from '@api/instance'
import { AxiosError } from 'axios'
import { useQuery, UseQueryOptions } from 'react-query'
import { QueryFunctionContext, useQuery, UseQueryOptions } from 'react-query'
export type QueryKeyAccount = ['Account', { id: Mastodon.Account['id'] }]
const queryFunction = ({ queryKey }: { queryKey: QueryKeyAccount }) => {
const queryFunction = ({ queryKey }: QueryFunctionContext<QueryKeyAccount>) => {
const { id } = queryKey[1]
return apiInstance<Mastodon.Account>({
@ -13,11 +13,11 @@ const queryFunction = ({ queryKey }: { queryKey: QueryKeyAccount }) => {
}).then(res => res.body)
}
const useAccountQuery = <TData = Mastodon.Account>({
const useAccountQuery = ({
options,
...queryKeyParams
}: QueryKeyAccount[1] & {
options?: UseQueryOptions<Mastodon.Account, AxiosError, TData>
options?: UseQueryOptions<Mastodon.Account, AxiosError>
}) => {
const queryKey: QueryKeyAccount = ['Account', { ...queryKeyParams }]
return useQuery(queryKey, queryFunction, options)

View File

@ -1,6 +1,7 @@
import apiInstance from '@api/instance'
import { AxiosError } from 'axios'
import {
QueryFunctionContext,
useMutation,
UseMutationOptions,
useQuery,
@ -9,7 +10,9 @@ import {
type QueryKeyAnnouncement = ['Announcements', { showAll?: boolean }]
const queryFunction = ({ queryKey }: { queryKey: QueryKeyAnnouncement }) => {
const queryFunction = ({
queryKey
}: QueryFunctionContext<QueryKeyAnnouncement>) => {
const { showAll } = queryKey[1]
return apiInstance<Mastodon.Announcement[]>({
@ -23,11 +26,11 @@ const queryFunction = ({ queryKey }: { queryKey: QueryKeyAnnouncement }) => {
}).then(res => res.body)
}
const useAnnouncementQuery = <TData = Mastodon.Announcement[]>({
const useAnnouncementQuery = ({
options,
...queryKeyParams
}: QueryKeyAnnouncement[1] & {
options?: UseQueryOptions<Mastodon.Announcement[], AxiosError, TData>
options?: UseQueryOptions<Mastodon.Announcement[], AxiosError>
}) => {
const queryKey: QueryKeyAnnouncement = [
'Announcements',

View File

@ -1,11 +1,11 @@
import apiGeneral from '@api/general'
import { AxiosError } from 'axios'
import * as AuthSession from 'expo-auth-session'
import { useQuery, UseQueryOptions } from 'react-query'
import { QueryFunctionContext, useQuery, UseQueryOptions } from 'react-query'
export type QueryKey = ['Apps', { domain?: string }]
export type QueryKeyApps = ['Apps', { domain?: string }]
const queryFunction = ({ queryKey }: { queryKey: QueryKey }) => {
const queryFunction = ({ queryKey }: QueryFunctionContext<QueryKeyApps>) => {
const redirectUri = AuthSession.makeRedirectUri({
native: 'tooot://instance-auth',
useProxy: false
@ -27,13 +27,13 @@ const queryFunction = ({ queryKey }: { queryKey: QueryKey }) => {
}).then(res => res.body)
}
const useAppsQuery = <TData = Mastodon.Apps>({
const useAppsQuery = ({
options,
...queryKeyParams
}: QueryKey[1] & {
options?: UseQueryOptions<Mastodon.Apps, AxiosError, TData>
}: QueryKeyApps[1] & {
options?: UseQueryOptions<Mastodon.Apps, AxiosError>
}) => {
const queryKey: QueryKey = ['Apps', { ...queryKeyParams }]
const queryKey: QueryKeyApps = ['Apps', { ...queryKeyParams }]
return useQuery(queryKey, queryFunction, options)
}

View File

@ -2,21 +2,22 @@ import apiInstance from '@api/instance'
import { AxiosError } from 'axios'
import { useQuery, UseQueryOptions } from 'react-query'
type QueryKey = ['Emojis']
type QueryKeyEmojis = ['Emojis']
const queryFunction = () => {
return apiInstance<Mastodon.Emoji[]>({
const queryFunction = async () => {
const res = await apiInstance<Mastodon.Emoji[]>({
method: 'get',
url: 'custom_emojis'
}).then(res => res.body)
})
return res.body
}
const useEmojisQuery = <TData = Mastodon.Emoji[]>({
const useEmojisQuery = ({
options
}: {
options?: UseQueryOptions<Mastodon.Emoji[], AxiosError, TData>
options?: UseQueryOptions<Mastodon.Emoji[], AxiosError>
}) => {
const queryKey: QueryKey = ['Emojis']
const queryKey: QueryKeyEmojis = ['Emojis']
return useQuery(queryKey, queryFunction, options)
}

View File

@ -1,10 +1,12 @@
import apiGeneral from '@api/general'
import { AxiosError } from 'axios'
import { useQuery, UseQueryOptions } from 'react-query'
import { QueryFunctionContext, useQuery, UseQueryOptions } from 'react-query'
export type QueryKey = ['Instance', { domain?: string }]
export type QueryKeyInstance = ['Instance', { domain?: string }]
const queryFunction = async ({ queryKey }: { queryKey: QueryKey }) => {
const queryFunction = async ({
queryKey
}: QueryFunctionContext<QueryKeyInstance>) => {
const { domain } = queryKey[1]
if (!domain) {
return Promise.reject()
@ -18,19 +20,16 @@ const queryFunction = async ({ queryKey }: { queryKey: QueryKey }) => {
return res.body
}
const useInstanceQuery = <
TData = Mastodon.Instance & { publicAllow?: boolean }
>({
const useInstanceQuery = ({
options,
...queryKeyParams
}: QueryKey[1] & {
}: QueryKeyInstance[1] & {
options?: UseQueryOptions<
Mastodon.Instance & { publicAllow?: boolean },
AxiosError,
TData
AxiosError
>
}) => {
const queryKey: QueryKey = ['Instance', { ...queryKeyParams }]
const queryKey: QueryKeyInstance = ['Instance', { ...queryKeyParams }]
return useQuery(queryKey, queryFunction, options)
}

View File

@ -4,17 +4,18 @@ import { useQuery, UseQueryOptions } from 'react-query'
export type QueryKey = ['Lists']
const queryFunction = () => {
return apiInstance<Mastodon.List[]>({
const queryFunction = async () => {
const res = await apiInstance<Mastodon.List[]>({
method: 'get',
url: 'lists'
}).then(res => res.body)
})
return res.body
}
const useListsQuery = <TData = Mastodon.List[]>({
const useListsQuery = ({
options
}: {
options?: UseQueryOptions<Mastodon.List[], AxiosError, TData>
options?: UseQueryOptions<Mastodon.List[], AxiosError>
}) => {
const queryKey: QueryKey = ['Lists']
return useQuery(queryKey, queryFunction, options)

View File

@ -14,17 +14,18 @@ type AccountWithSource = Mastodon.Account &
type QueryKeyProfile = ['Profile']
const queryKey: QueryKeyProfile = ['Profile']
const queryFunction = () => {
return apiInstance<AccountWithSource>({
const queryFunction = async () => {
const res = await apiInstance<AccountWithSource>({
method: 'get',
url: `accounts/verify_credentials`
}).then(res => res.body)
})
return res.body
}
const useProfileQuery = <TData = AccountWithSource>({
const useProfileQuery = ({
options
}: {
options?: UseQueryOptions<AccountWithSource, AxiosError, TData>
options?: UseQueryOptions<AccountWithSource, AxiosError>
}) => {
return useQuery(queryKey, queryFunction, options)
}

View File

@ -1,6 +1,7 @@
import apiInstance from '@api/instance'
import { AxiosError } from 'axios'
import {
QueryFunctionContext,
useMutation,
UseMutationOptions,
useQuery,
@ -12,7 +13,9 @@ export type QueryKeyRelationship = [
{ id: Mastodon.Account['id'] }
]
const queryFunction = ({ queryKey }: { queryKey: QueryKeyRelationship }) => {
const queryFunction = ({
queryKey
}: QueryFunctionContext<QueryKeyRelationship>) => {
const { id } = queryKey[1]
return apiInstance<Mastodon.Relationship[]>({

View File

@ -1,8 +1,8 @@
import apiInstance from '@api/instance'
import { AxiosError } from 'axios'
import { useQuery, UseQueryOptions } from 'react-query'
import { QueryFunctionContext, useQuery, UseQueryOptions } from 'react-query'
export type QueryKey = [
export type QueryKeySearch = [
'Search',
{
type?: 'accounts' | 'hashtags' | 'statuses'
@ -17,9 +17,11 @@ export type SearchResult = {
statuses: Mastodon.Status[]
}
const queryFunction = ({ queryKey }: { queryKey: QueryKey }) => {
const queryFunction = async ({
queryKey
}: QueryFunctionContext<QueryKeySearch>) => {
const { type, term, limit = 20 } = queryKey[1]
return apiInstance<SearchResult>({
const res = await apiInstance<SearchResult>({
version: 'v2',
method: 'get',
url: 'search',
@ -29,16 +31,17 @@ const queryFunction = ({ queryKey }: { queryKey: QueryKey }) => {
limit,
resolve: true
}
}).then(res => res.body)
})
return res.body
}
const useSearchQuery = <TData = SearchResult>({
const useSearchQuery = <T = unknown>({
options,
...queryKeyParams
}: QueryKey[1] & {
options?: UseQueryOptions<SearchResult, AxiosError, TData>
}: QueryKeySearch[1] & {
options?: UseQueryOptions<SearchResult, AxiosError, T>
}) => {
const queryKey: QueryKey = ['Search', { ...queryKeyParams }]
const queryKey: QueryKeySearch = ['Search', { ...queryKeyParams }]
return useQuery(queryKey, queryFunction, options)
}

View File

@ -1,4 +1,4 @@
import apiInstance from '@api/instance'
import apiInstance, { InstanceResponse } from '@api/instance'
import haptics from '@components/haptics'
import queryClient from '@helpers/queryClient'
import { store } from '@root/store'
@ -7,6 +7,7 @@ import { AxiosError } from 'axios'
import { uniqBy } from 'lodash'
import {
MutationOptions,
QueryFunctionContext,
useInfiniteQuery,
UseInfiniteQueryOptions,
useMutation
@ -28,10 +29,7 @@ export type QueryKeyTimeline = [
const queryFunction = async ({
queryKey,
pageParam
}: {
queryKey: QueryKeyTimeline
pageParam?: { [key: string]: string }
}) => {
}: QueryFunctionContext<QueryKeyTimeline>) => {
const { page, account, hashtag, list, toot } = queryKey[1]
let params: { [key: string]: string } = { ...pageParam }
@ -191,21 +189,15 @@ const queryFunction = async ({
type Unpromise<T extends Promise<any>> = T extends Promise<infer U> ? U : never
export type TimelineData = Unpromise<ReturnType<typeof queryFunction>>
const useTimelineQuery = <TData = TimelineData>({
const useTimelineQuery = ({
options,
...queryKeyParams
}: QueryKeyTimeline[1] & {
options?: UseInfiniteQueryOptions<
{
body:
| Mastodon.Status[]
| Mastodon.Notification[]
| Mastodon.Conversation[]
links?: { prev?: string; next?: string }
pinned?: Mastodon.Status['id'][]
},
AxiosError,
TData
InstanceResponse<
Mastodon.Status[] | Mastodon.Notification[] | Mastodon.Conversation[]
>,
AxiosError
>
}) => {
const queryKey: QueryKeyTimeline = ['Timeline', { ...queryKeyParams }]

View File

@ -1,7 +1,7 @@
import apiTooot from '@api/tooot'
import haptics from '@components/haptics'
import { AxiosError } from 'axios'
import { useQuery, UseQueryOptions } from 'react-query'
import { QueryFunctionContext, useQuery, UseQueryOptions } from 'react-query'
type Translations = {
provider: string
@ -18,7 +18,9 @@ export type QueryKeyTranslate = [
}
]
const queryFunction = async ({ queryKey }: { queryKey: QueryKeyTranslate }) => {
const queryFunction = async ({
queryKey
}: QueryFunctionContext<QueryKeyTranslate>) => {
const { source, target, text } = queryKey[1]
const res = await apiTooot<Translations>({
@ -34,7 +36,7 @@ const useTranslateQuery = ({
options,
...queryKeyParams
}: QueryKeyTranslate[1] & {
options?: UseQueryOptions<Translations, AxiosError, Translations>
options?: UseQueryOptions<Translations, AxiosError>
}) => {
const queryKey: QueryKeyTranslate = ['Translate', { ...queryKeyParams }]
return useQuery(queryKey, queryFunction, { ...options, retry: false })

View File

@ -1,7 +1,11 @@
import apiInstance from '@api/instance'
import apiInstance, { InstanceResponse } from '@api/instance'
import { TabSharedStackParamList } from '@utils/navigation/navigators'
import { AxiosError } from 'axios'
import { useInfiniteQuery, UseInfiniteQueryOptions } from 'react-query'
import {
QueryFunctionContext,
useInfiniteQuery,
UseInfiniteQueryOptions
} from 'react-query'
export type QueryKeyUsers = [
'Users',
@ -11,10 +15,7 @@ export type QueryKeyUsers = [
const queryFunction = ({
queryKey,
pageParam
}: {
queryKey: QueryKeyUsers
pageParam?: { [key: string]: string }
}) => {
}: QueryFunctionContext<QueryKeyUsers>) => {
const { reference, id, type } = queryKey[1]
let params: { [key: string]: string } = { ...pageParam }
@ -30,15 +31,8 @@ const useUsersQuery = ({
...queryKeyParams
}: QueryKeyUsers[1] & {
options?: UseInfiniteQueryOptions<
{
body: Mastodon.Account[]
links?: { prev?: string; next?: string }
},
AxiosError,
{
body: Mastodon.Account[]
links?: { prev?: string; next?: string }
}
InstanceResponse<Mastodon.Account[]>,
AxiosError
>
}) => {
const queryKey: QueryKeyUsers = ['Users', { ...queryKeyParams }]

View File

@ -99,7 +99,7 @@ const addInstance = createAsyncThunk(
mention: { loading: false, value: true },
poll: { loading: false, value: true }
},
keys: undefined
keys: { auth: undefined, public: undefined, private: undefined }
},
drafts: []
}