mirror of
				https://github.com/tooot-app/app
				synced 2025-06-05 22:19:13 +02:00 
			
		
		
		
	Basic notification working
This commit is contained in:
		| @@ -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" | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user