Basic new react-navigation types

This commit is contained in:
Zhiyuan Zheng 2021-08-29 15:25:38 +02:00
parent 6575a787f6
commit 122dae7404
68 changed files with 1099 additions and 1064 deletions

View File

@ -47,6 +47,9 @@ PODS:
- EXNotifications (0.12.3):
- ExpoModulesCore
- UMCore
- EXPermissions (12.1.1):
- ExpoModulesCore
- UMCore
- ExpoModulesCore (0.2.0):
- ExpoModulesCore/Core (= 0.2.0)
- ExpoModulesCore/Interfaces (= 0.2.0)
@ -377,9 +380,9 @@ PODS:
- React-Core
- react-native-cameraroll (4.0.4):
- React-Core
- react-native-netinfo (6.0.0):
- react-native-netinfo (6.0.1):
- React-Core
- react-native-pager-view (5.4.0):
- react-native-pager-view (5.4.1):
- React-Core
- react-native-safe-area-context (3.2.0):
- React-Core
@ -449,10 +452,8 @@ PODS:
- React-cxxreact (= 0.64.2)
- React-jsi (= 0.64.2)
- React-perflogger (= 0.64.2)
- RNCAsyncStorage (1.15.6):
- RNCAsyncStorage (1.15.7):
- React-Core
- RNCMaskedView (0.1.11):
- React
- RNFastImage (8.3.7):
- React-Core
- SDWebImage (~> 5.8)
@ -488,7 +489,7 @@ PODS:
- React-RCTVibration
- ReactCommon/turbomodule/core
- Yoga
- RNScreens (3.5.0):
- RNScreens (3.6.0):
- React-Core
- React-RCTImage
- RNSentry (2.6.2):
@ -534,6 +535,7 @@ DEPENDENCIES:
- EXKeepAwake (from `../node_modules/expo-keep-awake/ios`)
- EXLocalization (from `../node_modules/expo-localization/ios`)
- EXNotifications (from `../node_modules/expo-notifications/ios`)
- EXPermissions (from `../node_modules/expo-permissions/ios`)
- ExpoModulesCore (from `../node_modules/expo-modules-core/ios`)
- EXRandom (from `../node_modules/expo-random/ios`)
- EXScreenCapture (from `../node_modules/expo-screen-capture/ios`)
@ -584,7 +586,6 @@ DEPENDENCIES:
- React-runtimeexecutor (from `../node_modules/react-native/ReactCommon/runtimeexecutor`)
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
- "RNCMaskedView (from `../node_modules/@react-native-community/masked-view`)"
- RNFastImage (from `../node_modules/react-native-fast-image`)
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
- RNReanimated (from `../node_modules/react-native-reanimated`)
@ -654,6 +655,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/expo-localization/ios"
EXNotifications:
:path: "../node_modules/expo-notifications/ios"
EXPermissions:
:path: "../node_modules/expo-permissions/ios"
ExpoModulesCore:
:path: "../node_modules/expo-modules-core/ios"
EXRandom:
@ -744,8 +747,6 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon"
RNCAsyncStorage:
:path: "../node_modules/@react-native-async-storage/async-storage"
RNCMaskedView:
:path: "../node_modules/@react-native-community/masked-view"
RNFastImage:
:path: "../node_modules/react-native-fast-image"
RNGestureHandler:
@ -789,6 +790,7 @@ SPEC CHECKSUMS:
EXKeepAwake: f4105ef469be7b283f66ce2d7234bb71ac80cd26
EXLocalization: 356f4e16a606cec21a77d6250528fde526152b45
EXNotifications: 171ccaf17643811673c78f4c4830560d6e5a92aa
EXPermissions: 916efb5b817cb0a40160c0cd2f369af3c23a78be
ExpoModulesCore: 2734852616127a6c1fc23012197890a6f3763dc7
EXRandom: ecb71f5d01991f29bb0277f8a2c35d168f85d637
EXScreenCapture: c51844407fbac8bbca4415467bc43f2b7764d225
@ -830,8 +832,8 @@ SPEC CHECKSUMS:
react-native-blur: cad4d93b364f91e7b7931b3fa935455487e5c33c
react-native-blurhash: d978f8017ed091d9e1179775fe7bac14297e6e1e
react-native-cameraroll: 88f4e62d9ecd0e1f253abe4f685474f2ea14bfa2
react-native-netinfo: e849fc21ca2f4128a5726c801a82fc6f4a6db50d
react-native-pager-view: 54970cc27fdef14db2dcfedadb091d711e88065d
react-native-netinfo: 7cb7877ff31ebeb3d03ce0b4fbb616f121ddd859
react-native-pager-view: 43f51f45f37ec9715f6c188e4af46ccdf79872e8
react-native-safe-area-context: f0906bf8bc9835ac9a9d3f97e8bde2a997d8da79
react-native-segmented-control: 65df6cd0619b780b3843d574a72d4c7cec396097
React-perflogger: 25373e382fed75ce768a443822f07098a15ab737
@ -846,12 +848,11 @@ SPEC CHECKSUMS:
React-RCTVibration: 24600e3b1aaa77126989bc58b6747509a1ba14f3
React-runtimeexecutor: a9904c6d0218fb9f8b19d6dd88607225927668f9
ReactCommon: 149906e01aa51142707a10665185db879898e966
RNCAsyncStorage: b7c6564ce662366dd44d0189456183ef7eda2d4d
RNCMaskedView: 0e1bc4bfa8365eba5fbbb71e07fbdc0555249489
RNCAsyncStorage: 7102fe8985f889579a3ae148d957bbb3f308122b
RNFastImage: a7384db75df352500261e8e8f1ac2026def26102
RNGestureHandler: a479ebd5ed4221a810967000735517df0d2db211
RNReanimated: 9c13c86454bfd54dab7505c1a054470bfecd2563
RNScreens: 01ab149b5dd5c27f5ff26741b1d2bdf2cee1af35
RNScreens: eb0dfb2d6b21d2d7f980ad46b14eb306d2f1062e
RNSentry: 68644ef607b780551cc555f084869764f2566652
RNSVG: 551acb6562324b1d52a4e0758f7ca0ec234e278f
SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d

View File

@ -26,11 +26,10 @@
"dependencies": {
"@expo/react-native-action-sheet": "3.10.0",
"@neverdull-agency/expo-unlimited-secure-store": "1.0.10",
"@react-native-async-storage/async-storage": "1.15.6",
"@react-native-async-storage/async-storage": "1.15.7",
"@react-native-community/blur": "3.6.0",
"@react-native-community/cameraroll": "4.0.4",
"@react-native-community/masked-view": "0.1.11",
"@react-native-community/netinfo": "6.0.0",
"@react-native-community/netinfo": "6.0.1",
"@react-native-community/segmented-control": "2.2.2",
"@react-navigation/bottom-tabs": "6.0.5",
"@react-navigation/native": "6.0.2",
@ -52,6 +51,7 @@
"expo-linking": "2.3.1",
"expo-localization": "10.2.0",
"expo-notifications": "0.12.3",
"expo-permissions": "^12.1.1",
"expo-random": "11.2.0",
"expo-screen-capture": "3.2.0",
"expo-secure-store": "10.2.0",
@ -75,10 +75,10 @@
"react-native-flash-message": "0.1.23",
"react-native-gesture-handler": "1.10.3",
"react-native-htmlview": "0.16.0",
"react-native-pager-view": "5.4.0",
"react-native-pager-view": "5.4.1",
"react-native-reanimated": "2.2.0",
"react-native-safe-area-context": "3.2.0",
"react-native-screens": "3.5.0",
"react-native-screens": "3.6.0",
"react-native-svg": "12.1.1",
"react-native-swipe-list-view": "3.2.9",
"react-native-tab-view": "3.1.1",
@ -96,8 +96,8 @@
"@babel/core": "7.15.0",
"@babel/plugin-proposal-optional-chaining": "7.14.5",
"@babel/preset-typescript": "7.15.0",
"@expo/config": "5.0.8",
"@jest/types": "27.0.6",
"@expo/config": "5.0.9",
"@jest/types": "27.1.0",
"@testing-library/jest-native": "4.0.2",
"@testing-library/react-hooks": "7.0.1",
"@testing-library/react-native": "7.2.0",
@ -111,19 +111,19 @@
"@types/react-test-renderer": "17.0.1",
"@types/react-timeago": "4.1.3",
"@types/valid-url": "1.0.3",
"@welldone-software/why-did-you-render": "6.2.0",
"babel-jest": "27.0.6",
"@welldone-software/why-did-you-render": "6.2.1",
"babel-jest": "27.1.0",
"babel-plugin-module-resolver": "4.1.0",
"babel-plugin-transform-remove-console": "6.9.4",
"chalk": "4.1.2",
"dotenv": "10.0.0",
"jest": "27.0.6",
"jest": "27.1.0",
"jest-expo": "42.1.0",
"nock": "13.1.2",
"react-native-clean-project": "3.6.4",
"nock": "13.1.3",
"react-native-clean-project": "3.6.7",
"react-navigation": "4.4.4",
"react-navigation-stack": "2.10.4",
"react-test-renderer": "17.0.2",
"typescript": "4.3.5"
"typescript": "4.4.2"
}
}

View File

