Merge remote-tracking branch 'origin/main' into electrum-sp-refactors

This commit is contained in:
Rafael Saes 2025-04-09 09:17:55 -03:00
commit 0656450958
127 changed files with 464 additions and 265 deletions

25
.gitignore vendored
View file

@ -142,9 +142,28 @@ lib/wownero/wownero.dart
lib/zano/zano.dart lib/zano/zano.dart
lib/decred/decred.dart lib/decred/decred.dart
ios/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_180.png ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon@2x.png
ios/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_120.png ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon@2x~ipad.png
ios/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon@3x.png
ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-20@2x.png
ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-20@2x~ipad.png
ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-20@3x.png
ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-20~ipad.png
ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29.png
ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29@2x.png
ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29@2x~ipad.png
ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29@3x.png
ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29~ipad.png
ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-40@2x.png
ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-40@2x~ipad.png
ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-40@3x.png
ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-40~ipad.png
ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-60@2x~car.png
ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-60@3x~car.png
ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5@2x~ipad.png
ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon~ios-marketing.png
ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon~ipad.png
ios/Runner/Info.plist ios/Runner/Info.plist
android/app/src/main/res/mipmap-* android/app/src/main/res/mipmap-*
android/app/src/main/res/drawable/ic_launcher.png android/app/src/main/res/drawable/ic_launcher.png

View file

@ -26,10 +26,13 @@ Cake Wallet includes support for several cryptocurrencies, including:
* Ethereum (ETH) * Ethereum (ETH)
* Litecoin (LTC) * Litecoin (LTC)
* Bitcoin Cash (BCH) * Bitcoin Cash (BCH)
* Polygon (Pol) * Polygon (POL)
* Solana (SOL) * Solana (SOL)
* Tron (TRX)
* Nano (XNO) * Nano (XNO)
* Haven (XHV) * Zano (ZANO)
* Decred (DCR)
* Wownero (WOW)
## Features ## Features
@ -81,10 +84,6 @@ Cake Wallet includes support for several cryptocurrencies, including:
* Automatically generate new addresses * Automatically generate new addresses
* Specify multiple recipients for batch sending * Specify multiple recipients for batch sending
### Haven Specific Features
* Send, receive, and store XHV and all xAssets like xUSD, xEUR, xAG, etc.
# Monero.com by Cake Wallet for Android and iOS # Monero.com by Cake Wallet for Android and iOS
## Open Source Monero-Only Wallet ## Open Source Monero-Only Wallet

View file

@ -107,6 +107,9 @@
<meta-data <meta-data
android:name="flutterEmbedding" android:name="flutterEmbedding"
android:value="2" /> android:value="2" />
<meta-data
android:name="io.flutter.embedding.android.EnableImpeller"
android:value="false" />
<provider <provider
android:name="com.pichillilorenzo.flutter_inappwebview_android.InAppWebViewFileProvider" android:name="com.pichillilorenzo.flutter_inappwebview_android.InAppWebViewFileProvider"
android:authorities="${applicationId}.flutter_inappwebview_android.fileprovider" android:authorities="${applicationId}.flutter_inappwebview_android.fileprovider"

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 591 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1,019 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1,019 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 688 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

After

Width:  |  Height:  |  Size: 206 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 7 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 678 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Before After
Before After

View file

@ -13,9 +13,3 @@
- -
uri: nodes.hashvault.pro:18081 uri: nodes.hashvault.pro:18081
is_default: false is_default: false
-
uri: node.c3pool.com:18081
is_default: false
-
uri: node.community.rino.io:18081
is_default: false

View file

@ -1,5 +1,3 @@
Add background sync to Monero UI/UX enhancements
Enhance Backup files Performance improvements
Improve app usability and user experience
User interface enhancements
Bug fixes Bug fixes

View file

@ -1,8 +1,4 @@
Add background sync to Monero New App Logo
Add Decred Wallet UI/UX enhancements
Remove Haven Wallet Performance improvements
Fix and Improve Solana Wallet
Enhance Backup files
Improve app usability and user experience
User interface enhancements
Bug fixes Bug fixes

View file

@ -26,7 +26,7 @@ modules:
- "cp com.cakewallet.CakeWallet.desktop /app/share/applications" - "cp com.cakewallet.CakeWallet.desktop /app/share/applications"
sources: sources:
- type: dir - type: dir
path: build/linux/current/release path: build/linux/x64/release
- type: file - type: file
path: assets/images/cakewallet_icon_180.png path: assets/images/cakewallet_icon_180.png
- type: file - type: file

View file

@ -17,11 +17,11 @@ class Erc20Token extends CryptoCurrency with HiveObjectMixin {
@HiveField(4, defaultValue: true) @HiveField(4, defaultValue: true)
bool _enabled; bool _enabled;
@HiveField(5) @HiveField(5)
final String? iconPath; String? iconPath;
@HiveField(6) @HiveField(6)
final String? tag; final String? tag;
@HiveField(7, defaultValue: false) @HiveField(7, defaultValue: false)
final bool isPotentialScam; bool isPotentialScam;
bool get enabled => _enabled; bool get enabled => _enabled;

View file

@ -28,4 +28,9 @@ class Unspent with UnspentComparable {
bool get isP2wpkh => bool get isP2wpkh =>
address.startsWith('bc') || address.startsWith('tb') || address.startsWith('ltc'); address.startsWith('bc') || address.startsWith('tb') || address.startsWith('ltc');
@override
String toString() {
return 'Unspent(address: $address, hash: $hash, value: $value, vout: $vout, keyImage: $keyImage, isSending: $isSending, isFrozen: $isFrozen, isChange: $isChange, note: $note)';
}
} }

View file

