mirror of
https://github.com/tooot-app/app
synced 2025-02-16 20:00:53 +01:00
Updates
This commit is contained in:
parent
c46888acab
commit
a40a645337
6
.github/workflows/development.yml
vendored
6
.github/workflows/development.yml
vendored
@ -20,12 +20,10 @@ jobs:
|
|||||||
expo-username: ${{ secrets.EXPO_USERNAME }}
|
expo-username: ${{ secrets.EXPO_USERNAME }}
|
||||||
expo-token: ${{ secrets.EXPO_TOKEN }}
|
expo-token: ${{ secrets.EXPO_TOKEN }}
|
||||||
- name: -- Step 4 -- Install node dependencies
|
- name: -- Step 4 -- Install node dependencies
|
||||||
run: yarn install
|
|
||||||
- name: -- Step 5 -- Install native dependencies
|
|
||||||
run: npx pod-install
|
run: npx pod-install
|
||||||
- name: -- Step 6 -- Install ruby dependencies
|
- name: -- Step 5 -- Install ruby dependencies
|
||||||
run: bundle install
|
run: bundle install
|
||||||
- name: -- Step 7 -- Run fastlane
|
- name: -- Step 6 -- Run fastlane
|
||||||
env:
|
env:
|
||||||
TOOOT_ENVIRONMENT: development
|
TOOOT_ENVIRONMENT: development
|
||||||
SENTRY_ORGANIZATION: ${{ secrets.SENTRY_ORGANIZATION }}
|
SENTRY_ORGANIZATION: ${{ secrets.SENTRY_ORGANIZATION }}
|
||||||
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[submodule "src/modules/react-native-image-viewing"]
|
||||||
|
path = src/modules/react-native-image-viewing
|
||||||
|
url = https://github.com/xmflsct/react-native-image-viewing.git
|
@ -54,19 +54,16 @@
|
|||||||
"react-native-feather": "^1.0.2",
|
"react-native-feather": "^1.0.2",
|
||||||
"react-native-gesture-handler": "~1.9.0",
|
"react-native-gesture-handler": "~1.9.0",
|
||||||
"react-native-htmlview": "^0.16.0",
|
"react-native-htmlview": "^0.16.0",
|
||||||
"react-native-image-zoom-viewer": "^3.0.1",
|
|
||||||
"react-native-reanimated": "^2.0.0-rc.2",
|
"react-native-reanimated": "^2.0.0-rc.2",
|
||||||
"react-native-safe-area-context": "3.1.9",
|
"react-native-safe-area-context": "3.1.9",
|
||||||
"react-native-screens": "~2.17.1",
|
"react-native-screens": "~2.17.1",
|
||||||
"react-native-shared-element": "^0.7.0",
|
|
||||||
"react-native-svg": "12.1.0",
|
"react-native-svg": "12.1.0",
|
||||||
"react-native-swipe-list-view": "^3.2.6",
|
"react-native-swipe-list-view": "^3.2.6",
|
||||||
"react-native-tab-view": "^2.15.2",
|
"react-native-tab-view": "^2.15.2",
|
||||||
"react-native-tab-view-viewpager-adapter": "^1.1.0",
|
"react-native-tab-view-viewpager-adapter": "^1.1.0",
|
||||||
"react-native-toast-message": "^1.4.3",
|
"react-native-toast-message": "^1.4.3",
|
||||||
"react-native-unimodules": "~0.12.0",
|
"react-native-unimodules": "~0.12.0",
|
||||||
"react-navigation-shared-element": "^3.0.0",
|
"react-query": "^3.8.2",
|
||||||
"react-query": "^3.6.0",
|
|
||||||
"react-redux": "^7.2.2",
|
"react-redux": "^7.2.2",
|
||||||
"react-timeago": "^5.2.0",
|
"react-timeago": "^5.2.0",
|
||||||
"reconnecting-websocket": "^4.4.0",
|
"reconnecting-websocket": "^4.4.0",
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import client from '@api/client'
|
import client from '@api/client'
|
||||||
import { HeaderCenter, HeaderLeft } from '@components/Header'
|
|
||||||
import { toast, toastConfig } from '@components/toast'
|
import { toast, toastConfig } from '@components/toast'
|
||||||
import {
|
import {
|
||||||
NavigationContainer,
|
NavigationContainer,
|
||||||
@ -21,11 +20,11 @@ import * as Analytics from 'expo-firebase-analytics'
|
|||||||
import React, { createRef, useCallback, useEffect, useRef } from 'react'
|
import React, { createRef, useCallback, useEffect, useRef } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Platform, StatusBar } from 'react-native'
|
import { Platform, StatusBar } from 'react-native'
|
||||||
|
import { createNativeStackNavigator } from 'react-native-screens/native-stack'
|
||||||
import Toast from 'react-native-toast-message'
|
import Toast from 'react-native-toast-message'
|
||||||
import { createSharedElementStackNavigator } from 'react-navigation-shared-element'
|
|
||||||
import { useDispatch, useSelector } from 'react-redux'
|
import { useDispatch, useSelector } from 'react-redux'
|
||||||
|
|
||||||
const Stack = createSharedElementStackNavigator<Nav.RootStackParamList>()
|
const Stack = createNativeStackNavigator<Nav.RootStackParamList>()
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
localCorrupt?: string
|
localCorrupt?: string
|
||||||
@ -133,11 +132,7 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
|
|||||||
onReady={navigationContainerOnReady}
|
onReady={navigationContainerOnReady}
|
||||||
onStateChange={navigationContainerOnStateChange}
|
onStateChange={navigationContainerOnStateChange}
|
||||||
>
|
>
|
||||||
<Stack.Navigator
|
<Stack.Navigator initialRouteName='Screen-Tabs'>
|
||||||
mode='modal'
|
|
||||||
initialRouteName='Screen-Tabs'
|
|
||||||
screenOptions={{ cardStyle: { backgroundColor: theme.background } }}
|
|
||||||
>
|
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name='Screen-Tabs'
|
name='Screen-Tabs'
|
||||||
component={ScreenTabs}
|
component={ScreenTabs}
|
||||||
@ -148,80 +143,31 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
|
|||||||
name='Screen-Actions'
|
name='Screen-Actions'
|
||||||
component={ScreenActions}
|
component={ScreenActions}
|
||||||
options={{
|
options={{
|
||||||
headerShown: false,
|
stackPresentation: 'transparentModal',
|
||||||
cardStyle: { backgroundColor: 'transparent' },
|
stackAnimation: 'fade'
|
||||||
cardStyleInterpolator: ({ current: { progress } }) => ({
|
|
||||||
cardStyle: {
|
|
||||||
opacity: progress.interpolate({
|
|
||||||
inputRange: [0, 1],
|
|
||||||
outputRange: [0, 1]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name='Screen-Announcements'
|
name='Screen-Announcements'
|
||||||
component={ScreenAnnouncements}
|
component={ScreenAnnouncements}
|
||||||
options={{
|
options={{
|
||||||
gestureEnabled: false,
|
stackPresentation: 'transparentModal',
|
||||||
headerTitle: t('sharedAnnouncements:heading'),
|
stackAnimation: 'fade'
|
||||||
...(Platform.OS === 'android' && {
|
|
||||||
headerCenter: () => (
|
|
||||||
<HeaderCenter content={t('sharedAnnouncements:heading')} />
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
headerTransparent: true,
|
|
||||||
headerLeft: () => (
|
|
||||||
<HeaderLeft
|
|
||||||
content='X'
|
|
||||||
native={false}
|
|
||||||
onPress={() => navigationRef.current?.goBack()}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
animationTypeForReplace: 'pop',
|
|
||||||
cardStyle: { backgroundColor: 'transparent' },
|
|
||||||
cardStyleInterpolator: ({ current: { progress } }) => ({
|
|
||||||
cardStyle: {
|
|
||||||
opacity: progress.interpolate({
|
|
||||||
inputRange: [0, 1],
|
|
||||||
outputRange: [0, 1]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name='Screen-Compose'
|
name='Screen-Compose'
|
||||||
component={ScreenCompose}
|
component={ScreenCompose}
|
||||||
options={{ gestureEnabled: false, headerShown: false }}
|
options={{
|
||||||
|
stackPresentation: 'fullScreenModal'
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name='Screen-ImagesViewer'
|
name='Screen-ImagesViewer'
|
||||||
component={ScreenImagesViewer}
|
component={ScreenImagesViewer}
|
||||||
options={{
|
options={{
|
||||||
gestureEnabled: false,
|
stackPresentation: 'fullScreenModal',
|
||||||
headerTransparent: true,
|
stackAnimation: 'fade'
|
||||||
headerLeft: () => (
|
|
||||||
<HeaderLeft
|
|
||||||
content='X'
|
|
||||||
native={false}
|
|
||||||
onPress={() => navigationRef.current?.goBack()}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
cardStyle: { backgroundColor: 'transparent' },
|
|
||||||
cardStyleInterpolator: ({ current: { progress } }) => ({
|
|
||||||
cardStyle: {
|
|
||||||
opacity: progress.interpolate({
|
|
||||||
inputRange: [0, 1],
|
|
||||||
outputRange: [0, 1]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
sharedElements={route => {
|
|
||||||
const { imageIndex, imageUrls } = route.params
|
|
||||||
return [{ id: `image.${imageUrls[imageIndex].url}` }]
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Stack.Navigator>
|
</Stack.Navigator>
|
||||||
|
@ -4,7 +4,7 @@ import {
|
|||||||
updateLocalNotification
|
updateLocalNotification
|
||||||
} from '@utils/slices/instancesSlice'
|
} from '@utils/slices/instancesSlice'
|
||||||
import { useEffect, useRef } from 'react'
|
import { useEffect, useRef } from 'react'
|
||||||
import { InfiniteData, useQueryClient } from 'react-query'
|
import { useQueryClient } from 'react-query'
|
||||||
import { useDispatch, useSelector } from 'react-redux'
|
import { useDispatch, useSelector } from 'react-redux'
|
||||||
import ReconnectingWebSocket from 'reconnecting-websocket'
|
import ReconnectingWebSocket from 'reconnecting-websocket'
|
||||||
|
|
||||||
@ -17,7 +17,12 @@ const useWebsocket = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const dispatch = useDispatch()
|
const dispatch = useDispatch()
|
||||||
const localInstance = useSelector(getLocalInstance)
|
const localInstance = useSelector(
|
||||||
|
getLocalInstance,
|
||||||
|
(prev, next) =>
|
||||||
|
prev?.urls.streaming_api === next?.urls.streaming_api &&
|
||||||
|
prev?.token === next?.token
|
||||||
|
)
|
||||||
|
|
||||||
const rws = useRef<ReconnectingWebSocket>()
|
const rws = useRef<ReconnectingWebSocket>()
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -40,16 +45,7 @@ const useWebsocket = ({
|
|||||||
'Timeline',
|
'Timeline',
|
||||||
{ page: 'Notifications' }
|
{ page: 'Notifications' }
|
||||||
]
|
]
|
||||||
const queryData = queryClient.getQueryData(queryKey)
|
queryClient.invalidateQueries(queryKey)
|
||||||
queryData !== undefined &&
|
|
||||||
queryClient.setQueryData<
|
|
||||||
InfiniteData<Mastodon.Notification[]> | undefined
|
|
||||||
>(queryKey, old => {
|
|
||||||
if (old) {
|
|
||||||
old.pages[0].unshift(payload)
|
|
||||||
return old
|
|
||||||
}
|
|
||||||
})
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ import React, { useCallback, useMemo, useState } from 'react'
|
|||||||
import { Pressable, StyleProp, StyleSheet, ViewStyle } from 'react-native'
|
import { Pressable, StyleProp, StyleSheet, ViewStyle } from 'react-native'
|
||||||
import { Blurhash } from 'react-native-blurhash'
|
import { Blurhash } from 'react-native-blurhash'
|
||||||
import FastImage, { ImageStyle } from 'react-native-fast-image'
|
import FastImage, { ImageStyle } from 'react-native-fast-image'
|
||||||
import { SharedElement } from 'react-navigation-shared-element'
|
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
@ -73,23 +72,12 @@ const GracefullyImage = React.memo(
|
|||||||
const children = useCallback(() => {
|
const children = useCallback(() => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{sharedElement ? (
|
<FastImage
|
||||||
<SharedElement id={`image.${sharedElement}`} style={[styles.image]}>
|
source={{ uri: sourceUri }}
|
||||||
<FastImage
|
style={[styles.image, imageStyle]}
|
||||||
source={{ uri: sourceUri }}
|
onLoad={onLoad}
|
||||||
style={[styles.image, imageStyle]}
|
onError={onError}
|
||||||
onLoad={onLoad}
|
/>
|
||||||
onError={onError}
|
|
||||||
/>
|
|
||||||
</SharedElement>
|
|
||||||
) : (
|
|
||||||
<FastImage
|
|
||||||
source={{ uri: sourceUri }}
|
|
||||||
style={[styles.image, imageStyle]}
|
|
||||||
onLoad={onLoad}
|
|
||||||
onError={onError}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{blurhash &&
|
{blurhash &&
|
||||||
(hidden || !(previewLoaded || originalLoaded || remoteLoaded)) ? (
|
(hidden || !(previewLoaded || originalLoaded || remoteLoaded)) ? (
|
||||||
<Blurhash
|
<Blurhash
|
||||||
|
@ -5,16 +5,20 @@ import { StyleSheet, Text } from 'react-native'
|
|||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
content: string
|
content: string
|
||||||
|
inverted?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used for Android mostly
|
// Used for Android mostly
|
||||||
const HeaderCenter = React.memo(
|
const HeaderCenter = React.memo(
|
||||||
({ content }: Props) => {
|
({ content, inverted = false }: Props) => {
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Text
|
<Text
|
||||||
style={[styles.text, { color: theme.primary }]}
|
style={[
|
||||||
|
styles.text,
|
||||||
|
{ color: inverted ? theme.primaryOverlay : theme.primary }
|
||||||
|
]}
|
||||||
children={content}
|
children={content}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
@ -29,7 +29,7 @@ const ComponentInstance: React.FC<Props> = ({
|
|||||||
const { t } = useTranslation('componentInstance')
|
const { t } = useTranslation('componentInstance')
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
|
|
||||||
const localInstances = useSelector(getLocalInstances)
|
const localInstances = useSelector(getLocalInstances, () => true)
|
||||||
const [instanceDomain, setInstanceDomain] = useState<string>()
|
const [instanceDomain, setInstanceDomain] = useState<string>()
|
||||||
|
|
||||||
const instanceQuery = useInstanceQuery({
|
const instanceQuery = useInstanceQuery({
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import ComponentSeparator from '@components/Separator'
|
import ComponentSeparator from '@components/Separator'
|
||||||
import { useScrollToTop } from '@react-navigation/native'
|
import { useScrollToTop } from '@react-navigation/native'
|
||||||
import { QueryKeyTimeline, useTimelineQuery } from '@utils/queryHooks/timeline'
|
import { QueryKeyTimeline, useTimelineQuery } from '@utils/queryHooks/timeline'
|
||||||
|
import { getLocalActiveIndex } from '@utils/slices/instancesSlice'
|
||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
import { findIndex } from 'lodash'
|
import { findIndex } from 'lodash'
|
||||||
import React, { useCallback, useEffect, useMemo, useRef } from 'react'
|
import React, { useCallback, useEffect, useMemo, useRef } from 'react'
|
||||||
@ -12,6 +13,7 @@ import Animated, {
|
|||||||
withTiming
|
withTiming
|
||||||
} from 'react-native-reanimated'
|
} from 'react-native-reanimated'
|
||||||
import { InfiniteData, useQueryClient } from 'react-query'
|
import { InfiniteData, useQueryClient } from 'react-query'
|
||||||
|
import { useSelector } from 'react-redux'
|
||||||
import TimelineConversation from './Timeline/Conversation'
|
import TimelineConversation from './Timeline/Conversation'
|
||||||
import TimelineDefault from './Timeline/Default'
|
import TimelineDefault from './Timeline/Default'
|
||||||
import TimelineEmpty from './Timeline/Empty'
|
import TimelineEmpty from './Timeline/Empty'
|
||||||
@ -40,6 +42,8 @@ const Timeline: React.FC<Props> = ({
|
|||||||
disableInfinity = false,
|
disableInfinity = false,
|
||||||
customProps
|
customProps
|
||||||
}) => {
|
}) => {
|
||||||
|
// Update timeline when account switched
|
||||||
|
useSelector(getLocalActiveIndex)
|
||||||
const queryKeyParams = {
|
const queryKeyParams = {
|
||||||
page,
|
page,
|
||||||
...(hashtag && { hashtag }),
|
...(hashtag && { hashtag }),
|
||||||
@ -218,7 +222,7 @@ const Timeline: React.FC<Props> = ({
|
|||||||
ref={flRef}
|
ref={flRef}
|
||||||
windowSize={8}
|
windowSize={8}
|
||||||
data={flattenData}
|
data={flattenData}
|
||||||
initialNumToRender={3}
|
initialNumToRender={6}
|
||||||
maxToRenderPerBatch={3}
|
maxToRenderPerBatch={3}
|
||||||
style={styles.flatList}
|
style={styles.flatList}
|
||||||
renderItem={renderItem}
|
renderItem={renderItem}
|
||||||
|
@ -58,7 +58,10 @@ const TimelineConversation: React.FC<Props> = ({
|
|||||||
queryKey,
|
queryKey,
|
||||||
highlighted = false
|
highlighted = false
|
||||||
}) => {
|
}) => {
|
||||||
const localAccount = useSelector(getLocalAccount)
|
const localAccount = useSelector(
|
||||||
|
getLocalAccount,
|
||||||
|
(prev, next) => prev?.id === next?.id
|
||||||
|
)
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
|
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
|
@ -36,7 +36,10 @@ const TimelineDefault: React.FC<Props> = ({
|
|||||||
disableOnPress = false
|
disableOnPress = false
|
||||||
}) => {
|
}) => {
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
const localAccount = useSelector(getLocalAccount)
|
const localAccount = useSelector(
|
||||||
|
getLocalAccount,
|
||||||
|
(prev, next) => prev?.id === next?.id
|
||||||
|
)
|
||||||
const navigation = useNavigation<
|
const navigation = useNavigation<
|
||||||
StackNavigationProp<Nav.TabLocalStackParamList>
|
StackNavigationProp<Nav.TabLocalStackParamList>
|
||||||
>()
|
>()
|
||||||
|
@ -29,7 +29,10 @@ const TimelineNotifications: React.FC<Props> = ({
|
|||||||
highlighted = false
|
highlighted = false
|
||||||
}) => {
|
}) => {
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
const localAccount = useSelector(getLocalAccount)
|
const localAccount = useSelector(
|
||||||
|
getLocalAccount,
|
||||||
|
(prev, next) => prev?.id === next?.id
|
||||||
|
)
|
||||||
const navigation = useNavigation<
|
const navigation = useNavigation<
|
||||||
StackNavigationProp<Nav.TabLocalStackParamList>
|
StackNavigationProp<Nav.TabLocalStackParamList>
|
||||||
>()
|
>()
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
export default {
|
export default {
|
||||||
heading: 'Direct messages',
|
heading: 'Direct Messages',
|
||||||
content: {}
|
content: {}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,8 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
settings: '$t(meSettings:heading)',
|
accountSettings: 'Account Settings',
|
||||||
|
appSettings: '$t(meSettings:heading)',
|
||||||
logout: {
|
logout: {
|
||||||
button: 'Log out',
|
button: 'Log out',
|
||||||
alert: {
|
alert: {
|
||||||
|
@ -14,7 +14,8 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
settings: '$t(meSettings:heading)',
|
accountSettings: '账户设置',
|
||||||
|
appSettings: '$t(meSettings:heading)',
|
||||||
logout: {
|
logout: {
|
||||||
button: '退出当前账号',
|
button: '退出当前账号',
|
||||||
alert: {
|
alert: {
|
||||||
|
@ -1,32 +1,7 @@
|
|||||||
import analytics from '@components/analytics'
|
|
||||||
import Button from '@components/Button'
|
|
||||||
import { StackScreenProps } from '@react-navigation/stack'
|
import { StackScreenProps } from '@react-navigation/stack'
|
||||||
import { getLocalAccount, getLocalUrl } from '@utils/slices/instancesSlice'
|
import React from 'react'
|
||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { SafeAreaProvider } from 'react-native-safe-area-context'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import ScreenActionsRoot from './Actions/Root'
|
||||||
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 './Actions/Account'
|
|
||||||
import ActionsDomain from './Actions/Domain'
|
|
||||||
import ActionsShare from './Actions/Share'
|
|
||||||
import ActionsStatus from './Actions/Status'
|
|
||||||
|
|
||||||
export type ScreenAccountProp = StackScreenProps<
|
export type ScreenAccountProp = StackScreenProps<
|
||||||
Nav.RootStackParamList,
|
Nav.RootStackParamList,
|
||||||
@ -34,188 +9,14 @@ export type ScreenAccountProp = StackScreenProps<
|
|||||||
>
|
>
|
||||||
|
|
||||||
const ScreenActions = React.memo(
|
const ScreenActions = React.memo(
|
||||||
({ route: { params }, navigation }: ScreenAccountProp) => {
|
(props: ScreenAccountProp) => {
|
||||||
const { t } = useTranslation()
|
|
||||||
|
|
||||||
const localAccount = useSelector(getLocalAccount)
|
|
||||||
let sameAccount = false
|
|
||||||
switch (params.type) {
|
|
||||||
case 'status':
|
|
||||||
sameAccount = localAccount?.id === params.status.account.id
|
|
||||||
break
|
|
||||||
case 'account':
|
|
||||||
sameAccount = localAccount?.id === params.account.id
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
const localDomain = useSelector(getLocalUrl)
|
|
||||||
let sameDomain = true
|
|
||||||
let statusDomain: string
|
|
||||||
switch (params.type) {
|
|
||||||
case 'status':
|
|
||||||
statusDomain = params.status.uri
|
|
||||||
? params.status.uri.split(new RegExp(/\/\/(.*?)\//))[1]
|
|
||||||
: ''
|
|
||||||
sameDomain = localDomain === 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(() => {
|
|
||||||
panY.value = withTiming(DEFAULT_VALUE)
|
|
||||||
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}
|
|
||||||
account={params.status.account}
|
|
||||||
dismiss={dismiss}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{sameAccount && params.status && (
|
|
||||||
<ActionsStatus
|
|
||||||
navigation={navigation}
|
|
||||||
queryKey={params.queryKey}
|
|
||||||
status={params.status}
|
|
||||||
dismiss={dismiss}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{!sameDomain && statusDomain && (
|
|
||||||
<ActionsDomain
|
|
||||||
queryKey={params.queryKey}
|
|
||||||
domain={statusDomain}
|
|
||||||
dismiss={dismiss}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<ActionsShare
|
|
||||||
url={params.status.url || params.status.uri}
|
|
||||||
type={params.type}
|
|
||||||
dismiss={dismiss}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
case 'account':
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{!sameAccount && (
|
|
||||||
<ActionsAccount account={params.account} dismiss={dismiss} />
|
|
||||||
)}
|
|
||||||
<ActionsShare
|
|
||||||
url={params.account.url}
|
|
||||||
type={params.type}
|
|
||||||
dismiss={dismiss}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Animated.View style={{ flex: 1 }}>
|
<SafeAreaProvider>
|
||||||
<TapGestureHandler
|
<ScreenActionsRoot {...props} />
|
||||||
onHandlerStateChange={({ nativeEvent }) => {
|
</SafeAreaProvider>
|
||||||
if (nativeEvent.state === State.ACTIVE) {
|
|
||||||
dismiss()
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Animated.View
|
|
||||||
style={[
|
|
||||||
styles.overlay,
|
|
||||||
{ backgroundColor: theme.backgroundOverlay }
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<PanGestureHandler onGestureEvent={onGestureEvent}>
|
|
||||||
<Animated.View
|
|
||||||
style={[
|
|
||||||
styles.container,
|
|
||||||
styleTop,
|
|
||||||
{
|
|
||||||
backgroundColor: theme.background,
|
|
||||||
paddingBottom: insets.bottom || StyleConstants.Spacing.L
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<View
|
|
||||||
style={[
|
|
||||||
styles.handle,
|
|
||||||
{ backgroundColor: theme.primaryOverlay }
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
{actions}
|
|
||||||
<Button
|
|
||||||
type='text'
|
|
||||||
content={t('common:buttons.cancel')}
|
|
||||||
onPress={() => {
|
|
||||||
analytics('bottomsheet_cancel')
|
|
||||||
// dismiss()
|
|
||||||
}}
|
|
||||||
style={styles.button}
|
|
||||||
/>
|
|
||||||
</Animated.View>
|
|
||||||
</PanGestureHandler>
|
|
||||||
</Animated.View>
|
|
||||||
</TapGestureHandler>
|
|
||||||
</Animated.View>
|
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
() => true
|
() => 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
|
export default ScreenActions
|
||||||
|
224
src/screens/Actions/Root.tsx
Normal file
224
src/screens/Actions/Root.tsx
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
import analytics from '@components/analytics'
|
||||||
|
import Button from '@components/Button'
|
||||||
|
import { StackScreenProps } from '@react-navigation/stack'
|
||||||
|
import { getLocalAccount, getLocalUrl } 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 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 localAccount = useSelector(
|
||||||
|
getLocalAccount,
|
||||||
|
(prev, next) => prev?.id === next?.id
|
||||||
|
)
|
||||||
|
let sameAccount = false
|
||||||
|
switch (params.type) {
|
||||||
|
case 'status':
|
||||||
|
sameAccount = localAccount?.id === params.status.account.id
|
||||||
|
break
|
||||||
|
case 'account':
|
||||||
|
sameAccount = localAccount?.id === params.account.id
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
const localDomain = useSelector(getLocalUrl)
|
||||||
|
let sameDomain = true
|
||||||
|
let statusDomain: string
|
||||||
|
switch (params.type) {
|
||||||
|
case 'status':
|
||||||
|
statusDomain = params.status.uri
|
||||||
|
? params.status.uri.split(new RegExp(/\/\/(.*?)\//))[1]
|
||||||
|
: ''
|
||||||
|
sameDomain = localDomain === 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(() => {
|
||||||
|
panY.value = withTiming(DEFAULT_VALUE)
|
||||||
|
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}
|
||||||
|
account={params.status.account}
|
||||||
|
dismiss={dismiss}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{sameAccount && params.status && (
|
||||||
|
<ActionsStatus
|
||||||
|
navigation={navigation}
|
||||||
|
queryKey={params.queryKey}
|
||||||
|
status={params.status}
|
||||||
|
dismiss={dismiss}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{!sameDomain && statusDomain && (
|
||||||
|
<ActionsDomain
|
||||||
|
queryKey={params.queryKey}
|
||||||
|
domain={statusDomain}
|
||||||
|
dismiss={dismiss}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<ActionsShare
|
||||||
|
url={params.status.url || params.status.uri}
|
||||||
|
type={params.type}
|
||||||
|
dismiss={dismiss}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
case 'account':
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{!sameAccount && (
|
||||||
|
<ActionsAccount account={params.account} dismiss={dismiss} />
|
||||||
|
)}
|
||||||
|
<ActionsShare
|
||||||
|
url={params.account.url}
|
||||||
|
type={params.type}
|
||||||
|
dismiss={dismiss}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Animated.View style={{ flex: 1 }}>
|
||||||
|
<TapGestureHandler
|
||||||
|
onHandlerStateChange={({ nativeEvent }) => {
|
||||||
|
if (nativeEvent.state === State.ACTIVE) {
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Animated.View
|
||||||
|
style={[
|
||||||
|
styles.overlay,
|
||||||
|
{ backgroundColor: theme.backgroundOverlay }
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<PanGestureHandler onGestureEvent={onGestureEvent}>
|
||||||
|
<Animated.View
|
||||||
|
style={[
|
||||||
|
styles.container,
|
||||||
|
styleTop,
|
||||||
|
{
|
||||||
|
backgroundColor: theme.background,
|
||||||
|
paddingBottom: insets.bottom || StyleConstants.Spacing.L
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
styles.handle,
|
||||||
|
{ backgroundColor: theme.primaryOverlay }
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
{actions}
|
||||||
|
<Button
|
||||||
|
type='text'
|
||||||
|
content={t('common:buttons.cancel')}
|
||||||
|
onPress={() => {
|
||||||
|
analytics('bottomsheet_cancel')
|
||||||
|
// dismiss()
|
||||||
|
}}
|
||||||
|
style={styles.button}
|
||||||
|
/>
|
||||||
|
</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
|
@ -1,6 +1,7 @@
|
|||||||
import analytics from '@components/analytics'
|
import analytics from '@components/analytics'
|
||||||
import Button from '@components/Button'
|
import Button from '@components/Button'
|
||||||
import haptics from '@components/haptics'
|
import haptics from '@components/haptics'
|
||||||
|
import { HeaderCenter, HeaderLeft, HeaderRight } from '@components/Header'
|
||||||
import { ParseHTML } from '@components/Parse'
|
import { ParseHTML } from '@components/Parse'
|
||||||
import RelativeTime from '@components/RelativeTime'
|
import RelativeTime from '@components/RelativeTime'
|
||||||
import { BlurView } from '@react-native-community/blur'
|
import { BlurView } from '@react-native-community/blur'
|
||||||
@ -203,7 +204,29 @@ const ScreenAnnouncements: React.FC<ScreenAnnouncementsProp> = ({
|
|||||||
style={styles.base}
|
style={styles.base}
|
||||||
reducedTransparencyFallbackColor={theme.background}
|
reducedTransparencyFallbackColor={theme.background}
|
||||||
>
|
>
|
||||||
<SafeAreaView style={styles.base}>
|
<SafeAreaView style={styles.base} edges={['bottom']}>
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
alignItems: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<HeaderLeft
|
||||||
|
content='X'
|
||||||
|
native={false}
|
||||||
|
onPress={() => navigation.goBack()}
|
||||||
|
/>
|
||||||
|
<HeaderCenter content={t('sharedAnnouncements:heading')} />
|
||||||
|
<View style={{ opacity: 0 }}>
|
||||||
|
<HeaderRight
|
||||||
|
content='MoreHorizontal'
|
||||||
|
native={false}
|
||||||
|
onPress={() => {}}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
<FlatList
|
<FlatList
|
||||||
horizontal
|
horizontal
|
||||||
data={query.data}
|
data={query.data}
|
||||||
|
@ -75,7 +75,12 @@ const ScreenCompose: React.FC<ScreenComposeProp> = ({
|
|||||||
setHasKeyboard(false)
|
setHasKeyboard(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// const draft = useSelector(getLocalDraft, () => true)
|
const localAccount = useSelector(getLocalAccount, (prev, next) =>
|
||||||
|
prev?.preferences && next?.preferences
|
||||||
|
? prev?.preferences['posting:default:visibility'] ===
|
||||||
|
next?.preferences['posting:default:visibility']
|
||||||
|
: true
|
||||||
|
)
|
||||||
const initialReducerState = useMemo(() => {
|
const initialReducerState = useMemo(() => {
|
||||||
if (params) {
|
if (params) {
|
||||||
return composeParseState(params)
|
return composeParseState(params)
|
||||||
@ -92,7 +97,6 @@ const ScreenCompose: React.FC<ScreenComposeProp> = ({
|
|||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const localAccount = useSelector(getLocalAccount)
|
|
||||||
const [composeState, composeDispatch] = useReducer(
|
const [composeState, composeDispatch] = useReducer(
|
||||||
composeReducer,
|
composeReducer,
|
||||||
initialReducerState
|
initialReducerState
|
||||||
|
@ -18,12 +18,12 @@ const SingleEmoji = ({ emoji }: { emoji: Mastodon.Emoji }) => {
|
|||||||
newText: `:${emoji.shortcode}:`,
|
newText: `:${emoji.shortcode}:`,
|
||||||
type: 'emoji'
|
type: 'emoji'
|
||||||
})
|
})
|
||||||
composeDispatch({
|
// composeDispatch({
|
||||||
type: 'emoji',
|
// type: 'emoji',
|
||||||
payload: { ...composeState.emoji, active: false }
|
// payload: { ...composeState.emoji, active: false }
|
||||||
})
|
// })
|
||||||
haptics('Success')
|
haptics('Success')
|
||||||
}, [])
|
}, [composeState])
|
||||||
const children = useMemo(
|
const children = useMemo(
|
||||||
() => <FastImage source={{ uri: emoji.url }} style={styles.emoji} />,
|
() => <FastImage source={{ uri: emoji.url }} style={styles.emoji} />,
|
||||||
[]
|
[]
|
||||||
|
@ -14,7 +14,10 @@ import ComposeTextInput from './Header/TextInput'
|
|||||||
const ComposeRootHeader: React.FC = () => {
|
const ComposeRootHeader: React.FC = () => {
|
||||||
const { composeState } = useContext(ComposeContext)
|
const { composeState } = useContext(ComposeContext)
|
||||||
const localActiveIndex = useSelector(getLocalActiveIndex)
|
const localActiveIndex = useSelector(getLocalActiveIndex)
|
||||||
const localInstances = useSelector(getLocalInstances)
|
const localInstances = useSelector(
|
||||||
|
getLocalInstances,
|
||||||
|
(prev, next) => prev.length === next.length
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -11,7 +11,10 @@ const ComposePostingAs = React.memo(
|
|||||||
const { t } = useTranslation('sharedCompose')
|
const { t } = useTranslation('sharedCompose')
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
|
|
||||||
const localAccount = useSelector(getLocalAccount)
|
const localAccount = useSelector(
|
||||||
|
getLocalAccount,
|
||||||
|
(prev, next) => prev?.acct === next?.acct
|
||||||
|
)
|
||||||
const localUri = useSelector(getLocalUri)
|
const localUri = useSelector(getLocalUri)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,17 +1,21 @@
|
|||||||
import analytics from '@components/analytics'
|
import analytics from '@components/analytics'
|
||||||
import { HeaderRight } from '@components/Header'
|
import { HeaderCenter, HeaderLeft, HeaderRight } from '@components/Header'
|
||||||
import { useActionSheet } from '@expo/react-native-action-sheet'
|
|
||||||
import { StackScreenProps } from '@react-navigation/stack'
|
|
||||||
import CameraRoll from '@react-native-community/cameraroll'
|
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
|
||||||
import { findIndex } from 'lodash'
|
|
||||||
import React, { useCallback, useEffect, useState } from 'react'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
import { PermissionsAndroid, Platform, Share } from 'react-native'
|
|
||||||
import FastImage from 'react-native-fast-image'
|
|
||||||
import ImageViewer from 'react-native-image-zoom-viewer'
|
|
||||||
import { SharedElement } from 'react-navigation-shared-element'
|
|
||||||
import { toast } from '@components/toast'
|
import { toast } from '@components/toast'
|
||||||
|
import { useActionSheet } from '@expo/react-native-action-sheet'
|
||||||
|
import CameraRoll from '@react-native-community/cameraroll'
|
||||||
|
import { StackScreenProps } from '@react-navigation/stack'
|
||||||
|
import ImageView from '@root/modules/react-native-image-viewing/src/index'
|
||||||
|
import { findIndex } from 'lodash'
|
||||||
|
import React, { useCallback, useState } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import {
|
||||||
|
PermissionsAndroid,
|
||||||
|
Platform,
|
||||||
|
Share,
|
||||||
|
StyleSheet,
|
||||||
|
View
|
||||||
|
} from 'react-native'
|
||||||
|
import { SafeAreaView } from 'react-native-safe-area-context'
|
||||||
|
|
||||||
export type ScreenImagesViewerProp = StackScreenProps<
|
export type ScreenImagesViewerProp = StackScreenProps<
|
||||||
Nav.RootStackParamList,
|
Nav.RootStackParamList,
|
||||||
@ -24,7 +28,6 @@ const ScreenImagesViewer = ({
|
|||||||
},
|
},
|
||||||
navigation
|
navigation
|
||||||
}: ScreenImagesViewerProp) => {
|
}: ScreenImagesViewerProp) => {
|
||||||
const { theme } = useTheme()
|
|
||||||
const [currentIndex, setCurrentIndex] = useState(
|
const [currentIndex, setCurrentIndex] = useState(
|
||||||
findIndex(imageUrls, ['imageIndex', imageIndex])
|
findIndex(imageUrls, ['imageIndex', imageIndex])
|
||||||
)
|
)
|
||||||
@ -95,45 +98,53 @@ const ScreenImagesViewer = ({
|
|||||||
)
|
)
|
||||||
}, [currentIndex])
|
}, [currentIndex])
|
||||||
|
|
||||||
useEffect(
|
const HeaderComponent = useCallback(
|
||||||
() =>
|
() => (
|
||||||
navigation.setOptions({
|
<View
|
||||||
headerTitle: `${currentIndex + 1} / ${imageUrls.length}`,
|
style={{
|
||||||
headerTintColor: theme.primaryOverlay,
|
flex: 1,
|
||||||
headerRight: () => (
|
flexDirection: 'row',
|
||||||
<HeaderRight
|
justifyContent: 'space-between',
|
||||||
content='MoreHorizontal'
|
alignItems: 'center'
|
||||||
native={false}
|
}}
|
||||||
onPress={onPress}
|
>
|
||||||
/>
|
<HeaderLeft
|
||||||
)
|
content='X'
|
||||||
}),
|
native={false}
|
||||||
|
onPress={() => navigation.goBack()}
|
||||||
|
/>
|
||||||
|
<HeaderCenter
|
||||||
|
inverted
|
||||||
|
content={`${currentIndex + 1} / ${imageUrls.length}`}
|
||||||
|
/>
|
||||||
|
<HeaderRight
|
||||||
|
content='MoreHorizontal'
|
||||||
|
native={false}
|
||||||
|
onPress={onPress}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
),
|
||||||
[currentIndex]
|
[currentIndex]
|
||||||
)
|
)
|
||||||
|
|
||||||
const renderImage = useCallback(
|
|
||||||
prop => (
|
|
||||||
<SharedElement id={`imageFail.${imageUrls[imageIndex].url}`}>
|
|
||||||
<FastImage {...prop} />
|
|
||||||
</SharedElement>
|
|
||||||
),
|
|
||||||
[]
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ImageViewer
|
<SafeAreaView style={styles.base} edges={['top']}>
|
||||||
index={imageIndex}
|
<ImageView
|
||||||
imageUrls={imageUrls}
|
images={imageUrls.map(urls => ({ uri: urls.url }))}
|
||||||
enableSwipeDown
|
imageIndex={imageIndex}
|
||||||
useNativeDriver
|
onImageIndexChange={index => setCurrentIndex(index)}
|
||||||
swipeDownThreshold={100}
|
onRequestClose={() => navigation.goBack()}
|
||||||
renderIndicator={() => <></>}
|
HeaderComponent={HeaderComponent}
|
||||||
saveToLocalByLongPress={false}
|
/>
|
||||||
onSwipeDown={() => navigation.goBack()}
|
</SafeAreaView>
|
||||||
onChange={index => index && setCurrentIndex(index)}
|
|
||||||
renderImage={renderImage}
|
|
||||||
/>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
base: {
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: 'black'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
export default ScreenImagesViewer
|
export default ScreenImagesViewer
|
||||||
|
@ -7,17 +7,18 @@ import {
|
|||||||
} from '@react-navigation/bottom-tabs'
|
} from '@react-navigation/bottom-tabs'
|
||||||
import { NavigatorScreenParams } from '@react-navigation/native'
|
import { NavigatorScreenParams } from '@react-navigation/native'
|
||||||
import { StackScreenProps } from '@react-navigation/stack'
|
import { StackScreenProps } from '@react-navigation/stack'
|
||||||
|
import { useTimelineQuery } from '@utils/queryHooks/timeline'
|
||||||
import {
|
import {
|
||||||
getLocalAccount,
|
getLocalAccount,
|
||||||
getLocalActiveIndex,
|
getLocalActiveIndex,
|
||||||
getLocalInstances,
|
getLocalNotification,
|
||||||
getLocalNotification
|
updateLocalNotification
|
||||||
} from '@utils/slices/instancesSlice'
|
} from '@utils/slices/instancesSlice'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import React, { useCallback, useEffect, useMemo } from 'react'
|
import React, { useCallback, useMemo } from 'react'
|
||||||
import { Platform } from 'react-native'
|
import { Platform } from 'react-native'
|
||||||
import FastImage from 'react-native-fast-image'
|
import FastImage from 'react-native-fast-image'
|
||||||
import { useSelector } from 'react-redux'
|
import { useDispatch, useSelector } from 'react-redux'
|
||||||
import TabLocal from './Tabs/Local'
|
import TabLocal from './Tabs/Local'
|
||||||
import TabMe from './Tabs/Me'
|
import TabMe from './Tabs/Me'
|
||||||
import TabNotifications from './Tabs/Notifications'
|
import TabNotifications from './Tabs/Notifications'
|
||||||
@ -38,143 +39,171 @@ export type ScreenTabsProp = StackScreenProps<
|
|||||||
|
|
||||||
const Tab = createBottomTabNavigator<Nav.ScreenTabsStackParamList>()
|
const Tab = createBottomTabNavigator<Nav.ScreenTabsStackParamList>()
|
||||||
|
|
||||||
const ScreenTabs: React.FC<ScreenTabsProp> = ({ navigation }) => {
|
const ScreenTabs = React.memo(
|
||||||
const { theme } = useTheme()
|
({ navigation }: ScreenTabsProp) => {
|
||||||
const localActiveIndex = useSelector(getLocalActiveIndex)
|
const { theme } = useTheme()
|
||||||
const localAccount = useSelector(getLocalAccount)
|
const dispatch = useDispatch()
|
||||||
|
const localActiveIndex = useSelector(getLocalActiveIndex)
|
||||||
|
const localAccount = useSelector(
|
||||||
|
getLocalAccount,
|
||||||
|
(prev, next) => prev?.avatarStatic === next?.avatarStatic
|
||||||
|
)
|
||||||
|
|
||||||
const screenOptions = useCallback(
|
const screenOptions = useCallback(
|
||||||
({ route }): BottomTabNavigationOptions => ({
|
({ route }): BottomTabNavigationOptions => ({
|
||||||
tabBarIcon: ({
|
tabBarIcon: ({
|
||||||
focused,
|
focused,
|
||||||
color,
|
color,
|
||||||
size
|
size
|
||||||
}: {
|
}: {
|
||||||
focused: boolean
|
focused: boolean
|
||||||
color: string
|
color: string
|
||||||
size: number
|
size: number
|
||||||
}) => {
|
}) => {
|
||||||
switch (route.name) {
|
switch (route.name) {
|
||||||
case 'Tab-Local':
|
case 'Tab-Local':
|
||||||
return <Icon name='Home' size={size} color={color} />
|
return <Icon name='Home' size={size} color={color} />
|
||||||
case 'Tab-Public':
|
case 'Tab-Public':
|
||||||
return <Icon name='Globe' size={size} color={color} />
|
return <Icon name='Globe' size={size} color={color} />
|
||||||
case 'Tab-Compose':
|
case 'Tab-Compose':
|
||||||
return <Icon name='Plus' size={size} color={color} />
|
return <Icon name='Plus' size={size} color={color} />
|
||||||
case 'Tab-Notifications':
|
case 'Tab-Notifications':
|
||||||
return <Icon name='Bell' size={size} color={color} />
|
return <Icon name='Bell' size={size} color={color} />
|
||||||
case 'Tab-Me':
|
case 'Tab-Me':
|
||||||
return localActiveIndex !== null ? (
|
return localActiveIndex !== null ? (
|
||||||
<FastImage
|
<FastImage
|
||||||
source={{ uri: localAccount?.avatarStatic }}
|
source={{ uri: localAccount?.avatarStatic }}
|
||||||
style={{
|
style={{
|
||||||
width: size,
|
width: size,
|
||||||
height: size,
|
height: size,
|
||||||
borderRadius: size,
|
borderRadius: size,
|
||||||
borderWidth: focused ? 2 : 0,
|
borderWidth: focused ? 2 : 0,
|
||||||
borderColor: focused ? theme.secondary : color
|
borderColor: focused ? theme.secondary : color
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Icon
|
<Icon
|
||||||
name={focused ? 'Meh' : 'Smile'}
|
name={focused ? 'Meh' : 'Smile'}
|
||||||
size={size}
|
size={size}
|
||||||
color={!focused ? theme.secondary : color}
|
color={!focused ? theme.secondary : color}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
default:
|
default:
|
||||||
return <Icon name='AlertOctagon' size={size} color={color} />
|
return <Icon name='AlertOctagon' size={size} color={color} />
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
[localActiveIndex, localAccount]
|
|
||||||
)
|
|
||||||
const tabBarOptions = useMemo(
|
|
||||||
() => ({
|
|
||||||
activeTintColor: theme.primary,
|
|
||||||
inactiveTintColor:
|
|
||||||
localActiveIndex !== null ? theme.secondary : theme.disabled,
|
|
||||||
showLabel: false,
|
|
||||||
...(Platform.OS === 'android' && { keyboardHidesTabBar: true })
|
|
||||||
}),
|
|
||||||
[theme, localActiveIndex]
|
|
||||||
)
|
|
||||||
const localListeners = useCallback(
|
|
||||||
() => ({
|
|
||||||
tabPress: (e: any) => {
|
|
||||||
if (!(localActiveIndex !== null)) {
|
|
||||||
e.preventDefault()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
[localActiveIndex]
|
|
||||||
)
|
|
||||||
const composeListeners = useMemo(
|
|
||||||
() => ({
|
|
||||||
tabPress: (e: any) => {
|
|
||||||
e.preventDefault()
|
|
||||||
if (localActiveIndex !== null) {
|
|
||||||
haptics('Light')
|
|
||||||
navigation.navigate('Screen-Compose')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
[localActiveIndex]
|
|
||||||
)
|
|
||||||
const composeComponent = useCallback(() => null, [])
|
|
||||||
const notificationsListeners = useCallback(
|
|
||||||
() => ({
|
|
||||||
tabPress: (e: any) => {
|
|
||||||
if (!(localActiveIndex !== null)) {
|
|
||||||
e.preventDefault()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
[localActiveIndex]
|
|
||||||
)
|
|
||||||
|
|
||||||
// On launch check if there is any unread noficiations
|
|
||||||
useWebsocket({ stream: 'user', event: 'notification' })
|
|
||||||
const localNotification = useSelector(getLocalNotification)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Tab.Navigator
|
|
||||||
initialRouteName={localActiveIndex !== null ? 'Tab-Local' : 'Tab-Me'}
|
|
||||||
screenOptions={screenOptions}
|
|
||||||
tabBarOptions={tabBarOptions}
|
|
||||||
>
|
|
||||||
<Tab.Screen
|
|
||||||
name='Tab-Local'
|
|
||||||
component={TabLocal}
|
|
||||||
listeners={localListeners}
|
|
||||||
/>
|
|
||||||
<Tab.Screen name='Tab-Public' component={TabPublic} />
|
|
||||||
<Tab.Screen
|
|
||||||
name='Tab-Compose'
|
|
||||||
component={composeComponent}
|
|
||||||
listeners={composeListeners}
|
|
||||||
/>
|
|
||||||
<Tab.Screen
|
|
||||||
name='Tab-Notifications'
|
|
||||||
component={TabNotifications}
|
|
||||||
listeners={notificationsListeners}
|
|
||||||
options={{
|
|
||||||
tabBarBadge: localNotification?.latestTime
|
|
||||||
? !localNotification.readTime ||
|
|
||||||
new Date(localNotification.readTime) <
|
|
||||||
new Date(localNotification.latestTime)
|
|
||||||
? ''
|
|
||||||
: undefined
|
|
||||||
: undefined,
|
|
||||||
tabBarBadgeStyle: {
|
|
||||||
transform: [{ scale: 0.5 }],
|
|
||||||
backgroundColor: theme.red
|
|
||||||
}
|
}
|
||||||
}}
|
}
|
||||||
/>
|
}),
|
||||||
<Tab.Screen name='Tab-Me' component={TabMe} />
|
[localActiveIndex, localAccount?.avatarStatic]
|
||||||
</Tab.Navigator>
|
)
|
||||||
)
|
const tabBarOptions = useMemo(
|
||||||
}
|
() => ({
|
||||||
|
activeTintColor: theme.primary,
|
||||||
|
inactiveTintColor:
|
||||||
|
localActiveIndex !== null ? theme.secondary : theme.disabled,
|
||||||
|
showLabel: false,
|
||||||
|
...(Platform.OS === 'android' && { keyboardHidesTabBar: true })
|
||||||
|
}),
|
||||||
|
[theme, localActiveIndex]
|
||||||
|
)
|
||||||
|
const localListeners = useCallback(
|
||||||
|
() => ({
|
||||||
|
tabPress: (e: any) => {
|
||||||
|
if (!(localActiveIndex !== null)) {
|
||||||
|
e.preventDefault()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
[localActiveIndex]
|
||||||
|
)
|
||||||
|
const composeListeners = useMemo(
|
||||||
|
() => ({
|
||||||
|
tabPress: (e: any) => {
|
||||||
|
e.preventDefault()
|
||||||
|
if (localActiveIndex !== null) {
|
||||||
|
haptics('Light')
|
||||||
|
navigation.navigate('Screen-Compose')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
[localActiveIndex]
|
||||||
|
)
|
||||||
|
const composeComponent = useCallback(() => null, [])
|
||||||
|
const notificationsListeners = useCallback(
|
||||||
|
() => ({
|
||||||
|
tabPress: (e: any) => {
|
||||||
|
if (!(localActiveIndex !== null)) {
|
||||||
|
e.preventDefault()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
[localActiveIndex]
|
||||||
|
)
|
||||||
|
|
||||||
|
// On launch check if there is any unread noficiations
|
||||||
|
useTimelineQuery({
|
||||||
|
page: 'Notifications',
|
||||||
|
options: {
|
||||||
|
notifyOnChangeProps: [],
|
||||||
|
select: data => {
|
||||||
|
if (data.pages[0].length) {
|
||||||
|
dispatch(
|
||||||
|
updateLocalNotification({
|
||||||
|
latestTime: data.pages[0][0].created_at
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
useWebsocket({ stream: 'user', event: 'notification' })
|
||||||
|
const localNotification = useSelector(
|
||||||
|
getLocalNotification,
|
||||||
|
(prev, next) =>
|
||||||
|
prev?.readTime === next?.readTime &&
|
||||||
|
prev?.latestTime === next?.latestTime
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tab.Navigator
|
||||||
|
initialRouteName={localActiveIndex !== null ? 'Tab-Local' : 'Tab-Me'}
|
||||||
|
screenOptions={screenOptions}
|
||||||
|
tabBarOptions={tabBarOptions}
|
||||||
|
>
|
||||||
|
<Tab.Screen
|
||||||
|
name='Tab-Local'
|
||||||
|
component={TabLocal}
|
||||||
|
listeners={localListeners}
|
||||||
|
/>
|
||||||
|
<Tab.Screen name='Tab-Public' component={TabPublic} />
|
||||||
|
<Tab.Screen
|
||||||
|
name='Tab-Compose'
|
||||||
|
component={composeComponent}
|
||||||
|
listeners={composeListeners}
|
||||||
|
/>
|
||||||
|
<Tab.Screen
|
||||||
|
name='Tab-Notifications'
|
||||||
|
component={TabNotifications}
|
||||||
|
listeners={notificationsListeners}
|
||||||
|
options={{
|
||||||
|
tabBarBadge: localNotification?.latestTime
|
||||||
|
? !localNotification.readTime ||
|
||||||
|
new Date(localNotification.readTime) <
|
||||||
|
new Date(localNotification.latestTime)
|
||||||
|
? ''
|
||||||
|
: undefined
|
||||||
|
: undefined,
|
||||||
|
tabBarBadgeStyle: {
|
||||||
|
transform: [{ scale: 0.5 }],
|
||||||
|
backgroundColor: theme.red
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Tab.Screen name='Tab-Me' component={TabMe} />
|
||||||
|
</Tab.Navigator>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
() => true
|
||||||
|
)
|
||||||
|
|
||||||
export default ScreenTabs
|
export default ScreenTabs
|
||||||
|
@ -44,7 +44,7 @@ const Collections: React.FC = () => {
|
|||||||
onPress={() => navigation.navigate('Tab-Me-Bookmarks')}
|
onPress={() => navigation.navigate('Tab-Me-Bookmarks')}
|
||||||
/>
|
/>
|
||||||
<MenuRow
|
<MenuRow
|
||||||
iconFront='Star'
|
iconFront='Heart'
|
||||||
iconBack='ChevronRight'
|
iconBack='ChevronRight'
|
||||||
title={t('content.collections.favourites')}
|
title={t('content.collections.favourites')}
|
||||||
onPress={() => navigation.navigate('Tab-Me-Favourites')}
|
onPress={() => navigation.navigate('Tab-Me-Favourites')}
|
||||||
|
@ -10,7 +10,10 @@ export interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const MyInfo: React.FC<Props> = ({ setData }) => {
|
const MyInfo: React.FC<Props> = ({ setData }) => {
|
||||||
const localAccount = useSelector(getLocalAccount)
|
const localAccount = useSelector(
|
||||||
|
getLocalAccount,
|
||||||
|
(prev, next) => prev?.id === next?.id
|
||||||
|
)
|
||||||
const { data } = useAccountQuery({ id: localAccount!.id })
|
const { data } = useAccountQuery({ id: localAccount!.id })
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -1,26 +1,32 @@
|
|||||||
import { MenuContainer, MenuRow } from '@components/Menu'
|
import { MenuContainer, MenuRow } from '@components/Menu'
|
||||||
import { useNavigation } from '@react-navigation/native'
|
import { useNavigation } from '@react-navigation/native'
|
||||||
|
import { getLocalUrl } from '@utils/slices/instancesSlice'
|
||||||
|
import * as WebBrowser from 'expo-web-browser'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { useSelector } from 'react-redux'
|
||||||
|
|
||||||
const Settings: React.FC = () => {
|
const Settings: React.FC = () => {
|
||||||
const { t } = useTranslation('meRoot')
|
const { t } = useTranslation('meRoot')
|
||||||
const navigation = useNavigation()
|
const navigation = useNavigation()
|
||||||
|
|
||||||
const [loadingState, setLoadingState] = React.useState(false)
|
const localUrl = useSelector(getLocalUrl)
|
||||||
React.useEffect(() => {
|
|
||||||
const timer = setTimeout(() => {
|
|
||||||
setLoadingState(!loadingState)
|
|
||||||
}, 5000)
|
|
||||||
return () => clearTimeout(timer)
|
|
||||||
}, [loadingState])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MenuContainer>
|
<MenuContainer>
|
||||||
|
{/* <MenuRow
|
||||||
|
iconFront='User'
|
||||||
|
iconBack='ExternalLink'
|
||||||
|
title={t('content.accountSettings')}
|
||||||
|
onPress={() =>
|
||||||
|
localUrl &&
|
||||||
|
WebBrowser.openBrowserAsync(`https://${localUrl}/settings/profile`)
|
||||||
|
}
|
||||||
|
/> */}
|
||||||
<MenuRow
|
<MenuRow
|
||||||
iconFront='Settings'
|
iconFront='Settings'
|
||||||
iconBack='ChevronRight'
|
iconBack='ChevronRight'
|
||||||
title={t('content.settings')}
|
title={t('content.appSettings')}
|
||||||
onPress={() => navigation.navigate('Tab-Me-Settings')}
|
onPress={() => navigation.navigate('Tab-Me-Settings')}
|
||||||
/>
|
/>
|
||||||
</MenuContainer>
|
</MenuContainer>
|
||||||
|
@ -45,8 +45,8 @@ const AccountButton: React.FC<Props> = ({ instance, disabled = false }) => {
|
|||||||
onPress={() => {
|
onPress={() => {
|
||||||
haptics('Light')
|
haptics('Light')
|
||||||
analytics('switch_existing_press')
|
analytics('switch_existing_press')
|
||||||
queryClient.clear()
|
|
||||||
dispatch(updateLocalActiveIndex(instance))
|
dispatch(updateLocalActiveIndex(instance))
|
||||||
|
queryClient.clear()
|
||||||
navigation.goBack()
|
navigation.goBack()
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
@ -21,7 +21,9 @@ export interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const AccountInformation: React.FC<Props> = ({ account, myInfo = false }) => {
|
const AccountInformation: React.FC<Props> = ({ account, myInfo = false }) => {
|
||||||
const ownAccount = account?.id === useSelector(getLocalAccount)?.id
|
const ownAccount =
|
||||||
|
account?.id ===
|
||||||
|
useSelector(getLocalAccount, (prev, next) => prev?.id === next?.id)?.id
|
||||||
const { mode, theme } = useTheme()
|
const { mode, theme } = useTheme()
|
||||||
|
|
||||||
const animation = useCallback(
|
const animation = useCallback(
|
||||||
|
@ -14,7 +14,10 @@ export interface Props {
|
|||||||
|
|
||||||
const AccountInformationAccount: React.FC<Props> = ({ account, myInfo }) => {
|
const AccountInformationAccount: React.FC<Props> = ({ account, myInfo }) => {
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
const localAccount = useSelector(getLocalAccount)
|
const localAccount = useSelector(
|
||||||
|
getLocalAccount,
|
||||||
|
(prev, next) => prev?.acct === next?.acct
|
||||||
|
)
|
||||||
const localUri = useSelector(getLocalUri)
|
const localUri = useSelector(getLocalUri)
|
||||||
|
|
||||||
const movedStyle = useMemo(
|
const movedStyle = useMemo(
|
||||||
|
32
yarn.lock
32
yarn.lock
@ -8595,18 +8595,6 @@ react-native-htmlview@^0.16.0:
|
|||||||
entities "^1.1.1"
|
entities "^1.1.1"
|
||||||
htmlparser2-without-node-native "^3.9.2"
|
htmlparser2-without-node-native "^3.9.2"
|
||||||
|
|
||||||
react-native-image-pan-zoom@^2.1.12:
|
|
||||||
version "2.1.12"
|
|
||||||
resolved "https://registry.yarnpkg.com/react-native-image-pan-zoom/-/react-native-image-pan-zoom-2.1.12.tgz#eb98bf56fb5610379bdbfdb63219cc1baca98fd2"
|
|
||||||
integrity sha512-BF66XeP6dzuANsPmmFsJshM2Jyh/Mo1t8FsGc1L9Q9/sVP8MJULDabB1hms+eAoqgtyhMr5BuXV3E1hJ5U5H6Q==
|
|
||||||
|
|
||||||
react-native-image-zoom-viewer@^3.0.1:
|
|
||||||
version "3.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/react-native-image-zoom-viewer/-/react-native-image-zoom-viewer-3.0.1.tgz#a2bd5fb3bda15e0686ce88fcde8576726495d7fb"
|
|
||||||
integrity sha512-la6s5DNSuq4GCRLsi5CZ29FPjgTpdCuGIRdO5T9rUrAtxrlpBPhhSnHrbmPVxsdtOUvxHacTh2Gfa9+RraMZQA==
|
|
||||||
dependencies:
|
|
||||||
react-native-image-pan-zoom "^2.1.12"
|
|
||||||
|
|
||||||
react-native-iphone-x-helper@^1.3.0:
|
react-native-iphone-x-helper@^1.3.0:
|
||||||
version "1.3.1"
|
version "1.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/react-native-iphone-x-helper/-/react-native-iphone-x-helper-1.3.1.tgz#20c603e9a0e765fd6f97396638bdeb0e5a60b010"
|
resolved "https://registry.yarnpkg.com/react-native-iphone-x-helper/-/react-native-iphone-x-helper-1.3.1.tgz#20c603e9a0e765fd6f97396638bdeb0e5a60b010"
|
||||||
@ -8638,11 +8626,6 @@ react-native-screens@~2.17.1:
|
|||||||
resolved "https://registry.yarnpkg.com/react-native-screens/-/react-native-screens-2.17.1.tgz#c3c0ac750af48741c5b1635511e6af2a27b74309"
|
resolved "https://registry.yarnpkg.com/react-native-screens/-/react-native-screens-2.17.1.tgz#c3c0ac750af48741c5b1635511e6af2a27b74309"
|
||||||
integrity sha512-B4gD5e4csvlVwlhf+RNqjQZ9mHTwe/iL3rXondgZxnKz4oW0QAmtLnLRKOrYVxoaJaF9Fy7jhjo//24/472APQ==
|
integrity sha512-B4gD5e4csvlVwlhf+RNqjQZ9mHTwe/iL3rXondgZxnKz4oW0QAmtLnLRKOrYVxoaJaF9Fy7jhjo//24/472APQ==
|
||||||
|
|
||||||
react-native-shared-element@^0.7.0:
|
|
||||||
version "0.7.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/react-native-shared-element/-/react-native-shared-element-0.7.0.tgz#c5e02eb372f6e38e48eb1030fd59be8f3d8c7a1f"
|
|
||||||
integrity sha512-TJTGwQceABYete+vH3ahNSgzVzXz7X2SPv3thT91gdcFCrm7ht7IKXBXJiYjOA+4TfdqnGEAWkspCy80oEnOgw==
|
|
||||||
|
|
||||||
react-native-svg@12.1.0:
|
react-native-svg@12.1.0:
|
||||||
version "12.1.0"
|
version "12.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-native-svg/-/react-native-svg-12.1.0.tgz#acfe48c35cd5fca3d5fd767abae0560c36cfc03d"
|
resolved "https://registry.yarnpkg.com/react-native-svg/-/react-native-svg-12.1.0.tgz#acfe48c35cd5fca3d5fd767abae0560c36cfc03d"
|
||||||
@ -8732,13 +8715,6 @@ react-native@~0.63.4:
|
|||||||
use-subscription "^1.0.0"
|
use-subscription "^1.0.0"
|
||||||
whatwg-fetch "^3.0.0"
|
whatwg-fetch "^3.0.0"
|
||||||
|
|
||||||
react-navigation-shared-element@^3.0.0:
|
|
||||||
version "3.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/react-navigation-shared-element/-/react-navigation-shared-element-3.0.0.tgz#3dfa6a71f138e4ceb457a91aea3ef2a8ab2a6a32"
|
|
||||||
integrity sha512-nSmbgf4+hKSZU1Rzi5Bm1Is5mt0Z+xY5sXeTx4t5KMnmNW4lz5M83p9oTW6mKDoXUeCocUfeVwbCmsAjlyTLQw==
|
|
||||||
dependencies:
|
|
||||||
hoist-non-react-statics "^3.3.2"
|
|
||||||
|
|
||||||
react-navigation-stack@^2.10.2:
|
react-navigation-stack@^2.10.2:
|
||||||
version "2.10.2"
|
version "2.10.2"
|
||||||
resolved "https://registry.yarnpkg.com/react-navigation-stack/-/react-navigation-stack-2.10.2.tgz#9b6d38503496f9ef519acc6cad270ec0ace4ccbd"
|
resolved "https://registry.yarnpkg.com/react-navigation-stack/-/react-navigation-stack-2.10.2.tgz#9b6d38503496f9ef519acc6cad270ec0ace4ccbd"
|
||||||
@ -8755,10 +8731,10 @@ react-navigation@*, react-navigation@^4.4.3:
|
|||||||
"@react-navigation/core" "^3.7.9"
|
"@react-navigation/core" "^3.7.9"
|
||||||
"@react-navigation/native" "^3.8.3"
|
"@react-navigation/native" "^3.8.3"
|
||||||
|
|
||||||
react-query@^3.6.0:
|
react-query@^3.8.2:
|
||||||
version "3.6.0"
|
version "3.8.2"
|
||||||
resolved "https://registry.yarnpkg.com/react-query/-/react-query-3.6.0.tgz#3da307a4a4cb6ea95f9c95b7e50b5281d5244e4d"
|
resolved "https://registry.yarnpkg.com/react-query/-/react-query-3.8.2.tgz#e2dac76b5d9b3465d854f4ca040a35ba4bcae1ae"
|
||||||
integrity sha512-39ptLt4qaKO1DE+ta6SpPutweEgDvUQj/KlebC+okJ9Nxbs5ExxKV8RYlLeop6vdDFyiMmwYrt1POiF8oWGh1A==
|
integrity sha512-Ha8+WZLIHOUkKhqE4+2RZZB03WvEWmNhN4WIIw3zWVCtR7blo2n2TXtu+d3YhaY1o6dt+sHT+J+zNV8IzR583w==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime" "^7.5.5"
|
"@babel/runtime" "^7.5.5"
|
||||||
match-sorter "^6.0.2"
|
match-sorter "^6.0.2"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user