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>
This commit is contained in:
David Adegoke 2024-12-27 04:54:47 +01:00 committed by GitHub
parent b1c9be637f
commit c9a6abeea4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
43 changed files with 1257 additions and 1232 deletions

View file

@ -39,7 +39,7 @@ class ElectrumBalance extends Balance {
int secondUnconfirmed = 0;
@override
String get formattedAvailableBalance => bitcoinAmountToString(amount: confirmed - frozen);
String get formattedAvailableBalance => bitcoinAmountToString(amount: ((confirmed + unconfirmed) - frozen) );
@override
String get formattedAdditionalBalance => bitcoinAmountToString(amount: unconfirmed);
@ -58,7 +58,7 @@ class ElectrumBalance extends Balance {
@override
String get formattedFullAvailableBalance =>
bitcoinAmountToString(amount: confirmed + secondConfirmed - frozen);
bitcoinAmountToString(amount: (confirmed + unconfirmed) + secondConfirmed - frozen);
String toJSON() => json.encode({
'confirmed': confirmed,

View file

@ -2213,18 +2213,6 @@ abstract class ElectrumWalletBase
var totalConfirmed = 0;
var totalUnconfirmed = 0;
unspentCoinsInfo.values.forEach((info) {
unspentCoins.forEach((element) {
if (element.hash == info.hash &&
element.vout == info.vout &&
info.isFrozen &&
element.bitcoinAddressRecord.address == info.address &&
element.value == info.value) {
totalFrozen += element.value;
}
});
});
if (hasSilentPaymentsScanning) {
// Add values from unspent coins that are not fetched by the address list
// i.e. scanned silent payments
@ -2240,6 +2228,20 @@ abstract class ElectrumWalletBase
});
}
unspentCoinsInfo.values.forEach((info) {
unspentCoins.forEach((element) {
if (element.bitcoinAddressRecord is BitcoinSilentPaymentAddressRecord) return;
if (element.hash == info.hash &&
element.vout == info.vout &&
info.isFrozen &&
element.bitcoinAddressRecord.address == info.address &&
element.value == info.value) {
totalFrozen += element.value;
}
});
});
final balances = await Future.wait(balanceFutures);
if (balances.isNotEmpty && balances.first['confirmed'] == null) {

View file

@ -3,36 +3,25 @@ import 'package:cw_core/monero_amount_format.dart';
class MoneroBalance extends Balance {
MoneroBalance({required this.fullBalance, required this.unlockedBalance, this.frozenBalance = 0})
: formattedFullBalance = moneroAmountToString(amount: frozenBalance + fullBalance),
formattedUnlockedBalance = moneroAmountToString(amount: unlockedBalance),
formattedLockedBalance =
moneroAmountToString(amount: frozenBalance + fullBalance - unlockedBalance),
: formattedUnconfirmedBalance = moneroAmountToString(amount: fullBalance - unlockedBalance),
formattedUnlockedBalance = moneroAmountToString(amount: unlockedBalance - frozenBalance),
formattedFrozenBalance = moneroAmountToString(amount: frozenBalance),
super(unlockedBalance, fullBalance);
MoneroBalance.fromString(
{required this.formattedFullBalance,
required this.formattedUnlockedBalance,
this.formattedLockedBalance = '0.0'})
: fullBalance = moneroParseAmount(amount: formattedFullBalance),
unlockedBalance = moneroParseAmount(amount: formattedUnlockedBalance),
frozenBalance = moneroParseAmount(amount: formattedLockedBalance),
super(moneroParseAmount(amount: formattedUnlockedBalance),
moneroParseAmount(amount: formattedFullBalance));
final int fullBalance;
final int unlockedBalance;
final int frozenBalance;
final String formattedFullBalance;
final String formattedUnconfirmedBalance;
final String formattedUnlockedBalance;
final String formattedLockedBalance;
final String formattedFrozenBalance;
@override
String get formattedUnAvailableBalance =>
formattedLockedBalance == '0.0' ? '' : formattedLockedBalance;
formattedFrozenBalance == '0.0' ? '' : formattedFrozenBalance;
@override
String get formattedAvailableBalance => formattedUnlockedBalance;
@override
String get formattedAdditionalBalance => formattedFullBalance;
String get formattedAdditionalBalance => formattedUnconfirmedBalance;
}

View file

@ -3,36 +3,26 @@ import 'package:cw_core/wownero_amount_format.dart';
class WowneroBalance extends Balance {
WowneroBalance({required this.fullBalance, required this.unlockedBalance, this.frozenBalance = 0})
: formattedFullBalance = wowneroAmountToString(amount: fullBalance),
: formattedUnconfirmedBalance = wowneroAmountToString(amount: fullBalance - unlockedBalance),
formattedUnlockedBalance = wowneroAmountToString(amount: unlockedBalance - frozenBalance),
formattedLockedBalance =
wowneroAmountToString(amount: frozenBalance + fullBalance - unlockedBalance),
formattedFrozenBalance =
wowneroAmountToString(amount: frozenBalance),
super(unlockedBalance, fullBalance);
WowneroBalance.fromString(
{required this.formattedFullBalance,
required this.formattedUnlockedBalance,
this.formattedLockedBalance = '0.0'})
: fullBalance = wowneroParseAmount(amount: formattedFullBalance),
unlockedBalance = wowneroParseAmount(amount: formattedUnlockedBalance),
frozenBalance = wowneroParseAmount(amount: formattedLockedBalance),
super(wowneroParseAmount(amount: formattedUnlockedBalance),
wowneroParseAmount(amount: formattedFullBalance));
final int fullBalance;
final int unlockedBalance;
final int frozenBalance;
final String formattedFullBalance;
final String formattedUnconfirmedBalance;
final String formattedUnlockedBalance;
final String formattedLockedBalance;
final String formattedFrozenBalance;
@override
String get formattedUnAvailableBalance =>
formattedLockedBalance == '0.0' ? '' : formattedLockedBalance;
formattedFrozenBalance == '0.0' ? '' : formattedFrozenBalance;
@override
String get formattedAvailableBalance => formattedUnlockedBalance;
@override
String get formattedAdditionalBalance => formattedFullBalance;
String get formattedAdditionalBalance => formattedUnconfirmedBalance;
}

View file

@ -11,13 +11,12 @@ class EVMChainERC20Balance extends Balance {
final int exponent;
@override
String get formattedAdditionalBalance {
final String formattedBalance = (balance / BigInt.from(10).pow(exponent)).toString();
return formattedBalance.substring(0, min(12, formattedBalance.length));
}
String get formattedAdditionalBalance => _balance();
@override
String get formattedAvailableBalance {
String get formattedAvailableBalance => _balance();
String _balance() {
final String formattedBalance = (balance / BigInt.from(10).pow(exponent)).toString();
return formattedBalance.substring(0, min(12, formattedBalance.length));
}

View file

@ -751,11 +751,18 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
int _getFrozenBalance() {
var frozenBalance = 0;
for (var coin in unspentCoinsInfo.values.where((element) =>
element.walletId == id &&
element.accountIndex == walletAddresses.account!.id)) {
if (coin.isFrozen && !coin.isSending) frozenBalance += coin.value;
}
unspentCoinsInfo.values.forEach((info) {
unspentCoins.forEach((element) {
if (element.hash == info.hash &&
element.vout == info.vout &&
info.isFrozen &&
element.value == info.value && info.walletId == id &&
info.accountIndex == walletAddresses.account!.id) {
if (element.isFrozen && !element.isSending) frozenBalance+= element.value;
}
});
});
return frozenBalance;
}

View file

@ -1,6 +1,6 @@
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/dashboard/dashboard_page.dart';
import 'package:cake_wallet/src/screens/dashboard/pages/balance_page.dart';
import 'package:cake_wallet/src/screens/dashboard/pages/balance/crypto_balance_widget.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter_test/flutter_test.dart';

View file

@ -79,7 +79,7 @@ import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_wallet
import 'package:cake_wallet/src/screens/dashboard/edit_token_page.dart';
import 'package:cake_wallet/src/screens/dashboard/home_settings_page.dart';
import 'package:cake_wallet/src/screens/dashboard/pages/address_page.dart';
import 'package:cake_wallet/src/screens/dashboard/pages/balance_page.dart';
import 'package:cake_wallet/src/screens/dashboard/pages/balance/balance_page.dart';
import 'package:cake_wallet/src/screens/dashboard/pages/transactions_page.dart';
import 'package:cake_wallet/src/screens/exchange/exchange_page.dart';
import 'package:cake_wallet/src/screens/exchange/exchange_template_page.dart';

View file

@ -24,7 +24,7 @@ import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/menu_widget.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/action_button.dart';
import 'package:cake_wallet/src/screens/dashboard/pages/balance_page.dart';
import 'package:cake_wallet/src/screens/dashboard/pages/balance/balance_page.dart';
import 'package:cake_wallet/src/screens/dashboard/pages/transactions_page.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/sync_indicator.dart';
import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_view_model.dart';

View file

@ -8,7 +8,7 @@ import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/utils/version_comparator.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cake_wallet/src/screens/dashboard/pages/balance_page.dart';
import 'package:cake_wallet/src/screens/dashboard/pages/balance/balance_page.dart';
import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_view_model.dart';
import 'package:cake_wallet/main.dart';
import 'package:cake_wallet/router.dart' as Router;

View file

@ -0,0 +1,88 @@
import 'package:cake_wallet/reactions/wallet_connect.dart';
import 'package:cake_wallet/src/screens/dashboard/pages/balance/crypto_balance_widget.dart';
import 'package:cake_wallet/src/screens/dashboard/pages/nft_listing_page.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cake_wallet/view_model/dashboard/nft_view_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
class BalancePage extends StatelessWidget {
BalancePage({
required this.dashboardViewModel,
required this.settingsStore,
required this.nftViewModel,
});
final DashboardViewModel dashboardViewModel;
final NFTViewModel nftViewModel;
final SettingsStore settingsStore;
@override
Widget build(BuildContext context) {
return Observer(
builder: (context) {
final isEVMCompatible = isEVMCompatibleChain(dashboardViewModel.type);
return DefaultTabController(
length: isEVMCompatible ? 2 : 1,
child: Column(
children: [
if (isEVMCompatible)
Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: const EdgeInsets.only(left: 8),
child: TabBar(
indicatorSize: TabBarIndicatorSize.label,
isScrollable: true,
physics: NeverScrollableScrollPhysics(),
labelStyle: TextStyle(
fontSize: 18,
fontFamily: 'Lato',
fontWeight: FontWeight.w600,
color:
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
height: 1,
),
unselectedLabelStyle: TextStyle(
fontSize: 18,
fontFamily: 'Lato',
fontWeight: FontWeight.w600,
color:
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
height: 1,
),
labelColor:
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
dividerColor: Colors.transparent,
indicatorColor:
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
unselectedLabelColor: Theme.of(context)
.extension<DashboardPageTheme>()!
.pageTitleTextColor
.withOpacity(0.5),
tabAlignment: TabAlignment.start,
tabs: [
Tab(text: 'My Crypto'),
Tab(text: 'My NFTs'),
],
),
),
),
Expanded(
child: TabBarView(
physics: NeverScrollableScrollPhysics(),
children: [
CryptoBalanceWidget(dashboardViewModel: dashboardViewModel),
if (isEVMCompatible) NFTListingPage(nftViewModel: nftViewModel)
],
),
),
],
),
);
},
);
}
}

View file

@ -0,0 +1,654 @@
import 'dart:math';
import 'package:auto_size_text/auto_size_text.dart';
import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/exchange_trade/information_page.dart';
import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
import 'package:cake_wallet/utils/payment_request.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/unspent_coin_type.dart';
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
class BalanceRowWidget extends StatelessWidget {
BalanceRowWidget({
required this.availableBalanceLabel,
required this.availableBalance,
required this.availableFiatBalance,
required this.additionalBalanceLabel,
required this.additionalBalance,
required this.additionalFiatBalance,
required this.secondAvailableBalanceLabel,
required this.secondAvailableBalance,
required this.secondAvailableFiatBalance,
required this.secondAdditionalBalanceLabel,
required this.secondAdditionalBalance,
required this.secondAdditionalFiatBalance,
required this.frozenBalance,
required this.frozenFiatBalance,
required this.currency,
required this.hasAdditionalBalance,
required this.hasSecondAvailableBalance,
required this.hasSecondAdditionalBalance,
required this.isTestnet,
required this.dashboardViewModel,
super.key,
});
final String availableBalanceLabel;
final String availableBalance;
final String availableFiatBalance;
final String additionalBalanceLabel;
final String additionalBalance;
final String additionalFiatBalance;
final String secondAvailableBalanceLabel;
final String secondAvailableBalance;
final String secondAvailableFiatBalance;
final String secondAdditionalBalanceLabel;
final String secondAdditionalBalance;
final String secondAdditionalFiatBalance;
final String frozenBalance;
final String frozenFiatBalance;
final CryptoCurrency currency;
final bool hasAdditionalBalance;
final bool hasSecondAvailableBalance;
final bool hasSecondAdditionalBalance;
final bool isTestnet;
final DashboardViewModel dashboardViewModel;
@override
Widget build(BuildContext context) {
return Column(
children: [
Container(
margin: const EdgeInsets.only(left: 16, right: 16),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30.0),
border: Border.all(
color: Theme.of(context).extension<BalancePageTheme>()!.cardBorderColor,
width: 1,
),
color: Theme.of(context).extension<SyncIndicatorTheme>()!.syncedBackgroundColor,
),
child: Container(
margin: const EdgeInsets.only(top: 16, left: 24, right: 8, bottom: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
GestureDetector(
onTap: () => dashboardViewModel.balanceViewModel.switchBalanceValue(),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: hasAdditionalBalance
? () => _showBalanceDescription(
context, S.of(context).available_balance_description)
: null,
child: Row(
children: [
Semantics(
hint: 'Double tap to see more information',
container: true,
child: Text('${availableBalanceLabel}',
style: TextStyle(
fontSize: 12,
fontFamily: 'Lato',
fontWeight: FontWeight.w400,
color: Theme.of(context)
.extension<BalancePageTheme>()!
.labelTextColor,
height: 1)),
),
if (hasAdditionalBalance)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 4),
child: Icon(Icons.help_outline,
size: 16,
color: Theme.of(context)
.extension<BalancePageTheme>()!
.labelTextColor),
),
],
),
),
SizedBox(height: 6),
AutoSizeText(availableBalance,
style: TextStyle(
fontSize: 24,
fontFamily: 'Lato',
fontWeight: FontWeight.w900,
color: Theme.of(context)
.extension<BalancePageTheme>()!
.balanceAmountColor,
height: 1),
maxLines: 1,
textAlign: TextAlign.start),
SizedBox(height: 6),
if (isTestnet)
Text(S.of(context).testnet_coins_no_value,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 14,
fontFamily: 'Lato',
fontWeight: FontWeight.w400,
color:
Theme.of(context).extension<BalancePageTheme>()!.textColor,
height: 1)),
if (!isTestnet)
Text('${availableFiatBalance}',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
fontFamily: 'Lato',
fontWeight: FontWeight.w500,
color:
Theme.of(context).extension<BalancePageTheme>()!.textColor,
height: 1)),
],
),
SizedBox(
width: min(MediaQuery.of(context).size.width * 0.2, 100),
child: Center(
child: Column(
children: [
CakeImageWidget(
imageUrl: currency.iconPath,
height: 40,
width: 40,
displayOnError: Container(
height: 30.0,
width: 30.0,
child: Center(
child: Text(
currency.title.substring(0, min(currency.title.length, 2)),
style: TextStyle(fontSize: 11),
),
),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.grey.shade400,
),
),
),
const SizedBox(height: 10),
Text(
currency.title,
style: TextStyle(
fontSize: 15,
fontFamily: 'Lato',
fontWeight: FontWeight.w800,
color: Theme.of(context)
.extension<BalancePageTheme>()!
.assetTitleColor,
height: 1,
),
),
],
),
),
),
],
),
),
if (frozenBalance.isNotEmpty)
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: hasAdditionalBalance
? () => _showBalanceDescription(
context, S.of(context).unavailable_balance_description)
: null,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 26),
Row(
children: [
Text(
S.of(context).unavailable_balance,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12,
fontFamily: 'Lato',
fontWeight: FontWeight.w400,
color:
Theme.of(context).extension<BalancePageTheme>()!.labelTextColor,
height: 1,
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 4),
child: Icon(Icons.help_outline,
size: 16,
color: Theme.of(context)
.extension<BalancePageTheme>()!
.labelTextColor),
),
],
),
SizedBox(height: 8),
AutoSizeText(
frozenBalance,
style: TextStyle(
fontSize: 20,
fontFamily: 'Lato',
fontWeight: FontWeight.w400,
color:
Theme.of(context).extension<BalancePageTheme>()!.balanceAmountColor,
height: 1,
),
maxLines: 1,
textAlign: TextAlign.center,
),
SizedBox(height: 4),
if (!isTestnet)
Text(
frozenFiatBalance,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12,
fontFamily: 'Lato',
fontWeight: FontWeight.w400,
color: Theme.of(context).extension<BalancePageTheme>()!.textColor,
height: 1,
),
),
],
),
),
if (hasAdditionalBalance)
GestureDetector(
onTap: () => dashboardViewModel.balanceViewModel.switchBalanceValue(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 24),
Text(
'${additionalBalanceLabel}',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12,
fontFamily: 'Lato',
fontWeight: FontWeight.w400,
color: Theme.of(context).extension<BalancePageTheme>()!.labelTextColor,
height: 1,
),
),
SizedBox(height: 8),
AutoSizeText(
additionalBalance,
style: TextStyle(
fontSize: 20,
fontFamily: 'Lato',
fontWeight: FontWeight.w400,
color: Theme.of(context).extension<BalancePageTheme>()!.assetTitleColor,
height: 1,
),
maxLines: 1,
textAlign: TextAlign.center,
),
SizedBox(height: 4),
if (!isTestnet)
Text(
'${additionalFiatBalance}',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12,
fontFamily: 'Lato',
fontWeight: FontWeight.w400,
color: Theme.of(context).extension<BalancePageTheme>()!.textColor,
height: 1,
),
),
],
),
),
],
),
),
),
if (hasSecondAdditionalBalance || hasSecondAvailableBalance) ...[
SizedBox(height: 10),
Container(
margin: const EdgeInsets.only(left: 16, right: 16),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30.0),
border: Border.all(
color: Theme.of(context).extension<BalancePageTheme>()!.cardBorderColor,
width: 1,
),
color: Theme.of(context).extension<SyncIndicatorTheme>()!.syncedBackgroundColor,
),
child: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: const EdgeInsets.only(top: 16, left: 24, right: 8, bottom: 16),
child: Stack(
children: [
if (currency == CryptoCurrency.ltc)
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Container(
padding: EdgeInsets.only(right: 16, top: 0),
child: Column(
children: [
Container(
child: ImageIcon(
AssetImage('assets/images/mweb_logo.png'),
color: Theme.of(context)
.extension<BalancePageTheme>()!
.assetTitleColor,
size: 40,
),
),
const SizedBox(height: 10),
Text(
'MWEB',
style: TextStyle(
fontSize: 15,
fontFamily: 'Lato',
fontWeight: FontWeight.w800,
color: Theme.of(context)
.extension<BalancePageTheme>()!
.assetTitleColor,
height: 1,
),
),
],
),
),
],
),
if (hasSecondAvailableBalance)
GestureDetector(
onTap: () => dashboardViewModel.balanceViewModel.switchBalanceValue(),
child: Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => launchUrl(
Uri.parse(
"https://docs.cakewallet.com/cryptos/litecoin.html#mweb"),
mode: LaunchMode.externalApplication,
),
child: Row(
children: [
Text(
'${secondAvailableBalanceLabel}',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12,
fontFamily: 'Lato',
fontWeight: FontWeight.w400,
color: Theme.of(context)
.extension<BalancePageTheme>()!
.labelTextColor,
height: 1,
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 4),
child: Icon(Icons.help_outline,
size: 16,
color: Theme.of(context)
.extension<BalancePageTheme>()!
.labelTextColor),
)
],
),
),
SizedBox(height: 8),
AutoSizeText(
secondAvailableBalance,
style: TextStyle(
fontSize: 24,
fontFamily: 'Lato',
fontWeight: FontWeight.w900,
color: Theme.of(context)
.extension<BalancePageTheme>()!
.assetTitleColor,
height: 1,
),
maxLines: 1,
textAlign: TextAlign.center,
),
SizedBox(height: 6),
if (!isTestnet)
Text(
'${secondAvailableFiatBalance}',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
fontFamily: 'Lato',
fontWeight: FontWeight.w500,
color: Theme.of(context)
.extension<BalancePageTheme>()!
.textColor,
height: 1,
),
),
],
),
],
),
),
],
),
),
Container(
margin: const EdgeInsets.only(top: 0, left: 24, right: 8, bottom: 16),
child: Stack(
children: [
if (hasSecondAdditionalBalance)
Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 24),
Text(
'${secondAdditionalBalanceLabel}',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12,
fontFamily: 'Lato',
fontWeight: FontWeight.w400,
color: Theme.of(context)
.extension<BalancePageTheme>()!
.labelTextColor,
height: 1,
),
),
SizedBox(height: 8),
AutoSizeText(
secondAdditionalBalance,
style: TextStyle(
fontSize: 20,
fontFamily: 'Lato',
fontWeight: FontWeight.w400,
color: Theme.of(context)
.extension<BalancePageTheme>()!
.assetTitleColor,
height: 1,
),
maxLines: 1,
textAlign: TextAlign.center,
),
SizedBox(height: 4),
if (!isTestnet)
Text(
'${secondAdditionalFiatBalance}',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12,
fontFamily: 'Lato',
fontWeight: FontWeight.w400,
color: Theme.of(context)
.extension<BalancePageTheme>()!
.textColor,
height: 1,
),
),
],
),
],
),
],
),
),
IntrinsicHeight(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 24),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Semantics(
label: S.of(context).litecoin_mweb_pegin,
child: OutlinedButton(
onPressed: () {
final mwebAddress =
bitcoin!.getUnusedMwebAddress(dashboardViewModel.wallet);
PaymentRequest? paymentRequest = null;
if ((mwebAddress?.isNotEmpty ?? false)) {
paymentRequest = PaymentRequest.fromUri(
Uri.parse("litecoin:${mwebAddress}"));
}
Navigator.pushNamed(
context,
Routes.send,
arguments: {
'paymentRequest': paymentRequest,
'coinTypeToSpendFrom': UnspentCoinType.nonMweb,
},
);
},
style: OutlinedButton.styleFrom(
backgroundColor: Colors.grey.shade400.withAlpha(50),
side: BorderSide(
color: Colors.grey.shade400.withAlpha(50), width: 0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
),
child: Container(
padding: EdgeInsets.symmetric(vertical: 12),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
height: 30,
width: 30,
'assets/images/received.png',
color: Theme.of(context)
.extension<BalancePageTheme>()!
.balanceAmountColor,
),
const SizedBox(width: 8),
Text(
S.of(context).litecoin_mweb_pegin,
style: TextStyle(
color: Theme.of(context)
.extension<BalancePageTheme>()!
.textColor,
),
),
],
),
),
),
),
),
SizedBox(width: 24),
Expanded(
child: Semantics(
label: S.of(context).litecoin_mweb_pegout,
child: OutlinedButton(
onPressed: () {
final litecoinAddress =
bitcoin!.getUnusedSegwitAddress(dashboardViewModel.wallet);
PaymentRequest? paymentRequest = null;
if ((litecoinAddress?.isNotEmpty ?? false)) {
paymentRequest = PaymentRequest.fromUri(
Uri.parse("litecoin:${litecoinAddress}"));
}
Navigator.pushNamed(
context,
Routes.send,
arguments: {
'paymentRequest': paymentRequest,
'coinTypeToSpendFrom': UnspentCoinType.mweb,
},
);
},
style: OutlinedButton.styleFrom(
backgroundColor: Colors.grey.shade400.withAlpha(50),
side: BorderSide(
color: Colors.grey.shade400.withAlpha(50), width: 0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
),
child: Container(
padding: EdgeInsets.symmetric(vertical: 12),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
height: 30,
width: 30,
'assets/images/upload.png',
color: Theme.of(context)
.extension<BalancePageTheme>()!
.balanceAmountColor,
),
const SizedBox(width: 8),
Text(
S.of(context).litecoin_mweb_pegout,
style: TextStyle(
color: Theme.of(context)
.extension<BalancePageTheme>()!
.textColor,
),
),
],
),
),
),
),
),
],
),
),
),
SizedBox(height: 16),
],
),
),
),
],
],
);
}
void _showBalanceDescription(BuildContext context, String content) {
showPopUp<void>(context: context, builder: (_) => InformationPage(information: content));
}
}

