From 30aa8091a6a0d69d7f47b5020fb0d462cbeaf5ba Mon Sep 17 00:00:00 2001 From: Beast Date: Thu, 13 Aug 2026 09:32:24 +0800 Subject: [PATCH 01/38] feat: move app theme to SDK --- mobile-app/lib/app.dart | 2 +- .../lib/features/components/custom_text_field.dart | 1 - .../lib/features/components/migration_dialog.dart | 2 -- .../lib/features/components/mnemonic_grid.dart | 4 +--- .../components/shared_address_action_sheet.dart | 2 -- mobile-app/lib/features/components/skeleton.dart | 1 - mobile-app/lib/features/styles/app_theme.dart | 5 ++--- mobile-app/lib/v2/components/account_badge.dart | 2 -- .../address_checkphrase_with_initial.dart | 2 -- .../lib/v2/components/address_details_card.dart | 3 +-- .../lib/v2/components/address_input_field.dart | 2 -- .../components/amount_display_with_conversion.dart | 2 -- .../lib/v2/components/animated_qr_scanner.dart | 2 -- mobile-app/lib/v2/components/back_button.dart | 3 ++- mobile-app/lib/v2/components/base_background.dart | 2 +- .../lib/v2/components/bottom_sheet_container.dart | 3 +-- .../lib/v2/components/confirm_action_sheet.dart | 4 ++-- .../lib/v2/components/decoded_call_view.dart | 2 -- .../lib/v2/components/detail_summary_row.dart | 3 +-- mobile-app/lib/v2/components/explorer_link.dart | 4 ++-- mobile-app/lib/v2/components/loader.dart | 3 +-- mobile-app/lib/v2/components/menu_divider.dart | 2 +- .../v2/components/multisig_signer_list_tile.dart | 2 -- mobile-app/lib/v2/components/multisig_tag.dart | 2 -- .../v2/components/multisig_threshold_slider.dart | 2 -- mobile-app/lib/v2/components/name_field.dart | 3 +-- .../lib/v2/components/private_activity_notice.dart | 3 +-- .../lib/v2/components/proposal_list_tile.dart | 2 -- mobile-app/lib/v2/components/qr_scanner_page.dart | 1 - mobile-app/lib/v2/components/quantus_button.dart | 2 -- .../lib/v2/components/quantus_icon_button.dart | 1 - mobile-app/lib/v2/components/quantus_qr.dart | 2 +- .../lib/v2/components/recovery_phrase_body.dart | 3 +-- mobile-app/lib/v2/components/scaffold_base.dart | 2 +- .../components/scaffold_base_bottom_content.dart | 2 +- .../lib/v2/components/segmented_controls.dart | 3 +-- .../lib/v2/components/share_account_button.dart | 2 +- mobile-app/lib/v2/components/split_card.dart | 2 +- mobile-app/lib/v2/components/toaster.dart | 4 +--- mobile-app/lib/v2/components/toaster_helper.dart | 2 +- mobile-app/lib/v2/components/token_icon.dart | 2 -- mobile-app/lib/v2/components/v2_app_bar.dart | 3 +-- .../lib/v2/components/wormhole_progress_steps.dart | 2 -- .../v2/screens/accounts/account_menu_screen.dart | 2 -- .../v2/screens/accounts/account_ready_screen.dart | 2 -- .../lib/v2/screens/accounts/accounts_screen.dart | 2 -- .../accounts/add_hardware_account_screen.dart | 2 -- .../screens/accounts/connect_keystone_screen.dart | 2 -- .../accounts/multisig_account_menu_screen.dart | 2 -- .../screens/accounts/multisig_details_screen.dart | 2 -- .../accounts/open_accounts_management_button.dart | 2 +- .../v2/screens/accounts/wallet_name_screen.dart | 2 -- .../lib/v2/screens/activity/activity_screen.dart | 2 -- .../screens/activity/transaction_detail_sheet.dart | 2 -- mobile-app/lib/v2/screens/activity/tx_item.dart | 2 -- mobile-app/lib/v2/screens/auth/auth_wrapper.dart | 4 +--- .../lib/v2/screens/home/activity_section.dart | 2 -- .../v2/screens/home/backup_reminder_banner.dart | 3 +-- mobile-app/lib/v2/screens/home/home_screen.dart | 2 -- .../v2/screens/import/import_wallet_screen.dart | 2 -- .../v2/screens/multisig/add_multisig_screen.dart | 2 -- .../screens/multisig/discover_multisig_screen.dart | 2 -- .../multisig/multisig_action_confirm_sheet.dart | 2 -- .../multisig/multisig_activity_section.dart | 2 -- .../multisig/multisig_proposal_detail_sheet.dart | 2 -- .../multisig/multisig_signer_picker_sheet.dart | 2 -- .../lib/v2/screens/multisig/proposal_row.dart | 2 -- .../lib/v2/screens/pos/pos_amount_screen.dart | 2 -- mobile-app/lib/v2/screens/pos/pos_qr_screen.dart | 2 -- .../lib/v2/screens/receive/receive_screen.dart | 2 -- .../send/encrypted_send_progress_screen.dart | 2 -- .../v2/screens/send/encrypted_send_strategy.dart | 1 - .../lib/v2/screens/send/input_amount_screen.dart | 2 -- .../v2/screens/send/keystone_reject_screen.dart | 2 -- .../lib/v2/screens/send/keystone_sign_screen.dart | 2 -- .../v2/screens/send/keystone_signing_widgets.dart | 2 -- .../v2/screens/send/keystone_verify_screen.dart | 2 -- .../v2/screens/send/multisig_propose_strategy.dart | 2 -- .../lib/v2/screens/send/regular_send_strategy.dart | 1 - .../lib/v2/screens/send/review_send_screen.dart | 3 +-- .../v2/screens/send/select_recipient_screen.dart | 2 -- .../lib/v2/screens/send/send_terminal_screen.dart | 2 -- .../v2/screens/settings/about_quantus_screen.dart | 2 -- .../screens/settings/add_account_menu_screen.dart | 2 -- .../screens/settings/help_and_support_screen.dart | 1 - .../v2/screens/settings/mining_rewards_screen.dart | 2 -- .../settings/preferences_settings_screen.dart | 3 +-- .../v2/screens/settings/redeem_address_screen.dart | 2 -- .../screens/settings/redeem_progress_screen.dart | 2 -- .../v2/screens/settings/select_wallet_screen.dart | 3 +-- .../settings/settings_caution_scaffold.dart | 3 +-- .../lib/v2/screens/settings/settings_checkbox.dart | 3 +-- .../lib/v2/screens/settings/settings_divider.dart | 2 +- .../lib/v2/screens/settings/settings_list_row.dart | 3 +-- .../screens/settings/settings_picker_screen.dart | 3 +-- .../screens/settings/settings_picker_widgets.dart | 3 +-- .../lib/v2/screens/settings/settings_screen.dart | 2 +- .../v2/screens/settings/settings_tappable_row.dart | 3 +-- .../screens/settings/testnet_rewards_screen.dart | 3 +-- .../screens/settings/wallet_settings_screen.dart | 2 -- mobile-app/lib/v2/screens/swap/deposit_screen.dart | 2 -- .../screens/swap/refund_address_picker_sheet.dart | 2 -- .../lib/v2/screens/swap/review_quote_sheet.dart | 2 -- mobile-app/lib/v2/screens/swap/swap_screen.dart | 2 -- .../lib/v2/screens/swap/token_picker_sheet.dart | 2 -- .../v2/screens/welcome/onboarding_background.dart | 2 +- .../lib/v2/screens/welcome/welcome_screen.dart | 1 - mobile-app/lib/wallet_initializer.dart | 1 - mobile-app/test/extensions.dart | 2 +- .../unit/shared_address_action_sheet_test.dart | 1 - quantus_sdk/lib/quantus_sdk.dart | 6 ++++++ .../extensions/media_query_data_extension.dart | 0 .../lib/src/ui/themes}/app_colors.dart | 0 .../lib/src/ui/themes}/app_spacing.dart | 0 .../lib/src/ui/themes}/app_text_styles.dart | 0 .../lib/src/ui/themes}/app_theme.dart | 14 -------------- 116 files changed, 51 insertions(+), 213 deletions(-) rename {mobile-app/lib/shared => quantus_sdk/lib/src}/extensions/media_query_data_extension.dart (100%) rename {mobile-app/lib/v2/theme => quantus_sdk/lib/src/ui/themes}/app_colors.dart (100%) rename {mobile-app/lib/v2/theme => quantus_sdk/lib/src/ui/themes}/app_spacing.dart (100%) rename {mobile-app/lib/v2/theme => quantus_sdk/lib/src/ui/themes}/app_text_styles.dart (100%) rename {mobile-app/lib/v2/theme => quantus_sdk/lib/src/ui/themes}/app_theme.dart (65%) diff --git a/mobile-app/lib/app.dart b/mobile-app/lib/app.dart index 8bd6229bd..42485eb77 100644 --- a/mobile-app/lib/app.dart +++ b/mobile-app/lib/app.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/wallet_initializer.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/local_notifications_service.dart'; import 'package:resonance_network_wallet/services/notification_integration_service.dart'; import 'package:resonance_network_wallet/services/telemetry_navigator_observer.dart'; diff --git a/mobile-app/lib/features/components/custom_text_field.dart b/mobile-app/lib/features/components/custom_text_field.dart index 9453c8d60..6c97fda92 100644 --- a/mobile-app/lib/features/components/custom_text_field.dart +++ b/mobile-app/lib/features/components/custom_text_field.dart @@ -1,7 +1,6 @@ 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'; enum TextFieldVariant { primary, secondary } diff --git a/mobile-app/lib/features/components/migration_dialog.dart b/mobile-app/lib/features/components/migration_dialog.dart index 508d28195..0cf47c71e 100644 --- a/mobile-app/lib/features/components/migration_dialog.dart +++ b/mobile-app/lib/features/components/migration_dialog.dart @@ -3,8 +3,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; class MigrationDialog extends ConsumerStatefulWidget { final List migrationResults; diff --git a/mobile-app/lib/features/components/mnemonic_grid.dart b/mobile-app/lib/features/components/mnemonic_grid.dart index f376727c1..227c8ec94 100644 --- a/mobile-app/lib/features/components/mnemonic_grid.dart +++ b/mobile-app/lib/features/components/mnemonic_grid.dart @@ -1,9 +1,7 @@ import 'dart:ui'; import 'package:flutter/material.dart'; -import 'package:resonance_network_wallet/shared/extensions/media_query_data_extension.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; class MnemonicGrid extends StatelessWidget { final List words; diff --git a/mobile-app/lib/features/components/shared_address_action_sheet.dart b/mobile-app/lib/features/components/shared_address_action_sheet.dart index 381f9f08d..59ea9b67e 100644 --- a/mobile-app/lib/features/components/shared_address_action_sheet.dart +++ b/mobile-app/lib/features/components/shared_address_action_sheet.dart @@ -4,14 +4,12 @@ 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/styles/app_colors_theme.dart'; -import 'package:resonance_network_wallet/features/styles/app_text_theme.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; import 'package:resonance_network_wallet/routes.dart'; import 'package:resonance_network_wallet/shared/extensions/clipboard_extensions.dart'; import 'package:resonance_network_wallet/shared/extensions/current_route_extensions.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/print.dart'; import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; diff --git a/mobile-app/lib/features/components/skeleton.dart b/mobile-app/lib/features/components/skeleton.dart index de9b72eed..13bca7cd0 100644 --- a/mobile-app/lib/features/components/skeleton.dart +++ b/mobile-app/lib/features/components/skeleton.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; /// A skeleton widget with shimmer animation for loading states class Skeleton extends StatefulWidget { diff --git a/mobile-app/lib/features/styles/app_theme.dart b/mobile-app/lib/features/styles/app_theme.dart index f877fd85a..68ef2fea1 100644 --- a/mobile-app/lib/features/styles/app_theme.dart +++ b/mobile-app/lib/features/styles/app_theme.dart @@ -1,8 +1,7 @@ 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_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'; + class AppTheme { static ThemeData lightTheme(BuildContext context) { diff --git a/mobile-app/lib/v2/components/account_badge.dart b/mobile-app/lib/v2/components/account_badge.dart index 34d26274f..53bee1686 100644 --- a/mobile-app/lib/v2/components/account_badge.dart +++ b/mobile-app/lib/v2/components/account_badge.dart @@ -1,8 +1,6 @@ import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/shared/utils/account_utils.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; class AccountBadge extends StatelessWidget { final String name; diff --git a/mobile-app/lib/v2/components/address_checkphrase_with_initial.dart b/mobile-app/lib/v2/components/address_checkphrase_with_initial.dart index 00ef9ee3f..5f9906fde 100644 --- a/mobile-app/lib/v2/components/address_checkphrase_with_initial.dart +++ b/mobile-app/lib/v2/components/address_checkphrase_with_initial.dart @@ -1,8 +1,6 @@ import 'package:flutter/widgets.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/shared/utils/account_utils.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; class AddressCheckphraseWithInitial extends StatelessWidget { final String recipientChecksum; diff --git a/mobile-app/lib/v2/components/address_details_card.dart b/mobile-app/lib/v2/components/address_details_card.dart index c8eb5b675..23ce42583 100644 --- a/mobile-app/lib/v2/components/address_details_card.dart +++ b/mobile-app/lib/v2/components/address_details_card.dart @@ -2,12 +2,11 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/shared/extensions/clipboard_extensions.dart'; import 'package:resonance_network_wallet/v2/components/split_card.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; class AddressDetailsCard extends ConsumerStatefulWidget { final String accountId; diff --git a/mobile-app/lib/v2/components/address_input_field.dart b/mobile-app/lib/v2/components/address_input_field.dart index d60a3764e..9e0d8e219 100644 --- a/mobile-app/lib/v2/components/address_input_field.dart +++ b/mobile-app/lib/v2/components/address_input_field.dart @@ -1,7 +1,5 @@ import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; /// Dual-state address input shared by every flow where the user enters a /// destination address (send, redeem, ...). When the controller holds a valid diff --git a/mobile-app/lib/v2/components/amount_display_with_conversion.dart b/mobile-app/lib/v2/components/amount_display_with_conversion.dart index 23143a979..43561c548 100644 --- a/mobile-app/lib/v2/components/amount_display_with_conversion.dart +++ b/mobile-app/lib/v2/components/amount_display_with_conversion.dart @@ -3,8 +3,6 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/currency_display_provider.dart'; import 'package:resonance_network_wallet/v2/components/quantus_icon_button.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; class AmountDisplayWithConversion extends StatelessWidget { final CurrencyDisplayState amountDisplay; diff --git a/mobile-app/lib/v2/components/animated_qr_scanner.dart b/mobile-app/lib/v2/components/animated_qr_scanner.dart index 86ace9089..98dc1cb46 100644 --- a/mobile-app/lib/v2/components/animated_qr_scanner.dart +++ b/mobile-app/lib/v2/components/animated_qr_scanner.dart @@ -5,8 +5,6 @@ import 'package:mobile_scanner/mobile_scanner.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; /// Sequence metadata encoded in one frame of an animated QR payload. class AnimatedQrSequence { diff --git a/mobile-app/lib/v2/components/back_button.dart b/mobile-app/lib/v2/components/back_button.dart index 5de337377..35f0b084a 100644 --- a/mobile-app/lib/v2/components/back_button.dart +++ b/mobile-app/lib/v2/components/back_button.dart @@ -1,7 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/v2/components/glass_button_base.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; + class AppBackButton extends StatelessWidget { final VoidCallback? onTap; diff --git a/mobile-app/lib/v2/components/base_background.dart b/mobile-app/lib/v2/components/base_background.dart index 80bea0eaf..2de4bb7f6 100644 --- a/mobile-app/lib/v2/components/base_background.dart +++ b/mobile-app/lib/v2/components/base_background.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; class BaseBackground extends StatelessWidget { final Widget child; diff --git a/mobile-app/lib/v2/components/bottom_sheet_container.dart b/mobile-app/lib/v2/components/bottom_sheet_container.dart index 3fc43ab12..016dea567 100644 --- a/mobile-app/lib/v2/components/bottom_sheet_container.dart +++ b/mobile-app/lib/v2/components/bottom_sheet_container.dart @@ -1,7 +1,6 @@ import 'dart:ui'; 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:quantus_sdk/quantus_sdk.dart'; class BottomSheetContainer extends StatelessWidget { final String title; diff --git a/mobile-app/lib/v2/components/confirm_action_sheet.dart b/mobile-app/lib/v2/components/confirm_action_sheet.dart index 6760137de..6d4f93da4 100644 --- a/mobile-app/lib/v2/components/confirm_action_sheet.dart +++ b/mobile-app/lib/v2/components/confirm_action_sheet.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/v2/components/bottom_sheet_container.dart'; import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; + /// Generic "are you sure?" confirmation sheet. Resolves to true when the user /// taps the confirm action, false on cancel/dismiss. diff --git a/mobile-app/lib/v2/components/decoded_call_view.dart b/mobile-app/lib/v2/components/decoded_call_view.dart index bf15ed812..b2a33d114 100644 --- a/mobile-app/lib/v2/components/decoded_call_view.dart +++ b/mobile-app/lib/v2/components/decoded_call_view.dart @@ -3,8 +3,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/currency_display_provider.dart'; import 'package:resonance_network_wallet/v2/components/detail_summary_row.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; /// Renders every parameter of a [DecodedCall], nested calls included. /// diff --git a/mobile-app/lib/v2/components/detail_summary_row.dart b/mobile-app/lib/v2/components/detail_summary_row.dart index a7a7cac60..8f2d38db0 100644 --- a/mobile-app/lib/v2/components/detail_summary_row.dart +++ b/mobile-app/lib/v2/components/detail_summary_row.dart @@ -1,6 +1,5 @@ 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:quantus_sdk/quantus_sdk.dart'; /// Label/value row used in review screens and detail sheets. class DetailSummaryRow extends StatelessWidget { diff --git a/mobile-app/lib/v2/components/explorer_link.dart b/mobile-app/lib/v2/components/explorer_link.dart index dee140aa5..5b3312e30 100644 --- a/mobile-app/lib/v2/components/explorer_link.dart +++ b/mobile-app/lib/v2/components/explorer_link.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/shared/utils/open_external_url.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; + /// Underlined "View in Explorer ↗" link that opens [url] in an external /// browser. Shared across the send terminal, POS receipt and the diff --git a/mobile-app/lib/v2/components/loader.dart b/mobile-app/lib/v2/components/loader.dart index 21880d126..9a46186ff 100644 --- a/mobile-app/lib/v2/components/loader.dart +++ b/mobile-app/lib/v2/components/loader.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:resonance_network_wallet/shared/extensions/media_query_data_extension.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; class Loader extends StatelessWidget { final Color? color; diff --git a/mobile-app/lib/v2/components/menu_divider.dart b/mobile-app/lib/v2/components/menu_divider.dart index 1d1ef50e7..64bb9d1ac 100644 --- a/mobile-app/lib/v2/components/menu_divider.dart +++ b/mobile-app/lib/v2/components/menu_divider.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; /// Thin hairline divider used between rows in account/menu lists. class MenuDivider extends StatelessWidget { diff --git a/mobile-app/lib/v2/components/multisig_signer_list_tile.dart b/mobile-app/lib/v2/components/multisig_signer_list_tile.dart index 578cd7b00..af7d476ca 100644 --- a/mobile-app/lib/v2/components/multisig_signer_list_tile.dart +++ b/mobile-app/lib/v2/components/multisig_signer_list_tile.dart @@ -2,8 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; /// Displays a multisig signer with checksum, address, and optional badges. class MultisigSignerListTile extends ConsumerStatefulWidget { diff --git a/mobile-app/lib/v2/components/multisig_tag.dart b/mobile-app/lib/v2/components/multisig_tag.dart index dbe80439b..4cdc35dd3 100644 --- a/mobile-app/lib/v2/components/multisig_tag.dart +++ b/mobile-app/lib/v2/components/multisig_tag.dart @@ -1,7 +1,5 @@ import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; class MultisigTag extends StatelessWidget { final String label; diff --git a/mobile-app/lib/v2/components/multisig_threshold_slider.dart b/mobile-app/lib/v2/components/multisig_threshold_slider.dart index 6eea0e5b2..057e5b839 100644 --- a/mobile-app/lib/v2/components/multisig_threshold_slider.dart +++ b/mobile-app/lib/v2/components/multisig_threshold_slider.dart @@ -1,7 +1,5 @@ import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; /// Slider for choosing how many signer approvals a multisig proposal needs. class MultisigThresholdSlider extends StatelessWidget { diff --git a/mobile-app/lib/v2/components/name_field.dart b/mobile-app/lib/v2/components/name_field.dart index 68878f5a4..97116b743 100644 --- a/mobile-app/lib/v2/components/name_field.dart +++ b/mobile-app/lib/v2/components/name_field.dart @@ -1,8 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; class NameField extends ConsumerWidget { final TextEditingController controller; diff --git a/mobile-app/lib/v2/components/private_activity_notice.dart b/mobile-app/lib/v2/components/private_activity_notice.dart index a8d9ddbb3..da57bc4c0 100644 --- a/mobile-app/lib/v2/components/private_activity_notice.dart +++ b/mobile-app/lib/v2/components/private_activity_notice.dart @@ -1,6 +1,5 @@ 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:quantus_sdk/quantus_sdk.dart'; /// Circular lock badge used for encrypted / private UI (always Quantus orange). class EncryptedLockBadge extends StatelessWidget { diff --git a/mobile-app/lib/v2/components/proposal_list_tile.dart b/mobile-app/lib/v2/components/proposal_list_tile.dart index 07e0385ae..1a0d72eb0 100644 --- a/mobile-app/lib/v2/components/proposal_list_tile.dart +++ b/mobile-app/lib/v2/components/proposal_list_tile.dart @@ -4,8 +4,6 @@ import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/currency_display_provider.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/v2/components/decoded_call_view.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; /// Shared card layout for indexed and pending multisig proposal rows. class ProposalListTile extends ConsumerWidget { diff --git a/mobile-app/lib/v2/components/qr_scanner_page.dart b/mobile-app/lib/v2/components/qr_scanner_page.dart index b6af3996b..d2e4eb82e 100644 --- a/mobile-app/lib/v2/components/qr_scanner_page.dart +++ b/mobile-app/lib/v2/components/qr_scanner_page.dart @@ -7,7 +7,6 @@ import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/v2/components/quantus_icon_button.dart'; import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; class QrScannerPage extends ConsumerStatefulWidget { final bool Function(String)? validator; diff --git a/mobile-app/lib/v2/components/quantus_button.dart b/mobile-app/lib/v2/components/quantus_button.dart index bd1e5b630..687b4a449 100644 --- a/mobile-app/lib/v2/components/quantus_button.dart +++ b/mobile-app/lib/v2/components/quantus_button.dart @@ -2,8 +2,6 @@ import 'dart:math' as math; import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/v2/components/loader.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; enum ButtonVariant { transparent, primary, secondary, danger, success, outline, glass, underline } diff --git a/mobile-app/lib/v2/components/quantus_icon_button.dart b/mobile-app/lib/v2/components/quantus_icon_button.dart index 3126d72ab..d11c5c6ae 100644 --- a/mobile-app/lib/v2/components/quantus_icon_button.dart +++ b/mobile-app/lib/v2/components/quantus_icon_button.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/v2/components/glass_button_base.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; enum IconButtonShape { rounded, circular } diff --git a/mobile-app/lib/v2/components/quantus_qr.dart b/mobile-app/lib/v2/components/quantus_qr.dart index 65c96b87a..97a23e78f 100644 --- a/mobile-app/lib/v2/components/quantus_qr.dart +++ b/mobile-app/lib/v2/components/quantus_qr.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:qr_flutter/qr_flutter.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; class QuantusQr extends StatelessWidget { final String accountId; diff --git a/mobile-app/lib/v2/components/recovery_phrase_body.dart b/mobile-app/lib/v2/components/recovery_phrase_body.dart index 615e3f69c..3b399901c 100644 --- a/mobile-app/lib/v2/components/recovery_phrase_body.dart +++ b/mobile-app/lib/v2/components/recovery_phrase_body.dart @@ -1,5 +1,6 @@ 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/mnemonic_grid.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; @@ -10,8 +11,6 @@ import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; class RecoveryPhraseBody extends ConsumerStatefulWidget { final String appBarTitle; diff --git a/mobile-app/lib/v2/components/scaffold_base.dart b/mobile-app/lib/v2/components/scaffold_base.dart index a982ede31..0f3054eb1 100644 --- a/mobile-app/lib/v2/components/scaffold_base.dart +++ b/mobile-app/lib/v2/components/scaffold_base.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:resonance_network_wallet/features/components/network_status_banner.dart'; import 'package:resonance_network_wallet/v2/components/base_background.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; class ScaffoldBase extends StatelessWidget { final Widget? mainContent; diff --git a/mobile-app/lib/v2/components/scaffold_base_bottom_content.dart b/mobile-app/lib/v2/components/scaffold_base_bottom_content.dart index 1d2ef42d3..74e77cacd 100644 --- a/mobile-app/lib/v2/components/scaffold_base_bottom_content.dart +++ b/mobile-app/lib/v2/components/scaffold_base_bottom_content.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; class ScaffoldBaseBottomContent extends StatelessWidget { final Widget child; diff --git a/mobile-app/lib/v2/components/segmented_controls.dart b/mobile-app/lib/v2/components/segmented_controls.dart index 7e0041ffc..81804da76 100644 --- a/mobile-app/lib/v2/components/segmented_controls.dart +++ b/mobile-app/lib/v2/components/segmented_controls.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:collection/collection.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; class SegmentedControls extends StatelessWidget { final List> items; diff --git a/mobile-app/lib/v2/components/share_account_button.dart b/mobile-app/lib/v2/components/share_account_button.dart index 1eeb17e9b..d6e9c9546 100644 --- a/mobile-app/lib/v2/components/share_account_button.dart +++ b/mobile-app/lib/v2/components/share_account_button.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; class ShareAccountButton extends ConsumerWidget { final VoidCallback onTap; diff --git a/mobile-app/lib/v2/components/split_card.dart b/mobile-app/lib/v2/components/split_card.dart index fa4bb061b..203193f1e 100644 --- a/mobile-app/lib/v2/components/split_card.dart +++ b/mobile-app/lib/v2/components/split_card.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; class SplitCard extends StatelessWidget { final Widget topChild; diff --git a/mobile-app/lib/v2/components/toaster.dart b/mobile-app/lib/v2/components/toaster.dart index 2e9e290df..4b0e54baf 100644 --- a/mobile-app/lib/v2/components/toaster.dart +++ b/mobile-app/lib/v2/components/toaster.dart @@ -1,7 +1,5 @@ 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'; +import 'package:quantus_sdk/quantus_sdk.dart'; class Toaster extends StatelessWidget { final String message; diff --git a/mobile-app/lib/v2/components/toaster_helper.dart b/mobile-app/lib/v2/components/toaster_helper.dart index f877689f0..3a674aae1 100644 --- a/mobile-app/lib/v2/components/toaster_helper.dart +++ b/mobile-app/lib/v2/components/toaster_helper.dart @@ -2,7 +2,7 @@ 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'; +import 'package:quantus_sdk/quantus_sdk.dart'; Future showToaster( BuildContext context, { diff --git a/mobile-app/lib/v2/components/token_icon.dart b/mobile-app/lib/v2/components/token_icon.dart index 885ccdecc..5ceff5edf 100644 --- a/mobile-app/lib/v2/components/token_icon.dart +++ b/mobile-app/lib/v2/components/token_icon.dart @@ -1,7 +1,5 @@ import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; class TokenIcon extends StatelessWidget { final SwapToken token; diff --git a/mobile-app/lib/v2/components/v2_app_bar.dart b/mobile-app/lib/v2/components/v2_app_bar.dart index ec50d2042..4d3b4422d 100644 --- a/mobile-app/lib/v2/components/v2_app_bar.dart +++ b/mobile-app/lib/v2/components/v2_app_bar.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:resonance_network_wallet/v2/components/back_button.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; class V2AppBar extends StatelessWidget { final String title; diff --git a/mobile-app/lib/v2/components/wormhole_progress_steps.dart b/mobile-app/lib/v2/components/wormhole_progress_steps.dart index 26fdec48d..ce0c8c313 100644 --- a/mobile-app/lib/v2/components/wormhole_progress_steps.dart +++ b/mobile-app/lib/v2/components/wormhole_progress_steps.dart @@ -1,7 +1,5 @@ import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; class WormholeProgressSteps extends StatelessWidget { final List<(int, String)> steps; diff --git a/mobile-app/lib/v2/screens/accounts/account_menu_screen.dart b/mobile-app/lib/v2/screens/accounts/account_menu_screen.dart index 3e04446ec..d39679ab3 100644 --- a/mobile-app/lib/v2/screens/accounts/account_menu_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/account_menu_screen.dart @@ -19,8 +19,6 @@ import 'package:resonance_network_wallet/v2/screens/accounts/account_details_scr import 'package:resonance_network_wallet/v2/screens/accounts/accounts_navigation.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/edit_account_screen.dart'; import 'package:resonance_network_wallet/v2/screens/settings/recovery_phrase_confirmation_screen.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; class AccountMenuScreen extends ConsumerWidget { final Account initialAccount; diff --git a/mobile-app/lib/v2/screens/accounts/account_ready_screen.dart b/mobile-app/lib/v2/screens/accounts/account_ready_screen.dart index a71cf5fd5..24519dfbe 100644 --- a/mobile-app/lib/v2/screens/accounts/account_ready_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/account_ready_screen.dart @@ -13,8 +13,6 @@ import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/home/home_screen.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; enum AccountReadyOverviewOrigin { accountCreated, walletCreated, walletImported } diff --git a/mobile-app/lib/v2/screens/accounts/accounts_screen.dart b/mobile-app/lib/v2/screens/accounts/accounts_screen.dart index e24b2f473..8460fa54f 100644 --- a/mobile-app/lib/v2/screens/accounts/accounts_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/accounts_screen.dart @@ -13,7 +13,6 @@ import 'package:resonance_network_wallet/v2/components/quantus_icon_button.dart' import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; @@ -25,7 +24,6 @@ import 'package:resonance_network_wallet/v2/screens/accounts/accounts_navigation import 'package:resonance_network_wallet/v2/screens/accounts/multisig_account_menu_screen.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/wallet_name_screen.dart'; import 'package:resonance_network_wallet/v2/screens/settings/add_account_menu_screen.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; Future openAccountsScreen(BuildContext context) { return Navigator.of(context).push( diff --git a/mobile-app/lib/v2/screens/accounts/add_hardware_account_screen.dart b/mobile-app/lib/v2/screens/accounts/add_hardware_account_screen.dart index 0105a4e42..71f47a601 100644 --- a/mobile-app/lib/v2/screens/accounts/add_hardware_account_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/add_hardware_account_screen.dart @@ -7,8 +7,6 @@ import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/connect_keystone_screen.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; import 'package:url_launcher/url_launcher.dart'; /// Intro screen for adding a Keystone hardware wallet/account. diff --git a/mobile-app/lib/v2/screens/accounts/connect_keystone_screen.dart b/mobile-app/lib/v2/screens/accounts/connect_keystone_screen.dart index f9e19e3a1..eccf91d25 100644 --- a/mobile-app/lib/v2/screens/accounts/connect_keystone_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/connect_keystone_screen.dart @@ -11,8 +11,6 @@ import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/account_menu_screen.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; /// Second add-Keystone screen: on-device instructions, then scans the device's /// QR code to read the account address and saves the Keystone account. diff --git a/mobile-app/lib/v2/screens/accounts/multisig_account_menu_screen.dart b/mobile-app/lib/v2/screens/accounts/multisig_account_menu_screen.dart index b76bda3c5..621ea3f6c 100644 --- a/mobile-app/lib/v2/screens/accounts/multisig_account_menu_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/multisig_account_menu_screen.dart @@ -18,8 +18,6 @@ import 'package:resonance_network_wallet/v2/screens/accounts/account_details_scr import 'package:resonance_network_wallet/v2/screens/accounts/accounts_navigation.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/edit_account_screen.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/multisig_details_screen.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; class MultisigAccountMenuScreen extends ConsumerWidget { final MultisigAccount initialAccount; diff --git a/mobile-app/lib/v2/screens/accounts/multisig_details_screen.dart b/mobile-app/lib/v2/screens/accounts/multisig_details_screen.dart index cad4f850e..4c5a05a74 100644 --- a/mobile-app/lib/v2/screens/accounts/multisig_details_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/multisig_details_screen.dart @@ -7,8 +7,6 @@ import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/v2/components/multisig_signer_list_tile.dart'; import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; class MultisigDetailsScreen extends ConsumerWidget { const MultisigDetailsScreen({super.key, required this.account}); diff --git a/mobile-app/lib/v2/screens/accounts/open_accounts_management_button.dart b/mobile-app/lib/v2/screens/accounts/open_accounts_management_button.dart index 00cf58207..f9df36e40 100644 --- a/mobile-app/lib/v2/screens/accounts/open_accounts_management_button.dart +++ b/mobile-app/lib/v2/screens/accounts/open_accounts_management_button.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/v2/components/glass_button_base.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/accounts_screen.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; class OpenAccountsManagementButton extends StatelessWidget { const OpenAccountsManagementButton({super.key}); diff --git a/mobile-app/lib/v2/screens/accounts/wallet_name_screen.dart b/mobile-app/lib/v2/screens/accounts/wallet_name_screen.dart index f58b10e5e..f68dc3cc7 100644 --- a/mobile-app/lib/v2/screens/accounts/wallet_name_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/wallet_name_screen.dart @@ -9,8 +9,6 @@ import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/accounts_navigation.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; /// Names (or renames) a wallet. The name is optional: saving an empty field /// clears it and the wallet falls back to its "Wallet {n}" display name. diff --git a/mobile-app/lib/v2/screens/activity/activity_screen.dart b/mobile-app/lib/v2/screens/activity/activity_screen.dart index 18d2782d8..bd5294983 100644 --- a/mobile-app/lib/v2/screens/activity/activity_screen.dart +++ b/mobile-app/lib/v2/screens/activity/activity_screen.dart @@ -13,8 +13,6 @@ import 'package:resonance_network_wallet/services/transaction_service.dart'; import 'package:resonance_network_wallet/v2/components/loader.dart'; import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/v2/components/v2_app_bar.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/v2/screens/activity/tx_item.dart'; import 'package:resonance_network_wallet/v2/screens/activity/transaction_detail_sheet.dart'; 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 393ce6541..a9275bc15 100644 --- a/mobile-app/lib/v2/screens/activity/transaction_detail_sheet.dart +++ b/mobile-app/lib/v2/screens/activity/transaction_detail_sheet.dart @@ -13,8 +13,6 @@ import 'package:resonance_network_wallet/shared/extensions/transaction_event_ext import 'package:resonance_network_wallet/v2/components/amount_display_with_conversion.dart'; import 'package:resonance_network_wallet/v2/components/bottom_sheet_container.dart'; import 'package:resonance_network_wallet/v2/components/explorer_link.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; void showTransactionDetailSheet(BuildContext context, TransactionEvent tx, String activeAccountId) { if (context.peekTopRouteName == transactionDetailSheetRouteSettings.name) Navigator.pop(context); diff --git a/mobile-app/lib/v2/screens/activity/tx_item.dart b/mobile-app/lib/v2/screens/activity/tx_item.dart index 8cc58666a..d9a99a9bf 100644 --- a/mobile-app/lib/v2/screens/activity/tx_item.dart +++ b/mobile-app/lib/v2/screens/activity/tx_item.dart @@ -2,8 +2,6 @@ import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/shared/extensions/transaction_event_extension.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; class TxItemData { final String label; diff --git a/mobile-app/lib/v2/screens/auth/auth_wrapper.dart b/mobile-app/lib/v2/screens/auth/auth_wrapper.dart index c9ca2f3c0..1e0b79516 100644 --- a/mobile-app/lib/v2/screens/auth/auth_wrapper.dart +++ b/mobile-app/lib/v2/screens/auth/auth_wrapper.dart @@ -1,13 +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/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/local_auth_provider.dart'; import 'package:resonance_network_wallet/v2/components/base_background.dart'; import 'package:resonance_network_wallet/v2/components/loader.dart'; import 'package:resonance_network_wallet/v2/components/quantus_button.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}); diff --git a/mobile-app/lib/v2/screens/home/activity_section.dart b/mobile-app/lib/v2/screens/home/activity_section.dart index 8ddb2d0c6..df04a560d 100644 --- a/mobile-app/lib/v2/screens/home/activity_section.dart +++ b/mobile-app/lib/v2/screens/home/activity_section.dart @@ -14,8 +14,6 @@ import 'package:resonance_network_wallet/shared/constants/e2e_keys.dart'; import 'package:resonance_network_wallet/v2/screens/activity/activity_screen.dart'; import 'package:resonance_network_wallet/v2/screens/activity/transaction_detail_sheet.dart'; import 'package:resonance_network_wallet/v2/screens/activity/tx_item.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; class ActivitySection extends ConsumerStatefulWidget { final AsyncValue txAsync; diff --git a/mobile-app/lib/v2/screens/home/backup_reminder_banner.dart b/mobile-app/lib/v2/screens/home/backup_reminder_banner.dart index ef187b540..38495d200 100644 --- a/mobile-app/lib/v2/screens/home/backup_reminder_banner.dart +++ b/mobile-app/lib/v2/screens/home/backup_reminder_banner.dart @@ -1,9 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/v2/screens/settings/recovery_phrase_confirmation_screen.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; class BackupReminderBanner extends ConsumerWidget { const BackupReminderBanner({super.key, required this.walletIndex}); diff --git a/mobile-app/lib/v2/screens/home/home_screen.dart b/mobile-app/lib/v2/screens/home/home_screen.dart index 95dd84bf6..ee3cad07b 100644 --- a/mobile-app/lib/v2/screens/home/home_screen.dart +++ b/mobile-app/lib/v2/screens/home/home_screen.dart @@ -44,8 +44,6 @@ import 'package:resonance_network_wallet/providers/currency_display_provider.dar import 'package:resonance_network_wallet/providers/wallet_providers.dart'; import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_providers.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/v2/components/global_toast_listener.dart'; import 'package:resonance_network_wallet/v2/screens/home/activity_section.dart'; import 'package:resonance_network_wallet/v2/screens/home/backup_reminder_banner.dart'; diff --git a/mobile-app/lib/v2/screens/import/import_wallet_screen.dart b/mobile-app/lib/v2/screens/import/import_wallet_screen.dart index 213947e14..dec1907e8 100644 --- a/mobile-app/lib/v2/screens/import/import_wallet_screen.dart +++ b/mobile-app/lib/v2/screens/import/import_wallet_screen.dart @@ -17,8 +17,6 @@ import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_cont import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/wallet_name_screen.dart'; import 'package:resonance_network_wallet/v2/screens/home/home_screen.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; class ImportWalletScreenV2 extends ConsumerStatefulWidget { const ImportWalletScreenV2({super.key, this.walletIndex = 0, this.openAccountsOnComplete = false}); diff --git a/mobile-app/lib/v2/screens/multisig/add_multisig_screen.dart b/mobile-app/lib/v2/screens/multisig/add_multisig_screen.dart index 993657a76..9679ff952 100644 --- a/mobile-app/lib/v2/screens/multisig/add_multisig_screen.dart +++ b/mobile-app/lib/v2/screens/multisig/add_multisig_screen.dart @@ -20,8 +20,6 @@ import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/services/local_auth_service.dart'; import 'package:resonance_network_wallet/services/multisig_submission_service.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/accounts_navigation.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; class AddMultisigScreen extends ConsumerStatefulWidget { const AddMultisigScreen({super.key}); diff --git a/mobile-app/lib/v2/screens/multisig/discover_multisig_screen.dart b/mobile-app/lib/v2/screens/multisig/discover_multisig_screen.dart index 3154b044f..f793882aa 100644 --- a/mobile-app/lib/v2/screens/multisig/discover_multisig_screen.dart +++ b/mobile-app/lib/v2/screens/multisig/discover_multisig_screen.dart @@ -10,8 +10,6 @@ import 'package:resonance_network_wallet/shared/utils/print.dart'; import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; class DiscoverMultisigScreen extends ConsumerStatefulWidget { const DiscoverMultisigScreen({super.key}); diff --git a/mobile-app/lib/v2/screens/multisig/multisig_action_confirm_sheet.dart b/mobile-app/lib/v2/screens/multisig/multisig_action_confirm_sheet.dart index 18b6ca009..f3b9c69f5 100644 --- a/mobile-app/lib/v2/screens/multisig/multisig_action_confirm_sheet.dart +++ b/mobile-app/lib/v2/screens/multisig/multisig_action_confirm_sheet.dart @@ -18,8 +18,6 @@ import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_sign_cache.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_sign_screen.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_signing_session.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; /// Estimates the network fee for the action being confirmed. /// diff --git a/mobile-app/lib/v2/screens/multisig/multisig_activity_section.dart b/mobile-app/lib/v2/screens/multisig/multisig_activity_section.dart index 466561e92..b42b5848d 100644 --- a/mobile-app/lib/v2/screens/multisig/multisig_activity_section.dart +++ b/mobile-app/lib/v2/screens/multisig/multisig_activity_section.dart @@ -19,8 +19,6 @@ import 'package:resonance_network_wallet/v2/screens/activity/transaction_detail_ import 'package:resonance_network_wallet/v2/screens/activity/tx_item.dart'; import 'package:resonance_network_wallet/v2/screens/multisig/multisig_proposal_detail_sheet.dart'; import 'package:resonance_network_wallet/v2/screens/multisig/proposal_row.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; /// Home section for a multisig account: open proposals pinned on top, followed /// by a unified activity feed (past proposals + transfers) below. diff --git a/mobile-app/lib/v2/screens/multisig/multisig_proposal_detail_sheet.dart b/mobile-app/lib/v2/screens/multisig/multisig_proposal_detail_sheet.dart index e49f7b778..7b3bcafcd 100644 --- a/mobile-app/lib/v2/screens/multisig/multisig_proposal_detail_sheet.dart +++ b/mobile-app/lib/v2/screens/multisig/multisig_proposal_detail_sheet.dart @@ -26,8 +26,6 @@ import 'package:resonance_network_wallet/v2/screens/multisig/multisig_approve_co import 'package:resonance_network_wallet/v2/screens/multisig/multisig_cancel_confirm_sheet.dart'; import 'package:resonance_network_wallet/v2/screens/multisig/multisig_execute_confirm_sheet.dart'; import 'package:resonance_network_wallet/v2/screens/multisig/multisig_signer_picker_sheet.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; /// Shows proposal detail with approve or execute actions for eligible signers. void showMultisigProposalDetailSheet( diff --git a/mobile-app/lib/v2/screens/multisig/multisig_signer_picker_sheet.dart b/mobile-app/lib/v2/screens/multisig/multisig_signer_picker_sheet.dart index 722247651..b41f7bf74 100644 --- a/mobile-app/lib/v2/screens/multisig/multisig_signer_picker_sheet.dart +++ b/mobile-app/lib/v2/screens/multisig/multisig_signer_picker_sheet.dart @@ -4,8 +4,6 @@ import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/v2/components/account_badge.dart'; import 'package:resonance_network_wallet/v2/components/bottom_sheet_container.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; /// Picks which local signer account should approve a multisig proposal. /// diff --git a/mobile-app/lib/v2/screens/multisig/proposal_row.dart b/mobile-app/lib/v2/screens/multisig/proposal_row.dart index 2f8f69feb..9d73674fe 100644 --- a/mobile-app/lib/v2/screens/multisig/proposal_row.dart +++ b/mobile-app/lib/v2/screens/multisig/proposal_row.dart @@ -8,8 +8,6 @@ import 'package:resonance_network_wallet/providers/pending_multisig_cancellation import 'package:resonance_network_wallet/providers/pending_multisig_executions_provider.dart'; import 'package:resonance_network_wallet/shared/utils/multisig_local_signers.dart'; import 'package:resonance_network_wallet/v2/components/proposal_list_tile.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; class ProposalRow extends ConsumerWidget { final MultisigProposal proposal; diff --git a/mobile-app/lib/v2/screens/pos/pos_amount_screen.dart b/mobile-app/lib/v2/screens/pos/pos_amount_screen.dart index d0f80997f..0f69db475 100644 --- a/mobile-app/lib/v2/screens/pos/pos_amount_screen.dart +++ b/mobile-app/lib/v2/screens/pos/pos_amount_screen.dart @@ -16,8 +16,6 @@ import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/pos/pos_qr_screen.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; class PosAmountScreen extends ConsumerStatefulWidget { const PosAmountScreen({super.key}); diff --git a/mobile-app/lib/v2/screens/pos/pos_qr_screen.dart b/mobile-app/lib/v2/screens/pos/pos_qr_screen.dart index 3a61080a4..65cab7b04 100644 --- a/mobile-app/lib/v2/screens/pos/pos_qr_screen.dart +++ b/mobile-app/lib/v2/screens/pos/pos_qr_screen.dart @@ -23,8 +23,6 @@ import 'package:resonance_network_wallet/services/tx_watch_service.dart'; import 'package:resonance_network_wallet/v2/screens/pos/pos_amount_screen.dart'; import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; class PosQrScreen extends ConsumerStatefulWidget { final BigInt amountToken; diff --git a/mobile-app/lib/v2/screens/receive/receive_screen.dart b/mobile-app/lib/v2/screens/receive/receive_screen.dart index d8acd7bed..af2370223 100644 --- a/mobile-app/lib/v2/screens/receive/receive_screen.dart +++ b/mobile-app/lib/v2/screens/receive/receive_screen.dart @@ -12,7 +12,6 @@ import 'package:resonance_network_wallet/v2/components/loader.dart'; import 'package:resonance_network_wallet/v2/components/quantus_qr.dart'; import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; import 'package:resonance_network_wallet/v2/components/share_account_button.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; import 'package:resonance_network_wallet/shared/extensions/clipboard_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; import 'package:resonance_network_wallet/shared/utils/share_utils.dart'; @@ -20,7 +19,6 @@ import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/v2/components/segmented_controls.dart'; import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; enum ReceiveTab { qrCode, address } diff --git a/mobile-app/lib/v2/screens/send/encrypted_send_progress_screen.dart b/mobile-app/lib/v2/screens/send/encrypted_send_progress_screen.dart index 5e18f72f6..87e5bef42 100644 --- a/mobile-app/lib/v2/screens/send/encrypted_send_progress_screen.dart +++ b/mobile-app/lib/v2/screens/send/encrypted_send_progress_screen.dart @@ -15,8 +15,6 @@ import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/components/wormhole_progress_steps.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_strategy.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_terminal_screen.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; /// Renders an encrypted send driven by [encryptedSendControllerProvider]: the /// controller owns the operation (revalidation, proving, submission, cancel); diff --git a/mobile-app/lib/v2/screens/send/encrypted_send_strategy.dart b/mobile-app/lib/v2/screens/send/encrypted_send_strategy.dart index 05a543c9f..2cb0c37ba 100644 --- a/mobile-app/lib/v2/screens/send/encrypted_send_strategy.dart +++ b/mobile-app/lib/v2/screens/send/encrypted_send_strategy.dart @@ -8,7 +8,6 @@ import 'package:resonance_network_wallet/providers/wallet_providers.dart'; import 'package:resonance_network_wallet/services/local_auth_service.dart'; import 'package:resonance_network_wallet/v2/components/detail_summary_row.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_strategy.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; /// ZK-private transfer from an encrypted (wormhole) account. Coin selection /// runs during fee estimation; submission hands the plan to the proving diff --git a/mobile-app/lib/v2/screens/send/input_amount_screen.dart b/mobile-app/lib/v2/screens/send/input_amount_screen.dart index 373c617aa..290cf00ed 100644 --- a/mobile-app/lib/v2/screens/send/input_amount_screen.dart +++ b/mobile-app/lib/v2/screens/send/input_amount_screen.dart @@ -16,8 +16,6 @@ import 'package:resonance_network_wallet/v2/screens/send/review_send_screen.dart import 'package:resonance_network_wallet/v2/screens/send/send_screen_logic.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_strategy.dart'; import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.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/toaster_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/amount_input_logic.dart'; import 'package:resonance_network_wallet/shared/utils/debouncer.dart'; diff --git a/mobile-app/lib/v2/screens/send/keystone_reject_screen.dart b/mobile-app/lib/v2/screens/send/keystone_reject_screen.dart index 9f0a5d413..4a635fbc5 100644 --- a/mobile-app/lib/v2/screens/send/keystone_reject_screen.dart +++ b/mobile-app/lib/v2/screens/send/keystone_reject_screen.dart @@ -7,8 +7,6 @@ import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_signing_widgets.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; import 'package:url_launcher/url_launcher.dart'; /// Shown when the Keystone screen does not match what the app asked it to diff --git a/mobile-app/lib/v2/screens/send/keystone_sign_screen.dart b/mobile-app/lib/v2/screens/send/keystone_sign_screen.dart index 160073836..d7c968c92 100644 --- a/mobile-app/lib/v2/screens/send/keystone_sign_screen.dart +++ b/mobile-app/lib/v2/screens/send/keystone_sign_screen.dart @@ -17,8 +17,6 @@ import 'package:resonance_network_wallet/v2/screens/send/keystone_sign_cache.dar import 'package:resonance_network_wallet/v2/screens/send/keystone_signing_session.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_signing_widgets.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_verify_screen.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; /// Step 1/3 of Keystone signing: shows the unsigned transaction as an /// animated UR QR for the device to scan. diff --git a/mobile-app/lib/v2/screens/send/keystone_signing_widgets.dart b/mobile-app/lib/v2/screens/send/keystone_signing_widgets.dart index 84ef7cd36..b671be17d 100644 --- a/mobile-app/lib/v2/screens/send/keystone_signing_widgets.dart +++ b/mobile-app/lib/v2/screens/send/keystone_signing_widgets.dart @@ -3,8 +3,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; /// Orange mono "STEP n/3" label shared by the Keystone signing screens. class KeystoneStepLabel extends ConsumerWidget { diff --git a/mobile-app/lib/v2/screens/send/keystone_verify_screen.dart b/mobile-app/lib/v2/screens/send/keystone_verify_screen.dart index ce020a5d9..740d42742 100644 --- a/mobile-app/lib/v2/screens/send/keystone_verify_screen.dart +++ b/mobile-app/lib/v2/screens/send/keystone_verify_screen.dart @@ -12,8 +12,6 @@ import 'package:resonance_network_wallet/v2/screens/send/keystone_reject_screen. import 'package:resonance_network_wallet/v2/screens/send/keystone_signature_scan_screen.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_signing_session.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_signing_widgets.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; /// Step 2/3 of Keystone signing: shows what the device screen should display, /// so the user can compare before approving on the Keystone. diff --git a/mobile-app/lib/v2/screens/send/multisig_propose_strategy.dart b/mobile-app/lib/v2/screens/send/multisig_propose_strategy.dart index b630396e5..5d310a7e6 100644 --- a/mobile-app/lib/v2/screens/send/multisig_propose_strategy.dart +++ b/mobile-app/lib/v2/screens/send/multisig_propose_strategy.dart @@ -15,8 +15,6 @@ import 'package:resonance_network_wallet/shared/utils/print.dart'; import 'package:resonance_network_wallet/v2/components/detail_summary_row.dart'; import 'package:resonance_network_wallet/v2/components/multisig_expiry_value.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_strategy.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; /// Proposes a transfer from a multisig account. The multisig is a view-only /// account, so funds leave from [msig] while the proposing member pays the fee. diff --git a/mobile-app/lib/v2/screens/send/regular_send_strategy.dart b/mobile-app/lib/v2/screens/send/regular_send_strategy.dart index 2326f060d..da45e0b41 100644 --- a/mobile-app/lib/v2/screens/send/regular_send_strategy.dart +++ b/mobile-app/lib/v2/screens/send/regular_send_strategy.dart @@ -16,7 +16,6 @@ import 'package:resonance_network_wallet/v2/screens/send/keystone_sign_cache.dar import 'package:resonance_network_wallet/v2/screens/send/keystone_signing_session.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_providers.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_strategy.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; /// Standard single-signer transfer from the active account. Signs locally, or /// hands off to the Keystone QR flow for hardware accounts. diff --git a/mobile-app/lib/v2/screens/send/review_send_screen.dart b/mobile-app/lib/v2/screens/send/review_send_screen.dart index b5fc32c30..f32c5444f 100644 --- a/mobile-app/lib/v2/screens/send/review_send_screen.dart +++ b/mobile-app/lib/v2/screens/send/review_send_screen.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/currency_display_provider.dart'; @@ -19,8 +20,6 @@ import 'package:resonance_network_wallet/v2/screens/send/encrypted_send_progress import 'package:resonance_network_wallet/v2/screens/send/keystone_sign_screen.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_strategy.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_terminal_screen.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; class ReviewSendScreen extends ConsumerStatefulWidget { final SendStrategy strategy; diff --git a/mobile-app/lib/v2/screens/send/select_recipient_screen.dart b/mobile-app/lib/v2/screens/send/select_recipient_screen.dart index 8a54e3e77..711c8784b 100644 --- a/mobile-app/lib/v2/screens/send/select_recipient_screen.dart +++ b/mobile-app/lib/v2/screens/send/select_recipient_screen.dart @@ -23,8 +23,6 @@ import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/send/input_amount_screen.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_strategy.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; class SelectRecipientScreen extends ConsumerStatefulWidget { final SendStrategy strategy; diff --git a/mobile-app/lib/v2/screens/send/send_terminal_screen.dart b/mobile-app/lib/v2/screens/send/send_terminal_screen.dart index f067e0eb2..22c5ad6f1 100644 --- a/mobile-app/lib/v2/screens/send/send_terminal_screen.dart +++ b/mobile-app/lib/v2/screens/send/send_terminal_screen.dart @@ -11,8 +11,6 @@ import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_cont import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/home/home_screen.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_strategy.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; /// Shared success screen for both regular sends and multisig proposals, /// configured entirely by [SendTerminalContent]. diff --git a/mobile-app/lib/v2/screens/settings/about_quantus_screen.dart b/mobile-app/lib/v2/screens/settings/about_quantus_screen.dart index 938f76f87..bc268f0a1 100644 --- a/mobile-app/lib/v2/screens/settings/about_quantus_screen.dart +++ b/mobile-app/lib/v2/screens/settings/about_quantus_screen.dart @@ -9,8 +9,6 @@ import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_divider.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_tappable_row.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; class AboutQuantusScreenV2 extends ConsumerWidget { const AboutQuantusScreenV2({super.key}); diff --git a/mobile-app/lib/v2/screens/settings/add_account_menu_screen.dart b/mobile-app/lib/v2/screens/settings/add_account_menu_screen.dart index 09d6a25dc..7aeadac1d 100644 --- a/mobile-app/lib/v2/screens/settings/add_account_menu_screen.dart +++ b/mobile-app/lib/v2/screens/settings/add_account_menu_screen.dart @@ -15,8 +15,6 @@ import 'package:resonance_network_wallet/v2/screens/accounts/create_account_scre import 'package:resonance_network_wallet/v2/screens/import/import_wallet_screen.dart'; import 'package:resonance_network_wallet/v2/screens/multisig/add_multisig_screen.dart'; import 'package:resonance_network_wallet/v2/screens/multisig/discover_multisig_screen.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; class AddAccountMenuScreen extends ConsumerStatefulWidget { const AddAccountMenuScreen({super.key}); diff --git a/mobile-app/lib/v2/screens/settings/help_and_support_screen.dart b/mobile-app/lib/v2/screens/settings/help_and_support_screen.dart index 466d2f17e..acf508e2b 100644 --- a/mobile-app/lib/v2/screens/settings/help_and_support_screen.dart +++ b/mobile-app/lib/v2/screens/settings/help_and_support_screen.dart @@ -7,7 +7,6 @@ import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_divider.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_tappable_row.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; class HelpAndSupportScreenV2 extends ConsumerWidget { const HelpAndSupportScreenV2({super.key}); diff --git a/mobile-app/lib/v2/screens/settings/mining_rewards_screen.dart b/mobile-app/lib/v2/screens/settings/mining_rewards_screen.dart index 47970de60..5e2341fbf 100644 --- a/mobile-app/lib/v2/screens/settings/mining_rewards_screen.dart +++ b/mobile-app/lib/v2/screens/settings/mining_rewards_screen.dart @@ -14,8 +14,6 @@ import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_cont import 'package:resonance_network_wallet/v2/components/split_card.dart'; import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/settings/redeem_address_screen.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; class MiningRewardsScreen extends ConsumerWidget { const MiningRewardsScreen({super.key}); diff --git a/mobile-app/lib/v2/screens/settings/preferences_settings_screen.dart b/mobile-app/lib/v2/screens/settings/preferences_settings_screen.dart index 24b3fc215..b3450f7b0 100644 --- a/mobile-app/lib/v2/screens/settings/preferences_settings_screen.dart +++ b/mobile-app/lib/v2/screens/settings/preferences_settings_screen.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/currency_display_provider.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/notification_config_provider.dart'; @@ -10,8 +11,6 @@ import 'package:resonance_network_wallet/v2/screens/settings/currency_picker_scr import 'package:resonance_network_wallet/v2/screens/settings/language_picker_screen.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_divider.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_tappable_row.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; class PreferencesSettingsScreenV2 extends ConsumerStatefulWidget { const PreferencesSettingsScreenV2({super.key}); diff --git a/mobile-app/lib/v2/screens/settings/redeem_address_screen.dart b/mobile-app/lib/v2/screens/settings/redeem_address_screen.dart index dd23edf3d..7e06303a4 100644 --- a/mobile-app/lib/v2/screens/settings/redeem_address_screen.dart +++ b/mobile-app/lib/v2/screens/settings/redeem_address_screen.dart @@ -11,8 +11,6 @@ import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/settings/redeem_progress_screen.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; /// Fullscreen flow to pick a destination address for redeeming mining /// rewards. Defaults the field to the user's primary account (Account 0). diff --git a/mobile-app/lib/v2/screens/settings/redeem_progress_screen.dart b/mobile-app/lib/v2/screens/settings/redeem_progress_screen.dart index ea05313e5..8224093ff 100644 --- a/mobile-app/lib/v2/screens/settings/redeem_progress_screen.dart +++ b/mobile-app/lib/v2/screens/settings/redeem_progress_screen.dart @@ -11,8 +11,6 @@ import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/components/wormhole_progress_steps.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; class RedeemProgressScreen extends ConsumerStatefulWidget { final BigInt redeemableRewards; diff --git a/mobile-app/lib/v2/screens/settings/select_wallet_screen.dart b/mobile-app/lib/v2/screens/settings/select_wallet_screen.dart index 0fe20cd2a..1299f2dcc 100644 --- a/mobile-app/lib/v2/screens/settings/select_wallet_screen.dart +++ b/mobile-app/lib/v2/screens/settings/select_wallet_screen.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; @@ -8,8 +9,6 @@ import 'package:resonance_network_wallet/v2/components/loader.dart'; import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/settings/recovery_phrase_confirmation_screen.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/l10n/app_localizations.dart'; class SelectWalletScreen extends ConsumerWidget { diff --git a/mobile-app/lib/v2/screens/settings/settings_caution_scaffold.dart b/mobile-app/lib/v2/screens/settings/settings_caution_scaffold.dart index c561ca9e9..341323082 100644 --- a/mobile-app/lib/v2/screens/settings/settings_caution_scaffold.dart +++ b/mobile-app/lib/v2/screens/settings/settings_caution_scaffold.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; @@ -7,8 +8,6 @@ import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_checkbox.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_divider.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_list_row.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; class SettingsCautionScaffoldData { final String headline; diff --git a/mobile-app/lib/v2/screens/settings/settings_checkbox.dart b/mobile-app/lib/v2/screens/settings/settings_checkbox.dart index 8ef7d467f..dc83bc91f 100644 --- a/mobile-app/lib/v2/screens/settings/settings_checkbox.dart +++ b/mobile-app/lib/v2/screens/settings/settings_checkbox.dart @@ -1,6 +1,5 @@ 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:quantus_sdk/quantus_sdk.dart'; class SettingsCheckbox extends StatelessWidget { final bool checked; diff --git a/mobile-app/lib/v2/screens/settings/settings_divider.dart b/mobile-app/lib/v2/screens/settings/settings_divider.dart index 7b7bf07c4..d3b9b073e 100644 --- a/mobile-app/lib/v2/screens/settings/settings_divider.dart +++ b/mobile-app/lib/v2/screens/settings/settings_divider.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; enum SettingsDividerStyle { list, walletSection, sectionEmphasis, cardInterior, currencyList } diff --git a/mobile-app/lib/v2/screens/settings/settings_list_row.dart b/mobile-app/lib/v2/screens/settings/settings_list_row.dart index a461c53f3..90ce08cab 100644 --- a/mobile-app/lib/v2/screens/settings/settings_list_row.dart +++ b/mobile-app/lib/v2/screens/settings/settings_list_row.dart @@ -1,6 +1,5 @@ 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:quantus_sdk/quantus_sdk.dart'; class SettingsListRow extends StatelessWidget { const SettingsListRow({super.key, required this.label, required this.content}); diff --git a/mobile-app/lib/v2/screens/settings/settings_picker_screen.dart b/mobile-app/lib/v2/screens/settings/settings_picker_screen.dart index 7a3f8ce20..17ede74c0 100644 --- a/mobile-app/lib/v2/screens/settings/settings_picker_screen.dart +++ b/mobile-app/lib/v2/screens/settings/settings_picker_screen.dart @@ -1,12 +1,11 @@ import 'package:flutter/material.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_divider.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_picker_widgets.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; /// Searchable list for choosing a single settings value (language, currency, etc.). class SettingsPickerScreen extends StatefulWidget { diff --git a/mobile-app/lib/v2/screens/settings/settings_picker_widgets.dart b/mobile-app/lib/v2/screens/settings/settings_picker_widgets.dart index 7bfc3a408..6957d2002 100644 --- a/mobile-app/lib/v2/screens/settings/settings_picker_widgets.dart +++ b/mobile-app/lib/v2/screens/settings/settings_picker_widgets.dart @@ -1,6 +1,5 @@ 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:quantus_sdk/quantus_sdk.dart'; class SettingsPickerSearchField extends StatelessWidget { const SettingsPickerSearchField({ diff --git a/mobile-app/lib/v2/screens/settings/settings_screen.dart b/mobile-app/lib/v2/screens/settings/settings_screen.dart index 64276b4c0..58cb20b43 100644 --- a/mobile-app/lib/v2/screens/settings/settings_screen.dart +++ b/mobile-app/lib/v2/screens/settings/settings_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/flutter_svg.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/generated/version.g.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; @@ -17,7 +18,6 @@ import 'package:resonance_network_wallet/v2/screens/settings/settings_divider.da import 'package:resonance_network_wallet/v2/screens/settings/settings_tappable_row.dart'; import 'package:resonance_network_wallet/v2/screens/settings/mining_rewards_screen.dart'; import 'package:resonance_network_wallet/v2/screens/settings/wallet_settings_screen.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; class SettingsScreenV2 extends ConsumerStatefulWidget { const SettingsScreenV2({super.key}); diff --git a/mobile-app/lib/v2/screens/settings/settings_tappable_row.dart b/mobile-app/lib/v2/screens/settings/settings_tappable_row.dart index c3ed0a6a7..0eb0ddb5a 100644 --- a/mobile-app/lib/v2/screens/settings/settings_tappable_row.dart +++ b/mobile-app/lib/v2/screens/settings/settings_tappable_row.dart @@ -1,7 +1,6 @@ import 'package:flutter/cupertino.dart'; 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:quantus_sdk/quantus_sdk.dart'; abstract final class SettingsTappableRowUtils { static TextStyle? title(AppTextTheme text, AppColorsV2 colors, {Color? color}) { diff --git a/mobile-app/lib/v2/screens/settings/testnet_rewards_screen.dart b/mobile-app/lib/v2/screens/settings/testnet_rewards_screen.dart index aa26fe24b..95b0beffa 100644 --- a/mobile-app/lib/v2/screens/settings/testnet_rewards_screen.dart +++ b/mobile-app/lib/v2/screens/settings/testnet_rewards_screen.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/mining_rewards_provider.dart'; import 'package:resonance_network_wallet/services/mining_rewards_service.dart'; @@ -7,8 +8,6 @@ import 'package:resonance_network_wallet/v2/components/loader.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_divider.dart'; import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/v2/components/v2_app_bar.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/l10n/app_localizations.dart'; class TestnetRewardsScreen extends ConsumerWidget { diff --git a/mobile-app/lib/v2/screens/settings/wallet_settings_screen.dart b/mobile-app/lib/v2/screens/settings/wallet_settings_screen.dart index fa38529b5..50ba90da2 100644 --- a/mobile-app/lib/v2/screens/settings/wallet_settings_screen.dart +++ b/mobile-app/lib/v2/screens/settings/wallet_settings_screen.dart @@ -14,8 +14,6 @@ import 'package:resonance_network_wallet/v2/screens/settings/reset_confirmation_ import 'package:resonance_network_wallet/v2/screens/settings/select_wallet_screen.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_divider.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_tappable_row.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; class WalletSettingsScreenV2 extends ConsumerStatefulWidget { const WalletSettingsScreenV2({super.key}); diff --git a/mobile-app/lib/v2/screens/swap/deposit_screen.dart b/mobile-app/lib/v2/screens/swap/deposit_screen.dart index 323725aa2..21a162176 100644 --- a/mobile-app/lib/v2/screens/swap/deposit_screen.dart +++ b/mobile-app/lib/v2/screens/swap/deposit_screen.dart @@ -11,8 +11,6 @@ import 'package:resonance_network_wallet/v2/components/token_icon.dart'; import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/components/success_check.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/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; diff --git a/mobile-app/lib/v2/screens/swap/refund_address_picker_sheet.dart b/mobile-app/lib/v2/screens/swap/refund_address_picker_sheet.dart index 82dae3120..154ce4bbd 100644 --- a/mobile-app/lib/v2/screens/swap/refund_address_picker_sheet.dart +++ b/mobile-app/lib/v2/screens/swap/refund_address_picker_sheet.dart @@ -3,8 +3,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/v2/components/bottom_sheet_container.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; Future showRefundAddressPickerSheet(BuildContext context, String network) { return BottomSheetContainer.show(context, builder: (_) => _RefundAddressPickerContent(network: network)); diff --git a/mobile-app/lib/v2/screens/swap/review_quote_sheet.dart b/mobile-app/lib/v2/screens/swap/review_quote_sheet.dart index 55dfb1a6a..b3ef49d0a 100644 --- a/mobile-app/lib/v2/screens/swap/review_quote_sheet.dart +++ b/mobile-app/lib/v2/screens/swap/review_quote_sheet.dart @@ -6,8 +6,6 @@ import 'package:resonance_network_wallet/v2/components/bottom_sheet_container.da import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; import 'package:resonance_network_wallet/v2/components/token_icon.dart'; import 'package:resonance_network_wallet/v2/screens/swap/deposit_screen.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/l10n/app_localizations.dart'; void showReviewQuoteSheet(BuildContext context, SwapQuote quote, String refundAddress) { diff --git a/mobile-app/lib/v2/screens/swap/swap_screen.dart b/mobile-app/lib/v2/screens/swap/swap_screen.dart index 3cbb42a2f..df8a696a9 100644 --- a/mobile-app/lib/v2/screens/swap/swap_screen.dart +++ b/mobile-app/lib/v2/screens/swap/swap_screen.dart @@ -13,8 +13,6 @@ import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/swap/refund_address_picker_sheet.dart'; import 'package:resonance_network_wallet/v2/screens/swap/review_quote_sheet.dart'; import 'package:resonance_network_wallet/v2/screens/swap/token_picker_sheet.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; class SwapScreen extends ConsumerStatefulWidget { const SwapScreen({super.key}); diff --git a/mobile-app/lib/v2/screens/swap/token_picker_sheet.dart b/mobile-app/lib/v2/screens/swap/token_picker_sheet.dart index ca3e4a5d0..d2fb7392c 100644 --- a/mobile-app/lib/v2/screens/swap/token_picker_sheet.dart +++ b/mobile-app/lib/v2/screens/swap/token_picker_sheet.dart @@ -5,8 +5,6 @@ import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/v2/components/bottom_sheet_container.dart'; import 'package:resonance_network_wallet/v2/components/loader.dart'; import 'package:resonance_network_wallet/v2/components/token_icon.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/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; diff --git a/mobile-app/lib/v2/screens/welcome/onboarding_background.dart b/mobile-app/lib/v2/screens/welcome/onboarding_background.dart index 3bb243a2b..39cfaf53b 100644 --- a/mobile-app/lib/v2/screens/welcome/onboarding_background.dart +++ b/mobile-app/lib/v2/screens/welcome/onboarding_background.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:resonance_network_wallet/v2/theme/app_colors.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; class OnboardingBackground extends StatelessWidget { const OnboardingBackground({super.key}); diff --git a/mobile-app/lib/v2/screens/welcome/welcome_screen.dart b/mobile-app/lib/v2/screens/welcome/welcome_screen.dart index b0170dfc2..1ac5c1b39 100644 --- a/mobile-app/lib/v2/screens/welcome/welcome_screen.dart +++ b/mobile-app/lib/v2/screens/welcome/welcome_screen.dart @@ -15,7 +15,6 @@ import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/account_ready_screen.dart'; import 'package:resonance_network_wallet/v2/screens/import/import_wallet_screen.dart'; import 'package:resonance_network_wallet/v2/screens/welcome/onboarding_background.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; class WelcomeScreenV2 extends ConsumerStatefulWidget { const WelcomeScreenV2({super.key}); diff --git a/mobile-app/lib/wallet_initializer.dart b/mobile-app/lib/wallet_initializer.dart index 5922b2a03..613664619 100644 --- a/mobile-app/lib/wallet_initializer.dart +++ b/mobile-app/lib/wallet_initializer.dart @@ -10,7 +10,6 @@ import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/v2/screens/home/home_screen.dart'; import 'package:resonance_network_wallet/v2/screens/welcome/welcome_screen.dart'; -import 'package:resonance_network_wallet/v2/theme/app_text_styles.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/services/logout_service.dart'; import 'package:resonance_network_wallet/services/telemetry_service.dart'; diff --git a/mobile-app/test/extensions.dart b/mobile-app/test/extensions.dart index d1a7b9608..02247ab87 100644 --- a/mobile-app/test/extensions.dart +++ b/mobile-app/test/extensions.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/misc.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:resonance_network_wallet/v2/theme/app_theme.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; extension Device on WidgetTester { Size get devicePixel { diff --git a/mobile-app/test/unit/shared_address_action_sheet_test.dart b/mobile-app/test/unit/shared_address_action_sheet_test.dart index 4a936e479..98bade313 100644 --- a/mobile-app/test/unit/shared_address_action_sheet_test.dart +++ b/mobile-app/test/unit/shared_address_action_sheet_test.dart @@ -6,7 +6,6 @@ import 'package:flutter_riverpod/misc.dart'; import 'package:resonance_network_wallet/features/components/shared_address_action_sheet.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; import 'package:resonance_network_wallet/v2/screens/send/input_amount_screen.dart'; -import 'package:resonance_network_wallet/v2/theme/app_theme.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../fakes.dart'; diff --git a/quantus_sdk/lib/quantus_sdk.dart b/quantus_sdk/lib/quantus_sdk.dart index c11614bb1..454bda945 100644 --- a/quantus_sdk/lib/quantus_sdk.dart +++ b/quantus_sdk/lib/quantus_sdk.dart @@ -14,8 +14,14 @@ export 'src/extensions/color_extensions.dart'; export 'src/extensions/context_extension.dart'; export 'src/extensions/decimal_input_filter.dart'; export 'src/extensions/keypair_extensions.dart'; +export 'src/extensions/media_query_data_extension.dart'; export 'src/extensions/string_extensions.dart'; // UI-related exports +export 'src/ui/themes/app_theme.dart'; +export 'src/ui/themes/app_colors.dart'; +export 'src/ui/themes/app_spacing.dart'; +export 'src/ui/themes/app_text_styles.dart'; + export 'src/models/account.dart'; export 'src/models/base_account.dart'; export 'src/models/high_security_data.dart'; diff --git a/mobile-app/lib/shared/extensions/media_query_data_extension.dart b/quantus_sdk/lib/src/extensions/media_query_data_extension.dart similarity index 100% rename from mobile-app/lib/shared/extensions/media_query_data_extension.dart rename to quantus_sdk/lib/src/extensions/media_query_data_extension.dart diff --git a/mobile-app/lib/v2/theme/app_colors.dart b/quantus_sdk/lib/src/ui/themes/app_colors.dart similarity index 100% rename from mobile-app/lib/v2/theme/app_colors.dart rename to quantus_sdk/lib/src/ui/themes/app_colors.dart diff --git a/mobile-app/lib/v2/theme/app_spacing.dart b/quantus_sdk/lib/src/ui/themes/app_spacing.dart similarity index 100% rename from mobile-app/lib/v2/theme/app_spacing.dart rename to quantus_sdk/lib/src/ui/themes/app_spacing.dart diff --git a/mobile-app/lib/v2/theme/app_text_styles.dart b/quantus_sdk/lib/src/ui/themes/app_text_styles.dart similarity index 100% rename from mobile-app/lib/v2/theme/app_text_styles.dart rename to quantus_sdk/lib/src/ui/themes/app_text_styles.dart diff --git a/mobile-app/lib/v2/theme/app_theme.dart b/quantus_sdk/lib/src/ui/themes/app_theme.dart similarity index 65% rename from mobile-app/lib/v2/theme/app_theme.dart rename to quantus_sdk/lib/src/ui/themes/app_theme.dart index b8c7acd9d..d0ae40ae1 100644 --- a/mobile-app/lib/v2/theme/app_theme.dart +++ b/quantus_sdk/lib/src/ui/themes/app_theme.dart @@ -1,14 +1,5 @@ import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:resonance_network_wallet/shared/extensions/media_query_data_extension.dart'; - -import 'package:resonance_network_wallet/features/styles/app_colors_theme.dart' as v1_colors; -import 'package:resonance_network_wallet/features/styles/app_text_theme.dart' as v1_text; -import 'package:resonance_network_wallet/features/styles/app_size_theme.dart' as v1_size; - -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 AppTheme { static ThemeData darkTheme(BuildContext context) { @@ -49,11 +40,6 @@ class AppTheme { extensions: [ colors, text, - isTablet ? const AppSizeTheme.iPad() : const AppSizeTheme.defaultTheme(), - // v1 compat: keeps existing screens working until migrated - const v1_colors.AppColorsTheme.dark(), - isTablet ? const v1_text.AppTextTheme.iPad() : const v1_text.AppTextTheme.defaultTheme(), - isTablet ? const v1_size.AppSizeTheme.iPad() : const v1_size.AppSizeTheme.defaultTheme(), ], ); } From 52c42c74a652f6726b62bf05851a96ad0876d161 Mon Sep 17 00:00:00 2001 From: Beast Date: Thu, 13 Aug 2026 21:17:16 +0800 Subject: [PATCH 02/38] feat: add design system tokens --- mobile-app/lib/features/styles/app_theme.dart | 1 - mobile-app/lib/v2/components/back_button.dart | 1 - .../v2/components/confirm_action_sheet.dart | 1 - .../lib/v2/components/explorer_link.dart | 1 - quantus_sdk/lib/quantus_sdk.dart | 1 + quantus_sdk/lib/src/ui/themes/app_colors.dart | 155 ++++++++++ quantus_sdk/lib/src/ui/themes/app_radius.dart | 61 ++++ .../lib/src/ui/themes/app_text_styles.dart | 287 ++++++++++++++++++ quantus_sdk/lib/src/ui/themes/app_theme.dart | 10 +- 9 files changed, 508 insertions(+), 10 deletions(-) create mode 100644 quantus_sdk/lib/src/ui/themes/app_radius.dart diff --git a/mobile-app/lib/features/styles/app_theme.dart b/mobile-app/lib/features/styles/app_theme.dart index 68ef2fea1..414d126e6 100644 --- a/mobile-app/lib/features/styles/app_theme.dart +++ b/mobile-app/lib/features/styles/app_theme.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/features/styles/app_colors_theme.dart'; - class AppTheme { static ThemeData lightTheme(BuildContext context) { final appColors = const AppColorsTheme.light(); diff --git a/mobile-app/lib/v2/components/back_button.dart b/mobile-app/lib/v2/components/back_button.dart index 35f0b084a..3bfe7c319 100644 --- a/mobile-app/lib/v2/components/back_button.dart +++ b/mobile-app/lib/v2/components/back_button.dart @@ -3,7 +3,6 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/v2/components/glass_button_base.dart'; - class AppBackButton extends StatelessWidget { final VoidCallback? onTap; diff --git a/mobile-app/lib/v2/components/confirm_action_sheet.dart b/mobile-app/lib/v2/components/confirm_action_sheet.dart index 6d4f93da4..dfd015300 100644 --- a/mobile-app/lib/v2/components/confirm_action_sheet.dart +++ b/mobile-app/lib/v2/components/confirm_action_sheet.dart @@ -3,7 +3,6 @@ import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/v2/components/bottom_sheet_container.dart'; import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; - /// Generic "are you sure?" confirmation sheet. Resolves to true when the user /// taps the confirm action, false on cancel/dismiss. Future showConfirmActionSheet( diff --git a/mobile-app/lib/v2/components/explorer_link.dart b/mobile-app/lib/v2/components/explorer_link.dart index 5b3312e30..dbcaa438b 100644 --- a/mobile-app/lib/v2/components/explorer_link.dart +++ b/mobile-app/lib/v2/components/explorer_link.dart @@ -4,7 +4,6 @@ import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/shared/utils/open_external_url.dart'; - /// Underlined "View in Explorer ↗" link that opens [url] in an external /// browser. Shared across the send terminal, POS receipt and the /// transaction/proposal detail sheets. Renders disabled (non-tappable) when diff --git a/quantus_sdk/lib/quantus_sdk.dart b/quantus_sdk/lib/quantus_sdk.dart index 454bda945..0bcfc17ba 100644 --- a/quantus_sdk/lib/quantus_sdk.dart +++ b/quantus_sdk/lib/quantus_sdk.dart @@ -19,6 +19,7 @@ export 'src/extensions/string_extensions.dart'; // UI-related exports export 'src/ui/themes/app_theme.dart'; export 'src/ui/themes/app_colors.dart'; +export 'src/ui/themes/app_radius.dart'; export 'src/ui/themes/app_spacing.dart'; export 'src/ui/themes/app_text_styles.dart'; diff --git a/quantus_sdk/lib/src/ui/themes/app_colors.dart b/quantus_sdk/lib/src/ui/themes/app_colors.dart index f1e3cae09..04bbb9172 100644 --- a/quantus_sdk/lib/src/ui/themes/app_colors.dart +++ b/quantus_sdk/lib/src/ui/themes/app_colors.dart @@ -372,3 +372,158 @@ class AppColorsV2 extends ThemeExtension { extension AppColorsV2Extension on BuildContext { AppColorsV2 get colors => Theme.of(this).extension()!; } + +/// Quantus App v3 color tokens, mapped 1:1 from Figma SYSTEM / Color Tokens. +/// +/// Do not add colors that are not in the Figma table. Derive alpha with [Color.useOpacity] +/// at the call site when a widget needs a tint of an existing token. +@immutable +class AppColorsV3 extends ThemeExtension { + /// Screen background. Every screen base. Nothing else. + final Color bgVoid; + + /// Anything on the screen: cards, sheets, rows. This is elevation. + final Color bgSurface; + + /// Anything on a surface: inputs in cards, skeletons, disabled CTAs. + final Color bgSurface2; + + /// Default text. Titles, amounts, body. Warm, not pure white. + final Color textContent; + + /// Secondary. Darkest gray legal on small text (AA floor). + final Color textMuted; + + /// Tertiary. Large or decorative only. Never on small labels. + final Color textMuted2; + + /// Rare deliberate emphasis. Using it often means something is wrong. + final Color textWhite; + + /// Actions and CTAs only. Never selection, identity, or data. + final Color accentFlare; + + /// Settles. Success, confirmed, guaranteed minimum, funds safe. + final Color semanticSage; + + /// Warns. Expired, attention, advisory. Not an error. + final Color semanticSand; + + /// Fails. Errors, destructive actions. Large text only on dark. + final Color semanticEmber; + + /// Waits. Pending, suspended, reversible, in-between. + final Color semanticGlacier; + + /// Checkphrases only. Nothing else wears lilac, ever. + final Color semanticLilac; + + /// Default border. All cards, rows, dividers. White at 7%. + final Color borderHairline; + + /// Selected or focused containers. The loudest border allowed. White at 12%. + final Color borderEmphasis; + + const AppColorsV3({ + required this.bgVoid, + required this.bgSurface, + required this.bgSurface2, + required this.textContent, + required this.textMuted, + required this.textMuted2, + required this.textWhite, + required this.accentFlare, + required this.semanticSage, + required this.semanticSand, + required this.semanticEmber, + required this.semanticGlacier, + required this.semanticLilac, + required this.borderHairline, + required this.borderEmphasis, + }); + + /// Dark palette from Figma SYSTEM / Color Tokens (Table). + /// + /// Border alphas match [Color.useOpacity]: 7% → `0x12`, 12% → `0x1F`. + const AppColorsV3.dark() + : this( + bgVoid: const Color(0xFF0E0E0E), + bgSurface: const Color(0xFF181818), + bgSurface2: const Color(0xFF222222), + textContent: const Color(0xFFE8E6E0), + textMuted: const Color(0xFF8A8784), + textMuted2: const Color(0xFF6B6966), + textWhite: const Color(0xFFFFFFFF), + accentFlare: const Color(0xFFFF6B35), + semanticSage: const Color(0xFF6DBF8A), + semanticSand: const Color(0xFFD9BC8A), + semanticEmber: const Color(0xFFC94F3A), + semanticGlacier: const Color(0xFFA8D8E8), + semanticLilac: const Color(0xFFC4B1FC), + borderHairline: const Color(0x12FFFFFF), + borderEmphasis: const Color(0x1FFFFFFF), + ); + + @override + AppColorsV3 copyWith({ + Color? bgVoid, + Color? bgSurface, + Color? bgSurface2, + Color? textContent, + Color? textMuted, + Color? textMuted2, + Color? textWhite, + Color? accentFlare, + Color? semanticSage, + Color? semanticSand, + Color? semanticEmber, + Color? semanticGlacier, + Color? semanticLilac, + Color? borderHairline, + Color? borderEmphasis, + }) { + return AppColorsV3( + bgVoid: bgVoid ?? this.bgVoid, + bgSurface: bgSurface ?? this.bgSurface, + bgSurface2: bgSurface2 ?? this.bgSurface2, + textContent: textContent ?? this.textContent, + textMuted: textMuted ?? this.textMuted, + textMuted2: textMuted2 ?? this.textMuted2, + textWhite: textWhite ?? this.textWhite, + accentFlare: accentFlare ?? this.accentFlare, + semanticSage: semanticSage ?? this.semanticSage, + semanticSand: semanticSand ?? this.semanticSand, + semanticEmber: semanticEmber ?? this.semanticEmber, + semanticGlacier: semanticGlacier ?? this.semanticGlacier, + semanticLilac: semanticLilac ?? this.semanticLilac, + borderHairline: borderHairline ?? this.borderHairline, + borderEmphasis: borderEmphasis ?? this.borderEmphasis, + ); + } + + @override + AppColorsV3 lerp(AppColorsV3? other, double t) { + if (other is! AppColorsV3) return this; + return AppColorsV3( + bgVoid: Color.lerp(bgVoid, other.bgVoid, t) ?? bgVoid, + bgSurface: Color.lerp(bgSurface, other.bgSurface, t) ?? bgSurface, + bgSurface2: Color.lerp(bgSurface2, other.bgSurface2, t) ?? bgSurface2, + textContent: Color.lerp(textContent, other.textContent, t) ?? textContent, + textMuted: Color.lerp(textMuted, other.textMuted, t) ?? textMuted, + textMuted2: Color.lerp(textMuted2, other.textMuted2, t) ?? textMuted2, + textWhite: Color.lerp(textWhite, other.textWhite, t) ?? textWhite, + accentFlare: Color.lerp(accentFlare, other.accentFlare, t) ?? accentFlare, + semanticSage: Color.lerp(semanticSage, other.semanticSage, t) ?? semanticSage, + semanticSand: Color.lerp(semanticSand, other.semanticSand, t) ?? semanticSand, + semanticEmber: Color.lerp(semanticEmber, other.semanticEmber, t) ?? semanticEmber, + semanticGlacier: Color.lerp(semanticGlacier, other.semanticGlacier, t) ?? semanticGlacier, + semanticLilac: Color.lerp(semanticLilac, other.semanticLilac, t) ?? semanticLilac, + borderHairline: Color.lerp(borderHairline, other.borderHairline, t) ?? borderHairline, + borderEmphasis: Color.lerp(borderEmphasis, other.borderEmphasis, t) ?? borderEmphasis, + ); + } +} + +extension AppColorsV3Extension on BuildContext { + AppColorsV3 get colorsV3 => Theme.of(this).extension()!; +} diff --git a/quantus_sdk/lib/src/ui/themes/app_radius.dart b/quantus_sdk/lib/src/ui/themes/app_radius.dart new file mode 100644 index 000000000..cb873eef7 --- /dev/null +++ b/quantus_sdk/lib/src/ui/themes/app_radius.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; + +/// Quantus App v3 radius tokens, mapped 1:1 from Figma SYSTEM / Radius & Rules. +/// +/// Mobile-app law. Web surfaces stay zero-radius. +@immutable +class AppRadiusV3 extends ThemeExtension { + /// Tags, micro elements. Figma r-xs. + final double xs; + + /// Chips, small tiles. Figma r-sm. + final double sm; + + /// Buttons, inputs, cards, rows. Figma r-md. + final double md; + + /// Bottom sheets, modals. Figma r-lg. + final double lg; + + /// Full-round CTAs (height/2). Figma pill. + final double pill; + + const AppRadiusV3({required this.xs, required this.sm, required this.md, required this.lg, required this.pill}); + + /// Mobile radius scale from Figma SYSTEM / Radius Tokens. + const AppRadiusV3.standard() : this(xs: 4, sm: 8, md: 14, lg: 32, pill: 36); + + BorderRadius get xsBorder => BorderRadius.circular(xs); + BorderRadius get smBorder => BorderRadius.circular(sm); + BorderRadius get mdBorder => BorderRadius.circular(md); + BorderRadius get lgBorder => BorderRadius.circular(lg); + BorderRadius get pillBorder => BorderRadius.circular(pill); + + @override + AppRadiusV3 copyWith({double? xs, double? sm, double? md, double? lg, double? pill}) { + return AppRadiusV3( + xs: xs ?? this.xs, + sm: sm ?? this.sm, + md: md ?? this.md, + lg: lg ?? this.lg, + pill: pill ?? this.pill, + ); + } + + @override + AppRadiusV3 lerp(AppRadiusV3? other, double t) { + if (other is! AppRadiusV3) return this; + double l(double a, double b) => a + (b - a) * t; + return AppRadiusV3( + xs: l(xs, other.xs), + sm: l(sm, other.sm), + md: l(md, other.md), + lg: l(lg, other.lg), + pill: l(pill, other.pill), + ); + } +} + +extension AppRadiusV3Extension on BuildContext { + AppRadiusV3 get radiusV3 => Theme.of(this).extension()!; +} diff --git a/quantus_sdk/lib/src/ui/themes/app_text_styles.dart b/quantus_sdk/lib/src/ui/themes/app_text_styles.dart index 441eb64c4..5d5bd3478 100644 --- a/quantus_sdk/lib/src/ui/themes/app_text_styles.dart +++ b/quantus_sdk/lib/src/ui/themes/app_text_styles.dart @@ -249,3 +249,290 @@ class AppTextTheme extends ThemeExtension { extension AppTextThemeExtension on BuildContext { AppTextTheme get themeText => Theme.of(this).extension()!; } + +/// Quantus App v3 text styles, mapped 1:1 from Figma SYSTEM / Text Styles. +/// +/// Do not add styles that are not in the Figma table. Apply color at the call +/// site via [TextStyle.copyWith] using [AppColorsV3] tokens. +@immutable +class AppTextThemeV3 extends ThemeExtension { + /// POS charge display. Tabular figures. + final TextStyle displayCharge; + + /// Home balance. Tabular figures. + final TextStyle displayBalance; + + /// Terminal state titles. + final TextStyle titleSuccess; + + /// Onboarding and hero headers. + final TextStyle titleHero; + + /// Review-scale amounts. Tabular. + final TextStyle amountHero; + + /// Nav titles. 18px merged up here. + final TextStyle titleScreen; + + /// Inline numerics. Tabular. + final TextStyle amountInline; + + /// Row amounts. Tabular. + final TextStyle amountRow; + + /// Row and list headings. + final TextStyle headingRow; + + /// Row titles, action labels. + final TextStyle bodyLarge; + + /// Emphasized body. + final TextStyle bodyEmphasis; + + /// Default body text. + final TextStyle body; + + /// Supporting text. + final TextStyle caption; + + /// Badges and chips. + final TextStyle labelChip; + + /// Truncated addresses. Mono, always. + final TextStyle dataAddress; + + /// Full addresses on verification surfaces. + final TextStyle dataAddressLarge; + + /// Hidden balances. + final TextStyle dataMasked; + + /// Dossier data labels. + final TextStyle labelData; + + /// Account initials. + final TextStyle labelMonogram; + + const AppTextThemeV3({ + required this.displayCharge, + required this.displayBalance, + required this.titleSuccess, + required this.titleHero, + required this.amountHero, + required this.titleScreen, + required this.amountInline, + required this.amountRow, + required this.headingRow, + required this.bodyLarge, + required this.bodyEmphasis, + required this.body, + required this.caption, + required this.labelChip, + required this.dataAddress, + required this.dataAddressLarge, + required this.dataMasked, + required this.labelData, + required this.labelMonogram, + }); + + /// Typography from Figma SYSTEM / Text Styles. + const AppTextThemeV3.standard() + : this( + displayCharge: const TextStyle( + fontFamily: AppTextTheme.fontFamily, + fontSize: 80, + fontWeight: FontWeight.w400, + height: 1.0, + fontFeatures: [_tabularFigures], + ), + displayBalance: const TextStyle( + fontFamily: AppTextTheme.fontFamily, + fontSize: 40, + fontWeight: FontWeight.w400, + height: 1.0, + fontFeatures: [_tabularFigures], + ), + titleSuccess: const TextStyle( + fontFamily: AppTextTheme.fontFamily, + fontSize: 32, + fontWeight: FontWeight.w400, + height: 1.0, + ), + titleHero: const TextStyle( + fontFamily: AppTextTheme.fontFamily, + fontSize: 28, + fontWeight: FontWeight.w500, + height: 1.0, + ), + amountHero: const TextStyle( + fontFamily: AppTextTheme.fontFamily, + fontSize: 28, + fontWeight: FontWeight.w400, + height: 1.0, + fontFeatures: [_tabularFigures], + ), + titleScreen: const TextStyle( + fontFamily: AppTextTheme.fontFamily, + fontSize: 20, + fontWeight: FontWeight.w500, + height: 1.0, + ), + amountInline: const TextStyle( + fontFamily: AppTextTheme.fontFamily, + fontSize: 20, + fontWeight: FontWeight.w400, + height: 1.0, + fontFeatures: [_tabularFigures], + ), + amountRow: const TextStyle( + fontFamily: AppTextTheme.fontFamily, + fontSize: 18, + fontWeight: FontWeight.w400, + height: 1.0, + fontFeatures: [_tabularFigures], + ), + headingRow: const TextStyle( + fontFamily: AppTextTheme.fontFamily, + fontSize: 16, + fontWeight: FontWeight.w500, + height: 1.0, + ), + bodyLarge: const TextStyle( + fontFamily: AppTextTheme.fontFamily, + fontSize: 16, + fontWeight: FontWeight.w400, + height: 1.0, + ), + bodyEmphasis: const TextStyle( + fontFamily: AppTextTheme.fontFamily, + fontSize: 14, + fontWeight: FontWeight.w500, + height: 1.0, + ), + body: const TextStyle( + fontFamily: AppTextTheme.fontFamily, + fontSize: 14, + fontWeight: FontWeight.w400, + height: 1.0, + ), + caption: const TextStyle( + fontFamily: AppTextTheme.fontFamily, + fontSize: 12, + fontWeight: FontWeight.w400, + height: 1.0, + ), + labelChip: const TextStyle( + fontFamily: AppTextTheme.fontFamily, + fontSize: 12, + fontWeight: FontWeight.w500, + height: 1.0, + ), + dataAddress: const TextStyle( + fontFamily: AppTextTheme.fontFamilySecondary, + fontSize: 12, + fontWeight: FontWeight.w400, + height: 1.0, + ), + dataAddressLarge: const TextStyle( + fontFamily: AppTextTheme.fontFamilySecondary, + fontSize: 14, + fontWeight: FontWeight.w400, + height: 1.0, + ), + dataMasked: const TextStyle( + fontFamily: AppTextTheme.fontFamilySecondary, + fontSize: 16, + fontWeight: FontWeight.w400, + height: 1.0, + ), + labelData: const TextStyle( + fontFamily: AppTextTheme.fontFamilySecondary, + fontSize: 14, + fontWeight: FontWeight.w500, + height: 1.0, + ), + labelMonogram: const TextStyle( + fontFamily: AppTextTheme.fontFamilySecondary, + fontSize: 12, + fontWeight: FontWeight.w500, + height: 1.0, + ), + ); + + static const _tabularFigures = FontFeature.tabularFigures(); + + @override + AppTextThemeV3 copyWith({ + TextStyle? displayCharge, + TextStyle? displayBalance, + TextStyle? titleSuccess, + TextStyle? titleHero, + TextStyle? amountHero, + TextStyle? titleScreen, + TextStyle? amountInline, + TextStyle? amountRow, + TextStyle? headingRow, + TextStyle? bodyLarge, + TextStyle? bodyEmphasis, + TextStyle? body, + TextStyle? caption, + TextStyle? labelChip, + TextStyle? dataAddress, + TextStyle? dataAddressLarge, + TextStyle? dataMasked, + TextStyle? labelData, + TextStyle? labelMonogram, + }) { + return AppTextThemeV3( + displayCharge: displayCharge ?? this.displayCharge, + displayBalance: displayBalance ?? this.displayBalance, + titleSuccess: titleSuccess ?? this.titleSuccess, + titleHero: titleHero ?? this.titleHero, + amountHero: amountHero ?? this.amountHero, + titleScreen: titleScreen ?? this.titleScreen, + amountInline: amountInline ?? this.amountInline, + amountRow: amountRow ?? this.amountRow, + headingRow: headingRow ?? this.headingRow, + bodyLarge: bodyLarge ?? this.bodyLarge, + bodyEmphasis: bodyEmphasis ?? this.bodyEmphasis, + body: body ?? this.body, + caption: caption ?? this.caption, + labelChip: labelChip ?? this.labelChip, + dataAddress: dataAddress ?? this.dataAddress, + dataAddressLarge: dataAddressLarge ?? this.dataAddressLarge, + dataMasked: dataMasked ?? this.dataMasked, + labelData: labelData ?? this.labelData, + labelMonogram: labelMonogram ?? this.labelMonogram, + ); + } + + @override + AppTextThemeV3 lerp(AppTextThemeV3? other, double t) { + if (other is! AppTextThemeV3) return this; + return AppTextThemeV3( + displayCharge: TextStyle.lerp(displayCharge, other.displayCharge, t) ?? displayCharge, + displayBalance: TextStyle.lerp(displayBalance, other.displayBalance, t) ?? displayBalance, + titleSuccess: TextStyle.lerp(titleSuccess, other.titleSuccess, t) ?? titleSuccess, + titleHero: TextStyle.lerp(titleHero, other.titleHero, t) ?? titleHero, + amountHero: TextStyle.lerp(amountHero, other.amountHero, t) ?? amountHero, + titleScreen: TextStyle.lerp(titleScreen, other.titleScreen, t) ?? titleScreen, + amountInline: TextStyle.lerp(amountInline, other.amountInline, t) ?? amountInline, + amountRow: TextStyle.lerp(amountRow, other.amountRow, t) ?? amountRow, + headingRow: TextStyle.lerp(headingRow, other.headingRow, t) ?? headingRow, + bodyLarge: TextStyle.lerp(bodyLarge, other.bodyLarge, t) ?? bodyLarge, + bodyEmphasis: TextStyle.lerp(bodyEmphasis, other.bodyEmphasis, t) ?? bodyEmphasis, + body: TextStyle.lerp(body, other.body, t) ?? body, + caption: TextStyle.lerp(caption, other.caption, t) ?? caption, + labelChip: TextStyle.lerp(labelChip, other.labelChip, t) ?? labelChip, + dataAddress: TextStyle.lerp(dataAddress, other.dataAddress, t) ?? dataAddress, + dataAddressLarge: TextStyle.lerp(dataAddressLarge, other.dataAddressLarge, t) ?? dataAddressLarge, + dataMasked: TextStyle.lerp(dataMasked, other.dataMasked, t) ?? dataMasked, + labelData: TextStyle.lerp(labelData, other.labelData, t) ?? labelData, + labelMonogram: TextStyle.lerp(labelMonogram, other.labelMonogram, t) ?? labelMonogram, + ); + } +} + +extension AppTextThemeV3Extension on BuildContext { + AppTextThemeV3 get themeTextV3 => Theme.of(this).extension()!; +} diff --git a/quantus_sdk/lib/src/ui/themes/app_theme.dart b/quantus_sdk/lib/src/ui/themes/app_theme.dart index d0ae40ae1..388d46753 100644 --- a/quantus_sdk/lib/src/ui/themes/app_theme.dart +++ b/quantus_sdk/lib/src/ui/themes/app_theme.dart @@ -6,6 +6,7 @@ class AppTheme { final isTablet = context.isTablet; final colors = const AppColorsV2.dark(); final text = isTablet ? const AppTextTheme.iPad() : const AppTextTheme.defaultTheme(); + const radius = AppRadiusV3.standard(); return ThemeData( scaffoldBackgroundColor: colors.background, @@ -15,11 +16,11 @@ class AppTheme { elevatedButtonTheme: ElevatedButtonThemeData( style: ElevatedButton.styleFrom( foregroundColor: Colors.white, - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14)), + shape: RoundedRectangleBorder(borderRadius: radius.mdBorder), ), ), outlinedButtonTheme: OutlinedButtonThemeData( - style: OutlinedButton.styleFrom(shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14))), + style: OutlinedButton.styleFrom(shape: RoundedRectangleBorder(borderRadius: radius.mdBorder)), ), textButtonTheme: TextButtonThemeData(style: TextButton.styleFrom(foregroundColor: colors.textPrimary)), textSelectionTheme: TextSelectionThemeData( @@ -37,10 +38,7 @@ class AppTheme { filled: true, fillColor: Colors.transparent, ), - extensions: [ - colors, - text, - ], + extensions: [colors, const AppColorsV3.dark(), text, const AppTextThemeV3.standard(), radius], ); } } From 4eb11a7fea218db2440b550dfa97238ff053f169 Mon Sep 17 00:00:00 2001 From: Beast Date: Fri, 14 Aug 2026 10:10:16 +0800 Subject: [PATCH 03/38] wip: make component shared in SDK + new theme - already finished address details - finished updating quantus button --- miner-app/pubspec.lock | 16 ++ .../features/components/migration_dialog.dart | 2 +- .../shared_address_action_sheet.dart | 1 - .../shared/extensions/toaster_extensions.dart | 2 +- .../v2/components/address_details_card.dart | 146 ++----------- .../accounts/account_details_screen.dart | 10 +- .../screens/accounts/account_menu_screen.dart | 14 +- .../accounts/account_ready_screen.dart | 15 +- .../v2/screens/accounts/accounts_screen.dart | 18 +- .../accounts/add_hardware_account_screen.dart | 8 +- .../accounts/connect_keystone_screen.dart | 10 +- .../accounts/create_account_screen.dart | 10 +- .../screens/accounts/edit_account_screen.dart | 10 +- .../multisig_account_menu_screen.dart | 14 +- .../accounts/multisig_details_screen.dart | 6 +- .../open_accounts_management_button.dart | 1 - .../screens/accounts/wallet_name_screen.dart | 10 +- .../v2/screens/activity/activity_screen.dart | 6 +- .../activity/transaction_detail_sheet.dart | 6 +- .../lib/v2/screens/auth/auth_wrapper.dart | 6 +- .../lib/v2/screens/home/home_screen.dart | 16 +- .../screens/import/import_wallet_screen.dart | 8 +- .../screens/multisig/add_multisig_screen.dart | 14 +- .../multisig/discover_multisig_screen.dart | 6 +- .../multisig_action_confirm_sheet.dart | 8 +- .../multisig/multisig_activity_section.dart | 2 - .../multisig_approve_confirm_sheet.dart | 2 +- .../multisig_cancel_confirm_sheet.dart | 4 +- .../multisig_execute_confirm_sheet.dart | 2 +- .../multisig_proposal_detail_sheet.dart | 16 +- .../multisig_signer_picker_sheet.dart | 4 +- .../lib/v2/screens/multisig/proposal_row.dart | 2 +- .../lib/v2/screens/pos/pos_amount_screen.dart | 10 +- .../lib/v2/screens/pos/pos_qr_screen.dart | 16 +- .../v2/screens/receive/receive_screen.dart | 18 +- .../send/encrypted_send_progress_screen.dart | 13 +- .../screens/send/encrypted_send_strategy.dart | 2 +- .../v2/screens/send/input_amount_screen.dart | 12 +- .../screens/send/keystone_reject_screen.dart | 8 +- .../v2/screens/send/keystone_sign_screen.dart | 12 +- .../send/keystone_signature_scan_screen.dart | 2 +- .../screens/send/keystone_verify_screen.dart | 10 +- .../send/multisig_propose_strategy.dart | 4 +- .../screens/send/regular_send_strategy.dart | 2 +- .../v2/screens/send/review_send_screen.dart | 14 +- .../screens/send/select_recipient_screen.dart | 18 +- .../v2/screens/send/send_terminal_screen.dart | 13 +- .../settings/about_quantus_screen.dart | 4 +- .../settings/add_account_menu_screen.dart | 8 +- .../settings/help_and_support_screen.dart | 4 +- .../settings/mining_rewards_screen.dart | 10 +- .../settings/preferences_settings_screen.dart | 4 +- .../settings/recovery_phrase_screen.dart | 2 +- .../settings/redeem_address_screen.dart | 12 +- .../settings/redeem_progress_screen.dart | 10 +- .../settings/select_wallet_screen.dart | 6 +- .../settings/settings_caution_scaffold.dart | 8 +- .../settings/settings_picker_screen.dart | 4 +- .../v2/screens/settings/settings_screen.dart | 4 +- .../settings/testnet_rewards_screen.dart | 6 +- .../settings/wallet_settings_screen.dart | 5 +- .../lib/v2/screens/swap/deposit_screen.dart | 12 +- .../swap/refund_address_picker_sheet.dart | 2 +- .../v2/screens/swap/review_quote_sheet.dart | 6 +- .../lib/v2/screens/swap/swap_screen.dart | 10 +- .../v2/screens/swap/token_picker_sheet.dart | 6 +- .../v2/screens/welcome/welcome_screen.dart | 5 +- mobile-app/lib/wallet_initializer.dart | 6 +- quantus_sdk/lib/quantus_sdk.dart | 8 +- .../lib/src/ui}/components/account_badge.dart | 1 - .../address_checkphrase_with_initial.dart | 1 - .../ui/components/address_details_card.dart | 157 ++++++++++++++ .../ui}/components/address_input_field.dart | 0 .../amount_display_with_conversion.dart | 1 - .../ui}/components/animated_qr_scanner.dart | 4 +- .../src/ui}/components/animated_ur_qr.dart | 0 .../lib/src/ui}/components/back_button.dart | 1 - .../src/ui}/components/base_background.dart | 0 .../components/bottom_sheet_container.dart | 0 .../ui}/components/confirm_action_sheet.dart | 4 +- .../src/ui}/components/decoded_call_view.dart | 2 +- .../ui}/components/detail_summary_row.dart | 0 .../lib/src/ui}/components/explorer_link.dart | 0 .../src/ui}/components/glass_button_base.dart | 0 .../ui}/components/global_toast_listener.dart | 0 quantus_sdk/lib/src/ui/components/index.dart | 5 + .../lib/src/ui}/components/loader.dart | 0 .../lib/src/ui}/components/menu_divider.dart | 0 .../ui}/components/multisig_expiry_value.dart | 0 .../components/multisig_signer_list_tile.dart | 0 .../lib/src/ui}/components/multisig_tag.dart | 0 .../components/multisig_threshold_slider.dart | 0 .../lib/src/ui}/components/name_field.dart | 0 .../components/private_activity_notice.dart | 0 .../ui}/components/proposal_list_tile.dart | 2 +- .../src/ui}/components/qr_scanner_page.dart | 3 +- .../src/ui}/components/quantus_button.dart | 192 ++++++++++-------- .../ui}/components/quantus_icon_button.dart | 1 - .../lib/src/ui}/components/quantus_qr.dart | 0 .../ui}/components/recovery_phrase_body.dart | 10 +- .../lib/src/ui}/components/scaffold_base.dart | 2 +- .../scaffold_base_bottom_content.dart | 0 .../ui}/components/segmented_controls.dart | 0 .../ui}/components/share_account_button.dart | 2 +- .../lib/src/ui}/components/split_card.dart | 0 .../lib/src/ui}/components/success_check.dart | 0 .../lib/src/ui}/components/toaster.dart | 0 .../src/ui}/components/toaster_helper.dart | 2 +- .../lib/src/ui}/components/token_icon.dart | 0 .../lib/src/ui}/components/v2_app_bar.dart | 2 +- .../components/wormhole_progress_steps.dart | 0 quantus_sdk/lib/src/ui/index.dart | 2 + quantus_sdk/lib/src/ui/themes/app_colors.dart | 8 + quantus_sdk/lib/src/ui/themes/index.dart | 5 + .../lib/src}/utils/account_utils.dart | 0 quantus_sdk/pubspec.lock | 42 +++- quantus_sdk/pubspec.yaml | 5 +- 117 files changed, 643 insertions(+), 502 deletions(-) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/account_badge.dart (95%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/address_checkphrase_with_initial.dart (96%) create mode 100644 quantus_sdk/lib/src/ui/components/address_details_card.dart rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/address_input_field.dart (100%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/amount_display_with_conversion.dart (97%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/animated_qr_scanner.dart (98%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/animated_ur_qr.dart (100%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/back_button.dart (91%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/base_background.dart (100%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/bottom_sheet_container.dart (100%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/confirm_action_sheet.dart (92%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/decoded_call_view.dart (98%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/detail_summary_row.dart (100%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/explorer_link.dart (100%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/glass_button_base.dart (100%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/global_toast_listener.dart (100%) create mode 100644 quantus_sdk/lib/src/ui/components/index.dart rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/loader.dart (100%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/menu_divider.dart (100%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/multisig_expiry_value.dart (100%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/multisig_signer_list_tile.dart (100%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/multisig_tag.dart (100%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/multisig_threshold_slider.dart (100%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/name_field.dart (100%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/private_activity_notice.dart (100%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/proposal_list_tile.dart (98%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/qr_scanner_page.dart (97%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/quantus_button.dart (50%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/quantus_icon_button.dart (97%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/quantus_qr.dart (100%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/recovery_phrase_body.dart (92%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/scaffold_base.dart (97%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/scaffold_base_bottom_content.dart (100%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/segmented_controls.dart (100%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/share_account_button.dart (91%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/split_card.dart (100%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/success_check.dart (100%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/toaster.dart (100%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/toaster_helper.dart (97%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/token_icon.dart (100%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/v2_app_bar.dart (93%) rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/wormhole_progress_steps.dart (100%) create mode 100644 quantus_sdk/lib/src/ui/index.dart create mode 100644 quantus_sdk/lib/src/ui/themes/index.dart rename {mobile-app/lib/shared => quantus_sdk/lib/src}/utils/account_utils.dart (100%) diff --git a/miner-app/pubspec.lock b/miner-app/pubspec.lock index b9a9bff98..83951c528 100644 --- a/miner-app/pubspec.lock +++ b/miner-app/pubspec.lock @@ -744,6 +744,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.0" + qr: + dependency: transitive + description: + name: qr + sha256: "5a1d2586170e172b8a8c8470bbbffd5eb0cd38a66c0d77155ea138d3af3a4445" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + qr_flutter: + dependency: transitive + description: + name: qr_flutter + sha256: "5095f0fc6e3f71d08adef8feccc8cea4f12eec18a2e31c2e8d82cb6019f4b097" + url: "https://pub.dev" + source: hosted + version: "4.1.0" quantus_sdk: dependency: "direct main" description: diff --git a/mobile-app/lib/features/components/migration_dialog.dart b/mobile-app/lib/features/components/migration_dialog.dart index 0cf47c71e..ec0377159 100644 --- a/mobile-app/lib/features/components/migration_dialog.dart +++ b/mobile-app/lib/features/components/migration_dialog.dart @@ -2,7 +2,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/providers/l10n_provider.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; class MigrationDialog extends ConsumerStatefulWidget { final List migrationResults; diff --git a/mobile-app/lib/features/components/shared_address_action_sheet.dart b/mobile-app/lib/features/components/shared_address_action_sheet.dart index 59ea9b67e..1edf08497 100644 --- a/mobile-app/lib/features/components/shared_address_action_sheet.dart +++ b/mobile-app/lib/features/components/shared_address_action_sheet.dart @@ -12,7 +12,6 @@ import 'package:resonance_network_wallet/shared/extensions/clipboard_extensions. import 'package:resonance_network_wallet/shared/extensions/current_route_extensions.dart'; import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; import 'package:resonance_network_wallet/v2/screens/send/input_amount_screen.dart'; import 'package:resonance_network_wallet/v2/screens/send/regular_send_strategy.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_providers.dart'; diff --git a/mobile-app/lib/shared/extensions/toaster_extensions.dart b/mobile-app/lib/shared/extensions/toaster_extensions.dart index db4e3d7e5..d27614ed2 100644 --- a/mobile-app/lib/shared/extensions/toaster_extensions.dart +++ b/mobile-app/lib/shared/extensions/toaster_extensions.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:resonance_network_wallet/v2/components/toaster_helper.dart' as th; +import 'package:quantus_sdk/src/ui/components/toaster_helper.dart' as th; extension ToasterExtensions on BuildContext { Future showSuccessToaster({required String message}) async { diff --git a/mobile-app/lib/v2/components/address_details_card.dart b/mobile-app/lib/v2/components/address_details_card.dart index 23ce42583..651b8be2e 100644 --- a/mobile-app/lib/v2/components/address_details_card.dart +++ b/mobile-app/lib/v2/components/address_details_card.dart @@ -1,147 +1,31 @@ -import 'dart:async'; - import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:resonance_network_wallet/l10n/app_localizations.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' as sdk; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/shared/extensions/clipboard_extensions.dart'; -import 'package:resonance_network_wallet/v2/components/split_card.dart'; -class AddressDetailsCard extends ConsumerStatefulWidget { +class AddressDetailsCard extends ConsumerWidget { final String accountId; final String? checksum; const AddressDetailsCard({super.key, required this.accountId, this.checksum}); @override - ConsumerState createState() => _AddressDetailsCardState(); -} - -class _AddressDetailsCardState extends ConsumerState { - bool _addressCopied = false; - bool _checksumCopied = false; - Timer? _resetTimer; - - void _copyAddress(BuildContext context) { - context.copyTextWithToaster(widget.accountId); - _triggerCopied(isAddress: true); - } - - void _copyChecksum(BuildContext context, AppLocalizations l10n) { - if (widget.checksum == null) return; - - context.copyTextWithToaster(widget.checksum!, message: l10n.componentCheckphraseCopied); - _triggerCopied(isAddress: false); - } - - void _triggerCopied({required bool isAddress}) { - _resetTimer?.cancel(); - - setState(() { - if (isAddress) { - _addressCopied = true; - _checksumCopied = false; - } else { - _checksumCopied = true; - _addressCopied = false; - } - }); - - _resetTimer = Timer(const Duration(seconds: 2), () { - if (mounted) { - setState(() { - if (isAddress) { - _addressCopied = false; - } else { - _checksumCopied = false; - } - }); - } - }); - } - - @override - void dispose() { - _resetTimer?.cancel(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { final l10n = ref.watch(l10nProvider); - return SplitCard( - topChild: InkWell( - onTap: () => _copyAddress(context), - child: _buildItem(context, l10n.componentAddressLabel, widget.accountId, isCopied: _addressCopied), - ), - bottomChild: InkWell( - onTap: () => _copyChecksum(context, l10n), - child: _buildItem( - context, - l10n.componentCheckphraseLabel, - widget.checksum ?? l10n.commonLoading, - isCheckphrase: true, - isCopied: _checksumCopied, - ), - ), - ); - } - - Widget _buildItem( - BuildContext context, - String label, - String value, { - bool isCheckphrase = false, - required bool isCopied, - }) { - final valueTextStyle = isCheckphrase - ? context.themeText.smallParagraph?.copyWith(color: context.colors.checksum) - : context.themeText.smallParagraph?.copyWith(fontFamily: AppTextTheme.fontFamilySecondary); - - return Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(label, style: context.themeText.receiveLabel?.copyWith(color: context.colors.textLabel)), - const SizedBox(height: 16), - Text(value, style: valueTextStyle), - ], - ), - ), - const SizedBox(width: 32), - _copyButton(isCopied: isCopied), - ], - ); - } - - Widget _copyButton({required bool isCopied}) { - final containerSize = 40.0; - final iconSize = 16.0; - - return AnimatedContainer( - duration: const Duration(milliseconds: 200), - width: containerSize, - height: containerSize, - decoration: BoxDecoration( - color: isCopied ? context.colors.copyButtonCopiedBg : Colors.transparent, - border: Border.all( - color: isCopied ? context.colors.copyButtonCopiedBorder : context.colors.borderButton, - width: 1, - ), - borderRadius: BorderRadius.circular(containerSize / 2), - ), - child: Center( - child: Icon( - isCopied ? Icons.check : Icons.copy, - size: iconSize, - color: isCopied ? context.colors.success : context.colors.textPrimary, - ), - ), + return sdk.AddressDetailsCard( + accountId: accountId, + checksum: checksum, + addressLabel: l10n.componentAddressLabel, + checkphraseLabel: l10n.componentCheckphraseLabel, + checksumPlaceholder: l10n.commonLoading, + onCopyAddress: () => context.copyTextWithToaster(accountId), + onCopyChecksum: () { + final value = checksum; + if (value == null) return; + context.copyTextWithToaster(value, message: l10n.componentCheckphraseCopied); + }, ); } } diff --git a/mobile-app/lib/v2/screens/accounts/account_details_screen.dart b/mobile-app/lib/v2/screens/accounts/account_details_screen.dart index b40590b5d..c5b9c7fbd 100644 --- a/mobile-app/lib/v2/screens/accounts/account_details_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/account_details_screen.dart @@ -1,13 +1,13 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide AddressDetailsCard; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/shared/utils/share_utils.dart'; import 'package:resonance_network_wallet/v2/components/address_details_card.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; -import 'package:resonance_network_wallet/v2/components/share_account_button.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; +import 'package:quantus_sdk/src/ui/components/share_account_button.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; class AccountDetailsScreen extends ConsumerStatefulWidget { const AccountDetailsScreen({super.key, required this.accountId}); diff --git a/mobile-app/lib/v2/screens/accounts/account_menu_screen.dart b/mobile-app/lib/v2/screens/accounts/account_menu_screen.dart index d39679ab3..dac82b1da 100644 --- a/mobile-app/lib/v2/screens/accounts/account_menu_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/account_menu_screen.dart @@ -8,13 +8,13 @@ import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/accounts_grouping.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; -import 'package:resonance_network_wallet/v2/components/account_badge.dart'; -import 'package:resonance_network_wallet/v2/components/confirm_action_sheet.dart'; -import 'package:resonance_network_wallet/v2/components/menu_divider.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/account_badge.dart'; +import 'package:quantus_sdk/src/ui/components/confirm_action_sheet.dart'; +import 'package:quantus_sdk/src/ui/components/menu_divider.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/account_details_screen.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/accounts_navigation.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/edit_account_screen.dart'; diff --git a/mobile-app/lib/v2/screens/accounts/account_ready_screen.dart b/mobile-app/lib/v2/screens/accounts/account_ready_screen.dart index 24519dfbe..d1a6087ab 100644 --- a/mobile-app/lib/v2/screens/accounts/account_ready_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/account_ready_screen.dart @@ -1,3 +1,4 @@ + import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; @@ -5,13 +6,13 @@ import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; import 'package:resonance_network_wallet/shared/constants/e2e_keys.dart'; -import 'package:resonance_network_wallet/v2/components/account_badge.dart'; -import 'package:resonance_network_wallet/v2/components/loader.dart'; -import 'package:resonance_network_wallet/v2/components/private_activity_notice.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/account_badge.dart'; +import 'package:quantus_sdk/src/ui/components/loader.dart'; +import 'package:quantus_sdk/src/ui/components/private_activity_notice.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/home/home_screen.dart'; enum AccountReadyOverviewOrigin { accountCreated, walletCreated, walletImported } diff --git a/mobile-app/lib/v2/screens/accounts/accounts_screen.dart b/mobile-app/lib/v2/screens/accounts/accounts_screen.dart index 8460fa54f..deec54da5 100644 --- a/mobile-app/lib/v2/screens/accounts/accounts_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/accounts_screen.dart @@ -4,15 +4,15 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/multisig_providers.dart'; import 'package:resonance_network_wallet/shared/utils/accounts_grouping.dart'; -import 'package:resonance_network_wallet/v2/components/account_badge.dart'; -import 'package:resonance_network_wallet/v2/components/loader.dart'; -import 'package:resonance_network_wallet/v2/components/private_activity_notice.dart'; -import 'package:resonance_network_wallet/v2/components/multisig_tag.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_icon_button.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/account_badge.dart'; +import 'package:quantus_sdk/src/ui/components/loader.dart'; +import 'package:quantus_sdk/src/ui/components/private_activity_notice.dart'; +import 'package:quantus_sdk/src/ui/components/multisig_tag.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_icon_button.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; diff --git a/mobile-app/lib/v2/screens/accounts/add_hardware_account_screen.dart b/mobile-app/lib/v2/screens/accounts/add_hardware_account_screen.dart index 71f47a601..95b507b8b 100644 --- a/mobile-app/lib/v2/screens/accounts/add_hardware_account_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/add_hardware_account_screen.dart @@ -2,10 +2,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/connect_keystone_screen.dart'; import 'package:url_launcher/url_launcher.dart'; diff --git a/mobile-app/lib/v2/screens/accounts/connect_keystone_screen.dart b/mobile-app/lib/v2/screens/accounts/connect_keystone_screen.dart index eccf91d25..b7cef5fef 100644 --- a/mobile-app/lib/v2/screens/accounts/connect_keystone_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/connect_keystone_screen.dart @@ -5,11 +5,11 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/qr_scanner_page.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/qr_scanner_page.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/account_menu_screen.dart'; /// Second add-Keystone screen: on-device instructions, then scans the device's diff --git a/mobile-app/lib/v2/screens/accounts/create_account_screen.dart b/mobile-app/lib/v2/screens/accounts/create_account_screen.dart index 6bf2ff7df..b5c2df811 100644 --- a/mobile-app/lib/v2/screens/accounts/create_account_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/create_account_screen.dart @@ -8,11 +8,11 @@ import 'package:resonance_network_wallet/services/firebase_messaging_service.dar import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/account_utils.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; -import 'package:resonance_network_wallet/v2/components/name_field.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/name_field.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/accounts_navigation.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/add_hardware_account_screen.dart'; diff --git a/mobile-app/lib/v2/screens/accounts/edit_account_screen.dart b/mobile-app/lib/v2/screens/accounts/edit_account_screen.dart index 6dbccc731..57757dab1 100644 --- a/mobile-app/lib/v2/screens/accounts/edit_account_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/edit_account_screen.dart @@ -5,11 +5,11 @@ import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/multisig_providers.dart'; import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; -import 'package:resonance_network_wallet/v2/components/name_field.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/name_field.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; class EditAccountScreen extends ConsumerStatefulWidget { const EditAccountScreen({super.key, required Account initialAccount}) diff --git a/mobile-app/lib/v2/screens/accounts/multisig_account_menu_screen.dart b/mobile-app/lib/v2/screens/accounts/multisig_account_menu_screen.dart index 621ea3f6c..0097b8451 100644 --- a/mobile-app/lib/v2/screens/accounts/multisig_account_menu_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/multisig_account_menu_screen.dart @@ -7,13 +7,13 @@ import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/multisig_providers.dart'; import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; -import 'package:resonance_network_wallet/v2/components/account_badge.dart'; -import 'package:resonance_network_wallet/v2/components/confirm_action_sheet.dart'; -import 'package:resonance_network_wallet/v2/components/menu_divider.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/account_badge.dart'; +import 'package:quantus_sdk/src/ui/components/confirm_action_sheet.dart'; +import 'package:quantus_sdk/src/ui/components/menu_divider.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/account_details_screen.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/accounts_navigation.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/edit_account_screen.dart'; diff --git a/mobile-app/lib/v2/screens/accounts/multisig_details_screen.dart b/mobile-app/lib/v2/screens/accounts/multisig_details_screen.dart index 4c5a05a74..69fc770cc 100644 --- a/mobile-app/lib/v2/screens/accounts/multisig_details_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/multisig_details_screen.dart @@ -4,9 +4,9 @@ import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; -import 'package:resonance_network_wallet/v2/components/multisig_signer_list_tile.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/multisig_signer_list_tile.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; class MultisigDetailsScreen extends ConsumerWidget { const MultisigDetailsScreen({super.key, required this.account}); diff --git a/mobile-app/lib/v2/screens/accounts/open_accounts_management_button.dart b/mobile-app/lib/v2/screens/accounts/open_accounts_management_button.dart index f9df36e40..b813134ed 100644 --- a/mobile-app/lib/v2/screens/accounts/open_accounts_management_button.dart +++ b/mobile-app/lib/v2/screens/accounts/open_accounts_management_button.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:resonance_network_wallet/v2/components/glass_button_base.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/accounts_screen.dart'; class OpenAccountsManagementButton extends StatelessWidget { diff --git a/mobile-app/lib/v2/screens/accounts/wallet_name_screen.dart b/mobile-app/lib/v2/screens/accounts/wallet_name_screen.dart index f68dc3cc7..fbe0b12d2 100644 --- a/mobile-app/lib/v2/screens/accounts/wallet_name_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/wallet_name_screen.dart @@ -3,11 +3,11 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; -import 'package:resonance_network_wallet/v2/components/name_field.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/name_field.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/accounts_navigation.dart'; /// Names (or renames) a wallet. The name is optional: saving an empty field diff --git a/mobile-app/lib/v2/screens/activity/activity_screen.dart b/mobile-app/lib/v2/screens/activity/activity_screen.dart index bd5294983..f6a790f7c 100644 --- a/mobile-app/lib/v2/screens/activity/activity_screen.dart +++ b/mobile-app/lib/v2/screens/activity/activity_screen.dart @@ -10,9 +10,9 @@ import 'package:resonance_network_wallet/providers/currency_display_provider.dar import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; import 'package:resonance_network_wallet/services/transaction_service.dart'; -import 'package:resonance_network_wallet/v2/components/loader.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/loader.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/activity/tx_item.dart'; import 'package:resonance_network_wallet/v2/screens/activity/transaction_detail_sheet.dart'; 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 a9275bc15..9ab011e62 100644 --- a/mobile-app/lib/v2/screens/activity/transaction_detail_sheet.dart +++ b/mobile-app/lib/v2/screens/activity/transaction_detail_sheet.dart @@ -10,9 +10,9 @@ import 'package:resonance_network_wallet/providers/wallet_providers.dart'; import 'package:resonance_network_wallet/routes.dart'; import 'package:resonance_network_wallet/shared/extensions/current_route_extensions.dart'; import 'package:resonance_network_wallet/shared/extensions/transaction_event_extension.dart'; -import 'package:resonance_network_wallet/v2/components/amount_display_with_conversion.dart'; -import 'package:resonance_network_wallet/v2/components/bottom_sheet_container.dart'; -import 'package:resonance_network_wallet/v2/components/explorer_link.dart'; +import 'package:quantus_sdk/src/ui/components/amount_display_with_conversion.dart'; +import 'package:quantus_sdk/src/ui/components/bottom_sheet_container.dart'; +import 'package:quantus_sdk/src/ui/components/explorer_link.dart'; void showTransactionDetailSheet(BuildContext context, TransactionEvent tx, String activeAccountId) { if (context.peekTopRouteName == transactionDetailSheetRouteSettings.name) Navigator.pop(context); diff --git a/mobile-app/lib/v2/screens/auth/auth_wrapper.dart b/mobile-app/lib/v2/screens/auth/auth_wrapper.dart index 1e0b79516..61682e010 100644 --- a/mobile-app/lib/v2/screens/auth/auth_wrapper.dart +++ b/mobile-app/lib/v2/screens/auth/auth_wrapper.dart @@ -3,9 +3,9 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/local_auth_provider.dart'; -import 'package:resonance_network_wallet/v2/components/base_background.dart'; -import 'package:resonance_network_wallet/v2/components/loader.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/base_background.dart'; +import 'package:quantus_sdk/src/ui/components/loader.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; class AuthWrapper extends ConsumerWidget { const AuthWrapper({super.key}); diff --git a/mobile-app/lib/v2/screens/home/home_screen.dart b/mobile-app/lib/v2/screens/home/home_screen.dart index ee3cad07b..11a96c848 100644 --- a/mobile-app/lib/v2/screens/home/home_screen.dart +++ b/mobile-app/lib/v2/screens/home/home_screen.dart @@ -13,12 +13,12 @@ import 'package:resonance_network_wallet/shared/constants/e2e_keys.dart'; import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; import 'package:resonance_network_wallet/shared/utils/url_utils.dart'; -import 'package:resonance_network_wallet/v2/components/amount_display_with_conversion.dart'; -import 'package:resonance_network_wallet/v2/components/loader.dart'; -import 'package:resonance_network_wallet/v2/components/private_activity_notice.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_icon_button.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; +import 'package:quantus_sdk/src/ui/components/amount_display_with_conversion.dart'; +import 'package:quantus_sdk/src/ui/components/loader.dart'; +import 'package:quantus_sdk/src/ui/components/private_activity_notice.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_icon_button.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/open_accounts_management_button.dart'; import 'package:resonance_network_wallet/v2/screens/activity/transaction_detail_sheet.dart'; import 'package:resonance_network_wallet/v2/screens/receive/receive_screen.dart'; @@ -42,9 +42,9 @@ import 'package:resonance_network_wallet/providers/multisig_providers.dart'; import 'package:resonance_network_wallet/providers/route_intent_providers.dart'; import 'package:resonance_network_wallet/providers/currency_display_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_providers.dart'; -import 'package:resonance_network_wallet/v2/components/global_toast_listener.dart'; +import 'package:quantus_sdk/src/ui/components/global_toast_listener.dart'; import 'package:resonance_network_wallet/v2/screens/home/activity_section.dart'; import 'package:resonance_network_wallet/v2/screens/home/backup_reminder_banner.dart'; diff --git a/mobile-app/lib/v2/screens/import/import_wallet_screen.dart b/mobile-app/lib/v2/screens/import/import_wallet_screen.dart index dec1907e8..0d0bfc847 100644 --- a/mobile-app/lib/v2/screens/import/import_wallet_screen.dart +++ b/mobile-app/lib/v2/screens/import/import_wallet_screen.dart @@ -11,10 +11,10 @@ import 'package:resonance_network_wallet/services/firebase_messaging_service.dar import 'package:resonance_network_wallet/services/telemetry_service.dart'; import 'package:resonance_network_wallet/shared/constants/e2e_keys.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/wallet_name_screen.dart'; import 'package:resonance_network_wallet/v2/screens/home/home_screen.dart'; diff --git a/mobile-app/lib/v2/screens/multisig/add_multisig_screen.dart b/mobile-app/lib/v2/screens/multisig/add_multisig_screen.dart index 9679ff952..6c4b014a2 100644 --- a/mobile-app/lib/v2/screens/multisig/add_multisig_screen.dart +++ b/mobile-app/lib/v2/screens/multisig/add_multisig_screen.dart @@ -10,13 +10,13 @@ import 'package:resonance_network_wallet/providers/pending_multisig_creations_pr import 'package:resonance_network_wallet/providers/wallet_providers.dart'; import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; -import 'package:resonance_network_wallet/v2/components/multisig_signer_list_tile.dart'; -import 'package:resonance_network_wallet/v2/components/multisig_threshold_slider.dart'; -import 'package:resonance_network_wallet/v2/components/name_field.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/multisig_signer_list_tile.dart'; +import 'package:quantus_sdk/src/ui/components/multisig_threshold_slider.dart'; +import 'package:quantus_sdk/src/ui/components/name_field.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/services/local_auth_service.dart'; import 'package:resonance_network_wallet/services/multisig_submission_service.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/accounts_navigation.dart'; diff --git a/mobile-app/lib/v2/screens/multisig/discover_multisig_screen.dart b/mobile-app/lib/v2/screens/multisig/discover_multisig_screen.dart index f793882aa..0c00b12a1 100644 --- a/mobile-app/lib/v2/screens/multisig/discover_multisig_screen.dart +++ b/mobile-app/lib/v2/screens/multisig/discover_multisig_screen.dart @@ -7,9 +7,9 @@ import 'package:resonance_network_wallet/providers/multisig_providers.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; class DiscoverMultisigScreen extends ConsumerStatefulWidget { const DiscoverMultisigScreen({super.key}); diff --git a/mobile-app/lib/v2/screens/multisig/multisig_action_confirm_sheet.dart b/mobile-app/lib/v2/screens/multisig/multisig_action_confirm_sheet.dart index f3b9c69f5..ec6b4c30a 100644 --- a/mobile-app/lib/v2/screens/multisig/multisig_action_confirm_sheet.dart +++ b/mobile-app/lib/v2/screens/multisig/multisig_action_confirm_sheet.dart @@ -11,10 +11,10 @@ import 'package:resonance_network_wallet/providers/multisig_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/shared/utils/print.dart'; -import 'package:resonance_network_wallet/v2/components/bottom_sheet_container.dart'; -import 'package:resonance_network_wallet/v2/components/decoded_call_view.dart'; -import 'package:resonance_network_wallet/v2/components/detail_summary_row.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/bottom_sheet_container.dart'; +import 'package:quantus_sdk/src/ui/components/decoded_call_view.dart'; +import 'package:quantus_sdk/src/ui/components/detail_summary_row.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_sign_cache.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_sign_screen.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_signing_session.dart'; diff --git a/mobile-app/lib/v2/screens/multisig/multisig_activity_section.dart b/mobile-app/lib/v2/screens/multisig/multisig_activity_section.dart index b42b5848d..ab2411d6e 100644 --- a/mobile-app/lib/v2/screens/multisig/multisig_activity_section.dart +++ b/mobile-app/lib/v2/screens/multisig/multisig_activity_section.dart @@ -13,8 +13,6 @@ import 'package:resonance_network_wallet/providers/pending_multisig_executions_p import 'package:resonance_network_wallet/providers/pending_multisig_proposals_provider.dart'; import 'package:resonance_network_wallet/services/transaction_service.dart'; import 'package:resonance_network_wallet/shared/utils/multisig_local_signers.dart'; -import 'package:resonance_network_wallet/v2/components/loader.dart'; -import 'package:resonance_network_wallet/v2/components/proposal_list_tile.dart'; import 'package:resonance_network_wallet/v2/screens/activity/transaction_detail_sheet.dart'; import 'package:resonance_network_wallet/v2/screens/activity/tx_item.dart'; import 'package:resonance_network_wallet/v2/screens/multisig/multisig_proposal_detail_sheet.dart'; diff --git a/mobile-app/lib/v2/screens/multisig/multisig_approve_confirm_sheet.dart b/mobile-app/lib/v2/screens/multisig/multisig_approve_confirm_sheet.dart index a2279e4db..3ae664651 100644 --- a/mobile-app/lib/v2/screens/multisig/multisig_approve_confirm_sheet.dart +++ b/mobile-app/lib/v2/screens/multisig/multisig_approve_confirm_sheet.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/multisig_providers.dart'; import 'package:resonance_network_wallet/services/transaction_submission_service.dart'; -import 'package:resonance_network_wallet/v2/components/bottom_sheet_container.dart'; +import 'package:quantus_sdk/src/ui/components/bottom_sheet_container.dart'; import 'package:resonance_network_wallet/v2/screens/multisig/multisig_action_confirm_sheet.dart'; /// Shows the confirmation sheet for approving a multisig proposal. diff --git a/mobile-app/lib/v2/screens/multisig/multisig_cancel_confirm_sheet.dart b/mobile-app/lib/v2/screens/multisig/multisig_cancel_confirm_sheet.dart index ef031a85c..be4088a98 100644 --- a/mobile-app/lib/v2/screens/multisig/multisig_cancel_confirm_sheet.dart +++ b/mobile-app/lib/v2/screens/multisig/multisig_cancel_confirm_sheet.dart @@ -2,8 +2,8 @@ import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/multisig_providers.dart'; import 'package:resonance_network_wallet/services/transaction_submission_service.dart'; -import 'package:resonance_network_wallet/v2/components/bottom_sheet_container.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/bottom_sheet_container.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; import 'package:resonance_network_wallet/v2/screens/multisig/multisig_action_confirm_sheet.dart'; /// Shows the confirmation sheet for cancelling a multisig proposal. diff --git a/mobile-app/lib/v2/screens/multisig/multisig_execute_confirm_sheet.dart b/mobile-app/lib/v2/screens/multisig/multisig_execute_confirm_sheet.dart index 32d32fed8..fb0076a2a 100644 --- a/mobile-app/lib/v2/screens/multisig/multisig_execute_confirm_sheet.dart +++ b/mobile-app/lib/v2/screens/multisig/multisig_execute_confirm_sheet.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/multisig_providers.dart'; import 'package:resonance_network_wallet/services/transaction_submission_service.dart'; -import 'package:resonance_network_wallet/v2/components/bottom_sheet_container.dart'; +import 'package:quantus_sdk/src/ui/components/bottom_sheet_container.dart'; import 'package:resonance_network_wallet/v2/screens/multisig/multisig_action_confirm_sheet.dart'; /// Shows the confirmation sheet for executing an approved multisig proposal. diff --git a/mobile-app/lib/v2/screens/multisig/multisig_proposal_detail_sheet.dart b/mobile-app/lib/v2/screens/multisig/multisig_proposal_detail_sheet.dart index 7b3bcafcd..2df0114a5 100644 --- a/mobile-app/lib/v2/screens/multisig/multisig_proposal_detail_sheet.dart +++ b/mobile-app/lib/v2/screens/multisig/multisig_proposal_detail_sheet.dart @@ -11,17 +11,17 @@ import 'package:resonance_network_wallet/providers/pending_multisig_approvals_pr import 'package:resonance_network_wallet/providers/pending_multisig_cancellations_provider.dart'; import 'package:resonance_network_wallet/providers/pending_multisig_executions_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; -import 'package:resonance_network_wallet/v2/components/multisig_expiry_value.dart'; +import 'package:quantus_sdk/src/ui/components/multisig_expiry_value.dart'; import 'package:resonance_network_wallet/routes.dart'; import 'package:resonance_network_wallet/shared/extensions/current_route_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/multisig_local_signers.dart'; -import 'package:resonance_network_wallet/v2/components/amount_display_with_conversion.dart'; -import 'package:resonance_network_wallet/v2/components/decoded_call_view.dart'; -import 'package:resonance_network_wallet/v2/components/bottom_sheet_container.dart'; -import 'package:resonance_network_wallet/v2/components/detail_summary_row.dart'; -import 'package:resonance_network_wallet/v2/components/explorer_link.dart'; -import 'package:resonance_network_wallet/v2/components/loader.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/amount_display_with_conversion.dart'; +import 'package:quantus_sdk/src/ui/components/decoded_call_view.dart'; +import 'package:quantus_sdk/src/ui/components/bottom_sheet_container.dart'; +import 'package:quantus_sdk/src/ui/components/detail_summary_row.dart'; +import 'package:quantus_sdk/src/ui/components/explorer_link.dart'; +import 'package:quantus_sdk/src/ui/components/loader.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; import 'package:resonance_network_wallet/v2/screens/multisig/multisig_approve_confirm_sheet.dart'; import 'package:resonance_network_wallet/v2/screens/multisig/multisig_cancel_confirm_sheet.dart'; import 'package:resonance_network_wallet/v2/screens/multisig/multisig_execute_confirm_sheet.dart'; diff --git a/mobile-app/lib/v2/screens/multisig/multisig_signer_picker_sheet.dart b/mobile-app/lib/v2/screens/multisig/multisig_signer_picker_sheet.dart index b41f7bf74..3efe92f30 100644 --- a/mobile-app/lib/v2/screens/multisig/multisig_signer_picker_sheet.dart +++ b/mobile-app/lib/v2/screens/multisig/multisig_signer_picker_sheet.dart @@ -2,8 +2,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; -import 'package:resonance_network_wallet/v2/components/account_badge.dart'; -import 'package:resonance_network_wallet/v2/components/bottom_sheet_container.dart'; +import 'package:quantus_sdk/src/ui/components/account_badge.dart'; +import 'package:quantus_sdk/src/ui/components/bottom_sheet_container.dart'; /// Picks which local signer account should approve a multisig proposal. /// diff --git a/mobile-app/lib/v2/screens/multisig/proposal_row.dart b/mobile-app/lib/v2/screens/multisig/proposal_row.dart index 9d73674fe..ffc13ab47 100644 --- a/mobile-app/lib/v2/screens/multisig/proposal_row.dart +++ b/mobile-app/lib/v2/screens/multisig/proposal_row.dart @@ -7,7 +7,7 @@ import 'package:resonance_network_wallet/providers/pending_multisig_approvals_pr import 'package:resonance_network_wallet/providers/pending_multisig_cancellations_provider.dart'; import 'package:resonance_network_wallet/providers/pending_multisig_executions_provider.dart'; import 'package:resonance_network_wallet/shared/utils/multisig_local_signers.dart'; -import 'package:resonance_network_wallet/v2/components/proposal_list_tile.dart'; +import 'package:quantus_sdk/src/ui/components/proposal_list_tile.dart'; class ProposalRow extends ConsumerWidget { final MultisigProposal proposal; diff --git a/mobile-app/lib/v2/screens/pos/pos_amount_screen.dart b/mobile-app/lib/v2/screens/pos/pos_amount_screen.dart index 0f69db475..5aa5c780d 100644 --- a/mobile-app/lib/v2/screens/pos/pos_amount_screen.dart +++ b/mobile-app/lib/v2/screens/pos/pos_amount_screen.dart @@ -10,11 +10,11 @@ import 'package:resonance_network_wallet/providers/wallet_providers.dart'; import 'package:resonance_network_wallet/shared/utils/amount_input_logic.dart'; import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_icon_button.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_icon_button.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/pos/pos_qr_screen.dart'; class PosAmountScreen extends ConsumerStatefulWidget { diff --git a/mobile-app/lib/v2/screens/pos/pos_qr_screen.dart b/mobile-app/lib/v2/screens/pos/pos_qr_screen.dart index 65cab7b04..b7e41bb76 100644 --- a/mobile-app/lib/v2/screens/pos/pos_qr_screen.dart +++ b/mobile-app/lib/v2/screens/pos/pos_qr_screen.dart @@ -13,16 +13,16 @@ import 'package:resonance_network_wallet/services/pending_transaction_polling_se import 'package:resonance_network_wallet/services/pos_service.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; import 'package:resonance_network_wallet/shared/utils/url_utils.dart'; -import 'package:resonance_network_wallet/v2/components/explorer_link.dart'; -import 'package:resonance_network_wallet/v2/components/loader.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_icon_button.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_qr.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; +import 'package:quantus_sdk/src/ui/components/explorer_link.dart'; +import 'package:quantus_sdk/src/ui/components/loader.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_icon_button.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_qr.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; import 'package:resonance_network_wallet/services/tx_watch_service.dart'; import 'package:resonance_network_wallet/v2/screens/pos/pos_amount_screen.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; class PosQrScreen extends ConsumerStatefulWidget { final BigInt amountToken; diff --git a/mobile-app/lib/v2/screens/receive/receive_screen.dart b/mobile-app/lib/v2/screens/receive/receive_screen.dart index af2370223..a264366b0 100644 --- a/mobile-app/lib/v2/screens/receive/receive_screen.dart +++ b/mobile-app/lib/v2/screens/receive/receive_screen.dart @@ -2,23 +2,23 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide AddressDetailsCard; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/v2/components/address_details_card.dart'; -import 'package:resonance_network_wallet/v2/components/loader.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_qr.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; -import 'package:resonance_network_wallet/v2/components/share_account_button.dart'; +import 'package:quantus_sdk/src/ui/components/loader.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_qr.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; +import 'package:quantus_sdk/src/ui/components/share_account_button.dart'; import 'package:resonance_network_wallet/shared/extensions/clipboard_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; import 'package:resonance_network_wallet/shared/utils/share_utils.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/segmented_controls.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/segmented_controls.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; enum ReceiveTab { qrCode, address } diff --git a/mobile-app/lib/v2/screens/send/encrypted_send_progress_screen.dart b/mobile-app/lib/v2/screens/send/encrypted_send_progress_screen.dart index 87e5bef42..3a137f271 100644 --- a/mobile-app/lib/v2/screens/send/encrypted_send_progress_screen.dart +++ b/mobile-app/lib/v2/screens/send/encrypted_send_progress_screen.dart @@ -1,3 +1,4 @@ + import 'dart:async'; import 'package:flutter/material.dart'; @@ -7,12 +8,12 @@ import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/encrypted_send_provider.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; -import 'package:resonance_network_wallet/v2/components/back_button.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; -import 'package:resonance_network_wallet/v2/components/wormhole_progress_steps.dart'; +import 'package:quantus_sdk/src/ui/components/back_button.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/wormhole_progress_steps.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_strategy.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_terminal_screen.dart'; diff --git a/mobile-app/lib/v2/screens/send/encrypted_send_strategy.dart b/mobile-app/lib/v2/screens/send/encrypted_send_strategy.dart index 2cb0c37ba..d5f8d408d 100644 --- a/mobile-app/lib/v2/screens/send/encrypted_send_strategy.dart +++ b/mobile-app/lib/v2/screens/send/encrypted_send_strategy.dart @@ -6,7 +6,7 @@ import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.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/v2/components/detail_summary_row.dart'; +import 'package:quantus_sdk/src/ui/components/detail_summary_row.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_strategy.dart'; /// ZK-private transfer from an encrypted (wormhole) account. Coin selection diff --git a/mobile-app/lib/v2/screens/send/input_amount_screen.dart b/mobile-app/lib/v2/screens/send/input_amount_screen.dart index 290cf00ed..95cdcfd95 100644 --- a/mobile-app/lib/v2/screens/send/input_amount_screen.dart +++ b/mobile-app/lib/v2/screens/send/input_amount_screen.dart @@ -9,19 +9,19 @@ import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/currency_display_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; import 'package:resonance_network_wallet/shared/constants/e2e_keys.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/send/review_send_screen.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_screen_logic.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_strategy.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/amount_input_logic.dart'; import 'package:resonance_network_wallet/shared/utils/debouncer.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; -import 'package:resonance_network_wallet/v2/components/loader.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_icon_button.dart'; +import 'package:quantus_sdk/src/ui/components/loader.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_icon_button.dart'; class InputAmountScreen extends ConsumerStatefulWidget { final SendStrategy strategy; diff --git a/mobile-app/lib/v2/screens/send/keystone_reject_screen.dart b/mobile-app/lib/v2/screens/send/keystone_reject_screen.dart index 4a635fbc5..4d9c23eae 100644 --- a/mobile-app/lib/v2/screens/send/keystone_reject_screen.dart +++ b/mobile-app/lib/v2/screens/send/keystone_reject_screen.dart @@ -2,10 +2,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_signing_widgets.dart'; import 'package:url_launcher/url_launcher.dart'; diff --git a/mobile-app/lib/v2/screens/send/keystone_sign_screen.dart b/mobile-app/lib/v2/screens/send/keystone_sign_screen.dart index d7c968c92..68ae5a326 100644 --- a/mobile-app/lib/v2/screens/send/keystone_sign_screen.dart +++ b/mobile-app/lib/v2/screens/send/keystone_sign_screen.dart @@ -7,12 +7,12 @@ import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/services/telemetry_service.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; -import 'package:resonance_network_wallet/v2/components/animated_ur_qr.dart'; -import 'package:resonance_network_wallet/v2/components/loader.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/animated_ur_qr.dart'; +import 'package:quantus_sdk/src/ui/components/loader.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_sign_cache.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_signing_session.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_signing_widgets.dart'; diff --git a/mobile-app/lib/v2/screens/send/keystone_signature_scan_screen.dart b/mobile-app/lib/v2/screens/send/keystone_signature_scan_screen.dart index 1768610e6..e051e9911 100644 --- a/mobile-app/lib/v2/screens/send/keystone_signature_scan_screen.dart +++ b/mobile-app/lib/v2/screens/send/keystone_signature_scan_screen.dart @@ -4,7 +4,7 @@ import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/services/telemetry_service.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; -import 'package:resonance_network_wallet/v2/components/animated_qr_scanner.dart'; +import 'package:quantus_sdk/src/ui/components/animated_qr_scanner.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_sign_cache.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_signing_session.dart'; diff --git a/mobile-app/lib/v2/screens/send/keystone_verify_screen.dart b/mobile-app/lib/v2/screens/send/keystone_verify_screen.dart index 740d42742..fe98b7989 100644 --- a/mobile-app/lib/v2/screens/send/keystone_verify_screen.dart +++ b/mobile-app/lib/v2/screens/send/keystone_verify_screen.dart @@ -3,11 +3,11 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; -import 'package:resonance_network_wallet/v2/components/address_checkphrase_with_initial.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/address_checkphrase_with_initial.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_reject_screen.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_signature_scan_screen.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_signing_session.dart'; diff --git a/mobile-app/lib/v2/screens/send/multisig_propose_strategy.dart b/mobile-app/lib/v2/screens/send/multisig_propose_strategy.dart index 5d310a7e6..16ca38ca5 100644 --- a/mobile-app/lib/v2/screens/send/multisig_propose_strategy.dart +++ b/mobile-app/lib/v2/screens/send/multisig_propose_strategy.dart @@ -12,8 +12,8 @@ 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/shared/utils/print.dart'; -import 'package:resonance_network_wallet/v2/components/detail_summary_row.dart'; -import 'package:resonance_network_wallet/v2/components/multisig_expiry_value.dart'; +import 'package:quantus_sdk/src/ui/components/detail_summary_row.dart'; +import 'package:quantus_sdk/src/ui/components/multisig_expiry_value.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_strategy.dart'; /// Proposes a transfer from a multisig account. The multisig is a view-only diff --git a/mobile-app/lib/v2/screens/send/regular_send_strategy.dart b/mobile-app/lib/v2/screens/send/regular_send_strategy.dart index da45e0b41..2fc073397 100644 --- a/mobile-app/lib/v2/screens/send/regular_send_strategy.dart +++ b/mobile-app/lib/v2/screens/send/regular_send_strategy.dart @@ -11,7 +11,7 @@ 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/shared/utils/print.dart'; import 'package:resonance_network_wallet/shared/utils/url_utils.dart'; -import 'package:resonance_network_wallet/v2/components/detail_summary_row.dart'; +import 'package:quantus_sdk/src/ui/components/detail_summary_row.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_sign_cache.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_signing_session.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_providers.dart'; diff --git a/mobile-app/lib/v2/screens/send/review_send_screen.dart b/mobile-app/lib/v2/screens/send/review_send_screen.dart index f32c5444f..8c4fbad79 100644 --- a/mobile-app/lib/v2/screens/send/review_send_screen.dart +++ b/mobile-app/lib/v2/screens/send/review_send_screen.dart @@ -9,13 +9,13 @@ import 'package:resonance_network_wallet/providers/currency_display_provider.dar import 'package:resonance_network_wallet/shared/constants/e2e_keys.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; import 'package:resonance_network_wallet/shared/utils/url_utils.dart'; -import 'package:resonance_network_wallet/v2/components/address_checkphrase_with_initial.dart'; -import 'package:resonance_network_wallet/v2/components/amount_display_with_conversion.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; -import 'package:resonance_network_wallet/v2/components/split_card.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/address_checkphrase_with_initial.dart'; +import 'package:quantus_sdk/src/ui/components/amount_display_with_conversion.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; +import 'package:quantus_sdk/src/ui/components/split_card.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/send/encrypted_send_progress_screen.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_sign_screen.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_strategy.dart'; diff --git a/mobile-app/lib/v2/screens/send/select_recipient_screen.dart b/mobile-app/lib/v2/screens/send/select_recipient_screen.dart index 711c8784b..6b1258b8f 100644 --- a/mobile-app/lib/v2/screens/send/select_recipient_screen.dart +++ b/mobile-app/lib/v2/screens/send/select_recipient_screen.dart @@ -12,15 +12,15 @@ import 'package:resonance_network_wallet/routes.dart'; import 'package:resonance_network_wallet/shared/constants/e2e_keys.dart'; import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; -import 'package:resonance_network_wallet/v2/components/address_checkphrase_with_initial.dart'; -import 'package:resonance_network_wallet/v2/components/address_input_field.dart'; -import 'package:resonance_network_wallet/v2/components/loader.dart'; -import 'package:resonance_network_wallet/v2/components/private_activity_notice.dart'; -import 'package:resonance_network_wallet/v2/components/qr_scanner_page.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/address_checkphrase_with_initial.dart'; +import 'package:quantus_sdk/src/ui/components/address_input_field.dart'; +import 'package:quantus_sdk/src/ui/components/loader.dart'; +import 'package:quantus_sdk/src/ui/components/private_activity_notice.dart'; +import 'package:quantus_sdk/src/ui/components/qr_scanner_page.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/send/input_amount_screen.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_strategy.dart'; diff --git a/mobile-app/lib/v2/screens/send/send_terminal_screen.dart b/mobile-app/lib/v2/screens/send/send_terminal_screen.dart index 22c5ad6f1..56957d2ef 100644 --- a/mobile-app/lib/v2/screens/send/send_terminal_screen.dart +++ b/mobile-app/lib/v2/screens/send/send_terminal_screen.dart @@ -1,14 +1,15 @@ + import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/shared/constants/e2e_keys.dart'; -import 'package:resonance_network_wallet/v2/components/back_button.dart'; -import 'package:resonance_network_wallet/v2/components/explorer_link.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/back_button.dart'; +import 'package:quantus_sdk/src/ui/components/explorer_link.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/home/home_screen.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_strategy.dart'; diff --git a/mobile-app/lib/v2/screens/settings/about_quantus_screen.dart b/mobile-app/lib/v2/screens/settings/about_quantus_screen.dart index bc268f0a1..37b179236 100644 --- a/mobile-app/lib/v2/screens/settings/about_quantus_screen.dart +++ b/mobile-app/lib/v2/screens/settings/about_quantus_screen.dart @@ -5,8 +5,8 @@ import 'package:resonance_network_wallet/generated/version.g.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/shared/utils/open_external_url.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_divider.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_tappable_row.dart'; diff --git a/mobile-app/lib/v2/screens/settings/add_account_menu_screen.dart b/mobile-app/lib/v2/screens/settings/add_account_menu_screen.dart index 7aeadac1d..1054a5947 100644 --- a/mobile-app/lib/v2/screens/settings/add_account_menu_screen.dart +++ b/mobile-app/lib/v2/screens/settings/add_account_menu_screen.dart @@ -6,10 +6,10 @@ import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/multisig_providers.dart'; import 'package:resonance_network_wallet/providers/remote_config_provider.dart'; import 'package:resonance_network_wallet/shared/utils/account_utils.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/add_hardware_account_screen.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/create_account_screen.dart'; import 'package:resonance_network_wallet/v2/screens/import/import_wallet_screen.dart'; diff --git a/mobile-app/lib/v2/screens/settings/help_and_support_screen.dart b/mobile-app/lib/v2/screens/settings/help_and_support_screen.dart index acf508e2b..dd9b765e4 100644 --- a/mobile-app/lib/v2/screens/settings/help_and_support_screen.dart +++ b/mobile-app/lib/v2/screens/settings/help_and_support_screen.dart @@ -3,8 +3,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/shared/utils/open_external_url.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_divider.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_tappable_row.dart'; diff --git a/mobile-app/lib/v2/screens/settings/mining_rewards_screen.dart b/mobile-app/lib/v2/screens/settings/mining_rewards_screen.dart index 5e2341fbf..fb1390e3e 100644 --- a/mobile-app/lib/v2/screens/settings/mining_rewards_screen.dart +++ b/mobile-app/lib/v2/screens/settings/mining_rewards_screen.dart @@ -8,11 +8,11 @@ import 'package:resonance_network_wallet/providers/mining_rewards_provider.dart' import 'package:resonance_network_wallet/providers/wallet_providers.dart'; import 'package:resonance_network_wallet/services/mining_rewards_service.dart'; import 'package:resonance_network_wallet/shared/utils/open_external_url.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; -import 'package:resonance_network_wallet/v2/components/split_card.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; +import 'package:quantus_sdk/src/ui/components/split_card.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/settings/redeem_address_screen.dart'; class MiningRewardsScreen extends ConsumerWidget { diff --git a/mobile-app/lib/v2/screens/settings/preferences_settings_screen.dart b/mobile-app/lib/v2/screens/settings/preferences_settings_screen.dart index b3450f7b0..ab80a7b4a 100644 --- a/mobile-app/lib/v2/screens/settings/preferences_settings_screen.dart +++ b/mobile-app/lib/v2/screens/settings/preferences_settings_screen.dart @@ -5,8 +5,8 @@ import 'package:resonance_network_wallet/providers/currency_display_provider.dar import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/notification_config_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/settings/currency_picker_screen.dart'; import 'package:resonance_network_wallet/v2/screens/settings/language_picker_screen.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_divider.dart'; 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 f5a0040e0..76eacf6a7 100644 --- a/mobile-app/lib/v2/screens/settings/recovery_phrase_screen.dart +++ b/mobile-app/lib/v2/screens/settings/recovery_phrase_screen.dart @@ -4,7 +4,7 @@ import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; import 'package:resonance_network_wallet/shared/constants/e2e_keys.dart'; -import 'package:resonance_network_wallet/v2/components/recovery_phrase_body.dart'; +import 'package:quantus_sdk/src/ui/components/recovery_phrase_body.dart'; class RecoveryPhraseScreen extends ConsumerStatefulWidget { const RecoveryPhraseScreen({super.key, this.walletIndex = 0}); diff --git a/mobile-app/lib/v2/screens/settings/redeem_address_screen.dart b/mobile-app/lib/v2/screens/settings/redeem_address_screen.dart index 7e06303a4..6a9afc63d 100644 --- a/mobile-app/lib/v2/screens/settings/redeem_address_screen.dart +++ b/mobile-app/lib/v2/screens/settings/redeem_address_screen.dart @@ -4,12 +4,12 @@ import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; -import 'package:resonance_network_wallet/v2/components/address_input_field.dart'; -import 'package:resonance_network_wallet/v2/components/bottom_sheet_container.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/address_input_field.dart'; +import 'package:quantus_sdk/src/ui/components/bottom_sheet_container.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/settings/redeem_progress_screen.dart'; /// Fullscreen flow to pick a destination address for redeeming mining diff --git a/mobile-app/lib/v2/screens/settings/redeem_progress_screen.dart b/mobile-app/lib/v2/screens/settings/redeem_progress_screen.dart index 8224093ff..5d0fce7bc 100644 --- a/mobile-app/lib/v2/screens/settings/redeem_progress_screen.dart +++ b/mobile-app/lib/v2/screens/settings/redeem_progress_screen.dart @@ -6,11 +6,11 @@ import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/mining_rewards_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; -import 'package:resonance_network_wallet/v2/components/wormhole_progress_steps.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/wormhole_progress_steps.dart'; class RedeemProgressScreen extends ConsumerStatefulWidget { final BigInt redeemableRewards; diff --git a/mobile-app/lib/v2/screens/settings/select_wallet_screen.dart b/mobile-app/lib/v2/screens/settings/select_wallet_screen.dart index 1299f2dcc..e5a124048 100644 --- a/mobile-app/lib/v2/screens/settings/select_wallet_screen.dart +++ b/mobile-app/lib/v2/screens/settings/select_wallet_screen.dart @@ -5,9 +5,9 @@ import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; import 'package:resonance_network_wallet/shared/utils/account_utils.dart'; -import 'package:resonance_network_wallet/v2/components/loader.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/loader.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/settings/recovery_phrase_confirmation_screen.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; diff --git a/mobile-app/lib/v2/screens/settings/settings_caution_scaffold.dart b/mobile-app/lib/v2/screens/settings/settings_caution_scaffold.dart index 341323082..255bd39a2 100644 --- a/mobile-app/lib/v2/screens/settings/settings_caution_scaffold.dart +++ b/mobile-app/lib/v2/screens/settings/settings_caution_scaffold.dart @@ -1,10 +1,10 @@ import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_checkbox.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_divider.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_list_row.dart'; diff --git a/mobile-app/lib/v2/screens/settings/settings_picker_screen.dart b/mobile-app/lib/v2/screens/settings/settings_picker_screen.dart index 17ede74c0..e32497d13 100644 --- a/mobile-app/lib/v2/screens/settings/settings_picker_screen.dart +++ b/mobile-app/lib/v2/screens/settings/settings_picker_screen.dart @@ -2,8 +2,8 @@ import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_divider.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_picker_widgets.dart'; diff --git a/mobile-app/lib/v2/screens/settings/settings_screen.dart b/mobile-app/lib/v2/screens/settings/settings_screen.dart index 58cb20b43..64aa0fc99 100644 --- a/mobile-app/lib/v2/screens/settings/settings_screen.dart +++ b/mobile-app/lib/v2/screens/settings/settings_screen.dart @@ -8,8 +8,8 @@ import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/mining_rewards_provider.dart'; import 'package:resonance_network_wallet/shared/constants/e2e_keys.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/settings/about_quantus_screen.dart'; import 'package:resonance_network_wallet/v2/screens/settings/add_account_menu_screen.dart'; import 'package:resonance_network_wallet/v2/screens/settings/help_and_support_screen.dart'; diff --git a/mobile-app/lib/v2/screens/settings/testnet_rewards_screen.dart b/mobile-app/lib/v2/screens/settings/testnet_rewards_screen.dart index 95b0beffa..a1f79e3ca 100644 --- a/mobile-app/lib/v2/screens/settings/testnet_rewards_screen.dart +++ b/mobile-app/lib/v2/screens/settings/testnet_rewards_screen.dart @@ -4,10 +4,10 @@ import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/mining_rewards_provider.dart'; import 'package:resonance_network_wallet/services/mining_rewards_service.dart'; -import 'package:resonance_network_wallet/v2/components/loader.dart'; +import 'package:quantus_sdk/src/ui/components/loader.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_divider.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; class TestnetRewardsScreen extends ConsumerWidget { diff --git a/mobile-app/lib/v2/screens/settings/wallet_settings_screen.dart b/mobile-app/lib/v2/screens/settings/wallet_settings_screen.dart index 50ba90da2..47f52f5a6 100644 --- a/mobile-app/lib/v2/screens/settings/wallet_settings_screen.dart +++ b/mobile-app/lib/v2/screens/settings/wallet_settings_screen.dart @@ -6,9 +6,8 @@ import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/shared/constants/e2e_keys.dart'; import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/account_utils.dart'; -import 'package:resonance_network_wallet/v2/components/loader.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/settings/recovery_phrase_confirmation_screen.dart'; import 'package:resonance_network_wallet/v2/screens/settings/reset_confirmation_screen.dart'; import 'package:resonance_network_wallet/v2/screens/settings/select_wallet_screen.dart'; diff --git a/mobile-app/lib/v2/screens/swap/deposit_screen.dart b/mobile-app/lib/v2/screens/swap/deposit_screen.dart index 21a162176..12d700241 100644 --- a/mobile-app/lib/v2/screens/swap/deposit_screen.dart +++ b/mobile-app/lib/v2/screens/swap/deposit_screen.dart @@ -5,12 +5,12 @@ import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/shared/extensions/clipboard_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/share_utils.dart'; -import 'package:resonance_network_wallet/v2/components/loader.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/token_icon.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; -import 'package:resonance_network_wallet/v2/components/success_check.dart'; +import 'package:quantus_sdk/src/ui/components/loader.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/token_icon.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/success_check.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; diff --git a/mobile-app/lib/v2/screens/swap/refund_address_picker_sheet.dart b/mobile-app/lib/v2/screens/swap/refund_address_picker_sheet.dart index 154ce4bbd..36fa4e7e6 100644 --- a/mobile-app/lib/v2/screens/swap/refund_address_picker_sheet.dart +++ b/mobile-app/lib/v2/screens/swap/refund_address_picker_sheet.dart @@ -2,7 +2,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/providers/l10n_provider.dart'; -import 'package:resonance_network_wallet/v2/components/bottom_sheet_container.dart'; +import 'package:quantus_sdk/src/ui/components/bottom_sheet_container.dart'; Future showRefundAddressPickerSheet(BuildContext context, String network) { return BottomSheetContainer.show(context, builder: (_) => _RefundAddressPickerContent(network: network)); diff --git a/mobile-app/lib/v2/screens/swap/review_quote_sheet.dart b/mobile-app/lib/v2/screens/swap/review_quote_sheet.dart index b3ef49d0a..bc3a32470 100644 --- a/mobile-app/lib/v2/screens/swap/review_quote_sheet.dart +++ b/mobile-app/lib/v2/screens/swap/review_quote_sheet.dart @@ -2,9 +2,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; -import 'package:resonance_network_wallet/v2/components/bottom_sheet_container.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/token_icon.dart'; +import 'package:quantus_sdk/src/ui/components/bottom_sheet_container.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/token_icon.dart'; import 'package:resonance_network_wallet/v2/screens/swap/deposit_screen.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; diff --git a/mobile-app/lib/v2/screens/swap/swap_screen.dart b/mobile-app/lib/v2/screens/swap/swap_screen.dart index df8a696a9..6eb756d3f 100644 --- a/mobile-app/lib/v2/screens/swap/swap_screen.dart +++ b/mobile-app/lib/v2/screens/swap/swap_screen.dart @@ -3,13 +3,13 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/qr_scanner_page.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/qr_scanner_page.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; -import 'package:resonance_network_wallet/v2/components/token_icon.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/token_icon.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/swap/refund_address_picker_sheet.dart'; import 'package:resonance_network_wallet/v2/screens/swap/review_quote_sheet.dart'; import 'package:resonance_network_wallet/v2/screens/swap/token_picker_sheet.dart'; diff --git a/mobile-app/lib/v2/screens/swap/token_picker_sheet.dart b/mobile-app/lib/v2/screens/swap/token_picker_sheet.dart index d2fb7392c..caaceb95f 100644 --- a/mobile-app/lib/v2/screens/swap/token_picker_sheet.dart +++ b/mobile-app/lib/v2/screens/swap/token_picker_sheet.dart @@ -2,9 +2,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; -import 'package:resonance_network_wallet/v2/components/bottom_sheet_container.dart'; -import 'package:resonance_network_wallet/v2/components/loader.dart'; -import 'package:resonance_network_wallet/v2/components/token_icon.dart'; +import 'package:quantus_sdk/src/ui/components/bottom_sheet_container.dart'; +import 'package:quantus_sdk/src/ui/components/loader.dart'; +import 'package:quantus_sdk/src/ui/components/token_icon.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; diff --git a/mobile-app/lib/v2/screens/welcome/welcome_screen.dart b/mobile-app/lib/v2/screens/welcome/welcome_screen.dart index 1ac5c1b39..de0a17279 100644 --- a/mobile-app/lib/v2/screens/welcome/welcome_screen.dart +++ b/mobile-app/lib/v2/screens/welcome/welcome_screen.dart @@ -1,3 +1,4 @@ + import 'dart:async'; import 'package:flutter/material.dart'; @@ -10,8 +11,8 @@ import 'package:resonance_network_wallet/services/firebase_messaging_service.dar import 'package:resonance_network_wallet/services/wallet_creation_service.dart'; import 'package:resonance_network_wallet/shared/constants/e2e_keys.dart'; import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/account_ready_screen.dart'; import 'package:resonance_network_wallet/v2/screens/import/import_wallet_screen.dart'; import 'package:resonance_network_wallet/v2/screens/welcome/onboarding_background.dart'; diff --git a/mobile-app/lib/wallet_initializer.dart b/mobile-app/lib/wallet_initializer.dart index 613664619..dce33aa26 100644 --- a/mobile-app/lib/wallet_initializer.dart +++ b/mobile-app/lib/wallet_initializer.dart @@ -5,9 +5,9 @@ import 'package:resonance_network_wallet/features/components/migration_dialog.da import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; -import 'package:resonance_network_wallet/v2/components/bottom_sheet_container.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/bottom_sheet_container.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; import 'package:resonance_network_wallet/v2/screens/home/home_screen.dart'; import 'package:resonance_network_wallet/v2/screens/welcome/welcome_screen.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; diff --git a/quantus_sdk/lib/quantus_sdk.dart b/quantus_sdk/lib/quantus_sdk.dart index 0bcfc17ba..9a57c6c0a 100644 --- a/quantus_sdk/lib/quantus_sdk.dart +++ b/quantus_sdk/lib/quantus_sdk.dart @@ -17,12 +17,7 @@ export 'src/extensions/keypair_extensions.dart'; export 'src/extensions/media_query_data_extension.dart'; export 'src/extensions/string_extensions.dart'; // UI-related exports -export 'src/ui/themes/app_theme.dart'; -export 'src/ui/themes/app_colors.dart'; -export 'src/ui/themes/app_radius.dart'; -export 'src/ui/themes/app_spacing.dart'; -export 'src/ui/themes/app_text_styles.dart'; - +export 'src/ui/index.dart'; export 'src/models/account.dart'; export 'src/models/base_account.dart'; export 'src/models/high_security_data.dart'; @@ -54,6 +49,7 @@ export 'src/models/raid_stats.dart'; export 'src/rust/api/crypto.dart' hide crystalAlice, crystalCharlie, crystalBob; export 'src/rust/api/ur.dart'; export 'src/utils/ur_qr.dart'; +export 'src/utils/account_utils.dart'; export 'src/rust/api/wormhole.dart'; export 'src/services/account_discovery_service.dart'; export 'src/services/accounts_service.dart'; diff --git a/mobile-app/lib/v2/components/account_badge.dart b/quantus_sdk/lib/src/ui/components/account_badge.dart similarity index 95% rename from mobile-app/lib/v2/components/account_badge.dart rename to quantus_sdk/lib/src/ui/components/account_badge.dart index 53bee1686..4653e228c 100644 --- a/mobile-app/lib/v2/components/account_badge.dart +++ b/quantus_sdk/lib/src/ui/components/account_badge.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:resonance_network_wallet/shared/utils/account_utils.dart'; class AccountBadge extends StatelessWidget { final String name; diff --git a/mobile-app/lib/v2/components/address_checkphrase_with_initial.dart b/quantus_sdk/lib/src/ui/components/address_checkphrase_with_initial.dart similarity index 96% rename from mobile-app/lib/v2/components/address_checkphrase_with_initial.dart rename to quantus_sdk/lib/src/ui/components/address_checkphrase_with_initial.dart index 5f9906fde..06ad00f06 100644 --- a/mobile-app/lib/v2/components/address_checkphrase_with_initial.dart +++ b/quantus_sdk/lib/src/ui/components/address_checkphrase_with_initial.dart @@ -1,6 +1,5 @@ import 'package:flutter/widgets.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:resonance_network_wallet/shared/utils/account_utils.dart'; class AddressCheckphraseWithInitial extends StatelessWidget { final String recipientChecksum; diff --git a/quantus_sdk/lib/src/ui/components/address_details_card.dart b/quantus_sdk/lib/src/ui/components/address_details_card.dart new file mode 100644 index 000000000..591fdca98 --- /dev/null +++ b/quantus_sdk/lib/src/ui/components/address_details_card.dart @@ -0,0 +1,157 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +import 'split_card.dart'; + +/// Presentational address + checkphrase card. Copy side effects and copy live in the host app. +class AddressDetailsCard extends StatefulWidget { + final String accountId; + final String? checksum; + final String addressLabel; + final String checkphraseLabel; + final String checksumPlaceholder; + final VoidCallback onCopyAddress; + final VoidCallback onCopyChecksum; + + const AddressDetailsCard({ + super.key, + required this.accountId, + this.checksum, + required this.addressLabel, + required this.checkphraseLabel, + required this.checksumPlaceholder, + required this.onCopyAddress, + required this.onCopyChecksum, + }); + + @override + State createState() => _AddressDetailsCardState(); +} + +class _AddressDetailsCardState extends State { + bool _addressCopied = false; + bool _checksumCopied = false; + Timer? _resetTimer; + + void _copyAddress() { + widget.onCopyAddress(); + _triggerCopied(isAddress: true); + } + + void _copyChecksum() { + if (widget.checksum == null) return; + + widget.onCopyChecksum(); + _triggerCopied(isAddress: false); + } + + void _triggerCopied({required bool isAddress}) { + _resetTimer?.cancel(); + + setState(() { + if (isAddress) { + _addressCopied = true; + _checksumCopied = false; + } else { + _checksumCopied = true; + _addressCopied = false; + } + }); + + _resetTimer = Timer(const Duration(seconds: 2), () { + if (mounted) { + setState(() { + if (isAddress) { + _addressCopied = false; + } else { + _checksumCopied = false; + } + }); + } + }); + } + + @override + void dispose() { + _resetTimer?.cancel(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return SplitCard( + topChild: InkWell( + onTap: _copyAddress, + child: _buildItem(context, widget.addressLabel, widget.accountId, isCopied: _addressCopied), + ), + bottomChild: InkWell( + onTap: widget.checksum == null ? null : _copyChecksum, + child: _buildItem( + context, + widget.checkphraseLabel, + widget.checksum ?? widget.checksumPlaceholder, + isCheckphrase: true, + isCopied: _checksumCopied, + ), + ), + ); + } + + Widget _buildItem( + BuildContext context, + String label, + String value, { + bool isCheckphrase = false, + required bool isCopied, + }) { + final valueTextStyle = isCheckphrase + ? context.themeText.smallParagraph?.copyWith(color: context.colors.checksum) + : context.themeText.smallParagraph?.copyWith(fontFamily: AppTextTheme.fontFamilySecondary); + + return Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(label, style: context.themeText.receiveLabel?.copyWith(color: context.colors.textLabel)), + const SizedBox(height: 16), + Text(value, style: valueTextStyle), + ], + ), + ), + const SizedBox(width: 32), + _copyButton(isCopied: isCopied), + ], + ); + } + + Widget _copyButton({required bool isCopied}) { + const containerSize = 40.0; + const iconSize = 16.0; + + return AnimatedContainer( + duration: const Duration(milliseconds: 200), + width: containerSize, + height: containerSize, + decoration: BoxDecoration( + color: isCopied ? context.colors.copyButtonCopiedBg : Colors.transparent, + border: Border.all( + color: isCopied ? context.colors.copyButtonCopiedBorder : context.colors.borderButton, + width: 1, + ), + borderRadius: BorderRadius.circular(containerSize / 2), + ), + child: Center( + child: Icon( + isCopied ? Icons.check : Icons.copy, + size: iconSize, + color: isCopied ? context.colors.success : context.colors.textPrimary, + ), + ), + ); + } +} diff --git a/mobile-app/lib/v2/components/address_input_field.dart b/quantus_sdk/lib/src/ui/components/address_input_field.dart similarity index 100% rename from mobile-app/lib/v2/components/address_input_field.dart rename to quantus_sdk/lib/src/ui/components/address_input_field.dart diff --git a/mobile-app/lib/v2/components/amount_display_with_conversion.dart b/quantus_sdk/lib/src/ui/components/amount_display_with_conversion.dart similarity index 97% rename from mobile-app/lib/v2/components/amount_display_with_conversion.dart rename to quantus_sdk/lib/src/ui/components/amount_display_with_conversion.dart index 43561c548..4ac16a924 100644 --- a/mobile-app/lib/v2/components/amount_display_with_conversion.dart +++ b/quantus_sdk/lib/src/ui/components/amount_display_with_conversion.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/currency_display_provider.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_icon_button.dart'; class AmountDisplayWithConversion extends StatelessWidget { final CurrencyDisplayState amountDisplay; diff --git a/mobile-app/lib/v2/components/animated_qr_scanner.dart b/quantus_sdk/lib/src/ui/components/animated_qr_scanner.dart similarity index 98% rename from mobile-app/lib/v2/components/animated_qr_scanner.dart rename to quantus_sdk/lib/src/ui/components/animated_qr_scanner.dart index 98dc1cb46..53544dfc9 100644 --- a/mobile-app/lib/v2/components/animated_qr_scanner.dart +++ b/quantus_sdk/lib/src/ui/components/animated_qr_scanner.dart @@ -3,8 +3,8 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:mobile_scanner/mobile_scanner.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; /// Sequence metadata encoded in one frame of an animated QR payload. class AnimatedQrSequence { diff --git a/mobile-app/lib/v2/components/animated_ur_qr.dart b/quantus_sdk/lib/src/ui/components/animated_ur_qr.dart similarity index 100% rename from mobile-app/lib/v2/components/animated_ur_qr.dart rename to quantus_sdk/lib/src/ui/components/animated_ur_qr.dart diff --git a/mobile-app/lib/v2/components/back_button.dart b/quantus_sdk/lib/src/ui/components/back_button.dart similarity index 91% rename from mobile-app/lib/v2/components/back_button.dart rename to quantus_sdk/lib/src/ui/components/back_button.dart index 3bfe7c319..9da8a55e2 100644 --- a/mobile-app/lib/v2/components/back_button.dart +++ b/quantus_sdk/lib/src/ui/components/back_button.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:resonance_network_wallet/v2/components/glass_button_base.dart'; class AppBackButton extends StatelessWidget { final VoidCallback? onTap; diff --git a/mobile-app/lib/v2/components/base_background.dart b/quantus_sdk/lib/src/ui/components/base_background.dart similarity index 100% rename from mobile-app/lib/v2/components/base_background.dart rename to quantus_sdk/lib/src/ui/components/base_background.dart diff --git a/mobile-app/lib/v2/components/bottom_sheet_container.dart b/quantus_sdk/lib/src/ui/components/bottom_sheet_container.dart similarity index 100% rename from mobile-app/lib/v2/components/bottom_sheet_container.dart rename to quantus_sdk/lib/src/ui/components/bottom_sheet_container.dart diff --git a/mobile-app/lib/v2/components/confirm_action_sheet.dart b/quantus_sdk/lib/src/ui/components/confirm_action_sheet.dart similarity index 92% rename from mobile-app/lib/v2/components/confirm_action_sheet.dart rename to quantus_sdk/lib/src/ui/components/confirm_action_sheet.dart index dfd015300..f2beb0e79 100644 --- a/mobile-app/lib/v2/components/confirm_action_sheet.dart +++ b/quantus_sdk/lib/src/ui/components/confirm_action_sheet.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:resonance_network_wallet/v2/components/bottom_sheet_container.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/bottom_sheet_container.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; /// Generic "are you sure?" confirmation sheet. Resolves to true when the user /// taps the confirm action, false on cancel/dismiss. diff --git a/mobile-app/lib/v2/components/decoded_call_view.dart b/quantus_sdk/lib/src/ui/components/decoded_call_view.dart similarity index 98% rename from mobile-app/lib/v2/components/decoded_call_view.dart rename to quantus_sdk/lib/src/ui/components/decoded_call_view.dart index b2a33d114..dd80ea46d 100644 --- a/mobile-app/lib/v2/components/decoded_call_view.dart +++ b/quantus_sdk/lib/src/ui/components/decoded_call_view.dart @@ -2,7 +2,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/providers/currency_display_provider.dart'; -import 'package:resonance_network_wallet/v2/components/detail_summary_row.dart'; +import 'package:quantus_sdk/src/ui/components/detail_summary_row.dart'; /// Renders every parameter of a [DecodedCall], nested calls included. /// diff --git a/mobile-app/lib/v2/components/detail_summary_row.dart b/quantus_sdk/lib/src/ui/components/detail_summary_row.dart similarity index 100% rename from mobile-app/lib/v2/components/detail_summary_row.dart rename to quantus_sdk/lib/src/ui/components/detail_summary_row.dart diff --git a/mobile-app/lib/v2/components/explorer_link.dart b/quantus_sdk/lib/src/ui/components/explorer_link.dart similarity index 100% rename from mobile-app/lib/v2/components/explorer_link.dart rename to quantus_sdk/lib/src/ui/components/explorer_link.dart diff --git a/mobile-app/lib/v2/components/glass_button_base.dart b/quantus_sdk/lib/src/ui/components/glass_button_base.dart similarity index 100% rename from mobile-app/lib/v2/components/glass_button_base.dart rename to quantus_sdk/lib/src/ui/components/glass_button_base.dart diff --git a/mobile-app/lib/v2/components/global_toast_listener.dart b/quantus_sdk/lib/src/ui/components/global_toast_listener.dart similarity index 100% rename from mobile-app/lib/v2/components/global_toast_listener.dart rename to quantus_sdk/lib/src/ui/components/global_toast_listener.dart diff --git a/quantus_sdk/lib/src/ui/components/index.dart b/quantus_sdk/lib/src/ui/components/index.dart new file mode 100644 index 000000000..d7add23e3 --- /dev/null +++ b/quantus_sdk/lib/src/ui/components/index.dart @@ -0,0 +1,5 @@ +export 'quantus_button.dart'; +export 'loader.dart'; +export 'quantus_icon_button.dart'; +export 'glass_button_base.dart'; +export 'address_details_card.dart'; diff --git a/mobile-app/lib/v2/components/loader.dart b/quantus_sdk/lib/src/ui/components/loader.dart similarity index 100% rename from mobile-app/lib/v2/components/loader.dart rename to quantus_sdk/lib/src/ui/components/loader.dart diff --git a/mobile-app/lib/v2/components/menu_divider.dart b/quantus_sdk/lib/src/ui/components/menu_divider.dart similarity index 100% rename from mobile-app/lib/v2/components/menu_divider.dart rename to quantus_sdk/lib/src/ui/components/menu_divider.dart diff --git a/mobile-app/lib/v2/components/multisig_expiry_value.dart b/quantus_sdk/lib/src/ui/components/multisig_expiry_value.dart similarity index 100% rename from mobile-app/lib/v2/components/multisig_expiry_value.dart rename to quantus_sdk/lib/src/ui/components/multisig_expiry_value.dart diff --git a/mobile-app/lib/v2/components/multisig_signer_list_tile.dart b/quantus_sdk/lib/src/ui/components/multisig_signer_list_tile.dart similarity index 100% rename from mobile-app/lib/v2/components/multisig_signer_list_tile.dart rename to quantus_sdk/lib/src/ui/components/multisig_signer_list_tile.dart diff --git a/mobile-app/lib/v2/components/multisig_tag.dart b/quantus_sdk/lib/src/ui/components/multisig_tag.dart similarity index 100% rename from mobile-app/lib/v2/components/multisig_tag.dart rename to quantus_sdk/lib/src/ui/components/multisig_tag.dart diff --git a/mobile-app/lib/v2/components/multisig_threshold_slider.dart b/quantus_sdk/lib/src/ui/components/multisig_threshold_slider.dart similarity index 100% rename from mobile-app/lib/v2/components/multisig_threshold_slider.dart rename to quantus_sdk/lib/src/ui/components/multisig_threshold_slider.dart diff --git a/mobile-app/lib/v2/components/name_field.dart b/quantus_sdk/lib/src/ui/components/name_field.dart similarity index 100% rename from mobile-app/lib/v2/components/name_field.dart rename to quantus_sdk/lib/src/ui/components/name_field.dart diff --git a/mobile-app/lib/v2/components/private_activity_notice.dart b/quantus_sdk/lib/src/ui/components/private_activity_notice.dart similarity index 100% rename from mobile-app/lib/v2/components/private_activity_notice.dart rename to quantus_sdk/lib/src/ui/components/private_activity_notice.dart diff --git a/mobile-app/lib/v2/components/proposal_list_tile.dart b/quantus_sdk/lib/src/ui/components/proposal_list_tile.dart similarity index 98% rename from mobile-app/lib/v2/components/proposal_list_tile.dart rename to quantus_sdk/lib/src/ui/components/proposal_list_tile.dart index 1a0d72eb0..2bde3d049 100644 --- a/mobile-app/lib/v2/components/proposal_list_tile.dart +++ b/quantus_sdk/lib/src/ui/components/proposal_list_tile.dart @@ -3,7 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/currency_display_provider.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; -import 'package:resonance_network_wallet/v2/components/decoded_call_view.dart'; +import 'package:quantus_sdk/src/ui/components/decoded_call_view.dart'; /// Shared card layout for indexed and pending multisig proposal rows. class ProposalListTile extends ConsumerWidget { diff --git a/mobile-app/lib/v2/components/qr_scanner_page.dart b/quantus_sdk/lib/src/ui/components/qr_scanner_page.dart similarity index 97% rename from mobile-app/lib/v2/components/qr_scanner_page.dart rename to quantus_sdk/lib/src/ui/components/qr_scanner_page.dart index d2e4eb82e..8ebca78d4 100644 --- a/mobile-app/lib/v2/components/qr_scanner_page.dart +++ b/quantus_sdk/lib/src/ui/components/qr_scanner_page.dart @@ -5,8 +5,7 @@ import 'package:image_picker/image_picker.dart'; import 'package:mobile_scanner/mobile_scanner.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_icon_button.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; class QrScannerPage extends ConsumerStatefulWidget { final bool Function(String)? validator; diff --git a/mobile-app/lib/v2/components/quantus_button.dart b/quantus_sdk/lib/src/ui/components/quantus_button.dart similarity index 50% rename from mobile-app/lib/v2/components/quantus_button.dart rename to quantus_sdk/lib/src/ui/components/quantus_button.dart index 687b4a449..2afd70d68 100644 --- a/mobile-app/lib/v2/components/quantus_button.dart +++ b/quantus_sdk/lib/src/ui/components/quantus_button.dart @@ -1,9 +1,22 @@ import 'dart:math' as math; import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:resonance_network_wallet/v2/components/loader.dart'; -enum ButtonVariant { transparent, primary, secondary, danger, success, outline, glass, underline } +enum ButtonVariant { + transparent, + primary, + secondary, + danger, + outline, + glass, + underline, + + /// Not-yet-ready primary: surface fill and emphasis border. + staged, + + /// Escape route: no fill or border, muted label. + ghost, +} enum IconPlacement { leading, trailing, top } @@ -13,28 +26,25 @@ class QuantusButton extends StatelessWidget { final Widget? _icon; final IconPlacement _iconPlacement; final TextStyle? _textStyle; + final BorderRadius? borderRadius; final VoidCallback? onTap; final bool isLoading; final double? width; final EdgeInsets padding; final ButtonVariant variant; final bool isDisabled; - final double borderRadius; final bool centered; - static const double defaultBorderRadius = 14.0; - static const double buttonFontSize = 16.0; - const QuantusButton({ super.key, required Widget this.child, this.onTap, + this.borderRadius, this.isLoading = false, this.width = double.infinity, - this.padding = const EdgeInsets.symmetric(horizontal: 12, vertical: 12), + this.padding = const EdgeInsets.symmetric(horizontal: 16, vertical: 16), this.variant = ButtonVariant.primary, this.isDisabled = false, - this.borderRadius = defaultBorderRadius, this.centered = true, }) : _label = null, _icon = null, @@ -48,13 +58,13 @@ class QuantusButton extends StatelessWidget { Widget? icon, IconPlacement iconPlacement = IconPlacement.trailing, this.onTap, + this.borderRadius, this.isLoading = false, this.width = double.infinity, - this.padding = const EdgeInsets.symmetric(horizontal: 40, vertical: 12), + this.padding = const EdgeInsets.symmetric(horizontal: 40, vertical: 16), TextStyle? textStyle, this.variant = ButtonVariant.primary, this.isDisabled = false, - this.borderRadius = defaultBorderRadius, this.centered = true, }) : _label = label, _icon = icon, @@ -65,60 +75,15 @@ class QuantusButton extends StatelessWidget { @override Widget build(BuildContext context) { final bool disabled = onTap == null || isLoading || isDisabled; - final visibility = disabled ? 0.5 : 1.0; - final buttonContent = _buildContent(context, variant: variant, disabled: disabled); - final borderRadius = BorderRadius.circular(this.borderRadius); - final basicBorder = BorderSide(color: context.colors.borderButton, width: 1); - - Color? buttonDecorationColor; - LinearGradient? buttonDecorationGradient; - BorderSide borderSide = BorderSide.none; - - switch (variant) { - case ButtonVariant.primary: - buttonDecorationColor = context.colors.accentOrange; - break; - - case ButtonVariant.secondary: - buttonDecorationGradient = LinearGradient( - transform: const GradientRotation(90 * math.pi / 180), - colors: [context.colors.surfaceDeep, context.colors.sheetBackground], - stops: [0.0, 1.0], - ); - borderSide = basicBorder.copyWith(color: context.colors.borderButton.useOpacity(0.5)); - break; - - case ButtonVariant.danger: - buttonDecorationColor = context.colors.buttonDanger; - break; - - case ButtonVariant.success: - buttonDecorationColor = context.colors.success; - break; - - case ButtonVariant.transparent: - buttonDecorationColor = Colors.transparent; - break; - - case ButtonVariant.outline: - buttonDecorationColor = Colors.transparent; - borderSide = basicBorder; - break; - - case ButtonVariant.glass: - buttonDecorationColor = context.colors.surfaceGlass; - break; - - case ButtonVariant.underline: - buttonDecorationColor = Colors.transparent; - break; - } + final chrome = _chrome(context, disabled: disabled); + final buttonContent = _buildContent(context, textColor: chrome.textColor); + final borderRadius = this.borderRadius ?? context.radiusV3.mdBorder; if (variant == ButtonVariant.underline) { return InkWell( onTap: disabled ? null : onTap, child: Opacity( - opacity: visibility, + opacity: chrome.opacity, child: Container(width: width, padding: padding, child: buttonContent), ), ); @@ -127,14 +92,14 @@ class QuantusButton extends StatelessWidget { return InkWell( onTap: disabled ? null : onTap, child: Opacity( - opacity: visibility, + opacity: chrome.opacity, child: Container( width: width, padding: padding, decoration: ShapeDecoration( - color: disabled ? context.colors.sheetBackground : buttonDecorationColor, - gradient: disabled ? null : buttonDecorationGradient, - shape: RoundedRectangleBorder(borderRadius: borderRadius, side: disabled ? basicBorder : borderSide), + color: chrome.color, + gradient: chrome.gradient, + shape: RoundedRectangleBorder(borderRadius: borderRadius, side: chrome.borderSide), ), child: buttonContent, ), @@ -142,20 +107,76 @@ class QuantusButton extends StatelessWidget { ); } - Widget _buildContent(BuildContext context, {ButtonVariant variant = ButtonVariant.primary, bool disabled = false}) { - final textColor = switch (variant) { - ButtonVariant.primary => context.colors.background, - ButtonVariant.secondary => context.colors.textPrimary, - ButtonVariant.danger => context.colors.textPrimary, - ButtonVariant.transparent => context.colors.textPrimary, - ButtonVariant.success => context.colors.textPrimary, - ButtonVariant.outline => context.colors.textLabel, - ButtonVariant.glass => context.colors.textPrimary, - ButtonVariant.underline => context.colors.textMuted, + _ButtonChrome _chrome(BuildContext context, {required bool disabled}) { + final colors = context.colorsV3; + final basicBorder = BorderSide(color: colors.borderEmphasis, width: 1); + + if (disabled && (variant == ButtonVariant.primary || variant == ButtonVariant.staged)) { + return _ButtonChrome(color: colors.bgSurface2, textColor: colors.textMuted2); + } + + final enabled = switch (variant) { + ButtonVariant.primary => _ButtonChrome(color: colors.accentFlare, textColor: colors.textVoid), + ButtonVariant.staged => _ButtonChrome( + color: colors.bgSurface, + borderSide: basicBorder, + textColor: colors.textContent, + ), + ButtonVariant.ghost => _ButtonChrome( + color: Colors.transparent, + textColor: disabled ? colors.textMuted2 : colors.textMuted, + ), + ButtonVariant.secondary => _ButtonChrome( + gradient: LinearGradient( + transform: const GradientRotation(90 * math.pi / 180), + colors: [context.colors.surfaceDeep, context.colors.sheetBackground], + stops: [0.0, 1.0], + ), + borderSide: basicBorder.copyWith(color: context.colors.borderButton.useOpacity(0.5)), + textColor: colors.textContent, + ), + ButtonVariant.danger => _ButtonChrome(color: context.colors.buttonDanger, textColor: colors.textContent), + ButtonVariant.transparent => _ButtonChrome(color: Colors.transparent, textColor: colors.textContent), + ButtonVariant.outline => _ButtonChrome( + color: Colors.transparent, + borderSide: basicBorder, + textColor: colors.textContent, + ), + ButtonVariant.glass => _ButtonChrome(color: context.colors.surfaceGlass, textColor: colors.textContent), + ButtonVariant.underline => _ButtonChrome( + color: Colors.transparent, + opacity: disabled ? 0.5 : 1.0, + textColor: colors.textMuted, + ), }; + final usesLegacyDisabled = + disabled && + variant != ButtonVariant.primary && + variant != ButtonVariant.staged && + variant != ButtonVariant.ghost && + variant != ButtonVariant.underline; + if (usesLegacyDisabled) { + return _legacyDisabledChrome(context, basicBorder); + } + + return enabled; + } + + _ButtonChrome _legacyDisabledChrome(BuildContext context, BorderSide basicBorder) { + return _ButtonChrome( + color: context.colors.sheetBackground, + borderSide: basicBorder, + opacity: 0.5, + textColor: context.colors.textPrimary.useOpacity(0.5), + ); + } + + Widget _buildContent(BuildContext context, {required Color textColor}) { + final defaultTextStyle = context.themeTextV3.headingRow; + if (isLoading) { - final size = (_textStyle?.fontSize ?? buttonFontSize) + 6; + final size = (_textStyle?.fontSize ?? defaultTextStyle.fontSize!) + 6; return Center(child: Loader(size: size)); } @@ -163,12 +184,7 @@ class QuantusButton extends StatelessWidget { final effectiveTextStyle = variant == ButtonVariant.underline ? _underlineTextStyle(context, textColor) - : _textStyle ?? - context.themeText.paragraph!.copyWith( - fontSize: buttonFontSize, - color: disabled ? context.colors.textPrimary.useOpacity(0.5) : textColor, - fontWeight: FontWeight.w500, - ); + : _textStyle ?? defaultTextStyle.copyWith(color: textColor); Widget content; if (_iconPlacement == IconPlacement.top) { @@ -202,3 +218,19 @@ class QuantusButton extends StatelessWidget { return style.copyWith(decoration: TextDecoration.underline, decorationColor: style.color); } } + +class _ButtonChrome { + final Color? color; + final LinearGradient? gradient; + final BorderSide borderSide; + final double opacity; + final Color textColor; + + const _ButtonChrome({ + this.color, + this.gradient, + this.borderSide = BorderSide.none, + this.opacity = 1.0, + required this.textColor, + }); +} diff --git a/mobile-app/lib/v2/components/quantus_icon_button.dart b/quantus_sdk/lib/src/ui/components/quantus_icon_button.dart similarity index 97% rename from mobile-app/lib/v2/components/quantus_icon_button.dart rename to quantus_sdk/lib/src/ui/components/quantus_icon_button.dart index d11c5c6ae..4772ce0b9 100644 --- a/mobile-app/lib/v2/components/quantus_icon_button.dart +++ b/quantus_sdk/lib/src/ui/components/quantus_icon_button.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:resonance_network_wallet/v2/components/glass_button_base.dart'; enum IconButtonShape { rounded, circular } diff --git a/mobile-app/lib/v2/components/quantus_qr.dart b/quantus_sdk/lib/src/ui/components/quantus_qr.dart similarity index 100% rename from mobile-app/lib/v2/components/quantus_qr.dart rename to quantus_sdk/lib/src/ui/components/quantus_qr.dart diff --git a/mobile-app/lib/v2/components/recovery_phrase_body.dart b/quantus_sdk/lib/src/ui/components/recovery_phrase_body.dart similarity index 92% rename from mobile-app/lib/v2/components/recovery_phrase_body.dart rename to quantus_sdk/lib/src/ui/components/recovery_phrase_body.dart index 3b399901c..50202d366 100644 --- a/mobile-app/lib/v2/components/recovery_phrase_body.dart +++ b/quantus_sdk/lib/src/ui/components/recovery_phrase_body.dart @@ -6,11 +6,11 @@ import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/shared/constants/e2e_keys.dart'; import 'package:resonance_network_wallet/shared/extensions/clipboard_extensions.dart'; -import 'package:resonance_network_wallet/v2/components/loader.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; -import 'package:resonance_network_wallet/v2/components/scaffold_base_bottom_content.dart'; -import 'package:resonance_network_wallet/v2/components/v2_app_bar.dart'; +import 'package:quantus_sdk/src/ui/components/loader.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; +import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; +import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; class RecoveryPhraseBody extends ConsumerStatefulWidget { final String appBarTitle; diff --git a/mobile-app/lib/v2/components/scaffold_base.dart b/quantus_sdk/lib/src/ui/components/scaffold_base.dart similarity index 97% rename from mobile-app/lib/v2/components/scaffold_base.dart rename to quantus_sdk/lib/src/ui/components/scaffold_base.dart index 0f3054eb1..f6f6d1c59 100644 --- a/mobile-app/lib/v2/components/scaffold_base.dart +++ b/quantus_sdk/lib/src/ui/components/scaffold_base.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:resonance_network_wallet/features/components/network_status_banner.dart'; -import 'package:resonance_network_wallet/v2/components/base_background.dart'; +import 'package:quantus_sdk/src/ui/components/base_background.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; class ScaffoldBase extends StatelessWidget { diff --git a/mobile-app/lib/v2/components/scaffold_base_bottom_content.dart b/quantus_sdk/lib/src/ui/components/scaffold_base_bottom_content.dart similarity index 100% rename from mobile-app/lib/v2/components/scaffold_base_bottom_content.dart rename to quantus_sdk/lib/src/ui/components/scaffold_base_bottom_content.dart diff --git a/mobile-app/lib/v2/components/segmented_controls.dart b/quantus_sdk/lib/src/ui/components/segmented_controls.dart similarity index 100% rename from mobile-app/lib/v2/components/segmented_controls.dart rename to quantus_sdk/lib/src/ui/components/segmented_controls.dart diff --git a/mobile-app/lib/v2/components/share_account_button.dart b/quantus_sdk/lib/src/ui/components/share_account_button.dart similarity index 91% rename from mobile-app/lib/v2/components/share_account_button.dart rename to quantus_sdk/lib/src/ui/components/share_account_button.dart index d6e9c9546..a8bad924b 100644 --- a/mobile-app/lib/v2/components/share_account_button.dart +++ b/quantus_sdk/lib/src/ui/components/share_account_button.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; -import 'package:resonance_network_wallet/v2/components/quantus_button.dart'; +import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; class ShareAccountButton extends ConsumerWidget { diff --git a/mobile-app/lib/v2/components/split_card.dart b/quantus_sdk/lib/src/ui/components/split_card.dart similarity index 100% rename from mobile-app/lib/v2/components/split_card.dart rename to quantus_sdk/lib/src/ui/components/split_card.dart diff --git a/mobile-app/lib/v2/components/success_check.dart b/quantus_sdk/lib/src/ui/components/success_check.dart similarity index 100% rename from mobile-app/lib/v2/components/success_check.dart rename to quantus_sdk/lib/src/ui/components/success_check.dart diff --git a/mobile-app/lib/v2/components/toaster.dart b/quantus_sdk/lib/src/ui/components/toaster.dart similarity index 100% rename from mobile-app/lib/v2/components/toaster.dart rename to quantus_sdk/lib/src/ui/components/toaster.dart diff --git a/mobile-app/lib/v2/components/toaster_helper.dart b/quantus_sdk/lib/src/ui/components/toaster_helper.dart similarity index 97% rename from mobile-app/lib/v2/components/toaster_helper.dart rename to quantus_sdk/lib/src/ui/components/toaster_helper.dart index 3a674aae1..625ade4b6 100644 --- a/mobile-app/lib/v2/components/toaster_helper.dart +++ b/quantus_sdk/lib/src/ui/components/toaster_helper.dart @@ -1,7 +1,7 @@ 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:quantus_sdk/src/ui/components/toaster.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; Future showToaster( diff --git a/mobile-app/lib/v2/components/token_icon.dart b/quantus_sdk/lib/src/ui/components/token_icon.dart similarity index 100% rename from mobile-app/lib/v2/components/token_icon.dart rename to quantus_sdk/lib/src/ui/components/token_icon.dart diff --git a/mobile-app/lib/v2/components/v2_app_bar.dart b/quantus_sdk/lib/src/ui/components/v2_app_bar.dart similarity index 93% rename from mobile-app/lib/v2/components/v2_app_bar.dart rename to quantus_sdk/lib/src/ui/components/v2_app_bar.dart index 4d3b4422d..07667d9f3 100644 --- a/mobile-app/lib/v2/components/v2_app_bar.dart +++ b/quantus_sdk/lib/src/ui/components/v2_app_bar.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:resonance_network_wallet/v2/components/back_button.dart'; +import 'package:quantus_sdk/src/ui/components/back_button.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; class V2AppBar extends StatelessWidget { diff --git a/mobile-app/lib/v2/components/wormhole_progress_steps.dart b/quantus_sdk/lib/src/ui/components/wormhole_progress_steps.dart similarity index 100% rename from mobile-app/lib/v2/components/wormhole_progress_steps.dart rename to quantus_sdk/lib/src/ui/components/wormhole_progress_steps.dart diff --git a/quantus_sdk/lib/src/ui/index.dart b/quantus_sdk/lib/src/ui/index.dart new file mode 100644 index 000000000..c92b15cd2 --- /dev/null +++ b/quantus_sdk/lib/src/ui/index.dart @@ -0,0 +1,2 @@ +export 'components/index.dart'; +export 'themes/index.dart'; diff --git a/quantus_sdk/lib/src/ui/themes/app_colors.dart b/quantus_sdk/lib/src/ui/themes/app_colors.dart index 04bbb9172..6d50fe6ff 100644 --- a/quantus_sdk/lib/src/ui/themes/app_colors.dart +++ b/quantus_sdk/lib/src/ui/themes/app_colors.dart @@ -391,6 +391,9 @@ class AppColorsV3 extends ThemeExtension { /// Default text. Titles, amounts, body. Warm, not pure white. final Color textContent; + /// Void text. Used for text on accent color. + final Color textVoid; + /// Secondary. Darkest gray legal on small text (AA floor). final Color textMuted; @@ -429,6 +432,7 @@ class AppColorsV3 extends ThemeExtension { required this.bgSurface, required this.bgSurface2, required this.textContent, + required this.textVoid, required this.textMuted, required this.textMuted2, required this.textWhite, @@ -451,6 +455,7 @@ class AppColorsV3 extends ThemeExtension { bgSurface: const Color(0xFF181818), bgSurface2: const Color(0xFF222222), textContent: const Color(0xFFE8E6E0), + textVoid: const Color(0xFF0E0E0E), textMuted: const Color(0xFF8A8784), textMuted2: const Color(0xFF6B6966), textWhite: const Color(0xFFFFFFFF), @@ -470,6 +475,7 @@ class AppColorsV3 extends ThemeExtension { Color? bgSurface, Color? bgSurface2, Color? textContent, + Color? textVoid, Color? textMuted, Color? textMuted2, Color? textWhite, @@ -487,6 +493,7 @@ class AppColorsV3 extends ThemeExtension { bgSurface: bgSurface ?? this.bgSurface, bgSurface2: bgSurface2 ?? this.bgSurface2, textContent: textContent ?? this.textContent, + textVoid: textVoid ?? this.textVoid, textMuted: textMuted ?? this.textMuted, textMuted2: textMuted2 ?? this.textMuted2, textWhite: textWhite ?? this.textWhite, @@ -509,6 +516,7 @@ class AppColorsV3 extends ThemeExtension { bgSurface: Color.lerp(bgSurface, other.bgSurface, t) ?? bgSurface, bgSurface2: Color.lerp(bgSurface2, other.bgSurface2, t) ?? bgSurface2, textContent: Color.lerp(textContent, other.textContent, t) ?? textContent, + textVoid: Color.lerp(textVoid, other.textVoid, t) ?? textVoid, textMuted: Color.lerp(textMuted, other.textMuted, t) ?? textMuted, textMuted2: Color.lerp(textMuted2, other.textMuted2, t) ?? textMuted2, textWhite: Color.lerp(textWhite, other.textWhite, t) ?? textWhite, diff --git a/quantus_sdk/lib/src/ui/themes/index.dart b/quantus_sdk/lib/src/ui/themes/index.dart new file mode 100644 index 000000000..06b3d68e9 --- /dev/null +++ b/quantus_sdk/lib/src/ui/themes/index.dart @@ -0,0 +1,5 @@ +export 'app_theme.dart'; +export 'app_colors.dart'; +export 'app_radius.dart'; +export 'app_spacing.dart'; +export 'app_text_styles.dart'; diff --git a/mobile-app/lib/shared/utils/account_utils.dart b/quantus_sdk/lib/src/utils/account_utils.dart similarity index 100% rename from mobile-app/lib/shared/utils/account_utils.dart rename to quantus_sdk/lib/src/utils/account_utils.dart diff --git a/quantus_sdk/pubspec.lock b/quantus_sdk/pubspec.lock index 9ad456d4e..c5dfc127b 100644 --- a/quantus_sdk/pubspec.lock +++ b/quantus_sdk/pubspec.lock @@ -347,6 +347,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.1.0" + flutter_svg: + dependency: "direct main" + description: + name: flutter_svg + sha256: "35882981abcbfb8c15b286f0cd690ff25bac12d95eff3e25ee207f37d4c42e7f" + url: "https://pub.dev" + source: hosted + version: "2.3.0" flutter_test: dependency: "direct dev" description: flutter @@ -560,6 +568,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.1" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" + url: "https://pub.dev" + source: hosted + version: "1.1.0" path_provider: dependency: "direct main" description: @@ -697,7 +713,7 @@ packages: source: hosted version: "3.0.2" qr_flutter: - dependency: "direct dev" + dependency: "direct main" description: name: qr_flutter sha256: "5095f0fc6e3f71d08adef8feccc8cea4f12eec18a2e31c2e8d82cb6019f4b097" @@ -956,6 +972,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.3" + vector_graphics: + dependency: transitive + description: + name: vector_graphics + sha256: "9d0e3b9cb16542ad660daee871e726a10d13a93b7b5391677c3160e8f5e83935" + url: "https://pub.dev" + source: hosted + version: "1.2.3" + vector_graphics_codec: + dependency: transitive + description: + name: vector_graphics_codec + sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146" + url: "https://pub.dev" + source: hosted + version: "1.1.13" + vector_graphics_compiler: + dependency: transitive + description: + name: vector_graphics_compiler + sha256: "4dca4feb77dc3ec7f6e27e49c53241eb8217f55e4f9b12599a27f8903bca5682" + url: "https://pub.dev" + source: hosted + version: "1.3.0" vector_math: dependency: transitive description: diff --git a/quantus_sdk/pubspec.yaml b/quantus_sdk/pubspec.yaml index 002de93c2..82b58550a 100644 --- a/quantus_sdk/pubspec.yaml +++ b/quantus_sdk/pubspec.yaml @@ -42,6 +42,9 @@ dependencies: url: https://github.com/Quantus-Network/qp-human-checkphrase.git ref: v2.2.0 path: dart + + qr_flutter: ^4.1.0 + flutter_svg: ^2.3.0 dev_dependencies: flutter_test: @@ -49,7 +52,7 @@ dev_dependencies: integration_test: sdk: flutter flutter_lints: ^6.0.0 - qr_flutter: ^4.1.0 + # DO NOT UPDATE polkadart_cli - must match polkadart 0.7.x. See note above. polkadart_cli: ^0.7.1 From 688566dd7f114f595b7d7449652835ce968a1926 Mon Sep 17 00:00:00 2001 From: Beast Date: Sat, 15 Aug 2026 09:22:59 +0700 Subject: [PATCH 04/38] feat: move reusable component to sdk - move components - use theme from sdk --- .../components/custom_text_field.dart | 106 ------ .../components/notification_card.dart | 342 ------------------ .../components/notification_group.dart | 85 ----- .../lib/features/styles/app_colors_theme.dart | 289 --------------- .../lib/features/styles/app_size_theme.dart | 228 ------------ .../lib/features/styles/app_text_theme.dart | 191 ---------- mobile-app/lib/features/styles/app_theme.dart | 89 ----- mobile-app/lib/l10n/app_en.arb | 4 + mobile-app/lib/l10n/app_id.arb | 1 + mobile-app/lib/l10n/app_localizations.dart | 6 + mobile-app/lib/l10n/app_localizations_en.dart | 3 + mobile-app/lib/l10n/app_localizations_id.dart | 3 + .../extensions/clipboard_extensions.dart | 2 +- .../lib/shared}/utils/account_utils.dart | 0 .../lib/v2}/components/account_badge.dart | 1 + .../address_checkphrase_with_initial.dart | 1 + .../v2/components/address_details_card.dart | 146 +++++++- .../v2}/components/address_input_field.dart | 0 .../amount_display_with_conversion.dart | 0 .../v2}/components/animated_qr_scanner.dart | 2 - .../lib/v2/components/decoded_call_view.dart | 23 ++ .../components/dotted_border.dart | 0 .../lib/v2}/components/explorer_link.dart | 0 .../v2}/components/global_toast_listener.dart | 2 +- .../components/migration_dialog.dart | 1 - .../components/mnemonic_grid.dart | 0 .../v2}/components/multisig_expiry_value.dart | 0 .../components/multisig_signer_list_tile.dart | 0 .../lib/v2}/components/multisig_tag.dart | 0 .../components/multisig_threshold_slider.dart | 0 .../lib/v2}/components/name_field.dart | 0 .../components/network_status_banner.dart | 4 +- .../components/private_activity_notice.dart | 0 .../v2}/components/proposal_list_tile.dart | 1 - .../lib/v2}/components/qr_scanner_page.dart | 1 - .../v2}/components/recovery_phrase_body.dart | 11 +- .../v2}/components/share_account_button.dart | 1 - .../shared_address_action_sheet.dart | 4 +- .../{features => v2}/components/skeleton.dart | 0 .../lib/v2}/components/split_card.dart | 0 .../lib/v2}/components/success_check.dart | 0 .../lib/v2}/components/token_icon.dart | 0 .../components/wormhole_progress_steps.dart | 0 .../accounts/account_details_screen.dart | 7 +- .../screens/accounts/account_menu_screen.dart | 9 +- .../accounts/account_ready_screen.dart | 10 +- .../v2/screens/accounts/accounts_screen.dart | 12 +- .../accounts/add_hardware_account_screen.dart | 4 - .../accounts/connect_keystone_screen.dart | 6 +- .../accounts/create_account_screen.dart | 7 +- .../screens/accounts/edit_account_screen.dart | 7 +- .../multisig_account_menu_screen.dart | 9 +- .../accounts/multisig_details_screen.dart | 4 +- .../screens/accounts/wallet_name_screen.dart | 6 +- .../v2/screens/activity/activity_screen.dart | 5 +- .../activity/transaction_detail_sheet.dart | 7 +- .../lib/v2/screens/auth/auth_wrapper.dart | 3 - .../lib/v2/screens/home/activity_section.dart | 2 +- .../lib/v2/screens/home/home_screen.dart | 49 +-- .../screens/import/import_wallet_screen.dart | 4 - .../screens/multisig/add_multisig_screen.dart | 13 +- .../multisig/discover_multisig_screen.dart | 6 +- .../multisig_action_confirm_sheet.dart | 7 +- .../multisig/multisig_activity_section.dart | 1 + .../multisig_approve_confirm_sheet.dart | 1 - .../multisig_cancel_confirm_sheet.dart | 2 - .../multisig_execute_confirm_sheet.dart | 1 - .../multisig_proposal_detail_sheet.dart | 16 +- .../multisig_signer_picker_sheet.dart | 3 +- .../lib/v2/screens/multisig/proposal_row.dart | 2 +- .../lib/v2/screens/pos/pos_amount_screen.dart | 6 - .../lib/v2/screens/pos/pos_qr_screen.dart | 9 +- .../v2/screens/receive/receive_screen.dart | 14 +- .../send/encrypted_send_progress_screen.dart | 8 +- .../screens/send/encrypted_send_strategy.dart | 1 - .../v2/screens/send/input_amount_screen.dart | 7 - .../screens/send/keystone_reject_screen.dart | 4 - .../v2/screens/send/keystone_sign_screen.dart | 6 - .../send/keystone_signature_scan_screen.dart | 2 +- .../screens/send/keystone_verify_screen.dart | 6 +- .../send/multisig_propose_strategy.dart | 3 +- .../screens/send/regular_send_strategy.dart | 1 - .../v2/screens/send/review_send_screen.dart | 10 +- .../screens/send/select_recipient_screen.dart | 18 +- .../v2/screens/send/send_terminal_screen.dart | 8 +- .../settings/about_quantus_screen.dart | 2 - .../settings/add_account_menu_screen.dart | 4 - .../settings/help_and_support_screen.dart | 2 - .../settings/mining_rewards_screen.dart | 8 +- .../settings/preferences_settings_screen.dart | 2 - .../recovery_phrase_confirmation_screen.dart | 2 +- .../settings/recovery_phrase_screen.dart | 2 +- .../settings/redeem_address_screen.dart | 7 +- .../settings/redeem_progress_screen.dart | 6 +- .../settings/reset_confirmation_screen.dart | 2 +- .../settings/select_wallet_screen.dart | 3 - .../settings/settings_caution_scaffold.dart | 4 - .../settings/settings_picker_screen.dart | 3 - .../v2/screens/settings/settings_screen.dart | 2 - .../settings/testnet_rewards_screen.dart | 3 - .../settings/wallet_settings_screen.dart | 3 - .../lib/v2/screens/swap/deposit_screen.dart | 8 +- .../swap/refund_address_picker_sheet.dart | 1 - .../v2/screens/swap/review_quote_sheet.dart | 4 +- .../lib/v2/screens/swap/swap_screen.dart | 13 +- .../v2/screens/swap/token_picker_sheet.dart | 4 +- .../v2/screens/welcome/welcome_screen.dart | 4 - mobile-app/lib/wallet_initializer.dart | 6 +- mobile-app/pubspec.yaml | 1 - .../assets/v2/uppercase_q_black_bg.png | Bin quantus_sdk/lib/quantus_sdk.dart | 2 +- .../src}/extensions/toaster_extensions.dart | 0 .../ui/components/address_details_card.dart | 157 -------- .../ui/components/confirm_action_sheet.dart | 2 - .../src/ui/components/decoded_call_view.dart | 24 +- quantus_sdk/lib/src/ui/components/index.dart | 14 +- .../lib/src/ui/components/quantus_qr.dart | 2 +- .../lib/src/ui/components/scaffold_base.dart | 6 +- quantus_sdk/pubspec.yaml | 4 + 119 files changed, 292 insertions(+), 1868 deletions(-) delete mode 100644 mobile-app/lib/features/components/custom_text_field.dart delete mode 100644 mobile-app/lib/features/components/notification_card.dart delete mode 100644 mobile-app/lib/features/components/notification_group.dart delete mode 100644 mobile-app/lib/features/styles/app_colors_theme.dart delete mode 100644 mobile-app/lib/features/styles/app_size_theme.dart delete mode 100644 mobile-app/lib/features/styles/app_text_theme.dart delete mode 100644 mobile-app/lib/features/styles/app_theme.dart rename {quantus_sdk/lib/src => mobile-app/lib/shared}/utils/account_utils.dart (100%) rename {quantus_sdk/lib/src/ui => mobile-app/lib/v2}/components/account_badge.dart (95%) rename {quantus_sdk/lib/src/ui => mobile-app/lib/v2}/components/address_checkphrase_with_initial.dart (96%) rename {quantus_sdk/lib/src/ui => mobile-app/lib/v2}/components/address_input_field.dart (100%) rename {quantus_sdk/lib/src/ui => mobile-app/lib/v2}/components/amount_display_with_conversion.dart (100%) rename {quantus_sdk/lib/src/ui => mobile-app/lib/v2}/components/animated_qr_scanner.dart (98%) create mode 100644 mobile-app/lib/v2/components/decoded_call_view.dart rename mobile-app/lib/{features => v2}/components/dotted_border.dart (100%) rename {quantus_sdk/lib/src/ui => mobile-app/lib/v2}/components/explorer_link.dart (100%) rename {quantus_sdk/lib/src/ui => mobile-app/lib/v2}/components/global_toast_listener.dart (93%) rename mobile-app/lib/{features => v2}/components/migration_dialog.dart (98%) rename mobile-app/lib/{features => v2}/components/mnemonic_grid.dart (100%) rename {quantus_sdk/lib/src/ui => mobile-app/lib/v2}/components/multisig_expiry_value.dart (100%) rename {quantus_sdk/lib/src/ui => mobile-app/lib/v2}/components/multisig_signer_list_tile.dart (100%) rename {quantus_sdk/lib/src/ui => mobile-app/lib/v2}/components/multisig_tag.dart (100%) rename {quantus_sdk/lib/src/ui => mobile-app/lib/v2}/components/multisig_threshold_slider.dart (100%) rename {quantus_sdk/lib/src/ui => mobile-app/lib/v2}/components/name_field.dart (100%) rename mobile-app/lib/{features => v2}/components/network_status_banner.dart (88%) rename {quantus_sdk/lib/src/ui => mobile-app/lib/v2}/components/private_activity_notice.dart (100%) rename {quantus_sdk/lib/src/ui => mobile-app/lib/v2}/components/proposal_list_tile.dart (98%) rename {quantus_sdk/lib/src/ui => mobile-app/lib/v2}/components/qr_scanner_page.dart (99%) rename {quantus_sdk/lib/src/ui => mobile-app/lib/v2}/components/recovery_phrase_body.dart (92%) rename {quantus_sdk/lib/src/ui => mobile-app/lib/v2}/components/share_account_button.dart (92%) rename mobile-app/lib/{features => v2}/components/shared_address_action_sheet.dart (98%) rename mobile-app/lib/{features => v2}/components/skeleton.dart (100%) rename {quantus_sdk/lib/src/ui => mobile-app/lib/v2}/components/split_card.dart (100%) rename {quantus_sdk/lib/src/ui => mobile-app/lib/v2}/components/success_check.dart (100%) rename {quantus_sdk/lib/src/ui => mobile-app/lib/v2}/components/token_icon.dart (100%) rename {quantus_sdk/lib/src/ui => mobile-app/lib/v2}/components/wormhole_progress_steps.dart (100%) rename {mobile-app => quantus_sdk}/assets/v2/uppercase_q_black_bg.png (100%) rename {mobile-app/lib/shared => quantus_sdk/lib/src}/extensions/toaster_extensions.dart (100%) delete mode 100644 quantus_sdk/lib/src/ui/components/address_details_card.dart diff --git a/mobile-app/lib/features/components/custom_text_field.dart b/mobile-app/lib/features/components/custom_text_field.dart deleted file mode 100644 index 6c97fda92..000000000 --- a/mobile-app/lib/features/components/custom_text_field.dart +++ /dev/null @@ -1,106 +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'; - -enum TextFieldVariant { primary, secondary } - -class CustomTextField extends StatelessWidget { - final String? labelText; - final TextStyle? textStyle; - final String? initialValue; - final Color? fillColor; - final String? hintText; - final TextStyle? hintStyle; - final Icon? icon; - final Widget? trailing; - final bool obscureText; - final ValueChanged? onChanged; - final TextEditingController? controller; - final String? errorMsg; - final double? leftPadding; - final bool? disabled; - final TextFieldVariant variant; - - const CustomTextField({ - super.key, - this.labelText, - this.textStyle, - this.initialValue, - this.fillColor, - this.hintText, - this.hintStyle, - this.icon, - this.trailing, - this.obscureText = false, - this.errorMsg, - this.onChanged, - this.leftPadding, - this.controller, - this.disabled = false, - this.variant = TextFieldVariant.primary, - }) : assert(initialValue == null || controller == null, 'Cannot provide both an initialValue and a controller.'); - - @override - Widget build(BuildContext context) { - final effectiveTextStyle = variant == TextFieldVariant.primary - ? context.themeText.smallTitle - : context.themeText.paragraph; - final effectiveHintStyle = variant == TextFieldVariant.primary - ? context.themeText.smallTitle?.copyWith(color: context.themeColors.textPrimary.useOpacity(0.5)) - : context.themeText.paragraph?.copyWith(color: context.themeColors.textPrimary.useOpacity(0.5)); - - // The main container for the entire widget - return SizedBox( - width: double.infinity, - child: Column( - mainAxisSize: MainAxisSize.min, // Takes up minimum vertical space - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // The label is now optional and will only be displayed if labelText is not null. - if (labelText != null) ...[Text(labelText!, style: context.themeText.smallTitle), const SizedBox(height: 4)], - // The container that forms the background of the input field - Stack( - alignment: AlignmentGeometry.center, - children: [ - TextFormField( - controller: controller, - initialValue: initialValue, - enabled: disabled != true, - onChanged: onChanged, - obscureText: obscureText, - // Styling for the text inside the input field - style: textStyle ?? effectiveTextStyle, - decoration: InputDecoration( - fillColor: fillColor, - isDense: true, - enabledBorder: errorMsg != null - ? const OutlineInputBorder(borderSide: BorderSide(color: Colors.red, width: 1)) - : InputBorder.none, - focusedBorder: errorMsg != null - ? const OutlineInputBorder(borderSide: BorderSide(color: Colors.red, width: 1)) - : InputBorder.none, - contentPadding: EdgeInsets.only( - top: 10, - bottom: 10, - left: leftPadding ?? 11, - right: (trailing != null || icon != null) ? 40 : 11, - ), - hintText: hintText, - hintStyle: hintStyle ?? effectiveHintStyle, - ), - ), - - if (icon != null) Positioned(right: 16, child: icon!), - if (trailing != null) Positioned(right: 10, child: trailing!), - ], - ), - - if (errorMsg != null) ...[ - const SizedBox(height: 4), - Text(errorMsg!, style: context.themeText.tiny?.copyWith(color: context.themeColors.textError)), - ], - ], - ), - ); - } -} diff --git a/mobile-app/lib/features/components/notification_card.dart b/mobile-app/lib/features/components/notification_card.dart deleted file mode 100644 index 3288c0513..000000000 --- a/mobile-app/lib/features/components/notification_card.dart +++ /dev/null @@ -1,342 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:flutter_svg/svg.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:resonance_network_wallet/models/notification_models.dart'; -import 'package:resonance_network_wallet/providers/account_providers.dart'; -import 'package:resonance_network_wallet/services/transaction_service.dart'; -import 'package:resonance_network_wallet/v2/screens/activity/transaction_detail_sheet.dart'; - -class NotificationCard extends ConsumerStatefulWidget { - final NotificationData notification; - final VoidCallback onDismiss; - - const NotificationCard({super.key, required this.notification, required this.onDismiss}); - - @override - ConsumerState createState() => _NotificationCardState(); -} - -class _NotificationCardState extends ConsumerState with TickerProviderStateMixin { - late AnimationController _slideController; - late AnimationController _swipeController; - late Animation _slideAnimation; - late Animation _swipeAnimation; - bool _isDismissing = false; - double _swipeOffset = 0.0; - - Color get titleColor { - switch (widget.notification.type) { - case NotificationType.success: - return const Color(0xFF8AF9A8); // Green - case NotificationType.warning: - return const Color(0xFFFADC34); // Yellow - case NotificationType.alert: - return const Color(0xFFFF2D54); // Red - default: - return const Color(0xFF16CECE); // Info - } - } - - SvgPicture get icon { - switch (widget.notification.type) { - case NotificationType.success: - return SvgPicture.asset('assets/notification/tick_icon.svg', width: 22, height: 22); - case NotificationType.warning: - return SvgPicture.asset('assets/notification/alert_icon.svg', width: 21, height: 20); - case NotificationType.alert: - return SvgPicture.asset('assets/notification/red_alert_icon.svg', width: 21, height: 20); - default: - return SvgPicture.asset('assets/notification/hourglass_icon.svg', width: 21, height: 21); - } - } - - @override - void initState() { - super.initState(); - _slideController = AnimationController(duration: const Duration(milliseconds: 300), vsync: this); - - _swipeController = AnimationController(duration: const Duration(milliseconds: 200), vsync: this); - - _slideAnimation = Tween( - begin: const Offset(1.0, 0.0), - end: Offset.zero, - ).animate(CurvedAnimation(parent: _slideController, curve: Curves.easeOut)); - - _swipeAnimation = Tween( - begin: Offset.zero, - end: Offset.zero, - ).animate(CurvedAnimation(parent: _swipeController, curve: Curves.easeOut)); - - _slideController.forward(); - } - - @override - void dispose() { - _slideController.dispose(); - _swipeController.dispose(); - super.dispose(); - } - - void _handleSwipeDismiss() async { - if (_isDismissing) return; - - setState(() { - _isDismissing = true; - }); - - // Animate the swipe out - final swipeDirection = _swipeOffset > 0 ? 2.0 : -2.0; - _swipeAnimation = Tween( - begin: Offset(_swipeOffset / MediaQuery.of(context).size.width, 0), - end: Offset(swipeDirection, 0), - ).animate(CurvedAnimation(parent: _swipeController, curve: Curves.easeIn)); - - await _swipeController.forward(); - widget.onDismiss(); - } - - void _handleSwipeUpdate(double delta) { - if (_isDismissing) return; - - setState(() { - _swipeOffset += delta; - // Limit the swipe offset to prevent over-swiping - _swipeOffset = _swipeOffset.clamp(-150.0, 150.0); - }); - } - - void _handleSwipeEnd(double velocity) { - if (_isDismissing) return; - - const double threshold = 80.0; // Threshold distance for dismissal - const double velocityThreshold = 500.0; // Velocity threshold for quick swipes - - // Check if swipe meets dismissal criteria - bool shouldDismiss = _swipeOffset.abs() > threshold || velocity.abs() > velocityThreshold; - - if (shouldDismiss) { - _handleSwipeDismiss(); - } else { - // Animate back to original position - _resetSwipePosition(); - } - } - - void _resetSwipePosition() { - _swipeAnimation = Tween( - begin: Offset(_swipeOffset / MediaQuery.of(context).size.width, 0), - end: Offset.zero, - ).animate(CurvedAnimation(parent: _swipeController, curve: Curves.easeOut)); - - _swipeController.forward().then((_) { - setState(() { - _swipeOffset = 0.0; - }); - _swipeController.reset(); - }); - } - - void _onViewDetails() { - final txService = ref.read(transactionServiceProvider); - final transaction = txService.deserializeTxEventFromJsonIfPossible(widget.notification.metadata); - final activeAccount = ref.read(activeAccountProvider).value; - - if (transaction != null && activeAccount != null) { - showTransactionDetailSheet(context, transaction, activeAccount.account.accountId); - } - } - - @override - Widget build(BuildContext context) { - final notification = widget.notification; - final txService = ref.read(transactionServiceProvider); - final transaction = txService.deserializeTxEventFromJsonIfPossible(notification.metadata); - - return GestureDetector( - onHorizontalDragUpdate: (details) { - _handleSwipeUpdate(details.delta.dx); - }, - onHorizontalDragEnd: (details) { - _handleSwipeEnd(details.primaryVelocity ?? 0); - }, - child: SlideTransition( - position: _slideAnimation, - child: AnimatedBuilder( - animation: _slideController, - builder: (context, child) { - // Calculate opacity based on swipe offset - final swipeProgress = (_swipeOffset.abs() / 150.0).clamp(0.0, 1.0); - final opacity = 1.0 - (swipeProgress * 0.3); - - return Transform.translate( - offset: _isDismissing - ? _swipeAnimation.value * MediaQuery.of(context).size.width - : Offset(_swipeOffset, 0), - child: Opacity( - opacity: opacity, - child: Material( - elevation: 8, - borderRadius: BorderRadius.circular(4), - child: Container( - decoration: ShapeDecoration( - color: const Color(0x99313131), - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)), - ), - child: Column( - children: [ - Container( - width: double.infinity, - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 3), - decoration: ShapeDecoration( - color: Colors.white.withValues(alpha: 0.15), - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(4), - topRight: Radius.circular(4), - ), - ), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - spacing: 13, - children: [ - Text( - notification.accountName, - style: const TextStyle( - color: Colors.white, - fontSize: 12, - fontFamily: 'Fira Code', - fontWeight: FontWeight.w600, - ), - ), - ], - ), - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), - child: Column( - spacing: 13, - children: [ - Row( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, - spacing: 13, - children: [ - icon, - Expanded( - child: Column( - spacing: 2, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text.rich( - TextSpan( - children: [ - TextSpan( - text: notification.title, - style: TextStyle( - color: titleColor /* Green */, - fontSize: 14, - fontFamily: 'Fira Code', - fontWeight: FontWeight.w400, - ), - ), - const TextSpan( - text: ' ', - style: TextStyle( - color: Color(0xFFD9D9D9), - fontSize: 10, - fontFamily: 'Fira Code', - fontWeight: FontWeight.w400, - ), - ), - TextSpan( - text: - // ignore: lines_longer_than_80_chars - DatetimeFormattingService.format(notification.timestamp), - style: const TextStyle( - color: Color(0xFFD9D9D9), - fontSize: 10, - fontFamily: 'Fira Code', - fontWeight: FontWeight.w400, - ), - ), - ], - ), - ), - Text( - notification.message, - style: const TextStyle( - color: Colors.white, - fontSize: 12, - fontFamily: 'Fira Code', - fontWeight: FontWeight.w400, - ), - ), - ], - ), - ), - - GestureDetector( - onTap: widget.onDismiss, - child: const Icon(Icons.close, color: Colors.white70, size: 16), - ), - ], - ), - if (transaction != null) _buildViewDetailsButton(), - ], - ), - ), - ], - ), - ), - ), - ), - ); - }, - ), - ), - ); - } - - Widget _buildViewDetailsButton() { - return Align( - alignment: Alignment.bottomRight, - child: GestureDetector( - onTap: _onViewDetails, - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 3), - decoration: ShapeDecoration( - color: Colors.black.withValues(alpha: 0.25), - shape: RoundedRectangleBorder( - side: BorderSide(width: 1, color: Colors.white.withValues(alpha: 0.15)), - borderRadius: BorderRadius.circular(4), - ), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - spacing: 10, - children: [ - const Text( - 'View Details', - textAlign: TextAlign.center, - style: TextStyle( - color: Colors.white, - fontSize: 12, - fontFamily: 'Fira Code', - fontWeight: FontWeight.w400, - ), - ), - SvgPicture.asset('assets/notification/outward_arrow_icon.svg'), - ], - ), - ), - ), - ); - } -} diff --git a/mobile-app/lib/features/components/notification_group.dart b/mobile-app/lib/features/components/notification_group.dart deleted file mode 100644 index 16a8ce7a7..000000000 --- a/mobile-app/lib/features/components/notification_group.dart +++ /dev/null @@ -1,85 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:resonance_network_wallet/features/components/notification_card.dart'; -import 'package:resonance_network_wallet/models/notification_models.dart'; - -class NotificationGroup extends StatefulWidget { - final List notifications; - final VoidCallback onDismissAll; - final Function(String) onDismissSingle; - - const NotificationGroup({ - super.key, - required this.notifications, - required this.onDismissAll, - required this.onDismissSingle, - }); - - @override - State createState() => _NotificationGroupState(); -} - -class _NotificationGroupState extends State with TickerProviderStateMixin { - late AnimationController _slideController; - late Animation _slideAnimation; - - @override - void initState() { - super.initState(); - _slideController = AnimationController(duration: const Duration(milliseconds: 300), vsync: this); - - _slideAnimation = Tween( - begin: const Offset(1.0, 0.0), - end: Offset.zero, - ).animate(CurvedAnimation(parent: _slideController, curve: Curves.easeOut)); - - _slideController.forward(); - } - - @override - void dispose() { - _slideController.dispose(); - - super.dispose(); - } - - @override - Widget build(BuildContext context) { - final reveresedNotifications = widget.notifications.reversed; - - return SlideTransition( - position: _slideAnimation, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - // Dismiss All button - Align( - alignment: Alignment.centerRight, - child: InkWell( - onTap: widget.onDismissAll, - child: const Text('Dismiss All', style: TextStyle(color: Colors.red)), - ), - ), - const SizedBox(height: 16), - // Notifications list - flexible height - Flexible( - child: SingleChildScrollView( - child: Column( - mainAxisSize: MainAxisSize.min, - spacing: 24, - children: reveresedNotifications - .map( - (notification) => NotificationCard( - key: ValueKey(notification.id), - notification: notification, - onDismiss: () => widget.onDismissSingle(notification.id), - ), - ) - .toList(), - ), - ), - ), - ], - ), - ); - } -} diff --git a/mobile-app/lib/features/styles/app_colors_theme.dart b/mobile-app/lib/features/styles/app_colors_theme.dart deleted file mode 100644 index 5ab1e1343..000000000 --- a/mobile-app/lib/features/styles/app_colors_theme.dart +++ /dev/null @@ -1,289 +0,0 @@ -import 'package:flutter/material.dart'; - -@immutable -class AppColorsTheme extends ThemeExtension { - // I don't know about this two colors, it's already there since the beginning - // Keep it for now since I'm no sure if it will break something if I remove it - final Color primary; - final Color secondary; - - // What we use - final List aquaBlue; - final Color purple; - final Color pink; - final Color yellow; - final Color background; - final Color background2; - final Color surface; - final Color surfaceActive; - final Color error; - final Color textPrimary; - final Color textSecondary; - final Color textError; - final Color textMuted; - final Color inputLabel; - final Color light; - final Color circularLoader; - final Color authButtonBg; - final Color border; - final Color borderLight; - final Color buttonDisabled; - final Color navbarBg; - final Color checksum; - final Color checksumDarker; - final Color darkGray; - final Color settingCard; - final Color buttonGlass; - final Color buttonDanger; - final Color buttonSuccess; - final Color buttonNeutral; - final List buttonPrimary; - final Color accountTagGuardian; - final Color accountTagEntrusted; - final Color accountTagHighSecurity; - - const AppColorsTheme({ - required this.primary, - required this.secondary, - - required this.aquaBlue, - required this.purple, - required this.pink, - required this.yellow, - required this.background, - required this.background2, - required this.surface, - required this.surfaceActive, - required this.error, - required this.textPrimary, - required this.textSecondary, - required this.textError, - required this.inputLabel, - required this.light, - required this.circularLoader, - required this.authButtonBg, - required this.textMuted, - required this.border, - required this.borderLight, - required this.buttonDisabled, - required this.navbarBg, - required this.checksum, - required this.checksumDarker, - required this.darkGray, - required this.settingCard, - required this.buttonGlass, - required this.buttonDanger, - required this.buttonSuccess, - required this.buttonNeutral, - required this.buttonPrimary, - required this.accountTagGuardian, - required this.accountTagEntrusted, - required this.accountTagHighSecurity, - }); - - const AppColorsTheme.light() - : this( - primary: const Color(0xFF6B46C1), - secondary: const Color(0xFF9F7AEA), - - aquaBlue: const [Color(0xFF16CECE), Color(0xFF0000FF)], - purple: const Color(0xFFB259F2), - pink: const Color(0xFFED4CCE), - yellow: const Color(0xFFFFE91F), - background: const Color(0xFF0B0F14), - background2: const Color(0xFF0C1014), - surface: const Color(0xFF000000), - surfaceActive: const Color(0xFFF4F6F9), - error: const Color(0xFFFF2D54), - textError: const Color(0xFFFF5252), - textPrimary: const Color(0xFFF4F6F9), - textSecondary: const Color(0xFF0B0F14), - inputLabel: const Color(0xFFD4D3E0), - light: const Color(0xFFE6E6E6), - circularLoader: Colors.white, - authButtonBg: const Color(0xFF16CECE), - textMuted: const Color(0xFFD4D3E0), - border: const Color(0xcfe6e6e6), - borderLight: const Color(0x0FFFFFFF), - buttonDisabled: const Color(0xFF3D3C44), - navbarBg: Colors.black, - checksum: const Color(0xFF4CEDE7), - checksumDarker: const Color(0xFF16CECE), - darkGray: const Color(0xFF3D3C44), - settingCard: const Color(0x14F4F6F9), - buttonGlass: const Color(0x14F4F6F9), - buttonDanger: const Color(0xFFFF1F45), - buttonSuccess: const Color(0xFF1FFFA7), - buttonNeutral: const Color(0xFFF4F6F9), - buttonPrimary: const [Color(0xFF0000FF), Color(0xFFED4CCE)], - accountTagGuardian: const Color(0xFF9747FF), - accountTagEntrusted: const Color(0xFFFFD541), - accountTagHighSecurity: const Color(0xFF4CEDE7), - ); - - const AppColorsTheme.dark() - : this( - primary: const Color(0xFF6B46C1), - secondary: const Color(0xFF9F7AEA), - - aquaBlue: const [Color(0xFF16CECE), Color(0xFF0000FF)], - purple: const Color(0xFFB259F2), - pink: const Color(0xFFED4CCE), - yellow: const Color(0xFFFFE91F), - background: const Color(0xFF0B0F14), - background2: const Color(0xFF0C1014), - surface: const Color(0xFF000000), - surfaceActive: const Color(0xFFF4F6F9), - error: const Color(0xFFFF2D54), - textError: const Color(0xFFFF5252), - textPrimary: const Color(0xFFF4F6F9), - textSecondary: const Color(0xFF0B0F14), - inputLabel: const Color(0xFFD4D3E0), - light: const Color(0xFFE6E6E6), - circularLoader: Colors.white, - authButtonBg: const Color(0xFF16CECE), - textMuted: const Color(0xFFD4D3E0), - border: const Color(0xe6e6e6cf), - borderLight: const Color(0x0FFFFFFF), - buttonDisabled: const Color(0xFF3D3C44), - navbarBg: Colors.black, - checksum: const Color(0xFF4CEDE7), - checksumDarker: const Color(0xFF16CECE), - darkGray: const Color(0xFF3D3C44), - settingCard: const Color(0x14F4F6F9), - buttonGlass: const Color(0x14F4F6F9), - buttonDanger: const Color(0xFFFF1F45), - buttonSuccess: const Color(0xFF1FFFA7), - buttonNeutral: const Color(0xFFF4F6F9), - buttonPrimary: const [Color(0xFF0000FF), Color(0xFFED4CCE)], - accountTagGuardian: const Color(0xFF9747FF), - accountTagEntrusted: const Color(0xFFFFD541), - accountTagHighSecurity: const Color(0xFF4CEDE7), - ); - - @override - AppColorsTheme copyWith({ - Color? primary, - Color? secondary, - List? aquaBlue, - Color? purple, - Color? pink, - Color? yellow, - Color? background, - Color? background2, - Color? surface, - Color? surfaceActive, - Color? error, - Color? textPrimary, - Color? textSecondary, - Color? textError, - Color? inputLabel, - Color? light, - Color? circularLoader, - Color? authButtonBg, - Color? textMuted, - Color? border, - Color? borderLight, - Color? buttonDisabled, - Color? navbarBg, - Color? checksum, - Color? checksumDarker, - Color? buttonGlass, - Color? buttonGlassAlpha, - Color? darkGray, - Color? settingCard, - List? buttonPrimary, - Color? buttonNeutral, - Color? buttonDanger, - Color? buttonSuccess, - Color? accountTagGuardian, - Color? accountTagEntrusted, - Color? accountTagHighSecurity, - }) { - return AppColorsTheme( - primary: primary ?? this.primary, - secondary: secondary ?? this.secondary, - aquaBlue: aquaBlue ?? this.aquaBlue, - purple: purple ?? this.purple, - pink: pink ?? this.pink, - yellow: yellow ?? this.yellow, - background: background ?? this.background, - background2: background2 ?? this.background2, - surface: surface ?? this.surface, - surfaceActive: surfaceActive ?? this.surfaceActive, - error: error ?? this.error, - textPrimary: textPrimary ?? this.textPrimary, - textSecondary: textSecondary ?? this.textSecondary, - textError: textError ?? this.textError, - inputLabel: inputLabel ?? this.inputLabel, - light: light ?? this.light, - circularLoader: circularLoader ?? this.circularLoader, - authButtonBg: authButtonBg ?? this.authButtonBg, - textMuted: textMuted ?? this.textMuted, - border: border ?? this.border, - borderLight: borderLight ?? this.borderLight, - buttonDisabled: buttonDisabled ?? this.buttonDisabled, - navbarBg: navbarBg ?? this.navbarBg, - checksum: checksum ?? this.checksum, - checksumDarker: checksumDarker ?? this.checksumDarker, - darkGray: darkGray ?? this.darkGray, - settingCard: settingCard ?? this.settingCard, - buttonGlass: buttonGlass ?? this.buttonGlass, - buttonPrimary: buttonPrimary ?? this.buttonPrimary, - buttonNeutral: buttonNeutral ?? this.buttonNeutral, - buttonDanger: buttonDanger ?? this.buttonDanger, - buttonSuccess: buttonSuccess ?? this.buttonSuccess, - accountTagGuardian: accountTagGuardian ?? this.accountTagGuardian, - accountTagEntrusted: accountTagEntrusted ?? this.accountTagEntrusted, - accountTagHighSecurity: accountTagHighSecurity ?? this.accountTagHighSecurity, - ); - } - - @override - AppColorsTheme lerp(AppColorsTheme? other, double t) { - if (other is! AppColorsTheme) return this; - return AppColorsTheme( - primary: Color.lerp(primary, other.primary, t) ?? primary, - secondary: Color.lerp(secondary, other.secondary, t) ?? secondary, - aquaBlue: other.aquaBlue, - purple: Color.lerp(purple, other.purple, t) ?? purple, - pink: Color.lerp(pink, other.pink, t) ?? pink, - yellow: Color.lerp(yellow, other.yellow, t) ?? yellow, - background: Color.lerp(background, other.background, t) ?? background, - background2: Color.lerp(background2, other.background2, t) ?? background2, - surface: Color.lerp(surface, other.surface, t) ?? surface, - surfaceActive: Color.lerp(surfaceActive, other.surfaceActive, t) ?? surfaceActive, - error: Color.lerp(error, other.error, t) ?? error, - textPrimary: Color.lerp(textPrimary, other.textPrimary, t) ?? textPrimary, - textSecondary: Color.lerp(textSecondary, other.textSecondary, t) ?? textSecondary, - textError: Color.lerp(textError, other.textError, t) ?? textError, - inputLabel: Color.lerp(inputLabel, other.inputLabel, t) ?? inputLabel, - light: Color.lerp(light, other.light, t) ?? light, - circularLoader: Color.lerp(circularLoader, other.circularLoader, t) ?? circularLoader, - authButtonBg: Color.lerp(authButtonBg, other.authButtonBg, t) ?? authButtonBg, - textMuted: Color.lerp(textMuted, other.textMuted, t) ?? textMuted, - border: Color.lerp(border, other.border, t) ?? border, - borderLight: Color.lerp(borderLight, other.borderLight, t) ?? borderLight, - buttonDisabled: Color.lerp(buttonDisabled, other.buttonDisabled, t) ?? buttonDisabled, - navbarBg: Color.lerp(navbarBg, other.navbarBg, t) ?? navbarBg, - checksum: Color.lerp(checksum, other.checksum, t) ?? checksum, - checksumDarker: Color.lerp(checksumDarker, other.checksumDarker, t) ?? checksumDarker, - darkGray: Color.lerp(darkGray, other.darkGray, t) ?? darkGray, - settingCard: Color.lerp(settingCard, other.settingCard, t) ?? settingCard, - buttonGlass: Color.lerp(buttonGlass, other.buttonGlass, t) ?? buttonGlass, - buttonNeutral: Color.lerp(buttonNeutral, other.buttonNeutral, t) ?? buttonNeutral, - buttonDanger: Color.lerp(buttonDanger, other.buttonDanger, t) ?? buttonDanger, - buttonSuccess: Color.lerp(buttonSuccess, other.buttonSuccess, t) ?? buttonSuccess, - buttonPrimary: other.buttonPrimary, - accountTagGuardian: Color.lerp(accountTagGuardian, other.accountTagGuardian, t) ?? accountTagGuardian, - accountTagEntrusted: Color.lerp(accountTagEntrusted, other.accountTagEntrusted, t) ?? accountTagEntrusted, - accountTagHighSecurity: - Color.lerp(accountTagHighSecurity, other.accountTagHighSecurity, t) ?? accountTagHighSecurity, - ); - } -} - -// Extension on BuildContext to access AppTextTheme styles directly -extension AppColorsThemeExtension on BuildContext { - AppColorsTheme get themeColors => Theme.of(this).extension()!; -} diff --git a/mobile-app/lib/features/styles/app_size_theme.dart b/mobile-app/lib/features/styles/app_size_theme.dart deleted file mode 100644 index 9da58c2eb..000000000 --- a/mobile-app/lib/features/styles/app_size_theme.dart +++ /dev/null @@ -1,228 +0,0 @@ -import 'package:flutter/material.dart'; - -@immutable -class AppSizeTheme extends ThemeExtension { - final double logoHeight; - final double mainMenuHeight; - final double mainMenuWidth; - final double mainMenuIconSize; - final double navbarHeight; - final double navbarItemHeight; - final double navbarItemWidth; - final double navbarIconWidth; - final double floatingBtnHeight; - final double floatingBtnWidth; - final double settingMenuIconSize; - final double settingMenuShareIconSize; - final double accountListItemHeight; - final double accountListItemLogoWidth; - final double appbarIconSize; - final double sendOverlayContainerWidth; - final double overlayCloseIconSize; - final double mnemonicCellDesiredHeight; - final double txListItemIconWidth; - final double txDetailsIconHeight; - final double txDetailsIconWidth; - final double copyIconSize; - final double pasteIconSize; - final double timePickerSubtitleWidth; - final double bottomButtonSpacing; - final double buttonsHorizontalSpacing; - final double infoSheetTitleIcon; - - const AppSizeTheme({ - required this.logoHeight, - required this.mainMenuHeight, - required this.mainMenuWidth, - required this.mainMenuIconSize, - required this.navbarHeight, - required this.navbarItemHeight, - required this.navbarItemWidth, - required this.navbarIconWidth, - required this.floatingBtnHeight, - required this.floatingBtnWidth, - required this.settingMenuIconSize, - required this.settingMenuShareIconSize, - required this.accountListItemHeight, - required this.accountListItemLogoWidth, - required this.appbarIconSize, - required this.sendOverlayContainerWidth, - required this.overlayCloseIconSize, - required this.mnemonicCellDesiredHeight, - required this.txListItemIconWidth, - required this.txDetailsIconHeight, - required this.txDetailsIconWidth, - required this.copyIconSize, - required this.pasteIconSize, - required this.timePickerSubtitleWidth, - required this.bottomButtonSpacing, - required this.buttonsHorizontalSpacing, - required this.infoSheetTitleIcon, - }); - - const AppSizeTheme.defaultTheme() - : this( - logoHeight: 158.0, - mainMenuHeight: 20, - mainMenuWidth: 20, - mainMenuIconSize: 21.0, - navbarHeight: 67.0, - navbarItemHeight: 32, - navbarItemWidth: 40, - navbarIconWidth: 23, - floatingBtnHeight: 49.0, - floatingBtnWidth: 52.0, - settingMenuIconSize: 11.0, - settingMenuShareIconSize: 20.0, - accountListItemHeight: 110.0, - accountListItemLogoWidth: 36.0, - appbarIconSize: 18.0, - sendOverlayContainerWidth: double.infinity, - overlayCloseIconSize: 24.0, - mnemonicCellDesiredHeight: 31.0, - txListItemIconWidth: 21.0, - txDetailsIconHeight: 43.0, - txDetailsIconWidth: 51.0, - copyIconSize: 20.0, - pasteIconSize: 18.0, - timePickerSubtitleWidth: 249, - bottomButtonSpacing: 16, - buttonsHorizontalSpacing: 28, - infoSheetTitleIcon: 25, - ); - - const AppSizeTheme.iPad() - : this( - logoHeight: 180.0, - mainMenuHeight: 30, - mainMenuWidth: 30, - mainMenuIconSize: 29.0, - navbarHeight: 87.0, - navbarItemHeight: 40, - navbarItemWidth: 48, - navbarIconWidth: 32, - floatingBtnHeight: 74.0, - floatingBtnWidth: 77.0, - settingMenuIconSize: 16.0, - settingMenuShareIconSize: 24.0, - accountListItemHeight: 130.0, - accountListItemLogoWidth: 48.0, - appbarIconSize: 20.0, - sendOverlayContainerWidth: 510.0, - overlayCloseIconSize: 28.0, - mnemonicCellDesiredHeight: 80.0, - txListItemIconWidth: 32.0, - txDetailsIconHeight: 82.0, - txDetailsIconWidth: 91.0, - copyIconSize: 28.0, - pasteIconSize: 24.0, - timePickerSubtitleWidth: 400, - bottomButtonSpacing: 16, - buttonsHorizontalSpacing: 28, - infoSheetTitleIcon: 28, - ); - - @override - AppSizeTheme copyWith({ - double? logoHeight, - double? mainMenuHeight, - double? mainMenuWidth, - double? mainMenuIconSize, - double? navbarHeight, - double? navbarItemHeight, - double? navbarItemWidth, - double? navbarIconWidth, - double? floatingBtnHeight, - double? floatingBtnWidth, - double? settingMenuIconSize, - double? settingMenuShareIconSize, - double? accountListItemHeight, - double? accountListItemLogoWidth, - double? appbarIconSize, - double? sendOverlayContainerWidth, - double? overlayCloseIconSize, - double? mnemonicCellDesiredHeight, - double? txListItemIconWidth, - double? txDetailsIconHeight, - double? txDetailsIconWidth, - double? copyIconSize, - double? pasteIconSize, - double? timePickerSubtitleWidth, - double? bottomButtonSpacing, - double? buttonsHorizontalSpacing, - double? infoSheetTitleIcon, - }) { - return AppSizeTheme( - logoHeight: logoHeight ?? this.logoHeight, - mainMenuHeight: mainMenuHeight ?? this.mainMenuHeight, - mainMenuWidth: mainMenuWidth ?? this.mainMenuWidth, - mainMenuIconSize: mainMenuIconSize ?? this.mainMenuIconSize, - navbarHeight: navbarHeight ?? this.navbarHeight, - navbarItemHeight: navbarItemHeight ?? this.navbarItemHeight, - navbarItemWidth: navbarItemWidth ?? this.navbarItemWidth, - navbarIconWidth: navbarIconWidth ?? this.navbarIconWidth, - floatingBtnHeight: floatingBtnHeight ?? this.floatingBtnHeight, - floatingBtnWidth: floatingBtnWidth ?? this.floatingBtnWidth, - settingMenuIconSize: settingMenuIconSize ?? this.settingMenuIconSize, - settingMenuShareIconSize: settingMenuShareIconSize ?? this.settingMenuShareIconSize, - accountListItemHeight: accountListItemHeight ?? this.accountListItemHeight, - accountListItemLogoWidth: accountListItemLogoWidth ?? this.accountListItemLogoWidth, - appbarIconSize: appbarIconSize ?? this.appbarIconSize, - sendOverlayContainerWidth: sendOverlayContainerWidth ?? this.sendOverlayContainerWidth, - overlayCloseIconSize: overlayCloseIconSize ?? this.overlayCloseIconSize, - mnemonicCellDesiredHeight: mnemonicCellDesiredHeight ?? this.mnemonicCellDesiredHeight, - txListItemIconWidth: txListItemIconWidth ?? this.txListItemIconWidth, - txDetailsIconHeight: txDetailsIconHeight ?? this.txDetailsIconHeight, - txDetailsIconWidth: txDetailsIconWidth ?? this.txDetailsIconWidth, - copyIconSize: copyIconSize ?? this.copyIconSize, - pasteIconSize: pasteIconSize ?? this.pasteIconSize, - timePickerSubtitleWidth: timePickerSubtitleWidth ?? this.timePickerSubtitleWidth, - bottomButtonSpacing: bottomButtonSpacing ?? this.bottomButtonSpacing, - buttonsHorizontalSpacing: buttonsHorizontalSpacing ?? this.buttonsHorizontalSpacing, - infoSheetTitleIcon: infoSheetTitleIcon ?? this.infoSheetTitleIcon, - ); - } - - @override - AppSizeTheme lerp(AppSizeTheme? other, double t) { - if (other is! AppSizeTheme) return this; - return AppSizeTheme( - logoHeight: logoHeight + (other.logoHeight - logoHeight) * t, - mainMenuHeight: mainMenuHeight + (other.mainMenuHeight - mainMenuHeight) * t, - mainMenuWidth: mainMenuWidth + (other.mainMenuWidth - mainMenuWidth) * t, - mainMenuIconSize: mainMenuIconSize + (other.mainMenuIconSize - mainMenuIconSize) * t, - navbarHeight: navbarHeight + (other.navbarHeight - navbarHeight) * t, - navbarItemHeight: navbarItemHeight + (other.navbarItemHeight - navbarItemHeight) * t, - navbarItemWidth: navbarItemWidth + (other.navbarItemWidth - navbarItemWidth) * t, - navbarIconWidth: navbarIconWidth + (other.navbarIconWidth - navbarIconWidth) * t, - floatingBtnHeight: floatingBtnHeight + (other.floatingBtnHeight - floatingBtnHeight) * t, - floatingBtnWidth: floatingBtnWidth + (other.floatingBtnWidth - floatingBtnWidth) * t, - settingMenuIconSize: settingMenuIconSize + (other.settingMenuIconSize - settingMenuIconSize) * t, - settingMenuShareIconSize: - settingMenuShareIconSize + (other.settingMenuShareIconSize - settingMenuShareIconSize) * t, - accountListItemHeight: accountListItemHeight + (other.accountListItemHeight - accountListItemHeight) * t, - accountListItemLogoWidth: - accountListItemLogoWidth + (other.accountListItemLogoWidth - accountListItemLogoWidth) * t, - appbarIconSize: appbarIconSize + (other.appbarIconSize - appbarIconSize) * t, - sendOverlayContainerWidth: - sendOverlayContainerWidth + (other.sendOverlayContainerWidth - sendOverlayContainerWidth) * t, - overlayCloseIconSize: overlayCloseIconSize + (other.overlayCloseIconSize - overlayCloseIconSize) * t, - mnemonicCellDesiredHeight: - mnemonicCellDesiredHeight + (other.mnemonicCellDesiredHeight - mnemonicCellDesiredHeight) * t, - txListItemIconWidth: txListItemIconWidth + (other.txListItemIconWidth - txListItemIconWidth) * t, - txDetailsIconHeight: txDetailsIconHeight + (other.txDetailsIconHeight - txDetailsIconHeight) * t, - txDetailsIconWidth: txDetailsIconWidth + (other.txDetailsIconWidth - txDetailsIconWidth) * t, - copyIconSize: copyIconSize + (other.copyIconSize - copyIconSize) * t, - pasteIconSize: pasteIconSize + (other.pasteIconSize - pasteIconSize) * t, - timePickerSubtitleWidth: timePickerSubtitleWidth + (other.timePickerSubtitleWidth - timePickerSubtitleWidth) * t, - bottomButtonSpacing: bottomButtonSpacing + (other.bottomButtonSpacing - bottomButtonSpacing) * t, - buttonsHorizontalSpacing: - buttonsHorizontalSpacing + (other.buttonsHorizontalSpacing - buttonsHorizontalSpacing) * t, - infoSheetTitleIcon: infoSheetTitleIcon + (other.infoSheetTitleIcon - infoSheetTitleIcon) * t, - ); - } -} - -extension AppSizeThemeExtension on BuildContext { - AppSizeTheme get themeSize => Theme.of(this).extension()!; -} diff --git a/mobile-app/lib/features/styles/app_text_theme.dart b/mobile-app/lib/features/styles/app_text_theme.dart deleted file mode 100644 index ced8b8631..000000000 --- a/mobile-app/lib/features/styles/app_text_theme.dart +++ /dev/null @@ -1,191 +0,0 @@ -import 'package:flutter/material.dart'; - -@immutable -class AppTextTheme extends ThemeExtension { - final TextStyle? lockTitle; - final TextStyle? extraLargeTitle; - final TextStyle? largeTitle; - final TextStyle? mediumTitle; - final TextStyle? smallTitle; - final TextStyle? paragraph; - final TextStyle? smallParagraph; - final TextStyle? largeTag; - final TextStyle? tag; - final TextStyle? timer; - final TextStyle? detail; - final TextStyle? tiny; - - const AppTextTheme({ - this.lockTitle, - this.extraLargeTitle, - this.largeTitle, - this.mediumTitle, - this.smallTitle, - this.paragraph, - this.smallParagraph, - this.largeTag, - this.tag, - this.timer, - this.detail, - this.tiny, - }); - - const AppTextTheme.defaultTheme() - : this( - lockTitle: const TextStyle(fontSize: 24, fontFamily: 'Fira Code'), - extraLargeTitle: const TextStyle(fontSize: 40, fontFamily: 'Fira Code', fontWeight: FontWeight.w600), - largeTitle: const TextStyle(fontSize: 30, fontFamily: 'Fira Code', fontWeight: FontWeight.w300), - mediumTitle: const TextStyle(fontSize: 24, fontFamily: 'Fira Code', fontWeight: FontWeight.w500), - smallTitle: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.w500, - fontFamily: 'Fira Code', - fontStyle: FontStyle.normal, - decoration: TextDecoration.none, - ), - paragraph: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w400, - fontFamily: 'Fira Code', - fontStyle: FontStyle.normal, - decoration: TextDecoration.none, - ), - smallParagraph: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w400, - fontFamily: 'Fira Code', - fontStyle: FontStyle.normal, - decoration: TextDecoration.none, - ), - largeTag: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w400, - fontFamily: 'Fira Code', - fontStyle: FontStyle.normal, - decoration: TextDecoration.none, - ), - tag: const TextStyle(fontSize: 12, fontWeight: FontWeight.w300, fontFamily: 'Fira Code'), - timer: const TextStyle(fontSize: 28, fontWeight: FontWeight.w600, fontFamily: 'Fira Code'), - detail: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.w400, - fontFamily: 'Fira Code', - fontStyle: FontStyle.normal, - decoration: TextDecoration.none, - ), - tiny: const TextStyle( - fontSize: 11, - fontWeight: FontWeight.w400, - fontFamily: 'Fira Code', - fontStyle: FontStyle.normal, - decoration: TextDecoration.none, - ), - ); - - const AppTextTheme.iPad() - : this( - lockTitle: const TextStyle(color: Colors.white, fontSize: 28, fontFamily: 'Fira Code'), - extraLargeTitle: const TextStyle(fontSize: 52, fontFamily: 'Fira Code', fontWeight: FontWeight.w600), - largeTitle: const TextStyle(fontSize: 36, fontFamily: 'Fira Code', fontWeight: FontWeight.w300), - mediumTitle: const TextStyle(fontSize: 28, fontFamily: 'Fira Code', fontWeight: FontWeight.w400), - smallTitle: const TextStyle( - fontSize: 24, - fontWeight: FontWeight.w500, - fontFamily: 'Fira Code', - fontStyle: FontStyle.normal, - decoration: TextDecoration.none, - ), - paragraph: const TextStyle( - fontSize: 20, - fontWeight: FontWeight.w400, - fontFamily: 'Fira Code', - fontStyle: FontStyle.normal, - decoration: TextDecoration.none, - ), - smallParagraph: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.w400, - fontFamily: 'Fira Code', - fontStyle: FontStyle.normal, - decoration: TextDecoration.none, - ), - largeTag: const TextStyle( - fontSize: 24, - fontWeight: FontWeight.w400, - fontFamily: 'Fira Code', - fontStyle: FontStyle.normal, - decoration: TextDecoration.none, - ), - tag: const TextStyle(fontSize: 16, fontWeight: FontWeight.w300, fontFamily: 'Fira Code'), - timer: const TextStyle(fontSize: 36, fontWeight: FontWeight.w600, fontFamily: 'Fira Code'), - detail: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w400, - fontFamily: 'Fira Code', - fontStyle: FontStyle.normal, - decoration: TextDecoration.none, - ), - tiny: const TextStyle( - fontSize: 15, - fontWeight: FontWeight.w400, - fontFamily: 'Fira Code', - fontStyle: FontStyle.normal, - decoration: TextDecoration.none, - ), - ); - - @override - AppTextTheme copyWith({ - TextStyle? lockTitle, - TextStyle? extraLargeTitle, - TextStyle? largeTitle, - TextStyle? mediumTitle, - TextStyle? smallTitle, - TextStyle? paragraph, - TextStyle? smallParagraph, - TextStyle? largeTag, - TextStyle? tag, - TextStyle? timer, - TextStyle? detail, - TextStyle? tiny, - }) { - return AppTextTheme( - lockTitle: lockTitle ?? this.lockTitle, - extraLargeTitle: extraLargeTitle ?? this.extraLargeTitle, - largeTitle: largeTitle ?? this.largeTitle, - mediumTitle: mediumTitle ?? this.mediumTitle, - smallTitle: smallTitle ?? this.smallTitle, - paragraph: paragraph ?? this.paragraph, - smallParagraph: smallParagraph ?? this.smallParagraph, - largeTag: largeTag ?? this.largeTag, - tag: tag ?? this.tag, - timer: timer ?? this.timer, - detail: detail ?? this.detail, - tiny: tiny ?? this.tiny, - ); - } - - @override - AppTextTheme lerp(AppTextTheme? other, double t) { - if (other is! AppTextTheme) return this; - return AppTextTheme( - lockTitle: TextStyle.lerp(lockTitle, other.lockTitle, t), - extraLargeTitle: TextStyle.lerp(extraLargeTitle, other.extraLargeTitle, t), - largeTitle: TextStyle.lerp(largeTitle, other.largeTitle, t), - mediumTitle: TextStyle.lerp(mediumTitle, other.mediumTitle, t), - smallTitle: TextStyle.lerp(smallTitle, other.smallTitle, t), - paragraph: TextStyle.lerp(paragraph, other.paragraph, t), - smallParagraph: TextStyle.lerp(smallParagraph, other.smallParagraph, t), - largeTag: TextStyle.lerp(largeTag, other.largeTag, t), - tag: TextStyle.lerp(tag, other.tag, t), - timer: TextStyle.lerp(timer, other.timer, t), - detail: TextStyle.lerp(detail, other.detail, t), - tiny: TextStyle.lerp(tiny, other.tiny, t), - ); - } -} - -// Extension on BuildContext to access AppTextTheme styles directly -extension AppTextThemeExtension on BuildContext { - AppTextTheme get themeText => Theme.of(this).extension()!; -} diff --git a/mobile-app/lib/features/styles/app_theme.dart b/mobile-app/lib/features/styles/app_theme.dart deleted file mode 100644 index 414d126e6..000000000 --- a/mobile-app/lib/features/styles/app_theme.dart +++ /dev/null @@ -1,89 +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'; - -class AppTheme { - static ThemeData lightTheme(BuildContext context) { - final appColors = const AppColorsTheme.light(); - - return ThemeData( - primaryColor: appColors.primary, - scaffoldBackgroundColor: appColors.background, - cardColor: appColors.surface, - colorScheme: ColorScheme.dark( - primary: appColors.primary, - secondary: appColors.secondary, - surface: appColors.surface, - error: appColors.error, - ), - appBarTheme: AppBarTheme(backgroundColor: appColors.surface, elevation: 0), - elevatedButtonTheme: ElevatedButtonThemeData( - style: ElevatedButton.styleFrom( - backgroundColor: appColors.primary, - foregroundColor: appColors.textPrimary, - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), - ), - ), - outlinedButtonTheme: OutlinedButtonThemeData( - style: OutlinedButton.styleFrom( - foregroundColor: appColors.secondary, - side: BorderSide(color: appColors.secondary), - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), - ), - ), - textButtonTheme: TextButtonThemeData(style: TextButton.styleFrom(foregroundColor: appColors.textPrimary)), - inputDecorationTheme: InputDecorationTheme( - border: InputBorder.none, - enabledBorder: InputBorder.none, - focusedBorder: InputBorder.none, - filled: true, - fillColor: appColors.surface, - ), - ); - } - - static ThemeData darkTheme(BuildContext context) { - final isTablet = context.isTablet; - final appColors = const AppColorsTheme.dark(); - - return ThemeData( - primaryColor: appColors.primary, - scaffoldBackgroundColor: appColors.background, - cardColor: appColors.surface, - colorScheme: ColorScheme.dark( - primary: appColors.primary, - secondary: appColors.secondary, - surface: appColors.surface, - error: appColors.error, - ), - appBarTheme: AppBarTheme(backgroundColor: appColors.surface, elevation: 0), - elevatedButtonTheme: ElevatedButtonThemeData( - style: ElevatedButton.styleFrom( - backgroundColor: appColors.primary, - foregroundColor: Colors.white, - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), - ), - ), - outlinedButtonTheme: OutlinedButtonThemeData( - style: OutlinedButton.styleFrom( - foregroundColor: appColors.secondary, - side: BorderSide(color: appColors.secondary), - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), - ), - ), - textButtonTheme: TextButtonThemeData(style: TextButton.styleFrom(foregroundColor: appColors.textPrimary)), - inputDecorationTheme: InputDecorationTheme( - border: InputBorder.none, - enabledBorder: InputBorder.none, - focusedBorder: InputBorder.none, - filled: true, - fillColor: appColors.surface, - ), - extensions: [ - isTablet ? const AppTextTheme.iPad() : const AppTextTheme.defaultTheme(), - isTablet ? const AppSizeTheme.iPad() : const AppSizeTheme.defaultTheme(), - appColors, - ], - ); - } -} diff --git a/mobile-app/lib/l10n/app_en.arb b/mobile-app/lib/l10n/app_en.arb index 2ad8b356a..bda40b0de 100644 --- a/mobile-app/lib/l10n/app_en.arb +++ b/mobile-app/lib/l10n/app_en.arb @@ -2738,6 +2738,10 @@ "@componentNameFieldHint": { "description": "Hint text on account name field" }, + "componentAmountApproximatePrefix": "≈", + "@componentAmountApproximatePrefix": { + "description": "Prefix before a converted secondary amount" + }, "commonLoading": "Loading...", "@commonLoading": { diff --git a/mobile-app/lib/l10n/app_id.arb b/mobile-app/lib/l10n/app_id.arb index 527a3c76f..9f921fc4e 100644 --- a/mobile-app/lib/l10n/app_id.arb +++ b/mobile-app/lib/l10n/app_id.arb @@ -583,6 +583,7 @@ "componentCheckphraseLabel": "CHECKPHRASE", "componentCheckphraseCopied": "Checkphrase disalin", "componentNameFieldHint": "Masukkan nama untuk akun Anda", + "componentAmountApproximatePrefix": "≈", "commonLoading": "Memuat...", "commonCancel": "Batal", diff --git a/mobile-app/lib/l10n/app_localizations.dart b/mobile-app/lib/l10n/app_localizations.dart index 0213cdcc9..0f9dab8ee 100644 --- a/mobile-app/lib/l10n/app_localizations.dart +++ b/mobile-app/lib/l10n/app_localizations.dart @@ -3518,6 +3518,12 @@ abstract class AppLocalizations { /// **'Enter a name for your account'** String get componentNameFieldHint; + /// Prefix before a converted secondary amount + /// + /// In en, this message translates to: + /// **'≈'** + String get componentAmountApproximatePrefix; + /// Text for generic loading state /// /// In en, this message translates to: diff --git a/mobile-app/lib/l10n/app_localizations_en.dart b/mobile-app/lib/l10n/app_localizations_en.dart index cb9202dd1..db8235213 100644 --- a/mobile-app/lib/l10n/app_localizations_en.dart +++ b/mobile-app/lib/l10n/app_localizations_en.dart @@ -1898,6 +1898,9 @@ class AppLocalizationsEn extends AppLocalizations { @override String get componentNameFieldHint => 'Enter a name for your account'; + @override + String get componentAmountApproximatePrefix => '≈'; + @override String get commonLoading => 'Loading...'; diff --git a/mobile-app/lib/l10n/app_localizations_id.dart b/mobile-app/lib/l10n/app_localizations_id.dart index d0d5c3d49..c4326749e 100644 --- a/mobile-app/lib/l10n/app_localizations_id.dart +++ b/mobile-app/lib/l10n/app_localizations_id.dart @@ -1895,6 +1895,9 @@ class AppLocalizationsId extends AppLocalizations { @override String get componentNameFieldHint => 'Masukkan nama untuk akun Anda'; + @override + String get componentAmountApproximatePrefix => '≈'; + @override String get commonLoading => 'Memuat...'; diff --git a/mobile-app/lib/shared/extensions/clipboard_extensions.dart b/mobile-app/lib/shared/extensions/clipboard_extensions.dart index 97ee41c35..2682b9f8c 100644 --- a/mobile-app/lib/shared/extensions/clipboard_extensions.dart +++ b/mobile-app/lib/shared/extensions/clipboard_extensions.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:resonance_network_wallet/services/secure_clipboard_service.dart'; -import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; extension ClipboardWithToasterExtensions on BuildContext { Future copyTextWithToaster(String text, {String message = 'Address copied to clipboard'}) async { diff --git a/quantus_sdk/lib/src/utils/account_utils.dart b/mobile-app/lib/shared/utils/account_utils.dart similarity index 100% rename from quantus_sdk/lib/src/utils/account_utils.dart rename to mobile-app/lib/shared/utils/account_utils.dart diff --git a/quantus_sdk/lib/src/ui/components/account_badge.dart b/mobile-app/lib/v2/components/account_badge.dart similarity index 95% rename from quantus_sdk/lib/src/ui/components/account_badge.dart rename to mobile-app/lib/v2/components/account_badge.dart index 4653e228c..53bee1686 100644 --- a/quantus_sdk/lib/src/ui/components/account_badge.dart +++ b/mobile-app/lib/v2/components/account_badge.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:resonance_network_wallet/shared/utils/account_utils.dart'; class AccountBadge extends StatelessWidget { final String name; diff --git a/quantus_sdk/lib/src/ui/components/address_checkphrase_with_initial.dart b/mobile-app/lib/v2/components/address_checkphrase_with_initial.dart similarity index 96% rename from quantus_sdk/lib/src/ui/components/address_checkphrase_with_initial.dart rename to mobile-app/lib/v2/components/address_checkphrase_with_initial.dart index 06ad00f06..5f9906fde 100644 --- a/quantus_sdk/lib/src/ui/components/address_checkphrase_with_initial.dart +++ b/mobile-app/lib/v2/components/address_checkphrase_with_initial.dart @@ -1,5 +1,6 @@ import 'package:flutter/widgets.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:resonance_network_wallet/shared/utils/account_utils.dart'; class AddressCheckphraseWithInitial extends StatelessWidget { final String recipientChecksum; diff --git a/mobile-app/lib/v2/components/address_details_card.dart b/mobile-app/lib/v2/components/address_details_card.dart index 651b8be2e..6db6b9618 100644 --- a/mobile-app/lib/v2/components/address_details_card.dart +++ b/mobile-app/lib/v2/components/address_details_card.dart @@ -1,31 +1,147 @@ +import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart' as sdk; +import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/shared/extensions/clipboard_extensions.dart'; +import 'package:resonance_network_wallet/v2/components/split_card.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; -class AddressDetailsCard extends ConsumerWidget { +class AddressDetailsCard extends ConsumerStatefulWidget { final String accountId; final String? checksum; const AddressDetailsCard({super.key, required this.accountId, this.checksum}); @override - Widget build(BuildContext context, WidgetRef ref) { + ConsumerState createState() => _AddressDetailsCardState(); +} + +class _AddressDetailsCardState extends ConsumerState { + bool _addressCopied = false; + bool _checksumCopied = false; + Timer? _resetTimer; + + void _copyAddress(BuildContext context) { + context.copyTextWithToaster(widget.accountId); + _triggerCopied(isAddress: true); + } + + void _copyChecksum(BuildContext context, AppLocalizations l10n) { + if (widget.checksum == null) return; + + context.copyTextWithToaster(widget.checksum!, message: l10n.componentCheckphraseCopied); + _triggerCopied(isAddress: false); + } + + void _triggerCopied({required bool isAddress}) { + _resetTimer?.cancel(); + + setState(() { + if (isAddress) { + _addressCopied = true; + _checksumCopied = false; + } else { + _checksumCopied = true; + _addressCopied = false; + } + }); + + _resetTimer = Timer(const Duration(seconds: 2), () { + if (mounted) { + setState(() { + if (isAddress) { + _addressCopied = false; + } else { + _checksumCopied = false; + } + }); + } + }); + } + + @override + void dispose() { + _resetTimer?.cancel(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { final l10n = ref.watch(l10nProvider); - return sdk.AddressDetailsCard( - accountId: accountId, - checksum: checksum, - addressLabel: l10n.componentAddressLabel, - checkphraseLabel: l10n.componentCheckphraseLabel, - checksumPlaceholder: l10n.commonLoading, - onCopyAddress: () => context.copyTextWithToaster(accountId), - onCopyChecksum: () { - final value = checksum; - if (value == null) return; - context.copyTextWithToaster(value, message: l10n.componentCheckphraseCopied); - }, + return SplitCard( + topChild: InkWell( + onTap: () => _copyAddress(context), + child: _buildItem(context, l10n.componentAddressLabel, widget.accountId, isCopied: _addressCopied), + ), + bottomChild: InkWell( + onTap: () => _copyChecksum(context, l10n), + child: _buildItem( + context, + l10n.componentCheckphraseLabel, + widget.checksum ?? l10n.commonLoading, + isCheckphrase: true, + isCopied: _checksumCopied, + ), + ), + ); + } + + Widget _buildItem( + BuildContext context, + String label, + String value, { + bool isCheckphrase = false, + required bool isCopied, + }) { + final valueTextStyle = isCheckphrase + ? context.themeText.smallParagraph?.copyWith(color: context.colors.checksum) + : context.themeText.smallParagraph?.copyWith(fontFamily: AppTextTheme.fontFamilySecondary); + + return Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(label, style: context.themeText.receiveLabel?.copyWith(color: context.colors.textLabel)), + const SizedBox(height: 16), + Text(value, style: valueTextStyle), + ], + ), + ), + const SizedBox(width: 32), + _copyButton(isCopied: isCopied), + ], + ); + } + + Widget _copyButton({required bool isCopied}) { + final containerSize = 40.0; + final iconSize = 16.0; + + return AnimatedContainer( + duration: const Duration(milliseconds: 200), + width: containerSize, + height: containerSize, + decoration: BoxDecoration( + color: isCopied ? context.colors.copyButtonCopiedBg : Colors.transparent, + border: Border.all( + color: isCopied ? context.colors.copyButtonCopiedBorder : context.colors.borderButton, + width: 1, + ), + borderRadius: BorderRadius.circular(containerSize / 2), + ), + child: Center( + child: Icon( + isCopied ? Icons.check : Icons.copy, + size: iconSize, + color: isCopied ? context.colors.success : context.colors.textPrimary, + ), + ), ); } } diff --git a/quantus_sdk/lib/src/ui/components/address_input_field.dart b/mobile-app/lib/v2/components/address_input_field.dart similarity index 100% rename from quantus_sdk/lib/src/ui/components/address_input_field.dart rename to mobile-app/lib/v2/components/address_input_field.dart diff --git a/quantus_sdk/lib/src/ui/components/amount_display_with_conversion.dart b/mobile-app/lib/v2/components/amount_display_with_conversion.dart similarity index 100% rename from quantus_sdk/lib/src/ui/components/amount_display_with_conversion.dart rename to mobile-app/lib/v2/components/amount_display_with_conversion.dart diff --git a/quantus_sdk/lib/src/ui/components/animated_qr_scanner.dart b/mobile-app/lib/v2/components/animated_qr_scanner.dart similarity index 98% rename from quantus_sdk/lib/src/ui/components/animated_qr_scanner.dart rename to mobile-app/lib/v2/components/animated_qr_scanner.dart index 53544dfc9..cba4316d3 100644 --- a/quantus_sdk/lib/src/ui/components/animated_qr_scanner.dart +++ b/mobile-app/lib/v2/components/animated_qr_scanner.dart @@ -3,8 +3,6 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:mobile_scanner/mobile_scanner.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; /// Sequence metadata encoded in one frame of an animated QR payload. class AnimatedQrSequence { diff --git a/mobile-app/lib/v2/components/decoded_call_view.dart b/mobile-app/lib/v2/components/decoded_call_view.dart new file mode 100644 index 000000000..5328d1659 --- /dev/null +++ b/mobile-app/lib/v2/components/decoded_call_view.dart @@ -0,0 +1,23 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' as sdk; +import 'package:resonance_network_wallet/providers/currency_display_provider.dart'; + +/// App-level decoded-call tree: maps [txAmountDisplayProvider] onto the +/// presentational SDK widget. +class DecodedCallView extends ConsumerWidget { + final sdk.DecodedCall call; + final int depth; + + const DecodedCallView({super.key, required this.call, this.depth = 0}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final formatAmount = ref.watch(txAmountDisplayProvider); + return sdk.DecodedCallView( + call: call, + depth: depth, + amountText: (token) => formatAmount(token, isSend: true).primaryAmount, + ); + } +} diff --git a/mobile-app/lib/features/components/dotted_border.dart b/mobile-app/lib/v2/components/dotted_border.dart similarity index 100% rename from mobile-app/lib/features/components/dotted_border.dart rename to mobile-app/lib/v2/components/dotted_border.dart diff --git a/quantus_sdk/lib/src/ui/components/explorer_link.dart b/mobile-app/lib/v2/components/explorer_link.dart similarity index 100% rename from quantus_sdk/lib/src/ui/components/explorer_link.dart rename to mobile-app/lib/v2/components/explorer_link.dart diff --git a/quantus_sdk/lib/src/ui/components/global_toast_listener.dart b/mobile-app/lib/v2/components/global_toast_listener.dart similarity index 93% rename from quantus_sdk/lib/src/ui/components/global_toast_listener.dart rename to mobile-app/lib/v2/components/global_toast_listener.dart index b54080db1..acd553f8e 100644 --- a/quantus_sdk/lib/src/ui/components/global_toast_listener.dart +++ b/mobile-app/lib/v2/components/global_toast_listener.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:resonance_network_wallet/providers/global_toast_provider.dart'; -import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; /// Renders app-wide toasts requested through [globalToastProvider]. /// diff --git a/mobile-app/lib/features/components/migration_dialog.dart b/mobile-app/lib/v2/components/migration_dialog.dart similarity index 98% rename from mobile-app/lib/features/components/migration_dialog.dart rename to mobile-app/lib/v2/components/migration_dialog.dart index ec0377159..f239e6a5b 100644 --- a/mobile-app/lib/features/components/migration_dialog.dart +++ b/mobile-app/lib/v2/components/migration_dialog.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; class MigrationDialog extends ConsumerStatefulWidget { final List migrationResults; diff --git a/mobile-app/lib/features/components/mnemonic_grid.dart b/mobile-app/lib/v2/components/mnemonic_grid.dart similarity index 100% rename from mobile-app/lib/features/components/mnemonic_grid.dart rename to mobile-app/lib/v2/components/mnemonic_grid.dart diff --git a/quantus_sdk/lib/src/ui/components/multisig_expiry_value.dart b/mobile-app/lib/v2/components/multisig_expiry_value.dart similarity index 100% rename from quantus_sdk/lib/src/ui/components/multisig_expiry_value.dart rename to mobile-app/lib/v2/components/multisig_expiry_value.dart diff --git a/quantus_sdk/lib/src/ui/components/multisig_signer_list_tile.dart b/mobile-app/lib/v2/components/multisig_signer_list_tile.dart similarity index 100% rename from quantus_sdk/lib/src/ui/components/multisig_signer_list_tile.dart rename to mobile-app/lib/v2/components/multisig_signer_list_tile.dart diff --git a/quantus_sdk/lib/src/ui/components/multisig_tag.dart b/mobile-app/lib/v2/components/multisig_tag.dart similarity index 100% rename from quantus_sdk/lib/src/ui/components/multisig_tag.dart rename to mobile-app/lib/v2/components/multisig_tag.dart diff --git a/quantus_sdk/lib/src/ui/components/multisig_threshold_slider.dart b/mobile-app/lib/v2/components/multisig_threshold_slider.dart similarity index 100% rename from quantus_sdk/lib/src/ui/components/multisig_threshold_slider.dart rename to mobile-app/lib/v2/components/multisig_threshold_slider.dart diff --git a/quantus_sdk/lib/src/ui/components/name_field.dart b/mobile-app/lib/v2/components/name_field.dart similarity index 100% rename from quantus_sdk/lib/src/ui/components/name_field.dart rename to mobile-app/lib/v2/components/name_field.dart diff --git a/mobile-app/lib/features/components/network_status_banner.dart b/mobile-app/lib/v2/components/network_status_banner.dart similarity index 88% rename from mobile-app/lib/features/components/network_status_banner.dart rename to mobile-app/lib/v2/components/network_status_banner.dart index 37485f481..42e562341 100644 --- a/mobile-app/lib/features/components/network_status_banner.dart +++ b/mobile-app/lib/v2/components/network_status_banner.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:resonance_network_wallet/features/styles/app_colors_theme.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/connectivity_provider.dart'; class NetworkStatusBanner extends ConsumerWidget { @@ -26,7 +26,7 @@ class NetworkStatusBanner extends ConsumerWidget { Text( 'Not Connected', style: TextStyle( - color: context.themeColors.textPrimary, + color: context.colors.textPrimary, fontSize: 16, fontFamily: 'Fira Code', fontWeight: FontWeight.w400, diff --git a/quantus_sdk/lib/src/ui/components/private_activity_notice.dart b/mobile-app/lib/v2/components/private_activity_notice.dart similarity index 100% rename from quantus_sdk/lib/src/ui/components/private_activity_notice.dart rename to mobile-app/lib/v2/components/private_activity_notice.dart diff --git a/quantus_sdk/lib/src/ui/components/proposal_list_tile.dart b/mobile-app/lib/v2/components/proposal_list_tile.dart similarity index 98% rename from quantus_sdk/lib/src/ui/components/proposal_list_tile.dart rename to mobile-app/lib/v2/components/proposal_list_tile.dart index 2bde3d049..079cbec9d 100644 --- a/quantus_sdk/lib/src/ui/components/proposal_list_tile.dart +++ b/mobile-app/lib/v2/components/proposal_list_tile.dart @@ -3,7 +3,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/currency_display_provider.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; -import 'package:quantus_sdk/src/ui/components/decoded_call_view.dart'; /// Shared card layout for indexed and pending multisig proposal rows. class ProposalListTile extends ConsumerWidget { diff --git a/quantus_sdk/lib/src/ui/components/qr_scanner_page.dart b/mobile-app/lib/v2/components/qr_scanner_page.dart similarity index 99% rename from quantus_sdk/lib/src/ui/components/qr_scanner_page.dart rename to mobile-app/lib/v2/components/qr_scanner_page.dart index 8ebca78d4..ffb6b7d61 100644 --- a/quantus_sdk/lib/src/ui/components/qr_scanner_page.dart +++ b/mobile-app/lib/v2/components/qr_scanner_page.dart @@ -5,7 +5,6 @@ import 'package:image_picker/image_picker.dart'; import 'package:mobile_scanner/mobile_scanner.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; class QrScannerPage extends ConsumerStatefulWidget { final bool Function(String)? validator; diff --git a/quantus_sdk/lib/src/ui/components/recovery_phrase_body.dart b/mobile-app/lib/v2/components/recovery_phrase_body.dart similarity index 92% rename from quantus_sdk/lib/src/ui/components/recovery_phrase_body.dart rename to mobile-app/lib/v2/components/recovery_phrase_body.dart index 50202d366..6f55c9fb8 100644 --- a/quantus_sdk/lib/src/ui/components/recovery_phrase_body.dart +++ b/mobile-app/lib/v2/components/recovery_phrase_body.dart @@ -1,16 +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/mnemonic_grid.dart'; +import 'package:resonance_network_wallet/v2/components/mnemonic_grid.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/shared/constants/e2e_keys.dart'; import 'package:resonance_network_wallet/shared/extensions/clipboard_extensions.dart'; -import 'package:quantus_sdk/src/ui/components/loader.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; class RecoveryPhraseBody extends ConsumerStatefulWidget { final String appBarTitle; @@ -158,4 +153,4 @@ class _RecoveryPhraseBodyState extends ConsumerState { ), ); } -} +} \ No newline at end of file diff --git a/quantus_sdk/lib/src/ui/components/share_account_button.dart b/mobile-app/lib/v2/components/share_account_button.dart similarity index 92% rename from quantus_sdk/lib/src/ui/components/share_account_button.dart rename to mobile-app/lib/v2/components/share_account_button.dart index a8bad924b..3266a1b2a 100644 --- a/quantus_sdk/lib/src/ui/components/share_account_button.dart +++ b/mobile-app/lib/v2/components/share_account_button.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; class ShareAccountButton extends ConsumerWidget { diff --git a/mobile-app/lib/features/components/shared_address_action_sheet.dart b/mobile-app/lib/v2/components/shared_address_action_sheet.dart similarity index 98% rename from mobile-app/lib/features/components/shared_address_action_sheet.dart rename to mobile-app/lib/v2/components/shared_address_action_sheet.dart index 1edf08497..5dc1c8990 100644 --- a/mobile-app/lib/features/components/shared_address_action_sheet.dart +++ b/mobile-app/lib/v2/components/shared_address_action_sheet.dart @@ -3,14 +3,12 @@ import 'dart:ui'; 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/styles/app_colors_theme.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; import 'package:resonance_network_wallet/routes.dart'; import 'package:resonance_network_wallet/shared/extensions/clipboard_extensions.dart'; import 'package:resonance_network_wallet/shared/extensions/current_route_extensions.dart'; -import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; import 'package:resonance_network_wallet/v2/screens/send/input_amount_screen.dart'; import 'package:resonance_network_wallet/v2/screens/send/regular_send_strategy.dart'; @@ -100,7 +98,7 @@ class _SharedAddressActionSheetState extends State { child: Container( padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), decoration: ShapeDecoration( - color: context.themeColors.background, + color: context.colors.background, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)), ), child: Stack( diff --git a/mobile-app/lib/features/components/skeleton.dart b/mobile-app/lib/v2/components/skeleton.dart similarity index 100% rename from mobile-app/lib/features/components/skeleton.dart rename to mobile-app/lib/v2/components/skeleton.dart diff --git a/quantus_sdk/lib/src/ui/components/split_card.dart b/mobile-app/lib/v2/components/split_card.dart similarity index 100% rename from quantus_sdk/lib/src/ui/components/split_card.dart rename to mobile-app/lib/v2/components/split_card.dart diff --git a/quantus_sdk/lib/src/ui/components/success_check.dart b/mobile-app/lib/v2/components/success_check.dart similarity index 100% rename from quantus_sdk/lib/src/ui/components/success_check.dart rename to mobile-app/lib/v2/components/success_check.dart diff --git a/quantus_sdk/lib/src/ui/components/token_icon.dart b/mobile-app/lib/v2/components/token_icon.dart similarity index 100% rename from quantus_sdk/lib/src/ui/components/token_icon.dart rename to mobile-app/lib/v2/components/token_icon.dart diff --git a/quantus_sdk/lib/src/ui/components/wormhole_progress_steps.dart b/mobile-app/lib/v2/components/wormhole_progress_steps.dart similarity index 100% rename from quantus_sdk/lib/src/ui/components/wormhole_progress_steps.dart rename to mobile-app/lib/v2/components/wormhole_progress_steps.dart diff --git a/mobile-app/lib/v2/screens/accounts/account_details_screen.dart b/mobile-app/lib/v2/screens/accounts/account_details_screen.dart index c5b9c7fbd..b21fadb21 100644 --- a/mobile-app/lib/v2/screens/accounts/account_details_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/account_details_screen.dart @@ -1,13 +1,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart' hide AddressDetailsCard; +import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/shared/utils/share_utils.dart'; import 'package:resonance_network_wallet/v2/components/address_details_card.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; -import 'package:quantus_sdk/src/ui/components/share_account_button.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; +import 'package:resonance_network_wallet/v2/components/share_account_button.dart'; class AccountDetailsScreen extends ConsumerStatefulWidget { const AccountDetailsScreen({super.key, required this.accountId}); diff --git a/mobile-app/lib/v2/screens/accounts/account_menu_screen.dart b/mobile-app/lib/v2/screens/accounts/account_menu_screen.dart index dac82b1da..ebd3b4d3c 100644 --- a/mobile-app/lib/v2/screens/accounts/account_menu_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/account_menu_screen.dart @@ -5,16 +5,9 @@ import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; -import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/accounts_grouping.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; -import 'package:quantus_sdk/src/ui/components/account_badge.dart'; -import 'package:quantus_sdk/src/ui/components/confirm_action_sheet.dart'; -import 'package:quantus_sdk/src/ui/components/menu_divider.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; +import 'package:resonance_network_wallet/v2/components/account_badge.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/account_details_screen.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/accounts_navigation.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/edit_account_screen.dart'; diff --git a/mobile-app/lib/v2/screens/accounts/account_ready_screen.dart b/mobile-app/lib/v2/screens/accounts/account_ready_screen.dart index d1a6087ab..fcc5cde97 100644 --- a/mobile-app/lib/v2/screens/accounts/account_ready_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/account_ready_screen.dart @@ -1,4 +1,3 @@ - import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; @@ -6,13 +5,8 @@ import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; import 'package:resonance_network_wallet/shared/constants/e2e_keys.dart'; -import 'package:quantus_sdk/src/ui/components/account_badge.dart'; -import 'package:quantus_sdk/src/ui/components/loader.dart'; -import 'package:quantus_sdk/src/ui/components/private_activity_notice.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; +import 'package:resonance_network_wallet/v2/components/account_badge.dart'; +import 'package:resonance_network_wallet/v2/components/private_activity_notice.dart'; import 'package:resonance_network_wallet/v2/screens/home/home_screen.dart'; enum AccountReadyOverviewOrigin { accountCreated, walletCreated, walletImported } diff --git a/mobile-app/lib/v2/screens/accounts/accounts_screen.dart b/mobile-app/lib/v2/screens/accounts/accounts_screen.dart index deec54da5..dbba725a1 100644 --- a/mobile-app/lib/v2/screens/accounts/accounts_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/accounts_screen.dart @@ -4,21 +4,15 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/multisig_providers.dart'; import 'package:resonance_network_wallet/shared/utils/accounts_grouping.dart'; -import 'package:quantus_sdk/src/ui/components/account_badge.dart'; -import 'package:quantus_sdk/src/ui/components/loader.dart'; -import 'package:quantus_sdk/src/ui/components/private_activity_notice.dart'; -import 'package:quantus_sdk/src/ui/components/multisig_tag.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_icon_button.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.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/shared/utils/print.dart'; +import 'package:resonance_network_wallet/v2/components/account_badge.dart'; +import 'package:resonance_network_wallet/v2/components/multisig_tag.dart'; +import 'package:resonance_network_wallet/v2/components/private_activity_notice.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/account_menu_screen.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/accounts_navigation.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/multisig_account_menu_screen.dart'; diff --git a/mobile-app/lib/v2/screens/accounts/add_hardware_account_screen.dart b/mobile-app/lib/v2/screens/accounts/add_hardware_account_screen.dart index 95b507b8b..93fadc9cc 100644 --- a/mobile-app/lib/v2/screens/accounts/add_hardware_account_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/add_hardware_account_screen.dart @@ -2,10 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/connect_keystone_screen.dart'; import 'package:url_launcher/url_launcher.dart'; diff --git a/mobile-app/lib/v2/screens/accounts/connect_keystone_screen.dart b/mobile-app/lib/v2/screens/accounts/connect_keystone_screen.dart index b7cef5fef..e390c1704 100644 --- a/mobile-app/lib/v2/screens/accounts/connect_keystone_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/connect_keystone_screen.dart @@ -5,11 +5,7 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/qr_scanner_page.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; +import 'package:resonance_network_wallet/v2/components/qr_scanner_page.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/account_menu_screen.dart'; /// Second add-Keystone screen: on-device instructions, then scans the device's diff --git a/mobile-app/lib/v2/screens/accounts/create_account_screen.dart b/mobile-app/lib/v2/screens/accounts/create_account_screen.dart index b5c2df811..0c650a83d 100644 --- a/mobile-app/lib/v2/screens/accounts/create_account_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/create_account_screen.dart @@ -5,14 +5,9 @@ import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/remote_config_provider.dart'; import 'package:resonance_network_wallet/services/firebase_messaging_service.dart'; -import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/account_utils.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; -import 'package:quantus_sdk/src/ui/components/name_field.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; +import 'package:resonance_network_wallet/v2/components/name_field.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/accounts_navigation.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/add_hardware_account_screen.dart'; diff --git a/mobile-app/lib/v2/screens/accounts/edit_account_screen.dart b/mobile-app/lib/v2/screens/accounts/edit_account_screen.dart index 57757dab1..b35653314 100644 --- a/mobile-app/lib/v2/screens/accounts/edit_account_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/edit_account_screen.dart @@ -4,12 +4,7 @@ import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/multisig_providers.dart'; -import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; -import 'package:quantus_sdk/src/ui/components/name_field.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; +import 'package:resonance_network_wallet/v2/components/name_field.dart'; class EditAccountScreen extends ConsumerStatefulWidget { const EditAccountScreen({super.key, required Account initialAccount}) diff --git a/mobile-app/lib/v2/screens/accounts/multisig_account_menu_screen.dart b/mobile-app/lib/v2/screens/accounts/multisig_account_menu_screen.dart index 0097b8451..ab1d7bf14 100644 --- a/mobile-app/lib/v2/screens/accounts/multisig_account_menu_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/multisig_account_menu_screen.dart @@ -5,15 +5,8 @@ import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/multisig_providers.dart'; -import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; -import 'package:quantus_sdk/src/ui/components/account_badge.dart'; -import 'package:quantus_sdk/src/ui/components/confirm_action_sheet.dart'; -import 'package:quantus_sdk/src/ui/components/menu_divider.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; +import 'package:resonance_network_wallet/v2/components/account_badge.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/account_details_screen.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/accounts_navigation.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/edit_account_screen.dart'; diff --git a/mobile-app/lib/v2/screens/accounts/multisig_details_screen.dart b/mobile-app/lib/v2/screens/accounts/multisig_details_screen.dart index 69fc770cc..19adfb815 100644 --- a/mobile-app/lib/v2/screens/accounts/multisig_details_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/multisig_details_screen.dart @@ -4,9 +4,7 @@ import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; -import 'package:quantus_sdk/src/ui/components/multisig_signer_list_tile.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; +import 'package:resonance_network_wallet/v2/components/multisig_signer_list_tile.dart'; class MultisigDetailsScreen extends ConsumerWidget { const MultisigDetailsScreen({super.key, required this.account}); diff --git a/mobile-app/lib/v2/screens/accounts/wallet_name_screen.dart b/mobile-app/lib/v2/screens/accounts/wallet_name_screen.dart index fbe0b12d2..bad8fabed 100644 --- a/mobile-app/lib/v2/screens/accounts/wallet_name_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/wallet_name_screen.dart @@ -3,11 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; -import 'package:quantus_sdk/src/ui/components/name_field.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; +import 'package:resonance_network_wallet/v2/components/name_field.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/accounts_navigation.dart'; /// Names (or renames) a wallet. The name is optional: saving an empty field diff --git a/mobile-app/lib/v2/screens/activity/activity_screen.dart b/mobile-app/lib/v2/screens/activity/activity_screen.dart index f6a790f7c..d64864b6c 100644 --- a/mobile-app/lib/v2/screens/activity/activity_screen.dart +++ b/mobile-app/lib/v2/screens/activity/activity_screen.dart @@ -2,7 +2,7 @@ import 'package:collection/collection.dart'; 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/skeleton.dart'; +import 'package:resonance_network_wallet/v2/components/skeleton.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/active_account_transactions_provider.dart'; @@ -10,9 +10,6 @@ import 'package:resonance_network_wallet/providers/currency_display_provider.dar import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; import 'package:resonance_network_wallet/services/transaction_service.dart'; -import 'package:quantus_sdk/src/ui/components/loader.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/activity/tx_item.dart'; import 'package:resonance_network_wallet/v2/screens/activity/transaction_detail_sheet.dart'; 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 9ab011e62..b8914ab58 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_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:resonance_network_wallet/features/components/dotted_border.dart'; +import 'package:resonance_network_wallet/v2/components/dotted_border.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/currency_display_provider.dart'; @@ -10,9 +10,8 @@ import 'package:resonance_network_wallet/providers/wallet_providers.dart'; import 'package:resonance_network_wallet/routes.dart'; import 'package:resonance_network_wallet/shared/extensions/current_route_extensions.dart'; import 'package:resonance_network_wallet/shared/extensions/transaction_event_extension.dart'; -import 'package:quantus_sdk/src/ui/components/amount_display_with_conversion.dart'; -import 'package:quantus_sdk/src/ui/components/bottom_sheet_container.dart'; -import 'package:quantus_sdk/src/ui/components/explorer_link.dart'; +import 'package:resonance_network_wallet/v2/components/amount_display_with_conversion.dart'; +import 'package:resonance_network_wallet/v2/components/explorer_link.dart'; void showTransactionDetailSheet(BuildContext context, TransactionEvent tx, String activeAccountId) { if (context.peekTopRouteName == transactionDetailSheetRouteSettings.name) Navigator.pop(context); diff --git a/mobile-app/lib/v2/screens/auth/auth_wrapper.dart b/mobile-app/lib/v2/screens/auth/auth_wrapper.dart index 61682e010..7bdca5d46 100644 --- a/mobile-app/lib/v2/screens/auth/auth_wrapper.dart +++ b/mobile-app/lib/v2/screens/auth/auth_wrapper.dart @@ -3,9 +3,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/local_auth_provider.dart'; -import 'package:quantus_sdk/src/ui/components/base_background.dart'; -import 'package:quantus_sdk/src/ui/components/loader.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; class AuthWrapper extends ConsumerWidget { const AuthWrapper({super.key}); diff --git a/mobile-app/lib/v2/screens/home/activity_section.dart b/mobile-app/lib/v2/screens/home/activity_section.dart index df04a560d..2b2386968 100644 --- a/mobile-app/lib/v2/screens/home/activity_section.dart +++ b/mobile-app/lib/v2/screens/home/activity_section.dart @@ -2,7 +2,7 @@ import 'package:collection/collection.dart'; 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/skeleton.dart'; +import 'package:resonance_network_wallet/v2/components/skeleton.dart'; import 'package:resonance_network_wallet/models/combined_transactions_list.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/active_account_transactions_provider.dart'; diff --git a/mobile-app/lib/v2/screens/home/home_screen.dart b/mobile-app/lib/v2/screens/home/home_screen.dart index 11a96c848..f4809976e 100644 --- a/mobile-app/lib/v2/screens/home/home_screen.dart +++ b/mobile-app/lib/v2/screens/home/home_screen.dart @@ -4,21 +4,16 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/legacy.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:resonance_network_wallet/features/components/dotted_border.dart'; -import 'package:resonance_network_wallet/features/components/skeleton.dart'; +import 'package:resonance_network_wallet/v2/components/dotted_border.dart'; +import 'package:resonance_network_wallet/v2/components/skeleton.dart'; import 'package:resonance_network_wallet/features/components/shared_address_action_sheet.dart'; import 'package:resonance_network_wallet/services/global_history_polling_service.dart'; import 'package:resonance_network_wallet/services/telemetry_service.dart'; import 'package:resonance_network_wallet/shared/constants/e2e_keys.dart'; -import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; import 'package:resonance_network_wallet/shared/utils/url_utils.dart'; -import 'package:quantus_sdk/src/ui/components/amount_display_with_conversion.dart'; -import 'package:quantus_sdk/src/ui/components/loader.dart'; -import 'package:quantus_sdk/src/ui/components/private_activity_notice.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_icon_button.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; +import 'package:resonance_network_wallet/v2/components/amount_display_with_conversion.dart'; +import 'package:resonance_network_wallet/v2/components/private_activity_notice.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/open_accounts_management_button.dart'; import 'package:resonance_network_wallet/v2/screens/activity/transaction_detail_sheet.dart'; import 'package:resonance_network_wallet/v2/screens/receive/receive_screen.dart'; @@ -32,7 +27,6 @@ import 'package:resonance_network_wallet/v2/screens/send/select_recipient_screen import 'package:resonance_network_wallet/v2/screens/send/send_strategy.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_screen.dart'; import 'package:resonance_network_wallet/v2/screens/pos/pos_amount_screen.dart'; -import 'package:resonance_network_wallet/v2/screens/swap/swap_screen.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; @@ -42,9 +36,8 @@ import 'package:resonance_network_wallet/providers/multisig_providers.dart'; import 'package:resonance_network_wallet/providers/route_intent_providers.dart'; import 'package:resonance_network_wallet/providers/currency_display_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_providers.dart'; -import 'package:quantus_sdk/src/ui/components/global_toast_listener.dart'; +import 'package:resonance_network_wallet/v2/components/global_toast_listener.dart'; import 'package:resonance_network_wallet/v2/screens/home/activity_section.dart'; import 'package:resonance_network_wallet/v2/screens/home/backup_reminder_banner.dart'; @@ -363,7 +356,6 @@ class _HomeScreenState extends ConsumerState { Widget _buildActionButtons(AppLocalizations l10n, Account account) { final isEncrypted = isEncryptedAccount(account); - const enableSwap = true; // ref.watch(remoteConfigProvider).enableSwap; Override enable swap config for now final SendStrategy sendStrategy = isEncrypted ? EncryptedSendStrategy(account: account) : RegularSendStrategy(account: account); @@ -381,27 +373,7 @@ class _HomeScreenState extends ConsumerState { onTap: () => startSendFlow(context, screen: SelectRecipientScreen(strategy: sendStrategy)), ); - final swapCard = _actionCard( - iconAsset: 'assets/v2/action_swap.svg', - label: l10n.homeSwap, - // Swap is not available for encrypted accounts; keep the button visible - // but disabled so the layout doesn't change between account types. - isDisabled: isEncrypted, - onTap: () => Navigator.push(context, MaterialPageRoute(builder: (_) => const SwapScreen())), - ); - - final List children = []; - - children.add(receiveCard); - children.add(const SizedBox(width: 15)); - children.add(sendCard); - - if (enableSwap) { - children.add(const SizedBox(width: 15)); - children.add(swapCard); - } - - return Row(children: children); + return Row(children: [receiveCard, const SizedBox(width: 15), sendCard]); } Widget _buildMultisigActionButtons(AppLocalizations l10n, MultisigAccount msig) { @@ -425,19 +397,12 @@ class _HomeScreenState extends ConsumerState { ); } - Widget _actionCard({ - Key? key, - required String iconAsset, - required String label, - required VoidCallback onTap, - bool isDisabled = false, - }) { + Widget _actionCard({Key? key, required String iconAsset, required String label, required VoidCallback onTap}) { return Expanded( child: QuantusButton.simple( key: key, label: label, onTap: onTap, - isDisabled: isDisabled, icon: SvgPicture.asset( iconAsset, width: 24, diff --git a/mobile-app/lib/v2/screens/import/import_wallet_screen.dart b/mobile-app/lib/v2/screens/import/import_wallet_screen.dart index 0d0bfc847..315fd0b24 100644 --- a/mobile-app/lib/v2/screens/import/import_wallet_screen.dart +++ b/mobile-app/lib/v2/screens/import/import_wallet_screen.dart @@ -11,10 +11,6 @@ import 'package:resonance_network_wallet/services/firebase_messaging_service.dar import 'package:resonance_network_wallet/services/telemetry_service.dart'; import 'package:resonance_network_wallet/shared/constants/e2e_keys.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/wallet_name_screen.dart'; import 'package:resonance_network_wallet/v2/screens/home/home_screen.dart'; diff --git a/mobile-app/lib/v2/screens/multisig/add_multisig_screen.dart b/mobile-app/lib/v2/screens/multisig/add_multisig_screen.dart index 6c4b014a2..f26680f31 100644 --- a/mobile-app/lib/v2/screens/multisig/add_multisig_screen.dart +++ b/mobile-app/lib/v2/screens/multisig/add_multisig_screen.dart @@ -1,22 +1,17 @@ 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/skeleton.dart'; +import 'package:resonance_network_wallet/v2/components/multisig_signer_list_tile.dart'; +import 'package:resonance_network_wallet/v2/components/multisig_threshold_slider.dart'; +import 'package:resonance_network_wallet/v2/components/name_field.dart'; +import 'package:resonance_network_wallet/v2/components/skeleton.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/multisig_providers.dart'; import 'package:resonance_network_wallet/providers/pending_multisig_creations_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; -import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; -import 'package:quantus_sdk/src/ui/components/multisig_signer_list_tile.dart'; -import 'package:quantus_sdk/src/ui/components/multisig_threshold_slider.dart'; -import 'package:quantus_sdk/src/ui/components/name_field.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/services/local_auth_service.dart'; import 'package:resonance_network_wallet/services/multisig_submission_service.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/accounts_navigation.dart'; diff --git a/mobile-app/lib/v2/screens/multisig/discover_multisig_screen.dart b/mobile-app/lib/v2/screens/multisig/discover_multisig_screen.dart index 0c00b12a1..f0d35699c 100644 --- a/mobile-app/lib/v2/screens/multisig/discover_multisig_screen.dart +++ b/mobile-app/lib/v2/screens/multisig/discover_multisig_screen.dart @@ -1,15 +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/skeleton.dart'; +import 'package:resonance_network_wallet/v2/components/skeleton.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/multisig_providers.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; -import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; class DiscoverMultisigScreen extends ConsumerStatefulWidget { const DiscoverMultisigScreen({super.key}); diff --git a/mobile-app/lib/v2/screens/multisig/multisig_action_confirm_sheet.dart b/mobile-app/lib/v2/screens/multisig/multisig_action_confirm_sheet.dart index ec6b4c30a..554285026 100644 --- a/mobile-app/lib/v2/screens/multisig/multisig_action_confirm_sheet.dart +++ b/mobile-app/lib/v2/screens/multisig/multisig_action_confirm_sheet.dart @@ -3,7 +3,7 @@ import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide DecodedCallView; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; @@ -11,10 +11,7 @@ import 'package:resonance_network_wallet/providers/multisig_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/shared/utils/print.dart'; -import 'package:quantus_sdk/src/ui/components/bottom_sheet_container.dart'; -import 'package:quantus_sdk/src/ui/components/decoded_call_view.dart'; -import 'package:quantus_sdk/src/ui/components/detail_summary_row.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:resonance_network_wallet/v2/components/decoded_call_view.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_sign_cache.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_sign_screen.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_signing_session.dart'; diff --git a/mobile-app/lib/v2/screens/multisig/multisig_activity_section.dart b/mobile-app/lib/v2/screens/multisig/multisig_activity_section.dart index ab2411d6e..12f86312e 100644 --- a/mobile-app/lib/v2/screens/multisig/multisig_activity_section.dart +++ b/mobile-app/lib/v2/screens/multisig/multisig_activity_section.dart @@ -13,6 +13,7 @@ import 'package:resonance_network_wallet/providers/pending_multisig_executions_p import 'package:resonance_network_wallet/providers/pending_multisig_proposals_provider.dart'; import 'package:resonance_network_wallet/services/transaction_service.dart'; import 'package:resonance_network_wallet/shared/utils/multisig_local_signers.dart'; +import 'package:resonance_network_wallet/v2/components/proposal_list_tile.dart'; import 'package:resonance_network_wallet/v2/screens/activity/transaction_detail_sheet.dart'; import 'package:resonance_network_wallet/v2/screens/activity/tx_item.dart'; import 'package:resonance_network_wallet/v2/screens/multisig/multisig_proposal_detail_sheet.dart'; diff --git a/mobile-app/lib/v2/screens/multisig/multisig_approve_confirm_sheet.dart b/mobile-app/lib/v2/screens/multisig/multisig_approve_confirm_sheet.dart index 3ae664651..4e064fd52 100644 --- a/mobile-app/lib/v2/screens/multisig/multisig_approve_confirm_sheet.dart +++ b/mobile-app/lib/v2/screens/multisig/multisig_approve_confirm_sheet.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/multisig_providers.dart'; import 'package:resonance_network_wallet/services/transaction_submission_service.dart'; -import 'package:quantus_sdk/src/ui/components/bottom_sheet_container.dart'; import 'package:resonance_network_wallet/v2/screens/multisig/multisig_action_confirm_sheet.dart'; /// Shows the confirmation sheet for approving a multisig proposal. diff --git a/mobile-app/lib/v2/screens/multisig/multisig_cancel_confirm_sheet.dart b/mobile-app/lib/v2/screens/multisig/multisig_cancel_confirm_sheet.dart index be4088a98..f15fd9157 100644 --- a/mobile-app/lib/v2/screens/multisig/multisig_cancel_confirm_sheet.dart +++ b/mobile-app/lib/v2/screens/multisig/multisig_cancel_confirm_sheet.dart @@ -2,8 +2,6 @@ import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/multisig_providers.dart'; import 'package:resonance_network_wallet/services/transaction_submission_service.dart'; -import 'package:quantus_sdk/src/ui/components/bottom_sheet_container.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; import 'package:resonance_network_wallet/v2/screens/multisig/multisig_action_confirm_sheet.dart'; /// Shows the confirmation sheet for cancelling a multisig proposal. diff --git a/mobile-app/lib/v2/screens/multisig/multisig_execute_confirm_sheet.dart b/mobile-app/lib/v2/screens/multisig/multisig_execute_confirm_sheet.dart index fb0076a2a..f1fcd8cc5 100644 --- a/mobile-app/lib/v2/screens/multisig/multisig_execute_confirm_sheet.dart +++ b/mobile-app/lib/v2/screens/multisig/multisig_execute_confirm_sheet.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/multisig_providers.dart'; import 'package:resonance_network_wallet/services/transaction_submission_service.dart'; -import 'package:quantus_sdk/src/ui/components/bottom_sheet_container.dart'; import 'package:resonance_network_wallet/v2/screens/multisig/multisig_action_confirm_sheet.dart'; /// Shows the confirmation sheet for executing an approved multisig proposal. diff --git a/mobile-app/lib/v2/screens/multisig/multisig_proposal_detail_sheet.dart b/mobile-app/lib/v2/screens/multisig/multisig_proposal_detail_sheet.dart index 2df0114a5..5c998c018 100644 --- a/mobile-app/lib/v2/screens/multisig/multisig_proposal_detail_sheet.dart +++ b/mobile-app/lib/v2/screens/multisig/multisig_proposal_detail_sheet.dart @@ -1,7 +1,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/dotted_border.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide DecodedCallView; +import 'package:resonance_network_wallet/v2/components/dotted_border.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/currency_display_provider.dart'; @@ -11,17 +11,13 @@ import 'package:resonance_network_wallet/providers/pending_multisig_approvals_pr import 'package:resonance_network_wallet/providers/pending_multisig_cancellations_provider.dart'; import 'package:resonance_network_wallet/providers/pending_multisig_executions_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; -import 'package:quantus_sdk/src/ui/components/multisig_expiry_value.dart'; import 'package:resonance_network_wallet/routes.dart'; import 'package:resonance_network_wallet/shared/extensions/current_route_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/multisig_local_signers.dart'; -import 'package:quantus_sdk/src/ui/components/amount_display_with_conversion.dart'; -import 'package:quantus_sdk/src/ui/components/decoded_call_view.dart'; -import 'package:quantus_sdk/src/ui/components/bottom_sheet_container.dart'; -import 'package:quantus_sdk/src/ui/components/detail_summary_row.dart'; -import 'package:quantus_sdk/src/ui/components/explorer_link.dart'; -import 'package:quantus_sdk/src/ui/components/loader.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; +import 'package:resonance_network_wallet/v2/components/amount_display_with_conversion.dart'; +import 'package:resonance_network_wallet/v2/components/decoded_call_view.dart'; +import 'package:resonance_network_wallet/v2/components/explorer_link.dart'; +import 'package:resonance_network_wallet/v2/components/multisig_expiry_value.dart'; import 'package:resonance_network_wallet/v2/screens/multisig/multisig_approve_confirm_sheet.dart'; import 'package:resonance_network_wallet/v2/screens/multisig/multisig_cancel_confirm_sheet.dart'; import 'package:resonance_network_wallet/v2/screens/multisig/multisig_execute_confirm_sheet.dart'; diff --git a/mobile-app/lib/v2/screens/multisig/multisig_signer_picker_sheet.dart b/mobile-app/lib/v2/screens/multisig/multisig_signer_picker_sheet.dart index 3efe92f30..6e3fb7abb 100644 --- a/mobile-app/lib/v2/screens/multisig/multisig_signer_picker_sheet.dart +++ b/mobile-app/lib/v2/screens/multisig/multisig_signer_picker_sheet.dart @@ -2,8 +2,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/providers/l10n_provider.dart'; -import 'package:quantus_sdk/src/ui/components/account_badge.dart'; -import 'package:quantus_sdk/src/ui/components/bottom_sheet_container.dart'; +import 'package:resonance_network_wallet/v2/components/account_badge.dart'; /// Picks which local signer account should approve a multisig proposal. /// diff --git a/mobile-app/lib/v2/screens/multisig/proposal_row.dart b/mobile-app/lib/v2/screens/multisig/proposal_row.dart index ffc13ab47..9d73674fe 100644 --- a/mobile-app/lib/v2/screens/multisig/proposal_row.dart +++ b/mobile-app/lib/v2/screens/multisig/proposal_row.dart @@ -7,7 +7,7 @@ import 'package:resonance_network_wallet/providers/pending_multisig_approvals_pr import 'package:resonance_network_wallet/providers/pending_multisig_cancellations_provider.dart'; import 'package:resonance_network_wallet/providers/pending_multisig_executions_provider.dart'; import 'package:resonance_network_wallet/shared/utils/multisig_local_signers.dart'; -import 'package:quantus_sdk/src/ui/components/proposal_list_tile.dart'; +import 'package:resonance_network_wallet/v2/components/proposal_list_tile.dart'; class ProposalRow extends ConsumerWidget { final MultisigProposal proposal; diff --git a/mobile-app/lib/v2/screens/pos/pos_amount_screen.dart b/mobile-app/lib/v2/screens/pos/pos_amount_screen.dart index 5aa5c780d..ae40b4b10 100644 --- a/mobile-app/lib/v2/screens/pos/pos_amount_screen.dart +++ b/mobile-app/lib/v2/screens/pos/pos_amount_screen.dart @@ -8,13 +8,7 @@ import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/currency_display_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; import 'package:resonance_network_wallet/shared/utils/amount_input_logic.dart'; -import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_icon_button.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/pos/pos_qr_screen.dart'; class PosAmountScreen extends ConsumerStatefulWidget { diff --git a/mobile-app/lib/v2/screens/pos/pos_qr_screen.dart b/mobile-app/lib/v2/screens/pos/pos_qr_screen.dart index b7e41bb76..87b373d1b 100644 --- a/mobile-app/lib/v2/screens/pos/pos_qr_screen.dart +++ b/mobile-app/lib/v2/screens/pos/pos_qr_screen.dart @@ -13,16 +13,9 @@ import 'package:resonance_network_wallet/services/pending_transaction_polling_se import 'package:resonance_network_wallet/services/pos_service.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; import 'package:resonance_network_wallet/shared/utils/url_utils.dart'; -import 'package:quantus_sdk/src/ui/components/explorer_link.dart'; -import 'package:quantus_sdk/src/ui/components/loader.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_icon_button.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_qr.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; import 'package:resonance_network_wallet/services/tx_watch_service.dart'; +import 'package:resonance_network_wallet/v2/components/explorer_link.dart'; import 'package:resonance_network_wallet/v2/screens/pos/pos_amount_screen.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; class PosQrScreen extends ConsumerStatefulWidget { final BigInt amountToken; diff --git a/mobile-app/lib/v2/screens/receive/receive_screen.dart b/mobile-app/lib/v2/screens/receive/receive_screen.dart index a264366b0..fe23897c9 100644 --- a/mobile-app/lib/v2/screens/receive/receive_screen.dart +++ b/mobile-app/lib/v2/screens/receive/receive_screen.dart @@ -2,23 +2,15 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart' hide AddressDetailsCard; +import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; -import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; -import 'package:resonance_network_wallet/v2/components/address_details_card.dart'; -import 'package:quantus_sdk/src/ui/components/loader.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_qr.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; -import 'package:quantus_sdk/src/ui/components/share_account_button.dart'; import 'package:resonance_network_wallet/shared/extensions/clipboard_extensions.dart'; +import 'package:resonance_network_wallet/v2/components/address_details_card.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; import 'package:resonance_network_wallet/shared/utils/share_utils.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/segmented_controls.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; +import 'package:resonance_network_wallet/v2/components/share_account_button.dart'; enum ReceiveTab { qrCode, address } diff --git a/mobile-app/lib/v2/screens/send/encrypted_send_progress_screen.dart b/mobile-app/lib/v2/screens/send/encrypted_send_progress_screen.dart index 3a137f271..6b6181b1f 100644 --- a/mobile-app/lib/v2/screens/send/encrypted_send_progress_screen.dart +++ b/mobile-app/lib/v2/screens/send/encrypted_send_progress_screen.dart @@ -1,4 +1,3 @@ - import 'dart:async'; import 'package:flutter/material.dart'; @@ -8,12 +7,7 @@ import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/encrypted_send_provider.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; -import 'package:quantus_sdk/src/ui/components/back_button.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; -import 'package:quantus_sdk/src/ui/components/wormhole_progress_steps.dart'; +import 'package:resonance_network_wallet/v2/components/wormhole_progress_steps.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_strategy.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_terminal_screen.dart'; diff --git a/mobile-app/lib/v2/screens/send/encrypted_send_strategy.dart b/mobile-app/lib/v2/screens/send/encrypted_send_strategy.dart index d5f8d408d..12449c72b 100644 --- a/mobile-app/lib/v2/screens/send/encrypted_send_strategy.dart +++ b/mobile-app/lib/v2/screens/send/encrypted_send_strategy.dart @@ -6,7 +6,6 @@ import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; import 'package:resonance_network_wallet/services/local_auth_service.dart'; -import 'package:quantus_sdk/src/ui/components/detail_summary_row.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_strategy.dart'; /// ZK-private transfer from an encrypted (wormhole) account. Coin selection diff --git a/mobile-app/lib/v2/screens/send/input_amount_screen.dart b/mobile-app/lib/v2/screens/send/input_amount_screen.dart index 95cdcfd95..92b57ed92 100644 --- a/mobile-app/lib/v2/screens/send/input_amount_screen.dart +++ b/mobile-app/lib/v2/screens/send/input_amount_screen.dart @@ -9,19 +9,12 @@ import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/currency_display_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; import 'package:resonance_network_wallet/shared/constants/e2e_keys.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/send/review_send_screen.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_screen_logic.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_strategy.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; -import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/amount_input_logic.dart'; import 'package:resonance_network_wallet/shared/utils/debouncer.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; -import 'package:quantus_sdk/src/ui/components/loader.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_icon_button.dart'; class InputAmountScreen extends ConsumerStatefulWidget { final SendStrategy strategy; diff --git a/mobile-app/lib/v2/screens/send/keystone_reject_screen.dart b/mobile-app/lib/v2/screens/send/keystone_reject_screen.dart index 4d9c23eae..db7345145 100644 --- a/mobile-app/lib/v2/screens/send/keystone_reject_screen.dart +++ b/mobile-app/lib/v2/screens/send/keystone_reject_screen.dart @@ -2,10 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_signing_widgets.dart'; import 'package:url_launcher/url_launcher.dart'; diff --git a/mobile-app/lib/v2/screens/send/keystone_sign_screen.dart b/mobile-app/lib/v2/screens/send/keystone_sign_screen.dart index 68ae5a326..40f6c078c 100644 --- a/mobile-app/lib/v2/screens/send/keystone_sign_screen.dart +++ b/mobile-app/lib/v2/screens/send/keystone_sign_screen.dart @@ -7,12 +7,6 @@ import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/services/telemetry_service.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; -import 'package:quantus_sdk/src/ui/components/animated_ur_qr.dart'; -import 'package:quantus_sdk/src/ui/components/loader.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_sign_cache.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_signing_session.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_signing_widgets.dart'; diff --git a/mobile-app/lib/v2/screens/send/keystone_signature_scan_screen.dart b/mobile-app/lib/v2/screens/send/keystone_signature_scan_screen.dart index e051e9911..1768610e6 100644 --- a/mobile-app/lib/v2/screens/send/keystone_signature_scan_screen.dart +++ b/mobile-app/lib/v2/screens/send/keystone_signature_scan_screen.dart @@ -4,7 +4,7 @@ import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/services/telemetry_service.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; -import 'package:quantus_sdk/src/ui/components/animated_qr_scanner.dart'; +import 'package:resonance_network_wallet/v2/components/animated_qr_scanner.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_sign_cache.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_signing_session.dart'; diff --git a/mobile-app/lib/v2/screens/send/keystone_verify_screen.dart b/mobile-app/lib/v2/screens/send/keystone_verify_screen.dart index fe98b7989..66b031709 100644 --- a/mobile-app/lib/v2/screens/send/keystone_verify_screen.dart +++ b/mobile-app/lib/v2/screens/send/keystone_verify_screen.dart @@ -3,11 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; -import 'package:quantus_sdk/src/ui/components/address_checkphrase_with_initial.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; +import 'package:resonance_network_wallet/v2/components/address_checkphrase_with_initial.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_reject_screen.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_signature_scan_screen.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_signing_session.dart'; diff --git a/mobile-app/lib/v2/screens/send/multisig_propose_strategy.dart b/mobile-app/lib/v2/screens/send/multisig_propose_strategy.dart index 16ca38ca5..3e08ba4a2 100644 --- a/mobile-app/lib/v2/screens/send/multisig_propose_strategy.dart +++ b/mobile-app/lib/v2/screens/send/multisig_propose_strategy.dart @@ -12,8 +12,7 @@ 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/shared/utils/print.dart'; -import 'package:quantus_sdk/src/ui/components/detail_summary_row.dart'; -import 'package:quantus_sdk/src/ui/components/multisig_expiry_value.dart'; +import 'package:resonance_network_wallet/v2/components/multisig_expiry_value.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_strategy.dart'; /// Proposes a transfer from a multisig account. The multisig is a view-only diff --git a/mobile-app/lib/v2/screens/send/regular_send_strategy.dart b/mobile-app/lib/v2/screens/send/regular_send_strategy.dart index 2fc073397..f70fe88db 100644 --- a/mobile-app/lib/v2/screens/send/regular_send_strategy.dart +++ b/mobile-app/lib/v2/screens/send/regular_send_strategy.dart @@ -11,7 +11,6 @@ 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/shared/utils/print.dart'; import 'package:resonance_network_wallet/shared/utils/url_utils.dart'; -import 'package:quantus_sdk/src/ui/components/detail_summary_row.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_sign_cache.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_signing_session.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_providers.dart'; diff --git a/mobile-app/lib/v2/screens/send/review_send_screen.dart b/mobile-app/lib/v2/screens/send/review_send_screen.dart index 8c4fbad79..97028cd59 100644 --- a/mobile-app/lib/v2/screens/send/review_send_screen.dart +++ b/mobile-app/lib/v2/screens/send/review_send_screen.dart @@ -9,13 +9,9 @@ import 'package:resonance_network_wallet/providers/currency_display_provider.dar import 'package:resonance_network_wallet/shared/constants/e2e_keys.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; import 'package:resonance_network_wallet/shared/utils/url_utils.dart'; -import 'package:quantus_sdk/src/ui/components/address_checkphrase_with_initial.dart'; -import 'package:quantus_sdk/src/ui/components/amount_display_with_conversion.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; -import 'package:quantus_sdk/src/ui/components/split_card.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; +import 'package:resonance_network_wallet/v2/components/address_checkphrase_with_initial.dart'; +import 'package:resonance_network_wallet/v2/components/amount_display_with_conversion.dart'; +import 'package:resonance_network_wallet/v2/components/split_card.dart'; import 'package:resonance_network_wallet/v2/screens/send/encrypted_send_progress_screen.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_sign_screen.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_strategy.dart'; diff --git a/mobile-app/lib/v2/screens/send/select_recipient_screen.dart b/mobile-app/lib/v2/screens/send/select_recipient_screen.dart index 6b1258b8f..396da0b86 100644 --- a/mobile-app/lib/v2/screens/send/select_recipient_screen.dart +++ b/mobile-app/lib/v2/screens/send/select_recipient_screen.dart @@ -2,25 +2,19 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:resonance_network_wallet/features/components/dotted_border.dart'; -import 'package:resonance_network_wallet/features/components/skeleton.dart'; +import 'package:resonance_network_wallet/v2/components/dotted_border.dart'; +import 'package:resonance_network_wallet/v2/components/skeleton.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.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/routes.dart'; import 'package:resonance_network_wallet/shared/constants/e2e_keys.dart'; -import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; -import 'package:quantus_sdk/src/ui/components/address_checkphrase_with_initial.dart'; -import 'package:quantus_sdk/src/ui/components/address_input_field.dart'; -import 'package:quantus_sdk/src/ui/components/loader.dart'; -import 'package:quantus_sdk/src/ui/components/private_activity_notice.dart'; -import 'package:quantus_sdk/src/ui/components/qr_scanner_page.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; +import 'package:resonance_network_wallet/v2/components/address_checkphrase_with_initial.dart'; +import 'package:resonance_network_wallet/v2/components/address_input_field.dart'; +import 'package:resonance_network_wallet/v2/components/private_activity_notice.dart'; +import 'package:resonance_network_wallet/v2/components/qr_scanner_page.dart'; import 'package:resonance_network_wallet/v2/screens/send/input_amount_screen.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_strategy.dart'; diff --git a/mobile-app/lib/v2/screens/send/send_terminal_screen.dart b/mobile-app/lib/v2/screens/send/send_terminal_screen.dart index 56957d2ef..e6352bec0 100644 --- a/mobile-app/lib/v2/screens/send/send_terminal_screen.dart +++ b/mobile-app/lib/v2/screens/send/send_terminal_screen.dart @@ -1,15 +1,9 @@ - import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/shared/constants/e2e_keys.dart'; -import 'package:quantus_sdk/src/ui/components/back_button.dart'; -import 'package:quantus_sdk/src/ui/components/explorer_link.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; +import 'package:resonance_network_wallet/v2/components/explorer_link.dart'; import 'package:resonance_network_wallet/v2/screens/home/home_screen.dart'; import 'package:resonance_network_wallet/v2/screens/send/send_strategy.dart'; diff --git a/mobile-app/lib/v2/screens/settings/about_quantus_screen.dart b/mobile-app/lib/v2/screens/settings/about_quantus_screen.dart index 37b179236..24a033a4a 100644 --- a/mobile-app/lib/v2/screens/settings/about_quantus_screen.dart +++ b/mobile-app/lib/v2/screens/settings/about_quantus_screen.dart @@ -5,8 +5,6 @@ import 'package:resonance_network_wallet/generated/version.g.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/shared/utils/open_external_url.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_divider.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_tappable_row.dart'; diff --git a/mobile-app/lib/v2/screens/settings/add_account_menu_screen.dart b/mobile-app/lib/v2/screens/settings/add_account_menu_screen.dart index 1054a5947..c574d5644 100644 --- a/mobile-app/lib/v2/screens/settings/add_account_menu_screen.dart +++ b/mobile-app/lib/v2/screens/settings/add_account_menu_screen.dart @@ -6,10 +6,6 @@ import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/multisig_providers.dart'; import 'package:resonance_network_wallet/providers/remote_config_provider.dart'; import 'package:resonance_network_wallet/shared/utils/account_utils.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/add_hardware_account_screen.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/create_account_screen.dart'; import 'package:resonance_network_wallet/v2/screens/import/import_wallet_screen.dart'; diff --git a/mobile-app/lib/v2/screens/settings/help_and_support_screen.dart b/mobile-app/lib/v2/screens/settings/help_and_support_screen.dart index dd9b765e4..66afa1759 100644 --- a/mobile-app/lib/v2/screens/settings/help_and_support_screen.dart +++ b/mobile-app/lib/v2/screens/settings/help_and_support_screen.dart @@ -3,8 +3,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/shared/utils/open_external_url.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_divider.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_tappable_row.dart'; diff --git a/mobile-app/lib/v2/screens/settings/mining_rewards_screen.dart b/mobile-app/lib/v2/screens/settings/mining_rewards_screen.dart index fb1390e3e..98d5049aa 100644 --- a/mobile-app/lib/v2/screens/settings/mining_rewards_screen.dart +++ b/mobile-app/lib/v2/screens/settings/mining_rewards_screen.dart @@ -1,18 +1,14 @@ 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/skeleton.dart'; +import 'package:resonance_network_wallet/v2/components/skeleton.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/mining_rewards_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; import 'package:resonance_network_wallet/services/mining_rewards_service.dart'; import 'package:resonance_network_wallet/shared/utils/open_external_url.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; -import 'package:quantus_sdk/src/ui/components/split_card.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; +import 'package:resonance_network_wallet/v2/components/split_card.dart'; import 'package:resonance_network_wallet/v2/screens/settings/redeem_address_screen.dart'; class MiningRewardsScreen extends ConsumerWidget { diff --git a/mobile-app/lib/v2/screens/settings/preferences_settings_screen.dart b/mobile-app/lib/v2/screens/settings/preferences_settings_screen.dart index ab80a7b4a..88778e17e 100644 --- a/mobile-app/lib/v2/screens/settings/preferences_settings_screen.dart +++ b/mobile-app/lib/v2/screens/settings/preferences_settings_screen.dart @@ -5,8 +5,6 @@ import 'package:resonance_network_wallet/providers/currency_display_provider.dar import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/notification_config_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/settings/currency_picker_screen.dart'; import 'package:resonance_network_wallet/v2/screens/settings/language_picker_screen.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_divider.dart'; diff --git a/mobile-app/lib/v2/screens/settings/recovery_phrase_confirmation_screen.dart b/mobile-app/lib/v2/screens/settings/recovery_phrase_confirmation_screen.dart index c88d18408..46d8205bd 100644 --- a/mobile-app/lib/v2/screens/settings/recovery_phrase_confirmation_screen.dart +++ b/mobile-app/lib/v2/screens/settings/recovery_phrase_confirmation_screen.dart @@ -1,10 +1,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.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/shared/constants/e2e_keys.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/settings_caution_scaffold.dart'; 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 76eacf6a7..f5a0040e0 100644 --- a/mobile-app/lib/v2/screens/settings/recovery_phrase_screen.dart +++ b/mobile-app/lib/v2/screens/settings/recovery_phrase_screen.dart @@ -4,7 +4,7 @@ import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; import 'package:resonance_network_wallet/shared/constants/e2e_keys.dart'; -import 'package:quantus_sdk/src/ui/components/recovery_phrase_body.dart'; +import 'package:resonance_network_wallet/v2/components/recovery_phrase_body.dart'; class RecoveryPhraseScreen extends ConsumerStatefulWidget { const RecoveryPhraseScreen({super.key, this.walletIndex = 0}); diff --git a/mobile-app/lib/v2/screens/settings/redeem_address_screen.dart b/mobile-app/lib/v2/screens/settings/redeem_address_screen.dart index 6a9afc63d..919a17790 100644 --- a/mobile-app/lib/v2/screens/settings/redeem_address_screen.dart +++ b/mobile-app/lib/v2/screens/settings/redeem_address_screen.dart @@ -4,12 +4,7 @@ import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; -import 'package:quantus_sdk/src/ui/components/address_input_field.dart'; -import 'package:quantus_sdk/src/ui/components/bottom_sheet_container.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; +import 'package:resonance_network_wallet/v2/components/address_input_field.dart'; import 'package:resonance_network_wallet/v2/screens/settings/redeem_progress_screen.dart'; /// Fullscreen flow to pick a destination address for redeeming mining diff --git a/mobile-app/lib/v2/screens/settings/redeem_progress_screen.dart b/mobile-app/lib/v2/screens/settings/redeem_progress_screen.dart index 5d0fce7bc..247a74116 100644 --- a/mobile-app/lib/v2/screens/settings/redeem_progress_screen.dart +++ b/mobile-app/lib/v2/screens/settings/redeem_progress_screen.dart @@ -6,11 +6,7 @@ import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/mining_rewards_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; -import 'package:quantus_sdk/src/ui/components/wormhole_progress_steps.dart'; +import 'package:resonance_network_wallet/v2/components/wormhole_progress_steps.dart'; class RedeemProgressScreen extends ConsumerStatefulWidget { final BigInt redeemableRewards; diff --git a/mobile-app/lib/v2/screens/settings/reset_confirmation_screen.dart b/mobile-app/lib/v2/screens/settings/reset_confirmation_screen.dart index 9ce29eb44..c29ef0a35 100644 --- a/mobile-app/lib/v2/screens/settings/reset_confirmation_screen.dart +++ b/mobile-app/lib/v2/screens/settings/reset_confirmation_screen.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/services/local_auth_service.dart'; import 'package:resonance_network_wallet/services/logout_service.dart'; -import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_caution_scaffold.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_divider.dart'; diff --git a/mobile-app/lib/v2/screens/settings/select_wallet_screen.dart b/mobile-app/lib/v2/screens/settings/select_wallet_screen.dart index e5a124048..a3b330b7f 100644 --- a/mobile-app/lib/v2/screens/settings/select_wallet_screen.dart +++ b/mobile-app/lib/v2/screens/settings/select_wallet_screen.dart @@ -5,9 +5,6 @@ import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; import 'package:resonance_network_wallet/shared/utils/account_utils.dart'; -import 'package:quantus_sdk/src/ui/components/loader.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/settings/recovery_phrase_confirmation_screen.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; diff --git a/mobile-app/lib/v2/screens/settings/settings_caution_scaffold.dart b/mobile-app/lib/v2/screens/settings/settings_caution_scaffold.dart index 255bd39a2..447f5e2fd 100644 --- a/mobile-app/lib/v2/screens/settings/settings_caution_scaffold.dart +++ b/mobile-app/lib/v2/screens/settings/settings_caution_scaffold.dart @@ -1,10 +1,6 @@ import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base_bottom_content.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_checkbox.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_divider.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_list_row.dart'; diff --git a/mobile-app/lib/v2/screens/settings/settings_picker_screen.dart b/mobile-app/lib/v2/screens/settings/settings_picker_screen.dart index e32497d13..83aec8fa2 100644 --- a/mobile-app/lib/v2/screens/settings/settings_picker_screen.dart +++ b/mobile-app/lib/v2/screens/settings/settings_picker_screen.dart @@ -1,9 +1,6 @@ import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_divider.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_picker_widgets.dart'; diff --git a/mobile-app/lib/v2/screens/settings/settings_screen.dart b/mobile-app/lib/v2/screens/settings/settings_screen.dart index 64aa0fc99..2eec97c57 100644 --- a/mobile-app/lib/v2/screens/settings/settings_screen.dart +++ b/mobile-app/lib/v2/screens/settings/settings_screen.dart @@ -8,8 +8,6 @@ import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/mining_rewards_provider.dart'; import 'package:resonance_network_wallet/shared/constants/e2e_keys.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/settings/about_quantus_screen.dart'; import 'package:resonance_network_wallet/v2/screens/settings/add_account_menu_screen.dart'; import 'package:resonance_network_wallet/v2/screens/settings/help_and_support_screen.dart'; diff --git a/mobile-app/lib/v2/screens/settings/testnet_rewards_screen.dart b/mobile-app/lib/v2/screens/settings/testnet_rewards_screen.dart index a1f79e3ca..be58abb3f 100644 --- a/mobile-app/lib/v2/screens/settings/testnet_rewards_screen.dart +++ b/mobile-app/lib/v2/screens/settings/testnet_rewards_screen.dart @@ -4,10 +4,7 @@ import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/mining_rewards_provider.dart'; import 'package:resonance_network_wallet/services/mining_rewards_service.dart'; -import 'package:quantus_sdk/src/ui/components/loader.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_divider.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; class TestnetRewardsScreen extends ConsumerWidget { diff --git a/mobile-app/lib/v2/screens/settings/wallet_settings_screen.dart b/mobile-app/lib/v2/screens/settings/wallet_settings_screen.dart index 47f52f5a6..6cdaf4002 100644 --- a/mobile-app/lib/v2/screens/settings/wallet_settings_screen.dart +++ b/mobile-app/lib/v2/screens/settings/wallet_settings_screen.dart @@ -4,10 +4,7 @@ import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/shared/constants/e2e_keys.dart'; -import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/account_utils.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; import 'package:resonance_network_wallet/v2/screens/settings/recovery_phrase_confirmation_screen.dart'; import 'package:resonance_network_wallet/v2/screens/settings/reset_confirmation_screen.dart'; import 'package:resonance_network_wallet/v2/screens/settings/select_wallet_screen.dart'; diff --git a/mobile-app/lib/v2/screens/swap/deposit_screen.dart b/mobile-app/lib/v2/screens/swap/deposit_screen.dart index 12d700241..95f366348 100644 --- a/mobile-app/lib/v2/screens/swap/deposit_screen.dart +++ b/mobile-app/lib/v2/screens/swap/deposit_screen.dart @@ -5,12 +5,8 @@ import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/shared/extensions/clipboard_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/share_utils.dart'; -import 'package:quantus_sdk/src/ui/components/loader.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/token_icon.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; -import 'package:quantus_sdk/src/ui/components/success_check.dart'; +import 'package:resonance_network_wallet/v2/components/success_check.dart'; +import 'package:resonance_network_wallet/v2/components/token_icon.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; diff --git a/mobile-app/lib/v2/screens/swap/refund_address_picker_sheet.dart b/mobile-app/lib/v2/screens/swap/refund_address_picker_sheet.dart index 36fa4e7e6..295e780c8 100644 --- a/mobile-app/lib/v2/screens/swap/refund_address_picker_sheet.dart +++ b/mobile-app/lib/v2/screens/swap/refund_address_picker_sheet.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; -import 'package:quantus_sdk/src/ui/components/bottom_sheet_container.dart'; Future showRefundAddressPickerSheet(BuildContext context, String network) { return BottomSheetContainer.show(context, builder: (_) => _RefundAddressPickerContent(network: network)); diff --git a/mobile-app/lib/v2/screens/swap/review_quote_sheet.dart b/mobile-app/lib/v2/screens/swap/review_quote_sheet.dart index bc3a32470..eceedd874 100644 --- a/mobile-app/lib/v2/screens/swap/review_quote_sheet.dart +++ b/mobile-app/lib/v2/screens/swap/review_quote_sheet.dart @@ -2,9 +2,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/providers/l10n_provider.dart'; -import 'package:quantus_sdk/src/ui/components/bottom_sheet_container.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/token_icon.dart'; +import 'package:resonance_network_wallet/v2/components/token_icon.dart'; import 'package:resonance_network_wallet/v2/screens/swap/deposit_screen.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; diff --git a/mobile-app/lib/v2/screens/swap/swap_screen.dart b/mobile-app/lib/v2/screens/swap/swap_screen.dart index 6eb756d3f..3f392c419 100644 --- a/mobile-app/lib/v2/screens/swap/swap_screen.dart +++ b/mobile-app/lib/v2/screens/swap/swap_screen.dart @@ -3,13 +3,10 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/qr_scanner_page.dart'; +import 'package:resonance_network_wallet/v2/components/qr_scanner_page.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; -import 'package:quantus_sdk/src/ui/components/token_icon.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; -import 'package:quantus_sdk/src/ui/components/v2_app_bar.dart'; +import 'package:resonance_network_wallet/v2/components/token_icon.dart'; import 'package:resonance_network_wallet/v2/screens/swap/refund_address_picker_sheet.dart'; import 'package:resonance_network_wallet/v2/screens/swap/review_quote_sheet.dart'; import 'package:resonance_network_wallet/v2/screens/swap/token_picker_sheet.dart'; @@ -198,7 +195,7 @@ class _SwapScreenState extends ConsumerState { variant: ButtonVariant.glass, onTap: _pickToken, padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), - borderRadius: 8, + borderRadius: BorderRadius.circular(8), child: Row( children: [ TokenIcon(token: _fromToken, size: 25, networkBadgeSize: 10), @@ -316,7 +313,7 @@ class _SwapScreenState extends ConsumerState { onTap: onTap, variant: ButtonVariant.glass, padding: EdgeInsets.zero, - borderRadius: 8, + borderRadius: BorderRadius.circular(8), child: Center( child: SvgPicture.asset( iconAsset, @@ -361,7 +358,7 @@ class _SwapScreenState extends ConsumerState { variant: ButtonVariant.glass, onTap: () {}, padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12), - borderRadius: 8, + borderRadius: BorderRadius.circular(8), child: Row( mainAxisSize: MainAxisSize.min, children: [ diff --git a/mobile-app/lib/v2/screens/swap/token_picker_sheet.dart b/mobile-app/lib/v2/screens/swap/token_picker_sheet.dart index caaceb95f..57e36083b 100644 --- a/mobile-app/lib/v2/screens/swap/token_picker_sheet.dart +++ b/mobile-app/lib/v2/screens/swap/token_picker_sheet.dart @@ -2,9 +2,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/providers/l10n_provider.dart'; -import 'package:quantus_sdk/src/ui/components/bottom_sheet_container.dart'; -import 'package:quantus_sdk/src/ui/components/loader.dart'; -import 'package:quantus_sdk/src/ui/components/token_icon.dart'; +import 'package:resonance_network_wallet/v2/components/token_icon.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; diff --git a/mobile-app/lib/v2/screens/welcome/welcome_screen.dart b/mobile-app/lib/v2/screens/welcome/welcome_screen.dart index de0a17279..74e9073fa 100644 --- a/mobile-app/lib/v2/screens/welcome/welcome_screen.dart +++ b/mobile-app/lib/v2/screens/welcome/welcome_screen.dart @@ -1,4 +1,3 @@ - import 'dart:async'; import 'package:flutter/material.dart'; @@ -10,9 +9,6 @@ import 'package:resonance_network_wallet/providers/wallet_providers.dart'; import 'package:resonance_network_wallet/services/firebase_messaging_service.dart'; import 'package:resonance_network_wallet/services/wallet_creation_service.dart'; import 'package:resonance_network_wallet/shared/constants/e2e_keys.dart'; -import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/account_ready_screen.dart'; import 'package:resonance_network_wallet/v2/screens/import/import_wallet_screen.dart'; import 'package:resonance_network_wallet/v2/screens/welcome/onboarding_background.dart'; diff --git a/mobile-app/lib/wallet_initializer.dart b/mobile-app/lib/wallet_initializer.dart index dce33aa26..a159ef980 100644 --- a/mobile-app/lib/wallet_initializer.dart +++ b/mobile-app/lib/wallet_initializer.dart @@ -1,13 +1,9 @@ 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/migration_dialog.dart'; +import 'package:resonance_network_wallet/v2/components/migration_dialog.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; -import 'package:resonance_network_wallet/shared/extensions/toaster_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; -import 'package:quantus_sdk/src/ui/components/bottom_sheet_container.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; -import 'package:quantus_sdk/src/ui/components/scaffold_base.dart'; import 'package:resonance_network_wallet/v2/screens/home/home_screen.dart'; import 'package:resonance_network_wallet/v2/screens/welcome/welcome_screen.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; diff --git a/mobile-app/pubspec.yaml b/mobile-app/pubspec.yaml index 79436b8c0..7904f41fb 100644 --- a/mobile-app/pubspec.yaml +++ b/mobile-app/pubspec.yaml @@ -94,7 +94,6 @@ flutter: - assets/v2/uppercase_q.svg - assets/v2/uppercase_q.png - assets/v2/axe.svg - - assets/v2/uppercase_q_black_bg.png - assets/v2/swap_arrows_down_up.svg - assets/v2/swap_clock_counter_clockwise.svg - assets/v2/swap_qr_code.svg diff --git a/mobile-app/assets/v2/uppercase_q_black_bg.png b/quantus_sdk/assets/v2/uppercase_q_black_bg.png similarity index 100% rename from mobile-app/assets/v2/uppercase_q_black_bg.png rename to quantus_sdk/assets/v2/uppercase_q_black_bg.png diff --git a/quantus_sdk/lib/quantus_sdk.dart b/quantus_sdk/lib/quantus_sdk.dart index 9a57c6c0a..12450b928 100644 --- a/quantus_sdk/lib/quantus_sdk.dart +++ b/quantus_sdk/lib/quantus_sdk.dart @@ -16,6 +16,7 @@ export 'src/extensions/decimal_input_filter.dart'; export 'src/extensions/keypair_extensions.dart'; export 'src/extensions/media_query_data_extension.dart'; export 'src/extensions/string_extensions.dart'; +export 'src/extensions/toaster_extensions.dart'; // UI-related exports export 'src/ui/index.dart'; export 'src/models/account.dart'; @@ -49,7 +50,6 @@ export 'src/models/raid_stats.dart'; export 'src/rust/api/crypto.dart' hide crystalAlice, crystalCharlie, crystalBob; export 'src/rust/api/ur.dart'; export 'src/utils/ur_qr.dart'; -export 'src/utils/account_utils.dart'; export 'src/rust/api/wormhole.dart'; export 'src/services/account_discovery_service.dart'; export 'src/services/accounts_service.dart'; diff --git a/mobile-app/lib/shared/extensions/toaster_extensions.dart b/quantus_sdk/lib/src/extensions/toaster_extensions.dart similarity index 100% rename from mobile-app/lib/shared/extensions/toaster_extensions.dart rename to quantus_sdk/lib/src/extensions/toaster_extensions.dart diff --git a/quantus_sdk/lib/src/ui/components/address_details_card.dart b/quantus_sdk/lib/src/ui/components/address_details_card.dart deleted file mode 100644 index 591fdca98..000000000 --- a/quantus_sdk/lib/src/ui/components/address_details_card.dart +++ /dev/null @@ -1,157 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/material.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; - -import 'split_card.dart'; - -/// Presentational address + checkphrase card. Copy side effects and copy live in the host app. -class AddressDetailsCard extends StatefulWidget { - final String accountId; - final String? checksum; - final String addressLabel; - final String checkphraseLabel; - final String checksumPlaceholder; - final VoidCallback onCopyAddress; - final VoidCallback onCopyChecksum; - - const AddressDetailsCard({ - super.key, - required this.accountId, - this.checksum, - required this.addressLabel, - required this.checkphraseLabel, - required this.checksumPlaceholder, - required this.onCopyAddress, - required this.onCopyChecksum, - }); - - @override - State createState() => _AddressDetailsCardState(); -} - -class _AddressDetailsCardState extends State { - bool _addressCopied = false; - bool _checksumCopied = false; - Timer? _resetTimer; - - void _copyAddress() { - widget.onCopyAddress(); - _triggerCopied(isAddress: true); - } - - void _copyChecksum() { - if (widget.checksum == null) return; - - widget.onCopyChecksum(); - _triggerCopied(isAddress: false); - } - - void _triggerCopied({required bool isAddress}) { - _resetTimer?.cancel(); - - setState(() { - if (isAddress) { - _addressCopied = true; - _checksumCopied = false; - } else { - _checksumCopied = true; - _addressCopied = false; - } - }); - - _resetTimer = Timer(const Duration(seconds: 2), () { - if (mounted) { - setState(() { - if (isAddress) { - _addressCopied = false; - } else { - _checksumCopied = false; - } - }); - } - }); - } - - @override - void dispose() { - _resetTimer?.cancel(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return SplitCard( - topChild: InkWell( - onTap: _copyAddress, - child: _buildItem(context, widget.addressLabel, widget.accountId, isCopied: _addressCopied), - ), - bottomChild: InkWell( - onTap: widget.checksum == null ? null : _copyChecksum, - child: _buildItem( - context, - widget.checkphraseLabel, - widget.checksum ?? widget.checksumPlaceholder, - isCheckphrase: true, - isCopied: _checksumCopied, - ), - ), - ); - } - - Widget _buildItem( - BuildContext context, - String label, - String value, { - bool isCheckphrase = false, - required bool isCopied, - }) { - final valueTextStyle = isCheckphrase - ? context.themeText.smallParagraph?.copyWith(color: context.colors.checksum) - : context.themeText.smallParagraph?.copyWith(fontFamily: AppTextTheme.fontFamilySecondary); - - return Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(label, style: context.themeText.receiveLabel?.copyWith(color: context.colors.textLabel)), - const SizedBox(height: 16), - Text(value, style: valueTextStyle), - ], - ), - ), - const SizedBox(width: 32), - _copyButton(isCopied: isCopied), - ], - ); - } - - Widget _copyButton({required bool isCopied}) { - const containerSize = 40.0; - const iconSize = 16.0; - - return AnimatedContainer( - duration: const Duration(milliseconds: 200), - width: containerSize, - height: containerSize, - decoration: BoxDecoration( - color: isCopied ? context.colors.copyButtonCopiedBg : Colors.transparent, - border: Border.all( - color: isCopied ? context.colors.copyButtonCopiedBorder : context.colors.borderButton, - width: 1, - ), - borderRadius: BorderRadius.circular(containerSize / 2), - ), - child: Center( - child: Icon( - isCopied ? Icons.check : Icons.copy, - size: iconSize, - color: isCopied ? context.colors.success : context.colors.textPrimary, - ), - ), - ); - } -} diff --git a/quantus_sdk/lib/src/ui/components/confirm_action_sheet.dart b/quantus_sdk/lib/src/ui/components/confirm_action_sheet.dart index f2beb0e79..26a8a1633 100644 --- a/quantus_sdk/lib/src/ui/components/confirm_action_sheet.dart +++ b/quantus_sdk/lib/src/ui/components/confirm_action_sheet.dart @@ -1,7 +1,5 @@ import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:quantus_sdk/src/ui/components/bottom_sheet_container.dart'; -import 'package:quantus_sdk/src/ui/components/quantus_button.dart'; /// Generic "are you sure?" confirmation sheet. Resolves to true when the user /// taps the confirm action, false on cancel/dismiss. diff --git a/quantus_sdk/lib/src/ui/components/decoded_call_view.dart b/quantus_sdk/lib/src/ui/components/decoded_call_view.dart index dd80ea46d..cc47ddee3 100644 --- a/quantus_sdk/lib/src/ui/components/decoded_call_view.dart +++ b/quantus_sdk/lib/src/ui/components/decoded_call_view.dart @@ -1,8 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:resonance_network_wallet/providers/currency_display_provider.dart'; -import 'package:quantus_sdk/src/ui/components/detail_summary_row.dart'; /// Renders every parameter of a [DecodedCall], nested calls included. /// @@ -10,16 +7,19 @@ import 'package:quantus_sdk/src/ui/components/detail_summary_row.dart'; /// upgrade authorisations and batches all arrive through the same pallet — so a /// transfer-shaped layout silently misreports them. This shows the call the /// runtime actually declared, with each of its parameters. -class DecodedCallView extends ConsumerWidget { +class DecodedCallView extends StatelessWidget { final DecodedCall call; /// Nesting depth; nested calls indent and drop a level of visual weight. final int depth; - const DecodedCallView({super.key, required this.call, this.depth = 0}); + /// Formats a native token amount for the current locale and currency display. + final String Function(BigInt token) amountText; + + const DecodedCallView({super.key, required this.call, required this.amountText, this.depth = 0}); @override - Widget build(BuildContext context, WidgetRef ref) { + Widget build(BuildContext context) { final colors = context.colors; final text = context.themeText; @@ -35,12 +35,12 @@ class DecodedCallView extends ConsumerWidget { ), ), const SizedBox(height: 4), - for (final field in call.fields) _field(context, ref, field), + for (final field in call.fields) _field(context, field), ], ); } - Widget _field(BuildContext context, WidgetRef ref, CallField field) { + Widget _field(BuildContext context, CallField field) { final colors = context.colors; final text = context.themeText; @@ -62,9 +62,7 @@ class DecodedCallView extends ConsumerWidget { ); case AmountField(:final label, :final token, :final assetId, :final note): - final value = assetId == null - ? ref.watch(txAmountDisplayProvider)(token, isSend: true).primaryAmount - : '$token (asset #$assetId, raw units)'; + final value = assetId == null ? amountText(token) : '$token (asset #$assetId, raw units)'; return Padding( padding: const EdgeInsets.only(top: 6), child: Column( @@ -91,7 +89,7 @@ class DecodedCallView extends ConsumerWidget { padding: const EdgeInsets.only(left: 12), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, - children: [for (final item in items) _field(context, ref, item)], + children: [for (final item in items) _field(context, item)], ), ), ], @@ -113,7 +111,7 @@ class DecodedCallView extends ConsumerWidget { borderRadius: BorderRadius.circular(8), border: Border.all(color: colors.borderButton.useOpacity(0.4)), ), - child: DecodedCallView(call: call, depth: depth + 1), + child: DecodedCallView(call: call, depth: depth + 1, amountText: amountText), ), if (note != null) Padding( diff --git a/quantus_sdk/lib/src/ui/components/index.dart b/quantus_sdk/lib/src/ui/components/index.dart index d7add23e3..59e05a7f5 100644 --- a/quantus_sdk/lib/src/ui/components/index.dart +++ b/quantus_sdk/lib/src/ui/components/index.dart @@ -2,4 +2,16 @@ export 'quantus_button.dart'; export 'loader.dart'; export 'quantus_icon_button.dart'; export 'glass_button_base.dart'; -export 'address_details_card.dart'; +export 'decoded_call_view.dart'; +export 'v2_app_bar.dart'; +export 'bottom_sheet_container.dart'; +export 'scaffold_base.dart'; +export 'scaffold_base_bottom_content.dart'; +export 'menu_divider.dart'; +export 'confirm_action_sheet.dart'; +export 'base_background.dart'; +export 'detail_summary_row.dart'; +export 'quantus_qr.dart'; +export 'segmented_controls.dart'; +export 'back_button.dart'; +export 'animated_ur_qr.dart'; diff --git a/quantus_sdk/lib/src/ui/components/quantus_qr.dart b/quantus_sdk/lib/src/ui/components/quantus_qr.dart index 97a23e78f..69e82c2a0 100644 --- a/quantus_sdk/lib/src/ui/components/quantus_qr.dart +++ b/quantus_sdk/lib/src/ui/components/quantus_qr.dart @@ -22,7 +22,7 @@ class QuantusQr extends StatelessWidget { child: QrImageView( data: accountId, errorCorrectionLevel: QrErrorCorrectLevel.M, - embeddedImage: const AssetImage('assets/v2/uppercase_q_black_bg.png'), + embeddedImage: const AssetImage('assets/v2/uppercase_q_black_bg.png', package: 'quantus_sdk'), embeddedImageStyle: QrEmbeddedImageStyle(size: Size(qrLogoSize, qrLogoSize)), version: QrVersions.auto, size: qrSize, diff --git a/quantus_sdk/lib/src/ui/components/scaffold_base.dart b/quantus_sdk/lib/src/ui/components/scaffold_base.dart index f6f6d1c59..71dc8d635 100644 --- a/quantus_sdk/lib/src/ui/components/scaffold_base.dart +++ b/quantus_sdk/lib/src/ui/components/scaffold_base.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:resonance_network_wallet/features/components/network_status_banner.dart'; import 'package:quantus_sdk/src/ui/components/base_background.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; @@ -8,6 +7,7 @@ class ScaffoldBase extends StatelessWidget { final Widget? bottomContent; final List? slivers; final Widget? appBar; + final Widget? networkBanner; final ScrollController? scrollController; final ScrollPhysics? scrollPhysics; final RefreshCallback? onRefresh; @@ -20,6 +20,7 @@ class ScaffoldBase extends StatelessWidget { const ScaffoldBase({ super.key, this.appBar, + this.networkBanner, this.padding = defaultPadding, this.backgroundWidget, this.bottomContent, @@ -33,6 +34,7 @@ class ScaffoldBase extends StatelessWidget { const ScaffoldBase.refreshable({ super.key, this.appBar, + this.networkBanner, this.padding = defaultPadding, this.backgroundWidget, this.scrollController, @@ -48,7 +50,7 @@ class ScaffoldBase extends StatelessWidget { Widget bodyContent = Column( children: [ - const NetworkStatusBanner(), + ?networkBanner, if (appBar != null) Padding(padding: padding, child: appBar!), Expanded(child: _buildChild(colors)), ], diff --git a/quantus_sdk/pubspec.yaml b/quantus_sdk/pubspec.yaml index 82b58550a..4d534719c 100644 --- a/quantus_sdk/pubspec.yaml +++ b/quantus_sdk/pubspec.yaml @@ -60,3 +60,7 @@ polkadart: output_dir: lib/generated chains: planck: wss://a1-planck.quantus.cat + +flutter: + assets: + - assets/v2/uppercase_q_black_bg.png From e8688c9581925eba269001a8d0883f6780ba4063 Mon Sep 17 00:00:00 2001 From: Beast Date: Sat, 15 Aug 2026 09:32:49 +0700 Subject: [PATCH 05/38] fix: component import --- mobile-app/lib/v2/screens/home/home_screen.dart | 2 +- mobile-app/test/unit/shared_address_action_sheet_test.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mobile-app/lib/v2/screens/home/home_screen.dart b/mobile-app/lib/v2/screens/home/home_screen.dart index f4809976e..553eb9af3 100644 --- a/mobile-app/lib/v2/screens/home/home_screen.dart +++ b/mobile-app/lib/v2/screens/home/home_screen.dart @@ -6,7 +6,7 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/v2/components/dotted_border.dart'; import 'package:resonance_network_wallet/v2/components/skeleton.dart'; -import 'package:resonance_network_wallet/features/components/shared_address_action_sheet.dart'; +import 'package:resonance_network_wallet/v2/components/shared_address_action_sheet.dart'; import 'package:resonance_network_wallet/services/global_history_polling_service.dart'; import 'package:resonance_network_wallet/services/telemetry_service.dart'; import 'package:resonance_network_wallet/shared/constants/e2e_keys.dart'; diff --git a/mobile-app/test/unit/shared_address_action_sheet_test.dart b/mobile-app/test/unit/shared_address_action_sheet_test.dart index 98bade313..e74ca5b08 100644 --- a/mobile-app/test/unit/shared_address_action_sheet_test.dart +++ b/mobile-app/test/unit/shared_address_action_sheet_test.dart @@ -3,7 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:flutter_riverpod/misc.dart'; -import 'package:resonance_network_wallet/features/components/shared_address_action_sheet.dart'; +import 'package:resonance_network_wallet/v2/components/shared_address_action_sheet.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; import 'package:resonance_network_wallet/v2/screens/send/input_amount_screen.dart'; import 'package:shared_preferences/shared_preferences.dart'; From 00ee20bac89c6d4252a6f3f91905b3271080bf90 Mon Sep 17 00:00:00 2001 From: Beast Date: Tue, 18 Aug 2026 12:16:35 +0800 Subject: [PATCH 06/38] feat: add new text field component --- cold-wallet-app/lib/theme/app_theme.dart | 12 +- mobile-app/lib/v2/components/name_field.dart | 73 +------- quantus_sdk/lib/src/ui/components/index.dart | 1 + .../src/ui/components/quantus_text_field.dart | 169 ++++++++++++++++++ .../test/ui/quantus_text_field_test.dart | 69 +++++++ 5 files changed, 258 insertions(+), 66 deletions(-) create mode 100644 quantus_sdk/lib/src/ui/components/quantus_text_field.dart create mode 100644 quantus_sdk/test/ui/quantus_text_field_test.dart diff --git a/cold-wallet-app/lib/theme/app_theme.dart b/cold-wallet-app/lib/theme/app_theme.dart index 1977373ef..f6e9b07b6 100644 --- a/cold-wallet-app/lib/theme/app_theme.dart +++ b/cold-wallet-app/lib/theme/app_theme.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' show AppColorsV3, AppRadiusV3, AppTextThemeV3, ColorOpacityExtension; import 'package:quantus_cold_wallet/shared/context_extensions.dart'; import 'package:quantus_cold_wallet/theme/app_colors.dart'; import 'package:quantus_cold_wallet/theme/app_spacing.dart'; @@ -10,6 +10,7 @@ class AppTheme { final isTablet = context.isTablet; final colors = const AppColorsV2.dark(); final text = isTablet ? const AppTextTheme.iPad() : const AppTextTheme.defaultTheme(); + const radius = AppRadiusV3.standard(); return ThemeData( scaffoldBackgroundColor: colors.background, @@ -41,7 +42,14 @@ class AppTheme { filled: true, fillColor: Colors.transparent, ), - extensions: [colors, text, isTablet ? const AppSizeTheme.iPad() : const AppSizeTheme.defaultTheme()], + extensions: [ + colors, + const AppColorsV3.dark(), + text, + const AppTextThemeV3.standard(), + radius, + isTablet ? const AppSizeTheme.iPad() : const AppSizeTheme.defaultTheme(), + ], ); } } diff --git a/mobile-app/lib/v2/components/name_field.dart b/mobile-app/lib/v2/components/name_field.dart index 97116b743..b789a9a2e 100644 --- a/mobile-app/lib/v2/components/name_field.dart +++ b/mobile-app/lib/v2/components/name_field.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:resonance_network_wallet/providers/l10n_provider.dart'; class NameField extends ConsumerWidget { final TextEditingController controller; @@ -14,76 +14,21 @@ class NameField extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final l10n = ref.watch(l10nProvider); - final textStyle = context.themeText.smallTitle!.copyWith(fontWeight: FontWeight.w400); return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration(color: context.colors.surfaceDeep, borderRadius: BorderRadius.circular(14)), - child: Row( - children: [ - Expanded( - child: TextField( - controller: controller, - style: textStyle, - decoration: InputDecoration.collapsed( - hintText: hint ?? l10n.componentNameFieldHint, - hintStyle: textStyle.copyWith(color: context.colors.textSecondary), - ), - ), - ), - if (controller.text.isNotEmpty) ...[ - const SizedBox(width: 8), - _EditAccountClearButton(onTap: () => controller.clear()), - ], - ], - ), + QuantusTextField( + controller: controller, + hint: hint ?? l10n.componentNameFieldHint, + error: error, + showClearButton: true, ), if (subtitle != null) ...[ - const SizedBox(height: 16), - Text(subtitle!, style: context.themeText.smallParagraph?.copyWith(color: context.colors.textSecondary)), - ], - if (error != null) ...[ - const SizedBox(height: 16), - Text( - error!, - style: context.themeText.detail?.copyWith(color: context.colors.textError), - textAlign: TextAlign.center, - ), + const SizedBox(height: 8), + Text(subtitle!, style: context.themeTextV3.caption.copyWith(color: context.colorsV3.textMuted)), ], ], ); } } - -class _EditAccountClearButton extends StatelessWidget { - final VoidCallback onTap; - - const _EditAccountClearButton({required this.onTap}); - - @override - Widget build(BuildContext context) { - final size = 20.0; - final borderRadius = 16.0; - - return Material( - color: Colors.transparent, - child: InkWell( - onTap: onTap, - borderRadius: BorderRadius.circular(borderRadius), - child: Container( - width: size, - height: size, - alignment: Alignment.center, - decoration: BoxDecoration( - color: context.colors.textMuted, - border: Border.all(color: context.colors.borderButton, width: 0.5), - borderRadius: BorderRadius.circular(borderRadius), - ), - child: Icon(Icons.close, size: 12, color: context.colors.background), - ), - ), - ); - } -} diff --git a/quantus_sdk/lib/src/ui/components/index.dart b/quantus_sdk/lib/src/ui/components/index.dart index 59e05a7f5..b7466da51 100644 --- a/quantus_sdk/lib/src/ui/components/index.dart +++ b/quantus_sdk/lib/src/ui/components/index.dart @@ -1,4 +1,5 @@ export 'quantus_button.dart'; +export 'quantus_text_field.dart'; export 'loader.dart'; export 'quantus_icon_button.dart'; export 'glass_button_base.dart'; diff --git a/quantus_sdk/lib/src/ui/components/quantus_text_field.dart b/quantus_sdk/lib/src/ui/components/quantus_text_field.dart new file mode 100644 index 000000000..dc2eebf4b --- /dev/null +++ b/quantus_sdk/lib/src/ui/components/quantus_text_field.dart @@ -0,0 +1,169 @@ +import 'package:flutter/material.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +/// Shared v3 text field: default, focus, and inline error chrome. +/// +/// Presentational only. Callers pass already-resolved [hint] and [error] strings. +class QuantusTextField extends StatefulWidget { + final TextEditingController controller; + final String? hint; + final String? error; + final bool showClearButton; + final FocusNode? focusNode; + final ValueChanged? onChanged; + final bool enabled; + final TextInputType? keyboardType; + final TextInputAction? textInputAction; + final TextCapitalization textCapitalization; + final bool autocorrect; + + const QuantusTextField({ + super.key, + required this.controller, + this.hint, + this.error, + this.showClearButton = false, + this.focusNode, + this.onChanged, + this.enabled = true, + this.keyboardType, + this.textInputAction, + this.textCapitalization = TextCapitalization.none, + this.autocorrect = true, + }); + + @override + State createState() => _QuantusTextFieldState(); +} + +class _QuantusTextFieldState extends State { + late FocusNode _focusNode; + late bool _ownsFocusNode; + + bool get _hasError => widget.error != null; + + @override + void initState() { + super.initState(); + _ownsFocusNode = widget.focusNode == null; + _focusNode = widget.focusNode ?? FocusNode(); + _focusNode.addListener(_rebuild); + widget.controller.addListener(_rebuild); + } + + @override + void didUpdateWidget(QuantusTextField oldWidget) { + super.didUpdateWidget(oldWidget); + if (oldWidget.controller != widget.controller) { + oldWidget.controller.removeListener(_rebuild); + widget.controller.addListener(_rebuild); + } + if (oldWidget.focusNode != widget.focusNode) { + _focusNode.removeListener(_rebuild); + if (_ownsFocusNode) { + _focusNode.dispose(); + } + _ownsFocusNode = widget.focusNode == null; + _focusNode = widget.focusNode ?? FocusNode(); + _focusNode.addListener(_rebuild); + } + } + + @override + void dispose() { + widget.controller.removeListener(_rebuild); + _focusNode.removeListener(_rebuild); + if (_ownsFocusNode) { + _focusNode.dispose(); + } + super.dispose(); + } + + void _rebuild() => setState(() {}); + + Color _borderColor(AppColorsV3 colors) { + if (_hasError) return colors.semanticEmber.useOpacity(0.55); + if (_focusNode.hasFocus) return colors.accentFlare; + return colors.borderEmphasis; + } + + @override + Widget build(BuildContext context) { + final colors = context.colorsV3; + final textStyle = context.themeTextV3.dataAddressLarge.copyWith(color: colors.textContent); + final hintStyle = context.themeTextV3.dataAddressLarge.copyWith(color: colors.textMuted); + final showClear = widget.showClearButton && widget.controller.text.isNotEmpty; + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Container( + width: double.infinity, + constraints: const BoxConstraints(minHeight: 60), + padding: const EdgeInsets.all(14), + decoration: BoxDecoration( + color: colors.bgSurface, + borderRadius: context.radiusV3.mdBorder, + border: Border.all(color: _borderColor(colors), width: 1), + ), + child: Row( + children: [ + Expanded( + child: TextField( + controller: widget.controller, + focusNode: _focusNode, + enabled: widget.enabled, + keyboardType: widget.keyboardType, + textInputAction: widget.textInputAction, + textCapitalization: widget.textCapitalization, + autocorrect: widget.autocorrect, + onChanged: widget.onChanged, + cursorColor: colors.accentFlare, + style: textStyle, + decoration: InputDecoration.collapsed(hintText: widget.hint, hintStyle: hintStyle), + ), + ), + if (showClear) ...[ + const SizedBox(width: 8), + _QuantusTextFieldClearButton(onTap: widget.controller.clear), + ], + ], + ), + ), + if (widget.error != null) ...[ + const SizedBox(height: 8), + Text(widget.error!, style: context.themeTextV3.caption.copyWith(color: colors.semanticEmber)), + ], + ], + ); + } +} + +class _QuantusTextFieldClearButton extends StatelessWidget { + final VoidCallback onTap; + + const _QuantusTextFieldClearButton({required this.onTap}); + + @override + Widget build(BuildContext context) { + final colors = context.colorsV3; + const size = 20.0; + + return GestureDetector( + onTap: onTap, + behavior: HitTestBehavior.opaque, + child: Container( + width: size, + height: size, + alignment: Alignment.center, + decoration: BoxDecoration( + color: colors.textMuted, + border: Border.all(color: colors.borderHairline, width: 0.5), + borderRadius: BorderRadius.circular(16), + ), + child: Icon(Icons.close, size: 12, color: colors.textVoid), + ), + ); + } +} diff --git a/quantus_sdk/test/ui/quantus_text_field_test.dart b/quantus_sdk/test/ui/quantus_text_field_test.dart new file mode 100644 index 000000000..9de181218 --- /dev/null +++ b/quantus_sdk/test/ui/quantus_text_field_test.dart @@ -0,0 +1,69 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + Future pumpField(WidgetTester tester, Widget field) async { + await tester.pumpWidget( + MediaQuery( + data: const MediaQueryData(size: Size(375, 667)), + child: Builder( + builder: (context) => MaterialApp( + theme: AppTheme.darkTheme(context), + home: Scaffold(body: field), + ), + ), + ), + ); + await tester.pump(); + } + + testWidgets('hides error copy and clear button by default', (tester) async { + final controller = TextEditingController(text: 'Value'); + addTearDown(controller.dispose); + + await pumpField(tester, QuantusTextField(controller: controller, hint: 'Hint')); + + expect(find.text('Value'), findsOneWidget); + expect(find.byIcon(Icons.close), findsNothing); + }); + + testWidgets('shows inline error message', (tester) async { + final controller = TextEditingController(); + addTearDown(controller.dispose); + + await pumpField(tester, QuantusTextField(controller: controller, error: 'Fix this')); + + expect(find.text('Fix this'), findsOneWidget); + }); + + testWidgets('clear button empties the controller', (tester) async { + final controller = TextEditingController(text: 'Hello'); + addTearDown(controller.dispose); + + await pumpField(tester, QuantusTextField(controller: controller, showClearButton: true)); + + expect(find.byIcon(Icons.close), findsOneWidget); + await tester.tap(find.byIcon(Icons.close)); + await tester.pump(); + + expect(controller.text, isEmpty); + expect(find.byIcon(Icons.close), findsNothing); + }); + + testWidgets('requestFocus rebuilds without throwing', (tester) async { + final controller = TextEditingController(); + final focusNode = FocusNode(); + addTearDown(controller.dispose); + addTearDown(focusNode.dispose); + + await pumpField(tester, QuantusTextField(controller: controller, focusNode: focusNode)); + + expect(focusNode.hasFocus, isFalse); + focusNode.requestFocus(); + await tester.pump(); + expect(focusNode.hasFocus, isTrue); + }); +} From 3fc0ef5bcb091ec8cb8e8431a4d1c7b2afdce5fd Mon Sep 17 00:00:00 2001 From: Beast Date: Tue, 18 Aug 2026 12:33:20 +0800 Subject: [PATCH 07/38] feat: add quantus banner component --- quantus_sdk/lib/src/ui/components/index.dart | 1 + .../lib/src/ui/components/quantus_banner.dart | 94 +++++++++++++++++++ quantus_sdk/test/ui/quantus_banner_test.dart | 74 +++++++++++++++ 3 files changed, 169 insertions(+) create mode 100644 quantus_sdk/lib/src/ui/components/quantus_banner.dart create mode 100644 quantus_sdk/test/ui/quantus_banner_test.dart diff --git a/quantus_sdk/lib/src/ui/components/index.dart b/quantus_sdk/lib/src/ui/components/index.dart index b7466da51..5bb82ddb4 100644 --- a/quantus_sdk/lib/src/ui/components/index.dart +++ b/quantus_sdk/lib/src/ui/components/index.dart @@ -1,5 +1,6 @@ export 'quantus_button.dart'; export 'quantus_text_field.dart'; +export 'quantus_banner.dart'; export 'loader.dart'; export 'quantus_icon_button.dart'; export 'glass_button_base.dart'; diff --git a/quantus_sdk/lib/src/ui/components/quantus_banner.dart b/quantus_sdk/lib/src/ui/components/quantus_banner.dart new file mode 100644 index 000000000..10656df18 --- /dev/null +++ b/quantus_sdk/lib/src/ui/components/quantus_banner.dart @@ -0,0 +1,94 @@ +import 'package:flutter/material.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +/// Status grammar for [QuantusBanner]. +/// +/// Sage settles, sand warns, ember fails, glacier waits. +enum BannerTone { sage, sand, ember, glacier } + +/// Shared v3 status banner: tone gradient fill, 10% stroke, 40px icon circle. +/// +/// Presentational only. Callers pass an already-resolved [message]. +class QuantusBanner extends StatelessWidget { + final BannerTone tone; + final String message; + final Widget? leading; + + const QuantusBanner({super.key, required this.tone, required this.message, this.leading}); + + @override + Widget build(BuildContext context) { + final colors = context.colorsV3; + final foreground = _toneColor(colors, tone); + // Dark stop is tone mixed toward void so we do not add colors absent from the Figma table. + final fillEnd = Color.lerp(foreground, colors.bgVoid, 0.75)!; + + return Container( + width: double.infinity, + constraints: const BoxConstraints(minHeight: 60), + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [foreground.useOpacity(0.25), fillEnd.useOpacity(0.25)], + ), + borderRadius: context.radiusV3.mdBorder, + border: Border.all(color: foreground.useOpacity(0.10), width: 1), + ), + child: Row( + children: [ + _BannerIcon( + foreground: foreground, + child: leading ?? _DefaultBannerGlyph(foreground: foreground), + ), + const SizedBox(width: 12), + Expanded( + child: Text(message, style: context.themeTextV3.caption.copyWith(color: foreground, height: 1.5)), + ), + ], + ), + ); + } +} + +class _BannerIcon extends StatelessWidget { + final Color foreground; + final Widget child; + + const _BannerIcon({required this.foreground, required this.child}); + + @override + Widget build(BuildContext context) { + return Container( + width: 40, + height: 40, + alignment: Alignment.center, + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all(color: foreground.useOpacity(0.25), width: 1), + ), + child: child, + ); + } +} + +class _DefaultBannerGlyph extends StatelessWidget { + final Color foreground; + + const _DefaultBannerGlyph({required this.foreground}); + + @override + Widget build(BuildContext context) { + return Text('!', style: context.themeTextV3.body.copyWith(color: foreground, height: 1)); + } +} + +Color _toneColor(AppColorsV3 colors, BannerTone tone) { + return switch (tone) { + BannerTone.sage => colors.semanticSage, + BannerTone.sand => colors.semanticSand, + BannerTone.ember => colors.semanticEmber, + BannerTone.glacier => colors.semanticGlacier, + }; +} diff --git a/quantus_sdk/test/ui/quantus_banner_test.dart b/quantus_sdk/test/ui/quantus_banner_test.dart new file mode 100644 index 000000000..ae1aa3670 --- /dev/null +++ b/quantus_sdk/test/ui/quantus_banner_test.dart @@ -0,0 +1,74 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + const colors = AppColorsV3.dark(); + + Future pumpBanner(WidgetTester tester, Widget banner) async { + await tester.pumpWidget( + MediaQuery( + data: const MediaQueryData(size: Size(375, 667)), + child: Builder( + builder: (context) => MaterialApp( + theme: AppTheme.darkTheme(context), + home: Scaffold(body: banner), + ), + ), + ), + ); + await tester.pump(); + } + + BoxDecoration decorationAround(WidgetTester tester, String text) { + final container = tester.widget( + find.ancestor(of: find.text(text), matching: find.byType(Container)).first, + ); + return container.decoration! as BoxDecoration; + } + + testWidgets('shows message and default glyph', (tester) async { + await pumpBanner( + tester, + const QuantusBanner(tone: BannerTone.sage, message: 'Your funds are safe. Nothing left your wallet.'), + ); + + expect(find.text('Your funds are safe. Nothing left your wallet.'), findsOneWidget); + expect(find.text('!'), findsOneWidget); + }); + + testWidgets('custom leading replaces the default glyph', (tester) async { + await pumpBanner( + tester, + const QuantusBanner(tone: BannerTone.sand, message: 'The deposit window ended.', leading: Icon(Icons.schedule)), + ); + + expect(find.byIcon(Icons.schedule), findsOneWidget); + expect(find.text('!'), findsNothing); + }); + + testWidgets('paints 10 percent tone stroke and a vertical fill', (tester) async { + final cases = <(BannerTone, Color)>[ + (BannerTone.sage, colors.semanticSage), + (BannerTone.sand, colors.semanticSand), + (BannerTone.ember, colors.semanticEmber), + (BannerTone.glacier, colors.semanticGlacier), + ]; + + for (final (tone, color) in cases) { + await pumpBanner(tester, QuantusBanner(tone: tone, message: 'Status')); + + final border = decorationAround(tester, 'Status').border! as Border; + expect(border.top.color, color.useOpacity(0.10), reason: '$tone stroke'); + expect(decorationAround(tester, 'Status').gradient, isA(), reason: '$tone fill'); + } + }); + + testWidgets('uses v3 md radius', (tester) async { + await pumpBanner(tester, const QuantusBanner(tone: BannerTone.glacier, message: 'Waiting')); + + expect(decorationAround(tester, 'Waiting').borderRadius, const AppRadiusV3.standard().mdBorder); + }); +} From 95d3ea02cda4c12f00aba389f3d039a84f4cb0a2 Mon Sep 17 00:00:00 2001 From: Beast Date: Tue, 18 Aug 2026 12:35:21 +0800 Subject: [PATCH 08/38] feat: add badge component --- quantus_sdk/lib/src/ui/components/index.dart | 1 + .../lib/src/ui/components/quantus_badge.dart | 49 ++++++++++++++ quantus_sdk/test/ui/quantus_badge_test.dart | 67 +++++++++++++++++++ 3 files changed, 117 insertions(+) create mode 100644 quantus_sdk/lib/src/ui/components/quantus_badge.dart create mode 100644 quantus_sdk/test/ui/quantus_badge_test.dart diff --git a/quantus_sdk/lib/src/ui/components/index.dart b/quantus_sdk/lib/src/ui/components/index.dart index 5bb82ddb4..77dee0301 100644 --- a/quantus_sdk/lib/src/ui/components/index.dart +++ b/quantus_sdk/lib/src/ui/components/index.dart @@ -1,5 +1,6 @@ export 'quantus_button.dart'; export 'quantus_text_field.dart'; +export 'quantus_badge.dart'; export 'quantus_banner.dart'; export 'loader.dart'; export 'quantus_icon_button.dart'; diff --git a/quantus_sdk/lib/src/ui/components/quantus_badge.dart b/quantus_sdk/lib/src/ui/components/quantus_badge.dart new file mode 100644 index 000000000..26a056d49 --- /dev/null +++ b/quantus_sdk/lib/src/ui/components/quantus_badge.dart @@ -0,0 +1,49 @@ +import 'package:flutter/material.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +/// Status-grammar tones for [QuantusBadge]. +/// +/// Glacier waits, sage settles, ember fails, sand warns. Lilac is checkphrase +/// only. Flare is reserved for action emphasis. +enum BadgeTone { neutral, sage, sand, ember, glacier, lilac, flare } + +/// Stroke-only status badge: mono uppercase, tracked, tone on stroke and text. +/// +/// Presentational only. Callers pass an already-resolved [label]. +class QuantusBadge extends StatelessWidget { + final String label; + final BadgeTone tone; + + const QuantusBadge({super.key, required this.label, this.tone = BadgeTone.neutral}); + + @override + Widget build(BuildContext context) { + final color = _toneColor(context.colorsV3, tone); + + return Container( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3), + decoration: BoxDecoration( + borderRadius: context.radiusV3.xsBorder, + border: Border.all(color: color, width: 1), + ), + child: Text(label.toUpperCase(), style: _labelStyle(context, color), maxLines: 1, softWrap: false), + ); + } + + /// Figma Badge type: Geist Mono Medium 10, tracking 0.8, from Label / Monogram. + TextStyle _labelStyle(BuildContext context, Color color) { + return context.themeTextV3.labelMonogram.copyWith(fontSize: 10, letterSpacing: 0.8, color: color); + } +} + +Color _toneColor(AppColorsV3 colors, BadgeTone tone) { + return switch (tone) { + BadgeTone.neutral => colors.textMuted, + BadgeTone.sage => colors.semanticSage, + BadgeTone.sand => colors.semanticSand, + BadgeTone.ember => colors.semanticEmber, + BadgeTone.glacier => colors.semanticGlacier, + BadgeTone.lilac => colors.semanticLilac, + BadgeTone.flare => colors.accentFlare, + }; +} diff --git a/quantus_sdk/test/ui/quantus_badge_test.dart b/quantus_sdk/test/ui/quantus_badge_test.dart new file mode 100644 index 000000000..63cf895ec --- /dev/null +++ b/quantus_sdk/test/ui/quantus_badge_test.dart @@ -0,0 +1,67 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + const colors = AppColorsV3.dark(); + + Future pumpBadge(WidgetTester tester, Widget badge) async { + await tester.pumpWidget( + MediaQuery( + data: const MediaQueryData(size: Size(375, 667)), + child: Builder( + builder: (context) => MaterialApp( + theme: AppTheme.darkTheme(context), + home: Scaffold(body: badge), + ), + ), + ), + ); + await tester.pump(); + } + + BoxDecoration decorationAround(WidgetTester tester, String text) { + final container = tester.widget( + find.ancestor(of: find.text(text), matching: find.byType(Container)).first, + ); + return container.decoration! as BoxDecoration; + } + + testWidgets('renders label in uppercase', (tester) async { + await pumpBadge(tester, const QuantusBadge(label: 'Pending')); + + expect(find.text('PENDING'), findsOneWidget); + expect(find.text('Pending'), findsNothing); + }); + + testWidgets('paints stroke and text with the tone token', (tester) async { + final cases = <(BadgeTone, Color)>[ + (BadgeTone.neutral, colors.textMuted), + (BadgeTone.sage, colors.semanticSage), + (BadgeTone.sand, colors.semanticSand), + (BadgeTone.ember, colors.semanticEmber), + (BadgeTone.glacier, colors.semanticGlacier), + (BadgeTone.lilac, colors.semanticLilac), + (BadgeTone.flare, colors.accentFlare), + ]; + + for (final (tone, color) in cases) { + await pumpBadge(tester, QuantusBadge(label: 'Badge', tone: tone)); + + final text = tester.widget(find.text('BADGE')); + expect(text.style?.color, color, reason: '$tone text'); + + final border = decorationAround(tester, 'BADGE').border! as Border; + expect(border.top.color, color, reason: '$tone stroke'); + expect(border.top.width, 1); + } + }); + + testWidgets('uses v3 xs radius', (tester) async { + await pumpBadge(tester, const QuantusBadge(label: 'Badge')); + + expect(decorationAround(tester, 'BADGE').borderRadius, const AppRadiusV3.standard().xsBorder); + }); +} From 7d560adf92672170af78780f3bf0c4a7e3107fd4 Mon Sep 17 00:00:00 2001 From: Beast Date: Tue, 18 Aug 2026 12:53:22 +0800 Subject: [PATCH 09/38] feat: add dialog component --- quantus_sdk/lib/src/ui/components/index.dart | 1 + .../lib/src/ui/components/quantus_dialog.dart | 73 +++++++++++ quantus_sdk/test/ui/quantus_dialog_test.dart | 119 ++++++++++++++++++ 3 files changed, 193 insertions(+) create mode 100644 quantus_sdk/lib/src/ui/components/quantus_dialog.dart create mode 100644 quantus_sdk/test/ui/quantus_dialog_test.dart diff --git a/quantus_sdk/lib/src/ui/components/index.dart b/quantus_sdk/lib/src/ui/components/index.dart index 77dee0301..981599dd2 100644 --- a/quantus_sdk/lib/src/ui/components/index.dart +++ b/quantus_sdk/lib/src/ui/components/index.dart @@ -2,6 +2,7 @@ export 'quantus_button.dart'; export 'quantus_text_field.dart'; export 'quantus_badge.dart'; export 'quantus_banner.dart'; +export 'quantus_dialog.dart'; export 'loader.dart'; export 'quantus_icon_button.dart'; export 'glass_button_base.dart'; diff --git a/quantus_sdk/lib/src/ui/components/quantus_dialog.dart b/quantus_sdk/lib/src/ui/components/quantus_dialog.dart new file mode 100644 index 000000000..17d73b21c --- /dev/null +++ b/quantus_sdk/lib/src/ui/components/quantus_dialog.dart @@ -0,0 +1,73 @@ +import 'package:flutter/material.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +/// Shared v3 centered dialog: title, plain-consequence body, primary CTA. +/// +/// Presentational only. Callers pass already-resolved [title], [body], and +/// [actionLabel] strings. Overlay presentation is [showQuantusDialog]. +class QuantusDialog extends StatelessWidget { + final String title; + final String body; + final String actionLabel; + final VoidCallback? onAction; + + const QuantusDialog({super.key, required this.title, required this.body, required this.actionLabel, this.onAction}); + + @override + Widget build(BuildContext context) { + final colors = context.colorsV3; + final text = context.themeTextV3; + + return Container( + width: double.infinity, + constraints: const BoxConstraints(maxWidth: 326), + padding: const EdgeInsets.all(24), + decoration: BoxDecoration( + color: colors.bgSurface, + borderRadius: context.radiusV3.lgBorder, + border: Border.all(color: colors.borderEmphasis, width: 1), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Text(title, style: text.headingRow.copyWith(color: colors.textContent)), + const SizedBox(height: 10), + Text(body, style: text.body.copyWith(color: colors.textMuted, height: 1.55)), + const SizedBox(height: 18), + QuantusButton.simple(label: actionLabel, onTap: onAction), + ], + ), + ); + } +} + +/// Shows a centered [QuantusDialog]. +/// +/// Returns `true` when the primary action is tapped, `false` if the barrier is dismissed. +Future showQuantusDialog( + BuildContext context, { + required String title, + required String body, + required String actionLabel, + bool barrierDismissible = true, +}) async { + final confirmed = await showDialog( + context: context, + barrierDismissible: barrierDismissible, + builder: (dialogContext) { + return Dialog( + backgroundColor: Colors.transparent, + elevation: 0, + insetPadding: const EdgeInsets.symmetric(horizontal: 24, vertical: 24), + child: QuantusDialog( + title: title, + body: body, + actionLabel: actionLabel, + onAction: () => Navigator.pop(dialogContext, true), + ), + ); + }, + ); + return confirmed ?? false; +} diff --git a/quantus_sdk/test/ui/quantus_dialog_test.dart b/quantus_sdk/test/ui/quantus_dialog_test.dart new file mode 100644 index 000000000..40131f63e --- /dev/null +++ b/quantus_sdk/test/ui/quantus_dialog_test.dart @@ -0,0 +1,119 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + const colors = AppColorsV3.dark(); + + Future pumpDialog(WidgetTester tester, Widget dialog) async { + await tester.pumpWidget( + MediaQuery( + data: const MediaQueryData(size: Size(375, 667)), + child: Builder( + builder: (context) => MaterialApp( + theme: AppTheme.darkTheme(context), + home: Scaffold(body: dialog), + ), + ), + ), + ); + await tester.pump(); + } + + BoxDecoration decorationAround(WidgetTester tester, String text) { + final container = tester.widget( + find.ancestor(of: find.text(text), matching: find.byType(Container)).first, + ); + return container.decoration! as BoxDecoration; + } + + testWidgets('shows title, body, and action label', (tester) async { + await pumpDialog( + tester, + QuantusDialog( + title: 'Dialog title?', + body: 'One or two sentences stating consequences plainly. Nothing has been sent.', + actionLabel: 'Label', + onAction: () {}, + ), + ); + + expect(find.text('Dialog title?'), findsOneWidget); + expect(find.text('One or two sentences stating consequences plainly. Nothing has been sent.'), findsOneWidget); + expect(find.text('Label'), findsOneWidget); + }); + + testWidgets('tapping the action invokes the callback', (tester) async { + var tapped = false; + await pumpDialog( + tester, + QuantusDialog(title: 'Dialog title?', body: 'Consequences.', actionLabel: 'Label', onAction: () => tapped = true), + ); + + await tester.tap(find.text('Label')); + expect(tapped, isTrue); + }); + + testWidgets('paints surface fill and emphasis border', (tester) async { + await pumpDialog( + tester, + QuantusDialog(title: 'Dialog title?', body: 'Consequences.', actionLabel: 'Label', onAction: () {}), + ); + + final decoration = decorationAround(tester, 'Dialog title?'); + expect(decoration.color, colors.bgSurface); + final border = decoration.border! as Border; + expect(border.top.color, colors.borderEmphasis); + expect(border.top.width, 1); + }); + + testWidgets('uses v3 lg radius', (tester) async { + await pumpDialog( + tester, + QuantusDialog(title: 'Dialog title?', body: 'Consequences.', actionLabel: 'Label', onAction: () {}), + ); + + expect(decorationAround(tester, 'Dialog title?').borderRadius, const AppRadiusV3.standard().lgBorder); + }); + + testWidgets('showQuantusDialog returns true when the action is tapped', (tester) async { + bool? result; + await tester.pumpWidget( + MediaQuery( + data: const MediaQueryData(size: Size(375, 667)), + child: Builder( + builder: (context) => MaterialApp( + theme: AppTheme.darkTheme(context), + home: Scaffold( + body: Builder( + builder: (context) { + return TextButton( + onPressed: () async { + result = await showQuantusDialog( + context, + title: 'Dialog title?', + body: 'Consequences.', + actionLabel: 'Label', + ); + }, + child: const Text('Open'), + ); + }, + ), + ), + ), + ), + ), + ); + await tester.pump(); + + await tester.tap(find.text('Open')); + await tester.pumpAndSettle(); + await tester.tap(find.text('Label')); + await tester.pumpAndSettle(); + + expect(result, isTrue); + }); +} From ea13aa33f62a41d88da06e741df4c2609baf75a3 Mon Sep 17 00:00:00 2001 From: Beast Date: Tue, 18 Aug 2026 12:53:54 +0800 Subject: [PATCH 10/38] chore: fix linter --- quantus_sdk/lib/src/ui/components/scaffold_base.dart | 1 - quantus_sdk/lib/src/ui/components/v2_app_bar.dart | 1 - 2 files changed, 2 deletions(-) diff --git a/quantus_sdk/lib/src/ui/components/scaffold_base.dart b/quantus_sdk/lib/src/ui/components/scaffold_base.dart index 71dc8d635..e0d914484 100644 --- a/quantus_sdk/lib/src/ui/components/scaffold_base.dart +++ b/quantus_sdk/lib/src/ui/components/scaffold_base.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:quantus_sdk/src/ui/components/base_background.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; class ScaffoldBase extends StatelessWidget { diff --git a/quantus_sdk/lib/src/ui/components/v2_app_bar.dart b/quantus_sdk/lib/src/ui/components/v2_app_bar.dart index 07667d9f3..16bce12d1 100644 --- a/quantus_sdk/lib/src/ui/components/v2_app_bar.dart +++ b/quantus_sdk/lib/src/ui/components/v2_app_bar.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:quantus_sdk/src/ui/components/back_button.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; class V2AppBar extends StatelessWidget { From fd029aa4922b5cfb786e7c23ed13888235f70cdc Mon Sep 17 00:00:00 2001 From: Beast Date: Tue, 18 Aug 2026 13:04:40 +0800 Subject: [PATCH 11/38] feat: add action sheet component --- quantus_sdk/lib/src/ui/components/index.dart | 1 + .../ui/components/quantus_action_sheet.dart | 129 ++++++++++++ .../test/ui/quantus_action_sheet_test.dart | 185 ++++++++++++++++++ 3 files changed, 315 insertions(+) create mode 100644 quantus_sdk/lib/src/ui/components/quantus_action_sheet.dart create mode 100644 quantus_sdk/test/ui/quantus_action_sheet_test.dart diff --git a/quantus_sdk/lib/src/ui/components/index.dart b/quantus_sdk/lib/src/ui/components/index.dart index 981599dd2..a1f816ed4 100644 --- a/quantus_sdk/lib/src/ui/components/index.dart +++ b/quantus_sdk/lib/src/ui/components/index.dart @@ -3,6 +3,7 @@ export 'quantus_text_field.dart'; export 'quantus_badge.dart'; export 'quantus_banner.dart'; export 'quantus_dialog.dart'; +export 'quantus_action_sheet.dart'; export 'loader.dart'; export 'quantus_icon_button.dart'; export 'glass_button_base.dart'; diff --git a/quantus_sdk/lib/src/ui/components/quantus_action_sheet.dart b/quantus_sdk/lib/src/ui/components/quantus_action_sheet.dart new file mode 100644 index 000000000..e756607e4 --- /dev/null +++ b/quantus_sdk/lib/src/ui/components/quantus_action_sheet.dart @@ -0,0 +1,129 @@ +import 'package:flutter/material.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +/// One row in a [QuantusActionSheet]. +/// +/// Presentational only. Callers pass an already-resolved [label]. +class QuantusActionSheetItem { + final String label; + final VoidCallback onTap; + final bool isDestructive; + + const QuantusActionSheetItem({required this.label, required this.onTap, this.isDestructive = false}); +} + +/// Shared v3 kebab/action sheet: item list, ember destructive last, divider above it. +/// +/// Presentational only. Overlay presentation is [showQuantusActionSheet]. +class QuantusActionSheet extends StatelessWidget { + final List items; + + const QuantusActionSheet({super.key, required this.items}); + + @override + Widget build(BuildContext context) { + final colors = context.colorsV3; + + return Container( + width: double.infinity, + decoration: BoxDecoration( + color: colors.bgSurface, + borderRadius: context.radiusV3.lgBorder, + border: Border.all(color: colors.borderEmphasis, width: 1), + ), + clipBehavior: Clip.antiAlias, + child: Material( + color: Colors.transparent, + child: SafeArea( + top: false, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 6), + child: _ActionSheetItems(items: items), + ), + ), + ), + ); + } +} + +/// Shows a [QuantusActionSheet] as a modal bottom sheet. +/// +/// Tapping an item pops the sheet, then runs that item's [QuantusActionSheetItem.onTap]. +/// Barrier tap or drag-down dismisses without running an action. +Future showQuantusActionSheet(BuildContext context, {required List items}) { + return BottomSheetContainer.show( + context, + builder: (sheetContext) { + return QuantusActionSheet( + items: [ + for (final item in items) + QuantusActionSheetItem( + label: item.label, + isDestructive: item.isDestructive, + onTap: () { + Navigator.pop(sheetContext); + item.onTap(); + }, + ), + ], + ); + }, + ); +} + +class _ActionSheetItems extends StatelessWidget { + final List items; + + const _ActionSheetItems({required this.items}); + + @override + Widget build(BuildContext context) { + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + for (var i = 0; i < items.length; i++) ...[ + if (_isFirstDestructive(i)) const _ActionSheetDivider(), + _ActionSheetRow(item: items[i]), + ], + ], + ); + } + + bool _isFirstDestructive(int index) { + if (!items[index].isDestructive) return false; + return !items.take(index).any((item) => item.isDestructive); + } +} + +class _ActionSheetRow extends StatelessWidget { + final QuantusActionSheetItem item; + + const _ActionSheetRow({required this.item}); + + @override + Widget build(BuildContext context) { + final colors = context.colorsV3; + final color = item.isDestructive ? colors.semanticEmber : colors.textContent; + + return InkWell( + onTap: item.onTap, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + child: Text(item.label, style: context.themeTextV3.bodyEmphasis.copyWith(color: color)), + ), + ); + } +} + +class _ActionSheetDivider extends StatelessWidget { + const _ActionSheetDivider(); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Divider(height: 1, thickness: 1, color: context.colorsV3.borderHairline), + ); + } +} diff --git a/quantus_sdk/test/ui/quantus_action_sheet_test.dart b/quantus_sdk/test/ui/quantus_action_sheet_test.dart new file mode 100644 index 000000000..b9b4ba7f6 --- /dev/null +++ b/quantus_sdk/test/ui/quantus_action_sheet_test.dart @@ -0,0 +1,185 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + const colors = AppColorsV3.dark(); + + Future pumpSheet(WidgetTester tester, Widget sheet) async { + await tester.pumpWidget( + MediaQuery( + data: const MediaQueryData(size: Size(375, 667)), + child: Builder( + builder: (context) => MaterialApp( + theme: AppTheme.darkTheme(context), + home: Scaffold(body: sheet), + ), + ), + ), + ); + await tester.pump(); + } + + BoxDecoration decorationAround(WidgetTester tester, String text) { + final container = tester.widget( + find.ancestor(of: find.text(text), matching: find.byType(Container)).first, + ); + return container.decoration! as BoxDecoration; + } + + QuantusActionSheet accountSheet({VoidCallback? onCopy, VoidCallback? onRemove}) { + return QuantusActionSheet( + items: [ + QuantusActionSheetItem(label: 'Copy Address', onTap: onCopy ?? () {}), + QuantusActionSheetItem(label: 'Edit Account', onTap: () {}), + QuantusActionSheetItem(label: 'View Recovery Phrase', onTap: () {}), + QuantusActionSheetItem(label: 'Remove Account', isDestructive: true, onTap: onRemove ?? () {}), + ], + ); + } + + testWidgets('shows item labels', (tester) async { + await pumpSheet(tester, accountSheet()); + + expect(find.text('Copy Address'), findsOneWidget); + expect(find.text('Edit Account'), findsOneWidget); + expect(find.text('View Recovery Phrase'), findsOneWidget); + expect(find.text('Remove Account'), findsOneWidget); + }); + + testWidgets('tapping an item invokes its callback', (tester) async { + var copied = false; + await pumpSheet(tester, accountSheet(onCopy: () => copied = true)); + + await tester.tap(find.text('Copy Address')); + expect(copied, isTrue); + }); + + testWidgets('destructive label uses ember', (tester) async { + await pumpSheet(tester, accountSheet()); + + final destructive = tester.widget(find.text('Remove Account')); + expect(destructive.style?.color, colors.semanticEmber); + + final regular = tester.widget(find.text('Copy Address')); + expect(regular.style?.color, colors.textContent); + }); + + testWidgets('inserts a divider above the first destructive item', (tester) async { + await pumpSheet(tester, accountSheet()); + + expect(find.byType(Divider), findsOneWidget); + }); + + testWidgets('omits the divider when no item is destructive', (tester) async { + await pumpSheet( + tester, + QuantusActionSheet( + items: [ + QuantusActionSheetItem(label: 'Rename Wallet', onTap: () {}), + QuantusActionSheetItem(label: 'Add Account', onTap: () {}), + ], + ), + ); + + expect(find.byType(Divider), findsNothing); + }); + + testWidgets('paints surface fill and emphasis border', (tester) async { + await pumpSheet(tester, accountSheet()); + + final decoration = decorationAround(tester, 'Copy Address'); + expect(decoration.color, colors.bgSurface); + final border = decoration.border! as Border; + expect(border.top.color, colors.borderEmphasis); + expect(border.top.width, 1); + }); + + testWidgets('uses v3 lg radius', (tester) async { + await pumpSheet(tester, accountSheet()); + + expect(decorationAround(tester, 'Copy Address').borderRadius, const AppRadiusV3.standard().lgBorder); + }); + + testWidgets('showQuantusActionSheet pops then runs the tapped action', (tester) async { + var copied = false; + await tester.pumpWidget( + MediaQuery( + data: const MediaQueryData(size: Size(375, 667)), + child: Builder( + builder: (context) => MaterialApp( + theme: AppTheme.darkTheme(context), + home: Scaffold( + body: Builder( + builder: (context) { + return TextButton( + onPressed: () { + showQuantusActionSheet( + context, + items: [QuantusActionSheetItem(label: 'Copy Address', onTap: () => copied = true)], + ); + }, + child: const Text('Open'), + ); + }, + ), + ), + ), + ), + ), + ); + await tester.pump(); + + await tester.tap(find.text('Open')); + await tester.pumpAndSettle(); + expect(find.text('Copy Address'), findsOneWidget); + + await tester.tap(find.text('Copy Address')); + await tester.pumpAndSettle(); + + expect(copied, isTrue); + expect(find.text('Copy Address'), findsNothing); + }); + + testWidgets('dismissing the sheet does not run actions', (tester) async { + var copied = false; + await tester.pumpWidget( + MediaQuery( + data: const MediaQueryData(size: Size(375, 667)), + child: Builder( + builder: (context) => MaterialApp( + theme: AppTheme.darkTheme(context), + home: Scaffold( + body: Builder( + builder: (context) { + return TextButton( + onPressed: () { + showQuantusActionSheet( + context, + items: [QuantusActionSheetItem(label: 'Copy Address', onTap: () => copied = true)], + ); + }, + child: const Text('Open'), + ); + }, + ), + ), + ), + ), + ), + ); + await tester.pump(); + + await tester.tap(find.text('Open')); + await tester.pumpAndSettle(); + expect(find.text('Copy Address'), findsOneWidget); + + await tester.tapAt(const Offset(8, 8)); + await tester.pumpAndSettle(); + + expect(copied, isFalse); + expect(find.text('Copy Address'), findsNothing); + }); +} From 5887a901663863770f4d7f116819baccd9651f70 Mon Sep 17 00:00:00 2001 From: Beast Date: Tue, 18 Aug 2026 13:59:44 +0800 Subject: [PATCH 12/38] feat: update bottom sheet style --- .../activity/transaction_detail_sheet.dart | 1 - .../multisig_action_confirm_sheet.dart | 1 - .../multisig_proposal_detail_sheet.dart | 1 - .../swap/refund_address_picker_sheet.dart | 1 - .../ui/components/bottom_sheet_container.dart | 87 ++++---------- .../ui/components/confirm_action_sheet.dart | 1 - .../test/ui/bottom_sheet_container_test.dart | 109 ++++++++++++++++++ 7 files changed, 134 insertions(+), 67 deletions(-) create mode 100644 quantus_sdk/test/ui/bottom_sheet_container_test.dart 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 b8914ab58..6543d8d33 100644 --- a/mobile-app/lib/v2/screens/activity/transaction_detail_sheet.dart +++ b/mobile-app/lib/v2/screens/activity/transaction_detail_sheet.dart @@ -111,7 +111,6 @@ class _TransactionDetailSheet extends ConsumerWidget { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - const SizedBox(height: 16), _AmountSection(tx: tx, isSend: _isSend, activeAccountId: activeAccountId, colors: colors), const SizedBox(height: 20), _DetailRow( diff --git a/mobile-app/lib/v2/screens/multisig/multisig_action_confirm_sheet.dart b/mobile-app/lib/v2/screens/multisig/multisig_action_confirm_sheet.dart index 554285026..1b05d275b 100644 --- a/mobile-app/lib/v2/screens/multisig/multisig_action_confirm_sheet.dart +++ b/mobile-app/lib/v2/screens/multisig/multisig_action_confirm_sheet.dart @@ -362,7 +362,6 @@ class _MultisigActionConfirmSheetState extends ConsumerState Navigator.pop(context), - child: Icon(Icons.close, color: colors.textPrimary, size: 20), - ), - ], - ), - SizedBox(height: showDragHandle ? 28 : 32), - if (height != null) Expanded(child: child) else Flexible(child: SingleChildScrollView(child: child)), - ], + ), ), ); } diff --git a/quantus_sdk/lib/src/ui/components/confirm_action_sheet.dart b/quantus_sdk/lib/src/ui/components/confirm_action_sheet.dart index 26a8a1633..6dd570cfc 100644 --- a/quantus_sdk/lib/src/ui/components/confirm_action_sheet.dart +++ b/quantus_sdk/lib/src/ui/components/confirm_action_sheet.dart @@ -50,7 +50,6 @@ class _ConfirmActionSheet extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.stretch, mainAxisSize: MainAxisSize.min, children: [ - const SizedBox(height: 16), Text(message, style: text.paragraph?.copyWith(color: colors.textSecondary)), const SizedBox(height: 24), QuantusButton.simple( diff --git a/quantus_sdk/test/ui/bottom_sheet_container_test.dart b/quantus_sdk/test/ui/bottom_sheet_container_test.dart new file mode 100644 index 000000000..6828ed185 --- /dev/null +++ b/quantus_sdk/test/ui/bottom_sheet_container_test.dart @@ -0,0 +1,109 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + const colors = AppColorsV3.dark(); + const text = AppTextThemeV3.standard(); + + Future pumpSheet(WidgetTester tester, Widget sheet) async { + await tester.pumpWidget( + MediaQuery( + data: const MediaQueryData(size: Size(375, 667)), + child: Builder( + builder: (context) => MaterialApp( + theme: AppTheme.darkTheme(context), + home: Scaffold(body: sheet), + ), + ), + ), + ); + await tester.pump(); + } + + BoxDecoration decorationAround(WidgetTester tester, String label) { + final container = tester.widget( + find.ancestor(of: find.text(label), matching: find.byType(Container)).first, + ); + return container.decoration! as BoxDecoration; + } + + Container sheetContainer(WidgetTester tester, String label) { + return tester.widget(find.ancestor(of: find.text(label), matching: find.byType(Container)).first); + } + + Container? handleContainer(WidgetTester tester) { + for (final container in tester.widgetList(find.byType(Container))) { + if (container.constraints?.maxWidth == 36 && container.constraints?.maxHeight == 4) { + return container; + } + } + return null; + } + + BottomSheetContainer sheet() { + return const BottomSheetContainer(title: 'Sheet Title', child: Text('Slot')); + } + + testWidgets('shows title and content slot', (tester) async { + await pumpSheet(tester, sheet()); + + expect(find.text('Sheet Title'), findsOneWidget); + expect(find.text('Slot'), findsOneWidget); + }); + + testWidgets('omits the close icon', (tester) async { + await pumpSheet(tester, sheet()); + + expect(find.byIcon(Icons.close), findsNothing); + }); + + testWidgets('title uses heading row and content color', (tester) async { + await pumpSheet(tester, sheet()); + + final title = tester.widget(find.text('Sheet Title')); + expect(title.style?.color, colors.textContent); + expect(title.style?.fontSize, text.headingRow.fontSize); + expect(title.style?.fontWeight, text.headingRow.fontWeight); + }); + + testWidgets('paints surface fill without a border', (tester) async { + await pumpSheet(tester, sheet()); + + final decoration = decorationAround(tester, 'Sheet Title'); + expect(decoration.color, colors.bgSurface); + expect(decoration.border, isNull); + }); + + testWidgets('uses v3 lg radius', (tester) async { + await pumpSheet(tester, sheet()); + + expect(decorationAround(tester, 'Sheet Title').borderRadius, const AppRadiusV3.standard().lgBorder); + }); + + testWidgets('pads 24/16-32', (tester) async { + await pumpSheet(tester, sheet()); + + expect(sheetContainer(tester, 'Sheet Title').padding, const EdgeInsets.fromLTRB(24, 16, 24, 32)); + }); + + testWidgets('handle is 36 by 4 in surface-2', (tester) async { + await pumpSheet(tester, sheet()); + + final handle = handleContainer(tester); + expect(handle, isNotNull); + final decoration = handle!.decoration! as BoxDecoration; + expect(decoration.color, colors.bgSurface2); + }); + + testWidgets('caps width at 362', (tester) async { + await pumpSheet(tester, sheet()); + + expect( + tester.widgetList(find.byType(ConstrainedBox)).any((box) => box.constraints.maxWidth == 362), + isTrue, + ); + }); +} From 997f9f1f3b28752c4911ab12eed05d1b73723675 Mon Sep 17 00:00:00 2001 From: Beast Date: Tue, 18 Aug 2026 14:04:48 +0800 Subject: [PATCH 13/38] fix: sheet capped --- .../ui/components/bottom_sheet_container.dart | 43 +++++++++---------- .../test/ui/bottom_sheet_container_test.dart | 5 ++- 2 files changed, 23 insertions(+), 25 deletions(-) diff --git a/quantus_sdk/lib/src/ui/components/bottom_sheet_container.dart b/quantus_sdk/lib/src/ui/components/bottom_sheet_container.dart index 89f1b6a9f..e03fa72ea 100644 --- a/quantus_sdk/lib/src/ui/components/bottom_sheet_container.dart +++ b/quantus_sdk/lib/src/ui/components/bottom_sheet_container.dart @@ -17,30 +17,27 @@ class BottomSheetContainer extends StatelessWidget { final colors = context.colorsV3; final text = context.themeTextV3; - return ConstrainedBox( - constraints: const BoxConstraints(maxWidth: 362), - child: Container( - width: double.infinity, - height: height, - padding: const EdgeInsets.fromLTRB(24, 16, 24, 32), - decoration: BoxDecoration(color: colors.bgSurface, borderRadius: context.radiusV3.lgBorder), - child: Column( - mainAxisSize: height != null ? MainAxisSize.max : MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Center( - child: Container( - width: 36, - height: 4, - decoration: BoxDecoration(color: colors.bgSurface2, borderRadius: BorderRadius.circular(2)), - ), + return Container( + width: double.infinity, + height: height, + padding: const EdgeInsets.fromLTRB(24, 16, 24, 32), + decoration: BoxDecoration(color: colors.bgSurface, borderRadius: context.radiusV3.lgBorder), + child: Column( + mainAxisSize: height != null ? MainAxisSize.max : MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Center( + child: Container( + width: 36, + height: 4, + decoration: BoxDecoration(color: colors.bgSurface2, borderRadius: BorderRadius.circular(2)), ), - const SizedBox(height: 16), - Text(title, style: text.headingRow.copyWith(color: colors.textContent)), - const SizedBox(height: 16), - if (height != null) Expanded(child: child) else Flexible(child: SingleChildScrollView(child: child)), - ], - ), + ), + const SizedBox(height: 16), + Text(title, style: text.headingRow.copyWith(color: colors.textContent)), + const SizedBox(height: 16), + if (height != null) Expanded(child: child) else Flexible(child: SingleChildScrollView(child: child)), + ], ), ); } diff --git a/quantus_sdk/test/ui/bottom_sheet_container_test.dart b/quantus_sdk/test/ui/bottom_sheet_container_test.dart index 6828ed185..493364c2b 100644 --- a/quantus_sdk/test/ui/bottom_sheet_container_test.dart +++ b/quantus_sdk/test/ui/bottom_sheet_container_test.dart @@ -98,12 +98,13 @@ void main() { expect(decoration.color, colors.bgSurface2); }); - testWidgets('caps width at 362', (tester) async { + testWidgets('takes the full available width', (tester) async { await pumpSheet(tester, sheet()); expect( tester.widgetList(find.byType(ConstrainedBox)).any((box) => box.constraints.maxWidth == 362), - isTrue, + isFalse, ); + expect(tester.getSize(find.byType(BottomSheetContainer)).width, tester.getSize(find.byType(Scaffold)).width); }); } From b168401cc7af2b3c1e69b9f0addf69b37b0dd9c1 Mon Sep 17 00:00:00 2001 From: Beast Date: Tue, 18 Aug 2026 14:41:57 +0800 Subject: [PATCH 14/38] feat: add data row component --- .../v2/components/recovery_phrase_body.dart | 2 +- quantus_sdk/lib/src/ui/components/index.dart | 1 + .../src/ui/components/quantus_data_row.dart | 56 +++++++++++++ .../test/ui/quantus_data_row_test.dart | 80 +++++++++++++++++++ 4 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 quantus_sdk/lib/src/ui/components/quantus_data_row.dart create mode 100644 quantus_sdk/test/ui/quantus_data_row_test.dart diff --git a/mobile-app/lib/v2/components/recovery_phrase_body.dart b/mobile-app/lib/v2/components/recovery_phrase_body.dart index 6f55c9fb8..b2c0b4676 100644 --- a/mobile-app/lib/v2/components/recovery_phrase_body.dart +++ b/mobile-app/lib/v2/components/recovery_phrase_body.dart @@ -153,4 +153,4 @@ class _RecoveryPhraseBodyState extends ConsumerState { ), ); } -} \ No newline at end of file +} diff --git a/quantus_sdk/lib/src/ui/components/index.dart b/quantus_sdk/lib/src/ui/components/index.dart index a1f816ed4..bc132c722 100644 --- a/quantus_sdk/lib/src/ui/components/index.dart +++ b/quantus_sdk/lib/src/ui/components/index.dart @@ -1,6 +1,7 @@ export 'quantus_button.dart'; export 'quantus_text_field.dart'; export 'quantus_badge.dart'; +export 'quantus_data_row.dart'; export 'quantus_banner.dart'; export 'quantus_dialog.dart'; export 'quantus_action_sheet.dart'; diff --git a/quantus_sdk/lib/src/ui/components/quantus_data_row.dart b/quantus_sdk/lib/src/ui/components/quantus_data_row.dart new file mode 100644 index 000000000..b4b23e3e2 --- /dev/null +++ b/quantus_sdk/lib/src/ui/components/quantus_data_row.dart @@ -0,0 +1,56 @@ +import 'package:flutter/material.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +/// Declared data row: mono label left, mono value right, hairline border. +/// +/// Figma Row / Spec. Presentational only. Callers pass already-resolved [label] and [value] strings. +/// Tappable rows pass [onTap] and an affordance [trailing] glyph. +class QuantusDataRow extends StatelessWidget { + final String label; + final String value; + final VoidCallback? onTap; + final Widget? trailing; + + const QuantusDataRow({super.key, required this.label, required this.value, this.onTap, this.trailing}); + + @override + Widget build(BuildContext context) { + final colors = context.colorsV3; + final text = context.themeTextV3; + + final row = Container( + width: double.infinity, + constraints: const BoxConstraints(minHeight: 46), + padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 13), + decoration: BoxDecoration( + borderRadius: context.radiusV3.mdBorder, + border: Border.all(color: colors.borderHairline, width: 1), + ), + child: Row( + children: [ + Text(label.toUpperCase(), style: _labelStyle(text, colors), maxLines: 1, softWrap: false), + const SizedBox(width: 12), + Expanded( + child: Text( + value, + style: text.dataAddress.copyWith(color: colors.textContent), + textAlign: TextAlign.right, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ), + if (trailing != null) ...[const SizedBox(width: 12), trailing!], + ], + ), + ); + + if (onTap == null) return row; + + return GestureDetector(onTap: onTap, behavior: HitTestBehavior.opaque, child: row); + } + + /// Figma Row / Spec label: Geist Mono Medium 10, tracking 1, from Label / Monogram. + TextStyle _labelStyle(AppTextThemeV3 text, AppColorsV3 colors) { + return text.labelMonogram.copyWith(fontSize: 10, letterSpacing: 1, color: colors.textMuted); + } +} diff --git a/quantus_sdk/test/ui/quantus_data_row_test.dart b/quantus_sdk/test/ui/quantus_data_row_test.dart new file mode 100644 index 000000000..67a575187 --- /dev/null +++ b/quantus_sdk/test/ui/quantus_data_row_test.dart @@ -0,0 +1,80 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + const colors = AppColorsV3.dark(); + const text = AppTextThemeV3.standard(); + + Future pumpRow(WidgetTester tester, Widget row) async { + await tester.pumpWidget( + MediaQuery( + data: const MediaQueryData(size: Size(375, 667)), + child: Builder( + builder: (context) => MaterialApp( + theme: AppTheme.darkTheme(context), + home: Scaffold(body: row), + ), + ), + ), + ); + await tester.pump(); + } + + BoxDecoration decorationAround(WidgetTester tester, String text) { + final container = tester.widget( + find.ancestor(of: find.text(text), matching: find.byType(Container)).first, + ); + return container.decoration! as BoxDecoration; + } + + testWidgets('renders uppercase label and value', (tester) async { + await pumpRow(tester, const QuantusDataRow(label: 'Hash', value: '0xa5f3c2...e3a6c8f1')); + + expect(find.text('HASH'), findsOneWidget); + expect(find.text('Hash'), findsNothing); + expect(find.text('0xa5f3c2...e3a6c8f1'), findsOneWidget); + }); + + testWidgets('paints hairline border and v3 md radius', (tester) async { + await pumpRow(tester, const QuantusDataRow(label: 'Hash', value: '0xabc')); + + final decoration = decorationAround(tester, 'HASH'); + final border = decoration.border! as Border; + expect(border.top.color, colors.borderHairline); + expect(border.top.width, 1); + expect(decoration.borderRadius, const AppRadiusV3.standard().mdBorder); + }); + + testWidgets('uses muted label and content value tokens', (tester) async { + await pumpRow(tester, const QuantusDataRow(label: 'Hash', value: '0xabc')); + + final label = tester.widget(find.text('HASH')); + expect(label.style?.color, colors.textMuted); + expect(label.style?.fontSize, 10); + expect(label.style?.letterSpacing, 1); + expect(label.style?.fontFamily, AppTextTheme.fontFamilySecondary); + + final value = tester.widget(find.text('0xabc')); + expect(value.style?.color, colors.textContent); + expect(value.style?.fontSize, text.dataAddress.fontSize); + expect(value.style?.fontFamily, AppTextTheme.fontFamilySecondary); + expect(value.textAlign, TextAlign.right); + }); + + testWidgets('tapping invokes onTap', (tester) async { + var tapped = false; + await pumpRow(tester, QuantusDataRow(label: 'Hash', value: '0xabc', onTap: () => tapped = true)); + + await tester.tap(find.text('HASH')); + expect(tapped, isTrue); + }); + + testWidgets('shows trailing glyph when provided', (tester) async { + await pumpRow(tester, const QuantusDataRow(label: 'Hash', value: '0xabc', trailing: Icon(Icons.chevron_right))); + + expect(find.byIcon(Icons.chevron_right), findsOneWidget); + }); +} From 6b182d46fdc5b36a0fd540aa8e7cd2003b1c722e Mon Sep 17 00:00:00 2001 From: Beast Date: Tue, 18 Aug 2026 15:11:00 +0800 Subject: [PATCH 15/38] feat: add icon component --- quantus_sdk/assets/icons/caret_down.svg | 3 + quantus_sdk/assets/icons/chevron_left.svg | 3 + quantus_sdk/assets/icons/chevron_right.svg | 3 + quantus_sdk/assets/icons/kebab.svg | 5 ++ quantus_sdk/assets/icons/lock.svg | 4 ++ quantus_sdk/assets/icons/plus.svg | 3 + quantus_sdk/assets/icons/swap_vertical.svg | 4 ++ quantus_sdk/lib/src/ui/components/index.dart | 1 + .../lib/src/ui/components/quantus_icon.dart | 49 +++++++++++++++ quantus_sdk/pubspec.yaml | 1 + quantus_sdk/test/ui/quantus_icon_test.dart | 59 +++++++++++++++++++ 11 files changed, 135 insertions(+) create mode 100644 quantus_sdk/assets/icons/caret_down.svg create mode 100644 quantus_sdk/assets/icons/chevron_left.svg create mode 100644 quantus_sdk/assets/icons/chevron_right.svg create mode 100644 quantus_sdk/assets/icons/kebab.svg create mode 100644 quantus_sdk/assets/icons/lock.svg create mode 100644 quantus_sdk/assets/icons/plus.svg create mode 100644 quantus_sdk/assets/icons/swap_vertical.svg create mode 100644 quantus_sdk/lib/src/ui/components/quantus_icon.dart create mode 100644 quantus_sdk/test/ui/quantus_icon_test.dart diff --git a/quantus_sdk/assets/icons/caret_down.svg b/quantus_sdk/assets/icons/caret_down.svg new file mode 100644 index 000000000..54209fd36 --- /dev/null +++ b/quantus_sdk/assets/icons/caret_down.svg @@ -0,0 +1,3 @@ + + + diff --git a/quantus_sdk/assets/icons/chevron_left.svg b/quantus_sdk/assets/icons/chevron_left.svg new file mode 100644 index 000000000..d3333fcea --- /dev/null +++ b/quantus_sdk/assets/icons/chevron_left.svg @@ -0,0 +1,3 @@ + + + diff --git a/quantus_sdk/assets/icons/chevron_right.svg b/quantus_sdk/assets/icons/chevron_right.svg new file mode 100644 index 000000000..270adaca4 --- /dev/null +++ b/quantus_sdk/assets/icons/chevron_right.svg @@ -0,0 +1,3 @@ + + + diff --git a/quantus_sdk/assets/icons/kebab.svg b/quantus_sdk/assets/icons/kebab.svg new file mode 100644 index 000000000..577f77595 --- /dev/null +++ b/quantus_sdk/assets/icons/kebab.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/quantus_sdk/assets/icons/lock.svg b/quantus_sdk/assets/icons/lock.svg new file mode 100644 index 000000000..c4d6426f1 --- /dev/null +++ b/quantus_sdk/assets/icons/lock.svg @@ -0,0 +1,4 @@ + + + + diff --git a/quantus_sdk/assets/icons/plus.svg b/quantus_sdk/assets/icons/plus.svg new file mode 100644 index 000000000..9d342250e --- /dev/null +++ b/quantus_sdk/assets/icons/plus.svg @@ -0,0 +1,3 @@ + + + diff --git a/quantus_sdk/assets/icons/swap_vertical.svg b/quantus_sdk/assets/icons/swap_vertical.svg new file mode 100644 index 000000000..9ffa683ce --- /dev/null +++ b/quantus_sdk/assets/icons/swap_vertical.svg @@ -0,0 +1,4 @@ + + + + diff --git a/quantus_sdk/lib/src/ui/components/index.dart b/quantus_sdk/lib/src/ui/components/index.dart index bc132c722..25b24116d 100644 --- a/quantus_sdk/lib/src/ui/components/index.dart +++ b/quantus_sdk/lib/src/ui/components/index.dart @@ -6,6 +6,7 @@ export 'quantus_banner.dart'; export 'quantus_dialog.dart'; export 'quantus_action_sheet.dart'; export 'loader.dart'; +export 'quantus_icon.dart'; export 'quantus_icon_button.dart'; export 'glass_button_base.dart'; export 'decoded_call_view.dart'; diff --git a/quantus_sdk/lib/src/ui/components/quantus_icon.dart b/quantus_sdk/lib/src/ui/components/quantus_icon.dart new file mode 100644 index 000000000..abe8ef031 --- /dev/null +++ b/quantus_sdk/lib/src/ui/components/quantus_icon.dart @@ -0,0 +1,49 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +/// Glyphs from the v3 Figma interim icon set (Phosphor Light replacement pending). +enum QuantusIcons { + kebab('assets/icons/kebab.svg'), + chevronRight('assets/icons/chevron_right.svg'), + chevronLeft('assets/icons/chevron_left.svg'), + caretDown('assets/icons/caret_down.svg'), + plus('assets/icons/plus.svg'), + swapVertical('assets/icons/swap_vertical.svg'), + lock('assets/icons/lock.svg'); + + const QuantusIcons(this.assetPath); + + /// Package-relative SVG path for this glyph. + final String assetPath; +} + +/// Tinted 20px Figma glyph. Pass [color] to override [AppColorsV3.textMuted]. +class QuantusIcon extends StatelessWidget { + final QuantusIcons icon; + final double size; + final Color? color; + final String? semanticLabel; + + const QuantusIcon(this.icon, {super.key, this.size = 20, this.color, this.semanticLabel}); + + @override + Widget build(BuildContext context) { + final Color resolvedColor = color ?? context.colorsV3.textMuted; + + return SizedBox( + width: size, + height: size, + child: SvgPicture.asset( + icon.assetPath, + package: 'quantus_sdk', + width: size, + height: size, + fit: BoxFit.contain, + colorFilter: ColorFilter.mode(resolvedColor, BlendMode.srcIn), + excludeFromSemantics: semanticLabel == null, + semanticsLabel: semanticLabel, + ), + ); + } +} diff --git a/quantus_sdk/pubspec.yaml b/quantus_sdk/pubspec.yaml index 4d534719c..2e8a091b4 100644 --- a/quantus_sdk/pubspec.yaml +++ b/quantus_sdk/pubspec.yaml @@ -64,3 +64,4 @@ polkadart: flutter: assets: - assets/v2/uppercase_q_black_bg.png + - assets/icons/ diff --git a/quantus_sdk/test/ui/quantus_icon_test.dart b/quantus_sdk/test/ui/quantus_icon_test.dart new file mode 100644 index 000000000..e832a6d82 --- /dev/null +++ b/quantus_sdk/test/ui/quantus_icon_test.dart @@ -0,0 +1,59 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + const colors = AppColorsV3.dark(); + + Future pumpIcon(WidgetTester tester, Widget icon) async { + await tester.pumpWidget( + MediaQuery( + data: const MediaQueryData(size: Size(375, 667)), + child: Builder( + builder: (context) => MaterialApp( + theme: AppTheme.darkTheme(context), + home: Scaffold(body: icon), + ), + ), + ), + ); + await tester.pump(); + } + + SvgPicture svgOf(WidgetTester tester) => tester.widget(find.byType(SvgPicture)); + + SvgAssetLoader loaderOf(WidgetTester tester) => svgOf(tester).bytesLoader as SvgAssetLoader; + + testWidgets('loads every glyph from the SDK package', (tester) async { + for (final icon in QuantusIcons.values) { + await pumpIcon(tester, QuantusIcon(icon)); + + final loader = loaderOf(tester); + expect(loader.assetName, icon.assetPath, reason: '$icon asset'); + expect(loader.packageName, 'quantus_sdk', reason: '$icon package'); + } + }); + + testWidgets('defaults to 20px muted tint', (tester) async { + await pumpIcon(tester, const QuantusIcon(QuantusIcons.plus)); + + final svg = svgOf(tester); + expect(svg.width, 20); + expect(svg.height, 20); + expect(svg.colorFilter, ColorFilter.mode(colors.textMuted, BlendMode.srcIn)); + expect(tester.getSize(find.byType(QuantusIcon)), const Size(20, 20)); + }); + + testWidgets('honors size and color overrides', (tester) async { + await pumpIcon(tester, QuantusIcon(QuantusIcons.lock, size: 16, color: colors.accentFlare)); + + final svg = svgOf(tester); + expect(svg.width, 16); + expect(svg.height, 16); + expect(svg.colorFilter, ColorFilter.mode(colors.accentFlare, BlendMode.srcIn)); + expect(tester.getSize(find.byType(QuantusIcon)), const Size(16, 16)); + }); +} From bd11d5b92bade755c63e6e2b219395d1171d4127 Mon Sep 17 00:00:00 2001 From: Beast Date: Tue, 18 Aug 2026 16:25:04 +0800 Subject: [PATCH 16/38] feat: add new skeleton component --- mobile-app/lib/v2/components/skeleton.dart | 88 ------------------ .../lib/v2/screens/home/home_screen.dart | 1 - .../screens/multisig/add_multisig_screen.dart | 1 - .../multisig/discover_multisig_screen.dart | 1 - .../screens/send/select_recipient_screen.dart | 1 - .../settings/mining_rewards_screen.dart | 1 - quantus_sdk/lib/src/ui/components/index.dart | 1 + .../lib/src/ui/components/skeleton.dart | 91 +++++++++++++++++++ quantus_sdk/test/ui/skeleton_test.dart | 59 ++++++++++++ 9 files changed, 151 insertions(+), 93 deletions(-) create mode 100644 quantus_sdk/lib/src/ui/components/skeleton.dart create mode 100644 quantus_sdk/test/ui/skeleton_test.dart diff --git a/mobile-app/lib/v2/components/skeleton.dart b/mobile-app/lib/v2/components/skeleton.dart index 13bca7cd0..e451d1dca 100644 --- a/mobile-app/lib/v2/components/skeleton.dart +++ b/mobile-app/lib/v2/components/skeleton.dart @@ -1,94 +1,6 @@ import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; -/// A skeleton widget with shimmer animation for loading states -class Skeleton extends StatefulWidget { - final double? width; - final double? height; - final BorderRadius? borderRadius; - final Duration duration; - - static const defaultDuration = Duration(milliseconds: 1200); - - const Skeleton({super.key, this.width, this.height = 16, this.borderRadius, this.duration = defaultDuration}); - - /// Creates a circular skeleton (useful for avatars) - Skeleton.circular({super.key, required double size, this.duration = defaultDuration}) - : width = size, - height = size, - borderRadius = BorderRadius.circular(size); - - @override - State createState() => _SkeletonState(); -} - -class _SkeletonState extends State with SingleTickerProviderStateMixin { - late AnimationController _controller; - late Animation _animation; - - @override - void initState() { - super.initState(); - _controller = AnimationController(vsync: this, duration: widget.duration)..repeat(); - - _animation = Tween( - begin: -2, - end: 2, - ).animate(CurvedAnimation(parent: _controller, curve: Curves.easeInOutSine)); - } - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - final borderRadius = widget.borderRadius ?? BorderRadius.circular(4); - - return AnimatedBuilder( - animation: _animation, - builder: (context, child) { - return Container( - width: widget.width, - height: widget.height, - decoration: BoxDecoration(borderRadius: borderRadius, color: context.colors.skeletonBase), - child: Container( - width: widget.width, - height: widget.height, - decoration: BoxDecoration( - borderRadius: borderRadius, - gradient: LinearGradient( - begin: Alignment.centerLeft, - end: Alignment.centerRight, - colors: [ - context.colors.skeletonHighlightA.useOpacity(0.2), - context.colors.skeletonHighlightB.useOpacity(0.2), - context.colors.skeletonHighlightA.useOpacity(0.2), - ], - stops: const [0.0, 0.5, 1.0], - transform: _SlideGradientTransform(_animation.value), - ), - ), - ), - ); - }, - ); - } -} - -class _SlideGradientTransform extends GradientTransform { - final double slidePercent; - - const _SlideGradientTransform(this.slidePercent); - - @override - Matrix4? transform(Rect bounds, {TextDirection? textDirection}) { - return Matrix4.translationValues(bounds.width * slidePercent, 0.0, 0.0); - } -} - class TxItemSkeleton extends StatelessWidget { const TxItemSkeleton({super.key}); diff --git a/mobile-app/lib/v2/screens/home/home_screen.dart b/mobile-app/lib/v2/screens/home/home_screen.dart index 553eb9af3..ccea30ddf 100644 --- a/mobile-app/lib/v2/screens/home/home_screen.dart +++ b/mobile-app/lib/v2/screens/home/home_screen.dart @@ -5,7 +5,6 @@ import 'package:flutter_riverpod/legacy.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/v2/components/dotted_border.dart'; -import 'package:resonance_network_wallet/v2/components/skeleton.dart'; import 'package:resonance_network_wallet/v2/components/shared_address_action_sheet.dart'; import 'package:resonance_network_wallet/services/global_history_polling_service.dart'; import 'package:resonance_network_wallet/services/telemetry_service.dart'; diff --git a/mobile-app/lib/v2/screens/multisig/add_multisig_screen.dart b/mobile-app/lib/v2/screens/multisig/add_multisig_screen.dart index f26680f31..d438b08be 100644 --- a/mobile-app/lib/v2/screens/multisig/add_multisig_screen.dart +++ b/mobile-app/lib/v2/screens/multisig/add_multisig_screen.dart @@ -4,7 +4,6 @@ import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/v2/components/multisig_signer_list_tile.dart'; import 'package:resonance_network_wallet/v2/components/multisig_threshold_slider.dart'; import 'package:resonance_network_wallet/v2/components/name_field.dart'; -import 'package:resonance_network_wallet/v2/components/skeleton.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; diff --git a/mobile-app/lib/v2/screens/multisig/discover_multisig_screen.dart b/mobile-app/lib/v2/screens/multisig/discover_multisig_screen.dart index f0d35699c..76a4b5723 100644 --- a/mobile-app/lib/v2/screens/multisig/discover_multisig_screen.dart +++ b/mobile-app/lib/v2/screens/multisig/discover_multisig_screen.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:resonance_network_wallet/v2/components/skeleton.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/multisig_providers.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; diff --git a/mobile-app/lib/v2/screens/send/select_recipient_screen.dart b/mobile-app/lib/v2/screens/send/select_recipient_screen.dart index 396da0b86..4b0bf63eb 100644 --- a/mobile-app/lib/v2/screens/send/select_recipient_screen.dart +++ b/mobile-app/lib/v2/screens/send/select_recipient_screen.dart @@ -3,7 +3,6 @@ import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:resonance_network_wallet/v2/components/dotted_border.dart'; -import 'package:resonance_network_wallet/v2/components/skeleton.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/route_intent_providers.dart'; diff --git a/mobile-app/lib/v2/screens/settings/mining_rewards_screen.dart b/mobile-app/lib/v2/screens/settings/mining_rewards_screen.dart index 98d5049aa..8a9fcbbc2 100644 --- a/mobile-app/lib/v2/screens/settings/mining_rewards_screen.dart +++ b/mobile-app/lib/v2/screens/settings/mining_rewards_screen.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:resonance_network_wallet/v2/components/skeleton.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/mining_rewards_provider.dart'; diff --git a/quantus_sdk/lib/src/ui/components/index.dart b/quantus_sdk/lib/src/ui/components/index.dart index 25b24116d..239137810 100644 --- a/quantus_sdk/lib/src/ui/components/index.dart +++ b/quantus_sdk/lib/src/ui/components/index.dart @@ -1,4 +1,5 @@ export 'quantus_button.dart'; +export 'skeleton.dart'; export 'quantus_text_field.dart'; export 'quantus_badge.dart'; export 'quantus_data_row.dart'; diff --git a/quantus_sdk/lib/src/ui/components/skeleton.dart b/quantus_sdk/lib/src/ui/components/skeleton.dart new file mode 100644 index 000000000..e398a0779 --- /dev/null +++ b/quantus_sdk/lib/src/ui/components/skeleton.dart @@ -0,0 +1,91 @@ +import 'package:flutter/material.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +/// Shimmering loading bone. Compose rows and screens from sized instances. +class Skeleton extends StatefulWidget { + final double? width; + final double? height; + final BorderRadius? borderRadius; + final Duration duration; + + static const defaultDuration = Duration(milliseconds: 1200); + + const Skeleton({super.key, this.width, this.height = 16, this.borderRadius, this.duration = defaultDuration}); + + /// Circular bone for avatars and icon placeholders. + Skeleton.circular({super.key, required double size, this.duration = defaultDuration}) + : width = size, + height = size, + borderRadius = BorderRadius.circular(size); + + @override + State createState() => _SkeletonState(); +} + +class _SkeletonState extends State with SingleTickerProviderStateMixin { + late AnimationController _controller; + late Animation _animation; + + @override + void initState() { + super.initState(); + _controller = AnimationController(vsync: this, duration: widget.duration)..repeat(); + + _animation = Tween( + begin: -2, + end: 2, + ).animate(CurvedAnimation(parent: _controller, curve: Curves.easeInOutSine)); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final colors = context.colorsV3; + final borderRadius = widget.borderRadius ?? context.radiusV3.xsBorder; + + return AnimatedBuilder( + animation: _animation, + builder: (context, child) { + return Container( + width: widget.width, + height: widget.height, + decoration: BoxDecoration(borderRadius: borderRadius, color: colors.bgSurface), + child: Container( + width: widget.width, + height: widget.height, + decoration: BoxDecoration( + borderRadius: borderRadius, + gradient: LinearGradient( + begin: Alignment.centerLeft, + end: Alignment.centerRight, + colors: [ + colors.bgVoid.useOpacity(0.2), + colors.textMuted2.useOpacity(0.2), + colors.bgVoid.useOpacity(0.2), + ], + stops: const [0.0, 0.5, 1.0], + transform: _SlideGradientTransform(_animation.value), + ), + ), + ), + ); + }, + ); + } +} + +class _SlideGradientTransform extends GradientTransform { + final double slidePercent; + + const _SlideGradientTransform(this.slidePercent); + + @override + Matrix4? transform(Rect bounds, {TextDirection? textDirection}) { + return Matrix4.translationValues(bounds.width * slidePercent, 0.0, 0.0); + } +} diff --git a/quantus_sdk/test/ui/skeleton_test.dart b/quantus_sdk/test/ui/skeleton_test.dart new file mode 100644 index 000000000..42cc1ed83 --- /dev/null +++ b/quantus_sdk/test/ui/skeleton_test.dart @@ -0,0 +1,59 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + const colors = AppColorsV3.dark(); + + Future pumpSkeleton(WidgetTester tester, Widget skeleton) async { + await tester.pumpWidget( + MediaQuery( + data: const MediaQueryData(size: Size(375, 667)), + child: Builder( + builder: (context) => MaterialApp( + theme: AppTheme.darkTheme(context), + home: Scaffold(body: skeleton), + ), + ), + ), + ); + await tester.pump(); + } + + List decorations(WidgetTester tester) { + return tester + .widgetList(find.descendant(of: find.byType(Skeleton), matching: find.byType(Container))) + .map((container) => container.decoration! as BoxDecoration) + .toList(); + } + + testWidgets('paints v3 surface fill and default height', (tester) async { + await pumpSkeleton(tester, const Skeleton(width: 180)); + + expect(tester.getSize(find.byType(Skeleton)), const Size(180, 16)); + + final outer = decorations(tester).first; + expect(outer.color, colors.bgSurface); + expect(outer.borderRadius, const AppRadiusV3.standard().xsBorder); + }); + + testWidgets('circular constructor is a square pill of the given size', (tester) async { + await pumpSkeleton(tester, Skeleton.circular(size: 40)); + + expect(tester.getSize(find.byType(Skeleton)), const Size(40, 40)); + expect(decorations(tester).first.borderRadius, BorderRadius.circular(40)); + }); + + testWidgets('shimmer highlights use v3 tokens', (tester) async { + await pumpSkeleton(tester, const Skeleton(width: 110, height: 10)); + + final gradient = decorations(tester)[1].gradient! as LinearGradient; + expect(gradient.colors, [ + colors.bgVoid.useOpacity(0.2), + colors.textMuted2.useOpacity(0.2), + colors.bgVoid.useOpacity(0.2), + ]); + }); +} From b8938e136527ebf5b73f9957475ed24b453fbb4b Mon Sep 17 00:00:00 2001 From: Beast Date: Tue, 18 Aug 2026 16:44:00 +0800 Subject: [PATCH 17/38] feat: add step progression row component --- quantus_sdk/lib/src/ui/components/index.dart | 1 + .../src/ui/components/quantus_step_row.dart | 189 ++++++++++++++++++ .../test/ui/quantus_step_row_test.dart | 135 +++++++++++++ 3 files changed, 325 insertions(+) create mode 100644 quantus_sdk/lib/src/ui/components/quantus_step_row.dart create mode 100644 quantus_sdk/test/ui/quantus_step_row_test.dart diff --git a/quantus_sdk/lib/src/ui/components/index.dart b/quantus_sdk/lib/src/ui/components/index.dart index 239137810..7703321f1 100644 --- a/quantus_sdk/lib/src/ui/components/index.dart +++ b/quantus_sdk/lib/src/ui/components/index.dart @@ -3,6 +3,7 @@ export 'skeleton.dart'; export 'quantus_text_field.dart'; export 'quantus_badge.dart'; export 'quantus_data_row.dart'; +export 'quantus_step_row.dart'; export 'quantus_banner.dart'; export 'quantus_dialog.dart'; export 'quantus_action_sheet.dart'; diff --git a/quantus_sdk/lib/src/ui/components/quantus_step_row.dart b/quantus_sdk/lib/src/ui/components/quantus_step_row.dart new file mode 100644 index 000000000..eb7d63b95 --- /dev/null +++ b/quantus_sdk/lib/src/ui/components/quantus_step_row.dart @@ -0,0 +1,189 @@ +import 'package:flutter/material.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +/// Tracking-timeline states for [QuantusStepRow]. +/// +/// Done settles, active is in flight, pending has not started, ended stopped. +enum StepRowState { done, active, pending, ended } + +/// Figma Block / Step Row. Presentational only. Callers pass already-resolved [label] and [substate]. +/// +/// Takes the available width. Parent owns [state]; Active spins the flare mark. +class QuantusStepRow extends StatefulWidget { + final StepRowState state; + final String label; + final String? substate; + + const QuantusStepRow({super.key, required this.state, required this.label, this.substate}); + + @override + State createState() => _QuantusStepRowState(); +} + +class _QuantusStepRowState extends State with SingleTickerProviderStateMixin { + static const _spinDuration = Duration(seconds: 1); + + late final AnimationController _spin; + + bool get _isActive => widget.state == StepRowState.active; + + @override + void initState() { + super.initState(); + _spin = AnimationController(vsync: this, duration: _spinDuration); + if (_isActive) _spin.repeat(); + } + + @override + void didUpdateWidget(QuantusStepRow oldWidget) { + super.didUpdateWidget(oldWidget); + if (_isActive) { + if (!_spin.isAnimating) _spin.repeat(); + } else if (_spin.isAnimating) { + _spin + ..stop() + ..reset(); + } + } + + @override + void dispose() { + _spin.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return SizedBox( + width: double.infinity, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 12), + child: Row( + children: [ + _StepStatusMark(state: widget.state, turns: _spin), + const SizedBox(width: 14), + Expanded( + child: _StepCopy(state: widget.state, label: widget.label, substate: widget.substate), + ), + ], + ), + ), + ); + } +} + +class _StepStatusMark extends StatelessWidget { + static const _slot = 22.0; + + final StepRowState state; + final Animation turns; + + const _StepStatusMark({required this.state, required this.turns}); + + @override + Widget build(BuildContext context) { + final colors = context.colorsV3; + final mark = switch (state) { + StepRowState.pending => _PendingDot(color: colors.bgSurface2), + StepRowState.done => _Glyph(text: '✓', color: colors.semanticSage), + StepRowState.active => RotationTransition( + turns: turns, + child: _Glyph(text: '◌', color: colors.accentFlare), + ), + StepRowState.ended => _Glyph(text: '⊘', color: colors.semanticSand), + }; + + return SizedBox( + width: _slot, + height: _slot, + child: Center(child: mark), + ); + } +} + +class _Glyph extends StatelessWidget { + final String text; + final Color color; + + const _Glyph({required this.text, required this.color}); + + @override + Widget build(BuildContext context) { + return Text( + text, + style: TextStyle( + fontFamily: AppTextTheme.fontFamily, + fontSize: 13, + fontWeight: FontWeight.w400, + height: 1, + color: color, + ), + ); + } +} + +class _PendingDot extends StatelessWidget { + final Color color; + + const _PendingDot({required this.color}); + + @override + Widget build(BuildContext context) { + return Container( + width: 5, + height: 5, + decoration: BoxDecoration(color: color, shape: BoxShape.circle), + ); + } +} + +class _StepCopy extends StatelessWidget { + final StepRowState state; + final String label; + final String? substate; + + const _StepCopy({required this.state, required this.label, this.substate}); + + bool get _showSubstate { + return (state == StepRowState.active || state == StepRowState.ended) && (substate?.isNotEmpty ?? false); + } + + @override + Widget build(BuildContext context) { + final colors = context.colorsV3; + final text = context.themeTextV3; + final emphasized = state == StepRowState.active || state == StepRowState.ended; + final labelStyle = (emphasized ? text.bodyEmphasis : text.body).copyWith( + color: emphasized ? colors.textContent : colors.textMuted2, + ); + final substateText = substate; + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text(label, style: labelStyle, maxLines: 1, overflow: TextOverflow.ellipsis), + if (_showSubstate && substateText != null) + Padding( + padding: const EdgeInsets.only(top: 4), + child: Text( + substateText.toUpperCase(), + style: _substateStyle(text, colors), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ), + ], + ); + } + + /// Figma substate microlabel: Geist Mono Regular 10, tracking 0.8, from Label / Monogram. + TextStyle _substateStyle(AppTextThemeV3 text, AppColorsV3 colors) { + return text.labelMonogram.copyWith( + fontSize: 10, + fontWeight: FontWeight.w400, + letterSpacing: 0.8, + color: colors.textMuted2, + ); + } +} diff --git a/quantus_sdk/test/ui/quantus_step_row_test.dart b/quantus_sdk/test/ui/quantus_step_row_test.dart new file mode 100644 index 000000000..d1f51d5c0 --- /dev/null +++ b/quantus_sdk/test/ui/quantus_step_row_test.dart @@ -0,0 +1,135 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + const colors = AppColorsV3.dark(); + const text = AppTextThemeV3.standard(); + + Future pumpRow(WidgetTester tester, Widget row) async { + await tester.pumpWidget( + MediaQuery( + data: const MediaQueryData(size: Size(375, 667)), + child: Builder( + builder: (context) => MaterialApp( + theme: AppTheme.darkTheme(context), + home: Scaffold(body: row), + ), + ), + ), + ); + await tester.pump(); + } + + Finder pendingDot() { + return find.byWidgetPredicate((widget) { + if (widget is! Container) return false; + final decoration = widget.decoration; + return decoration is BoxDecoration && + decoration.color == colors.bgSurface2 && + decoration.shape == BoxShape.circle; + }); + } + + testWidgets('done paints sage check and muted label', (tester) async { + await pumpRow(tester, const QuantusStepRow(state: StepRowState.done, label: 'Preparing')); + + expect(find.text('Preparing'), findsOneWidget); + expect(find.text('✓'), findsOneWidget); + expect(find.text('◌'), findsNothing); + + final mark = tester.widget(find.text('✓')); + expect(mark.style?.color, colors.semanticSage); + expect(mark.style?.fontSize, 13); + expect(mark.style?.fontFamily, AppTextTheme.fontFamily); + + final label = tester.widget(find.text('Preparing')); + expect(label.style?.color, colors.textMuted2); + expect(label.style?.fontSize, text.body.fontSize); + expect(label.style?.fontWeight, text.body.fontWeight); + }); + + testWidgets('active paints spinning flare mark, content label, and uppercase substate', (tester) async { + await pumpRow( + tester, + const QuantusStepRow(state: StepRowState.active, label: 'Building privacy proof', substate: 'substate · detail'), + ); + + expect(find.text('Building privacy proof'), findsOneWidget); + expect(find.text('◌'), findsOneWidget); + expect(find.descendant(of: find.byType(QuantusStepRow), matching: find.byType(RotationTransition)), findsOneWidget); + expect(find.text('SUBSTATE · DETAIL'), findsOneWidget); + expect(find.text('substate · detail'), findsNothing); + + final mark = tester.widget(find.text('◌')); + expect(mark.style?.color, colors.accentFlare); + expect(mark.style?.fontSize, 13); + + final label = tester.widget(find.text('Building privacy proof')); + expect(label.style?.color, colors.textContent); + expect(label.style?.fontWeight, text.bodyEmphasis.fontWeight); + + final substate = tester.widget(find.text('SUBSTATE · DETAIL')); + expect(substate.style?.color, colors.textMuted2); + expect(substate.style?.fontSize, 10); + expect(substate.style?.letterSpacing, 0.8); + expect(substate.style?.fontFamily, AppTextTheme.fontFamilySecondary); + expect(substate.style?.fontWeight, FontWeight.w400); + }); + + testWidgets('pending paints muted dot and hides substate', (tester) async { + await pumpRow( + tester, + const QuantusStepRow(state: StepRowState.pending, label: 'Submitting to network', substate: 'hidden'), + ); + + expect(find.text('Submitting to network'), findsOneWidget); + expect(find.text('✓'), findsNothing); + expect(find.text('HIDDEN'), findsNothing); + expect(pendingDot(), findsOneWidget); + expect(tester.getSize(pendingDot()), const Size(5, 5)); + + final label = tester.widget(find.text('Submitting to network')); + expect(label.style?.color, colors.textMuted2); + }); + + testWidgets('ended paints sand mark, content label, and substate', (tester) async { + await pumpRow(tester, const QuantusStepRow(state: StepRowState.ended, label: 'Cancelled', substate: 'user abort')); + + expect(find.text('⊘'), findsOneWidget); + expect(find.text('Cancelled'), findsOneWidget); + expect(find.text('USER ABORT'), findsOneWidget); + expect(find.descendant(of: find.byType(QuantusStepRow), matching: find.byType(RotationTransition)), findsNothing); + + final mark = tester.widget(find.text('⊘')); + expect(mark.style?.color, colors.semanticSand); + + final label = tester.widget(find.text('Cancelled')); + expect(label.style?.color, colors.textContent); + expect(label.style?.fontWeight, text.bodyEmphasis.fontWeight); + }); + + testWidgets('expands to the available width', (tester) async { + await pumpRow( + tester, + const SizedBox( + width: 300, + child: QuantusStepRow(state: StepRowState.done, label: 'Preparing'), + ), + ); + + expect(tester.getSize(find.byType(QuantusStepRow)).width, 300); + }); + + testWidgets('rebuilding with a new state replaces the mark', (tester) async { + await pumpRow(tester, const QuantusStepRow(state: StepRowState.pending, label: 'Preparing')); + expect(pendingDot(), findsOneWidget); + + await pumpRow(tester, const QuantusStepRow(state: StepRowState.active, label: 'Preparing')); + expect(find.text('◌'), findsOneWidget); + expect(find.descendant(of: find.byType(QuantusStepRow), matching: find.byType(RotationTransition)), findsOneWidget); + expect(pendingDot(), findsNothing); + }); +} From 6f7a92dca85a5620524a227c9fc6adedeb319e16 Mon Sep 17 00:00:00 2001 From: Beast Date: Tue, 18 Aug 2026 20:03:53 +0800 Subject: [PATCH 18/38] feat: use SDK theme and components --- cold-wallet-app/lib/app.dart | 2 +- .../lib/components/animated_ur_qr.dart | 86 ----- .../lib/components/back_button.dart | 32 -- .../lib/components/base_background.dart | 13 - .../lib/components/call_detail_view.dart | 2 - .../lib/components/confirm_dialog.dart | 2 +- .../lib/components/detail_row.dart | 3 +- cold-wallet-app/lib/components/loader.dart | 21 -- .../lib/components/mnemonic_grid.dart | 4 +- .../lib/components/qr_tuning_controls.dart | 3 +- .../lib/components/quantus_button.dart | 178 ---------- .../lib/components/quantus_qr.dart | 35 -- .../lib/components/scaffold_base.dart | 107 ------ .../scaffold_base_bottom_content.dart | 21 -- .../lib/components/v2_app_bar.dart | 42 --- .../lib/screens/create_wallet_screen.dart | 7 - cold-wallet-app/lib/screens/home_screen.dart | 7 +- .../lib/screens/import_wallet_screen.dart | 6 - cold-wallet-app/lib/screens/lock_screen.dart | 5 +- cold-wallet-app/lib/screens/root_gate.dart | 6 +- .../lib/screens/scan_transaction_screen.dart | 2 - .../secure_element_warning_screen.dart | 7 +- .../lib/screens/set_password_screen.dart | 7 +- .../lib/screens/settings_screen.dart | 5 +- .../lib/screens/show_key_screen.dart | 7 +- .../lib/screens/sign_transaction_screen.dart | 7 - .../lib/screens/welcome_screen.dart | 6 +- .../lib/shared/context_extensions.dart | 6 - cold-wallet-app/lib/theme/app_colors.dart | 332 ------------------ cold-wallet-app/lib/theme/app_spacing.dart | 282 --------------- .../lib/theme/app_text_styles.dart | 251 ------------- cold-wallet-app/lib/theme/app_theme.dart | 55 --- .../lib/widgets/change_password_sheet.dart | 4 +- .../lib/widgets/connectivity_guard.dart | 5 +- .../lib/widgets/password_field.dart | 3 +- .../test/change_password_sheet_test.dart | 2 +- .../lib/src/ui/components/animated_ur_qr.dart | 69 ++-- quantus_sdk/test/ui/animated_ur_qr_test.dart | 137 ++++++++ 38 files changed, 203 insertions(+), 1566 deletions(-) delete mode 100644 cold-wallet-app/lib/components/animated_ur_qr.dart delete mode 100644 cold-wallet-app/lib/components/back_button.dart delete mode 100644 cold-wallet-app/lib/components/base_background.dart delete mode 100644 cold-wallet-app/lib/components/loader.dart delete mode 100644 cold-wallet-app/lib/components/quantus_button.dart delete mode 100644 cold-wallet-app/lib/components/quantus_qr.dart delete mode 100644 cold-wallet-app/lib/components/scaffold_base.dart delete mode 100644 cold-wallet-app/lib/components/scaffold_base_bottom_content.dart delete mode 100644 cold-wallet-app/lib/components/v2_app_bar.dart delete mode 100644 cold-wallet-app/lib/shared/context_extensions.dart delete mode 100644 cold-wallet-app/lib/theme/app_colors.dart delete mode 100644 cold-wallet-app/lib/theme/app_spacing.dart delete mode 100644 cold-wallet-app/lib/theme/app_text_styles.dart delete mode 100644 cold-wallet-app/lib/theme/app_theme.dart create mode 100644 quantus_sdk/test/ui/animated_ur_qr_test.dart diff --git a/cold-wallet-app/lib/app.dart b/cold-wallet-app/lib/app.dart index 8b6370746..4b079d332 100644 --- a/cold-wallet-app/lib/app.dart +++ b/cold-wallet-app/lib/app.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:quantus_cold_wallet/providers/wallet_providers.dart'; import 'package:quantus_cold_wallet/screens/root_gate.dart'; -import 'package:quantus_cold_wallet/theme/app_theme.dart'; import 'package:quantus_cold_wallet/widgets/connectivity_guard.dart'; import 'package:quantus_cold_wallet/widgets/lock_overlay.dart'; diff --git a/cold-wallet-app/lib/components/animated_ur_qr.dart b/cold-wallet-app/lib/components/animated_ur_qr.dart deleted file mode 100644 index d3fc00fb7..000000000 --- a/cold-wallet-app/lib/components/animated_ur_qr.dart +++ /dev/null @@ -1,86 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/material.dart'; -import 'package:qr_flutter/qr_flutter.dart'; - -/// Renders a UR payload as a QR code. A multi-part UR is animated by cycling -/// through its fragments with a [Timer] (no post-frame callbacks). Reacts to -/// [fps], [paused] and [parts] changes so the animation can be tuned live. -/// -/// Every frame's QR is encoded once up front: encoding a dense QR takes long -/// enough that doing it inside build caps the real frame rate well below the -/// requested one. Painting a precomputed module matrix keeps ticks cheap. -class AnimatedUrQr extends StatefulWidget { - final List parts; - final int fps; - final bool paused; - final double size; - - const AnimatedUrQr({super.key, required this.parts, required this.fps, this.paused = false, this.size = 280}); - - @override - State createState() => _AnimatedUrQrState(); -} - -class _AnimatedUrQrState extends State { - Timer? _timer; - int _index = 0; - late List _painters; - - @override - void initState() { - super.initState(); - _painters = _buildPainters(); - _restartTimer(); - } - - List _buildPainters() => widget.parts - .map( - (part) => QrPainter.withQr( - qr: QrCode.fromData(data: part, errorCorrectLevel: QrErrorCorrectLevel.L), - gapless: true, - eyeStyle: const QrEyeStyle(eyeShape: QrEyeShape.square, color: Colors.black), - dataModuleStyle: const QrDataModuleStyle(dataModuleShape: QrDataModuleShape.square, color: Colors.black), - ), - ) - .toList(); - - @override - void didUpdateWidget(AnimatedUrQr oldWidget) { - super.didUpdateWidget(oldWidget); - final partsChanged = !identical(widget.parts, oldWidget.parts); - if (partsChanged) { - _painters = _buildPainters(); - _index = 0; - } - if (partsChanged || widget.fps != oldWidget.fps || widget.paused != oldWidget.paused) { - _restartTimer(); - } - } - - void _restartTimer() { - _timer?.cancel(); - _timer = null; - if (widget.paused || widget.parts.length <= 1) return; - _timer = Timer.periodic(Duration(milliseconds: (1000 / widget.fps).round()), (_) { - setState(() => _index = (_index + 1) % widget.parts.length); - }); - } - - @override - void dispose() { - _timer?.cancel(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Container( - width: widget.size, - height: widget.size, - padding: const EdgeInsets.all(16), - decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(16)), - child: CustomPaint(painter: _painters[_index]), - ); - } -} diff --git a/cold-wallet-app/lib/components/back_button.dart b/cold-wallet-app/lib/components/back_button.dart deleted file mode 100644 index c92deba44..000000000 --- a/cold-wallet-app/lib/components/back_button.dart +++ /dev/null @@ -1,32 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; -import 'package:quantus_cold_wallet/components/glass_button_base.dart'; -import 'package:quantus_cold_wallet/theme/app_colors.dart'; - -class AppBackButton extends StatelessWidget { - final VoidCallback? onTap; - - const AppBackButton({super.key, this.onTap}); - - @override - Widget build(BuildContext context) { - final double containerSize = 28; - final double iconSize = 24; - - return GestureDetector( - onTap: onTap ?? () => Navigator.pop(context), - child: GlassButtonBase( - buttonHeight: containerSize, - buttonWidth: containerSize, - borderRadius: BorderRadius.circular(containerSize / 2), - padding: const EdgeInsets.all(2), - child: SvgPicture.asset( - 'assets/v2/caret_left.svg', - width: iconSize, - height: iconSize, - colorFilter: ColorFilter.mode(context.colors.textPrimary, BlendMode.srcIn), - ), - ), - ); - } -} diff --git a/cold-wallet-app/lib/components/base_background.dart b/cold-wallet-app/lib/components/base_background.dart deleted file mode 100644 index b17c84a0b..000000000 --- a/cold-wallet-app/lib/components/base_background.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:quantus_cold_wallet/theme/app_colors.dart'; - -class BaseBackground extends StatelessWidget { - final Widget child; - - const BaseBackground({super.key, required this.child}); - - @override - Widget build(BuildContext context) { - return Container(color: context.colors.background, child: child); - } -} diff --git a/cold-wallet-app/lib/components/call_detail_view.dart b/cold-wallet-app/lib/components/call_detail_view.dart index c660eb68d..4914b0965 100644 --- a/cold-wallet-app/lib/components/call_detail_view.dart +++ b/cold-wallet-app/lib/components/call_detail_view.dart @@ -2,8 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:quantus_cold_wallet/components/detail_row.dart'; -import 'package:quantus_cold_wallet/theme/app_colors.dart'; -import 'package:quantus_cold_wallet/theme/app_text_styles.dart'; /// Resolves human checkphrases for every address on screen, not just a /// destination — an approval or a governance call can name several accounts, and diff --git a/cold-wallet-app/lib/components/confirm_dialog.dart b/cold-wallet-app/lib/components/confirm_dialog.dart index 708fe105c..ef864c33e 100644 --- a/cold-wallet-app/lib/components/confirm_dialog.dart +++ b/cold-wallet-app/lib/components/confirm_dialog.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:quantus_cold_wallet/theme/app_colors.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; Future showConfirmDialog( BuildContext context, { diff --git a/cold-wallet-app/lib/components/detail_row.dart b/cold-wallet-app/lib/components/detail_row.dart index 5db85ab8a..c11a0fa7e 100644 --- a/cold-wallet-app/lib/components/detail_row.dart +++ b/cold-wallet-app/lib/components/detail_row.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:quantus_cold_wallet/theme/app_colors.dart'; -import 'package:quantus_cold_wallet/theme/app_text_styles.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; /// Label-above-value row used throughout the signing review screen. /// diff --git a/cold-wallet-app/lib/components/loader.dart b/cold-wallet-app/lib/components/loader.dart deleted file mode 100644 index 654ec4cd3..000000000 --- a/cold-wallet-app/lib/components/loader.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:quantus_cold_wallet/shared/context_extensions.dart'; -import 'package:quantus_cold_wallet/theme/app_colors.dart'; - -class Loader extends StatelessWidget { - final Color? color; - final double? size; - - const Loader({super.key, this.color, this.size}); - - @override - Widget build(BuildContext context) { - final effectiveSize = size ?? (context.isTablet ? 24 : 16); - - return SizedBox( - height: effectiveSize, - width: effectiveSize, - child: CircularProgressIndicator(strokeWidth: 2, color: color ?? context.colors.textSecondary), - ); - } -} diff --git a/cold-wallet-app/lib/components/mnemonic_grid.dart b/cold-wallet-app/lib/components/mnemonic_grid.dart index 7fbe76e2f..01abb8569 100644 --- a/cold-wallet-app/lib/components/mnemonic_grid.dart +++ b/cold-wallet-app/lib/components/mnemonic_grid.dart @@ -1,9 +1,7 @@ import 'dart:ui'; import 'package:flutter/material.dart'; -import 'package:quantus_cold_wallet/shared/context_extensions.dart'; -import 'package:quantus_cold_wallet/theme/app_colors.dart'; -import 'package:quantus_cold_wallet/theme/app_text_styles.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; class MnemonicGrid extends StatelessWidget { final List words; diff --git a/cold-wallet-app/lib/components/qr_tuning_controls.dart b/cold-wallet-app/lib/components/qr_tuning_controls.dart index 52d433419..00e930782 100644 --- a/cold-wallet-app/lib/components/qr_tuning_controls.dart +++ b/cold-wallet-app/lib/components/qr_tuning_controls.dart @@ -1,8 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:quantus_cold_wallet/providers/settings_providers.dart'; -import 'package:quantus_cold_wallet/theme/app_colors.dart'; -import 'package:quantus_cold_wallet/theme/app_text_styles.dart'; /// FPS and bytes-per-frame sliders bound to [coldSettingsProvider], shared by /// the settings screen and the signature view so tuning behaves identically. diff --git a/cold-wallet-app/lib/components/quantus_button.dart b/cold-wallet-app/lib/components/quantus_button.dart deleted file mode 100644 index 499643ba7..000000000 --- a/cold-wallet-app/lib/components/quantus_button.dart +++ /dev/null @@ -1,178 +0,0 @@ -import 'dart:math' as math; -import 'package:flutter/material.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:quantus_cold_wallet/components/loader.dart'; -import 'package:quantus_cold_wallet/theme/app_colors.dart'; -import 'package:quantus_cold_wallet/theme/app_text_styles.dart'; - -enum ButtonVariant { transparent, primary, secondary, danger, success, outline } - -enum IconPlacement { leading, trailing, top } - -class QuantusButton extends StatelessWidget { - final Widget? child; - final String? _label; - final Widget? _icon; - final IconPlacement _iconPlacement; - final TextStyle? _textStyle; - final VoidCallback? onTap; - final bool isLoading; - final double? width; - final EdgeInsets padding; - final ButtonVariant variant; - final bool isDisabled; - final double borderRadius; - final bool centered; - - static const double defaultBorderRadius = 14.0; - static const double buttonFontSize = 16.0; - - const QuantusButton({ - super.key, - required Widget this.child, - this.onTap, - this.isLoading = false, - this.width = double.infinity, - this.padding = const EdgeInsets.symmetric(horizontal: 12, vertical: 12), - this.variant = ButtonVariant.primary, - this.isDisabled = false, - this.borderRadius = defaultBorderRadius, - this.centered = true, - }) : _label = null, - _icon = null, - _iconPlacement = IconPlacement.trailing, - _textStyle = null; - - // this is a simple button with a label and an icon - const QuantusButton.simple({ - super.key, - required String label, - Widget? icon, - IconPlacement iconPlacement = IconPlacement.trailing, - this.onTap, - this.isLoading = false, - this.width = double.infinity, - this.padding = const EdgeInsets.symmetric(horizontal: 40, vertical: 12), - TextStyle? textStyle, - this.variant = ButtonVariant.primary, - this.isDisabled = false, - this.borderRadius = defaultBorderRadius, - this.centered = true, - }) : _label = label, - _icon = icon, - _iconPlacement = iconPlacement, - _textStyle = textStyle, - child = null; - - @override - Widget build(BuildContext context) { - final bool disabled = onTap == null || isLoading || isDisabled; - final visibility = disabled ? 0.5 : 1.0; - final buttonContent = _buildContent(context, variant: variant, disabled: disabled); - final borderRadius = BorderRadius.circular(this.borderRadius); - final basicBorder = BorderSide(color: context.colors.borderButton, width: 1); - - Color? buttonDecorationColor; - LinearGradient? buttonDecorationGradient; - BorderSide borderSide = BorderSide.none; - - switch (variant) { - case ButtonVariant.primary: - buttonDecorationColor = context.colors.accentOrange; - break; - - case ButtonVariant.secondary: - buttonDecorationGradient = LinearGradient( - transform: const GradientRotation(90 * math.pi / 180), - colors: [context.colors.surfaceDeep, context.colors.sheetBackground], - stops: [0.0, 1.0], - ); - borderSide = basicBorder.copyWith(color: context.colors.borderButton.useOpacity(0.5)); - break; - - case ButtonVariant.danger: - buttonDecorationColor = context.colors.buttonDanger; - break; - - case ButtonVariant.success: - buttonDecorationColor = context.colors.success; - break; - - case ButtonVariant.transparent: - buttonDecorationColor = Colors.transparent; - break; - - case ButtonVariant.outline: - buttonDecorationColor = Colors.transparent; - borderSide = basicBorder; - break; - } - - return InkWell( - onTap: disabled ? null : onTap, - child: Opacity( - opacity: visibility, - child: Container( - width: width, - padding: padding, - decoration: ShapeDecoration( - color: disabled ? context.colors.sheetBackground : buttonDecorationColor, - gradient: disabled ? null : buttonDecorationGradient, - shape: RoundedRectangleBorder(borderRadius: borderRadius, side: disabled ? basicBorder : borderSide), - ), - child: buttonContent, - ), - ), - ); - } - - Widget _buildContent(BuildContext context, {ButtonVariant variant = ButtonVariant.primary, bool disabled = false}) { - final textColor = switch (variant) { - ButtonVariant.primary => context.colors.background, - ButtonVariant.secondary => context.colors.textPrimary, - ButtonVariant.danger => context.colors.textPrimary, - ButtonVariant.transparent => context.colors.textPrimary, - ButtonVariant.success => context.colors.textPrimary, - ButtonVariant.outline => context.colors.textLabel, - }; - - if (isLoading) { - final size = (_textStyle?.fontSize ?? buttonFontSize) + 6; - return Center(child: Loader(size: size)); - } - - if (child != null) return child!; - - final effectiveTextStyle = - _textStyle ?? - context.themeText.paragraph!.copyWith( - fontSize: buttonFontSize, - color: disabled ? context.colors.textPrimary.useOpacity(0.5) : textColor, - fontWeight: FontWeight.w500, - ); - - Widget content; - if (_iconPlacement == IconPlacement.top) { - content = Column( - mainAxisAlignment: MainAxisAlignment.center, - spacing: 8, - children: [ - ?_icon, - Text(_label!, style: effectiveTextStyle), - ], - ); - } else { - content = Row( - mainAxisAlignment: MainAxisAlignment.center, - spacing: 8, - children: [ - if (_iconPlacement == IconPlacement.leading && _icon != null) _icon, - Text(_label!, style: effectiveTextStyle), - if (_iconPlacement == IconPlacement.trailing && _icon != null) _icon, - ], - ); - } - - return Center(child: content); - } -} diff --git a/cold-wallet-app/lib/components/quantus_qr.dart b/cold-wallet-app/lib/components/quantus_qr.dart deleted file mode 100644 index bba9f983f..000000000 --- a/cold-wallet-app/lib/components/quantus_qr.dart +++ /dev/null @@ -1,35 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:qr_flutter/qr_flutter.dart'; -import 'package:quantus_cold_wallet/theme/app_colors.dart'; - -class QuantusQr extends StatelessWidget { - final String accountId; - - const QuantusQr({super.key, required this.accountId}); - - @override - Widget build(BuildContext context) { - final qrSize = 267.0; - final qrLogoSize = 64.0; - - return Container( - decoration: BoxDecoration( - border: Border.all(color: context.colors.textTertiary, width: 1), - borderRadius: BorderRadius.circular(16), - ), - width: qrSize, - height: qrSize, - child: QrImageView( - data: accountId, - errorCorrectionLevel: QrErrorCorrectLevel.M, - embeddedImage: const AssetImage('assets/v2/uppercase_q_black_bg.png'), - embeddedImageStyle: QrEmbeddedImageStyle(size: Size(qrLogoSize, qrLogoSize)), - version: QrVersions.auto, - size: qrSize, - padding: const EdgeInsets.all(16), - eyeStyle: const QrEyeStyle(eyeShape: QrEyeShape.square, color: Colors.white), - dataModuleStyle: const QrDataModuleStyle(dataModuleShape: QrDataModuleShape.square, color: Colors.white), - ), - ); - } -} diff --git a/cold-wallet-app/lib/components/scaffold_base.dart b/cold-wallet-app/lib/components/scaffold_base.dart deleted file mode 100644 index a3201458d..000000000 --- a/cold-wallet-app/lib/components/scaffold_base.dart +++ /dev/null @@ -1,107 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:quantus_cold_wallet/components/base_background.dart'; -import 'package:quantus_cold_wallet/theme/app_colors.dart'; - -class ScaffoldBase extends StatelessWidget { - final Widget? mainContent; - final Widget? bottomContent; - final List? slivers; - final Widget? appBar; - final ScrollController? scrollController; - final ScrollPhysics? scrollPhysics; - final RefreshCallback? onRefresh; - final EdgeInsetsGeometry padding; - final Widget? backgroundWidget; - - static const defaultPadding = EdgeInsets.symmetric(horizontal: 24.0); - - // Default constructor - static content - const ScaffoldBase({ - super.key, - this.appBar, - this.padding = defaultPadding, - this.backgroundWidget, - this.bottomContent, - required Widget this.mainContent, - }) : slivers = null, - scrollController = null, - scrollPhysics = null, - onRefresh = null; - - // Refreshable constructor - CustomScrollView with pull-to-refresh - const ScaffoldBase.refreshable({ - super.key, - this.appBar, - this.padding = defaultPadding, - this.backgroundWidget, - this.scrollController, - this.scrollPhysics = const AlwaysScrollableScrollPhysics(), - this.bottomContent, - required RefreshCallback this.onRefresh, - required List this.slivers, - }) : mainContent = null; - - @override - Widget build(BuildContext context) { - final colors = context.colors; - - Widget bodyContent = Column( - children: [ - if (appBar != null) Padding(padding: padding, child: appBar!), - Expanded(child: _buildChild(colors)), - ], - ); - - Widget scaffoldBody = SafeArea(child: bodyContent); - - if (backgroundWidget != null) { - scaffoldBody = Stack(fit: StackFit.expand, children: [backgroundWidget!, scaffoldBody]); - } else { - scaffoldBody = BaseBackground(child: scaffoldBody); - } - - return Scaffold(body: scaffoldBody); - } - - Widget _buildChild(AppColorsV2 colors) { - // Scrollable with refresh (CustomScrollView with slivers) - if (onRefresh != null && slivers != null) { - return RefreshIndicator( - onRefresh: onRefresh!, - color: colors.textPrimary, - backgroundColor: colors.surface, - child: Column( - children: [ - Expanded( - child: CustomScrollView( - controller: scrollController, - physics: scrollPhysics ?? const AlwaysScrollableScrollPhysics(), - slivers: [ - SliverPadding( - padding: padding, - sliver: SliverList(delegate: SliverChildListDelegate(slivers!)), - ), - ], - ), - ), - ?bottomContent, - ], - ), - ); - } - - // Static content - if (mainContent != null) { - return Column( - children: [ - Expanded( - child: Padding(padding: padding, child: mainContent!), - ), - ?bottomContent, - ], - ); - } - - return const SizedBox.shrink(); - } -} diff --git a/cold-wallet-app/lib/components/scaffold_base_bottom_content.dart b/cold-wallet-app/lib/components/scaffold_base_bottom_content.dart deleted file mode 100644 index 801332f0c..000000000 --- a/cold-wallet-app/lib/components/scaffold_base_bottom_content.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:quantus_cold_wallet/theme/app_colors.dart'; - -class ScaffoldBaseBottomContent extends StatelessWidget { - final Widget child; - - const ScaffoldBaseBottomContent({super.key, required this.child}); - - @override - Widget build(BuildContext context) { - final padding = const EdgeInsets.all(24); - - return Container( - padding: padding, - decoration: BoxDecoration( - border: Border(top: BorderSide(color: context.colors.surfaceDeep, width: 1)), - ), - child: child, - ); - } -} diff --git a/cold-wallet-app/lib/components/v2_app_bar.dart b/cold-wallet-app/lib/components/v2_app_bar.dart deleted file mode 100644 index be416600c..000000000 --- a/cold-wallet-app/lib/components/v2_app_bar.dart +++ /dev/null @@ -1,42 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:quantus_cold_wallet/components/back_button.dart'; -import 'package:quantus_cold_wallet/theme/app_colors.dart'; -import 'package:quantus_cold_wallet/theme/app_text_styles.dart'; - -class V2AppBar extends StatelessWidget { - final String title; - final Widget? leading; - final Widget? trailing; - final bool showBackButton; - final EdgeInsetsGeometry padding; - - const V2AppBar({ - super.key, - required this.title, - this.leading, - this.trailing, - this.showBackButton = true, - this.padding = const EdgeInsets.only(top: 16.0, bottom: 32.0), - }); - - @override - Widget build(BuildContext context) { - final colors = context.colors; - final text = context.themeText; - - Widget leftWidget = leading ?? (showBackButton ? const AppBackButton() : const SizedBox(width: 24)); - Widget rightWidget = trailing ?? const SizedBox(width: 24); - - return Padding( - padding: padding, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - leftWidget, - Text(title, style: text.smallTitle?.copyWith(color: colors.textPrimary, fontSize: 20)), - rightWidget, - ], - ), - ); - } -} diff --git a/cold-wallet-app/lib/screens/create_wallet_screen.dart b/cold-wallet-app/lib/screens/create_wallet_screen.dart index 55de2f570..30865c274 100644 --- a/cold-wallet-app/lib/screens/create_wallet_screen.dart +++ b/cold-wallet-app/lib/screens/create_wallet_screen.dart @@ -1,14 +1,7 @@ import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:quantus_cold_wallet/components/loader.dart'; import 'package:quantus_cold_wallet/components/mnemonic_grid.dart'; -import 'package:quantus_cold_wallet/components/quantus_button.dart'; -import 'package:quantus_cold_wallet/components/scaffold_base.dart'; -import 'package:quantus_cold_wallet/components/scaffold_base_bottom_content.dart'; -import 'package:quantus_cold_wallet/components/v2_app_bar.dart'; import 'package:quantus_cold_wallet/screens/set_password_screen.dart'; -import 'package:quantus_cold_wallet/theme/app_colors.dart'; -import 'package:quantus_cold_wallet/theme/app_text_styles.dart'; class CreateWalletScreen extends StatefulWidget { const CreateWalletScreen({super.key}); diff --git a/cold-wallet-app/lib/screens/home_screen.dart b/cold-wallet-app/lib/screens/home_screen.dart index a39735692..3b8ae24a1 100644 --- a/cold-wallet-app/lib/screens/home_screen.dart +++ b/cold-wallet-app/lib/screens/home_screen.dart @@ -1,17 +1,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_cold_wallet/components/quantus_button.dart'; -import 'package:quantus_cold_wallet/components/scaffold_base.dart'; -import 'package:quantus_cold_wallet/components/scaffold_base_bottom_content.dart'; -import 'package:quantus_cold_wallet/components/v2_app_bar.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:quantus_cold_wallet/providers/connectivity_provider.dart'; import 'package:quantus_cold_wallet/providers/settings_providers.dart'; import 'package:quantus_cold_wallet/providers/wallet_providers.dart'; import 'package:quantus_cold_wallet/screens/scan_transaction_screen.dart'; import 'package:quantus_cold_wallet/screens/settings_screen.dart'; import 'package:quantus_cold_wallet/screens/show_key_screen.dart'; -import 'package:quantus_cold_wallet/theme/app_colors.dart'; -import 'package:quantus_cold_wallet/theme/app_text_styles.dart'; class HomeScreen extends ConsumerWidget { const HomeScreen({super.key}); diff --git a/cold-wallet-app/lib/screens/import_wallet_screen.dart b/cold-wallet-app/lib/screens/import_wallet_screen.dart index 18c662f0f..e52b645cb 100644 --- a/cold-wallet-app/lib/screens/import_wallet_screen.dart +++ b/cold-wallet-app/lib/screens/import_wallet_screen.dart @@ -1,12 +1,6 @@ import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:quantus_cold_wallet/components/quantus_button.dart'; -import 'package:quantus_cold_wallet/components/scaffold_base.dart'; -import 'package:quantus_cold_wallet/components/scaffold_base_bottom_content.dart'; -import 'package:quantus_cold_wallet/components/v2_app_bar.dart'; import 'package:quantus_cold_wallet/screens/set_password_screen.dart'; -import 'package:quantus_cold_wallet/theme/app_colors.dart'; -import 'package:quantus_cold_wallet/theme/app_text_styles.dart'; class ImportWalletScreen extends StatefulWidget { const ImportWalletScreen({super.key}); diff --git a/cold-wallet-app/lib/screens/lock_screen.dart b/cold-wallet-app/lib/screens/lock_screen.dart index ccc32d1c1..8495dc3f8 100644 --- a/cold-wallet-app/lib/screens/lock_screen.dart +++ b/cold-wallet-app/lib/screens/lock_screen.dart @@ -1,10 +1,7 @@ import 'package:flutter/material.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_cold_wallet/components/quantus_button.dart'; -import 'package:quantus_cold_wallet/components/scaffold_base.dart'; import 'package:quantus_cold_wallet/providers/wallet_providers.dart'; -import 'package:quantus_cold_wallet/theme/app_colors.dart'; -import 'package:quantus_cold_wallet/theme/app_text_styles.dart'; import 'package:quantus_cold_wallet/widgets/password_field.dart'; class LockScreen extends ConsumerStatefulWidget { diff --git a/cold-wallet-app/lib/screens/root_gate.dart b/cold-wallet-app/lib/screens/root_gate.dart index cba403c24..1ff54ecff 100644 --- a/cold-wallet-app/lib/screens/root_gate.dart +++ b/cold-wallet-app/lib/screens/root_gate.dart @@ -1,13 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_cold_wallet/components/base_background.dart'; -import 'package:quantus_cold_wallet/components/loader.dart'; -import 'package:quantus_cold_wallet/components/quantus_button.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:quantus_cold_wallet/providers/wallet_providers.dart'; import 'package:quantus_cold_wallet/screens/home_screen.dart'; import 'package:quantus_cold_wallet/screens/welcome_screen.dart'; -import 'package:quantus_cold_wallet/theme/app_colors.dart'; -import 'package:quantus_cold_wallet/theme/app_text_styles.dart'; /// Routes the app to setup, lock, or home based on the wallet status. class RootGate extends ConsumerWidget { diff --git a/cold-wallet-app/lib/screens/scan_transaction_screen.dart b/cold-wallet-app/lib/screens/scan_transaction_screen.dart index c965e0458..42b4155bd 100644 --- a/cold-wallet-app/lib/screens/scan_transaction_screen.dart +++ b/cold-wallet-app/lib/screens/scan_transaction_screen.dart @@ -4,8 +4,6 @@ import 'package:mobile_scanner/mobile_scanner.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:quantus_cold_wallet/debug/debug_payloads.dart'; import 'package:quantus_cold_wallet/screens/sign_transaction_screen.dart'; -import 'package:quantus_cold_wallet/theme/app_colors.dart'; -import 'package:quantus_cold_wallet/theme/app_text_styles.dart'; /// Scans a (possibly multi-part / animated) UR QR code, accumulating parts /// until [isCompleteUr] is satisfied, then decodes to the raw payload bytes diff --git a/cold-wallet-app/lib/screens/secure_element_warning_screen.dart b/cold-wallet-app/lib/screens/secure_element_warning_screen.dart index ad2203fb4..84d7b965d 100644 --- a/cold-wallet-app/lib/screens/secure_element_warning_screen.dart +++ b/cold-wallet-app/lib/screens/secure_element_warning_screen.dart @@ -1,10 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:quantus_cold_wallet/components/quantus_button.dart'; -import 'package:quantus_cold_wallet/components/scaffold_base.dart'; -import 'package:quantus_cold_wallet/components/scaffold_base_bottom_content.dart'; -import 'package:quantus_cold_wallet/components/v2_app_bar.dart'; -import 'package:quantus_cold_wallet/theme/app_colors.dart'; -import 'package:quantus_cold_wallet/theme/app_text_styles.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; /// Shown during setup when the device reports no biometrics / device lock, /// which we treat as a proxy for a missing hardware-backed secure element. diff --git a/cold-wallet-app/lib/screens/set_password_screen.dart b/cold-wallet-app/lib/screens/set_password_screen.dart index afcaaf5e9..634c40ae0 100644 --- a/cold-wallet-app/lib/screens/set_password_screen.dart +++ b/cold-wallet-app/lib/screens/set_password_screen.dart @@ -1,12 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_cold_wallet/components/quantus_button.dart'; -import 'package:quantus_cold_wallet/components/scaffold_base.dart'; -import 'package:quantus_cold_wallet/components/scaffold_base_bottom_content.dart'; -import 'package:quantus_cold_wallet/components/v2_app_bar.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:quantus_cold_wallet/providers/wallet_providers.dart'; -import 'package:quantus_cold_wallet/theme/app_colors.dart'; -import 'package:quantus_cold_wallet/theme/app_text_styles.dart'; import 'package:quantus_cold_wallet/widgets/password_field.dart'; class SetPasswordScreen extends ConsumerStatefulWidget { diff --git a/cold-wallet-app/lib/screens/settings_screen.dart b/cold-wallet-app/lib/screens/settings_screen.dart index 0ffa1075d..54e323d0d 100644 --- a/cold-wallet-app/lib/screens/settings_screen.dart +++ b/cold-wallet-app/lib/screens/settings_screen.dart @@ -1,13 +1,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:quantus_cold_wallet/components/confirm_dialog.dart'; import 'package:quantus_cold_wallet/components/qr_tuning_controls.dart'; -import 'package:quantus_cold_wallet/components/scaffold_base.dart'; -import 'package:quantus_cold_wallet/components/v2_app_bar.dart'; import 'package:quantus_cold_wallet/providers/settings_providers.dart'; import 'package:quantus_cold_wallet/providers/wallet_providers.dart'; -import 'package:quantus_cold_wallet/theme/app_colors.dart'; -import 'package:quantus_cold_wallet/theme/app_text_styles.dart'; import 'package:quantus_cold_wallet/widgets/change_password_sheet.dart'; class SettingsScreen extends ConsumerWidget { diff --git a/cold-wallet-app/lib/screens/show_key_screen.dart b/cold-wallet-app/lib/screens/show_key_screen.dart index de0cec21e..6af1cb1fa 100644 --- a/cold-wallet-app/lib/screens/show_key_screen.dart +++ b/cold-wallet-app/lib/screens/show_key_screen.dart @@ -1,12 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_cold_wallet/components/loader.dart'; -import 'package:quantus_cold_wallet/components/quantus_qr.dart'; -import 'package:quantus_cold_wallet/components/scaffold_base.dart'; -import 'package:quantus_cold_wallet/components/v2_app_bar.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:quantus_cold_wallet/providers/wallet_providers.dart'; -import 'package:quantus_cold_wallet/theme/app_colors.dart'; -import 'package:quantus_cold_wallet/theme/app_text_styles.dart'; class ShowKeyScreen extends ConsumerWidget { const ShowKeyScreen({super.key}); diff --git a/cold-wallet-app/lib/screens/sign_transaction_screen.dart b/cold-wallet-app/lib/screens/sign_transaction_screen.dart index dfc594f0d..2150b012c 100644 --- a/cold-wallet-app/lib/screens/sign_transaction_screen.dart +++ b/cold-wallet-app/lib/screens/sign_transaction_screen.dart @@ -4,18 +4,11 @@ import 'package:convert/convert.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:quantus_cold_wallet/components/animated_ur_qr.dart'; import 'package:quantus_cold_wallet/components/call_detail_view.dart'; import 'package:quantus_cold_wallet/components/detail_row.dart'; -import 'package:quantus_cold_wallet/components/quantus_button.dart'; import 'package:quantus_cold_wallet/components/qr_tuning_controls.dart'; -import 'package:quantus_cold_wallet/components/scaffold_base.dart'; -import 'package:quantus_cold_wallet/components/scaffold_base_bottom_content.dart'; -import 'package:quantus_cold_wallet/components/v2_app_bar.dart'; import 'package:quantus_cold_wallet/providers/settings_providers.dart'; import 'package:quantus_cold_wallet/providers/wallet_providers.dart'; -import 'package:quantus_cold_wallet/theme/app_colors.dart'; -import 'package:quantus_cold_wallet/theme/app_text_styles.dart'; /// Reviews a scanned signing payload and, on approval, produces the signature QR. /// diff --git a/cold-wallet-app/lib/screens/welcome_screen.dart b/cold-wallet-app/lib/screens/welcome_screen.dart index 24089ea88..e416d69af 100644 --- a/cold-wallet-app/lib/screens/welcome_screen.dart +++ b/cold-wallet-app/lib/screens/welcome_screen.dart @@ -1,14 +1,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_cold_wallet/components/quantus_button.dart'; -import 'package:quantus_cold_wallet/components/scaffold_base.dart'; -import 'package:quantus_cold_wallet/components/scaffold_base_bottom_content.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:quantus_cold_wallet/providers/wallet_providers.dart'; import 'package:quantus_cold_wallet/screens/create_wallet_screen.dart'; import 'package:quantus_cold_wallet/screens/import_wallet_screen.dart'; import 'package:quantus_cold_wallet/screens/secure_element_warning_screen.dart'; -import 'package:quantus_cold_wallet/theme/app_colors.dart'; -import 'package:quantus_cold_wallet/theme/app_text_styles.dart'; class WelcomeScreen extends ConsumerWidget { const WelcomeScreen({super.key}); diff --git a/cold-wallet-app/lib/shared/context_extensions.dart b/cold-wallet-app/lib/shared/context_extensions.dart deleted file mode 100644 index d47f98bde..000000000 --- a/cold-wallet-app/lib/shared/context_extensions.dart +++ /dev/null @@ -1,6 +0,0 @@ -import 'package:flutter/material.dart'; - -extension MediaQueryDataExtension on BuildContext { - bool get isTablet => MediaQuery.of(this).size.width > 600; - bool get isSmallHeight => MediaQuery.of(this).size.height < 750; -} diff --git a/cold-wallet-app/lib/theme/app_colors.dart b/cold-wallet-app/lib/theme/app_colors.dart deleted file mode 100644 index 4210495df..000000000 --- a/cold-wallet-app/lib/theme/app_colors.dart +++ /dev/null @@ -1,332 +0,0 @@ -import 'package:flutter/material.dart'; - -@immutable -class AppColorsV2 extends ThemeExtension { - // Backgrounds - final Color background; - - // Surfaces - final Color surface; - final Color surfaceGlass; - final Color surfaceCard; - - // Text - final Color textPrimary; - final Color textSecondary; - final Color textTertiary; - final Color textMuted; - final Color textError; - final Color textLabel; - final Color textLightGray; - - // Accents - final Color accentOrange; - final Color accentGreen; - final Color checksum; - - // Semantic - final Color error; - final Color danger; - final Color success; - - // Glow & Gradients - final Color backgroundGlow; - final List buttonPrimaryGradient; - - // UI elements - final Color separator; - final Color txItemSeparator; - final Color txItemIncomingHighlightBg; - final Color txItemOutgoingHighlightBg; - final Color txItemOutgoingHighlightBorder; - final Color txItemIconDefault; - final Color txItemIncomingHighlightBorder; - final Color txItemBorderDefault; - final Color border; - final Color buttonDisabled; - final Color buttonDanger; - final Color skeletonBase; - final Color skeletonHighlightA; - final Color skeletonHighlightB; - final Color toasterBorder; - final Color toasterBackground; - final Color sheetBackground; - final Color borderButton; - final Color borderSubtle; - final Color borderDanger; - - // Segmented control - final Color segmentedControlPill; - - // Receive screen - final Color surfaceDeep; - final Color copyButtonCopiedBg; - final Color copyButtonCopiedBorder; - - // Account tags - final Color tagGuardian; - final Color tagEntrusted; - final Color tagHighSecurity; - - const AppColorsV2({ - required this.background, - required this.toasterBackground, - required this.toasterBorder, - required this.sheetBackground, - required this.borderSubtle, - required this.borderDanger, - required this.borderButton, - required this.surface, - required this.surfaceGlass, - required this.surfaceCard, - required this.textPrimary, - required this.textSecondary, - required this.textTertiary, - required this.textMuted, - required this.textError, - required this.textLabel, - required this.textLightGray, - required this.accentOrange, - required this.accentGreen, - required this.checksum, - required this.error, - required this.danger, - required this.success, - required this.backgroundGlow, - required this.buttonPrimaryGradient, - required this.separator, - required this.txItemSeparator, - required this.txItemIncomingHighlightBg, - required this.txItemOutgoingHighlightBg, - required this.txItemOutgoingHighlightBorder, - required this.txItemIconDefault, - required this.txItemIncomingHighlightBorder, - required this.txItemBorderDefault, - required this.border, - required this.buttonDisabled, - required this.buttonDanger, - required this.skeletonBase, - required this.skeletonHighlightA, - required this.skeletonHighlightB, - required this.segmentedControlPill, - required this.surfaceDeep, - required this.copyButtonCopiedBg, - required this.copyButtonCopiedBorder, - required this.tagGuardian, - required this.tagEntrusted, - required this.tagHighSecurity, - }); - - const AppColorsV2.dark() - : this( - background: const Color(0xFF0E0E0E), - toasterBackground: const Color(0xFF181818), - toasterBorder: const Color(0xFF272727), - sheetBackground: const Color(0xFF1A1A1A), - border: const Color(0x33FFFFFF), - borderSubtle: const Color(0x70FFFFFF), - borderDanger: const Color(0x70FF0000), - borderButton: const Color(0xFF272727), - surface: const Color(0xFF292929), - surfaceGlass: const Color(0x1AFFFFFF), - surfaceCard: const Color(0x0FFFFFFF), - textPrimary: const Color(0xFFFFFFFF), - textSecondary: const Color(0x80FFFFFF), - textTertiary: const Color(0xFF3D3D3D), - textMuted: const Color(0xFF888888), - textError: const Color(0xFFC0392B), - textLabel: const Color(0xFF787878), - textLightGray: const Color(0xFFEBEBEB), - accentOrange: const Color(0xFFFF6B35), - accentGreen: const Color(0xFF34C759), - checksum: const Color(0xFF95A7FB), - error: const Color(0xFFFF2D54), - danger: const Color(0xFFFF1F45), - success: const Color(0xFF22A27F), - backgroundGlow: const Color(0xFFFFFFFF), - buttonPrimaryGradient: const [Color(0xFF0000FF), Color(0xFFED4CCE)], - separator: const Color(0x1AFFFFFF), - txItemSeparator: const Color(0x7F272727), - txItemIncomingHighlightBg: const Color(0x14408C6B), - txItemOutgoingHighlightBg: const Color(0x1440618C), - txItemOutgoingHighlightBorder: const Color(0x2640618C), - txItemIconDefault: const Color(0xFF363636), - txItemIncomingHighlightBorder: const Color(0x26408C6B), - txItemBorderDefault: const Color(0xFF191919), - segmentedControlPill: const Color(0xFF1C1C1C), - surfaceDeep: const Color(0xFF141414), - copyButtonCopiedBg: const Color(0xFF0C1C14), - copyButtonCopiedBorder: const Color(0xFF1A3226), - buttonDisabled: const Color(0xFF3D3C44), - buttonDanger: const Color(0x1AFF0000), - skeletonBase: const Color(0xFF161616), - skeletonHighlightA: const Color(0xFF000000), - skeletonHighlightB: const Color(0xFF666666), - tagGuardian: const Color(0xFF9747FF), - tagEntrusted: const Color(0xFFFFD541), - tagHighSecurity: const Color(0xFF4CEDE7), - ); - - @override - AppColorsV2 copyWith({ - Color? background, - Color? surface, - Color? surfaceGlass, - Color? surfaceCard, - Color? textPrimary, - Color? textSecondary, - Color? textTertiary, - Color? textMuted, - Color? textError, - Color? textLabel, - Color? textLightGray, - Color? accentOrange, - Color? accentGreen, - Color? checksum, - Color? error, - Color? danger, - Color? success, - Color? backgroundGlow, - List? buttonPrimaryGradient, - Color? separator, - Color? txItemSeparator, - Color? txItemIncomingHighlightBg, - Color? txItemOutgoingHighlightBg, - Color? txItemOutgoingHighlightBorder, - Color? txItemIconDefault, - Color? txItemIncomingHighlightBorder, - Color? txItemBorderDefault, - Color? border, - Color? borderButton, - Color? toasterBackground, - Color? toasterBorder, - Color? sheetBackground, - Color? borderSubtle, - Color? buttonDisabled, - Color? buttonDanger, - Color? borderDanger, - Color? skeletonBase, - Color? skeletonHighlightA, - Color? skeletonHighlightB, - Color? segmentedControlPill, - Color? surfaceDeep, - Color? copyButtonCopiedBg, - Color? copyButtonCopiedBorder, - Color? tagGuardian, - Color? tagEntrusted, - Color? tagHighSecurity, - }) { - return AppColorsV2( - background: background ?? this.background, - toasterBackground: toasterBackground ?? this.toasterBackground, - toasterBorder: toasterBorder ?? this.toasterBorder, - sheetBackground: sheetBackground ?? this.sheetBackground, - borderSubtle: borderSubtle ?? this.borderSubtle, - borderButton: borderButton ?? this.borderButton, - surface: surface ?? this.surface, - surfaceGlass: surfaceGlass ?? this.surfaceGlass, - surfaceCard: surfaceCard ?? this.surfaceCard, - textPrimary: textPrimary ?? this.textPrimary, - textSecondary: textSecondary ?? this.textSecondary, - textTertiary: textTertiary ?? this.textTertiary, - textMuted: textMuted ?? this.textMuted, - textError: textError ?? this.textError, - textLabel: textLabel ?? this.textLabel, - textLightGray: textLightGray ?? this.textLightGray, - accentOrange: accentOrange ?? this.accentOrange, - accentGreen: accentGreen ?? this.accentGreen, - checksum: checksum ?? this.checksum, - error: error ?? this.error, - danger: danger ?? this.danger, - success: success ?? this.success, - backgroundGlow: backgroundGlow ?? this.backgroundGlow, - buttonPrimaryGradient: buttonPrimaryGradient ?? this.buttonPrimaryGradient, - separator: separator ?? this.separator, - txItemSeparator: txItemSeparator ?? this.txItemSeparator, - txItemIncomingHighlightBg: txItemIncomingHighlightBg ?? this.txItemIncomingHighlightBg, - txItemOutgoingHighlightBg: txItemOutgoingHighlightBg ?? this.txItemOutgoingHighlightBg, - txItemOutgoingHighlightBorder: txItemOutgoingHighlightBorder ?? this.txItemOutgoingHighlightBorder, - txItemIconDefault: txItemIconDefault ?? this.txItemIconDefault, - txItemIncomingHighlightBorder: txItemIncomingHighlightBorder ?? this.txItemIncomingHighlightBorder, - txItemBorderDefault: txItemBorderDefault ?? this.txItemBorderDefault, - border: border ?? this.border, - buttonDisabled: buttonDisabled ?? this.buttonDisabled, - buttonDanger: buttonDanger ?? this.buttonDanger, - borderDanger: borderDanger ?? this.borderDanger, - skeletonBase: skeletonBase ?? this.skeletonBase, - skeletonHighlightA: skeletonHighlightA ?? this.skeletonHighlightA, - skeletonHighlightB: skeletonHighlightB ?? this.skeletonHighlightB, - segmentedControlPill: segmentedControlPill ?? this.segmentedControlPill, - surfaceDeep: surfaceDeep ?? this.surfaceDeep, - copyButtonCopiedBg: copyButtonCopiedBg ?? this.copyButtonCopiedBg, - copyButtonCopiedBorder: copyButtonCopiedBorder ?? this.copyButtonCopiedBorder, - tagGuardian: tagGuardian ?? this.tagGuardian, - tagEntrusted: tagEntrusted ?? this.tagEntrusted, - tagHighSecurity: tagHighSecurity ?? this.tagHighSecurity, - ); - } - - @override - AppColorsV2 lerp(AppColorsV2? other, double t) { - if (other is! AppColorsV2) return this; - return AppColorsV2( - background: Color.lerp(background, other.background, t) ?? background, - toasterBackground: Color.lerp(toasterBackground, other.toasterBackground, t) ?? toasterBackground, - toasterBorder: Color.lerp(toasterBorder, other.toasterBorder, t) ?? toasterBorder, - sheetBackground: Color.lerp(sheetBackground, other.sheetBackground, t) ?? sheetBackground, - borderSubtle: Color.lerp(borderSubtle, other.borderSubtle, t) ?? borderSubtle, - borderButton: Color.lerp(borderButton, other.borderButton, t) ?? borderButton, - surface: Color.lerp(surface, other.surface, t) ?? surface, - surfaceGlass: Color.lerp(surfaceGlass, other.surfaceGlass, t) ?? surfaceGlass, - surfaceCard: Color.lerp(surfaceCard, other.surfaceCard, t) ?? surfaceCard, - textPrimary: Color.lerp(textPrimary, other.textPrimary, t) ?? textPrimary, - textSecondary: Color.lerp(textSecondary, other.textSecondary, t) ?? textSecondary, - textTertiary: Color.lerp(textTertiary, other.textTertiary, t) ?? textTertiary, - textMuted: Color.lerp(textMuted, other.textMuted, t) ?? textMuted, - textError: Color.lerp(textError, other.textError, t) ?? textError, - textLabel: Color.lerp(textLabel, other.textLabel, t) ?? textLabel, - textLightGray: Color.lerp(textLightGray, other.textLightGray, t) ?? textLightGray, - accentOrange: Color.lerp(accentOrange, other.accentOrange, t) ?? accentOrange, - accentGreen: Color.lerp(accentGreen, other.accentGreen, t) ?? accentGreen, - checksum: Color.lerp(checksum, other.checksum, t) ?? checksum, - error: Color.lerp(error, other.error, t) ?? error, - danger: Color.lerp(danger, other.danger, t) ?? danger, - success: Color.lerp(success, other.success, t) ?? success, - backgroundGlow: Color.lerp(backgroundGlow, other.backgroundGlow, t) ?? backgroundGlow, - buttonPrimaryGradient: other.buttonPrimaryGradient, - separator: Color.lerp(separator, other.separator, t) ?? separator, - txItemSeparator: Color.lerp(txItemSeparator, other.txItemSeparator, t) ?? txItemSeparator, - txItemIncomingHighlightBg: - Color.lerp(txItemIncomingHighlightBg, other.txItemIncomingHighlightBg, t) ?? txItemIncomingHighlightBg, - txItemOutgoingHighlightBg: - Color.lerp(txItemOutgoingHighlightBg, other.txItemOutgoingHighlightBg, t) ?? txItemOutgoingHighlightBg, - txItemOutgoingHighlightBorder: - Color.lerp(txItemOutgoingHighlightBorder, other.txItemOutgoingHighlightBorder, t) ?? - txItemOutgoingHighlightBorder, - txItemIconDefault: Color.lerp(txItemIconDefault, other.txItemIconDefault, t) ?? txItemIconDefault, - txItemIncomingHighlightBorder: - Color.lerp(txItemIncomingHighlightBorder, other.txItemIncomingHighlightBorder, t) ?? - txItemIncomingHighlightBorder, - txItemBorderDefault: Color.lerp(txItemBorderDefault, other.txItemBorderDefault, t) ?? txItemBorderDefault, - border: Color.lerp(border, other.border, t) ?? border, - buttonDisabled: Color.lerp(buttonDisabled, other.buttonDisabled, t) ?? buttonDisabled, - buttonDanger: Color.lerp(buttonDanger, other.buttonDanger, t) ?? buttonDanger, - borderDanger: Color.lerp(borderDanger, other.borderDanger, t) ?? borderDanger, - skeletonBase: Color.lerp(skeletonBase, other.skeletonBase, t) ?? skeletonBase, - skeletonHighlightA: Color.lerp(skeletonHighlightA, other.skeletonHighlightA, t) ?? skeletonHighlightA, - skeletonHighlightB: Color.lerp(skeletonHighlightB, other.skeletonHighlightB, t) ?? skeletonHighlightB, - segmentedControlPill: Color.lerp(segmentedControlPill, other.segmentedControlPill, t) ?? segmentedControlPill, - surfaceDeep: Color.lerp(surfaceDeep, other.surfaceDeep, t) ?? surfaceDeep, - copyButtonCopiedBg: Color.lerp(copyButtonCopiedBg, other.copyButtonCopiedBg, t) ?? copyButtonCopiedBg, - copyButtonCopiedBorder: - Color.lerp(copyButtonCopiedBorder, other.copyButtonCopiedBorder, t) ?? copyButtonCopiedBorder, - tagGuardian: Color.lerp(tagGuardian, other.tagGuardian, t) ?? tagGuardian, - tagEntrusted: Color.lerp(tagEntrusted, other.tagEntrusted, t) ?? tagEntrusted, - tagHighSecurity: Color.lerp(tagHighSecurity, other.tagHighSecurity, t) ?? tagHighSecurity, - ); - } -} - -extension AppColorsV2Extension on BuildContext { - AppColorsV2 get colors => Theme.of(this).extension()!; -} diff --git a/cold-wallet-app/lib/theme/app_spacing.dart b/cold-wallet-app/lib/theme/app_spacing.dart deleted file mode 100644 index ce7c34de8..000000000 --- a/cold-wallet-app/lib/theme/app_spacing.dart +++ /dev/null @@ -1,282 +0,0 @@ -import 'package:flutter/material.dart'; - -@immutable -class AppSizeTheme extends ThemeExtension { - final double logoHeight; - final double mainMenuHeight; - final double mainMenuWidth; - final double mainMenuIconSize; - final double navbarHeight; - final double navbarItemHeight; - final double navbarItemWidth; - final double navbarIconWidth; - final double floatingBtnHeight; - final double floatingBtnWidth; - final double settingMenuIconSize; - final double settingMenuShareIconSize; - final double accountListItemHeight; - final double accountListItemLogoWidth; - final double appbarIconSize; - final double sendOverlayContainerWidth; - final double overlayCloseIconSize; - final double mnemonicCellDesiredHeight; - final double txListItemIconWidth; - final double txDetailsIconHeight; - final double txDetailsIconWidth; - final double copyIconSize; - final double pasteIconSize; - final double timePickerSubtitleWidth; - final double bottomButtonSpacing; - final double buttonsHorizontalSpacing; - final double infoSheetTitleIcon; - - final double screenPadding; - final double cardPadding; - final double sectionGap; - final double itemGap; - final double sectionHeaderToContent; - - final double radiusFull; - final double radiusCard; - final double radiusSmall; - - const AppSizeTheme({ - required this.logoHeight, - required this.mainMenuHeight, - required this.mainMenuWidth, - required this.mainMenuIconSize, - required this.navbarHeight, - required this.navbarItemHeight, - required this.navbarItemWidth, - required this.navbarIconWidth, - required this.floatingBtnHeight, - required this.floatingBtnWidth, - required this.settingMenuIconSize, - required this.settingMenuShareIconSize, - required this.accountListItemHeight, - required this.accountListItemLogoWidth, - required this.appbarIconSize, - required this.sendOverlayContainerWidth, - required this.overlayCloseIconSize, - required this.mnemonicCellDesiredHeight, - required this.txListItemIconWidth, - required this.txDetailsIconHeight, - required this.txDetailsIconWidth, - required this.copyIconSize, - required this.pasteIconSize, - required this.timePickerSubtitleWidth, - required this.bottomButtonSpacing, - required this.buttonsHorizontalSpacing, - required this.infoSheetTitleIcon, - required this.screenPadding, - required this.cardPadding, - required this.sectionGap, - required this.itemGap, - required this.sectionHeaderToContent, - required this.radiusFull, - required this.radiusCard, - required this.radiusSmall, - }); - - const AppSizeTheme.defaultTheme() - : this( - logoHeight: 158.0, - mainMenuHeight: 20, - mainMenuWidth: 20, - mainMenuIconSize: 21.0, - navbarHeight: 67.0, - navbarItemHeight: 32, - navbarItemWidth: 40, - navbarIconWidth: 23, - floatingBtnHeight: 49.0, - floatingBtnWidth: 52.0, - settingMenuIconSize: 11.0, - settingMenuShareIconSize: 20.0, - accountListItemHeight: 110.0, - accountListItemLogoWidth: 36.0, - appbarIconSize: 18.0, - sendOverlayContainerWidth: double.infinity, - overlayCloseIconSize: 24.0, - mnemonicCellDesiredHeight: 31.0, - txListItemIconWidth: 21.0, - txDetailsIconHeight: 43.0, - txDetailsIconWidth: 51.0, - copyIconSize: 20.0, - pasteIconSize: 18.0, - timePickerSubtitleWidth: 249, - bottomButtonSpacing: 16, - buttonsHorizontalSpacing: 28, - infoSheetTitleIcon: 25, - screenPadding: 24.0, - cardPadding: 20.0, - sectionGap: 40.0, - itemGap: 12.0, - sectionHeaderToContent: 36.0, - radiusFull: 30.0, - radiusCard: 14.0, - radiusSmall: 6.0, - ); - - const AppSizeTheme.iPad() - : this( - logoHeight: 180.0, - mainMenuHeight: 30, - mainMenuWidth: 30, - mainMenuIconSize: 29.0, - navbarHeight: 87.0, - navbarItemHeight: 40, - navbarItemWidth: 48, - navbarIconWidth: 32, - floatingBtnHeight: 74.0, - floatingBtnWidth: 77.0, - settingMenuIconSize: 16.0, - settingMenuShareIconSize: 24.0, - accountListItemHeight: 130.0, - accountListItemLogoWidth: 48.0, - appbarIconSize: 20.0, - sendOverlayContainerWidth: 510.0, - overlayCloseIconSize: 28.0, - mnemonicCellDesiredHeight: 80.0, - txListItemIconWidth: 32.0, - txDetailsIconHeight: 82.0, - txDetailsIconWidth: 91.0, - copyIconSize: 28.0, - pasteIconSize: 24.0, - timePickerSubtitleWidth: 400, - bottomButtonSpacing: 16, - buttonsHorizontalSpacing: 28, - infoSheetTitleIcon: 28, - screenPadding: 32.0, - cardPadding: 24.0, - sectionGap: 48.0, - itemGap: 16.0, - sectionHeaderToContent: 40.0, - radiusFull: 30.0, - radiusCard: 14.0, - radiusSmall: 6.0, - ); - - @override - AppSizeTheme copyWith({ - double? logoHeight, - double? mainMenuHeight, - double? mainMenuWidth, - double? mainMenuIconSize, - double? navbarHeight, - double? navbarItemHeight, - double? navbarItemWidth, - double? navbarIconWidth, - double? floatingBtnHeight, - double? floatingBtnWidth, - double? settingMenuIconSize, - double? settingMenuShareIconSize, - double? accountListItemHeight, - double? accountListItemLogoWidth, - double? appbarIconSize, - double? sendOverlayContainerWidth, - double? overlayCloseIconSize, - double? mnemonicCellDesiredHeight, - double? txListItemIconWidth, - double? txDetailsIconHeight, - double? txDetailsIconWidth, - double? copyIconSize, - double? pasteIconSize, - double? timePickerSubtitleWidth, - double? bottomButtonSpacing, - double? buttonsHorizontalSpacing, - double? infoSheetTitleIcon, - double? screenPadding, - double? cardPadding, - double? sectionGap, - double? itemGap, - double? sectionHeaderToContent, - double? radiusFull, - double? radiusCard, - double? radiusSmall, - }) { - return AppSizeTheme( - logoHeight: logoHeight ?? this.logoHeight, - mainMenuHeight: mainMenuHeight ?? this.mainMenuHeight, - mainMenuWidth: mainMenuWidth ?? this.mainMenuWidth, - mainMenuIconSize: mainMenuIconSize ?? this.mainMenuIconSize, - navbarHeight: navbarHeight ?? this.navbarHeight, - navbarItemHeight: navbarItemHeight ?? this.navbarItemHeight, - navbarItemWidth: navbarItemWidth ?? this.navbarItemWidth, - navbarIconWidth: navbarIconWidth ?? this.navbarIconWidth, - floatingBtnHeight: floatingBtnHeight ?? this.floatingBtnHeight, - floatingBtnWidth: floatingBtnWidth ?? this.floatingBtnWidth, - settingMenuIconSize: settingMenuIconSize ?? this.settingMenuIconSize, - settingMenuShareIconSize: settingMenuShareIconSize ?? this.settingMenuShareIconSize, - accountListItemHeight: accountListItemHeight ?? this.accountListItemHeight, - accountListItemLogoWidth: accountListItemLogoWidth ?? this.accountListItemLogoWidth, - appbarIconSize: appbarIconSize ?? this.appbarIconSize, - sendOverlayContainerWidth: sendOverlayContainerWidth ?? this.sendOverlayContainerWidth, - overlayCloseIconSize: overlayCloseIconSize ?? this.overlayCloseIconSize, - mnemonicCellDesiredHeight: mnemonicCellDesiredHeight ?? this.mnemonicCellDesiredHeight, - txListItemIconWidth: txListItemIconWidth ?? this.txListItemIconWidth, - txDetailsIconHeight: txDetailsIconHeight ?? this.txDetailsIconHeight, - txDetailsIconWidth: txDetailsIconWidth ?? this.txDetailsIconWidth, - copyIconSize: copyIconSize ?? this.copyIconSize, - pasteIconSize: pasteIconSize ?? this.pasteIconSize, - timePickerSubtitleWidth: timePickerSubtitleWidth ?? this.timePickerSubtitleWidth, - bottomButtonSpacing: bottomButtonSpacing ?? this.bottomButtonSpacing, - buttonsHorizontalSpacing: buttonsHorizontalSpacing ?? this.buttonsHorizontalSpacing, - infoSheetTitleIcon: infoSheetTitleIcon ?? this.infoSheetTitleIcon, - screenPadding: screenPadding ?? this.screenPadding, - cardPadding: cardPadding ?? this.cardPadding, - sectionGap: sectionGap ?? this.sectionGap, - itemGap: itemGap ?? this.itemGap, - sectionHeaderToContent: sectionHeaderToContent ?? this.sectionHeaderToContent, - radiusFull: radiusFull ?? this.radiusFull, - radiusCard: radiusCard ?? this.radiusCard, - radiusSmall: radiusSmall ?? this.radiusSmall, - ); - } - - @override - AppSizeTheme lerp(AppSizeTheme? other, double t) { - if (other is! AppSizeTheme) return this; - double l(double a, double b) => a + (b - a) * t; - return AppSizeTheme( - logoHeight: l(logoHeight, other.logoHeight), - mainMenuHeight: l(mainMenuHeight, other.mainMenuHeight), - mainMenuWidth: l(mainMenuWidth, other.mainMenuWidth), - mainMenuIconSize: l(mainMenuIconSize, other.mainMenuIconSize), - navbarHeight: l(navbarHeight, other.navbarHeight), - navbarItemHeight: l(navbarItemHeight, other.navbarItemHeight), - navbarItemWidth: l(navbarItemWidth, other.navbarItemWidth), - navbarIconWidth: l(navbarIconWidth, other.navbarIconWidth), - floatingBtnHeight: l(floatingBtnHeight, other.floatingBtnHeight), - floatingBtnWidth: l(floatingBtnWidth, other.floatingBtnWidth), - settingMenuIconSize: l(settingMenuIconSize, other.settingMenuIconSize), - settingMenuShareIconSize: l(settingMenuShareIconSize, other.settingMenuShareIconSize), - accountListItemHeight: l(accountListItemHeight, other.accountListItemHeight), - accountListItemLogoWidth: l(accountListItemLogoWidth, other.accountListItemLogoWidth), - appbarIconSize: l(appbarIconSize, other.appbarIconSize), - sendOverlayContainerWidth: l(sendOverlayContainerWidth, other.sendOverlayContainerWidth), - overlayCloseIconSize: l(overlayCloseIconSize, other.overlayCloseIconSize), - mnemonicCellDesiredHeight: l(mnemonicCellDesiredHeight, other.mnemonicCellDesiredHeight), - txListItemIconWidth: l(txListItemIconWidth, other.txListItemIconWidth), - txDetailsIconHeight: l(txDetailsIconHeight, other.txDetailsIconHeight), - txDetailsIconWidth: l(txDetailsIconWidth, other.txDetailsIconWidth), - copyIconSize: l(copyIconSize, other.copyIconSize), - pasteIconSize: l(pasteIconSize, other.pasteIconSize), - timePickerSubtitleWidth: l(timePickerSubtitleWidth, other.timePickerSubtitleWidth), - bottomButtonSpacing: l(bottomButtonSpacing, other.bottomButtonSpacing), - buttonsHorizontalSpacing: l(buttonsHorizontalSpacing, other.buttonsHorizontalSpacing), - infoSheetTitleIcon: l(infoSheetTitleIcon, other.infoSheetTitleIcon), - screenPadding: l(screenPadding, other.screenPadding), - cardPadding: l(cardPadding, other.cardPadding), - sectionGap: l(sectionGap, other.sectionGap), - itemGap: l(itemGap, other.itemGap), - sectionHeaderToContent: l(sectionHeaderToContent, other.sectionHeaderToContent), - radiusFull: l(radiusFull, other.radiusFull), - radiusCard: l(radiusCard, other.radiusCard), - radiusSmall: l(radiusSmall, other.radiusSmall), - ); - } -} - -extension AppSizeThemeExtension on BuildContext { - AppSizeTheme get themeSize => Theme.of(this).extension()!; -} diff --git a/cold-wallet-app/lib/theme/app_text_styles.dart b/cold-wallet-app/lib/theme/app_text_styles.dart deleted file mode 100644 index 441eb64c4..000000000 --- a/cold-wallet-app/lib/theme/app_text_styles.dart +++ /dev/null @@ -1,251 +0,0 @@ -import 'package:flutter/material.dart'; - -@immutable -class AppTextTheme extends ThemeExtension { - static const fontFamily = 'Geist'; - static const fontFamilySecondary = 'Geist Mono'; - - final TextStyle? lockTitle; - final TextStyle? extraLargeTitle; - final TextStyle? largeTitle; - final TextStyle? mediumTitle; - final TextStyle? smallTitle; - final TextStyle? paragraph; - final TextStyle? smallParagraph; - final TextStyle? receiveLabel; - final TextStyle? largeTag; - final TextStyle? tag; - final TextStyle? timer; - final TextStyle? detail; - final TextStyle? tiny; - final TextStyle? totalMinedBlocks; - final TextStyle? transactionDetailAmountPrimary; - final TextStyle? transactionDetailAmountSymbol; - final TextStyle? transactionDetailRowLabel; - final TextStyle? transactionDetailRowValue; - final TextStyle? sendSectionLabel; - final TextStyle? conversionAmountPrimary; - - const AppTextTheme({ - this.lockTitle, - this.extraLargeTitle, - this.largeTitle, - this.mediumTitle, - this.smallTitle, - this.paragraph, - this.smallParagraph, - this.receiveLabel, - this.largeTag, - this.tag, - this.timer, - this.detail, - this.tiny, - this.totalMinedBlocks, - this.transactionDetailAmountPrimary, - this.transactionDetailAmountSymbol, - this.transactionDetailRowLabel, - this.transactionDetailRowValue, - this.sendSectionLabel, - this.conversionAmountPrimary, - }); - - const AppTextTheme.defaultTheme() - : this( - lockTitle: const TextStyle(fontSize: 24, fontFamily: fontFamily), - extraLargeTitle: const TextStyle(fontSize: 40, fontFamily: fontFamily, fontWeight: FontWeight.w600), - largeTitle: const TextStyle(fontSize: 30, fontFamily: fontFamily, fontWeight: FontWeight.w300), - mediumTitle: const TextStyle(fontSize: 24, fontFamily: fontFamily, fontWeight: FontWeight.w500), - smallTitle: const TextStyle(fontSize: 18, fontWeight: FontWeight.w500, fontFamily: fontFamily), - paragraph: const TextStyle(fontSize: 16, fontWeight: FontWeight.w400, fontFamily: fontFamily), - smallParagraph: const TextStyle(fontSize: 14, fontWeight: FontWeight.w400, fontFamily: fontFamily), - receiveLabel: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500, fontFamily: fontFamilySecondary), - largeTag: const TextStyle(fontSize: 16, fontWeight: FontWeight.w400, fontFamily: fontFamily), - tag: const TextStyle(fontSize: 12, fontWeight: FontWeight.w300, fontFamily: fontFamily), - timer: const TextStyle(fontSize: 28, fontWeight: FontWeight.w600, fontFamily: fontFamily), - detail: const TextStyle(fontSize: 12, fontWeight: FontWeight.w400, fontFamily: fontFamily), - tiny: const TextStyle(fontSize: 11, fontWeight: FontWeight.w400, fontFamily: fontFamily), - totalMinedBlocks: const TextStyle( - fontFamily: fontFamilySecondary, - fontSize: 56, - fontWeight: FontWeight.w400, - height: 1.0, - ), - transactionDetailAmountPrimary: const TextStyle( - fontFamily: fontFamilySecondary, - fontSize: 64, - fontWeight: FontWeight.w300, - letterSpacing: -2.77, - height: 1.0, - ), - transactionDetailAmountSymbol: const TextStyle( - fontFamily: fontFamilySecondary, - fontSize: 24, - fontWeight: FontWeight.w300, - ), - transactionDetailRowLabel: const TextStyle( - fontFamily: fontFamilySecondary, - fontSize: 12, - fontWeight: FontWeight.w400, - letterSpacing: 0.85, - ), - transactionDetailRowValue: const TextStyle( - fontFamily: fontFamilySecondary, - fontSize: 12, - fontWeight: FontWeight.w500, - ), - sendSectionLabel: const TextStyle( - fontSize: 20, - height: 1.0, - fontWeight: FontWeight.w400, - fontFamily: fontFamily, - ), - conversionAmountPrimary: const TextStyle( - fontSize: 40, - fontFamily: fontFamilySecondary, - fontWeight: FontWeight.w400, - ), - ); - - const AppTextTheme.iPad() - : this( - lockTitle: const TextStyle(color: Colors.white, fontSize: 28, fontFamily: fontFamily), - extraLargeTitle: const TextStyle(fontSize: 52, fontFamily: fontFamily, fontWeight: FontWeight.w600), - largeTitle: const TextStyle(fontSize: 36, fontFamily: fontFamily, fontWeight: FontWeight.w300), - mediumTitle: const TextStyle(fontSize: 28, fontFamily: fontFamily, fontWeight: FontWeight.w400), - smallTitle: const TextStyle(fontSize: 24, fontWeight: FontWeight.w500, fontFamily: fontFamily), - paragraph: const TextStyle(fontSize: 20, fontWeight: FontWeight.w400, fontFamily: fontFamily), - smallParagraph: const TextStyle(fontSize: 18, fontWeight: FontWeight.w400, fontFamily: fontFamily), - receiveLabel: const TextStyle(fontSize: 18, fontWeight: FontWeight.w500, fontFamily: fontFamilySecondary), - largeTag: const TextStyle(fontSize: 24, fontWeight: FontWeight.w400, fontFamily: fontFamily), - tag: const TextStyle(fontSize: 16, fontWeight: FontWeight.w300, fontFamily: fontFamily), - timer: const TextStyle(fontSize: 36, fontWeight: FontWeight.w600, fontFamily: fontFamily), - detail: const TextStyle(fontSize: 16, fontWeight: FontWeight.w400, fontFamily: fontFamily), - tiny: const TextStyle(fontSize: 15, fontWeight: FontWeight.w400, fontFamily: fontFamily), - totalMinedBlocks: const TextStyle( - fontFamily: fontFamilySecondary, - fontSize: 60, - fontWeight: FontWeight.w400, - height: 1.0, - ), - transactionDetailAmountPrimary: const TextStyle( - fontFamily: fontFamilySecondary, - fontSize: 80, - fontWeight: FontWeight.w300, - letterSpacing: -2.77, - height: 1.0, - ), - transactionDetailAmountSymbol: const TextStyle( - fontFamily: fontFamilySecondary, - fontSize: 30, - fontWeight: FontWeight.w300, - ), - transactionDetailRowLabel: const TextStyle( - fontFamily: fontFamilySecondary, - fontSize: 16, - fontWeight: FontWeight.w400, - letterSpacing: 0.85, - ), - transactionDetailRowValue: const TextStyle( - fontFamily: fontFamilySecondary, - fontSize: 16, - fontWeight: FontWeight.w500, - ), - sendSectionLabel: const TextStyle( - fontSize: 24, - height: 1.0, - fontWeight: FontWeight.w400, - fontFamily: fontFamily, - ), - conversionAmountPrimary: const TextStyle( - fontSize: 52, - fontFamily: fontFamilySecondary, - fontWeight: FontWeight.w400, - ), - ); - - @override - AppTextTheme copyWith({ - TextStyle? lockTitle, - TextStyle? extraLargeTitle, - TextStyle? largeTitle, - TextStyle? mediumTitle, - TextStyle? smallTitle, - TextStyle? paragraph, - TextStyle? smallParagraph, - TextStyle? receiveLabel, - TextStyle? largeTag, - TextStyle? tag, - TextStyle? timer, - TextStyle? detail, - TextStyle? tiny, - TextStyle? totalMinedBlocks, - TextStyle? transactionDetailAmountPrimary, - TextStyle? transactionDetailAmountSymbol, - TextStyle? transactionDetailRowLabel, - TextStyle? transactionDetailRowValue, - TextStyle? sendSectionLabel, - TextStyle? conversionAmountPrimary, - }) { - return AppTextTheme( - lockTitle: lockTitle ?? this.lockTitle, - extraLargeTitle: extraLargeTitle ?? this.extraLargeTitle, - largeTitle: largeTitle ?? this.largeTitle, - mediumTitle: mediumTitle ?? this.mediumTitle, - smallTitle: smallTitle ?? this.smallTitle, - paragraph: paragraph ?? this.paragraph, - smallParagraph: smallParagraph ?? this.smallParagraph, - receiveLabel: receiveLabel ?? this.receiveLabel, - largeTag: largeTag ?? this.largeTag, - tag: tag ?? this.tag, - timer: timer ?? this.timer, - detail: detail ?? this.detail, - tiny: tiny ?? this.tiny, - totalMinedBlocks: totalMinedBlocks ?? this.totalMinedBlocks, - transactionDetailAmountPrimary: transactionDetailAmountPrimary ?? this.transactionDetailAmountPrimary, - transactionDetailAmountSymbol: transactionDetailAmountSymbol ?? this.transactionDetailAmountSymbol, - transactionDetailRowLabel: transactionDetailRowLabel ?? this.transactionDetailRowLabel, - transactionDetailRowValue: transactionDetailRowValue ?? this.transactionDetailRowValue, - sendSectionLabel: sendSectionLabel ?? this.sendSectionLabel, - conversionAmountPrimary: conversionAmountPrimary ?? this.conversionAmountPrimary, - ); - } - - @override - AppTextTheme lerp(AppTextTheme? other, double t) { - if (other is! AppTextTheme) return this; - return AppTextTheme( - lockTitle: TextStyle.lerp(lockTitle, other.lockTitle, t), - extraLargeTitle: TextStyle.lerp(extraLargeTitle, other.extraLargeTitle, t), - largeTitle: TextStyle.lerp(largeTitle, other.largeTitle, t), - mediumTitle: TextStyle.lerp(mediumTitle, other.mediumTitle, t), - smallTitle: TextStyle.lerp(smallTitle, other.smallTitle, t), - paragraph: TextStyle.lerp(paragraph, other.paragraph, t), - smallParagraph: TextStyle.lerp(smallParagraph, other.smallParagraph, t), - receiveLabel: TextStyle.lerp(receiveLabel, other.receiveLabel, t), - largeTag: TextStyle.lerp(largeTag, other.largeTag, t), - tag: TextStyle.lerp(tag, other.tag, t), - timer: TextStyle.lerp(timer, other.timer, t), - detail: TextStyle.lerp(detail, other.detail, t), - tiny: TextStyle.lerp(tiny, other.tiny, t), - totalMinedBlocks: TextStyle.lerp(totalMinedBlocks, other.totalMinedBlocks, t), - transactionDetailAmountPrimary: TextStyle.lerp( - transactionDetailAmountPrimary, - other.transactionDetailAmountPrimary, - t, - ), - transactionDetailAmountSymbol: TextStyle.lerp( - transactionDetailAmountSymbol, - other.transactionDetailAmountSymbol, - t, - ), - transactionDetailRowLabel: TextStyle.lerp(transactionDetailRowLabel, other.transactionDetailRowLabel, t), - transactionDetailRowValue: TextStyle.lerp(transactionDetailRowValue, other.transactionDetailRowValue, t), - sendSectionLabel: TextStyle.lerp(sendSectionLabel, other.sendSectionLabel, t), - conversionAmountPrimary: TextStyle.lerp(conversionAmountPrimary, other.conversionAmountPrimary, t), - ); - } -} - -extension AppTextThemeExtension on BuildContext { - AppTextTheme get themeText => Theme.of(this).extension()!; -} diff --git a/cold-wallet-app/lib/theme/app_theme.dart b/cold-wallet-app/lib/theme/app_theme.dart deleted file mode 100644 index f6e9b07b6..000000000 --- a/cold-wallet-app/lib/theme/app_theme.dart +++ /dev/null @@ -1,55 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:quantus_sdk/quantus_sdk.dart' show AppColorsV3, AppRadiusV3, AppTextThemeV3, ColorOpacityExtension; -import 'package:quantus_cold_wallet/shared/context_extensions.dart'; -import 'package:quantus_cold_wallet/theme/app_colors.dart'; -import 'package:quantus_cold_wallet/theme/app_spacing.dart'; -import 'package:quantus_cold_wallet/theme/app_text_styles.dart'; - -class AppTheme { - static ThemeData darkTheme(BuildContext context) { - final isTablet = context.isTablet; - final colors = const AppColorsV2.dark(); - final text = isTablet ? const AppTextTheme.iPad() : const AppTextTheme.defaultTheme(); - const radius = AppRadiusV3.standard(); - - return ThemeData( - scaffoldBackgroundColor: colors.background, - cardColor: colors.surface, - colorScheme: ColorScheme.dark(surface: colors.surface, error: colors.error), - appBarTheme: AppBarTheme(backgroundColor: colors.surface, elevation: 0), - elevatedButtonTheme: ElevatedButtonThemeData( - style: ElevatedButton.styleFrom( - foregroundColor: Colors.white, - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14)), - ), - ), - outlinedButtonTheme: OutlinedButtonThemeData( - style: OutlinedButton.styleFrom(shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14))), - ), - textButtonTheme: TextButtonThemeData(style: TextButton.styleFrom(foregroundColor: colors.textPrimary)), - textSelectionTheme: TextSelectionThemeData( - cursorColor: colors.accentOrange, - selectionColor: colors.accentOrange.useOpacity(0.2), - selectionHandleColor: colors.accentOrange, - ), - inputDecorationTheme: InputDecorationTheme( - hintStyle: text.smallParagraph?.copyWith(color: colors.textLabel, fontFamily: AppTextTheme.fontFamilySecondary), - contentPadding: EdgeInsets.zero, - isDense: true, - border: InputBorder.none, - enabledBorder: InputBorder.none, - focusedBorder: InputBorder.none, - filled: true, - fillColor: Colors.transparent, - ), - extensions: [ - colors, - const AppColorsV3.dark(), - text, - const AppTextThemeV3.standard(), - radius, - isTablet ? const AppSizeTheme.iPad() : const AppSizeTheme.defaultTheme(), - ], - ); - } -} diff --git a/cold-wallet-app/lib/widgets/change_password_sheet.dart b/cold-wallet-app/lib/widgets/change_password_sheet.dart index 8468bb56f..cd8ea69b2 100644 --- a/cold-wallet-app/lib/widgets/change_password_sheet.dart +++ b/cold-wallet-app/lib/widgets/change_password_sheet.dart @@ -1,9 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_cold_wallet/components/quantus_button.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:quantus_cold_wallet/providers/wallet_providers.dart'; -import 'package:quantus_cold_wallet/theme/app_colors.dart'; -import 'package:quantus_cold_wallet/theme/app_text_styles.dart'; import 'package:quantus_cold_wallet/widgets/password_field.dart'; /// Action pane for setting or changing the vault password. Resolves to true diff --git a/cold-wallet-app/lib/widgets/connectivity_guard.dart b/cold-wallet-app/lib/widgets/connectivity_guard.dart index ecb1a917e..2a6eb273c 100644 --- a/cold-wallet-app/lib/widgets/connectivity_guard.dart +++ b/cold-wallet-app/lib/widgets/connectivity_guard.dart @@ -1,11 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_cold_wallet/components/base_background.dart'; -import 'package:quantus_cold_wallet/components/quantus_button.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:quantus_cold_wallet/providers/connectivity_provider.dart'; import 'package:quantus_cold_wallet/providers/settings_providers.dart'; -import 'package:quantus_cold_wallet/theme/app_colors.dart'; -import 'package:quantus_cold_wallet/theme/app_text_styles.dart'; /// Full-screen blocker shown whenever any network is reachable. A cold wallet /// must stay air-gapped, so this overlays everything and only clears once the diff --git a/cold-wallet-app/lib/widgets/password_field.dart b/cold-wallet-app/lib/widgets/password_field.dart index 8798021e8..1d0251708 100644 --- a/cold-wallet-app/lib/widgets/password_field.dart +++ b/cold-wallet-app/lib/widgets/password_field.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:quantus_cold_wallet/theme/app_colors.dart'; -import 'package:quantus_cold_wallet/theme/app_text_styles.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; class PasswordField extends StatefulWidget { final TextEditingController controller; diff --git a/cold-wallet-app/test/change_password_sheet_test.dart b/cold-wallet-app/test/change_password_sheet_test.dart index ab21dd0f8..7394101d1 100644 --- a/cold-wallet-app/test/change_password_sheet_test.dart +++ b/cold-wallet-app/test/change_password_sheet_test.dart @@ -4,8 +4,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:quantus_cold_wallet/providers/wallet_providers.dart'; -import 'package:quantus_cold_wallet/theme/app_theme.dart'; import 'package:quantus_cold_wallet/widgets/change_password_sheet.dart'; class _HangingController extends WalletController { diff --git a/quantus_sdk/lib/src/ui/components/animated_ur_qr.dart b/quantus_sdk/lib/src/ui/components/animated_ur_qr.dart index 4c61f08cc..81a441500 100644 --- a/quantus_sdk/lib/src/ui/components/animated_ur_qr.dart +++ b/quantus_sdk/lib/src/ui/components/animated_ur_qr.dart @@ -4,18 +4,20 @@ import 'package:flutter/material.dart'; import 'package:qr_flutter/qr_flutter.dart'; /// Renders a UR payload as a QR code. A multi-part UR is animated by cycling -/// through its fragments with a [Timer]. A single-part UR renders statically. +/// through its fragments with a [Timer] (no post-frame callbacks). Reacts to +/// [fps], [paused] and [parts] changes so the animation can be tuned live. +/// +/// Every frame's QR is encoded once up front: encoding a dense QR takes long +/// enough that doing it inside build caps the real frame rate well below the +/// requested one. Painting a precomputed module matrix keeps ticks cheap. class AnimatedUrQr extends StatefulWidget { final List parts; - final Duration interval; + final int fps; + final bool paused; final double size; - const AnimatedUrQr({ - super.key, - required this.parts, - this.interval = const Duration(milliseconds: 200), - this.size = 280, - }); + const AnimatedUrQr({super.key, required this.parts, this.fps = 15, this.paused = false, this.size = 280}) + : assert(fps > 0, 'AnimatedUrQr fps must be positive'); @override State createState() => _AnimatedUrQrState(); @@ -24,15 +26,49 @@ class AnimatedUrQr extends StatefulWidget { class _AnimatedUrQrState extends State { Timer? _timer; int _index = 0; + late List _painters; @override void initState() { super.initState(); - if (widget.parts.length > 1) { - _timer = Timer.periodic(widget.interval, (_) { - setState(() => _index = (_index + 1) % widget.parts.length); - }); + _painters = _buildPainters(); + _restartTimer(); + } + + List _buildPainters() { + assert(widget.parts.isNotEmpty, 'AnimatedUrQr requires at least one UR part'); + return widget.parts + .map( + (part) => QrPainter.withQr( + qr: QrCode.fromData(data: part, errorCorrectLevel: QrErrorCorrectLevel.L), + gapless: true, + eyeStyle: const QrEyeStyle(eyeShape: QrEyeShape.square, color: Colors.black), + dataModuleStyle: const QrDataModuleStyle(dataModuleShape: QrDataModuleShape.square, color: Colors.black), + ), + ) + .toList(); + } + + @override + void didUpdateWidget(AnimatedUrQr oldWidget) { + super.didUpdateWidget(oldWidget); + final partsChanged = !identical(widget.parts, oldWidget.parts); + if (partsChanged) { + _painters = _buildPainters(); + _index = 0; } + if (partsChanged || widget.fps != oldWidget.fps || widget.paused != oldWidget.paused) { + _restartTimer(); + } + } + + void _restartTimer() { + _timer?.cancel(); + _timer = null; + if (widget.paused || widget.parts.length <= 1) return; + _timer = Timer.periodic(Duration(milliseconds: (1000 / widget.fps).round()), (_) { + setState(() => _index = (_index + 1) % widget.parts.length); + }); } @override @@ -48,14 +84,7 @@ class _AnimatedUrQrState extends State { height: widget.size, padding: const EdgeInsets.all(16), decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(16)), - child: QrImageView( - data: widget.parts[_index], - errorCorrectionLevel: QrErrorCorrectLevel.L, - version: QrVersions.auto, - backgroundColor: Colors.white, - eyeStyle: const QrEyeStyle(eyeShape: QrEyeShape.square, color: Colors.black), - dataModuleStyle: const QrDataModuleStyle(dataModuleShape: QrDataModuleShape.square, color: Colors.black), - ), + child: CustomPaint(painter: _painters[_index]), ); } } diff --git a/quantus_sdk/test/ui/animated_ur_qr_test.dart b/quantus_sdk/test/ui/animated_ur_qr_test.dart new file mode 100644 index 000000000..c2bc268c8 --- /dev/null +++ b/quantus_sdk/test/ui/animated_ur_qr_test.dart @@ -0,0 +1,137 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:qr_flutter/qr_flutter.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + const parts = ['ur:bytes/1-3/first', 'ur:bytes/2-3/second', 'ur:bytes/3-3/third']; + + Future pumpQr(WidgetTester tester, {required List parts, int fps = 10, bool paused = false}) async { + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: AnimatedUrQr(parts: parts, fps: fps, paused: paused), + ), + ), + ); + } + + Finder qrPaintFinder() => find.descendant(of: find.byType(AnimatedUrQr), matching: find.byType(CustomPaint)); + + QrPainter painterOf(WidgetTester tester) { + final paint = tester.widget(qrPaintFinder()); + return paint.painter! as QrPainter; + } + + testWidgets('paints a precomputed QR matrix instead of encoding in build', (tester) async { + await pumpQr(tester, parts: parts); + + expect(qrPaintFinder(), findsOneWidget); + expect(find.byType(QrImageView), findsNothing); + expect(painterOf(tester), isA()); + }); + + testWidgets('cycles to the next precomputed frame on each tick', (tester) async { + await pumpQr(tester, parts: parts, fps: 10); + + final first = painterOf(tester); + await tester.pump(const Duration(milliseconds: 100)); + final second = painterOf(tester); + expect(identical(first, second), isFalse); + + await tester.pump(const Duration(milliseconds: 100)); + final third = painterOf(tester); + expect(identical(second, third), isFalse); + + await tester.pump(const Duration(milliseconds: 100)); + expect(identical(painterOf(tester), first), isTrue); + }); + + testWidgets('does not advance while paused', (tester) async { + await pumpQr(tester, parts: parts, fps: 10, paused: true); + + final first = painterOf(tester); + await tester.pump(const Duration(milliseconds: 500)); + expect(identical(painterOf(tester), first), isTrue); + }); + + testWidgets('restarts the timer when fps changes', (tester) async { + var fps = 1; + late VoidCallback setFps; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: StatefulBuilder( + builder: (context, setState) { + setFps = () => setState(() => fps = 10); + return AnimatedUrQr(parts: parts, fps: fps); + }, + ), + ), + ), + ); + + final first = painterOf(tester); + await tester.pump(const Duration(milliseconds: 500)); + expect(identical(painterOf(tester), first), isTrue, reason: '1 fps should not tick in 500ms'); + + setFps(); + await tester.pump(); + await tester.pump(const Duration(milliseconds: 100)); + expect(identical(painterOf(tester), first), isFalse); + }); + + testWidgets('starts animating when parts grow from one to many', (tester) async { + var currentParts = const ['ur:bytes/only']; + late VoidCallback growParts; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: StatefulBuilder( + builder: (context, setState) { + growParts = () => setState(() => currentParts = parts); + return AnimatedUrQr(parts: currentParts, fps: 10); + }, + ), + ), + ), + ); + + await tester.pump(const Duration(milliseconds: 200)); + + growParts(); + await tester.pump(); + final afterUpdate = painterOf(tester); + await tester.pump(const Duration(milliseconds: 100)); + expect(identical(painterOf(tester), afterUpdate), isFalse); + }); + + testWidgets('defaults fps to 15 and paused to false', (tester) async { + await tester.pumpWidget( + const MaterialApp( + home: Scaffold(body: AnimatedUrQr(parts: parts)), + ), + ); + + final qr = tester.widget(find.byType(AnimatedUrQr)); + expect(qr.fps, 15); + expect(qr.paused, isFalse); + }); + + testWidgets('rejects an empty parts list', (tester) async { + await tester.pumpWidget( + const MaterialApp( + home: Scaffold(body: AnimatedUrQr(parts: [])), + ), + ); + expect(tester.takeException(), isAssertionError); + }); + + test('rejects a non-positive fps', () { + expect(() => AnimatedUrQr(parts: parts, fps: 0), throwsA(isA())); + }); +} From 8d3638f94b1375f2d38193c71d0c6e6eeac9631b Mon Sep 17 00:00:00 2001 From: Beast Date: Wed, 19 Aug 2026 12:43:00 +0800 Subject: [PATCH 19/38] feat: reusable mnemonic grid --- .../lib/components/glass_button_base.dart | 58 --------------- .../lib/components/mnemonic_grid.dart | 73 ------------------- .../lib/screens/create_wallet_screen.dart | 1 - .../v2/components/recovery_phrase_body.dart | 1 - quantus_sdk/lib/src/ui/components/index.dart | 1 + .../lib/src/ui}/components/mnemonic_grid.dart | 0 6 files changed, 1 insertion(+), 133 deletions(-) delete mode 100644 cold-wallet-app/lib/components/glass_button_base.dart delete mode 100644 cold-wallet-app/lib/components/mnemonic_grid.dart rename {mobile-app/lib/v2 => quantus_sdk/lib/src/ui}/components/mnemonic_grid.dart (100%) diff --git a/cold-wallet-app/lib/components/glass_button_base.dart b/cold-wallet-app/lib/components/glass_button_base.dart deleted file mode 100644 index 6306026a6..000000000 --- a/cold-wallet-app/lib/components/glass_button_base.dart +++ /dev/null @@ -1,58 +0,0 @@ -import 'dart:math' as math; -import 'package:flutter/material.dart'; - -class GlassButtonBase extends StatelessWidget { - final Widget child; - final double? buttonHeight; - final double? buttonWidth; - final BorderRadius? borderRadius; - final EdgeInsets? padding; - - const GlassButtonBase({ - super.key, - required this.child, - this.buttonHeight, - this.buttonWidth, - this.borderRadius, - this.padding, - }); - - @override - Widget build(BuildContext context) { - return Container( - height: buttonHeight, - width: buttonWidth, - decoration: BoxDecoration( - borderRadius: borderRadius, - gradient: const LinearGradient( - transform: GradientRotation(30 * math.pi / 180), - colors: [ - Color(0xFF6F6F6F), // 0% - Color(0xFF1F1F1F), // 25% - Color(0xFF0E0E0E), // 50% - Color(0xFF1F1F1F), // 75% - Color(0xFF6F6F6F), // 100% - ], - stops: [0.0, 0.25, 0.50, 0.75, 1.0], - ), - ), - // The padding acts as the border thickness! - padding: const EdgeInsets.all(0.5), - child: Container( - decoration: BoxDecoration( - borderRadius: borderRadius, - gradient: const LinearGradient( - transform: GradientRotation(45 * math.pi / 180), - colors: [Color(0xFF050505), Color(0xFF171717)], - stops: [0, 1], - ), - ), - child: Container( - padding: padding, - decoration: BoxDecoration(borderRadius: borderRadius, color: const Color.fromRGBO(255, 255, 255, 0.02)), - child: child, - ), - ), - ); - } -} diff --git a/cold-wallet-app/lib/components/mnemonic_grid.dart b/cold-wallet-app/lib/components/mnemonic_grid.dart deleted file mode 100644 index 01abb8569..000000000 --- a/cold-wallet-app/lib/components/mnemonic_grid.dart +++ /dev/null @@ -1,73 +0,0 @@ -import 'dart:ui'; - -import 'package:flutter/material.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; - -class MnemonicGrid extends StatelessWidget { - final List words; - final bool isRevealed; - - const MnemonicGrid({super.key, required this.words, this.isRevealed = false}); - - @override - Widget build(BuildContext context) { - return LayoutBuilder( - builder: (context, constraints) { - // Calculate the available width for each item - // constraints.maxWidth is the total width of the GridView - // 2 * crossAxisSpacing (for the gaps between 3 items) - // Adjust for any padding within the _buildMnemonicWord container - final double availableWidth = constraints.maxWidth - (2 * 9.0); // 2 gaps of 9.0 - final double itemWidth = (availableWidth / 3); // 3 items per row - - // You might need to adjust this value slightly based on padding/margins - // and font rendering. - final double desiredCellHeight = context.isTablet ? 61 : 36.0; - - // Calculate the aspect ratio - final double childAspectRatio = itemWidth / desiredCellHeight; - - return GridView.count( - crossAxisCount: 3, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - mainAxisSpacing: 10.0, - crossAxisSpacing: 9.0, - childAspectRatio: childAspectRatio, - children: List.generate(words.length, (index) { - return _buildMnemonicWord(index + 1, words[index], isRevealed, context); - }), - ); - }, - ); - } - - Widget _buildMnemonicWord(int index, String word, bool isRevealed, BuildContext context) { - final padding = const EdgeInsets.symmetric(horizontal: 10); - final double blur = isRevealed ? 0 : 5; - final effectiveWord = isRevealed ? word : 'x' * word.length; - - return Container( - padding: padding, - decoration: BoxDecoration(color: context.colors.surfaceDeep, borderRadius: BorderRadius.circular(14)), - child: Row( - children: [ - Text( - '$index', - textAlign: TextAlign.left, - style: context.themeText.detail?.copyWith(color: context.colors.textTertiary), - ), - const SizedBox(width: 8), - ImageFiltered( - imageFilter: ImageFilter.blur(sigmaX: blur, sigmaY: blur), - child: Text( - effectiveWord, - textAlign: TextAlign.left, - style: context.themeText.detail?.copyWith(color: context.colors.checksum), - ), - ), - ], - ), - ); - } -} diff --git a/cold-wallet-app/lib/screens/create_wallet_screen.dart b/cold-wallet-app/lib/screens/create_wallet_screen.dart index 30865c274..1cfce74b0 100644 --- a/cold-wallet-app/lib/screens/create_wallet_screen.dart +++ b/cold-wallet-app/lib/screens/create_wallet_screen.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:quantus_cold_wallet/components/mnemonic_grid.dart'; import 'package:quantus_cold_wallet/screens/set_password_screen.dart'; class CreateWalletScreen extends StatefulWidget { diff --git a/mobile-app/lib/v2/components/recovery_phrase_body.dart b/mobile-app/lib/v2/components/recovery_phrase_body.dart index b2c0b4676..87ff4365b 100644 --- a/mobile-app/lib/v2/components/recovery_phrase_body.dart +++ b/mobile-app/lib/v2/components/recovery_phrase_body.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:resonance_network_wallet/v2/components/mnemonic_grid.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/shared/constants/e2e_keys.dart'; diff --git a/quantus_sdk/lib/src/ui/components/index.dart b/quantus_sdk/lib/src/ui/components/index.dart index 7703321f1..8ac75ed3b 100644 --- a/quantus_sdk/lib/src/ui/components/index.dart +++ b/quantus_sdk/lib/src/ui/components/index.dart @@ -24,3 +24,4 @@ export 'quantus_qr.dart'; export 'segmented_controls.dart'; export 'back_button.dart'; export 'animated_ur_qr.dart'; +export 'mnemonic_grid.dart'; \ No newline at end of file diff --git a/mobile-app/lib/v2/components/mnemonic_grid.dart b/quantus_sdk/lib/src/ui/components/mnemonic_grid.dart similarity index 100% rename from mobile-app/lib/v2/components/mnemonic_grid.dart rename to quantus_sdk/lib/src/ui/components/mnemonic_grid.dart From 162b964b2d49c2064e2f113935b11fc745f7bd26 Mon Sep 17 00:00:00 2001 From: Beast Date: Wed, 19 Aug 2026 12:52:50 +0800 Subject: [PATCH 20/38] feat: update dialog component --- .../lib/components/confirm_dialog.dart | 20 +----- cold-wallet-app/test/confirm_dialog_test.dart | 67 +++++++++++++++++++ quantus_sdk/lib/src/ui/components/index.dart | 2 +- 3 files changed, 70 insertions(+), 19 deletions(-) create mode 100644 cold-wallet-app/test/confirm_dialog_test.dart diff --git a/cold-wallet-app/lib/components/confirm_dialog.dart b/cold-wallet-app/lib/components/confirm_dialog.dart index ef864c33e..e6da05a84 100644 --- a/cold-wallet-app/lib/components/confirm_dialog.dart +++ b/cold-wallet-app/lib/components/confirm_dialog.dart @@ -6,22 +6,6 @@ Future showConfirmDialog( required String title, required String message, required String confirmLabel, -}) async { - final colors = context.colors; - final confirmed = await showDialog( - context: context, - builder: (ctx) => AlertDialog( - backgroundColor: colors.sheetBackground, - title: Text(title), - content: Text(message), - actions: [ - TextButton(onPressed: () => Navigator.pop(ctx, false), child: const Text('Cancel')), - TextButton( - onPressed: () => Navigator.pop(ctx, true), - child: Text(confirmLabel, style: TextStyle(color: colors.error)), - ), - ], - ), - ); - return confirmed == true; +}) { + return showQuantusDialog(context, title: title, body: message, actionLabel: confirmLabel); } diff --git a/cold-wallet-app/test/confirm_dialog_test.dart b/cold-wallet-app/test/confirm_dialog_test.dart new file mode 100644 index 000000000..ea0167cba --- /dev/null +++ b/cold-wallet-app/test/confirm_dialog_test.dart @@ -0,0 +1,67 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:quantus_cold_wallet/components/confirm_dialog.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + Future pumpConfirm(WidgetTester tester, {required Future Function(bool result) onResult}) async { + await tester.pumpWidget( + MediaQuery( + data: const MediaQueryData(size: Size(375, 667)), + child: Builder( + builder: (context) => MaterialApp( + theme: AppTheme.darkTheme(context), + home: Scaffold( + body: Builder( + builder: (context) { + return TextButton( + onPressed: () async { + final confirmed = await showConfirmDialog( + context, + title: 'Reset wallet?', + message: 'This erases the encrypted key from this device.', + confirmLabel: 'Reset', + ); + await onResult(confirmed); + }, + child: const Text('Open'), + ); + }, + ), + ), + ), + ), + ), + ); + await tester.pump(); + await tester.tap(find.text('Open')); + await tester.pumpAndSettle(); + } + + testWidgets('presents QuantusDialog instead of AlertDialog', (tester) async { + await pumpConfirm(tester, onResult: (_) async {}); + + expect(find.byType(QuantusDialog), findsOneWidget); + expect(find.byType(AlertDialog), findsNothing); + expect(find.text('Reset wallet?'), findsOneWidget); + expect(find.text('This erases the encrypted key from this device.'), findsOneWidget); + expect(find.text('Reset'), findsOneWidget); + }); + + testWidgets('returns true when the QuantusDialog action is tapped', (tester) async { + bool? result; + await pumpConfirm( + tester, + onResult: (confirmed) async { + result = confirmed; + }, + ); + + await tester.tap(find.text('Reset')); + await tester.pumpAndSettle(); + + expect(result, isTrue); + }); +} diff --git a/quantus_sdk/lib/src/ui/components/index.dart b/quantus_sdk/lib/src/ui/components/index.dart index 8ac75ed3b..8eadbf415 100644 --- a/quantus_sdk/lib/src/ui/components/index.dart +++ b/quantus_sdk/lib/src/ui/components/index.dart @@ -24,4 +24,4 @@ export 'quantus_qr.dart'; export 'segmented_controls.dart'; export 'back_button.dart'; export 'animated_ur_qr.dart'; -export 'mnemonic_grid.dart'; \ No newline at end of file +export 'mnemonic_grid.dart'; From 1b7539e34ce60f3a5d0c7a65a14d63d374238e8e Mon Sep 17 00:00:00 2001 From: Beast Date: Wed, 19 Aug 2026 15:26:24 +0800 Subject: [PATCH 21/38] feat: unify decode call view component --- .../lib/components/call_detail_view.dart | 157 -------- .../lib/components/decoded_call_view.dart | 39 ++ .../lib/components/detail_row.dart | 56 --- .../lib/providers/wallet_providers.dart | 4 + .../lib/screens/sign_transaction_screen.dart | 172 ++++---- .../lib/v2/components/decoded_call_view.dart | 14 + .../v2/components/multisig_expiry_value.dart | 7 +- .../multisig_action_confirm_sheet.dart | 3 +- .../multisig_proposal_detail_sheet.dart | 9 +- .../screens/send/encrypted_send_strategy.dart | 9 +- .../send/multisig_propose_strategy.dart | 48 +-- .../screens/send/regular_send_strategy.dart | 9 +- quantus_sdk/lib/src/chain/decoded_call.dart | 27 ++ .../src/ui/components/decoded_call_view.dart | 377 ++++++++++++++---- .../src/ui/components/detail_summary_row.dart | 82 +++- quantus_sdk/test/chain/decoded_call_test.dart | 37 ++ .../test/ui/decoded_call_view_test.dart | 125 ++++++ .../test/ui/detail_summary_row_test.dart | 69 ++++ 18 files changed, 788 insertions(+), 456 deletions(-) delete mode 100644 cold-wallet-app/lib/components/call_detail_view.dart create mode 100644 cold-wallet-app/lib/components/decoded_call_view.dart delete mode 100644 cold-wallet-app/lib/components/detail_row.dart create mode 100644 quantus_sdk/test/chain/decoded_call_test.dart create mode 100644 quantus_sdk/test/ui/decoded_call_view_test.dart create mode 100644 quantus_sdk/test/ui/detail_summary_row_test.dart diff --git a/cold-wallet-app/lib/components/call_detail_view.dart b/cold-wallet-app/lib/components/call_detail_view.dart deleted file mode 100644 index 4914b0965..000000000 --- a/cold-wallet-app/lib/components/call_detail_view.dart +++ /dev/null @@ -1,157 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:quantus_cold_wallet/components/detail_row.dart'; - -/// Resolves human checkphrases for every address on screen, not just a -/// destination — an approval or a governance call can name several accounts, and -/// each one needs to be verifiable by eye. -final _checkphraseProvider = FutureProvider.family((ref, address) async { - return (await HumanReadableChecksumService().getHumanReadableName(address)) ?? ''; -}); - -/// Renders every parameter of a decoded call, recursing into nested calls. -/// -/// This is the whole point of the signing screen: nothing is summarised away and -/// nothing is hidden behind a "details" tap. If a field is in the bytes being -/// signed, it is on this screen. -class CallDetailView extends StatelessWidget { - final DecodedCall call; - - /// Nesting depth; nested calls are boxed and indented. - final int depth; - - const CallDetailView({super.key, required this.call, this.depth = 0}); - - @override - Widget build(BuildContext context) { - final colors = context.colors; - final text = context.themeText; - - return Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Text( - call.displayTitle, - style: text.transactionDetailRowValue?.copyWith( - color: depth == 0 ? colors.textPrimary : colors.checksum, - fontWeight: FontWeight.w600, - ), - ), - for (final field in call.fields) _CallFieldView(field: field, depth: depth), - ], - ); - } -} - -class _CallFieldView extends ConsumerWidget { - final CallField field; - final int depth; - - const _CallFieldView({required this.field, required this.depth}); - - @override - Widget build(BuildContext context, WidgetRef ref) { - final colors = context.colors; - final text = context.themeText; - - switch (field) { - case ValueField(:final label, :final value, :final kind, :final note): - if (kind == ValueKind.address) { - return _AddressField(label: label, address: value, note: note); - } - return DetailRow( - label: label, - value: value, - monospace: kind == ValueKind.hash || kind == ValueKind.bytes, - note: note, - ); - - case AmountField(:final label, :final token, :final assetId, :final note): - return DetailRow( - label: label, - value: assetId == null - ? '${NumberFormattingService().formatAmount(token)} ${AppConstants.tokenSymbol}' - : '$token raw units of asset #$assetId', - note: assetId == null - ? note - : [ - note, - 'Asset decimals are not part of this payload, so the raw amount is shown.', - ].whereType().join(' '), - ); - - case FieldGroup(:final label, :final items): - return Padding( - padding: const EdgeInsets.only(top: 10), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Text(label.toUpperCase(), style: text.transactionDetailRowLabel?.copyWith(color: colors.textLabel)), - Padding( - padding: const EdgeInsets.only(left: 12), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [for (final item in items) _CallFieldView(field: item, depth: depth)], - ), - ), - ], - ), - ); - - case NestedCallField(:final label, :final call, :final note): - return Padding( - padding: const EdgeInsets.only(top: 14), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Text(label.toUpperCase(), style: text.transactionDetailRowLabel?.copyWith(color: colors.textLabel)), - const SizedBox(height: 8), - Container( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), - decoration: BoxDecoration( - color: colors.surfaceCard, - borderRadius: BorderRadius.circular(10), - border: Border.all(color: colors.borderButton), - ), - child: CallDetailView(call: call, depth: depth + 1), - ), - if (note != null) ...[ - const SizedBox(height: 6), - Text(note, style: text.detail?.copyWith(color: colors.textMuted)), - ], - ], - ), - ); - } - } -} - -/// An address plus its checkphrase, so the signer can verify it out loud rather -/// than character by character. -class _AddressField extends ConsumerWidget { - final String label; - final String address; - final String? note; - - const _AddressField({required this.label, required this.address, this.note}); - - @override - Widget build(BuildContext context, WidgetRef ref) { - final colors = context.colors; - final checkphrase = ref.watch(_checkphraseProvider(address)); - - return Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - DetailRow(label: label, value: address, monospace: true, note: note), - checkphrase.maybeWhen( - data: (phrase) => phrase.isEmpty - ? const SizedBox.shrink() - : DetailRow(label: '$label checkphrase', value: phrase, valueColor: colors.checksum), - orElse: () => const SizedBox.shrink(), - ), - ], - ); - } -} diff --git a/cold-wallet-app/lib/components/decoded_call_view.dart b/cold-wallet-app/lib/components/decoded_call_view.dart new file mode 100644 index 000000000..fb06748f1 --- /dev/null +++ b/cold-wallet-app/lib/components/decoded_call_view.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' as sdk; +import 'package:quantus_cold_wallet/providers/wallet_providers.dart'; + +/// Cold-wallet decoded-call tree: stacked signing layout, checkphrases, amounts. +class DecodedCallView extends ConsumerWidget { + final sdk.DecodedCall call; + final int depth; + + const DecodedCallView({super.key, required this.call, this.depth = 0}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final checkphrases = _watchCheckphrases(ref, call); + return sdk.DecodedCallView( + call: call, + depth: depth, + layout: sdk.DecodedCallLayout.stacked, + amountText: (token) => '${sdk.NumberFormattingService().formatAmount(token)} ${sdk.AppConstants.tokenSymbol}', + checkphraseOf: (address) => checkphrases[address], + ); + } +} + +Map _watchCheckphrases(WidgetRef ref, sdk.DecodedCall call) { + final checkphrases = {}; + for (final address in call.addresses) { + ref + .watch(checksumNameProvider(address)) + .maybeWhen( + data: (phrase) { + if (phrase.isNotEmpty) checkphrases[address] = phrase; + }, + orElse: () {}, + ); + } + return checkphrases; +} diff --git a/cold-wallet-app/lib/components/detail_row.dart b/cold-wallet-app/lib/components/detail_row.dart deleted file mode 100644 index c11a0fa7e..000000000 --- a/cold-wallet-app/lib/components/detail_row.dart +++ /dev/null @@ -1,56 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; - -/// Label-above-value row used throughout the signing review screen. -/// -/// Values wrap rather than ellipsize: a signer must be able to read a full -/// address or hash, so nothing on this screen is ever visually truncated. -class DetailRow extends StatelessWidget { - final String label; - final String value; - - /// Monospace value, for addresses, hashes and byte blobs. - final bool monospace; - - final Color? valueColor; - - /// Caveat shown under the value, e.g. that a hash-referenced proposal's - /// contents are not part of the payload. - final String? note; - - const DetailRow({ - super.key, - required this.label, - required this.value, - this.monospace = false, - this.valueColor, - this.note, - }); - - @override - Widget build(BuildContext context) { - final colors = context.colors; - final text = context.themeText; - - return Padding( - padding: const EdgeInsets.symmetric(vertical: 10), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(label.toUpperCase(), style: text.transactionDetailRowLabel?.copyWith(color: colors.textLabel)), - const SizedBox(height: 6), - Text( - value, - style: monospace - ? text.transactionDetailRowValue?.copyWith(color: valueColor ?? colors.textPrimary) - : text.smallParagraph?.copyWith(color: valueColor ?? colors.textPrimary), - ), - if (note != null) ...[ - const SizedBox(height: 4), - Text(note!, style: text.detail?.copyWith(color: colors.textMuted)), - ], - ], - ), - ); - } -} diff --git a/cold-wallet-app/lib/providers/wallet_providers.dart b/cold-wallet-app/lib/providers/wallet_providers.dart index bc07bd3d8..339ec5321 100644 --- a/cold-wallet-app/lib/providers/wallet_providers.dart +++ b/cold-wallet-app/lib/providers/wallet_providers.dart @@ -168,3 +168,7 @@ final checkphraseProvider = FutureProvider((ref) async { final name = await HumanReadableChecksumService().getHumanReadableName(address); return name ?? ''; }); + +final checksumNameProvider = FutureProvider.family((ref, address) async { + return (await HumanReadableChecksumService().getHumanReadableName(address)) ?? ''; +}); diff --git a/cold-wallet-app/lib/screens/sign_transaction_screen.dart b/cold-wallet-app/lib/screens/sign_transaction_screen.dart index 2150b012c..909f46213 100644 --- a/cold-wallet-app/lib/screens/sign_transaction_screen.dart +++ b/cold-wallet-app/lib/screens/sign_transaction_screen.dart @@ -3,9 +3,8 @@ import 'dart:typed_data'; import 'package:convert/convert.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:quantus_cold_wallet/components/call_detail_view.dart'; -import 'package:quantus_cold_wallet/components/detail_row.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide DecodedCallView; +import 'package:quantus_cold_wallet/components/decoded_call_view.dart'; import 'package:quantus_cold_wallet/components/qr_tuning_controls.dart'; import 'package:quantus_cold_wallet/providers/settings_providers.dart'; import 'package:quantus_cold_wallet/providers/wallet_providers.dart'; @@ -119,27 +118,27 @@ class _SignTransactionScreenState extends ConsumerState { } Widget _errorView(BuildContext context, String reason) { - final colors = context.colors; - final text = context.themeText; + final colors = context.colorsV3; + final text = context.themeTextV3; return ScaffoldBase( appBar: const V2AppBar(title: 'Sign Transaction'), mainContent: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon(Icons.error_outline, size: 64, color: colors.error), + Icon(Icons.error_outline, size: 64, color: colors.semanticEmber), const SizedBox(height: 24), - Text('Could not read transaction', style: text.mediumTitle?.copyWith(color: colors.textPrimary)), + Text('Could not read transaction', style: text.titleScreen.copyWith(color: colors.textContent)), const SizedBox(height: 12), Text( 'This QR code is not a transaction this wallet can read in full, so it will not be signed. ' 'Nothing was signed.', - style: text.smallParagraph?.copyWith(color: colors.textSecondary), + style: text.body.copyWith(color: colors.textMuted), textAlign: TextAlign.center, ), const SizedBox(height: 12), Text( reason, - style: text.detail?.copyWith(color: colors.textMuted), + style: text.caption.copyWith(color: colors.textMuted), textAlign: TextAlign.center, ), ], @@ -151,8 +150,8 @@ class _SignTransactionScreenState extends ConsumerState { } Widget _reviewView(BuildContext context, ParsedPayload parsed) { - final colors = context.colors; - final text = context.themeText; + final colors = context.colorsV3; + final text = context.themeTextV3; final ext = parsed.extensions; final signerAddress = ref.watch(addressProvider); final signerCheckphrase = ref.watch(checkphraseProvider); @@ -167,40 +166,48 @@ class _SignTransactionScreenState extends ConsumerState { crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const SizedBox(height: 8), - if (!parsed.specMatchesBundled) _specDriftBanner(context, ext), + if (!parsed.specMatchesBundled) _specDriftBanner(ext), _hero(context, parsed), const SizedBox(height: 24), - if (signerAddress != null) DetailRow(label: 'Signing as', value: signerAddress, monospace: true), + if (signerAddress != null) + DetailSummaryRow.stacked(label: 'Signing as', value: signerAddress, monospace: true), signerCheckphrase.maybeWhen( data: (phrase) => phrase.isEmpty ? const SizedBox.shrink() - : DetailRow(label: 'Signing as checkphrase', value: phrase, valueColor: colors.checksum), + : DetailSummaryRow.stacked( + label: 'Signing as checkphrase', + value: phrase, + valueColor: colors.semanticLilac, + ), orElse: () => const SizedBox.shrink(), ), const SizedBox(height: 8), - Divider(color: colors.borderButton), + Divider(color: colors.borderHairline), const SizedBox(height: 8), - Text('CALL', style: text.transactionDetailRowLabel?.copyWith(color: colors.textLabel)), + Text('CALL', style: _sectionLabel(text, colors)), const SizedBox(height: 8), - CallDetailView(call: parsed.call), + DecodedCallView(call: parsed.call), const SizedBox(height: 16), - Divider(color: colors.borderButton), + Divider(color: colors.borderHairline), const SizedBox(height: 8), - Text('SIGNED EXTENSIONS', style: text.transactionDetailRowLabel?.copyWith(color: colors.textLabel)), - DetailRow(label: 'Network', value: parsed.network), - DetailRow(label: 'Runtime', value: 'spec ${ext.specVersion}, tx version ${ext.transactionVersion}'), - DetailRow(label: 'Nonce', value: '${ext.nonce}'), - DetailRow(label: 'Era', value: '${ext.era}'), - DetailRow( + Text('SIGNED EXTENSIONS', style: _sectionLabel(text, colors)), + DetailSummaryRow.stacked(label: 'Network', value: parsed.network), + DetailSummaryRow.stacked( + label: 'Runtime', + value: 'spec ${ext.specVersion}, tx version ${ext.transactionVersion}', + ), + DetailSummaryRow.stacked(label: 'Nonce', value: '${ext.nonce}'), + DetailSummaryRow.stacked(label: 'Era', value: '${ext.era}'), + DetailSummaryRow.stacked( label: 'Tip', value: '${NumberFormattingService().formatAmount(ext.tip)} ${AppConstants.tokenSymbol}', ), - DetailRow(label: 'Genesis hash', value: '0x${hex.encode(ext.genesisHash)}', monospace: true), - DetailRow(label: 'Block hash', value: '0x${hex.encode(ext.blockHash)}', monospace: true), - DetailRow( + DetailSummaryRow.stacked(label: 'Genesis hash', value: '0x${hex.encode(ext.genesisHash)}', monospace: true), + DetailSummaryRow.stacked(label: 'Block hash', value: '0x${hex.encode(ext.blockHash)}', monospace: true), + DetailSummaryRow.stacked( label: 'Metadata hash', value: ext.metadataHash == null ? 'None (check disabled)' : '0x${hex.encode(ext.metadataHash!)}', monospace: ext.metadataHash != null, @@ -213,7 +220,7 @@ class _SignTransactionScreenState extends ConsumerState { const SizedBox(height: 16), Text( _error!, - style: text.detail?.copyWith(color: colors.error), + style: text.caption.copyWith(color: colors.semanticEmber), textAlign: TextAlign.center, ), ], @@ -229,7 +236,7 @@ class _SignTransactionScreenState extends ConsumerState { padding: const EdgeInsets.only(bottom: 12), child: Text( 'Scroll through every parameter to enable signing.', - style: text.detail?.copyWith(color: colors.textMuted), + style: text.caption.copyWith(color: colors.textMuted), textAlign: TextAlign.center, ), ), @@ -259,57 +266,30 @@ class _SignTransactionScreenState extends ConsumerState { ); } - Widget _specDriftBanner(BuildContext context, SignedExtensions ext) { - final colors = context.colors; - final text = context.themeText; - - return Container( - margin: const EdgeInsets.only(bottom: 20), - padding: const EdgeInsets.all(14), - decoration: BoxDecoration( - color: colors.error.withValues(alpha: 0.12), - borderRadius: BorderRadius.circular(10), - border: Border.all(color: colors.error), - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Icon(Icons.warning_amber_rounded, color: colors.error, size: 22), - const SizedBox(width: 10), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Built for a different runtime', - style: text.smallParagraph?.copyWith(color: colors.error, fontWeight: FontWeight.w700), - ), - const SizedBox(height: 4), - Text( - 'This payload targets spec ${ext.specVersion} / tx version ${ext.transactionVersion}, but this ' - 'wallet decodes spec ${AppConstants.bundledSpecVersion} / tx version ' - '${AppConstants.bundledTransactionVersion}. Across runtime versions the same index can mean a ' - 'different call, so the parameters below may be mislabelled. Update the cold wallet before signing ' - 'anything you cannot verify another way.', - style: text.detail?.copyWith(color: colors.textSecondary), - ), - ], - ), - ), - ], + Widget _specDriftBanner(SignedExtensions ext) { + return Padding( + padding: const EdgeInsets.only(bottom: 20), + child: QuantusBanner( + tone: BannerTone.ember, + message: + 'Built for a different runtime. This payload targets spec ${ext.specVersion} / tx version ' + '${ext.transactionVersion}, but this wallet decodes spec ${AppConstants.bundledSpecVersion} / tx version ' + '${AppConstants.bundledTransactionVersion}. Across runtime versions the same index can mean a different ' + 'call, so the parameters below may be mislabelled. Update the cold wallet before signing anything you ' + 'cannot verify another way.', ), ); } Widget _hero(BuildContext context, ParsedPayload parsed) { - final colors = context.colors; - final text = context.themeText; + final colors = context.colorsV3; + final text = context.themeTextV3; final summary = parsed.call.summary; return Center( child: Column( children: [ - Text('You are signing', style: text.smallParagraph?.copyWith(color: colors.textSecondary)), + Text('You are signing', style: text.caption.copyWith(color: colors.textMuted)), const SizedBox(height: 8), if (summary != null && summary.assetId == null) RichText( @@ -317,11 +297,11 @@ class _SignTransactionScreenState extends ConsumerState { children: [ TextSpan( text: NumberFormattingService().formatAmount(summary.amount), - style: text.transactionDetailAmountPrimary?.copyWith(color: colors.textPrimary), + style: text.amountHero.copyWith(color: colors.textContent), ), TextSpan( text: ' ${AppConstants.tokenSymbol}', - style: text.transactionDetailAmountSymbol?.copyWith(color: colors.textSecondary), + style: text.amountInline.copyWith(color: colors.textMuted), ), ], ), @@ -329,19 +309,19 @@ class _SignTransactionScreenState extends ConsumerState { else if (summary != null) Text( '${summary.amount} of asset #${summary.assetId}', - style: text.mediumTitle?.copyWith(color: colors.textPrimary), + style: text.titleScreen.copyWith(color: colors.textContent), textAlign: TextAlign.center, ) else Text( parsed.call.humanCall, - style: text.mediumTitle?.copyWith(color: colors.textPrimary), + style: text.titleScreen.copyWith(color: colors.textContent), textAlign: TextAlign.center, ), const SizedBox(height: 6), Text( parsed.call.displayTitle, - style: text.detail?.copyWith(color: colors.textMuted), + style: text.caption.copyWith(color: colors.textMuted), textAlign: TextAlign.center, ), ], @@ -350,8 +330,8 @@ class _SignTransactionScreenState extends ConsumerState { } Widget _rawPayloadSection(BuildContext context, ParsedPayload parsed) { - final colors = context.colors; - final text = context.themeText; + final colors = context.colorsV3; + final text = context.themeTextV3; return Column( crossAxisAlignment: CrossAxisAlignment.stretch, @@ -360,21 +340,15 @@ class _SignTransactionScreenState extends ConsumerState { onTap: () => setState(() => _showRawPayload = !_showRawPayload), child: Row( children: [ - Text( - 'RAW PAYLOAD (${parsed.raw.length} BYTES)', - style: text.transactionDetailRowLabel?.copyWith(color: colors.textLabel), - ), + Text('RAW PAYLOAD (${parsed.raw.length} BYTES)', style: _sectionLabel(text, colors)), const SizedBox(width: 6), - Icon(_showRawPayload ? Icons.expand_less : Icons.expand_more, size: 18, color: colors.textLabel), + Icon(_showRawPayload ? Icons.expand_less : Icons.expand_more, size: 18, color: colors.textMuted), ], ), ), if (_showRawPayload) ...[ const SizedBox(height: 8), - Text( - '0x${hex.encode(parsed.raw)}', - style: text.detail?.copyWith(color: colors.textMuted, fontFamily: AppTextTheme.fontFamilySecondary), - ), + Text('0x${hex.encode(parsed.raw)}', style: text.dataAddress.copyWith(color: colors.textMuted)), ], ], ); @@ -383,18 +357,18 @@ class _SignTransactionScreenState extends ConsumerState { /// Pauses the animation and opens the tuning sheet; resumes when it closes. Future _pauseAndTune() async { setState(() => _qrPaused = true); - final colors = context.colors; - final text = context.themeText; + final colors = context.colorsV3; + final text = context.themeTextV3; await showModalBottomSheet( context: context, - backgroundColor: colors.sheetBackground, + backgroundColor: colors.bgSurface, builder: (_) => Padding( padding: const EdgeInsets.fromLTRB(24, 24, 24, 40), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - Text('QR display options', style: text.smallTitle?.copyWith(color: colors.textPrimary)), + Text('QR display options', style: text.titleScreen.copyWith(color: colors.textContent)), const SizedBox(height: 16), const QrTuningControls(), ], @@ -405,8 +379,8 @@ class _SignTransactionScreenState extends ConsumerState { } Widget _signatureView(BuildContext context, Uint8List signed) { - final colors = context.colors; - final text = context.themeText; + final colors = context.colorsV3; + final text = context.themeTextV3; final settings = ref.watch(coldSettingsProvider); if (_urParts == null || _urPartsBytes != settings.qrBytes) { @@ -424,7 +398,7 @@ class _SignTransactionScreenState extends ConsumerState { const SizedBox(height: 8), Text( 'Scan this with your hot wallet to broadcast the transaction.', - style: text.smallParagraph?.copyWith(color: colors.textSecondary), + style: text.body.copyWith(color: colors.textMuted), textAlign: TextAlign.center, ), const SizedBox(height: 24), @@ -438,7 +412,7 @@ class _SignTransactionScreenState extends ConsumerState { Text( '${parts.length} ${parts.length == 1 ? 'frame' : 'frames'} · ${settings.qrFps} FPS · ' '${settings.qrBytes} bytes', - style: text.detail?.copyWith(color: colors.textMuted), + style: text.caption.copyWith(color: colors.textMuted), ), if (parts.length > 1) ...[ const SizedBox(width: 12), @@ -447,8 +421,8 @@ class _SignTransactionScreenState extends ConsumerState { child: Container( width: 32, height: 32, - decoration: BoxDecoration(color: colors.surfaceDeep, shape: BoxShape.circle), - child: Icon(Icons.pause_rounded, size: 20, color: colors.textPrimary), + decoration: BoxDecoration(color: colors.bgSurface2, shape: BoxShape.circle), + child: Icon(Icons.pause_rounded, size: 20, color: colors.textContent), ), ), ], @@ -458,7 +432,7 @@ class _SignTransactionScreenState extends ConsumerState { const SizedBox(height: 16), Text( 'Animated QR — keep both devices steady until the hot wallet finishes scanning.', - style: text.detail?.copyWith(color: colors.textMuted), + style: text.caption.copyWith(color: colors.textMuted), textAlign: TextAlign.center, ), ], @@ -471,3 +445,7 @@ class _SignTransactionScreenState extends ConsumerState { ); } } + +TextStyle _sectionLabel(AppTextThemeV3 text, AppColorsV3 colors) { + return text.labelMonogram.copyWith(fontSize: 10, letterSpacing: 1, color: colors.textMuted); +} diff --git a/mobile-app/lib/v2/components/decoded_call_view.dart b/mobile-app/lib/v2/components/decoded_call_view.dart index 5328d1659..51a24597e 100644 --- a/mobile-app/lib/v2/components/decoded_call_view.dart +++ b/mobile-app/lib/v2/components/decoded_call_view.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart' as sdk; import 'package:resonance_network_wallet/providers/currency_display_provider.dart'; +import 'package:resonance_network_wallet/providers/wallet_providers.dart'; /// App-level decoded-call tree: maps [txAmountDisplayProvider] onto the /// presentational SDK widget. @@ -14,10 +15,23 @@ class DecodedCallView extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final formatAmount = ref.watch(txAmountDisplayProvider); + final checkphrases = {}; + for (final address in call.addresses) { + ref + .watch(checksumNameProvider(address)) + .maybeWhen( + data: (phrase) { + if (phrase.isNotEmpty) checkphrases[address] = phrase; + }, + orElse: () {}, + ); + } return sdk.DecodedCallView( call: call, depth: depth, + layout: sdk.DecodedCallLayout.compact, amountText: (token) => formatAmount(token, isSend: true).primaryAmount, + checkphraseOf: (address) => checkphrases[address], ); } } diff --git a/mobile-app/lib/v2/components/multisig_expiry_value.dart b/mobile-app/lib/v2/components/multisig_expiry_value.dart index 7e675ed2a..de3c43f37 100644 --- a/mobile-app/lib/v2/components/multisig_expiry_value.dart +++ b/mobile-app/lib/v2/components/multisig_expiry_value.dart @@ -31,21 +31,22 @@ MultisigExpiryParts resolveMultisigExpiryParts({ /// Two-line expiry: block height, then estimated datetime on its own line. class MultisigExpiryValue extends StatelessWidget { - const MultisigExpiryValue({super.key, required this.parts, required this.style}); + const MultisigExpiryValue({super.key, required this.parts, this.style}); final MultisigExpiryParts parts; final TextStyle? style; @override Widget build(BuildContext context) { + final resolved = style ?? context.themeTextV3.body.copyWith(color: context.colorsV3.textContent); return Column( crossAxisAlignment: CrossAxisAlignment.end, mainAxisSize: MainAxisSize.min, children: [ - Text(parts.blockLabel, style: style, textAlign: TextAlign.right), + Text(parts.blockLabel, style: resolved, textAlign: TextAlign.right), if (parts.estimatedDateTime != null) ...[ const SizedBox(height: 2), - Text(parts.estimatedDateTime!, style: style, textAlign: TextAlign.right, softWrap: true), + Text(parts.estimatedDateTime!, style: resolved, textAlign: TextAlign.right, softWrap: true), ], ], ); diff --git a/mobile-app/lib/v2/screens/multisig/multisig_action_confirm_sheet.dart b/mobile-app/lib/v2/screens/multisig/multisig_action_confirm_sheet.dart index 1b05d275b..8c1243ff1 100644 --- a/mobile-app/lib/v2/screens/multisig/multisig_action_confirm_sheet.dart +++ b/mobile-app/lib/v2/screens/multisig/multisig_action_confirm_sheet.dart @@ -343,7 +343,6 @@ class _MultisigActionConfirmSheetState extends ConsumerState l10n.commonAmountBalance(fmt.formatBalance(v, smartDecimals: AppConstants.decimals), AppConstants.tokenSymbol); return [ const SizedBox(height: 7), - DetailSummaryRow.review(label: l10n.sendReviewTo, value: recipientAddress.trim(), valueStyle: valueStyle), + DetailSummaryRow.review(label: l10n.sendReviewTo, value: recipientAddress.trim()), const SizedBox(height: 7), - DetailSummaryRow.review(label: l10n.sendReviewAmount, value: amt(amount), valueStyle: valueStyle), + DetailSummaryRow.review(label: l10n.sendReviewAmount, value: amt(amount)), const SizedBox(height: 7), - DetailSummaryRow.review(label: l10n.encryptedSendFeeLabel, value: amt(feeAmount), valueStyle: valueStyle), + DetailSummaryRow.review(label: l10n.encryptedSendFeeLabel, value: amt(feeAmount)), const SizedBox(height: 7), - DetailSummaryRow.review(label: l10n.sendReviewYouPay, value: amt(amount + feeAmount), valueStyle: valueStyle), + DetailSummaryRow.review(label: l10n.sendReviewYouPay, value: amt(amount + feeAmount)), const SizedBox(height: 7), ]; } diff --git a/mobile-app/lib/v2/screens/send/multisig_propose_strategy.dart b/mobile-app/lib/v2/screens/send/multisig_propose_strategy.dart index 3e08ba4a2..997d4bf3e 100644 --- a/mobile-app/lib/v2/screens/send/multisig_propose_strategy.dart +++ b/mobile-app/lib/v2/screens/send/multisig_propose_strategy.dart @@ -114,7 +114,6 @@ class MultisigProposeStrategy extends SendStrategy { final multisigService = ref.watch(multisigServiceProvider); final currentBlock = ref.watch(multisigCurrentBlockProvider).value; final breakdown = (fee as ProposeFee).breakdown; - final valueStyle = context.themeText.transactionDetailRowLabel; final proposerChecksum = ref.watch(checksumNameProvider(msig.myMemberAccountId)).value ?? ''; String amt(BigInt v) => @@ -124,17 +123,15 @@ class MultisigProposeStrategy extends SendStrategy { const SizedBox(height: 4), DetailSummaryRow.review( label: l10n.multisigProposeProposerLabel, - valueWidget: _ProposerValue(address: msig.myMemberAccountId, checkphrase: proposerChecksum, style: valueStyle), + valueWidget: _ProposerValue(address: msig.myMemberAccountId, checkphrase: proposerChecksum), valueFlex: 4, - valueStyle: valueStyle, ), const SizedBox(height: 4), - DetailSummaryRow.review(label: l10n.sendReviewAmount, value: amt(amount), valueStyle: valueStyle), + DetailSummaryRow.review(label: l10n.sendReviewAmount, value: amt(amount)), const SizedBox(height: 4), DetailSummaryRow.review( label: l10n.multisigProposeThresholdLabel, value: '${msig.threshold}/${msig.signers.length}', - valueStyle: valueStyle, ), const SizedBox(height: 4), DetailSummaryRow.review( @@ -146,35 +143,17 @@ class MultisigProposeStrategy extends SendStrategy { multisigService: multisigService, currentBlock: currentBlock, ), - style: valueStyle, ), valueFlex: 4, - valueStyle: valueStyle, ), const SizedBox(height: 4), - DetailSummaryRow.review( - label: l10n.sendReviewNetworkFee, - value: amt(breakdown.networkFee), - valueStyle: valueStyle, - ), + DetailSummaryRow.review(label: l10n.sendReviewNetworkFee, value: amt(breakdown.networkFee)), const SizedBox(height: 4), - DetailSummaryRow.review( - label: l10n.multisigProposalDepositLabel, - value: amt(breakdown.deposit), - valueStyle: valueStyle, - ), + DetailSummaryRow.review(label: l10n.multisigProposalDepositLabel, value: amt(breakdown.deposit)), const SizedBox(height: 4), - DetailSummaryRow.review( - label: l10n.multisigProposeFeeRowLabel, - value: amt(breakdown.creationFee), - valueStyle: valueStyle, - ), + DetailSummaryRow.review(label: l10n.multisigProposeFeeRowLabel, value: amt(breakdown.creationFee)), const SizedBox(height: 4), - DetailSummaryRow.review( - label: l10n.multisigProposeMemberTotalLabel, - value: amt(breakdown.memberCost), - valueStyle: valueStyle, - ), + DetailSummaryRow.review(label: l10n.multisigProposeMemberTotalLabel, value: amt(breakdown.memberCost)), const SizedBox(height: 4), ]; } @@ -256,15 +235,15 @@ class MultisigProposeStrategy extends SendStrategy { } class _ProposerValue extends StatelessWidget { - const _ProposerValue({required this.address, required this.checkphrase, required this.style}); + const _ProposerValue({required this.address, required this.checkphrase}); final String address; final String checkphrase; - final TextStyle? style; @override Widget build(BuildContext context) { - final colors = context.colors; + final colors = context.colorsV3; + final text = context.themeTextV3; return Column( crossAxisAlignment: CrossAxisAlignment.end, mainAxisSize: MainAxisSize.min, @@ -272,11 +251,16 @@ class _ProposerValue extends StatelessWidget { if (checkphrase.isNotEmpty) Text( checkphrase, - style: style?.copyWith(color: colors.checksum), + style: text.caption.copyWith(color: colors.semanticLilac), textAlign: TextAlign.right, ), const SizedBox(height: 2), - Text(address, style: style, textAlign: TextAlign.right, softWrap: true), + Text( + address, + style: text.body.copyWith(color: colors.textContent), + textAlign: TextAlign.right, + softWrap: true, + ), ], ); } diff --git a/mobile-app/lib/v2/screens/send/regular_send_strategy.dart b/mobile-app/lib/v2/screens/send/regular_send_strategy.dart index f70fe88db..77553be12 100644 --- a/mobile-app/lib/v2/screens/send/regular_send_strategy.dart +++ b/mobile-app/lib/v2/screens/send/regular_send_strategy.dart @@ -97,7 +97,6 @@ class RegularSendStrategy extends SendStrategy { final l10n = ref.watch(l10nProvider); final fmt = ref.watch(numberFormattingServiceProvider); final networkFee = (fee as RegularFee).networkFee; - final valueStyle = context.themeText.transactionDetailRowLabel; final addr = recipientAddress.trim(); String amt(BigInt v) => @@ -105,13 +104,13 @@ class RegularSendStrategy extends SendStrategy { return [ const SizedBox(height: 7), - DetailSummaryRow.review(label: l10n.sendReviewTo, value: addr, valueStyle: valueStyle), + DetailSummaryRow.review(label: l10n.sendReviewTo, value: addr), const SizedBox(height: 7), - DetailSummaryRow.review(label: l10n.sendReviewAmount, value: amt(amount), valueStyle: valueStyle), + DetailSummaryRow.review(label: l10n.sendReviewAmount, value: amt(amount)), const SizedBox(height: 7), - DetailSummaryRow.review(label: l10n.sendReviewNetworkFee, value: amt(networkFee), valueStyle: valueStyle), + DetailSummaryRow.review(label: l10n.sendReviewNetworkFee, value: amt(networkFee)), const SizedBox(height: 7), - DetailSummaryRow.review(label: l10n.sendReviewYouPay, value: amt(amount + networkFee), valueStyle: valueStyle), + DetailSummaryRow.review(label: l10n.sendReviewYouPay, value: amt(amount + networkFee)), const SizedBox(height: 7), ]; } diff --git a/quantus_sdk/lib/src/chain/decoded_call.dart b/quantus_sdk/lib/src/chain/decoded_call.dart index b6a628093..058296e9b 100644 --- a/quantus_sdk/lib/src/chain/decoded_call.dart +++ b/quantus_sdk/lib/src/chain/decoded_call.dart @@ -121,4 +121,31 @@ class DecodedCall { final words = call.split('_').where((w) => w.isNotEmpty).join(' '); return words[0].toUpperCase() + words.substring(1); } + + /// Every ss58 address this call names, nested calls included, first-seen order. + /// + /// Renderers watch checkphrases for this list in the host app, then pass the + /// resolved strings into the presentational tree. + List get addresses { + final seen = {}; + final out = []; + void walk(List fields) { + for (final field in fields) { + switch (field) { + case ValueField(:final value, kind: ValueKind.address): + if (seen.add(value)) out.add(value); + case FieldGroup(:final items): + walk(items); + case NestedCallField(:final call): + walk(call.fields); + case AmountField(): + case ValueField(): + break; + } + } + } + + walk(fields); + return out; + } } diff --git a/quantus_sdk/lib/src/ui/components/decoded_call_view.dart b/quantus_sdk/lib/src/ui/components/decoded_call_view.dart index cc47ddee3..dcad9b211 100644 --- a/quantus_sdk/lib/src/ui/components/decoded_call_view.dart +++ b/quantus_sdk/lib/src/ui/components/decoded_call_view.dart @@ -1,12 +1,19 @@ import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; +/// Density for [DecodedCallView] until design picks one layout. +enum DecodedCallLayout { + /// Signing review: label above value, wrap, no ellipsis. + stacked, + + /// Sheet/list: label left, value right, tighter. + compact, +} + /// Renders every parameter of a [DecodedCall], nested calls included. /// -/// Multisig proposals are not always transfers — governance votes, runtime -/// upgrade authorisations and batches all arrive through the same pallet — so a -/// transfer-shaped layout silently misreports them. This shows the call the -/// runtime actually declared, with each of its parameters. +/// Presentational only. Amounts and checkphrases are already-resolved strings +/// from the host app. Both layouts use v3 tokens; only geometry differs. class DecodedCallView extends StatelessWidget { final DecodedCall call; @@ -16,115 +23,313 @@ class DecodedCallView extends StatelessWidget { /// Formats a native token amount for the current locale and currency display. final String Function(BigInt token) amountText; - const DecodedCallView({super.key, required this.call, required this.amountText, this.depth = 0}); + final DecodedCallLayout layout; + + /// Resolved checkphrase for an ss58 address, or null while loading / unknown. + final String? Function(String address)? checkphraseOf; + + const DecodedCallView({ + super.key, + required this.call, + required this.amountText, + this.layout = DecodedCallLayout.compact, + this.checkphraseOf, + this.depth = 0, + }); @override Widget build(BuildContext context) { - final colors = context.colors; - final text = context.themeText; + final colors = context.colorsV3; + final text = context.themeTextV3; return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text( call.displayTitle, - style: text.detail?.copyWith( - color: depth == 0 ? colors.textPrimary : colors.textSecondary, - fontWeight: FontWeight.w600, - fontFamily: AppTextTheme.fontFamilySecondary, - ), + style: text.headingRow.copyWith(color: depth == 0 ? colors.textContent : colors.textMuted), ), - const SizedBox(height: 4), - for (final field in call.fields) _field(context, field), + SizedBox(height: layout == DecodedCallLayout.stacked ? 8 : 4), + for (final field in call.fields) + _CallFieldView( + field: field, + depth: depth, + layout: layout, + amountText: amountText, + checkphraseOf: checkphraseOf, + ), ], ); } +} + +class _CallFieldView extends StatelessWidget { + final CallField field; + final int depth; + final DecodedCallLayout layout; + final String Function(BigInt token) amountText; + final String? Function(String address)? checkphraseOf; - Widget _field(BuildContext context, CallField field) { - final colors = context.colors; - final text = context.themeText; + const _CallFieldView({ + required this.field, + required this.depth, + required this.layout, + required this.amountText, + required this.checkphraseOf, + }); - switch (field) { - case ValueField(:final label, :final value, :final note): - return Padding( - padding: const EdgeInsets.only(top: 6), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - DetailSummaryRow.review(label: label, value: value), - if (note != null) - Padding( - padding: const EdgeInsets.only(top: 2), - child: Text(note, style: text.detail?.copyWith(color: colors.textTertiary, fontSize: 11)), - ), - ], - ), - ); - - case AmountField(:final label, :final token, :final assetId, :final note): - final value = assetId == null ? amountText(token) : '$token (asset #$assetId, raw units)'; - return Padding( - padding: const EdgeInsets.only(top: 6), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - DetailSummaryRow.review(label: label, value: value), - if (note != null) - Padding( - padding: const EdgeInsets.only(top: 2), - child: Text(note, style: text.detail?.copyWith(color: colors.textTertiary, fontSize: 11)), - ), - ], + @override + Widget build(BuildContext context) { + return switch (field) { + ValueField(:final label, :final value, :final kind, :final note) => _FieldRow( + label: label, + value: value, + kind: kind, + note: note, + checkphrase: kind == ValueKind.address ? _phrase(value) : null, + layout: layout, + ), + AmountField(:final label, :final token, :final assetId, :final note) => _FieldRow( + label: label, + value: assetId == null ? amountText(token) : '$token raw units of asset #$assetId', + kind: ValueKind.number, + note: _amountNote(note, assetId), + layout: layout, + ), + FieldGroup(:final label, :final items) => _FieldGroupView( + label: label, + items: items, + depth: depth, + layout: layout, + amountText: amountText, + checkphraseOf: checkphraseOf, + ), + NestedCallField(:final label, :final call, :final note) => _NestedCallBox( + label: label, + call: call, + note: note, + depth: depth, + layout: layout, + amountText: amountText, + checkphraseOf: checkphraseOf, + ), + }; + } + + String? _phrase(String address) { + final phrase = checkphraseOf?.call(address); + if (phrase == null || phrase.isEmpty) return null; + return phrase; + } + + String? _amountNote(String? note, int? assetId) { + if (assetId == null) return note; + return [ + note, + 'Asset decimals are not part of this payload, so the raw amount is shown.', + ].whereType().join(' '); + } +} + +class _FieldGroupView extends StatelessWidget { + final String label; + final List items; + final int depth; + final DecodedCallLayout layout; + final String Function(BigInt token) amountText; + final String? Function(String address)? checkphraseOf; + + const _FieldGroupView({ + required this.label, + required this.items, + required this.depth, + required this.layout, + required this.amountText, + required this.checkphraseOf, + }); + + @override + Widget build(BuildContext context) { + final stacked = layout == DecodedCallLayout.stacked; + return Padding( + padding: EdgeInsets.only(top: stacked ? 12 : 8), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Text(stacked ? label.toUpperCase() : label, style: _labelStyle(context)), + Padding( + padding: const EdgeInsets.only(left: 12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + for (final item in items) + _CallFieldView( + field: item, + depth: depth, + layout: layout, + amountText: amountText, + checkphraseOf: checkphraseOf, + ), + ], + ), ), - ); + ], + ), + ); + } +} - case FieldGroup(:final label, :final items): - return Padding( - padding: const EdgeInsets.only(top: 6), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Text(label, style: text.transactionDetailRowLabel?.copyWith(color: colors.textTertiary)), - Padding( - padding: const EdgeInsets.only(left: 12), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [for (final item in items) _field(context, item)], - ), - ), - ], +class _NestedCallBox extends StatelessWidget { + final String label; + final DecodedCall call; + final String? note; + final int depth; + final DecodedCallLayout layout; + final String Function(BigInt token) amountText; + final String? Function(String address)? checkphraseOf; + + const _NestedCallBox({ + required this.label, + required this.call, + required this.note, + required this.depth, + required this.layout, + required this.amountText, + required this.checkphraseOf, + }); + + @override + Widget build(BuildContext context) { + final colors = context.colorsV3; + final stacked = layout == DecodedCallLayout.stacked; + return Padding( + padding: EdgeInsets.only(top: stacked ? 14 : 10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Text(stacked ? label.toUpperCase() : label, style: _labelStyle(context)), + const SizedBox(height: 8), + Container( + padding: EdgeInsets.symmetric(horizontal: 12, vertical: stacked ? 8 : 10), + decoration: BoxDecoration( + color: colors.bgSurface2, + borderRadius: context.radiusV3.mdBorder, + border: Border.all(color: colors.borderHairline), + ), + child: DecodedCallView( + call: call, + depth: depth + 1, + layout: layout, + amountText: amountText, + checkphraseOf: checkphraseOf, + ), ), - ); + if (note != null) ...[const SizedBox(height: 4), Text(note!, style: _noteStyle(context))], + ], + ), + ); + } +} + +class _FieldRow extends StatelessWidget { + final String label; + final String value; + final ValueKind kind; + final String? note; + final String? checkphrase; + final DecodedCallLayout layout; + + const _FieldRow({ + required this.label, + required this.value, + required this.kind, + required this.layout, + this.note, + this.checkphrase, + }); - case NestedCallField(:final label, :final call, :final note): - return Padding( - padding: const EdgeInsets.only(top: 10), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, + @override + Widget build(BuildContext context) { + return layout == DecodedCallLayout.stacked ? _stacked(context) : _compact(context); + } + + Widget _stacked(BuildContext context) { + final colors = context.colorsV3; + return Padding( + padding: const EdgeInsets.only(top: 12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Text(label.toUpperCase(), style: _labelStyle(context)), + const SizedBox(height: 8), + Text(value, style: _valueStyle(context, kind, layout)), + if (note != null) ...[const SizedBox(height: 4), Text(note!, style: _noteStyle(context))], + if (checkphrase != null) ...[ + const SizedBox(height: 12), + Text('$label checkphrase'.toUpperCase(), style: _labelStyle(context)), + const SizedBox(height: 8), + Text(checkphrase!, style: _valueStyle(context, kind, layout).copyWith(color: colors.semanticLilac)), + ], + ], + ), + ); + } + + Widget _compact(BuildContext context) { + final colors = context.colorsV3; + return Padding( + padding: const EdgeInsets.only(top: 8), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(label, style: text.transactionDetailRowLabel?.copyWith(color: colors.textTertiary)), - const SizedBox(height: 4), - Container( - padding: const EdgeInsets.all(10), - decoration: BoxDecoration( - color: colors.surfaceDeep, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: colors.borderButton.useOpacity(0.4)), + Expanded(flex: 2, child: Text(label, style: _labelStyle(context))), + const SizedBox(width: 8), + Expanded( + flex: 3, + child: Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Text(value, style: _valueStyle(context, kind, layout), textAlign: TextAlign.right, softWrap: true), + if (checkphrase != null) + Text( + checkphrase!, + style: context.themeTextV3.caption.copyWith(color: colors.semanticLilac), + textAlign: TextAlign.right, + ), + ], ), - child: DecodedCallView(call: call, depth: depth + 1, amountText: amountText), ), - if (note != null) - Padding( - padding: const EdgeInsets.only(top: 4), - child: Text(note, style: text.detail?.copyWith(color: colors.textTertiary, fontSize: 11)), - ), ], ), - ); - } + if (note != null) ...[const SizedBox(height: 4), Text(note!, style: _noteStyle(context))], + ], + ), + ); } } +TextStyle _labelStyle(BuildContext context) { + return context.themeTextV3.labelMonogram.copyWith(fontSize: 10, letterSpacing: 1, color: context.colorsV3.textMuted); +} + +TextStyle _noteStyle(BuildContext context) { + return context.themeTextV3.caption.copyWith(color: context.colorsV3.textMuted); +} + +TextStyle _valueStyle(BuildContext context, ValueKind kind, DecodedCallLayout layout) { + final text = context.themeTextV3; + final colors = context.colorsV3; + final stacked = layout == DecodedCallLayout.stacked; + final base = switch (kind) { + ValueKind.address || ValueKind.hash || ValueKind.bytes => stacked ? text.dataAddressLarge : text.dataAddress, + _ => text.body, + }; + return base.copyWith(color: colors.textContent); +} + /// The one-line-plus-subtitle form of a decoded call, for list rows and sheets. /// /// A transfer keeps reading as an amount and a recipient; anything else names diff --git a/quantus_sdk/lib/src/ui/components/detail_summary_row.dart b/quantus_sdk/lib/src/ui/components/detail_summary_row.dart index 8f2d38db0..e3e013172 100644 --- a/quantus_sdk/lib/src/ui/components/detail_summary_row.dart +++ b/quantus_sdk/lib/src/ui/components/detail_summary_row.dart @@ -1,7 +1,16 @@ import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; -/// Label/value row used in review screens and detail sheets. +/// Density for [DetailSummaryRow] until design picks one layout. +enum DetailSummaryLayout { + /// Sheet/list: label left, value right. + compact, + + /// Signing review: label above value, wrap, no ellipsis. + stacked, +} + +/// Label/value row used in review screens, detail sheets, and signing. class DetailSummaryRow extends StatelessWidget { final String label; final String? value; @@ -11,6 +20,15 @@ class DetailSummaryRow extends StatelessWidget { final EdgeInsetsGeometry padding; final TextStyle? labelStyle; final TextStyle? valueStyle; + final DetailSummaryLayout layout; + + /// Monospace value, for addresses, hashes and byte blobs. [stacked] only. + final bool monospace; + + final Color? valueColor; + + /// Caveat shown under the value. [stacked] only. + final String? note; const DetailSummaryRow({ super.key, @@ -22,6 +40,10 @@ class DetailSummaryRow extends StatelessWidget { this.padding = const EdgeInsets.symmetric(vertical: 8), this.labelStyle, this.valueStyle, + this.layout = DetailSummaryLayout.compact, + this.monospace = false, + this.valueColor, + this.note, }) : assert(value != null || valueWidget != null); factory DetailSummaryRow.review({ @@ -43,13 +65,33 @@ class DetailSummaryRow extends StatelessWidget { ); } + /// Label-above-value row. Values wrap rather than ellipsize so a signer can + /// read a full address or hash. + const DetailSummaryRow.stacked({ + super.key, + required this.label, + required String this.value, + this.monospace = false, + this.valueColor, + this.note, + }) : valueWidget = null, + labelFlex = 2, + valueFlex = 3, + labelStyle = null, + valueStyle = null, + layout = DetailSummaryLayout.stacked, + padding = const EdgeInsets.symmetric(vertical: 10); + @override Widget build(BuildContext context) { - final text = context.themeText; - final colors = context.colors; - final effectiveLabelStyle = labelStyle ?? text.transactionDetailRowLabel?.copyWith(color: colors.textTertiary); - final effectiveValueStyle = - valueStyle ?? text.transactionDetailRowValue?.copyWith(color: Colors.white.withValues(alpha: 0.8)); + return layout == DetailSummaryLayout.stacked ? _stacked(context) : _compact(context); + } + + Widget _compact(BuildContext context) { + final text = context.themeTextV3; + final colors = context.colorsV3; + final effectiveLabelStyle = labelStyle ?? _labelStyle(text, colors); + final effectiveValueStyle = valueStyle ?? text.body.copyWith(color: colors.textContent); return Container( padding: padding, @@ -73,4 +115,32 @@ class DetailSummaryRow extends StatelessWidget { ), ); } + + Widget _stacked(BuildContext context) { + final text = context.themeTextV3; + final colors = context.colorsV3; + + return Padding( + padding: padding, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(label.toUpperCase(), style: _labelStyle(text, colors)), + const SizedBox(height: 6), + Text( + value!, + style: (monospace ? text.dataAddressLarge : text.body).copyWith(color: valueColor ?? colors.textContent), + ), + if (note != null) ...[ + const SizedBox(height: 4), + Text(note!, style: text.caption.copyWith(color: colors.textMuted)), + ], + ], + ), + ); + } + + TextStyle _labelStyle(AppTextThemeV3 text, AppColorsV3 colors) { + return text.labelMonogram.copyWith(fontSize: 10, letterSpacing: 1, color: colors.textMuted); + } } diff --git a/quantus_sdk/test/chain/decoded_call_test.dart b/quantus_sdk/test/chain/decoded_call_test.dart new file mode 100644 index 000000000..06241fb3e --- /dev/null +++ b/quantus_sdk/test/chain/decoded_call_test.dart @@ -0,0 +1,37 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +void main() { + test('addresses lists unique ss58 values from nested calls and groups', () { + final inner = DecodedCall( + pallet: 'Balances', + call: 'transfer_allow_death', + fields: [ + const ValueField('Destination', 'qzDest', kind: ValueKind.address), + AmountField('Amount', BigInt.one), + ], + ); + final call = DecodedCall( + pallet: 'Utility', + call: 'batch', + fields: [ + FieldGroup('Calls', [NestedCallField('Call 0', inner)]), + const ValueField('Origin', 'qzDest', kind: ValueKind.address), + const ValueField('Other', 'qzOther', kind: ValueKind.address), + const ValueField('Hash', '0xabc', kind: ValueKind.hash), + ], + ); + + expect(call.addresses, ['qzDest', 'qzOther']); + }); + + test('addresses is empty when no address fields are present', () { + const call = DecodedCall( + pallet: 'System', + call: 'remark', + fields: [ValueField('Remark', 'hello', kind: ValueKind.text)], + ); + + expect(call.addresses, isEmpty); + }); +} diff --git a/quantus_sdk/test/ui/decoded_call_view_test.dart b/quantus_sdk/test/ui/decoded_call_view_test.dart new file mode 100644 index 000000000..8bdb0ba50 --- /dev/null +++ b/quantus_sdk/test/ui/decoded_call_view_test.dart @@ -0,0 +1,125 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + const colors = AppColorsV3.dark(); + const text = AppTextThemeV3.standard(); + + const dest = ValueField('Destination', 'qzDest', kind: ValueKind.address); + final amount = AmountField('Amount', BigInt.from(1000)); + final transfer = DecodedCall(pallet: 'Balances', call: 'transfer_allow_death', fields: [dest, amount]); + + Future pumpCall(WidgetTester tester, Widget view, {Size size = const Size(375, 667)}) async { + await tester.pumpWidget( + MediaQuery( + data: MediaQueryData(size: size), + child: Builder( + builder: (context) => MaterialApp( + theme: AppTheme.darkTheme(context), + home: Scaffold(body: SingleChildScrollView(child: view)), + ), + ), + ), + ); + await tester.pump(); + } + + DecodedCallView view({ + required DecodedCall call, + DecodedCallLayout layout = DecodedCallLayout.compact, + String? Function(String address)? checkphraseOf, + int depth = 0, + }) { + return DecodedCallView( + call: call, + layout: layout, + amountText: (token) => '$token QNT', + checkphraseOf: checkphraseOf, + depth: depth, + ); + } + + testWidgets('renders pallet title, fields, and formatted native amount', (tester) async { + await pumpCall(tester, view(call: transfer)); + + expect(find.text('Balances · transfer_allow_death'), findsOneWidget); + expect(find.text('Destination'), findsOneWidget); + expect(find.text('qzDest'), findsOneWidget); + expect(find.text('1000 QNT'), findsOneWidget); + }); + + testWidgets('stacked layout uppercases labels and wraps checkphrase in lilac', (tester) async { + await pumpCall( + tester, + view(call: transfer, layout: DecodedCallLayout.stacked, checkphraseOf: (address) => 'alpha bravo charlie'), + ); + + expect(find.text('DESTINATION'), findsOneWidget); + expect(find.text('DESTINATION CHECKPHRASE'), findsOneWidget); + final phrase = tester.widget(find.text('alpha bravo charlie')); + expect(phrase.style?.color, colors.semanticLilac); + }); + + testWidgets('compact layout keeps title-case labels and right-aligns values', (tester) async { + await pumpCall(tester, view(call: transfer)); + + expect(find.text('Destination'), findsOneWidget); + expect(find.text('DESTINATION'), findsNothing); + final value = tester.widget(find.text('qzDest')); + expect(value.textAlign, TextAlign.right); + expect(value.style?.fontFamily, AppTextTheme.fontFamilySecondary); + }); + + testWidgets('nested call uses surface2 fill, hairline, and v3 md radius', (tester) async { + const nested = DecodedCall(pallet: 'Balances', call: 'transfer_allow_death', fields: [dest]); + const outer = DecodedCall(pallet: 'Multisig', call: 'as_multi', fields: [NestedCallField('Call', nested)]); + + await pumpCall(tester, view(call: outer)); + + expect(find.text('Multisig · as_multi'), findsOneWidget); + expect(find.text('Balances · transfer_allow_death'), findsOneWidget); + + final nestedTitle = tester.widget(find.text('Balances · transfer_allow_death')); + expect(nestedTitle.style?.color, colors.textMuted); + expect(nestedTitle.style?.fontSize, text.headingRow.fontSize); + + final container = tester.widget( + find.ancestor(of: find.text('Balances · transfer_allow_death'), matching: find.byType(Container)).first, + ); + final decoration = container.decoration! as BoxDecoration; + expect(decoration.color, colors.bgSurface2); + expect(decoration.borderRadius, const AppRadiusV3.standard().mdBorder); + final border = decoration.border! as Border; + expect(border.top.color, colors.borderHairline); + }); + + testWidgets('asset amounts show raw units and the decimals caveat', (tester) async { + final call = DecodedCall( + pallet: 'Assets', + call: 'transfer', + fields: [AmountField('Amount', BigInt.from(99), assetId: 7)], + ); + + await pumpCall(tester, view(call: call)); + + expect(find.text('99 raw units of asset #7'), findsOneWidget); + expect(find.text('Asset decimals are not part of this payload, so the raw amount is shown.'), findsOneWidget); + }); + + testWidgets('hash fields use the mono data style', (tester) async { + const call = DecodedCall( + pallet: 'Preimage', + call: 'note_preimage', + fields: [ValueField('Hash', '0xdead', kind: ValueKind.hash)], + ); + + await pumpCall(tester, view(call: call)); + + final hash = tester.widget(find.text('0xdead')); + expect(hash.style?.fontFamily, AppTextTheme.fontFamilySecondary); + expect(hash.style?.color, colors.textContent); + }); +} diff --git a/quantus_sdk/test/ui/detail_summary_row_test.dart b/quantus_sdk/test/ui/detail_summary_row_test.dart new file mode 100644 index 000000000..263461161 --- /dev/null +++ b/quantus_sdk/test/ui/detail_summary_row_test.dart @@ -0,0 +1,69 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + const colors = AppColorsV3.dark(); + const text = AppTextThemeV3.standard(); + + Future pumpRow(WidgetTester tester, Widget row) async { + await tester.pumpWidget( + MediaQuery( + data: const MediaQueryData(size: Size(375, 667)), + child: Builder( + builder: (context) => MaterialApp( + theme: AppTheme.darkTheme(context), + home: Scaffold(body: row), + ), + ), + ), + ); + await tester.pump(); + } + + testWidgets('uses v3 muted label and content value tokens', (tester) async { + await pumpRow(tester, const DetailSummaryRow(label: 'Network fee', value: '1.00 QNT')); + + final label = tester.widget(find.text('Network fee')); + expect(label.style?.color, colors.textMuted); + expect(label.style?.fontSize, 10); + expect(label.style?.letterSpacing, 1); + expect(label.style?.fontFamily, AppTextTheme.fontFamilySecondary); + + final value = tester.widget(find.text('1.00 QNT')); + expect(value.style?.color, colors.textContent); + expect(value.style?.fontSize, text.body.fontSize); + expect(value.textAlign, TextAlign.right); + }); + + testWidgets('stacked uppercases the label and paints a wrapping value', (tester) async { + await pumpRow(tester, const DetailSummaryRow.stacked(label: 'Genesis hash', value: '0xabc', monospace: true)); + + expect(find.text('GENESIS HASH'), findsOneWidget); + expect(find.text('Genesis hash'), findsNothing); + + final value = tester.widget(find.text('0xabc')); + expect(value.textAlign, isNull); + expect(value.style?.fontFamily, AppTextTheme.fontFamilySecondary); + expect(value.style?.fontSize, text.dataAddressLarge.fontSize); + expect(value.style?.color, colors.textContent); + }); + + testWidgets('stacked applies valueColor and shows a note', (tester) async { + await pumpRow( + tester, + DetailSummaryRow.stacked( + label: 'Signing as checkphrase', + value: 'alpha bravo', + valueColor: colors.semanticLilac, + note: 'Verify out loud.', + ), + ); + + final value = tester.widget(find.text('alpha bravo')); + expect(value.style?.color, colors.semanticLilac); + expect(find.text('Verify out loud.'), findsOneWidget); + }); +} From 8a9b295749d7d94e4261dddeb3dd355728423b14 Mon Sep 17 00:00:00 2001 From: Beast Date: Wed, 19 Aug 2026 17:02:07 +0800 Subject: [PATCH 22/38] feat: update dialog --- .../lib/components/confirm_dialog.dart | 11 -- .../lib/screens/settings_screen.dart | 15 +- cold-wallet-app/test/confirm_dialog_test.dart | 67 -------- .../lib/src/ui/components/quantus_dialog.dart | 37 ++++- quantus_sdk/test/ui/quantus_dialog_test.dart | 147 ++++++++++++++---- 5 files changed, 155 insertions(+), 122 deletions(-) delete mode 100644 cold-wallet-app/lib/components/confirm_dialog.dart delete mode 100644 cold-wallet-app/test/confirm_dialog_test.dart diff --git a/cold-wallet-app/lib/components/confirm_dialog.dart b/cold-wallet-app/lib/components/confirm_dialog.dart deleted file mode 100644 index e6da05a84..000000000 --- a/cold-wallet-app/lib/components/confirm_dialog.dart +++ /dev/null @@ -1,11 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; - -Future showConfirmDialog( - BuildContext context, { - required String title, - required String message, - required String confirmLabel, -}) { - return showQuantusDialog(context, title: title, body: message, actionLabel: confirmLabel); -} diff --git a/cold-wallet-app/lib/screens/settings_screen.dart b/cold-wallet-app/lib/screens/settings_screen.dart index 54e323d0d..83fa30ac1 100644 --- a/cold-wallet-app/lib/screens/settings_screen.dart +++ b/cold-wallet-app/lib/screens/settings_screen.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:quantus_cold_wallet/components/confirm_dialog.dart'; import 'package:quantus_cold_wallet/components/qr_tuning_controls.dart'; import 'package:quantus_cold_wallet/providers/settings_providers.dart'; import 'package:quantus_cold_wallet/providers/wallet_providers.dart'; @@ -15,23 +14,25 @@ class SettingsScreen extends ConsumerWidget { await ref.read(coldSettingsProvider.notifier).setWifiOverrideEnabled(false); return; } - final confirmed = await showConfirmDialog( + final confirmed = await showQuantusDialog( context, title: 'Override network lock?', - message: + body: 'A cold wallet is only safe while fully offline — override the lock for testing only, never with a ' 'wallet that holds real funds.', - confirmLabel: 'Override', + actionLabel: 'Override', + isDestructive: true, ); if (confirmed) await ref.read(coldSettingsProvider.notifier).setWifiOverrideEnabled(true); } Future _confirmReset(BuildContext context, WidgetRef ref) async { - final confirmed = await showConfirmDialog( + final confirmed = await showQuantusDialog( context, title: 'Reset wallet?', - message: 'This erases the encrypted key from this device. You can only restore it with your recovery phrase.', - confirmLabel: 'Reset', + body: 'This erases the encrypted key from this device. You can only restore it with your recovery phrase.', + actionLabel: 'Reset', + isDestructive: true, ); if (!confirmed) return; await ref.read(walletControllerProvider.notifier).wipe(); diff --git a/cold-wallet-app/test/confirm_dialog_test.dart b/cold-wallet-app/test/confirm_dialog_test.dart deleted file mode 100644 index ea0167cba..000000000 --- a/cold-wallet-app/test/confirm_dialog_test.dart +++ /dev/null @@ -1,67 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:quantus_cold_wallet/components/confirm_dialog.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; - -void main() { - TestWidgetsFlutterBinding.ensureInitialized(); - - Future pumpConfirm(WidgetTester tester, {required Future Function(bool result) onResult}) async { - await tester.pumpWidget( - MediaQuery( - data: const MediaQueryData(size: Size(375, 667)), - child: Builder( - builder: (context) => MaterialApp( - theme: AppTheme.darkTheme(context), - home: Scaffold( - body: Builder( - builder: (context) { - return TextButton( - onPressed: () async { - final confirmed = await showConfirmDialog( - context, - title: 'Reset wallet?', - message: 'This erases the encrypted key from this device.', - confirmLabel: 'Reset', - ); - await onResult(confirmed); - }, - child: const Text('Open'), - ); - }, - ), - ), - ), - ), - ), - ); - await tester.pump(); - await tester.tap(find.text('Open')); - await tester.pumpAndSettle(); - } - - testWidgets('presents QuantusDialog instead of AlertDialog', (tester) async { - await pumpConfirm(tester, onResult: (_) async {}); - - expect(find.byType(QuantusDialog), findsOneWidget); - expect(find.byType(AlertDialog), findsNothing); - expect(find.text('Reset wallet?'), findsOneWidget); - expect(find.text('This erases the encrypted key from this device.'), findsOneWidget); - expect(find.text('Reset'), findsOneWidget); - }); - - testWidgets('returns true when the QuantusDialog action is tapped', (tester) async { - bool? result; - await pumpConfirm( - tester, - onResult: (confirmed) async { - result = confirmed; - }, - ); - - await tester.tap(find.text('Reset')); - await tester.pumpAndSettle(); - - expect(result, isTrue); - }); -} diff --git a/quantus_sdk/lib/src/ui/components/quantus_dialog.dart b/quantus_sdk/lib/src/ui/components/quantus_dialog.dart index 17d73b21c..19cffbb11 100644 --- a/quantus_sdk/lib/src/ui/components/quantus_dialog.dart +++ b/quantus_sdk/lib/src/ui/components/quantus_dialog.dart @@ -1,17 +1,30 @@ import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; -/// Shared v3 centered dialog: title, plain-consequence body, primary CTA. +/// Shared v3 centered dialog: title, plain-consequence body, primary CTA, Cancel. /// -/// Presentational only. Callers pass already-resolved [title], [body], and -/// [actionLabel] strings. Overlay presentation is [showQuantusDialog]. +/// Presentational only. Callers pass already-resolved [title], [body], +/// [actionLabel], and [cancelLabel] strings. Overlay presentation is +/// [showQuantusDialog]. class QuantusDialog extends StatelessWidget { final String title; final String body; final String actionLabel; + final String cancelLabel; + final bool isDestructive; final VoidCallback? onAction; + final VoidCallback? onCancel; - const QuantusDialog({super.key, required this.title, required this.body, required this.actionLabel, this.onAction}); + const QuantusDialog({ + super.key, + required this.title, + required this.body, + required this.actionLabel, + this.cancelLabel = 'Cancel', + this.isDestructive = false, + this.onAction, + this.onCancel, + }); @override Widget build(BuildContext context) { @@ -35,7 +48,13 @@ class QuantusDialog extends StatelessWidget { const SizedBox(height: 10), Text(body, style: text.body.copyWith(color: colors.textMuted, height: 1.55)), const SizedBox(height: 18), - QuantusButton.simple(label: actionLabel, onTap: onAction), + QuantusButton.simple( + label: actionLabel, + variant: isDestructive ? ButtonVariant.danger : ButtonVariant.primary, + onTap: onAction, + ), + const SizedBox(height: 12), + QuantusButton.simple(label: cancelLabel, variant: ButtonVariant.secondary, onTap: onCancel), ], ), ); @@ -44,12 +63,15 @@ class QuantusDialog extends StatelessWidget { /// Shows a centered [QuantusDialog]. /// -/// Returns `true` when the primary action is tapped, `false` if the barrier is dismissed. +/// Returns `true` when the primary action is tapped, `false` when Cancel is +/// tapped or the barrier is dismissed. Future showQuantusDialog( BuildContext context, { required String title, required String body, required String actionLabel, + String cancelLabel = 'Cancel', + bool isDestructive = false, bool barrierDismissible = true, }) async { final confirmed = await showDialog( @@ -64,7 +86,10 @@ Future showQuantusDialog( title: title, body: body, actionLabel: actionLabel, + cancelLabel: cancelLabel, + isDestructive: isDestructive, onAction: () => Navigator.pop(dialogContext, true), + onCancel: () => Navigator.pop(dialogContext, false), ), ); }, diff --git a/quantus_sdk/test/ui/quantus_dialog_test.dart b/quantus_sdk/test/ui/quantus_dialog_test.dart index 40131f63e..c64ef42ac 100644 --- a/quantus_sdk/test/ui/quantus_dialog_test.dart +++ b/quantus_sdk/test/ui/quantus_dialog_test.dart @@ -22,6 +22,40 @@ void main() { await tester.pump(); } + Future pumpShownDialog(WidgetTester tester, {required Future Function(bool result) onResult}) async { + await tester.pumpWidget( + MediaQuery( + data: const MediaQueryData(size: Size(375, 667)), + child: Builder( + builder: (context) => MaterialApp( + theme: AppTheme.darkTheme(context), + home: Scaffold( + body: Builder( + builder: (context) { + return TextButton( + onPressed: () async { + final result = await showQuantusDialog( + context, + title: 'Dialog title?', + body: 'Consequences.', + actionLabel: 'Label', + ); + await onResult(result); + }, + child: const Text('Open'), + ); + }, + ), + ), + ), + ), + ), + ); + await tester.pump(); + await tester.tap(find.text('Open')); + await tester.pumpAndSettle(); + } + BoxDecoration decorationAround(WidgetTester tester, String text) { final container = tester.widget( find.ancestor(of: find.text(text), matching: find.byType(Container)).first, @@ -29,7 +63,11 @@ void main() { return container.decoration! as BoxDecoration; } - testWidgets('shows title, body, and action label', (tester) async { + QuantusButton actionButton(WidgetTester tester, String label) { + return tester.widget(find.ancestor(of: find.text(label), matching: find.byType(QuantusButton))); + } + + testWidgets('shows title, body, action, and Cancel', (tester) async { await pumpDialog( tester, QuantusDialog( @@ -37,12 +75,61 @@ void main() { body: 'One or two sentences stating consequences plainly. Nothing has been sent.', actionLabel: 'Label', onAction: () {}, + onCancel: () {}, ), ); expect(find.text('Dialog title?'), findsOneWidget); expect(find.text('One or two sentences stating consequences plainly. Nothing has been sent.'), findsOneWidget); expect(find.text('Label'), findsOneWidget); + expect(find.text('Cancel'), findsOneWidget); + }); + + testWidgets('action uses primary variant by default', (tester) async { + await pumpDialog( + tester, + QuantusDialog( + title: 'Dialog title?', + body: 'Consequences.', + actionLabel: 'Label', + onAction: () {}, + onCancel: () {}, + ), + ); + + expect(actionButton(tester, 'Label').variant, ButtonVariant.primary); + }); + + testWidgets('action uses danger variant when destructive', (tester) async { + await pumpDialog( + tester, + QuantusDialog( + title: 'Dialog title?', + body: 'Consequences.', + actionLabel: 'Label', + isDestructive: true, + onAction: () {}, + onCancel: () {}, + ), + ); + + expect(actionButton(tester, 'Label').variant, ButtonVariant.danger); + expect(actionButton(tester, 'Cancel').variant, ButtonVariant.secondary); + }); + + testWidgets('stacks Cancel below the primary action', (tester) async { + await pumpDialog( + tester, + QuantusDialog( + title: 'Dialog title?', + body: 'Consequences.', + actionLabel: 'Label', + onAction: () {}, + onCancel: () {}, + ), + ); + + expect(tester.getTopLeft(find.text('Cancel')).dy, greaterThan(tester.getTopLeft(find.text('Label')).dy)); }); testWidgets('tapping the action invokes the callback', (tester) async { @@ -56,6 +143,23 @@ void main() { expect(tapped, isTrue); }); + testWidgets('tapping Cancel invokes the cancel callback', (tester) async { + var cancelled = false; + await pumpDialog( + tester, + QuantusDialog( + title: 'Dialog title?', + body: 'Consequences.', + actionLabel: 'Label', + onAction: () {}, + onCancel: () => cancelled = true, + ), + ); + + await tester.tap(find.text('Cancel')); + expect(cancelled, isTrue); + }); + testWidgets('paints surface fill and emphasis border', (tester) async { await pumpDialog( tester, @@ -80,40 +184,21 @@ void main() { testWidgets('showQuantusDialog returns true when the action is tapped', (tester) async { bool? result; - await tester.pumpWidget( - MediaQuery( - data: const MediaQueryData(size: Size(375, 667)), - child: Builder( - builder: (context) => MaterialApp( - theme: AppTheme.darkTheme(context), - home: Scaffold( - body: Builder( - builder: (context) { - return TextButton( - onPressed: () async { - result = await showQuantusDialog( - context, - title: 'Dialog title?', - body: 'Consequences.', - actionLabel: 'Label', - ); - }, - child: const Text('Open'), - ); - }, - ), - ), - ), - ), - ), - ); - await tester.pump(); + await pumpShownDialog(tester, onResult: (confirmed) async => result = confirmed); - await tester.tap(find.text('Open')); - await tester.pumpAndSettle(); await tester.tap(find.text('Label')); await tester.pumpAndSettle(); expect(result, isTrue); }); + + testWidgets('showQuantusDialog returns false when Cancel is tapped', (tester) async { + bool? result; + await pumpShownDialog(tester, onResult: (confirmed) async => result = confirmed); + + await tester.tap(find.text('Cancel')); + await tester.pumpAndSettle(); + + expect(result, isFalse); + }); } From aa1ad5eeb0c051762bf1cb2e197e72468907e94b Mon Sep 17 00:00:00 2001 From: Beast Date: Wed, 19 Aug 2026 17:14:01 +0800 Subject: [PATCH 23/38] feat: update tuning controls design tokens --- .../lib/components/qr_tuning_controls.dart | 16 +++--- .../test/qr_tuning_controls_test.dart | 56 +++++++++++++++++++ 2 files changed, 64 insertions(+), 8 deletions(-) create mode 100644 cold-wallet-app/test/qr_tuning_controls_test.dart diff --git a/cold-wallet-app/lib/components/qr_tuning_controls.dart b/cold-wallet-app/lib/components/qr_tuning_controls.dart index 00e930782..79e9334e9 100644 --- a/cold-wallet-app/lib/components/qr_tuning_controls.dart +++ b/cold-wallet-app/lib/components/qr_tuning_controls.dart @@ -61,8 +61,8 @@ class _TuningSlider extends StatelessWidget { @override Widget build(BuildContext context) { - final colors = context.colors; - final text = context.themeText; + final colors = context.colorsV3; + final text = context.themeTextV3; return Column( crossAxisAlignment: CrossAxisAlignment.stretch, @@ -70,16 +70,16 @@ class _TuningSlider extends StatelessWidget { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text(label, style: text.detail?.copyWith(color: colors.textSecondary)), - Text(valueText, style: text.detail?.copyWith(color: colors.textPrimary)), + Text(label, style: text.caption.copyWith(color: colors.textMuted)), + Text(valueText, style: text.caption.copyWith(color: colors.textContent)), ], ), SliderTheme( data: SliderTheme.of(context).copyWith( - activeTrackColor: colors.accentOrange, - inactiveTrackColor: colors.borderButton, - thumbColor: colors.accentOrange, - overlayColor: colors.accentOrange.withValues(alpha: 0.15), + activeTrackColor: colors.accentFlare, + inactiveTrackColor: colors.borderHairline, + thumbColor: colors.accentFlare, + overlayColor: colors.accentFlare.useOpacity(0.15), trackHeight: 2, ), child: Slider(value: value, min: min, max: max, divisions: divisions, onChanged: onChanged), diff --git a/cold-wallet-app/test/qr_tuning_controls_test.dart b/cold-wallet-app/test/qr_tuning_controls_test.dart new file mode 100644 index 000000000..9d039d48e --- /dev/null +++ b/cold-wallet-app/test/qr_tuning_controls_test.dart @@ -0,0 +1,56 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:quantus_cold_wallet/components/qr_tuning_controls.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + const colors = AppColorsV3.dark(); + const text = AppTextThemeV3.standard(); + + Future pumpControls(WidgetTester tester) async { + SharedPreferences.setMockInitialValues({}); + await tester.pumpWidget( + ProviderScope( + child: MediaQuery( + data: const MediaQueryData(size: Size(375, 667)), + child: Builder( + builder: (context) => MaterialApp( + theme: AppTheme.darkTheme(context), + home: const Scaffold(body: QrTuningControls()), + ), + ), + ), + ), + ); + await tester.pump(); + } + + testWidgets('uses v3 caption, muted labels, content values, and flare slider chrome', (tester) async { + await pumpControls(tester); + + for (final label in ['Frame rate', 'Bytes per frame']) { + final widget = tester.widget(find.text(label)); + expect(widget.style?.color, colors.textMuted); + expect(widget.style?.fontSize, text.caption.fontSize); + } + + for (final value in ['15 FPS', '1100 bytes']) { + final widget = tester.widget(find.text(value)); + expect(widget.style?.color, colors.textContent); + expect(widget.style?.fontSize, text.caption.fontSize); + } + + final themes = tester.widgetList(find.byType(SliderTheme)); + expect(themes, hasLength(2)); + for (final theme in themes) { + expect(theme.data.activeTrackColor, colors.accentFlare); + expect(theme.data.inactiveTrackColor, colors.borderHairline); + expect(theme.data.thumbColor, colors.accentFlare); + expect(theme.data.overlayColor, colors.accentFlare.useOpacity(0.15)); + } + }); +} From 050d51bbb10d87248c1bf003421bfeef6034e00a Mon Sep 17 00:00:00 2001 From: Beast Date: Wed, 19 Aug 2026 17:28:38 +0800 Subject: [PATCH 24/38] feat: reorg component files, update password sheet --- cold-wallet-app/lib/app.dart | 4 +- .../change_password_sheet.dart | 24 +++---- .../connectivity_guard.dart | 0 .../{widgets => components}/lock_overlay.dart | 2 +- .../{screens => components}/lock_screen.dart | 2 +- .../password_field.dart | 0 .../lib/screens/set_password_screen.dart | 2 +- .../lib/screens/settings_screen.dart | 2 +- .../test/change_password_sheet_test.dart | 64 +++++++++++++++++-- 9 files changed, 76 insertions(+), 24 deletions(-) rename cold-wallet-app/lib/{widgets => components}/change_password_sheet.dart (86%) rename cold-wallet-app/lib/{widgets => components}/connectivity_guard.dart (100%) rename cold-wallet-app/lib/{widgets => components}/lock_overlay.dart (91%) rename cold-wallet-app/lib/{screens => components}/lock_screen.dart (97%) rename cold-wallet-app/lib/{widgets => components}/password_field.dart (100%) diff --git a/cold-wallet-app/lib/app.dart b/cold-wallet-app/lib/app.dart index 4b079d332..b3bd6077b 100644 --- a/cold-wallet-app/lib/app.dart +++ b/cold-wallet-app/lib/app.dart @@ -3,8 +3,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:quantus_cold_wallet/providers/wallet_providers.dart'; import 'package:quantus_cold_wallet/screens/root_gate.dart'; -import 'package:quantus_cold_wallet/widgets/connectivity_guard.dart'; -import 'package:quantus_cold_wallet/widgets/lock_overlay.dart'; +import 'package:quantus_cold_wallet/components/connectivity_guard.dart'; +import 'package:quantus_cold_wallet/components/lock_overlay.dart'; class ColdWalletApp extends ConsumerStatefulWidget { const ColdWalletApp({super.key}); diff --git a/cold-wallet-app/lib/widgets/change_password_sheet.dart b/cold-wallet-app/lib/components/change_password_sheet.dart similarity index 86% rename from cold-wallet-app/lib/widgets/change_password_sheet.dart rename to cold-wallet-app/lib/components/change_password_sheet.dart index cd8ea69b2..3a13eca13 100644 --- a/cold-wallet-app/lib/widgets/change_password_sheet.dart +++ b/cold-wallet-app/lib/components/change_password_sheet.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:quantus_cold_wallet/providers/wallet_providers.dart'; -import 'package:quantus_cold_wallet/widgets/password_field.dart'; +import 'package:quantus_cold_wallet/components/password_field.dart'; /// Action pane for setting or changing the vault password. Resolves to true /// when the password was changed. @@ -11,7 +11,7 @@ Future showChangePasswordSheet(BuildContext context) async { context: context, isScrollControlled: true, enableDrag: false, - backgroundColor: context.colors.sheetBackground, + backgroundColor: context.colorsV3.bgSurface, builder: (_) => const _ChangePasswordSheet(), ); return changed == true; @@ -80,8 +80,8 @@ class _ChangePasswordSheetState extends ConsumerState<_ChangePasswordSheet> { @override Widget build(BuildContext context) { - final colors = context.colors; - final text = context.themeText; + final colors = context.colorsV3; + final text = context.themeTextV3; // The rotation must not look cancellable once it is running: block barrier // taps and back navigation until the result lands in this sheet. @@ -97,16 +97,16 @@ class _ChangePasswordSheetState extends ConsumerState<_ChangePasswordSheet> { ); } - Widget _successContent(AppColorsV2 colors, AppTextTheme text) { + Widget _successContent(AppColorsV3 colors, AppTextThemeV3 text) { return Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - Icon(Icons.check_circle_outline_rounded, size: 48, color: colors.success), + Icon(Icons.check_circle_outline_rounded, size: 48, color: colors.semanticSage), const SizedBox(height: 16), Text( 'Password changed', - style: text.smallTitle?.copyWith(color: colors.textPrimary), + style: text.titleScreen.copyWith(color: colors.textContent), textAlign: TextAlign.center, ), if (_biometricDisabled) ...[ @@ -114,7 +114,7 @@ class _ChangePasswordSheetState extends ConsumerState<_ChangePasswordSheet> { Text( 'Biometric unlock was turned off because its key could not be updated for the new password. ' 'Unlock with your password.', - style: text.detail?.copyWith(color: colors.textSecondary), + style: text.body.copyWith(color: colors.textMuted, height: 1.55), textAlign: TextAlign.center, ), ], @@ -124,17 +124,17 @@ class _ChangePasswordSheetState extends ConsumerState<_ChangePasswordSheet> { ); } - Widget _formContent(AppColorsV2 colors, AppTextTheme text) { + Widget _formContent(AppColorsV3 colors, AppTextThemeV3 text) { return Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - Text('Change password', style: text.smallTitle?.copyWith(color: colors.textPrimary)), + Text('Change password', style: text.titleScreen.copyWith(color: colors.textContent)), const SizedBox(height: 8), Text( 'Your password encrypts the wallet key stored on this device. If you never set one, leave the current ' 'password empty.', - style: text.detail?.copyWith(color: colors.textSecondary), + style: text.body.copyWith(color: colors.textMuted, height: 1.55), ), const SizedBox(height: 24), PasswordField(controller: _current, hintText: 'Current password', enabled: !_busy), @@ -149,7 +149,7 @@ class _ChangePasswordSheetState extends ConsumerState<_ChangePasswordSheet> { ), if (_error != null) ...[ const SizedBox(height: 16), - Text(_error!, style: text.detail?.copyWith(color: colors.error)), + Text(_error!, style: text.caption.copyWith(color: colors.semanticEmber)), ], const SizedBox(height: 24), QuantusButton.simple(label: 'Change password', isLoading: _busy, onTap: _busy ? null : _submit), diff --git a/cold-wallet-app/lib/widgets/connectivity_guard.dart b/cold-wallet-app/lib/components/connectivity_guard.dart similarity index 100% rename from cold-wallet-app/lib/widgets/connectivity_guard.dart rename to cold-wallet-app/lib/components/connectivity_guard.dart diff --git a/cold-wallet-app/lib/widgets/lock_overlay.dart b/cold-wallet-app/lib/components/lock_overlay.dart similarity index 91% rename from cold-wallet-app/lib/widgets/lock_overlay.dart rename to cold-wallet-app/lib/components/lock_overlay.dart index 935be5a75..f312fb545 100644 --- a/cold-wallet-app/lib/widgets/lock_overlay.dart +++ b/cold-wallet-app/lib/components/lock_overlay.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_cold_wallet/providers/wallet_providers.dart'; -import 'package:quantus_cold_wallet/screens/lock_screen.dart'; +import 'package:quantus_cold_wallet/components/lock_screen.dart'; /// Shows the lock screen as a full-screen overlay whenever the wallet is /// locked, so it covers any pushed route (Show Key, Sign) — not just the home diff --git a/cold-wallet-app/lib/screens/lock_screen.dart b/cold-wallet-app/lib/components/lock_screen.dart similarity index 97% rename from cold-wallet-app/lib/screens/lock_screen.dart rename to cold-wallet-app/lib/components/lock_screen.dart index 8495dc3f8..4fbfb77bd 100644 --- a/cold-wallet-app/lib/screens/lock_screen.dart +++ b/cold-wallet-app/lib/components/lock_screen.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_cold_wallet/providers/wallet_providers.dart'; -import 'package:quantus_cold_wallet/widgets/password_field.dart'; +import 'package:quantus_cold_wallet/components/password_field.dart'; class LockScreen extends ConsumerStatefulWidget { const LockScreen({super.key}); diff --git a/cold-wallet-app/lib/widgets/password_field.dart b/cold-wallet-app/lib/components/password_field.dart similarity index 100% rename from cold-wallet-app/lib/widgets/password_field.dart rename to cold-wallet-app/lib/components/password_field.dart diff --git a/cold-wallet-app/lib/screens/set_password_screen.dart b/cold-wallet-app/lib/screens/set_password_screen.dart index 634c40ae0..090ad939a 100644 --- a/cold-wallet-app/lib/screens/set_password_screen.dart +++ b/cold-wallet-app/lib/screens/set_password_screen.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:quantus_cold_wallet/providers/wallet_providers.dart'; -import 'package:quantus_cold_wallet/widgets/password_field.dart'; +import 'package:quantus_cold_wallet/components/password_field.dart'; class SetPasswordScreen extends ConsumerStatefulWidget { final String mnemonic; diff --git a/cold-wallet-app/lib/screens/settings_screen.dart b/cold-wallet-app/lib/screens/settings_screen.dart index 83fa30ac1..cb443c127 100644 --- a/cold-wallet-app/lib/screens/settings_screen.dart +++ b/cold-wallet-app/lib/screens/settings_screen.dart @@ -4,7 +4,7 @@ import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:quantus_cold_wallet/components/qr_tuning_controls.dart'; import 'package:quantus_cold_wallet/providers/settings_providers.dart'; import 'package:quantus_cold_wallet/providers/wallet_providers.dart'; -import 'package:quantus_cold_wallet/widgets/change_password_sheet.dart'; +import 'package:quantus_cold_wallet/components/change_password_sheet.dart'; class SettingsScreen extends ConsumerWidget { const SettingsScreen({super.key}); diff --git a/cold-wallet-app/test/change_password_sheet_test.dart b/cold-wallet-app/test/change_password_sheet_test.dart index 7394101d1..2de9c594b 100644 --- a/cold-wallet-app/test/change_password_sheet_test.dart +++ b/cold-wallet-app/test/change_password_sheet_test.dart @@ -6,7 +6,7 @@ import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:quantus_cold_wallet/providers/wallet_providers.dart'; -import 'package:quantus_cold_wallet/widgets/change_password_sheet.dart'; +import 'package:quantus_cold_wallet/components/change_password_sheet.dart'; class _HangingController extends WalletController { final completer = Completer(); @@ -17,13 +17,16 @@ class _HangingController extends WalletController { } void main() { - testWidgets('password fields freeze while the rotation is in flight', (tester) async { - FlutterSecureStorage.setMockInitialValues({}); - final controller = _HangingController(); + TestWidgetsFlutterBinding.ensureInitialized(); + + const colors = AppColorsV3.dark(); + const text = AppTextThemeV3.standard(); + Future openSheet(WidgetTester tester, {_HangingController? controller}) async { + FlutterSecureStorage.setMockInitialValues({}); await tester.pumpWidget( ProviderScope( - overrides: [walletControllerProvider.overrideWith(() => controller)], + overrides: [if (controller != null) walletControllerProvider.overrideWith(() => controller)], child: MaterialApp( home: Builder( builder: (context) => Theme( @@ -40,9 +43,13 @@ void main() { ), ), ); - await tester.tap(find.text('open')); await tester.pumpAndSettle(); + } + + testWidgets('password fields freeze while the rotation is in flight', (tester) async { + final controller = _HangingController(); + await openSheet(tester, controller: controller); await tester.enterText(find.byType(TextField).at(0), 'alpha'); await tester.enterText(find.byType(TextField).at(1), 'beta'); @@ -60,4 +67,49 @@ void main() { await tester.pumpAndSettle(); expect(find.text('Password changed'), findsOneWidget); }); + + testWidgets('uses v3 title, body, error, and surface tokens', (tester) async { + await openSheet(tester); + + final title = tester.widget(find.text('Change password').first); + expect(title.style?.color, colors.textContent); + expect(title.style?.fontSize, text.titleScreen.fontSize); + expect(title.style?.fontWeight, text.titleScreen.fontWeight); + + final body = tester.widget( + find.textContaining('Your password encrypts the wallet key stored on this device'), + ); + expect(body.style?.color, colors.textMuted); + expect(body.style?.fontSize, text.body.fontSize); + + expect(tester.widget(find.byType(BottomSheet)).backgroundColor, colors.bgSurface); + + await tester.enterText(find.byType(TextField).at(1), 'beta'); + await tester.enterText(find.byType(TextField).at(2), 'gamma'); + await tester.tap(find.text('Change password').last); + await tester.pump(); + + final error = tester.widget(find.text('New passwords do not match')); + expect(error.style?.color, colors.semanticEmber); + expect(error.style?.fontSize, text.caption.fontSize); + }); + + testWidgets('success state uses sage icon and v3 title', (tester) async { + final controller = _HangingController(); + await openSheet(tester, controller: controller); + + await tester.enterText(find.byType(TextField).at(1), 'beta'); + await tester.enterText(find.byType(TextField).at(2), 'beta'); + await tester.tap(find.text('Change password').last); + controller.completer.complete(PasswordChangeResult.changed); + await tester.pumpAndSettle(); + + final icon = tester.widget(find.byIcon(Icons.check_circle_outline_rounded)); + expect(icon.color, colors.semanticSage); + + final title = tester.widget(find.text('Password changed')); + expect(title.style?.color, colors.textContent); + expect(title.style?.fontSize, text.titleScreen.fontSize); + expect(title.style?.fontWeight, text.titleScreen.fontWeight); + }); } From 82fdd55b364b0f4c175d8b1c6476f69d63446ab9 Mon Sep 17 00:00:00 2001 From: Beast Date: Wed, 19 Aug 2026 20:17:44 +0800 Subject: [PATCH 25/38] feat: update v3 design tokens --- .../lib/components/connectivity_guard.dart | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/cold-wallet-app/lib/components/connectivity_guard.dart b/cold-wallet-app/lib/components/connectivity_guard.dart index 2a6eb273c..b5f4c0743 100644 --- a/cold-wallet-app/lib/components/connectivity_guard.dart +++ b/cold-wallet-app/lib/components/connectivity_guard.dart @@ -43,7 +43,7 @@ class _ConnectivityGuardState extends ConsumerState { return Positioned.fill( child: Material( - color: context.colors.background, + color: context.colorsV3.bgVoid, child: BaseBackground( child: SafeArea( child: Padding( @@ -57,30 +57,30 @@ class _ConnectivityGuardState extends ConsumerState { } Widget _lockContent(BuildContext context) { - final colors = context.colors; - final text = context.themeText; + final colors = context.colorsV3; + final text = context.themeTextV3; return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon(Icons.wifi_off_rounded, size: 72, color: colors.accentOrange), + Icon(Icons.wifi_off_rounded, size: 72, color: colors.semanticSand), const SizedBox(height: 32), Text( 'Network detected', - style: text.mediumTitle?.copyWith(color: colors.textPrimary), + style: text.titleScreen.copyWith(color: colors.textContent), textAlign: TextAlign.center, ), const SizedBox(height: 16), Text( 'This is a cold wallet and must stay offline. Turn on Airplane Mode and disable Wi-Fi, cellular, ' 'Bluetooth and any other connections to continue.', - style: text.paragraph?.copyWith(color: colors.textSecondary), + style: text.body.copyWith(color: colors.textMuted, height: 1.55), textAlign: TextAlign.center, ), const SizedBox(height: 32), Text( 'The signer will unlock automatically once the device is fully offline.', - style: text.detail?.copyWith(color: colors.textMuted), + style: text.caption.copyWith(color: colors.textMuted), textAlign: TextAlign.center, ), const SizedBox(height: 32), @@ -94,29 +94,30 @@ class _ConnectivityGuardState extends ConsumerState { } Widget _confirmContent(BuildContext context) { - final colors = context.colors; - final text = context.themeText; + final colors = context.colorsV3; + final text = context.themeTextV3; return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon(Icons.warning_amber_rounded, size: 72, color: colors.error), + Icon(Icons.warning_amber_rounded, size: 72, color: colors.semanticEmber), const SizedBox(height: 32), Text( 'Override network lock?', - style: text.mediumTitle?.copyWith(color: colors.textPrimary), + style: text.titleScreen.copyWith(color: colors.textContent), textAlign: TextAlign.center, ), const SizedBox(height: 16), Text( 'This device is connected to a network. A cold wallet is only safe while fully offline — override the ' 'lock for testing only, never with a wallet that holds real funds.', - style: text.paragraph?.copyWith(color: colors.textSecondary), + style: text.body.copyWith(color: colors.textMuted, height: 1.55), textAlign: TextAlign.center, ), const SizedBox(height: 40), QuantusButton.simple( label: 'Override — I accept the risk', + variant: ButtonVariant.danger, onTap: () { ref.read(coldSettingsProvider.notifier).setWifiOverrideEnabled(true); setState(() => _confirming = false); From 64f196877f65aaaf1295af5b0509a7799602a210 Mon Sep 17 00:00:00 2001 From: Beast Date: Wed, 19 Aug 2026 22:22:07 +0800 Subject: [PATCH 26/38] feat: update lock and password --- .../lib/components/lock_screen.dart | 12 +-- .../lib/components/password_field.dart | 80 +++++-------------- cold-wallet-app/test/lock_screen_test.dart | 66 +++++++++++++++ cold-wallet-app/test/password_field_test.dart | 54 +++++++++++++ .../src/ui/components/quantus_text_field.dart | 12 +++ .../test/ui/quantus_text_field_test.dart | 33 ++++++++ 6 files changed, 192 insertions(+), 65 deletions(-) create mode 100644 cold-wallet-app/test/lock_screen_test.dart create mode 100644 cold-wallet-app/test/password_field_test.dart diff --git a/cold-wallet-app/lib/components/lock_screen.dart b/cold-wallet-app/lib/components/lock_screen.dart index 4fbfb77bd..8d72d1203 100644 --- a/cold-wallet-app/lib/components/lock_screen.dart +++ b/cold-wallet-app/lib/components/lock_screen.dart @@ -50,8 +50,8 @@ class _LockScreenState extends ConsumerState { @override Widget build(BuildContext context) { - final colors = context.colors; - final text = context.themeText; + final colors = context.colorsV3; + final text = context.themeTextV3; final biometricEnabled = ref.watch(walletControllerProvider).biometricEnabled; return ScaffoldBase( @@ -59,11 +59,11 @@ class _LockScreenState extends ConsumerState { crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const Spacer(), - Icon(Icons.lock_outline_rounded, size: 64, color: colors.accentOrange), + Icon(Icons.lock_outline_rounded, size: 64, color: colors.accentFlare), const SizedBox(height: 24), Text( 'Cold Wallet Locked', - style: text.mediumTitle?.copyWith(color: colors.textPrimary), + style: text.titleScreen.copyWith(color: colors.textContent), textAlign: TextAlign.center, ), const SizedBox(height: 32), @@ -76,7 +76,7 @@ class _LockScreenState extends ConsumerState { const SizedBox(height: 12), Text( _error!, - style: text.detail?.copyWith(color: colors.error), + style: text.caption.copyWith(color: colors.semanticEmber), textAlign: TextAlign.center, ), ], @@ -86,7 +86,7 @@ class _LockScreenState extends ConsumerState { const SizedBox(height: 12), QuantusButton.simple( label: 'Use biometrics', - icon: Icon(Icons.fingerprint, color: colors.textPrimary, size: 18), + icon: Icon(Icons.fingerprint, color: colors.textContent, size: 18), iconPlacement: IconPlacement.leading, variant: ButtonVariant.secondary, onTap: _busy ? null : _unlockWithBiometric, diff --git a/cold-wallet-app/lib/components/password_field.dart b/cold-wallet-app/lib/components/password_field.dart index 1d0251708..72fdcd026 100644 --- a/cold-wallet-app/lib/components/password_field.dart +++ b/cold-wallet-app/lib/components/password_field.dart @@ -25,68 +25,30 @@ class PasswordField extends StatefulWidget { class _PasswordFieldState extends State { bool _obscured = true; - final _focusNode = FocusNode(); - - @override - void initState() { - super.initState(); - _focusNode.addListener(_onFocusChanged); - } - - void _onFocusChanged() => setState(() {}); - - @override - void dispose() { - _focusNode.removeListener(_onFocusChanged); - _focusNode.dispose(); - super.dispose(); - } @override Widget build(BuildContext context) { - final colors = context.colors; - final text = context.themeText; - final focused = _focusNode.hasFocus; - - return Container( - height: 56, - padding: const EdgeInsets.only(left: 16, right: 4), - decoration: BoxDecoration( - color: colors.surfaceDeep, - borderRadius: BorderRadius.circular(14), - border: Border.all(color: focused ? colors.accentOrange : colors.borderButton, width: 1), - ), - child: Row( - children: [ - Expanded( - child: TextField( - controller: widget.controller, - focusNode: _focusNode, - enabled: widget.enabled, - obscureText: _obscured, - autocorrect: false, - enableSuggestions: false, - textInputAction: - widget.textInputAction ?? (widget.onSubmitted != null ? TextInputAction.done : TextInputAction.next), - onChanged: widget.onChanged, - onSubmitted: widget.onSubmitted, - style: text.smallParagraph?.copyWith(color: colors.textPrimary), - decoration: InputDecoration(hintText: widget.hintText), - ), - ), - GestureDetector( - onTap: () => setState(() => _obscured = !_obscured), - behavior: HitTestBehavior.opaque, - child: Padding( - padding: const EdgeInsets.all(12), - child: Icon( - _obscured ? Icons.visibility_off_outlined : Icons.visibility_outlined, - size: 22, - color: focused ? colors.textSecondary : colors.textMuted, - ), - ), - ), - ], + final colors = context.colorsV3; + + return QuantusTextField( + controller: widget.controller, + hint: widget.hintText, + enabled: widget.enabled, + obscureText: _obscured, + autocorrect: false, + enableSuggestions: false, + textInputAction: + widget.textInputAction ?? (widget.onSubmitted != null ? TextInputAction.done : TextInputAction.next), + onChanged: widget.onChanged, + onSubmitted: widget.onSubmitted, + trailing: GestureDetector( + onTap: () => setState(() => _obscured = !_obscured), + behavior: HitTestBehavior.opaque, + child: Icon( + _obscured ? Icons.visibility_off_outlined : Icons.visibility_outlined, + size: 22, + color: colors.textMuted, + ), ), ); } diff --git a/cold-wallet-app/test/lock_screen_test.dart b/cold-wallet-app/test/lock_screen_test.dart new file mode 100644 index 000000000..11d250151 --- /dev/null +++ b/cold-wallet-app/test/lock_screen_test.dart @@ -0,0 +1,66 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:quantus_cold_wallet/components/lock_screen.dart'; +import 'package:quantus_cold_wallet/providers/wallet_providers.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +class _LockedController extends WalletController { + _LockedController({this.biometric = false}); + + final bool biometric; + + @override + WalletState build() => WalletState(status: WalletStatus.locked, biometricEnabled: biometric); + + @override + Future unlockWithPassword(String password) async => false; +} + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + const colors = AppColorsV3.dark(); + const text = AppTextThemeV3.standard(); + + Future pumpLockScreen(WidgetTester tester, {_LockedController? controller}) async { + FlutterSecureStorage.setMockInitialValues({}); + await tester.pumpWidget( + ProviderScope( + overrides: [if (controller != null) walletControllerProvider.overrideWith(() => controller)], + child: Builder( + builder: (context) => MaterialApp(theme: AppTheme.darkTheme(context), home: const LockScreen()), + ), + ), + ); + await tester.pump(); + } + + testWidgets('uses v3 lock icon, title, and error tokens', (tester) async { + await pumpLockScreen(tester, controller: _LockedController()); + + final icon = tester.widget(find.byIcon(Icons.lock_outline_rounded)); + expect(icon.color, colors.accentFlare); + + final title = tester.widget(find.text('Cold Wallet Locked')); + expect(title.style?.color, colors.textContent); + expect(title.style?.fontSize, text.titleScreen.fontSize); + expect(title.style?.fontWeight, text.titleScreen.fontWeight); + + await tester.tap(find.text('Unlock')); + await tester.pump(); + + final error = tester.widget(find.text('Incorrect password')); + expect(error.style?.color, colors.semanticEmber); + expect(error.style?.fontSize, text.caption.fontSize); + }); + + testWidgets('biometric button uses v3 content icon color', (tester) async { + await pumpLockScreen(tester, controller: _LockedController(biometric: true)); + + expect(find.text('Use biometrics'), findsOneWidget); + final icon = tester.widget(find.byIcon(Icons.fingerprint)); + expect(icon.color, colors.textContent); + }); +} diff --git a/cold-wallet-app/test/password_field_test.dart b/cold-wallet-app/test/password_field_test.dart new file mode 100644 index 000000000..bb7dd1362 --- /dev/null +++ b/cold-wallet-app/test/password_field_test.dart @@ -0,0 +1,54 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_cold_wallet/components/password_field.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + const colors = AppColorsV3.dark(); + + Future pumpField(WidgetTester tester, PasswordField field) async { + await tester.pumpWidget( + MediaQuery( + data: const MediaQueryData(size: Size(375, 667)), + child: Builder( + builder: (context) => MaterialApp( + theme: AppTheme.darkTheme(context), + home: Scaffold(body: field), + ), + ), + ), + ); + await tester.pump(); + } + + testWidgets('wraps QuantusTextField and starts obscured', (tester) async { + final controller = TextEditingController(text: 'secret'); + addTearDown(controller.dispose); + + await pumpField(tester, PasswordField(controller: controller, hintText: 'Password')); + + expect(find.byType(QuantusTextField), findsOneWidget); + final field = tester.widget(find.byType(TextField)); + expect(field.obscureText, isTrue); + expect(field.autocorrect, isFalse); + expect(field.enableSuggestions, isFalse); + expect(find.byIcon(Icons.visibility_off_outlined), findsOneWidget); + }); + + testWidgets('visibility toggle reveals the password', (tester) async { + final controller = TextEditingController(text: 'secret'); + addTearDown(controller.dispose); + + await pumpField(tester, PasswordField(controller: controller, hintText: 'Password')); + + await tester.tap(find.byIcon(Icons.visibility_off_outlined)); + await tester.pump(); + + final field = tester.widget(find.byType(TextField)); + expect(field.obscureText, isFalse); + expect(find.byIcon(Icons.visibility_outlined), findsOneWidget); + expect(tester.widget(find.byIcon(Icons.visibility_outlined)).color, colors.textMuted); + }); +} diff --git a/quantus_sdk/lib/src/ui/components/quantus_text_field.dart b/quantus_sdk/lib/src/ui/components/quantus_text_field.dart index dc2eebf4b..e6d0650fc 100644 --- a/quantus_sdk/lib/src/ui/components/quantus_text_field.dart +++ b/quantus_sdk/lib/src/ui/components/quantus_text_field.dart @@ -12,10 +12,14 @@ class QuantusTextField extends StatefulWidget { final FocusNode? focusNode; final ValueChanged? onChanged; final bool enabled; + final bool obscureText; + final bool enableSuggestions; final TextInputType? keyboardType; final TextInputAction? textInputAction; final TextCapitalization textCapitalization; final bool autocorrect; + final ValueChanged? onSubmitted; + final Widget? trailing; const QuantusTextField({ super.key, @@ -26,10 +30,14 @@ class QuantusTextField extends StatefulWidget { this.focusNode, this.onChanged, this.enabled = true, + this.obscureText = false, + this.enableSuggestions = true, this.keyboardType, this.textInputAction, this.textCapitalization = TextCapitalization.none, this.autocorrect = true, + this.onSubmitted, + this.trailing, }); @override @@ -114,11 +122,14 @@ class _QuantusTextFieldState extends State { controller: widget.controller, focusNode: _focusNode, enabled: widget.enabled, + obscureText: widget.obscureText, + enableSuggestions: widget.enableSuggestions, keyboardType: widget.keyboardType, textInputAction: widget.textInputAction, textCapitalization: widget.textCapitalization, autocorrect: widget.autocorrect, onChanged: widget.onChanged, + onSubmitted: widget.onSubmitted, cursorColor: colors.accentFlare, style: textStyle, decoration: InputDecoration.collapsed(hintText: widget.hint, hintStyle: hintStyle), @@ -128,6 +139,7 @@ class _QuantusTextFieldState extends State { const SizedBox(width: 8), _QuantusTextFieldClearButton(onTap: widget.controller.clear), ], + if (widget.trailing != null) ...[const SizedBox(width: 8), widget.trailing!], ], ), ), diff --git a/quantus_sdk/test/ui/quantus_text_field_test.dart b/quantus_sdk/test/ui/quantus_text_field_test.dart index 9de181218..d21895171 100644 --- a/quantus_sdk/test/ui/quantus_text_field_test.dart +++ b/quantus_sdk/test/ui/quantus_text_field_test.dart @@ -66,4 +66,37 @@ void main() { await tester.pump(); expect(focusNode.hasFocus, isTrue); }); + + testWidgets('obscureText and enableSuggestions are forwarded', (tester) async { + final controller = TextEditingController(text: 'secret'); + addTearDown(controller.dispose); + + await pumpField(tester, QuantusTextField(controller: controller, obscureText: true, enableSuggestions: false)); + + final field = tester.widget(find.byType(TextField)); + expect(field.obscureText, isTrue); + expect(field.enableSuggestions, isFalse); + }); + + testWidgets('onSubmitted fires on IME done', (tester) async { + final controller = TextEditingController(text: 'hello'); + addTearDown(controller.dispose); + String? submitted; + + await pumpField(tester, QuantusTextField(controller: controller, onSubmitted: (value) => submitted = value)); + + await tester.showKeyboard(find.byType(TextField)); + await tester.testTextInput.receiveAction(TextInputAction.done); + expect(submitted, 'hello'); + }); + + testWidgets('trailing widget is shown', (tester) async { + final controller = TextEditingController(); + addTearDown(controller.dispose); + + await pumpField(tester, QuantusTextField(controller: controller, trailing: const Icon(Icons.visibility_outlined))); + + expect(find.byIcon(Icons.visibility_outlined), findsOneWidget); + expect(find.byIcon(Icons.close), findsNothing); + }); } From eda1053ed5b7831209edb5787f51718dbb3260f5 Mon Sep 17 00:00:00 2001 From: Beast Date: Wed, 19 Aug 2026 23:00:37 +0800 Subject: [PATCH 27/38] feat: update design tokens 1st pass --- .../lib/screens/create_wallet_screen.dart | 6 +- .../lib/screens/import_wallet_screen.dart | 22 +++---- .../secure_element_warning_screen.dart | 36 +++++------ .../lib/screens/set_password_screen.dart | 22 +++---- .../lib/screens/welcome_screen.dart | 8 +-- .../test/create_wallet_screen_test.dart | 25 ++++++++ .../test/import_wallet_screen_test.dart | 60 +++++++++++++++++++ .../secure_element_warning_screen_test.dart | 32 ++++++++++ .../test/set_password_screen_test.dart | 41 +++++++++++++ cold-wallet-app/test/welcome_screen_test.dart | 34 +++++++++++ 10 files changed, 241 insertions(+), 45 deletions(-) create mode 100644 cold-wallet-app/test/create_wallet_screen_test.dart create mode 100644 cold-wallet-app/test/import_wallet_screen_test.dart create mode 100644 cold-wallet-app/test/secure_element_warning_screen_test.dart create mode 100644 cold-wallet-app/test/set_password_screen_test.dart create mode 100644 cold-wallet-app/test/welcome_screen_test.dart diff --git a/cold-wallet-app/lib/screens/create_wallet_screen.dart b/cold-wallet-app/lib/screens/create_wallet_screen.dart index 1cfce74b0..420cc4f5d 100644 --- a/cold-wallet-app/lib/screens/create_wallet_screen.dart +++ b/cold-wallet-app/lib/screens/create_wallet_screen.dart @@ -32,8 +32,8 @@ class _CreateWalletScreenState extends State { @override Widget build(BuildContext context) { - final colors = context.colors; - final text = context.themeText; + final colors = context.colorsV3; + final text = context.themeTextV3; final words = _words; return ScaffoldBase( @@ -46,7 +46,7 @@ class _CreateWalletScreenState extends State { Text( 'Write these words down in order and keep them offline. Anyone with this phrase controls your funds. ' 'It is never shown again and cannot be copied from this device.', - style: text.smallParagraph?.copyWith(color: colors.textTertiary), + style: text.body.copyWith(color: colors.textMuted), ), const SizedBox(height: 24), Expanded( diff --git a/cold-wallet-app/lib/screens/import_wallet_screen.dart b/cold-wallet-app/lib/screens/import_wallet_screen.dart index e52b645cb..39414c959 100644 --- a/cold-wallet-app/lib/screens/import_wallet_screen.dart +++ b/cold-wallet-app/lib/screens/import_wallet_screen.dart @@ -85,9 +85,10 @@ class _ImportWalletScreenState extends State { @override Widget build(BuildContext context) { - final colors = context.colors; - final text = context.themeText; - final fieldTextStyle = text.smallTitle?.copyWith(color: colors.checksum, fontWeight: FontWeight.w400); + final colors = context.colorsV3; + final text = context.themeTextV3; + final fieldTextStyle = text.dataAddressLarge.copyWith(color: colors.textContent); + final hintStyle = text.dataAddressLarge.copyWith(color: colors.textMuted); return ScaffoldBase( appBar: const V2AppBar(title: 'Import Wallet'), @@ -99,16 +100,16 @@ class _ImportWalletScreenState extends State { children: [ Text( 'Restore an existing wallet with your 12 or 24 words recovery phrase', - style: text.smallParagraph?.copyWith(color: colors.textSecondary), + style: text.body.copyWith(color: colors.textMuted), ), const SizedBox(height: 16), Container( height: 202, padding: const EdgeInsets.all(16), decoration: BoxDecoration( - color: colors.surfaceDeep, - borderRadius: BorderRadius.circular(14), - border: Border.all(color: colors.borderButton, width: 1), + color: colors.bgSurface, + borderRadius: context.radiusV3.mdBorder, + border: Border.all(color: colors.borderHairline, width: 1), ), child: Stack( children: [ @@ -118,10 +119,11 @@ class _ImportWalletScreenState extends State { controller: _controller, focusNode: _focusNode, onChanged: (_) => setState(() {}), + cursorColor: colors.accentFlare, style: fieldTextStyle, decoration: InputDecoration.collapsed( hintText: 'Type in or paste your recovery phrase. Separate words with spaces.', - hintStyle: fieldTextStyle?.copyWith(color: colors.textSecondary), + hintStyle: hintStyle, ), maxLines: null, keyboardType: TextInputType.multiline, @@ -139,7 +141,7 @@ class _ImportWalletScreenState extends State { child: Icon( _controller.obscured ? Icons.visibility_off_outlined : Icons.visibility_outlined, size: 22, - color: colors.textSecondary, + color: colors.textMuted, ), ), ), @@ -150,7 +152,7 @@ class _ImportWalletScreenState extends State { const SizedBox(height: 16), Text( _error!, - style: text.detail?.copyWith(color: colors.error), + style: text.caption.copyWith(color: colors.semanticEmber), textAlign: TextAlign.center, ), ], diff --git a/cold-wallet-app/lib/screens/secure_element_warning_screen.dart b/cold-wallet-app/lib/screens/secure_element_warning_screen.dart index 84d7b965d..9e8679405 100644 --- a/cold-wallet-app/lib/screens/secure_element_warning_screen.dart +++ b/cold-wallet-app/lib/screens/secure_element_warning_screen.dart @@ -9,26 +9,28 @@ class SecureElementWarningScreen extends StatelessWidget { @override Widget build(BuildContext context) { - final colors = context.colors; - final text = context.themeText; + final colors = context.colorsV3; + final text = context.themeTextV3; return ScaffoldBase( appBar: const V2AppBar(title: 'Security warning', leading: SizedBox(width: 24)), - mainContent: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - const SizedBox(height: 20), - Icon(Icons.warning_amber_rounded, size: 64, color: colors.accentOrange), - const SizedBox(height: 24), - Text('No secure element detected', style: text.mediumTitle?.copyWith(color: colors.textPrimary)), - const SizedBox(height: 16), - Text( - 'This device has no biometrics or device lock configured, so your wallet key cannot be stored in a ' - 'hardware-backed secure element. Your encrypted key will be protected only by your password.\n\n' - 'For a cold wallet we strongly recommend a device with a secure element and a device lock.', - style: text.paragraph?.copyWith(color: colors.textSecondary), - ), - ], + mainContent: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const SizedBox(height: 20), + Icon(Icons.warning_amber_rounded, size: 64, color: colors.semanticSand), + const SizedBox(height: 24), + Text('No secure element detected', style: text.titleScreen.copyWith(color: colors.textContent)), + const SizedBox(height: 16), + Text( + 'This device has no biometrics or device lock configured, so your wallet key cannot be stored in a ' + 'hardware-backed secure element. Your encrypted key will be protected only by your password.\n\n' + 'For a cold wallet we strongly recommend a device with a secure element and a device lock.', + style: text.body.copyWith(color: colors.textMuted), + ), + ], + ), ), bottomContent: ScaffoldBaseBottomContent( child: Column( diff --git a/cold-wallet-app/lib/screens/set_password_screen.dart b/cold-wallet-app/lib/screens/set_password_screen.dart index 090ad939a..0038ae04e 100644 --- a/cold-wallet-app/lib/screens/set_password_screen.dart +++ b/cold-wallet-app/lib/screens/set_password_screen.dart @@ -74,8 +74,8 @@ class _SetPasswordScreenState extends ConsumerState { @override Widget build(BuildContext context) { - final colors = context.colors; - final text = context.themeText; + final colors = context.colorsV3; + final text = context.themeTextV3; return ScaffoldBase( appBar: const V2AppBar(title: 'Set password'), @@ -85,7 +85,7 @@ class _SetPasswordScreenState extends ConsumerState { children: [ Text( 'Your password encrypts the wallet key stored on this device. There is no recovery if you forget it.', - style: text.smallParagraph?.copyWith(color: colors.textTertiary), + style: text.body.copyWith(color: colors.textMuted), ), const SizedBox(height: 24), PasswordField(controller: _password, hintText: 'Password'), @@ -94,7 +94,7 @@ class _SetPasswordScreenState extends ConsumerState { if (_biometricAvailable) ...[const SizedBox(height: 24), _biometricToggle(colors, text)], if (_error != null) ...[ const SizedBox(height: 16), - Text(_error!, style: text.detail?.copyWith(color: colors.error)), + Text(_error!, style: text.caption.copyWith(color: colors.semanticEmber)), ], ], ), @@ -105,24 +105,24 @@ class _SetPasswordScreenState extends ConsumerState { ); } - Widget _biometricToggle(AppColorsV2 colors, AppTextTheme text) { + Widget _biometricToggle(AppColorsV3 colors, AppTextThemeV3 text) { return Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), decoration: BoxDecoration( - color: colors.surfaceDeep, - borderRadius: BorderRadius.circular(14), - border: Border.all(color: colors.borderButton, width: 1), + color: colors.bgSurface, + borderRadius: context.radiusV3.mdBorder, + border: Border.all(color: colors.borderHairline, width: 1), ), child: Row( children: [ - Icon(Icons.fingerprint, color: colors.textPrimary, size: 20), + Icon(Icons.fingerprint, color: colors.textContent, size: 20), const SizedBox(width: 12), Expanded( - child: Text('Enable biometric unlock', style: text.smallParagraph?.copyWith(color: colors.textPrimary)), + child: Text('Enable biometric unlock', style: text.body.copyWith(color: colors.textContent)), ), Switch( value: _enableBiometric, - activeThumbColor: colors.accentOrange, + activeTrackColor: colors.accentFlare, onChanged: (v) => setState(() => _enableBiometric = v), ), ], diff --git a/cold-wallet-app/lib/screens/welcome_screen.dart b/cold-wallet-app/lib/screens/welcome_screen.dart index e416d69af..be323e58e 100644 --- a/cold-wallet-app/lib/screens/welcome_screen.dart +++ b/cold-wallet-app/lib/screens/welcome_screen.dart @@ -28,8 +28,8 @@ class WelcomeScreen extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final colors = context.colors; - final text = context.themeText; + final colors = context.colorsV3; + final text = context.themeTextV3; return ScaffoldBase( mainContent: Column( @@ -40,13 +40,13 @@ class WelcomeScreen extends ConsumerWidget { const SizedBox(height: 32), Text( 'Quantus Cold Wallet', - style: text.largeTitle?.copyWith(color: colors.textPrimary), + style: text.titleHero.copyWith(color: colors.textContent), textAlign: TextAlign.center, ), const SizedBox(height: 12), Text( 'An air-gapped signer for the Quantus network. This device never touches the internet.', - style: text.paragraph?.copyWith(color: colors.textSecondary), + style: text.body.copyWith(color: colors.textMuted), textAlign: TextAlign.center, ), const Spacer(flex: 3), diff --git a/cold-wallet-app/test/create_wallet_screen_test.dart b/cold-wallet-app/test/create_wallet_screen_test.dart new file mode 100644 index 000000000..31b185666 --- /dev/null +++ b/cold-wallet-app/test/create_wallet_screen_test.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:quantus_cold_wallet/screens/create_wallet_screen.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + const colors = AppColorsV3.dark(); + const text = AppTextThemeV3.standard(); + + testWidgets('uses v3 body tokens for recovery-phrase instructions', (tester) async { + await tester.pumpWidget( + Builder( + builder: (context) => MaterialApp(theme: AppTheme.darkTheme(context), home: const CreateWalletScreen()), + ), + ); + await tester.pump(); + await tester.pump(const Duration(milliseconds: 50)); + + final body = tester.widget(find.textContaining('Write these words down in order')); + expect(body.style?.color, colors.textMuted); + expect(body.style?.fontSize, text.body.fontSize); + }); +} diff --git a/cold-wallet-app/test/import_wallet_screen_test.dart b/cold-wallet-app/test/import_wallet_screen_test.dart new file mode 100644 index 000000000..82e9bdb0a --- /dev/null +++ b/cold-wallet-app/test/import_wallet_screen_test.dart @@ -0,0 +1,60 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:quantus_cold_wallet/screens/import_wallet_screen.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + const colors = AppColorsV3.dark(); + const text = AppTextThemeV3.standard(); + const radius = AppRadiusV3.standard(); + + Future pumpScreen(WidgetTester tester) async { + await tester.pumpWidget( + Builder( + builder: (context) => MaterialApp(theme: AppTheme.darkTheme(context), home: const ImportWalletScreen()), + ), + ); + await tester.pump(); + } + + testWidgets('uses v3 helper, field, and surface tokens', (tester) async { + await pumpScreen(tester); + + final helper = tester.widget(find.textContaining('Restore an existing wallet')); + expect(helper.style?.color, colors.textMuted); + expect(helper.style?.fontSize, text.body.fontSize); + + final field = tester.widget(find.byType(TextField)); + expect(field.style?.color, colors.textContent); + expect(field.style?.fontSize, text.dataAddressLarge.fontSize); + expect(field.cursorColor, colors.accentFlare); + expect(field.decoration?.hintStyle?.color, colors.textMuted); + + final fieldBox = tester + .widgetList(find.byType(Container)) + .map((c) => c.decoration) + .whereType() + .firstWhere((d) => d.color == colors.bgSurface); + expect(fieldBox.borderRadius, radius.mdBorder); + expect((fieldBox.border as Border?)?.top.color, colors.borderHairline); + + final eye = tester.widget(find.byIcon(Icons.visibility_off_outlined)); + expect(eye.color, colors.textMuted); + }); + + testWidgets('uses v3 ember caption for validation errors', (tester) async { + await pumpScreen(tester); + + await tester.enterText(find.byType(TextField), 'one two three'); + await tester.pump(); + await tester.tap(find.text('Import')); + await tester.pump(); + await tester.pump(const Duration(milliseconds: 400)); + + final error = tester.widget(find.text('Recovery phrase must be 12 or 24 words')); + expect(error.style?.color, colors.semanticEmber); + expect(error.style?.fontSize, text.caption.fontSize); + }); +} diff --git a/cold-wallet-app/test/secure_element_warning_screen_test.dart b/cold-wallet-app/test/secure_element_warning_screen_test.dart new file mode 100644 index 000000000..7762455cf --- /dev/null +++ b/cold-wallet-app/test/secure_element_warning_screen_test.dart @@ -0,0 +1,32 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:quantus_cold_wallet/screens/secure_element_warning_screen.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + const colors = AppColorsV3.dark(); + const text = AppTextThemeV3.standard(); + + testWidgets('uses v3 warning icon, title, and body tokens', (tester) async { + await tester.pumpWidget( + Builder( + builder: (context) => MaterialApp(theme: AppTheme.darkTheme(context), home: const SecureElementWarningScreen()), + ), + ); + await tester.pump(); + + final icon = tester.widget(find.byIcon(Icons.warning_amber_rounded)); + expect(icon.color, colors.semanticSand); + + final title = tester.widget(find.text('No secure element detected')); + expect(title.style?.color, colors.textContent); + expect(title.style?.fontSize, text.titleScreen.fontSize); + expect(title.style?.fontWeight, text.titleScreen.fontWeight); + + final body = tester.widget(find.textContaining('This device has no biometrics')); + expect(body.style?.color, colors.textMuted); + expect(body.style?.fontSize, text.body.fontSize); + }); +} diff --git a/cold-wallet-app/test/set_password_screen_test.dart b/cold-wallet-app/test/set_password_screen_test.dart new file mode 100644 index 000000000..0e2369315 --- /dev/null +++ b/cold-wallet-app/test/set_password_screen_test.dart @@ -0,0 +1,41 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:quantus_cold_wallet/screens/set_password_screen.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + const colors = AppColorsV3.dark(); + const text = AppTextThemeV3.standard(); + + testWidgets('uses v3 body and ember error tokens', (tester) async { + FlutterSecureStorage.setMockInitialValues({}); + await tester.pumpWidget( + ProviderScope( + child: Builder( + builder: (context) => MaterialApp( + theme: AppTheme.darkTheme(context), + home: const SetPasswordScreen(mnemonic: 'test mnemonic'), + ), + ), + ), + ); + await tester.pump(); + + final body = tester.widget(find.textContaining('Your password encrypts the wallet key')); + expect(body.style?.color, colors.textMuted); + expect(body.style?.fontSize, text.body.fontSize); + + await tester.enterText(find.byType(TextField).at(0), 'alpha'); + await tester.enterText(find.byType(TextField).at(1), 'beta'); + await tester.tap(find.text('Create wallet')); + await tester.pump(); + + final error = tester.widget(find.text('Passwords do not match')); + expect(error.style?.color, colors.semanticEmber); + expect(error.style?.fontSize, text.caption.fontSize); + }); +} diff --git a/cold-wallet-app/test/welcome_screen_test.dart b/cold-wallet-app/test/welcome_screen_test.dart new file mode 100644 index 000000000..d8da93069 --- /dev/null +++ b/cold-wallet-app/test/welcome_screen_test.dart @@ -0,0 +1,34 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:quantus_cold_wallet/screens/welcome_screen.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + const colors = AppColorsV3.dark(); + const text = AppTextThemeV3.standard(); + + testWidgets('uses v3 hero title and muted body tokens', (tester) async { + FlutterSecureStorage.setMockInitialValues({}); + await tester.pumpWidget( + ProviderScope( + child: Builder( + builder: (context) => MaterialApp(theme: AppTheme.darkTheme(context), home: const WelcomeScreen()), + ), + ), + ); + await tester.pump(); + + final title = tester.widget(find.text('Quantus Cold Wallet')); + expect(title.style?.color, colors.textContent); + expect(title.style?.fontSize, text.titleHero.fontSize); + expect(title.style?.fontWeight, text.titleHero.fontWeight); + + final body = tester.widget(find.textContaining('An air-gapped signer')); + expect(body.style?.color, colors.textMuted); + expect(body.style?.fontSize, text.body.fontSize); + }); +} From 2c79a3dbabe5d33c8c0d06f0810bb97f8417643f Mon Sep 17 00:00:00 2001 From: Beast Date: Wed, 19 Aug 2026 23:10:54 +0800 Subject: [PATCH 28/38] feat: update design tokens 2nd pass --- cold-wallet-app/lib/screens/root_gate.dart | 10 ++--- cold-wallet-app/test/root_gate_test.dart | 44 ++++++++++++++++++++++ 2 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 cold-wallet-app/test/root_gate_test.dart diff --git a/cold-wallet-app/lib/screens/root_gate.dart b/cold-wallet-app/lib/screens/root_gate.dart index 1ff54ecff..5b4bae9f0 100644 --- a/cold-wallet-app/lib/screens/root_gate.dart +++ b/cold-wallet-app/lib/screens/root_gate.dart @@ -37,8 +37,8 @@ class _InitError extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final colors = context.colors; - final text = context.themeText; + final colors = context.colorsV3; + final text = context.themeTextV3; return Scaffold( body: BaseBackground( child: SafeArea( @@ -47,17 +47,17 @@ class _InitError extends ConsumerWidget { child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon(Icons.error_outline, size: 64, color: colors.error), + Icon(Icons.error_outline, size: 64, color: colors.semanticEmber), const SizedBox(height: 24), Text( 'Storage error', - style: text.mediumTitle?.copyWith(color: colors.textPrimary), + style: text.titleScreen.copyWith(color: colors.textContent), textAlign: TextAlign.center, ), const SizedBox(height: 12), Text( message, - style: text.smallParagraph?.copyWith(color: colors.textSecondary), + style: text.body.copyWith(color: colors.textMuted), textAlign: TextAlign.center, ), const SizedBox(height: 32), diff --git a/cold-wallet-app/test/root_gate_test.dart b/cold-wallet-app/test/root_gate_test.dart new file mode 100644 index 000000000..da596f1cc --- /dev/null +++ b/cold-wallet-app/test/root_gate_test.dart @@ -0,0 +1,44 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:quantus_cold_wallet/providers/wallet_providers.dart'; +import 'package:quantus_cold_wallet/screens/root_gate.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +class _InitErrorController extends WalletController { + @override + WalletState build() => const WalletState(status: WalletStatus.initializing, error: 'Could not read secure storage.'); +} + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + const colors = AppColorsV3.dark(); + const text = AppTextThemeV3.standard(); + + testWidgets('init error uses v3 ember icon, title, and muted body tokens', (tester) async { + FlutterSecureStorage.setMockInitialValues({}); + await tester.pumpWidget( + ProviderScope( + overrides: [walletControllerProvider.overrideWith(_InitErrorController.new)], + child: Builder( + builder: (context) => MaterialApp(theme: AppTheme.darkTheme(context), home: const RootGate()), + ), + ), + ); + await tester.pump(); + + final icon = tester.widget(find.byIcon(Icons.error_outline)); + expect(icon.color, colors.semanticEmber); + + final title = tester.widget(find.text('Storage error')); + expect(title.style?.color, colors.textContent); + expect(title.style?.fontSize, text.titleScreen.fontSize); + expect(title.style?.fontWeight, text.titleScreen.fontWeight); + + final body = tester.widget(find.text('Could not read secure storage.')); + expect(body.style?.color, colors.textMuted); + expect(body.style?.fontSize, text.body.fontSize); + }); +} From a2f07893b01d26bcdc4dcd6ffdfc9a0e2efc403b Mon Sep 17 00:00:00 2001 From: Beast Date: Wed, 19 Aug 2026 23:47:36 +0800 Subject: [PATCH 29/38] feat: update design tokens 3rd pass --- cold-wallet-app/lib/screens/home_screen.dart | 30 ++++----- .../lib/screens/settings_screen.dart | 30 ++++----- .../lib/screens/show_key_screen.dart | 15 ++--- cold-wallet-app/test/home_screen_test.dart | 61 +++++++++++++++++++ .../test/settings_screen_test.dart | 59 ++++++++++++++++++ .../test/show_key_screen_test.dart | 55 +++++++++++++++++ 6 files changed, 211 insertions(+), 39 deletions(-) create mode 100644 cold-wallet-app/test/home_screen_test.dart create mode 100644 cold-wallet-app/test/settings_screen_test.dart create mode 100644 cold-wallet-app/test/show_key_screen_test.dart diff --git a/cold-wallet-app/lib/screens/home_screen.dart b/cold-wallet-app/lib/screens/home_screen.dart index 3b8ae24a1..dad2e46ec 100644 --- a/cold-wallet-app/lib/screens/home_screen.dart +++ b/cold-wallet-app/lib/screens/home_screen.dart @@ -13,19 +13,19 @@ class HomeScreen extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final colors = context.colors; - final text = context.themeText; + final colors = context.colorsV3; + final text = context.themeTextV3; return ScaffoldBase( appBar: V2AppBar( title: 'Quantus Cold Wallet', leading: GestureDetector( onTap: () => ref.read(walletControllerProvider.notifier).lock(), - child: Icon(Icons.lock_outline, color: colors.textPrimary, size: 22), + child: Icon(Icons.lock_outline, color: colors.textContent, size: 22), ), trailing: GestureDetector( onTap: () => Navigator.push(context, MaterialPageRoute(builder: (_) => const SettingsScreen())), - child: Icon(Icons.settings_outlined, color: colors.textPrimary, size: 22), + child: Icon(Icons.settings_outlined, color: colors.textContent, size: 22), ), ), mainContent: Column( @@ -34,7 +34,7 @@ class HomeScreen extends ConsumerWidget { const SizedBox(height: 8), Text( 'Choose an action. This signer stays offline at all times.', - style: text.smallParagraph?.copyWith(color: colors.textSecondary), + style: text.body.copyWith(color: colors.textMuted), textAlign: TextAlign.center, ), const SizedBox(height: 32), @@ -61,7 +61,7 @@ class HomeScreen extends ConsumerWidget { : ScaffoldBaseBottomContent( child: QuantusButton.simple( label: 'Online — tap to re-lock', - icon: Icon(Icons.wifi_rounded, size: 18, color: colors.textPrimary), + icon: Icon(Icons.wifi_rounded, size: 18, color: colors.textContent), iconPlacement: IconPlacement.leading, variant: ButtonVariant.danger, onTap: () => ref.read(coldSettingsProvider.notifier).setWifiOverrideEnabled(false), @@ -77,33 +77,33 @@ class HomeScreen extends ConsumerWidget { required String subtitle, required VoidCallback onTap, }) { - final colors = context.colors; - final text = context.themeText; + final colors = context.colorsV3; + final text = context.themeTextV3; return GestureDetector( onTap: onTap, child: Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( - color: colors.surfaceDeep, - borderRadius: BorderRadius.circular(16), - border: Border.all(color: colors.borderButton, width: 1), + color: colors.bgSurface, + borderRadius: context.radiusV3.mdBorder, + border: Border.all(color: colors.borderHairline, width: 1), ), child: Row( children: [ Container( width: 52, height: 52, - decoration: BoxDecoration(color: colors.surface, borderRadius: BorderRadius.circular(12)), - child: Icon(icon, color: colors.accentOrange, size: 28), + decoration: BoxDecoration(color: colors.bgSurface2, borderRadius: context.radiusV3.smBorder), + child: Icon(icon, color: colors.accentFlare, size: 28), ), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(title, style: text.smallTitle?.copyWith(color: colors.textPrimary)), + Text(title, style: text.headingRow.copyWith(color: colors.textContent)), const SizedBox(height: 4), - Text(subtitle, style: text.detail?.copyWith(color: colors.textSecondary)), + Text(subtitle, style: text.caption.copyWith(color: colors.textMuted)), ], ), ), diff --git a/cold-wallet-app/lib/screens/settings_screen.dart b/cold-wallet-app/lib/screens/settings_screen.dart index cb443c127..a1cafd2c1 100644 --- a/cold-wallet-app/lib/screens/settings_screen.dart +++ b/cold-wallet-app/lib/screens/settings_screen.dart @@ -41,8 +41,8 @@ class SettingsScreen extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final colors = context.colors; - final text = context.themeText; + final colors = context.colorsV3; + final text = context.themeTextV3; final settings = ref.watch(coldSettingsProvider); return ScaffoldBase( @@ -52,7 +52,7 @@ class SettingsScreen extends ConsumerWidget { crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const SizedBox(height: 8), - Text('SECURITY', style: text.transactionDetailRowLabel?.copyWith(color: colors.textLabel)), + Text('SECURITY', style: text.labelMonogram.copyWith(color: colors.textMuted)), const SizedBox(height: 8), GestureDetector( onTap: () => showChangePasswordSheet(context), @@ -63,11 +63,11 @@ class SettingsScreen extends ConsumerWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('Change password', style: text.smallParagraph?.copyWith(color: colors.textPrimary)), + Text('Change password', style: text.body.copyWith(color: colors.textContent)), const SizedBox(height: 4), Text( 'Set or change the password that encrypts the wallet key on this device.', - style: text.detail?.copyWith(color: colors.textSecondary), + style: text.caption.copyWith(color: colors.textMuted), ), ], ), @@ -94,13 +94,13 @@ class SettingsScreen extends ConsumerWidget { children: [ Text( 'Wi-Fi Lock Override (debugging only)', - style: text.smallParagraph?.copyWith(color: colors.textPrimary), + style: text.body.copyWith(color: colors.textContent), ), const SizedBox(height: 4), Text( 'For debugging only — disables the network lock so the signer can be used while online. ' 'Not safe: never use this with a wallet that holds real funds.', - style: text.detail?.copyWith(color: colors.textSecondary), + style: text.caption.copyWith(color: colors.textMuted), ), ], ), @@ -108,26 +108,26 @@ class SettingsScreen extends ConsumerWidget { const SizedBox(width: 16), Switch( value: settings.wifiOverrideEnabled, - activeTrackColor: colors.accentOrange, + activeTrackColor: colors.accentFlare, onChanged: (v) => _setWifiOverride(context, ref, v), ), ], ), const SizedBox(height: 24), - Divider(color: colors.borderButton), + Divider(color: colors.borderHairline), const SizedBox(height: 16), - Text('SIGNATURE QR', style: text.transactionDetailRowLabel?.copyWith(color: colors.textLabel)), + Text('SIGNATURE QR', style: text.labelMonogram.copyWith(color: colors.textMuted)), const SizedBox(height: 8), Text( 'How the animated signature QR is displayed. Higher values transfer faster but are harder to scan.', - style: text.detail?.copyWith(color: colors.textSecondary), + style: text.caption.copyWith(color: colors.textMuted), ), const SizedBox(height: 16), const QrTuningControls(), const SizedBox(height: 24), - Divider(color: colors.borderButton), + Divider(color: colors.borderHairline), const SizedBox(height: 16), - Text('DANGER ZONE', style: text.transactionDetailRowLabel?.copyWith(color: colors.textLabel)), + Text('DANGER ZONE', style: text.labelMonogram.copyWith(color: colors.textMuted)), const SizedBox(height: 8), GestureDetector( onTap: () => _confirmReset(context, ref), @@ -138,11 +138,11 @@ class SettingsScreen extends ConsumerWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('Reset wallet', style: text.smallParagraph?.copyWith(color: colors.error)), + Text('Reset wallet', style: text.body.copyWith(color: colors.semanticEmber)), const SizedBox(height: 4), Text( 'Erase the encrypted key from this device.', - style: text.detail?.copyWith(color: colors.textSecondary), + style: text.caption.copyWith(color: colors.textMuted), ), ], ), diff --git a/cold-wallet-app/lib/screens/show_key_screen.dart b/cold-wallet-app/lib/screens/show_key_screen.dart index 6af1cb1fa..94bd3be7f 100644 --- a/cold-wallet-app/lib/screens/show_key_screen.dart +++ b/cold-wallet-app/lib/screens/show_key_screen.dart @@ -8,8 +8,8 @@ class ShowKeyScreen extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final colors = context.colors; - final text = context.themeText; + final colors = context.colorsV3; + final text = context.themeTextV3; final address = ref.watch(addressProvider); final checkphrase = ref.watch(checkphraseProvider); @@ -24,7 +24,7 @@ class ShowKeyScreen extends ConsumerWidget { const SizedBox(height: 8), Text( 'Scan with your Quantus hot wallet to add this account.', - style: text.smallParagraph?.copyWith(color: colors.textSecondary), + style: text.body.copyWith(color: colors.textMuted), textAlign: TextAlign.center, ), const SizedBox(height: 24), @@ -33,7 +33,7 @@ class ShowKeyScreen extends ConsumerWidget { checkphrase.when( data: (phrase) => Text( phrase, - style: text.smallTitle?.copyWith(color: colors.checksum), + style: text.headingRow.copyWith(color: colors.semanticLilac), textAlign: TextAlign.center, ), loading: () => const Loader(size: 16), @@ -42,13 +42,10 @@ class ShowKeyScreen extends ConsumerWidget { const SizedBox(height: 16), Container( padding: const EdgeInsets.all(16), - decoration: BoxDecoration(color: colors.surfaceDeep, borderRadius: BorderRadius.circular(14)), + decoration: BoxDecoration(color: colors.bgSurface, borderRadius: context.radiusV3.mdBorder), child: Text( address, - style: text.detail?.copyWith( - color: colors.textPrimary, - fontFamily: AppTextTheme.fontFamilySecondary, - ), + style: text.dataAddressLarge.copyWith(color: colors.textContent), textAlign: TextAlign.center, ), ), diff --git a/cold-wallet-app/test/home_screen_test.dart b/cold-wallet-app/test/home_screen_test.dart new file mode 100644 index 000000000..5e9ef66a9 --- /dev/null +++ b/cold-wallet-app/test/home_screen_test.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:quantus_cold_wallet/providers/connectivity_provider.dart'; +import 'package:quantus_cold_wallet/screens/home_screen.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + const colors = AppColorsV3.dark(); + const text = AppTextThemeV3.standard(); + const radius = AppRadiusV3.standard(); + + Future pumpHome(WidgetTester tester) async { + FlutterSecureStorage.setMockInitialValues({}); + SharedPreferences.setMockInitialValues({}); + await tester.pumpWidget( + ProviderScope( + overrides: [isOnlineProvider.overrideWith((ref) => false)], + child: Builder( + builder: (context) => MaterialApp(theme: AppTheme.darkTheme(context), home: const HomeScreen()), + ), + ), + ); + await tester.pump(); + } + + testWidgets('uses v3 intro, card, and icon tokens', (tester) async { + await pumpHome(tester); + + final intro = tester.widget(find.textContaining('Choose an action')); + expect(intro.style?.color, colors.textMuted); + expect(intro.style?.fontSize, text.body.fontSize); + + final title = tester.widget(find.text('Show Key')); + expect(title.style?.color, colors.textContent); + expect(title.style?.fontSize, text.headingRow.fontSize); + expect(title.style?.fontWeight, text.headingRow.fontWeight); + + final subtitle = tester.widget(find.textContaining('Display your public address')); + expect(subtitle.style?.color, colors.textMuted); + expect(subtitle.style?.fontSize, text.caption.fontSize); + + final actionIcon = tester.widget(find.byIcon(Icons.qr_code_2_rounded)); + expect(actionIcon.color, colors.accentFlare); + + final card = tester.widget( + find.ancestor(of: find.text('Show Key'), matching: find.byType(Container)).first, + ); + final decoration = card.decoration! as BoxDecoration; + expect(decoration.color, colors.bgSurface); + expect(decoration.borderRadius, radius.mdBorder); + expect((decoration.border as Border?)?.top.color, colors.borderHairline); + + expect(tester.widget(find.byIcon(Icons.lock_outline)).color, colors.textContent); + expect(tester.widget(find.byIcon(Icons.settings_outlined)).color, colors.textContent); + }); +} diff --git a/cold-wallet-app/test/settings_screen_test.dart b/cold-wallet-app/test/settings_screen_test.dart new file mode 100644 index 000000000..c57c45b17 --- /dev/null +++ b/cold-wallet-app/test/settings_screen_test.dart @@ -0,0 +1,59 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:quantus_cold_wallet/screens/settings_screen.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + const colors = AppColorsV3.dark(); + const text = AppTextThemeV3.standard(); + + Future pumpSettings(WidgetTester tester) async { + FlutterSecureStorage.setMockInitialValues({}); + SharedPreferences.setMockInitialValues({}); + await tester.pumpWidget( + ProviderScope( + child: Builder( + builder: (context) => MaterialApp(theme: AppTheme.darkTheme(context), home: const SettingsScreen()), + ), + ), + ); + await tester.pump(); + } + + testWidgets('uses v3 section, row, divider, and switch tokens', (tester) async { + await pumpSettings(tester); + + for (final label in ['SECURITY', 'SIGNATURE QR', 'DANGER ZONE']) { + final widget = tester.widget(find.text(label)); + expect(widget.style?.color, colors.textMuted); + expect(widget.style?.fontSize, text.labelMonogram.fontSize); + expect(widget.style?.fontFamily, text.labelMonogram.fontFamily); + } + + final rowTitle = tester.widget(find.text('Change password')); + expect(rowTitle.style?.color, colors.textContent); + expect(rowTitle.style?.fontSize, text.body.fontSize); + + final helper = tester.widget(find.textContaining('Set or change the password')); + expect(helper.style?.color, colors.textMuted); + expect(helper.style?.fontSize, text.caption.fontSize); + + final reset = tester.widget(find.text('Reset wallet')); + expect(reset.style?.color, colors.semanticEmber); + expect(reset.style?.fontSize, text.body.fontSize); + + final dividers = tester.widgetList(find.byType(Divider)); + expect(dividers, isNotEmpty); + for (final divider in dividers) { + expect(divider.color, colors.borderHairline); + } + + final wifiSwitch = tester.widget(find.byType(Switch)); + expect(wifiSwitch.activeTrackColor, colors.accentFlare); + }); +} diff --git a/cold-wallet-app/test/show_key_screen_test.dart b/cold-wallet-app/test/show_key_screen_test.dart new file mode 100644 index 000000000..cffd9c451 --- /dev/null +++ b/cold-wallet-app/test/show_key_screen_test.dart @@ -0,0 +1,55 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:quantus_cold_wallet/providers/wallet_providers.dart'; +import 'package:quantus_cold_wallet/screens/show_key_screen.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + const colors = AppColorsV3.dark(); + const text = AppTextThemeV3.standard(); + const radius = AppRadiusV3.standard(); + const address = '5FakeSs58AddressForTests'; + const checkphrase = 'amber glacier quartz'; + + Future pumpShowKey(WidgetTester tester) async { + await tester.pumpWidget( + ProviderScope( + overrides: [ + addressProvider.overrideWith((ref) => address), + checkphraseProvider.overrideWith((ref) async => checkphrase), + ], + child: Builder( + builder: (context) => MaterialApp(theme: AppTheme.darkTheme(context), home: const ShowKeyScreen()), + ), + ), + ); + await tester.pump(); + await tester.pump(); + } + + testWidgets('uses v3 helper, lilac checkphrase, and address tokens', (tester) async { + await pumpShowKey(tester); + + final helper = tester.widget(find.textContaining('Scan with your Quantus hot wallet')); + expect(helper.style?.color, colors.textMuted); + expect(helper.style?.fontSize, text.body.fontSize); + + final phrase = tester.widget(find.text(checkphrase)); + expect(phrase.style?.color, colors.semanticLilac); + expect(phrase.style?.fontSize, text.headingRow.fontSize); + expect(phrase.style?.fontWeight, text.headingRow.fontWeight); + + final addressText = tester.widget(find.text(address)); + expect(addressText.style?.color, colors.textContent); + expect(addressText.style?.fontSize, text.dataAddressLarge.fontSize); + expect(addressText.style?.fontFamily, text.dataAddressLarge.fontFamily); + + final box = tester.widget(find.ancestor(of: find.text(address), matching: find.byType(Container)).first); + final decoration = box.decoration! as BoxDecoration; + expect(decoration.color, colors.bgSurface); + expect(decoration.borderRadius, radius.mdBorder); + }); +} From 7c9f225aba9e1900ed0565a2ce98cca16b96531e Mon Sep 17 00:00:00 2001 From: Beast Date: Thu, 20 Aug 2026 00:01:38 +0800 Subject: [PATCH 30/38] feat: update design tokens 4th pass --- .../lib/screens/scan_transaction_screen.dart | 47 ++++++++++--------- .../test/scan_transaction_screen_test.dart | 46 ++++++++++++++++++ 2 files changed, 71 insertions(+), 22 deletions(-) create mode 100644 cold-wallet-app/test/scan_transaction_screen_test.dart diff --git a/cold-wallet-app/lib/screens/scan_transaction_screen.dart b/cold-wallet-app/lib/screens/scan_transaction_screen.dart index 42b4155bd..3030c67b1 100644 --- a/cold-wallet-app/lib/screens/scan_transaction_screen.dart +++ b/cold-wallet-app/lib/screens/scan_transaction_screen.dart @@ -75,19 +75,20 @@ class _ScanTransactionScreenState extends State { } Widget _debugPayloadButtons(BuildContext context) { - final text = context.themeText; + final colors = context.colorsV3; + final text = context.themeTextV3; Widget button(String label, Uint8List Function() build) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 4), child: ElevatedButton( style: ElevatedButton.styleFrom( - backgroundColor: Colors.white24, + backgroundColor: colors.bgSurface2, padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), visualDensity: VisualDensity.compact, ), onPressed: () => _loadDebugPayload(build()), - child: Text(label, style: text.detail?.copyWith(color: Colors.white)), + child: Text(label, style: text.caption.copyWith(color: colors.textContent)), ), ); } @@ -95,7 +96,7 @@ class _ScanTransactionScreenState extends State { return Column( mainAxisSize: MainAxisSize.min, children: [ - Text('DEBUG PAYLOADS', style: text.detail?.copyWith(color: Colors.white38, letterSpacing: 1.2)), + Text('DEBUG PAYLOADS', style: text.caption.copyWith(color: colors.textMuted)), const SizedBox(height: 8), Row( mainAxisAlignment: MainAxisAlignment.center, @@ -111,25 +112,27 @@ class _ScanTransactionScreenState extends State { } Widget _cameraError(BuildContext context, MobileScannerException error) { + final colors = context.colorsV3; + final text = context.themeTextV3; return ColoredBox( - color: Colors.black, + color: colors.bgVoid, child: Center( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 32), child: Column( mainAxisSize: MainAxisSize.min, children: [ - const Icon(Icons.no_photography_outlined, color: Colors.white70, size: 64), + Icon(Icons.no_photography_outlined, color: colors.textMuted, size: 64), const SizedBox(height: 24), - const Text( + Text( 'Camera unavailable', - style: TextStyle(color: Colors.white, fontSize: 20, fontWeight: FontWeight.w600), + style: text.titleScreen.copyWith(color: colors.textContent), textAlign: TextAlign.center, ), const SizedBox(height: 12), Text( 'Grant camera access in Settings to scan the transaction QR (${error.errorCode.name}).', - style: const TextStyle(color: Colors.white70), + style: text.body.copyWith(color: colors.textMuted), textAlign: TextAlign.center, ), ], @@ -141,15 +144,15 @@ class _ScanTransactionScreenState extends State { @override Widget build(BuildContext context) { - final colors = context.colors; - final text = context.themeText; + final colors = context.colorsV3; + final text = context.themeTextV3; final size = MediaQuery.of(context).size; final frame = (size.width - 96).clamp(220.0, 300.0); final progress = _expectedParts == null ? null : (_seenSeq.length / _expectedParts!).clamp(0.0, 1.0); return Scaffold( - backgroundColor: Colors.black, + backgroundColor: colors.bgVoid, body: Stack( children: [ MobileScanner(controller: _controller, onDetect: _onDetect, errorBuilder: _cameraError), @@ -158,8 +161,8 @@ class _ScanTransactionScreenState extends State { width: frame, height: frame, decoration: BoxDecoration( - border: Border.all(color: colors.accentOrange, width: 2), - borderRadius: BorderRadius.circular(16), + border: Border.all(color: colors.accentFlare, width: 2), + borderRadius: context.radiusV3.mdBorder, ), ), ), @@ -172,12 +175,12 @@ class _ScanTransactionScreenState extends State { children: [ IconButton( onPressed: () => Navigator.pop(context), - icon: const Icon(Icons.arrow_back, color: Colors.white), + icon: Icon(Icons.arrow_back, color: colors.textContent), ), const Spacer(), IconButton( onPressed: _controller.toggleTorch, - icon: const Icon(Icons.flash_on, color: Colors.white), + icon: Icon(Icons.flash_on, color: colors.textContent), ), ], ), @@ -193,27 +196,27 @@ class _ScanTransactionScreenState extends State { if (kDebugMode) _debugPayloadButtons(context), Text( _error ?? 'Scan the transaction QR from your hot wallet', - style: text.paragraph?.copyWith(color: _error != null ? colors.error : Colors.white), + style: text.body.copyWith(color: _error != null ? colors.semanticEmber : colors.textContent), textAlign: TextAlign.center, ), const SizedBox(height: 16), if (progress != null) ...[ ClipRRect( - borderRadius: BorderRadius.circular(4), + borderRadius: context.radiusV3.xsBorder, child: LinearProgressIndicator( value: progress, minHeight: 6, - backgroundColor: colors.surface, - color: colors.accentOrange, + backgroundColor: colors.bgSurface2, + color: colors.accentFlare, ), ), const SizedBox(height: 8), Text( '${_seenSeq.length} / ${_expectedParts!} parts', - style: text.detail?.copyWith(color: Colors.white70), + style: text.caption.copyWith(color: colors.textMuted), ), ] else if (_parts.isNotEmpty) - Text('${_parts.length} parts scanned', style: text.detail?.copyWith(color: Colors.white70)), + Text('${_parts.length} parts scanned', style: text.caption.copyWith(color: colors.textMuted)), ], ), ), diff --git a/cold-wallet-app/test/scan_transaction_screen_test.dart b/cold-wallet-app/test/scan_transaction_screen_test.dart new file mode 100644 index 000000000..9be6a2b3e --- /dev/null +++ b/cold-wallet-app/test/scan_transaction_screen_test.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:quantus_cold_wallet/screens/scan_transaction_screen.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + const colors = AppColorsV3.dark(); + const text = AppTextThemeV3.standard(); + const radius = AppRadiusV3.standard(); + + Future pumpScan(WidgetTester tester) async { + await tester.pumpWidget( + Builder( + builder: (context) => MaterialApp(theme: AppTheme.darkTheme(context), home: const ScanTransactionScreen()), + ), + ); + await tester.pump(); + } + + testWidgets('uses v3 overlay, frame, and instruction tokens', (tester) async { + await pumpScan(tester); + + expect(tester.widget(find.byType(Scaffold)).backgroundColor, colors.bgVoid); + + final instruction = tester.widget(find.textContaining('Scan the transaction QR from your hot wallet')); + expect(instruction.style?.color, colors.textContent); + expect(instruction.style?.fontSize, text.body.fontSize); + + expect(tester.widget(find.byIcon(Icons.arrow_back)).color, colors.textContent); + expect(tester.widget(find.byIcon(Icons.flash_on)).color, colors.textContent); + + final frame = tester.widgetList(find.byType(Container)).firstWhere((container) { + final decoration = container.decoration; + return decoration is BoxDecoration && decoration.border != null; + }); + final decoration = frame.decoration! as BoxDecoration; + expect((decoration.border as Border?)?.top.color, colors.accentFlare); + expect(decoration.borderRadius, radius.mdBorder); + + final debugLabel = tester.widget(find.text('DEBUG PAYLOADS')); + expect(debugLabel.style?.color, colors.textMuted); + expect(debugLabel.style?.fontSize, text.caption.fontSize); + }); +} From 3670473f44eca766d727140f2552129b548ecf6a Mon Sep 17 00:00:00 2001 From: Beast Date: Thu, 20 Aug 2026 01:00:31 +0800 Subject: [PATCH 31/38] feat: update design tokens 5th pass --- .../lib/src/ui/components/back_button.dart | 8 +-- .../src/ui/components/base_background.dart | 2 +- .../lib/src/ui/components/mnemonic_grid.dart | 9 ++-- .../lib/src/ui/components/scaffold_base.dart | 8 +-- .../scaffold_base_bottom_content.dart | 2 +- .../lib/src/ui/components/v2_app_bar.dart | 6 +-- quantus_sdk/lib/src/ui/themes/app_colors.dart | 2 +- quantus_sdk/test/ui/mnemonic_grid_test.dart | 41 ++++++++++++++ quantus_sdk/test/ui/scaffold_base_test.dart | 54 +++++++++++++++++++ quantus_sdk/test/ui/v2_app_bar_test.dart | 48 +++++++++++++++++ 10 files changed, 160 insertions(+), 20 deletions(-) create mode 100644 quantus_sdk/test/ui/mnemonic_grid_test.dart create mode 100644 quantus_sdk/test/ui/scaffold_base_test.dart create mode 100644 quantus_sdk/test/ui/v2_app_bar_test.dart diff --git a/quantus_sdk/lib/src/ui/components/back_button.dart b/quantus_sdk/lib/src/ui/components/back_button.dart index 9da8a55e2..56eb4602d 100644 --- a/quantus_sdk/lib/src/ui/components/back_button.dart +++ b/quantus_sdk/lib/src/ui/components/back_button.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; class AppBackButton extends StatelessWidget { @@ -19,12 +18,7 @@ class AppBackButton extends StatelessWidget { buttonWidth: containerSize, borderRadius: BorderRadius.circular(containerSize / 2), padding: const EdgeInsets.all(2), - child: SvgPicture.asset( - 'assets/v2/caret_left.svg', - width: iconSize, - height: iconSize, - colorFilter: ColorFilter.mode(context.colors.textPrimary, BlendMode.srcIn), - ), + child: QuantusIcon(QuantusIcons.chevronLeft, size: iconSize, color: context.colorsV3.textContent), ), ); } diff --git a/quantus_sdk/lib/src/ui/components/base_background.dart b/quantus_sdk/lib/src/ui/components/base_background.dart index 2de4bb7f6..34ce414c1 100644 --- a/quantus_sdk/lib/src/ui/components/base_background.dart +++ b/quantus_sdk/lib/src/ui/components/base_background.dart @@ -8,6 +8,6 @@ class BaseBackground extends StatelessWidget { @override Widget build(BuildContext context) { - return Container(color: context.colors.background, child: child); + return Container(color: context.colorsV3.bgVoid, child: child); } } diff --git a/quantus_sdk/lib/src/ui/components/mnemonic_grid.dart b/quantus_sdk/lib/src/ui/components/mnemonic_grid.dart index 227c8ec94..ef1fbce59 100644 --- a/quantus_sdk/lib/src/ui/components/mnemonic_grid.dart +++ b/quantus_sdk/lib/src/ui/components/mnemonic_grid.dart @@ -48,15 +48,18 @@ class MnemonicGrid extends StatelessWidget { final double blur = isRevealed ? 0 : 5; final effectiveWord = isRevealed ? word : 'blurred'; + final colors = context.colorsV3; + final text = context.themeTextV3; + return Container( padding: padding, - decoration: BoxDecoration(color: context.colors.surfaceDeep, borderRadius: BorderRadius.circular(14)), + decoration: BoxDecoration(color: colors.bgSurface, borderRadius: context.radiusV3.mdBorder), child: Row( children: [ Text( '$index', textAlign: TextAlign.left, - style: context.themeText.detail?.copyWith(color: context.colors.textTertiary), + style: text.caption.copyWith(color: colors.textMuted), ), const SizedBox(width: 8), ImageFiltered( @@ -64,7 +67,7 @@ class MnemonicGrid extends StatelessWidget { child: Text( effectiveWord, textAlign: TextAlign.left, - style: context.themeText.detail?.copyWith(color: context.colors.checksum), + style: text.caption.copyWith(color: colors.semanticLilac), ), ), ], diff --git a/quantus_sdk/lib/src/ui/components/scaffold_base.dart b/quantus_sdk/lib/src/ui/components/scaffold_base.dart index e0d914484..b931f557e 100644 --- a/quantus_sdk/lib/src/ui/components/scaffold_base.dart +++ b/quantus_sdk/lib/src/ui/components/scaffold_base.dart @@ -45,7 +45,7 @@ class ScaffoldBase extends StatelessWidget { @override Widget build(BuildContext context) { - final colors = context.colors; + final colors = context.colorsV3; Widget bodyContent = Column( children: [ @@ -66,13 +66,13 @@ class ScaffoldBase extends StatelessWidget { return Scaffold(body: scaffoldBody); } - Widget _buildChild(AppColorsV2 colors) { + Widget _buildChild(AppColorsV3 colors) { // Scrollable with refresh (CustomScrollView with slivers) if (onRefresh != null && slivers != null) { return RefreshIndicator( onRefresh: onRefresh!, - color: colors.textPrimary, - backgroundColor: colors.surface, + color: colors.textContent, + backgroundColor: colors.bgSurface, child: Column( children: [ Expanded( diff --git a/quantus_sdk/lib/src/ui/components/scaffold_base_bottom_content.dart b/quantus_sdk/lib/src/ui/components/scaffold_base_bottom_content.dart index 74e77cacd..2484f9e31 100644 --- a/quantus_sdk/lib/src/ui/components/scaffold_base_bottom_content.dart +++ b/quantus_sdk/lib/src/ui/components/scaffold_base_bottom_content.dart @@ -13,7 +13,7 @@ class ScaffoldBaseBottomContent extends StatelessWidget { return Container( padding: padding, decoration: BoxDecoration( - border: Border(top: BorderSide(color: context.colors.surfaceDeep, width: 1)), + border: Border(top: BorderSide(color: context.colorsV3.borderHairline, width: 1)), ), child: child, ); diff --git a/quantus_sdk/lib/src/ui/components/v2_app_bar.dart b/quantus_sdk/lib/src/ui/components/v2_app_bar.dart index 16bce12d1..35de52882 100644 --- a/quantus_sdk/lib/src/ui/components/v2_app_bar.dart +++ b/quantus_sdk/lib/src/ui/components/v2_app_bar.dart @@ -19,8 +19,8 @@ class V2AppBar extends StatelessWidget { @override Widget build(BuildContext context) { - final colors = context.colors; - final text = context.themeText; + final colors = context.colorsV3; + final text = context.themeTextV3; Widget leftWidget = leading ?? (showBackButton ? const AppBackButton() : const SizedBox(width: 24)); Widget rightWidget = trailing ?? const SizedBox(width: 24); @@ -31,7 +31,7 @@ class V2AppBar extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ leftWidget, - Text(title, style: text.smallTitle?.copyWith(color: colors.textPrimary, fontSize: 20)), + Text(title, style: text.titleScreen.copyWith(color: colors.textContent)), rightWidget, ], ), diff --git a/quantus_sdk/lib/src/ui/themes/app_colors.dart b/quantus_sdk/lib/src/ui/themes/app_colors.dart index 6d50fe6ff..38326aaa3 100644 --- a/quantus_sdk/lib/src/ui/themes/app_colors.dart +++ b/quantus_sdk/lib/src/ui/themes/app_colors.dart @@ -418,7 +418,7 @@ class AppColorsV3 extends ThemeExtension { /// Waits. Pending, suspended, reversible, in-between. final Color semanticGlacier; - /// Checkphrases only. Nothing else wears lilac, ever. + /// Checkphrases and recovery/mnemonic words. Nothing else wears lilac. final Color semanticLilac; /// Default border. All cards, rows, dividers. White at 7%. diff --git a/quantus_sdk/test/ui/mnemonic_grid_test.dart b/quantus_sdk/test/ui/mnemonic_grid_test.dart new file mode 100644 index 000000000..0760b2cee --- /dev/null +++ b/quantus_sdk/test/ui/mnemonic_grid_test.dart @@ -0,0 +1,41 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + const colors = AppColorsV3.dark(); + const text = AppTextThemeV3.standard(); + const radius = AppRadiusV3.standard(); + + testWidgets('uses v3 surface, muted index, and lilac word tokens', (tester) async { + await tester.pumpWidget( + MediaQuery( + data: const MediaQueryData(size: Size(375, 667)), + child: Builder( + builder: (context) => MaterialApp( + theme: AppTheme.darkTheme(context), + home: const Scaffold(body: MnemonicGrid(words: ['abandon', 'ability', 'able'], isRevealed: true)), + ), + ), + ), + ); + await tester.pump(); + + final index = tester.widget(find.text('1')); + expect(index.style?.color, colors.textMuted); + expect(index.style?.fontSize, text.caption.fontSize); + + final word = tester.widget(find.text('abandon')); + expect(word.style?.color, colors.semanticLilac); + expect(word.style?.fontSize, text.caption.fontSize); + + final container = tester.widget( + find.ancestor(of: find.text('abandon'), matching: find.byType(Container)).first, + ); + final decoration = container.decoration! as BoxDecoration; + expect(decoration.color, colors.bgSurface); + expect(decoration.borderRadius, radius.mdBorder); + }); +} diff --git a/quantus_sdk/test/ui/scaffold_base_test.dart b/quantus_sdk/test/ui/scaffold_base_test.dart new file mode 100644 index 000000000..3ba18c67c --- /dev/null +++ b/quantus_sdk/test/ui/scaffold_base_test.dart @@ -0,0 +1,54 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + const colors = AppColorsV3.dark(); + + Future pump(WidgetTester tester, Widget child) async { + await tester.pumpWidget( + MediaQuery( + data: const MediaQueryData(size: Size(375, 667)), + child: Builder( + builder: (context) => MaterialApp(theme: AppTheme.darkTheme(context), home: child), + ), + ), + ); + await tester.pump(); + } + + testWidgets('BaseBackground fills with v3 void', (tester) async { + await pump(tester, const ScaffoldBase(mainContent: Text('Hello'))); + + final container = tester.widget( + find.descendant(of: find.byType(BaseBackground), matching: find.byType(Container)).first, + ); + expect(container.color, colors.bgVoid); + }); + + testWidgets('bottom content uses v3 hairline divider', (tester) async { + await pump( + tester, + const ScaffoldBase( + mainContent: Text('Hello'), + bottomContent: ScaffoldBaseBottomContent(child: Text('Continue')), + ), + ); + + final container = tester.widget( + find.descendant(of: find.byType(ScaffoldBaseBottomContent), matching: find.byType(Container)).first, + ); + final decoration = container.decoration! as BoxDecoration; + expect((decoration.border! as Border).top.color, colors.borderHairline); + }); + + testWidgets('refresh indicator uses v3 content and surface tokens', (tester) async { + await pump(tester, ScaffoldBase.refreshable(onRefresh: () async {}, slivers: const [Text('Item')])); + + final indicator = tester.widget(find.byType(RefreshIndicator)); + expect(indicator.color, colors.textContent); + expect(indicator.backgroundColor, colors.bgSurface); + }); +} diff --git a/quantus_sdk/test/ui/v2_app_bar_test.dart b/quantus_sdk/test/ui/v2_app_bar_test.dart new file mode 100644 index 000000000..106125379 --- /dev/null +++ b/quantus_sdk/test/ui/v2_app_bar_test.dart @@ -0,0 +1,48 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + const colors = AppColorsV3.dark(); + const text = AppTextThemeV3.standard(); + + Future pump(WidgetTester tester, Widget child) async { + await tester.pumpWidget( + MediaQuery( + data: const MediaQueryData(size: Size(375, 667)), + child: Builder( + builder: (context) => MaterialApp( + theme: AppTheme.darkTheme(context), + home: Scaffold(body: child), + ), + ), + ), + ); + await tester.pump(); + } + + testWidgets('title uses v3 screen title and content color', (tester) async { + await pump(tester, const V2AppBar(title: 'Settings', showBackButton: false)); + + final title = tester.widget(find.text('Settings')); + expect(title.style?.color, colors.textContent); + expect(title.style?.fontSize, text.titleScreen.fontSize); + expect(title.style?.fontWeight, text.titleScreen.fontWeight); + expect(title.style?.height, text.titleScreen.height); + }); + + testWidgets('default back button uses v3 chevron and content color', (tester) async { + await pump(tester, const AppBackButton()); + + expect(find.byType(QuantusIcon), findsOneWidget); + final icon = tester.widget(find.byType(QuantusIcon)); + expect(icon.icon, QuantusIcons.chevronLeft); + expect(icon.color, colors.textContent); + + final svg = tester.widget(find.byType(SvgPicture)); + expect(svg.colorFilter, ColorFilter.mode(colors.textContent, BlendMode.srcIn)); + }); +} From c5d23847cc324f4a75aeeb560638719bcbf8979b Mon Sep 17 00:00:00 2001 From: Beast Date: Thu, 20 Aug 2026 01:24:07 +0800 Subject: [PATCH 32/38] feat: update loader and menu divider design tokens --- quantus_sdk/lib/src/ui/components/loader.dart | 2 +- .../lib/src/ui/components/menu_divider.dart | 2 +- quantus_sdk/test/ui/loader_test.dart | 42 +++++++++++++++++++ quantus_sdk/test/ui/menu_divider_test.dart | 32 ++++++++++++++ 4 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 quantus_sdk/test/ui/loader_test.dart create mode 100644 quantus_sdk/test/ui/menu_divider_test.dart diff --git a/quantus_sdk/lib/src/ui/components/loader.dart b/quantus_sdk/lib/src/ui/components/loader.dart index 9a46186ff..b055cb3bb 100644 --- a/quantus_sdk/lib/src/ui/components/loader.dart +++ b/quantus_sdk/lib/src/ui/components/loader.dart @@ -14,7 +14,7 @@ class Loader extends StatelessWidget { return SizedBox( height: effectiveSize, width: effectiveSize, - child: CircularProgressIndicator(strokeWidth: 2, color: color ?? context.colors.textSecondary), + child: CircularProgressIndicator(strokeWidth: 2, color: color ?? context.colorsV3.textMuted), ); } } diff --git a/quantus_sdk/lib/src/ui/components/menu_divider.dart b/quantus_sdk/lib/src/ui/components/menu_divider.dart index 64bb9d1ac..3479fc7c8 100644 --- a/quantus_sdk/lib/src/ui/components/menu_divider.dart +++ b/quantus_sdk/lib/src/ui/components/menu_divider.dart @@ -6,5 +6,5 @@ class MenuDivider extends StatelessWidget { const MenuDivider({super.key}); @override - Widget build(BuildContext context) => Divider(color: context.colors.toasterBackground, height: 1); + Widget build(BuildContext context) => Divider(color: context.colorsV3.borderHairline, height: 1); } diff --git a/quantus_sdk/test/ui/loader_test.dart b/quantus_sdk/test/ui/loader_test.dart new file mode 100644 index 000000000..9cf4cc579 --- /dev/null +++ b/quantus_sdk/test/ui/loader_test.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + const colors = AppColorsV3.dark(); + + Future pumpLoader(WidgetTester tester, Widget loader, {Size size = const Size(375, 667)}) async { + await tester.pumpWidget( + MediaQuery( + data: MediaQueryData(size: size), + child: Builder( + builder: (context) => MaterialApp( + theme: AppTheme.darkTheme(context), + home: Scaffold(body: loader), + ), + ), + ), + ); + await tester.pump(); + } + + CircularProgressIndicator indicator(WidgetTester tester) { + return tester.widget(find.byType(CircularProgressIndicator)); + } + + testWidgets('defaults to v3 textMuted', (tester) async { + await pumpLoader(tester, const Loader()); + + expect(indicator(tester).color, colors.textMuted); + expect(tester.getSize(find.byType(Loader)), const Size(16, 16)); + }); + + testWidgets('uses the explicit color when provided', (tester) async { + await pumpLoader(tester, Loader(color: colors.accentFlare, size: 20)); + + expect(indicator(tester).color, colors.accentFlare); + expect(tester.getSize(find.byType(Loader)), const Size(20, 20)); + }); +} diff --git a/quantus_sdk/test/ui/menu_divider_test.dart b/quantus_sdk/test/ui/menu_divider_test.dart new file mode 100644 index 000000000..a949ef455 --- /dev/null +++ b/quantus_sdk/test/ui/menu_divider_test.dart @@ -0,0 +1,32 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:quantus_sdk/quantus_sdk.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + const colors = AppColorsV3.dark(); + + Future pumpDivider(WidgetTester tester) async { + await tester.pumpWidget( + MediaQuery( + data: const MediaQueryData(size: Size(375, 667)), + child: Builder( + builder: (context) => MaterialApp( + theme: AppTheme.darkTheme(context), + home: const Scaffold(body: MenuDivider()), + ), + ), + ), + ); + await tester.pump(); + } + + testWidgets('paints v3 borderHairline', (tester) async { + await pumpDivider(tester); + + final divider = tester.widget(find.byType(Divider)); + expect(divider.color, colors.borderHairline); + expect(divider.height, 1); + }); +} From 44af58053535d97617a7db320ac32090920aec8c Mon Sep 17 00:00:00 2001 From: Beast Date: Thu, 20 Aug 2026 13:36:10 +0800 Subject: [PATCH 33/38] feat: update sign screen + detail call components --- .../components/address_with_checkphrase.dart | 29 -- .../lib/components/call_detail_view.dart | 213 -------------- .../lib/components/decoded_call_view.dart | 6 +- .../lib/components/detail_row.dart | 68 ----- .../lib/components/titled_sheet.dart | 38 --- .../lib/providers/wallet_providers.dart | 8 +- .../lib/screens/scan_transaction_screen.dart | 2 +- .../lib/screens/sign_transaction_screen.dart | 118 ++++---- cold-wallet-app/test/call_display_test.dart | 73 +---- .../src/ui/components/decoded_call_view.dart | 278 ++++++++++-------- .../src/ui/components/detail_summary_row.dart | 89 ++++-- .../test/ui/decoded_call_view_test.dart | 96 +++++- .../test/ui/detail_summary_row_test.dart | 40 +++ 13 files changed, 421 insertions(+), 637 deletions(-) delete mode 100644 cold-wallet-app/lib/components/address_with_checkphrase.dart delete mode 100644 cold-wallet-app/lib/components/call_detail_view.dart delete mode 100644 cold-wallet-app/lib/components/detail_row.dart delete mode 100644 cold-wallet-app/lib/components/titled_sheet.dart diff --git a/cold-wallet-app/lib/components/address_with_checkphrase.dart b/cold-wallet-app/lib/components/address_with_checkphrase.dart deleted file mode 100644 index cfa1814d3..000000000 --- a/cold-wallet-app/lib/components/address_with_checkphrase.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_cold_wallet/components/detail_row.dart'; -import 'package:quantus_cold_wallet/providers/wallet_providers.dart'; -import 'package:quantus_cold_wallet/theme/app_colors.dart'; - -/// An address plus its checkphrase, so the signer can verify it out loud rather -/// than character by character. -class AddressWithCheckphrase extends ConsumerWidget { - final String label; - final String address; - final String? note; - - const AddressWithCheckphrase({super.key, required this.label, required this.address, this.note}); - - @override - Widget build(BuildContext context, WidgetRef ref) { - final phrase = ref.watch(addressCheckphraseProvider(address)).asData?.value; - - return DetailRow( - label: label, - value: address, - monospace: true, - subValue: (phrase == null || phrase.isEmpty) ? null : phrase, - subValueColor: context.colors.checksum, - note: note, - ); - } -} diff --git a/cold-wallet-app/lib/components/call_detail_view.dart b/cold-wallet-app/lib/components/call_detail_view.dart deleted file mode 100644 index 62f5d22e0..000000000 --- a/cold-wallet-app/lib/components/call_detail_view.dart +++ /dev/null @@ -1,213 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:quantus_cold_wallet/components/address_with_checkphrase.dart'; -import 'package:quantus_cold_wallet/components/detail_row.dart'; - -/// True when [summary] already puts this exact field on screen, so listing it -/// again would only add noise. Matches by identity, never by label or value, so -/// a renamed field — or a different field that merely carries an equal value — -/// can never be silently dropped. -bool coveredBySummary(CallField field, TransferSummary summary) { - if (identical(field, summary.amountField)) return true; - // With no plain recipient there is no To row, so the field must be listed. - return summary.recipient != null && identical(field, summary.recipientField); -} - -/// The transfer a call performs, or null when it dispatches another call. -/// -/// A wrapper (multisig approve, batch, `as_derivative`) inherits the summary of -/// the call it carries; the amount belongs on that inner call, where the nested -/// box shows it, not on the wrapper. -TransferSummary? heroSummary(DecodedCall call) => call.isWrapper ? null : call.summary; - -/// `4200 raw units of asset 1` — asset amounts stay in the payload's own raw -/// units, and say so: decimals are per-asset chain state an air-gapped signer -/// cannot resolve, so this integer must never read as a human asset quantity. -String assetAmountText(BigInt amount, int assetId) => '$amount raw units of asset $assetId'; - -/// The amount, recipient, and every parameter the two of them do not already -/// cover — the body shared by the top-level review and each nested call box. -List callSummaryBody(DecodedCall call, {int depth = 0}) { - final summary = heroSummary(call); - final recipient = summary?.recipient; - - return [ - if (summary != null) TransferAmount(summary: summary, large: depth == 0), - if (recipient != null) AddressWithCheckphrase(label: 'To', address: recipient), - for (final field in call.fields) - if (summary == null || !coveredBySummary(field, summary)) CallFieldView(field: field, depth: depth), - ]; -} - -/// The amount being moved, in the largest type on the screen. -class TransferAmount extends StatelessWidget { - final TransferSummary summary; - - /// Top-level calls get the hero treatment; nested ones step down a size. - final bool large; - - const TransferAmount({super.key, required this.summary, this.large = true}); - - @override - Widget build(BuildContext context) { - final colors = context.colors; - final text = context.themeText; - - if (summary.assetId != null) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 10), - child: Text( - assetAmountText(summary.amount, summary.assetId!), - style: text.mediumTitle?.copyWith(color: colors.textPrimary), - ), - ); - } - - final amount = NumberFormattingService().formatAmount(summary.amount); - final style = large ? text.transactionDetailAmountPrimary : text.conversionAmountPrimary; - final symbolStyle = large ? text.transactionDetailAmountSymbol : text.conversionAmountPrimary; - - return Padding( - padding: const EdgeInsets.symmetric(vertical: 10), - child: FittedBox( - fit: BoxFit.scaleDown, - alignment: Alignment.centerLeft, - child: RichText( - text: TextSpan( - children: [ - TextSpan( - text: amount, - style: style?.copyWith(color: colors.textPrimary), - ), - TextSpan( - text: ' ${AppConstants.tokenSymbol}', - style: symbolStyle?.copyWith(color: colors.textSecondary), - ), - ], - ), - ), - ), - ); - } -} - -/// A decoded call rendered the way a signer reads it: what it does, how much, -/// to whom — then every remaining parameter, nested calls included. -/// -/// The summary is a lead, never a replacement: any field it does not already -/// show is listed underneath, so if a byte is being signed it is on this screen. -/// -/// The heading is [DecodedCall.actionTitle] — an INTENTIONALLY opinionated -/// summary (`SEND`, `REVERSIBLE SEND`, `ASSET SEND`) at every depth, never -/// runtime naming. Do not add a `pallet · call` line here: that identity is -/// deliberately kept to one place, [DecodedCall.displayTitleChain] on the -/// signing screen's Advanced list. -class CallDetailView extends StatelessWidget { - final DecodedCall call; - - /// Nesting depth; nested calls are boxed and indented. - final int depth; - - const CallDetailView({super.key, required this.call, this.depth = 0}); - - @override - Widget build(BuildContext context) { - final colors = context.colors; - final text = context.themeText; - - return Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Text( - call.actionTitle, - style: text.smallTitle?.copyWith(color: depth == 0 ? colors.textPrimary : colors.checksum), - ), - ...callSummaryBody(call, depth: depth), - ], - ); - } -} - -class CallFieldView extends ConsumerWidget { - final CallField field; - final int depth; - - const CallFieldView({super.key, required this.field, this.depth = 0}); - - @override - Widget build(BuildContext context, WidgetRef ref) { - final colors = context.colors; - final text = context.themeText; - - switch (field) { - case ValueField(:final label, :final value, :final kind, :final note): - if (kind == ValueKind.address) { - return AddressWithCheckphrase(label: label, address: value, note: note); - } - return DetailRow( - label: label, - value: value, - monospace: kind == ValueKind.hash || kind == ValueKind.bytes, - note: note, - ); - - case AmountField(:final label, :final token, :final assetId, :final note): - return DetailRow( - label: label, - value: assetId == null - ? '${NumberFormattingService().formatAmount(token)} ${AppConstants.tokenSymbol}' - : assetAmountText(token, assetId), - note: assetId == null - ? note - : [ - note, - 'Asset decimals are not part of this payload, so the raw amount is shown.', - ].whereType().join(' '), - ); - - case FieldGroup(:final label, :final items): - return Padding( - padding: const EdgeInsets.only(top: 10), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Text(label.toUpperCase(), style: text.transactionDetailRowLabel?.copyWith(color: colors.textLabel)), - Padding( - padding: const EdgeInsets.only(left: 12), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [for (final item in items) CallFieldView(field: item, depth: depth)], - ), - ), - ], - ), - ); - - case NestedCallField(:final label, :final call, :final note): - return Padding( - padding: const EdgeInsets.only(top: 14), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Text(label.toUpperCase(), style: text.transactionDetailRowLabel?.copyWith(color: colors.textLabel)), - const SizedBox(height: 8), - Container( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), - decoration: BoxDecoration( - color: colors.surfaceCard, - borderRadius: BorderRadius.circular(10), - border: Border.all(color: colors.borderButton), - ), - child: CallDetailView(call: call, depth: depth + 1), - ), - if (note != null) ...[ - const SizedBox(height: 6), - Text(note, style: text.detail?.copyWith(color: colors.textMuted)), - ], - ], - ), - ); - } - } -} diff --git a/cold-wallet-app/lib/components/decoded_call_view.dart b/cold-wallet-app/lib/components/decoded_call_view.dart index fb06748f1..78cff895d 100644 --- a/cold-wallet-app/lib/components/decoded_call_view.dart +++ b/cold-wallet-app/lib/components/decoded_call_view.dart @@ -7,8 +7,9 @@ import 'package:quantus_cold_wallet/providers/wallet_providers.dart'; class DecodedCallView extends ConsumerWidget { final sdk.DecodedCall call; final int depth; + final Widget? signer; - const DecodedCallView({super.key, required this.call, this.depth = 0}); + const DecodedCallView({super.key, required this.call, this.depth = 0, this.signer}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -17,8 +18,11 @@ class DecodedCallView extends ConsumerWidget { call: call, depth: depth, layout: sdk.DecodedCallLayout.stacked, + showTitle: false, + recipientLabel: 'To', amountText: (token) => '${sdk.NumberFormattingService().formatAmount(token)} ${sdk.AppConstants.tokenSymbol}', checkphraseOf: (address) => checkphrases[address], + signer: signer, ); } } diff --git a/cold-wallet-app/lib/components/detail_row.dart b/cold-wallet-app/lib/components/detail_row.dart deleted file mode 100644 index cfa588fce..000000000 --- a/cold-wallet-app/lib/components/detail_row.dart +++ /dev/null @@ -1,68 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; - -/// Label-above-value row used throughout the signing review screen. -/// -/// Values wrap rather than ellipsize: a signer must be able to read a full -/// address or hash, so nothing on this screen is ever visually truncated. -class DetailRow extends StatelessWidget { - final String label; - final String value; - - /// Monospace value, for addresses, hashes and byte blobs. - final bool monospace; - - final Color? valueColor; - - /// A second reading of the same value, shown directly under it — the human - /// checkphrase for an address. - final String? subValue; - - final Color? subValueColor; - - /// Caveat shown under the value, e.g. that a hash-referenced proposal's - /// contents are not part of the payload. - final String? note; - - const DetailRow({ - super.key, - required this.label, - required this.value, - this.monospace = false, - this.valueColor, - this.subValue, - this.subValueColor, - this.note, - }); - - @override - Widget build(BuildContext context) { - final colors = context.colors; - final text = context.themeText; - - return Padding( - padding: const EdgeInsets.symmetric(vertical: 10), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(label.toUpperCase(), style: text.transactionDetailRowLabel?.copyWith(color: colors.textLabel)), - const SizedBox(height: 6), - Text( - value, - style: monospace - ? text.transactionDetailRowValue?.copyWith(color: valueColor ?? colors.textPrimary) - : text.smallParagraph?.copyWith(color: valueColor ?? colors.textPrimary), - ), - if (subValue != null) ...[ - const SizedBox(height: 4), - Text(subValue!, style: text.smallParagraph?.copyWith(color: subValueColor ?? colors.textSecondary)), - ], - if (note != null) ...[ - const SizedBox(height: 4), - Text(note!, style: text.detail?.copyWith(color: colors.textMuted)), - ], - ], - ), - ); - } -} diff --git a/cold-wallet-app/lib/components/titled_sheet.dart b/cold-wallet-app/lib/components/titled_sheet.dart deleted file mode 100644 index 6aae80500..000000000 --- a/cold-wallet-app/lib/components/titled_sheet.dart +++ /dev/null @@ -1,38 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:quantus_cold_wallet/theme/app_colors.dart'; -import 'package:quantus_cold_wallet/theme/app_text_styles.dart'; - -/// A titled bottom sheet that sizes to its content and scrolls once that -/// content outgrows the screen. -/// -/// Disclosure that lives at the end of a long scrolling page cannot expand in -/// place: the reader is already at the bottom, so the revealed content lands -/// below the viewport and nothing appears to happen. A sheet is visible wherever -/// the page happens to be scrolled. -Future showTitledSheet(BuildContext context, {required String title, required Widget child}) { - final colors = context.colors; - final text = context.themeText; - - return showModalBottomSheet( - context: context, - backgroundColor: colors.sheetBackground, - isScrollControlled: true, - builder: (sheetContext) => SafeArea( - child: ConstrainedBox( - constraints: BoxConstraints(maxHeight: MediaQuery.of(sheetContext).size.height * 0.8), - child: Padding( - padding: const EdgeInsets.fromLTRB(24, 24, 24, 24), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Text(title, style: text.smallTitle?.copyWith(color: colors.textPrimary)), - const SizedBox(height: 16), - Flexible(child: SingleChildScrollView(child: child)), - ], - ), - ), - ), - ), - ); -} diff --git a/cold-wallet-app/lib/providers/wallet_providers.dart b/cold-wallet-app/lib/providers/wallet_providers.dart index 5e67a03eb..bd6f15967 100644 --- a/cold-wallet-app/lib/providers/wallet_providers.dart +++ b/cold-wallet-app/lib/providers/wallet_providers.dart @@ -165,16 +165,12 @@ final addressProvider = Provider((ref) => ref.watch(keypairProvider)?.s /// Resolves human checkphrases for every address on screen, not just the /// wallet's own — an approval or a governance call can name several accounts, /// and each one needs to be verifiable by eye. -final addressCheckphraseProvider = FutureProvider.family((ref, address) async { +final checksumNameProvider = FutureProvider.family((ref, address) async { return (await HumanReadableChecksumService().getHumanReadableName(address)) ?? ''; }); final checkphraseProvider = FutureProvider((ref) async { final address = ref.watch(addressProvider); if (address == null) return ''; - return ref.watch(addressCheckphraseProvider(address).future); -}); - -final checksumNameProvider = FutureProvider.family((ref, address) async { - return (await HumanReadableChecksumService().getHumanReadableName(address)) ?? ''; + return ref.watch(checksumNameProvider(address).future); }); diff --git a/cold-wallet-app/lib/screens/scan_transaction_screen.dart b/cold-wallet-app/lib/screens/scan_transaction_screen.dart index 96fb73501..a6411c965 100644 --- a/cold-wallet-app/lib/screens/scan_transaction_screen.dart +++ b/cold-wallet-app/lib/screens/scan_transaction_screen.dart @@ -240,4 +240,4 @@ class _ScanTransactionScreenState extends State { ), ); } -} \ No newline at end of file +} diff --git a/cold-wallet-app/lib/screens/sign_transaction_screen.dart b/cold-wallet-app/lib/screens/sign_transaction_screen.dart index c365ab6bf..02201db24 100644 --- a/cold-wallet-app/lib/screens/sign_transaction_screen.dart +++ b/cold-wallet-app/lib/screens/sign_transaction_screen.dart @@ -3,11 +3,9 @@ import 'dart:typed_data'; import 'package:convert/convert.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:quantus_cold_wallet/components/address_with_checkphrase.dart'; -import 'package:quantus_cold_wallet/components/call_detail_view.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide DecodedCallView; +import 'package:quantus_cold_wallet/components/decoded_call_view.dart'; import 'package:quantus_cold_wallet/components/qr_tuning_controls.dart'; -import 'package:quantus_cold_wallet/components/titled_sheet.dart'; import 'package:quantus_cold_wallet/providers/settings_providers.dart'; import 'package:quantus_cold_wallet/providers/wallet_providers.dart'; @@ -85,27 +83,27 @@ class _SignTransactionScreenState extends ConsumerState { } Widget _errorView(BuildContext context, String reason) { - final colors = context.colors; - final text = context.themeText; + final colors = context.colorsV3; + final text = context.themeTextV3; return ScaffoldBase( appBar: const V2AppBar(title: 'Sign Transaction'), mainContent: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon(Icons.error_outline, size: 64, color: colors.error), + Icon(Icons.error_outline, size: 64, color: colors.semanticEmber), const SizedBox(height: 24), - Text('Could not read transaction', style: text.mediumTitle?.copyWith(color: colors.textPrimary)), + Text('Could not read transaction', style: text.titleScreen.copyWith(color: colors.textContent)), const SizedBox(height: 12), Text( 'This QR code is not a transaction this wallet can read in full, so it will not be signed. ' 'Nothing was signed.', - style: text.smallParagraph?.copyWith(color: colors.textSecondary), + style: text.body.copyWith(color: colors.textMuted), textAlign: TextAlign.center, ), const SizedBox(height: 12), Text( reason, - style: text.detail?.copyWith(color: colors.textMuted), + style: text.caption.copyWith(color: colors.textMuted2), textAlign: TextAlign.center, ), ], @@ -117,8 +115,8 @@ class _SignTransactionScreenState extends ConsumerState { } Widget _reviewView(BuildContext context, ParsedPayload parsed) { - final colors = context.colors; - final text = context.themeText; + final colors = context.colorsV3; + final text = context.themeTextV3; return ScaffoldBase( appBar: const V2AppBar(title: 'Review & Sign'), @@ -131,18 +129,15 @@ class _SignTransactionScreenState extends ConsumerState { // The headline is an opinionated human summary (SEND / REVERSIBLE // SEND / …) by design; the exact pallet · call chain is the Call // line in the Advanced sheet. See [DecodedCall.actionTitle]. - Text( - parsed.call.actionTitle, - style: text.mediumTitle?.copyWith(color: colors.accentOrange, letterSpacing: 1.2), - ), - ..._callBody(context, parsed.call), + Text(parsed.call.actionTitle, style: text.titleScreen.copyWith(color: colors.accentFlare)), + DecodedCallView(call: parsed.call, signer: _signer(parsed.call)), const SizedBox(height: 20), _advancedSection(context, parsed), if (_error != null) ...[ const SizedBox(height: 16), Text( _error!, - style: text.detail?.copyWith(color: colors.error), + style: text.caption.copyWith(color: colors.semanticEmber), textAlign: TextAlign.center, ), ], @@ -170,60 +165,45 @@ class _SignTransactionScreenState extends ConsumerState { ); } - /// What is being authorised, then who is authorising it, then the parameters - /// neither of those already showed. - /// - /// A call that dispatches another one — a multisig approval, a batch — leads - /// with the boxed inner call: the amount and recipient inside it are what the - /// signer is really approving, and the wrapper's own parameters (which - /// multisig, which proposal) are context that follows. - /// /// The signer's row claims `From` only when the summary shows a plain send /// and the call names no other account the funds could leave instead — a /// `force_transfer` moves its Source's funds, not the signer's. Anything /// else says no more than `Signed by`. - List _callBody(BuildContext context, DecodedCall call) { + Widget? _signer(DecodedCall call) { final signerAddress = ref.watch(addressProvider); + if (signerAddress == null) return null; + final transfer = heroSummary(call); final fromSigner = transfer?.recipient != null && !call.fields.any( (f) => f is ValueField && f.kind == ValueKind.address && !identical(f, transfer!.recipientField), ); - final signer = signerAddress == null - ? null - : AddressWithCheckphrase(label: fromSigner ? 'From' : 'Signed by', address: signerAddress); - - if (!call.isWrapper) return [...callSummaryBody(call), ?signer]; + final label = fromSigner ? 'From' : 'Signed by'; + final phrase = ref + .watch(checksumNameProvider(signerAddress)) + .maybeWhen(data: (value) => value.isEmpty ? null : value, orElse: () => null); - return [ - for (final field in call.fields.whereType()) CallFieldView(field: field), - ?signer, - for (final field in call.fields.where((f) => f is! NestedCallField)) CallFieldView(field: field), - ]; + return DetailSummaryRow.stacked(label: label, value: signerAddress, monospace: true, checkphrase: phrase); } /// Everything a signer never verifies by eye: the signed extensions and the /// bytes themselves, listed plainly for the rare reader who wants them. Widget _advancedSection(BuildContext context, ParsedPayload parsed) { - final colors = context.colors; - final text = context.themeText; + final colors = context.colorsV3; + final text = context.themeTextV3; return GestureDetector( behavior: HitTestBehavior.opaque, - onTap: () => showTitledSheet( - context, + onTap: () => _showSheet( title: 'Advanced', - child: Text( - _advancedLines(parsed).join('\n'), - style: text.detail?.copyWith(color: colors.textMuted, fontFamily: AppTextTheme.fontFamilySecondary), - ), + child: Text(_advancedLines(parsed).join('\n'), style: text.dataAddress.copyWith(color: colors.textMuted)), ), child: Row( children: [ - Text('ADVANCED', style: text.transactionDetailRowLabel?.copyWith(color: colors.textLabel)), + Text('ADVANCED', style: text.labelData.copyWith(color: colors.textMuted)), const SizedBox(width: 6), - Icon(Icons.chevron_right, size: 18, color: colors.textLabel), + Icon(Icons.chevron_right, size: 18, color: colors.textMuted), ], ), ); @@ -248,30 +228,27 @@ class _SignTransactionScreenState extends ConsumerState { } Widget _specDriftBanner(BuildContext context, SignedExtensions ext) { - final colors = context.colors; - final text = context.themeText; + final colors = context.colorsV3; + final text = context.themeTextV3; return Container( margin: const EdgeInsets.only(bottom: 20), padding: const EdgeInsets.all(14), decoration: BoxDecoration( - color: colors.error.withValues(alpha: 0.12), - borderRadius: BorderRadius.circular(10), - border: Border.all(color: colors.error), + color: colors.semanticEmber.useOpacity(0.12), + borderRadius: context.radiusV3.mdBorder, + border: Border.all(color: colors.semanticEmber), ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Icon(Icons.warning_amber_rounded, color: colors.error, size: 22), + Icon(Icons.warning_amber_rounded, color: colors.semanticEmber, size: 22), const SizedBox(width: 10), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - 'Built for a different runtime', - style: text.smallParagraph?.copyWith(color: colors.error, fontWeight: FontWeight.w700), - ), + Text('Built for a different runtime', style: text.bodyEmphasis.copyWith(color: colors.semanticEmber)), const SizedBox(height: 4), Text( 'This payload targets spec ${ext.specVersion} / tx version ${ext.transactionVersion}, but this ' @@ -279,7 +256,7 @@ class _SignTransactionScreenState extends ConsumerState { '${AppConstants.bundledTransactionVersion}. Across runtime versions the same index can mean a ' 'different call, so the parameters below may be mislabelled. Update the cold wallet before signing ' 'anything you cannot verify another way.', - style: text.detail?.copyWith(color: colors.textSecondary), + style: text.caption.copyWith(color: colors.textMuted), ), ], ), @@ -289,16 +266,23 @@ class _SignTransactionScreenState extends ConsumerState { ); } + Future _showSheet({required String title, required Widget child}) { + return BottomSheetContainer.show( + context, + builder: (ctx) => BottomSheetContainer(title: title, child: child), + ); + } + /// Pauses the animation and opens the tuning sheet; resumes when it closes. Future _pauseAndTune() async { setState(() => _qrPaused = true); - await showTitledSheet(context, title: 'QR display options', child: const QrTuningControls()); + await _showSheet(title: 'QR display options', child: const QrTuningControls()); if (mounted) setState(() => _qrPaused = false); } Widget _signatureView(BuildContext context, Uint8List signed) { - final colors = context.colors; - final text = context.themeText; + final colors = context.colorsV3; + final text = context.themeTextV3; final settings = ref.watch(coldSettingsProvider); if (_urParts == null || _urPartsBytes != settings.qrBytes) { @@ -316,7 +300,7 @@ class _SignTransactionScreenState extends ConsumerState { const SizedBox(height: 8), Text( 'Scan this with your hot wallet to broadcast the transaction.', - style: text.smallParagraph?.copyWith(color: colors.textSecondary), + style: text.body.copyWith(color: colors.textMuted), textAlign: TextAlign.center, ), const SizedBox(height: 24), @@ -330,7 +314,7 @@ class _SignTransactionScreenState extends ConsumerState { Text( '${parts.length} ${parts.length == 1 ? 'frame' : 'frames'} · ${settings.qrFps} FPS · ' '${settings.qrBytes} bytes', - style: text.detail?.copyWith(color: colors.textMuted), + style: text.caption.copyWith(color: colors.textMuted), ), if (parts.length > 1) ...[ const SizedBox(width: 12), @@ -339,8 +323,8 @@ class _SignTransactionScreenState extends ConsumerState { child: Container( width: 32, height: 32, - decoration: BoxDecoration(color: colors.surfaceDeep, shape: BoxShape.circle), - child: Icon(Icons.pause_rounded, size: 20, color: colors.textPrimary), + decoration: BoxDecoration(color: colors.bgSurface2, shape: BoxShape.circle), + child: Icon(Icons.pause_rounded, size: 20, color: colors.textContent), ), ), ], @@ -350,7 +334,7 @@ class _SignTransactionScreenState extends ConsumerState { const SizedBox(height: 16), Text( 'Animated QR — keep both devices steady until the hot wallet finishes scanning.', - style: text.detail?.copyWith(color: colors.textMuted), + style: text.caption.copyWith(color: colors.textMuted), textAlign: TextAlign.center, ), ], @@ -362,4 +346,4 @@ class _SignTransactionScreenState extends ConsumerState { ), ); } -} \ No newline at end of file +} diff --git a/cold-wallet-app/test/call_display_test.dart b/cold-wallet-app/test/call_display_test.dart index 11e28b93b..241a3f163 100644 --- a/cold-wallet-app/test/call_display_test.dart +++ b/cold-wallet-app/test/call_display_test.dart @@ -7,15 +7,11 @@ import 'package:quantus_sdk/generated/planck/pallets/assets.dart' as assets_pall import 'package:quantus_sdk/generated/planck/pallets/balances.dart' as balances_pallet; import 'package:quantus_sdk/generated/planck/pallets/multisig.dart' as multisig_pallet; import 'package:quantus_sdk/generated/planck/pallets/reversible_transfers.dart' as reversible_pallet; -import 'package:quantus_sdk/generated/planck/pallets/tech_collective.dart' as collective_pallet; import 'package:quantus_sdk/generated/planck/types/sp_runtime/multiaddress/multi_address.dart' as multi_address; import 'package:quantus_sdk/quantus_sdk.dart'; -import 'package:quantus_cold_wallet/components/address_with_checkphrase.dart'; -import 'package:quantus_cold_wallet/components/call_detail_view.dart'; import 'package:quantus_cold_wallet/debug/debug_payloads.dart'; import 'package:quantus_cold_wallet/providers/wallet_providers.dart'; import 'package:quantus_cold_wallet/screens/sign_transaction_screen.dart'; -import 'package:quantus_cold_wallet/theme/app_theme.dart'; final aliceId = Uint8List.fromList(List.filled(32, 0xAA)); final bobId = Uint8List.fromList(List.filled(32, 0xBB)); @@ -24,37 +20,12 @@ const signerAddress = 'qz-test-signer-address'; multi_address.MultiAddress account(Uint8List id) => multi_address.MultiAddress.values.id(id); -DecodedCall roundTrip(RuntimeCall call) => CallDecoder.decodeBytes(call.encode()); - -/// The screen's contract: every field of [call] reaches the screen exactly -/// once — as its own row, or restated by the summary hero the body leads with. -/// A field is only ever suppressed for the exact hero widget that restates it. -void expectEveryFieldShownOnce(DecodedCall call) { - final body = callSummaryBody(call); - final rows = body.whereType().map((w) => w.field).toList(); - final summary = heroSummary(call); - final showsAmount = body.any((w) => w is TransferAmount); - final showsRecipient = body.any((w) => w is AddressWithCheckphrase && w.label == 'To'); - - for (final field in call.fields) { - final restated = - (showsAmount && identical(field, summary?.amountField)) || - (showsRecipient && identical(field, summary?.recipientField)); - expect( - rows.where((f) => identical(f, field)).length, - restated ? 0 : 1, - reason: '${call.displayTitle}: "${field.label}" must reach the screen exactly once', - ); - if (field is NestedCallField) expectEveryFieldShownOnce(field.call); - } -} - Future pumpSignScreen(WidgetTester tester, Uint8List payload) async { await tester.pumpWidget( ProviderScope( overrides: [ addressProvider.overrideWith((ref) => signerAddress), - addressCheckphraseProvider.overrideWith((ref, address) async => 'check phrase'), + checksumNameProvider.overrideWith((ref, address) async => 'check phrase'), ], child: MaterialApp( home: Builder( @@ -69,43 +40,7 @@ Future pumpSignScreen(WidgetTester tester, Uint8List payload) async { await tester.pumpAndSettle(); } -AddressWithCheckphrase signerRow(WidgetTester tester) => tester.widget( - find.byWidgetPredicate((w) => w is AddressWithCheckphrase && w.address == signerAddress), -); - void main() { - group('every field reaches the screen exactly once', () { - final fixtures = { - 'plain transfer': const balances_pallet.Txs().transferAllowDeath(dest: account(bobId), value: oneToken), - 'force_transfer with source == destination': const balances_pallet.Txs().forceTransfer( - source: account(bobId), - dest: account(bobId), - value: oneToken, - ), - 'multisig approve wrapping a transfer': const multisig_pallet.Txs().approve( - multisigAddress: aliceId, - proposalId: 12, - call: const balances_pallet.Txs().transferAllowDeath(dest: account(bobId), value: oneToken).encode(), - ), - 'governance vote (no transfer summary)': const collective_pallet.Txs().vote(poll: 7, aye: true), - }; - - for (final entry in fixtures.entries) { - test(entry.key, () => expectEveryFieldShownOnce(roundTrip(entry.value))); - } - }); - - test('force_transfer keeps its Source row even when it equals the recipient', () { - final call = roundTrip( - const balances_pallet.Txs().forceTransfer(source: account(bobId), dest: account(bobId), value: oneToken), - ); - final body = callSummaryBody(call); - final labels = body.whereType().map((w) => w.field.label).toList(); - expect(labels, contains('Source')); - expect(labels, isNot(contains('Destination')), reason: 'the To row already restates the destination'); - expect(body.any((w) => w is AddressWithCheckphrase && w.label == 'To'), isTrue); - }); - group('sign screen', () { testWidgets('headlines summarise; the exact call chain lives in Advanced', (tester) async { final inner = const balances_pallet.Txs().transferAllowDeath(dest: account(bobId), value: oneToken); @@ -155,7 +90,7 @@ void main() { ), ); expect(find.text('SEND'), findsOneWidget); - expect(signerRow(tester).label, 'From'); + expect(find.text('FROM'), findsOneWidget); }); testWidgets('signer row reads Signed by when the funds leave an explicit source', (tester) async { @@ -165,12 +100,12 @@ void main() { const balances_pallet.Txs().forceTransfer(source: account(aliceId), dest: account(bobId), value: oneToken), ), ); - expect(signerRow(tester).label, 'Signed by'); + expect(find.text('SIGNED BY'), findsOneWidget); }); testWidgets('signer row reads Signed by when nothing is sent', (tester) async { await pumpSignScreen(tester, DebugPayloads.governanceVoteAye()); - expect(signerRow(tester).label, 'Signed by'); + expect(find.text('SIGNED BY'), findsOneWidget); }); }); } diff --git a/quantus_sdk/lib/src/ui/components/decoded_call_view.dart b/quantus_sdk/lib/src/ui/components/decoded_call_view.dart index dcad9b211..9063f28ab 100644 --- a/quantus_sdk/lib/src/ui/components/decoded_call_view.dart +++ b/quantus_sdk/lib/src/ui/components/decoded_call_view.dart @@ -10,10 +10,61 @@ enum DecodedCallLayout { compact, } +/// True when [summary] already puts this exact field on screen, so listing it +/// again would only add noise. Matches by identity, never by label or value. +bool coveredBySummary(CallField field, TransferSummary summary) { + if (identical(field, summary.amountField)) return true; + return summary.recipient != null && identical(field, summary.recipientField); +} + +/// The transfer a call performs, or null when it dispatches another call. +/// +/// A wrapper inherits the summary of the call it carries; the amount belongs +/// on that inner call, where the nested box shows it, not on the wrapper. +TransferSummary? heroSummary(DecodedCall call) => call.isWrapper ? null : call.summary; + +/// Asset amounts stay in the payload's own raw units: decimals are per-asset +/// chain state an air-gapped signer cannot resolve. +String assetAmountText(BigInt amount, int assetId) => '$amount raw units of asset $assetId'; + +String? _resolvedPhrase(String address, String? Function(String address)? checkphraseOf) { + final phrase = checkphraseOf?.call(address); + if (phrase == null || phrase.isEmpty) return null; + return phrase; +} + +bool _isMonospace(ValueKind kind) => switch (kind) { + ValueKind.address || ValueKind.hash || ValueKind.bytes => true, + _ => false, +}; + +Widget _callDetailRow({ + required String label, + required String value, + required ValueKind kind, + required DecodedCallLayout layout, + String? note, + String? checkphrase, +}) { + final monospace = _isMonospace(kind); + if (layout == DecodedCallLayout.stacked) { + return DetailSummaryRow.stacked( + label: label, + value: value, + monospace: monospace, + note: note, + checkphrase: checkphrase, + ); + } + return DetailSummaryRow(label: label, value: value, monospace: monospace, note: note, checkphrase: checkphrase); +} + /// Renders every parameter of a [DecodedCall], nested calls included. /// /// Presentational only. Amounts and checkphrases are already-resolved strings -/// from the host app. Both layouts use v3 tokens; only geometry differs. +/// from the host app. Compact lists every field under the runtime title. +/// Stacked is the signing reading order: action title, hero amount and +/// recipient, then every remaining parameter. class DecodedCallView extends StatelessWidget { final DecodedCall call; @@ -28,6 +79,15 @@ class DecodedCallView extends StatelessWidget { /// Resolved checkphrase for an ss58 address, or null while loading / unknown. final String? Function(String address)? checkphraseOf; + /// Host-provided signer row. Stacked wrappers insert it after nested calls. + final Widget? signer; + + /// When false, the call title is omitted (the host already showed it). + final bool showTitle; + + /// Label for the stacked recipient row. Ignored in compact layout. + final String recipientLabel; + const DecodedCallView({ super.key, required this.call, @@ -35,32 +95,107 @@ class DecodedCallView extends StatelessWidget { this.layout = DecodedCallLayout.compact, this.checkphraseOf, this.depth = 0, + this.signer, + this.showTitle = true, + this.recipientLabel = 'To', }); @override Widget build(BuildContext context) { final colors = context.colorsV3; final text = context.themeTextV3; + final stacked = layout == DecodedCallLayout.stacked; return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - Text( - call.displayTitle, - style: text.headingRow.copyWith(color: depth == 0 ? colors.textContent : colors.textMuted), - ), - SizedBox(height: layout == DecodedCallLayout.stacked ? 8 : 4), - for (final field in call.fields) - _CallFieldView( - field: field, - depth: depth, - layout: layout, - amountText: amountText, - checkphraseOf: checkphraseOf, + if (showTitle) ...[ + Text( + stacked ? call.actionTitle : call.displayTitle, + style: text.headingRow.copyWith(color: depth == 0 ? colors.textContent : colors.textMuted), ), + SizedBox(height: stacked ? 8 : 4), + ], + ..._children(), ], ); } + + List _children() { + if (layout == DecodedCallLayout.stacked && depth == 0 && signer != null && call.isWrapper) { + return [ + for (final field in call.fields.whereType()) _field(field), + signer!, + for (final field in call.fields.where((f) => f is! NestedCallField)) _field(field), + ]; + } + return [..._body(), if (depth == 0 && signer != null) signer!]; + } + + List _body() { + if (layout != DecodedCallLayout.stacked) { + return [for (final field in call.fields) _field(field)]; + } + + final summary = heroSummary(call); + final recipient = summary?.recipient; + return [ + if (summary != null) _TransferAmount(summary: summary, large: depth == 0, amountText: amountText), + if (recipient != null) + _callDetailRow( + label: recipientLabel, + value: recipient, + kind: ValueKind.address, + checkphrase: _resolvedPhrase(recipient, checkphraseOf), + layout: layout, + ), + for (final field in call.fields) + if (summary == null || !coveredBySummary(field, summary)) _field(field), + ]; + } + + Widget _field(CallField field) => _CallFieldView( + field: field, + depth: depth, + layout: layout, + amountText: amountText, + checkphraseOf: checkphraseOf, + recipientLabel: recipientLabel, + ); +} + +class _TransferAmount extends StatelessWidget { + final TransferSummary summary; + final bool large; + final String Function(BigInt token) amountText; + + const _TransferAmount({required this.summary, required this.large, required this.amountText}); + + @override + Widget build(BuildContext context) { + final colors = context.colorsV3; + final text = context.themeTextV3; + + if (summary.assetId != null) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 10), + child: Text( + assetAmountText(summary.amount, summary.assetId!), + style: text.headingRow.copyWith(color: colors.textContent), + ), + ); + } + + final style = large ? text.amountHero : text.amountInline; + return Padding( + padding: const EdgeInsets.symmetric(vertical: 10), + child: FittedBox( + fit: BoxFit.scaleDown, + alignment: Alignment.centerLeft, + child: Text(amountText(summary.amount), style: style.copyWith(color: colors.textContent)), + ), + ); + } } class _CallFieldView extends StatelessWidget { @@ -69,6 +204,7 @@ class _CallFieldView extends StatelessWidget { final DecodedCallLayout layout; final String Function(BigInt token) amountText; final String? Function(String address)? checkphraseOf; + final String recipientLabel; const _CallFieldView({ required this.field, @@ -76,22 +212,23 @@ class _CallFieldView extends StatelessWidget { required this.layout, required this.amountText, required this.checkphraseOf, + required this.recipientLabel, }); @override Widget build(BuildContext context) { return switch (field) { - ValueField(:final label, :final value, :final kind, :final note) => _FieldRow( + ValueField(:final label, :final value, :final kind, :final note) => _callDetailRow( label: label, value: value, kind: kind, note: note, - checkphrase: kind == ValueKind.address ? _phrase(value) : null, + checkphrase: kind == ValueKind.address ? _resolvedPhrase(value, checkphraseOf) : null, layout: layout, ), - AmountField(:final label, :final token, :final assetId, :final note) => _FieldRow( + AmountField(:final label, :final token, :final assetId, :final note) => _callDetailRow( label: label, - value: assetId == null ? amountText(token) : '$token raw units of asset #$assetId', + value: assetId == null ? amountText(token) : assetAmountText(token, assetId), kind: ValueKind.number, note: _amountNote(note, assetId), layout: layout, @@ -103,6 +240,7 @@ class _CallFieldView extends StatelessWidget { layout: layout, amountText: amountText, checkphraseOf: checkphraseOf, + recipientLabel: recipientLabel, ), NestedCallField(:final label, :final call, :final note) => _NestedCallBox( label: label, @@ -112,16 +250,11 @@ class _CallFieldView extends StatelessWidget { layout: layout, amountText: amountText, checkphraseOf: checkphraseOf, + recipientLabel: recipientLabel, ), }; } - String? _phrase(String address) { - final phrase = checkphraseOf?.call(address); - if (phrase == null || phrase.isEmpty) return null; - return phrase; - } - String? _amountNote(String? note, int? assetId) { if (assetId == null) return note; return [ @@ -138,6 +271,7 @@ class _FieldGroupView extends StatelessWidget { final DecodedCallLayout layout; final String Function(BigInt token) amountText; final String? Function(String address)? checkphraseOf; + final String recipientLabel; const _FieldGroupView({ required this.label, @@ -146,6 +280,7 @@ class _FieldGroupView extends StatelessWidget { required this.layout, required this.amountText, required this.checkphraseOf, + required this.recipientLabel, }); @override @@ -169,6 +304,7 @@ class _FieldGroupView extends StatelessWidget { layout: layout, amountText: amountText, checkphraseOf: checkphraseOf, + recipientLabel: recipientLabel, ), ], ), @@ -187,6 +323,7 @@ class _NestedCallBox extends StatelessWidget { final DecodedCallLayout layout; final String Function(BigInt token) amountText; final String? Function(String address)? checkphraseOf; + final String recipientLabel; const _NestedCallBox({ required this.label, @@ -196,6 +333,7 @@ class _NestedCallBox extends StatelessWidget { required this.layout, required this.amountText, required this.checkphraseOf, + required this.recipientLabel, }); @override @@ -222,6 +360,7 @@ class _NestedCallBox extends StatelessWidget { layout: layout, amountText: amountText, checkphraseOf: checkphraseOf, + recipientLabel: recipientLabel, ), ), if (note != null) ...[const SizedBox(height: 4), Text(note!, style: _noteStyle(context))], @@ -231,86 +370,6 @@ class _NestedCallBox extends StatelessWidget { } } -class _FieldRow extends StatelessWidget { - final String label; - final String value; - final ValueKind kind; - final String? note; - final String? checkphrase; - final DecodedCallLayout layout; - - const _FieldRow({ - required this.label, - required this.value, - required this.kind, - required this.layout, - this.note, - this.checkphrase, - }); - - @override - Widget build(BuildContext context) { - return layout == DecodedCallLayout.stacked ? _stacked(context) : _compact(context); - } - - Widget _stacked(BuildContext context) { - final colors = context.colorsV3; - return Padding( - padding: const EdgeInsets.only(top: 12), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Text(label.toUpperCase(), style: _labelStyle(context)), - const SizedBox(height: 8), - Text(value, style: _valueStyle(context, kind, layout)), - if (note != null) ...[const SizedBox(height: 4), Text(note!, style: _noteStyle(context))], - if (checkphrase != null) ...[ - const SizedBox(height: 12), - Text('$label checkphrase'.toUpperCase(), style: _labelStyle(context)), - const SizedBox(height: 8), - Text(checkphrase!, style: _valueStyle(context, kind, layout).copyWith(color: colors.semanticLilac)), - ], - ], - ), - ); - } - - Widget _compact(BuildContext context) { - final colors = context.colorsV3; - return Padding( - padding: const EdgeInsets.only(top: 8), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded(flex: 2, child: Text(label, style: _labelStyle(context))), - const SizedBox(width: 8), - Expanded( - flex: 3, - child: Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Text(value, style: _valueStyle(context, kind, layout), textAlign: TextAlign.right, softWrap: true), - if (checkphrase != null) - Text( - checkphrase!, - style: context.themeTextV3.caption.copyWith(color: colors.semanticLilac), - textAlign: TextAlign.right, - ), - ], - ), - ), - ], - ), - if (note != null) ...[const SizedBox(height: 4), Text(note!, style: _noteStyle(context))], - ], - ), - ); - } -} - TextStyle _labelStyle(BuildContext context) { return context.themeTextV3.labelMonogram.copyWith(fontSize: 10, letterSpacing: 1, color: context.colorsV3.textMuted); } @@ -319,17 +378,6 @@ TextStyle _noteStyle(BuildContext context) { return context.themeTextV3.caption.copyWith(color: context.colorsV3.textMuted); } -TextStyle _valueStyle(BuildContext context, ValueKind kind, DecodedCallLayout layout) { - final text = context.themeTextV3; - final colors = context.colorsV3; - final stacked = layout == DecodedCallLayout.stacked; - final base = switch (kind) { - ValueKind.address || ValueKind.hash || ValueKind.bytes => stacked ? text.dataAddressLarge : text.dataAddress, - _ => text.body, - }; - return base.copyWith(color: colors.textContent); -} - /// The one-line-plus-subtitle form of a decoded call, for list rows and sheets. /// /// A transfer keeps reading as an amount and a recipient; anything else names @@ -360,7 +408,7 @@ class DecodedCallHeadline { ); } return DecodedCallHeadline( - primary: summary.assetId == null ? amountText(summary.amount) : '${summary.amount} (asset #${summary.assetId})', + primary: summary.assetId == null ? amountText(summary.amount) : '${summary.amount} (asset ${summary.assetId})', recipient: summary.recipient == null ? null : AddressFormattingService.formatAddress(summary.recipient!), ); } diff --git a/quantus_sdk/lib/src/ui/components/detail_summary_row.dart b/quantus_sdk/lib/src/ui/components/detail_summary_row.dart index e3e013172..67d2cb396 100644 --- a/quantus_sdk/lib/src/ui/components/detail_summary_row.dart +++ b/quantus_sdk/lib/src/ui/components/detail_summary_row.dart @@ -22,14 +22,19 @@ class DetailSummaryRow extends StatelessWidget { final TextStyle? valueStyle; final DetailSummaryLayout layout; - /// Monospace value, for addresses, hashes and byte blobs. [stacked] only. + /// Monospace value, for addresses, hashes and byte blobs. final bool monospace; final Color? valueColor; - /// Caveat shown under the value. [stacked] only. + /// Caveat shown under the value. final String? note; + /// Resolved checkphrase for an address value. + /// + /// Compact paints it under the value; stacked uses a second labeled row. + final String? checkphrase; + const DetailSummaryRow({ super.key, required this.label, @@ -44,7 +49,9 @@ class DetailSummaryRow extends StatelessWidget { this.monospace = false, this.valueColor, this.note, - }) : assert(value != null || valueWidget != null); + this.checkphrase, + }) : assert(value != null || valueWidget != null), + assert(checkphrase == null || valueWidget == null); factory DetailSummaryRow.review({ Key? key, @@ -74,6 +81,7 @@ class DetailSummaryRow extends StatelessWidget { this.monospace = false, this.valueColor, this.note, + this.checkphrase, }) : valueWidget = null, labelFlex = 2, valueFlex = 3, @@ -91,34 +99,59 @@ class DetailSummaryRow extends StatelessWidget { final text = context.themeTextV3; final colors = context.colorsV3; final effectiveLabelStyle = labelStyle ?? _labelStyle(text, colors); - final effectiveValueStyle = valueStyle ?? text.body.copyWith(color: colors.textContent); + final effectiveValueStyle = + valueStyle ?? (monospace ? text.dataAddress : text.body).copyWith(color: valueColor ?? colors.textContent); - return Container( + return Padding( padding: padding, - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - Expanded( - flex: labelFlex, - child: Text(label, style: effectiveLabelStyle), - ), - const SizedBox(width: 8), - Expanded( - flex: valueFlex, - child: Align( - alignment: Alignment.centerRight, - child: - valueWidget ?? Text(value!, style: effectiveValueStyle, textAlign: TextAlign.right, softWrap: true), - ), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + flex: labelFlex, + child: Text(label, style: effectiveLabelStyle), + ), + const SizedBox(width: 8), + Expanded( + flex: valueFlex, + child: Align( + alignment: Alignment.centerRight, + child: valueWidget ?? _compactValue(effectiveValueStyle, text, colors), + ), + ), + ], ), + if (note != null) ...[const SizedBox(height: 4), Text(note!, style: _noteStyle(text, colors))], ], ), ); } + Widget _compactValue(TextStyle valueStyle, AppTextThemeV3 text, AppColorsV3 colors) { + final valueText = Text(value!, style: valueStyle, textAlign: TextAlign.right, softWrap: true); + if (checkphrase == null) return valueText; + return Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + valueText, + Text( + checkphrase!, + style: text.caption.copyWith(color: colors.semanticLilac), + textAlign: TextAlign.right, + ), + ], + ); + } + Widget _stacked(BuildContext context) { final text = context.themeTextV3; final colors = context.colorsV3; + final effectiveValueStyle = (monospace ? text.dataAddressLarge : text.body).copyWith( + color: valueColor ?? colors.textContent, + ); return Padding( padding: padding, @@ -127,13 +160,13 @@ class DetailSummaryRow extends StatelessWidget { children: [ Text(label.toUpperCase(), style: _labelStyle(text, colors)), const SizedBox(height: 6), - Text( - value!, - style: (monospace ? text.dataAddressLarge : text.body).copyWith(color: valueColor ?? colors.textContent), - ), - if (note != null) ...[ - const SizedBox(height: 4), - Text(note!, style: text.caption.copyWith(color: colors.textMuted)), + Text(value!, style: effectiveValueStyle), + if (note != null) ...[const SizedBox(height: 4), Text(note!, style: _noteStyle(text, colors))], + if (checkphrase != null) ...[ + const SizedBox(height: 10), + Text('$label checkphrase'.toUpperCase(), style: _labelStyle(text, colors)), + const SizedBox(height: 6), + Text(checkphrase!, style: effectiveValueStyle.copyWith(color: colors.semanticLilac)), ], ], ), @@ -143,4 +176,8 @@ class DetailSummaryRow extends StatelessWidget { TextStyle _labelStyle(AppTextThemeV3 text, AppColorsV3 colors) { return text.labelMonogram.copyWith(fontSize: 10, letterSpacing: 1, color: colors.textMuted); } + + TextStyle _noteStyle(AppTextThemeV3 text, AppColorsV3 colors) { + return text.caption.copyWith(color: colors.textMuted); + } } diff --git a/quantus_sdk/test/ui/decoded_call_view_test.dart b/quantus_sdk/test/ui/decoded_call_view_test.dart index 8bdb0ba50..f48f02916 100644 --- a/quantus_sdk/test/ui/decoded_call_view_test.dart +++ b/quantus_sdk/test/ui/decoded_call_view_test.dart @@ -10,7 +10,12 @@ void main() { const dest = ValueField('Destination', 'qzDest', kind: ValueKind.address); final amount = AmountField('Amount', BigInt.from(1000)); - final transfer = DecodedCall(pallet: 'Balances', call: 'transfer_allow_death', fields: [dest, amount]); + final transfer = DecodedCall( + pallet: 'Balances', + call: 'transfer_allow_death', + fields: [dest, amount], + summary: TransferSummary(amount: amount.token, recipient: dest.value, amountField: amount, recipientField: dest), + ); Future pumpCall(WidgetTester tester, Widget view, {Size size = const Size(375, 667)}) async { await tester.pumpWidget( @@ -57,10 +62,11 @@ void main() { view(call: transfer, layout: DecodedCallLayout.stacked, checkphraseOf: (address) => 'alpha bravo charlie'), ); - expect(find.text('DESTINATION'), findsOneWidget); - expect(find.text('DESTINATION CHECKPHRASE'), findsOneWidget); + expect(find.text('TO'), findsOneWidget); + expect(find.text('TO CHECKPHRASE'), findsOneWidget); final phrase = tester.widget(find.text('alpha bravo charlie')); expect(phrase.style?.color, colors.semanticLilac); + expect(find.ancestor(of: find.text('TO'), matching: find.byType(DetailSummaryRow)), findsOneWidget); }); testWidgets('compact layout keeps title-case labels and right-aligns values', (tester) async { @@ -71,6 +77,7 @@ void main() { final value = tester.widget(find.text('qzDest')); expect(value.textAlign, TextAlign.right); expect(value.style?.fontFamily, AppTextTheme.fontFamilySecondary); + expect(find.ancestor(of: find.text('Destination'), matching: find.byType(DetailSummaryRow)), findsOneWidget); }); testWidgets('nested call uses surface2 fill, hairline, and v3 md radius', (tester) async { @@ -105,7 +112,7 @@ void main() { await pumpCall(tester, view(call: call)); - expect(find.text('99 raw units of asset #7'), findsOneWidget); + expect(find.text('99 raw units of asset 7'), findsOneWidget); expect(find.text('Asset decimals are not part of this payload, so the raw amount is shown.'), findsOneWidget); }); @@ -122,4 +129,85 @@ void main() { expect(hash.style?.fontFamily, AppTextTheme.fontFamilySecondary); expect(hash.style?.color, colors.textContent); }); + + testWidgets('stacked transfer headlines as SEND and leads with amount and To once', (tester) async { + await pumpCall(tester, view(call: transfer, layout: DecodedCallLayout.stacked)); + + expect(find.text('SEND'), findsOneWidget); + expect(find.text('Balances · transfer_allow_death'), findsNothing); + expect(find.text('1000 QNT'), findsOneWidget); + expect(find.text('TO'), findsOneWidget); + expect(find.text('qzDest'), findsOneWidget); + expect(find.text('AMOUNT'), findsNothing); + expect(find.text('DESTINATION'), findsNothing); + }); + + testWidgets('stacked force_transfer keeps Source when it equals the recipient', (tester) async { + const source = ValueField('Source', 'qzDest', kind: ValueKind.address); + final call = DecodedCall( + pallet: 'Balances', + call: 'force_transfer', + fields: [source, dest, amount], + summary: TransferSummary(amount: amount.token, recipient: dest.value, amountField: amount, recipientField: dest), + ); + + await pumpCall(tester, view(call: call, layout: DecodedCallLayout.stacked)); + + expect(find.text('SOURCE'), findsOneWidget); + expect(find.text('DESTINATION'), findsNothing); + expect(find.text('TO'), findsOneWidget); + }); + + testWidgets('stacked wrapper names itself and puts the hero on the inner call', (tester) async { + final outer = DecodedCall( + pallet: 'Multisig', + call: 'approve', + fields: [ + NestedCallField('You are approving', transfer), + const ValueField('Proposal id', '12', kind: ValueKind.number), + ], + summary: transfer.summary, + ); + + await pumpCall(tester, view(call: outer, layout: DecodedCallLayout.stacked)); + + expect(find.text('MULTISIG APPROVE'), findsOneWidget); + expect(find.text('SEND'), findsOneWidget); + expect(find.text('1000 QNT'), findsOneWidget); + expect(find.text('YOU ARE APPROVING'), findsOneWidget); + expect(find.text('PROPOSAL ID'), findsOneWidget); + }); + + testWidgets('stacked wrapper with signer leads with the nested call', (tester) async { + final outer = DecodedCall( + pallet: 'Multisig', + call: 'approve', + fields: [ + NestedCallField('You are approving', transfer), + const ValueField('Proposal id', '12', kind: ValueKind.number), + ], + summary: transfer.summary, + ); + + await pumpCall( + tester, + DecodedCallView( + call: outer, + layout: DecodedCallLayout.stacked, + amountText: (token) => '$token QNT', + showTitle: false, + signer: const Text('SIGNER'), + ), + ); + + expect(find.text('MULTISIG APPROVE'), findsNothing); + expect(find.text('SEND'), findsOneWidget); + expect(find.text('SIGNER'), findsOneWidget); + + final nestedTop = tester.getTopLeft(find.text('YOU ARE APPROVING')).dy; + final signerTop = tester.getTopLeft(find.text('SIGNER')).dy; + final proposalTop = tester.getTopLeft(find.text('PROPOSAL ID')).dy; + expect(nestedTop, lessThan(signerTop)); + expect(signerTop, lessThan(proposalTop)); + }); } diff --git a/quantus_sdk/test/ui/detail_summary_row_test.dart b/quantus_sdk/test/ui/detail_summary_row_test.dart index 263461161..a4232f430 100644 --- a/quantus_sdk/test/ui/detail_summary_row_test.dart +++ b/quantus_sdk/test/ui/detail_summary_row_test.dart @@ -66,4 +66,44 @@ void main() { expect(value.style?.color, colors.semanticLilac); expect(find.text('Verify out loud.'), findsOneWidget); }); + + testWidgets('stacked checkphrase is a second labeled row in lilac', (tester) async { + await pumpRow( + tester, + const DetailSummaryRow.stacked(label: 'To', value: 'qzDest', monospace: true, checkphrase: 'alpha bravo'), + ); + + expect(find.text('TO'), findsOneWidget); + expect(find.text('TO CHECKPHRASE'), findsOneWidget); + final phrase = tester.widget(find.text('alpha bravo')); + expect(phrase.style?.color, colors.semanticLilac); + expect(phrase.style?.fontSize, text.dataAddressLarge.fontSize); + }); + + testWidgets('compact checkphrase sits under the value without a second label', (tester) async { + await pumpRow( + tester, + const DetailSummaryRow(label: 'Destination', value: 'qzDest', monospace: true, checkphrase: 'alpha bravo'), + ); + + expect(find.text('DESTINATION CHECKPHRASE'), findsNothing); + expect(find.text('Destination checkphrase'), findsNothing); + final phrase = tester.widget(find.text('alpha bravo')); + expect(phrase.style?.color, colors.semanticLilac); + expect(phrase.style?.fontSize, text.caption.fontSize); + expect(phrase.textAlign, TextAlign.right); + + final value = tester.widget(find.text('qzDest')); + expect(value.style?.fontFamily, AppTextTheme.fontFamilySecondary); + expect(value.textAlign, TextAlign.right); + }); + + testWidgets('compact shows a note under the row', (tester) async { + await pumpRow( + tester, + const DetailSummaryRow(label: 'Amount', value: '99 raw', note: 'Asset decimals are not in this payload.'), + ); + + expect(find.text('Asset decimals are not in this payload.'), findsOneWidget); + }); } From 80f8279fb02578fa9d5f3e9b6934970f7f7cd079 Mon Sep 17 00:00:00 2001 From: Beast Date: Thu, 20 Aug 2026 13:50:11 +0800 Subject: [PATCH 34/38] feat: finish updating to V3 --- .../lib/screens/scan_transaction_screen.dart | 48 ++++++++++--------- .../test/scan_transaction_screen_test.dart | 8 ++++ 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/cold-wallet-app/lib/screens/scan_transaction_screen.dart b/cold-wallet-app/lib/screens/scan_transaction_screen.dart index a6411c965..338fc2dd3 100644 --- a/cold-wallet-app/lib/screens/scan_transaction_screen.dart +++ b/cold-wallet-app/lib/screens/scan_transaction_screen.dart @@ -77,12 +77,13 @@ class _ScanTransactionScreenState extends State { /// One button per payload in [DebugPayloads.all], so every screen the signer /// can be shown is one tap away on a simulator. Widget _debugPayloadButtons(BuildContext context) { - final text = context.themeText; + final colors = context.colorsV3; + final text = context.themeTextV3; return Column( mainAxisSize: MainAxisSize.min, children: [ - Text('DEBUG PAYLOADS', style: text.detail?.copyWith(color: Colors.white38, letterSpacing: 1.2)), + Text('DEBUG PAYLOADS', style: text.caption.copyWith(color: colors.textMuted)), const SizedBox(height: 8), Wrap( alignment: WrapAlignment.center, @@ -92,12 +93,12 @@ class _ScanTransactionScreenState extends State { for (final entry in DebugPayloads.all.entries) ElevatedButton( style: ElevatedButton.styleFrom( - backgroundColor: Colors.white24, + backgroundColor: colors.bgSurface, padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), visualDensity: VisualDensity.compact, ), onPressed: () => _loadDebugPayload(entry.value()), - child: Text(entry.key, style: text.detail?.copyWith(color: Colors.white)), + child: Text(entry.key, style: text.caption.copyWith(color: colors.textContent)), ), ], ), @@ -122,22 +123,24 @@ class _ScanTransactionScreenState extends State { } Widget _cameraError(BuildContext context, MobileScannerException error) { + final colors = context.colorsV3; + final text = context.themeTextV3; final denied = error.errorCode == MobileScannerErrorCode.permissionDenied; final detail = error.errorDetails?.message; return ColoredBox( - color: Colors.black, + color: colors.bgVoid, child: Center( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 32), child: Column( mainAxisSize: MainAxisSize.min, children: [ - const Icon(Icons.no_photography_outlined, color: Colors.white70, size: 64), + Icon(Icons.no_photography_outlined, color: colors.textMuted, size: 64), const SizedBox(height: 24), - const Text( + Text( 'Camera unavailable', - style: TextStyle(color: Colors.white, fontSize: 20, fontWeight: FontWeight.w600), + style: text.titleScreen.copyWith(color: colors.textContent), textAlign: TextAlign.center, ), const SizedBox(height: 12), @@ -146,7 +149,7 @@ class _ScanTransactionScreenState extends State { ? 'Grant camera access in Settings to scan the transaction QR.' : 'The camera could not be started (${error.errorCode.name})' '${detail == null ? '' : ': $detail'}.', - style: const TextStyle(color: Colors.white70), + style: text.body.copyWith(color: colors.textMuted), textAlign: TextAlign.center, ), const SizedBox(height: 24), @@ -160,15 +163,16 @@ class _ScanTransactionScreenState extends State { @override Widget build(BuildContext context) { - final colors = context.colors; - final text = context.themeText; + final colors = context.colorsV3; + final text = context.themeTextV3; + final radius = context.radiusV3; final size = MediaQuery.of(context).size; final frame = (size.width - 96).clamp(220.0, 300.0); final progress = _expectedParts == null ? null : (_seenSeq.length / _expectedParts!).clamp(0.0, 1.0); return Scaffold( - backgroundColor: Colors.black, + backgroundColor: colors.bgVoid, body: Stack( children: [ MobileScanner(controller: _controller, onDetect: _onDetect, errorBuilder: _cameraError), @@ -177,8 +181,8 @@ class _ScanTransactionScreenState extends State { width: frame, height: frame, decoration: BoxDecoration( - border: Border.all(color: colors.accentOrange, width: 2), - borderRadius: BorderRadius.circular(16), + border: Border.all(color: colors.accentFlare, width: 2), + borderRadius: radius.mdBorder, ), ), ), @@ -191,12 +195,12 @@ class _ScanTransactionScreenState extends State { children: [ IconButton( onPressed: () => Navigator.pop(context), - icon: const Icon(Icons.arrow_back, color: Colors.white), + icon: Icon(Icons.arrow_back, color: colors.textContent), ), const Spacer(), IconButton( onPressed: _controller.toggleTorch, - icon: const Icon(Icons.flash_on, color: Colors.white), + icon: Icon(Icons.flash_on, color: colors.textContent), ), ], ), @@ -212,27 +216,27 @@ class _ScanTransactionScreenState extends State { if (kDebugMode) _debugPayloadButtons(context), Text( _error ?? 'Scan the transaction QR from your hot wallet', - style: text.paragraph?.copyWith(color: _error != null ? colors.error : Colors.white), + style: text.body.copyWith(color: _error != null ? colors.semanticEmber : colors.textContent), textAlign: TextAlign.center, ), const SizedBox(height: 16), if (progress != null) ...[ ClipRRect( - borderRadius: BorderRadius.circular(4), + borderRadius: radius.xsBorder, child: LinearProgressIndicator( value: progress, minHeight: 6, - backgroundColor: colors.surface, - color: colors.accentOrange, + backgroundColor: colors.bgSurface, + color: colors.accentFlare, ), ), const SizedBox(height: 8), Text( '${_seenSeq.length} / ${_expectedParts!} parts', - style: text.detail?.copyWith(color: Colors.white70), + style: text.caption.copyWith(color: colors.textMuted), ), ] else if (_parts.isNotEmpty) - Text('${_parts.length} parts scanned', style: text.detail?.copyWith(color: Colors.white70)), + Text('${_parts.length} parts scanned', style: text.caption.copyWith(color: colors.textMuted)), ], ), ), diff --git a/cold-wallet-app/test/scan_transaction_screen_test.dart b/cold-wallet-app/test/scan_transaction_screen_test.dart index 9be6a2b3e..30aaf9037 100644 --- a/cold-wallet-app/test/scan_transaction_screen_test.dart +++ b/cold-wallet-app/test/scan_transaction_screen_test.dart @@ -42,5 +42,13 @@ void main() { final debugLabel = tester.widget(find.text('DEBUG PAYLOADS')); expect(debugLabel.style?.color, colors.textMuted); expect(debugLabel.style?.fontSize, text.caption.fontSize); + + final sendButton = tester.widget(find.widgetWithText(ElevatedButton, 'Send')); + expect(sendButton.style?.backgroundColor?.resolve({}), colors.bgSurface); + final sendLabel = tester.widget( + find.descendant(of: find.widgetWithText(ElevatedButton, 'Send'), matching: find.text('Send')), + ); + expect(sendLabel.style?.color, colors.textContent); + expect(sendLabel.style?.fontSize, text.caption.fontSize); }); } From abbefd018f52f246b7d266c338291a023652b2b9 Mon Sep 17 00:00:00 2001 From: Beast Date: Thu, 20 Aug 2026 14:42:29 +0800 Subject: [PATCH 35/38] fix: try again button width --- cold-wallet-app/lib/screens/scan_transaction_screen.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cold-wallet-app/lib/screens/scan_transaction_screen.dart b/cold-wallet-app/lib/screens/scan_transaction_screen.dart index 338fc2dd3..0e54906c2 100644 --- a/cold-wallet-app/lib/screens/scan_transaction_screen.dart +++ b/cold-wallet-app/lib/screens/scan_transaction_screen.dart @@ -153,7 +153,7 @@ class _ScanTransactionScreenState extends State { textAlign: TextAlign.center, ), const SizedBox(height: 24), - QuantusButton.simple(label: 'Try again', width: null, onTap: _restartCamera), + QuantusButton.simple(label: 'Try again', width: 240, onTap: _restartCamera), ], ), ), From bef7f155c27e424d5906809ad577ff05e1cd1faf Mon Sep 17 00:00:00 2001 From: Beast Date: Thu, 20 Aug 2026 14:56:46 +0800 Subject: [PATCH 36/38] fix: not showing network banner --- .../v2/components/recovery_phrase_body.dart | 3 +- .../lib/v2/components/scaffold_base.dart | 70 +++++++++++++++++++ .../accounts/account_details_screen.dart | 3 +- .../screens/accounts/account_menu_screen.dart | 3 +- .../accounts/account_ready_screen.dart | 3 +- .../v2/screens/accounts/accounts_screen.dart | 3 +- .../accounts/add_hardware_account_screen.dart | 3 +- .../accounts/connect_keystone_screen.dart | 3 +- .../accounts/create_account_screen.dart | 3 +- .../screens/accounts/edit_account_screen.dart | 3 +- .../multisig_account_menu_screen.dart | 3 +- .../accounts/multisig_details_screen.dart | 3 +- .../screens/accounts/wallet_name_screen.dart | 3 +- .../v2/screens/activity/activity_screen.dart | 3 +- .../lib/v2/screens/home/home_screen.dart | 3 +- .../screens/import/import_wallet_screen.dart | 3 +- .../screens/multisig/add_multisig_screen.dart | 3 +- .../multisig/discover_multisig_screen.dart | 3 +- .../lib/v2/screens/pos/pos_amount_screen.dart | 3 +- .../lib/v2/screens/pos/pos_qr_screen.dart | 3 +- .../v2/screens/receive/receive_screen.dart | 3 +- .../send/encrypted_send_progress_screen.dart | 3 +- .../v2/screens/send/input_amount_screen.dart | 3 +- .../screens/send/keystone_reject_screen.dart | 3 +- .../v2/screens/send/keystone_sign_screen.dart | 3 +- .../screens/send/keystone_verify_screen.dart | 3 +- .../v2/screens/send/review_send_screen.dart | 3 +- .../screens/send/select_recipient_screen.dart | 3 +- .../v2/screens/send/send_terminal_screen.dart | 3 +- .../settings/about_quantus_screen.dart | 3 +- .../settings/add_account_menu_screen.dart | 3 +- .../settings/help_and_support_screen.dart | 3 +- .../settings/mining_rewards_screen.dart | 3 +- .../settings/preferences_settings_screen.dart | 3 +- .../settings/redeem_address_screen.dart | 3 +- .../settings/redeem_progress_screen.dart | 3 +- .../settings/select_wallet_screen.dart | 3 +- .../settings/settings_caution_scaffold.dart | 3 +- .../settings/settings_picker_screen.dart | 3 +- .../v2/screens/settings/settings_screen.dart | 3 +- .../settings/testnet_rewards_screen.dart | 3 +- .../settings/wallet_settings_screen.dart | 3 +- .../lib/v2/screens/swap/deposit_screen.dart | 3 +- .../lib/v2/screens/swap/swap_screen.dart | 3 +- .../v2/screens/welcome/welcome_screen.dart | 3 +- mobile-app/lib/wallet_initializer.dart | 3 +- mobile-app/test/unit/scaffold_base_test.dart | 37 ++++++++++ 47 files changed, 197 insertions(+), 45 deletions(-) create mode 100644 mobile-app/lib/v2/components/scaffold_base.dart create mode 100644 mobile-app/test/unit/scaffold_base_test.dart diff --git a/mobile-app/lib/v2/components/recovery_phrase_body.dart b/mobile-app/lib/v2/components/recovery_phrase_body.dart index 87ff4365b..19798dba5 100644 --- a/mobile-app/lib/v2/components/recovery_phrase_body.dart +++ b/mobile-app/lib/v2/components/recovery_phrase_body.dart @@ -4,7 +4,8 @@ import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/shared/constants/e2e_keys.dart'; import 'package:resonance_network_wallet/shared/extensions/clipboard_extensions.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; class RecoveryPhraseBody extends ConsumerStatefulWidget { final String appBarTitle; diff --git a/mobile-app/lib/v2/components/scaffold_base.dart b/mobile-app/lib/v2/components/scaffold_base.dart new file mode 100644 index 000000000..7fefe7c67 --- /dev/null +++ b/mobile-app/lib/v2/components/scaffold_base.dart @@ -0,0 +1,70 @@ +import 'package:flutter/material.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' as sdk; +import 'package:resonance_network_wallet/v2/components/network_status_banner.dart'; + +class ScaffoldBase extends StatelessWidget { + final Widget? mainContent; + final Widget? bottomContent; + final List? slivers; + final Widget? appBar; + final Widget? networkBanner; + final ScrollController? scrollController; + final ScrollPhysics? scrollPhysics; + final RefreshCallback? onRefresh; + final EdgeInsetsGeometry padding; + final Widget? backgroundWidget; + + const ScaffoldBase({ + super.key, + this.appBar, + this.networkBanner, + this.padding = sdk.ScaffoldBase.defaultPadding, + this.backgroundWidget, + this.bottomContent, + required Widget this.mainContent, + }) : slivers = null, + scrollController = null, + scrollPhysics = null, + onRefresh = null; + + const ScaffoldBase.refreshable({ + super.key, + this.appBar, + this.networkBanner, + this.padding = sdk.ScaffoldBase.defaultPadding, + this.backgroundWidget, + this.scrollController, + this.scrollPhysics = const AlwaysScrollableScrollPhysics(), + this.bottomContent, + required RefreshCallback this.onRefresh, + required List this.slivers, + }) : mainContent = null; + + @override + Widget build(BuildContext context) { + final banner = networkBanner ?? const NetworkStatusBanner(); + + if (onRefresh != null && slivers != null) { + return sdk.ScaffoldBase.refreshable( + appBar: appBar, + networkBanner: banner, + padding: padding, + backgroundWidget: backgroundWidget, + scrollController: scrollController, + scrollPhysics: scrollPhysics, + bottomContent: bottomContent, + onRefresh: onRefresh!, + slivers: slivers!, + ); + } + + return sdk.ScaffoldBase( + appBar: appBar, + networkBanner: banner, + padding: padding, + backgroundWidget: backgroundWidget, + bottomContent: bottomContent, + mainContent: mainContent!, + ); + } +} diff --git a/mobile-app/lib/v2/screens/accounts/account_details_screen.dart b/mobile-app/lib/v2/screens/accounts/account_details_screen.dart index b21fadb21..23d69c827 100644 --- a/mobile-app/lib/v2/screens/accounts/account_details_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/account_details_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/shared/utils/share_utils.dart'; import 'package:resonance_network_wallet/v2/components/address_details_card.dart'; diff --git a/mobile-app/lib/v2/screens/accounts/account_menu_screen.dart b/mobile-app/lib/v2/screens/accounts/account_menu_screen.dart index ebd3b4d3c..9093af928 100644 --- a/mobile-app/lib/v2/screens/accounts/account_menu_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/account_menu_screen.dart @@ -1,7 +1,8 @@ import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; diff --git a/mobile-app/lib/v2/screens/accounts/account_ready_screen.dart b/mobile-app/lib/v2/screens/accounts/account_ready_screen.dart index fcc5cde97..f8645feee 100644 --- a/mobile-app/lib/v2/screens/accounts/account_ready_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/account_ready_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; diff --git a/mobile-app/lib/v2/screens/accounts/accounts_screen.dart b/mobile-app/lib/v2/screens/accounts/accounts_screen.dart index dbba725a1..5b9d7775b 100644 --- a/mobile-app/lib/v2/screens/accounts/accounts_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/accounts_screen.dart @@ -1,7 +1,8 @@ import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/providers/multisig_providers.dart'; import 'package:resonance_network_wallet/shared/utils/accounts_grouping.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; diff --git a/mobile-app/lib/v2/screens/accounts/add_hardware_account_screen.dart b/mobile-app/lib/v2/screens/accounts/add_hardware_account_screen.dart index 93fadc9cc..45567fae0 100644 --- a/mobile-app/lib/v2/screens/accounts/add_hardware_account_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/add_hardware_account_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/v2/screens/accounts/connect_keystone_screen.dart'; import 'package:url_launcher/url_launcher.dart'; diff --git a/mobile-app/lib/v2/screens/accounts/connect_keystone_screen.dart b/mobile-app/lib/v2/screens/accounts/connect_keystone_screen.dart index e390c1704..e5c1e36ed 100644 --- a/mobile-app/lib/v2/screens/accounts/connect_keystone_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/connect_keystone_screen.dart @@ -2,7 +2,8 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/flutter_svg.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/v2/components/qr_scanner_page.dart'; diff --git a/mobile-app/lib/v2/screens/accounts/create_account_screen.dart b/mobile-app/lib/v2/screens/accounts/create_account_screen.dart index 0c650a83d..589fa711b 100644 --- a/mobile-app/lib/v2/screens/accounts/create_account_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/create_account_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/remote_config_provider.dart'; diff --git a/mobile-app/lib/v2/screens/accounts/edit_account_screen.dart b/mobile-app/lib/v2/screens/accounts/edit_account_screen.dart index b35653314..628d25da3 100644 --- a/mobile-app/lib/v2/screens/accounts/edit_account_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/edit_account_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/multisig_providers.dart'; diff --git a/mobile-app/lib/v2/screens/accounts/multisig_account_menu_screen.dart b/mobile-app/lib/v2/screens/accounts/multisig_account_menu_screen.dart index ab1d7bf14..3c3884b59 100644 --- a/mobile-app/lib/v2/screens/accounts/multisig_account_menu_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/multisig_account_menu_screen.dart @@ -1,7 +1,8 @@ import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/multisig_providers.dart'; diff --git a/mobile-app/lib/v2/screens/accounts/multisig_details_screen.dart b/mobile-app/lib/v2/screens/accounts/multisig_details_screen.dart index 19adfb815..b9a82dfec 100644 --- a/mobile-app/lib/v2/screens/accounts/multisig_details_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/multisig_details_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; diff --git a/mobile-app/lib/v2/screens/accounts/wallet_name_screen.dart b/mobile-app/lib/v2/screens/accounts/wallet_name_screen.dart index bad8fabed..0275d329e 100644 --- a/mobile-app/lib/v2/screens/accounts/wallet_name_screen.dart +++ b/mobile-app/lib/v2/screens/accounts/wallet_name_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; import 'package:resonance_network_wallet/v2/components/name_field.dart'; diff --git a/mobile-app/lib/v2/screens/activity/activity_screen.dart b/mobile-app/lib/v2/screens/activity/activity_screen.dart index d64864b6c..a7fa66a31 100644 --- a/mobile-app/lib/v2/screens/activity/activity_screen.dart +++ b/mobile-app/lib/v2/screens/activity/activity_screen.dart @@ -1,7 +1,8 @@ import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/v2/components/skeleton.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; diff --git a/mobile-app/lib/v2/screens/home/home_screen.dart b/mobile-app/lib/v2/screens/home/home_screen.dart index ccea30ddf..1fbb9814e 100644 --- a/mobile-app/lib/v2/screens/home/home_screen.dart +++ b/mobile-app/lib/v2/screens/home/home_screen.dart @@ -3,7 +3,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/legacy.dart'; import 'package:flutter_svg/flutter_svg.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/v2/components/dotted_border.dart'; import 'package:resonance_network_wallet/v2/components/shared_address_action_sheet.dart'; import 'package:resonance_network_wallet/services/global_history_polling_service.dart'; diff --git a/mobile-app/lib/v2/screens/import/import_wallet_screen.dart b/mobile-app/lib/v2/screens/import/import_wallet_screen.dart index 315fd0b24..c6de62a65 100644 --- a/mobile-app/lib/v2/screens/import/import_wallet_screen.dart +++ b/mobile-app/lib/v2/screens/import/import_wallet_screen.dart @@ -3,7 +3,8 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; diff --git a/mobile-app/lib/v2/screens/multisig/add_multisig_screen.dart b/mobile-app/lib/v2/screens/multisig/add_multisig_screen.dart index d438b08be..21761de0a 100644 --- a/mobile-app/lib/v2/screens/multisig/add_multisig_screen.dart +++ b/mobile-app/lib/v2/screens/multisig/add_multisig_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/v2/components/multisig_signer_list_tile.dart'; import 'package:resonance_network_wallet/v2/components/multisig_threshold_slider.dart'; import 'package:resonance_network_wallet/v2/components/name_field.dart'; diff --git a/mobile-app/lib/v2/screens/multisig/discover_multisig_screen.dart b/mobile-app/lib/v2/screens/multisig/discover_multisig_screen.dart index 76a4b5723..95c86829d 100644 --- a/mobile-app/lib/v2/screens/multisig/discover_multisig_screen.dart +++ b/mobile-app/lib/v2/screens/multisig/discover_multisig_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/multisig_providers.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; diff --git a/mobile-app/lib/v2/screens/pos/pos_amount_screen.dart b/mobile-app/lib/v2/screens/pos/pos_amount_screen.dart index ae40b4b10..ae3d9ca5f 100644 --- a/mobile-app/lib/v2/screens/pos/pos_amount_screen.dart +++ b/mobile-app/lib/v2/screens/pos/pos_amount_screen.dart @@ -1,7 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/models/fiat_currency.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; diff --git a/mobile-app/lib/v2/screens/pos/pos_qr_screen.dart b/mobile-app/lib/v2/screens/pos/pos_qr_screen.dart index 87b373d1b..8fecf933c 100644 --- a/mobile-app/lib/v2/screens/pos/pos_qr_screen.dart +++ b/mobile-app/lib/v2/screens/pos/pos_qr_screen.dart @@ -2,7 +2,8 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/currency_display_provider.dart'; diff --git a/mobile-app/lib/v2/screens/receive/receive_screen.dart b/mobile-app/lib/v2/screens/receive/receive_screen.dart index fe23897c9..bf3e8b11a 100644 --- a/mobile-app/lib/v2/screens/receive/receive_screen.dart +++ b/mobile-app/lib/v2/screens/receive/receive_screen.dart @@ -2,7 +2,8 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; diff --git a/mobile-app/lib/v2/screens/send/encrypted_send_progress_screen.dart b/mobile-app/lib/v2/screens/send/encrypted_send_progress_screen.dart index 6b6181b1f..3bfec343d 100644 --- a/mobile-app/lib/v2/screens/send/encrypted_send_progress_screen.dart +++ b/mobile-app/lib/v2/screens/send/encrypted_send_progress_screen.dart @@ -2,7 +2,8 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/encrypted_send_provider.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; diff --git a/mobile-app/lib/v2/screens/send/input_amount_screen.dart b/mobile-app/lib/v2/screens/send/input_amount_screen.dart index 92b57ed92..26e513358 100644 --- a/mobile-app/lib/v2/screens/send/input_amount_screen.dart +++ b/mobile-app/lib/v2/screens/send/input_amount_screen.dart @@ -2,7 +2,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/misc.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/models/fiat_currency.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; diff --git a/mobile-app/lib/v2/screens/send/keystone_reject_screen.dart b/mobile-app/lib/v2/screens/send/keystone_reject_screen.dart index db7345145..dc0c46780 100644 --- a/mobile-app/lib/v2/screens/send/keystone_reject_screen.dart +++ b/mobile-app/lib/v2/screens/send/keystone_reject_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/v2/screens/send/keystone_signing_widgets.dart'; import 'package:url_launcher/url_launcher.dart'; diff --git a/mobile-app/lib/v2/screens/send/keystone_sign_screen.dart b/mobile-app/lib/v2/screens/send/keystone_sign_screen.dart index 40f6c078c..167470fe2 100644 --- a/mobile-app/lib/v2/screens/send/keystone_sign_screen.dart +++ b/mobile-app/lib/v2/screens/send/keystone_sign_screen.dart @@ -2,7 +2,8 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/services/telemetry_service.dart'; diff --git a/mobile-app/lib/v2/screens/send/keystone_verify_screen.dart b/mobile-app/lib/v2/screens/send/keystone_verify_screen.dart index 66b031709..0631fb4e1 100644 --- a/mobile-app/lib/v2/screens/send/keystone_verify_screen.dart +++ b/mobile-app/lib/v2/screens/send/keystone_verify_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/v2/components/address_checkphrase_with_initial.dart'; diff --git a/mobile-app/lib/v2/screens/send/review_send_screen.dart b/mobile-app/lib/v2/screens/send/review_send_screen.dart index 97028cd59..aa4763972 100644 --- a/mobile-app/lib/v2/screens/send/review_send_screen.dart +++ b/mobile-app/lib/v2/screens/send/review_send_screen.dart @@ -2,7 +2,8 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/currency_display_provider.dart'; diff --git a/mobile-app/lib/v2/screens/send/select_recipient_screen.dart b/mobile-app/lib/v2/screens/send/select_recipient_screen.dart index 4b0bf63eb..677d5a272 100644 --- a/mobile-app/lib/v2/screens/send/select_recipient_screen.dart +++ b/mobile-app/lib/v2/screens/send/select_recipient_screen.dart @@ -1,7 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/v2/components/dotted_border.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; diff --git a/mobile-app/lib/v2/screens/send/send_terminal_screen.dart b/mobile-app/lib/v2/screens/send/send_terminal_screen.dart index e6352bec0..10456f2d2 100644 --- a/mobile-app/lib/v2/screens/send/send_terminal_screen.dart +++ b/mobile-app/lib/v2/screens/send/send_terminal_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/shared/constants/e2e_keys.dart'; import 'package:resonance_network_wallet/v2/components/explorer_link.dart'; diff --git a/mobile-app/lib/v2/screens/settings/about_quantus_screen.dart b/mobile-app/lib/v2/screens/settings/about_quantus_screen.dart index 24a033a4a..d4e4fe3bf 100644 --- a/mobile-app/lib/v2/screens/settings/about_quantus_screen.dart +++ b/mobile-app/lib/v2/screens/settings/about_quantus_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/generated/version.g.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; diff --git a/mobile-app/lib/v2/screens/settings/add_account_menu_screen.dart b/mobile-app/lib/v2/screens/settings/add_account_menu_screen.dart index c574d5644..6af7f0330 100644 --- a/mobile-app/lib/v2/screens/settings/add_account_menu_screen.dart +++ b/mobile-app/lib/v2/screens/settings/add_account_menu_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/multisig_providers.dart'; diff --git a/mobile-app/lib/v2/screens/settings/help_and_support_screen.dart b/mobile-app/lib/v2/screens/settings/help_and_support_screen.dart index 66afa1759..d3e355716 100644 --- a/mobile-app/lib/v2/screens/settings/help_and_support_screen.dart +++ b/mobile-app/lib/v2/screens/settings/help_and_support_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/shared/utils/open_external_url.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_divider.dart'; diff --git a/mobile-app/lib/v2/screens/settings/mining_rewards_screen.dart b/mobile-app/lib/v2/screens/settings/mining_rewards_screen.dart index 8a9fcbbc2..8634c3143 100644 --- a/mobile-app/lib/v2/screens/settings/mining_rewards_screen.dart +++ b/mobile-app/lib/v2/screens/settings/mining_rewards_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/mining_rewards_provider.dart'; diff --git a/mobile-app/lib/v2/screens/settings/preferences_settings_screen.dart b/mobile-app/lib/v2/screens/settings/preferences_settings_screen.dart index 88778e17e..9ec9167b3 100644 --- a/mobile-app/lib/v2/screens/settings/preferences_settings_screen.dart +++ b/mobile-app/lib/v2/screens/settings/preferences_settings_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/providers/currency_display_provider.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/notification_config_provider.dart'; diff --git a/mobile-app/lib/v2/screens/settings/redeem_address_screen.dart b/mobile-app/lib/v2/screens/settings/redeem_address_screen.dart index bc01c4e6d..863a6fc05 100644 --- a/mobile-app/lib/v2/screens/settings/redeem_address_screen.dart +++ b/mobile-app/lib/v2/screens/settings/redeem_address_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; diff --git a/mobile-app/lib/v2/screens/settings/redeem_progress_screen.dart b/mobile-app/lib/v2/screens/settings/redeem_progress_screen.dart index 247a74116..34e3ebb74 100644 --- a/mobile-app/lib/v2/screens/settings/redeem_progress_screen.dart +++ b/mobile-app/lib/v2/screens/settings/redeem_progress_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/mining_rewards_provider.dart'; diff --git a/mobile-app/lib/v2/screens/settings/select_wallet_screen.dart b/mobile-app/lib/v2/screens/settings/select_wallet_screen.dart index a3b330b7f..fe6820e43 100644 --- a/mobile-app/lib/v2/screens/settings/select_wallet_screen.dart +++ b/mobile-app/lib/v2/screens/settings/select_wallet_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; diff --git a/mobile-app/lib/v2/screens/settings/settings_caution_scaffold.dart b/mobile-app/lib/v2/screens/settings/settings_caution_scaffold.dart index 447f5e2fd..868e1a6f5 100644 --- a/mobile-app/lib/v2/screens/settings/settings_caution_scaffold.dart +++ b/mobile-app/lib/v2/screens/settings/settings_caution_scaffold.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_checkbox.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_divider.dart'; diff --git a/mobile-app/lib/v2/screens/settings/settings_picker_screen.dart b/mobile-app/lib/v2/screens/settings/settings_picker_screen.dart index 83aec8fa2..d73edebbb 100644 --- a/mobile-app/lib/v2/screens/settings/settings_picker_screen.dart +++ b/mobile-app/lib/v2/screens/settings/settings_picker_screen.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_divider.dart'; import 'package:resonance_network_wallet/v2/screens/settings/settings_picker_widgets.dart'; diff --git a/mobile-app/lib/v2/screens/settings/settings_screen.dart b/mobile-app/lib/v2/screens/settings/settings_screen.dart index 2eec97c57..09c167d15 100644 --- a/mobile-app/lib/v2/screens/settings/settings_screen.dart +++ b/mobile-app/lib/v2/screens/settings/settings_screen.dart @@ -1,7 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/flutter_svg.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/generated/version.g.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; diff --git a/mobile-app/lib/v2/screens/settings/testnet_rewards_screen.dart b/mobile-app/lib/v2/screens/settings/testnet_rewards_screen.dart index be58abb3f..9baf0e219 100644 --- a/mobile-app/lib/v2/screens/settings/testnet_rewards_screen.dart +++ b/mobile-app/lib/v2/screens/settings/testnet_rewards_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/mining_rewards_provider.dart'; import 'package:resonance_network_wallet/services/mining_rewards_service.dart'; diff --git a/mobile-app/lib/v2/screens/settings/wallet_settings_screen.dart b/mobile-app/lib/v2/screens/settings/wallet_settings_screen.dart index 6cdaf4002..1295a1004 100644 --- a/mobile-app/lib/v2/screens/settings/wallet_settings_screen.dart +++ b/mobile-app/lib/v2/screens/settings/wallet_settings_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/shared/constants/e2e_keys.dart'; diff --git a/mobile-app/lib/v2/screens/swap/deposit_screen.dart b/mobile-app/lib/v2/screens/swap/deposit_screen.dart index 95f366348..917a55e6e 100644 --- a/mobile-app/lib/v2/screens/swap/deposit_screen.dart +++ b/mobile-app/lib/v2/screens/swap/deposit_screen.dart @@ -1,7 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:qr_flutter/qr_flutter.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/shared/extensions/clipboard_extensions.dart'; import 'package:resonance_network_wallet/shared/utils/share_utils.dart'; diff --git a/mobile-app/lib/v2/screens/swap/swap_screen.dart b/mobile-app/lib/v2/screens/swap/swap_screen.dart index 3f392c419..1ac108a8a 100644 --- a/mobile-app/lib/v2/screens/swap/swap_screen.dart +++ b/mobile-app/lib/v2/screens/swap/swap_screen.dart @@ -4,7 +4,8 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:resonance_network_wallet/l10n/app_localizations.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/v2/components/qr_scanner_page.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/shared/utils/print.dart'; import 'package:resonance_network_wallet/v2/components/token_icon.dart'; import 'package:resonance_network_wallet/v2/screens/swap/refund_address_picker_sheet.dart'; diff --git a/mobile-app/lib/v2/screens/welcome/welcome_screen.dart b/mobile-app/lib/v2/screens/welcome/welcome_screen.dart index 74e9073fa..04fd28332 100644 --- a/mobile-app/lib/v2/screens/welcome/welcome_screen.dart +++ b/mobile-app/lib/v2/screens/welcome/welcome_screen.dart @@ -2,7 +2,8 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/providers/account_providers.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/providers/wallet_providers.dart'; diff --git a/mobile-app/lib/wallet_initializer.dart b/mobile-app/lib/wallet_initializer.dart index 9e74736c9..fe202db69 100644 --- a/mobile-app/lib/wallet_initializer.dart +++ b/mobile-app/lib/wallet_initializer.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:quantus_sdk/quantus_sdk.dart'; +import 'package:quantus_sdk/quantus_sdk.dart' hide ScaffoldBase; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; import 'package:resonance_network_wallet/providers/l10n_provider.dart'; import 'package:resonance_network_wallet/v2/screens/home/home_screen.dart'; import 'package:resonance_network_wallet/v2/screens/welcome/welcome_screen.dart'; diff --git a/mobile-app/test/unit/scaffold_base_test.dart b/mobile-app/test/unit/scaffold_base_test.dart new file mode 100644 index 000000000..0bbd2345a --- /dev/null +++ b/mobile-app/test/unit/scaffold_base_test.dart @@ -0,0 +1,37 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:resonance_network_wallet/providers/connectivity_provider.dart'; +import 'package:resonance_network_wallet/v2/components/scaffold_base.dart'; + +import '../extensions.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + testWidgets('shows Not Connected when offline', (tester) async { + await tester.pumpApp( + const ScaffoldBase(mainContent: Text('Hello')), + overrides: [isOnlineProvider.overrideWith((ref) => false)], + ); + + expect(find.text('Not Connected'), findsOneWidget); + }); + + testWidgets('hides Not Connected when online', (tester) async { + await tester.pumpApp( + const ScaffoldBase(mainContent: Text('Hello')), + overrides: [isOnlineProvider.overrideWith((ref) => true)], + ); + + expect(find.text('Not Connected'), findsNothing); + }); + + testWidgets('refreshable shows Not Connected when offline', (tester) async { + await tester.pumpApp( + ScaffoldBase.refreshable(onRefresh: () async {}, slivers: const [Text('Item')]), + overrides: [isOnlineProvider.overrideWith((ref) => false)], + ); + + expect(find.text('Not Connected'), findsOneWidget); + }); +} From cbad48a83aee3e00156e916f3269b01ed9c044bc Mon Sep 17 00:00:00 2001 From: Beast Date: Thu, 20 Aug 2026 15:07:24 +0800 Subject: [PATCH 37/38] feat: add test cold wallet to CI --- .github/workflows/ci.yaml | 2 ++ cold-wallet-app/test/qr_tuning_controls_test.dart | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index e82d64e76..a342a1098 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -40,6 +40,8 @@ jobs: - name: Test Quantus SDK # Tests tagged 'native' need the Rust dylib built locally; skip them in CI. run: melos exec --concurrency=1 --scope="quantus_sdk" -- "flutter test --exclude-tags=native" + - name: Test Cold Wallet App + run: melos exec --concurrency=1 --scope="quantus_cold_wallet" -- "flutter test" # build_android: # name: Build Android diff --git a/cold-wallet-app/test/qr_tuning_controls_test.dart b/cold-wallet-app/test/qr_tuning_controls_test.dart index 9d039d48e..559789e64 100644 --- a/cold-wallet-app/test/qr_tuning_controls_test.dart +++ b/cold-wallet-app/test/qr_tuning_controls_test.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:quantus_cold_wallet/components/qr_tuning_controls.dart'; +import 'package:quantus_cold_wallet/providers/settings_providers.dart'; import 'package:quantus_sdk/quantus_sdk.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -38,7 +39,7 @@ void main() { expect(widget.style?.fontSize, text.caption.fontSize); } - for (final value in ['15 FPS', '1100 bytes']) { + for (final value in ['${ColdSettings.defaultQrFps} FPS', '${ColdSettings.defaultQrBytes} bytes']) { final widget = tester.widget(find.text(value)); expect(widget.style?.color, colors.textContent); expect(widget.style?.fontSize, text.caption.fontSize); From fe597d11010005e0ce5846752c2a1e2ec81265cf Mon Sep 17 00:00:00 2001 From: Beast Date: Thu, 20 Aug 2026 15:28:54 +0800 Subject: [PATCH 38/38] fix: crashing auth wrapper --- mobile-app/lib/v2/screens/auth/auth_wrapper.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile-app/lib/v2/screens/auth/auth_wrapper.dart b/mobile-app/lib/v2/screens/auth/auth_wrapper.dart index 7bdca5d46..a1db2c70a 100644 --- a/mobile-app/lib/v2/screens/auth/auth_wrapper.dart +++ b/mobile-app/lib/v2/screens/auth/auth_wrapper.dart @@ -51,7 +51,7 @@ class AuthWrapper extends ConsumerWidget { const Loader() else Padding( - padding: EdgeInsets.symmetric(horizontal: context.themeSize.screenPadding), + padding: const EdgeInsets.symmetric(horizontal: 24), child: QuantusButton.simple( label: l10n.authUnlockWallet, onTap: () {