diff --git a/app/App.tsx b/app/App.tsx index 98bd2d896..d6000e2b4 100644 --- a/app/App.tsx +++ b/app/App.tsx @@ -6,10 +6,11 @@ import { YStack } from 'tamagui'; import ErrorBoundary from './src/components/ErrorBoundary'; import AppNavigation from './src/navigation'; +import { AuthProvider } from './src/providers/authProvider'; +import { DatabaseProvider } from './src/providers/databaseProvider'; +import { NotificationTrackingProvider } from './src/providers/notificationTrackingProvider'; +import { PassportProvider } from './src/providers/passportDataProvider'; import { initSentry, wrapWithSentry } from './src/Sentry'; -import { AuthProvider } from './src/stores/authProvider'; -import { DatabaseProvider } from './src/stores/databaseProvider'; -import { PassportProvider } from './src/stores/passportDataProvider'; initSentry(); @@ -22,7 +23,9 @@ function App(): React.JSX.Element { - + + + diff --git a/app/android/app/build.gradle b/app/android/app/build.gradle index 8adf156c5..c1ba63a2f 100644 --- a/app/android/app/build.gradle +++ b/app/android/app/build.gradle @@ -47,11 +47,11 @@ react { // extraPackagerArgs = [] /* Hermes Commands */ - // The hermes compiler command to run. By default it is 'hermesc' - // hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc" - // - // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map" - // hermesFlags = ["-O", "-output-source-map"] + // The hermes compiler command to run. By default it is 'hermesc' + hermesCommand = "../node_modules/react-native/sdks/hermesc/osx-bin/hermesc" + + // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map" + hermesFlags = ["-O", "-output-source-map"] /* Autolinking */ autolinkLibrariesWithApp() @@ -86,7 +86,7 @@ android { applicationId "com.proofofpassportapp" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 66 + versionCode 67 versionName "2.5.2" externalNativeBuild { cmake { diff --git a/app/fastlane/Fastfile b/app/fastlane/Fastfile index 74fd97f86..7b2af4acd 100644 --- a/app/fastlane/Fastfile +++ b/app/fastlane/Fastfile @@ -257,7 +257,7 @@ platform :android do Fastlane::Helpers.with_retry(max_retries: 3, delay: 10) do gradle( - task: "clean bundleRelease", + task: "clean bundleRelease --stacktrace --info", project_dir: "android/", properties: { "android.injected.signing.store.file" => ENV["ANDROID_KEYSTORE_PATH"], diff --git a/app/ios/OpenPassport/AppDelegate.mm b/app/ios/OpenPassport/AppDelegate.mm index ef53149e0..ee123aefe 100644 --- a/app/ios/OpenPassport/AppDelegate.mm +++ b/app/ios/OpenPassport/AppDelegate.mm @@ -13,10 +13,21 @@ { [FIRApp configure]; - if ([UNUserNotificationCenter class] != nil) { - UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; - center.delegate = self; - } + // TODO: Uncomment this after the APN has been configured + // if ([UNUserNotificationCenter class] != nil) { + // UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; + // center.delegate = self; + + // // Request permission for notifications + // [center requestAuthorizationWithOptions:(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge) + // completionHandler:^(BOOL granted, NSError * _Nullable error) { + // if (granted) { + // dispatch_async(dispatch_get_main_queue(), ^{ + // [[UIApplication sharedApplication] registerForRemoteNotifications]; + // }); + // } + // }]; + // } self.moduleName = @"OpenPassport"; self.initialProps = @{}; diff --git a/app/ios/Podfile.lock b/app/ios/Podfile.lock index 0a1b46eb3..0b3ad6b7a 100644 --- a/app/ios/Podfile.lock +++ b/app/ios/Podfile.lock @@ -1811,9 +1811,9 @@ PODS: - segment-analytics-react-native (2.21.0): - React-Core - sovran-react-native - - Sentry (8.52.0): - - Sentry/Core (= 8.52.0) - - Sentry/Core (8.52.0) + - Sentry (8.52.1): + - Sentry/Core (= 8.52.1) + - Sentry/Core (8.52.1) - Sentry/HybridSDK (8.48.0) - SentryPrivate (8.21.0) - SocketRocket (0.7.0) diff --git a/app/ios/Self.xcodeproj/project.pbxproj b/app/ios/Self.xcodeproj/project.pbxproj index ef9d12a0b..620e404ad 100644 --- a/app/ios/Self.xcodeproj/project.pbxproj +++ b/app/ios/Self.xcodeproj/project.pbxproj @@ -427,7 +427,7 @@ CODE_SIGN_ENTITLEMENTS = OpenPassport/OpenPassportDebug.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 127; + CURRENT_PROJECT_VERSION = 128; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 5B29R5LYHQ; ENABLE_BITCODE = NO; @@ -565,7 +565,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = OpenPassport/OpenPassport.entitlements; - CURRENT_PROJECT_VERSION = 127; + CURRENT_PROJECT_VERSION = 128; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 5B29R5LYHQ; FRAMEWORK_SEARCH_PATHS = ( diff --git a/app/package.json b/app/package.json index dc43dd5bc..9d9206e95 100644 --- a/app/package.json +++ b/app/package.json @@ -16,9 +16,14 @@ "bump-version:major": "npm version major && yarn sync-versions", "bump-version:minor": "npm version minor && yarn sync-versions", "bump-version:patch": "npm version patch && yarn sync-versions", - "clean": "watchman watch-del-all && rm -rf ../node_modules ios/Pods ios/build android/app/build android/build ../.yarn/cache ios/.xcode.env.local", + "clean": "yarn clean:watchman && yarn clean:build && yarn clean:ios && yarn clean:android && yarn clean:xcode && yarn clean:pod-cache && yarn clean:node", "clean:android": "rm -rf android/app/build android/build", - "clean:ios": "rm -rf ios/Pods ios/build", + "clean:build": "rm -rf ios/build android/app/build android/build", + "clean:ios": "rm -rf ios/Pods ios/Podfile.lock", + "clean:node": "rm -rf ../node_modules app/node_modules", + "clean:pod-cache": "cd ios && pod cache clean --all && cd ..", + "clean:watchman": "watchman watch-del-all", + "clean:xcode": "rm -rf ~/Library/Developer/Xcode/DerivedData", "clean:xcode-env-local": "rm -f ios/.xcode.env.local", "fmt": "prettier --check .", "fmt:fix": "prettier --write .", diff --git a/app/src/consts/analytics.ts b/app/src/consts/analytics.ts index bffa2af40..e8af73ab2 100644 --- a/app/src/consts/analytics.ts +++ b/app/src/consts/analytics.ts @@ -6,6 +6,13 @@ export const AppEvents = { UPDATE_STARTED: 'App: Update Started', }; +export const NotificationEvents = { + BACKGROUND_NOTIFICATION_OPENED: + 'Notification: Background Notification Opened', + COLD_START_NOTIFICATION_OPENED: + 'Notification: Cold Start Notification Opened', +}; + export const AuthEvents = { AUTHENTICATION_TIMEOUT: 'Auth: Authentication Timeout', BIOMETRIC_AUTH_FAILED: 'Auth: Biometric Auth Failed', diff --git a/app/src/hooks/useMnemonic.ts b/app/src/hooks/useMnemonic.ts index 967bb408c..935d66899 100644 --- a/app/src/hooks/useMnemonic.ts +++ b/app/src/hooks/useMnemonic.ts @@ -1,7 +1,7 @@ import { ethers } from 'ethers'; import { useCallback, useState } from 'react'; -import { useAuth } from '../stores/authProvider'; +import { useAuth } from '../providers/authProvider'; export default function useMnemonic() { const { getOrCreateMnemonic } = useAuth(); diff --git a/app/src/stores/authProvider.tsx b/app/src/providers/authProvider.tsx similarity index 100% rename from app/src/stores/authProvider.tsx rename to app/src/providers/authProvider.tsx diff --git a/app/src/stores/databaseProvider.tsx b/app/src/providers/databaseProvider.tsx similarity index 86% rename from app/src/stores/databaseProvider.tsx rename to app/src/providers/databaseProvider.tsx index 751d481e7..30e54e2d4 100644 --- a/app/src/stores/databaseProvider.tsx +++ b/app/src/providers/databaseProvider.tsx @@ -1,6 +1,6 @@ import React, { createContext, useEffect } from 'react'; -import { useProofHistoryStore } from './proofHistoryStore'; +import { useProofHistoryStore } from '../stores/proofHistoryStore'; export const DatabaseContext = createContext(null); diff --git a/app/src/providers/notificationTrackingProvider.tsx b/app/src/providers/notificationTrackingProvider.tsx new file mode 100644 index 000000000..79e16baa0 --- /dev/null +++ b/app/src/providers/notificationTrackingProvider.tsx @@ -0,0 +1,41 @@ +import messaging from '@react-native-firebase/messaging'; +import React, { PropsWithChildren, useEffect } from 'react'; + +import { NotificationEvents } from '../consts/analytics'; +import analytics from '../utils/analytics'; + +const { trackEvent } = analytics(); + +export const NotificationTrackingProvider: React.FC = ({ + children, +}) => { + useEffect(() => { + const unsubscribe = messaging().onNotificationOpenedApp(remoteMessage => { + trackEvent(NotificationEvents.BACKGROUND_NOTIFICATION_OPENED, { + messageId: remoteMessage.messageId, + // Only track notification type/category if available + type: remoteMessage.data?.type, + // Track if user interacted with any actions + actionId: remoteMessage.data?.actionId, + }); + }); + + messaging() + .getInitialNotification() + .then(remoteMessage => { + if (remoteMessage) { + trackEvent(NotificationEvents.COLD_START_NOTIFICATION_OPENED, { + messageId: remoteMessage.messageId, + // Only track notification type/category if available + type: remoteMessage.data?.type, + // Track if user interacted with any actions + actionId: remoteMessage.data?.actionId, + }); + } + }); + + return unsubscribe; + }, []); + + return <>{children}; +}; diff --git a/app/src/stores/passportDataProvider.tsx b/app/src/providers/passportDataProvider.tsx similarity index 98% rename from app/src/stores/passportDataProvider.tsx rename to app/src/providers/passportDataProvider.tsx index ac80c7fa1..d6c088f68 100644 --- a/app/src/stores/passportDataProvider.tsx +++ b/app/src/providers/passportDataProvider.tsx @@ -11,7 +11,7 @@ import React, { } from 'react'; import Keychain from 'react-native-keychain'; -import { unsafe_getPrivateKey } from '../stores/authProvider'; +import { unsafe_getPrivateKey } from '../providers/authProvider'; import { useAuth } from './authProvider'; // TODO: refactor this as it shouldnt be used directly IMHO diff --git a/app/src/screens/dev/DevSettingsScreen.tsx b/app/src/screens/dev/DevSettingsScreen.tsx index 8c1da7729..2f471eb8e 100644 --- a/app/src/screens/dev/DevSettingsScreen.tsx +++ b/app/src/screens/dev/DevSettingsScreen.tsx @@ -25,11 +25,11 @@ import { RootStackParamList } from '../../navigation'; import { unsafe_clearSecrets, unsafe_getPrivateKey, -} from '../../stores/authProvider'; +} from '../../providers/authProvider'; import { storePassportData, usePassport, -} from '../../stores/passportDataProvider'; +} from '../../providers/passportDataProvider'; import { borderColor, textBlack } from '../../utils/colors'; interface DevSettingsScreenProps extends PropsWithChildren { diff --git a/app/src/screens/dev/MockDataScreen.tsx b/app/src/screens/dev/MockDataScreen.tsx index 8376d7ee6..b1aaf05a9 100644 --- a/app/src/screens/dev/MockDataScreen.tsx +++ b/app/src/screens/dev/MockDataScreen.tsx @@ -29,7 +29,7 @@ import ButtonsContainer from '../../components/ButtonsContainer'; import { BodyText } from '../../components/typography/BodyText'; import { Title } from '../../components/typography/Title'; import { MockDataEvents } from '../../consts/analytics'; -import { storePassportData } from '../../stores/passportDataProvider'; +import { storePassportData } from '../../providers/passportDataProvider'; import analytics from '../../utils/analytics'; import { borderColor, diff --git a/app/src/screens/dev/MockDataScreenDeepLink.tsx b/app/src/screens/dev/MockDataScreenDeepLink.tsx index 84f3b9d40..e91c911e1 100644 --- a/app/src/screens/dev/MockDataScreenDeepLink.tsx +++ b/app/src/screens/dev/MockDataScreenDeepLink.tsx @@ -14,7 +14,7 @@ import { BodyText } from '../../components/typography/BodyText'; import Description from '../../components/typography/Description'; import { Title } from '../../components/typography/Title'; import { MockDataEvents } from '../../consts/analytics'; -import { storePassportData } from '../../stores/passportDataProvider'; +import { storePassportData } from '../../providers/passportDataProvider'; import useUserStore from '../../stores/userStore'; import { black, borderColor, white } from '../../utils/colors'; diff --git a/app/src/screens/misc/LoadingScreen.tsx b/app/src/screens/misc/LoadingScreen.tsx index ade17b0fe..4f85b15f1 100644 --- a/app/src/screens/misc/LoadingScreen.tsx +++ b/app/src/screens/misc/LoadingScreen.tsx @@ -15,7 +15,7 @@ import CloseWarningIcon from '../../images/icons/close-warning.svg'; import { clearPassportData, loadPassportDataAndSecret, -} from '../../stores/passportDataProvider'; +} from '../../providers/passportDataProvider'; import analytics from '../../utils/analytics'; import { black, slate400, white, zinc500, zinc900 } from '../../utils/colors'; import { advercase, dinot } from '../../utils/fonts'; diff --git a/app/src/screens/misc/SplashScreen.tsx b/app/src/screens/misc/SplashScreen.tsx index 1fcc6219a..9a0f182b0 100644 --- a/app/src/screens/misc/SplashScreen.tsx +++ b/app/src/screens/misc/SplashScreen.tsx @@ -5,8 +5,8 @@ import React, { useCallback, useEffect, useRef } from 'react'; import { StyleSheet } from 'react-native'; import splashAnimation from '../../assets/animations/splash.json'; -import { useAuth } from '../../stores/authProvider'; -import { loadPassportDataAndSecret } from '../../stores/passportDataProvider'; +import { useAuth } from '../../providers/authProvider'; +import { loadPassportDataAndSecret } from '../../providers/passportDataProvider'; import { useProtocolStore } from '../../stores/protocolStore'; import { useSettingStore } from '../../stores/settingStore'; import { black } from '../../utils/colors'; diff --git a/app/src/screens/passport/PassportNFCScanScreen.tsx b/app/src/screens/passport/PassportNFCScanScreen.tsx index 7136a8374..6d9e7fd1f 100644 --- a/app/src/screens/passport/PassportNFCScanScreen.tsx +++ b/app/src/screens/passport/PassportNFCScanScreen.tsx @@ -31,7 +31,7 @@ import { PassportEvents } from '../../consts/analytics'; import useHapticNavigation from '../../hooks/useHapticNavigation'; import NFC_IMAGE from '../../images/nfc.png'; import { ExpandableBottomLayout } from '../../layouts/ExpandableBottomLayout'; -import { storePassportData } from '../../stores/passportDataProvider'; +import { storePassportData } from '../../providers/passportDataProvider'; import useUserStore from '../../stores/userStore'; import analytics from '../../utils/analytics'; import { black, slate100, white } from '../../utils/colors'; diff --git a/app/src/screens/recovery/AccountRecoveryChoiceScreen.tsx b/app/src/screens/recovery/AccountRecoveryChoiceScreen.tsx index 09424f703..85892aef3 100644 --- a/app/src/screens/recovery/AccountRecoveryChoiceScreen.tsx +++ b/app/src/screens/recovery/AccountRecoveryChoiceScreen.tsx @@ -12,11 +12,11 @@ import useHapticNavigation from '../../hooks/useHapticNavigation'; import Keyboard from '../../images/icons/keyboard.svg'; import RestoreAccountSvg from '../../images/icons/restore_account.svg'; import { ExpandableBottomLayout } from '../../layouts/ExpandableBottomLayout'; -import { useAuth } from '../../stores/authProvider'; +import { useAuth } from '../../providers/authProvider'; import { loadPassportDataAndSecret, reStorePassportDataWithRightCSCA, -} from '../../stores/passportDataProvider'; +} from '../../providers/passportDataProvider'; import { useSettingStore } from '../../stores/settingStore'; import analytics from '../../utils/analytics'; import { STORAGE_NAME, useBackupMnemonic } from '../../utils/cloudBackup'; diff --git a/app/src/screens/recovery/RecoverWithPhraseScreen.tsx b/app/src/screens/recovery/RecoverWithPhraseScreen.tsx index 7d074e13c..f4d6e0ab5 100644 --- a/app/src/screens/recovery/RecoverWithPhraseScreen.tsx +++ b/app/src/screens/recovery/RecoverWithPhraseScreen.tsx @@ -8,11 +8,11 @@ import { Text, TextArea, View, XStack, YStack } from 'tamagui'; import { SecondaryButton } from '../../components/buttons/SecondaryButton'; import Description from '../../components/typography/Description'; import Paste from '../../images/icons/paste.svg'; -import { useAuth } from '../../stores/authProvider'; +import { useAuth } from '../../providers/authProvider'; import { loadPassportDataAndSecret, reStorePassportDataWithRightCSCA, -} from '../../stores/passportDataProvider'; +} from '../../providers/passportDataProvider'; import { black, slate300, diff --git a/app/src/screens/settings/CloudBackupScreen.tsx b/app/src/screens/settings/CloudBackupScreen.tsx index 5b14a2281..e37d48160 100644 --- a/app/src/screens/settings/CloudBackupScreen.tsx +++ b/app/src/screens/settings/CloudBackupScreen.tsx @@ -13,7 +13,7 @@ import { useModal } from '../../hooks/useModal'; import Cloud from '../../images/icons/logo_cloud_backup.svg'; import { ExpandableBottomLayout } from '../../layouts/ExpandableBottomLayout'; import { RootStackParamList } from '../../navigation'; -import { useAuth } from '../../stores/authProvider'; +import { useAuth } from '../../providers/authProvider'; import { useSettingStore } from '../../stores/settingStore'; import analytics from '../../utils/analytics'; import { STORAGE_NAME, useBackupMnemonic } from '../../utils/cloudBackup'; diff --git a/app/src/screens/settings/PassportDataInfoScreen.tsx b/app/src/screens/settings/PassportDataInfoScreen.tsx index 7152c9451..13699ff71 100644 --- a/app/src/screens/settings/PassportDataInfoScreen.tsx +++ b/app/src/screens/settings/PassportDataInfoScreen.tsx @@ -5,7 +5,7 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { ScrollView, Separator, XStack, YStack } from 'tamagui'; import { Caption } from '../../components/typography/Caption'; -import { usePassport } from '../../stores/passportDataProvider'; +import { usePassport } from '../../providers/passportDataProvider'; import { black, slate200, white } from '../../utils/colors'; import { extraYPadding } from '../../utils/constants'; diff --git a/app/src/utils/proving/provingMachine.ts b/app/src/utils/proving/provingMachine.ts index a63735e9a..d45fc7bb9 100644 --- a/app/src/utils/proving/provingMachine.ts +++ b/app/src/utils/proving/provingMachine.ts @@ -13,7 +13,7 @@ import { clearPassportData, loadPassportDataAndSecret, reStorePassportDataWithRightCSCA, -} from '../../stores/passportDataProvider'; +} from '../../providers/passportDataProvider'; import { useProtocolStore } from '../../stores/protocolStore'; import { useSelfAppStore } from '../../stores/selfAppStore'; import { getPublicKey, verifyAttestation } from './attest';