@ -193,7 +193,7 @@ String walletTypeToDisplayName(WalletType type) {
case WalletType.banano: case WalletType.banano:
return 'Banano (BAN)'; return 'Banano (BAN)';
case WalletType.polygon: case WalletType.polygon:
return 'Polygon (MATIC)'; return 'Polygon (POL)';
case WalletType.solana: case WalletType.solana:
return 'Solana (SOL)'; return 'Solana (SOL)';
case WalletType.tron: case WalletType.tron:

View file

@ -4,6 +4,7 @@ import 'dart:io';
import 'package:cw_core/exceptions.dart'; import 'package:cw_core/exceptions.dart';
import 'package:cw_core/transaction_direction.dart'; import 'package:cw_core/transaction_direction.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_decred/amount_format.dart';
import 'package:cw_decred/pending_transaction.dart'; import 'package:cw_decred/pending_transaction.dart';
import 'package:cw_decred/transaction_credentials.dart'; import 'package:cw_decred/transaction_credentials.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
@ -122,6 +123,9 @@ abstract class DecredWalletBase extends WalletBase<DecredBalance, DecredTransact
return _pubkey; return _pubkey;
} }
@override
String formatCryptoAmount(String amount) => decredAmountToString(amount: int.parse(amount));
Future<void> init() async { Future<void> init() async {
final getSeed = () async { final getSeed = () async {
if (!watchingOnly) { if (!watchingOnly) {

View file

@ -76,9 +76,13 @@ class EthereumWallet extends EVMChainWallet {
await erc20TokensBox.deleteFromDisk(); await erc20TokensBox.deleteFromDisk();
// Add all the previous tokens with configs to the new box // Add all the previous tokens with configs to the new box
evmChainErc20TokensBox.addAll(allValues); await evmChainErc20TokensBox.addAll(allValues);
} }
@override
List<String> get getDefaultTokenContractAddresses =>
DefaultEthereumErc20Tokens().initialErc20Tokens.map((e) => e.contractAddress).toList();
@override @override
EVMChainTransactionInfo getTransactionInfo( EVMChainTransactionInfo getTransactionInfo(
EVMChainTransactionModel transactionModel, String address) { EVMChainTransactionModel transactionModel, String address) {

View file

@ -146,6 +146,8 @@ abstract class EVMChainWalletBase extends WalletBase<
// required WalletInfo walletInfo, // required WalletInfo walletInfo,
// }); // });
List<String> get getDefaultTokenContractAddresses;
Future<void> initErc20TokensBox(); Future<void> initErc20TokensBox();
String getTransactionHistoryFileName(); String getTransactionHistoryFileName();
@ -173,6 +175,9 @@ abstract class EVMChainWalletBase extends WalletBase<
await walletAddresses.init(); await walletAddresses.init();
await transactionHistory.init(); await transactionHistory.init();
// check for Already existing scam tokens, cuz users can get scammed twice ¯\_()_/¯
await _checkForExistingScamTokens();
if (walletInfo.isHardwareWallet) { if (walletInfo.isHardwareWallet) {
_evmChainPrivateKey = EvmLedgerCredentials(walletInfo.address); _evmChainPrivateKey = EvmLedgerCredentials(walletInfo.address);
walletAddresses.address = walletInfo.address; walletAddresses.address = walletInfo.address;
@ -188,6 +193,31 @@ abstract class EVMChainWalletBase extends WalletBase<
await save(); await save();
} }
Future<void> _checkForExistingScamTokens() async {
final baseCurrencySymbols = CryptoCurrency.all.map((e) => e.title.toUpperCase()).toList();
for (var token in erc20Currencies) {
bool isPotentialScam = false;
bool isWhitelisted =
getDefaultTokenContractAddresses.any((element) => element == token.contractAddress);
final tokenSymbol = token.title.toUpperCase();
// check if the token symbol is the same as any of the base currencies symbols (ETH, SOL, POL, TRX, etc):
// if it is, then it's probably a scam unless it's in the whitelist
if (baseCurrencySymbols.contains(tokenSymbol.trim().toUpperCase()) && !isWhitelisted) {
isPotentialScam = true;
}
if (isPotentialScam) {
token.isPotentialScam = true;
token.iconPath = null;
await token.save();
}
}
}
@override @override
Future<int> calculateEstimatedFee(TransactionPriority priority) async { Future<int> calculateEstimatedFee(TransactionPriority priority) async {
{ {

View file

@ -4,21 +4,32 @@ import 'package:cw_monero/api/coins_info.dart';
import 'package:monero/monero.dart' as monero; import 'package:monero/monero.dart' as monero;
class MoneroUnspent extends Unspent { class MoneroUnspent extends Unspent {
static Future<MoneroUnspent> fromUnspent(String address, String hash, String keyImage, int value, bool isFrozen, bool isUnlocked) async {
return MoneroUnspent(
address: address,
hash: hash,
keyImage: keyImage,
value: value,
isFrozen: isFrozen,
isUnlocked: isUnlocked);
}
MoneroUnspent( MoneroUnspent(
String address, String hash, String keyImage, int value, bool isFrozen, this.isUnlocked) {required String address,
required String hash,
required String keyImage,
required int value,
required bool isFrozen,
required this.isUnlocked})
: super(address, hash, value, 0, keyImage) { : super(address, hash, value, 0, keyImage) {
getCoinByKeyImage(keyImage).then((coinId) { _frozen = isFrozen;
if (coinId == null) return;
getCoin(coinId).then((coin) {
_frozen = monero.CoinsInfo_frozen(coin);
});
});
} }
bool _frozen = false; bool _frozen = false;
@override @override
set isFrozen(bool freeze) { set isFrozen(bool freeze) {
_frozen = freeze;
printV("set isFrozen: $freeze ($keyImage): $freeze"); printV("set isFrozen: $freeze ($keyImage): $freeze");
getCoinByKeyImage(keyImage!).then((coinId) async { getCoinByKeyImage(keyImage!).then((coinId) async {
if (coinId == null) return; if (coinId == null) return;

View file

@ -592,7 +592,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance, MoneroTransact
final coin = await getCoin(i); final coin = await getCoin(i);
final coinSpent = monero.CoinsInfo_spent(coin); final coinSpent = monero.CoinsInfo_spent(coin);
if (coinSpent == false && monero.CoinsInfo_subaddrAccount(coin) == walletAddresses.account!.id) { if (coinSpent == false && monero.CoinsInfo_subaddrAccount(coin) == walletAddresses.account!.id) {
final unspent = MoneroUnspent( final unspent = await MoneroUnspent.fromUnspent(
monero.CoinsInfo_address(coin), monero.CoinsInfo_address(coin),
monero.CoinsInfo_hash(coin), monero.CoinsInfo_hash(coin),
monero.CoinsInfo_keyImage(coin), monero.CoinsInfo_keyImage(coin),

View file

@ -49,6 +49,10 @@ class PolygonWallet extends EVMChainWallet {
} }
} }
@override
List<String> get getDefaultTokenContractAddresses =>
DefaultPolygonErc20Tokens().initialPolygonErc20Tokens.map((e) => e.contractAddress).toList();
@override @override
Future<bool> checkIfScanProviderIsEnabled() async { Future<bool> checkIfScanProviderIsEnabled() async {
bool isPolygonScanEnabled = (await sharedPrefs.future).getBool("use_polygonscan") ?? true; bool isPolygonScanEnabled = (await sharedPrefs.future).getBool("use_polygonscan") ?? true;

View file

@ -1,114 +1,134 @@
{ {
"images" : [ "images": [
{ {
"filename" : "Icon-App-40x40@1x.png", "filename": "AppIcon@2x.png",
"idiom" : "iphone", "idiom": "iphone",
"scale" : "2x", "scale": "2x",
"size" : "20x20" "size": "60x60"
}, },
{ {
"filename" : "Icon-App-20x20@3x.png", "filename": "AppIcon@3x.png",
"idiom" : "iphone", "idiom": "iphone",
"scale" : "3x", "scale": "3x",
"size" : "20x20" "size": "60x60"
}, },
{ {
"filename" : "Icon-App-29x29@2x 1.png", "filename": "AppIcon~ipad.png",
"idiom" : "iphone", "idiom": "ipad",
"scale" : "2x", "scale": "1x",
"size" : "29x29" "size": "76x76"
}, },
{ {
"filename" : "Icon-App-29x29@3x.png", "filename": "AppIcon@2x~ipad.png",
"idiom" : "iphone", "idiom": "ipad",
"scale" : "3x", "scale": "2x",
"size" : "29x29" "size": "76x76"
}, },
{ {
"idiom" : "iphone", "filename": "AppIcon-83.5@2x~ipad.png",
"scale" : "2x", "idiom": "ipad",
"size" : "40x40" "scale": "2x",
"size": "83.5x83.5"
}, },
{ {
"filename" : "Icon-App-40x40@3x.png", "filename": "AppIcon-40@2x.png",
"idiom" : "iphone", "idiom": "iphone",
"scale" : "3x", "scale": "2x",
"size" : "40x40" "size": "40x40"
}, },
{ {
"filename" : "app_icon_120.png", "filename": "AppIcon-40@3x.png",
"idiom" : "iphone", "idiom": "iphone",
"scale" : "2x", "scale": "3x",
"size" : "60x60" "size": "40x40"
}, },
{ {
"filename" : "app_icon_180.png", "filename": "AppIcon-40~ipad.png",
"idiom" : "iphone", "idiom": "ipad",
"scale" : "3x", "scale": "1x",
"size" : "60x60" "size": "40x40"
}, },
{ {
"filename" : "Icon-App-20x20@1x.png", "filename": "AppIcon-40@2x~ipad.png",
"idiom" : "ipad", "idiom": "ipad",
"scale" : "1x", "scale": "2x",
"size" : "20x20" "size": "40x40"
}, },
{ {
"filename" : "Icon-App-20x20@2x.png", "filename": "AppIcon-20@2x.png",
"idiom" : "ipad", "idiom": "iphone",
"scale" : "2x", "scale": "2x",
"size" : "20x20" "size": "20x20"
}, },
{ {
"filename" : "Icon-App-29x29@1x.png", "filename": "AppIcon-20@3x.png",
"idiom" : "ipad", "idiom": "iphone",
"scale" : "1x", "scale": "3x",
"size" : "29x29" "size": "20x20"
}, },
{ {
"filename" : "Icon-App-29x29@2x.png", "filename": "AppIcon-20~ipad.png",
"idiom" : "ipad", "idiom": "ipad",
"scale" : "2x", "scale": "1x",
"size" : "29x29" "size": "20x20"
}, },
{ {
"filename" : "Icon-App-40x40@1x 1.png", "filename": "AppIcon-20@2x~ipad.png",
"idiom" : "ipad", "idiom": "ipad",
"scale" : "1x", "scale": "2x",
"size" : "40x40" "size": "20x20"
}, },
{ {
"idiom" : "ipad", "filename": "AppIcon-29.png",
"scale" : "2x", "idiom": "iphone",
"size" : "40x40" "scale": "1x",
"size": "29x29"
}, },
{ {
"filename" : "Icon-App-76x76@1x.png", "filename": "AppIcon-29@2x.png",
"idiom" : "ipad", "idiom": "iphone",
"scale" : "1x", "scale": "2x",
"size" : "76x76" "size": "29x29"
}, },
{ {
"filename" : "Icon-App-76x76@2x.png", "filename": "AppIcon-29@3x.png",
"idiom" : "ipad", "idiom": "iphone",
"scale" : "2x", "scale": "3x",
"size" : "76x76" "size": "29x29"
}, },
{ {
"filename" : "Icon-App-83.5x83.5@2x.png", "filename": "AppIcon-29~ipad.png",
"idiom" : "ipad", "idiom": "ipad",
"scale" : "2x", "scale": "1x",
"size" : "83.5x83.5" "size": "29x29"
}, },
{ {
"filename" : "app_icon_1024.png", "filename": "AppIcon-29@2x~ipad.png",
"idiom" : "ios-marketing", "idiom": "ipad",
"scale" : "1x", "scale": "2x",
"size" : "1024x1024" "size": "29x29"
},
{
"filename": "AppIcon-60@2x~car.png",
"idiom": "car",
"scale": "2x",
"size": "60x60"
},
{
"filename": "AppIcon-60@3x~car.png",
"idiom": "car",
"scale": "3x",
"size": "60x60"
},
{
"filename": "AppIcon~ios-marketing.png",
"idiom": "ios-marketing",
"scale": "1x",
"size": "1024x1024"
} }
], ],
"info" : { "info": {
"author" : "xcode", "author": "iconkitchen",
"version" : 1 "version": 1
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 880 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

View file

@ -6,7 +6,6 @@ import 'package:cake_wallet/buy/moonpay/moonpay_provider.dart';
import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart'; import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart';
import 'package:cake_wallet/buy/robinhood/robinhood_buy_provider.dart'; import 'package:cake_wallet/buy/robinhood/robinhood_buy_provider.dart';
import 'package:cake_wallet/di.dart'; import 'package:cake_wallet/di.dart';
import 'package:cw_core/wallet_type.dart';
enum ProviderType { robinhood, dfx, onramper, moonpay, meld, kriptonim } enum ProviderType { robinhood, dfx, onramper, moonpay, meld, kriptonim }
@ -47,7 +46,7 @@ extension ProviderTypeName on ProviderType {
} }
class ProvidersHelper { class ProvidersHelper {
static List<ProviderType> getAvailableBuyProviderTypes(WalletType walletType) => [ static List<ProviderType> getAvailableBuyProviderTypes() => [
ProviderType.robinhood, ProviderType.robinhood,
ProviderType.dfx, ProviderType.dfx,
ProviderType.onramper, ProviderType.onramper,
@ -55,7 +54,7 @@ class ProvidersHelper {
ProviderType.kriptonim ProviderType.kriptonim
]; ];
static List<ProviderType> getAvailableSellProviderTypes(WalletType walletType) => [ static List<ProviderType> getAvailableSellProviderTypes() => [
ProviderType.robinhood, ProviderType.robinhood,
ProviderType.dfx, ProviderType.dfx,
ProviderType.onramper, ProviderType.onramper,
@ -63,7 +62,7 @@ class ProvidersHelper {
ProviderType.kriptonim ProviderType.kriptonim
]; ];
static BuyProvider? getProviderByType(ProviderType type) { static BuyProvider getProviderByType(ProviderType type) {
switch (type) { switch (type) {
case ProviderType.robinhood: case ProviderType.robinhood:
return getIt.get<RobinhoodBuyProvider>(); return getIt.get<RobinhoodBuyProvider>();
@ -77,8 +76,6 @@ class ProvidersHelper {
return getIt.get<MeldBuyProvider>(); return getIt.get<MeldBuyProvider>();
case ProviderType.kriptonim: case ProviderType.kriptonim:
return getIt.get<KryptonimBuyProvider>(); return getIt.get<KryptonimBuyProvider>();
default: }
return null;
}
} }
} }

View file

@ -139,6 +139,7 @@ class BackupPage extends BasePage {
await backupViewModelBase.saveToDownload( await backupViewModelBase.saveToDownload(
backup.name, backup.file); backup.name, backup.file);
Navigator.of(dialogContext).pop(); Navigator.of(dialogContext).pop();
await showBar<void>(context, S.of(context).file_saved);
}, },
actionLeftButton: () async { actionLeftButton: () async {
Navigator.of(dialogContext).pop(); Navigator.of(dialogContext).pop();

View file

@ -1,5 +1,4 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/utils/show_pop_up.dart';
@ -68,7 +67,9 @@ class EditBackupPasswordPage extends BasePage {
actionRightButton: () async { actionRightButton: () async {
await editBackupPasswordViewModel.save(); await editBackupPasswordViewModel.save();
Navigator.of(dialogContext).pop(); Navigator.of(dialogContext).pop();
Navigator.of(context).pop(); if (context.mounted) {
Navigator.of(context).pop();
}
}, },
actionLeftButton: () => Navigator.of(dialogContext).pop()); actionLeftButton: () => Navigator.of(dialogContext).pop());
}); });

View file

@ -162,7 +162,7 @@ class AddressPage extends BasePage {
} }
reaction((_) => receiveOptionViewModel.selectedReceiveOption, (ReceivePageOption option) { reaction((_) => receiveOptionViewModel.selectedReceiveOption, (ReceivePageOption option) {
if (bitcoin!.isBitcoinReceivePageOption(option)) { if (dashboardViewModel.type == WalletType.bitcoin && bitcoin!.isBitcoinReceivePageOption(option)) {
addressListViewModel.setAddressType(bitcoin!.getOptionToType(option)); addressListViewModel.setAddressType(bitcoin!.getOptionToType(option));
return; return;
} }

View file

@ -32,7 +32,7 @@ class NavigationDock extends StatelessWidget {
), ),
), ),
child: Container( child: Container(
margin: const EdgeInsets.only(left: 16, right: 16, bottom: 16), margin: const EdgeInsets.only(left: 8, right: 8, bottom: 16),
child: ClipRRect( child: ClipRRect(
borderRadius: BorderRadius.circular(50), borderRadius: BorderRadius.circular(50),
child: BackdropFilter( child: BackdropFilter(
@ -48,7 +48,7 @@ class NavigationDock extends StatelessWidget {
Theme.of(context).extension<SyncIndicatorTheme>()!.syncedBackgroundColor, Theme.of(context).extension<SyncIndicatorTheme>()!.syncedBackgroundColor,
), ),
child: Container( child: Container(
padding: EdgeInsets.symmetric(horizontal: 10), padding: EdgeInsets.symmetric(horizontal: 8),
child: IntrinsicHeight( child: IntrinsicHeight(
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,

View file

@ -45,20 +45,17 @@ class TransactionsPage extends StatelessWidget {
Observer(builder: (_) { Observer(builder: (_) {
final status = dashboardViewModel.status; final status = dashboardViewModel.status;
if (status is SyncingSyncStatus) { if (status is SyncingSyncStatus) {
return Padding( return DashBoardRoundedCardWidget(
padding: const EdgeInsets.fromLTRB(24, 0, 24, 8), key: ValueKey('transactions_page_syncing_alert_card_key'),
child: DashBoardRoundedCardWidget( onTap: () {
key: ValueKey('transactions_page_syncing_alert_card_key'), try {
onTap: () { final uri = Uri.parse(
try { "https://docs.cakewallet.com/faq/funds-not-appearing");
final uri = Uri.parse( launchUrl(uri, mode: LaunchMode.externalApplication);
"https://docs.cakewallet.com/faq/funds-not-appearing"); } catch (_) {}
launchUrl(uri, mode: LaunchMode.externalApplication); },
} catch (_) {} title: S.of(context).syncing_wallet_alert_title,
}, subTitle: S.of(context).syncing_wallet_alert_content,
title: S.of(context).syncing_wallet_alert_title,
subTitle: S.of(context).syncing_wallet_alert_content,
),
); );
} else { } else {
return Container(); return Container();
@ -72,7 +69,6 @@ class TransactionsPage extends StatelessWidget {
child: Observer( child: Observer(
builder: (_) { builder: (_) {
final items = dashboardViewModel.items; final items = dashboardViewModel.items;
final amount = items.length + 1;
return items.isNotEmpty return items.isNotEmpty
? ListView.builder( ? ListView.builder(
key: ValueKey('transactions_page_list_view_builder_key'), key: ValueKey('transactions_page_list_view_builder_key'),

View file

@ -47,6 +47,8 @@ class ActionButton extends StatelessWidget {
SizedBox(height: 4), SizedBox(height: 4),
Text( Text(
title, title,
maxLines: 1,
overflow: TextOverflow.visible,
style: TextStyle( style: TextStyle(
fontSize: 9, fontSize: 9,
color: textColor ?? color: textColor ??

View file

@ -182,7 +182,9 @@ class NodeCreateOrEditPage extends BasePage {
await nodeCreateOrEditViewModel.save( await nodeCreateOrEditViewModel.save(
editingNode: editingNode, saveAsCurrent: isSelected ?? false); editingNode: editingNode, saveAsCurrent: isSelected ?? false);
Navigator.of(context).pop(); if (context.mounted) {
Navigator.of(context).pop();
}
}, },
text: S.of(context).save, text: S.of(context).save,
color: Theme.of(context).primaryColor, color: Theme.of(context).primaryColor,

View file

@ -98,7 +98,7 @@ class SendPage extends BasePage {
return MergeSemantics( return MergeSemantics(
child: SizedBox( child: SizedBox(
height: isMobileView ? 37 : 45, height: isMobileView ? 37 : 45,
width: isMobileView ? 47: 45, width: isMobileView ? 47 : 45,
child: ButtonTheme( child: ButtonTheme(
minWidth: double.minPositive, minWidth: double.minPositive,
child: Semantics( child: Semantics(
@ -397,7 +397,6 @@ class SendPage extends BasePage {
return LoadingPrimaryButton( return LoadingPrimaryButton(
key: ValueKey('send_page_send_button_key'), key: ValueKey('send_page_send_button_key'),
onPressed: () async { onPressed: () async {
//Request dummy node to get the focus out of the text fields //Request dummy node to get the focus out of the text fields
FocusScope.of(context).requestFocus(FocusNode()); FocusScope.of(context).requestFocus(FocusNode());
@ -507,7 +506,6 @@ class SendPage extends BasePage {
Navigator.of(loadingBottomSheetContext!).pop(); Navigator.of(loadingBottomSheetContext!).pop();
} }
if (state is FailureState) { if (state is FailureState) {
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
showPopUp<void>( showPopUp<void>(
@ -525,7 +523,6 @@ class SendPage extends BasePage {
} }
if (state is IsExecutingState) { if (state is IsExecutingState) {
// wait a bit to avoid showing the loading dialog if transaction is failed // wait a bit to avoid showing the loading dialog if transaction is failed
await Future.delayed(const Duration(milliseconds: 300)); await Future.delayed(const Duration(milliseconds: 300));
final currentState = sendViewModel.state; final currentState = sendViewModel.state;
@ -584,8 +581,6 @@ class SendPage extends BasePage {
}); });
} }
if (state is TransactionCommitted) { if (state is TransactionCommitted) {
WidgetsBinding.instance.addPostFrameCallback((_) async { WidgetsBinding.instance.addPostFrameCallback((_) async {
if (!context.mounted) { if (!context.mounted) {
@ -594,7 +589,8 @@ class SendPage extends BasePage {
newContactAddress = newContactAddress ?? sendViewModel.newContactAddress(); newContactAddress = newContactAddress ?? sendViewModel.newContactAddress();
if (newContactAddress?.address != null && isRegularElectrumAddress(newContactAddress!.address)) { if (newContactAddress?.address != null &&
isRegularElectrumAddress(newContactAddress!.address)) {
newContactAddress = null; newContactAddress = null;
} }
@ -606,47 +602,53 @@ class SendPage extends BasePage {
builder: (BuildContext bottomSheetContext) { builder: (BuildContext bottomSheetContext) {
return showContactSheet return showContactSheet
? InfoBottomSheet( ? InfoBottomSheet(
currentTheme: currentTheme, currentTheme: currentTheme,
showDontAskMeCheckbox: true, showDontAskMeCheckbox: true,
onCheckboxChanged: (value) => sendViewModel.setShowAddressBookPopup(!value), onCheckboxChanged: (value) => sendViewModel.setShowAddressBookPopup(!value),
titleText: S.of(bottomSheetContext).transaction_sent, titleText: S.of(bottomSheetContext).transaction_sent,
contentImage: 'assets/images/contact_icon.svg', contentImage: 'assets/images/contact_icon.svg',
contentImageColor: Theme.of(context) contentImageColor: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
.extension<CakeTextTheme>()! content: S.of(bottomSheetContext).add_contact_to_address_book,
.titleColor, isTwoAction: true,
content: S.of(bottomSheetContext).add_contact_to_address_book, leftButtonText: 'No',
isTwoAction: true, rightButtonText: 'Yes',
leftButtonText: 'No', actionLeftButton: () {
rightButtonText: 'Yes', Navigator.of(bottomSheetContext).pop();
actionLeftButton: () { if (context.mounted) {
Navigator.of(bottomSheetContext).pop(); Navigator.of(context)
Navigator.of(context) .pushNamedAndRemoveUntil(Routes.dashboard, (route) => false);
.pushNamedAndRemoveUntil(Routes.dashboard, (route) => false); }
RequestReviewHandler.requestReview(); RequestReviewHandler.requestReview();
newContactAddress = null; newContactAddress = null;
}, },
actionRightButton: () { actionRightButton: () {
Navigator.of(bottomSheetContext).pop(); Navigator.of(bottomSheetContext).pop();
RequestReviewHandler.requestReview(); RequestReviewHandler.requestReview();
Navigator.of(context) if (context.mounted) {
.pushNamed(Routes.addressBookAddContact, arguments: newContactAddress); Navigator.of(context).pushNamed(Routes.addressBookAddContact,
newContactAddress = null; arguments: newContactAddress);
}, }
) newContactAddress = null;
},
)
: InfoBottomSheet( : InfoBottomSheet(
currentTheme: currentTheme, currentTheme: currentTheme,
titleText: S.of(bottomSheetContext).transaction_sent, titleText: S.of(bottomSheetContext).transaction_sent,
contentImage: 'assets/images/birthday_cake.svg', contentImage: 'assets/images/birthday_cake.svg',
actionButtonText: S.of(bottomSheetContext).close, actionButtonText: S.of(bottomSheetContext).close,
actionButtonKey: ValueKey('send_page_sent_dialog_ok_button_key'), actionButtonKey: ValueKey('send_page_sent_dialog_ok_button_key'),
actionButton: () { actionButton: () {
Navigator.of(bottomSheetContext).pop(); Navigator.of(bottomSheetContext).pop();
Navigator.of(context) Future.delayed(Duration.zero, () {
.pushNamedAndRemoveUntil(Routes.dashboard, (route) => false); if (context.mounted) {
RequestReviewHandler.requestReview(); Navigator.of(context)
newContactAddress = null; .pushNamedAndRemoveUntil(Routes.dashboard, (route) => false);
}, }
); RequestReviewHandler.requestReview();
newContactAddress = null;
});
},
);
}, },
); );
@ -678,8 +680,7 @@ class SendPage extends BasePage {
currentTheme: currentTheme, currentTheme: currentTheme,
titleText: S.of(bottomSheetContext).proceed_on_device, titleText: S.of(bottomSheetContext).proceed_on_device,
contentImage: 'assets/images/hardware_wallet/ledger_nano_x.png', contentImage: 'assets/images/hardware_wallet/ledger_nano_x.png',
contentImageColor: contentImageColor: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
Theme.of(context).extension<CakeTextTheme>()!.titleColor,
content: S.of(bottomSheetContext).proceed_on_device_description, content: S.of(bottomSheetContext).proceed_on_device_description,
isTwoAction: false, isTwoAction: false,
actionButtonText: S.of(context).cancel, actionButtonText: S.of(context).cancel,
@ -778,5 +779,4 @@ class SendPage extends BasePage {
return isValid; return isValid;
} }
} }

View file

@ -90,6 +90,9 @@ class SendCardState extends State<SendCard> with AutomaticKeepAliveClientMixin<S
@override @override
void initState() { void initState() {
super.initState(); super.initState();
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
sendViewModel.updateSendingBalance();
});
/// if the current wallet doesn't match the one in the qr code /// if the current wallet doesn't match the one in the qr code
if (initialPaymentRequest != null && if (initialPaymentRequest != null &&
@ -240,38 +243,47 @@ class SendCardState extends State<SendCard> with AutomaticKeepAliveClientMixin<S
currencyValueValidator: output.sendAll currencyValueValidator: output.sendAll
? sendViewModel.allAmountValidator ? sendViewModel.allAmountValidator
: sendViewModel.amountValidator, : sendViewModel.amountValidator,
allAmountCallback: () async => output.setSendAll(sendViewModel.sendingBalance)), allAmountCallback: () async => output.setSendAll(await sendViewModel.sendingBalance)),
Divider( Divider(
height: 1, height: 1,
color: Theme.of(context).extension<SendPageTheme>()!.textFieldHintColor), color: Theme.of(context).extension<SendPageTheme>()!.textFieldHintColor),
Observer( Observer(
builder: (_) => Padding( builder: (_) {
padding: EdgeInsets.only(top: 10), // force rebuild on mobx
child: Row( final _ = sendViewModel.coinTypeToSpendFrom;
mainAxisSize: MainAxisSize.max, return Padding(
mainAxisAlignment: MainAxisAlignment.spaceBetween, padding: EdgeInsets.only(top: 10),
children: <Widget>[ child: Row(
Expanded( mainAxisSize: MainAxisSize.max,
child: Text( mainAxisAlignment: MainAxisAlignment.spaceBetween,
S.of(context).available_balance + ':', children: <Widget>[
style: TextStyle( Expanded(
child: Text(
S.of(context).available_balance + ':',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color:
Theme.of(context).extension<SendPageTheme>()!.textFieldHintColor),
),
),
FutureBuilder<String>(
future: sendViewModel.sendingBalance,
builder: (context, snapshot) {
return Text(
snapshot.data ?? sendViewModel.balance, // default to balance while loading
style: TextStyle(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
color: color:
Theme.of(context).extension<SendPageTheme>()!.textFieldHintColor), Theme.of(context).extension<SendPageTheme>()!.textFieldHintColor),
), );
), },
Text( )
sendViewModel.sendingBalance, ],
style: TextStyle( ),
fontSize: 12, );
fontWeight: FontWeight.w600, },
color:
Theme.of(context).extension<SendPageTheme>()!.textFieldHintColor),
)
],
),
),
), ),
if (!sendViewModel.isFiatDisabled) if (!sendViewModel.isFiatDisabled)
CurrencyAmountTextField( CurrencyAmountTextField(
@ -523,9 +535,9 @@ class SendCardState extends State<SendCard> with AutomaticKeepAliveClientMixin<S
} }
}); });
reaction((_) => sendViewModel.selectedCryptoCurrency, (Currency currency) { reaction((_) => sendViewModel.selectedCryptoCurrency, (Currency currency) async {
if (output.sendAll) { if (output.sendAll) {
output.setSendAll(sendViewModel.sendingBalance); output.setSendAll(await sendViewModel.sendingBalance);
} }
output.setCryptoAmount(cryptoAmountController.text); output.setCryptoAmount(cryptoAmountController.text);

View file

@ -101,7 +101,7 @@ class WCCDetailsWidget extends BasePage {
child: CircleAvatar( child: CircleAvatar(
backgroundImage: (pairing.peerMetadata!.icons.isNotEmpty backgroundImage: (pairing.peerMetadata!.icons.isNotEmpty
? NetworkImage(pairing.peerMetadata!.icons[0]) ? NetworkImage(pairing.peerMetadata!.icons[0])
: const AssetImage('assets/images/default_icon.png')) : const AssetImage('assets/images/app_logo.png'))
as ImageProvider<Object>, as ImageProvider<Object>,
), ),
), ),

View file

@ -15,7 +15,6 @@ import 'package:cake_wallet/store/app_store.dart';
import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/themes/theme_base.dart'; import 'package:cake_wallet/themes/theme_base.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/currency_for_wallet_type.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
@ -61,21 +60,17 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S
late Timer bestRateSync; late Timer bestRateSync;
List<BuyProvider> get availableBuyProviders { List<BuyProvider> get availableBuyProviders {
final providerTypes = ProvidersHelper.getAvailableBuyProviderTypes( final providerTypes = ProvidersHelper.getAvailableBuyProviderTypes();
walletTypeForCurrency(cryptoCurrency) ?? wallet.type);
return providerTypes return providerTypes
.map((type) => ProvidersHelper.getProviderByType(type)) .map((type) => ProvidersHelper.getProviderByType(type))
.where((provider) => provider != null)
.cast<BuyProvider>() .cast<BuyProvider>()
.toList(); .toList();
} }
List<BuyProvider> get availableSellProviders { List<BuyProvider> get availableSellProviders {
final providerTypes = ProvidersHelper.getAvailableSellProviderTypes( final providerTypes = ProvidersHelper.getAvailableSellProviderTypes();
walletTypeForCurrency(cryptoCurrency) ?? wallet.type);
return providerTypes return providerTypes
.map((type) => ProvidersHelper.getProviderByType(type)) .map((type) => ProvidersHelper.getProviderByType(type))
.where((provider) => provider != null)
.cast<BuyProvider>() .cast<BuyProvider>()
.toList(); .toList();
} }

View file

@ -245,7 +245,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
} }
@computed @computed
String get sendingBalance { Future<String> get sendingBalance async {
// only for electrum, monero, wownero, decred wallets atm: // only for electrum, monero, wownero, decred wallets atm:
switch (wallet.type) { switch (wallet.type) {
case WalletType.bitcoin: case WalletType.bitcoin:
@ -255,7 +255,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
case WalletType.wownero: case WalletType.wownero:
case WalletType.decred: case WalletType.decred:
return wallet.formatCryptoAmount( return wallet.formatCryptoAmount(
unspentCoinsListViewModel.getSendingBalance(coinTypeToSpendFrom).toString()); (await unspentCoinsListViewModel.getSendingBalance(coinTypeToSpendFrom)).toString());
default: default:
return balance; return balance;
} }

View file

@ -149,12 +149,15 @@ abstract class UnspentCoinsListViewModelBase with Store {
} }
@action @action
int getSendingBalance(UnspentCoinType overrideCoinTypeToSpendFrom) { Future<int> getSendingBalance(UnspentCoinType overrideCoinTypeToSpendFrom) async {
// return items.where((element) => element.isSending).fold(0, (previousValue, element) => previousValue + element.value); // return items.where((element) => element.isSending).fold(0, (previousValue, element) => previousValue + element.value);
// go through all unspent coins and add up the value minus frozen and non sending: // go through all unspent coins and add up the value minus frozen and non sending:
int total = 0; int total = 0;
await _updateUnspents();
Set<String> seen = {};
for (final item in _getSpecificUnspents(overrideCoinTypeToSpendFrom)) { for (final item in _getSpecificUnspents(overrideCoinTypeToSpendFrom)) {
if (seen.contains(item.toString())) continue;
seen.add(item.toString());
if (item.isFrozen || !item.isSending) continue; if (item.isFrozen || !item.isSending) continue;
total += item.value; total += item.value;
} }
@ -163,8 +166,6 @@ abstract class UnspentCoinsListViewModelBase with Store {
@action @action
void _updateUnspentCoinsInfo() { void _updateUnspentCoinsInfo() {
items.clear();
final unspents = _getUnspents() final unspents = _getUnspents()
.map((elem) { .map((elem) {
try { try {
@ -198,7 +199,7 @@ abstract class UnspentCoinsListViewModelBase with Store {
.toList(); .toList();
unspents.sort((a, b) => b.value.compareTo(a.value)); unspents.sort((a, b) => b.value.compareTo(a.value));
items.clear();
items.addAll(unspents); items.addAll(unspents);
} }

View file

@ -333,6 +333,7 @@
"fiat_api": "Fiat API", "fiat_api": "Fiat API",
"fiat_balance": "الرصيد فيات", "fiat_balance": "الرصيد فيات",
"field_required": "هذه الخانة مطلوبه", "field_required": "هذه الخانة مطلوبه",
"file_saved": "تم حفظ الملف",
"fill_code": "يرجى ملء رمز التحقق المرسل إلى بريدك الإلكتروني", "fill_code": "يرجى ملء رمز التحقق المرسل إلى بريدك الإلكتروني",
"filter_by": "تصفية حسب", "filter_by": "تصفية حسب",
"first_wallet_text": "محفظة رائعة ل Monero, Bitcoin, Ethereum, Litecoin و Haven", "first_wallet_text": "محفظة رائعة ل Monero, Bitcoin, Ethereum, Litecoin و Haven",

View file

@ -333,6 +333,7 @@
"fiat_api": "Fiat API", "fiat_api": "Fiat API",
"fiat_balance": "Фиат Баланс", "fiat_balance": "Фиат Баланс",
"field_required": "Това поле е задължително", "field_required": "Това поле е задължително",
"file_saved": "Запасен файл",
"fill_code": "Моля, въведето кода за потвърждаване, изпратен на Вашия имейл", "fill_code": "Моля, въведето кода за потвърждаване, изпратен на Вашия имейл",
"filter_by": "Филтрирай по", "filter_by": "Филтрирай по",
"first_wallet_text": "Невероятен портфейл за Monero, Bitcoin, Ethereum, Litecoin и Haven", "first_wallet_text": "Невероятен портфейл за Monero, Bitcoin, Ethereum, Litecoin и Haven",

View file

@ -333,6 +333,7 @@
"fiat_api": "Fiat API", "fiat_api": "Fiat API",
"fiat_balance": "Fiat Balance", "fiat_balance": "Fiat Balance",
"field_required": "Toto pole je povinné", "field_required": "Toto pole je povinné",
"file_saved": "Uložen soubor",
"fill_code": "Prosím vyplňte ověřovací kód zaslaný na Váš e-mail", "fill_code": "Prosím vyplňte ověřovací kód zaslaný na Váš e-mail",
"filter_by": "Filtrovat podle", "filter_by": "Filtrovat podle",
"first_wallet_text": "Úžasná peněženka pro Monero, Bitcoin, Ethereum, Litecoin a Haven", "first_wallet_text": "Úžasná peněženka pro Monero, Bitcoin, Ethereum, Litecoin a Haven",

View file

@ -333,6 +333,7 @@
"fiat_api": "Fiat API", "fiat_api": "Fiat API",
"fiat_balance": "Fiat Balance", "fiat_balance": "Fiat Balance",
"field_required": "Dieses Feld ist erforderlich", "field_required": "Dieses Feld ist erforderlich",
"file_saved": "Datei gespeichert",
"fill_code": "Geben Sie den Bestätigungscode ein, den Sie per E-Mail erhalten haben", "fill_code": "Geben Sie den Bestätigungscode ein, den Sie per E-Mail erhalten haben",
"filter_by": "Filtern nach", "filter_by": "Filtern nach",
"first_wallet_text": "Eine großartige Wallet für Monero, Bitcoin, Ethereum, Litecoin, und Haven", "first_wallet_text": "Eine großartige Wallet für Monero, Bitcoin, Ethereum, Litecoin, und Haven",

View file

@ -333,6 +333,7 @@
"fiat_api": "Fiat API", "fiat_api": "Fiat API",
"fiat_balance": "Fiat Balance", "fiat_balance": "Fiat Balance",
"field_required": "This field is required", "field_required": "This field is required",
"file_saved": "File saved",
"fill_code": "Please fill in the verification code provided to your email", "fill_code": "Please fill in the verification code provided to your email",
"filter_by": "Filter by", "filter_by": "Filter by",
"first_wallet_text": "Awesome wallet for Monero, Bitcoin, Ethereum, Litecoin, and Haven", "first_wallet_text": "Awesome wallet for Monero, Bitcoin, Ethereum, Litecoin, and Haven",

View file

@ -333,6 +333,7 @@
"fiat_api": "Fiat API", "fiat_api": "Fiat API",
"fiat_balance": "Balance fiat", "fiat_balance": "Balance fiat",
"field_required": "Este campo es obligatorio", "field_required": "Este campo es obligatorio",
"file_saved": "Archivo guardado",
"fill_code": "Por favor completa el código de verificación proporcionado en tu correo electrónico", "fill_code": "Por favor completa el código de verificación proporcionado en tu correo electrónico",
"filter_by": "Filtrado por", "filter_by": "Filtrado por",
"first_wallet_text": "Impresionante billetera para Monero, Bitcoin, Ethereum, Litecoin, y Haven", "first_wallet_text": "Impresionante billetera para Monero, Bitcoin, Ethereum, Litecoin, y Haven",
@ -1035,4 +1036,4 @@
"you_will_receive_estimated_amount": "Recibirá(estimado )", "you_will_receive_estimated_amount": "Recibirá(estimado )",
"you_will_send": "Convertir de", "you_will_send": "Convertir de",
"yy": "YY" "yy": "YY"
} }

View file

@ -333,6 +333,7 @@
"fiat_api": "Fiat API", "fiat_api": "Fiat API",
"fiat_balance": "Solde fiat", "fiat_balance": "Solde fiat",
"field_required": "Ce champ est obligatoire", "field_required": "Ce champ est obligatoire",
"file_saved": "Dossier enregistré",
"fill_code": "Veuillez remplir le code de vérification fourni sur votre e-mail", "fill_code": "Veuillez remplir le code de vérification fourni sur votre e-mail",
"filter_by": "Filtrer par", "filter_by": "Filtrer par",
"first_wallet_text": "Super portefeuille (wallet) pour Monero, Bitcoin, Ethereum, Litecoin et Haven", "first_wallet_text": "Super portefeuille (wallet) pour Monero, Bitcoin, Ethereum, Litecoin et Haven",

Some files were not shown because too many files have changed in this diff Show more