diff --git a/app/_layout.tsx b/app/_layout.tsx index c58362e..c12d147 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -24,6 +24,7 @@ import { NAV_THEME } from "~/lib/constants"; import { isBiometricSupported } from "~/lib/isBiometricSupported"; import { useAppStore } from "~/lib/state/appStore"; import { useColorScheme } from "~/lib/useColorScheme"; +import { registerForPushNotificationsAsync } from "~/services/Notifications"; const LIGHT_THEME: Theme = { ...DefaultTheme, @@ -68,6 +69,15 @@ export default function RootLayout() { } } + async function checkAndPromptForNotifications() { + const isEnabled = useAppStore.getState().isNotificationsEnabled; + // prompt the user to enable notifications on first open + if (isEnabled === null) { + const enabled = await registerForPushNotificationsAsync(); + useAppStore.getState().setNotificationsEnabled(enabled); + } + } + const loadTheme = React.useCallback((): Promise => { return new Promise((resolve) => { const theme = useAppStore.getState().theme; @@ -86,6 +96,7 @@ export default function RootLayout() { await Promise.all([loadTheme(), loadFonts(), checkBiometricStatus()]); } finally { setResourcesLoaded(true); + await checkAndPromptForNotifications(); SplashScreen.hide(); } }; diff --git a/lib/state/appStore.ts b/lib/state/appStore.ts index 147d29b..801440a 100644 --- a/lib/state/appStore.ts +++ b/lib/state/appStore.ts @@ -11,7 +11,7 @@ interface AppState { readonly wallets: Wallet[]; readonly addressBookEntries: AddressBookEntry[]; readonly isSecurityEnabled: boolean; - readonly isNotificationsEnabled: boolean; + readonly isNotificationsEnabled: boolean | null; readonly isOnboarded: boolean; readonly expoPushToken: string; readonly theme?: Theme; @@ -28,7 +28,7 @@ interface AppState { setFiatCurrency(fiatCurrency: string): void; setSelectedWalletId(walletId: number): void; setSecurityEnabled(securityEnabled: boolean): void; - setNotificationsEnabled(notificationsEnabled: boolean): void; + setNotificationsEnabled(notificationsEnabled: boolean | null): void; addWallet(wallet: Wallet): void; addAddressBookEntry(entry: AddressBookEntry): void; removeAddressBookEntry: (index: number) => void; @@ -196,8 +196,9 @@ export const useAppStore = create()((set, get) => { nwcClient: getNWCClient(initialSelectedWalletId), fiatCurrency: secureStorage.getItem(fiatCurrencyKey) || "", isSecurityEnabled, - isNotificationsEnabled: - secureStorage.getItem(isNotificationsEnabledKey) === "true", + isNotificationsEnabled: secureStorage.getItem(isNotificationsEnabledKey) + ? secureStorage.getItem(isNotificationsEnabledKey) === "true" + : null, theme, balanceDisplayMode, isOnboarded: secureStorage.getItem(hasOnboardedKey) === "true", @@ -239,7 +240,11 @@ export const useAppStore = create()((set, get) => { }); }, setNotificationsEnabled: (isEnabled) => { - secureStorage.setItem(isNotificationsEnabledKey, isEnabled.toString()); + if (isEnabled === null) { + secureStorage.removeItem(isNotificationsEnabledKey); + } else { + secureStorage.setItem(isNotificationsEnabledKey, isEnabled.toString()); + } set({ isNotificationsEnabled: isEnabled, }); diff --git a/pages/settings/Notifications.tsx b/pages/settings/Notifications.tsx index 60ac6ff..9d3bfab 100644 --- a/pages/settings/Notifications.tsx +++ b/pages/settings/Notifications.tsx @@ -22,11 +22,12 @@ export function Notifications() { { setLoading(true); - if (checked) { - checked = await registerForPushNotificationsAsync(); + let enabled: boolean | null = checked; + if (enabled) { + enabled = await registerForPushNotificationsAsync(); } else { const wallets = useAppStore.getState().wallets; for (const wallet of wallets) { @@ -35,7 +36,7 @@ export function Notifications() { await removeAllInfo(); useAppStore.getState().setExpoPushToken(""); } - useAppStore.getState().setNotificationsEnabled(checked); + useAppStore.getState().setNotificationsEnabled(enabled); setLoading(false); }} nativeID="security" diff --git a/services/Notifications.ts b/services/Notifications.ts index d9ab39f..74355af 100644 --- a/services/Notifications.ts +++ b/services/Notifications.ts @@ -7,7 +7,9 @@ import { errorToast } from "~/lib/errorToast"; import { registerWalletNotifications } from "~/lib/notifications"; import { useAppStore } from "~/lib/state/appStore"; -export async function registerForPushNotificationsAsync(): Promise { +export async function registerForPushNotificationsAsync(): Promise< + boolean | null +> { if (Platform.OS === "android") { ExpoNotifications.setNotificationChannelAsync("default", { name: "default", @@ -27,12 +29,13 @@ export async function registerForPushNotificationsAsync(): Promise { const { status } = await ExpoNotifications.requestPermissionsAsync(); finalStatus = status; } - if (finalStatus !== "granted") { - errorToast( - new Error( - "Permission not granted to get push token for push notification", - ), - ); + if (finalStatus === "undetermined") { + return null; + } + if (finalStatus === "denied") { + if (existingStatus === "denied") { + errorToast(new Error("Enable app notifications in device settings")); + } return false; } const projectId =