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

This commit is contained in:
Rafael Saes 2024-11-27 06:50:56 -03:00
commit 3ee697b4c1
29 changed files with 353 additions and 177 deletions

View file

@ -1,6 +1,3 @@
-
uri: electrum.cakewallet.com:50002
useSSL: true
- -
uri: btc-electrum.cakewallet.com:50002 uri: btc-electrum.cakewallet.com:50002
useSSL: true useSSL: true

View file

@ -2,6 +2,7 @@
uri: xmr-node.cakewallet.com:18081 uri: xmr-node.cakewallet.com:18081
is_default: true is_default: true
trusted: true trusted: true
useSSL: true
- -
uri: cakexmrl7bonq7ovjka5kuwuyd3f7qnkz6z6s6dmsy3uckwra7bvggyd.onion:18081 uri: cakexmrl7bonq7ovjka5kuwuyd3f7qnkz6z6s6dmsy3uckwra7bvggyd.onion:18081
is_default: false is_default: false

View file

@ -203,9 +203,30 @@ class Node extends HiveObject with Keyable {
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
body: json.encode(body), body: json.encode(body),
); );
client.close(); client.close();
if ((
response.body.contains("400 Bad Request") // Some other generic error
|| response.body.contains("plain HTTP request was sent to HTTPS port") // Cloudflare
|| response.headers["location"] != null // Generic reverse proxy
|| response.body.contains("301 Moved Permanently") // Poorly configured generic reverse proxy
) && !(useSSL??false)
) {
final oldUseSSL = useSSL;
useSSL = true;
try {
final ret = await requestMoneroNode();
if (ret == true) {
await save();
return ret;
}
useSSL = oldUseSSL;
} catch (e) {
useSSL = oldUseSSL;
}
}
final resBody = json.decode(response.body) as Map<String, dynamic>; final resBody = json.decode(response.body) as Map<String, dynamic>;
return !(resBody['result']['offline'] as bool); return !(resBody['result']['offline'] as bool);
} catch (_) { } catch (_) {

View file

@ -2,14 +2,14 @@ group 'com.cakewallet.cw_haven'
version '1.0-SNAPSHOT' version '1.0-SNAPSHOT'
buildscript { buildscript {
ext.kotlin_version = '1.7.10' ext.kotlin_version = '2.0.21'
repositories { repositories {
google() google()
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:7.3.0' classpath 'com.android.tools.build:gradle:8.7.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
} }
} }
@ -25,8 +25,20 @@ apply plugin: 'com.android.library'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
android { android {
compileSdkVersion 28 compileSdkVersion 33
if (project.android.hasProperty("namespace")) {
namespace 'com.cakewallet.cw_haven'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = '17'
}
sourceSets { sourceSets {
main.java.srcDirs += 'src/main/kotlin' main.java.srcDirs += 'src/main/kotlin'
} }

View file

@ -17,7 +17,7 @@ String getTxKey(String txId) {
final status = monero.Wallet_status(wptr!); final status = monero.Wallet_status(wptr!);
if (status != 0) { if (status != 0) {
final error = monero.Wallet_errorString(wptr!); final error = monero.Wallet_errorString(wptr!);
return txId+"_"+error; return "";
} }
return txKey; return txKey;
} }
@ -92,11 +92,18 @@ Future<PendingTransactionDescription> createTransactionSync(
final amt = amount == null ? 0 : monero.Wallet_amountFromString(amount); final amt = amount == null ? 0 : monero.Wallet_amountFromString(amount);
final waddr = wptr!.address;
// force reconnection in case the os killed the connection?
// fixes failed to get block height error.
Isolate.run(() async {
monero.Wallet_synchronized(Pointer.fromAddress(waddr));
});
final address_ = address.toNativeUtf8(); final address_ = address.toNativeUtf8();
final paymentId_ = paymentId.toNativeUtf8(); final paymentId_ = paymentId.toNativeUtf8();
final preferredInputs_ = preferredInputs.join(monero.defaultSeparatorStr).toNativeUtf8(); final preferredInputs_ = preferredInputs.join(monero.defaultSeparatorStr).toNativeUtf8();
final waddr = wptr!.address;
final addraddr = address_.address; final addraddr = address_.address;
final paymentIdAddr = paymentId_.address; final paymentIdAddr = paymentId_.address;
final preferredInputsAddr = preferredInputs_.address; final preferredInputsAddr = preferredInputs_.address;
@ -357,16 +364,7 @@ class Transaction {
confirmations = monero.TransactionInfo_confirmations(txInfo), confirmations = monero.TransactionInfo_confirmations(txInfo),
fee = monero.TransactionInfo_fee(txInfo), fee = monero.TransactionInfo_fee(txInfo),
description = monero.TransactionInfo_description(txInfo), description = monero.TransactionInfo_description(txInfo),
key = getTxKey(txInfo); key = getTxKey(monero.TransactionInfo_hash(txInfo));
static String getTxKey(monero.TransactionInfo txInfo) {
final txKey = monero.Wallet_getTxKey(wptr!, txid: monero.TransactionInfo_hash(txInfo));
final status = monero.Wallet_status(wptr!);
if (status != 0) {
return "";
}
return txKey;
}
Transaction.dummy({ Transaction.dummy({
required this.displayLabel, required this.displayLabel,

View file

@ -150,14 +150,15 @@ final storeMutex = Mutex();
int lastStorePointer = 0; int lastStorePointer = 0;
int lastStoreHeight = 0; int lastStoreHeight = 0;
void storeSync() async { void storeSync({bool force = false}) async {
final addr = wptr!.address; final addr = wptr!.address;
final synchronized = await Isolate.run(() { final synchronized = await Isolate.run(() {
return monero.Wallet_synchronized(Pointer.fromAddress(addr)); return monero.Wallet_synchronized(Pointer.fromAddress(addr));
}); });
if (lastStorePointer == wptr!.address && if (lastStorePointer == wptr!.address &&
lastStoreHeight + 5000 > monero.Wallet_blockChainHeight(wptr!) && lastStoreHeight + 5000 > monero.Wallet_blockChainHeight(wptr!) &&
!synchronized) { !synchronized &&
!force) {
return; return;
} }
lastStorePointer = wptr!.address; lastStorePointer = wptr!.address;

View file

@ -286,8 +286,18 @@ Future<void> loadWallet(
/// 0: Software Wallet /// 0: Software Wallet
/// 1: Ledger /// 1: Ledger
/// 2: Trezor /// 2: Trezor
final deviceType = monero.WalletManager_queryWalletDevice(wmPtr, late final deviceType;
keysFileName: "$path.keys", password: password, kdfRounds: 1);
if (Platform.isAndroid || Platform.isIOS) {
deviceType = monero.WalletManager_queryWalletDevice(
wmPtr,
keysFileName: "$path.keys",
password: password,
kdfRounds: 1,
);
} else {
deviceType = 0;
}
if (deviceType == 1) { if (deviceType == 1) {
final dummyWPtr = wptr ?? final dummyWPtr = wptr ??

View file

@ -6,6 +6,7 @@ import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/amount_converter.dart'; import 'package:cw_core/amount_converter.dart';
import 'package:cw_core/pending_transaction.dart'; import 'package:cw_core/pending_transaction.dart';
import 'package:cw_monero/api/wallet.dart';
class DoubleSpendException implements Exception { class DoubleSpendException implements Exception {
DoubleSpendException(); DoubleSpendException();
@ -53,6 +54,7 @@ class PendingMoneroTransaction with PendingTransaction {
rethrow; rethrow;
} }
storeSync(force: true);
} }
@override @override

View file

@ -25,7 +25,20 @@ apply plugin: 'com.android.library'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
android { android {
compileSdkVersion 30 compileSdkVersion 33
if (project.android.hasProperty("namespace")) {
namespace 'com.cakewallet.cw_shared_external'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = '17'
}
sourceSets { sourceSets {
main.java.srcDirs += 'src/main/kotlin' main.java.srcDirs += 'src/main/kotlin'

View file

@ -251,8 +251,12 @@ class OnRamperBuyProvider extends BuyProvider {
return tag; return tag;
case 'POL': case 'POL':
return 'POLYGON'; return 'POLYGON';
default: default:
return CryptoCurrency.fromString(tag).fullName ?? tag; try {
return CryptoCurrency.fromString(tag).fullName!;
} catch (_) {
return tag;
}
} }
} }

View file

@ -260,10 +260,34 @@ Future<void> defaultSettingsMigration(
updateBtcElectrumNodeToUseSSL(nodes, sharedPreferences); updateBtcElectrumNodeToUseSSL(nodes, sharedPreferences);
break; break;
case 43: case 43:
_updateCakeXmrNode(nodes); await _updateCakeXmrNode(nodes);
_deselectExchangeProvider(sharedPreferences, "THORChain"); _deselectExchangeProvider(sharedPreferences, "THORChain");
_deselectExchangeProvider(sharedPreferences, "SimpleSwap"); _deselectExchangeProvider(sharedPreferences, "SimpleSwap");
break; break;
case 44:
await _updateCakeXmrNode(nodes);
await _changeDefaultNode(
nodes: nodes,
sharedPreferences: sharedPreferences,
type: WalletType.bitcoin,
newDefaultUri: newCakeWalletBitcoinUri,
currentNodePreferenceKey: PreferencesKey.currentBitcoinElectrumSererIdKey,
useSSL: true,
oldUri: ['cakewallet.com'],
);
_changeDefaultNode(
nodes: nodes,
sharedPreferences: sharedPreferences,
type: WalletType.tron,
newDefaultUri: tronDefaultNodeUri,
currentNodePreferenceKey: PreferencesKey.currentTronNodeIdKey,
useSSL: true,
oldUri: [
'tron-rpc.publicnode.com:443',
'api.trongrid.io',
],
);
break;
default: default:
break; break;
@ -279,17 +303,54 @@ Future<void> defaultSettingsMigration(
await sharedPreferences.setInt(PreferencesKey.currentDefaultSettingsMigrationVersion, version); await sharedPreferences.setInt(PreferencesKey.currentDefaultSettingsMigrationVersion, version);
} }
void _updateCakeXmrNode(Box<Node> nodes) { /// generic function for changing any wallet default node
/// instead of making a new function for each change
Future<void> _changeDefaultNode({
required Box<Node> nodes,
required SharedPreferences sharedPreferences,
required WalletType type,
required String newDefaultUri,
required String currentNodePreferenceKey,
required bool useSSL,
required List<String> oldUri, // leave empty if you want to force replace the node regardless of the user's current node
}) async {
final currentNodeId = sharedPreferences.getInt(currentNodePreferenceKey);
final currentNode = nodes.values.firstWhere((node) => node.key == currentNodeId);
final shouldReplace = oldUri.any((e) => currentNode.uriRaw.contains(e));
if (shouldReplace) {
var newNodeId =
nodes.values.firstWhereOrNull((element) => element.uriRaw == newDefaultUri)?.key;
// new node doesn't exist, then add it
if (newNodeId == null) {
final newNode = Node(
uri: newDefaultUri,
type: type,
useSSL: useSSL,
);
await nodes.add(newNode);
newNodeId = newNode.key;
}
await sharedPreferences.setInt(currentNodePreferenceKey, newNodeId as int);
}
}
Future<void> _updateCakeXmrNode(Box<Node> nodes) async {
final node = nodes.values.firstWhereOrNull((element) => element.uriRaw == newCakeWalletMoneroUri); final node = nodes.values.firstWhereOrNull((element) => element.uriRaw == newCakeWalletMoneroUri);
if (node != null && !node.trusted) { if (node != null) {
node.trusted = true; node.trusted = true;
node.save(); node.useSSL = true;
await node.save();
} }
} }
void updateBtcElectrumNodeToUseSSL(Box<Node> nodes, SharedPreferences sharedPreferences) { void updateBtcElectrumNodeToUseSSL(Box<Node> nodes, SharedPreferences sharedPreferences) {
final btcElectrumNode = nodes.values.firstWhereOrNull((element) => element.uriRaw == newCakeWalletBitcoinUri); final btcElectrumNode =
nodes.values.firstWhereOrNull((element) => element.uriRaw == newCakeWalletBitcoinUri);
if (btcElectrumNode != null) { if (btcElectrumNode != null) {
btcElectrumNode.useSSL = true; btcElectrumNode.useSSL = true;
@ -538,7 +599,6 @@ Node? getBitcoinCashDefaultElectrumServer({required Box<Node> nodes}) {
} }
Node getMoneroDefaultNode({required Box<Node> nodes}) { Node getMoneroDefaultNode({required Box<Node> nodes}) {
final timeZone = DateTime.now().timeZoneOffset.inHours;
var nodeUri = newCakeWalletMoneroUri; var nodeUri = newCakeWalletMoneroUri;
try { try {
@ -858,7 +918,8 @@ Future<void> changeDefaultMoneroNode(
} }
}); });
final newCakeWalletNode = Node(uri: newCakeWalletMoneroUri, type: WalletType.monero, trusted: true); final newCakeWalletNode =
Node(uri: newCakeWalletMoneroUri, type: WalletType.monero, trusted: true);
await nodeSource.add(newCakeWalletNode); await nodeSource.add(newCakeWalletNode);
@ -897,7 +958,7 @@ Future<void> updateBtcNanoWalletInfos(Box<WalletInfo> walletsInfoSource) async {
Future<void> changeDefaultNanoNode( Future<void> changeDefaultNanoNode(
Box<Node> nodeSource, SharedPreferences sharedPreferences) async { Box<Node> nodeSource, SharedPreferences sharedPreferences) async {
const oldNanoNodeUriPattern = 'rpc.nano.to'; const oldNanoNodeUriPattern = 'rpc.nano.to';
final currentNanoNodeId = sharedPreferences.getInt(PreferencesKey.currentNodeIdKey); final currentNanoNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoNodeIdKey);
final currentNanoNode = nodeSource.values.firstWhere((node) => node.key == currentNanoNodeId); final currentNanoNode = nodeSource.values.firstWhere((node) => node.key == currentNanoNodeId);
final newCakeWalletNode = Node( final newCakeWalletNode = Node(
@ -909,7 +970,8 @@ Future<void> changeDefaultNanoNode(
await nodeSource.add(newCakeWalletNode); await nodeSource.add(newCakeWalletNode);
if (currentNanoNode.uri.toString().contains(oldNanoNodeUriPattern)) { if (currentNanoNode.uri.toString().contains(oldNanoNodeUriPattern)) {
await sharedPreferences.setInt(PreferencesKey.currentNodeIdKey, newCakeWalletNode.key as int); await sharedPreferences.setInt(
PreferencesKey.currentNanoNodeIdKey, newCakeWalletNode.key as int);
} }
} }
@ -924,7 +986,7 @@ Future<void> changeDefaultBitcoinNode(
currentBitcoinNode.uri.toString().contains(cakeWalletBitcoinNodeUriPattern); currentBitcoinNode.uri.toString().contains(cakeWalletBitcoinNodeUriPattern);
final newCakeWalletBitcoinNode = final newCakeWalletBitcoinNode =
Node(uri: newCakeWalletBitcoinUri, type: WalletType.bitcoin, useSSL: false); Node(uri: newCakeWalletBitcoinUri, type: WalletType.bitcoin, useSSL: true);
if (!nodeSource.values.any((element) => element.uriRaw == newCakeWalletBitcoinUri)) { if (!nodeSource.values.any((element) => element.uriRaw == newCakeWalletBitcoinUri)) {
await nodeSource.add(newCakeWalletBitcoinNode); await nodeSource.add(newCakeWalletBitcoinNode);

View file

@ -1,7 +1,5 @@
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart'; import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -68,7 +66,7 @@ class MainActions {
static MainActions tradeAction = MainActions._( static MainActions tradeAction = MainActions._(
name: (context) => '${S.of(context).buy} / ${S.of(context).sell}', name: (context) => '${S.of(context).buy}/${S.of(context).sell}',
image: 'assets/images/buy_sell.png', image: 'assets/images/buy_sell.png',
isEnabled: (viewModel) => viewModel.isEnabledTradeAction, isEnabled: (viewModel) => viewModel.isEnabledTradeAction,
canShow: (viewModel) => viewModel.hasTradeAction, canShow: (viewModel) => viewModel.hasTradeAction,

View file

@ -26,23 +26,80 @@ class AddressResolver {
final SettingsStore settingsStore; final SettingsStore settingsStore;
static const unstoppableDomains = [ static const unstoppableDomains = [
'crypto', "888",
'zil', "altimist",
'x', "anime",
'wallet', "austin",
'bitcoin', "bald",
'888', "benji",
'nft', "bet",
'dao', "binanceus",
'blockchain', "bitcoin",
'polygon', "bitget",
'klever', "blockchain",
'hi', "ca",
'kresus', "chomp",
'anime', "clay",
'manga', "co",
'binanceus', "com",
'xmr', "crypto",
"dao",
"dfz",
"digital",
"dream",
"eth",
"ethermail",
"farms",
"fun",
"go",
"group",
"hi",
"host",
"info",
"io",
"klever",
"kresus",
"kryptic",
"lfg",
"life",
"live",
"ltd",
"manga",
"metropolis",
"moon",
"mumu",
"net",
"nft",
"online",
"org",
"pog",
"polygon",
"press",
"pro",
"propykeys",
"pudgy",
"pw",
"raiin",
"secret",
"site",
"smobler",
"space",
"stepn",
"store",
"tball",
"tech",
"ubu",
"uno",
"unstoppable",
"wallet",
"website",
"wifi",
"witg",
"wrkx",
"x",
"xmr",
"xyz",
"zil",
]; ];
static String? extractAddressByType({required String raw, required CryptoCurrency type}) { static String? extractAddressByType({required String raw, required CryptoCurrency type}) {

View file

@ -203,7 +203,7 @@ Future<void> initializeAppConfigs() async {
transactionDescriptions: transactionDescriptions, transactionDescriptions: transactionDescriptions,
secureStorage: secureStorage, secureStorage: secureStorage,
anonpayInvoiceInfo: anonpayInvoiceInfo, anonpayInvoiceInfo: anonpayInvoiceInfo,
initialMigrationVersion: 43, initialMigrationVersion: 44,
); );
} }

View file

@ -63,6 +63,8 @@ void startCurrentWalletChangeReaction(
startWalletSyncStatusChangeReaction(wallet, fiatConversionStore); startWalletSyncStatusChangeReaction(wallet, fiatConversionStore);
startCheckConnectionReaction(wallet, settingsStore); startCheckConnectionReaction(wallet, settingsStore);
await Future.delayed(Duration.zero);
if (wallet.type == WalletType.monero || if (wallet.type == WalletType.monero ||
wallet.type == WalletType.wownero || wallet.type == WalletType.wownero ||
wallet.type == WalletType.bitcoin || wallet.type == WalletType.bitcoin ||

View file

@ -291,32 +291,34 @@ class _DashboardPageView extends BasePage {
children: MainActions.all children: MainActions.all
.where((element) => element.canShow?.call(dashboardViewModel) ?? true) .where((element) => element.canShow?.call(dashboardViewModel) ?? true)
.map( .map(
(action) => Semantics( (action) => Expanded(
button: true, child: Semantics(
enabled: (action.isEnabled?.call(dashboardViewModel) ?? true), button: true,
child: ActionButton( enabled: (action.isEnabled?.call(dashboardViewModel) ?? true),
key: ValueKey( child: ActionButton(
'dashboard_page_${action.name(context)}_action_button_key'), key: ValueKey(
image: Image.asset( 'dashboard_page_${action.name(context)}_action_button_key'),
action.image, image: Image.asset(
height: 24, action.image,
width: 24, height: 24,
color: action.isEnabled?.call(dashboardViewModel) ?? true width: 24,
? Theme.of(context) color: action.isEnabled?.call(dashboardViewModel) ?? true
.extension<DashboardPageTheme>()! ? Theme.of(context)
.mainActionsIconColor .extension<DashboardPageTheme>()!
.mainActionsIconColor
: Theme.of(context)
.extension<BalancePageTheme>()!
.labelTextColor,
),
title: action.name(context),
onClick: () async =>
await action.onTap(context, dashboardViewModel),
textColor: action.isEnabled?.call(dashboardViewModel) ?? true
? null
: Theme.of(context) : Theme.of(context)
.extension<BalancePageTheme>()! .extension<BalancePageTheme>()!
.labelTextColor, .labelTextColor,
), ),
title: action.name(context),
onClick: () async =>
await action.onTap(context, dashboardViewModel),
textColor: action.isEnabled?.call(dashboardViewModel) ?? true
? null
: Theme.of(context)
.extension<BalancePageTheme>()!
.labelTextColor,
), ),
), ),
) )

View file

@ -10,91 +10,81 @@ import 'package:cake_wallet/view_model/dashboard/cake_features_view_model.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import 'package:flutter_svg/flutter_svg.dart';
class CakeFeaturesPage extends StatelessWidget { class CakeFeaturesPage extends StatelessWidget {
CakeFeaturesPage({required this.dashboardViewModel, required this.cakeFeaturesViewModel}); CakeFeaturesPage({required this.dashboardViewModel, required this.cakeFeaturesViewModel});
final DashboardViewModel dashboardViewModel; final DashboardViewModel dashboardViewModel;
final CakeFeaturesViewModel cakeFeaturesViewModel; final CakeFeaturesViewModel cakeFeaturesViewModel;
final _scrollController = ScrollController();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Padding( return Padding(
padding: const EdgeInsets.symmetric(horizontal: 10.0), padding: const EdgeInsets.symmetric(horizontal: 10.0),
child: RawScrollbar( child: Padding(
thumbColor: Colors.white.withOpacity(0.15), padding: const EdgeInsets.symmetric(horizontal: 10.0),
radius: Radius.circular(20), child: Column(
thumbVisibility: true, crossAxisAlignment: CrossAxisAlignment.start,
thickness: 2, children: [
controller: _scrollController, SizedBox(height: 50),
child: Padding( Text(
padding: const EdgeInsets.symmetric(horizontal: 10.0), 'Cake ${S.of(context).features}',
child: Column( style: TextStyle(
crossAxisAlignment: CrossAxisAlignment.start, fontSize: 24,
children: [ fontWeight: FontWeight.w500,
SizedBox(height: 50), color: Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
Text(
'Cake ${S.of(context).features}',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.w500,
color: Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
),
), ),
Expanded( ),
child: ListView( Expanded(
controller: _scrollController, child: ListView(
children: <Widget>[ children: <Widget>[
SizedBox(height: 20), SizedBox(height: 20),
DashBoardRoundedCardWidget( DashBoardRoundedCardWidget(
onTap: () => _navigatorToGiftCardsPage(context), onTap: () => _navigatorToGiftCardsPage(context),
title: 'Cake Pay', title: 'Cake Pay',
subTitle: S.of(context).cake_pay_subtitle, subTitle: S.of(context).cake_pay_subtitle,
image: Image.asset( image: Image.asset(
'assets/images/cards.png', 'assets/images/cards.png',
height: 100, height: 100,
width: 115, width: 115,
fit: BoxFit.cover, fit: BoxFit.cover,
),
), ),
SizedBox(height: 10), ),
DashBoardRoundedCardWidget( SizedBox(height: 10),
onTap: () => _launchUrl("cake.nano-gpt.com"), DashBoardRoundedCardWidget(
title: "NanoGPT", onTap: () => _launchUrl("cake.nano-gpt.com"),
subTitle: S.of(context).nanogpt_subtitle, title: "NanoGPT",
image: Image.asset( subTitle: S.of(context).nanogpt_subtitle,
'assets/images/nanogpt.png', image: Image.asset(
height: 80, 'assets/images/nanogpt.png',
width: 80, height: 80,
fit: BoxFit.cover, width: 80,
), fit: BoxFit.cover,
), ),
SizedBox(height: 10), ),
Observer( SizedBox(height: 10),
builder: (context) { Observer(
if (!dashboardViewModel.hasSignMessages) { builder: (context) {
return const SizedBox(); if (!dashboardViewModel.hasSignMessages) {
} return const SizedBox();
return DashBoardRoundedCardWidget( }
onTap: () => Navigator.of(context).pushNamed(Routes.signPage), return DashBoardRoundedCardWidget(
title: S.current.sign_verify_message, onTap: () => Navigator.of(context).pushNamed(Routes.signPage),
subTitle: S.current.sign_verify_message_sub, title: S.current.sign_verify_message,
icon: Icon( subTitle: S.current.sign_verify_message_sub,
Icons.speaker_notes_rounded, icon: Icon(
color: Icons.speaker_notes_rounded,
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor, color:
size: 75, Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
), size: 75,
); ),
}, );
), },
], ),
), ],
), ),
], ),
), ],
), ),
), ),
); );

View file

@ -8,7 +8,7 @@ class SyncIndicatorIcon extends StatelessWidget {
{this.boolMode = true, {this.boolMode = true,
this.isSynced = false, this.isSynced = false,
this.value = waiting, this.value = waiting,
this.size = 4.0}); this.size = 6.0});
final bool boolMode; final bool boolMode;
final bool isSynced; final bool isSynced;

View file

@ -191,11 +191,13 @@ class BlockchainHeightState extends State<BlockchainHeightWidget> {
height = wownero!.getHeightByDate(date: date); height = wownero!.getHeightByDate(date: date);
} }
} }
setState(() { if (mounted) {
dateController.text = DateFormat('yyyy-MM-dd').format(date); setState(() {
restoreHeightController.text = '$height'; dateController.text = DateFormat('yyyy-MM-dd').format(date);
_changeHeight(height); restoreHeightController.text = '$height';
}); _changeHeight(height);
});
}
} }
} }

View file

@ -92,15 +92,17 @@ class _ServicesUpdatesWidgetState extends State<ServicesUpdatesWidget> {
); );
} }
return Padding( return Padding(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 20), padding: const EdgeInsets.symmetric(horizontal: 12),
child: Stack( child: Column(
children: [ children: [
body, Expanded(child: body),
Align( Align(
alignment: Alignment.bottomCenter, alignment: Alignment.bottomCenter,
child: Padding( child: Padding(
padding: EdgeInsets.symmetric( padding: EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width / 8), horizontal: MediaQuery.of(context).size.width / 8,
vertical: 20,
),
child: PrimaryImageButton( child: PrimaryImageButton(
onPressed: () { onPressed: () {
try { try {

View file

@ -50,8 +50,8 @@ abstract class AppStoreBase with Store {
getIt.get<Web3WalletService>().create(); getIt.get<Web3WalletService>().create();
await getIt.get<Web3WalletService>().init(); await getIt.get<Web3WalletService>().init();
} }
await getIt.get<SharedPreferences>().setString(PreferencesKey.currentWalletName, wallet.name); getIt.get<SharedPreferences>().setString(PreferencesKey.currentWalletName, wallet.name);
await getIt getIt
.get<SharedPreferences>() .get<SharedPreferences>()
.setInt(PreferencesKey.currentWalletType, serializeToInt(wallet.type)); .setInt(PreferencesKey.currentWalletType, serializeToInt(wallet.type));
} }

View file

@ -204,7 +204,11 @@ abstract class CakePayCardsListViewModelBase with Store {
} }
@action @action
void setSelectedCountry(Country country) => settingsStore.selectedCakePayCountry = country; void setSelectedCountry(Country country) {
// just so it triggers the reaction even when selecting the default country
settingsStore.selectedCakePayCountry = null;
settingsStore.selectedCakePayCountry = country;
}
@action @action
void togglePrepaidCards() => displayPrepaidCards = !displayPrepaidCards; void togglePrepaidCards() => displayPrepaidCards = !displayPrepaidCards;

View file

@ -159,7 +159,7 @@ abstract class TransactionDetailsViewModelBase with Store {
case WalletType.monero: case WalletType.monero:
return 'https://monero.com/tx/${txId}'; return 'https://monero.com/tx/${txId}';
case WalletType.bitcoin: case WalletType.bitcoin:
return 'https://mempool.space/${wallet.isTestnet ? "testnet/" : ""}tx/${txId}'; return 'https://mempool.cakewallet.com/${wallet.isTestnet ? "testnet/" : ""}tx/${txId}';
case WalletType.litecoin: case WalletType.litecoin:
return 'https://blockchair.com/litecoin/transaction/${txId}'; return 'https://blockchair.com/litecoin/transaction/${txId}';
case WalletType.bitcoinCash: case WalletType.bitcoinCash:

View file

@ -26,7 +26,7 @@ dependencies:
share_plus: ^10.0.0 share_plus: ^10.0.0
# date_range_picker: ^1.0.6 # date_range_picker: ^1.0.6
#https://api.flutter.dev/flutter/material/showDateRangePicker.html #https://api.flutter.dev/flutter/material/showDateRangePicker.html
dio: ^4.0.6 dio: ^5.7.0
hive: ^2.2.3 hive: ^2.2.3
hive_flutter: ^1.1.0 hive_flutter: ^1.1.0
local_auth_android: ^1.0.46 local_auth_android: ^1.0.46

View file

@ -921,7 +921,7 @@
"wallet_seed_legacy": "Graine de portefeuille hérité", "wallet_seed_legacy": "Graine de portefeuille hérité",
"wallet_store_monero_wallet": "Portefeuille (Wallet) Monero", "wallet_store_monero_wallet": "Portefeuille (Wallet) Monero",
"walletConnect": "WalletConnect", "walletConnect": "WalletConnect",
"wallets": "Portefeuilles (Wallets)", "wallets": "Portefeuilles",
"warning": "Avertissement", "warning": "Avertissement",
"welcome": "Bienvenue sur", "welcome": "Bienvenue sur",
"welcome_to_cakepay": "Bienvenue sur Cake Pay !", "welcome_to_cakepay": "Bienvenue sur Cake Pay !",

View file

@ -7,9 +7,9 @@ fi
cd ../.. cd ../..
set -x set -x
universal_sed "0,/version:/{s/version:.*/version: ${APP_ANDROID_VERSION}+${APP_ANDROID_BUILD_NUMBER}/}" ./pubspec.yaml universal_sed "1,/version:/ {s/version:.*/version: ${APP_ANDROID_VERSION}+${APP_ANDROID_BUILD_NUMBER}/;}" ./pubspec.yaml
universal_sed "0,/version:/{s/__APP_PACKAGE__/${APP_ANDROID_PACKAGE}/}" ./android/app/src/main/AndroidManifest.xml universal_sed "1,/version:/ {s/__APP_PACKAGE__/${APP_ANDROID_PACKAGE}/;}" ./android/app/src/main/AndroidManifest.xml
universal_sed "0,/__APP_SCHEME__/s/__APP_SCHEME__/${APP_ANDROID_SCHEME}/" ./android/app/src/main/AndroidManifest.xml universal_sed "1,/__APP_SCHEME__/ {s/__APP_SCHEME__/${APP_ANDROID_SCHEME}/;}" ./android/app/src/main/AndroidManifest.xml
universal_sed "0,/version:/{s/__versionCode__/${APP_ANDROID_BUILD_NUMBER}/}" ./android/app/src/main/AndroidManifest.xml universal_sed "1,/version:/ {s/__versionCode__/${APP_ANDROID_BUILD_NUMBER}/;}" ./android/app/src/main/AndroidManifest.xml
universal_sed "0,/version:/{s/__versionName__/${APP_ANDROID_VERSION}/}" ./android/app/src/main/AndroidManifest.xml universal_sed "1,/version:/ {s/__versionName__/${APP_ANDROID_VERSION}/;}" ./android/app/src/main/AndroidManifest.xml
cd scripts/android cd scripts/android

View file

@ -43,7 +43,6 @@ case $APP_IOS_TYPE in
CONFIG_ARGS="--haven" CONFIG_ARGS="--haven"
;; ;;
esac esac
CONFIG_ARGS="--monero --ethereum --polygon --nano --solana --tron --wownero"
cp -rf pubspec_description.yaml pubspec.yaml cp -rf pubspec_description.yaml pubspec.yaml
flutter pub get flutter pub get

View file

@ -16,13 +16,13 @@ if [ -n "$1" ]; then
fi fi
MONERO_COM_NAME="Monero.com" MONERO_COM_NAME="Monero.com"
MONERO_COM_VERSION="1.8.0" MONERO_COM_VERSION="1.8.1"
MONERO_COM_BUILD_NUMBER=36 MONERO_COM_BUILD_NUMBER=37
MONERO_COM_BUNDLE_ID="com.cakewallet.monero" MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
CAKEWALLET_NAME="Cake Wallet" CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="1.14.0" CAKEWALLET_VERSION="1.14.1"
CAKEWALLET_BUILD_NUMBER=95 CAKEWALLET_BUILD_NUMBER=96
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet" CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
if ! [[ " ${TYPES[*]} " =~ " ${APP_MACOS_TYPE} " ]]; then if ! [[ " ${TYPES[*]} " =~ " ${APP_MACOS_TYPE} " ]]; then

View file

@ -13,7 +13,6 @@ universal_sed() {
local file=$2 local file=$2
if [[ "$SED_TYPE" == "GNU" ]]; then if [[ "$SED_TYPE" == "GNU" ]]; then
pwd
sed -i "$expression" "$file" sed -i "$expression" "$file"
else else
sed -i '' "$expression" "$file" sed -i '' "$expression" "$file"