View file

@ -0,0 +1,424 @@
import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/dashboard/pages/balance/balance_row_widget.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/home_screen_account_widget.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/src/widgets/dashboard_card_widget.dart';
import 'package:cake_wallet/src/widgets/introducing_card.dart';
import 'package:cake_wallet/src/widgets/standard_switch.dart';
import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
import 'package:cake_wallet/utils/feature_flag.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:url_launcher/url_launcher.dart';
class CryptoBalanceWidget extends StatelessWidget {
const CryptoBalanceWidget({
super.key,
required this.dashboardViewModel,
});
final DashboardViewModel dashboardViewModel;
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Observer(
builder: (_) {
if (dashboardViewModel.getMoneroError != null) {
return Padding(
padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
child: DashBoardRoundedCardWidget(
title: "Invalid monero bindings",
subTitle: dashboardViewModel.getMoneroError.toString(),
onTap: () {},
),
);
}
return Container();
},
),
Observer(
builder: (_) {
if (dashboardViewModel.getWowneroError != null) {
return Padding(
padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
child: DashBoardRoundedCardWidget(
title: "Invalid wownero bindings",
subTitle: dashboardViewModel.getWowneroError.toString(),
onTap: () {},
));
}
return Container();
},
),
Observer(
builder: (_) => dashboardViewModel.balanceViewModel.hasAccounts
? HomeScreenAccountWidget(
walletName: dashboardViewModel.name, accountName: dashboardViewModel.subname)
: Column(
children: [
SizedBox(height: 16),
Container(
margin: const EdgeInsets.only(left: 24, bottom: 16),
child: Observer(
builder: (_) {
return Row(
children: [
Text(
dashboardViewModel.balanceViewModel.asset,
style: TextStyle(
fontSize: 24,
fontFamily: 'Lato',
fontWeight: FontWeight.w600,
color: Theme.of(context)
.extension<DashboardPageTheme>()!
.pageTitleTextColor,
height: 1,
),
maxLines: 1,
textAlign: TextAlign.center,
),
if (dashboardViewModel.wallet.isHardwareWallet)
Padding(
padding: const EdgeInsets.all(8.0),
child: Image.asset(
'assets/images/hardware_wallet/ledger_nano_x.png',
width: 24,
color: Theme.of(context)
.extension<DashboardPageTheme>()!
.pageTitleTextColor,
),
),
if (dashboardViewModel
.balanceViewModel.isHomeScreenSettingsEnabled)
InkWell(
onTap: () => Navigator.pushNamed(context, Routes.homeSettings,
arguments: dashboardViewModel.balanceViewModel),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Image.asset(
'assets/images/home_screen_settings_icon.png',
color: Theme.of(context)
.extension<DashboardPageTheme>()!
.pageTitleTextColor,
),
),
),
],
);
},
),
),
],
)),
Observer(
builder: (_) {
if (dashboardViewModel.balanceViewModel.isShowCard && FeatureFlag.isCakePayEnabled) {
return IntroducingCard(
title: S.of(context).introducing_cake_pay,
subTitle: S.of(context).cake_pay_learn_more,
borderColor: Theme.of(context).extension<BalancePageTheme>()!.cardBorderColor,
closeCard: dashboardViewModel.balanceViewModel.disableIntroCakePayCard);
}
return Container();
},
),
Observer(builder: (_) {
if (!dashboardViewModel.showRepWarning) {
return const SizedBox();
}
return Padding(
padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
child: DashBoardRoundedCardWidget(
title: S.of(context).rep_warning,
subTitle: S.of(context).rep_warning_sub,
onTap: () => Navigator.of(context).pushNamed(Routes.changeRep),
onClose: () {
dashboardViewModel.settingsStore.shouldShowRepWarning = false;
},
),
);
}),
Observer(
builder: (_) {
return ListView.separated(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
separatorBuilder: (_, __) => Container(padding: EdgeInsets.only(bottom: 8)),
itemCount: dashboardViewModel.balanceViewModel.formattedBalances.length,
itemBuilder: (__, index) {
final balance =
dashboardViewModel.balanceViewModel.formattedBalances.elementAt(index);
return Observer(builder: (_) {
return BalanceRowWidget(
dashboardViewModel: dashboardViewModel,
availableBalanceLabel:
'${dashboardViewModel.balanceViewModel.availableBalanceLabel}',
availableBalance: balance.availableBalance,
availableFiatBalance: balance.fiatAvailableBalance,
additionalBalanceLabel:
'${dashboardViewModel.balanceViewModel.additionalBalanceLabel}',
additionalBalance: balance.additionalBalance,
additionalFiatBalance: balance.fiatAdditionalBalance,
frozenBalance: balance.frozenBalance,
frozenFiatBalance: balance.fiatFrozenBalance,
currency: balance.asset,
hasAdditionalBalance:
dashboardViewModel.balanceViewModel.hasAdditionalBalance,
hasSecondAdditionalBalance:
dashboardViewModel.balanceViewModel.hasSecondAdditionalBalance,
hasSecondAvailableBalance:
dashboardViewModel.balanceViewModel.hasSecondAvailableBalance,
secondAdditionalBalance: balance.secondAdditionalBalance,
secondAdditionalFiatBalance: balance.fiatSecondAdditionalBalance,
secondAvailableBalance: balance.secondAvailableBalance,
secondAvailableFiatBalance: balance.fiatSecondAvailableBalance,
secondAdditionalBalanceLabel:
'${dashboardViewModel.balanceViewModel.secondAdditionalBalanceLabel}',
secondAvailableBalanceLabel:
'${dashboardViewModel.balanceViewModel.secondAvailableBalanceLabel}',
isTestnet: dashboardViewModel.isTestnet,
);
});
},
);
},
),
Observer(builder: (context) {
return Column(
children: [
if (dashboardViewModel.isMoneroWalletBrokenReasons.isNotEmpty) ...[
SizedBox(height: 10),
Padding(
padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
child: DashBoardRoundedCardWidget(
customBorder: 30,
title: "This wallet has encountered an issue",
subTitle: "Here are the things that you should note:\n - " +
dashboardViewModel.isMoneroWalletBrokenReasons.join("\n - ") +
"\n\nPlease restart your wallet and if it doesn't help contact our support.",
onTap: () {},
))
],
if (dashboardViewModel.showSilentPaymentsCard) ...[
SizedBox(height: 10),
Padding(
padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
child: DashBoardRoundedCardWidget(
customBorder: 30,
title: S.of(context).silent_payments,
subTitle: S.of(context).enable_silent_payments_scanning,
hint: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => launchUrl(
Uri.parse(
"https://docs.cakewallet.com/cryptos/bitcoin#silent-payments"),
mode: LaunchMode.externalApplication,
),
child: Row(
children: [
Text(
S.of(context).what_is_silent_payments,
style: TextStyle(
fontSize: 12,
fontFamily: 'Lato',
fontWeight: FontWeight.w400,
color: Theme.of(context)
.extension<BalancePageTheme>()!
.labelTextColor,
height: 1,
),
softWrap: true,
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 4),
child: Icon(Icons.help_outline,
size: 16,
color: Theme.of(context)
.extension<BalancePageTheme>()!
.labelTextColor),
)
],
),
),
Observer(
builder: (_) => StandardSwitch(
value: dashboardViewModel.silentPaymentsScanningActive,
onTaped: () => _toggleSilentPaymentsScanning(context),
),
)
],
),
],
),
onTap: () => _toggleSilentPaymentsScanning(context),
icon: Icon(
Icons.lock,
color:
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
size: 50,
),
),
),
],
if (dashboardViewModel.showMwebCard) ...[
SizedBox(height: 10),
Padding(
padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
child: DashBoardRoundedCardWidget(
customBorder: 30,
title: S.of(context).litecoin_mweb,
subTitle: S.of(context).litecoin_mweb_description,
hint: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => launchUrl(
Uri.parse("https://docs.cakewallet.com/cryptos/litecoin/#mweb"),
mode: LaunchMode.externalApplication,
),
child: Text(
S.of(context).learn_more,
style: TextStyle(
fontSize: 12,
fontFamily: 'Lato',
fontWeight: FontWeight.w400,
color:
Theme.of(context).extension<BalancePageTheme>()!.labelTextColor,
height: 1,
),
softWrap: true,
),
),
SizedBox(height: 8),
Row(
children: [
Expanded(
child: ElevatedButton(
onPressed: () => _dismissMweb(context),
style: ElevatedButton.styleFrom(
backgroundColor: Theme.of(context).primaryColor,
),
child: Text(
S.of(context).litecoin_mweb_dismiss,
style: TextStyle(color: Colors.white),
),
),
),
const SizedBox(width: 8),
Expanded(
child: ElevatedButton(
onPressed: () => _enableMweb(context),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.white,
foregroundColor: Colors.black,
),
child: Text(
S.of(context).enable,
maxLines: 1,
),
),
),
],
),
],
),
onTap: () => {},
icon: Container(
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
),
child: ImageIcon(
AssetImage('assets/images/mweb_logo.png'),
color: Color.fromARGB(255, 11, 70, 129),
size: 40,
),
),
),
),
],
],
);
}),
],
),
);
}
Future<void> _toggleSilentPaymentsScanning(BuildContext context) async {
final isSilentPaymentsScanningActive = dashboardViewModel.silentPaymentsScanningActive;
final newValue = !isSilentPaymentsScanningActive;
dashboardViewModel.silentPaymentsScanningActive = newValue;
final needsToSwitch = !isSilentPaymentsScanningActive &&
await bitcoin!.getNodeIsElectrsSPEnabled(dashboardViewModel.wallet) == false;
if (needsToSwitch) {
return showPopUp<void>(
context: context,
builder: (BuildContext context) => AlertWithTwoActions(
alertTitle: S.of(context).change_current_node_title,
alertContent: S.of(context).confirm_silent_payments_switch_node,
rightButtonText: S.of(context).confirm,
leftButtonText: S.of(context).cancel,
actionRightButton: () {
dashboardViewModel.setSilentPaymentsScanning(newValue);
Navigator.of(context).pop();
},
actionLeftButton: () {
dashboardViewModel.silentPaymentsScanningActive = isSilentPaymentsScanningActive;
Navigator.of(context).pop();
},
));
}
return dashboardViewModel.setSilentPaymentsScanning(newValue);
}
Future<void> _enableMweb(BuildContext context) async {
if (!dashboardViewModel.hasEnabledMwebBefore) {
await showPopUp<void>(
context: context,
builder: (BuildContext context) => AlertWithOneAction(
alertTitle: S.of(context).alert_notice,
alertContent: S.of(context).litecoin_mweb_warning,
buttonText: S.of(context).understand,
buttonAction: () {
Navigator.of(context).pop();
},
));
}
dashboardViewModel.setMwebEnabled();
}
Future<void> _dismissMweb(BuildContext context) async {
await showPopUp<void>(
context: context,
builder: (BuildContext context) => AlertWithOneAction(
alertTitle: S.of(context).alert_notice,
alertContent: S.of(context).litecoin_mweb_enable_later,
buttonText: S.of(context).understand,
buttonAction: () {
Navigator.of(context).pop();
},
));
dashboardViewModel.dismissMweb();
}
}

