diff --git a/lib/pages/cakepay/cakepay_send_from_view.dart b/lib/pages/cakepay/cakepay_send_from_view.dart index 4213625d36..e7395f2d3b 100644 --- a/lib/pages/cakepay/cakepay_send_from_view.dart +++ b/lib/pages/cakepay/cakepay_send_from_view.dart @@ -28,6 +28,7 @@ import '../../widgets/conditional_parent.dart'; import '../../widgets/custom_buttons/app_bar_icon_button.dart'; import '../../widgets/desktop/desktop_dialog.dart'; import '../../widgets/desktop/desktop_dialog_close_button.dart'; +import '../../widgets/hideable_balance.dart'; import '../../widgets/rounded_white_container.dart'; import '../../widgets/stack_dialog.dart'; import '../../pages_desktop_specific/desktop_home_view.dart'; @@ -80,9 +81,9 @@ class _CakePaySendFromViewState extends ConsumerState { builder: (child) { return Background( child: Scaffold( - backgroundColor: Theme.of( - context, - ).extension()!.background, + backgroundColor: Theme.of(context) + .extension()! + .background, appBar: AppBar( leading: AppBarBackButton( onPressed: () => Navigator.of(context).pop(), @@ -208,9 +209,9 @@ class _CakePaySendFromCardState extends ConsumerState<_CakePaySendFromCard> { child: Text( "Ok", style: STextStyles.button(context).copyWith( - color: Theme.of( - context, - ).extension()!.buttonTextSecondary, + color: Theme.of(context) + .extension()! + .buttonTextSecondary, ), ), onPressed: () => Navigator.of(context).pop(), @@ -327,9 +328,9 @@ class _CakePaySendFromCardState extends ConsumerState<_CakePaySendFromCard> { child: Text( "Ok", style: STextStyles.button(context).copyWith( - color: Theme.of( - context, - ).extension()!.buttonTextSecondary, + color: Theme.of(context) + .extension()! + .buttonTextSecondary, ), ), onPressed: () => Navigator.of(context).pop(), @@ -389,13 +390,21 @@ class _CakePaySendFromCardState extends ConsumerState<_CakePaySendFromCard> { style: STextStyles.titleBold12(context), ), const SizedBox(height: 2), - Text( - ref - .watch(pAmountFormatter(coin)) - .format( - ref.watch(pWalletBalance(widget.walletId)).spendable, - ), - style: STextStyles.itemSubtitle(context), + HideableBalance( + iconColor: Theme.of(context) + .extension()! + .infoItemLabel, + iconSize: 16, + child: Text( + ref + .watch(pAmountFormatter(coin)) + .format( + ref + .watch(pWalletBalance(widget.walletId)) + .spendable, + ), + style: STextStyles.itemSubtitle(context), + ), ), ], ), diff --git a/lib/pages/exchange_view/exchange_step_views/step_4_view.dart b/lib/pages/exchange_view/exchange_step_views/step_4_view.dart index dc75032f94..bceff00f3e 100644 --- a/lib/pages/exchange_view/exchange_step_views/step_4_view.dart +++ b/lib/pages/exchange_view/exchange_step_views/step_4_view.dart @@ -192,6 +192,7 @@ class _Step4ViewState extends ConsumerState { final coin = ref.read(pWalletCoin(walletId)); final balancePublic = ref.read(pWalletBalance(walletId)); final balancePrivate = ref.read(pWalletBalanceTertiary(walletId)); + final hideBalances = ref.read(hideBalancesProvider); return await showModalBottomSheet( context: context, @@ -217,14 +218,16 @@ class _Step4ViewState extends ConsumerState { ), const SizedBox(height: 32), SecondaryButton( - label: - "${ref.watch(pAmountFormatter(coin)).format(balancePrivate.spendable)} (private)", + label: hideBalances + ? "Private balance" + : "${ref.watch(pAmountFormatter(coin)).format(balancePrivate.spendable)} (private)", onPressed: () => Navigator.of(context).pop(false), ), const SizedBox(height: 16), SecondaryButton( - label: - "${ref.watch(pAmountFormatter(coin)).format(balancePublic.spendable)} (public)", + label: hideBalances + ? "Public balance" + : "${ref.watch(pAmountFormatter(coin)).format(balancePublic.spendable)} (public)", onPressed: () => Navigator.of(context).pop(true), ), const SizedBox(height: 32), diff --git a/lib/pages/exchange_view/send_from_view.dart b/lib/pages/exchange_view/send_from_view.dart index 9fe4121ee0..2c953911ac 100644 --- a/lib/pages/exchange_view/send_from_view.dart +++ b/lib/pages/exchange_view/send_from_view.dart @@ -43,6 +43,7 @@ import '../../widgets/custom_buttons/app_bar_icon_button.dart'; import '../../widgets/desktop/desktop_dialog.dart'; import '../../widgets/desktop/desktop_dialog_close_button.dart'; import '../../widgets/expandable.dart'; +import '../../widgets/hideable_balance.dart'; import '../../widgets/rounded_white_container.dart'; import '../../widgets/stack_dialog.dart'; import '../home_view/home_view.dart'; @@ -106,9 +107,9 @@ class _SendFromViewState extends ConsumerState { builder: (child) { return Background( child: Scaffold( - backgroundColor: Theme.of( - context, - ).extension()!.background, + backgroundColor: Theme.of(context) + .extension()! + .background, appBar: AppBar( leading: AppBarBackButton( onPressed: () { @@ -381,9 +382,9 @@ class _SendFromCardState extends ConsumerState { child: Text( "Ok", style: STextStyles.button(context).copyWith( - color: Theme.of( - context, - ).extension()!.buttonTextSecondary, + color: Theme.of(context) + .extension()! + .buttonTextSecondary, ), ), onPressed: () { @@ -427,9 +428,9 @@ class _SendFromCardState extends ConsumerState { children: [ if (!trade.exchangeName.startsWith(TrocadorExchange.exchangeName)) MaterialButton( - splashColor: Theme.of( - context, - ).extension()!.highlight, + splashColor: Theme.of(context) + .extension()! + .highlight, key: Key("walletsSheetItemButtonFiroPrivateKey_$walletId"), padding: const EdgeInsets.all(0), materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, @@ -463,17 +464,23 @@ class _SendFromCardState extends ConsumerState { "Use private balance", style: STextStyles.itemSubtitle(context), ), - Text( - ref - .watch(pAmountFormatter(coin)) - .format( - ref - .watch( - pWalletBalanceTertiary(walletId), - ) - .spendable, - ), - style: STextStyles.itemSubtitle(context), + HideableBalance( + iconColor: Theme.of(context) + .extension()! + .infoItemLabel, + iconSize: 16, + child: Text( + ref + .watch(pAmountFormatter(coin)) + .format( + ref + .watch( + pWalletBalanceTertiary(walletId), + ) + .spendable, + ), + style: STextStyles.itemSubtitle(context), + ), ), ], ), @@ -481,9 +488,9 @@ class _SendFromCardState extends ConsumerState { Assets.svg.chevronRight, height: 14, width: 7, - color: Theme.of( - context, - ).extension()!.infoItemLabel, + color: Theme.of(context) + .extension()! + .infoItemLabel, ), ], ), @@ -491,9 +498,9 @@ class _SendFromCardState extends ConsumerState { ), ), MaterialButton( - splashColor: Theme.of( - context, - ).extension()!.highlight, + splashColor: Theme.of(context) + .extension()! + .highlight, key: Key("walletsSheetItemButtonFiroPublicKey_$walletId"), padding: const EdgeInsets.all(0), materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, @@ -527,15 +534,21 @@ class _SendFromCardState extends ConsumerState { "Use public balance", style: STextStyles.itemSubtitle(context), ), - Text( - ref - .watch(pAmountFormatter(coin)) - .format( - ref - .watch(pWalletBalance(walletId)) - .spendable, - ), - style: STextStyles.itemSubtitle(context), + HideableBalance( + iconColor: Theme.of(context) + .extension()! + .infoItemLabel, + iconSize: 16, + child: Text( + ref + .watch(pAmountFormatter(coin)) + .format( + ref + .watch(pWalletBalance(walletId)) + .spendable, + ), + style: STextStyles.itemSubtitle(context), + ), ), ], ), @@ -543,9 +556,9 @@ class _SendFromCardState extends ConsumerState { Assets.svg.chevronRight, height: 14, width: 7, - color: Theme.of( - context, - ).extension()!.infoItemLabel, + color: Theme.of(context) + .extension()! + .infoItemLabel, ), ], ), @@ -605,13 +618,19 @@ class _SendFromCardState extends ConsumerState { ), if (!isFiro) const SizedBox(height: 2), if (!isFiro) - Text( - ref - .watch(pAmountFormatter(coin)) - .format( - ref.watch(pWalletBalance(walletId)).spendable, - ), - style: STextStyles.itemSubtitle(context), + HideableBalance( + iconColor: Theme.of(context) + .extension()! + .infoItemLabel, + iconSize: 16, + child: Text( + ref + .watch(pAmountFormatter(coin)) + .format( + ref.watch(pWalletBalance(walletId)).spendable, + ), + style: STextStyles.itemSubtitle(context), + ), ), ], ), diff --git a/lib/pages/send_view/frost_ms/frost_send_view.dart b/lib/pages/send_view/frost_ms/frost_send_view.dart index ce67095ce5..07796e401c 100644 --- a/lib/pages/send_view/frost_ms/frost_send_view.dart +++ b/lib/pages/send_view/frost_ms/frost_send_view.dart @@ -43,6 +43,7 @@ import '../../../widgets/desktop/primary_button.dart'; import '../../../widgets/desktop/secondary_button.dart'; import '../../../widgets/fee_slider.dart'; import '../../../widgets/frost_scaffold.dart'; +import '../../../widgets/hideable_balance.dart'; import '../../../widgets/icon_widgets/x_icon.dart'; import '../../../widgets/rounded_white_container.dart'; import '../../../widgets/stack_dialog.dart'; @@ -341,22 +342,28 @@ class _FrostSendViewState extends ConsumerState { onTap: () {}, child: Container( color: Colors.transparent, - child: Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Text( - ref - .watch(pAmountFormatter(coin)) - .format( - ref - .watch(pWalletBalance(walletId)) - .spendable, - ), - style: STextStyles.titleBold12(context) - .copyWith(fontSize: 10), - textAlign: TextAlign.right, - ), - ], + child: HideableBalance( + iconColor: Theme.of(context) + .extension()! + .textDark, + iconSize: 16, + child: Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Text( + ref + .watch(pAmountFormatter(coin)) + .format( + ref + .watch(pWalletBalance(walletId)) + .spendable, + ), + style: STextStyles.titleBold12(context) + .copyWith(fontSize: 10), + textAlign: TextAlign.right, + ), + ], + ), ), ), ), diff --git a/lib/pages/send_view/send_view.dart b/lib/pages/send_view/send_view.dart index e6249006a7..2668c71101 100644 --- a/lib/pages/send_view/send_view.dart +++ b/lib/pages/send_view/send_view.dart @@ -72,6 +72,7 @@ import '../../widgets/dialogs/firo_exchange_address_dialog.dart'; import '../../widgets/epic_txs_method_toggle.dart'; import '../../widgets/eth_fee_form.dart'; import '../../widgets/fee_slider.dart'; +import '../../widgets/hideable_balance.dart'; import '../../widgets/icon_widgets/addressbook_icon.dart'; import '../../widgets/icon_widgets/clipboard_icon.dart'; import '../../widgets/icon_widgets/qrcode_icon.dart'; @@ -1655,31 +1656,45 @@ class _SendViewState extends ConsumerState { }, child: Container( color: Colors.transparent, - child: Column( - crossAxisAlignment: - CrossAxisAlignment.end, - children: [ - Text( - ref - .watch( - pAmountFormatter(coin), - ) - .format(amount), - style: - STextStyles.titleBold12( - context, - ).copyWith(fontSize: 10), - textAlign: TextAlign.right, - ), - if (price != null) + child: HideableBalance( + iconColor: Theme.of(context) + .extension()! + .textDark, + iconSize: 16, + child: Column( + crossAxisAlignment: + CrossAxisAlignment.end, + children: [ Text( - "${(amount.decimal * price).toAmount(fractionDigits: 2).fiatString(locale: locale)} ${ref.watch(prefsChangeNotifierProvider.select((value) => value.currency))}", - style: STextStyles.subtitle( - context, - ).copyWith(fontSize: 8), + ref + .watch( + pAmountFormatter( + coin, + ), + ) + .format(amount), + style: + STextStyles.titleBold12( + context, + ).copyWith( + fontSize: 10, + ), textAlign: TextAlign.right, ), - ], + if (price != null) + Text( + "${(amount.decimal * price).toAmount(fractionDigits: 2).fiatString(locale: locale)} ${ref.watch(prefsChangeNotifierProvider.select((value) => value.currency))}", + style: + STextStyles.subtitle( + context, + ).copyWith( + fontSize: 8, + ), + textAlign: + TextAlign.right, + ), + ], + ), ), ), ); @@ -2175,18 +2190,26 @@ class _SendViewState extends ConsumerState { break; } - return Text( - ref - .watch( - pAmountFormatter( - coin, + return HideableBalance( + iconColor: Theme.of(context) + .extension< + StackColors + >()! + .infoItemLabel, + iconSize: 16, + child: Text( + ref + .watch( + pAmountFormatter( + coin, + ), + ) + .format(amount), + style: + STextStyles.itemSubtitle( + context, ), - ) - .format(amount), - style: - STextStyles.itemSubtitle( - context, - ), + ), ); }, ), diff --git a/lib/pages/send_view/sol_token_send_view.dart b/lib/pages/send_view/sol_token_send_view.dart index 13c66ff01d..414b061fc0 100644 --- a/lib/pages/send_view/sol_token_send_view.dart +++ b/lib/pages/send_view/sol_token_send_view.dart @@ -46,6 +46,7 @@ import '../../wallets/models/tx_data.dart'; import '../../widgets/animated_text.dart'; import '../../widgets/background.dart'; import '../../widgets/custom_buttons/app_bar_icon_button.dart'; +import '../../widgets/hideable_balance.dart'; import '../../widgets/icon_widgets/clipboard_icon.dart'; import '../../widgets/icon_widgets/qrcode_icon.dart'; import '../../widgets/icon_widgets/sol_token_icon.dart'; @@ -799,36 +800,42 @@ class _SolTokenSendViewState extends ConsumerState { }, child: Container( color: Colors.transparent, - child: Column( - crossAxisAlignment: - CrossAxisAlignment.end, - children: [ - Text( - _formatTokenBalance( - ref - .watch( - pSolanaTokenBalance(( - walletId: - widget.walletId, - tokenMint: tokenMint, - )), - ) - .spendable, - ), - style: STextStyles.titleBold12( - context, - ).copyWith(fontSize: 10), - textAlign: TextAlign.right, - ), - if (price != null) + child: HideableBalance( + iconColor: Theme.of(context) + .extension()! + .textDark, + iconSize: 16, + child: Column( + crossAxisAlignment: + CrossAxisAlignment.end, + children: [ Text( - "${(ref.watch(pSolanaTokenBalance((walletId: widget.walletId, tokenMint: tokenMint))).spendable.decimal * price).toAmount(fractionDigits: 2).fiatString(locale: locale)} ${ref.watch(prefsChangeNotifierProvider.select((value) => value.currency))}", - style: STextStyles.subtitle( + _formatTokenBalance( + ref + .watch( + pSolanaTokenBalance(( + walletId: + widget.walletId, + tokenMint: tokenMint, + )), + ) + .spendable, + ), + style: STextStyles.titleBold12( context, - ).copyWith(fontSize: 8), + ).copyWith(fontSize: 10), textAlign: TextAlign.right, ), - ], + if (price != null) + Text( + "${(ref.watch(pSolanaTokenBalance((walletId: widget.walletId, tokenMint: tokenMint))).spendable.decimal * price).toAmount(fractionDigits: 2).fiatString(locale: locale)} ${ref.watch(prefsChangeNotifierProvider.select((value) => value.currency))}", + style: STextStyles.subtitle( + context, + ).copyWith(fontSize: 8), + textAlign: TextAlign.right, + ), + ], + ), ), ), ), diff --git a/lib/pages/send_view/sub_widgets/dual_balance_selection_sheet.dart b/lib/pages/send_view/sub_widgets/dual_balance_selection_sheet.dart index e4505bcd0e..6e664115ea 100644 --- a/lib/pages/send_view/sub_widgets/dual_balance_selection_sheet.dart +++ b/lib/pages/send_view/sub_widgets/dual_balance_selection_sheet.dart @@ -18,6 +18,7 @@ import '../../../utilities/constants.dart'; import '../../../utilities/text_styles.dart'; import '../../../wallets/crypto_currency/coins/firo.dart'; import '../../../wallets/isar/providers/wallet_info_provider.dart'; +import '../../../widgets/hideable_balance.dart'; class DualBalanceSelectionSheet extends ConsumerStatefulWidget { const DualBalanceSelectionSheet({super.key, required this.walletId}); @@ -148,24 +149,30 @@ class _FiroBalanceSelectionSheetState textAlign: TextAlign.left, ), const SizedBox(width: 2), - Text( - ref - .watch(pAmountFormatter(coin)) - .format( - ref - .watch( - coin is Firo - ? pWalletBalanceTertiary( - walletId, - ) - : pWalletBalanceSecondary( - walletId, - ), - ) - .spendable, - ), - style: STextStyles.itemSubtitle(context), - textAlign: TextAlign.left, + HideableBalance( + iconColor: Theme.of(context) + .extension()! + .infoItemLabel, + iconSize: 16, + child: Text( + ref + .watch(pAmountFormatter(coin)) + .format( + ref + .watch( + coin is Firo + ? pWalletBalanceTertiary( + walletId, + ) + : pWalletBalanceSecondary( + walletId, + ), + ) + .spendable, + ), + style: STextStyles.itemSubtitle(context), + textAlign: TextAlign.left, + ), ), ], ), @@ -238,16 +245,22 @@ class _FiroBalanceSelectionSheetState textAlign: TextAlign.left, ), const SizedBox(width: 2), - Text( - ref - .watch(pAmountFormatter(coin)) - .format( - ref - .watch(pWalletBalance(walletId)) - .spendable, - ), - style: STextStyles.itemSubtitle(context), - textAlign: TextAlign.left, + HideableBalance( + iconColor: Theme.of(context) + .extension()! + .infoItemLabel, + iconSize: 16, + child: Text( + ref + .watch(pAmountFormatter(coin)) + .format( + ref + .watch(pWalletBalance(walletId)) + .spendable, + ), + style: STextStyles.itemSubtitle(context), + textAlign: TextAlign.left, + ), ), ], ), diff --git a/lib/pages/send_view/token_send_view.dart b/lib/pages/send_view/token_send_view.dart index 5601d41c9a..6af3ddcfb3 100644 --- a/lib/pages/send_view/token_send_view.dart +++ b/lib/pages/send_view/token_send_view.dart @@ -48,6 +48,7 @@ import '../../widgets/animated_text.dart'; import '../../widgets/background.dart'; import '../../widgets/custom_buttons/app_bar_icon_button.dart'; import '../../widgets/eth_fee_form.dart'; +import '../../widgets/hideable_balance.dart'; import '../../widgets/icon_widgets/addressbook_icon.dart'; import '../../widgets/icon_widgets/clipboard_icon.dart'; import '../../widgets/icon_widgets/eth_token_icon.dart'; @@ -767,42 +768,50 @@ class _TokenSendViewState extends ConsumerState { }, child: Container( color: Colors.transparent, - child: Column( - crossAxisAlignment: - CrossAxisAlignment.end, - children: [ - Text( - ref - .watch(pAmountFormatter(coin)) - .format( - ref - .watch( - pTokenBalance(( - walletId: - widget.walletId, - contractAddress: - tokenContract - .address, - )), - ) - .spendable, - tokenContract: - tokenContract, - ), - style: STextStyles.titleBold12( - context, - ).copyWith(fontSize: 10), - textAlign: TextAlign.right, - ), - if (price != null) + child: HideableBalance( + iconColor: Theme.of(context) + .extension()! + .textDark, + iconSize: 16, + child: Column( + crossAxisAlignment: + CrossAxisAlignment.end, + children: [ Text( - "${(ref.watch(pTokenBalance((walletId: widget.walletId, contractAddress: tokenContract.address))).spendable.decimal * price).toAmount(fractionDigits: 2).fiatString(locale: locale)} ${ref.watch(prefsChangeNotifierProvider.select((value) => value.currency))}", - style: STextStyles.subtitle( + ref + .watch( + pAmountFormatter(coin), + ) + .format( + ref + .watch( + pTokenBalance(( + walletId: widget + .walletId, + contractAddress: + tokenContract + .address, + )), + ) + .spendable, + tokenContract: + tokenContract, + ), + style: STextStyles.titleBold12( context, - ).copyWith(fontSize: 8), + ).copyWith(fontSize: 10), textAlign: TextAlign.right, ), - ], + if (price != null) + Text( + "${(ref.watch(pTokenBalance((walletId: widget.walletId, contractAddress: tokenContract.address))).spendable.decimal * price).toAmount(fractionDigits: 2).fiatString(locale: locale)} ${ref.watch(prefsChangeNotifierProvider.select((value) => value.currency))}", + style: STextStyles.subtitle( + context, + ).copyWith(fontSize: 8), + textAlign: TextAlign.right, + ), + ], + ), ), ), ), diff --git a/lib/pages/settings_views/global_settings_view/appearance_settings/appearance_settings_view.dart b/lib/pages/settings_views/global_settings_view/appearance_settings/appearance_settings_view.dart index aa10724a7f..d5dcc842fa 100644 --- a/lib/pages/settings_views/global_settings_view/appearance_settings/appearance_settings_view.dart +++ b/lib/pages/settings_views/global_settings_view/appearance_settings/appearance_settings_view.dart @@ -59,10 +59,9 @@ class AppearanceSettingsView extends ConsumerWidget { child: Consumer( builder: (_, ref, __) { return RawMaterialButton( - splashColor: - Theme.of( - context, - ).extension()!.highlight, + splashColor: Theme.of(context) + .extension()! + .highlight, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( @@ -91,17 +90,78 @@ class AppearanceSettingsView extends ConsumerWidget { width: 40, child: DraggableSwitchButton( isOn: ref.watch( - prefsChangeNotifierProvider.select( - (value) => - value.showFavoriteWallets, - ), + prefsChangeNotifierProvider + .select( + (value) => value + .showFavoriteWallets, + ), ), onValueChanged: (newValue) { ref - .read( - prefsChangeNotifierProvider, - ) - .showFavoriteWallets = newValue; + .read( + prefsChangeNotifierProvider, + ) + .showFavoriteWallets = + newValue; + }, + ), + ), + ], + ), + ), + ); + }, + ), + ), + const SizedBox(height: 10), + RoundedWhiteContainer( + child: Consumer( + builder: (_, ref, __) { + return RawMaterialButton( + splashColor: Theme.of(context) + .extension()! + .highlight, + materialTapTargetSize: + MaterialTapTargetSize.shrinkWrap, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular( + Constants.size.circularBorderRadius, + ), + ), + onPressed: null, + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 8, + ), + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text( + "Hide balances", + style: STextStyles.titleBold12( + context, + ), + textAlign: TextAlign.left, + ), + SizedBox( + height: 20, + width: 40, + child: DraggableSwitchButton( + isOn: ref.watch( + prefsChangeNotifierProvider + .select( + (value) => + value.hideBalances, + ), + ), + onValueChanged: (newValue) { + ref + .read( + prefsChangeNotifierProvider, + ) + .hideBalances = + newValue; }, ), ), @@ -142,9 +202,8 @@ class AppearanceSettingsView extends ConsumerWidget { SecondaryButton( label: "Add more themes", onPressed: () { - Navigator.of( - context, - ).pushNamed(ManageThemesView.routeName); + Navigator.of(context) + .pushNamed(ManageThemesView.routeName); }, ), ], diff --git a/lib/pages/settings_views/global_settings_view/syncing_preferences_views/wallet_syncing_options_view.dart b/lib/pages/settings_views/global_settings_view/syncing_preferences_views/wallet_syncing_options_view.dart index c5916cf708..619653ee10 100644 --- a/lib/pages/settings_views/global_settings_view/syncing_preferences_views/wallet_syncing_options_view.dart +++ b/lib/pages/settings_views/global_settings_view/syncing_preferences_views/wallet_syncing_options_view.dart @@ -27,6 +27,7 @@ import '../../../../widgets/background.dart'; import '../../../../widgets/conditional_parent.dart'; import '../../../../widgets/custom_buttons/app_bar_icon_button.dart'; import '../../../../widgets/custom_buttons/draggable_switch_button.dart'; +import '../../../../widgets/hideable_balance.dart'; import '../../../../widgets/rounded_white_container.dart'; class WalletSyncingOptionsView extends ConsumerWidget { @@ -44,8 +45,9 @@ class WalletSyncingOptionsView extends ConsumerWidget { builder: (child) { return Background( child: Scaffold( - backgroundColor: - Theme.of(context).extension()!.background, + backgroundColor: Theme.of(context) + .extension()! + .background, appBar: AppBar( leading: AppBarBackButton( onPressed: () async { @@ -98,12 +100,11 @@ class WalletSyncingOptionsView extends ConsumerWidget { const SizedBox(height: 12), RoundedWhiteContainer( padding: const EdgeInsets.all(0), - borderColor: - !isDesktop - ? Colors.transparent - : Theme.of( - context, - ).extension()!.background, + borderColor: !isDesktop + ? Colors.transparent + : Theme.of(context) + .extension()! + .background, child: Column( children: [ ...walletInfos.map( @@ -150,22 +151,31 @@ class WalletSyncingOptionsView extends ConsumerWidget { ), ), const SizedBox(height: 2), - Text( - ref - .watch( - pAmountFormatter(info.coin), - ) - .format( - ref - .watch( - pWalletBalance( - info.walletId, - ), - ) - .total, - ), - style: STextStyles.itemSubtitle( - context, + HideableBalance( + key: ValueKey( + "hideBalance_${info.walletId}", + ), + iconColor: Theme.of(context) + .extension()! + .infoItemLabel, + iconSize: 16, + child: Text( + ref + .watch( + pAmountFormatter(info.coin), + ) + .format( + ref + .watch( + pWalletBalance( + info.walletId, + ), + ) + .total, + ), + style: STextStyles.itemSubtitle( + context, + ), ), ), ], @@ -177,24 +187,23 @@ class WalletSyncingOptionsView extends ConsumerWidget { child: DraggableSwitchButton( isOn: ref .watch( - prefsChangeNotifierProvider.select( - (value) => - value + prefsChangeNotifierProvider + .select( + (value) => value .walletIdsSyncOnStartup, - ), + ), ) .contains(info.walletId), onValueChanged: (value) { // final syncType = ref // .read(prefsChangeNotifierProvider) // .syncType; - final ids = - ref - .read( - prefsChangeNotifierProvider, - ) - .walletIdsSyncOnStartup - .toList(); + final ids = ref + .read( + prefsChangeNotifierProvider, + ) + .walletIdsSyncOnStartup + .toList(); if (value) { ids.add(info.walletId); } else { @@ -222,10 +231,11 @@ class WalletSyncingOptionsView extends ConsumerWidget { // } ref - .read( - prefsChangeNotifierProvider, - ) - .walletIdsSyncOnStartup = ids; + .read( + prefsChangeNotifierProvider, + ) + .walletIdsSyncOnStartup = + ids; }, ), ), diff --git a/lib/pages/shopinbit/shopinbit_send_from_view.dart b/lib/pages/shopinbit/shopinbit_send_from_view.dart index fb54b1f41b..ef7939bf12 100644 --- a/lib/pages/shopinbit/shopinbit_send_from_view.dart +++ b/lib/pages/shopinbit/shopinbit_send_from_view.dart @@ -34,6 +34,7 @@ import '../../widgets/conditional_parent.dart'; import '../../widgets/custom_buttons/app_bar_icon_button.dart'; import '../../widgets/desktop/desktop_dialog.dart'; import '../../widgets/desktop/desktop_dialog_close_button.dart'; +import '../../widgets/hideable_balance.dart'; import '../../widgets/rounded_white_container.dart'; import '../../widgets/stack_dialog.dart'; import '../home_view/home_view.dart'; @@ -115,9 +116,9 @@ class _ShopInBitSendFromViewState extends ConsumerState { builder: (child) { return Background( child: Scaffold( - backgroundColor: Theme.of( - context, - ).extension()!.background, + backgroundColor: Theme.of(context) + .extension()! + .background, appBar: AppBar( leading: AppBarBackButton( onPressed: () { @@ -270,9 +271,9 @@ class _ShopInBitSendFromCardState extends ConsumerState { child: Text( "Ok", style: STextStyles.button(context).copyWith( - color: Theme.of( - context, - ).extension()!.buttonTextSecondary, + color: Theme.of(context) + .extension()! + .buttonTextSecondary, ), ), onPressed: () => Navigator.of(context).pop(), @@ -413,9 +414,9 @@ class _ShopInBitSendFromCardState extends ConsumerState { child: Text( "Ok", style: STextStyles.button(context).copyWith( - color: Theme.of( - context, - ).extension()!.buttonTextSecondary, + color: Theme.of(context) + .extension()! + .buttonTextSecondary, ), ), onPressed: () { @@ -500,20 +501,32 @@ class _ShopInBitSendFromCardState extends ConsumerState { contractAddress: tokenContract!.address, )), ); - return Text( - "${balance.spendable.decimal.toStringAsFixed(tokenContract!.decimals)} ${tokenContract!.symbol}", - style: STextStyles.itemSubtitle(context), + return HideableBalance( + iconColor: Theme.of(context) + .extension()! + .infoItemLabel, + iconSize: 16, + child: Text( + "${balance.spendable.decimal.toStringAsFixed(tokenContract!.decimals)} ${tokenContract!.symbol}", + style: STextStyles.itemSubtitle(context), + ), ); }, ) else - Text( - ref - .watch(pAmountFormatter(coin)) - .format( - ref.watch(pWalletBalance(walletId)).spendable, - ), - style: STextStyles.itemSubtitle(context), + HideableBalance( + iconColor: Theme.of(context) + .extension()! + .infoItemLabel, + iconSize: 16, + child: Text( + ref + .watch(pAmountFormatter(coin)) + .format( + ref.watch(pWalletBalance(walletId)).spendable, + ), + style: STextStyles.itemSubtitle(context), + ), ), ], ), diff --git a/lib/pages/token_view/sub_widgets/my_token_select_item.dart b/lib/pages/token_view/sub_widgets/my_token_select_item.dart index a00813e23f..f6917aa16c 100644 --- a/lib/pages/token_view/sub_widgets/my_token_select_item.dart +++ b/lib/pages/token_view/sub_widgets/my_token_select_item.dart @@ -32,6 +32,7 @@ import '../../../wallets/wallet/impl/sub_wallets/eth_token_wallet.dart'; import '../../../wallets/wallet/wallet.dart'; import '../../../widgets/desktop/primary_button.dart'; import '../../../widgets/dialogs/basic_dialog.dart'; +import '../../../widgets/hideable_balance.dart'; import '../../../widgets/icon_widgets/eth_token_icon.dart'; import '../../../widgets/rounded_white_container.dart'; import '../token_view.dart'; @@ -86,14 +87,11 @@ class _MyTokenSelectItemState extends ConsumerState { final old = ref.read(tokenServiceStateProvider); // exit previous if there is one unawaited(old?.exit()); - ref.read(tokenServiceStateProvider.state).state = - Wallet.loadTokenWallet( - ethWallet: - ref.read(pWallets).getWallet(widget.walletId) - as EthereumWallet, - contract: widget.token, - ) - as EthTokenWallet; + ref.read(tokenServiceStateProvider.state).state = Wallet.loadTokenWallet( + ethWallet: + ref.read(pWallets).getWallet(widget.walletId) as EthereumWallet, + contract: widget.token, + ) as EthTokenWallet; final success = await showLoading( whileFuture: _loadTokenWallet(context, ref), @@ -179,43 +177,56 @@ class _MyTokenSelectItemState extends ConsumerState { Text( widget.token.name, style: isDesktop - ? STextStyles.desktopTextExtraSmall( - context, - ).copyWith( - color: Theme.of( - context, - ).extension()!.textDark, - ) + ? STextStyles.desktopTextExtraSmall(context) + .copyWith( + color: Theme.of(context) + .extension()! + .textDark, + ) : STextStyles.titleBold12(context), ), const Spacer(), - Text( - ref - .watch( - pAmountFormatter( - Ethereum(CryptoCurrencyNetwork.main), - ), - ) - .format( - ref - .watch( - pTokenBalance(( - walletId: widget.walletId, - contractAddress: widget.token.address, - )), - ) - .total, - tokenContract: widget.token, - ), - style: isDesktop - ? STextStyles.desktopTextExtraSmall( - context, - ).copyWith( - color: Theme.of( - context, - ).extension()!.textDark, + HideableBalance( + key: ValueKey( + "hideBalance_${widget.walletId}_" + "${widget.token.address}", + ), + iconColor: isDesktop + ? Theme.of(context) + .extension()! + .textDark + : Theme.of(context) + .extension()! + .infoItemLabel, + iconSize: 16, + child: Text( + ref + .watch( + pAmountFormatter( + Ethereum(CryptoCurrencyNetwork.main), + ), ) - : STextStyles.itemSubtitle(context), + .format( + ref + .watch( + pTokenBalance(( + walletId: widget.walletId, + contractAddress: + widget.token.address, + )), + ) + .total, + tokenContract: widget.token, + ), + style: isDesktop + ? STextStyles.desktopTextExtraSmall(context) + .copyWith( + color: Theme.of(context) + .extension()! + .textDark, + ) + : STextStyles.itemSubtitle(context), + ), ), ], ), diff --git a/lib/pages/token_view/sub_widgets/sol_token_select_item.dart b/lib/pages/token_view/sub_widgets/sol_token_select_item.dart index 498ef025c8..47d8845b6f 100644 --- a/lib/pages/token_view/sub_widgets/sol_token_select_item.dart +++ b/lib/pages/token_view/sub_widgets/sol_token_select_item.dart @@ -27,6 +27,7 @@ import '../../../wallets/wallet/impl/sub_wallets/solana_token_wallet.dart'; import '../../../wallets/wallet/wallet.dart'; import '../../../widgets/desktop/primary_button.dart'; import '../../../widgets/dialogs/basic_dialog.dart'; +import '../../../widgets/hideable_balance.dart'; import '../../../widgets/icon_widgets/sol_token_icon.dart'; import '../../../widgets/rounded_white_container.dart'; import '../sol_token_view.dart'; @@ -104,12 +105,12 @@ class _SolTokenSelectItemState extends ConsumerState { return; } - ref.read(solanaTokenServiceStateProvider.state).state = - Wallet.loadSolTokenWallet( - solWallet: solanaWallet, - contract: widget.token, - ) - as SolanaTokenWallet; + ref + .read(solanaTokenServiceStateProvider.state) + .state = Wallet.loadSolTokenWallet( + solWallet: solanaWallet, + contract: widget.token, + ) as SolanaTokenWallet; final success = await showLoading( whileFuture: _loadTokenWallet(context, ref), @@ -186,27 +187,39 @@ class _SolTokenSelectItemState extends ConsumerState { Text( widget.token.name, style: isDesktop - ? STextStyles.desktopTextExtraSmall( - context, - ).copyWith( - color: Theme.of( - context, - ).extension()!.textDark, - ) + ? STextStyles.desktopTextExtraSmall(context) + .copyWith( + color: Theme.of(context) + .extension()! + .textDark, + ) : STextStyles.titleBold12(context), ), const Spacer(), - Text( - balanceString, - style: isDesktop - ? STextStyles.desktopTextExtraSmall( - context, - ).copyWith( - color: Theme.of( - context, - ).extension()!.textDark, - ) - : STextStyles.itemSubtitle(context), + HideableBalance( + key: ValueKey( + "hideBalance_${widget.walletId}_" + "${widget.token.address}", + ), + iconColor: isDesktop + ? Theme.of(context) + .extension()! + .textDark + : Theme.of(context) + .extension()! + .infoItemLabel, + iconSize: 16, + child: Text( + balanceString, + style: isDesktop + ? STextStyles.desktopTextExtraSmall(context) + .copyWith( + color: Theme.of(context) + .extension()! + .textDark, + ) + : STextStyles.itemSubtitle(context), + ), ), ], ), diff --git a/lib/pages/token_view/sub_widgets/token_summary.dart b/lib/pages/token_view/sub_widgets/token_summary.dart index 0f1bd177d4..ec0dd346df 100644 --- a/lib/pages/token_view/sub_widgets/token_summary.dart +++ b/lib/pages/token_view/sub_widgets/token_summary.dart @@ -36,6 +36,7 @@ import '../../../wallets/isar/providers/eth/token_balance_provider.dart'; import '../../../wallets/isar/providers/wallet_info_provider.dart'; import '../../../widgets/coin_ticker_tag.dart'; import '../../../widgets/conditional_parent.dart'; +import '../../../widgets/hideable_balance.dart'; import '../../../widgets/rounded_container.dart'; import '../../buy_view/buy_in_wallet_view.dart'; import '../../exchange_view/wallet_initiated_exchange_view.dart'; @@ -83,9 +84,9 @@ class TokenSummary extends ConsumerWidget { children: [ SvgPicture.asset( Assets.svg.walletDesktop, - color: Theme.of( - context, - ).extension()!.tokenSummaryTextSecondary, + color: Theme.of(context) + .extension()! + .tokenSummaryTextSecondary, width: 12, height: 12, ), @@ -93,9 +94,9 @@ class TokenSummary extends ConsumerWidget { Text( ref.watch(pWalletName(walletId)), style: STextStyles.w500_12(context).copyWith( - color: Theme.of( - context, - ).extension()!.tokenSummaryTextSecondary, + color: Theme.of(context) + .extension()! + .tokenSummaryTextSecondary, ), ), ], @@ -104,18 +105,24 @@ class TokenSummary extends ConsumerWidget { Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Text( - ref - .watch( - pAmountFormatter( - Ethereum(CryptoCurrencyNetwork.main), - ), - ) - .format(balance.total, tokenContract: token), - style: STextStyles.pageTitleH1(context).copyWith( - color: Theme.of( - context, - ).extension()!.tokenSummaryTextPrimary, + HideableBalance( + iconColor: Theme.of(context) + .extension()! + .tokenSummaryTextPrimary, + iconSize: 24, + child: Text( + ref + .watch( + pAmountFormatter( + Ethereum(CryptoCurrencyNetwork.main), + ), + ) + .format(balance.total, tokenContract: token), + style: STextStyles.pageTitleH1(context).copyWith( + color: Theme.of(context) + .extension()! + .tokenSummaryTextPrimary, + ), ), ), const SizedBox(width: 10), @@ -128,12 +135,18 @@ class TokenSummary extends ConsumerWidget { ), if (price != null) const SizedBox(height: 6), if (price != null) - Text( - "${(balance.total.decimal * price).toAmount(fractionDigits: 2).fiatString(locale: ref.watch(localeServiceChangeNotifierProvider.select((value) => value.locale)))} ${ref.watch(prefsChangeNotifierProvider.select((value) => value.currency))}", - style: STextStyles.subtitle500(context).copyWith( - color: Theme.of( - context, - ).extension()!.tokenSummaryTextPrimary, + HideableBalance( + iconColor: Theme.of(context) + .extension()! + .tokenSummaryTextPrimary, + iconSize: 16, + child: Text( + "${(balance.total.decimal * price).toAmount(fractionDigits: 2).fiatString(locale: ref.watch(localeServiceChangeNotifierProvider.select((value) => value.locale)))} ${ref.watch(prefsChangeNotifierProvider.select((value) => value.currency))}", + style: STextStyles.subtitle500(context).copyWith( + color: Theme.of(context) + .extension()! + .tokenSummaryTextPrimary, + ), ), ), const SizedBox(height: 20), @@ -152,9 +165,9 @@ class TokenSummary extends ConsumerWidget { (value) => value!.tokenContract.address, ), ), - overrideIconColor: Theme.of( - context, - ).extension()!.topNavIconPrimary, + overrideIconColor: Theme.of(context) + .extension()! + .topNavIconPrimary, ), ), ], @@ -263,9 +276,9 @@ class TokenOptionsButton extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.center, children: [ RawMaterialButton( - fillColor: Theme.of( - context, - ).extension()!.tokenSummaryButtonBG, + fillColor: Theme.of(context) + .extension()! + .tokenSummaryButtonBG, elevation: 0, focusElevation: 0, hoverElevation: 0, @@ -283,26 +296,27 @@ class TokenOptionsButton extends StatelessWidget { condition: iconSize < 24, builder: (child) => RoundedContainer( padding: const EdgeInsets.all(6), - color: Theme.of( - context, - ).extension()!.tokenSummaryIcon.withOpacity(0.4), + color: Theme.of(context) + .extension()! + .tokenSummaryIcon + .withOpacity(0.4), radiusMultiplier: 10, child: Center(child: child), ), child: iconAssetPathSVG.startsWith("assets/") ? SvgPicture.asset( iconAssetPathSVG, - color: Theme.of( - context, - ).extension()!.tokenSummaryIcon, + color: Theme.of(context) + .extension()! + .tokenSummaryIcon, width: iconSize, height: iconSize, ) : SvgPicture.file( File(iconAssetPathSVG), - color: Theme.of( - context, - ).extension()!.tokenSummaryIcon, + color: Theme.of(context) + .extension()! + .tokenSummaryIcon, width: iconSize, height: iconSize, ), @@ -313,9 +327,9 @@ class TokenOptionsButton extends StatelessWidget { Text( subLabel, style: STextStyles.w500_12(context).copyWith( - color: Theme.of( - context, - ).extension()!.tokenSummaryTextPrimary, + color: Theme.of(context) + .extension()! + .tokenSummaryTextPrimary, ), ), ], diff --git a/lib/pages/token_view/sub_widgets/token_summary_sol.dart b/lib/pages/token_view/sub_widgets/token_summary_sol.dart index 9d627c1f58..2c9136bf1c 100644 --- a/lib/pages/token_view/sub_widgets/token_summary_sol.dart +++ b/lib/pages/token_view/sub_widgets/token_summary_sol.dart @@ -23,12 +23,12 @@ import '../../../utilities/amount/amount.dart'; import '../../../utilities/assets.dart'; import '../../../utilities/constants.dart'; import '../../../utilities/text_styles.dart'; -import '../../../wallets/crypto_currency/crypto_currency.dart'; import '../../../wallets/isar/providers/solana/current_sol_token_wallet_provider.dart'; import '../../../wallets/isar/providers/solana/sol_token_balance_provider.dart'; import '../../../wallets/isar/providers/wallet_info_provider.dart'; import '../../../widgets/coin_ticker_tag.dart'; import '../../../widgets/conditional_parent.dart'; +import '../../../widgets/hideable_balance.dart'; import '../../../widgets/rounded_container.dart'; import '../../receive_view/sol_token_receive_view.dart'; import '../../send_view/sol_token_send_view.dart'; @@ -63,8 +63,9 @@ class SolanaTokenSummary extends ConsumerWidget { child: Text( "Loading token data...", style: STextStyles.subtitle500(context).copyWith( - color: - Theme.of(context).extension()!.tokenSummaryTextPrimary, + color: Theme.of(context) + .extension()! + .tokenSummaryTextPrimary, ), ), ), @@ -73,12 +74,7 @@ class SolanaTokenSummary extends ConsumerWidget { // Watch the balance from the database provider. final balance = ref.watch( - pSolanaTokenBalance( - ( - walletId: walletId, - tokenMint: tokenMint, - ), - ), + pSolanaTokenBalance((walletId: walletId, tokenMint: tokenMint)), ); Decimal? price; @@ -103,9 +99,9 @@ class SolanaTokenSummary extends ConsumerWidget { children: [ SvgPicture.asset( Assets.svg.walletDesktop, - color: Theme.of( - context, - ).extension()!.tokenSummaryTextSecondary, + color: Theme.of(context) + .extension()! + .tokenSummaryTextSecondary, width: 12, height: 12, ), @@ -113,9 +109,9 @@ class SolanaTokenSummary extends ConsumerWidget { Text( ref.watch(pWalletName(walletId)), style: STextStyles.w500_12(context).copyWith( - color: Theme.of( - context, - ).extension()!.tokenSummaryTextSecondary, + color: Theme.of(context) + .extension()! + .tokenSummaryTextSecondary, ), ), ], @@ -124,28 +120,40 @@ class SolanaTokenSummary extends ConsumerWidget { Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Text( - balance.total.decimal.toStringAsFixed(tokenWallet.tokenDecimals), - style: STextStyles.pageTitleH1(context).copyWith( - color: Theme.of( - context, - ).extension()!.tokenSummaryTextPrimary, + HideableBalance( + iconColor: Theme.of(context) + .extension()! + .tokenSummaryTextPrimary, + iconSize: 24, + child: Text( + balance.total.decimal.toStringAsFixed( + tokenWallet.tokenDecimals, + ), + style: STextStyles.pageTitleH1(context).copyWith( + color: Theme.of(context) + .extension()! + .tokenSummaryTextPrimary, + ), ), ), const SizedBox(width: 10), - CoinTickerTag( - ticker: tokenWallet.tokenSymbol, - ), + CoinTickerTag(ticker: tokenWallet.tokenSymbol), ], ), if (price != null) const SizedBox(height: 6), if (price != null) - Text( - "${(balance.total.decimal * price).toAmount(fractionDigits: 2).fiatString(locale: ref.watch(localeServiceChangeNotifierProvider.select((value) => value.locale)))} ${ref.watch(prefsChangeNotifierProvider.select((value) => value.currency))}", - style: STextStyles.subtitle500(context).copyWith( - color: Theme.of( - context, - ).extension()!.tokenSummaryTextPrimary, + HideableBalance( + iconColor: Theme.of(context) + .extension()! + .tokenSummaryTextPrimary, + iconSize: 16, + child: Text( + "${(balance.total.decimal * price).toAmount(fractionDigits: 2).fiatString(locale: ref.watch(localeServiceChangeNotifierProvider.select((value) => value.locale)))} ${ref.watch(prefsChangeNotifierProvider.select((value) => value.currency))}", + style: STextStyles.subtitle500(context).copyWith( + color: Theme.of(context) + .extension()! + .tokenSummaryTextPrimary, + ), ), ), const SizedBox(height: 20), @@ -163,8 +171,9 @@ class SolanaTokenSummary extends ConsumerWidget { walletId: walletId, initialSyncStatus: initialSyncStatus, tokenContractAddress: tokenMint, - overrideIconColor: - Theme.of(context).extension()!.topNavIconPrimary, + overrideIconColor: Theme.of(context) + .extension()! + .topNavIconPrimary, ), ), ], @@ -250,8 +259,9 @@ class TokenOptionsButton extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.center, children: [ RawMaterialButton( - fillColor: - Theme.of(context).extension()!.tokenSummaryButtonBG, + fillColor: Theme.of(context) + .extension()! + .tokenSummaryButtonBG, elevation: 0, focusElevation: 0, hoverElevation: 0, @@ -267,36 +277,32 @@ class TokenOptionsButton extends StatelessWidget { padding: const EdgeInsets.all(10), child: ConditionalParent( condition: iconSize < 24, - builder: - (child) => RoundedContainer( - padding: const EdgeInsets.all(6), - color: Theme.of(context) - .extension()! - .tokenSummaryIcon - .withOpacity(0.4), - radiusMultiplier: 10, - child: Center(child: child), - ), - child: - iconAssetPathSVG.startsWith("assets/") - ? SvgPicture.asset( - iconAssetPathSVG, - color: - Theme.of( - context, - ).extension()!.tokenSummaryIcon, - width: iconSize, - height: iconSize, - ) - : SvgPicture.file( - File(iconAssetPathSVG), - color: - Theme.of( - context, - ).extension()!.tokenSummaryIcon, - width: iconSize, - height: iconSize, - ), + builder: (child) => RoundedContainer( + padding: const EdgeInsets.all(6), + color: Theme.of(context) + .extension()! + .tokenSummaryIcon + .withOpacity(0.4), + radiusMultiplier: 10, + child: Center(child: child), + ), + child: iconAssetPathSVG.startsWith("assets/") + ? SvgPicture.asset( + iconAssetPathSVG, + color: Theme.of(context) + .extension()! + .tokenSummaryIcon, + width: iconSize, + height: iconSize, + ) + : SvgPicture.file( + File(iconAssetPathSVG), + color: Theme.of(context) + .extension()! + .tokenSummaryIcon, + width: iconSize, + height: iconSize, + ), ), ), ), @@ -304,10 +310,9 @@ class TokenOptionsButton extends StatelessWidget { Text( subLabel, style: STextStyles.w500_12(context).copyWith( - color: - Theme.of( - context, - ).extension()!.tokenSummaryTextPrimary, + color: Theme.of(context) + .extension()! + .tokenSummaryTextPrimary, ), ), ], diff --git a/lib/pages/wallet_view/sub_widgets/wallet_balance_toggle_sheet.dart b/lib/pages/wallet_view/sub_widgets/wallet_balance_toggle_sheet.dart index 120b99b258..f3d8f0a6e1 100644 --- a/lib/pages/wallet_view/sub_widgets/wallet_balance_toggle_sheet.dart +++ b/lib/pages/wallet_view/sub_widgets/wallet_balance_toggle_sheet.dart @@ -22,6 +22,7 @@ import '../../../utilities/enums/wallet_balance_toggle_state.dart'; import '../../../utilities/text_styles.dart'; import '../../../wallets/crypto_currency/crypto_currency.dart'; import '../../../wallets/isar/providers/wallet_info_provider.dart'; +import '../../../widgets/hideable_balance.dart'; enum _BalanceType { available, full, privateAvailable, privateFull } @@ -44,23 +45,21 @@ class WalletBalanceToggleSheet extends ConsumerWidget { _BalanceType _bal = ref.watch(walletBalanceToggleStateProvider.state).state == - WalletBalanceToggleState.available - ? _BalanceType.available - : _BalanceType.full; + WalletBalanceToggleState.available + ? _BalanceType.available + : _BalanceType.full; Balance? balancePrivate; if (hasPrivate) { - balancePrivate = - isMweb - ? ref.watch(pWalletBalanceSecondary(walletId)) - : ref.watch(pWalletBalanceTertiary(walletId)); + balancePrivate = isMweb + ? ref.watch(pWalletBalanceSecondary(walletId)) + : ref.watch(pWalletBalanceTertiary(walletId)); if (ref.watch(publicPrivateBalanceStateProvider.state).state == BalanceType.private) { - _bal = - _bal == _BalanceType.available - ? _BalanceType.privateAvailable - : _BalanceType.privateFull; + _bal = _bal == _BalanceType.available + ? _BalanceType.privateAvailable + : _BalanceType.privateFull; } } @@ -85,10 +84,9 @@ class WalletBalanceToggleSheet extends ConsumerWidget { Center( child: Container( decoration: BoxDecoration( - color: - Theme.of( - context, - ).extension()!.textFieldDefaultBG, + color: Theme.of(context) + .extension()! + .textFieldDefaultBG, borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, ), @@ -244,10 +242,9 @@ class BalanceSelector extends ConsumerWidget { width: 20, height: 20, child: Radio( - activeColor: - Theme.of( - context, - ).extension()!.radioButtonIconEnabled, + activeColor: Theme.of(context) + .extension()! + .radioButtonIconEnabled, value: value, groupValue: groupValue, onChanged: onChanged, @@ -259,13 +256,18 @@ class BalanceSelector extends ConsumerWidget { children: [ Text(title, style: STextStyles.titleBold12(context)), const SizedBox(height: 2), - Text( - ref.watch(pAmountFormatter(coin)).format(balance), - style: STextStyles.itemSubtitle12(context).copyWith( - color: - Theme.of( - context, - ).extension()!.textSubtitle1, + HideableBalance( + iconColor: Theme.of(context) + .extension()! + .textSubtitle1, + iconSize: 16, + child: Text( + ref.watch(pAmountFormatter(coin)).format(balance), + style: STextStyles.itemSubtitle12(context).copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, + ), ), ), ], diff --git a/lib/pages/wallet_view/sub_widgets/wallet_summary_info.dart b/lib/pages/wallet_view/sub_widgets/wallet_summary_info.dart index 68e0123bc8..704f8d8367 100644 --- a/lib/pages/wallet_view/sub_widgets/wallet_summary_info.dart +++ b/lib/pages/wallet_view/sub_widgets/wallet_summary_info.dart @@ -33,6 +33,7 @@ import '../../../wallets/crypto_currency/coins/firo.dart'; import '../../../wallets/isar/providers/wallet_info_provider.dart'; import '../../../wallets/wallet/impl/banano_wallet.dart'; import '../../../widgets/conditional_parent.dart'; +import '../../../widgets/hideable_balance.dart'; import 'wallet_balance_toggle_sheet.dart'; import 'wallet_refresh_button.dart'; @@ -101,10 +102,9 @@ class WalletSummaryInfo extends ConsumerWidget { "${_showAvailable ? "Available" : "Full"} ${type.name.capitalize()} balance"; switch (type) { case BalanceType.private: - final balance = - coin is Firo - ? ref.watch(pWalletBalanceTertiary(walletId)) - : ref.watch(pWalletBalanceSecondary(walletId)); + final balance = coin is Firo + ? ref.watch(pWalletBalanceTertiary(walletId)) + : ref.watch(pWalletBalanceSecondary(walletId)); balanceToShow = _showAvailable ? balance.spendable : balance.total; break; @@ -122,23 +122,21 @@ class WalletSummaryInfo extends ConsumerWidget { List? imageBytes; if (coin is Banano) { - imageBytes = - (ref.watch(pWallets).getWallet(walletId) as BananoWallet) - .getMonkeyImageBytes(); + imageBytes = (ref.watch(pWallets).getWallet(walletId) as BananoWallet) + .getMonkeyImageBytes(); } return ConditionalParent( condition: imageBytes != null, - builder: - (child) => Stack( - children: [ - Positioned.fill( - left: 150.0, - child: SvgPicture.memory(Uint8List.fromList(imageBytes!)), - ), - child, - ], + builder: (child) => Stack( + children: [ + Positioned.fill( + left: 150.0, + child: SvgPicture.memory(Uint8List.fromList(imageBytes!)), ), + child, + ], + ), child: Row( children: [ Expanded( @@ -151,12 +149,14 @@ class WalletSummaryInfo extends ConsumerWidget { if (ref.read(walletBalanceToggleStateProvider) == WalletBalanceToggleState.available) { ref - .read(walletBalanceToggleStateProvider.notifier) - .state = WalletBalanceToggleState.full; + .read(walletBalanceToggleStateProvider.notifier) + .state = + WalletBalanceToggleState.full; } else { ref - .read(walletBalanceToggleStateProvider.notifier) - .state = WalletBalanceToggleState.available; + .read(walletBalanceToggleStateProvider.notifier) + .state = + WalletBalanceToggleState.available; } } else { showSheet(context); @@ -167,20 +167,18 @@ class WalletSummaryInfo extends ConsumerWidget { Text( title, style: STextStyles.subtitle500(context).copyWith( - color: - Theme.of( - context, - ).extension()!.textFavoriteCard, + color: Theme.of(context) + .extension()! + .textFavoriteCard, ), ), if (!toggleBalance) ...[ const SizedBox(width: 4), SvgPicture.asset( Assets.svg.chevronDown, - color: - Theme.of( - context, - ).extension()!.textFavoriteCard, + color: Theme.of(context) + .extension()! + .textFavoriteCard, width: 8, height: 4, ), @@ -206,25 +204,35 @@ class WalletSummaryInfo extends ConsumerWidget { const Spacer(), FittedBox( fit: BoxFit.scaleDown, - child: SelectableText( - ref.watch(pAmountFormatter(coin)).format(balanceToShow), - style: STextStyles.pageTitleH1(context).copyWith( - fontSize: 24, - color: - Theme.of( - context, - ).extension()!.textFavoriteCard, + child: HideableBalance( + iconColor: Theme.of(context) + .extension()! + .textFavoriteCard, + iconSize: 24, + child: SelectableText( + ref.watch(pAmountFormatter(coin)).format(balanceToShow), + style: STextStyles.pageTitleH1(context).copyWith( + fontSize: 24, + color: Theme.of(context) + .extension()! + .textFavoriteCard, + ), ), ), ), if (price != null) - Text( - "${(price.value * balanceToShow.decimal).toAmount(fractionDigits: 2).fiatString(locale: locale)} $baseCurrency", - style: STextStyles.subtitle500(context).copyWith( - color: - Theme.of( - context, - ).extension()!.textFavoriteCard, + HideableBalance( + iconColor: Theme.of(context) + .extension()! + .textFavoriteCard, + iconSize: 16, + child: Text( + "${(price.value * balanceToShow.decimal).toAmount(fractionDigits: 2).fiatString(locale: locale)} $baseCurrency", + style: STextStyles.subtitle500(context).copyWith( + color: Theme.of(context) + .extension()! + .textFavoriteCard, + ), ), ), ], diff --git a/lib/pages/wallets_view/sub_widgets/favorite_card.dart b/lib/pages/wallets_view/sub_widgets/favorite_card.dart index aad2dc5dbb..da5e017277 100644 --- a/lib/pages/wallets_view/sub_widgets/favorite_card.dart +++ b/lib/pages/wallets_view/sub_widgets/favorite_card.dart @@ -31,6 +31,7 @@ import '../../../wallets/isar/providers/wallet_info_provider.dart'; import '../../../wallets/wallet/intermediate/external_wallet.dart'; import '../../../widgets/coin_card.dart'; import '../../../widgets/conditional_parent.dart'; +import '../../../widgets/hideable_balance.dart'; import '../../wallet_view/wallet_view.dart'; class FavoriteCard extends ConsumerStatefulWidget { @@ -78,53 +79,51 @@ class _FavoriteCardState extends ConsumerState { } return ConditionalParent( condition: Util.isDesktop, - builder: - (child) => MouseRegion( - cursor: SystemMouseCursors.click, - onEnter: (_) { - setState(() { - _hovering = true; - }); - }, - onExit: (_) { - setState(() { - _hovering = false; - }); - }, - child: AnimatedScale( - duration: const Duration(milliseconds: 200), - scale: _hovering ? 1.05 : 1, - child: AnimatedContainer( - duration: const Duration(milliseconds: 200), - decoration: - _hovering - ? BoxDecoration( - color: Colors.transparent, - borderRadius: BorderRadius.circular( - Constants.size.circularBorderRadius, - ), - boxShadow: [ - Theme.of( - context, - ).extension()!.standardBoxShadow, - Theme.of( - context, - ).extension()!.standardBoxShadow, - Theme.of( - context, - ).extension()!.standardBoxShadow, - ], - ) - : BoxDecoration( - color: Colors.transparent, - borderRadius: BorderRadius.circular( - Constants.size.circularBorderRadius, - ), - ), - child: child, - ), - ), + builder: (child) => MouseRegion( + cursor: SystemMouseCursors.click, + onEnter: (_) { + setState(() { + _hovering = true; + }); + }, + onExit: (_) { + setState(() { + _hovering = false; + }); + }, + child: AnimatedScale( + duration: const Duration(milliseconds: 200), + scale: _hovering ? 1.05 : 1, + child: AnimatedContainer( + duration: const Duration(milliseconds: 200), + decoration: _hovering + ? BoxDecoration( + color: Colors.transparent, + borderRadius: BorderRadius.circular( + Constants.size.circularBorderRadius, + ), + boxShadow: [ + Theme.of(context) + .extension()! + .standardBoxShadow, + Theme.of(context) + .extension()! + .standardBoxShadow, + Theme.of(context) + .extension()! + .standardBoxShadow, + ], + ) + : BoxDecoration( + color: Colors.transparent, + borderRadius: BorderRadius.circular( + Constants.size.circularBorderRadius, + ), + ), + child: child, ), + ), + ), child: GestureDetector( onTap: () async { final wallet = ref.read(pWallets).getWallet(walletId); @@ -159,13 +158,11 @@ class _FavoriteCardState extends ConsumerState { if (mounted) { if (Util.isDesktop) { - await Navigator.of( - context, - ).pushNamed(DesktopWalletView.routeName, arguments: walletId); + await Navigator.of(context) + .pushNamed(DesktopWalletView.routeName, arguments: walletId); } else { - await Navigator.of( - context, - ).pushNamed(WalletView.routeName, arguments: walletId); + await Navigator.of(context) + .pushNamed(WalletView.routeName, arguments: walletId); } } }, @@ -193,10 +190,9 @@ class _FavoriteCardState extends ConsumerState { child: Text( ref.watch(pWalletName(walletId)), style: STextStyles.itemSubtitle12(context).copyWith( - color: - Theme.of( - context, - ).extension()!.textFavoriteCard, + color: Theme.of(context) + .extension()! + .textFavoriteCard, ), overflow: TextOverflow.fade, ), @@ -215,15 +211,18 @@ class _FavoriteCardState extends ConsumerState { Amount total = balance.total; if (coin is Firo) { - total += - ref.watch(pWalletBalanceSecondary(walletId)).total; - total += - ref.watch(pWalletBalanceTertiary(walletId)).total; + total += ref + .watch(pWalletBalanceSecondary(walletId)) + .total; + total += ref + .watch(pWalletBalanceTertiary(walletId)) + .total; } else if (ref.watch( pWalletInfo(walletId).select((s) => s.isMwebEnabled), )) { - total += - ref.watch(pWalletBalanceSecondary(walletId)).total; + total += ref + .watch(pWalletBalanceSecondary(walletId)) + .total; } Amount fiatTotal = Amount.zero; @@ -241,30 +240,40 @@ class _FavoriteCardState extends ConsumerState { children: [ FittedBox( fit: BoxFit.scaleDown, - child: Text( - ref.watch(pAmountFormatter(coin)).format(total), - style: STextStyles.titleBold12(context).copyWith( - fontSize: 16, - color: - Theme.of(context) - .extension()! - .textFavoriteCard, + child: HideableBalance( + iconColor: Theme.of(context) + .extension()! + .textFavoriteCard, + iconSize: 16, + child: Text( + ref.watch(pAmountFormatter(coin)).format(total), + style: STextStyles.titleBold12(context) + .copyWith( + fontSize: 16, + color: Theme.of(context) + .extension()! + .textFavoriteCard, + ), ), ), ), if (externalCalls && price != null) const SizedBox(height: 4), if (externalCalls && price != null) - Text( - "${fiatTotal.fiatString(locale: ref.watch(localeServiceChangeNotifierProvider.select((value) => value.locale)))} ${ref.watch(prefsChangeNotifierProvider.select((value) => value.currency))}", - style: STextStyles.itemSubtitle12( - context, - ).copyWith( - fontSize: 10, - color: - Theme.of(context) - .extension()! - .textFavoriteCard, + HideableBalance( + iconColor: Theme.of(context) + .extension()! + .textFavoriteCard, + iconSize: 10, + child: Text( + "${fiatTotal.fiatString(locale: ref.watch(localeServiceChangeNotifierProvider.select((value) => value.locale)))} ${ref.watch(prefsChangeNotifierProvider.select((value) => value.currency))}", + style: STextStyles.itemSubtitle12(context) + .copyWith( + fontSize: 10, + color: Theme.of(context) + .extension()! + .textFavoriteCard, + ), ), ), ], diff --git a/lib/pages_desktop_specific/desktop_exchange/subwidgets/desktop_choose_address_from_stack.dart b/lib/pages_desktop_specific/desktop_exchange/subwidgets/desktop_choose_address_from_stack.dart index 8eaf949914..2a7062f58b 100644 --- a/lib/pages_desktop_specific/desktop_exchange/subwidgets/desktop_choose_address_from_stack.dart +++ b/lib/pages_desktop_specific/desktop_exchange/subwidgets/desktop_choose_address_from_stack.dart @@ -28,6 +28,7 @@ import '../../../wallets/isar/providers/wallet_info_provider.dart'; import '../../../wallets/wallet/wallet_mixin_interfaces/spark_interface.dart'; import '../../../widgets/custom_buttons/blue_text_button.dart'; import '../../../widgets/desktop/secondary_button.dart'; +import '../../../widgets/hideable_balance.dart'; import '../../../widgets/icon_widgets/x_icon.dart'; import '../../../widgets/rounded_white_container.dart'; import '../../../widgets/stack_dialog.dart'; @@ -108,9 +109,9 @@ class _DesktopChooseFromStackState }); }, style: STextStyles.desktopTextExtraSmall(context).copyWith( - color: Theme.of( - context, - ).extension()!.textFieldActiveText, + color: Theme.of(context) + .extension()! + .textFieldActiveText, height: 1.8, ), decoration: @@ -167,9 +168,9 @@ class _DesktopChooseFromStackState return Column( children: [ RoundedWhiteContainer( - borderColor: Theme.of( - context, - ).extension()!.background, + borderColor: Theme.of(context) + .extension()! + .background, child: Center( child: Text( "No ${widget.coin.ticker.toUpperCase()} wallets", @@ -234,12 +235,16 @@ class _BalanceDisplay extends ConsumerWidget { ref.watch(pWalletBalanceSecondary(walletId)).total + ref.watch(pWalletBalanceTertiary(walletId)).total; - return Text( - ref.watch(pAmountFormatter(coin)).format(total), - style: STextStyles.desktopTextExtraSmall(context).copyWith( - color: Theme.of(context).extension()!.textSubtitle1, + return HideableBalance( + iconColor: Theme.of(context).extension()!.textSubtitle1, + iconSize: 16, + child: Text( + ref.watch(pAmountFormatter(coin)).format(total), + style: STextStyles.desktopTextExtraSmall(context).copyWith( + color: Theme.of(context).extension()!.textSubtitle1, + ), + textAlign: TextAlign.right, ), - textAlign: TextAlign.right, ); } } @@ -267,9 +272,9 @@ class _WalletRow extends ConsumerWidget { ref.watch(pWalletName(walletId)), style: STextStyles.desktopTextExtraExtraSmall(context) .copyWith( - color: Theme.of( - context, - ).extension()!.textDark, + color: Theme.of(context) + .extension()! + .textDark, ), ), ], diff --git a/lib/pages_desktop_specific/my_stack_view/paynym/desktop_paynym_send_dialog.dart b/lib/pages_desktop_specific/my_stack_view/paynym/desktop_paynym_send_dialog.dart index 1ff4405dfa..3019172d3b 100644 --- a/lib/pages_desktop_specific/my_stack_view/paynym/desktop_paynym_send_dialog.dart +++ b/lib/pages_desktop_specific/my_stack_view/paynym/desktop_paynym_send_dialog.dart @@ -29,6 +29,7 @@ import '../../../utilities/text_styles.dart'; import '../../../wallets/isar/providers/wallet_info_provider.dart'; import '../../../widgets/desktop/desktop_dialog.dart'; import '../../../widgets/desktop/desktop_dialog_close_button.dart'; +import '../../../widgets/hideable_balance.dart'; import '../../../widgets/rounded_white_container.dart'; import '../wallet_view/sub_widgets/desktop_send.dart'; @@ -92,8 +93,9 @@ class _DesktopPaynymSendDialogState Padding( padding: const EdgeInsets.symmetric(horizontal: 32), child: RoundedWhiteContainer( - borderColor: - Theme.of(context).extension()!.background, + borderColor: Theme.of(context) + .extension()! + .background, // Theme.of(context).extension()!.textSubtitle4, child: Row( children: [ @@ -116,10 +118,9 @@ class _DesktopPaynymSendDialogState Text( "Available balance", style: STextStyles.baseXS(context).copyWith( - color: - Theme.of( - context, - ).extension()!.textSubtitle1, + color: Theme.of(context) + .extension()! + .textSubtitle1, ), ), ], @@ -127,33 +128,38 @@ class _DesktopPaynymSendDialogState const Spacer(), Container( color: Colors.transparent, - child: Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Text( - ref - .watch(pAmountFormatter(coin)) - .format( - ref - .watch(pWalletBalance(widget.walletId)) - .spendable, - ), - style: STextStyles.titleBold12(context), - textAlign: TextAlign.right, - ), - if (price != null) const SizedBox(height: 2), - if (price != null) + child: HideableBalance( + iconColor: Theme.of(context) + .extension()! + .textDark, + iconSize: 16, + child: Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ Text( - "${(ref.watch(pWalletBalance(widget.walletId)).spendable.decimal * price).toAmount(fractionDigits: 2).fiatString(locale: locale)} ${ref.watch(prefsChangeNotifierProvider.select((value) => value.currency))}", - style: STextStyles.baseXS(context).copyWith( - color: - Theme.of( - context, - ).extension()!.textSubtitle1, - ), + ref + .watch(pAmountFormatter(coin)) + .format( + ref + .watch(pWalletBalance(widget.walletId)) + .spendable, + ), + style: STextStyles.titleBold12(context), textAlign: TextAlign.right, ), - ], + if (price != null) const SizedBox(height: 2), + if (price != null) + Text( + "${(ref.watch(pWalletBalance(widget.walletId)).spendable.decimal * price).toAmount(fractionDigits: 2).fiatString(locale: locale)} ${ref.watch(prefsChangeNotifierProvider.select((value) => value.currency))}", + style: STextStyles.baseXS(context).copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, + ), + textAlign: TextAlign.right, + ), + ], + ), ), ), ], diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_send.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_send.dart index b411775efe..274b192597 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_send.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_send.dart @@ -73,6 +73,7 @@ import '../../../../widgets/desktop/secondary_button.dart'; import '../../../../widgets/dialogs/firo_exchange_address_dialog.dart'; import '../../../../widgets/epic_txs_method_toggle.dart'; import '../../../../widgets/eth_fee_form.dart'; +import '../../../../widgets/hideable_balance.dart'; import '../../../../widgets/icon_widgets/addressbook_icon.dart'; import '../../../../widgets/icon_widgets/clipboard_icon.dart'; import '../../../../widgets/icon_widgets/qrcode_icon.dart'; @@ -1531,19 +1532,25 @@ class _DesktopSendState extends ConsumerState { style: STextStyles.itemSubtitle12(context), ), const SizedBox(width: 10), - Text( - ref - .watch(pAmountFormatter(coin)) - .format( - ref - .watch( - isMwebEnabled - ? pWalletBalanceSecondary(walletId) - : pWalletBalanceTertiary(walletId), - ) - .spendable, - ), - style: STextStyles.itemSubtitle(context), + HideableBalance( + iconColor: Theme.of(context) + .extension()! + .infoItemLabel, + iconSize: 16, + child: Text( + ref + .watch(pAmountFormatter(coin)) + .format( + ref + .watch( + isMwebEnabled + ? pWalletBalanceSecondary(walletId) + : pWalletBalanceTertiary(walletId), + ) + .spendable, + ), + style: STextStyles.itemSubtitle(context), + ), ), ], ), @@ -1557,13 +1564,19 @@ class _DesktopSendState extends ConsumerState { style: STextStyles.itemSubtitle12(context), ), const SizedBox(width: 10), - Text( - ref - .watch(pAmountFormatter(coin)) - .format( - ref.watch(pWalletBalance(walletId)).spendable, - ), - style: STextStyles.itemSubtitle(context), + HideableBalance( + iconColor: Theme.of(context) + .extension()! + .infoItemLabel, + iconSize: 16, + child: Text( + ref + .watch(pAmountFormatter(coin)) + .format( + ref.watch(pWalletBalance(walletId)).spendable, + ), + style: STextStyles.itemSubtitle(context), + ), ), ], ), diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_wallet_summary.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_wallet_summary.dart index ac01104ff3..ebb8960965 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_wallet_summary.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_wallet_summary.dart @@ -33,6 +33,7 @@ import '../../../../wallets/isar/providers/eth/token_balance_provider.dart'; import '../../../../wallets/isar/providers/solana/current_sol_token_wallet_provider.dart'; import '../../../../wallets/isar/providers/solana/sol_token_balance_provider.dart'; import '../../../../wallets/isar/providers/wallet_info_provider.dart'; +import '../../../../widgets/hideable_balance.dart'; import 'desktop_balance_toggle_button.dart'; class DesktopWalletSummary extends ConsumerStatefulWidget { @@ -171,20 +172,33 @@ class _WDesktopWalletSummaryState extends ConsumerState { children: [ FittedBox( fit: BoxFit.scaleDown, - child: SelectableText( - ref - .watch(pAmountFormatter(coin)) - .format(balanceToShow, tokenContract: tokenContract), - style: STextStyles.desktopH3(context), + child: HideableBalance( + iconColor: Theme.of(context) + .extension()! + .textDark, + iconSize: 24, + child: SelectableText( + ref + .watch(pAmountFormatter(coin)) + .format(balanceToShow, tokenContract: tokenContract), + style: STextStyles.desktopH3(context), + ), ), ), if (externalCalls && price != null) - SelectableText( - "${Amount.fromDecimal(price.value * balanceToShow.decimal, fractionDigits: 2).fiatString(locale: locale)} $baseCurrency", - style: STextStyles.desktopTextExtraSmall(context).copyWith( - color: Theme.of( - context, - ).extension()!.textSubtitle1, + HideableBalance( + iconColor: Theme.of(context) + .extension()! + .textSubtitle1, + iconSize: 16, + child: SelectableText( + "${Amount.fromDecimal(price.value * balanceToShow.decimal, fractionDigits: 2).fiatString(locale: locale)} $baseCurrency", + style: STextStyles.desktopTextExtraSmall(context) + .copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, + ), ), ), // if (coin is Firo) diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/firo_desktop_wallet_summary.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/firo_desktop_wallet_summary.dart index e193ab380c..5728276544 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/firo_desktop_wallet_summary.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/firo_desktop_wallet_summary.dart @@ -27,6 +27,7 @@ import '../../../../utilities/extensions/extensions.dart'; import '../../../../utilities/text_styles.dart'; import '../../../../wallets/crypto_currency/coins/firo.dart'; import '../../../../wallets/isar/providers/wallet_info_provider.dart'; +import '../../../../widgets/hideable_balance.dart'; import 'desktop_balance_toggle_button.dart'; class FiroDesktopWalletSummary extends ConsumerStatefulWidget { @@ -194,10 +195,14 @@ class _Balance extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - return SelectableText( - ref.watch(pAmountFormatter(coin)).format(amount, tokenContract: null), - style: STextStyles.desktopH3(context), - textAlign: TextAlign.end, + return HideableBalance( + iconColor: Theme.of(context).extension()!.textDark, + iconSize: 24, + child: SelectableText( + ref.watch(pAmountFormatter(coin)).format(amount, tokenContract: null), + style: STextStyles.desktopH3(context), + textAlign: TextAlign.end, + ), ); } } @@ -218,14 +223,17 @@ class _Price extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { return Padding( padding: const EdgeInsets.only(left: 16), - child: SelectableText( - "${Amount.fromDecimal(price * amount.decimal, fractionDigits: 2).fiatString(locale: ref.watch(localeServiceChangeNotifierProvider.select((value) => value.locale)))} " - "${ref.watch(prefsChangeNotifierProvider.select((value) => value.currency))}", - style: STextStyles.desktopTextExtraSmall(context).copyWith( - color: Theme.of(context).extension()!.textSubtitle1, + child: HideableBalance( + iconColor: Theme.of(context).extension()!.textSubtitle1, + iconSize: 16, + child: SelectableText( + "${Amount.fromDecimal(price * amount.decimal, fractionDigits: 2).fiatString(locale: ref.watch(localeServiceChangeNotifierProvider.select((value) => value.locale)))} " + "${ref.watch(prefsChangeNotifierProvider.select((value) => value.currency))}", + style: STextStyles.desktopTextExtraSmall(context).copyWith( + color: Theme.of(context).extension()!.textSubtitle1, + ), + textAlign: TextAlign.end, ), - - textAlign: TextAlign.end, ), ); } diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/mweb_desktop_wallet_summary.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/mweb_desktop_wallet_summary.dart index 6b025f0dd7..765e6734b9 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/mweb_desktop_wallet_summary.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/mweb_desktop_wallet_summary.dart @@ -23,6 +23,7 @@ import '../../../../utilities/enums/wallet_balance_toggle_state.dart'; import '../../../../utilities/text_styles.dart'; import '../../../../wallets/crypto_currency/crypto_currency.dart'; import '../../../../wallets/isar/providers/wallet_info_provider.dart'; +import '../../../../widgets/hideable_balance.dart'; import 'desktop_balance_toggle_button.dart'; class MwebDesktopWalletSummary extends ConsumerStatefulWidget { @@ -169,10 +170,14 @@ class _Balance extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - return SelectableText( - ref.watch(pAmountFormatter(coin)).format(amount, tokenContract: null), - style: STextStyles.desktopH3(context), - textAlign: TextAlign.end, + return HideableBalance( + iconColor: Theme.of(context).extension()!.textDark, + iconSize: 24, + child: SelectableText( + ref.watch(pAmountFormatter(coin)).format(amount, tokenContract: null), + style: STextStyles.desktopH3(context), + textAlign: TextAlign.end, + ), ); } } @@ -193,14 +198,17 @@ class _Price extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { return Padding( padding: const EdgeInsets.only(left: 16), - child: SelectableText( - "${Amount.fromDecimal(price * amount.decimal, fractionDigits: 2).fiatString(locale: ref.watch(localeServiceChangeNotifierProvider.select((value) => value.locale)))} " - "${ref.watch(prefsChangeNotifierProvider.select((value) => value.currency))}", - style: STextStyles.desktopTextExtraSmall(context).copyWith( - color: Theme.of(context).extension()!.textSubtitle1, + child: HideableBalance( + iconColor: Theme.of(context).extension()!.textSubtitle1, + iconSize: 16, + child: SelectableText( + "${Amount.fromDecimal(price * amount.decimal, fractionDigits: 2).fiatString(locale: ref.watch(localeServiceChangeNotifierProvider.select((value) => value.locale)))} " + "${ref.watch(prefsChangeNotifierProvider.select((value) => value.currency))}", + style: STextStyles.desktopTextExtraSmall(context).copyWith( + color: Theme.of(context).extension()!.textSubtitle1, + ), + textAlign: TextAlign.end, ), - - textAlign: TextAlign.end, ), ); } diff --git a/lib/pages_desktop_specific/settings/settings_menu/appearance_settings/appearance_settings.dart b/lib/pages_desktop_specific/settings/settings_menu/appearance_settings/appearance_settings.dart index 8fa05124b1..36db9a7350 100644 --- a/lib/pages_desktop_specific/settings/settings_menu/appearance_settings/appearance_settings.dart +++ b/lib/pages_desktop_specific/settings/settings_menu/appearance_settings/appearance_settings.dart @@ -14,6 +14,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; + import '../../../../app_config.dart'; import '../../../../models/isar/stack_theme.dart'; import 'sub_widgets/desktop_manage_themes.dart'; @@ -27,6 +28,7 @@ import '../../../../utilities/constants.dart'; import '../../../../utilities/text_styles.dart'; import '../../../../widgets/custom_buttons/draggable_switch_button.dart'; import '../../../../widgets/rounded_white_container.dart'; + import 'package:tuple/tuple.dart'; class AppearanceOptionSettings extends ConsumerStatefulWidget { @@ -48,9 +50,7 @@ class _AppearanceOptionSettings child: Column( children: [ Padding( - padding: const EdgeInsets.only( - right: 30, - ), + padding: const EdgeInsets.only(right: 30), child: RoundedWhiteContainer( radiusMultiplier: 2, child: Wrap( @@ -77,16 +77,17 @@ class _AppearanceOptionSettings children: [ TextSpan( text: "Appearances", - style: - STextStyles.desktopTextSmall(context), + style: STextStyles.desktopTextSmall( + context, + ), ), TextSpan( text: "\n\nCustomize how your ${AppConfig.appName} looks according to your preferences.", style: STextStyles.desktopTextExtraExtraSmall( - context, - ), + context, + ), ), ], ), @@ -96,9 +97,7 @@ class _AppearanceOptionSettings ), const Padding( padding: EdgeInsets.all(10.0), - child: Divider( - thickness: 0.5, - ), + child: Divider(thickness: 0.5), ), Padding( padding: const EdgeInsets.all(10.0), @@ -109,10 +108,10 @@ class _AppearanceOptionSettings "Display favorite wallets", style: STextStyles.desktopTextExtraSmall(context) .copyWith( - color: Theme.of(context) - .extension()! - .textDark, - ), + color: Theme.of(context) + .extension()! + .textDark, + ), textAlign: TextAlign.left, ), SizedBox( @@ -126,8 +125,9 @@ class _AppearanceOptionSettings ), onValueChanged: (newValue) { ref - .read(prefsChangeNotifierProvider) - .showFavoriteWallets = newValue; + .read(prefsChangeNotifierProvider) + .showFavoriteWallets = + newValue; }, ), ), @@ -136,10 +136,47 @@ class _AppearanceOptionSettings ), const Padding( padding: EdgeInsets.all(10.0), - child: Divider( - thickness: 0.5, + child: Divider(thickness: 0.5), + ), + Padding( + padding: const EdgeInsets.all(10.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "Hide balances", + style: STextStyles.desktopTextExtraSmall(context) + .copyWith( + color: Theme.of(context) + .extension()! + .textDark, + ), + textAlign: TextAlign.left, + ), + SizedBox( + height: 20, + width: 40, + child: DraggableSwitchButton( + isOn: ref.watch( + prefsChangeNotifierProvider.select( + (value) => value.hideBalances, + ), + ), + onValueChanged: (newValue) { + ref + .read(prefsChangeNotifierProvider) + .hideBalances = + newValue; + }, + ), + ), + ], ), ), + const Padding( + padding: EdgeInsets.all(10.0), + child: Divider(thickness: 0.5), + ), Padding( padding: const EdgeInsets.all(10.0), child: Row( @@ -149,10 +186,10 @@ class _AppearanceOptionSettings "Choose theme", style: STextStyles.desktopTextExtraSmall(context) .copyWith( - color: Theme.of(context) - .extension()! - .textDark, - ), + color: Theme.of(context) + .extension()! + .textDark, + ), textAlign: TextAlign.left, ), ], @@ -175,9 +212,7 @@ class _AppearanceOptionSettings } class ThemeToggle extends ConsumerStatefulWidget { - const ThemeToggle({ - super.key, - }); + const ThemeToggle({super.key}); @override ConsumerState createState() => _ThemeToggle(); @@ -219,8 +254,9 @@ class _ThemeToggle extends ConsumerState { } // apply theme - ref.read(themeProvider.notifier).state = - ref.read(pThemeService).getTheme(themeId: themeId)!; + ref.read(themeProvider.notifier).state = ref + .read(pThemeService) + .getTheme(themeId: themeId)!; // Assets.precache(context); } else { @@ -239,8 +275,9 @@ class _ThemeToggle extends ConsumerState { ref.read(prefsChangeNotifierProvider.notifier).themeId = themeId; // apply theme - ref.read(themeProvider.notifier).state = - ref.read(pThemeService).getTheme(themeId: themeId)!; + ref.read(themeProvider.notifier).state = ref + .read(pThemeService) + .getTheme(themeId: themeId)!; // Assets.precache(context); } @@ -278,16 +315,20 @@ class _ThemeToggle extends ConsumerState { void initState() { _updateInstalledList(); - _subscription = - ref.read(mainDBProvider).isar.stackThemes.watchLazy().listen((_) { - if (mounted) { - WidgetsBinding.instance.addPostFrameCallback((_) { - setState(() { - _updateInstalledList(); - }); + _subscription = ref + .read(mainDBProvider) + .isar + .stackThemes + .watchLazy() + .listen((_) { + if (mounted) { + WidgetsBinding.instance.addPostFrameCallback((_) { + setState(() { + _updateInstalledList(); + }); + }); + } }); - } - }); super.initState(); } @@ -328,27 +369,23 @@ class _ThemeToggle extends ConsumerState { width: 2.5, color: _current == i ? Theme.of(context) - .extension()! - .infoItemIcons + .extension()! + .infoItemIcons : Theme.of(context) - .extension()! - .popupBG, + .extension()! + .popupBG, ), borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, ), ), child: SvgPicture.file( - File( - installedThemeIdNames[i].item3, - ), + File(installedThemeIdNames[i].item3), height: 160, width: 200, ), ), - const SizedBox( - height: 12, - ), + const SizedBox(height: 12), Row( children: [ SizedBox( @@ -367,17 +404,15 @@ class _ThemeToggle extends ConsumerState { }, ), ), - const SizedBox( - width: 14, - ), + const SizedBox(width: 14), Text( installedThemeIdNames[i].item2, style: STextStyles.desktopTextExtraSmall(context) .copyWith( - color: Theme.of(context) - .extension()! - .textDark, - ), + color: Theme.of(context) + .extension()! + .textDark, + ), ), ], ), diff --git a/lib/providers/global/prefs_provider.dart b/lib/providers/global/prefs_provider.dart index abe6653d20..2b79b31cb2 100644 --- a/lib/providers/global/prefs_provider.dart +++ b/lib/providers/global/prefs_provider.dart @@ -8,15 +8,16 @@ * */ -import 'package:flutter/foundation.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; + import '../../utilities/prefs.dart'; -int _count = 0; -final prefsChangeNotifierProvider = ChangeNotifierProvider((_) { - if (kDebugMode) { - _count++; - } +final prefsChangeNotifierProvider = ChangeNotifierProvider( + (_) => Prefs.instance, +); - return Prefs.instance; -}); +final hideBalancesProvider = Provider( + (ref) => ref.watch( + prefsChangeNotifierProvider.select((value) => value.hideBalances), + ), +); diff --git a/lib/utilities/prefs.dart b/lib/utilities/prefs.dart index 56013d64d7..15e4ca0eb7 100644 --- a/lib/utilities/prefs.dart +++ b/lib/utilities/prefs.dart @@ -83,6 +83,7 @@ class Prefs extends ChangeNotifier { _autoLockInfo = await _getAutoLockInfo(); _privacyScreen = await _getPrivacyScreen(); _disableScreenShots = await _getDisableScreenShots(); + _hideBalances = await _getHideBalances(); _initialized = true; } @@ -108,10 +109,9 @@ class Prefs extends ChangeNotifier { Future _getLastUnlockedTimeout() async { return (DB.instance.get( - boxName: DB.boxNamePrefs, - key: "lastUnlockedTimeout", - )) - as int? ?? + boxName: DB.boxNamePrefs, + key: "lastUnlockedTimeout", + )) as int? ?? 60; } @@ -135,10 +135,9 @@ class Prefs extends ChangeNotifier { Future _getLastUnlocked() async { return await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "lastUnlocked", - ) - as int? ?? + boxName: DB.boxNamePrefs, + key: "lastUnlocked", + ) as int? ?? 0; } @@ -171,10 +170,9 @@ class Prefs extends ChangeNotifier { Future _getCurrentNotificationIndex() async { return await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "currentNotificationId", - ) - as int? ?? + boxName: DB.boxNamePrefs, + key: "currentNotificationId", + ) as int? ?? 0; } @@ -199,10 +197,9 @@ class Prefs extends ChangeNotifier { Future> _getWalletIdsSyncOnStartup() async { final list = await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "walletIdsSyncOnStartup", - ) - as List? ?? + boxName: DB.boxNamePrefs, + key: "walletIdsSyncOnStartup", + ) as List? ?? []; return List.from(list); } @@ -228,10 +225,9 @@ class Prefs extends ChangeNotifier { Future _getSyncType() async { final int index = await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "syncTypeIndex", - ) - as int? ?? + boxName: DB.boxNamePrefs, + key: "syncTypeIndex", + ) as int? ?? SyncingType.allWalletsOnStartup.index; return SyncingType.values[index]; } @@ -256,10 +252,9 @@ class Prefs extends ChangeNotifier { Future _getUseWifiOnly() async { return await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "wifiOnly", - ) - as bool? ?? + boxName: DB.boxNamePrefs, + key: "wifiOnly", + ) as bool? ?? false; } @@ -283,10 +278,9 @@ class Prefs extends ChangeNotifier { Future _getShowFavoriteWallets() async { return await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "showFavoriteWallets", - ) - as bool? ?? + boxName: DB.boxNamePrefs, + key: "showFavoriteWallets", + ) as bool? ?? true; } @@ -310,10 +304,9 @@ class Prefs extends ChangeNotifier { Future _getPreferredLanguage() async { return await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "language", - ) - as String? ?? + boxName: DB.boxNamePrefs, + key: "language", + ) as String? ?? Language.englishUS.description; } @@ -337,10 +330,9 @@ class Prefs extends ChangeNotifier { Future _getPreferredCurrency() async { return await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "currency", - ) - as String? ?? + boxName: DB.boxNamePrefs, + key: "currency", + ) as String? ?? "USD"; } @@ -405,10 +397,9 @@ class Prefs extends ChangeNotifier { Future _getRandomizePIN() async { return await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "randomizePIN", - ) - as bool? ?? + boxName: DB.boxNamePrefs, + key: "randomizePIN", + ) as bool? ?? false; } @@ -432,10 +423,9 @@ class Prefs extends ChangeNotifier { Future _getUseBiometrics() async { return await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "useBiometrics", - ) - as bool? ?? + boxName: DB.boxNamePrefs, + key: "useBiometrics", + ) as bool? ?? false; } @@ -459,10 +449,9 @@ class Prefs extends ChangeNotifier { Future _getHasPin() async { return await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "hasPin", - ) - as bool? ?? + boxName: DB.boxNamePrefs, + key: "hasPin", + ) as bool? ?? false; } @@ -486,10 +475,9 @@ class Prefs extends ChangeNotifier { Future _getHasDuressPin() async { return await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "hasDuressPin", - ) - as bool? ?? + boxName: DB.boxNamePrefs, + key: "hasDuressPin", + ) as bool? ?? false; } @@ -513,10 +501,9 @@ class Prefs extends ChangeNotifier { Future _getBiometricsDuress() async { return await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "biometricsDuress", - ) - as bool? ?? + boxName: DB.boxNamePrefs, + key: "biometricsDuress", + ) as bool? ?? false; } @@ -540,10 +527,9 @@ class Prefs extends ChangeNotifier { Future _getHasFamiliarity() async { return await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "familiarity", - ) - as int? ?? + boxName: DB.boxNamePrefs, + key: "familiarity", + ) as int? ?? 0; } @@ -567,10 +553,9 @@ class Prefs extends ChangeNotifier { Future _getTorKillswitch() async { return await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "torKillswitch", - ) - as bool? ?? + boxName: DB.boxNamePrefs, + key: "torKillswitch", + ) as bool? ?? true; } @@ -594,10 +579,9 @@ class Prefs extends ChangeNotifier { Future _getShowTestNetCoins() async { return await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "showTestNetCoins", - ) - as bool? ?? + boxName: DB.boxNamePrefs, + key: "showTestNetCoins", + ) as bool? ?? false; } @@ -624,10 +608,9 @@ class Prefs extends ChangeNotifier { Future _getIsAutoBackupEnabled() async { return await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "isAutoBackupEnabled", - ) - as bool? ?? + boxName: DB.boxNamePrefs, + key: "isAutoBackupEnabled", + ) as bool? ?? false; } @@ -651,10 +634,9 @@ class Prefs extends ChangeNotifier { Future _getAutoBackupLocation() async { return await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "autoBackupLocation", - ) - as String?; + boxName: DB.boxNamePrefs, + key: "autoBackupLocation", + ) as String?; } // auto backup frequency type @@ -695,12 +677,10 @@ class Prefs extends ChangeNotifier { } Future _getBackupFrequencyType() async { - String? rate = - await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "backupFrequencyType", - ) - as String?; + String? rate = await DB.instance.get( + boxName: DB.boxNamePrefs, + key: "backupFrequencyType", + ) as String?; rate ??= "10Min"; switch (rate) { case "10Min": @@ -734,10 +714,9 @@ class Prefs extends ChangeNotifier { Future _getLastAutoBackup() async { return await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "lastAutoBackup", - ) - as DateTime?; + boxName: DB.boxNamePrefs, + key: "lastAutoBackup", + ) as DateTime?; } // auto backup @@ -763,10 +742,9 @@ class Prefs extends ChangeNotifier { Future _getHideBlockExplorerWarning() async { return await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "hideBlockExplorerWarning", - ) - as bool? ?? + boxName: DB.boxNamePrefs, + key: "hideBlockExplorerWarning", + ) as bool? ?? false; } @@ -793,10 +771,9 @@ class Prefs extends ChangeNotifier { Future _getGotoWalletOnStartup() async { return await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "gotoWalletOnStartup", - ) - as bool? ?? + boxName: DB.boxNamePrefs, + key: "gotoWalletOnStartup", + ) as bool? ?? false; } @@ -820,10 +797,9 @@ class Prefs extends ChangeNotifier { Future _getStartupWalletId() async { return await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "startupWalletId", - ) - as String?; + boxName: DB.boxNamePrefs, + key: "startupWalletId", + ) as String?; } // incognito mode off by default @@ -849,10 +825,9 @@ class Prefs extends ChangeNotifier { Future _getHasExternalCalls() async { return await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "externalCalls", - ) - as bool? ?? + boxName: DB.boxNamePrefs, + key: "externalCalls", + ) as bool? ?? true; } @@ -871,9 +846,10 @@ class Prefs extends ChangeNotifier { String? get userID => _userId; Future _getUserId() async { - String? userID = - await DB.instance.get(boxName: DB.boxNamePrefs, key: "userID") - as String?; + String? userID = await DB.instance.get( + boxName: DB.boxNamePrefs, + key: "userID", + ) as String?; if (userID == null) { userID = const Uuid().v4(); await saveUserID(userID); @@ -895,12 +871,10 @@ class Prefs extends ChangeNotifier { int? get signupEpoch => _signupEpoch; Future _getSignupEpoch() async { - int? signupEpoch = - await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "signupEpoch", - ) - as int?; + int? signupEpoch = await DB.instance.get( + boxName: DB.boxNamePrefs, + key: "signupEpoch", + ) as int?; if (signupEpoch == null) { signupEpoch = DateTime.now().millisecondsSinceEpoch ~/ @@ -940,10 +914,9 @@ class Prefs extends ChangeNotifier { Future _getEnableCoinControl() async { return await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "enableCoinControl", - ) - as bool? ?? + boxName: DB.boxNamePrefs, + key: "enableCoinControl", + ) as bool? ?? false; } @@ -967,10 +940,9 @@ class Prefs extends ChangeNotifier { Future _getEnableSystemBrightness() async { return await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "enableSystemBrightness", - ) - as bool? ?? + boxName: DB.boxNamePrefs, + key: "enableSystemBrightness", + ) as bool? ?? false; } @@ -994,10 +966,9 @@ class Prefs extends ChangeNotifier { Future _getThemeId() async { return await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "themeId", - ) - as String? ?? + boxName: DB.boxNamePrefs, + key: "themeId", + ) as String? ?? "light"; } @@ -1021,10 +992,9 @@ class Prefs extends ChangeNotifier { Future _getSystemBrightnessLightThemeId() async { return await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "systemBrightnessLightThemeId", - ) - as String? ?? + boxName: DB.boxNamePrefs, + key: "systemBrightnessLightThemeId", + ) as String? ?? "light"; } @@ -1048,10 +1018,9 @@ class Prefs extends ChangeNotifier { Future _getSystemBrightnessDarkTheme() async { return await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "systemBrightnessDarkThemeId", - ) - as String? ?? + boxName: DB.boxNamePrefs, + key: "systemBrightnessDarkThemeId", + ) as String? ?? "dark"; } @@ -1081,10 +1050,9 @@ class Prefs extends ChangeNotifier { for (final coin in AppConfig.coins) { final unitIndex = await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "amountUnitFor${coin.identifier}", - ) - as int? ?? + boxName: DB.boxNamePrefs, + key: "amountUnitFor${coin.identifier}", + ) as int? ?? 0; // 0 is "normal" _amountUnits[coin] = AmountUnit.values[unitIndex]; } @@ -1116,10 +1084,9 @@ class Prefs extends ChangeNotifier { for (final coin in AppConfig.coins) { final decimals = await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "maxDecimalsFor${coin.identifier}", - ) - as int? ?? + boxName: DB.boxNamePrefs, + key: "maxDecimalsFor${coin.identifier}", + ) as int? ?? (coin.fractionDigits > 18 ? 18 : coin.fractionDigits); // use some sane max rather than up to 30 that nano uses _amountDecimals[coin.identifier] = decimals; @@ -1152,10 +1119,9 @@ class Prefs extends ChangeNotifier { Future _getUseTor() async { return await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "useTor", - ) - as bool? ?? + boxName: DB.boxNamePrefs, + key: "useTor", + ) as bool? ?? false; } @@ -1184,30 +1150,25 @@ class Prefs extends ChangeNotifier { } Future> _getFusionServerInfo() async { - final map = - await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "fusionServerInfoMap", - ) - as Map?; + final map = await DB.instance.get( + boxName: DB.boxNamePrefs, + key: "fusionServerInfoMap", + ) as Map?; if (map == null) { return _fusionServerInfo; } - final actualMap = Map.from( - map, - ).map((key, value) => MapEntry(key, FusionInfo.fromJsonString(value))); + final actualMap = Map.from(map) + .map((key, value) => MapEntry(key, FusionInfo.fromJsonString(value))); // legacy bch check if (actualMap["bitcoincash"] == null || actualMap["bitcoincashTestnet"] == null) { - final saved = - await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "fusionServerInfo", - ) - as String?; + final saved = await DB.instance.get( + boxName: DB.boxNamePrefs, + key: "fusionServerInfo", + ) as String?; if (saved != null) { final bchInfo = FusionInfo.fromJsonString(saved); @@ -1248,10 +1209,9 @@ class Prefs extends ChangeNotifier { Future _getAutoPin() async { return await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "autoPin", - ) - as bool? ?? + boxName: DB.boxNamePrefs, + key: "autoPin", + ) as bool? ?? false; } @@ -1275,10 +1235,9 @@ class Prefs extends ChangeNotifier { Future _getEnableExchange() async { return await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "showExchange", - ) - as bool? ?? + boxName: DB.boxNamePrefs, + key: "showExchange", + ) as bool? ?? true; } @@ -1299,10 +1258,9 @@ class Prefs extends ChangeNotifier { Future _getAdvancedFiroFeatures() async { return await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "advancedFiroFeatures", - ) - as bool? ?? + boxName: DB.boxNamePrefs, + key: "advancedFiroFeatures", + ) as bool? ?? false; } @@ -1323,10 +1281,9 @@ class Prefs extends ChangeNotifier { Future _getLogsPath() async { return await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "logsPath", - ) - as String?; + boxName: DB.boxNamePrefs, + key: "logsPath", + ) as String?; } // log level pref @@ -1345,12 +1302,10 @@ class Prefs extends ChangeNotifier { } Future _getLogLevel() async { - final value = - await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "logLevel", - ) - as int?; + final value = await DB.instance.get( + boxName: DB.boxNamePrefs, + key: "logLevel", + ) as int?; try { return Level.values.firstWhere((e) => e.value == value); @@ -1384,10 +1339,9 @@ class Prefs extends ChangeNotifier { Future _getAutoLockInfo() async { final map = await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "autoLockInfo", - ) - as Map? ?? + boxName: DB.boxNamePrefs, + key: "autoLockInfo", + ) as Map? ?? {"enabled": false, "minutes": 10}; return (enabled: map["enabled"] as bool, minutes: map["minutes"] as int); @@ -1410,10 +1364,9 @@ class Prefs extends ChangeNotifier { Future _getPrivacyScreen() async { return await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "privacyScreen", - ) - as bool? ?? + boxName: DB.boxNamePrefs, + key: "privacyScreen", + ) as bool? ?? false; } @@ -1434,10 +1387,35 @@ class Prefs extends ChangeNotifier { Future _getDisableScreenShots() async { return await DB.instance.get( - boxName: DB.boxNamePrefs, - key: "disableScreenShots", - ) - as bool? ?? + boxName: DB.boxNamePrefs, + key: "disableScreenShots", + ) as bool? ?? + false; + } + + // hide balances + + bool _hideBalances = false; + + bool get hideBalances => _hideBalances; + + set hideBalances(bool hideBalances) { + if (_hideBalances != hideBalances) { + DB.instance.put( + boxName: DB.boxNamePrefs, + key: "hideBalances", + value: hideBalances, + ); + _hideBalances = hideBalances; + notifyListeners(); + } + } + + Future _getHideBalances() async { + return await DB.instance.get( + boxName: DB.boxNamePrefs, + key: "hideBalances", + ) as bool? ?? false; } } diff --git a/lib/widgets/hideable_balance.dart b/lib/widgets/hideable_balance.dart new file mode 100644 index 0000000000..a6b220cebb --- /dev/null +++ b/lib/widgets/hideable_balance.dart @@ -0,0 +1,91 @@ +/* + * This file is part of Stack Wallet. + * + * Copyright (c) 2023 Cypher Stack + * All Rights Reserved. + * The code is distributed under GPLv3 license, see LICENSE file for details. + * Generated by Cypher Stack on 2023-05-26 + * + */ + +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_svg/svg.dart'; + +import '../providers/global/prefs_provider.dart'; +import '../utilities/assets.dart'; + +/// Masks a balance and temporarily reveals it without changing the preference. +class HideableBalance extends ConsumerStatefulWidget { + const HideableBalance({ + super.key, + required this.child, + this.iconColor, + this.iconSize = 20, + }); + + final Widget child; + final Color? iconColor; + final double iconSize; + + static const Duration revealDuration = Duration(seconds: 3); + + @override + ConsumerState createState() => _HideableBalanceState(); +} + +class _HideableBalanceState extends ConsumerState { + Timer? _revealTimer; + bool _revealed = false; + + void _reveal() { + _revealTimer?.cancel(); + setState(() { + _revealed = true; + }); + _revealTimer = Timer(HideableBalance.revealDuration, () { + if (mounted) { + setState(() { + _revealed = false; + }); + } + }); + } + + @override + void dispose() { + _revealTimer?.cancel(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final hideBalances = ref.watch(hideBalancesProvider); + + if (!hideBalances || _revealed) { + return widget.child; + } + + // IconButton publishes the button/enabled/focus flags, the focus action + // and the tooltip as the accessible name; an enclosing Semantics node + // would mask all of it. + return IconButton( + tooltip: "Show balance temporarily", + onPressed: _reveal, + padding: EdgeInsets.zero, + constraints: const BoxConstraints(minWidth: 24, minHeight: 24), + visualDensity: VisualDensity.compact, + icon: SvgPicture.asset( + Assets.svg.eyeSlash, + semanticsLabel: "Show balance temporarily", + colorFilter: widget.iconColor == null + ? null + : ColorFilter.mode(widget.iconColor!, BlendMode.srcIn), + width: widget.iconSize, + height: widget.iconSize, + ), + ); + } +} diff --git a/lib/widgets/managed_favorite.dart b/lib/widgets/managed_favorite.dart index c89bc483b2..39b55c6517 100644 --- a/lib/widgets/managed_favorite.dart +++ b/lib/widgets/managed_favorite.dart @@ -13,6 +13,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; + import '../providers/db/main_db_provider.dart'; import '../themes/coin_icon_provider.dart'; import '../themes/stack_colors.dart'; @@ -25,13 +26,11 @@ import '../utilities/util.dart'; import '../wallets/crypto_currency/coins/firo.dart'; import '../wallets/isar/providers/wallet_info_provider.dart'; import 'custom_buttons/favorite_toggle.dart'; +import 'hideable_balance.dart'; import 'rounded_white_container.dart'; class ManagedFavorite extends ConsumerStatefulWidget { - const ManagedFavorite({ - super.key, - required this.walletId, - }); + const ManagedFavorite({super.key, required this.walletId}); final String walletId; @@ -54,7 +53,7 @@ class _ManagedFavoriteCardState extends ConsumerState { if (coin is Firo) { final balancePrivate = ref.watch(pWalletBalanceSecondary(walletId)).total + - ref.watch(pWalletBalanceTertiary(walletId)).total; + ref.watch(pWalletBalanceTertiary(walletId)).total; total += balancePrivate; } @@ -65,7 +64,9 @@ class _ManagedFavoriteCardState extends ConsumerState { padding: EdgeInsets.all(isDesktop ? 0 : 4.0), child: RawMaterialButton( onPressed: () { - ref.read(pWalletInfo(walletId)).updateIsFavourite( + ref + .read(pWalletInfo(walletId)) + .updateIsFavourite( !isFavourite, isar: ref.read(mainDBProvider).isar, ); @@ -77,10 +78,7 @@ class _ManagedFavoriteCardState extends ConsumerState { ), child: Padding( padding: isDesktop - ? const EdgeInsets.symmetric( - horizontal: 20, - vertical: 12, - ) + ? const EdgeInsets.symmetric(horizontal: 20, vertical: 12) : const EdgeInsets.all(8), child: Row( children: [ @@ -94,17 +92,13 @@ class _ManagedFavoriteCardState extends ConsumerState { child: Padding( padding: EdgeInsets.all(isDesktop ? 6 : 4), child: SvgPicture.file( - File( - ref.watch(coinIconProvider(coin)), - ), + File(ref.watch(coinIconProvider(coin))), width: 20, height: 20, ), ), ), - const SizedBox( - width: 12, - ), + const SizedBox(width: 12), if (isDesktop) Expanded( child: Row( @@ -116,29 +110,32 @@ class _ManagedFavoriteCardState extends ConsumerState { ), ), Expanded( - child: Text( - ref - .watch( - pAmountFormatter(coin), - ) - .format(total), - style: STextStyles.itemSubtitle(context), + child: HideableBalance( + key: ValueKey("hideBalance_$walletId"), + iconColor: Theme.of(context) + .extension()! + .infoItemLabel, + iconSize: 16, + child: Text( + ref.watch(pAmountFormatter(coin)).format(total), + style: STextStyles.itemSubtitle(context), + ), ), ), Text( isFavourite ? "Remove from favorites" : "Add to favorites", - style: - STextStyles.desktopTextExtraSmall(context).copyWith( - color: isFavourite - ? Theme.of(context) - .extension()! - .accentColorRed - : Theme.of(context) - .extension()! - .buttonTextBorderless, - ), + style: STextStyles.desktopTextExtraSmall(context) + .copyWith( + color: isFavourite + ? Theme.of(context) + .extension()! + .accentColorRed + : Theme.of(context) + .extension()! + .buttonTextBorderless, + ), ), ], ), @@ -153,16 +150,17 @@ class _ManagedFavoriteCardState extends ConsumerState { ref.watch(pWalletName(walletId)), style: STextStyles.titleBold12(context), ), - const SizedBox( - height: 2, - ), - Text( - ref - .watch( - pAmountFormatter(coin), - ) - .format(total), - style: STextStyles.itemSubtitle(context), + const SizedBox(height: 2), + HideableBalance( + key: ValueKey("hideBalance_$walletId"), + iconColor: Theme.of(context) + .extension()! + .infoItemLabel, + iconSize: 16, + child: Text( + ref.watch(pAmountFormatter(coin)).format(total), + style: STextStyles.itemSubtitle(context), + ), ), ], ), diff --git a/lib/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance.dart b/lib/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance.dart index a1ec77214b..3bf2a02dd6 100644 --- a/lib/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance.dart +++ b/lib/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance.dart @@ -23,6 +23,7 @@ import '../../../wallets/crypto_currency/coins/solana.dart'; import '../../../wallets/isar/providers/eth/token_balance_provider.dart'; import '../../../wallets/isar/providers/solana/sol_token_balance_provider.dart'; import '../../../wallets/isar/providers/wallet_info_provider.dart'; +import '../../hideable_balance.dart'; class WalletInfoRowBalance extends ConsumerWidget { const WalletInfoRowBalance({ @@ -88,15 +89,26 @@ class WalletInfoRowBalance extends ConsumerWidget { } } - return Text( - ref - .watch(pAmountFormatter(info.coin)) - .format(totalBalance, tokenContract: contract), - style: Util.isDesktop - ? STextStyles.desktopTextExtraSmall(context).copyWith( - color: Theme.of(context).extension()!.textSubtitle1, - ) - : STextStyles.itemSubtitle(context), + return HideableBalance( + // These rows live in sorted/filtered lists; keep reveal state pinned to + // the balance being shown rather than to the row's position. + key: ValueKey("hideBalance_${walletId}_${contractAddress}_$balanceType"), + iconColor: Util.isDesktop + ? Theme.of(context).extension()!.textSubtitle1 + : Theme.of(context).extension()!.infoItemLabel, + iconSize: 16, + child: Text( + ref + .watch(pAmountFormatter(info.coin)) + .format(totalBalance, tokenContract: contract), + style: Util.isDesktop + ? STextStyles.desktopTextExtraSmall(context).copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, + ) + : STextStyles.itemSubtitle(context), + ), ); } } diff --git a/test/wallets/support/xelis_test_fakes.dart b/test/wallets/support/xelis_test_fakes.dart index 06ff17da81..1c3ecac5b6 100644 --- a/test/wallets/support/xelis_test_fakes.dart +++ b/test/wallets/support/xelis_test_fakes.dart @@ -101,6 +101,8 @@ class ConfirmationPrefs extends ChangeNotifier implements Prefs { @override String get currency => 'USD'; @override + bool get hideBalances => false; + @override dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); } diff --git a/test/widget_tests/hide_balances_coverage_test.dart b/test/widget_tests/hide_balances_coverage_test.dart new file mode 100644 index 0000000000..55d935b210 --- /dev/null +++ b/test/widget_tests/hide_balances_coverage_test.dart @@ -0,0 +1,144 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:stackwallet/models/balance.dart'; +import 'package:stackwallet/models/isar/models/blockchain_data/address.dart'; +import 'package:stackwallet/models/isar/stack_theme.dart'; +import 'package:stackwallet/pages/send_view/sub_widgets/dual_balance_selection_sheet.dart'; +import 'package:stackwallet/pages/wallet_view/sub_widgets/wallet_balance_toggle_sheet.dart'; +import 'package:stackwallet/providers/global/prefs_provider.dart'; +import 'package:stackwallet/themes/coin_icon_provider.dart'; +import 'package:stackwallet/themes/stack_colors.dart'; +import 'package:stackwallet/themes/theme_providers.dart'; +import 'package:stackwallet/utilities/amount/amount.dart'; +import 'package:stackwallet/utilities/amount/amount_formatter.dart'; +import 'package:stackwallet/utilities/amount/amount_unit.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; +import 'package:stackwallet/wallets/isar/models/wallet_info.dart'; +import 'package:stackwallet/wallets/isar/providers/wallet_info_provider.dart'; +import 'package:stackwallet/widgets/hideable_balance.dart'; +import 'package:stackwallet/widgets/managed_favorite.dart'; +import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance.dart'; + +import '../sample_data/theme_json.dart'; + +void main() { + const walletId = "some-wallet-id"; + final coin = Bitcoin(CryptoCurrencyNetwork.main); + + final total = Amount( + rawValue: BigInt.from(123456789), + fractionDigits: coin.fractionDigits, + ); + + final formatter = AmountFormatter( + unit: AmountUnit.normal, + locale: "en_US", + coin: coin, + maxDecimals: 8, + ); + + final formatted = formatter.format(total); + + final balance = Balance( + total: total, + spendable: total, + blockedTotal: Amount.zeroWith(fractionDigits: coin.fractionDigits), + pendingSpendable: total, + ); + + final theme = StackTheme.fromJson(json: lightThemeJsonMap); + + Widget app({required bool hidden, required Widget child}) { + return ProviderScope( + overrides: [ + hideBalancesProvider.overrideWithValue(hidden), + pAmountFormatter(coin).overrideWithValue(formatter), + themeProvider.overrideWithProvider(StateProvider((_) => theme)), + coinIconProvider.overrideWithProvider( + (_) => Provider( + (_) => + "${Directory.current.path}/test/sample_data/light/assets/dummy.svg", + ), + ), + pWalletInfo(walletId).overrideWithValue( + WalletInfo( + walletId: walletId, + name: "some wallet", + mainAddressType: AddressType.p2wpkh, + coinName: coin.identifier, + cachedBalanceString: balance.toJsonIgnoreCoin(), + ), + ), + pWalletName(walletId).overrideWithValue("some wallet"), + pWalletCoin(walletId).overrideWithValue(coin), + pWalletBalance(walletId).overrideWithValue(balance), + pWalletBalanceSecondary(walletId).overrideWithValue(balance), + pWalletIsFavourite(walletId).overrideWithValue(false), + ], + child: MaterialApp( + theme: ThemeData(extensions: [StackColors.fromStackColorTheme(theme)]), + home: Scaffold(body: child), + ), + ); + } + + Future expectMasking( + WidgetTester tester, + Widget Function() build, + Finder balance, + ) async { + await tester.pumpWidget(app(hidden: true, child: build())); + await tester.pump(); + expect(balance, findsNothing); + expect(find.byType(HideableBalance), findsWidgets); + + await tester.pumpWidget(app(hidden: false, child: build())); + await tester.pump(); + expect(balance, findsWidgets); + } + + testWidgets("wallet list rows mask their balance", (tester) async { + await expectMasking( + tester, + () => const WalletInfoRowBalance(walletId: walletId), + find.text(formatted), + ); + }); + + testWidgets("the balance toggle sheet masks its balances", (tester) async { + await expectMasking( + tester, + () => BalanceSelector( + title: "Available balance", + coin: coin, + balance: total, + onPressed: () {}, + onChanged: (_) {}, + value: 0, + groupValue: 0, + ), + find.text(formatted), + ); + }); + + testWidgets("manage favorites masks wallet balances", (tester) async { + await expectMasking( + tester, + () => const ManagedFavorite(walletId: walletId), + find.text(formatted), + ); + }); + + testWidgets("the send balance selection sheet masks its balances", ( + tester, + ) async { + await expectMasking( + tester, + () => const DualBalanceSelectionSheet(walletId: walletId), + find.text(formatted), + ); + }); +} diff --git a/test/widget_tests/hideable_balance_test.dart b/test/widget_tests/hideable_balance_test.dart new file mode 100644 index 0000000000..8ce3f6e807 --- /dev/null +++ b/test/widget_tests/hideable_balance_test.dart @@ -0,0 +1,104 @@ +import 'dart:ui' show SemanticsAction, Tristate; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:stackwallet/providers/global/prefs_provider.dart'; +import 'package:stackwallet/widgets/hideable_balance.dart'; + +void main() { + Widget testApp({required bool hidden, required Widget child}) { + return ProviderScope( + overrides: [hideBalancesProvider.overrideWithValue(hidden)], + child: MaterialApp(home: Scaffold(body: child)), + ); + } + + testWidgets("shows the balance when masking is disabled", (tester) async { + await tester.pumpWidget( + testApp( + hidden: false, + child: const HideableBalance(child: Text("12.34 BTC")), + ), + ); + + expect(find.text("12.34 BTC"), findsOneWidget); + expect(find.byType(IconButton), findsNothing); + }); + + testWidgets("exposes a labeled keyboard-accessible reveal control", ( + tester, + ) async { + final semantics = tester.ensureSemantics(); + + await tester.pumpWidget( + testApp( + hidden: true, + child: const HideableBalance(child: Text("12.34 BTC")), + ), + ); + + final control = find.byType(IconButton); + expect(find.text("12.34 BTC"), findsNothing); + expect( + tester.widget(control).tooltip, + "Show balance temporarily", + ); + expect(tester.getSize(control).shortestSide, greaterThanOrEqualTo(24)); + + final semanticsNode = tester.getSemantics(control); + final semanticsData = semanticsNode.getSemanticsData(); + expect(semanticsData.tooltip, contains("Show balance temporarily")); + expect(semanticsNode.flagsCollection.isButton, isTrue); + expect(semanticsNode.flagsCollection.isEnabled, Tristate.isTrue); + expect(semanticsData.hasAction(SemanticsAction.tap), isTrue); + expect(semanticsData.hasAction(SemanticsAction.focus), isTrue); + + await tester.sendKeyEvent(LogicalKeyboardKey.tab); + await tester.pump(); + expect( + tester.getSemantics(control).flagsCollection.isFocused, + Tristate.isTrue, + reason: "screen readers need the focus flag on desktop", + ); + + await tester.sendKeyEvent(LogicalKeyboardKey.tab); + await tester.pump(); + await tester.sendKeyEvent(LogicalKeyboardKey.enter); + await tester.pump(); + + expect(find.text("12.34 BTC"), findsOneWidget); + expect(control, findsNothing); + + await tester.pump(HideableBalance.revealDuration); + expect(find.text("12.34 BTC"), findsNothing); + expect(find.byType(IconButton), findsOneWidget); + semantics.dispose(); + }); + + testWidgets("reveals only the selected balance", (tester) async { + await tester.pumpWidget( + testApp( + hidden: true, + child: const Column( + children: [ + HideableBalance(child: Text("1 BTC")), + HideableBalance(child: Text(r"$2")), + ], + ), + ), + ); + + await tester.tap(find.byType(IconButton).first); + await tester.pump(); + + expect(find.text("1 BTC"), findsOneWidget); + expect(find.text(r"$2"), findsNothing); + expect(find.byType(IconButton), findsOneWidget); + + await tester.pumpWidget(const SizedBox()); + await tester.pump(HideableBalance.revealDuration); + expect(tester.takeException(), isNull); + }); +}