diff --git a/apps/wallet-mobile/.storybook/storybook.requires.js b/apps/wallet-mobile/.storybook/storybook.requires.js
index f593d32e88..7046d09d9b 100644
--- a/apps/wallet-mobile/.storybook/storybook.requires.js
+++ b/apps/wallet-mobile/.storybook/storybook.requires.js
@@ -75,6 +75,7 @@ const getStories = () => {
"./src/components/ExpandableInfoCard/ExpandableInfoCard.stories.tsx": require("../src/components/ExpandableInfoCard/ExpandableInfoCard.stories.tsx"),
"./src/components/HideableText/HideableText.stories.tsx": require("../src/components/HideableText/HideableText.stories.tsx"),
"./src/components/Icon/Icon.stories.tsx": require("../src/components/Icon/Icon.stories.tsx"),
+ "./src/components/InfoBanner/InfoBanner.stories.tsx": require("../src/components/InfoBanner/InfoBanner.stories.tsx"),
"./src/components/LanguagePicker/LanguagePicker.stories.tsx": require("../src/components/LanguagePicker/LanguagePicker.stories.tsx"),
"./src/components/LanguagePicker/LanguagePickerWarning.stories.tsx": require("../src/components/LanguagePicker/LanguagePickerWarning.stories.tsx"),
"./src/components/legacy/Modal/Modal.stories.tsx": require("../src/components/legacy/Modal/Modal.stories.tsx"),
diff --git a/apps/wallet-mobile/src/AppNavigator.tsx b/apps/wallet-mobile/src/AppNavigator.tsx
index 89f7e2c376..44e6691b4d 100644
--- a/apps/wallet-mobile/src/AppNavigator.tsx
+++ b/apps/wallet-mobile/src/AppNavigator.tsx
@@ -33,7 +33,6 @@ import {
import {useDeepLinkWatcher} from './features/Links/common/useDeepLinkWatcher'
import {useNotifications} from './features/Notifications/useCases/common/hooks'
import {NotificationsDevScreen} from './features/Notifications/useCases/NotificationsDevScreen'
-import {PortfolioScreen} from './features/Portfolio/useCases/PortfolioScreen'
import {SearchProvider} from './features/Search/SearchContext'
import {SetupWalletNavigator} from './features/SetupWallet/SetupWalletNavigator'
import {useHasWallets} from './features/WalletManager/common/hooks/useHasWallets'
@@ -206,8 +205,6 @@ export const AppNavigator = () => {
-
-
)}
diff --git a/apps/wallet-mobile/src/YoroiApp.tsx b/apps/wallet-mobile/src/YoroiApp.tsx
index 97c06b05aa..8404aa272d 100644
--- a/apps/wallet-mobile/src/YoroiApp.tsx
+++ b/apps/wallet-mobile/src/YoroiApp.tsx
@@ -28,6 +28,8 @@ import {useMigrations} from './kernel/storage/migrations/useMigrations'
import {rootStorage} from './kernel/storage/rootStorage'
import {PoolTransitionProvider} from './legacy/Staking/PoolTransition/PoolTransitionProvider'
import {useThemeStorageMaker} from './yoroi-wallets/hooks'
+import {NotificationProvider} from '@yoroi/notifications'
+import {notificationManager} from './features/Notifications/useCases/common/notification-manager'
enableScreens(true)
enableFreeze(true)
@@ -63,7 +65,9 @@ const Yoroi = () => {
-
+
+
+
diff --git a/apps/wallet-mobile/src/features/Notifications/useCases/NotificationsDevScreen.tsx b/apps/wallet-mobile/src/features/Notifications/useCases/NotificationsDevScreen.tsx
index 004b94f495..265ccf81e4 100644
--- a/apps/wallet-mobile/src/features/Notifications/useCases/NotificationsDevScreen.tsx
+++ b/apps/wallet-mobile/src/features/Notifications/useCases/NotificationsDevScreen.tsx
@@ -14,11 +14,11 @@ import {SafeAreaView} from 'react-native-safe-area-context'
import {Button} from '../../../components/Button/Button'
import {ScrollView} from '../../../components/ScrollView/ScrollView'
-import {useMockedNotifications} from './common/mocks'
import {createTransactionReceivedNotification} from './common/transaction-received-notification'
+import {notificationManager} from './common/notification-manager'
export const NotificationsDevScreen = () => {
- const {manager} = useMockedNotifications()
+ const manager = notificationManager
return (
@@ -30,7 +30,7 @@ const Screen = () => {
const manager = useNotificationManager()
const handleOnTriggerTransactionReceived = () => {
- manager.notification$.next(
+ manager.events.push(
createTransactionReceivedNotification({
previousTxsCounter: 0,
nextTxsCounter: 1,
diff --git a/apps/wallet-mobile/src/features/Notifications/useCases/common/hooks.ts b/apps/wallet-mobile/src/features/Notifications/useCases/common/hooks.ts
index 31f8d522e1..621b386082 100644
--- a/apps/wallet-mobile/src/features/Notifications/useCases/common/hooks.ts
+++ b/apps/wallet-mobile/src/features/Notifications/useCases/common/hooks.ts
@@ -1,12 +1,7 @@
import {Notification, Notifications} from '@jamsinclair/react-native-notifications'
-import {useAsyncStorage} from '@yoroi/common'
-import {notificationManagerMaker} from '@yoroi/notifications'
-import {Notifications as NotificationTypes} from '@yoroi/types'
-import * as React from 'react'
import {useEffect} from 'react'
-
-import {displayNotificationEvent} from './notifications'
-import {useTransactionReceivedNotificationSubject} from './transaction-received-notification'
+import {notificationManager} from './notification-manager'
+import {useTransactionReceivedNotifications} from './transaction-received-notification'
let initialized = false
@@ -21,51 +16,14 @@ const init = () => {
Notifications.events().registerNotificationReceivedBackground((notification: Notification) => {
console.log(`Notification received in background: ${notification.title} : ${notification.body}`)
})
-}
-
-export const useNotificationsManager = (options?: {
- subscriptions?: NotificationTypes.ManagerMakerProps['subscriptions']
-}) => {
- const storage = useAsyncStorage()
- const subscriptions = options?.subscriptions
-
- const manager = React.useMemo(() => {
- const eventsStorage = storage.join('events/')
- const configStorage = storage.join('settings/')
-
- return notificationManagerMaker({
- eventsStorage,
- configStorage,
- subscriptions,
- })
- }, [storage, subscriptions])
+ notificationManager.hydrate()
- React.useEffect(() => {
- manager.hydrate()
- return () => {
- manager.destroy()
- }
- }, [manager])
-
- return manager
+ return () => {
+ notificationManager.destroy()
+ }
}
export const useNotifications = () => {
- useEffect(() => {
- init()
- }, [])
-
- const transactionReceivedSubject = useTransactionReceivedNotificationSubject()
-
- const manager = useNotificationsManager({
- subscriptions: {
- [NotificationTypes.Trigger.TransactionReceived]: transactionReceivedSubject,
- },
- })
- React.useEffect(() => {
- const subscription = manager.notification$.subscribe(displayNotificationEvent)
- return () => {
- subscription.unsubscribe()
- }
- }, [manager])
+ useEffect(() => init(), [])
+ useTransactionReceivedNotifications()
}
diff --git a/apps/wallet-mobile/src/features/Notifications/useCases/common/mocks.ts b/apps/wallet-mobile/src/features/Notifications/useCases/common/mocks.ts
deleted file mode 100644
index 6c94b7f026..0000000000
--- a/apps/wallet-mobile/src/features/Notifications/useCases/common/mocks.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import {Notifications as NotificationTypes} from '@yoroi/types'
-import * as React from 'react'
-import {Subject} from 'rxjs'
-
-import {useNotificationsManager} from './hooks'
-import {displayNotificationEvent} from './notifications'
-import {createTransactionReceivedNotification} from './transaction-received-notification'
-
-export const useMockedNotifications = () => {
- const [transactionReceivedSubject] = React.useState(new Subject())
- const manager = useNotificationsManager({
- subscriptions: {
- [NotificationTypes.Trigger.TransactionReceived]: transactionReceivedSubject,
- },
- })
- React.useEffect(() => {
- const subscription = manager.notification$.subscribe(displayNotificationEvent)
- return () => {
- subscription.unsubscribe()
- }
- }, [manager])
-
- const triggerTransactionReceived = (metadata: NotificationTypes.TransactionReceivedEvent['metadata']) => {
- transactionReceivedSubject.next(createTransactionReceivedNotification(metadata))
- }
-
- return {triggerTransactionReceived, manager}
-}
diff --git a/apps/wallet-mobile/src/features/Notifications/useCases/common/notification-manager.ts b/apps/wallet-mobile/src/features/Notifications/useCases/common/notification-manager.ts
index eeb7b1286d..b8a1db6349 100644
--- a/apps/wallet-mobile/src/features/Notifications/useCases/common/notification-manager.ts
+++ b/apps/wallet-mobile/src/features/Notifications/useCases/common/notification-manager.ts
@@ -1,9 +1,16 @@
-import {mountAsyncStorage} from '@yoroi/common/src'
+import {mountAsyncStorage} from '@yoroi/common'
import {notificationManagerMaker} from '@yoroi/notifications'
+import {displayNotificationEvent} from './notifications'
+import {Notifications} from '@yoroi/types'
+import {transactionReceivedSubject} from './transaction-received-notification'
const appStorage = mountAsyncStorage({path: '/'})
export const notificationManager = notificationManagerMaker({
eventsStorage: appStorage.join('events/'),
configStorage: appStorage.join('settings/'),
+ display: displayNotificationEvent,
+ subscriptions: {
+ [Notifications.Trigger.TransactionReceived]: transactionReceivedSubject,
+ },
})
diff --git a/apps/wallet-mobile/src/features/Notifications/useCases/common/notifications.ts b/apps/wallet-mobile/src/features/Notifications/useCases/common/notifications.ts
index 4677d3581b..6cda39ffb9 100644
--- a/apps/wallet-mobile/src/features/Notifications/useCases/common/notifications.ts
+++ b/apps/wallet-mobile/src/features/Notifications/useCases/common/notifications.ts
@@ -8,7 +8,7 @@ export const displayNotificationEvent = (notificationEvent: NotificationTypes.Ev
}
}
-export const sendNotification = (title: string, body: string) => {
+const sendNotification = (title: string, body: string) => {
const notification = new Notification({
title,
body,
diff --git a/apps/wallet-mobile/src/features/Notifications/useCases/common/transaction-received-notification.ts b/apps/wallet-mobile/src/features/Notifications/useCases/common/transaction-received-notification.ts
index 0289b028d8..d18e9f1585 100644
--- a/apps/wallet-mobile/src/features/Notifications/useCases/common/transaction-received-notification.ts
+++ b/apps/wallet-mobile/src/features/Notifications/useCases/common/transaction-received-notification.ts
@@ -11,27 +11,19 @@ import {YoroiWallet} from '../../../../yoroi-wallets/cardano/types'
import {useWalletManager} from '../../../WalletManager/context/WalletManagerProvider'
import {WalletManager, walletManager} from '../../../WalletManager/wallet-manager'
import {notificationManager} from './notification-manager'
-import {displayNotificationEvent} from './notifications'
const BACKGROUND_FETCH_TASK = 'yoroi-notifications-background-fetch'
if (!TaskManager.isTaskDefined(BACKGROUND_FETCH_TASK)) {
const appStorage = mountAsyncStorage({path: '/'})
-
TaskManager.defineTask(BACKGROUND_FETCH_TASK, async () => {
- const now = Date.now()
- console.log(`Got background fetch call at date: ${new Date(now).toISOString()}`)
-
await syncAllWallets(walletManager)
- await checkForNewTransactions(walletManager, appStorage)
-
- // TODO: Be sure to return the correct result type!
- return BackgroundFetch.BackgroundFetchResult.NewData
+ const notifications = await checkForNewTransactions(walletManager, appStorage)
+ notifications.forEach((notification) => notificationManager.events.push(notification))
+ const hasNewData = notifications.length > 0
+ return hasNewData ? BackgroundFetch.BackgroundFetchResult.NewData : BackgroundFetch.BackgroundFetchResult.NoData
})
}
-// 2. Register the task at some point in your app by providing the same name,
-// and some configuration options for how the background fetch should behave
-// Note: This does NOT need to be in the global scope and CAN be used in your React components!
export async function registerBackgroundFetchAsync() {
return BackgroundFetch.registerTaskAsync(BACKGROUND_FETCH_TASK, {
minimumInterval: 60 * 10, // 10 minutes
@@ -61,26 +53,29 @@ const syncAllWallets = async (walletManager: WalletManager) => {
export const checkForNewTransactions = async (walletManager: WalletManager, appStorage: App.Storage) => {
const walletIds = [...walletManager.walletMetas.keys()]
const notificationsAsyncStorage = appStorage.join('notifications-transaction-received-subject/')
+ const notifications: NotificationTypes.TransactionReceivedEvent[] = []
for (const id of walletIds) {
const wallet = walletManager.getWalletById(id)
- if (!wallet) return
+ if (!wallet) continue
const processed = (await notificationsAsyncStorage.getItem(id)) || []
const txIds = getTxIds(wallet)
- // TODO: Improve this
if (processed.length === 0) {
console.log(`Wallet ${id} has no processed tx ids`)
await notificationsAsyncStorage.setItem(id, txIds)
- return
+ continue
}
+
const newTxIds = txIds.filter((txId) => !processed.includes(txId))
+
if (newTxIds.length === 0) {
console.log(`Wallet ${id} has no new tx ids on network ${wallet.networkManager.network}`)
- return
+ continue
}
console.log('new tx ids', newTxIds)
await notificationsAsyncStorage.setItem(id, [...processed, ...newTxIds])
+
newTxIds.forEach((id) => {
const metadata: NotificationTypes.TransactionReceivedEvent['metadata'] = {
txId: id,
@@ -88,11 +83,11 @@ export const checkForNewTransactions = async (walletManager: WalletManager, appS
nextTxsCounter: 1,
previousTxsCounter: 0,
}
- const notification = createTransactionReceivedNotification(metadata)
- notificationManager.events.save(notification)
- displayNotificationEvent(notification)
+ notifications.push(createTransactionReceivedNotification(metadata))
})
}
+
+ return notifications
}
const getTxIds = (wallet: YoroiWallet) => {
@@ -112,10 +107,11 @@ export const createTransactionReceivedNotification = (
} as const
}
-export const useTransactionReceivedNotificationSubject = () => {
+export const transactionReceivedSubject = new Subject()
+
+export const useTransactionReceivedNotifications = () => {
const {walletManager} = useWalletManager()
const asyncStorage = useAsyncStorage()
- const [transactionReceivedSubject] = React.useState(new Subject())
React.useEffect(() => {
registerBackgroundFetchAsync()
@@ -131,7 +127,8 @@ export const useTransactionReceivedNotificationSubject = () => {
const areAllDone = walletsDoneSyncing.length === walletInfos.length
if (!areAllDone) return
- await checkForNewTransactions(walletManager, asyncStorage)
+ const notifications = await checkForNewTransactions(walletManager, asyncStorage)
+ notifications.forEach((notification) => transactionReceivedSubject.next(notification))
})
return () => {
diff --git a/apps/wallet-mobile/translations/messages/src/AppNavigator.json b/apps/wallet-mobile/translations/messages/src/AppNavigator.json
index 8902a072e3..6e8d9c302b 100644
--- a/apps/wallet-mobile/translations/messages/src/AppNavigator.json
+++ b/apps/wallet-mobile/translations/messages/src/AppNavigator.json
@@ -4,14 +4,14 @@
"defaultMessage": "!!!Enter PIN",
"file": "src/AppNavigator.tsx",
"start": {
- "line": 230,
+ "line": 235,
"column": 17,
- "index": 8390
+ "index": 8675
},
"end": {
- "line": 233,
+ "line": 238,
"column": 3,
- "index": 8480
+ "index": 8765
}
},
{
@@ -19,14 +19,14 @@
"defaultMessage": "!!!Set PIN",
"file": "src/AppNavigator.tsx",
"start": {
- "line": 234,
+ "line": 239,
"column": 18,
- "index": 8500
+ "index": 8785
},
"end": {
- "line": 237,
+ "line": 242,
"column": 3,
- "index": 8598
+ "index": 8883
}
},
{
@@ -34,14 +34,14 @@
"defaultMessage": "!!!Auth with OS changes",
"file": "src/AppNavigator.tsx",
"start": {
- "line": 238,
+ "line": 243,
"column": 25,
- "index": 8625
+ "index": 8910
},
"end": {
- "line": 241,
+ "line": 246,
"column": 3,
- "index": 8739
+ "index": 9024
}
},
{
@@ -49,14 +49,14 @@
"defaultMessage": "!!!Auth with OS changed detected",
"file": "src/AppNavigator.tsx",
"start": {
- "line": 242,
+ "line": 247,
"column": 27,
- "index": 8768
+ "index": 9053
},
"end": {
- "line": 245,
+ "line": 250,
"column": 3,
- "index": 8889
+ "index": 9174
}
}
]
\ No newline at end of file
diff --git a/packages/notifications/src/notification-manager.ts b/packages/notifications/src/notification-manager.ts
index e01a131e9c..efd3699832 100644
--- a/packages/notifications/src/notification-manager.ts
+++ b/packages/notifications/src/notification-manager.ts
@@ -7,11 +7,11 @@ type ConfigStorageData = Notifications.Config
const getAllTriggers = (): Array =>
Object.values(Notifications.Trigger)
-// TODO: Add handler to show notification
export const notificationManagerMaker = ({
eventsStorage,
configStorage,
subscriptions,
+ display,
}: Notifications.ManagerMakerProps): Notifications.Manager => {
const localSubscriptions: Subscription[] = []
@@ -31,6 +31,7 @@ export const notificationManagerMaker = ({
const {events, unreadCounterByGroup$, notification$} = eventsManagerMaker({
storage: eventsStorage,
config,
+ display,
})
const clear = async () => {
@@ -72,7 +73,9 @@ const notificationTriggerGroups: Record<
const eventsManagerMaker = ({
storage,
config,
+ display,
}: {
+ display: (event: Notifications.Event) => void
storage: App.Storage
config: Notifications.Manager['config']
}): {
@@ -120,8 +123,7 @@ const eventsManagerMaker = ({
read: async (): Promise => {
return (await storage.getItem('events')) ?? []
},
- save: async (event: Readonly) => {
- // TODO: Maybe rename to notify
+ push: async (event: Readonly) => {
if (!shouldNotify(event, await config.read())) {
return
}
@@ -130,6 +132,7 @@ const eventsManagerMaker = ({
if (!event.isRead) {
await updateUnreadCounter()
notification$.next(event)
+ display(event)
}
},
clear: async (): Promise => {
diff --git a/packages/types/src/notifications/manager.ts b/packages/types/src/notifications/manager.ts
index de74784da8..4214207535 100644
--- a/packages/types/src/notifications/manager.ts
+++ b/packages/types/src/notifications/manager.ts
@@ -13,6 +13,7 @@ export type NotificationManagerMakerProps = {
subscriptions?: Partial<
Record>
>
+ display: (event: NotificationEvent) => void
}
export interface NotificationTransactionReceivedEvent
@@ -78,7 +79,7 @@ export type NotificationManager = {
markAllAsRead: () => Promise
markAsRead(id: NotificationEventId): Promise
read: () => Promise>
- save: (event: Readonly) => Promise
+ push: (event: Readonly) => Promise
clear: () => Promise
}
// Config sets the ground to what, when, and if should notify user