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/decred/decred.dart
ios/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_180.png
ios/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_120.png
ios/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png
ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon@2x.png
ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon@2x~ipad.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
android/app/src/main/res/mipmap-*
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)
* Litecoin (LTC)
* Bitcoin Cash (BCH)
* Polygon (Pol)
* Polygon (POL)
* Solana (SOL)
* Tron (TRX)
* Nano (XNO)
* Haven (XHV)
* Zano (ZANO)
* Decred (DCR)
* Wownero (WOW)
## Features
@ -81,10 +84,6 @@ Cake Wallet includes support for several cryptocurrencies, including:
* Automatically generate new addresses
* 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
## Open Source Monero-Only Wallet

View file

@ -107,6 +107,9 @@
<meta-data
android:name="flutterEmbedding"
android:value="2" />
<meta-data
android:name="io.flutter.embedding.android.EnableImpeller"
android:value="false" />
<provider
android:name="com.pichillilorenzo.flutter_inappwebview_android.InAppWebViewFileProvider"
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
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
Enhance Backup files
Improve app usability and user experience
User interface enhancements
UI/UX enhancements
Performance improvements
Bug fixes

View file

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

View file

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

View file

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

View file

@ -28,4 +28,9 @@ class Unspent with UnspentComparable {
bool get isP2wpkh =>
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:
return 'Banano (BAN)';
case WalletType.polygon:
return 'Polygon (MATIC)';
return 'Polygon (POL)';
case WalletType.solana:
return 'Solana (SOL)';
case WalletType.tron:

View file

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

View file

@ -76,9 +76,13 @@ class EthereumWallet extends EVMChainWallet {
await erc20TokensBox.deleteFromDisk();
// 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
EVMChainTransactionInfo getTransactionInfo(
EVMChainTransactionModel transactionModel, String address) {

View file

@ -146,6 +146,8 @@ abstract class EVMChainWalletBase extends WalletBase<
// required WalletInfo walletInfo,
// });
List<String> get getDefaultTokenContractAddresses;
Future<void> initErc20TokensBox();
String getTransactionHistoryFileName();
@ -173,6 +175,9 @@ abstract class EVMChainWalletBase extends WalletBase<
await walletAddresses.init();
await transactionHistory.init();
// check for Already existing scam tokens, cuz users can get scammed twice ¯\_()_/¯
await _checkForExistingScamTokens();
if (walletInfo.isHardwareWallet) {
_evmChainPrivateKey = EvmLedgerCredentials(walletInfo.address);
walletAddresses.address = walletInfo.address;
@ -188,6 +193,31 @@ abstract class EVMChainWalletBase extends WalletBase<
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
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;
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(
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) {
getCoinByKeyImage(keyImage).then((coinId) {
if (coinId == null) return;
getCoin(coinId).then((coin) {
_frozen = monero.CoinsInfo_frozen(coin);
});
});
_frozen = isFrozen;
}
bool _frozen = false;
@override
set isFrozen(bool freeze) {
_frozen = freeze;
printV("set isFrozen: $freeze ($keyImage): $freeze");
getCoinByKeyImage(keyImage!).then((coinId) async {
if (coinId == null) return;

View file

@ -592,7 +592,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance, MoneroTransact
final coin = await getCoin(i);
final coinSpent = monero.CoinsInfo_spent(coin);
if (coinSpent == false && monero.CoinsInfo_subaddrAccount(coin) == walletAddresses.account!.id) {
final unspent = MoneroUnspent(
final unspent = await MoneroUnspent.fromUnspent(
monero.CoinsInfo_address(coin),
monero.CoinsInfo_hash(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
Future<bool> checkIfScanProviderIsEnabled() async {
bool isPolygonScanEnabled = (await sharedPrefs.future).getBool("use_polygonscan") ?? true;

View file

@ -1,114 +1,134 @@
{
"images" : [
"images": [
{
"filename" : "Icon-App-40x40@1x.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "20x20"
"filename": "AppIcon@2x.png",
"idiom": "iphone",
"scale": "2x",
"size": "60x60"
},
{
"filename" : "Icon-App-20x20@3x.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "20x20"
"filename": "AppIcon@3x.png",
"idiom": "iphone",
"scale": "3x",
"size": "60x60"
},
{
"filename" : "Icon-App-29x29@2x 1.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "29x29"
"filename": "AppIcon~ipad.png",
"idiom": "ipad",
"scale": "1x",
"size": "76x76"
},
{
"filename" : "Icon-App-29x29@3x.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "29x29"
"filename": "AppIcon@2x~ipad.png",
"idiom": "ipad",
"scale": "2x",
"size": "76x76"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "40x40"
"filename": "AppIcon-83.5@2x~ipad.png",
"idiom": "ipad",
"scale": "2x",
"size": "83.5x83.5"
},
{
"filename" : "Icon-App-40x40@3x.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "40x40"
"filename": "AppIcon-40@2x.png",
"idiom": "iphone",
"scale": "2x",
"size": "40x40"
},
{
"filename" : "app_icon_120.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "60x60"
"filename": "AppIcon-40@3x.png",
"idiom": "iphone",
"scale": "3x",
"size": "40x40"
},
{
"filename" : "app_icon_180.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "60x60"
"filename": "AppIcon-40~ipad.png",
"idiom": "ipad",
"scale": "1x",
"size": "40x40"
},
{
"filename" : "Icon-App-20x20@1x.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "20x20"
"filename": "AppIcon-40@2x~ipad.png",
"idiom": "ipad",
"scale": "2x",
"size": "40x40"
},
{
"filename" : "Icon-App-20x20@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "20x20"
"filename": "AppIcon-20@2x.png",
"idiom": "iphone",
"scale": "2x",
"size": "20x20"
},
{
"filename" : "Icon-App-29x29@1x.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "29x29"
"filename": "AppIcon-20@3x.png",
"idiom": "iphone",
"scale": "3x",
"size": "20x20"
},
{
"filename" : "Icon-App-29x29@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "29x29"
"filename": "AppIcon-20~ipad.png",
"idiom": "ipad",
"scale": "1x",
"size": "20x20"
},
{
"filename" : "Icon-App-40x40@1x 1.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "40x40"
"filename": "AppIcon-20@2x~ipad.png",
"idiom": "ipad",
"scale": "2x",
"size": "20x20"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "40x40"
"filename": "AppIcon-29.png",
"idiom": "iphone",
"scale": "1x",
"size": "29x29"
},
{
"filename" : "Icon-App-76x76@1x.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "76x76"
"filename": "AppIcon-29@2x.png",
"idiom": "iphone",
"scale": "2x",
"size": "29x29"
},
{
"filename" : "Icon-App-76x76@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "76x76"
"filename": "AppIcon-29@3x.png",
"idiom": "iphone",
"scale": "3x",
"size": "29x29"
},
{
"filename" : "Icon-App-83.5x83.5@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "83.5x83.5"
"filename": "AppIcon-29~ipad.png",
"idiom": "ipad",
"scale": "1x",
"size": "29x29"
},
{
"filename" : "app_icon_1024.png",
"idiom" : "ios-marketing",
"scale" : "1x",
"size" : "1024x1024"
"filename": "AppIcon-29@2x~ipad.png",
"idiom": "ipad",
"scale": "2x",
"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" : {
"author" : "xcode",
"version" : 1
"info": {
"author": "iconkitchen",
"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/robinhood/robinhood_buy_provider.dart';
import 'package:cake_wallet/di.dart';
import 'package:cw_core/wallet_type.dart';
enum ProviderType { robinhood, dfx, onramper, moonpay, meld, kriptonim }
@ -47,7 +46,7 @@ extension ProviderTypeName on ProviderType {
}
class ProvidersHelper {
static List<ProviderType> getAvailableBuyProviderTypes(WalletType walletType) => [
static List<ProviderType> getAvailableBuyProviderTypes() => [
ProviderType.robinhood,
ProviderType.dfx,
ProviderType.onramper,
@ -55,7 +54,7 @@ class ProvidersHelper {
ProviderType.kriptonim
];
static List<ProviderType> getAvailableSellProviderTypes(WalletType walletType) => [
static List<ProviderType> getAvailableSellProviderTypes() => [
ProviderType.robinhood,
ProviderType.dfx,
ProviderType.onramper,
@ -63,7 +62,7 @@ class ProvidersHelper {
ProviderType.kriptonim
];
static BuyProvider? getProviderByType(ProviderType type) {
static BuyProvider getProviderByType(ProviderType type) {
switch (type) {
case ProviderType.robinhood:
return getIt.get<RobinhoodBuyProvider>();
@ -77,8 +76,6 @@ class ProvidersHelper {
return getIt.get<MeldBuyProvider>();
case ProviderType.kriptonim:
return getIt.get<KryptonimBuyProvider>();
default:
return null;
}
}
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -101,7 +101,7 @@ class WCCDetailsWidget extends BasePage {
child: CircleAvatar(
backgroundImage: (pairing.peerMetadata!.icons.isNotEmpty
? NetworkImage(pairing.peerMetadata!.icons[0])
: const AssetImage('assets/images/default_icon.png'))
: const AssetImage('assets/images/app_logo.png'))
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/themes/theme_base.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/currency_for_wallet_type.dart';
import 'package:flutter/cupertino.dart';
import 'package:intl/intl.dart';
import 'package:mobx/mobx.dart';
@ -61,21 +60,17 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S
late Timer bestRateSync;
List<BuyProvider> get availableBuyProviders {
final providerTypes = ProvidersHelper.getAvailableBuyProviderTypes(
walletTypeForCurrency(cryptoCurrency) ?? wallet.type);
final providerTypes = ProvidersHelper.getAvailableBuyProviderTypes();
return providerTypes
.map((type) => ProvidersHelper.getProviderByType(type))
.where((provider) => provider != null)
.cast<BuyProvider>()
.toList();
}
List<BuyProvider> get availableSellProviders {
final providerTypes = ProvidersHelper.getAvailableSellProviderTypes(
walletTypeForCurrency(cryptoCurrency) ?? wallet.type);
final providerTypes = ProvidersHelper.getAvailableSellProviderTypes();
return providerTypes
.map((type) => ProvidersHelper.getProviderByType(type))
.where((provider) => provider != null)
.cast<BuyProvider>()
.toList();
}

View file

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

View file

@ -149,12 +149,15 @@ abstract class UnspentCoinsListViewModelBase with Store {
}
@action
int getSendingBalance(UnspentCoinType overrideCoinTypeToSpendFrom) {
Future<int> getSendingBalance(UnspentCoinType overrideCoinTypeToSpendFrom) async {
// 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:
int total = 0;
await _updateUnspents();
Set<String> seen = {};
for (final item in _getSpecificUnspents(overrideCoinTypeToSpendFrom)) {
if (seen.contains(item.toString())) continue;
seen.add(item.toString());
if (item.isFrozen || !item.isSending) continue;
total += item.value;
}
@ -163,8 +166,6 @@ abstract class UnspentCoinsListViewModelBase with Store {
@action
void _updateUnspentCoinsInfo() {
items.clear();
final unspents = _getUnspents()
.map((elem) {
try {
@ -198,7 +199,7 @@ abstract class UnspentCoinsListViewModelBase with Store {
.toList();
unspents.sort((a, b) => b.value.compareTo(a.value));
items.clear();
items.addAll(unspents);
}

View file

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

View file

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

View file

@ -333,6 +333,7 @@
"fiat_api": "Fiat API",
"fiat_balance": "Fiat Balance",
"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",
"filter_by": "Filtrovat podle",
"first_wallet_text": "Úžasná peněženka pro Monero, Bitcoin, Ethereum, Litecoin a Haven",

View file

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

View file

@ -333,6 +333,7 @@
"fiat_api": "Fiat API",
"fiat_balance": "Balance fiat",
"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",
"filter_by": "Filtrado por",
"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_send": "Convertir de",
"yy": "YY"
}
}

View file

@ -333,6 +333,7 @@
"fiat_api": "Fiat API",
"fiat_balance": "Solde fiat",
"field_required": "Ce champ est obligatoire",
"file_saved": "Dossier enregistré",
"fill_code": "Veuillez remplir le code de vérification fourni sur votre e-mail",
"filter_by": "Filtrer par",
"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