From ceaba85d808d391ad609759d1bac24dc67a08f9f Mon Sep 17 00:00:00 2001 From: Beast Date: Mon, 16 Feb 2026 11:25:28 +0800 Subject: [PATCH 1/9] fix: wrong filename for glass bg --- mobile-app/lib/v2/components/glass_container.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile-app/lib/v2/components/glass_container.dart b/mobile-app/lib/v2/components/glass_container.dart index 9779fa48..33958748 100644 --- a/mobile-app/lib/v2/components/glass_container.dart +++ b/mobile-app/lib/v2/components/glass_container.dart @@ -11,7 +11,7 @@ class GlassContainer extends StatelessWidget { static const mediumAsset = 'assets/v2/glass_medium_clear.png'; static const mediumSmallAsset = 'assets/v2/glass_medium_clear_small.png'; // 36px height - static const smallAsset = 'assets/v2/glass_button_40_bg.png'; + static const smallAsset = 'assets/v2/glass_40.png'; static const wideAsset = 'assets/v2/glass_button_wide_340_bg.png'; static const _inset = 42.0; From eb6234fbe6ae4483bbced957542cc0cfee594b9c Mon Sep 17 00:00:00 2001 From: Beast Date: Mon, 16 Feb 2026 11:25:53 +0800 Subject: [PATCH 2/9] feat: make toaster for new design --- .../extensions/clipboard_extensions.dart | 12 ++++ .../shared/extensions/toaster_extensions.dart | 16 +++++ mobile-app/lib/v2/components/toaster.dart | 41 ++++++++++++ .../lib/v2/components/toaster_helper.dart | 63 +++++++++++++++++++ .../activity/transaction_detail_sheet.dart | 10 +-- .../screens/create/wallet_ready_screen.dart | 8 +-- .../lib/v2/screens/receive/receive_sheet.dart | 4 +- .../settings/recovery_phrase_screen.dart | 18 ++++-- .../lib/v2/screens/swap/deposit_screen.dart | 11 ++-- mobile-app/lib/v2/theme/app_colors.dart | 12 ++++ 10 files changed, 171 insertions(+), 24 deletions(-) create mode 100644 mobile-app/lib/shared/extensions/toaster_extensions.dart create mode 100644 mobile-app/lib/v2/components/toaster.dart create mode 100644 mobile-app/lib/v2/components/toaster_helper.dart diff --git a/mobile-app/lib/shared/extensions/clipboard_extensions.dart b/mobile-app/lib/shared/extensions/clipboard_extensions.dart index 200fc6e2..327669b2 100644 --- a/mobile-app/lib/shared/extensions/clipboard_extensions.dart +++ b/mobile-app/lib/shared/extensions/clipboard_extensions.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:resonance_network_wallet/features/components/snackbar_helper.dart'; +import 'package:resonance_network_wallet/v2/components/toaster_helper.dart'; extension ClipboardExtensions on Clipboard { static Future copyTextWithSnackbar( @@ -15,3 +16,14 @@ extension ClipboardExtensions on Clipboard { await showCopySnackbar(context, title: title, message: message); } } + +extension ClipboardWithToasterExtensions on BuildContext { + Future copyTextWithToaster( + String text, { + String message = 'Address copied to clipboard', + }) async { + await Clipboard.setData(ClipboardData(text: text)); + + await showCopyToaster(this, message: message); + } +} \ No newline at end of file diff --git a/mobile-app/lib/shared/extensions/toaster_extensions.dart b/mobile-app/lib/shared/extensions/toaster_extensions.dart new file mode 100644 index 00000000..1adf6885 --- /dev/null +++ b/mobile-app/lib/shared/extensions/toaster_extensions.dart @@ -0,0 +1,16 @@ +import 'package:flutter/material.dart'; +import 'package:resonance_network_wallet/v2/components/toaster_helper.dart' as th; + +extension ToasterExtensions on BuildContext { + Future showSuccessToaster({required String message}) async { + await th.showSuccessToaster(this, message: message); + } + + Future showWarningToaster({required String message}) async { + await th.showWarningToaster(this, message: message); + } + + Future showErrorToaster({required String message}) async { + await th.showErrorToaster(this, message: message); + } +} diff --git a/mobile-app/lib/v2/components/toaster.dart b/mobile-app/lib/v2/components/toaster.dart new file mode 100644 index 00000000..a1e6a1fb --- /dev/null +++ b/mobile-app/lib/v2/components/toaster.dart @@ -0,0 +1,41 @@ +import 'package:flutter/material.dart'; +import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; +import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; +import 'package:resonance_network_wallet/shared/extensions/media_query_data_extension.dart'; + +class Toaster extends StatelessWidget { + final String message; + final Icon? icon; + + const Toaster({super.key, required this.message, this.icon}); + + @override + Widget build(BuildContext context) { + final Widget displayIcon = Icon( + icon?.icon ?? Icons.copy, + color: icon?.color ?? Colors.white, + size: context.isTablet ? 20 : 16, + ); + + return Container( + // width: 343, // Width will be handled by the flash package's constraints + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 20), + decoration: ShapeDecoration( + color: context.colors.toasterBackground, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(14.22), + side: BorderSide(color: context.colors.toasterBorder), + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + displayIcon, + const SizedBox(width: 12), + Expanded(child: Text(message, style: context.themeText.smallParagraph, softWrap: true)), + ], + ), + ); + } +} diff --git a/mobile-app/lib/v2/components/toaster_helper.dart b/mobile-app/lib/v2/components/toaster_helper.dart new file mode 100644 index 00000000..5464affc --- /dev/null +++ b/mobile-app/lib/v2/components/toaster_helper.dart @@ -0,0 +1,63 @@ +import 'package:flash/flash.dart'; +import 'package:flash/flash_helper.dart'; +import 'package:flutter/material.dart'; +import 'package:resonance_network_wallet/v2/components/toaster.dart'; +import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; + +Future showToaster( + BuildContext context, { + required String message, + Icon? icon, + Duration duration = const Duration(seconds: 3), + FlashBehavior style = FlashBehavior.floating, +}) async { + if (!context.mounted) return; + + await context.showFlash( + duration: duration, + persistent: true, + builder: (context, controller) { + return FlashBar( + controller: controller, + behavior: style, + backgroundColor: Colors.transparent, + surfaceTintColor: Colors.transparent, + shadowColor: Colors.transparent, + indicatorColor: Colors.transparent, + position: FlashPosition.top, + clipBehavior: Clip.none, + shouldIconPulse: false, + content: Toaster(message: message, icon: icon), + ); + }, + ); +} + +Future showCopyToaster(BuildContext context, {required String message}) async { + await showToaster(context, icon: const Icon(Icons.copy), message: message); +} + +Future showWarningToaster(BuildContext context, {required String message}) async { + await showToaster( + context, + message: message, + icon: const Icon(Icons.warning, color: Colors.amber), + ); +} + +Future showErrorToaster(BuildContext context, {required String message}) async { + await showToaster( + context, + message: message, + duration: const Duration(seconds: 10), + icon: Icon(Icons.error_rounded, color: context.colors.error), + ); +} + +Future showSuccessToaster(BuildContext context, {required String message}) async { + await showToaster( + context, + message: message, + icon: Icon(Icons.check_circle_rounded, color: context.colors.success), + ); +} diff --git a/mobile-app/lib/v2/screens/activity/transaction_detail_sheet.dart b/mobile-app/lib/v2/screens/activity/transaction_detail_sheet.dart index f02e9349..c24f2f6b 100644 --- a/mobile-app/lib/v2/screens/activity/transaction_detail_sheet.dart +++ b/mobile-app/lib/v2/screens/activity/transaction_detail_sheet.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:intl/intl.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:resonance_network_wallet/shared/extensions/clipboard_extensions.dart'; import 'package:resonance_network_wallet/shared/extensions/transaction_event_extension.dart'; import 'package:resonance_network_wallet/v2/components/bottom_sheet_container.dart'; import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; @@ -122,7 +122,7 @@ class _TransactionDetailSheetState extends State<_TransactionDetailSheet> { ), ), const SizedBox(width: 8), - _copyButton(colors, _counterparty), + _copyButton(colors, value: _counterparty), ], ), if (_checkphrase != null) ...[ @@ -133,7 +133,7 @@ class _TransactionDetailSheetState extends State<_TransactionDetailSheet> { child: Text(_checkphrase!, style: text.smallParagraph?.copyWith(color: colors.accentPink)), ), const SizedBox(width: 8), - _copyButton(colors, _checkphrase!), + _copyButton(colors, value: _checkphrase!, message: 'Checkphrase copied to clipboard'), ], ), ], @@ -142,9 +142,9 @@ class _TransactionDetailSheetState extends State<_TransactionDetailSheet> { ); } - Widget _copyButton(AppColorsV2 colors, String value) { + Widget _copyButton(AppColorsV2 colors, {required String value, String message = 'Address copied to clipboard'}) { return GestureDetector( - onTap: () => Clipboard.setData(ClipboardData(text: value)), + onTap: () => context.copyTextWithToaster(value, message: message), child: Container( width: 20, height: 20, diff --git a/mobile-app/lib/v2/screens/create/wallet_ready_screen.dart b/mobile-app/lib/v2/screens/create/wallet_ready_screen.dart index 43aaafc0..9b853fea 100644 --- a/mobile-app/lib/v2/screens/create/wallet_ready_screen.dart +++ b/mobile-app/lib/v2/screens/create/wallet_ready_screen.dart @@ -152,7 +152,7 @@ class _WalletReadyScreenV2State extends ConsumerState { ), isLoading: _isLoading, actionIcon: Icons.copy, - onAction: () => ClipboardExtensions.copyTextWithSnackbar(context, _address), + onAction: () => context.copyTextWithToaster(_address), ), const SizedBox(height: 24), _Field( @@ -161,11 +161,7 @@ class _WalletReadyScreenV2State extends ConsumerState { isLoading: _isLoading, valueColor: colors.accentPink, actionIcon: Icons.copy, - onAction: () => ClipboardExtensions.copyTextWithSnackbar( - context, - _checksum, - message: 'Checkphrase copied', - ), + onAction: () => context.copyTextWithToaster(_checksum, message: 'Checkphrase copied'), ), const SizedBox(height: 16), GestureDetector( diff --git a/mobile-app/lib/v2/screens/receive/receive_sheet.dart b/mobile-app/lib/v2/screens/receive/receive_sheet.dart index 0116898f..daa272d0 100644 --- a/mobile-app/lib/v2/screens/receive/receive_sheet.dart +++ b/mobile-app/lib/v2/screens/receive/receive_sheet.dart @@ -43,13 +43,13 @@ class _ReceiveSheetState extends State { void _copyAddress() { if (_accountId != null) { - ClipboardExtensions.copyTextWithSnackbar(context, _accountId!); + context.copyTextWithToaster(_accountId!); } } void _copyChecksum() { if (_checksum != null) { - ClipboardExtensions.copyTextWithSnackbar(context, _checksum!, message: 'Checkphrase copied'); + context.copyTextWithToaster(_checksum!, message: 'Checkphrase copied'); } } diff --git a/mobile-app/lib/v2/screens/settings/recovery_phrase_screen.dart b/mobile-app/lib/v2/screens/settings/recovery_phrase_screen.dart index cf7222db..be3f5b1b 100644 --- a/mobile-app/lib/v2/screens/settings/recovery_phrase_screen.dart +++ b/mobile-app/lib/v2/screens/settings/recovery_phrase_screen.dart @@ -1,9 +1,8 @@ import 'dart:ui'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:resonance_network_wallet/features/components/snackbar_helper.dart'; import 'package:resonance_network_wallet/services/local_auth_service.dart'; +import 'package:resonance_network_wallet/shared/extensions/clipboard_extensions.dart'; import 'package:resonance_network_wallet/v2/components/back_button.dart'; import 'package:resonance_network_wallet/v2/components/glass_container.dart'; import 'package:resonance_network_wallet/v2/components/gradient_background.dart'; @@ -50,8 +49,7 @@ class _RecoveryPhraseScreenState extends State { } void _copyToClipboard() { - Clipboard.setData(ClipboardData(text: _words.join(' '))); - showCopySnackbar(context, title: 'Copied!', message: 'Recovery phrase copied to clipboard'); + context.copyTextWithToaster(_words.join(' '), message: 'Recovery phrase copied to clipboard'); } @override @@ -146,7 +144,17 @@ class _RecoveryPhraseScreenState extends State { ); return SizedBox( - child: GlassContainer(asset: GlassContainer.mediumSmallAsset, filled: true, child: Row(mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [const SizedBox(width: 8), Text('$index', style: text.detail?.copyWith(color: colors.textSecondary)), const SizedBox(width: 6), Expanded( + child: GlassContainer( + asset: GlassContainer.mediumSmallAsset, + filled: true, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox(width: 8), + Text('$index', style: text.detail?.copyWith(color: colors.textSecondary)), + const SizedBox(width: 6), + Expanded( child: Stack( alignment: Alignment.centerLeft, children: [ diff --git a/mobile-app/lib/v2/screens/swap/deposit_screen.dart b/mobile-app/lib/v2/screens/swap/deposit_screen.dart index 06f7979e..2b713fe0 100644 --- a/mobile-app/lib/v2/screens/swap/deposit_screen.dart +++ b/mobile-app/lib/v2/screens/swap/deposit_screen.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:qr_flutter/qr_flutter.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:resonance_network_wallet/shared/extensions/clipboard_extensions.dart'; import 'package:resonance_network_wallet/v2/components/back_button.dart'; import 'package:resonance_network_wallet/v2/components/glass_container.dart'; import 'package:resonance_network_wallet/v2/components/gradient_background.dart'; @@ -56,10 +57,7 @@ class _DepositScreenState extends State { } void _copyAddress() { - Clipboard.setData(ClipboardData(text: _order.depositAddress)); - ScaffoldMessenger.of( - context, - ).showSnackBar(const SnackBar(content: Text('Address copied'), duration: Duration(seconds: 1))); + context.copyTextWithToaster(_order.depositAddress); } @override @@ -118,7 +116,7 @@ class _DepositScreenState extends State { Text('Deposit Amount', style: text.smallParagraph?.copyWith(color: colors.textPrimary, height: 1.35)), const SizedBox(width: 6), GestureDetector( - onTap: () => Clipboard.setData(ClipboardData(text: quote.totalAmount.toStringAsFixed(2))), + onTap: () => context.copyTextWithToaster(quote.totalAmount.toStringAsFixed(2), message: 'Deposit amount copied to clipboard'), child: Container( width: 20, height: 20, @@ -155,8 +153,9 @@ class _DepositScreenState extends State { child: Container( color: Colors.white, padding: const EdgeInsets.all(8), + /// for now this QR Code is invalid so people don't transfer by accident - // child: QrImageView(data: _order.depositAddress, version: QrVersions.auto, size: 184), + // child: QrImageView(data: _order.depositAddress, version: QrVersions.auto, size: 184), child: QrImageView(data: 'quantum secure bitcoin - quantus!', version: QrVersions.auto, size: 184), ), ), diff --git a/mobile-app/lib/v2/theme/app_colors.dart b/mobile-app/lib/v2/theme/app_colors.dart index 141feb92..a81e5a57 100644 --- a/mobile-app/lib/v2/theme/app_colors.dart +++ b/mobile-app/lib/v2/theme/app_colors.dart @@ -5,6 +5,7 @@ class AppColorsV2 extends ThemeExtension { // Backgrounds final Color background; final Color backgroundAlt; + final Color toasterBackground; // Surfaces final Color surface; @@ -38,6 +39,7 @@ class AppColorsV2 extends ThemeExtension { final Color buttonDisabled; final Color skeletonBase; final Color skeletonHighlight; + final Color toasterBorder; // Account tags final Color tagGuardian; @@ -47,6 +49,8 @@ class AppColorsV2 extends ThemeExtension { const AppColorsV2({ required this.background, required this.backgroundAlt, + required this.toasterBackground, + required this.toasterBorder, required this.surface, required this.surfaceGlass, required this.surfaceCard, @@ -77,6 +81,8 @@ class AppColorsV2 extends ThemeExtension { : this( background: const Color(0xFF141414), backgroundAlt: const Color(0xFF1F1F1F), + toasterBackground: const Color(0xFF191919), + toasterBorder: const Color(0xFF3D3D3D), surface: const Color(0xFF292929), surfaceGlass: const Color(0x1AFFFFFF), surfaceCard: const Color(0x0FFFFFFF), @@ -125,6 +131,8 @@ class AppColorsV2 extends ThemeExtension { Color? separator, Color? txItemSeparator, Color? border, + Color? toasterBackground, + Color? toasterBorder, Color? buttonDisabled, Color? skeletonBase, Color? skeletonHighlight, @@ -135,6 +143,8 @@ class AppColorsV2 extends ThemeExtension { return AppColorsV2( background: background ?? this.background, backgroundAlt: backgroundAlt ?? this.backgroundAlt, + toasterBackground: toasterBackground ?? this.toasterBackground, + toasterBorder: toasterBorder ?? this.toasterBorder, surface: surface ?? this.surface, surfaceGlass: surfaceGlass ?? this.surfaceGlass, surfaceCard: surfaceCard ?? this.surfaceCard, @@ -168,6 +178,8 @@ class AppColorsV2 extends ThemeExtension { return AppColorsV2( background: Color.lerp(background, other.background, t) ?? background, backgroundAlt: Color.lerp(backgroundAlt, other.backgroundAlt, t) ?? backgroundAlt, + toasterBackground: Color.lerp(toasterBackground, other.toasterBackground, t) ?? toasterBackground, + toasterBorder: Color.lerp(toasterBorder, other.toasterBorder, t) ?? toasterBorder, surface: Color.lerp(surface, other.surface, t) ?? surface, surfaceGlass: Color.lerp(surfaceGlass, other.surfaceGlass, t) ?? surfaceGlass, surfaceCard: Color.lerp(surfaceCard, other.surfaceCard, t) ?? surfaceCard, From 558ad68662a99f859ed1b451867ac57236f3a2e3 Mon Sep 17 00:00:00 2001 From: Beast Date: Mon, 16 Feb 2026 11:26:12 +0800 Subject: [PATCH 3/9] chore: remove unused import --- mobile-app/lib/v2/screens/swap/deposit_screen.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/mobile-app/lib/v2/screens/swap/deposit_screen.dart b/mobile-app/lib/v2/screens/swap/deposit_screen.dart index 2b713fe0..a9ec7178 100644 --- a/mobile-app/lib/v2/screens/swap/deposit_screen.dart +++ b/mobile-app/lib/v2/screens/swap/deposit_screen.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:qr_flutter/qr_flutter.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/shared/extensions/clipboard_extensions.dart'; From e479579cdd7dcc71440543fe114839c812ace389 Mon Sep 17 00:00:00 2001 From: Beast Date: Mon, 16 Feb 2026 13:06:54 +0800 Subject: [PATCH 4/9] fix: code formatting --- mobile-app/lib/features/main/screens/app.dart | 2 +- mobile-app/lib/services/transaction_service.dart | 2 +- .../lib/shared/extensions/clipboard_extensions.dart | 7 ++----- mobile-app/lib/v2/components/glass_container.dart | 13 +++++++++++-- .../lib/v2/screens/home/activity_section.dart | 6 ++++-- mobile-app/lib/v2/screens/swap/deposit_screen.dart | 5 ++++- 6 files changed, 23 insertions(+), 12 deletions(-) diff --git a/mobile-app/lib/features/main/screens/app.dart b/mobile-app/lib/features/main/screens/app.dart index 58918cd0..127af5b4 100644 --- a/mobile-app/lib/features/main/screens/app.dart +++ b/mobile-app/lib/features/main/screens/app.dart @@ -38,7 +38,7 @@ class _ResonanceWalletAppState extends ConsumerState { if (FeatureFlags.enableRemoteNotifications) { ref.read(firebaseMessagingServiceProvider).setupNotificationTapHandlers(navigatorKey); } - + if (Platform.isAndroid) _referralService.checkPlayStoreReferralCode(); }); } diff --git a/mobile-app/lib/services/transaction_service.dart b/mobile-app/lib/services/transaction_service.dart index 3280ee9e..7bc3aa45 100644 --- a/mobile-app/lib/services/transaction_service.dart +++ b/mobile-app/lib/services/transaction_service.dart @@ -91,7 +91,7 @@ class TransactionService { void navigateToTransactionFromPayloadIfPossible(Map? json, GlobalKey navigatorKey) { final event = deserializeTxEventFromJsonIfPossible(json); - + if (event != null) { _ref.read(transactionIntentProvider.notifier).state = event; navigatorKey.currentState?.pushNamed('/transactions'); diff --git a/mobile-app/lib/shared/extensions/clipboard_extensions.dart b/mobile-app/lib/shared/extensions/clipboard_extensions.dart index 327669b2..9740cad9 100644 --- a/mobile-app/lib/shared/extensions/clipboard_extensions.dart +++ b/mobile-app/lib/shared/extensions/clipboard_extensions.dart @@ -18,12 +18,9 @@ extension ClipboardExtensions on Clipboard { } extension ClipboardWithToasterExtensions on BuildContext { - Future copyTextWithToaster( - String text, { - String message = 'Address copied to clipboard', - }) async { + Future copyTextWithToaster(String text, {String message = 'Address copied to clipboard'}) async { await Clipboard.setData(ClipboardData(text: text)); await showCopyToaster(this, message: message); } -} \ No newline at end of file +} diff --git a/mobile-app/lib/v2/components/glass_container.dart b/mobile-app/lib/v2/components/glass_container.dart index 33958748..5e71553f 100644 --- a/mobile-app/lib/v2/components/glass_container.dart +++ b/mobile-app/lib/v2/components/glass_container.dart @@ -22,7 +22,11 @@ class GlassContainer extends StatelessWidget { wideAsset: Rect.fromLTRB(_inset, _inset, 1020 - _inset, 168 - _inset), }; - double get defaultHeight => asset == smallAsset ? 40 : asset == mediumSmallAsset ? 36 : 56; + double get defaultHeight => asset == smallAsset + ? 40 + : asset == mediumSmallAsset + ? 36 + : 56; const GlassContainer({ super.key, @@ -49,7 +53,12 @@ class GlassContainer extends StatelessWidget { ), if (filled) Positioned.fill( - child: DecoratedBox(decoration: BoxDecoration(color: Colors.white.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(14))), + child: DecoratedBox( + decoration: BoxDecoration( + color: Colors.white.withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(14), + ), + ), ), Positioned.fill( child: Padding( diff --git a/mobile-app/lib/v2/screens/home/activity_section.dart b/mobile-app/lib/v2/screens/home/activity_section.dart index 2d0d9943..1be9c4aa 100644 --- a/mobile-app/lib/v2/screens/home/activity_section.dart +++ b/mobile-app/lib/v2/screens/home/activity_section.dart @@ -59,7 +59,7 @@ class ActivitySection extends ConsumerWidget { const SizedBox(height: 40), _header(colors, text, context), const SizedBox(height: 24), - + ...recentTransactions.mapIndexed((index, tx) { final data = TxItemData.from(tx, activeAccount.accountId); final isLastItem = index == recentTransactions.length - 1; @@ -137,7 +137,9 @@ class ActivitySection extends ConsumerWidget { 'View All', style: text.paragraph?.copyWith( color: Colors.transparent, - shadows: [Shadow(color: colors.textSecondary, offset: const Offset(0, -2))], // Shadow trick to create gap between text and underline + shadows: [ + Shadow(color: colors.textSecondary, offset: const Offset(0, -2)), + ], // Shadow trick to create gap between text and underline decoration: TextDecoration.underline, decorationColor: colors.textSecondary, decorationStyle: TextDecorationStyle.solid, diff --git a/mobile-app/lib/v2/screens/swap/deposit_screen.dart b/mobile-app/lib/v2/screens/swap/deposit_screen.dart index a9ec7178..662d87c8 100644 --- a/mobile-app/lib/v2/screens/swap/deposit_screen.dart +++ b/mobile-app/lib/v2/screens/swap/deposit_screen.dart @@ -115,7 +115,10 @@ class _DepositScreenState extends State { Text('Deposit Amount', style: text.smallParagraph?.copyWith(color: colors.textPrimary, height: 1.35)), const SizedBox(width: 6), GestureDetector( - onTap: () => context.copyTextWithToaster(quote.totalAmount.toStringAsFixed(2), message: 'Deposit amount copied to clipboard'), + onTap: () => context.copyTextWithToaster( + quote.totalAmount.toStringAsFixed(2), + message: 'Deposit amount copied to clipboard', + ), child: Container( width: 20, height: 20, From a55d6d7fd75473ed94a2b6003fca5a5604432284 Mon Sep 17 00:00:00 2001 From: Beast Date: Mon, 16 Feb 2026 15:21:21 +0800 Subject: [PATCH 5/9] feat: remove old snackbar and use toaster --- .../components/account_copy_action_sheet.dart | 4 +- .../features/components/emergency_button.dart | 9 +- ...remove_association_confirmation_sheet.dart | 6 +- .../reversible_transaction_action_sheet.dart | 4 +- .../shared_address_action_sheet.dart | 4 +- .../features/components/snackbar_helper.dart | 88 ------------------- .../components/top_snackbar_content.dart | 69 --------------- .../transaction_details_action_sheet.dart | 6 +- .../main/screens/account_settings_screen.dart | 8 +- .../main/screens/create_account_screen.dart | 8 +- .../create_wallet_and_backup_screen.dart | 15 ++-- .../quests/account_associations_screen.dart | 13 +-- .../quests/complete_setup_action_sheet.dart | 12 +-- .../quests/raid_submission_action_sheet.dart | 4 +- .../quests/referrals_quest_screen.dart | 2 +- .../main/screens/quests/update_x_screen.dart | 8 +- .../features/main/screens/receive_screen.dart | 4 +- .../main/screens/send/send_screen.dart | 20 ++--- .../main/screens/settings_screen.dart | 18 ++-- .../screens/show_recovery_phrase_screen.dart | 6 +- .../extensions/clipboard_extensions.dart | 15 ---- .../extensions/snackbar_extensions.dart | 16 ---- .../screens/create/wallet_ready_screen.dart | 4 +- .../v2/screens/settings/settings_screen.dart | 4 +- 24 files changed, 63 insertions(+), 284 deletions(-) delete mode 100644 mobile-app/lib/features/components/snackbar_helper.dart delete mode 100644 mobile-app/lib/features/components/top_snackbar_content.dart delete mode 100644 mobile-app/lib/shared/extensions/snackbar_extensions.dart diff --git a/mobile-app/lib/features/components/account_copy_action_sheet.dart b/mobile-app/lib/features/components/account_copy_action_sheet.dart index ab74ae90..4183d44a 100644 --- a/mobile-app/lib/features/components/account_copy_action_sheet.dart +++ b/mobile-app/lib/features/components/account_copy_action_sheet.dart @@ -40,13 +40,13 @@ class _AccountCopyActionSheetState extends State { } void _copyAddress() { - ClipboardExtensions.copyTextWithSnackbar(context, widget.activeAccount.accountId); + context.copyTextWithToaster(widget.activeAccount.accountId); Navigator.pop(context); } void _copyChecksum() { if (_checksum != null) { - ClipboardExtensions.copyTextWithSnackbar(context, _checksum!, message: 'Checkphrase copied to clipboard'); + context.copyTextWithToaster(_checksum!, message: 'Checkphrase copied to clipboard'); Navigator.pop(context); } } diff --git a/mobile-app/lib/features/components/emergency_button.dart b/mobile-app/lib/features/components/emergency_button.dart index 2334b25e..4a54eef9 100644 --- a/mobile-app/lib/features/components/emergency_button.dart +++ b/mobile-app/lib/features/components/emergency_button.dart @@ -5,7 +5,7 @@ import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/features/components/pull_funds_confirmation_sheet.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; -import 'package:resonance_network_wallet/shared/extensions/snackbar_extensions.dart'; +import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; class EmergencyButton extends ConsumerWidget { const EmergencyButton({super.key}); @@ -33,15 +33,14 @@ class EmergencyButton extends ConsumerWidget { await highSecurityService.pullAllFunds(activeDisplayAccount.account.accountId, guardianAccount); if (context.mounted) { - context.showSuccessSnackbar( - title: 'Success', + context.showSuccessToaster( message: 'Emergency funds pull initiated successfully', ); } } catch (e) { print('Error: Failed to pull funds: $e'); if (context.mounted) { - context.showErrorSnackbar(title: 'Error', message: 'Failed to pull funds: $e'); + context.showErrorToaster(message: 'Failed to pull funds: $e'); } } }, @@ -50,7 +49,7 @@ class EmergencyButton extends ConsumerWidget { } else { print('Error: Guardian account not found on this device'); if (context.mounted) { - context.showErrorSnackbar(title: 'Error', message: 'Guardian account not found on this device'); + context.showErrorToaster(message: 'Guardian account not found on this device'); } } } diff --git a/mobile-app/lib/features/components/remove_association_confirmation_sheet.dart b/mobile-app/lib/features/components/remove_association_confirmation_sheet.dart index 9650efe4..dc20502f 100644 --- a/mobile-app/lib/features/components/remove_association_confirmation_sheet.dart +++ b/mobile-app/lib/features/components/remove_association_confirmation_sheet.dart @@ -5,7 +5,7 @@ import 'package:resonance_network_wallet/features/styles/app_colors_theme.dart'; import 'package:resonance_network_wallet/features/styles/app_size_theme.dart'; import 'package:resonance_network_wallet/features/styles/app_text_theme.dart'; import 'package:resonance_network_wallet/shared/extensions/media_query_data_extension.dart'; -import 'package:resonance_network_wallet/shared/extensions/snackbar_extensions.dart'; +import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; class RemoveAssociationConfirmationSheet extends StatefulWidget { final Future Function() onRemove; @@ -28,7 +28,7 @@ class _RemoveAssociationConfirmationSheetState extends State { } void _copyAddress() { - ClipboardExtensions.copyTextWithSnackbar(context, widget.address); + context.copyTextWithToaster(widget.address); } void _copyChecksum() { if (_checksum != null) { - ClipboardExtensions.copyTextWithSnackbar(context, _checksum!, message: 'Checkphrase copied to clipboard'); + context.copyTextWithToaster(_checksum!, message: 'Checkphrase copied to clipboard'); } } diff --git a/mobile-app/lib/features/components/snackbar_helper.dart b/mobile-app/lib/features/components/snackbar_helper.dart deleted file mode 100644 index 7d4cf237..00000000 --- a/mobile-app/lib/features/components/snackbar_helper.dart +++ /dev/null @@ -1,88 +0,0 @@ -import 'package:flash/flash.dart'; -import 'package:flash/flash_helper.dart'; -import 'package:flutter/material.dart'; -import 'package:resonance_network_wallet/features/components/copy_icon.dart'; -import 'package:resonance_network_wallet/features/components/top_snackbar_content.dart'; -import 'package:resonance_network_wallet/features/styles/app_colors_theme.dart'; -import 'package:resonance_network_wallet/shared/extensions/media_query_data_extension.dart'; - -// Helper function to show a custom top snackbar -Future showTopSnackBar( - BuildContext context, { - required String title, - required String message, - Widget? icon, - Duration duration = const Duration(seconds: 3), // Default duration - FlashBehavior style = FlashBehavior.floating, // Floating style -}) async { - if (!context.mounted) return; - - // Use context.showFlash for better type safety and context awareness if - // available, otherwise fallback to showFlash - await context.showFlash( - duration: duration, - persistent: true, - builder: (context, controller) { - return FlashBar( - controller: controller, - behavior: style, - backgroundColor: Colors.transparent, // FlashBar itself is transparent - surfaceTintColor: Colors.transparent, - shadowColor: Colors.transparent, - indicatorColor: Colors.transparent, - position: FlashPosition.top, // Position at the top - clipBehavior: Clip.none, // Allow shadow to be visible if added - shouldIconPulse: false, - // Pass the actual content widget - content: TopSnackBarContent( - title: title, - message: message, - icon: icon, // Pass the icon through - ), - ); - }, - ); -} - -Future showCopySnackbar(BuildContext context, {required String title, required String message}) async { - await showTopSnackBar( - context, - icon: Container( - width: context.isTablet ? 44 : 36, - height: context.isTablet ? 44 : 36, - decoration: const ShapeDecoration(color: Color(0xFF494949), shape: OvalBorder()), - alignment: Alignment.center, - child: const CopyIcon(), - ), - title: title, - message: message, - ); -} - -Future showWarningSnackbar(BuildContext context, {required String title, required String message}) async { - await showTopSnackBar( - context, - title: title, - message: message, - icon: const Icon(Icons.warning, color: Colors.amber), - ); -} - -Future showErrorSnackbar(BuildContext context, {required String title, required String message}) async { - await showTopSnackBar( - context, - title: title, - message: message, - duration: const Duration(seconds: 10), - icon: Icon(Icons.error_rounded, color: context.themeColors.error), - ); -} - -Future showSuccessSnackbar(BuildContext context, {required String title, required String message}) async { - await showTopSnackBar( - context, - title: title, - message: message, - icon: Icon(Icons.check_circle_rounded, color: context.themeColors.buttonSuccess), - ); -} diff --git a/mobile-app/lib/features/components/top_snackbar_content.dart b/mobile-app/lib/features/components/top_snackbar_content.dart deleted file mode 100644 index afa944b2..00000000 --- a/mobile-app/lib/features/components/top_snackbar_content.dart +++ /dev/null @@ -1,69 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:resonance_network_wallet/features/styles/app_colors_theme.dart'; -import 'package:resonance_network_wallet/features/styles/app_text_theme.dart'; -import 'package:resonance_network_wallet/shared/extensions/media_query_data_extension.dart'; - -class TopSnackBarContent extends StatelessWidget { - final String title; - final String message; - final Widget? icon; - - const TopSnackBarContent({super.key, required this.title, required this.message, this.icon}); - - @override - Widget build(BuildContext context) { - // Default Icon if none provided - final Widget displayIcon = - icon ?? - Container( - width: context.isTablet ? 44 : 36, - height: context.isTablet ? 44 : 36, - decoration: const ShapeDecoration( - color: Color(0xFF494949), // Default grey background - shape: OvalBorder(), // Use OvalBorder for circle - ), - alignment: Alignment.center, - child: Icon(Icons.check, color: Colors.white, size: context.isTablet ? 24 : 20), // Default check icon - ); - - return Container( - // width: 343, // Width will be handled by the flash package's constraints - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), - decoration: ShapeDecoration( - color: Colors.white, // White background - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)), - // Optional shadow for better visibility - shadows: const [BoxShadow(color: Colors.black26, blurRadius: 4, offset: Offset(0, 2))], - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - displayIcon, // Use the provided or default icon - const SizedBox(width: 16), // Spacing - Expanded( - // Allow text to wrap - child: Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - title, - style: context.themeText.smallParagraph?.copyWith(color: context.themeColors.textSecondary), - ), - const SizedBox(height: 2), // Spacing - Text( - message, - style: context.themeText.detail?.copyWith(color: Colors.black.useOpacity(0.6)), - // softWrap: true, // Ensure message wraps - ), - ], - ), - ), - ], - ), - ); - } -} diff --git a/mobile-app/lib/features/components/transaction_details_action_sheet.dart b/mobile-app/lib/features/components/transaction_details_action_sheet.dart index 6919153a..f6c51451 100644 --- a/mobile-app/lib/features/components/transaction_details_action_sheet.dart +++ b/mobile-app/lib/features/components/transaction_details_action_sheet.dart @@ -18,7 +18,7 @@ import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/services/transaction_submission_service.dart'; import 'package:resonance_network_wallet/shared/extensions/clipboard_extensions.dart'; import 'package:resonance_network_wallet/shared/extensions/media_query_data_extension.dart'; -import 'package:resonance_network_wallet/shared/extensions/snackbar_extensions.dart'; +import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/shared/extensions/transaction_event_extension.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -145,7 +145,7 @@ class _TransactionDetailsActionSheetState extends ConsumerState ClipboardExtensions.copyTextWithSnackbar(context, accountId), + onTap: () => context.copyTextWithToaster(accountId), child: Padding( padding: const EdgeInsets.all(8.0), child: Row( diff --git a/mobile-app/lib/features/main/screens/account_settings_screen.dart b/mobile-app/lib/features/main/screens/account_settings_screen.dart index a1896662..0aa735f8 100644 --- a/mobile-app/lib/features/main/screens/account_settings_screen.dart +++ b/mobile-app/lib/features/main/screens/account_settings_screen.dart @@ -23,8 +23,8 @@ import 'package:resonance_network_wallet/features/styles/app_colors_theme.dart'; import 'package:resonance_network_wallet/features/styles/app_text_theme.dart'; import 'package:resonance_network_wallet/shared/extensions/clipboard_extensions.dart'; import 'package:resonance_network_wallet/shared/extensions/media_query_data_extension.dart'; -import 'package:resonance_network_wallet/shared/extensions/snackbar_extensions.dart'; import 'package:resonance_network_wallet/shared/extensions/svg_extensions.dart'; +import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/utils/feature_flags.dart'; class AccountSettingsScreen extends ConsumerStatefulWidget { @@ -151,7 +151,7 @@ class _AccountSettingsScreenState extends ConsumerState { } catch (e) { print('Failed to disconnect: $e'); if (mounted) { - context.showErrorSnackbar(title: 'Error', message: 'Failed to disconnect wallet: $e'); + context.showErrorToaster(message: 'Failed to disconnect wallet: $e'); } } } @@ -278,7 +278,7 @@ class _AccountSettingsScreenState extends ConsumerState { child: Padding( padding: const EdgeInsets.only(top: 10.0, left: 10.0, bottom: 10.0, right: 18.0), child: InkWell( - onTap: () => ClipboardExtensions.copyTextWithSnackbar(context, widget.account.accountId), + onTap: () => context.copyTextWithToaster(widget.account.accountId), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -293,7 +293,7 @@ class _AccountSettingsScreenState extends ConsumerState { ), InkWell( child: const CopyIcon(), - onTap: () => ClipboardExtensions.copyTextWithSnackbar(context, widget.account.accountId), + onTap: () => context.copyTextWithToaster(widget.account.accountId), ), ], ), diff --git a/mobile-app/lib/features/main/screens/create_account_screen.dart b/mobile-app/lib/features/main/screens/create_account_screen.dart index a6adf675..5995bee5 100644 --- a/mobile-app/lib/features/main/screens/create_account_screen.dart +++ b/mobile-app/lib/features/main/screens/create_account_screen.dart @@ -14,7 +14,7 @@ import 'package:resonance_network_wallet/providers/notification_provider.dart'; import 'package:resonance_network_wallet/services/referral_service.dart'; import 'package:resonance_network_wallet/services/telemetry_service.dart'; import 'package:resonance_network_wallet/shared/extensions/clipboard_extensions.dart'; -import 'package:resonance_network_wallet/shared/extensions/snackbar_extensions.dart'; +import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; class CreateAccountScreen extends ConsumerStatefulWidget { final Account? accountToEdit; @@ -70,7 +70,7 @@ class _CreateAccountScreenState extends ConsumerState { setState(() { _isLoading = false; }); - context.showErrorSnackbar(title: 'Error', message: 'Failed to load account details: $e'); + context.showErrorToaster(message: 'Failed to load account details: $e'); } } } @@ -97,7 +97,7 @@ class _CreateAccountScreenState extends ConsumerState { setState(() { _isLoading = false; }); - context.showErrorSnackbar(title: 'Error', message: 'Failed to generate account details: $e'); + context.showErrorToaster(message: 'Failed to generate account details: $e'); } } } @@ -218,7 +218,7 @@ class _CreateAccountScreenState extends ConsumerState { : AddressFormattingService.splitIntoChunks(_provisionalAccount.accountId).join(' '), icon: const CopyIcon(), onPressed: () { - ClipboardExtensions.copyTextWithSnackbar(context, _provisionalAccount.accountId); + context.copyTextWithToaster(_provisionalAccount.accountId); }, label: 'ACCOUNT ADDRESS', ), diff --git a/mobile-app/lib/features/main/screens/create_wallet_and_backup_screen.dart b/mobile-app/lib/features/main/screens/create_wallet_and_backup_screen.dart index 62d610f4..6dfaaabb 100644 --- a/mobile-app/lib/features/main/screens/create_wallet_and_backup_screen.dart +++ b/mobile-app/lib/features/main/screens/create_wallet_and_backup_screen.dart @@ -10,7 +10,6 @@ import 'package:resonance_network_wallet/features/components/copy_icon.dart'; import 'package:resonance_network_wallet/features/components/custom_text_field.dart'; import 'package:resonance_network_wallet/features/components/mnemonic_grid.dart'; import 'package:resonance_network_wallet/features/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/features/components/snackbar_helper.dart'; import 'package:resonance_network_wallet/features/components/sphere.dart'; import 'package:resonance_network_wallet/features/components/wallet_app_bar.dart'; import 'package:resonance_network_wallet/features/main/screens/navbar.dart'; @@ -21,6 +20,7 @@ import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/services/referral_service.dart'; import 'package:resonance_network_wallet/services/telemetry_service.dart'; import 'package:resonance_network_wallet/shared/extensions/clipboard_extensions.dart'; +import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; class CreateWalletAndBackupScreen extends ConsumerStatefulWidget { const CreateWalletAndBackupScreen({super.key, this.walletIndex = 0, this.popOnComplete = false}); @@ -96,7 +96,7 @@ class CreateWalletAndBackupScreenState extends ConsumerState words, bool isLo width: double.infinity, child: GestureDetector( onTap: () { - Clipboard.setData(ClipboardData(text: mnemonic)); - showTopSnackBar( - context, - title: 'Copied!', - message: 'Recovery phrase copied to clipboard', - ); + context.copyTextWithToaster(mnemonic, message: 'Recovery phrase copied to clipboard'); telemetry.sendEvent('onboarding_copy_recovery_phrase'); }, child: Opacity( diff --git a/mobile-app/lib/features/main/screens/quests/account_associations_screen.dart b/mobile-app/lib/features/main/screens/quests/account_associations_screen.dart index 496a5af1..2dba2660 100644 --- a/mobile-app/lib/features/main/screens/quests/account_associations_screen.dart +++ b/mobile-app/lib/features/main/screens/quests/account_associations_screen.dart @@ -18,7 +18,7 @@ import 'package:resonance_network_wallet/providers/account_associations_provider import 'package:resonance_network_wallet/providers/raider_quest_providers.dart'; import 'package:resonance_network_wallet/shared/extensions/clipboard_extensions.dart'; import 'package:resonance_network_wallet/shared/extensions/media_query_data_extension.dart'; -import 'package:resonance_network_wallet/shared/extensions/snackbar_extensions.dart'; +import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; class AccountAssociationsScreen extends ConsumerStatefulWidget { const AccountAssociationsScreen({super.key}); @@ -52,8 +52,7 @@ class _AccountAssociationsScreenState extends ConsumerState { } catch (e) { if (mounted) { setState(() => _isUnlinking = false); - context.showErrorSnackbar(title: 'Error', message: 'Error: $e'); + context.showErrorToaster(message: 'Error: $e'); } } } diff --git a/mobile-app/lib/features/main/screens/quests/raid_submission_action_sheet.dart b/mobile-app/lib/features/main/screens/quests/raid_submission_action_sheet.dart index 0f7554f5..1aeb25f5 100644 --- a/mobile-app/lib/features/main/screens/quests/raid_submission_action_sheet.dart +++ b/mobile-app/lib/features/main/screens/quests/raid_submission_action_sheet.dart @@ -12,7 +12,7 @@ import 'package:resonance_network_wallet/features/styles/app_size_theme.dart'; import 'package:resonance_network_wallet/features/styles/app_text_theme.dart'; import 'package:resonance_network_wallet/providers/raider_quest_providers.dart'; import 'package:resonance_network_wallet/shared/extensions/media_query_data_extension.dart'; -import 'package:resonance_network_wallet/shared/extensions/snackbar_extensions.dart'; +import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/utils/validators.dart'; class RaidSubmissionActionSheet extends ConsumerStatefulWidget { @@ -68,7 +68,7 @@ class _RaidSubmissionActionSheetState extends ConsumerState { void _copyReferralCode() { if (_referralCode != null) { - ClipboardExtensions.copyTextWithSnackbar(context, _referralCode!, message: 'Referral code copied to clipboard'); + context.copyTextWithToaster(_referralCode!, message: 'Referral code copied to clipboard'); } } diff --git a/mobile-app/lib/features/main/screens/quests/update_x_screen.dart b/mobile-app/lib/features/main/screens/quests/update_x_screen.dart index 78590cf1..73b9daea 100644 --- a/mobile-app/lib/features/main/screens/quests/update_x_screen.dart +++ b/mobile-app/lib/features/main/screens/quests/update_x_screen.dart @@ -13,7 +13,7 @@ import 'package:resonance_network_wallet/features/styles/app_size_theme.dart'; import 'package:resonance_network_wallet/features/styles/app_text_theme.dart'; import 'package:resonance_network_wallet/providers/account_associations_providers.dart'; import 'package:resonance_network_wallet/shared/extensions/media_query_data_extension.dart'; -import 'package:resonance_network_wallet/shared/extensions/snackbar_extensions.dart'; +import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/utils/validators.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -58,7 +58,7 @@ class _UpdateXScreenState extends ConsumerState { final Uri url = Uri.parse('https://x.com/${_handleController.text.trim()}'); if (!await launchUrl(url, mode: LaunchMode.externalNonBrowserApplication)) { if (mounted) { - context.showErrorSnackbar(title: 'Error', message: 'Could not launch X app'); + context.showErrorToaster(message: 'Could not launch X app'); } } } @@ -71,7 +71,7 @@ It's quantum secure bitcoin'''; if (!await launchUrl(url, mode: LaunchMode.externalNonBrowserApplication)) { if (mounted) { - context.showErrorSnackbar(title: 'Error', message: 'Could not launch X app'); + context.showErrorToaster(message: 'Could not launch X app'); } } } @@ -110,7 +110,7 @@ It's quantum secure bitcoin'''; await _taskmasterService.associateXHandle(handle); if (mounted) { - context.showSuccessSnackbar(title: 'Success', message: 'X account associated!'); + context.showSuccessToaster(message: 'X account associated!'); } ref.invalidate(accountAssociationsProvider); diff --git a/mobile-app/lib/features/main/screens/receive_screen.dart b/mobile-app/lib/features/main/screens/receive_screen.dart index 7be156d5..2ab6b7a7 100644 --- a/mobile-app/lib/features/main/screens/receive_screen.dart +++ b/mobile-app/lib/features/main/screens/receive_screen.dart @@ -58,13 +58,13 @@ class _ReceiveSheetState extends State { void _copyAddress() { if (_accountId != null) { - ClipboardExtensions.copyTextWithSnackbar(context, _accountId!); + context.copyTextWithToaster(_accountId!); } } void _copyChecksum() { if (_checksum != null) { - ClipboardExtensions.copyTextWithSnackbar(context, _checksum!, message: 'Checkphrase copied to clipboard'); + context.copyTextWithToaster(_checksum!, message: 'Checkphrase copied to clipboard'); } } diff --git a/mobile-app/lib/features/main/screens/send/send_screen.dart b/mobile-app/lib/features/main/screens/send/send_screen.dart index 4079d455..c850f466 100644 --- a/mobile-app/lib/features/main/screens/send/send_screen.dart +++ b/mobile-app/lib/features/main/screens/send/send_screen.dart @@ -10,7 +10,6 @@ import 'package:resonance_network_wallet/features/components/copy_icon.dart'; import 'package:resonance_network_wallet/features/components/custom_text_field.dart'; import 'package:resonance_network_wallet/features/components/scaffold_base.dart'; import 'package:resonance_network_wallet/features/components/segmented_control.dart'; -import 'package:resonance_network_wallet/features/components/snackbar_helper.dart'; import 'package:resonance_network_wallet/features/components/wallet_app_bar.dart'; import 'package:resonance_network_wallet/features/main/screens/send/qr_scanner_screen.dart'; import 'package:resonance_network_wallet/features/main/screens/send/recent_addresses.dart'; @@ -24,6 +23,7 @@ import 'package:resonance_network_wallet/features/styles/app_text_theme.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; import 'package:resonance_network_wallet/shared/extensions/clipboard_extensions.dart'; import 'package:resonance_network_wallet/shared/extensions/media_query_data_extension.dart'; +import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; enum SendMode { immediate, reversible } @@ -316,7 +316,7 @@ class SendScreenState extends ConsumerState { ); }); if (mounted) { - showTopSnackBar(context, title: 'Error', message: 'Error fetching network fee: ${e.toString()}'); + context.showErrorToaster(message: 'Error fetching network fee: ${e.toString()}'); } } } @@ -341,7 +341,7 @@ class SendScreenState extends ConsumerState { Future _setMaxAmount() async { String? recipient = _getValidRecipient(); if (recipient == null) { - showTopSnackBar(context, title: 'Error', message: 'Invalid recipient address'); + context.showErrorToaster(message: 'Invalid recipient address'); return; } @@ -372,12 +372,7 @@ class SendScreenState extends ConsumerState { } catch (e, s) { print('Error setting max amount: $e'); print('Error setting max amount stack trace: $s'); - showTopSnackBar( - // ignore: use_build_context_synchronously - context, - title: 'Error', - message: 'Error setting max amount: $e', - ); + if (mounted) context.showErrorToaster(message: 'Error setting max amount: $e'); } } @@ -603,12 +598,7 @@ class SendScreenState extends ConsumerState { padding: const EdgeInsets.only(bottom: 10.0), child: InkWell( onTap: () async { - ClipboardExtensions.copyTextWithSnackbar( - context, - _humanReadableCheckphrase, - title: 'Copied', - message: 'Check phrase copied to clipboard', - ); + context.copyTextWithToaster(_humanReadableCheckphrase, message: 'Check phrase copied to clipboard'); HapticFeedback.lightImpact(); }, borderRadius: BorderRadius.circular(4), diff --git a/mobile-app/lib/features/main/screens/settings_screen.dart b/mobile-app/lib/features/main/screens/settings_screen.dart index 76afbc5d..e07abeb5 100644 --- a/mobile-app/lib/features/main/screens/settings_screen.dart +++ b/mobile-app/lib/features/main/screens/settings_screen.dart @@ -6,7 +6,6 @@ import 'package:resonance_network_wallet/features/components/list_item.dart'; import 'package:resonance_network_wallet/features/components/referral_action_sheet.dart'; import 'package:resonance_network_wallet/features/components/reset_confirmation_bottom_sheet.dart'; import 'package:resonance_network_wallet/features/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/features/components/snackbar_helper.dart'; import 'package:resonance_network_wallet/features/components/sphere.dart'; import 'package:resonance_network_wallet/features/components/wallet_app_bar.dart'; import 'package:resonance_network_wallet/features/main/screens/accounts_screen.dart'; @@ -23,6 +22,7 @@ import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/pending_transactions_provider.dart'; import 'package:resonance_network_wallet/services/referral_service.dart'; import 'package:resonance_network_wallet/shared/extensions/media_query_data_extension.dart'; +import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/account_utils.dart'; import 'package:share_plus/share_plus.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -78,7 +78,7 @@ class _SettingsScreenState extends ConsumerState { } catch (e) { debugPrint('Logout error: $e'); if (mounted) { - showTopSnackBar(context, title: 'Error', message: 'Logout failed: $e'); + context.showErrorToaster(message: 'Logout failed: $e'); } } } @@ -98,7 +98,7 @@ class _SettingsScreenState extends ConsumerState { final walletIndices = getNonHardwareWalletIndices(accounts); if (walletIndices.isEmpty) { - showTopSnackBar(context, title: 'No Wallets', message: 'No wallets with recovery phrases found.'); + context.showErrorToaster(message: 'No wallets with recovery phrases found.'); return; } @@ -288,21 +288,13 @@ class _SettingsScreenState extends ConsumerState { await migrationService.createDebugOldAccounts(); if (mounted) { - showTopSnackBar( - context, - title: 'Debug', + context.showWarningToaster( message: 'Created debug old accounts with indices 0 and 1. Restart app to see migration dialog.', - icon: const Icon(Icons.check_circle, color: Colors.green), ); } } catch (e) { if (mounted) { - showTopSnackBar( - context, - title: 'Error', - message: 'Failed to create debug accounts: ${e.toString()}', - icon: const Icon(Icons.error, color: Colors.red), - ); + context.showErrorToaster(message: 'Failed to create debug accounts: ${e.toString()}'); } } } diff --git a/mobile-app/lib/features/main/screens/show_recovery_phrase_screen.dart b/mobile-app/lib/features/main/screens/show_recovery_phrase_screen.dart index 1d1f4ce6..0d60276d 100644 --- a/mobile-app/lib/features/main/screens/show_recovery_phrase_screen.dart +++ b/mobile-app/lib/features/main/screens/show_recovery_phrase_screen.dart @@ -126,11 +126,7 @@ class _ShowRecoveryPhraseScreenState extends State { padding: const EdgeInsets.symmetric(horizontal: 25.0), child: InkWell( onTap: () { - ClipboardExtensions.copyTextWithSnackbar( - context, - _recoveryPhrase.join(' '), - message: 'Recovery phrase copied to clipboard', - ); + context.copyTextWithToaster(_recoveryPhrase.join(' '), message: 'Recovery phrase copied to clipboard'); TelemetryService().sendEvent('settings_copy_recovery_phrase'); }, child: Opacity( diff --git a/mobile-app/lib/shared/extensions/clipboard_extensions.dart b/mobile-app/lib/shared/extensions/clipboard_extensions.dart index 9740cad9..63fed051 100644 --- a/mobile-app/lib/shared/extensions/clipboard_extensions.dart +++ b/mobile-app/lib/shared/extensions/clipboard_extensions.dart @@ -1,22 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:resonance_network_wallet/features/components/snackbar_helper.dart'; import 'package:resonance_network_wallet/v2/components/toaster_helper.dart'; -extension ClipboardExtensions on Clipboard { - static Future copyTextWithSnackbar( - BuildContext context, - String text, { - String title = 'Copied!', - String message = 'Address copied to clipboard', - }) async { - await Clipboard.setData(ClipboardData(text: text)); - - // ignore: use_build_context_synchronously - await showCopySnackbar(context, title: title, message: message); - } -} - extension ClipboardWithToasterExtensions on BuildContext { Future copyTextWithToaster(String text, {String message = 'Address copied to clipboard'}) async { await Clipboard.setData(ClipboardData(text: text)); diff --git a/mobile-app/lib/shared/extensions/snackbar_extensions.dart b/mobile-app/lib/shared/extensions/snackbar_extensions.dart deleted file mode 100644 index 1547e7b8..00000000 --- a/mobile-app/lib/shared/extensions/snackbar_extensions.dart +++ /dev/null @@ -1,16 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:resonance_network_wallet/features/components/snackbar_helper.dart' as sh; - -extension SnackbarExtensions on BuildContext { - Future showSuccessSnackbar({required String title, required String message}) async { - await sh.showSuccessSnackbar(this, title: title, message: message); - } - - Future showWarningSnackbar({required String title, required String message}) async { - await sh.showWarningSnackbar(this, title: title, message: message); - } - - Future showErrorSnackbar({required String title, required String message}) async { - await sh.showErrorSnackbar(this, title: title, message: message); - } -} diff --git a/mobile-app/lib/v2/screens/create/wallet_ready_screen.dart b/mobile-app/lib/v2/screens/create/wallet_ready_screen.dart index 9b853fea..945df0ea 100644 --- a/mobile-app/lib/v2/screens/create/wallet_ready_screen.dart +++ b/mobile-app/lib/v2/screens/create/wallet_ready_screen.dart @@ -1,11 +1,11 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:resonance_network_wallet/features/components/snackbar_helper.dart'; import 'package:resonance_network_wallet/features/main/screens/create_wallet_and_backup_screen.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/services/referral_service.dart'; import 'package:resonance_network_wallet/shared/extensions/clipboard_extensions.dart'; +import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/v2/components/back_button.dart'; import 'package:resonance_network_wallet/v2/components/glass_container.dart'; import 'package:resonance_network_wallet/v2/components/gradient_background.dart'; @@ -91,7 +91,7 @@ class _WalletReadyScreenV2State extends ConsumerState { if (!mounted) return; Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (_) => const HomeScreen()), (route) => false); } catch (e) { - if (mounted) showCopySnackbar(context, title: 'Error', message: 'Error saving wallet: $e'); + if (mounted) context.showErrorToaster(message: 'Error saving wallet: $e'); } finally { if (mounted) setState(() => _isSubmitting = false); } diff --git a/mobile-app/lib/v2/screens/settings/settings_screen.dart b/mobile-app/lib/v2/screens/settings/settings_screen.dart index ea814254..9a26d5e1 100644 --- a/mobile-app/lib/v2/screens/settings/settings_screen.dart +++ b/mobile-app/lib/v2/screens/settings/settings_screen.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/features/components/reset_confirmation_bottom_sheet.dart'; -import 'package:resonance_network_wallet/features/components/snackbar_helper.dart'; +import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/v2/screens/settings/recovery_phrase_screen.dart'; import 'package:resonance_network_wallet/v2/screens/settings/select_wallet_screen.dart'; import 'package:resonance_network_wallet/v2/screens/welcome/welcome_screen.dart'; @@ -71,7 +71,7 @@ class _SettingsScreenV2State extends ConsumerState { if (enable) { final available = await _authService.isBiometricAvailable(); if (!available) { - if (mounted) showTopSnackBar(context, title: 'Error', message: 'Biometric not available on this device'); + if (mounted) context.showErrorToaster(message: 'Biometric not available on this device'); return; } } From 39b8a90b637a6d6cb9bf655211c35fc6afb892bd Mon Sep 17 00:00:00 2001 From: Beast Date: Mon, 16 Feb 2026 15:24:08 +0800 Subject: [PATCH 6/9] feat: make toaster api better colocated --- mobile-app/lib/shared/extensions/clipboard_extensions.dart | 4 ++-- mobile-app/lib/shared/extensions/toaster_extensions.dart | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/mobile-app/lib/shared/extensions/clipboard_extensions.dart b/mobile-app/lib/shared/extensions/clipboard_extensions.dart index 63fed051..1bb882ed 100644 --- a/mobile-app/lib/shared/extensions/clipboard_extensions.dart +++ b/mobile-app/lib/shared/extensions/clipboard_extensions.dart @@ -1,11 +1,11 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:resonance_network_wallet/v2/components/toaster_helper.dart'; +import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; extension ClipboardWithToasterExtensions on BuildContext { Future copyTextWithToaster(String text, {String message = 'Address copied to clipboard'}) async { await Clipboard.setData(ClipboardData(text: text)); - await showCopyToaster(this, message: message); + showCopyToaster(message: message); } } diff --git a/mobile-app/lib/shared/extensions/toaster_extensions.dart b/mobile-app/lib/shared/extensions/toaster_extensions.dart index 1adf6885..98decab3 100644 --- a/mobile-app/lib/shared/extensions/toaster_extensions.dart +++ b/mobile-app/lib/shared/extensions/toaster_extensions.dart @@ -13,4 +13,8 @@ extension ToasterExtensions on BuildContext { Future showErrorToaster({required String message}) async { await th.showErrorToaster(this, message: message); } + + Future showCopyToaster({required String message}) async { + await th.showCopyToaster(this, message: message); + } } From fcbd5108a3a91a352b892cb8169c5e6d90abb00d Mon Sep 17 00:00:00 2001 From: Beast Date: Mon, 16 Feb 2026 15:28:17 +0800 Subject: [PATCH 7/9] feat: add info toaster, fix configuration for toaster, clean up unused code --- .../lib/shared/extensions/toaster_extensions.dart | 4 ++++ mobile-app/lib/v2/components/toaster.dart | 12 +++--------- mobile-app/lib/v2/components/toaster_helper.dart | 12 ++++++++---- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/mobile-app/lib/shared/extensions/toaster_extensions.dart b/mobile-app/lib/shared/extensions/toaster_extensions.dart index 98decab3..db4e3d7e 100644 --- a/mobile-app/lib/shared/extensions/toaster_extensions.dart +++ b/mobile-app/lib/shared/extensions/toaster_extensions.dart @@ -17,4 +17,8 @@ extension ToasterExtensions on BuildContext { Future showCopyToaster({required String message}) async { await th.showCopyToaster(this, message: message); } + + Future showInfoToaster({required String message}) async { + await th.showInfoToaster(this, message: message); + } } diff --git a/mobile-app/lib/v2/components/toaster.dart b/mobile-app/lib/v2/components/toaster.dart index a1e6a1fb..42380627 100644 --- a/mobile-app/lib/v2/components/toaster.dart +++ b/mobile-app/lib/v2/components/toaster.dart @@ -5,20 +5,15 @@ import 'package:resonance_network_wallet/shared/extensions/media_query_data_exte class Toaster extends StatelessWidget { final String message; - final Icon? icon; + final Icon icon; - const Toaster({super.key, required this.message, this.icon}); + const Toaster({super.key, required this.message, required this.icon}); @override Widget build(BuildContext context) { - final Widget displayIcon = Icon( - icon?.icon ?? Icons.copy, - color: icon?.color ?? Colors.white, - size: context.isTablet ? 20 : 16, - ); + final Widget displayIcon = Icon(icon.icon, color: icon.color, size: context.isTablet ? 20 : 16); return Container( - // width: 343, // Width will be handled by the flash package's constraints padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 20), decoration: ShapeDecoration( color: context.colors.toasterBackground, @@ -28,7 +23,6 @@ class Toaster extends StatelessWidget { ), ), child: Row( - mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.center, children: [ displayIcon, diff --git a/mobile-app/lib/v2/components/toaster_helper.dart b/mobile-app/lib/v2/components/toaster_helper.dart index 5464affc..9eda674b 100644 --- a/mobile-app/lib/v2/components/toaster_helper.dart +++ b/mobile-app/lib/v2/components/toaster_helper.dart @@ -7,19 +7,19 @@ import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; Future showToaster( BuildContext context, { required String message, - Icon? icon, + required Icon icon, Duration duration = const Duration(seconds: 3), - FlashBehavior style = FlashBehavior.floating, + FlashBehavior behavior = FlashBehavior.floating, }) async { if (!context.mounted) return; await context.showFlash( duration: duration, - persistent: true, + persistent: false, builder: (context, controller) { return FlashBar( controller: controller, - behavior: style, + behavior: behavior, backgroundColor: Colors.transparent, surfaceTintColor: Colors.transparent, shadowColor: Colors.transparent, @@ -45,6 +45,10 @@ Future showWarningToaster(BuildContext context, {required String message}) ); } +Future showInfoToaster(BuildContext context, {required String message}) async { + await showToaster(context, message: message, icon: const Icon(Icons.info)); +} + Future showErrorToaster(BuildContext context, {required String message}) async { await showToaster( context, From f04c885d893296c81c468657ef17155c602bcd15 Mon Sep 17 00:00:00 2001 From: I Dewa Gede Bisma Mahendra <60723576+dewabisma@users.noreply.github.com> Date: Mon, 16 Feb 2026 16:25:43 +0800 Subject: [PATCH 8/9] New Auth Wrapper (#386) * feat: create new auth wrapper * fix: code formatting * feat: remove old auth wrapper, rename new auth wrapper to lock screen * feat: revert name back to auth wrapper, add button to trigger authentication * feat: use the unfilled button style --- mobile-app/assets/v2/auth_wrapper_bracket.png | Bin 0 -> 333 bytes mobile-app/lib/features/main/screens/app.dart | 4 +- .../main/screens/authentication_wrapper.dart | 46 ------------- .../lib/v2/screens/auth/auth_wrapper.dart | 64 ++++++++++++++++++ mobile-app/pubspec.yaml | 1 + 5 files changed, 67 insertions(+), 48 deletions(-) create mode 100644 mobile-app/assets/v2/auth_wrapper_bracket.png delete mode 100644 mobile-app/lib/features/main/screens/authentication_wrapper.dart create mode 100644 mobile-app/lib/v2/screens/auth/auth_wrapper.dart diff --git a/mobile-app/assets/v2/auth_wrapper_bracket.png b/mobile-app/assets/v2/auth_wrapper_bracket.png new file mode 100644 index 0000000000000000000000000000000000000000..f993853cfbe72f3b8aadbef989089eca9d650160 GIT binary patch literal 333 zcmeAS@N?(olHy`uVBq!ia0vp^&w;pugAGW^g#B3$q&N#aB8wRqxP?KOkzv*x37{Zj zage(c!@6@aFM%AEbVpxD28NCO+ST>CVq1f$Yq|celF{r5}E*TUQ~hr literal 0 HcmV?d00001 diff --git a/mobile-app/lib/features/main/screens/app.dart b/mobile-app/lib/features/main/screens/app.dart index 127af5b4..112e1746 100644 --- a/mobile-app/lib/features/main/screens/app.dart +++ b/mobile-app/lib/features/main/screens/app.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:resonance_network_wallet/features/main/screens/authentication_wrapper.dart'; import 'package:resonance_network_wallet/features/main/screens/wallet_initializer.dart'; import 'package:resonance_network_wallet/utils/feature_flags.dart'; +import 'package:resonance_network_wallet/v2/screens/auth/auth_wrapper.dart'; import 'package:resonance_network_wallet/v2/theme/app_theme.dart'; import 'package:resonance_network_wallet/services/firebase_messaging_service.dart'; import 'package:resonance_network_wallet/services/local_notifications_service.dart'; @@ -66,7 +66,7 @@ class _ResonanceWalletAppState extends ConsumerState { darkTheme: AppTheme.darkTheme(context), themeMode: ThemeMode.dark, builder: (context, child) { - return Stack(children: [child!, const AuthenticationWrapper()]); + return Stack(children: [child!, const AuthWrapper()]); }, ); } diff --git a/mobile-app/lib/features/main/screens/authentication_wrapper.dart b/mobile-app/lib/features/main/screens/authentication_wrapper.dart deleted file mode 100644 index 94039c6a..00000000 --- a/mobile-app/lib/features/main/screens/authentication_wrapper.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:resonance_network_wallet/features/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/features/styles/app_colors_theme.dart'; -import 'package:resonance_network_wallet/features/styles/app_text_theme.dart'; -import 'package:resonance_network_wallet/providers/local_auth_provider.dart'; - -class AuthenticationWrapper extends ConsumerWidget { - const AuthenticationWrapper({super.key}); - - @override - Widget build(BuildContext context, WidgetRef ref) { - final authState = ref.watch(localAuthProvider); - - if (authState.isAuthenticated) { - // If authenticated, be invisible. - return const SizedBox.shrink(); - } - - return _buildLockScreen(context, ref, authState.isAuthenticating); - } - - Widget _buildLockScreen(BuildContext context, WidgetRef ref, bool isAuthenticating) { - return ScaffoldBase( - child: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text('Authentication Required', style: context.themeText.lockTitle), - const SizedBox(height: 30), - if (isAuthenticating) - CircularProgressIndicator(valueColor: AlwaysStoppedAnimation(context.themeColors.circularLoader)) - else - IconButton( - icon: const Icon(Icons.fingerprint, size: 64), - color: context.themeColors.circularLoader, - onPressed: () { - ref.read(localAuthProvider.notifier).authenticate(); - }, - ), - ], - ), - ), - ); - } -} diff --git a/mobile-app/lib/v2/screens/auth/auth_wrapper.dart b/mobile-app/lib/v2/screens/auth/auth_wrapper.dart new file mode 100644 index 00000000..ae349ccc --- /dev/null +++ b/mobile-app/lib/v2/screens/auth/auth_wrapper.dart @@ -0,0 +1,64 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:resonance_network_wallet/providers/local_auth_provider.dart'; +import 'package:resonance_network_wallet/v2/components/glass_container.dart'; +import 'package:resonance_network_wallet/v2/components/gradient_background.dart'; +import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; +import 'package:resonance_network_wallet/v2/theme/app_spacing.dart'; +import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; + +class AuthWrapper extends ConsumerWidget { + const AuthWrapper({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final authState = ref.watch(localAuthProvider); + + if (authState.isAuthenticated) { + // If authenticated, be invisible. + return const SizedBox.shrink(); + } + + return _buildLockScreen(context, ref, authState.isAuthenticating); + } + + Widget _buildLockScreen(BuildContext context, WidgetRef ref, bool isAuthenticating) { + return Scaffold( + backgroundColor: context.colors.background, + body: GradientBackground( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + 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: 120), + Padding( + padding: EdgeInsets.symmetric(horizontal: context.themeSize.screenPadding), + child: GlassContainer( + asset: GlassContainer.wideAsset, + onTap: () { + ref.read(localAuthProvider.notifier).authenticate(); + }, + child: Center( + child: Text( + 'Unlock Wallet', + style: context.themeText.paragraph?.copyWith( + fontWeight: FontWeight.w500, + color: context.colors.textPrimary, + ), + ), + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/mobile-app/pubspec.yaml b/mobile-app/pubspec.yaml index b91711bb..74401b2f 100644 --- a/mobile-app/pubspec.yaml +++ b/mobile-app/pubspec.yaml @@ -125,6 +125,7 @@ flutter: - assets/v2/swap_clock_counter_clockwise.svg - assets/v2/swap_qr_code.svg - assets/v2/quantus_white_logo.png + - assets/v2/auth_wrapper_bracket.png From 160ea1d7bd111e3fcb4f420a37de0b6b24a41ed4 Mon Sep 17 00:00:00 2001 From: Beast Date: Mon, 16 Feb 2026 16:34:17 +0800 Subject: [PATCH 9/9] fix: toaster icon construction, extensions async await --- .../extensions/clipboard_extensions.dart | 2 +- mobile-app/lib/v2/components/toaster.dart | 9 +++++---- .../lib/v2/components/toaster_helper.dart | 18 +++++++++++------- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/mobile-app/lib/shared/extensions/clipboard_extensions.dart b/mobile-app/lib/shared/extensions/clipboard_extensions.dart index 1bb882ed..b8e22dbd 100644 --- a/mobile-app/lib/shared/extensions/clipboard_extensions.dart +++ b/mobile-app/lib/shared/extensions/clipboard_extensions.dart @@ -6,6 +6,6 @@ extension ClipboardWithToasterExtensions on BuildContext { Future copyTextWithToaster(String text, {String message = 'Address copied to clipboard'}) async { await Clipboard.setData(ClipboardData(text: text)); - showCopyToaster(message: message); + await showCopyToaster(message: message); } } diff --git a/mobile-app/lib/v2/components/toaster.dart b/mobile-app/lib/v2/components/toaster.dart index 42380627..3a7ef267 100644 --- a/mobile-app/lib/v2/components/toaster.dart +++ b/mobile-app/lib/v2/components/toaster.dart @@ -5,13 +5,14 @@ import 'package:resonance_network_wallet/shared/extensions/media_query_data_exte class Toaster extends StatelessWidget { final String message; - final Icon icon; + final IconData iconData; + final Color? iconColor; - const Toaster({super.key, required this.message, required this.icon}); + const Toaster({super.key, required this.message, required this.iconData, this.iconColor}); @override Widget build(BuildContext context) { - final Widget displayIcon = Icon(icon.icon, color: icon.color, size: context.isTablet ? 20 : 16); + final double iconSize = context.isTablet ? 20 : 16; return Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 20), @@ -25,7 +26,7 @@ class Toaster extends StatelessWidget { child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ - displayIcon, + Icon(iconData, color: iconColor, size: iconSize), const SizedBox(width: 12), Expanded(child: Text(message, style: context.themeText.smallParagraph, softWrap: true)), ], diff --git a/mobile-app/lib/v2/components/toaster_helper.dart b/mobile-app/lib/v2/components/toaster_helper.dart index 9eda674b..0b511723 100644 --- a/mobile-app/lib/v2/components/toaster_helper.dart +++ b/mobile-app/lib/v2/components/toaster_helper.dart @@ -7,7 +7,8 @@ import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; Future showToaster( BuildContext context, { required String message, - required Icon icon, + required IconData iconData, + Color? iconColor, Duration duration = const Duration(seconds: 3), FlashBehavior behavior = FlashBehavior.floating, }) async { @@ -27,26 +28,27 @@ Future showToaster( position: FlashPosition.top, clipBehavior: Clip.none, shouldIconPulse: false, - content: Toaster(message: message, icon: icon), + content: Toaster(message: message, iconData: iconData, iconColor: iconColor), ); }, ); } Future showCopyToaster(BuildContext context, {required String message}) async { - await showToaster(context, icon: const Icon(Icons.copy), message: message); + await showToaster(context, iconData: Icons.copy, message: message); } Future showWarningToaster(BuildContext context, {required String message}) async { await showToaster( context, message: message, - icon: const Icon(Icons.warning, color: Colors.amber), + iconData: Icons.warning, + iconColor: Colors.amber, ); } Future showInfoToaster(BuildContext context, {required String message}) async { - await showToaster(context, message: message, icon: const Icon(Icons.info)); + await showToaster(context, message: message, iconData: Icons.info); } Future showErrorToaster(BuildContext context, {required String message}) async { @@ -54,7 +56,8 @@ Future showErrorToaster(BuildContext context, {required String message}) a context, message: message, duration: const Duration(seconds: 10), - icon: Icon(Icons.error_rounded, color: context.colors.error), + iconData: Icons.error_rounded, + iconColor: context.colors.error, ); } @@ -62,6 +65,7 @@ Future showSuccessToaster(BuildContext context, {required String message}) await showToaster( context, message: message, - icon: Icon(Icons.check_circle_rounded, color: context.colors.success), + iconData: Icons.check_circle_rounded, + iconColor: context.colors.success, ); }