2021-02-28 17:41:21 +01:00
|
|
|
import apiInstance from '@api/instance'
|
2021-02-08 23:19:55 +01:00
|
|
|
import useWebsocket from '@api/websocket'
|
2021-01-30 01:29:15 +01:00
|
|
|
import haptics from '@components/haptics'
|
|
|
|
import Icon from '@components/Icon'
|
|
|
|
import {
|
|
|
|
BottomTabNavigationOptions,
|
|
|
|
createBottomTabNavigator
|
|
|
|
} from '@react-navigation/bottom-tabs'
|
|
|
|
import { NavigatorScreenParams } from '@react-navigation/native'
|
|
|
|
import { StackScreenProps } from '@react-navigation/stack'
|
2021-02-10 00:40:44 +01:00
|
|
|
import { useTimelineQuery } from '@utils/queryHooks/timeline'
|
2021-02-11 23:42:13 +01:00
|
|
|
import { getPreviousTab } from '@utils/slices/contextsSlice'
|
2021-01-30 01:29:15 +01:00
|
|
|
import {
|
2021-02-20 19:12:44 +01:00
|
|
|
getInstanceAccount,
|
|
|
|
getInstanceActive,
|
|
|
|
getInstanceNotification,
|
2021-02-28 17:41:21 +01:00
|
|
|
getInstances,
|
|
|
|
updateInstanceActive,
|
2021-02-20 19:12:44 +01:00
|
|
|
updateInstanceNotification
|
2021-01-30 01:29:15 +01:00
|
|
|
} from '@utils/slices/instancesSlice'
|
|
|
|
import { useTheme } from '@utils/styles/ThemeManager'
|
2021-02-28 17:41:21 +01:00
|
|
|
import * as Notifications from 'expo-notifications'
|
|
|
|
import { findIndex } from 'lodash'
|
|
|
|
import React, { useCallback, useEffect, useMemo } from 'react'
|
2021-01-30 01:29:15 +01:00
|
|
|
import { Platform } from 'react-native'
|
|
|
|
import FastImage from 'react-native-fast-image'
|
2021-02-10 00:40:44 +01:00
|
|
|
import { useDispatch, useSelector } from 'react-redux'
|
2021-01-30 01:29:15 +01:00
|
|
|
import TabLocal from './Tabs/Local'
|
|
|
|
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>
|
2021-01-31 03:09:35 +01:00
|
|
|
'Tab-Compose': NavigatorScreenParams<Nav.ScreenComposeStackParamList>
|
2021-01-30 01:29:15 +01:00
|
|
|
'Tab-Notifications': NavigatorScreenParams<Nav.TabNotificationsStackParamList>
|
|
|
|
'Tab-Me': NavigatorScreenParams<Nav.TabMeStackParamList>
|
|
|
|
}
|
|
|
|
|
|
|
|
export type ScreenTabsProp = StackScreenProps<
|
|
|
|
Nav.RootStackParamList,
|
|
|
|
'Screen-Tabs'
|
|
|
|
>
|
|
|
|
|
2021-02-28 17:41:21 +01:00
|
|
|
const convertNotificationToToot = (
|
|
|
|
navigation: any,
|
|
|
|
id: Mastodon.Notification['id']
|
|
|
|
) => {
|
|
|
|
apiInstance<Mastodon.Notification>({
|
|
|
|
method: 'get',
|
|
|
|
url: `notifications/${id}`
|
|
|
|
}).then(({ body }) => {
|
|
|
|
// @ts-ignore
|
|
|
|
navigation.navigate('Tab-Notifications', {
|
|
|
|
screen: 'Tab-Notifications-Root'
|
|
|
|
})
|
|
|
|
if (body.status) {
|
|
|
|
// @ts-ignore
|
|
|
|
navigation.navigate('Tab-Notifications', {
|
|
|
|
screen: 'Tab-Shared-Toot',
|
|
|
|
params: { toot: body.status }
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-01-30 01:29:15 +01:00
|
|
|
const Tab = createBottomTabNavigator<Nav.ScreenTabsStackParamList>()
|
|
|
|
|
2021-02-10 00:40:44 +01:00
|
|
|
const ScreenTabs = React.memo(
|
|
|
|
({ navigation }: ScreenTabsProp) => {
|
2021-02-28 17:41:21 +01:00
|
|
|
// Push notifications
|
|
|
|
const instances = useSelector(
|
|
|
|
getInstances,
|
|
|
|
(prev, next) => prev.length === next.length
|
|
|
|
)
|
|
|
|
const lastNotificationResponse = Notifications.useLastNotificationResponse()
|
|
|
|
useEffect(() => {
|
|
|
|
const subscription = Notifications.addNotificationResponseReceivedListener(
|
|
|
|
({ notification }) => {
|
|
|
|
const payloadData = notification.request.content.data as {
|
|
|
|
notification_id?: string
|
|
|
|
instanceUrl: string
|
|
|
|
accountId: string
|
|
|
|
}
|
|
|
|
|
|
|
|
const notificationIndex = findIndex(
|
|
|
|
instances,
|
|
|
|
instance =>
|
|
|
|
instance.url === payloadData.instanceUrl &&
|
|
|
|
instance.account.id === payloadData.accountId
|
|
|
|
)
|
|
|
|
if (notificationIndex !== -1) {
|
|
|
|
dispatch(updateInstanceActive(instances[notificationIndex]))
|
|
|
|
}
|
|
|
|
if (payloadData?.notification_id) {
|
|
|
|
convertNotificationToToot(
|
|
|
|
navigation,
|
|
|
|
notification.request.content.data.notification_id as string
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
return () => subscription.remove()
|
|
|
|
|
|
|
|
// if (
|
|
|
|
// lastNotificationResponse &&
|
|
|
|
// lastNotificationResponse.actionIdentifier ===
|
|
|
|
// Notifications.DEFAULT_ACTION_IDENTIFIER
|
|
|
|
// ) {
|
|
|
|
// const payloadData = lastNotificationResponse.notification.request
|
|
|
|
// .content.data as {
|
|
|
|
// notification_id?: string
|
|
|
|
// instanceUrl: string
|
|
|
|
// accountId: string
|
|
|
|
// }
|
|
|
|
|
|
|
|
// const notificationIndex = findIndex(
|
|
|
|
// instances,
|
|
|
|
// instance =>
|
|
|
|
// instance.url === payloadData.instanceUrl &&
|
|
|
|
// instance.account.id === payloadData.accountId
|
|
|
|
// )
|
|
|
|
// if (notificationIndex !== -1) {
|
|
|
|
// dispatch(updateInstanceActive(instances[notificationIndex]))
|
|
|
|
// }
|
|
|
|
// if (payloadData?.notification_id) {
|
|
|
|
// convertNotificationToToot(
|
|
|
|
// navigation,
|
|
|
|
// lastNotificationResponse.notification.request.content.data
|
|
|
|
// .notification_id as string
|
|
|
|
// )
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
}, [instances, lastNotificationResponse])
|
|
|
|
|
2021-02-11 23:42:13 +01:00
|
|
|
const { mode, theme } = useTheme()
|
2021-02-10 00:40:44 +01:00
|
|
|
const dispatch = useDispatch()
|
2021-02-20 19:12:44 +01:00
|
|
|
const instanceActive = useSelector(getInstanceActive)
|
2021-02-10 00:40:44 +01:00
|
|
|
const localAccount = useSelector(
|
2021-02-20 19:12:44 +01:00
|
|
|
getInstanceAccount,
|
2021-02-10 00:40:44 +01:00
|
|
|
(prev, next) => prev?.avatarStatic === next?.avatarStatic
|
|
|
|
)
|
2021-01-30 01:29:15 +01:00
|
|
|
|
2021-02-10 00:40:44 +01:00
|
|
|
const screenOptions = useCallback(
|
|
|
|
({ route }): BottomTabNavigationOptions => ({
|
2021-02-20 19:12:44 +01:00
|
|
|
tabBarVisible: instanceActive !== -1,
|
2021-02-10 00:40:44 +01:00
|
|
|
tabBarIcon: ({
|
|
|
|
focused,
|
|
|
|
color,
|
|
|
|
size
|
|
|
|
}: {
|
|
|
|
focused: boolean
|
|
|
|
color: string
|
|
|
|
size: number
|
|
|
|
}) => {
|
|
|
|
switch (route.name) {
|
|
|
|
case 'Tab-Local':
|
|
|
|
return <Icon name='Home' size={size} color={color} />
|
|
|
|
case 'Tab-Public':
|
|
|
|
return <Icon name='Globe' size={size} color={color} />
|
|
|
|
case 'Tab-Compose':
|
|
|
|
return <Icon name='Plus' size={size} color={color} />
|
|
|
|
case 'Tab-Notifications':
|
|
|
|
return <Icon name='Bell' size={size} color={color} />
|
|
|
|
case 'Tab-Me':
|
2021-02-20 19:12:44 +01:00
|
|
|
return instanceActive !== -1 ? (
|
2021-02-10 00:40:44 +01:00
|
|
|
<FastImage
|
|
|
|
source={{ uri: localAccount?.avatarStatic }}
|
|
|
|
style={{
|
|
|
|
width: size,
|
|
|
|
height: size,
|
|
|
|
borderRadius: size,
|
|
|
|
borderWidth: focused ? 2 : 0,
|
|
|
|
borderColor: focused ? theme.secondary : color
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
) : (
|
|
|
|
<Icon
|
|
|
|
name={focused ? 'Meh' : 'Smile'}
|
|
|
|
size={size}
|
|
|
|
color={!focused ? theme.secondary : color}
|
|
|
|
/>
|
|
|
|
)
|
|
|
|
default:
|
|
|
|
return <Icon name='AlertOctagon' size={size} color={color} />
|
|
|
|
}
|
2021-01-30 01:29:15 +01:00
|
|
|
}
|
2021-02-10 00:40:44 +01:00
|
|
|
}),
|
2021-02-20 19:12:44 +01:00
|
|
|
[instanceActive, localAccount?.avatarStatic]
|
2021-02-10 00:40:44 +01:00
|
|
|
)
|
|
|
|
const tabBarOptions = useMemo(
|
|
|
|
() => ({
|
|
|
|
activeTintColor: theme.primary,
|
2021-02-20 19:12:44 +01:00
|
|
|
inactiveTintColor: theme.secondary,
|
2021-02-10 00:40:44 +01:00
|
|
|
showLabel: false,
|
|
|
|
...(Platform.OS === 'android' && { keyboardHidesTabBar: true })
|
|
|
|
}),
|
2021-02-20 19:12:44 +01:00
|
|
|
[mode]
|
2021-02-10 00:40:44 +01:00
|
|
|
)
|
|
|
|
const composeListeners = useMemo(
|
|
|
|
() => ({
|
|
|
|
tabPress: (e: any) => {
|
2021-01-30 01:29:15 +01:00
|
|
|
e.preventDefault()
|
2021-02-20 19:12:44 +01:00
|
|
|
haptics('Light')
|
|
|
|
navigation.navigate('Screen-Compose')
|
2021-01-30 01:29:15 +01:00
|
|
|
}
|
2021-02-10 00:40:44 +01:00
|
|
|
}),
|
2021-02-20 19:12:44 +01:00
|
|
|
[]
|
2021-02-10 00:40:44 +01:00
|
|
|
)
|
|
|
|
const composeComponent = useCallback(() => null, [])
|
|
|
|
|
|
|
|
// On launch check if there is any unread noficiations
|
|
|
|
useTimelineQuery({
|
|
|
|
page: 'Notifications',
|
|
|
|
options: {
|
2021-02-20 19:12:44 +01:00
|
|
|
enabled: instanceActive !== -1,
|
2021-02-10 00:40:44 +01:00
|
|
|
notifyOnChangeProps: [],
|
|
|
|
select: data => {
|
2021-02-11 01:33:31 +01:00
|
|
|
if (data.pages[0].body.length) {
|
2021-02-10 00:40:44 +01:00
|
|
|
dispatch(
|
2021-02-20 19:12:44 +01:00
|
|
|
updateInstanceNotification({
|
2021-02-11 01:33:31 +01:00
|
|
|
// @ts-ignore
|
|
|
|
latestTime: data.pages[0].body[0].created_at
|
2021-02-10 00:40:44 +01:00
|
|
|
})
|
|
|
|
)
|
|
|
|
}
|
|
|
|
return data
|
2021-01-30 01:29:15 +01:00
|
|
|
}
|
|
|
|
}
|
2021-02-10 00:40:44 +01:00
|
|
|
})
|
|
|
|
useWebsocket({ stream: 'user', event: 'notification' })
|
|
|
|
const localNotification = useSelector(
|
2021-02-20 19:12:44 +01:00
|
|
|
getInstanceNotification,
|
2021-02-10 00:40:44 +01:00
|
|
|
(prev, next) =>
|
|
|
|
prev?.readTime === next?.readTime &&
|
|
|
|
prev?.latestTime === next?.latestTime
|
|
|
|
)
|
2021-01-30 01:29:15 +01:00
|
|
|
|
2021-02-20 19:12:44 +01:00
|
|
|
const previousTab = useSelector(getPreviousTab, () => true)
|
|
|
|
|
2021-02-10 00:40:44 +01:00
|
|
|
return (
|
|
|
|
<Tab.Navigator
|
2021-02-20 19:12:44 +01:00
|
|
|
initialRouteName={instanceActive !== -1 ? previousTab : 'Tab-Me'}
|
2021-02-10 00:40:44 +01:00
|
|
|
screenOptions={screenOptions}
|
|
|
|
tabBarOptions={tabBarOptions}
|
|
|
|
>
|
2021-02-20 19:12:44 +01:00
|
|
|
<Tab.Screen name='Tab-Local' component={TabLocal} />
|
2021-02-10 00:40:44 +01:00
|
|
|
<Tab.Screen name='Tab-Public' component={TabPublic} />
|
|
|
|
<Tab.Screen
|
|
|
|
name='Tab-Compose'
|
|
|
|
component={composeComponent}
|
|
|
|
listeners={composeListeners}
|
|
|
|
/>
|
|
|
|
<Tab.Screen
|
|
|
|
name='Tab-Notifications'
|
|
|
|
component={TabNotifications}
|
|
|
|
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
|
|
|
|
)
|
2021-01-30 01:29:15 +01:00
|
|
|
|
|
|
|
export default ScreenTabs
|