File diff suppressed because it is too large Load diff

View file

@ -158,17 +158,17 @@ abstract class BalanceViewModelBase with Store {
case WalletType.banano:
case WalletType.solana:
case WalletType.tron:
case WalletType.bitcoin:
case WalletType.litecoin:
case WalletType.bitcoinCash:
case WalletType.none:
return S.current.xmr_available_balance;
default:
return S.current.confirmed;
}
}
@computed
String get additionalBalanceLabel {
switch (wallet.type) {
case WalletType.monero:
case WalletType.wownero:
case WalletType.haven:
case WalletType.ethereum:
case WalletType.polygon:
@ -357,7 +357,12 @@ abstract class BalanceViewModelBase with Store {
bool mwebEnabled = false;
@computed
bool get hasAdditionalBalance => _hasAdditionalBalanceForWalletType(wallet.type);
bool get hasAdditionalBalance {
bool isWalletTypeActivated = _hasAdditionalBalanceForWalletType(wallet.type);
bool isNotZeroAmount = additionalBalance != "0.0";
return isWalletTypeActivated && isNotZeroAmount;
}
@computed
bool get hasSecondAdditionalBalance =>
@ -373,6 +378,9 @@ abstract class BalanceViewModelBase with Store {
case WalletType.polygon:
case WalletType.solana:
case WalletType.tron:
case WalletType.bitcoin:
case WalletType.bitcoinCash:
case WalletType.litecoin:
return false;
default:
return true;

View file

@ -330,6 +330,7 @@
"freeze": "تجميد",
"frequently_asked_questions": "الأسئلة الشائعة",
"frozen": "مجمدة",
"frozen_balance": "التوازن المجمد",
"full_balance": "الرصيد الكامل",
"gas_exceeds_allowance": "الغاز المطلوب بالمعاملة يتجاوز البدل.",
"generate_name": "توليد الاسم",

View file

@ -330,6 +330,7 @@
"freeze": "Замразяване",
"frequently_asked_questions": "Често задавани въпроси",
"frozen": "Замразени",
"frozen_balance": "Замразен баланс",
"full_balance": "Пълен баланс",
"gas_exceeds_allowance": "Газът, изискван от транзакцията, надвишава надбавката.",
"generate_name": "Генериране на име",

View file

@ -330,6 +330,7 @@
"freeze": "Zmrazit",
"frequently_asked_questions": "Často kladené otázky",
"frozen": "Zmraženo",
"frozen_balance": "Zmrazená rovnováha",
"full_balance": "Celkový zůstatek",
"gas_exceeds_allowance": "Plyn vyžadovaný transakcí přesahuje příspěvek.",
"generate_name": "Generovat jméno",

View file

@ -330,6 +330,7 @@
"freeze": "Einfrieren",
"frequently_asked_questions": "Häufig gestellte Fragen",
"frozen": "Gefroren",
"frozen_balance": "Gefrorenes Gleichgewicht",
"full_balance": "Gesamtguthaben",
"gas_exceeds_allowance": "Die durch Transaktion erforderliche Gas übertrifft die Zulage.",
"generate_name": "Namen generieren",

View file

@ -330,6 +330,7 @@
"freeze": "Freeze",
"frequently_asked_questions": "Frequently asked questions",
"frozen": "Frozen",
"frozen_balance": "Frozen Balance",
"full_balance": "Full Balance",
"gas_exceeds_allowance": "Gas required by transaction exceeds allowance.",
"generate_name": "Generate Name",

View file

@ -330,6 +330,7 @@
"freeze": "Congelar",
"frequently_asked_questions": "Preguntas frecuentes",
"frozen": "Congelada",
"frozen_balance": "Equilibrio congelado",
"full_balance": "Balance completo",
"gas_exceeds_allowance": "El gas requerido por la transacción excede la asignación.",
"generate_name": "Generar nombre",

View file

@ -330,6 +330,7 @@
"freeze": "Geler",
"frequently_asked_questions": "Foire aux questions",
"frozen": "Gelées",
"frozen_balance": "Équilibre gelé",
"full_balance": "Solde Complet",
"gas_exceeds_allowance": "Le gaz requis par la transaction dépasse l'allocation.",
"generate_name": "Générer un nom",

View file

@ -330,6 +330,7 @@
"freeze": "Daskare",
"frequently_asked_questions": "Tambayoyin da ake yawan yi",
"frozen": "Daskararre",
"frozen_balance": "Daidaituwa mai sanyi",
"full_balance": "DUKAN KUDI",
"gas_exceeds_allowance": "Gas da ake buƙata ta hanyar ma'amala ya wuce izini.",
"generate_name": "Ƙirƙirar Suna",

View file

@ -330,6 +330,7 @@
"freeze": "फ्रीज",
"frequently_asked_questions": "अक्सर पूछे जाने वाले प्रश्न",
"frozen": "जमा हुआ",
"frozen_balance": "जमे हुए संतुलन",
"full_balance": "पूर्ण संतुलन",
"gas_exceeds_allowance": "लेनदेन द्वारा आवश्यक गैस भत्ता से अधिक है।",
"generate_name": "नाम जनरेट करें",

View file

@ -330,6 +330,7 @@
"freeze": "Zamrznuti",
"frequently_asked_questions": "Često postavljana pitanja",
"frozen": "Smrznuto",
"frozen_balance": "Smrznuta ravnoteža",
"full_balance": "Pun iznos",
"gas_exceeds_allowance": "Plin potreban transakcijom premašuje dodatak.",
"generate_name": "Generiraj ime",

View file

@ -330,6 +330,7 @@
"freeze": "Կասեցնել",
"frequently_asked_questions": "Հաճախ տրվող հարցեր",
"frozen": "Կասեցված",
"frozen_balance": "Սառեցված հավասարակշռություն",
"full_balance": "Լրիվ մնացորդ",
"gas_exceeds_allowance": "Գործարքով պահանջվող գազը գերազանցում է նպաստը:",
"generate_name": "Գեներացնել անուն",

View file

@ -330,6 +330,7 @@
"freeze": "Freeze",
"frequently_asked_questions": "Pertanyaan yang sering diajukan",
"frozen": "Dibekukan",
"frozen_balance": "Keseimbangan beku",
"full_balance": "Saldo Penuh",
"gas_exceeds_allowance": "Gas yang dibutuhkan oleh transaksi melebihi tunjangan.",
"generate_name": "Hasilkan Nama",

View file

@ -331,6 +331,7 @@
"freeze": "Congelare",
"frequently_asked_questions": "Domande frequenti",
"frozen": "Congelato",
"frozen_balance": "Equilibrio congelato",
"full_balance": "Saldo Completo",
"gas_exceeds_allowance": "Il gas richiesto dalla transazione supera l'indennità.",
"generate_name": "Genera nome",

View file

@ -330,6 +330,7 @@
"freeze": "氷結",
"frequently_asked_questions": "よくある質問",
"frozen": "凍った",
"frozen_balance": "凍結バランス",
"full_balance": "フルバランス",
"gas_exceeds_allowance": "取引に必要なガスは、手当を超えています。",
"generate_name": "名前の生成",

View file

@ -330,6 +330,7 @@
"freeze": "얼다",
"frequently_asked_questions": "자주 묻는 질문",
"frozen": "겨울 왕국",
"frozen_balance": "냉동 균형",
"full_balance": "풀 밸런스",
"gas_exceeds_allowance": "거래에 필요한 가스는 수당을 초과합니다.",
"generate_name": "이름 생성",

View file

@ -330,6 +330,7 @@
"freeze": "အေးခဲ",
"frequently_asked_questions": "မေးလေ့ရှိသောမေးခွန်းများ",
"frozen": "ဖြူဖြူ",
"frozen_balance": "လက်ကျန်ငွေ",
"full_balance": "Balance အပြည့်",
"gas_exceeds_allowance": "ငွေပေးငွေယူမှလိုအပ်သောဓာတ်ငွေ့ထောက်ပံ့ကြေးကျော်လွန်။",
"generate_name": "အမည်ဖန်တီးပါ။",

View file

@ -330,6 +330,7 @@
"freeze": "Bevriezen",
"frequently_asked_questions": "Veelgestelde vragen",
"frozen": "Bevroren",
"frozen_balance": "Bevroren balans",
"full_balance": "Volledig saldo",
"gas_exceeds_allowance": "Gas vereist door transactie overschrijdt de vergoeding.",
"generate_name": "Naam genereren",

View file

@ -330,6 +330,7 @@
"freeze": "Zamróź",
"frequently_asked_questions": "Często zadawane pytania",
"frozen": "Zamrożone",
"frozen_balance": "Mrożona równowaga",
"full_balance": "Pełne saldo",
"gas_exceeds_allowance": "Gaz wymagany przez transakcję przekracza dodatek.",
"generate_name": "Wygeneruj nazwę",

View file

@ -330,6 +330,7 @@
"freeze": "Congelar",
"frequently_asked_questions": "Perguntas frequentes",
"frozen": "Congeladas",
"frozen_balance": "Equilíbrio congelado",
"full_balance": "Saldo total",
"gas_exceeds_allowance": "O gás exigido pela transação excede o subsídio.",
"generate_name": "Gerar nome",

View file

@ -330,6 +330,7 @@
"freeze": "Заморозить",
"frequently_asked_questions": "Часто задаваемые вопросы",
"frozen": "Заморожено",
"frozen_balance": "Замороженный баланс",
"full_balance": "Весь баланс",
"gas_exceeds_allowance": "Газ, требуемый в результате транзакции, превышает пособие.",
"generate_name": "Создать имя",

View file

@ -330,6 +330,7 @@
"freeze": "ดักจับ",
"frequently_asked_questions": "คำถามที่พบบ่อย",
"frozen": "ถูกดักจับ",
"frozen_balance": "สมดุลแช่แข็ง",
"full_balance": "ยอดคงเหลือทั้งหมด",
"gas_exceeds_allowance": "ก๊าซที่ต้องการโดยการทำธุรกรรมเกินค่าเผื่อ",
"generate_name": "สร้างชื่อ",

View file

@ -330,6 +330,7 @@
"freeze": "I-freeze",
"frequently_asked_questions": "Mga madalas itanong",
"frozen": "Frozen",
"frozen_balance": "Frozen na balanse",
"full_balance": "Buong Balanse",
"gas_exceeds_allowance": "Ang gas na kinakailangan ng transaksyon ay lumampas sa allowance.",
"generate_name": "Bumuo ng pangalan",

View file

@ -330,6 +330,7 @@
"freeze": "Dondur",
"frequently_asked_questions": "Sıkça sorulan sorular",
"frozen": "Dondurulmuş",
"frozen_balance": "Dondurulmuş denge",
"full_balance": "Tüm bakiye",
"gas_exceeds_allowance": "İşlemin gerektirdiği gaz ödeneği aşar.",
"generate_name": "İsim Oluştur",

View file

@ -330,6 +330,7 @@
"freeze": "Заморозити",
"frequently_asked_questions": "Часті запитання",
"frozen": "Заморожено",
"frozen_balance": "Заморожений баланс",
"full_balance": "Весь баланс",
"gas_exceeds_allowance": "Газ, необхідний транзакціям, перевищує надбавку.",
"generate_name": "Згенерувати назву",

View file

@ -330,6 +330,7 @@
"freeze": "منجمد",
"frequently_asked_questions": "اکثر پوچھے گئے سوالات",
"frozen": "منجمد",
"frozen_balance": "منجمد توازن",
"full_balance": "مکمل بیلنس",
"gas_exceeds_allowance": "لین دین کے ذریعہ درکار گیس الاؤنس سے زیادہ ہے۔",
"generate_name": "نام پیدا کریں۔",

View file

@ -329,6 +329,7 @@
"freeze": "Đóng băng",
"frequently_asked_questions": "Các câu hỏi thường gặp",
"frozen": "Đã đóng băng",
"frozen_balance": "Cân bằng đông lạnh",
"full_balance": "Số dư đầy đủ",
"gas_exceeds_allowance": "Gas theo yêu cầu của giao dịch vượt quá trợ cấp.",
"generate_name": "Tạo tên",

View file

@ -331,6 +331,7 @@
"freeze": "Tì pa",
"frequently_asked_questions": "Àwọn ìbéèrè la máa ń béèrè",
"frozen": "Ó l'a tì pa",
"frozen_balance": "Iwontunwonsi ti o tutu",
"full_balance": "Ìyókù owó kíkún",
"gas_exceeds_allowance": "Gaasi ti a beere nipasẹ idunadura ju lọ.",
"generate_name": "Ṣẹda Orukọ",

View file

@ -330,6 +330,7 @@
"freeze": "凍結",
"frequently_asked_questions": "常见问题",
"frozen": "凍結的",
"frozen_balance": "冷冻平衡",
"full_balance": "全部余额",
"gas_exceeds_allowance": "交易要求的气体超出了津贴。",
"generate_name": "生成名称",