diff --git a/.changeset/wise-jars-add.md b/.changeset/wise-jars-add.md
new file mode 100644
index 000000000..5e5432568
--- /dev/null
+++ b/.changeset/wise-jars-add.md
@@ -0,0 +1,5 @@
+---
+"@alephium/mobile-wallet": patch
+---
+
+Fix authentication issues
diff --git a/apps/mobile-wallet/src/features/auto-lock/useAutoLock.tsx b/apps/mobile-wallet/src/features/auto-lock/useAutoLock.tsx
index e27fb99be..d673c06da 100644
--- a/apps/mobile-wallet/src/features/auto-lock/useAutoLock.tsx
+++ b/apps/mobile-wallet/src/features/auto-lock/useAutoLock.tsx
@@ -17,20 +17,15 @@ along with the library. If not, see .
*/
import { appBecameInactive } from '@alephium/shared'
-import { useCallback, useEffect, useRef, useState } from 'react'
+import { useEffect, useRef, useState } from 'react'
import { AppState, AppStateStatus } from 'react-native'
import BackgroundTimer from 'react-native-background-timer'
import { useAppDispatch, useAppSelector } from '~/hooks/redux'
-interface UseAutoLockProps {
- unlockApp: () => Promise
- onAuthRequired: () => void
-}
-
let lockTimer: number | undefined
-const useAutoLock = ({ unlockApp, onAuthRequired }: UseAutoLockProps) => {
+const useAutoLock = (unlockApp: () => Promise) => {
const appState = useRef('active')
const settingsLoadedFromStorage = useAppSelector((s) => s.settings.loadedFromStorage)
const isCameraOpen = useAppSelector((s) => s.app.isCameraOpen)
@@ -41,12 +36,6 @@ const useAutoLock = ({ unlockApp, onAuthRequired }: UseAutoLockProps) => {
const [isAppStateChangeCallbackRegistered, setIsAppStateChangeCallbackRegistered] = useState(false)
- const lockApp = useCallback(() => {
- if (biometricsRequiredForAppAccess) onAuthRequired()
-
- dispatch(appBecameInactive())
- }, [biometricsRequiredForAppAccess, dispatch, onAuthRequired])
-
useEffect(() => {
if (!settingsLoadedFromStorage) return
@@ -54,12 +43,12 @@ const useAutoLock = ({ unlockApp, onAuthRequired }: UseAutoLockProps) => {
if (autoLockSeconds !== -1) {
if (nextAppState === 'background' && isWalletUnlocked && !isCameraOpen) {
if (autoLockSeconds === 0) {
- lockApp()
+ dispatch(appBecameInactive())
} else {
clearBackgroundTimer()
lockTimer = BackgroundTimer.setTimeout(() => {
if (lockTimer) {
- lockApp()
+ dispatch(appBecameInactive())
}
}, autoLockSeconds * 1000)
}
@@ -70,6 +59,8 @@ const useAutoLock = ({ unlockApp, onAuthRequired }: UseAutoLockProps) => {
unlockApp()
}
}
+ } else if (nextAppState === 'active' && !isWalletUnlocked) {
+ unlockApp()
}
appState.current = nextAppState
@@ -91,7 +82,6 @@ const useAutoLock = ({ unlockApp, onAuthRequired }: UseAutoLockProps) => {
isAppStateChangeCallbackRegistered,
isCameraOpen,
isWalletUnlocked,
- lockApp,
settingsLoadedFromStorage,
unlockApp
])
diff --git a/apps/mobile-wallet/src/navigation/RootStackNavigation.tsx b/apps/mobile-wallet/src/navigation/RootStackNavigation.tsx
index 525d9d52a..a6ac0636e 100644
--- a/apps/mobile-wallet/src/navigation/RootStackNavigation.tsx
+++ b/apps/mobile-wallet/src/navigation/RootStackNavigation.tsx
@@ -140,12 +140,11 @@ export default RootStackNavigation
const AppUnlockModal = () => {
const dispatch = useAppDispatch()
const isWalletUnlocked = useAppSelector((s) => s.wallet.isUnlocked)
+ const biometricsRequiredForAppAccess = useAppSelector((s) => s.settings.usesBiometrics)
const navigation = useNavigation>()
const { triggerBiometricsAuthGuard } = useBiometricsAuthGuard()
const { t } = useTranslation()
- const [isAuthModalVisible, setIsAuthModalVisible] = useState(false)
-
const { width, height } = Dimensions.get('window')
const [dimensions, setDimensions] = useState({ width, height })
@@ -155,10 +154,6 @@ const AppUnlockModal = () => {
setDimensions({ width, height })
}
- const openAuthModal = useCallback(() => {
- setIsAuthModalVisible(true)
- }, [])
-
const initializeAppWithStoredWallet = useCallback(async () => {
try {
dispatch(walletUnlocked(await getStoredWallet()))
@@ -168,8 +163,6 @@ const AppUnlockModal = () => {
if (!lastRoute || ['LandingScreen', 'LoginWithPinScreen'].includes(lastRoute)) {
resetNavigation(navigation)
}
-
- setIsAuthModalVisible(false)
} catch (error) {
const message = 'Could not initialize app with stored wallet'
showExceptionToast(error, message)
@@ -188,7 +181,6 @@ const AppUnlockModal = () => {
try {
await triggerBiometricsAuthGuard({
settingsToCheck: 'appAccess',
- onPromptDisplayed: openAuthModal,
successCallback: initializeAppWithStoredWallet
})
@@ -252,23 +244,16 @@ const AppUnlockModal = () => {
showExceptionToast(e, t('Could not unlock app'))
}
}
- }, [
- dispatch,
- initializeAppWithStoredWallet,
- isWalletUnlocked,
- navigation,
- openAuthModal,
- t,
- triggerBiometricsAuthGuard
- ])
+ }, [dispatch, initializeAppWithStoredWallet, isWalletUnlocked, navigation, t, triggerBiometricsAuthGuard])
- useAutoLock({
- unlockApp,
- onAuthRequired: openAuthModal
- })
+ useAutoLock(unlockApp)
return (
-
+
diff --git a/apps/mobile-wallet/src/screens/LandingScreen.tsx b/apps/mobile-wallet/src/screens/LandingScreen.tsx
index feb2dde0f..01ed24de7 100644
--- a/apps/mobile-wallet/src/screens/LandingScreen.tsx
+++ b/apps/mobile-wallet/src/screens/LandingScreen.tsx
@@ -16,9 +16,10 @@ You should have received a copy of the GNU Lesser General Public License
along with the library. If not, see .
*/
+import { useFocusEffect } from '@react-navigation/native'
import { StackScreenProps } from '@react-navigation/stack'
import { Canvas, RadialGradient, Rect, vec } from '@shopify/react-native-skia'
-import { useEffect, useState } from 'react'
+import { useCallback, useEffect, useState } from 'react'
import { Trans, useTranslation } from 'react-i18next'
import { AppState, Dimensions, Image, LayoutChangeEvent, Platform, StatusBar } from 'react-native'
import Animated, {
@@ -37,7 +38,7 @@ import styled, { ThemeProvider, useTheme } from 'styled-components/native'
import AppText from '~/components/AppText'
import Button from '~/components/buttons/Button'
import Screen, { ScreenProps } from '~/components/layout/Screen'
-import { useAppDispatch } from '~/hooks/redux'
+import { useAppDispatch, useAppSelector } from '~/hooks/redux'
import altLogoSrc from '~/images/logos/alephiumHackLogo.png'
import AlephiumLogo from '~/images/logos/AlephiumLogo'
import RootStackParamList from '~/navigation/rootStackRoutes'
@@ -46,6 +47,7 @@ import { methodSelected, WalletGenerationMethod } from '~/store/walletGeneration
import { BORDER_RADIUS_BIG, BORDER_RADIUS_HUGE } from '~/style/globalStyle'
import { themes } from '~/style/themes'
import { showExceptionToast } from '~/utils/layout'
+import { resetNavigation } from '~/utils/navigation'
interface LandingScreenProps extends StackScreenProps, ScreenProps {}
@@ -57,11 +59,25 @@ const LandingScreen = ({ navigation, ...props }: LandingScreenProps) => {
const insets = useSafeAreaInsets()
const theme = useTheme()
const { t } = useTranslation()
+ const isWalletUnlocked = useAppSelector((s) => s.wallet.isUnlocked)
const { width, height } = Dimensions.get('window')
const [dimensions, setDimensions] = useState({ width, height })
const [showNewWalletButtons, setShowNewWalletButtons] = useState(false)
+ // Normally, when the app is unlocked, this screen is not in focus. However, under certain conditions we end up with
+ // an unlocked wallet and no screen in focus at all. This happens when:
+ // 1. the auto-lock is set to anything but "Fast"
+ // 2. the user manually kills the app before the auto-lock timer completes
+ // 3. the WalletConnect feature is activated
+ // Since there is no screen in focus and since the default screen set in the RootStackNavigation is this screen, we
+ // need to navigate back to the dashboard.
+ useFocusEffect(
+ useCallback(() => {
+ if (isWalletUnlocked) resetNavigation(navigation)
+ }, [isWalletUnlocked, navigation])
+ )
+
useEffect(() => {
const unsubscribeBlurListener = navigation.addListener('blur', () => {
StatusBar.setBarStyle(theme.name === 'light' ? 'dark-content' : 'light-content')
diff --git a/patches/react-native-background-actions@3.0.1.patch b/patches/react-native-background-actions@3.0.1.patch
index 5d18a95fe..bda7e3472 100644
--- a/patches/react-native-background-actions@3.0.1.patch
+++ b/patches/react-native-background-actions@3.0.1.patch
@@ -10,7 +10,7 @@ index b67ef4d1837363489a1749acb852997a6c93c1b5..6aa30a826c2f17a35ccd30b64291d3d2
-
-+
++
diff --git a/android/src/main/java/com/asterinet/react/bgactions/RNBackgroundActionsTask.java b/android/src/main/java/com/asterinet/react/bgactions/RNBackgroundActionsTask.java
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index cfcc3c524..883f85fa0 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -30,7 +30,7 @@ patchedDependencies:
hash: sm7rpv6bikakdvmsl6ekayqewu
path: patches/react-native-aes-crypto@2.1.1.patch
react-native-background-actions@3.0.1:
- hash: 3u44z2aocqips4ucm32wcdde3y
+ hash: bczt4hbkdy2a6n4hvzyilx3qg4
path: patches/react-native-background-actions@3.0.1.patch
importers:
@@ -746,7 +746,7 @@ importers:
version: 2.1.1(patch_hash=sm7rpv6bikakdvmsl6ekayqewu)
react-native-background-actions:
specifier: ^3.0.1
- version: 3.0.1(patch_hash=3u44z2aocqips4ucm32wcdde3y)(react-native@0.74.2(@babel/core@7.24.7)(@babel/preset-env@7.23.8(@babel/core@7.24.7))(@types/react@18.2.79)(react@18.2.0))
+ version: 3.0.1(patch_hash=bczt4hbkdy2a6n4hvzyilx3qg4)(react-native@0.74.2(@babel/core@7.24.7)(@babel/preset-env@7.23.8(@babel/core@7.24.7))(@types/react@18.2.79)(react@18.2.0))
react-native-background-timer:
specifier: ^2.4.1
version: 2.4.1(react-native@0.74.2(@babel/core@7.24.7)(@babel/preset-env@7.23.8(@babel/core@7.24.7))(@types/react@18.2.79)(react@18.2.0))
@@ -21740,7 +21740,7 @@ snapshots:
react-native-aes-crypto@2.1.1(patch_hash=sm7rpv6bikakdvmsl6ekayqewu): {}
- react-native-background-actions@3.0.1(patch_hash=3u44z2aocqips4ucm32wcdde3y)(react-native@0.74.2(@babel/core@7.24.7)(@babel/preset-env@7.23.8(@babel/core@7.24.7))(@types/react@18.2.79)(react@18.2.0)):
+ react-native-background-actions@3.0.1(patch_hash=bczt4hbkdy2a6n4hvzyilx3qg4)(react-native@0.74.2(@babel/core@7.24.7)(@babel/preset-env@7.23.8(@babel/core@7.24.7))(@types/react@18.2.79)(react@18.2.0)):
dependencies:
eventemitter3: 4.0.7
react-native: 0.74.2(@babel/core@7.24.7)(@babel/preset-env@7.23.8(@babel/core@7.24.7))(@types/react@18.2.79)(react@18.2.0)