@ -1,152 +0,0 @@
declare namespace Nav {
type RootStackParamList = {
'Screen-Tabs': undefined
'Screen-Actions':
| {
type: 'status'
queryKey: QueryKeyTimeline
rootQueryKey?: QueryKeyTimeline
status: Mastodon.Status
}
| {
type: 'account'
account: Mastodon.Account
}
| {
type: 'notifications_filter'
}
'Screen-Announcements': { showAll: boolean }
'Screen-Compose':
| {
type: 'edit'
incomingStatus: Mastodon.Status
replyToStatus?: Mastodon.Status
queryKey?: [
'Timeline',
{
page: App.Pages
hashtag?: Mastodon.Tag['name']
list?: Mastodon.List['id']
toot?: Mastodon.Status['id']
account?: Mastodon.Account['id']
}
]
}
| {
type: 'reply'
incomingStatus: Mastodon.Status
accts: Mastodon.Account['acct'][]
queryKey?: [
'Timeline',
{
page: App.Pages
hashtag?: Mastodon.Tag['name']
list?: Mastodon.List['id']
toot?: Mastodon.Status['id']
account?: Mastodon.Account['id']
}
]
}
| {
type: 'conversation'
accts: Mastodon.Account['acct'][]
}
| undefined
'Screen-ImagesViewer': {
imageUrls: {
id: Mastodon.Attachment['id']
preview_url: Mastodon.AttachmentImage['preview_url']
url: Mastodon.AttachmentImage['url']
remote_url?: Mastodon.AttachmentImage['remote_url']
blurhash: Mastodon.AttachmentImage['blurhash']
width?: number
height?: number
}[]
id: Mastodon.Attachment['id']
}
}
type ScreenComposeStackParamList = {
'Screen-Compose-Root': undefined
'Screen-Compose-EditAttachment': { index: number }
'Screen-Compose-DraftsList': { timestamp: number }
}
type ScreenTabsStackParamList = {
'Tab-Local': undefined
'Tab-Public': undefined
'Tab-Compose': undefined
'Tab-Notifications': undefined
'Tab-Me': undefined
}
type TabSharedStackParamList = {
'Tab-Shared-Account': {
account: Mastodon.Account | Mastodon.Mention
}
'Tab-Shared-Attachments': { account: Mastodon.Account }
'Tab-Shared-Hashtag': {
hashtag: Mastodon.Tag['name']
}
'Tab-Shared-Search': { text: string | undefined }
'Tab-Shared-Toot': {
toot: Mastodon.Status
rootQueryKey?: QueryKeyTimeline
}
'Tab-Shared-Users':
| {
reference: 'accounts'
id: Mastodon.Account['id']
type: 'following' | 'followers'
count: number
}
| {
reference: 'statuses'
id: Mastodon.Status['id']
type: 'reblogged_by' | 'favourited_by'
count: number
}
}
type TabLocalStackParamList = {
'Tab-Local-Root': undefined
} & TabSharedStackParamList
type TabPublicStackParamList = {
'Tab-Public-Root': undefined
} & TabSharedStackParamList
type TabNotificationsStackParamList = {
'Tab-Notifications-Root': undefined
} & TabSharedStackParamList
type TabMeStackParamList = {
'Tab-Me-Root': undefined
'Tab-Me-Bookmarks': undefined
'Tab-Me-Conversations': undefined
'Tab-Me-Favourites': undefined
'Tab-Me-Lists': undefined
'Tab-Me-Lists-List': {
list: Mastodon.List['id']
title: Mastodon.List['title']
}
'Tab-Me-Profile': undefined
'Tab-Me-Push': undefined
'Tab-Me-Settings': undefined
'Tab-Me-Settings-Fontsize': undefined
'Tab-Me-Switch': undefined
} & TabSharedStackParamList
type TabMeProfileStackParamList = {
'Tab-Me-Profile-Root': undefined
'Tab-Me-Profile-Name': {
display_name: Mastodon.Account['display_name']
}
'Tab-Me-Profile-Note': {
note: Mastodon.Source['note']
}
'Tab-Me-Profile-Fields': {
fields?: Mastodon.Source['fields']
}
}
}

View File

