Full balance (#1457)

* fix: Confirm widget is still mounted * feat: Modify balance display to include full balance * fix: Modifying balance * chore: Feature cleanup * fix: Add frozen balance into consideration when taking available balance and add field to make full balance display only on bitcoin and litecoin wallets * fix: Adjust balance card to display correct available and unavailable balance, unavailable balance should only be displayed when there is one WIP * fix: Cleanup balance page and balance page view_model * chore: Revert formatting * fix: Remove full balance * fix: Remove full balance * fix: Remove full balance * chore: Rever formating [skip ci] * feat: Finalize display only available and unavailable balance * fix: Modify the way balance is displayed, activate frozen balance with label, remove unavailable/additional balance for bitcoin wallet type * fix: Issues coming from syncing with main * fix: Modify additional balance label * fix: Monero and Wownero balances display bug * fix: Resolve merge conflicts * feat: Activate CPFP for BTC, LTC and BCH, also fix issues with frozen balance display * - minor fix - remove unused functions * Fix conflicts --------- Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com> Co-authored-by: tuxsudo <tuxsudo@tux.pizza>

David Adegoke committed Dec 27, 2024 at 04:54 UTC c9a6abeea4a075611467e08e7134ccf8665c7f91
43 files changed +1257 -1232
cw_bitcoin/lib/electrum_balance.dart
+2 -2
@@ -39,7 +39,7 @@ class ElectrumBalance extends Balance {
39 int secondUnconfirmed = 0;
40
41 @override
42 - String get formattedAvailableBalance => bitcoinAmountToString(amount: confirmed - frozen);
42 + String get formattedAvailableBalance => bitcoinAmountToString(amount: ((confirmed + unconfirmed) - frozen) );
43
44 @override
45 String get formattedAdditionalBalance => bitcoinAmountToString(amount: unconfirmed);
@@ -58,7 +58,7 @@ class ElectrumBalance extends Balance {
58
59 @override
60 String get formattedFullAvailableBalance =>
61 - bitcoinAmountToString(amount: confirmed + secondConfirmed - frozen);
61 + bitcoinAmountToString(amount: (confirmed + unconfirmed) + secondConfirmed - frozen);
62
63 String toJSON() => json.encode({
64 'confirmed': confirmed,
cw_bitcoin/lib/electrum_wallet.dart
+14 -12
@@ -2213,18 +2213,6 @@ abstract class ElectrumWalletBase
2213 var totalConfirmed = 0;
2214 var totalUnconfirmed = 0;
2215
2216 - unspentCoinsInfo.values.forEach((info) {
2217 - unspentCoins.forEach((element) {
2218 - if (element.hash == info.hash &&
2219 - element.vout == info.vout &&
2220 - info.isFrozen &&
2221 - element.bitcoinAddressRecord.address == info.address &&
2222 - element.value == info.value) {
2223 - totalFrozen += element.value;
2224 - }
2225 - });
2226 - });
2227 -
2216 if (hasSilentPaymentsScanning) {
2217 // Add values from unspent coins that are not fetched by the address list
2218 // i.e. scanned silent payments
@@ -2240,6 +2228,20 @@ abstract class ElectrumWalletBase
2228 });
2229 }
2230
2231 + unspentCoinsInfo.values.forEach((info) {
2232 + unspentCoins.forEach((element) {
2233 + if (element.bitcoinAddressRecord is BitcoinSilentPaymentAddressRecord) return;
2234 +
2235 + if (element.hash == info.hash &&
2236 + element.vout == info.vout &&
2237 + info.isFrozen &&
2238 + element.bitcoinAddressRecord.address == info.address &&
2239 + element.value == info.value) {
2240 + totalFrozen += element.value;
2241 + }
2242 + });
2243 + });
2244 +
2245 final balances = await Future.wait(balanceFutures);
2246
2247 if (balances.isNotEmpty && balances.first['confirmed'] == null) {
cw_core/lib/monero_balance.dart
+7 -18
@@ -3,36 +3,25 @@ import 'package:cw_core/monero_amount_format.dart';
3
4 class MoneroBalance extends Balance {
5 MoneroBalance({required this.fullBalance, required this.unlockedBalance, this.frozenBalance = 0})
6 - : formattedFullBalance = moneroAmountToString(amount: frozenBalance + fullBalance),
7 - formattedUnlockedBalance = moneroAmountToString(amount: unlockedBalance),
8 - formattedLockedBalance =
9 - moneroAmountToString(amount: frozenBalance + fullBalance - unlockedBalance),
6 + : formattedUnconfirmedBalance = moneroAmountToString(amount: fullBalance - unlockedBalance),
7 + formattedUnlockedBalance = moneroAmountToString(amount: unlockedBalance - frozenBalance),
8 + formattedFrozenBalance = moneroAmountToString(amount: frozenBalance),
9 super(unlockedBalance, fullBalance);
10
12 - MoneroBalance.fromString(
13 - {required this.formattedFullBalance,
14 - required this.formattedUnlockedBalance,
15 - this.formattedLockedBalance = '0.0'})
16 - : fullBalance = moneroParseAmount(amount: formattedFullBalance),
17 - unlockedBalance = moneroParseAmount(amount: formattedUnlockedBalance),
18 - frozenBalance = moneroParseAmount(amount: formattedLockedBalance),
19 - super(moneroParseAmount(amount: formattedUnlockedBalance),
20 - moneroParseAmount(amount: formattedFullBalance));
21 -
11 final int fullBalance;
12 final int unlockedBalance;
13 final int frozenBalance;
25 - final String formattedFullBalance;
14 + final String formattedUnconfirmedBalance;
15 final String formattedUnlockedBalance;
27 - final String formattedLockedBalance;
16 + final String formattedFrozenBalance;
17
18 @override
19 String get formattedUnAvailableBalance =>
31 - formattedLockedBalance == '0.0' ? '' : formattedLockedBalance;
20 + formattedFrozenBalance == '0.0' ? '' : formattedFrozenBalance;
21
22 @override
23 String get formattedAvailableBalance => formattedUnlockedBalance;
24
25 @override
37 - String get formattedAdditionalBalance => formattedFullBalance;
26 + String get formattedAdditionalBalance => formattedUnconfirmedBalance;
27 }
cw_core/lib/wownero_balance.dart
+7 -17
@@ -3,36 +3,26 @@ import 'package:cw_core/wownero_amount_format.dart';
3
4 class WowneroBalance extends Balance {
5 WowneroBalance({required this.fullBalance, required this.unlockedBalance, this.frozenBalance = 0})
6 - : formattedFullBalance = wowneroAmountToString(amount: fullBalance),
6 + : formattedUnconfirmedBalance = wowneroAmountToString(amount: fullBalance - unlockedBalance),
7 formattedUnlockedBalance = wowneroAmountToString(amount: unlockedBalance - frozenBalance),
8 - formattedLockedBalance =
9 - wowneroAmountToString(amount: frozenBalance + fullBalance - unlockedBalance),
8 + formattedFrozenBalance =
9 + wowneroAmountToString(amount: frozenBalance),
10 super(unlockedBalance, fullBalance);
11
12 - WowneroBalance.fromString(
13 - {required this.formattedFullBalance,
14 - required this.formattedUnlockedBalance,
15 - this.formattedLockedBalance = '0.0'})
16 - : fullBalance = wowneroParseAmount(amount: formattedFullBalance),
17 - unlockedBalance = wowneroParseAmount(amount: formattedUnlockedBalance),
18 - frozenBalance = wowneroParseAmount(amount: formattedLockedBalance),
19 - super(wowneroParseAmount(amount: formattedUnlockedBalance),
20 - wowneroParseAmount(amount: formattedFullBalance));
21 -
12 final int fullBalance;
13 final int unlockedBalance;
14 final int frozenBalance;
25 - final String formattedFullBalance;
15 + final String formattedUnconfirmedBalance;
16 final String formattedUnlockedBalance;
27 - final String formattedLockedBalance;
17 + final String formattedFrozenBalance;
18
19 @override
20 String get formattedUnAvailableBalance =>
31 - formattedLockedBalance == '0.0' ? '' : formattedLockedBalance;
21 + formattedFrozenBalance == '0.0' ? '' : formattedFrozenBalance;
22
23 @override
24 String get formattedAvailableBalance => formattedUnlockedBalance;
25
26 @override
37 - String get formattedAdditionalBalance => formattedFullBalance;
27 + String get formattedAdditionalBalance => formattedUnconfirmedBalance;
28 }
\ No newline at end of file
cw_evm/lib/evm_erc20_balance.dart
+4 -5
@@ -11,13 +11,12 @@ class EVMChainERC20Balance extends Balance {
11 final int exponent;
12
13 @override
14 - String get formattedAdditionalBalance {
15 - final String formattedBalance = (balance / BigInt.from(10).pow(exponent)).toString();
16 - return formattedBalance.substring(0, min(12, formattedBalance.length));
17 - }
14 + String get formattedAdditionalBalance => _balance();
15
16 @override
20 - String get formattedAvailableBalance {
17 + String get formattedAvailableBalance => _balance();
18 +
19 + String _balance() {
20 final String formattedBalance = (balance / BigInt.from(10).pow(exponent)).toString();
21 return formattedBalance.substring(0, min(12, formattedBalance.length));
22 }
cw_monero/lib/monero_wallet.dart
+12 -5
@@ -751,11 +751,18 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
751 int _getFrozenBalance() {
752 var frozenBalance = 0;
753
754 - for (var coin in unspentCoinsInfo.values.where((element) =>
755 - element.walletId == id &&
756 - element.accountIndex == walletAddresses.account!.id)) {
757 - if (coin.isFrozen && !coin.isSending) frozenBalance += coin.value;
758 - }
754 + unspentCoinsInfo.values.forEach((info) {
755 + unspentCoins.forEach((element) {
756 + if (element.hash == info.hash &&
757 + element.vout == info.vout &&
758 + info.isFrozen &&
759 + element.value == info.value && info.walletId == id &&
760 + info.accountIndex == walletAddresses.account!.id) {
761 + if (element.isFrozen && !element.isSending) frozenBalance+= element.value;
762 + }
763 + });
764 + });
765 +
766 return frozenBalance;
767 }
768
integration_test/robots/dashboard_page_robot.dart
+1 -1
@@ -1,6 +1,6 @@
1 import 'package:cake_wallet/generated/i18n.dart';
2 import 'package:cake_wallet/src/screens/dashboard/dashboard_page.dart';
3 -import 'package:cake_wallet/src/screens/dashboard/pages/balance_page.dart';
3 +import 'package:cake_wallet/src/screens/dashboard/pages/balance/crypto_balance_widget.dart';
4 import 'package:cw_core/wallet_type.dart';
5 import 'package:flutter_test/flutter_test.dart';
6
lib/di.dart
+1 -1
@@ -79,7 +79,7 @@ import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_wallet
79 import 'package:cake_wallet/src/screens/dashboard/edit_token_page.dart';
80 import 'package:cake_wallet/src/screens/dashboard/home_settings_page.dart';
81 import 'package:cake_wallet/src/screens/dashboard/pages/address_page.dart';
82 -import 'package:cake_wallet/src/screens/dashboard/pages/balance_page.dart';
82 +import 'package:cake_wallet/src/screens/dashboard/pages/balance/balance_page.dart';
83 import 'package:cake_wallet/src/screens/dashboard/pages/transactions_page.dart';
84 import 'package:cake_wallet/src/screens/exchange/exchange_page.dart';
85 import 'package:cake_wallet/src/screens/exchange/exchange_template_page.dart';
lib/src/screens/dashboard/dashboard_page.dart
+1 -1
@@ -24,7 +24,7 @@ import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
24 import 'package:cake_wallet/src/screens/base_page.dart';
25 import 'package:cake_wallet/src/screens/dashboard/widgets/menu_widget.dart';
26 import 'package:cake_wallet/src/screens/dashboard/widgets/action_button.dart';
27 -import 'package:cake_wallet/src/screens/dashboard/pages/balance_page.dart';
27 +import 'package:cake_wallet/src/screens/dashboard/pages/balance/balance_page.dart';
28 import 'package:cake_wallet/src/screens/dashboard/pages/transactions_page.dart';
29 import 'package:cake_wallet/src/screens/dashboard/widgets/sync_indicator.dart';
30 import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_view_model.dart';
lib/src/screens/dashboard/desktop_dashboard_page.dart
+1 -1
@@ -8,7 +8,7 @@ import 'package:cake_wallet/utils/show_pop_up.dart';
8 import 'package:cake_wallet/utils/version_comparator.dart';
9 import 'package:flutter/material.dart';
10 import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
11 -import 'package:cake_wallet/src/screens/dashboard/pages/balance_page.dart';
11 +import 'package:cake_wallet/src/screens/dashboard/pages/balance/balance_page.dart';
12 import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_view_model.dart';
13 import 'package:cake_wallet/main.dart';
14 import 'package:cake_wallet/router.dart' as Router;
lib/src/screens/dashboard/pages/balance/balance_page.dart new
+88
@@ -0,0 +1,88 @@
1 +import 'package:cake_wallet/reactions/wallet_connect.dart';
2 +import 'package:cake_wallet/src/screens/dashboard/pages/balance/crypto_balance_widget.dart';
3 +import 'package:cake_wallet/src/screens/dashboard/pages/nft_listing_page.dart';
4 +import 'package:cake_wallet/store/settings_store.dart';
5 +import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
6 +import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
7 +import 'package:cake_wallet/view_model/dashboard/nft_view_model.dart';
8 +import 'package:flutter/material.dart';
9 +import 'package:flutter_mobx/flutter_mobx.dart';
10 +
11 +class BalancePage extends StatelessWidget {
12 + BalancePage({
13 + required this.dashboardViewModel,
14 + required this.settingsStore,
15 + required this.nftViewModel,
16 + });
17 +
18 + final DashboardViewModel dashboardViewModel;
19 + final NFTViewModel nftViewModel;
20 + final SettingsStore settingsStore;
21 +
22 + @override
23 + Widget build(BuildContext context) {
24 + return Observer(
25 + builder: (context) {
26 + final isEVMCompatible = isEVMCompatibleChain(dashboardViewModel.type);
27 + return DefaultTabController(
28 + length: isEVMCompatible ? 2 : 1,
29 + child: Column(
30 + children: [
31 + if (isEVMCompatible)
32 + Align(
33 + alignment: Alignment.centerLeft,
34 + child: Padding(
35 + padding: const EdgeInsets.only(left: 8),
36 + child: TabBar(
37 + indicatorSize: TabBarIndicatorSize.label,
38 + isScrollable: true,
39 + physics: NeverScrollableScrollPhysics(),
40 + labelStyle: TextStyle(
41 + fontSize: 18,
42 + fontFamily: 'Lato',
43 + fontWeight: FontWeight.w600,
44 + color:
45 + Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
46 + height: 1,
47 + ),
48 + unselectedLabelStyle: TextStyle(
49 + fontSize: 18,
50 + fontFamily: 'Lato',
51 + fontWeight: FontWeight.w600,
52 + color:
53 + Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
54 + height: 1,
55 + ),
56 + labelColor:
57 + Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
58 + dividerColor: Colors.transparent,
59 + indicatorColor:
60 + Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
61 + unselectedLabelColor: Theme.of(context)
62 + .extension<DashboardPageTheme>()!
63 + .pageTitleTextColor
64 + .withOpacity(0.5),
65 + tabAlignment: TabAlignment.start,
66 + tabs: [
67 + Tab(text: 'My Crypto'),
68 + Tab(text: 'My NFTs'),
69 + ],
70 + ),
71 + ),
72 + ),
73 + Expanded(
74 + child: TabBarView(
75 + physics: NeverScrollableScrollPhysics(),
76 + children: [
77 + CryptoBalanceWidget(dashboardViewModel: dashboardViewModel),
78 + if (isEVMCompatible) NFTListingPage(nftViewModel: nftViewModel)
79 + ],
80 + ),
81 + ),
82 + ],
83 + ),
84 + );
85 + },
86 + );
87 + }
88 +}
lib/src/screens/dashboard/pages/balance/balance_row_widget.dart new
+654
@@ -0,0 +1,654 @@
1 +import 'dart:math';
2 +
3 +import 'package:auto_size_text/auto_size_text.dart';
4 +import 'package:cake_wallet/bitcoin/bitcoin.dart';
5 +import 'package:cake_wallet/generated/i18n.dart';
6 +import 'package:cake_wallet/routes.dart';
7 +import 'package:cake_wallet/src/screens/exchange_trade/information_page.dart';
8 +import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
9 +import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
10 +import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
11 +import 'package:cake_wallet/utils/payment_request.dart';
12 +import 'package:cake_wallet/utils/show_pop_up.dart';
13 +import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
14 +import 'package:cw_core/crypto_currency.dart';
15 +import 'package:cw_core/unspent_coin_type.dart';
16 +import 'package:flutter/material.dart';
17 +import 'package:url_launcher/url_launcher.dart';
18 +
19 +class BalanceRowWidget extends StatelessWidget {
20 + BalanceRowWidget({
21 + required this.availableBalanceLabel,
22 + required this.availableBalance,
23 + required this.availableFiatBalance,
24 + required this.additionalBalanceLabel,
25 + required this.additionalBalance,
26 + required this.additionalFiatBalance,
27 + required this.secondAvailableBalanceLabel,
28 + required this.secondAvailableBalance,
29 + required this.secondAvailableFiatBalance,
30 + required this.secondAdditionalBalanceLabel,
31 + required this.secondAdditionalBalance,
32 + required this.secondAdditionalFiatBalance,
33 + required this.frozenBalance,
34 + required this.frozenFiatBalance,
35 + required this.currency,
36 + required this.hasAdditionalBalance,
37 + required this.hasSecondAvailableBalance,
38 + required this.hasSecondAdditionalBalance,
39 + required this.isTestnet,
40 + required this.dashboardViewModel,
41 + super.key,
42 + });
43 +
44 + final String availableBalanceLabel;
45 + final String availableBalance;
46 + final String availableFiatBalance;
47 + final String additionalBalanceLabel;
48 + final String additionalBalance;
49 + final String additionalFiatBalance;
50 + final String secondAvailableBalanceLabel;
51 + final String secondAvailableBalance;
52 + final String secondAvailableFiatBalance;
53 + final String secondAdditionalBalanceLabel;
54 + final String secondAdditionalBalance;
55 + final String secondAdditionalFiatBalance;
56 + final String frozenBalance;
57 + final String frozenFiatBalance;
58 + final CryptoCurrency currency;
59 + final bool hasAdditionalBalance;
60 + final bool hasSecondAvailableBalance;
61 + final bool hasSecondAdditionalBalance;
62 + final bool isTestnet;
63 + final DashboardViewModel dashboardViewModel;
64 +
65 + @override
66 + Widget build(BuildContext context) {
67 + return Column(
68 + children: [
69 + Container(
70 + margin: const EdgeInsets.only(left: 16, right: 16),
71 + decoration: BoxDecoration(
72 + borderRadius: BorderRadius.circular(30.0),
73 + border: Border.all(
74 + color: Theme.of(context).extension<BalancePageTheme>()!.cardBorderColor,
75 + width: 1,
76 + ),
77 + color: Theme.of(context).extension<SyncIndicatorTheme>()!.syncedBackgroundColor,
78 + ),
79 + child: Container(
80 + margin: const EdgeInsets.only(top: 16, left: 24, right: 8, bottom: 16),
81 + child: Column(
82 + crossAxisAlignment: CrossAxisAlignment.start,
83 + children: [
84 + GestureDetector(
85 + onTap: () => dashboardViewModel.balanceViewModel.switchBalanceValue(),
86 + child: Row(
87 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
88 + crossAxisAlignment: CrossAxisAlignment.center,
89 + children: [
90 + Column(
91 + crossAxisAlignment: CrossAxisAlignment.start,
92 + children: [
93 + GestureDetector(
94 + behavior: HitTestBehavior.opaque,
95 + onTap: hasAdditionalBalance
96 + ? () => _showBalanceDescription(
97 + context, S.of(context).available_balance_description)
98 + : null,
99 + child: Row(
100 + children: [
101 + Semantics(
102 + hint: 'Double tap to see more information',
103 + container: true,
104 + child: Text('${availableBalanceLabel}',
105 + style: TextStyle(
106 + fontSize: 12,
107 + fontFamily: 'Lato',
108 + fontWeight: FontWeight.w400,
109 + color: Theme.of(context)
110 + .extension<BalancePageTheme>()!
111 + .labelTextColor,
112 + height: 1)),
113 + ),
114 + if (hasAdditionalBalance)
115 + Padding(
116 + padding: const EdgeInsets.symmetric(horizontal: 4),
117 + child: Icon(Icons.help_outline,
118 + size: 16,
119 + color: Theme.of(context)
120 + .extension<BalancePageTheme>()!
121 + .labelTextColor),
122 + ),
123 + ],
124 + ),
125 + ),
126 + SizedBox(height: 6),
127 + AutoSizeText(availableBalance,
128 + style: TextStyle(
129 + fontSize: 24,
130 + fontFamily: 'Lato',
131 + fontWeight: FontWeight.w900,
132 + color: Theme.of(context)
133 + .extension<BalancePageTheme>()!
134 + .balanceAmountColor,
135 + height: 1),
136 + maxLines: 1,
137 + textAlign: TextAlign.start),
138 + SizedBox(height: 6),
139 + if (isTestnet)
140 + Text(S.of(context).testnet_coins_no_value,
141 + textAlign: TextAlign.center,
142 + style: TextStyle(
143 + fontSize: 14,
144 + fontFamily: 'Lato',
145 + fontWeight: FontWeight.w400,
146 + color:
147 + Theme.of(context).extension<BalancePageTheme>()!.textColor,
148 + height: 1)),
149 + if (!isTestnet)
150 + Text('${availableFiatBalance}',
151 + textAlign: TextAlign.center,
152 + style: TextStyle(
153 + fontSize: 16,
154 + fontFamily: 'Lato',
155 + fontWeight: FontWeight.w500,
156 + color:
157 + Theme.of(context).extension<BalancePageTheme>()!.textColor,
158 + height: 1)),
159 + ],
160 + ),
161 + SizedBox(
162 + width: min(MediaQuery.of(context).size.width * 0.2, 100),
163 + child: Center(
164 + child: Column(
165 + children: [
166 + CakeImageWidget(
167 + imageUrl: currency.iconPath,
168 + height: 40,
169 + width: 40,
170 + displayOnError: Container(
171 + height: 30.0,
172 + width: 30.0,
173 + child: Center(
174 + child: Text(
175 + currency.title.substring(0, min(currency.title.length, 2)),
176 + style: TextStyle(fontSize: 11),
177 + ),
178 + ),
179 + decoration: BoxDecoration(
180 + shape: BoxShape.circle,
181 + color: Colors.grey.shade400,
182 + ),
183 + ),
184 + ),
185 + const SizedBox(height: 10),
186 + Text(
187 + currency.title,
188 + style: TextStyle(
189 + fontSize: 15,
190 + fontFamily: 'Lato',
191 + fontWeight: FontWeight.w800,
192 + color: Theme.of(context)
193 + .extension<BalancePageTheme>()!
194 + .assetTitleColor,
195 + height: 1,
196 + ),
197 + ),
198 + ],
199 + ),
200 + ),
201 + ),
202 + ],
203 + ),
204 + ),
205 + if (frozenBalance.isNotEmpty)
206 + GestureDetector(
207 + behavior: HitTestBehavior.opaque,
208 + onTap: hasAdditionalBalance
209 + ? () => _showBalanceDescription(
210 + context, S.of(context).unavailable_balance_description)
211 + : null,
212 + child: Column(
213 + crossAxisAlignment: CrossAxisAlignment.start,
214 + children: [
215 + SizedBox(height: 26),
216 + Row(
217 + children: [
218 + Text(
219 + S.of(context).unavailable_balance,
220 + textAlign: TextAlign.center,
221 + style: TextStyle(
222 + fontSize: 12,
223 + fontFamily: 'Lato',
224 + fontWeight: FontWeight.w400,
225 + color:
226 + Theme.of(context).extension<BalancePageTheme>()!.labelTextColor,
227 + height: 1,
228 + ),
229 + ),
230 + Padding(
231 + padding: const EdgeInsets.symmetric(horizontal: 4),
232 + child: Icon(Icons.help_outline,
233 + size: 16,
234 + color: Theme.of(context)
235 + .extension<BalancePageTheme>()!
236 + .labelTextColor),
237 + ),
238 + ],
239 + ),
240 + SizedBox(height: 8),
241 + AutoSizeText(
242 + frozenBalance,
243 + style: TextStyle(
244 + fontSize: 20,
245 + fontFamily: 'Lato',
246 + fontWeight: FontWeight.w400,
247 + color:
248 + Theme.of(context).extension<BalancePageTheme>()!.balanceAmountColor,
249 + height: 1,
250 + ),
251 + maxLines: 1,
252 + textAlign: TextAlign.center,
253 + ),
254 + SizedBox(height: 4),
255 + if (!isTestnet)
256 + Text(
257 + frozenFiatBalance,
258 + textAlign: TextAlign.center,
259 + style: TextStyle(
260 + fontSize: 12,
261 + fontFamily: 'Lato',
262 + fontWeight: FontWeight.w400,
263 + color: Theme.of(context).extension<BalancePageTheme>()!.textColor,
264 + height: 1,
265 + ),
266 + ),
267 + ],
268 + ),
269 + ),
270 + if (hasAdditionalBalance)
271 + GestureDetector(
272 + onTap: () => dashboardViewModel.balanceViewModel.switchBalanceValue(),
273 + child: Column(
274 + crossAxisAlignment: CrossAxisAlignment.start,
275 + children: [
276 + SizedBox(height: 24),
277 + Text(
278 + '${additionalBalanceLabel}',
279 + textAlign: TextAlign.center,
280 + style: TextStyle(
281 + fontSize: 12,
282 + fontFamily: 'Lato',
283 + fontWeight: FontWeight.w400,
284 + color: Theme.of(context).extension<BalancePageTheme>()!.labelTextColor,
285 + height: 1,
286 + ),
287 + ),
288 + SizedBox(height: 8),
289 + AutoSizeText(
290 + additionalBalance,
291 + style: TextStyle(
292 + fontSize: 20,
293 + fontFamily: 'Lato',
294 + fontWeight: FontWeight.w400,
295 + color: Theme.of(context).extension<BalancePageTheme>()!.assetTitleColor,
296 + height: 1,
297 + ),
298 + maxLines: 1,
299 + textAlign: TextAlign.center,
300 + ),
301 + SizedBox(height: 4),
302 + if (!isTestnet)
303 + Text(
304 + '${additionalFiatBalance}',
305 + textAlign: TextAlign.center,
306 + style: TextStyle(
307 + fontSize: 12,
308 + fontFamily: 'Lato',
309 + fontWeight: FontWeight.w400,
310 + color: Theme.of(context).extension<BalancePageTheme>()!.textColor,
311 + height: 1,
312 + ),
313 + ),
314 + ],
315 + ),
316 + ),
317 + ],
318 + ),
319 + ),
320 + ),
321 + if (hasSecondAdditionalBalance || hasSecondAvailableBalance) ...[
322 + SizedBox(height: 10),
323 + Container(
324 + margin: const EdgeInsets.only(left: 16, right: 16),
325 + decoration: BoxDecoration(
326 + borderRadius: BorderRadius.circular(30.0),
327 + border: Border.all(
328 + color: Theme.of(context).extension<BalancePageTheme>()!.cardBorderColor,
329 + width: 1,
330 + ),
331 + color: Theme.of(context).extension<SyncIndicatorTheme>()!.syncedBackgroundColor,
332 + ),
333 + child: Container(
334 + child: Column(
335 + crossAxisAlignment: CrossAxisAlignment.start,
336 + children: [
337 + Container(
338 + margin: const EdgeInsets.only(top: 16, left: 24, right: 8, bottom: 16),
339 + child: Stack(
340 + children: [
341 + if (currency == CryptoCurrency.ltc)
342 + Row(
343 + mainAxisAlignment: MainAxisAlignment.end,
344 + children: [
345 + Container(
346 + padding: EdgeInsets.only(right: 16, top: 0),
347 + child: Column(
348 + children: [
349 + Container(
350 + child: ImageIcon(
351 + AssetImage('assets/images/mweb_logo.png'),
352 + color: Theme.of(context)
353 + .extension<BalancePageTheme>()!
354 + .assetTitleColor,
355 + size: 40,
356 + ),
357 + ),
358 + const SizedBox(height: 10),
359 + Text(
360 + 'MWEB',
361 + style: TextStyle(
362 + fontSize: 15,
363 + fontFamily: 'Lato',
364 + fontWeight: FontWeight.w800,
365 + color: Theme.of(context)
366 + .extension<BalancePageTheme>()!
367 + .assetTitleColor,
368 + height: 1,
369 + ),
370 + ),
371 + ],
372 + ),
373 + ),
374 + ],
375 + ),
376 + if (hasSecondAvailableBalance)
377 + GestureDetector(
378 + onTap: () => dashboardViewModel.balanceViewModel.switchBalanceValue(),
379 + child: Row(
380 + children: [
381 + Column(
382 + crossAxisAlignment: CrossAxisAlignment.start,
383 + children: [
384 + GestureDetector(
385 + behavior: HitTestBehavior.opaque,
386 + onTap: () => launchUrl(
387 + Uri.parse(
388 + "https://docs.cakewallet.com/cryptos/litecoin.html#mweb"),
389 + mode: LaunchMode.externalApplication,
390 + ),
391 + child: Row(
392 + children: [
393 + Text(
394 + '${secondAvailableBalanceLabel}',
395 + textAlign: TextAlign.center,
396 + style: TextStyle(
397 + fontSize: 12,
398 + fontFamily: 'Lato',
399 + fontWeight: FontWeight.w400,
400 + color: Theme.of(context)
401 + .extension<BalancePageTheme>()!
402 + .labelTextColor,
403 + height: 1,
404 + ),
405 + ),
406 + Padding(
407 + padding: const EdgeInsets.symmetric(horizontal: 4),
408 + child: Icon(Icons.help_outline,
409 + size: 16,
410 + color: Theme.of(context)
411 + .extension<BalancePageTheme>()!
412 + .labelTextColor),
413 + )
414 + ],
415 + ),
416 + ),
417 + SizedBox(height: 8),
418 + AutoSizeText(
419 + secondAvailableBalance,
420 + style: TextStyle(
421 + fontSize: 24,
422 + fontFamily: 'Lato',
423 + fontWeight: FontWeight.w900,
424 + color: Theme.of(context)
425 + .extension<BalancePageTheme>()!
426 + .assetTitleColor,
427 + height: 1,
428 + ),
429 + maxLines: 1,
430 + textAlign: TextAlign.center,
431 + ),
432 + SizedBox(height: 6),
433 + if (!isTestnet)
434 + Text(
435 + '${secondAvailableFiatBalance}',
436 + textAlign: TextAlign.center,
437 + style: TextStyle(
438 + fontSize: 16,
439 + fontFamily: 'Lato',
440 + fontWeight: FontWeight.w500,
441 + color: Theme.of(context)
442 + .extension<BalancePageTheme>()!
443 + .textColor,
444 + height: 1,
445 + ),
446 + ),
447 + ],
448 + ),
449 + ],
450 + ),
451 + ),
452 + ],
453 + ),
454 + ),
455 + Container(
456 + margin: const EdgeInsets.only(top: 0, left: 24, right: 8, bottom: 16),
457 + child: Stack(
458 + children: [
459 + if (hasSecondAdditionalBalance)
460 + Row(
461 + children: [
462 + Column(
463 + crossAxisAlignment: CrossAxisAlignment.start,
464 + children: [
465 + SizedBox(height: 24),
466 + Text(
467 + '${secondAdditionalBalanceLabel}',
468 + textAlign: TextAlign.center,
469 + style: TextStyle(
470 + fontSize: 12,
471 + fontFamily: 'Lato',
472 + fontWeight: FontWeight.w400,
473 + color: Theme.of(context)
474 + .extension<BalancePageTheme>()!
475 + .labelTextColor,
476 + height: 1,
477 + ),
478 + ),
479 + SizedBox(height: 8),
480 + AutoSizeText(
481 + secondAdditionalBalance,
482 + style: TextStyle(
483 + fontSize: 20,
484 + fontFamily: 'Lato',
485 + fontWeight: FontWeight.w400,
486 + color: Theme.of(context)
487 + .extension<BalancePageTheme>()!
488 + .assetTitleColor,
489 + height: 1,
490 + ),
491 + maxLines: 1,
492 + textAlign: TextAlign.center,
493 + ),
494 + SizedBox(height: 4),
495 + if (!isTestnet)
496 + Text(
497 + '${secondAdditionalFiatBalance}',
498 + textAlign: TextAlign.center,
499 + style: TextStyle(
500 + fontSize: 12,
501 + fontFamily: 'Lato',
502 + fontWeight: FontWeight.w400,
503 + color: Theme.of(context)
504 + .extension<BalancePageTheme>()!
505 + .textColor,
506 + height: 1,
507 + ),
508 + ),
509 + ],
510 + ),
511 + ],
512 + ),
513 + ],
514 + ),
515 + ),
516 + IntrinsicHeight(
517 + child: Container(
518 + padding: EdgeInsets.symmetric(horizontal: 24),
519 + child: Row(
520 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
521 + children: [
522 + Expanded(
523 + child: Semantics(
524 + label: S.of(context).litecoin_mweb_pegin,
525 + child: OutlinedButton(
526 + onPressed: () {
527 + final mwebAddress =
528 + bitcoin!.getUnusedMwebAddress(dashboardViewModel.wallet);
529 + PaymentRequest? paymentRequest = null;
530 + if ((mwebAddress?.isNotEmpty ?? false)) {
531 + paymentRequest = PaymentRequest.fromUri(
532 + Uri.parse("litecoin:${mwebAddress}"));
533 + }
534 + Navigator.pushNamed(
535 + context,
536 + Routes.send,
537 + arguments: {
538 + 'paymentRequest': paymentRequest,
539 + 'coinTypeToSpendFrom': UnspentCoinType.nonMweb,
540 + },
541 + );
542 + },
543 + style: OutlinedButton.styleFrom(
544 + backgroundColor: Colors.grey.shade400.withAlpha(50),
545 + side: BorderSide(
546 + color: Colors.grey.shade400.withAlpha(50), width: 0),
547 + shape: RoundedRectangleBorder(
548 + borderRadius: BorderRadius.circular(20),
549 + ),
550 + ),
551 + child: Container(
552 + padding: EdgeInsets.symmetric(vertical: 12),
553 + child: Row(
554 + mainAxisAlignment: MainAxisAlignment.center,
555 + children: [
556 + Image.asset(
557 + height: 30,
558 + width: 30,
559 + 'assets/images/received.png',
560 + color: Theme.of(context)
561 + .extension<BalancePageTheme>()!
562 + .balanceAmountColor,
563 + ),
564 + const SizedBox(width: 8),
565 + Text(
566 + S.of(context).litecoin_mweb_pegin,
567 + style: TextStyle(
568 + color: Theme.of(context)
569 + .extension<BalancePageTheme>()!
570 + .textColor,
571 + ),
572 + ),
573 + ],
574 + ),
575 + ),
576 + ),
577 + ),
578 + ),
579 + SizedBox(width: 24),
580 + Expanded(
581 + child: Semantics(
582 + label: S.of(context).litecoin_mweb_pegout,
583 + child: OutlinedButton(
584 + onPressed: () {
585 + final litecoinAddress =
586 + bitcoin!.getUnusedSegwitAddress(dashboardViewModel.wallet);
587 + PaymentRequest? paymentRequest = null;
588 + if ((litecoinAddress?.isNotEmpty ?? false)) {
589 + paymentRequest = PaymentRequest.fromUri(
590 + Uri.parse("litecoin:${litecoinAddress}"));
591 + }
592 + Navigator.pushNamed(
593 + context,
594 + Routes.send,
595 + arguments: {
596 + 'paymentRequest': paymentRequest,
597 + 'coinTypeToSpendFrom': UnspentCoinType.mweb,
598 + },
599 + );
600 + },
601 + style: OutlinedButton.styleFrom(
602 + backgroundColor: Colors.grey.shade400.withAlpha(50),
603 + side: BorderSide(
604 + color: Colors.grey.shade400.withAlpha(50), width: 0),
605 + shape: RoundedRectangleBorder(
606 + borderRadius: BorderRadius.circular(20),
607 + ),
608 + ),
609 + child: Container(
610 + padding: EdgeInsets.symmetric(vertical: 12),
611 + child: Row(
612 + mainAxisAlignment: MainAxisAlignment.center,
613 + children: [
614 + Image.asset(
615 + height: 30,
616 + width: 30,
617 + 'assets/images/upload.png',
618 + color: Theme.of(context)
619 + .extension<BalancePageTheme>()!
620 + .balanceAmountColor,
621 + ),
622 + const SizedBox(width: 8),
623 + Text(
624 + S.of(context).litecoin_mweb_pegout,
625 + style: TextStyle(
626 + color: Theme.of(context)
627 + .extension<BalancePageTheme>()!
628 + .textColor,
629 + ),
630 + ),
631 + ],
632 + ),
633 + ),
634 + ),
635 + ),
636 + ),
637 + ],
638 + ),
639 + ),
640 + ),
641 + SizedBox(height: 16),
642 + ],
643 + ),
644 + ),
645 + ),
646 + ],
647 + ],
648 + );
649 + }
650 +
651 + void _showBalanceDescription(BuildContext context, String content) {
652 + showPopUp<void>(context: context, builder: (_) => InformationPage(information: content));
653 + }
654 +}
lib/src/screens/dashboard/pages/balance/crypto_balance_widget.dart new
+424
@@ -0,0 +1,424 @@
1 +import 'package:cake_wallet/bitcoin/bitcoin.dart';
2 +import 'package:cake_wallet/generated/i18n.dart';
3 +import 'package:cake_wallet/routes.dart';
4 +import 'package:cake_wallet/src/screens/dashboard/pages/balance/balance_row_widget.dart';
5 +import 'package:cake_wallet/src/screens/dashboard/widgets/home_screen_account_widget.dart';
6 +import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
7 +import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
8 +import 'package:cake_wallet/src/widgets/dashboard_card_widget.dart';
9 +import 'package:cake_wallet/src/widgets/introducing_card.dart';
10 +import 'package:cake_wallet/src/widgets/standard_switch.dart';
11 +import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
12 +import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
13 +import 'package:cake_wallet/utils/feature_flag.dart';
14 +import 'package:cake_wallet/utils/show_pop_up.dart';
15 +import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
16 +import 'package:flutter/material.dart';
17 +import 'package:flutter_mobx/flutter_mobx.dart';
18 +import 'package:url_launcher/url_launcher.dart';
19 +
20 +class CryptoBalanceWidget extends StatelessWidget {
21 + const CryptoBalanceWidget({
22 + super.key,
23 + required this.dashboardViewModel,
24 + });
25 +
26 + final DashboardViewModel dashboardViewModel;
27 +
28 + @override
29 + Widget build(BuildContext context) {
30 + return SingleChildScrollView(
31 + child: Column(
32 + crossAxisAlignment: CrossAxisAlignment.center,
33 + children: [
34 + Observer(
35 + builder: (_) {
36 + if (dashboardViewModel.getMoneroError != null) {
37 + return Padding(
38 + padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
39 + child: DashBoardRoundedCardWidget(
40 + title: "Invalid monero bindings",
41 + subTitle: dashboardViewModel.getMoneroError.toString(),
42 + onTap: () {},
43 + ),
44 + );
45 + }
46 + return Container();
47 + },
48 + ),
49 + Observer(
50 + builder: (_) {
51 + if (dashboardViewModel.getWowneroError != null) {
52 + return Padding(
53 + padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
54 + child: DashBoardRoundedCardWidget(
55 + title: "Invalid wownero bindings",
56 + subTitle: dashboardViewModel.getWowneroError.toString(),
57 + onTap: () {},
58 + ));
59 + }
60 + return Container();
61 + },
62 + ),
63 + Observer(
64 + builder: (_) => dashboardViewModel.balanceViewModel.hasAccounts
65 + ? HomeScreenAccountWidget(
66 + walletName: dashboardViewModel.name, accountName: dashboardViewModel.subname)
67 + : Column(
68 + children: [
69 + SizedBox(height: 16),
70 + Container(
71 + margin: const EdgeInsets.only(left: 24, bottom: 16),
72 + child: Observer(
73 + builder: (_) {
74 + return Row(
75 + children: [
76 + Text(
77 + dashboardViewModel.balanceViewModel.asset,
78 + style: TextStyle(
79 + fontSize: 24,
80 + fontFamily: 'Lato',
81 + fontWeight: FontWeight.w600,
82 + color: Theme.of(context)
83 + .extension<DashboardPageTheme>()!
84 + .pageTitleTextColor,
85 + height: 1,
86 + ),
87 + maxLines: 1,
88 + textAlign: TextAlign.center,
89 + ),
90 + if (dashboardViewModel.wallet.isHardwareWallet)
91 + Padding(
92 + padding: const EdgeInsets.all(8.0),
93 + child: Image.asset(
94 + 'assets/images/hardware_wallet/ledger_nano_x.png',
95 + width: 24,
96 + color: Theme.of(context)
97 + .extension<DashboardPageTheme>()!
98 + .pageTitleTextColor,
99 + ),
100 + ),
101 + if (dashboardViewModel
102 + .balanceViewModel.isHomeScreenSettingsEnabled)
103 + InkWell(
104 + onTap: () => Navigator.pushNamed(context, Routes.homeSettings,
105 + arguments: dashboardViewModel.balanceViewModel),
106 + child: Padding(
107 + padding: const EdgeInsets.all(8.0),
108 + child: Image.asset(
109 + 'assets/images/home_screen_settings_icon.png',
110 + color: Theme.of(context)
111 + .extension<DashboardPageTheme>()!
112 + .pageTitleTextColor,
113 + ),
114 + ),
115 + ),
116 + ],
117 + );
118 + },
119 + ),
120 + ),
121 + ],
122 + )),
123 + Observer(
124 + builder: (_) {
125 + if (dashboardViewModel.balanceViewModel.isShowCard && FeatureFlag.isCakePayEnabled) {
126 + return IntroducingCard(
127 + title: S.of(context).introducing_cake_pay,
128 + subTitle: S.of(context).cake_pay_learn_more,
129 + borderColor: Theme.of(context).extension<BalancePageTheme>()!.cardBorderColor,
130 + closeCard: dashboardViewModel.balanceViewModel.disableIntroCakePayCard);
131 + }
132 + return Container();
133 + },
134 + ),
135 + Observer(builder: (_) {
136 + if (!dashboardViewModel.showRepWarning) {
137 + return const SizedBox();
138 + }
139 + return Padding(
140 + padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
141 + child: DashBoardRoundedCardWidget(
142 + title: S.of(context).rep_warning,
143 + subTitle: S.of(context).rep_warning_sub,
144 + onTap: () => Navigator.of(context).pushNamed(Routes.changeRep),
145 + onClose: () {
146 + dashboardViewModel.settingsStore.shouldShowRepWarning = false;
147 + },
148 + ),
149 + );
150 + }),
151 + Observer(
152 + builder: (_) {
153 + return ListView.separated(
154 + physics: NeverScrollableScrollPhysics(),
155 + shrinkWrap: true,
156 + separatorBuilder: (_, __) => Container(padding: EdgeInsets.only(bottom: 8)),
157 + itemCount: dashboardViewModel.balanceViewModel.formattedBalances.length,
158 + itemBuilder: (__, index) {
159 + final balance =
160 + dashboardViewModel.balanceViewModel.formattedBalances.elementAt(index);
161 + return Observer(builder: (_) {
162 + return BalanceRowWidget(
163 + dashboardViewModel: dashboardViewModel,
164 + availableBalanceLabel:
165 + '${dashboardViewModel.balanceViewModel.availableBalanceLabel}',
166 + availableBalance: balance.availableBalance,
167 + availableFiatBalance: balance.fiatAvailableBalance,
168 + additionalBalanceLabel:
169 + '${dashboardViewModel.balanceViewModel.additionalBalanceLabel}',
170 + additionalBalance: balance.additionalBalance,
171 + additionalFiatBalance: balance.fiatAdditionalBalance,
172 + frozenBalance: balance.frozenBalance,
173 + frozenFiatBalance: balance.fiatFrozenBalance,
174 + currency: balance.asset,
175 + hasAdditionalBalance:
176 + dashboardViewModel.balanceViewModel.hasAdditionalBalance,
177 + hasSecondAdditionalBalance:
178 + dashboardViewModel.balanceViewModel.hasSecondAdditionalBalance,
179 + hasSecondAvailableBalance:
180 + dashboardViewModel.balanceViewModel.hasSecondAvailableBalance,
181 + secondAdditionalBalance: balance.secondAdditionalBalance,
182 + secondAdditionalFiatBalance: balance.fiatSecondAdditionalBalance,
183 + secondAvailableBalance: balance.secondAvailableBalance,
184 + secondAvailableFiatBalance: balance.fiatSecondAvailableBalance,
185 + secondAdditionalBalanceLabel:
186 + '${dashboardViewModel.balanceViewModel.secondAdditionalBalanceLabel}',
187 + secondAvailableBalanceLabel:
188 + '${dashboardViewModel.balanceViewModel.secondAvailableBalanceLabel}',
189 + isTestnet: dashboardViewModel.isTestnet,
190 + );
191 + });
192 + },
193 + );
194 + },
195 + ),
196 + Observer(builder: (context) {
197 + return Column(
198 + children: [
199 + if (dashboardViewModel.isMoneroWalletBrokenReasons.isNotEmpty) ...[
200 + SizedBox(height: 10),
201 + Padding(
202 + padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
203 + child: DashBoardRoundedCardWidget(
204 + customBorder: 30,
205 + title: "This wallet has encountered an issue",
206 + subTitle: "Here are the things that you should note:\n - " +
207 + dashboardViewModel.isMoneroWalletBrokenReasons.join("\n - ") +
208 + "\n\nPlease restart your wallet and if it doesn't help contact our support.",
209 + onTap: () {},
210 + ))
211 + ],
212 + if (dashboardViewModel.showSilentPaymentsCard) ...[
213 + SizedBox(height: 10),
214 + Padding(
215 + padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
216 + child: DashBoardRoundedCardWidget(
217 + customBorder: 30,
218 + title: S.of(context).silent_payments,
219 + subTitle: S.of(context).enable_silent_payments_scanning,
220 + hint: Column(
221 + children: [
222 + Row(
223 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
224 + children: [
225 + GestureDetector(
226 + behavior: HitTestBehavior.opaque,
227 + onTap: () => launchUrl(
228 + Uri.parse(
229 + "https://docs.cakewallet.com/cryptos/bitcoin#silent-payments"),
230 + mode: LaunchMode.externalApplication,
231 + ),
232 + child: Row(
233 + children: [
234 + Text(
235 + S.of(context).what_is_silent_payments,
236 + style: TextStyle(
237 + fontSize: 12,
238 + fontFamily: 'Lato',
239 + fontWeight: FontWeight.w400,
240 + color: Theme.of(context)
241 + .extension<BalancePageTheme>()!
242 + .labelTextColor,
243 + height: 1,
244 + ),
245 + softWrap: true,
246 + ),
247 + Padding(
248 + padding: const EdgeInsets.symmetric(horizontal: 4),
249 + child: Icon(Icons.help_outline,
250 + size: 16,
251 + color: Theme.of(context)
252 + .extension<BalancePageTheme>()!
253 + .labelTextColor),
254 + )
255 + ],
256 + ),
257 + ),
258 + Observer(
259 + builder: (_) => StandardSwitch(
260 + value: dashboardViewModel.silentPaymentsScanningActive,
261 + onTaped: () => _toggleSilentPaymentsScanning(context),
262 + ),
263 + )
264 + ],
265 + ),
266 + ],
267 + ),
268 + onTap: () => _toggleSilentPaymentsScanning(context),
269 + icon: Icon(
270 + Icons.lock,
271 + color:
272 + Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
273 + size: 50,
274 + ),
275 + ),
276 + ),
277 + ],
278 + if (dashboardViewModel.showMwebCard) ...[
279 + SizedBox(height: 10),
280 + Padding(
281 + padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
282 + child: DashBoardRoundedCardWidget(
283 + customBorder: 30,
284 + title: S.of(context).litecoin_mweb,
285 + subTitle: S.of(context).litecoin_mweb_description,
286 + hint: Column(
287 + crossAxisAlignment: CrossAxisAlignment.start,
288 + children: [
289 + GestureDetector(
290 + behavior: HitTestBehavior.opaque,
291 + onTap: () => launchUrl(
292 + Uri.parse("https://docs.cakewallet.com/cryptos/litecoin/#mweb"),
293 + mode: LaunchMode.externalApplication,
294 + ),
295 + child: Text(
296 + S.of(context).learn_more,
297 + style: TextStyle(
298 + fontSize: 12,
299 + fontFamily: 'Lato',
300 + fontWeight: FontWeight.w400,
301 + color:
302 + Theme.of(context).extension<BalancePageTheme>()!.labelTextColor,
303 + height: 1,
304 + ),
305 + softWrap: true,
306 + ),
307 + ),
308 + SizedBox(height: 8),
309 + Row(
310 + children: [
311 + Expanded(
312 + child: ElevatedButton(
313 + onPressed: () => _dismissMweb(context),
314 + style: ElevatedButton.styleFrom(
315 + backgroundColor: Theme.of(context).primaryColor,
316 + ),
317 + child: Text(
318 + S.of(context).litecoin_mweb_dismiss,
319 + style: TextStyle(color: Colors.white),
320 + ),
321 + ),
322 + ),
323 + const SizedBox(width: 8),
324 + Expanded(
325 + child: ElevatedButton(
326 + onPressed: () => _enableMweb(context),
327 + style: ElevatedButton.styleFrom(
328 + backgroundColor: Colors.white,
329 + foregroundColor: Colors.black,
330 + ),
331 + child: Text(
332 + S.of(context).enable,
333 + maxLines: 1,
334 + ),
335 + ),
336 + ),
337 + ],
338 + ),
339 + ],
340 + ),
341 + onTap: () => {},
342 + icon: Container(
343 + decoration: BoxDecoration(
344 + color: Colors.white,
345 + shape: BoxShape.circle,
346 + ),
347 + child: ImageIcon(
348 + AssetImage('assets/images/mweb_logo.png'),
349 + color: Color.fromARGB(255, 11, 70, 129),
350 + size: 40,
351 + ),
352 + ),
353 + ),
354 + ),
355 + ],
356 + ],
357 + );
358 + }),
359 + ],
360 + ),
361 + );
362 + }
363 +
364 + Future<void> _toggleSilentPaymentsScanning(BuildContext context) async {
365 + final isSilentPaymentsScanningActive = dashboardViewModel.silentPaymentsScanningActive;
366 + final newValue = !isSilentPaymentsScanningActive;
367 +
368 + dashboardViewModel.silentPaymentsScanningActive = newValue;
369 +
370 + final needsToSwitch = !isSilentPaymentsScanningActive &&
371 + await bitcoin!.getNodeIsElectrsSPEnabled(dashboardViewModel.wallet) == false;
372 +
373 + if (needsToSwitch) {
374 + return showPopUp<void>(
375 + context: context,
376 + builder: (BuildContext context) => AlertWithTwoActions(
377 + alertTitle: S.of(context).change_current_node_title,
378 + alertContent: S.of(context).confirm_silent_payments_switch_node,
379 + rightButtonText: S.of(context).confirm,
380 + leftButtonText: S.of(context).cancel,
381 + actionRightButton: () {
382 + dashboardViewModel.setSilentPaymentsScanning(newValue);
383 + Navigator.of(context).pop();
384 + },
385 + actionLeftButton: () {
386 + dashboardViewModel.silentPaymentsScanningActive = isSilentPaymentsScanningActive;
387 + Navigator.of(context).pop();
388 + },
389 + ));
390 + }
391 +
392 + return dashboardViewModel.setSilentPaymentsScanning(newValue);
393 + }
394 +
395 + Future<void> _enableMweb(BuildContext context) async {
396 + if (!dashboardViewModel.hasEnabledMwebBefore) {
397 + await showPopUp<void>(
398 + context: context,
399 + builder: (BuildContext context) => AlertWithOneAction(
400 + alertTitle: S.of(context).alert_notice,
401 + alertContent: S.of(context).litecoin_mweb_warning,
402 + buttonText: S.of(context).understand,
403 + buttonAction: () {
404 + Navigator.of(context).pop();
405 + },
406 + ));
407 + }
408 + dashboardViewModel.setMwebEnabled();
409 + }
410 +
411 + Future<void> _dismissMweb(BuildContext context) async {
412 + await showPopUp<void>(
413 + context: context,
414 + builder: (BuildContext context) => AlertWithOneAction(
415 + alertTitle: S.of(context).alert_notice,
416 + alertContent: S.of(context).litecoin_mweb_enable_later,
417 + buttonText: S.of(context).understand,
418 + buttonAction: () {
419 + Navigator.of(context).pop();
420 + },
421 + ));
422 + dashboardViewModel.dismissMweb();
423 + }
424 +}
lib/src/screens/dashboard/pages/balance_page.dart deleted
-1164
@@ -1,1164 +0,0 @@
1 -import 'dart:math';
2 -
3 -import 'package:auto_size_text/auto_size_text.dart';
4 -import 'package:cake_wallet/bitcoin/bitcoin.dart';
5 -import 'package:cake_wallet/generated/i18n.dart';
6 -import 'package:cake_wallet/reactions/wallet_connect.dart';
7 -import 'package:cake_wallet/routes.dart';
8 -import 'package:cake_wallet/src/screens/dashboard/pages/nft_listing_page.dart';
9 -import 'package:cake_wallet/src/screens/dashboard/widgets/home_screen_account_widget.dart';
10 -import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
11 -import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
12 -import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
13 -import 'package:cake_wallet/src/screens/exchange_trade/information_page.dart';
14 -import 'package:cake_wallet/src/widgets/dashboard_card_widget.dart';
15 -import 'package:cake_wallet/src/widgets/introducing_card.dart';
16 -import 'package:cake_wallet/src/widgets/standard_switch.dart';
17 -import 'package:cake_wallet/store/settings_store.dart';
18 -import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
19 -import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
20 -import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
21 -import 'package:cake_wallet/utils/feature_flag.dart';
22 -import 'package:cake_wallet/utils/payment_request.dart';
23 -import 'package:cake_wallet/utils/show_pop_up.dart';
24 -import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
25 -import 'package:cake_wallet/view_model/dashboard/nft_view_model.dart';
26 -import 'package:cw_core/crypto_currency.dart';
27 -import 'package:cw_core/unspent_coin_type.dart';
28 -import 'package:flutter/material.dart';
29 -import 'package:flutter_mobx/flutter_mobx.dart';
30 -import 'package:url_launcher/url_launcher.dart';
31 -
32 -class BalancePage extends StatelessWidget {
33 - BalancePage({
34 - required this.dashboardViewModel,
35 - required this.settingsStore,
36 - required this.nftViewModel,
37 - });
38 -
39 - final DashboardViewModel dashboardViewModel;
40 - final NFTViewModel nftViewModel;
41 - final SettingsStore settingsStore;
42 -
43 - @override
44 - Widget build(BuildContext context) {
45 - return Observer(
46 - builder: (context) {
47 - final isEVMCompatible = isEVMCompatibleChain(dashboardViewModel.type);
48 - return DefaultTabController(
49 - length: isEVMCompatible ? 2 : 1,
50 - child: Column(
51 - children: [
52 - if (isEVMCompatible)
53 - Align(
54 - alignment: Alignment.centerLeft,
55 - child: Padding(
56 - padding: const EdgeInsets.only(left: 8),
57 - child: TabBar(
58 - indicatorSize: TabBarIndicatorSize.label,
59 - isScrollable: true,
60 - physics: NeverScrollableScrollPhysics(),
61 - labelStyle: TextStyle(
62 - fontSize: 18,
63 - fontFamily: 'Lato',
64 - fontWeight: FontWeight.w600,
65 - color:
66 - Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
67 - height: 1,
68 - ),
69 - unselectedLabelStyle: TextStyle(
70 - fontSize: 18,
71 - fontFamily: 'Lato',
72 - fontWeight: FontWeight.w600,
73 - color:
74 - Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
75 - height: 1,
76 - ),
77 - labelColor:
78 - Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
79 - dividerColor: Colors.transparent,
80 - indicatorColor:
81 - Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
82 - unselectedLabelColor: Theme.of(context)
83 - .extension<DashboardPageTheme>()!
84 - .pageTitleTextColor
85 - .withOpacity(0.5),
86 - tabAlignment: TabAlignment.start,
87 - tabs: [
88 - Tab(text: 'My Crypto'),
89 - Tab(text: 'My NFTs'),
90 - ],
91 - ),
92 - ),
93 - ),
94 - Expanded(
95 - child: TabBarView(
96 - physics: NeverScrollableScrollPhysics(),
97 - children: [
98 - CryptoBalanceWidget(dashboardViewModel: dashboardViewModel),
99 - if (isEVMCompatible) NFTListingPage(nftViewModel: nftViewModel)
100 - ],
101 - ),
102 - ),
103 - ],
104 - ),
105 - );
106 - },
107 - );
108 - }
109 -}
110 -
111 -class CryptoBalanceWidget extends StatelessWidget {
112 - const CryptoBalanceWidget({
113 - super.key,
114 - required this.dashboardViewModel,
115 - });
116 -
117 - final DashboardViewModel dashboardViewModel;
118 -
119 - @override
120 - Widget build(BuildContext context) {
121 - return SingleChildScrollView(
122 - child: Column(
123 - crossAxisAlignment: CrossAxisAlignment.center,
124 - children: [
125 - Observer(
126 - builder: (_) {
127 - if (dashboardViewModel.getMoneroError != null) {
128 - return Padding(
129 - padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
130 - child: DashBoardRoundedCardWidget(
131 - title: "Invalid monero bindings",
132 - subTitle: dashboardViewModel.getMoneroError.toString(),
133 - onTap: () {},
134 - ),
135 - );
136 - }
137 - return Container();
138 - },
139 - ),
140 - Observer(
141 - builder: (_) {
142 - if (dashboardViewModel.getWowneroError != null) {
143 - return Padding(
144 - padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
145 - child: DashBoardRoundedCardWidget(
146 - title: "Invalid wownero bindings",
147 - subTitle: dashboardViewModel.getWowneroError.toString(),
148 - onTap: () {},
149 - ));
150 - }
151 - return Container();
152 - },
153 - ),
154 - Observer(
155 - builder: (_) => dashboardViewModel.balanceViewModel.hasAccounts
156 - ? HomeScreenAccountWidget(
157 - walletName: dashboardViewModel.name,
158 - accountName: dashboardViewModel.subname)
159 - : Column(
160 - children: [
161 - SizedBox(height: 16),
162 - Container(
163 - margin: const EdgeInsets.only(left: 24, bottom: 16),
164 - child: Observer(
165 - builder: (_) {
166 - return Row(
167 - children: [
168 - Text(
169 - dashboardViewModel.balanceViewModel.asset,
170 - style: TextStyle(
171 - fontSize: 24,
172 - fontFamily: 'Lato',
173 - fontWeight: FontWeight.w600,
174 - color: Theme.of(context)
175 - .extension<DashboardPageTheme>()!
176 - .pageTitleTextColor,
177 - height: 1,
178 - ),
179 - maxLines: 1,
180 - textAlign: TextAlign.center,
181 - ),
182 - if (dashboardViewModel.wallet.isHardwareWallet)
183 - Padding(
184 - padding: const EdgeInsets.all(8.0),
185 - child: Image.asset(
186 - 'assets/images/hardware_wallet/ledger_nano_x.png',
187 - width: 24,
188 - color: Theme.of(context)
189 - .extension<DashboardPageTheme>()!
190 - .pageTitleTextColor,
191 - ),
192 - ),
193 - if (dashboardViewModel
194 - .balanceViewModel.isHomeScreenSettingsEnabled)
195 - InkWell(
196 - onTap: () => Navigator.pushNamed(
197 - context, Routes.homeSettings,
198 - arguments: dashboardViewModel.balanceViewModel),
199 - child: Padding(
200 - padding: const EdgeInsets.all(8.0),
201 - child: Image.asset(
202 - 'assets/images/home_screen_settings_icon.png',
203 - color: Theme.of(context)
204 - .extension<DashboardPageTheme>()!
205 - .pageTitleTextColor,
206 - ),
207 - ),
208 - ),
209 - ],
210 - );
211 - },
212 - ),
213 - ),
214 - ],
215 - )),
216 - Observer(
217 - builder: (_) {
218 - if (dashboardViewModel.balanceViewModel.isShowCard &&
219 - FeatureFlag.isCakePayEnabled) {
220 - return IntroducingCard(
221 - title: S.of(context).introducing_cake_pay,
222 - subTitle: S.of(context).cake_pay_learn_more,
223 - borderColor: Theme.of(context).extension<BalancePageTheme>()!.cardBorderColor,
224 - closeCard: dashboardViewModel.balanceViewModel.disableIntroCakePayCard);
225 - }
226 - return Container();
227 - },
228 - ),
229 - Observer(builder: (_) {
230 - if (!dashboardViewModel.showRepWarning) {
231 - return const SizedBox();
232 - }
233 - return Padding(
234 - padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
235 - child: DashBoardRoundedCardWidget(
236 - title: S.of(context).rep_warning,
237 - subTitle: S.of(context).rep_warning_sub,
238 - onTap: () => Navigator.of(context).pushNamed(Routes.changeRep),
239 - onClose: () {
240 - dashboardViewModel.settingsStore.shouldShowRepWarning = false;
241 - },
242 - ),
243 - );
244 - }),
245 - Observer(
246 - builder: (_) {
247 - return ListView.separated(
248 - physics: NeverScrollableScrollPhysics(),
249 - shrinkWrap: true,
250 - separatorBuilder: (_, __) => Container(padding: EdgeInsets.only(bottom: 8)),
251 - itemCount: dashboardViewModel.balanceViewModel.formattedBalances.length,
252 - itemBuilder: (__, index) {
253 - final balance =
254 - dashboardViewModel.balanceViewModel.formattedBalances.elementAt(index);
255 - return Observer(builder: (_) {
256 - return BalanceRowWidget(
257 - dashboardViewModel: dashboardViewModel,
258 - availableBalanceLabel:
259 - '${dashboardViewModel.balanceViewModel.availableBalanceLabel}',
260 - availableBalance: balance.availableBalance,
261 - availableFiatBalance: balance.fiatAvailableBalance,
262 - additionalBalanceLabel:
263 - '${dashboardViewModel.balanceViewModel.additionalBalanceLabel}',
264 - additionalBalance: balance.additionalBalance,
265 - additionalFiatBalance: balance.fiatAdditionalBalance,
266 - frozenBalance: balance.frozenBalance,
267 - frozenFiatBalance: balance.fiatFrozenBalance,
268 - currency: balance.asset,
269 - hasAdditionalBalance:
270 - dashboardViewModel.balanceViewModel.hasAdditionalBalance,
271 - hasSecondAdditionalBalance:
272 - dashboardViewModel.balanceViewModel.hasSecondAdditionalBalance,
273 - hasSecondAvailableBalance:
274 - dashboardViewModel.balanceViewModel.hasSecondAvailableBalance,
275 - secondAdditionalBalance: balance.secondAdditionalBalance,
276 - secondAdditionalFiatBalance: balance.fiatSecondAdditionalBalance,
277 - secondAvailableBalance: balance.secondAvailableBalance,
278 - secondAvailableFiatBalance: balance.fiatSecondAvailableBalance,
279 - secondAdditionalBalanceLabel:
280 - '${dashboardViewModel.balanceViewModel.secondAdditionalBalanceLabel}',
281 - secondAvailableBalanceLabel:
282 - '${dashboardViewModel.balanceViewModel.secondAvailableBalanceLabel}',
283 - isTestnet: dashboardViewModel.isTestnet,
284 - );
285 - });
286 - },
287 - );
288 - },
289 - ),
290 - Observer(builder: (context) {
291 - return Column(
292 - children: [
293 - if (dashboardViewModel.isMoneroWalletBrokenReasons.isNotEmpty) ...[
294 - SizedBox(height: 10),
295 - Padding(
296 - padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
297 - child: DashBoardRoundedCardWidget(
298 - customBorder: 30,
299 - title: "This wallet has encountered an issue",
300 - subTitle: "Here are the things that you should note:\n - " +
301 - dashboardViewModel.isMoneroWalletBrokenReasons.join("\n - ") +
302 - "\n\nPlease restart your wallet and if it doesn't help contact our support.",
303 - onTap: () {},
304 - ))
305 - ],
306 - if (dashboardViewModel.showSilentPaymentsCard) ...[
307 - SizedBox(height: 10),
308 - Padding(
309 - padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
310 - child: DashBoardRoundedCardWidget(
311 - customBorder: 30,
312 - title: S.of(context).silent_payments,
313 - subTitle: S.of(context).enable_silent_payments_scanning,
314 - hint: Column(
315 - children: [
316 - Row(
317 - mainAxisAlignment: MainAxisAlignment.spaceBetween,
318 - children: [
319 - GestureDetector(
320 - behavior: HitTestBehavior.opaque,
321 - onTap: () => launchUrl(
322 - Uri.parse(
323 - "https://docs.cakewallet.com/cryptos/bitcoin#silent-payments"),
324 - mode: LaunchMode.externalApplication,
325 - ),
326 - child: Row(
327 - children: [
328 - Text(
329 - S.of(context).what_is_silent_payments,
330 - style: TextStyle(
331 - fontSize: 12,
332 - fontFamily: 'Lato',
333 - fontWeight: FontWeight.w400,
334 - color: Theme.of(context)
335 - .extension<BalancePageTheme>()!
336 - .labelTextColor,
337 - height: 1,
338 - ),
339 - softWrap: true,
340 - ),
341 - Padding(
342 - padding: const EdgeInsets.symmetric(horizontal: 4),
343 - child: Icon(Icons.help_outline,
344 - size: 16,
345 - color: Theme.of(context)
346 - .extension<BalancePageTheme>()!
347 - .labelTextColor),
348 - )
349 - ],
350 - ),
351 - ),
352 - Observer(
353 - builder: (_) => StandardSwitch(
354 - value: dashboardViewModel.silentPaymentsScanningActive,
355 - onTaped: () => _toggleSilentPaymentsScanning(context),
356 - ),
357 - )
358 - ],
359 - ),
360 - ],
361 - ),
362 - onTap: () => _toggleSilentPaymentsScanning(context),
363 - icon: Icon(
364 - Icons.lock,
365 - color:
366 - Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
367 - size: 50,
368 - ),
369 - ),
370 - ),
371 - ],
372 - if (dashboardViewModel.showMwebCard) ...[
373 - SizedBox(height: 10),
374 - Padding(
375 - padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
376 - child: DashBoardRoundedCardWidget(
377 - customBorder: 30,
378 - title: S.of(context).litecoin_mweb,
379 - subTitle: S.of(context).litecoin_mweb_description,
380 - hint: Column(
381 - crossAxisAlignment: CrossAxisAlignment.start,
382 - children: [
383 - GestureDetector(
384 - behavior: HitTestBehavior.opaque,
385 - onTap: () => launchUrl(
386 - Uri.parse(
387 - "https://docs.cakewallet.com/cryptos/litecoin/#mweb"),
388 - mode: LaunchMode.externalApplication,
389 - ),
390 - child: Text(
391 - S.of(context).learn_more,
392 - style: TextStyle(
393 - fontSize: 12,
394 - fontFamily: 'Lato',
395 - fontWeight: FontWeight.w400,
396 - color: Theme.of(context)
397 - .extension<BalancePageTheme>()!
398 - .labelTextColor,
399 - height: 1,
400 - ),
401 - softWrap: true,
402 - ),
403 - ),
404 - SizedBox(height: 8),
405 - Row(
406 - children: [
407 - Expanded(
408 - child: ElevatedButton(
409 - onPressed: () => _dismissMweb(context),
410 - style: ElevatedButton.styleFrom(
411 - backgroundColor: Theme.of(context).primaryColor,
412 - ),
413 - child: Text(
414 - S.of(context).litecoin_mweb_dismiss,
415 - style: TextStyle(color: Colors.white),
416 - ),
417 - ),
418 - ),
419 - const SizedBox(width: 8),
420 - Expanded(
421 - child: ElevatedButton(
422 - onPressed: () => _enableMweb(context),
423 - style: ElevatedButton.styleFrom(
424 - backgroundColor: Colors.white,
425 - foregroundColor: Colors.black,
426 - ),
427 - child: Text(
428 - S.of(context).enable,
429 - maxLines: 1,
430 - ),
431 - ),
432 - ),
433 - ],
434 - ),
435 - ],
436 - ),
437 - onTap: () => {},
438 - icon: Container(
439 - decoration: BoxDecoration(
440 - color: Colors.white,
441 - shape: BoxShape.circle,
442 - ),
443 - child: ImageIcon(
444 - AssetImage('assets/images/mweb_logo.png'),
445 - color: Color.fromARGB(255, 11, 70, 129),
446 - size: 40,
447 - ),
448 - ),
449 - ),
450 - ),
451 - ],
452 - ],
453 - );
454 - }),
455 - ],
456 - ),
457 - );
458 - }
459 -
460 - Future<void> _toggleSilentPaymentsScanning(BuildContext context) async {
461 - final isSilentPaymentsScanningActive = dashboardViewModel.silentPaymentsScanningActive;
462 - final newValue = !isSilentPaymentsScanningActive;
463 -
464 - dashboardViewModel.silentPaymentsScanningActive = newValue;
465 -
466 - final needsToSwitch = !isSilentPaymentsScanningActive &&
467 - await bitcoin!.getNodeIsElectrsSPEnabled(dashboardViewModel.wallet) == false;
468 -
469 - if (needsToSwitch) {
470 - return showPopUp<void>(
471 - context: context,
472 - builder: (BuildContext context) => AlertWithTwoActions(
473 - alertTitle: S.of(context).change_current_node_title,
474 - alertContent: S.of(context).confirm_silent_payments_switch_node,
475 - rightButtonText: S.of(context).confirm,
476 - leftButtonText: S.of(context).cancel,
477 - actionRightButton: () {
478 - dashboardViewModel.setSilentPaymentsScanning(newValue);
479 - Navigator.of(context).pop();
480 - },
481 - actionLeftButton: () {
482 - dashboardViewModel.silentPaymentsScanningActive = isSilentPaymentsScanningActive;
483 - Navigator.of(context).pop();
484 - },
485 - ));
486 - }
487 -
488 - return dashboardViewModel.setSilentPaymentsScanning(newValue);
489 - }
490 -
491 - Future<void> _enableMweb(BuildContext context) async {
492 - if (!dashboardViewModel.hasEnabledMwebBefore) {
493 - await showPopUp<void>(
494 - context: context,
495 - builder: (BuildContext context) => AlertWithOneAction(
496 - alertTitle: S.of(context).alert_notice,
497 - alertContent: S.of(context).litecoin_mweb_warning,
498 - buttonText: S.of(context).understand,
499 - buttonAction: () {
500 - Navigator.of(context).pop();
501 - },
502 - ));
503 - }
504 - dashboardViewModel.setMwebEnabled();
505 - }
506 -
507 - Future<void> _dismissMweb(BuildContext context) async {
508 - await showPopUp<void>(
509 - context: context,
510 - builder: (BuildContext context) => AlertWithOneAction(
511 - alertTitle: S.of(context).alert_notice,
512 - alertContent: S.of(context).litecoin_mweb_enable_later,
513 - buttonText: S.of(context).understand,
514 - buttonAction: () {
515 - Navigator.of(context).pop();
516 - },
517 - ));
518 - dashboardViewModel.dismissMweb();
519 - }
520 -}
521 -
522 -class BalanceRowWidget extends StatelessWidget {
523 - BalanceRowWidget({
524 - required this.availableBalanceLabel,
525 - required this.availableBalance,
526 - required this.availableFiatBalance,
527 - required this.additionalBalanceLabel,
528 - required this.additionalBalance,
529 - required this.additionalFiatBalance,
530 - required this.secondAvailableBalanceLabel,
531 - required this.secondAvailableBalance,
532 - required this.secondAvailableFiatBalance,
533 - required this.secondAdditionalBalanceLabel,
534 - required this.secondAdditionalBalance,
535 - required this.secondAdditionalFiatBalance,
536 - required this.frozenBalance,
537 - required this.frozenFiatBalance,
538 - required this.currency,
539 - required this.hasAdditionalBalance,
540 - required this.hasSecondAvailableBalance,
541 - required this.hasSecondAdditionalBalance,
542 - required this.isTestnet,
543 - required this.dashboardViewModel,
544 - super.key,
545 - });
546 -
547 - final String availableBalanceLabel;
548 - final String availableBalance;
549 - final String availableFiatBalance;
550 - final String additionalBalanceLabel;
551 - final String additionalBalance;
552 - final String additionalFiatBalance;
553 - final String secondAvailableBalanceLabel;
554 - final String secondAvailableBalance;
555 - final String secondAvailableFiatBalance;
556 - final String secondAdditionalBalanceLabel;
557 - final String secondAdditionalBalance;
558 - final String secondAdditionalFiatBalance;
559 - final String frozenBalance;
560 - final String frozenFiatBalance;
561 - final CryptoCurrency currency;
562 - final bool hasAdditionalBalance;
563 - final bool hasSecondAvailableBalance;
564 - final bool hasSecondAdditionalBalance;
565 - final bool isTestnet;
566 - final DashboardViewModel dashboardViewModel;
567 -
568 - // void _showBalanceDescription(BuildContext context) {
569 - // showPopUp<void>(
570 - // context: context,
571 - // builder: (_) =>
572 - // InformationPage(information: S.of(context).available_balance_description),
573 - // );
574 - // }
575 -
576 - @override
577 - Widget build(BuildContext context) {
578 - return Column(children: [
579 - Container(
580 - margin: const EdgeInsets.only(left: 16, right: 16),
581 - decoration: BoxDecoration(
582 - borderRadius: BorderRadius.circular(30.0),
583 - border: Border.all(
584 - color: Theme.of(context).extension<BalancePageTheme>()!.cardBorderColor,
585 - width: 1,
586 - ),
587 - color: Theme.of(context).extension<SyncIndicatorTheme>()!.syncedBackgroundColor,
588 - ),
589 - child: Container(
590 - margin: const EdgeInsets.only(top: 16, left: 24, right: 8, bottom: 16),
591 - child: Column(
592 - crossAxisAlignment: CrossAxisAlignment.start,
593 - children: [
594 - GestureDetector(
595 - onTap: () => dashboardViewModel.balanceViewModel.switchBalanceValue(),
596 - child: Row(
597 - mainAxisAlignment: MainAxisAlignment.spaceBetween,
598 - crossAxisAlignment: CrossAxisAlignment.center,
599 - children: [
600 - Column(
601 - crossAxisAlignment: CrossAxisAlignment.start,
602 - children: [
603 - GestureDetector(
604 - behavior: HitTestBehavior.opaque,
605 - onTap: hasAdditionalBalance
606 - ? () => _showBalanceDescription(
607 - context, S.of(context).available_balance_description)
608 - : null,
609 - child: Row(
610 - children: [
611 - Semantics(
612 - hint: 'Double tap to see more information',
613 - container: true,
614 - child: Text('${availableBalanceLabel}',
615 - style: TextStyle(
616 - fontSize: 12,
617 - fontFamily: 'Lato',
618 - fontWeight: FontWeight.w400,
619 - color: Theme.of(context)
620 - .extension<BalancePageTheme>()!
621 - .labelTextColor,
622 - height: 1)),
623 - ),
624 - if (hasAdditionalBalance)
625 - Padding(
626 - padding: const EdgeInsets.symmetric(horizontal: 4),
627 - child: Icon(Icons.help_outline,
628 - size: 16,
629 - color: Theme.of(context)
630 - .extension<BalancePageTheme>()!
631 - .labelTextColor),
632 - ),
633 - ],
634 - ),
635 - ),
636 - SizedBox(height: 6),
637 - AutoSizeText(availableBalance,
638 - style: TextStyle(
639 - fontSize: 24,
640 - fontFamily: 'Lato',
641 - fontWeight: FontWeight.w900,
642 - color: Theme.of(context)
643 - .extension<BalancePageTheme>()!
644 - .balanceAmountColor,
645 - height: 1),
646 - maxLines: 1,
647 - textAlign: TextAlign.start),
648 - SizedBox(height: 6),
649 - if (isTestnet)
650 - Text(S.of(context).testnet_coins_no_value,
651 - textAlign: TextAlign.center,
652 - style: TextStyle(
653 - fontSize: 14,
654 - fontFamily: 'Lato',
655 - fontWeight: FontWeight.w400,
656 - color: Theme.of(context).extension<BalancePageTheme>()!.textColor,
657 - height: 1)),
658 - if (!isTestnet)
659 - Text('${availableFiatBalance}',
660 - textAlign: TextAlign.center,
661 - style: TextStyle(
662 - fontSize: 16,
663 - fontFamily: 'Lato',
664 - fontWeight: FontWeight.w500,
665 - color: Theme.of(context).extension<BalancePageTheme>()!.textColor,
666 - height: 1)),
667 -
668 - ],
669 - ),
670 -
671 - SizedBox(
672 - width: min(MediaQuery.of(context).size.width * 0.2, 100),
673 - child: Center(
674 - child: Column(
675 - children: [
676 - CakeImageWidget(
677 - imageUrl: currency.iconPath,
678 - height: 40,
679 - width: 40,
680 - displayOnError: Container(
681 - height: 30.0,
682 - width: 30.0,
683 - child: Center(
684 - child: Text(
685 - currency.title.substring(0, min(currency.title.length, 2)),
686 - style: TextStyle(fontSize: 11),
687 - ),
688 - ),
689 - decoration: BoxDecoration(
690 - shape: BoxShape.circle,
691 - color: Colors.grey.shade400,
692 - ),
693 - ),
694 - ),
695 - const SizedBox(height: 10),
696 - Text(
697 - currency.title,
698 - style: TextStyle(
699 - fontSize: 15,
700 - fontFamily: 'Lato',
701 - fontWeight: FontWeight.w800,
702 - color:
703 - Theme.of(context).extension<BalancePageTheme>()!.assetTitleColor,
704 - height: 1,
705 - ),
706 - ),
707 - ],
708 - ),
709 - ),
710 - ),
711 - ],
712 - ),
713 - ),
714 - if (frozenBalance.isNotEmpty)
715 - GestureDetector(
716 - behavior: HitTestBehavior.opaque,
717 - onTap: hasAdditionalBalance
718 - ? () => _showBalanceDescription(
719 - context, S.of(context).unavailable_balance_description)
720 - : null,
721 - child: Column(
722 - crossAxisAlignment: CrossAxisAlignment.start,
723 - children: [
724 - SizedBox(height: 26),
725 - Row(
726 - children: [
727 - Text(
728 - S.of(context).unavailable_balance,
729 - textAlign: TextAlign.center,
730 - style: TextStyle(
731 - fontSize: 12,
732 - fontFamily: 'Lato',
733 - fontWeight: FontWeight.w400,
734 - color:
735 - Theme.of(context).extension<BalancePageTheme>()!.labelTextColor,
736 - height: 1,
737 - ),
738 - ),
739 - Padding(
740 - padding: const EdgeInsets.symmetric(horizontal: 4),
741 - child: Icon(Icons.help_outline,
742 - size: 16,
743 - color: Theme.of(context)
744 - .extension<BalancePageTheme>()!
745 - .labelTextColor),
746 - ),
747 - ],
748 - ),
749 - SizedBox(height: 8),
750 - AutoSizeText(
751 - frozenBalance,
752 - style: TextStyle(
753 - fontSize: 20,
754 - fontFamily: 'Lato',
755 - fontWeight: FontWeight.w400,
756 - color:
757 - Theme.of(context).extension<BalancePageTheme>()!.balanceAmountColor,
758 - height: 1,
759 - ),
760 - maxLines: 1,
761 - textAlign: TextAlign.center,
762 - ),
763 - SizedBox(height: 4),
764 - if (!isTestnet)
765 - Text(
766 - frozenFiatBalance,
767 - textAlign: TextAlign.center,
768 - style: TextStyle(
769 - fontSize: 12,
770 - fontFamily: 'Lato',
771 - fontWeight: FontWeight.w400,
772 - color: Theme.of(context).extension<BalancePageTheme>()!.textColor,
773 - height: 1,
774 - ),
775 - ),
776 - ],
777 - ),
778 - ),
779 - if (hasAdditionalBalance)
780 - GestureDetector(
781 - onTap: () => dashboardViewModel.balanceViewModel.switchBalanceValue(),
782 - child: Column(
783 - crossAxisAlignment: CrossAxisAlignment.start,
784 - children: [
785 - SizedBox(height: 24),
786 - Text(
787 - '${additionalBalanceLabel}',
788 - textAlign: TextAlign.center,
789 - style: TextStyle(
790 - fontSize: 12,
791 - fontFamily: 'Lato',
792 - fontWeight: FontWeight.w400,
793 - color: Theme.of(context).extension<BalancePageTheme>()!.labelTextColor,
794 - height: 1,
795 - ),
796 - ),
797 - SizedBox(height: 8),
798 - AutoSizeText(
799 - additionalBalance,
800 - style: TextStyle(
801 - fontSize: 20,
802 - fontFamily: 'Lato',
803 - fontWeight: FontWeight.w400,
804 - color: Theme.of(context).extension<BalancePageTheme>()!.assetTitleColor,
805 - height: 1,
806 - ),
807 - maxLines: 1,
808 - textAlign: TextAlign.center,
809 - ),
810 - SizedBox(height: 4),
811 - if (!isTestnet)
812 - Text(
813 - '${additionalFiatBalance}',
814 - textAlign: TextAlign.center,
815 - style: TextStyle(
816 - fontSize: 12,
817 - fontFamily: 'Lato',
818 - fontWeight: FontWeight.w400,
819 - color: Theme.of(context).extension<BalancePageTheme>()!.textColor,
820 - height: 1,
821 - ),
822 - ),
823 - ],
824 - ),
825 - ),
826 - ],
827 - ),
828 - ),
829 - ),
830 - if (hasSecondAdditionalBalance || hasSecondAvailableBalance) ...[
831 - SizedBox(height: 10),
832 - Container(
833 - margin: const EdgeInsets.only(left: 16, right: 16),
834 - decoration: BoxDecoration(
835 - borderRadius: BorderRadius.circular(30.0),
836 - border: Border.all(
837 - color: Theme.of(context).extension<BalancePageTheme>()!.cardBorderColor,
838 - width: 1,
839 - ),
840 - color: Theme.of(context).extension<SyncIndicatorTheme>()!.syncedBackgroundColor,
841 - ),
842 - child: Container(
843 - child: Column(
844 - crossAxisAlignment: CrossAxisAlignment.start,
845 - children: [
846 - Container(
847 - margin: const EdgeInsets.only(top: 16, left: 24, right: 8, bottom: 16),
848 - child: Stack(
849 - children: [
850 - if (currency == CryptoCurrency.ltc)
851 - Row(
852 - mainAxisAlignment: MainAxisAlignment.end,
853 - children: [
854 - Container(
855 - padding: EdgeInsets.only(right: 16, top: 0),
856 - child: Column(
857 - children: [
858 - Container(
859 - child: ImageIcon(
860 - AssetImage('assets/images/mweb_logo.png'),
861 - color: Theme.of(context)
862 - .extension<BalancePageTheme>()!
863 - .assetTitleColor,
864 - size: 40,
865 - ),
866 - ),
867 - const SizedBox(height: 10),
868 - Text(
869 - 'MWEB',
870 - style: TextStyle(
871 - fontSize: 15,
872 - fontFamily: 'Lato',
873 - fontWeight: FontWeight.w800,
874 - color: Theme.of(context)
875 - .extension<BalancePageTheme>()!
876 - .assetTitleColor,
877 - height: 1,
878 - ),
879 - ),
880 - ],
881 - ),
882 - ),
883 - ],
884 - ),
885 - if (hasSecondAvailableBalance)
886 - GestureDetector(
887 - onTap: () => dashboardViewModel.balanceViewModel.switchBalanceValue(),
888 - child: Row(
889 - children: [
890 - Column(
891 - crossAxisAlignment: CrossAxisAlignment.start,
892 - children: [
893 - GestureDetector(
894 - behavior: HitTestBehavior.opaque,
895 - onTap: () => launchUrl(
896 - Uri.parse(
897 - "https://docs.cakewallet.com/cryptos/litecoin.html#mweb"),
898 - mode: LaunchMode.externalApplication,
899 - ),
900 - child: Row(
901 - children: [
902 - Text(
903 - '${secondAvailableBalanceLabel}',
904 - textAlign: TextAlign.center,
905 - style: TextStyle(
906 - fontSize: 12,
907 - fontFamily: 'Lato',
908 - fontWeight: FontWeight.w400,
909 - color: Theme.of(context)
910 - .extension<BalancePageTheme>()!
911 - .labelTextColor,
912 - height: 1,
913 - ),
914 - ),
915 - Padding(
916 - padding: const EdgeInsets.symmetric(horizontal: 4),
917 - child: Icon(Icons.help_outline,
918 - size: 16,
919 - color: Theme.of(context)
920 - .extension<BalancePageTheme>()!
921 - .labelTextColor),
922 - )
923 - ],
924 - ),
925 - ),
926 - SizedBox(height: 8),
927 - AutoSizeText(
928 - secondAvailableBalance,
929 - style: TextStyle(
930 - fontSize: 24,
931 - fontFamily: 'Lato',
932 - fontWeight: FontWeight.w900,
933 - color: Theme.of(context)
934 - .extension<BalancePageTheme>()!
935 - .assetTitleColor,
936 - height: 1,
937 - ),
938 - maxLines: 1,
939 - textAlign: TextAlign.center,
940 - ),
941 - SizedBox(height: 6),
942 - if (!isTestnet)
943 - Text(
944 - '${secondAvailableFiatBalance}',
945 - textAlign: TextAlign.center,
946 - style: TextStyle(
947 - fontSize: 16,
948 - fontFamily: 'Lato',
949 - fontWeight: FontWeight.w500,
950 - color: Theme.of(context)
951 - .extension<BalancePageTheme>()!
952 - .textColor,
953 - height: 1,
954 - ),
955 - ),
956 - ],
957 - ),
958 - ],
959 - ),
960 - ),
961 - ],
962 - ),
963 - ),
964 - Container(
965 - margin: const EdgeInsets.only(top: 0, left: 24, right: 8, bottom: 16),
966 - child: Stack(
967 - children: [
968 - if (hasSecondAdditionalBalance)
969 - Row(
970 - children: [
971 - Column(
972 - crossAxisAlignment: CrossAxisAlignment.start,
973 - children: [
974 - SizedBox(height: 24),
975 - Text(
976 - '${secondAdditionalBalanceLabel}',
977 - textAlign: TextAlign.center,
978 - style: TextStyle(
979 - fontSize: 12,
980 - fontFamily: 'Lato',
981 - fontWeight: FontWeight.w400,
982 - color: Theme.of(context)
983 - .extension<BalancePageTheme>()!
984 - .labelTextColor,
985 - height: 1,
986 - ),
987 - ),
988 - SizedBox(height: 8),
989 - AutoSizeText(
990 - secondAdditionalBalance,
991 - style: TextStyle(
992 - fontSize: 20,
993 - fontFamily: 'Lato',
994 - fontWeight: FontWeight.w400,
995 - color: Theme.of(context)
996 - .extension<BalancePageTheme>()!
997 - .assetTitleColor,
998 - height: 1,
999 - ),
1000 - maxLines: 1,
1001 - textAlign: TextAlign.center,
1002 - ),
1003 - SizedBox(height: 4),
1004 - if (!isTestnet)
1005 - Text(
1006 - '${secondAdditionalFiatBalance}',
1007 - textAlign: TextAlign.center,
1008 - style: TextStyle(
1009 - fontSize: 12,
1010 - fontFamily: 'Lato',
1011 - fontWeight: FontWeight.w400,
1012 - color: Theme.of(context)
1013 - .extension<BalancePageTheme>()!
1014 - .textColor,
1015 - height: 1,
1016 - ),
1017 - ),
1018 - ],
1019 - ),
1020 - ],
1021 - ),
1022 - ],
1023 - ),
1024 - ),
1025 - IntrinsicHeight(
1026 - child: Container(
1027 - padding: EdgeInsets.symmetric(horizontal: 24),
1028 - child: Row(
1029 - mainAxisAlignment: MainAxisAlignment.spaceBetween,
1030 - children: [
1031 - Expanded(
1032 - child: Semantics(
1033 - label: S.of(context).litecoin_mweb_pegin,
1034 - child: OutlinedButton(
1035 - onPressed: () {
1036 - final mwebAddress =
1037 - bitcoin!.getUnusedMwebAddress(dashboardViewModel.wallet);
1038 - PaymentRequest? paymentRequest = null;
1039 - if ((mwebAddress?.isNotEmpty ?? false)) {
1040 - paymentRequest =
1041 - PaymentRequest.fromUri(Uri.parse("litecoin:${mwebAddress}"));
1042 - }
1043 - Navigator.pushNamed(
1044 - context,
1045 - Routes.send,
1046 - arguments: {
1047 - 'paymentRequest': paymentRequest,
1048 - 'coinTypeToSpendFrom': UnspentCoinType.nonMweb,
1049 - },
1050 - );
1051 - },
1052 - style: OutlinedButton.styleFrom(
1053 - backgroundColor: Colors.grey.shade400
1054 - .withAlpha(50),
1055 - side: BorderSide(color: Colors.grey.shade400
1056 - .withAlpha(50), width: 0),
1057 - shape: RoundedRectangleBorder(
1058 - borderRadius: BorderRadius.circular(20),
1059 - ),
1060 - ),
1061 - child: Container(
1062 - padding: EdgeInsets.symmetric(vertical: 12),
1063 - child: Row(
1064 - mainAxisAlignment: MainAxisAlignment.center,
1065 - children: [
1066 - Image.asset(
1067 - height: 30,
1068 - width: 30,
1069 - 'assets/images/received.png',
1070 - color: Theme.of(context)
1071 - .extension<BalancePageTheme>()!
1072 - .balanceAmountColor,
1073 - ),
1074 - const SizedBox(width: 8),
1075 - Text(
1076 - S.of(context).litecoin_mweb_pegin,
1077 - style: TextStyle(
1078 - color: Theme.of(context)
1079 - .extension<BalancePageTheme>()!
1080 - .textColor,
1081 - ),
1082 - ),
1083 - ],
1084 - ),
1085 - ),
1086 - ),
1087 - ),
1088 - ),
1089 - SizedBox(width: 24),
1090 - Expanded(
1091 - child: Semantics(
1092 - label: S.of(context).litecoin_mweb_pegout,
1093 - child: OutlinedButton(
1094 - onPressed: () {
1095 - final litecoinAddress =
1096 - bitcoin!.getUnusedSegwitAddress(dashboardViewModel.wallet);
1097 - PaymentRequest? paymentRequest = null;
1098 - if ((litecoinAddress?.isNotEmpty ?? false)) {
1099 - paymentRequest = PaymentRequest.fromUri(
1100 - Uri.parse("litecoin:${litecoinAddress}"));
1101 - }
1102 - Navigator.pushNamed(
1103 - context,
1104 - Routes.send,
1105 - arguments: {
1106 - 'paymentRequest': paymentRequest,
1107 - 'coinTypeToSpendFrom': UnspentCoinType.mweb,
1108 - },
1109 - );
1110 - },
1111 - style: OutlinedButton.styleFrom(
1112 - backgroundColor: Colors.grey.shade400
1113 - .withAlpha(50),
1114 - side: BorderSide(color: Colors.grey.shade400
1115 - .withAlpha(50), width: 0),
1116 - shape: RoundedRectangleBorder(
1117 - borderRadius: BorderRadius.circular(20),
1118 - ),
1119 - ),
1120 - child: Container(
1121 - padding: EdgeInsets.symmetric(vertical: 12),
1122 - child: Row(
1123 - mainAxisAlignment: MainAxisAlignment.center,
1124 - children: [
1125 - Image.asset(
1126 - height: 30,
1127 - width: 30,
1128 - 'assets/images/upload.png',
1129 - color: Theme.of(context)
1130 - .extension<BalancePageTheme>()!
1131 - .balanceAmountColor,
1132 - ),
1133 - const SizedBox(width: 8),
1134 - Text(
1135 - S.of(context).litecoin_mweb_pegout,
1136 - style: TextStyle(
1137 - color: Theme.of(context)
1138 - .extension<BalancePageTheme>()!
1139 - .textColor,
1140 - ),
1141 - ),
1142 - ],
1143 - ),
1144 - ),
1145 - ),
1146 - ),
1147 - ),
1148 - ],
1149 - ),
1150 - ),
1151 - ),
1152 - SizedBox(height: 16),
1153 - ],
1154 - ),
1155 - ),
1156 - ),
1157 - ],
1158 - ]);
1159 - }
1160 -
1161 - void _showBalanceDescription(BuildContext context, String content) {
1162 - showPopUp<void>(context: context, builder: (_) => InformationPage(information: content));
1163 - }
1164 -}
lib/view_model/dashboard/balance_view_model.dart
+13 -5
@@ -158,17 +158,17 @@ abstract class BalanceViewModelBase with Store {
158 case WalletType.banano:
159 case WalletType.solana:
160 case WalletType.tron:
161 + case WalletType.bitcoin:
162 + case WalletType.litecoin:
163 + case WalletType.bitcoinCash:
164 + case WalletType.none:
165 return S.current.xmr_available_balance;
162 - default:
163 - return S.current.confirmed;
166 }
167 }
168
169 @computed
170 String get additionalBalanceLabel {
171 switch (wallet.type) {
170 - case WalletType.monero:
171 - case WalletType.wownero:
172 case WalletType.haven:
173 case WalletType.ethereum:
174 case WalletType.polygon:
@@ -357,7 +357,12 @@ abstract class BalanceViewModelBase with Store {
357 bool mwebEnabled = false;
358
359 @computed
360 - bool get hasAdditionalBalance => _hasAdditionalBalanceForWalletType(wallet.type);
360 + bool get hasAdditionalBalance {
361 + bool isWalletTypeActivated = _hasAdditionalBalanceForWalletType(wallet.type);
362 + bool isNotZeroAmount = additionalBalance != "0.0";
363 +
364 + return isWalletTypeActivated && isNotZeroAmount;
365 + }
366
367 @computed
368 bool get hasSecondAdditionalBalance =>
@@ -373,6 +378,9 @@ abstract class BalanceViewModelBase with Store {
378 case WalletType.polygon:
379 case WalletType.solana:
380 case WalletType.tron:
381 + case WalletType.bitcoin:
382 + case WalletType.bitcoinCash:
383 + case WalletType.litecoin:
384 return false;
385 default:
386 return true;
res/values/strings_ar.arb
+1
@@ -330,6 +330,7 @@
330 "freeze": "تجميد",
331 "frequently_asked_questions": "الأسئلة الشائعة",
332 "frozen": "مجمدة",
333 + "frozen_balance": "التوازن المجمد",
334 "full_balance": "الرصيد الكامل",
335 "gas_exceeds_allowance": "الغاز المطلوب بالمعاملة يتجاوز البدل.",
336 "generate_name": "توليد الاسم",
res/values/strings_bg.arb
+1
@@ -330,6 +330,7 @@
330 "freeze": "Замразяване",
331 "frequently_asked_questions": "Често задавани въпроси",
332 "frozen": "Замразени",
333 + "frozen_balance": "Замразен баланс",
334 "full_balance": "Пълен баланс",
335 "gas_exceeds_allowance": "Газът, изискван от транзакцията, надвишава надбавката.",
336 "generate_name": "Генериране на име",
res/values/strings_cs.arb
+1
@@ -330,6 +330,7 @@
330 "freeze": "Zmrazit",
331 "frequently_asked_questions": "Často kladené otázky",
332 "frozen": "Zmraženo",
333 + "frozen_balance": "Zmrazená rovnováha",
334 "full_balance": "Celkový zůstatek",
335 "gas_exceeds_allowance": "Plyn vyžadovaný transakcí přesahuje příspěvek.",
336 "generate_name": "Generovat jméno",
res/values/strings_de.arb
+1
@@ -330,6 +330,7 @@
330 "freeze": "Einfrieren",
331 "frequently_asked_questions": "Häufig gestellte Fragen",
332 "frozen": "Gefroren",
333 + "frozen_balance": "Gefrorenes Gleichgewicht",
334 "full_balance": "Gesamtguthaben",
335 "gas_exceeds_allowance": "Die durch Transaktion erforderliche Gas übertrifft die Zulage.",
336 "generate_name": "Namen generieren",
res/values/strings_en.arb
+1
@@ -330,6 +330,7 @@
330 "freeze": "Freeze",
331 "frequently_asked_questions": "Frequently asked questions",
332 "frozen": "Frozen",
333 + "frozen_balance": "Frozen Balance",
334 "full_balance": "Full Balance",
335 "gas_exceeds_allowance": "Gas required by transaction exceeds allowance.",
336 "generate_name": "Generate Name",
res/values/strings_es.arb
+1
@@ -330,6 +330,7 @@
330 "freeze": "Congelar",
331 "frequently_asked_questions": "Preguntas frecuentes",
332 "frozen": "Congelada",
333 + "frozen_balance": "Equilibrio congelado",
334 "full_balance": "Balance completo",
335 "gas_exceeds_allowance": "El gas requerido por la transacción excede la asignación.",
336 "generate_name": "Generar nombre",
res/values/strings_fr.arb
+1
@@ -330,6 +330,7 @@
330 "freeze": "Geler",
331 "frequently_asked_questions": "Foire aux questions",
332 "frozen": "Gelées",
333 + "frozen_balance": "Équilibre gelé",
334 "full_balance": "Solde Complet",
335 "gas_exceeds_allowance": "Le gaz requis par la transaction dépasse l'allocation.",
336 "generate_name": "Générer un nom",
res/values/strings_ha.arb
+1
@@ -330,6 +330,7 @@
330 "freeze": "Daskare",
331 "frequently_asked_questions": "Tambayoyin da ake yawan yi",
332 "frozen": "Daskararre",
333 + "frozen_balance": "Daidaituwa mai sanyi",
334 "full_balance": "DUKAN KUDI",
335 "gas_exceeds_allowance": "Gas da ake buƙata ta hanyar ma'amala ya wuce izini.",
336 "generate_name": "Ƙirƙirar Suna",
res/values/strings_hi.arb
+1
@@ -330,6 +330,7 @@
330 "freeze": "फ्रीज",
331 "frequently_asked_questions": "अक्सर पूछे जाने वाले प्रश्न",
332 "frozen": "जमा हुआ",
333 + "frozen_balance": "जमे हुए संतुलन",
334 "full_balance": "पूर्ण संतुलन",
335 "gas_exceeds_allowance": "लेनदेन द्वारा आवश्यक गैस भत्ता से अधिक है।",
336 "generate_name": "नाम जनरेट करें",
res/values/strings_hr.arb
+1
@@ -330,6 +330,7 @@
330 "freeze": "Zamrznuti",
331 "frequently_asked_questions": "Često postavljana pitanja",
332 "frozen": "Smrznuto",
333 + "frozen_balance": "Smrznuta ravnoteža",
334 "full_balance": "Pun iznos",
335 "gas_exceeds_allowance": "Plin potreban transakcijom premašuje dodatak.",
336 "generate_name": "Generiraj ime",
res/values/strings_hy.arb
+1
@@ -330,6 +330,7 @@
330 "freeze": "Կասեցնել",
331 "frequently_asked_questions": "Հաճախ տրվող հարցեր",
332 "frozen": "Կասեցված",
333 + "frozen_balance": "Սառեցված հավասարակշռություն",
334 "full_balance": "Լրիվ մնացորդ",
335 "gas_exceeds_allowance": "Գործարքով պահանջվող գազը գերազանցում է նպաստը:",
336 "generate_name": "Գեներացնել անուն",
res/values/strings_id.arb
+1
@@ -330,6 +330,7 @@
330 "freeze": "Freeze",
331 "frequently_asked_questions": "Pertanyaan yang sering diajukan",
332 "frozen": "Dibekukan",
333 + "frozen_balance": "Keseimbangan beku",
334 "full_balance": "Saldo Penuh",
335 "gas_exceeds_allowance": "Gas yang dibutuhkan oleh transaksi melebihi tunjangan.",
336 "generate_name": "Hasilkan Nama",
res/values/strings_it.arb
+1
@@ -331,6 +331,7 @@
331 "freeze": "Congelare",
332 "frequently_asked_questions": "Domande frequenti",
333 "frozen": "Congelato",
334 + "frozen_balance": "Equilibrio congelato",
335 "full_balance": "Saldo Completo",
336 "gas_exceeds_allowance": "Il gas richiesto dalla transazione supera l'indennità.",
337 "generate_name": "Genera nome",
res/values/strings_ja.arb
+1
@@ -330,6 +330,7 @@
330 "freeze": "氷結",
331 "frequently_asked_questions": "よくある質問",
332 "frozen": "凍った",
333 + "frozen_balance": "凍結バランス",
334 "full_balance": "フルバランス",
335 "gas_exceeds_allowance": "取引に必要なガスは、手当を超えています。",
336 "generate_name": "名前の生成",
res/values/strings_ko.arb
+1
@@ -330,6 +330,7 @@
330 "freeze": "얼다",
331 "frequently_asked_questions": "자주 묻는 질문",
332 "frozen": "겨울 왕국",
333 + "frozen_balance": "냉동 균형",
334 "full_balance": "풀 밸런스",
335 "gas_exceeds_allowance": "거래에 필요한 가스는 수당을 초과합니다.",
336 "generate_name": "이름 생성",
res/values/strings_my.arb
+1
@@ -330,6 +330,7 @@
330 "freeze": "အေးခဲ",
331 "frequently_asked_questions": "မေးလေ့ရှိသောမေးခွန်းများ",
332 "frozen": "ဖြူဖြူ",
333 + "frozen_balance": "လက်ကျန်ငွေ",
334 "full_balance": "Balance အပြည့်",
335 "gas_exceeds_allowance": "ငွေပေးငွေယူမှလိုအပ်သောဓာတ်ငွေ့ထောက်ပံ့ကြေးကျော်လွန်။",
336 "generate_name": "အမည်ဖန်တီးပါ။",
res/values/strings_nl.arb
+1
@@ -330,6 +330,7 @@
330 "freeze": "Bevriezen",
331 "frequently_asked_questions": "Veelgestelde vragen",
332 "frozen": "Bevroren",
333 + "frozen_balance": "Bevroren balans",
334 "full_balance": "Volledig saldo",
335 "gas_exceeds_allowance": "Gas vereist door transactie overschrijdt de vergoeding.",
336 "generate_name": "Naam genereren",
res/values/strings_pl.arb
+1
@@ -330,6 +330,7 @@
330 "freeze": "Zamróź",
331 "frequently_asked_questions": "Często zadawane pytania",
332 "frozen": "Zamrożone",
333 + "frozen_balance": "Mrożona równowaga",
334 "full_balance": "Pełne saldo",
335 "gas_exceeds_allowance": "Gaz wymagany przez transakcję przekracza dodatek.",
336 "generate_name": "Wygeneruj nazwę",
res/values/strings_pt.arb
+1
@@ -330,6 +330,7 @@
330 "freeze": "Congelar",
331 "frequently_asked_questions": "Perguntas frequentes",
332 "frozen": "Congeladas",
333 + "frozen_balance": "Equilíbrio congelado",
334 "full_balance": "Saldo total",
335 "gas_exceeds_allowance": "O gás exigido pela transação excede o subsídio.",
336 "generate_name": "Gerar nome",
res/values/strings_ru.arb
+1
@@ -330,6 +330,7 @@
330 "freeze": "Заморозить",
331 "frequently_asked_questions": "Часто задаваемые вопросы",
332 "frozen": "Заморожено",
333 + "frozen_balance": "Замороженный баланс",
334 "full_balance": "Весь баланс",
335 "gas_exceeds_allowance": "Газ, требуемый в результате транзакции, превышает пособие.",
336 "generate_name": "Создать имя",
res/values/strings_th.arb
+1
@@ -330,6 +330,7 @@
330 "freeze": "ดักจับ",
331 "frequently_asked_questions": "คำถามที่พบบ่อย",
332 "frozen": "ถูกดักจับ",
333 + "frozen_balance": "สมดุลแช่แข็ง",
334 "full_balance": "ยอดคงเหลือทั้งหมด",
335 "gas_exceeds_allowance": "ก๊าซที่ต้องการโดยการทำธุรกรรมเกินค่าเผื่อ",
336 "generate_name": "สร้างชื่อ",
res/values/strings_tl.arb
+1
@@ -330,6 +330,7 @@
330 "freeze": "I-freeze",
331 "frequently_asked_questions": "Mga madalas itanong",
332 "frozen": "Frozen",
333 + "frozen_balance": "Frozen na balanse",
334 "full_balance": "Buong Balanse",
335 "gas_exceeds_allowance": "Ang gas na kinakailangan ng transaksyon ay lumampas sa allowance.",
336 "generate_name": "Bumuo ng pangalan",
res/values/strings_tr.arb
+1
@@ -330,6 +330,7 @@
330 "freeze": "Dondur",
331 "frequently_asked_questions": "Sıkça sorulan sorular",
332 "frozen": "Dondurulmuş",
333 + "frozen_balance": "Dondurulmuş denge",
334 "full_balance": "Tüm bakiye",
335 "gas_exceeds_allowance": "İşlemin gerektirdiği gaz ödeneği aşar.",
336 "generate_name": "İsim Oluştur",
res/values/strings_uk.arb
+1
@@ -330,6 +330,7 @@
330 "freeze": "Заморозити",
331 "frequently_asked_questions": "Часті запитання",
332 "frozen": "Заморожено",
333 + "frozen_balance": "Заморожений баланс",
334 "full_balance": "Весь баланс",
335 "gas_exceeds_allowance": "Газ, необхідний транзакціям, перевищує надбавку.",
336 "generate_name": "Згенерувати назву",
res/values/strings_ur.arb
+1
@@ -330,6 +330,7 @@
330 "freeze": "منجمد",
331 "frequently_asked_questions": "اکثر پوچھے گئے سوالات",
332 "frozen": "منجمد",
333 + "frozen_balance": "منجمد توازن",
334 "full_balance": "مکمل بیلنس",
335 "gas_exceeds_allowance": "لین دین کے ذریعہ درکار گیس الاؤنس سے زیادہ ہے۔",
336 "generate_name": "نام پیدا کریں۔",
res/values/strings_vi.arb
+1
@@ -329,6 +329,7 @@
329 "freeze": "Đóng băng",
330 "frequently_asked_questions": "Các câu hỏi thường gặp",
331 "frozen": "Đã đóng băng",
332 + "frozen_balance": "Cân bằng đông lạnh",
333 "full_balance": "Số dư đầy đủ",
334 "gas_exceeds_allowance": "Gas theo yêu cầu của giao dịch vượt quá trợ cấp.",
335 "generate_name": "Tạo tên",
res/values/strings_yo.arb
+1
@@ -331,6 +331,7 @@
331 "freeze": "Tì pa",
332 "frequently_asked_questions": "Àwọn ìbéèrè la máa ń béèrè",
333 "frozen": "Ó l'a tì pa",
334 + "frozen_balance": "Iwontunwonsi ti o tutu",
335 "full_balance": "Ìyókù owó kíkún",
336 "gas_exceeds_allowance": "Gaasi ti a beere nipasẹ idunadura ju lọ.",
337 "generate_name": "Ṣẹda Orukọ",
res/values/strings_zh.arb
+1
@@ -330,6 +330,7 @@
330 "freeze": "凍結",
331 "frequently_asked_questions": "常见问题",
332 "frozen": "凍結的",
333 + "frozen_balance": "冷冻平衡",
334 "full_balance": "全部余额",
335 "gas_exceeds_allowance": "交易要求的气体超出了津贴。",
336 "generate_name": "生成名称",