mirror of
https://github.com/tooot-app/app
synced 2025-02-24 15:47:41 +01:00
Basic notification working
This commit is contained in:
parent
4eea2bf58c
commit
78898059cb
@ -118,6 +118,7 @@
|
|||||||
"react-navigation": "^4.4.3",
|
"react-navigation": "^4.4.3",
|
||||||
"react-navigation-stack": "^2.10.2",
|
"react-navigation-stack": "^2.10.2",
|
||||||
"react-test-renderer": "^16.13.1",
|
"react-test-renderer": "^16.13.1",
|
||||||
"typescript": "~4.1.3"
|
"typescript": "~4.1.3",
|
||||||
|
"uri-scheme": "^1.0.67"
|
||||||
}
|
}
|
||||||
}
|
}
|
2
src/@types/react-navigation.d.ts
vendored
2
src/@types/react-navigation.d.ts
vendored
@ -71,7 +71,7 @@ declare namespace Nav {
|
|||||||
'Tab-Local': undefined
|
'Tab-Local': undefined
|
||||||
'Tab-Public': undefined
|
'Tab-Public': undefined
|
||||||
'Tab-Compose': undefined
|
'Tab-Compose': undefined
|
||||||
'Tab-Notifications': { id?: Mastodon.Notification['id'] }
|
'Tab-Notifications': undefined
|
||||||
'Tab-Me': undefined
|
'Tab-Me': undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,18 +8,17 @@ import ScreenAnnouncements from '@screens/Announcements'
|
|||||||
import ScreenCompose from '@screens/Compose'
|
import ScreenCompose from '@screens/Compose'
|
||||||
import ScreenImagesViewer from '@screens/ImagesViewer'
|
import ScreenImagesViewer from '@screens/ImagesViewer'
|
||||||
import ScreenTabs from '@screens/Tabs'
|
import ScreenTabs from '@screens/Tabs'
|
||||||
import { useAnnouncementQuery } from '@utils/queryHooks/announcement'
|
|
||||||
import { updatePreviousTab } from '@utils/slices/contextsSlice'
|
import { updatePreviousTab } from '@utils/slices/contextsSlice'
|
||||||
|
import { connectInstancesPush } from '@utils/slices/instances/connectPush'
|
||||||
import { updateAccountPreferences } from '@utils/slices/instances/updateAccountPreferences'
|
import { updateAccountPreferences } from '@utils/slices/instances/updateAccountPreferences'
|
||||||
import { getInstanceActive } from '@utils/slices/instancesSlice'
|
import { getInstanceActive } from '@utils/slices/instancesSlice'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import { themes } from '@utils/styles/themes'
|
import { themes } from '@utils/styles/themes'
|
||||||
import * as Analytics from 'expo-firebase-analytics'
|
import * as Analytics from 'expo-firebase-analytics'
|
||||||
import * as Notifications from 'expo-notifications'
|
|
||||||
import { addScreenshotListener } from 'expo-screen-capture'
|
import { addScreenshotListener } from 'expo-screen-capture'
|
||||||
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 { Alert, Linking, Platform, StatusBar } from 'react-native'
|
import { Alert, Platform, StatusBar } from 'react-native'
|
||||||
import { createNativeStackNavigator } from 'react-native-screens/native-stack'
|
import { createNativeStackNavigator } from 'react-native-screens/native-stack'
|
||||||
import Toast from 'react-native-toast-message'
|
import Toast from 'react-native-toast-message'
|
||||||
import { useDispatch, useSelector } from 'react-redux'
|
import { useDispatch, useSelector } from 'react-redux'
|
||||||
@ -27,35 +26,6 @@ import * as Sentry from 'sentry-expo'
|
|||||||
|
|
||||||
const Stack = createNativeStackNavigator<Nav.RootStackParamList>()
|
const Stack = createNativeStackNavigator<Nav.RootStackParamList>()
|
||||||
|
|
||||||
const linking = {
|
|
||||||
prefixes: ['tooot://', 'https://tooot.app'],
|
|
||||||
config: {
|
|
||||||
screens: {
|
|
||||||
'Screen-Tabs': {
|
|
||||||
screens: {
|
|
||||||
'Tab-Notifications': 'push/:id'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
subscribe (listener: (arg0: string) => any) {
|
|
||||||
const onReceiveURL = ({ url }: { url: string }) => listener(url)
|
|
||||||
Linking.addEventListener('url', onReceiveURL)
|
|
||||||
const subscription = Notifications.addNotificationResponseReceivedListener(
|
|
||||||
response => {
|
|
||||||
const url = response.notification.request.content.data.url
|
|
||||||
console.log(url)
|
|
||||||
url && typeof url === 'string' && listener(url)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
Linking.removeEventListener('url', onReceiveURL)
|
|
||||||
subscription.remove()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
localCorrupt?: string
|
localCorrupt?: string
|
||||||
}
|
}
|
||||||
@ -87,6 +57,11 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
|
|||||||
// }
|
// }
|
||||||
// }, [isConnected, firstRender])
|
// }, [isConnected, firstRender])
|
||||||
|
|
||||||
|
// Update Expo Token to server
|
||||||
|
useEffect(() => {
|
||||||
|
dispatch(connectInstancesPush())
|
||||||
|
}, [])
|
||||||
|
|
||||||
// Prevent screenshot alert
|
// Prevent screenshot alert
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const screenshotListener = addScreenshotListener(() =>
|
const screenshotListener = addScreenshotListener(() =>
|
||||||
@ -116,23 +91,6 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
|
|||||||
return showLocalCorrect()
|
return showLocalCorrect()
|
||||||
}, [localCorrupt])
|
}, [localCorrupt])
|
||||||
|
|
||||||
// On launch check if there is any unread announcements
|
|
||||||
useAnnouncementQuery({
|
|
||||||
showAll: false,
|
|
||||||
options: {
|
|
||||||
notifyOnChangeProps: [],
|
|
||||||
select: announcements =>
|
|
||||||
announcements.filter(announcement => !announcement.read),
|
|
||||||
onSuccess: data => {
|
|
||||||
if (data.length) {
|
|
||||||
navigationRef.current?.navigate('Screen-Announcements', {
|
|
||||||
showAll: false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Lazily update users's preferences, for e.g. composing default visibility
|
// Lazily update users's preferences, for e.g. composing default visibility
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (instanceActive !== -1) {
|
if (instanceActive !== -1) {
|
||||||
@ -175,7 +133,6 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
|
|||||||
theme={themes[mode]}
|
theme={themes[mode]}
|
||||||
onReady={navigationContainerOnReady}
|
onReady={navigationContainerOnReady}
|
||||||
onStateChange={navigationContainerOnStateChange}
|
onStateChange={navigationContainerOnStateChange}
|
||||||
linking={linking}
|
|
||||||
>
|
>
|
||||||
<Stack.Navigator initialRouteName='Screen-Tabs'>
|
<Stack.Navigator initialRouteName='Screen-Tabs'>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
|
@ -6,7 +6,10 @@ import * as WebBrowser from 'expo-web-browser'
|
|||||||
const openLink = async (url: string) => {
|
const openLink = async (url: string) => {
|
||||||
switch (getSettingsBrowser(store.getState())) {
|
switch (getSettingsBrowser(store.getState())) {
|
||||||
case 'internal':
|
case 'internal':
|
||||||
await WebBrowser.openBrowserAsync(url)
|
await WebBrowser.openBrowserAsync(url, {
|
||||||
|
dismissButtonStyle: 'close',
|
||||||
|
enableBarCollapsing: true
|
||||||
|
})
|
||||||
break
|
break
|
||||||
case 'external':
|
case 'external':
|
||||||
await Linking.openURL(url)
|
await Linking.openURL(url)
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import apiInstance from '@api/instance'
|
||||||
import useWebsocket from '@api/websocket'
|
import useWebsocket from '@api/websocket'
|
||||||
import haptics from '@components/haptics'
|
import haptics from '@components/haptics'
|
||||||
import Icon from '@components/Icon'
|
import Icon from '@components/Icon'
|
||||||
@ -13,10 +14,14 @@ import {
|
|||||||
getInstanceAccount,
|
getInstanceAccount,
|
||||||
getInstanceActive,
|
getInstanceActive,
|
||||||
getInstanceNotification,
|
getInstanceNotification,
|
||||||
|
getInstances,
|
||||||
|
updateInstanceActive,
|
||||||
updateInstanceNotification
|
updateInstanceNotification
|
||||||
} from '@utils/slices/instancesSlice'
|
} from '@utils/slices/instancesSlice'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import React, { useCallback, useMemo } from 'react'
|
import * as Notifications from 'expo-notifications'
|
||||||
|
import { findIndex } from 'lodash'
|
||||||
|
import React, { useCallback, useEffect, 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 { useDispatch, useSelector } from 'react-redux'
|
import { useDispatch, useSelector } from 'react-redux'
|
||||||
@ -38,10 +43,97 @@ export type ScreenTabsProp = StackScreenProps<
|
|||||||
'Screen-Tabs'
|
'Screen-Tabs'
|
||||||
>
|
>
|
||||||
|
|
||||||
|
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 }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const Tab = createBottomTabNavigator<Nav.ScreenTabsStackParamList>()
|
const Tab = createBottomTabNavigator<Nav.ScreenTabsStackParamList>()
|
||||||
|
|
||||||
const ScreenTabs = React.memo(
|
const ScreenTabs = React.memo(
|
||||||
({ navigation }: ScreenTabsProp) => {
|
({ navigation }: ScreenTabsProp) => {
|
||||||
|
// 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])
|
||||||
|
|
||||||
const { mode, theme } = useTheme()
|
const { mode, theme } = useTheme()
|
||||||
const dispatch = useDispatch()
|
const dispatch = useDispatch()
|
||||||
const instanceActive = useSelector(getInstanceActive)
|
const instanceActive = useSelector(getInstanceActive)
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
import Timeline from '@components/Timeline'
|
import Timeline from '@components/Timeline'
|
||||||
|
import TimelineDefault from '@components/Timeline/Default'
|
||||||
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
||||||
import React from 'react'
|
import React, { useCallback } from 'react'
|
||||||
|
|
||||||
const ScreenMeBookmarks = React.memo(
|
const ScreenMeBookmarks = React.memo(
|
||||||
() => {
|
() => {
|
||||||
const queryKey: QueryKeyTimeline = ['Timeline', { page: 'Bookmarks' }]
|
const queryKey: QueryKeyTimeline = ['Timeline', { page: 'Bookmarks' }]
|
||||||
|
const renderItem = useCallback(
|
||||||
return <Timeline queryKey={queryKey} />
|
({ item }) => <TimelineDefault item={item} queryKey={queryKey} />,
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
return <Timeline queryKey={queryKey} customProps={{ renderItem }} />
|
||||||
},
|
},
|
||||||
() => true
|
() => true
|
||||||
)
|
)
|
||||||
|
@ -1,12 +1,17 @@
|
|||||||
import Timeline from '@components/Timeline'
|
import Timeline from '@components/Timeline'
|
||||||
|
import TimelineDefault from '@components/Timeline/Default'
|
||||||
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
||||||
import React from 'react'
|
import React, { useCallback } from 'react'
|
||||||
|
|
||||||
const ScreenMeFavourites = React.memo(
|
const ScreenMeFavourites = React.memo(
|
||||||
() => {
|
() => {
|
||||||
const queryKey: QueryKeyTimeline = ['Timeline', { page: 'Favourites' }]
|
const queryKey: QueryKeyTimeline = ['Timeline', { page: 'Favourites' }]
|
||||||
|
const renderItem = useCallback(
|
||||||
|
({ item }) => <TimelineDefault item={item} queryKey={queryKey} />,
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
|
||||||
return <Timeline queryKey={queryKey} />
|
return <Timeline queryKey={queryKey} customProps={{ renderItem }} />
|
||||||
},
|
},
|
||||||
() => true
|
() => true
|
||||||
)
|
)
|
||||||
|
@ -1,18 +1,17 @@
|
|||||||
import { MenuRow } from '@components/Menu'
|
import { MenuRow } from '@components/Menu'
|
||||||
import TimelineEmpty from '@components/Timeline/Empty'
|
|
||||||
import { StackScreenProps } from '@react-navigation/stack'
|
import { StackScreenProps } from '@react-navigation/stack'
|
||||||
import { useListsQuery } from '@utils/queryHooks/lists'
|
import { useListsQuery } from '@utils/queryHooks/lists'
|
||||||
import React, { useMemo } from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
const ScreenMeLists: React.FC<StackScreenProps<
|
const ScreenMeLists: React.FC<StackScreenProps<
|
||||||
Nav.TabMeStackParamList,
|
Nav.TabMeStackParamList,
|
||||||
'Tab-Me-Switch'
|
'Tab-Me-Lists'
|
||||||
>> = ({ navigation }) => {
|
>> = ({ navigation }) => {
|
||||||
const { status, data, refetch } = useListsQuery({})
|
const { data } = useListsQuery({})
|
||||||
|
|
||||||
const children = useMemo(() => {
|
return (
|
||||||
if (status === 'success') {
|
<>
|
||||||
return data?.map((d: Mastodon.List, i: number) => (
|
{data?.map((d: Mastodon.List, i: number) => (
|
||||||
<MenuRow
|
<MenuRow
|
||||||
key={i}
|
key={i}
|
||||||
iconFront='List'
|
iconFront='List'
|
||||||
@ -24,13 +23,9 @@ const ScreenMeLists: React.FC<StackScreenProps<
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
))
|
))}
|
||||||
} else {
|
</>
|
||||||
return <TimelineEmpty status={status} refetch={refetch} />
|
)
|
||||||
}
|
|
||||||
}, [status])
|
|
||||||
|
|
||||||
return <>{children}</>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ScreenMeLists
|
export default ScreenMeLists
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
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 { useAnnouncementQuery } from '@utils/queryHooks/announcement'
|
import { useAnnouncementQuery } from '@utils/queryHooks/announcement'
|
||||||
|
import { useListsQuery } from '@utils/queryHooks/lists'
|
||||||
import React, { useMemo } from 'react'
|
import React, { useMemo } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
@ -8,26 +9,54 @@ const Collections: React.FC = () => {
|
|||||||
const { t, i18n } = useTranslation('meRoot')
|
const { t, i18n } = useTranslation('meRoot')
|
||||||
const navigation = useNavigation()
|
const navigation = useNavigation()
|
||||||
|
|
||||||
const { data, isFetching } = useAnnouncementQuery({
|
const listsQuery = useListsQuery({
|
||||||
showAll: true
|
options: {
|
||||||
})
|
notifyOnChangeProps: []
|
||||||
|
|
||||||
const announcementContent = useMemo(() => {
|
|
||||||
if (data) {
|
|
||||||
if (data.length === 0) {
|
|
||||||
return t('content.collections.announcements.content.empty')
|
|
||||||
} else {
|
|
||||||
const amount = data.filter(announcement => !announcement.read).length
|
|
||||||
if (amount) {
|
|
||||||
return t('content.collections.announcements.content.unread', {
|
|
||||||
amount
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
return t('content.collections.announcements.content.read')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}, [data, i18n.language])
|
})
|
||||||
|
const rowLists = useMemo(() => {
|
||||||
|
if (listsQuery.isSuccess && listsQuery.data?.length) {
|
||||||
|
return (
|
||||||
|
<MenuRow
|
||||||
|
iconFront='List'
|
||||||
|
iconBack='ChevronRight'
|
||||||
|
title={t('content.collections.lists')}
|
||||||
|
onPress={() => navigation.navigate('Tab-Me-Lists')}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}, [listsQuery.isSuccess, listsQuery.data, i18n.language])
|
||||||
|
|
||||||
|
const announcementsQuery = useAnnouncementQuery({
|
||||||
|
showAll: true,
|
||||||
|
options: {
|
||||||
|
notifyOnChangeProps: []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const rowAnnouncements = useMemo(() => {
|
||||||
|
if (announcementsQuery.isSuccess && announcementsQuery.data?.length) {
|
||||||
|
const amount = announcementsQuery.data.filter(
|
||||||
|
announcement => !announcement.read
|
||||||
|
).length
|
||||||
|
return (
|
||||||
|
<MenuRow
|
||||||
|
iconFront='Clipboard'
|
||||||
|
iconBack='ChevronRight'
|
||||||
|
title={t('content.collections.announcements.heading')}
|
||||||
|
content={
|
||||||
|
amount
|
||||||
|
? t('content.collections.announcements.content.unread', {
|
||||||
|
amount
|
||||||
|
})
|
||||||
|
: t('content.collections.announcements.content.read')
|
||||||
|
}
|
||||||
|
onPress={() =>
|
||||||
|
navigation.navigate('Screen-Announcements', { showAll: true })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}, [announcementsQuery.isSuccess, announcementsQuery.data, i18n.language])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MenuContainer>
|
<MenuContainer>
|
||||||
@ -49,24 +78,8 @@ const Collections: React.FC = () => {
|
|||||||
title={t('content.collections.favourites')}
|
title={t('content.collections.favourites')}
|
||||||
onPress={() => navigation.navigate('Tab-Me-Favourites')}
|
onPress={() => navigation.navigate('Tab-Me-Favourites')}
|
||||||
/>
|
/>
|
||||||
<MenuRow
|
{rowLists}
|
||||||
iconFront='List'
|
{rowAnnouncements}
|
||||||
iconBack='ChevronRight'
|
|
||||||
title={t('content.collections.lists')}
|
|
||||||
onPress={() => navigation.navigate('Tab-Me-Lists')}
|
|
||||||
/>
|
|
||||||
<MenuRow
|
|
||||||
iconFront='Clipboard'
|
|
||||||
iconBack={data && data.length === 0 ? undefined : 'ChevronRight'}
|
|
||||||
title={t('content.collections.announcements.heading')}
|
|
||||||
content={announcementContent}
|
|
||||||
loading={isFetching}
|
|
||||||
onPress={() =>
|
|
||||||
data &&
|
|
||||||
data.length &&
|
|
||||||
navigation.navigate('Screen-Announcements', { showAll: true })
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</MenuContainer>
|
</MenuContainer>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -43,32 +43,32 @@ const TabNotifications = React.memo(
|
|||||||
<Timeline
|
<Timeline
|
||||||
queryKey={queryKey}
|
queryKey={queryKey}
|
||||||
customProps={{
|
customProps={{
|
||||||
renderItem,
|
renderItem
|
||||||
viewabilityConfigCallbackPairs: [
|
// viewabilityConfigCallbackPairs: [
|
||||||
{
|
// {
|
||||||
onViewableItemsChanged: ({
|
// onViewableItemsChanged: ({
|
||||||
viewableItems
|
// viewableItems
|
||||||
}: {
|
// }: {
|
||||||
viewableItems: ViewToken[]
|
// viewableItems: ViewToken[]
|
||||||
}) => {
|
// }) => {
|
||||||
if (
|
// if (
|
||||||
navigation.isFocused() &&
|
// navigation.isFocused() &&
|
||||||
viewableItems.length &&
|
// viewableItems.length &&
|
||||||
viewableItems[0].index === 0
|
// viewableItems[0].index === 0
|
||||||
) {
|
// ) {
|
||||||
dispatch(
|
// dispatch(
|
||||||
updateInstanceNotification({
|
// updateInstanceNotification({
|
||||||
readTime: viewableItems[0].item.created_at
|
// readTime: viewableItems[0].item.created_at
|
||||||
})
|
// })
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
viewabilityConfig: {
|
// viewabilityConfig: {
|
||||||
minimumViewTime: 100,
|
// minimumViewTime: 100,
|
||||||
itemVisiblePercentThreshold: 60
|
// itemVisiblePercentThreshold: 60
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
]
|
// ]
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
|
34
src/utils/slices/instances/connectPush.ts
Normal file
34
src/utils/slices/instances/connectPush.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import apiGeneral from '@api/general'
|
||||||
|
import { createAsyncThunk } from '@reduxjs/toolkit'
|
||||||
|
import { RootState } from '@root/store'
|
||||||
|
import * as Notifications from 'expo-notifications'
|
||||||
|
import { PUSH_SERVER } from '../instancesSlice'
|
||||||
|
|
||||||
|
export const connectInstancesPush = createAsyncThunk(
|
||||||
|
'instances/connectPush',
|
||||||
|
async (_, { getState }): Promise<any> => {
|
||||||
|
const state = getState() as RootState
|
||||||
|
const pushEnabled = state.instances.instances.filter(
|
||||||
|
instance => instance.push.global.value
|
||||||
|
)
|
||||||
|
|
||||||
|
if (pushEnabled.length) {
|
||||||
|
const expoToken = (
|
||||||
|
await Notifications.getExpoPushTokenAsync({
|
||||||
|
experienceId: '@xmflsct/tooot'
|
||||||
|
})
|
||||||
|
).data
|
||||||
|
|
||||||
|
return apiGeneral({
|
||||||
|
method: 'post',
|
||||||
|
domain: PUSH_SERVER,
|
||||||
|
url: 'v1/connect',
|
||||||
|
body: {
|
||||||
|
expoToken
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return Promise.resolve()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
@ -10286,6 +10286,11 @@ uri-js@^4.2.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
punycode "^2.1.0"
|
punycode "^2.1.0"
|
||||||
|
|
||||||
|
uri-scheme@^1.0.67:
|
||||||
|
version "1.0.67"
|
||||||
|
resolved "https://registry.yarnpkg.com/uri-scheme/-/uri-scheme-1.0.67.tgz#a18c8752489967783eb94784b9d08adaf124d9eb"
|
||||||
|
integrity sha512-q0xH1d4w3fMaEJfpmA+mXN+L9fzV8bBZz96llWLG4TXO98vbMeXptDhvasQP30y/okwsQnO5gbVYJmeZW2OWIw==
|
||||||
|
|
||||||
urix@^0.1.0:
|
urix@^0.1.0:
|
||||||
version "0.1.0"
|
version "0.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
|
resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user