@ -9,6 +9,7 @@ import ScreenAnnouncements from '@screens/Announcements'
import ScreenCompose from '@screens/Compose'
import ScreenImagesViewer from '@screens/ImagesViewer'
import ScreenTabs from '@screens/Tabs'
import { RootStackParamList } from '@utils/navigation/navigators'
import pushUseConnect from '@utils/push/useConnect'
import pushUseReceive from '@utils/push/useReceive'
import pushUseRespond from '@utils/push/useRespond'
@ -27,7 +28,7 @@ import { onlineManager, useQueryClient } from 'react-query'
import { useDispatch, useSelector } from 'react-redux'
import * as Sentry from 'sentry-expo'
const Stack = createNativeStackNavigator<Nav.RootStackParamList>()
const Stack = createNativeStackNavigator<RootStackParamList>()
export interface Props {
localCorrupt?: string
@ -71,9 +72,9 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
(prev, next) => prev.length === next.length
)
const queryClient = useQueryClient()
pushUseConnect({ navigationRef, mode, t, instances, dispatch })
pushUseReceive({ navigationRef, queryClient, instances })
pushUseRespond({ navigationRef, queryClient, instances, dispatch })
pushUseConnect({ mode, t, instances, dispatch })
pushUseReceive({ queryClient, instances })
pushUseRespond({ queryClient, instances, dispatch })
// Prevent screenshot alert
useEffect(() => {
@ -96,7 +97,7 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
type: 'error',
mode
})
navigationRef.current?.navigate('Screen-Tabs', {
navigationRef.navigate('Screen-Tabs', {
screen: 'Tab-Me'
})
}
@ -114,7 +115,7 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
// Callbacks
const navigationContainerOnReady = useCallback(() => {
const currentRoute = navigationRef.current?.getCurrentRoute()
const currentRoute = navigationRef.getCurrentRoute()
routeRef.current = {
name: currentRoute?.name,
params: currentRoute?.params
@ -124,7 +125,7 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
}, [])
const navigationContainerOnStateChange = useCallback(() => {
const previousRoute = routeRef.current
const currentRoute = navigationRef.current?.getCurrentRoute()
const currentRoute = navigationRef.getCurrentRoute()
const matchTabName = currentRoute?.name?.match(/(Tab-.*)-Root/)
if (matchTabName) {

View File

@ -46,7 +46,7 @@ const apiGeneral = async <T = unknown>({
params,
headers: {
'Content-Type': 'application/json',
'User-Agent': `tooot/${Constants.manifest.version}`,
'User-Agent': `tooot/${Constants.manifest?.version}`,
Accept: '*/*',
...headers
},

View File

@ -68,7 +68,7 @@ const apiInstance = async <T = unknown>({
params,
headers: {
'Content-Type': 'application/json',
'User-Agent': `tooot/${Constants.manifest.version}`,
'User-Agent': `tooot/${Constants.manifest?.version}`,
Accept: '*/*',
...headers,
...(token && {

View File

@ -1,6 +1,7 @@
import { ParseEmojis } from '@components/Parse'
import { useNavigation } from '@react-navigation/native'
import { StackNavigationProp } from '@react-navigation/stack'
import { TabLocalStackParamList } from '@utils/navigation/navigators'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useCallback } from 'react'
@ -21,7 +22,7 @@ const ComponentAccount: React.FC<Props> = ({
}) => {
const { theme } = useTheme()
const navigation = useNavigation<
StackNavigationProp<Nav.TabLocalStackParamList>
StackNavigationProp<TabLocalStackParamList>
>()
const onPress = useCallback(() => {

View File

@ -10,10 +10,9 @@ import TimelinePoll from '@components/Timeline/Shared/Poll'
import { useNavigation } from '@react-navigation/native'
import { StackNavigationProp } from '@react-navigation/stack'
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
import { getInstance, getInstanceAccount } from '@utils/slices/instancesSlice'
import { getInstanceAccount } from '@utils/slices/instancesSlice'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import htmlparser2 from 'htmlparser2-without-node-native'
import { uniqBy } from 'lodash'
import React, { useCallback } from 'react'
import { Pressable, StyleSheet, View } from 'react-native'

View File

@ -52,7 +52,7 @@ const openLink = async (
// @ts-ignore
navigation.push(page, options)
} else {
navigationRef.current?.navigate(page, options)
navigationRef.navigate(page, options)
}
}

View File

@ -1,6 +1,6 @@
import { NavigationContainerRef } from '@react-navigation/native'
import { createRef } from 'react'
import { createNavigationContainerRef } from '@react-navigation/native'
import { RootStackParamList } from '@utils/navigation/navigators'
const navigationRef = createRef<NavigationContainerRef>()
const navigationRef = createNavigationContainerRef<RootStackParamList>()
export default navigationRef

View File

@ -1,22 +1,244 @@
import { StackScreenProps } from '@react-navigation/stack'
import React from 'react'
import { SafeAreaProvider } from 'react-native-safe-area-context'
import ScreenActionsRoot from './Actions/Root'
export type ScreenAccountProp = StackScreenProps<
Nav.RootStackParamList,
'Screen-Actions'
>
import analytics from '@components/analytics'
import Button from '@components/Button'
import { RootStackScreenProps } from '@utils/navigation/navigators'
import {
getInstanceAccount,
getInstanceUrl
} from '@utils/slices/instancesSlice'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useCallback, useEffect, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { Dimensions, StyleSheet, View } from 'react-native'
import {
PanGestureHandler,
State,
TapGestureHandler
} from 'react-native-gesture-handler'
import Animated, {
Extrapolate,
interpolate,
runOnJS,
useAnimatedGestureHandler,
useAnimatedStyle,
useSharedValue,
withTiming
} from 'react-native-reanimated'
import {
SafeAreaProvider,
useSafeAreaInsets
} from 'react-native-safe-area-context'
import { useSelector } from 'react-redux'
import ActionsAccount from './Actions/Account'
import ActionsDomain from './Actions/Domain'
import ActionsNotificationsFilter from './Actions/NotificationsFilter'
import ActionsShare from './Actions/Share'
import ActionsStatus from './Actions/Status'
const ScreenActions = React.memo(
(props: ScreenAccountProp) => {
({
route: { params },
navigation
}: RootStackScreenProps<'Screen-Actions'>) => {
const { t } = useTranslation()
const instanceAccount = useSelector(
getInstanceAccount,
(prev, next) => prev?.id === next?.id
)
let sameAccount = false
switch (params.type) {
case 'status':
sameAccount = instanceAccount?.id === params.status.account.id
break
case 'account':
sameAccount = instanceAccount?.id === params.account.id
break
}
const instanceDomain = useSelector(getInstanceUrl)
let sameDomain = true
let statusDomain: string
switch (params.type) {
case 'status':
statusDomain = params.status.uri
? params.status.uri.split(new RegExp(/\/\/(.*?)\//))[1]
: ''
sameDomain = instanceDomain === statusDomain
break
}
const { theme } = useTheme()
const insets = useSafeAreaInsets()
const DEFAULT_VALUE = 350
const screenHeight = Dimensions.get('screen').height
const panY = useSharedValue(DEFAULT_VALUE)
useEffect(() => {
panY.value = withTiming(0)
}, [])
const styleTop = useAnimatedStyle(() => {
return {
bottom: interpolate(
panY.value,
[0, screenHeight],
[0, -screenHeight],
Extrapolate.CLAMP
)
}
})
const dismiss = useCallback(() => {
navigation.goBack()
}, [])
const onGestureEvent = useAnimatedGestureHandler({
onActive: ({ translationY }) => {
panY.value = translationY
},
onEnd: ({ velocityY }) => {
if (velocityY > 500) {
runOnJS(dismiss)()
} else {
panY.value = withTiming(0)
}
}
})
const actions = useMemo(() => {
switch (params.type) {
case 'status':
return (
<>
{!sameAccount ? (
<ActionsAccount
queryKey={params.queryKey}
rootQueryKey={params.rootQueryKey}
account={params.status.account}
dismiss={dismiss}
/>
) : null}
{sameAccount && params.status ? (
<ActionsStatus
navigation={navigation}
queryKey={params.queryKey}
rootQueryKey={params.rootQueryKey}
status={params.status}
dismiss={dismiss}
/>
) : null}
{!sameDomain && statusDomain ? (
<ActionsDomain
queryKey={params.queryKey}
rootQueryKey={params.rootQueryKey}
domain={statusDomain}
dismiss={dismiss}
/>
) : null}
{params.status.visibility !== 'direct' ? (
<ActionsShare
url={params.status.url || params.status.uri}
type={params.type}
dismiss={dismiss}
/>
) : null}
<Button
type='text'
content={t('common:buttons.cancel')}
onPress={() => {
analytics('bottomsheet_acknowledge')
}}
style={styles.button}
/>
</>
)
case 'account':
return (
<>
{!sameAccount ? (
<ActionsAccount account={params.account} dismiss={dismiss} />
) : null}
<ActionsShare
url={params.account.url}
type={params.type}
dismiss={dismiss}
/>
<Button
type='text'
content={t('common:buttons.cancel')}
onPress={() => {
analytics('bottomsheet_acknowledge')
}}
style={styles.button}
/>
</>
)
case 'notifications_filter':
return <ActionsNotificationsFilter />
}
}, [])
return (
<SafeAreaProvider>
<ScreenActionsRoot {...props} />
<Animated.View style={{ flex: 1 }}>
<TapGestureHandler
onHandlerStateChange={({ nativeEvent }) => {
if (nativeEvent.state === State.ACTIVE) {
dismiss()
}
}}
>
<Animated.View
style={[
styles.overlay,
{ backgroundColor: theme.backgroundOverlayInvert }
]}
>
<PanGestureHandler onGestureEvent={onGestureEvent}>
<Animated.View
style={[
styles.container,
styleTop,
{
backgroundColor: theme.backgroundDefault,
paddingBottom: insets.bottom || StyleConstants.Spacing.L
}
]}
>
<View
style={[
styles.handle,
{ backgroundColor: theme.primaryOverlay }
]}
/>
{actions}
</Animated.View>
</PanGestureHandler>
</Animated.View>
</TapGestureHandler>
</Animated.View>
</SafeAreaProvider>
)
},
() => true
)
const styles = StyleSheet.create({
overlay: {
flex: 1,
justifyContent: 'flex-end'
},
container: {
paddingTop: StyleConstants.Spacing.M
},
handle: {
alignSelf: 'center',
width: StyleConstants.Spacing.S * 8,
height: StyleConstants.Spacing.S / 2,
borderRadius: 100,
top: -StyleConstants.Spacing.M * 2
},
button: {
marginHorizontal: StyleConstants.Spacing.Global.PagePadding * 2
}
})
export default ScreenActions

View File

@ -1,241 +0,0 @@
import analytics from '@components/analytics'
import Button from '@components/Button'
import { StackScreenProps } from '@react-navigation/stack'
import {
getInstanceAccount,
getInstanceUrl
} from '@utils/slices/instancesSlice'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useCallback, useEffect, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { Dimensions, StyleSheet, View } from 'react-native'
import {
PanGestureHandler,
State,
TapGestureHandler
} from 'react-native-gesture-handler'
import Animated, {
Extrapolate,
interpolate,
runOnJS,
useAnimatedGestureHandler,
useAnimatedStyle,
useSharedValue,
withTiming
} from 'react-native-reanimated'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { useSelector } from 'react-redux'
import ActionsAccount from './Account'
import ActionsDomain from './Domain'
import ActionsNotificationsFilter from './NotificationsFilter'
import ActionsShare from './Share'
import ActionsStatus from './Status'
export type ScreenAccountProp = StackScreenProps<
Nav.RootStackParamList,
'Screen-Actions'
>
const ScreenActionsRoot = React.memo(
({ route: { params }, navigation }: ScreenAccountProp) => {
const { t } = useTranslation()
const instanceAccount = useSelector(
getInstanceAccount,
(prev, next) => prev?.id === next?.id
)
let sameAccount = false
switch (params.type) {
case 'status':
sameAccount = instanceAccount?.id === params.status.account.id
break
case 'account':
sameAccount = instanceAccount?.id === params.account.id
break
}
const instanceDomain = useSelector(getInstanceUrl)
let sameDomain = true
let statusDomain: string
switch (params.type) {
case 'status':
statusDomain = params.status.uri
? params.status.uri.split(new RegExp(/\/\/(.*?)\//))[1]
: ''
sameDomain = instanceDomain === statusDomain
break
}
const { theme } = useTheme()
const insets = useSafeAreaInsets()
const DEFAULT_VALUE = 350
const screenHeight = Dimensions.get('screen').height
const panY = useSharedValue(DEFAULT_VALUE)
useEffect(() => {
panY.value = withTiming(0)
}, [])
const styleTop = useAnimatedStyle(() => {
return {
bottom: interpolate(
panY.value,
[0, screenHeight],
[0, -screenHeight],
Extrapolate.CLAMP
)
}
})
const dismiss = useCallback(() => {
navigation.goBack()
}, [])
const onGestureEvent = useAnimatedGestureHandler({
onActive: ({ translationY }) => {
panY.value = translationY
},
onEnd: ({ velocityY }) => {
if (velocityY > 500) {
runOnJS(dismiss)()
} else {
panY.value = withTiming(0)
}
}
})
const actions = useMemo(() => {
switch (params.type) {
case 'status':
return (
<>
{!sameAccount ? (
<ActionsAccount
queryKey={params.queryKey}
rootQueryKey={params.rootQueryKey}
account={params.status.account}
dismiss={dismiss}
/>
) : null}
{sameAccount && params.status ? (
<ActionsStatus
navigation={navigation}
queryKey={params.queryKey}
rootQueryKey={params.rootQueryKey}
status={params.status}
dismiss={dismiss}
/>
) : null}
{!sameDomain && statusDomain ? (
<ActionsDomain
queryKey={params.queryKey}
rootQueryKey={params.rootQueryKey}
domain={statusDomain}
dismiss={dismiss}
/>
) : null}
{params.status.visibility !== 'direct' ? (
<ActionsShare
url={params.status.url || params.status.uri}
type={params.type}
dismiss={dismiss}
/>
) : null}
<Button
type='text'
content={t('common:buttons.cancel')}
onPress={() => {
analytics('bottomsheet_acknowledge')
}}
style={styles.button}
/>
</>
)
case 'account':
return (
<>
{!sameAccount ? (
<ActionsAccount account={params.account} dismiss={dismiss} />
) : null}
<ActionsShare
url={params.account.url}
type={params.type}
dismiss={dismiss}
/>
<Button
type='text'
content={t('common:buttons.cancel')}
onPress={() => {
analytics('bottomsheet_acknowledge')
}}
style={styles.button}
/>
</>
)
case 'notifications_filter':
return <ActionsNotificationsFilter />
}
}, [])
return (
<Animated.View style={{ flex: 1 }}>
<TapGestureHandler
onHandlerStateChange={({ nativeEvent }) => {
if (nativeEvent.state === State.ACTIVE) {
dismiss()
}
}}
>
<Animated.View
style={[
styles.overlay,
{ backgroundColor: theme.backgroundOverlayInvert }
]}
>
<PanGestureHandler onGestureEvent={onGestureEvent}>
<Animated.View
style={[
styles.container,
styleTop,
{
backgroundColor: theme.backgroundDefault,
paddingBottom: insets.bottom || StyleConstants.Spacing.L
}
]}
>
<View
style={[
styles.handle,
{ backgroundColor: theme.primaryOverlay }
]}
/>
{actions}
</Animated.View>
</PanGestureHandler>
</Animated.View>
</TapGestureHandler>
</Animated.View>
)
},
() => true
)
const styles = StyleSheet.create({
overlay: {
flex: 1,
justifyContent: 'flex-end'
},
container: {
paddingTop: StyleConstants.Spacing.M
},
handle: {
alignSelf: 'center',
width: StyleConstants.Spacing.S * 8,
height: StyleConstants.Spacing.S / 2,
borderRadius: 100,
top: -StyleConstants.Spacing.M * 2
},
button: {
marginHorizontal: StyleConstants.Spacing.Global.PagePadding * 2
}
})
export default ScreenActionsRoot

View File

@ -9,13 +9,14 @@ import {
useTimelineMutation
} from '@utils/queryHooks/timeline'
import analytics from '@components/analytics'
import { StackNavigationProp } from '@react-navigation/stack'
import { displayMessage } from '@components/Message'
import { useTheme } from '@utils/styles/ThemeManager'
import apiInstance from '@api/instance'
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import { RootStackParamList } from '@utils/navigation/navigators'
export interface Props {
navigation: StackNavigationProp<Nav.RootStackParamList, 'Screen-Actions'>
navigation: NativeStackNavigationProp<RootStackParamList, 'Screen-Actions'>
queryKey: QueryKeyTimeline
rootQueryKey?: QueryKeyTimeline
status: Mastodon.Status

View File

@ -4,8 +4,8 @@ import haptics from '@components/haptics'
import { ParseHTML } from '@components/Parse'
import RelativeTime from '@components/RelativeTime'
import { BlurView } from '@react-native-community/blur'
import { StackScreenProps } from '@react-navigation/stack'
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
import { RootStackScreenProps } from '@utils/navigation/navigators'
import {
useAnnouncementMutation,
useAnnouncementQuery
@ -20,12 +20,9 @@ import FastImage from 'react-native-fast-image'
import { FlatList, ScrollView } from 'react-native-gesture-handler'
import { SafeAreaView } from 'react-native-safe-area-context'
export type ScreenAnnouncementsProp = StackScreenProps<
Nav.RootStackParamList,
const ScreenAnnouncements: React.FC<RootStackScreenProps<
'Screen-Announcements'
>
const ScreenAnnouncements: React.FC<ScreenAnnouncementsProp> = ({
>> = ({
route: {
params: { showAll = false }
},

View File

@ -1,10 +1,10 @@
import analytics from '@components/analytics'
import { HeaderCenter, HeaderLeft, HeaderRight } from '@components/Header'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
import { StackScreenProps } from '@react-navigation/stack'
import haptics from '@root/components/haptics'
import formatText from '@screens/Compose/formatText'
import ComposeRoot from '@screens/Compose/Root'
import { RootStackScreenProps } from '@utils/navigation/navigators'
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
import { updateStoreReview } from '@utils/slices/contextsSlice'
import {
@ -43,14 +43,9 @@ import composeParseState from './Compose/utils/parseState'
import composePost from './Compose/utils/post'
import composeReducer from './Compose/utils/reducer'
export type ScreenComposeProp = StackScreenProps<
Nav.RootStackParamList,
'Screen-Compose'
>
const Stack = createNativeStackNavigator()
const ScreenCompose: React.FC<ScreenComposeProp> = ({
const ScreenCompose: React.FC<RootStackScreenProps<'Screen-Compose'>> = ({
route: { params },
navigation
}) => {

View File

@ -1,6 +1,6 @@
import { HeaderCenter, HeaderLeft } from '@components/Header'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
import { StackScreenProps } from '@react-navigation/stack'
import { ScreenComposeStackScreenProps } from '@utils/navigation/navigators'
import React, { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import { Platform } from 'react-native'
@ -8,12 +8,9 @@ import ComposeDraftsListRoot from './DraftsList/Root'
const Stack = createNativeStackNavigator()
export type ScreenComposeEditAttachmentProp = StackScreenProps<
Nav.ScreenComposeStackParamList,
const ComposeDraftsList: React.FC<ScreenComposeStackScreenProps<
'Screen-Compose-DraftsList'
>
const ComposeDraftsList: React.FC<ScreenComposeEditAttachmentProp> = ({
>> = ({
route: {
params: { timestamp }
},

View File

@ -1,6 +1,6 @@
import { HeaderLeft } from '@components/Header'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
import { StackScreenProps } from '@react-navigation/stack'
import { ScreenComposeStackScreenProps } from '@utils/navigation/navigators'
import React, { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import { KeyboardAvoidingView, Platform } from 'react-native'
@ -10,12 +10,9 @@ import ComposeEditAttachmentSubmit from './EditAttachment/Submit'
const Stack = createNativeStackNavigator()
export type ScreenComposeEditAttachmentProp = StackScreenProps<
Nav.ScreenComposeStackParamList,
const ComposeEditAttachment: React.FC<ScreenComposeStackScreenProps<
'Screen-Compose-EditAttachment'
>
const ComposeEditAttachment: React.FC<ScreenComposeEditAttachmentProp> = ({
>> = ({
route: {
params: { index }
},

View File

@ -15,7 +15,7 @@ export interface Props {
const ComposeDrafts: React.FC<Props> = ({ accessibleRefDrafts }) => {
const { t } = useTranslation('screenCompose')
const navigation = useNavigation()
const navigation = useNavigation<any>()
const { composeState } = useContext(ComposeContext)
const instanceDrafts = useSelector(getInstanceDrafts)?.filter(
draft => draft.timestamp !== composeState.timestamp

View File

@ -40,7 +40,7 @@ const ComposeAttachments: React.FC<Props> = ({ accessibleRefAttachments }) => {
const { composeState, composeDispatch } = useContext(ComposeContext)
const { t } = useTranslation('screenCompose')
const { theme } = useTheme()
const navigation = useNavigation()
const navigation = useNavigation<any>()
const flatListRef = useRef<FlatList>(null)

View File

@ -1,4 +1,5 @@
import { store } from '@root/store'
import { RootStackParamList } from '@utils/navigation/navigators'
import { getInstanceAccount } from '@utils/slices/instancesSlice'
import composeInitialState from './initialState'
import { ComposeState } from './types'
@ -34,7 +35,7 @@ const assignVisibility = (
}
const composeParseState = (
params: NonNullable<Nav.RootStackParamList['Screen-Compose']>
params: NonNullable<RootStackParamList['Screen-Compose']>
): ComposeState => {
switch (params.type) {
case 'edit':

View File

@ -1,9 +1,10 @@
import apiInstance from '@api/instance'
import { ComposeState } from '@screens/Compose/utils/types'
import { RootStackParamList } from '@utils/navigation/navigators'
import * as Crypto from 'expo-crypto'
const composePost = async (
params: Nav.RootStackParamList['Screen-Compose'],
params: RootStackParamList['Screen-Compose'],
composeState: ComposeState
) => {
const formData = new FormData()

View File

@ -6,6 +6,7 @@
*
*/
import { RootStackParamList } from '@utils/navigation/navigators'
import React, { ComponentType, useCallback, useEffect } from 'react'
import {
Animated,
@ -20,11 +21,11 @@ import useImageIndexChange from './hooks/useImageIndexChange'
import useRequestClose from './hooks/useRequestClose'
type Props = {
images: Nav.RootStackParamList['Screen-ImagesViewer']['imageUrls']
images: RootStackParamList['Screen-ImagesViewer']['imageUrls']
imageIndex: number
onRequestClose: () => void
onLongPress?: (
image: Nav.RootStackParamList['Screen-ImagesViewer']['imageUrls'][0]
image: RootStackParamList['Screen-ImagesViewer']['imageUrls'][0]
) => void
onImageIndexChange?: (imageIndex: number) => void
backgroundColor?: string
@ -50,9 +51,7 @@ function ImageViewer ({
HeaderComponent
}: Props) {
const imageList = React.createRef<
VirtualizedList<
Nav.RootStackParamList['Screen-ImagesViewer']['imageUrls'][0]
>
VirtualizedList<RootStackParamList['Screen-ImagesViewer']['imageUrls'][0]>
>()
const [opacity, onRequestCloseEnhanced] = useRequestClose(onRequestClose)
const [currentImageIndex, onScroll] = useImageIndexChange(imageIndex, SCREEN)

View File

@ -1,6 +1,7 @@
import haptics from '@components/haptics'
import { displayMessage } from '@components/Message'
import CameraRoll from '@react-native-community/cameraroll'
import { RootStackParamList } from '@utils/navigation/navigators'
import i18next from 'i18next'
import { RefObject } from 'react'
import { Platform } from 'react-native'
@ -10,7 +11,7 @@ import { FileSystem, Permissions } from 'react-native-unimodules'
type CommonProps = {
messageRef: RefObject<FlashMessage>
mode: 'light' | 'dark'
image: Nav.RootStackParamList['Screen-ImagesViewer']['imageUrls'][0]
image: RootStackParamList['Screen-ImagesViewer']['imageUrls'][0]
}
const saveIos = async ({ messageRef, mode, image }: CommonProps) => {

View File

@ -2,7 +2,11 @@ import analytics from '@components/analytics'
import { HeaderCenter, HeaderLeft, HeaderRight } from '@components/Header'
import { Message } from '@components/Message'
import { useActionSheet } from '@expo/react-native-action-sheet'
import { StackScreenProps } from '@react-navigation/stack'
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import {
RootStackParamList,
RootStackScreenProps
} from '@utils/navigation/navigators'
import { useTheme } from '@utils/styles/ThemeManager'
import { findIndex } from 'lodash'
import React, { RefObject, useCallback, useRef, useState } from 'react'
@ -24,9 +28,12 @@ const HeaderComponent = React.memo(
imageUrls
}: {
messageRef: RefObject<FlashMessage>
navigation: ScreenImagesViewerProp['navigation']
navigation: NativeStackNavigationProp<
RootStackParamList,
'Screen-ImagesViewer'
>
currentIndex: number
imageUrls: Nav.RootStackParamList['Screen-ImagesViewer']['imageUrls']
imageUrls: RootStackParamList['Screen-ImagesViewer']['imageUrls']
}) => {
const insets = useSafeAreaInsets()
const { mode } = useTheme()
@ -98,17 +105,12 @@ const HeaderComponent = React.memo(
(prev, next) => prev.currentIndex === next.currentIndex
)
export type ScreenImagesViewerProp = StackScreenProps<
Nav.RootStackParamList,
'Screen-ImagesViewer'
>
const ScreenImagesViewer = ({
route: {
params: { imageUrls, id }
},
navigation
}: ScreenImagesViewerProp) => {
}: RootStackScreenProps<'Screen-ImagesViewer'>) => {
if (imageUrls.length === 0) {
navigation.goBack()
return null

View File

@ -5,8 +5,10 @@ import {
BottomTabNavigationOptions,
createBottomTabNavigator
} from '@react-navigation/bottom-tabs'
import { NavigatorScreenParams } from '@react-navigation/native'
import { StackScreenProps } from '@react-navigation/stack'
import {
RootStackScreenProps,
ScreenTabsStackParamList
} from '@utils/navigation/navigators'
import { getPreviousTab } from '@utils/slices/contextsSlice'
import {
getInstanceAccount,
@ -25,23 +27,10 @@ import TabMe from './Tabs/Me'
import TabNotifications from './Tabs/Notifications'
import TabPublic from './Tabs/Public'
export type ScreenTabsParamList = {
'Tab-Local': NavigatorScreenParams<Nav.TabLocalStackParamList>
'Tab-Public': NavigatorScreenParams<Nav.TabPublicStackParamList>
'Tab-Compose': NavigatorScreenParams<Nav.ScreenComposeStackParamList>
'Tab-Notifications': NavigatorScreenParams<Nav.TabNotificationsStackParamList>
'Tab-Me': NavigatorScreenParams<Nav.TabMeStackParamList>
}
export type ScreenTabsProp = StackScreenProps<
Nav.RootStackParamList,
'Screen-Tabs'
>
const Tab = createBottomTabNavigator<Nav.ScreenTabsStackParamList>()
const Tab = createBottomTabNavigator<ScreenTabsStackParamList>()
const ScreenTabs = React.memo(
({ navigation }: ScreenTabsProp) => {
({ navigation }: RootStackScreenProps<'Screen-Tabs'>) => {
const { mode, theme } = useTheme()
const instanceActive = useSelector(getInstanceActive)

View File

@ -2,24 +2,21 @@ import analytics from '@components/analytics'
import { HeaderCenter, HeaderRight } from '@components/Header'
import Timeline from '@components/Timeline'
import TimelineDefault from '@components/Timeline/Default'
import { BottomTabScreenProps } from '@react-navigation/bottom-tabs'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
import { ScreenTabsParamList } from '@screens/Tabs'
import {
ScreenTabsScreenProps,
TabLocalStackParamList
} from '@utils/navigation/navigators'
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
import React, { useCallback, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { Platform } from 'react-native'
import sharedScreens from './Shared/sharedScreens'
import TabSharedRoot from './Shared/Root'
export type TabLocalProp = BottomTabScreenProps<
ScreenTabsParamList,
'Tab-Local'
>
const Stack = createNativeStackNavigator<Nav.TabLocalStackParamList>()
const Stack = createNativeStackNavigator<TabLocalStackParamList>()
const TabLocal = React.memo(
({ navigation }: TabLocalProp) => {
({ navigation }: ScreenTabsScreenProps<'Tab-Local'>) => {
const { t, i18n } = useTranslation('screenTabs')
const screenOptionsRoot = useMemo(
@ -63,7 +60,7 @@ const TabLocal = React.memo(
options={screenOptionsRoot}
children={children}
/>
{sharedScreens(Stack as any)}
{TabSharedRoot({ Stack })}
</Stack.Navigator>
)
},

View File

@ -1,5 +1,6 @@
import { HeaderCenter, HeaderLeft } from '@components/Header'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
import { TabMeStackParamList } from '@utils/navigation/navigators'
import React from 'react'
import { useTranslation } from 'react-i18next'
import { Platform } from 'react-native'
@ -14,9 +15,9 @@ import TabMeRoot from './Me/Root'
import TabMeSettings from './Me/Settings'
import TabMeSettingsFontsize from './Me/SettingsFontsize'
import TabMeSwitch from './Me/Switch'
import sharedScreens from './Shared/sharedScreens'
import TabSharedRoot from './Shared/Root'
const Stack = createNativeStackNavigator<Nav.TabMeStackParamList>()
const Stack = createNativeStackNavigator<TabMeStackParamList>()
const TabMe = React.memo(
() => {
@ -177,7 +178,7 @@ const TabMe = React.memo(
})}
/>
{sharedScreens(Stack as any)}
{TabSharedRoot({ Stack })}
</Stack.Navigator>
)
},

View File

@ -1,12 +1,11 @@
import { MenuContainer, MenuRow } from '@components/Menu'
import { StackScreenProps } from '@react-navigation/stack'
import { TabMeStackScreenProps } from '@utils/navigation/navigators'
import { useListsQuery } from '@utils/queryHooks/lists'
import React from 'react'
const TabMeLists: React.FC<StackScreenProps<
Nav.TabMeStackParamList,
'Tab-Me-Lists'
>> = ({ navigation }) => {
const TabMeLists: React.FC<TabMeStackScreenProps<'Tab-Me-Lists'>> = ({
navigation
}) => {
const { data } = useListsQuery({})
return (

View File

@ -1,13 +1,10 @@
import Timeline from '@components/Timeline'
import TimelineDefault from '@components/Timeline/Default'
import { StackScreenProps } from '@react-navigation/stack'
import { TabMeStackScreenProps } from '@utils/navigation/navigators'
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
import React, { useCallback } from 'react'
const TabMeListsList: React.FC<StackScreenProps<
Nav.TabMeStackParamList,
'Tab-Me-Lists-List'
>> = ({
const TabMeListsList: React.FC<TabMeStackScreenProps<'Tab-Me-Lists-List'>> = ({
route: {
params: { list }
}

View File

@ -1,7 +1,10 @@
import { HeaderCenter, HeaderLeft } from '@components/Header'
import { Message } from '@components/Message'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
import { StackScreenProps } from '@react-navigation/stack'
import {
TabMeProfileStackParamList,
TabMeStackScreenProps
} from '@utils/navigation/navigators'
import React, { useRef } from 'react'
import { useTranslation } from 'react-i18next'
import { KeyboardAvoidingView, Platform } from 'react-native'
@ -11,12 +14,11 @@ import TabMeProfileName from './Profile/Name'
import TabMeProfileNote from './Profile/Note'
import TabMeProfileRoot from './Profile/Root'
const Stack = createNativeStackNavigator<Nav.TabMeProfileStackParamList>()
const Stack = createNativeStackNavigator<TabMeProfileStackParamList>()
const TabMeProfile: React.FC<StackScreenProps<
Nav.TabMeStackParamList,
'Tab-Me-Switch'
>> = ({ navigation }) => {
const TabMeProfile: React.FC<TabMeStackScreenProps<'Tab-Me-Switch'>> = ({
navigation
}) => {
const { t } = useTranslation('screenTabs')
const messageRef = useRef<FlashMessage>(null)

View File

@ -1,6 +1,6 @@
import { HeaderLeft, HeaderRight } from '@components/Header'
import Input from '@components/Input'
import { StackScreenProps } from '@react-navigation/stack'
import { TabMeProfileStackScreenProps } from '@utils/navigation/navigators'
import { useProfileMutation } from '@utils/queryHooks/profile'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
@ -23,8 +23,7 @@ const prepareFields = (
})
}
const TabMeProfileFields: React.FC<StackScreenProps<
Nav.TabMeProfileStackParamList,
const TabMeProfileFields: React.FC<TabMeProfileStackScreenProps<
'Tab-Me-Profile-Fields'
> & { messageRef: RefObject<FlashMessage> }> = ({
messageRef,

View File

@ -1,6 +1,6 @@
import { HeaderLeft, HeaderRight } from '@components/Header'
import Input from '@components/Input'
import { StackScreenProps } from '@react-navigation/stack'
import { TabMeProfileStackScreenProps } from '@utils/navigation/navigators'
import { useProfileMutation } from '@utils/queryHooks/profile'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
@ -10,8 +10,7 @@ import { Alert, StyleSheet } from 'react-native'
import FlashMessage from 'react-native-flash-message'
import { ScrollView } from 'react-native-gesture-handler'
const TabMeProfileName: React.FC<StackScreenProps<
Nav.TabMeProfileStackParamList,
const TabMeProfileName: React.FC<TabMeProfileStackScreenProps<
'Tab-Me-Profile-Name'
> & { messageRef: RefObject<FlashMessage> }> = ({
messageRef,

View File

@ -1,6 +1,6 @@
import { HeaderLeft, HeaderRight } from '@components/Header'
import Input from '@components/Input'
import { StackScreenProps } from '@react-navigation/stack'
import { TabMeProfileStackScreenProps } from '@utils/navigation/navigators'
import { useProfileMutation } from '@utils/queryHooks/profile'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
@ -10,8 +10,7 @@ import { Alert, StyleSheet, View } from 'react-native'
import FlashMessage from 'react-native-flash-message'
import { ScrollView } from 'react-native-gesture-handler'
const TabMeProfileNote: React.FC<StackScreenProps<
Nav.TabMeProfileStackParamList,
const TabMeProfileNote: React.FC<TabMeProfileStackScreenProps<
'Tab-Me-Profile-Note'
> & { messageRef: RefObject<FlashMessage> }> = ({
messageRef,

View File

@ -1,7 +1,7 @@
import analytics from '@components/analytics'
import { MenuContainer, MenuRow } from '@components/Menu'
import { useActionSheet } from '@expo/react-native-action-sheet'
import { StackScreenProps } from '@react-navigation/stack'
import { TabMeProfileStackScreenProps } from '@utils/navigation/navigators'
import { useProfileMutation, useProfileQuery } from '@utils/queryHooks/profile'
import { updateAccountPreferences } from '@utils/slices/instances/updateAccountPreferences'
import { useTheme } from '@utils/styles/ThemeManager'
@ -12,8 +12,7 @@ import { ScrollView } from 'react-native-gesture-handler'
import { useDispatch } from 'react-redux'
import ProfileAvatarHeader from './Root/AvatarHeader'
const TabMeProfileRoot: React.FC<StackScreenProps<
Nav.TabMeProfileStackParamList,
const TabMeProfileRoot: React.FC<TabMeProfileStackScreenProps<
'Tab-Me-Profile-Root'
> & { messageRef: RefObject<FlashMessage> }> = ({ messageRef, navigation }) => {
const { mode } = useTheme()

View File

@ -7,7 +7,7 @@ import { useTranslation } from 'react-i18next'
const Collections: React.FC = () => {
const { t } = useTranslation('screenTabs')
const navigation = useNavigation()
const navigation = useNavigation<any>()
const listsQuery = useListsQuery({
options: {

View File

@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next'
const Settings: React.FC = () => {
const { t } = useTranslation('screenTabs')
const navigation = useNavigation()
const navigation = useNavigation<any>()
return (
<MenuContainer>

View File

@ -5,7 +5,7 @@ import React from 'react'
import { useTranslation } from 'react-i18next'
const AccountInformationSwitch: React.FC = () => {
const navigation = useNavigation()
const navigation = useNavigation<any>()
const { t } = useTranslation('screenTabs')
return (

View File

@ -29,7 +29,7 @@ const SettingsAnalytics: React.FC = () => {
}
/>
<Text style={[styles.version, { color: theme.secondary }]}>
{t('me.settings.version', { version: Constants.manifest.version })}
{t('me.settings.version', { version: Constants.manifest?.version })}
</Text>
</MenuContainer>
)

View File

@ -23,7 +23,7 @@ import { useDispatch, useSelector } from 'react-redux'
import { mapFontsizeToName } from '../SettingsFontsize'
const SettingsApp: React.FC = () => {
const navigation = useNavigation()
const navigation = useNavigation<any>()
const dispatch = useDispatch()
const { showActionSheetWithOptions } = useActionSheet()
const { setTheme } = useTheme()

View File

@ -15,7 +15,7 @@ import { getInstanceActive } from '@utils/slices/instancesSlice'
const SettingsTooot: React.FC = () => {
const instanceActive = useSelector(getInstanceActive)
const navigation = useNavigation()
const navigation = useNavigation<any>()
const { theme } = useTheme()
const { t } = useTranslation('screenTabs')

View File

@ -2,7 +2,7 @@ import Button from '@components/Button'
import haptics from '@components/haptics'
import ComponentSeparator from '@components/Separator'
import TimelineDefault from '@components/Timeline/Default'
import { StackScreenProps } from '@react-navigation/stack'
import { TabMeStackScreenProps } from '@utils/navigation/navigators'
import {
changeFontsize,
getSettingsFontsize,
@ -32,8 +32,7 @@ export const mapFontsizeToName = (size: SettingsState['fontsize']) => {
}
}
const TabMeSettingsFontsize: React.FC<StackScreenProps<
Nav.TabMeStackParamList,
const TabMeSettingsFontsize: React.FC<TabMeStackScreenProps<
'Tab-Me-Settings-Fontsize'
>> = () => {
const { mode, theme } = useTheme()
@ -129,6 +128,7 @@ const TabMeSettingsFontsize: React.FC<StackScreenProps<
onPress={() => {
if (initialSize > -1) {
haptics('Light')
// @ts-ignore
dispatch(changeFontsize(initialSize - 1))
}
}}
@ -142,6 +142,7 @@ const TabMeSettingsFontsize: React.FC<StackScreenProps<
onPress={() => {
if (initialSize < 3) {
haptics('Light')
// @ts-ignore
dispatch(changeFontsize(initialSize + 1))
}
}}

View File

@ -2,19 +2,19 @@ import analytics from '@components/analytics'
import { HeaderCenter, HeaderRight } from '@components/Header'
import Timeline from '@components/Timeline'
import TimelineNotifications from '@components/Timeline/Notifications'
import { useNavigation } from '@react-navigation/native'
import navigationRef from '@helpers/navigationRef'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
import sharedScreens from '@screens/Tabs/Shared/sharedScreens'
import { TabNotificationsStackParamList } from '@utils/navigation/navigators'
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
import React, { useCallback, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { Platform } from 'react-native'
import TabSharedRoot from './Shared/Root'
const Stack = createNativeStackNavigator<Nav.TabNotificationsStackParamList>()
const Stack = createNativeStackNavigator<TabNotificationsStackParamList>()
const TabNotifications = React.memo(
() => {
const navigation = useNavigation()
const { t, i18n } = useTranslation('screenTabs')
const screenOptionsRoot = useMemo(
@ -32,7 +32,7 @@ const TabNotifications = React.memo(
content='Filter'
onPress={() => {
analytics('notificationsfilter_tap')
navigation.navigate('Screen-Actions', {
navigationRef.navigate('Screen-Actions', {
type: 'notifications_filter'
})
}}
@ -61,7 +61,7 @@ const TabNotifications = React.memo(
children={children}
options={screenOptionsRoot}
/>
{sharedScreens(Stack as any)}
{TabSharedRoot({ Stack })}
</Stack.Navigator>
)
},

View File

@ -3,26 +3,23 @@ import { HeaderRight } from '@components/Header'
import Timeline from '@components/Timeline'
import TimelineDefault from '@components/Timeline/Default'
import SegmentedControl from '@react-native-community/segmented-control'
import { BottomTabScreenProps } from '@react-navigation/bottom-tabs'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
import { ScreenTabsParamList } from '@screens/Tabs'
import sharedScreens from '@screens/Tabs/Shared/sharedScreens'
import {
ScreenTabsScreenProps,
TabPublicStackParamList
} from '@utils/navigation/navigators'
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useCallback, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Dimensions, StyleSheet } from 'react-native'
import { TabView } from 'react-native-tab-view'
import TabSharedRoot from './Shared/Root'
export type TabPublicProps = BottomTabScreenProps<
ScreenTabsParamList,
'Tab-Public'
>
const Stack = createNativeStackNavigator<Nav.TabPublicStackParamList>()
const Stack = createNativeStackNavigator<TabPublicStackParamList>()
const TabPublic = React.memo(
({ navigation }: TabPublicProps) => {
({ navigation }: ScreenTabsScreenProps<'Tab-Public'>) => {
const { t, i18n } = useTranslation('screenTabs')
const { mode } = useTheme()
@ -112,7 +109,7 @@ const TabPublic = React.memo(
options={screenOptionsRoot}
children={children}
/>
{sharedScreens(Stack as any)}
{TabSharedRoot({ Stack })}
</Stack.Navigator>
)
},

View File

@ -3,6 +3,7 @@ import { HeaderRight } from '@components/Header'
import Timeline from '@components/Timeline'
import TimelineDefault from '@components/Timeline/Default'
import SegmentedControl from '@react-native-community/segmented-control'
import { TabSharedStackScreenProps } from '@utils/navigation/navigators'
import { useAccountQuery } from '@utils/queryHooks/account'
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
import { StyleConstants } from '@utils/styles/constants'
@ -16,9 +17,10 @@ import AccountAttachments from './Account/Attachments'
import AccountHeader from './Account/Header'
import AccountInformation from './Account/Information'
import AccountNav from './Account/Nav'
import { SharedAccountProp } from './sharedScreens'
const TabSharedAccount: React.FC<SharedAccountProp> = ({
const TabSharedAccount: React.FC<TabSharedStackScreenProps<
'Tab-Shared-Account'
>> = ({
route: {
params: { account }
},

View File

@ -3,6 +3,7 @@ import GracefullyImage from '@components/GracefullyImage'
import Icon from '@components/Icon'
import { useNavigation } from '@react-navigation/native'
import { StackNavigationProp } from '@react-navigation/stack'
import { TabLocalStackParamList } from '@utils/navigation/navigators'
import { useTimelineQuery } from '@utils/queryHooks/timeline'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
@ -24,7 +25,7 @@ export interface Props {
const AccountAttachments = React.memo(
({ account }: Props) => {
const navigation = useNavigation<
StackNavigationProp<Nav.TabLocalStackParamList>
StackNavigationProp<TabLocalStackParamList>
>()
const { theme } = useTheme()

View File

@ -19,7 +19,7 @@ export interface Props {
}
const Conversation = ({ account }: { account: Mastodon.Account }) => {
const navigation = useNavigation()
const navigation = useNavigation<any>()
const query = useRelationshipQuery({ id: account.id })
return query.data && !query.data.blocked_by ? (
@ -45,7 +45,7 @@ const AccountInformationActions: React.FC<Props> = ({ account, myInfo }) => {
}
const { t } = useTranslation('screenTabs')
const navigation = useNavigation()
const navigation = useNavigation<any>()
if (account?.moved) {
const accountMoved = account.moved

View File

@ -4,6 +4,7 @@ import GracefullyImage from '@components/GracefullyImage'
import { useNavigation } from '@react-navigation/native'
import { StackNavigationProp } from '@react-navigation/stack'
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
import { TabLocalStackParamList } from '@utils/navigation/navigators'
import { StyleConstants } from '@utils/styles/constants'
import React from 'react'
import { Pressable, StyleSheet, View } from 'react-native'
@ -20,7 +21,7 @@ const AccountInformationAvatar: React.FC<Props> = ({
edit
}) => {
const navigation = useNavigation<
StackNavigationProp<Nav.TabLocalStackParamList>
StackNavigationProp<TabLocalStackParamList>
>()
const { reduceMotionEnabled } = useAccessibility()

View File

@ -3,6 +3,7 @@ import { useNavigation } from '@react-navigation/native'
import { StackNavigationProp } from '@react-navigation/stack'
import { StyleConstants } from '@root/utils/styles/constants'
import { useTheme } from '@root/utils/styles/ThemeManager'
import { TabLocalStackParamList } from '@utils/navigation/navigators'
import React from 'react'
import { useTranslation } from 'react-i18next'
import { StyleSheet, Text, View } from 'react-native'
@ -15,7 +16,7 @@ export interface Props {
const AccountInformationStats: React.FC<Props> = ({ account, myInfo }) => {
const navigation = useNavigation<
StackNavigationProp<Nav.TabLocalStackParamList>
StackNavigationProp<TabLocalStackParamList>
>()
const { theme } = useTheme()
const { t } = useTranslation('screenTabs')

View File

@ -1,10 +1,12 @@
import Timeline from '@components/Timeline'
import TimelineDefault from '@components/Timeline/Default'
import { TabSharedStackScreenProps } from '@utils/navigation/navigators'
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
import React, { useCallback } from 'react'
import { SharedAttachmentsProp } from './sharedScreens'
const TabSharedAttachments: React.FC<SharedAttachmentsProp> = ({
const TabSharedAttachments: React.FC<TabSharedStackScreenProps<
'Tab-Shared-Attachments'
>> = ({
route: {
params: { account }
}

View File

@ -1,10 +1,12 @@
import Timeline from '@components/Timeline'
import TimelineDefault from '@components/Timeline/Default'
import { TabSharedStackScreenProps } from '@utils/navigation/navigators'
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
import React, { useCallback } from 'react'
import { SharedHashtagProp } from './sharedScreens'
const TabSharedHashtag: React.FC<SharedHashtagProp> = ({
const TabSharedHashtag: React.FC<TabSharedStackScreenProps<
'Tab-Shared-Hashtag'
>> = ({
route: {
params: { hashtag }
}

View File

@ -1,22 +1,13 @@
import { HeaderCenter, HeaderLeft } from '@components/Header'
import { ParseEmojis } from '@components/Parse'
import {
ParamListBase,
StackNavigationState,
TypedNavigator
} from '@react-navigation/native'
import {
NativeStackNavigationEventMap,
NativeStackNavigationOptions,
NativeStackNavigatorProps
} from '@react-navigation/native-stack/lib/typescript/src/types'
import { StackScreenProps } from '@react-navigation/stack'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
import TabSharedAccount from '@screens/Tabs/Shared/Account'
import TabSharedAttachments from '@screens/Tabs/Shared/Attachments'
import TabSharedHashtag from '@screens/Tabs/Shared/Hashtag'
import TabSharedSearch from '@screens/Tabs/Shared/Search'
import TabSharedToot from '@screens/Tabs/Shared/Toot'
import TabSharedUsers from '@screens/Tabs/Shared/Users'
import { TabSharedStackScreenProps } from '@utils/navigation/navigators'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import { debounce } from 'lodash'
@ -24,55 +15,27 @@ import React from 'react'
import { Trans, useTranslation } from 'react-i18next'
import { Platform, StyleSheet, Text, TextInput, View } from 'react-native'
export type BaseScreens =
| Nav.TabLocalStackParamList
| Nav.TabPublicStackParamList
| Nav.TabNotificationsStackParamList
| Nav.TabMeStackParamList
export type SharedAccountProp = StackScreenProps<
BaseScreens,
'Tab-Shared-Account'
>
export type SharedAttachmentsProp = StackScreenProps<
BaseScreens,
'Tab-Shared-Attachments'
>
export type SharedHashtagProp = StackScreenProps<
BaseScreens,
'Tab-Shared-Hashtag'
>
export type SharedSearchProp = StackScreenProps<
BaseScreens,
'Tab-Shared-Search'
>
export type SharedTootProp = StackScreenProps<BaseScreens, 'Tab-Shared-Toot'>
export type SharedUsersProp = StackScreenProps<BaseScreens, 'Tab-Shared-Users'>
const sharedScreens = (
Stack: TypedNavigator<
Nav.TabLocalStackParamList,
StackNavigationState<ParamListBase>,
NativeStackNavigationOptions,
NativeStackNavigationEventMap,
({}: NativeStackNavigatorProps) => JSX.Element
>
) => {
const TabSharedRoot = ({
Stack
}: {
Stack: ReturnType<typeof createNativeStackNavigator>
}) => {
const { mode, theme } = useTheme()
const { t } = useTranslation('screenTabs')
return (
<Stack.Group>
<Stack.Group
screenOptions={({ navigation }) => ({
headerLeft: () => <HeaderLeft onPress={() => navigation.goBack()} />
})}
>
<Stack.Screen
key='Tab-Shared-Account'
name='Tab-Shared-Account'
component={TabSharedAccount}
options={({ navigation }: SharedAccountProp) => {
options={({
navigation
}: TabSharedStackScreenProps<'Tab-Shared-Account'>) => {
return {
headerTransparent: true,
headerStyle: {
@ -93,13 +56,9 @@ const sharedScreens = (
options={({
route: {
params: { account }
},
navigation
}: SharedAttachmentsProp) => {
}
}: TabSharedStackScreenProps<'Tab-Shared-Attachments'>) => {
return {
headerLeft: () => (
<HeaderLeft onPress={() => navigation.goBack()} />
),
headerTitle: () => (
<Text numberOfLines={1}>
<Trans
@ -129,7 +88,9 @@ const sharedScreens = (
key='Tab-Shared-Hashtag'
name='Tab-Shared-Hashtag'
component={TabSharedHashtag}
options={({ route, navigation }: SharedHashtagProp) => ({
options={({
route
}: TabSharedStackScreenProps<'Tab-Shared-Hashtag'>) => ({
headerTitle: `#${decodeURIComponent(route.params.hashtag)}`,
...(Platform.OS === 'android' && {
headerCenter: () => (
@ -137,8 +98,7 @@ const sharedScreens = (
content={`#${decodeURIComponent(route.params.hashtag)}`}
/>
)
}),
headerLeft: () => <HeaderLeft onPress={() => navigation.goBack()} />
})
})}
/>
@ -146,8 +106,9 @@ const sharedScreens = (
key='Tab-Shared-Search'
name='Tab-Shared-Search'
component={TabSharedSearch}
options={({ navigation }: SharedSearchProp) => ({
headerLeft: () => <HeaderLeft onPress={() => navigation.goBack()} />,
options={({
navigation
}: TabSharedStackScreenProps<'Tab-Shared-Search'>) => ({
headerTitle: () => {
const onChangeText = debounce(
(text: string) => navigation.setParams({ text }),
@ -202,13 +163,12 @@ const sharedScreens = (
key='Tab-Shared-Toot'
name='Tab-Shared-Toot'
component={TabSharedToot}
options={({ navigation }: SharedTootProp) => ({
options={{
headerTitle: t('shared.toot.name'),
...(Platform.OS === 'android' && {
headerCenter: () => <HeaderCenter content={t('shared.toot.name')} />
}),
headerLeft: () => <HeaderLeft onPress={() => navigation.goBack()} />
})}
})
}}
/>
<Stack.Screen
@ -216,12 +176,10 @@ const sharedScreens = (
name='Tab-Shared-Users'
component={TabSharedUsers}
options={({
navigation,
route: {
params: { reference, type, count }
}
}: SharedUsersProp) => ({
headerLeft: () => <HeaderLeft onPress={() => navigation.goBack()} />,
}: TabSharedStackScreenProps<'Tab-Shared-Users'>) => ({
headerTitle: t(`shared.users.${reference}.${type}`, { count }),
...(Platform.OS === 'android' && {
headerCenter: () => (
@ -247,4 +205,4 @@ const styles = StyleSheet.create({
}
})
export default sharedScreens
export default TabSharedRoot

View File

@ -2,6 +2,7 @@ import ComponentAccount from '@components/Account'
import ComponentHashtag from '@components/Hashtag'
import ComponentSeparator from '@components/Separator'
import TimelineDefault from '@components/Timeline/Default'
import { TabSharedStackScreenProps } from '@utils/navigation/navigators'
import { useSearchQuery } from '@utils/queryHooks/search'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
@ -16,9 +17,10 @@ import {
View
} from 'react-native'
import { Circle } from 'react-native-animated-spinkit'
import { SharedSearchProp } from './sharedScreens'
const TabSharedSearch: React.FC<SharedSearchProp> = ({
const TabSharedSearch: React.FC<TabSharedStackScreenProps<
'Tab-Shared-Search'
>> = ({
route: {
params: { text }
}

View File

@ -1,14 +1,14 @@
import Timeline from '@components/Timeline'
import TimelineDefault from '@components/Timeline/Default'
import { useNavigation } from '@react-navigation/native'
import { TabSharedStackScreenProps } from '@utils/navigation/navigators'
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
import { findIndex } from 'lodash'
import React, { useCallback, useEffect, useRef } from 'react'
import { FlatList } from 'react-native'
import { InfiniteQueryObserver, useQueryClient } from 'react-query'
import { SharedTootProp } from './sharedScreens'
const TabSharedToot: React.FC<SharedTootProp> = ({
const TabSharedToot: React.FC<TabSharedStackScreenProps<'Tab-Shared-Toot'>> = ({
route: {
params: { toot, rootQueryKey }
}

View File

@ -1,13 +1,13 @@
import ComponentAccount from '@components/Account'
import ComponentSeparator from '@components/Separator'
import { TabSharedStackScreenProps } from '@utils/navigation/navigators'
import { QueryKeyUsers, useUsersQuery } from '@utils/queryHooks/users'
import React, { useCallback } from 'react'
import { StyleSheet } from 'react-native'
import { FlatList } from 'react-native-gesture-handler'
import { SharedUsersProp } from './sharedScreens'
const TabSharedUsers = React.memo(
({ route: { params } }: SharedUsersProp) => {
({ route: { params } }: TabSharedStackScreenProps<'Tab-Shared-Users'>) => {
const queryKey: QueryKeyUsers = ['Users', params]
const {
data,

View File

@ -1,10 +1,10 @@
import createSecureStore from '@neverdull-agency/expo-unlimited-secure-store'
import AsyncStorage from '@react-native-async-storage/async-storage'
import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit'
import { AnyAction, configureStore, Reducer } from '@reduxjs/toolkit'
import instancesMigration from '@utils/migrations/instances/migration'
import contextsSlice from '@utils/slices/contextsSlice'
import instancesSlice from '@utils/slices/instancesSlice'
import settingsSlice from '@utils/slices/settingsSlice'
import contextsSlice, { ContextsState } from '@utils/slices/contextsSlice'
import instancesSlice, { InstancesState } from '@utils/slices/instancesSlice'
import settingsSlice, { SettingsState } from '@utils/slices/settingsSlice'
import versionSlice from '@utils/slices/versionSlice'
import { createMigrate, persistReducer, persistStore } from 'redux-persist'
@ -35,16 +35,26 @@ const settingsPersistConfig = {
const store = configureStore({
reducer: {
contexts: persistReducer(contextsPersistConfig, contextsSlice),
instances: persistReducer(instancesPersistConfig, instancesSlice),
settings: persistReducer(settingsPersistConfig, settingsSlice),
contexts: persistReducer(contextsPersistConfig, contextsSlice) as Reducer<
ContextsState,
AnyAction
>,
instances: persistReducer(
instancesPersistConfig,
instancesSlice
) as Reducer<InstancesState, AnyAction>,
settings: persistReducer(settingsPersistConfig, settingsSlice) as Reducer<
SettingsState,
AnyAction
>,
version: versionSlice
},
middleware: getDefaultMiddleware({
serializableCheck: {
ignoredActions: ['persist/PERSIST']
}
})
middleware: getDefaultMiddleware =>
getDefaultMiddleware({
serializableCheck: {
ignoredActions: ['persist/PERSIST']
}
})
})
let persistor = persistStore(store)

View File

@ -0,0 +1,173 @@
import { BottomTabScreenProps } from '@react-navigation/bottom-tabs'
import { NavigatorScreenParams } from '@react-navigation/native'
import { NativeStackScreenProps } from '@react-navigation/native-stack'
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
export type RootStackParamList = {
'Screen-Tabs': NavigatorScreenParams<ScreenTabsStackParamList>
'Screen-Actions':
| {
type: 'status'
queryKey: QueryKeyTimeline
rootQueryKey?: QueryKeyTimeline
status: Mastodon.Status
}
| {
type: 'account'
account: Mastodon.Account
}
| {
type: 'notifications_filter'
}
'Screen-Announcements': { showAll: boolean }
'Screen-Compose':
| {
type: 'edit'
incomingStatus: Mastodon.Status
replyToStatus?: Mastodon.Status
queryKey?: [
'Timeline',
{
page: App.Pages
hashtag?: Mastodon.Tag['name']
list?: Mastodon.List['id']
toot?: Mastodon.Status['id']
account?: Mastodon.Account['id']
}
]
}
| {
type: 'reply'
incomingStatus: Mastodon.Status
accts: Mastodon.Account['acct'][]
queryKey?: [
'Timeline',
{
page: App.Pages
hashtag?: Mastodon.Tag['name']
list?: Mastodon.List['id']
toot?: Mastodon.Status['id']
account?: Mastodon.Account['id']
}
]
}
| {
type: 'conversation'
accts: Mastodon.Account['acct'][]
}
| undefined
'Screen-ImagesViewer': {
imageUrls: {
id: Mastodon.Attachment['id']
preview_url: Mastodon.AttachmentImage['preview_url']
url: Mastodon.AttachmentImage['url']
remote_url?: Mastodon.AttachmentImage['remote_url']
blurhash: Mastodon.AttachmentImage['blurhash']
width?: number
height?: number
}[]
id: Mastodon.Attachment['id']
}
}
export type RootStackScreenProps<
T extends keyof RootStackParamList
> = NativeStackScreenProps<RootStackParamList, T>
export type ScreenComposeStackParamList = {
'Screen-Compose-Root': undefined
'Screen-Compose-EditAttachment': { index: number }
'Screen-Compose-DraftsList': { timestamp: number }
}
export type ScreenComposeStackScreenProps<
T extends keyof ScreenComposeStackParamList
> = NativeStackScreenProps<ScreenComposeStackParamList, T>
export type ScreenTabsStackParamList = {
'Tab-Local': NavigatorScreenParams<TabLocalStackParamList>
'Tab-Public': NavigatorScreenParams<TabPublicStackParamList>
'Tab-Compose': undefined
'Tab-Notifications': NavigatorScreenParams<TabNotificationsStackParamList>
'Tab-Me': NavigatorScreenParams<TabMeStackParamList>
}
export type ScreenTabsScreenProps<
T extends keyof ScreenTabsStackParamList
> = BottomTabScreenProps<ScreenTabsStackParamList, T>
export type TabSharedStackParamList = {
'Tab-Shared-Account': {
account: Mastodon.Account | Mastodon.Mention
}
'Tab-Shared-Attachments': { account: Mastodon.Account }
'Tab-Shared-Hashtag': {
hashtag: Mastodon.Tag['name']
}
'Tab-Shared-Search': { text: string | undefined }
'Tab-Shared-Toot': {
toot: Mastodon.Status
rootQueryKey?: QueryKeyTimeline
}
'Tab-Shared-Users':
| {
reference: 'accounts'
id: Mastodon.Account['id']
type: 'following' | 'followers'
count: number
}
| {
reference: 'statuses'
id: Mastodon.Status['id']
type: 'reblogged_by' | 'favourited_by'
count: number
}
}
export type TabSharedStackScreenProps<
T extends keyof TabSharedStackParamList
> = NativeStackScreenProps<TabSharedStackParamList, T>
export type TabLocalStackParamList = {
'Tab-Local-Root': undefined
} & TabSharedStackParamList
export type TabPublicStackParamList = {
'Tab-Public-Root': undefined
} & TabSharedStackParamList
export type TabNotificationsStackParamList = {
'Tab-Notifications-Root': undefined
} & TabSharedStackParamList
export type TabMeStackParamList = {
'Tab-Me-Root': undefined
'Tab-Me-Bookmarks': undefined
'Tab-Me-Conversations': undefined
'Tab-Me-Favourites': undefined
'Tab-Me-Lists': undefined
'Tab-Me-Lists-List': {
list: Mastodon.List['id']
title: Mastodon.List['title']
}
'Tab-Me-Profile': undefined
'Tab-Me-Push': undefined
'Tab-Me-Settings': undefined
'Tab-Me-Settings-Fontsize': undefined
'Tab-Me-Switch': undefined
} & TabSharedStackParamList
export type TabMeStackScreenProps<
T extends keyof TabMeStackParamList
> = NativeStackScreenProps<TabMeStackParamList, T>
export type TabMeProfileStackParamList = {
'Tab-Me-Profile-Root': undefined
'Tab-Me-Profile-Name': {
display_name: Mastodon.Account['display_name']
}
'Tab-Me-Profile-Note': {
note: Mastodon.Source['note']
}
'Tab-Me-Profile-Fields': {
fields?: Mastodon.Source['fields']
}
}
export type TabMeProfileStackScreenProps<
T extends keyof TabMeProfileStackParamList
> = NativeStackScreenProps<TabMeProfileStackParamList, T>

View File

@ -1,7 +1,7 @@
import apiGeneral from '@api/general'
import apiTooot from '@api/tooot'
import { displayMessage } from '@components/Message'
import { NavigationContainerRef } from '@react-navigation/native'
import navigationRef from '@helpers/navigationRef'
import { Dispatch } from '@reduxjs/toolkit'
import { disableAllPushes, Instance } from '@utils/slices/instancesSlice'
import * as Notifications from 'expo-notifications'
@ -9,20 +9,13 @@ import { useEffect } from 'react'
import { TFunction } from 'react-i18next'
export interface Params {
navigationRef: React.RefObject<NavigationContainerRef>
mode: 'light' | 'dark'
t: TFunction<'screens'>
instances: Instance[]
dispatch: Dispatch<any>
}
const pushUseConnect = ({
navigationRef,
mode,
t,
instances,
dispatch
}: Params) => {
const pushUseConnect = ({ mode, t, instances, dispatch }: Params) => {
return useEffect(() => {
const connect = async () => {
const expoToken = (
@ -48,13 +41,13 @@ const pushUseConnect = ({
message: t('pushError.message'),
description: t('pushError.description'),
onPress: () => {
navigationRef.current?.navigate('Screen-Tabs', {
navigationRef.navigate('Screen-Tabs', {
screen: 'Tab-Me',
params: {
screen: 'Tab-Me-Root'
}
})
navigationRef.current?.navigate('Screen-Tabs', {
navigationRef.navigate('Screen-Tabs', {
screen: 'Tab-Me',
params: {
screen: 'Tab-Me-Settings'

View File

@ -1,11 +1,8 @@
import apiInstance from '@api/instance'
import { NavigationContainerRef } from '@react-navigation/native'
import navigationRef from '@helpers/navigationRef'
const pushUseNavigate = (
navigationRef: React.RefObject<NavigationContainerRef>,
id?: Mastodon.Notification['id']
) => {
navigationRef.current?.navigate('Screen-Tabs', {
const pushUseNavigate = (id?: Mastodon.Notification['id']) => {
navigationRef.navigate('Screen-Tabs', {
screen: 'Tab-Notifications',
params: {
screen: 'Tab-Notifications-Root'
@ -21,7 +18,7 @@ const pushUseNavigate = (
url: `notifications/${id}`
}).then(({ body }) => {
if (body.status) {
navigationRef.current?.navigate('Screen-Tabs', {
navigationRef.navigate('Screen-Tabs', {
screen: 'Tab-Notifications',
params: {
screen: 'Tab-Shared-Toot',

View File

@ -1,5 +1,4 @@
import { displayMessage } from '@components/Message'
import { NavigationContainerRef } from '@react-navigation/native'
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
import { Instance, updateInstanceActive } from '@utils/slices/instancesSlice'
import * as Notifications from 'expo-notifications'
@ -10,12 +9,11 @@ import { useDispatch } from 'react-redux'
import pushUseNavigate from './useNavigate'
export interface Params {
navigationRef: React.RefObject<NavigationContainerRef>
queryClient: QueryClient
instances: Instance[]
}
const pushUseReceive = ({ navigationRef, queryClient, instances }: Params) => {
const pushUseReceive = ({ queryClient, instances }: Params) => {
const dispatch = useDispatch()
return useEffect(() => {
@ -46,7 +44,7 @@ const pushUseReceive = ({ navigationRef, queryClient, instances }: Params) => {
if (notificationIndex !== -1) {
dispatch(updateInstanceActive(instances[notificationIndex]))
}
pushUseNavigate(navigationRef, payloadData.notification_id)
pushUseNavigate(payloadData.notification_id)
}
})
}

View File

@ -1,4 +1,3 @@
import { NavigationContainerRef } from '@react-navigation/native'
import { Dispatch } from '@reduxjs/toolkit'
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
import { Instance, updateInstanceActive } from '@utils/slices/instancesSlice'
@ -9,18 +8,12 @@ import { QueryClient } from 'react-query'
import pushUseNavigate from './useNavigate'
export interface Params {
navigationRef: React.RefObject<NavigationContainerRef>
queryClient: QueryClient
instances: Instance[]
dispatch: Dispatch<any>
}
const pushUseRespond = ({
navigationRef,
queryClient,
instances,
dispatch
}: Params) => {
const pushUseRespond = ({ queryClient, instances, dispatch }: Params) => {
return useEffect(() => {
const subscription = Notifications.addNotificationResponseReceivedListener(
({ notification }) => {
@ -44,7 +37,7 @@ const pushUseRespond = ({
if (notificationIndex !== -1) {
dispatch(updateInstanceActive(instances[notificationIndex]))
}
pushUseNavigate(navigationRef, payloadData.notification_id)
pushUseNavigate(payloadData.notification_id)
}
)
return () => subscription.remove()

View File

@ -87,7 +87,9 @@ const queryFunction = async ({
}
})
} else {
const res1 = await apiInstance<(Mastodon.Status & { _pinned: boolean} )[]>({
const res1 = await apiInstance<
(Mastodon.Status & { _pinned: boolean })[]
>({
method: 'get',
url: `accounts/${account}/statuses`,
params: {
@ -105,7 +107,7 @@ const queryFunction = async ({
exclude_replies: 'true'
}
})
return await {
return {
body: uniqBy([...res1.body, ...res2.body], 'id'),
...(res2.links.next && { links: { next: res2.links.next } })
}
@ -175,8 +177,12 @@ const queryFunction = async ({
method: 'get',
url: `statuses/${toot}/context`
})
return await {
body: [...res2_1.body.ancestors, res1_1.body, ...res2_1.body.descendants]
return {
body: [
...res2_1.body.ancestors,
res1_1.body,
...res2_1.body.descendants
]
}
default:
return Promise.reject()

View File

@ -1,10 +1,11 @@
import apiInstance from '@api/instance'
import { TabSharedStackParamList } from '@utils/navigation/navigators'
import { AxiosError } from 'axios'
import { useInfiniteQuery, UseInfiniteQueryOptions } from 'react-query'
export type QueryKeyUsers = [
'Users',
Nav.TabSharedStackParamList['Tab-Shared-Users']
TabSharedStackParamList['Tab-Shared-Users']
]
const queryFunction = ({

View File

@ -54,6 +54,13 @@ const addInstance = createAsyncThunk(
headers: { Authorization: `Bearer ${token}` }
})
const { body: filters } = await apiGeneral<Mastodon.Filter[]>({
method: 'get',
domain,
url: `api/v1/filters`,
headers: { Authorization: `Bearer ${token}` }
})
return Promise.resolve({
type,
data: {
@ -70,6 +77,7 @@ const addInstance = createAsyncThunk(
avatarStatic: avatar_static,
preferences
},
filters,
notifications_filter: {
follow: true,
favourite: true,

View File

@ -12,7 +12,7 @@ export const updateInstancePushDecode = createAsyncThunk(
async (
disable: boolean,
{ getState }
): Promise<Instance['push']['decode']['value']> => {
): Promise<{ disable: Instance['push']['decode']['value'] }> => {
const state = getState() as RootState
const instance = getInstance(state)
if (!instance?.url || !instance.account.id || !instance.push.keys) {
@ -89,6 +89,6 @@ export const updateInstancePushDecode = createAsyncThunk(
}
}
return Promise.resolve(disable)
return Promise.resolve({ disable })
}
)

View File

@ -274,7 +274,7 @@ const instancesSlice = createSlice({
.addCase(updateInstancePushDecode.fulfilled, (state, action) => {
const activeIndex = findInstanceActive(state.instances)
state.instances[activeIndex].push.decode.loading = false
state.instances[activeIndex].push.decode.value = action.payload
state.instances[activeIndex].push.decode.value = action.payload.disable
})
.addCase(updateInstancePushDecode.rejected, state => {
const activeIndex = findInstanceActive(state.instances)

View File

@ -13,7 +13,7 @@ export const changeAnalytics = createAsyncThunk(
'settings/changeAnalytics',
async (newValue: SettingsState['analytics']) => {
await Analytics.setAnalyticsCollectionEnabled(newValue)
return newValue
return { newValue }
}
)
@ -75,7 +75,7 @@ const settingsSlice = createSlice({
},
extraReducers: builder => {
builder.addCase(changeAnalytics.fulfilled, (state, action) => {
state.analytics = action.payload
state.analytics = action.payload.newValue
})
}
})

View File

@ -29,7 +29,7 @@ const versionSlice = createSlice({
reducers: {},
extraReducers: builder => {
builder.addCase(retriveVersionLatest.fulfilled, (state, action) => {
if (action.payload && Constants.manifest.version) {
if (action.payload && Constants.manifest?.version) {
if (parseInt(action.payload) > parseInt(Constants.manifest.version)) {
state.update = true
}

774
yarn.lock

File diff suppressed because it is too large Load Diff