From 2f8899791b47fd4ffe2c7ce896efc662a0ddc313 Mon Sep 17 00:00:00 2001 From: Nikolaus Heger Date: Wed, 8 Apr 2026 15:55:43 +0800 Subject: [PATCH 01/16] auth improvements --- mobile-app/lib/app_lifecycle_manager.dart | 11 +++++--- .../lib/providers/local_auth_provider.dart | 13 ++++++--- .../lib/services/local_auth_service.dart | 9 +++++-- .../lib/v2/screens/auth/auth_wrapper.dart | 27 ++++++++++++------- 4 files changed, 41 insertions(+), 19 deletions(-) diff --git a/mobile-app/lib/app_lifecycle_manager.dart b/mobile-app/lib/app_lifecycle_manager.dart index de441ed8..5d7f56cc 100644 --- a/mobile-app/lib/app_lifecycle_manager.dart +++ b/mobile-app/lib/app_lifecycle_manager.dart @@ -97,7 +97,9 @@ class _AppLifecycleManagerState extends ConsumerState with print('App resumed but offline - polling paused'); } - // Always check authentication on resume to enforce inactivity timeout + // Check authentication ONLY on resume from background. + // This prevents flicker from transient backgrounds (FaceID, system overlays) + // that briefly pause/resume the app. localAuthNotifier.checkAuthentication(); // Initialize Taskmaster login if wallet exists @@ -108,16 +110,17 @@ class _AppLifecycleManagerState extends ConsumerState with } } else { // Handle background states (inactive, paused, hidden, detached) - // Only act if we haven't already processed a background transition if (!_isBackgrounded) { - print('AppLifecycleState.$state - pausing and locking'); + print('AppLifecycleState.$state - pausing (update pause time only)'); _isBackgrounded = true; // Pause global polling when app goes to background // Transaction tracking continues for pending transactions pollingManager.pausePolling(); - // When the app goes into the background, lock it. + // Update last paused time for timeout calculation, but DO NOT lock + // the UI immediately. This avoids flicker on short system pauses. + // The checkAuthentication() on resume will decide if auth is needed. localAuthNotifier.lockApp(); } else { print('AppLifecycleState.$state - already backgrounded, skipping actions'); diff --git a/mobile-app/lib/providers/local_auth_provider.dart b/mobile-app/lib/providers/local_auth_provider.dart index 0493b61e..9c6184aa 100644 --- a/mobile-app/lib/providers/local_auth_provider.dart +++ b/mobile-app/lib/providers/local_auth_provider.dart @@ -5,7 +5,7 @@ class LocalAuthState { final bool isAuthenticated; final bool isAuthenticating; - LocalAuthState({this.isAuthenticated = false, this.isAuthenticating = false}); + LocalAuthState({this.isAuthenticated = true, this.isAuthenticating = false}); LocalAuthState copyWith({bool? isAuthenticated, bool? isAuthenticating}) { return LocalAuthState( @@ -41,14 +41,19 @@ class LocalAuthController extends StateNotifier { void checkAuthentication() { if (_localAuthService.shouldRequireAuthentication()) { state = state.copyWith(isAuthenticated: false); - authenticate(); + // Trigger auth only if not already authenticating + if (!state.isAuthenticating) { + authenticate(); + } } else { - state = state.copyWith(isAuthenticated: true); + state = state.copyWith(isAuthenticated: true, isAuthenticating: false); } } void lockApp() { + // Only update pause time on true background; don't set authenticated=false immediately + // to avoid UI flicker on transient pauses (FaceID, overlays) _localAuthService.updateLastPausedTime(); - state = state.copyWith(isAuthenticated: false); + // Do NOT set isAuthenticated=false here - let checkAuthentication on resume decide } } diff --git a/mobile-app/lib/services/local_auth_service.dart b/mobile-app/lib/services/local_auth_service.dart index e9fb5ee2..71a053e4 100644 --- a/mobile-app/lib/services/local_auth_service.dart +++ b/mobile-app/lib/services/local_auth_service.dart @@ -11,7 +11,7 @@ class LocalAuthService { final LocalAuthentication _localAuth = LocalAuthentication(); final SettingsService _settingsService = SettingsService(); - static const _authTimeout = Duration(seconds: 30); + static const _authTimeout = Duration(minutes: 5); Future isBiometricAvailable() async { try { @@ -45,7 +45,12 @@ class LocalAuthService { final didAuthenticate = await _localAuth.authenticate( localizedReason: localizedReason, - options: const AuthenticationOptions(biometricOnly: false, stickyAuth: true, sensitiveTransaction: true), + options: const AuthenticationOptions( + biometricOnly: false, + stickyAuth: true, + sensitiveTransaction: true, + // Use default useErrorDialogs: true for better native UX on Android/iOS + ), ); if (didAuthenticate) _cleanLastPausedTime(); diff --git a/mobile-app/lib/v2/screens/auth/auth_wrapper.dart b/mobile-app/lib/v2/screens/auth/auth_wrapper.dart index 71279f03..6baa226f 100644 --- a/mobile-app/lib/v2/screens/auth/auth_wrapper.dart +++ b/mobile-app/lib/v2/screens/auth/auth_wrapper.dart @@ -37,16 +37,25 @@ class AuthWrapper extends ConsumerWidget { Text('Authorization \n Required', style: context.themeText.lockTitle, textAlign: TextAlign.center), ], ), - const SizedBox(height: 120), - Padding( - padding: EdgeInsets.symmetric(horizontal: context.themeSize.screenPadding), - child: GlassButton.simple( - label: 'Unlock Wallet', - onTap: () { - ref.read(localAuthProvider.notifier).authenticate(); - }, - variant: ButtonVariant.secondary, + const SizedBox(height: 60), + if (isAuthenticating) + const CircularProgressIndicator() + else + Padding( + padding: EdgeInsets.symmetric(horizontal: context.themeSize.screenPadding), + child: GlassButton.simple( + label: 'Unlock Wallet', + onTap: () { + ref.read(localAuthProvider.notifier).authenticate(); + }, + variant: ButtonVariant.secondary, + ), ), + const SizedBox(height: 40), + Text( + isAuthenticating ? 'Authenticating...' : 'Use device biometrics to unlock', + style: context.themeText.smallParagraph?.copyWith(color: context.colors.textSecondary), + textAlign: TextAlign.center, ), ], ), From 497de3fd19702270adf6aa8faa0a0cbb9ce4e332 Mon Sep 17 00:00:00 2001 From: Nikolaus Heger Date: Wed, 8 Apr 2026 16:23:04 +0800 Subject: [PATCH 02/16] revert auth timeout back --- mobile-app/lib/services/local_auth_service.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile-app/lib/services/local_auth_service.dart b/mobile-app/lib/services/local_auth_service.dart index 71a053e4..12d98613 100644 --- a/mobile-app/lib/services/local_auth_service.dart +++ b/mobile-app/lib/services/local_auth_service.dart @@ -11,7 +11,7 @@ class LocalAuthService { final LocalAuthentication _localAuth = LocalAuthentication(); final SettingsService _settingsService = SettingsService(); - static const _authTimeout = Duration(minutes: 5); + static const _authTimeout = Duration(seconds: 30); Future isBiometricAvailable() async { try { From c32d0ae87880a1c17a3add84fecac6f9c5bea407 Mon Sep 17 00:00:00 2001 From: Nikolaus Heger Date: Wed, 8 Apr 2026 16:37:52 +0800 Subject: [PATCH 03/16] more states for fine grained auth lock add visually locked state --- .../lib/providers/local_auth_provider.dart | 34 ++++++++++++++----- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/mobile-app/lib/providers/local_auth_provider.dart b/mobile-app/lib/providers/local_auth_provider.dart index 9c6184aa..3084bdf9 100644 --- a/mobile-app/lib/providers/local_auth_provider.dart +++ b/mobile-app/lib/providers/local_auth_provider.dart @@ -4,13 +4,23 @@ import 'package:resonance_network_wallet/services/local_auth_service.dart'; class LocalAuthState { final bool isAuthenticated; final bool isAuthenticating; + final bool isVisuallyLocked; - LocalAuthState({this.isAuthenticated = true, this.isAuthenticating = false}); + LocalAuthState({ + this.isAuthenticated = true, + this.isAuthenticating = false, + this.isVisuallyLocked = false, + }); - LocalAuthState copyWith({bool? isAuthenticated, bool? isAuthenticating}) { + LocalAuthState copyWith({ + bool? isAuthenticated, + bool? isAuthenticating, + bool? isVisuallyLocked, + }) { return LocalAuthState( isAuthenticated: isAuthenticated ?? this.isAuthenticated, isAuthenticating: isAuthenticating ?? this.isAuthenticating, + isVisuallyLocked: isVisuallyLocked ?? this.isVisuallyLocked, ); } } @@ -40,20 +50,26 @@ class LocalAuthController extends StateNotifier { void checkAuthentication() { if (_localAuthService.shouldRequireAuthentication()) { + final alreadyAuthenticating = state.isAuthenticating; state = state.copyWith(isAuthenticated: false); - // Trigger auth only if not already authenticating - if (!state.isAuthenticating) { + if (!alreadyAuthenticating) { authenticate(); } } else { - state = state.copyWith(isAuthenticated: true, isAuthenticating: false); + state = state.copyWith( + isAuthenticated: true, + isAuthenticating: false, + isVisuallyLocked: false, + ); } } - void lockApp() { - // Only update pause time on true background; don't set authenticated=false immediately - // to avoid UI flicker on transient pauses (FaceID, overlays) + void recordBackgroundTime() { _localAuthService.updateLastPausedTime(); - // Do NOT set isAuthenticated=false here - let checkAuthentication on resume decide + state = state.copyWith(isVisuallyLocked: true); + } + + void clearVisualLock() { + state = state.copyWith(isVisuallyLocked: false); } } From 6173bc0c3114a2a1fa56ba73793d1e5c342bcdf4 Mon Sep 17 00:00:00 2001 From: Nikolaus Heger Date: Wed, 8 Apr 2026 19:15:22 +0800 Subject: [PATCH 04/16] compile error fixed --- mobile-app/lib/app_lifecycle_manager.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile-app/lib/app_lifecycle_manager.dart b/mobile-app/lib/app_lifecycle_manager.dart index 5d7f56cc..4cc38e4c 100644 --- a/mobile-app/lib/app_lifecycle_manager.dart +++ b/mobile-app/lib/app_lifecycle_manager.dart @@ -121,7 +121,7 @@ class _AppLifecycleManagerState extends ConsumerState with // Update last paused time for timeout calculation, but DO NOT lock // the UI immediately. This avoids flicker on short system pauses. // The checkAuthentication() on resume will decide if auth is needed. - localAuthNotifier.lockApp(); + localAuthNotifier.recordBackgroundTime(); } else { print('AppLifecycleState.$state - already backgrounded, skipping actions'); } From 8b176e778316f1423b2d5caca99b490b3cba8ee0 Mon Sep 17 00:00:00 2001 From: Nikolaus Heger Date: Wed, 8 Apr 2026 19:29:23 +0800 Subject: [PATCH 05/16] making test build --- mobile-app/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile-app/pubspec.yaml b/mobile-app/pubspec.yaml index 6c3053ae..2603dd21 100644 --- a/mobile-app/pubspec.yaml +++ b/mobile-app/pubspec.yaml @@ -2,7 +2,7 @@ name: resonance_network_wallet description: A Flutter wallet for the Quantus blockchain. publish_to: "none" -version: 1.3.1+86 +version: 1.3.2+87 environment: sdk: ">=3.8.0 <4.0.0" From 4f4e4df2960bcdaf627ed74956a0b282bcbfbe39 Mon Sep 17 00:00:00 2001 From: Nikolaus Heger Date: Wed, 8 Apr 2026 21:28:08 +0800 Subject: [PATCH 06/16] auth on send, privacy overlay --- .../lib/services/local_auth_service.dart | 6 ++-- .../lib/v2/screens/auth/auth_wrapper.dart | 33 ++++++++++++++++--- .../lib/v2/screens/send/send_sheet.dart | 9 +++++ 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/mobile-app/lib/services/local_auth_service.dart b/mobile-app/lib/services/local_auth_service.dart index 12d98613..0ec7b1c2 100644 --- a/mobile-app/lib/services/local_auth_service.dart +++ b/mobile-app/lib/services/local_auth_service.dart @@ -11,7 +11,7 @@ class LocalAuthService { final LocalAuthentication _localAuth = LocalAuthentication(); final SettingsService _settingsService = SettingsService(); - static const _authTimeout = Duration(seconds: 30); + static const _authTimeout = Duration(seconds: 10); Future isBiometricAvailable() async { try { @@ -53,7 +53,7 @@ class LocalAuthService { ), ); - if (didAuthenticate) _cleanLastPausedTime(); + if (didAuthenticate) cleanLastPausedTime(); return didAuthenticate; } on PlatformException catch (e) { debugPrint('Platform exception during authentication: $e'); @@ -79,7 +79,7 @@ class LocalAuthService { _settingsService.setLastPausedTime(DateTime.now()); } - void _cleanLastPausedTime() { + void cleanLastPausedTime() { _settingsService.cleanLastPausedTime(); } diff --git a/mobile-app/lib/v2/screens/auth/auth_wrapper.dart b/mobile-app/lib/v2/screens/auth/auth_wrapper.dart index 6baa226f..755c7b7b 100644 --- a/mobile-app/lib/v2/screens/auth/auth_wrapper.dart +++ b/mobile-app/lib/v2/screens/auth/auth_wrapper.dart @@ -1,3 +1,4 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:resonance_network_wallet/providers/local_auth_provider.dart'; @@ -14,12 +15,26 @@ class AuthWrapper extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final authState = ref.watch(localAuthProvider); - if (authState.isAuthenticated) { - // If authenticated, be invisible. - return const SizedBox.shrink(); + if (!authState.isAuthenticated) { + return _buildLockScreen(context, ref, authState.isAuthenticating); } - return _buildLockScreen(context, ref, authState.isAuthenticating); + if (authState.isVisuallyLocked) { + return _buildPrivacyOverlay(context); + } + + return const SizedBox.shrink(); + } + + Widget _buildPrivacyOverlay(BuildContext context) { + return Scaffold( + backgroundColor: context.colors.background, + body: GradientBackground( + child: Center( + child: Image.asset('assets/v2/auth_wrapper_bracket.png'), + ), + ), + ); } Widget _buildLockScreen(BuildContext context, WidgetRef ref, bool isAuthenticating) { @@ -57,6 +72,16 @@ class AuthWrapper extends ConsumerWidget { style: context.themeText.smallParagraph?.copyWith(color: context.colors.textSecondary), textAlign: TextAlign.center, ), + if (kDebugMode) ...[ + const SizedBox(height: 40), + TextButton( + onPressed: () => ref.read(localAuthProvider.notifier).debugUnlock(), + child: Text( + '[DEBUG] Simulate Unlock', + style: context.themeText.detail?.copyWith(color: context.colors.accentGreen), + ), + ), + ], ], ), ), diff --git a/mobile-app/lib/v2/screens/send/send_sheet.dart b/mobile-app/lib/v2/screens/send/send_sheet.dart index fb38cf43..b08d42fa 100644 --- a/mobile-app/lib/v2/screens/send/send_sheet.dart +++ b/mobile-app/lib/v2/screens/send/send_sheet.dart @@ -11,6 +11,7 @@ import 'package:resonance_network_wallet/v2/screens/send/send_screen_logic.dart' import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/route_intent_providers.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; +import 'package:resonance_network_wallet/services/local_auth_service.dart'; import 'package:resonance_network_wallet/services/transaction_submission_service.dart'; import 'package:resonance_network_wallet/v2/components/success_check.dart'; import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; @@ -193,6 +194,14 @@ class _SendSheetState extends ConsumerState { void _backToForm() => setState(() => _step = _Step.form); Future _confirmSend() async { + final authed = await LocalAuthService().authenticate( + localizedReason: 'Authenticate to confirm transaction', + ); + if (!authed || !mounted) { + if (mounted) setState(() => _errorMessage = 'Authentication required to send'); + return; + } + setState(() { _step = _Step.sending; _errorMessage = null; From a9ce3577b928f121bba11ce10fb9f70db5f11a39 Mon Sep 17 00:00:00 2001 From: Nikolaus Heger Date: Wed, 8 Apr 2026 21:28:28 +0800 Subject: [PATCH 07/16] format --- mobile-app/lib/v2/screens/auth/auth_wrapper.dart | 6 +----- mobile-app/lib/v2/screens/send/send_sheet.dart | 4 +--- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/mobile-app/lib/v2/screens/auth/auth_wrapper.dart b/mobile-app/lib/v2/screens/auth/auth_wrapper.dart index 755c7b7b..a4e5c1c1 100644 --- a/mobile-app/lib/v2/screens/auth/auth_wrapper.dart +++ b/mobile-app/lib/v2/screens/auth/auth_wrapper.dart @@ -29,11 +29,7 @@ class AuthWrapper extends ConsumerWidget { Widget _buildPrivacyOverlay(BuildContext context) { return Scaffold( backgroundColor: context.colors.background, - body: GradientBackground( - child: Center( - child: Image.asset('assets/v2/auth_wrapper_bracket.png'), - ), - ), + body: GradientBackground(child: Center(child: Image.asset('assets/v2/auth_wrapper_bracket.png'))), ); } diff --git a/mobile-app/lib/v2/screens/send/send_sheet.dart b/mobile-app/lib/v2/screens/send/send_sheet.dart index b08d42fa..44e4f06a 100644 --- a/mobile-app/lib/v2/screens/send/send_sheet.dart +++ b/mobile-app/lib/v2/screens/send/send_sheet.dart @@ -194,9 +194,7 @@ class _SendSheetState extends ConsumerState { void _backToForm() => setState(() => _step = _Step.form); Future _confirmSend() async { - final authed = await LocalAuthService().authenticate( - localizedReason: 'Authenticate to confirm transaction', - ); + final authed = await LocalAuthService().authenticate(localizedReason: 'Authenticate to confirm transaction'); if (!authed || !mounted) { if (mounted) setState(() => _errorMessage = 'Authentication required to send'); return; From 4c96bbdd648bc763a52c7b52c5856d9540f61d04 Mon Sep 17 00:00:00 2001 From: Nikolaus Heger Date: Thu, 9 Apr 2026 09:39:00 +0800 Subject: [PATCH 08/16] remove debug UX --- .../lib/providers/local_auth_provider.dart | 18 +++--------------- .../lib/v2/screens/auth/auth_wrapper.dart | 11 ----------- 2 files changed, 3 insertions(+), 26 deletions(-) diff --git a/mobile-app/lib/providers/local_auth_provider.dart b/mobile-app/lib/providers/local_auth_provider.dart index 3084bdf9..f40c847e 100644 --- a/mobile-app/lib/providers/local_auth_provider.dart +++ b/mobile-app/lib/providers/local_auth_provider.dart @@ -6,17 +6,9 @@ class LocalAuthState { final bool isAuthenticating; final bool isVisuallyLocked; - LocalAuthState({ - this.isAuthenticated = true, - this.isAuthenticating = false, - this.isVisuallyLocked = false, - }); + LocalAuthState({this.isAuthenticated = true, this.isAuthenticating = false, this.isVisuallyLocked = false}); - LocalAuthState copyWith({ - bool? isAuthenticated, - bool? isAuthenticating, - bool? isVisuallyLocked, - }) { + LocalAuthState copyWith({bool? isAuthenticated, bool? isAuthenticating, bool? isVisuallyLocked}) { return LocalAuthState( isAuthenticated: isAuthenticated ?? this.isAuthenticated, isAuthenticating: isAuthenticating ?? this.isAuthenticating, @@ -56,11 +48,7 @@ class LocalAuthController extends StateNotifier { authenticate(); } } else { - state = state.copyWith( - isAuthenticated: true, - isAuthenticating: false, - isVisuallyLocked: false, - ); + state = state.copyWith(isAuthenticated: true, isAuthenticating: false, isVisuallyLocked: false); } } diff --git a/mobile-app/lib/v2/screens/auth/auth_wrapper.dart b/mobile-app/lib/v2/screens/auth/auth_wrapper.dart index a4e5c1c1..34f6a971 100644 --- a/mobile-app/lib/v2/screens/auth/auth_wrapper.dart +++ b/mobile-app/lib/v2/screens/auth/auth_wrapper.dart @@ -1,4 +1,3 @@ -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:resonance_network_wallet/providers/local_auth_provider.dart'; @@ -68,16 +67,6 @@ class AuthWrapper extends ConsumerWidget { style: context.themeText.smallParagraph?.copyWith(color: context.colors.textSecondary), textAlign: TextAlign.center, ), - if (kDebugMode) ...[ - const SizedBox(height: 40), - TextButton( - onPressed: () => ref.read(localAuthProvider.notifier).debugUnlock(), - child: Text( - '[DEBUG] Simulate Unlock', - style: context.themeText.detail?.copyWith(color: context.colors.accentGreen), - ), - ), - ], ], ), ), From 38287d4f41eda170457ac586f67b0bb3a149ac0c Mon Sep 17 00:00:00 2001 From: Nikolaus Heger Date: Thu, 9 Apr 2026 09:40:04 +0800 Subject: [PATCH 09/16] Build 88 --- mobile-app/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile-app/pubspec.yaml b/mobile-app/pubspec.yaml index 2603dd21..3143d613 100644 --- a/mobile-app/pubspec.yaml +++ b/mobile-app/pubspec.yaml @@ -2,7 +2,7 @@ name: resonance_network_wallet description: A Flutter wallet for the Quantus blockchain. publish_to: "none" -version: 1.3.2+87 +version: 1.3.2+88 environment: sdk: ">=3.8.0 <4.0.0" From 85cf3a81ddd959921b03266c5a5438eb0e765ca6 Mon Sep 17 00:00:00 2001 From: Nikolaus Heger Date: Thu, 9 Apr 2026 11:16:47 +0800 Subject: [PATCH 10/16] centering auth --- mobile-app/lib/generated/version.g.dart | 4 ++-- mobile-app/lib/v2/screens/auth/auth_wrapper.dart | 11 ++++++----- mobile-app/pubspec.lock | 8 ++++---- mobile-app/pubspec.yaml | 2 +- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/mobile-app/lib/generated/version.g.dart b/mobile-app/lib/generated/version.g.dart index 1b9e87e9..1cc73b18 100644 --- a/mobile-app/lib/generated/version.g.dart +++ b/mobile-app/lib/generated/version.g.dart @@ -1,2 +1,2 @@ -const appVersion = '1.3.0'; -const appBuildNumber = '85'; +const appVersion = '1.3.2'; +const appBuildNumber = '89'; diff --git a/mobile-app/lib/v2/screens/auth/auth_wrapper.dart b/mobile-app/lib/v2/screens/auth/auth_wrapper.dart index 34f6a971..e4c68f39 100644 --- a/mobile-app/lib/v2/screens/auth/auth_wrapper.dart +++ b/mobile-app/lib/v2/screens/auth/auth_wrapper.dart @@ -36,10 +36,10 @@ class AuthWrapper extends ConsumerWidget { return Scaffold( backgroundColor: context.colors.background, body: GradientBackground( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ + child: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ Stack( alignment: Alignment.center, children: [ @@ -67,7 +67,8 @@ class AuthWrapper extends ConsumerWidget { style: context.themeText.smallParagraph?.copyWith(color: context.colors.textSecondary), textAlign: TextAlign.center, ), - ], + ], + ), ), ), ); diff --git a/mobile-app/pubspec.lock b/mobile-app/pubspec.lock index f32d4549..c022048e 100644 --- a/mobile-app/pubspec.lock +++ b/mobile-app/pubspec.lock @@ -1085,10 +1085,10 @@ packages: dependency: transitive description: name: matcher - sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6" + sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861 url: "https://pub.dev" source: hosted - version: "0.12.18" + version: "0.12.19" material_color_utilities: dependency: transitive description: @@ -1744,10 +1744,10 @@ packages: dependency: transitive description: name: test_api - sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636" + sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a" url: "https://pub.dev" source: hosted - version: "0.7.9" + version: "0.7.10" timezone: dependency: "direct main" description: diff --git a/mobile-app/pubspec.yaml b/mobile-app/pubspec.yaml index 3143d613..89557437 100644 --- a/mobile-app/pubspec.yaml +++ b/mobile-app/pubspec.yaml @@ -2,7 +2,7 @@ name: resonance_network_wallet description: A Flutter wallet for the Quantus blockchain. publish_to: "none" -version: 1.3.2+88 +version: 1.3.2+89 environment: sdk: ">=3.8.0 <4.0.0" From c546e8845f75e124e6beac3290a628590b905d2a Mon Sep 17 00:00:00 2001 From: Nikolaus Heger Date: Thu, 9 Apr 2026 11:17:03 +0800 Subject: [PATCH 11/16] Build 90 --- mobile-app/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile-app/pubspec.yaml b/mobile-app/pubspec.yaml index 89557437..8241d294 100644 --- a/mobile-app/pubspec.yaml +++ b/mobile-app/pubspec.yaml @@ -2,7 +2,7 @@ name: resonance_network_wallet description: A Flutter wallet for the Quantus blockchain. publish_to: "none" -version: 1.3.2+89 +version: 1.3.2+90 environment: sdk: ">=3.8.0 <4.0.0" From 10a2a3b776c1260182ba21b64bda492f6fa5d963 Mon Sep 17 00:00:00 2001 From: Nikolaus Heger Date: Thu, 9 Apr 2026 11:41:59 +0800 Subject: [PATCH 12/16] snappier unlock flow --- mobile-app/lib/providers/local_auth_provider.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile-app/lib/providers/local_auth_provider.dart b/mobile-app/lib/providers/local_auth_provider.dart index f40c847e..3a2bd668 100644 --- a/mobile-app/lib/providers/local_auth_provider.dart +++ b/mobile-app/lib/providers/local_auth_provider.dart @@ -37,7 +37,7 @@ class LocalAuthController extends StateNotifier { localizedReason: 'Please authenticate to access your wallet', ); - state = state.copyWith(isAuthenticated: didAuthenticate, isAuthenticating: false); + state = state.copyWith(isAuthenticated: didAuthenticate, isAuthenticating: false, isVisuallyLocked: false); } void checkAuthentication() { From 302f715854e1b3786a5d21ce77a4845406619471 Mon Sep 17 00:00:00 2001 From: Nikolaus Heger Date: Thu, 9 Apr 2026 11:42:14 +0800 Subject: [PATCH 13/16] format --- .../lib/v2/screens/auth/auth_wrapper.dart | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/mobile-app/lib/v2/screens/auth/auth_wrapper.dart b/mobile-app/lib/v2/screens/auth/auth_wrapper.dart index e4c68f39..0985946c 100644 --- a/mobile-app/lib/v2/screens/auth/auth_wrapper.dart +++ b/mobile-app/lib/v2/screens/auth/auth_wrapper.dart @@ -40,33 +40,33 @@ class AuthWrapper extends ConsumerWidget { child: Column( mainAxisSize: MainAxisSize.min, children: [ - Stack( - alignment: Alignment.center, - children: [ - Image.asset('assets/v2/auth_wrapper_bracket.png'), - Text('Authorization \n Required', style: context.themeText.lockTitle, textAlign: TextAlign.center), - ], - ), - const SizedBox(height: 60), - if (isAuthenticating) - const CircularProgressIndicator() - else - Padding( - padding: EdgeInsets.symmetric(horizontal: context.themeSize.screenPadding), - child: GlassButton.simple( - label: 'Unlock Wallet', - onTap: () { - ref.read(localAuthProvider.notifier).authenticate(); - }, - variant: ButtonVariant.secondary, + Stack( + alignment: Alignment.center, + children: [ + Image.asset('assets/v2/auth_wrapper_bracket.png'), + Text('Authorization \n Required', style: context.themeText.lockTitle, textAlign: TextAlign.center), + ], + ), + const SizedBox(height: 60), + if (isAuthenticating) + const CircularProgressIndicator() + else + Padding( + padding: EdgeInsets.symmetric(horizontal: context.themeSize.screenPadding), + child: GlassButton.simple( + label: 'Unlock Wallet', + onTap: () { + ref.read(localAuthProvider.notifier).authenticate(); + }, + variant: ButtonVariant.secondary, + ), ), + const SizedBox(height: 40), + Text( + isAuthenticating ? 'Authenticating...' : 'Use device biometrics to unlock', + style: context.themeText.smallParagraph?.copyWith(color: context.colors.textSecondary), + textAlign: TextAlign.center, ), - const SizedBox(height: 40), - Text( - isAuthenticating ? 'Authenticating...' : 'Use device biometrics to unlock', - style: context.themeText.smallParagraph?.copyWith(color: context.colors.textSecondary), - textAlign: TextAlign.center, - ), ], ), ), From ea0db2f27e5ece196d99148b6edc6d1ed4ad4dda Mon Sep 17 00:00:00 2001 From: Nikolaus Heger Date: Thu, 9 Apr 2026 12:20:49 +0800 Subject: [PATCH 14/16] Build 91 --- mobile-app/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile-app/pubspec.yaml b/mobile-app/pubspec.yaml index 8241d294..52d1c2ca 100644 --- a/mobile-app/pubspec.yaml +++ b/mobile-app/pubspec.yaml @@ -2,7 +2,7 @@ name: resonance_network_wallet description: A Flutter wallet for the Quantus blockchain. publish_to: "none" -version: 1.3.2+90 +version: 1.3.2+91 environment: sdk: ">=3.8.0 <4.0.0" From 9b1beb000ea16681a5f6b5738e189c074274b4d2 Mon Sep 17 00:00:00 2001 From: Nikolaus Heger Date: Thu, 9 Apr 2026 12:28:49 +0800 Subject: [PATCH 15/16] Update version.g.dart --- mobile-app/lib/generated/version.g.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile-app/lib/generated/version.g.dart b/mobile-app/lib/generated/version.g.dart index 1cc73b18..ecd72fc0 100644 --- a/mobile-app/lib/generated/version.g.dart +++ b/mobile-app/lib/generated/version.g.dart @@ -1,2 +1,2 @@ const appVersion = '1.3.2'; -const appBuildNumber = '89'; +const appBuildNumber = '91'; From b313e95cb73be9f20841c51201d79239a053c86a Mon Sep 17 00:00:00 2001 From: Nikolaus Heger Date: Thu, 9 Apr 2026 13:41:22 +0800 Subject: [PATCH 16/16] remove confusing comment --- mobile-app/lib/services/local_auth_service.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/mobile-app/lib/services/local_auth_service.dart b/mobile-app/lib/services/local_auth_service.dart index 0ec7b1c2..cdfee453 100644 --- a/mobile-app/lib/services/local_auth_service.dart +++ b/mobile-app/lib/services/local_auth_service.dart @@ -49,7 +49,6 @@ class LocalAuthService { biometricOnly: false, stickyAuth: true, sensitiveTransaction: true, - // Use default useErrorDialogs: true for better native UX on Android/iOS ), );