v4.28.0 Release Candidate (#2260)

* v4.28.0 Release Candidate

* Fix Android deeplinking

* minor [skip ci]

* update app versions [skip ci]

* merge main

* - Re-enable SwapTrade
- Hide Keyboard on opening fee selection

* handle old backups import

* - Fix seed type UI
- Temp fix for Deleting Monero wallet

* update build number [skip ci]

* minor nullability handling

* disable payjoin for SP
This commit is contained in:
Omar Hatem 2025-05-16 13:51:36 +03:00 committed by GitHub
parent c12daced40
commit 914561716d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 113 additions and 109 deletions

View file

@ -111,6 +111,8 @@
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="nano-gpt" />
</intent-filter>
<meta-data android:name="flutter_deeplinking_enabled" android:value="false" />
</activity>
<meta-data
android:name="flutterEmbedding"

View file

@ -1,4 +1,3 @@
Background sync improvements
Payment notifications
UI/UX improvements
Monero enhancements
UI improvements
Bug fixes

View file

@ -1,5 +1,4 @@
Background sync improvements
Payment notifications
WalletConnect enhancements
UI/UX improvements
Add Bitcoin Payjoin
Monero enhancements
UI improvements
Bug fixes

View file

@ -20,6 +20,7 @@ BitcoinBaseAddress addressFromScript(Script script,
return P2pkhAddress.fromScriptPubkey(
script: script, network: BitcoinNetwork.mainnet);
case P2shAddressType.p2pkhInP2sh:
case P2shAddressType.p2pkInP2sh:
return P2shAddress.fromScriptPubkey(
script: script, network: BitcoinNetwork.mainnet);
case SegwitAddresType.p2wpkh:

View file

@ -1167,4 +1167,4 @@ packages:
version: "2.2.2"
sdks:
dart: ">=3.5.0 <4.0.0"
flutter: ">=3.27.4"
flutter: ">=3.24.0"

View file

@ -810,4 +810,4 @@ packages:
version: "3.1.3"
sdks:
dart: ">=3.5.0 <4.0.0"
flutter: ">=3.27.4"
flutter: ">=3.24.0"

View file

@ -25,8 +25,8 @@ bool isUpdating = false;
void refreshAccounts() {
try {
isUpdating = true;
subaddressAccount = currentWallet!.subaddressAccount();
subaddressAccount!.refresh();
subaddressAccount = currentWallet?.subaddressAccount();
subaddressAccount?.refresh();
isUpdating = false;
} catch (e) {
isUpdating = false;

View file

@ -34,12 +34,12 @@ import 'package:cw_monero/monero_transaction_history.dart';
import 'package:cw_monero/monero_transaction_info.dart';
import 'package:cw_monero/monero_unspent.dart';
import 'package:cw_monero/monero_wallet_addresses.dart';
import 'package:cw_monero/monero_wallet_service.dart';
import 'package:cw_monero/pending_monero_transaction.dart';
import 'package:flutter/foundation.dart';
import 'package:hive/hive.dart';
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
import 'package:mobx/mobx.dart';
import 'package:monero/src/monero.dart' as m;
import 'package:monero/monero.dart' as monero;
part 'monero_wallet.g.dart';
@ -193,19 +193,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
final wmaddr = wmPtr.ffiAddress();
final waddr = openedWalletsByPath["$currentWalletDirPath/$name"]!.ffiAddress();
openedWalletsByPath.remove("$currentWalletDirPath/$name");
if (Platform.isWindows) {
await Isolate.run(() {
monero.WalletManager_closeWallet(
Pointer.fromAddress(wmaddr), Pointer.fromAddress(waddr), true);
monero.WalletManager_errorString(Pointer.fromAddress(wmaddr));
});
} else {
unawaited(Isolate.run(() {
monero.WalletManager_closeWallet(
Pointer.fromAddress(wmaddr), Pointer.fromAddress(waddr), true);
monero.WalletManager_errorString(Pointer.fromAddress(wmaddr));
}));
}
closeWalletAwaitIfShould(wmaddr, waddr);
currentWallet = null;
printV("wallet closed");
}

View file

@ -978,4 +978,4 @@ packages:
version: "3.1.3"
sdks:
dart: ">=3.6.0 <4.0.0"
flutter: ">=3.27.4"
flutter: ">=3.24.0"

View file

@ -845,4 +845,4 @@ packages:
version: "3.1.3"
sdks:
dart: ">=3.5.0 <4.0.0"
flutter: ">=3.27.4"
flutter: ">=3.24.0"

View file

@ -76,6 +76,7 @@ PODS:
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- payjoin_flutter (0.20.0)
- permission_handler_apple (9.3.0):
- Flutter
- reown_yttrium (0.0.1):
@ -126,6 +127,7 @@ DEPENDENCIES:
- integration_test (from `.symlinks/plugins/integration_test/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- payjoin_flutter (from `.symlinks/plugins/payjoin_flutter/ios`)
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
- reown_yttrium (from `.symlinks/plugins/reown_yttrium/ios`)
- sensitive_clipboard (from `.symlinks/plugins/sensitive_clipboard/ios`)
@ -186,6 +188,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/package_info_plus/ios"
path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
payjoin_flutter:
:path: ".symlinks/plugins/payjoin_flutter/ios"
permission_handler_apple:
:path: ".symlinks/plugins/permission_handler_apple/ios"
reown_yttrium:
@ -208,40 +212,43 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/wakelock_plus/ios"
SPEC CHECKSUMS:
connectivity_plus: 481668c94744c30c53b8895afb39159d1e619bdf
connectivity_plus: 2a701ffec2c0ae28a48cf7540e279787e77c447d
CryptoSwift: e64e11850ede528a02a0f3e768cec8e9d92ecb90
cw_decred: a02cf30175a46971c1e2fa22c48407534541edc6
cw_mweb: 3aea2fb35b2bd04d8b2d21b83216f3b8fb768d85
device_display_brightness: 04374ebd653619292c1d996f00f42877ea19f17f
device_info_plus: 335f3ce08d2e174b9fdc3db3db0f4e3b1f66bd89
devicelocale: bd64aa714485a8afdaded0892c1e7d5b7f680cf8
cw_decred: 9c0e1df74745b51a1289ec5e91fb9e24b68fa14a
cw_mweb: 22cd01dfb8ad2d39b15332006f22046aaa8352a3
device_display_brightness: 1510e72c567a1f6ce6ffe393dcd9afd1426034f7
device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6
devicelocale: 35ba84dc7f45f527c3001535d8c8d104edd5d926
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
fast_scanner: 2cb1ad3e69e645e9980fb4961396ce5804caa3e3
file_picker: 9b3292d7c8bc68c8a7bf8eb78f730e49c8efc517
fast_scanner: 44c00940355a51258cd6c2085734193cd23d95bc
file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99
flutter_local_authentication: 989278c681612f1ee0e36019e149137f114b9d7f
flutter_mailer: 3a8cd4f36c960fb04528d5471097270c19fec1c4
flutter_secure_storage: 2c2ff13db9e0a5647389bff88b0ecac56e3f3418
fluttertoast: 2c67e14dce98bbdb200df9e1acf610d7a6264ea1
in_app_review: 5596fe56fab799e8edb3561c03d053363ab13457
integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e
flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4
flutter_local_authentication: 1172a4dd88f6306dadce067454e2c4caf07977bb
flutter_local_notifications: ff50f8405aaa0ccdc7dcfb9022ca192e8ad9688f
flutter_mailer: 2ef5a67087bc8c6c4cefd04a178bf1ae2c94cd83
flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be
fluttertoast: 21eecd6935e7064cc1fcb733a4c5a428f3f24f0f
in_app_review: a31b5257259646ea78e0e35fc914979b0031d011
integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
ReachabilitySwift: 32793e867593cfc1177f5d16491e3a197d2fccda
package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
payjoin_flutter: 6397d7b698cdad6453be4949ab6aca1863f6c5e5
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
reown_yttrium: c0e87e5965fa60a3559564cc35cffbba22976089
SDWebImage: 73c6079366fea25fa4bb9640d5fb58f0893facd8
sensitive_clipboard: 161e9abc3d56b3131309d8a321eb4690a803c16b
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
sp_scanner: b1bc9321690980bdb44bba7ec85d5543e716d1b5
sensitive_clipboard: d4866e5d176581536c27bb1618642ee83adca986
share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
sp_scanner: eaa617fa827396b967116b7f1f43549ca62e9a12
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
uni_links: ed8c961e47ed9ce42b6d91e1de8049e38a4b3152
universal_ble: ff19787898040d721109c6324472e5dd4bc86adc
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556
uni_links: d97da20c7701486ba192624d99bffaaffcfc298a
universal_ble: cf52a7b3fd2e7c14d6d7262e9fdadb72ab6b88a6
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
wakelock_plus: 76957ab028e12bfa4e66813c99e46637f367fc7e
YttriumWrapper: 31e937fe9fbe0f1314d2ca6be9ce9b379a059966
PODFILE CHECKSUM: 5296465b1c6d14d506230356756826012f65d97a

View file

@ -327,5 +327,7 @@
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>FlutterDeepLinkingEnabled</key>
<false/>
</dict>
</plist>

View file

@ -251,10 +251,12 @@ class $BackupService {
await importWalletKeychainInfo(info);
});
if (keychainJSON['_all'] is Map<String, dynamic>) {
for (var key in (keychainJSON['_all'] as Map<String, dynamic>).keys) {
try {
if (!key.startsWith('MONERO_WALLET_')) continue;
final decodedPassword = decodeWalletPassword(password: keychainJSON['_all'][key].toString());
final decodedPassword = decodeWalletPassword(
password: keychainJSON['_all'][key].toString());
final walletName = key.split('_WALLET_')[1];
final walletType = key.split('_WALLET_')[0].toLowerCase();
await importWalletKeychainInfo({
@ -266,6 +268,7 @@ class $BackupService {
printV('Error importing wallet ($key) password: $e');
}
}
}
keychainDumpFile.deleteSync();
}

View file

@ -2,16 +2,19 @@ import 'package:cw_core/enumerable_item.dart';
import 'package:cw_core/wallet_info.dart';
class MoneroSeedType extends EnumerableItem<int> with Serializable<int> {
const MoneroSeedType({required String title, required int raw}) : super(title: title, raw: raw);
const MoneroSeedType({required String title, required int raw, this.shortTitle})
: super(title: title, raw: raw);
final String? shortTitle;
static const all = [legacy, polyseed, bip39];
static const defaultSeedType = polyseed;
static const legacy = MoneroSeedType(raw: 0, title: 'Legacy (25 words)');
static const polyseed = MoneroSeedType(raw: 1, title: 'Polyseed (16 words)');
static const legacy = MoneroSeedType(raw: 0, title: 'Legacy (25 words)', shortTitle: "Legacy");
static const polyseed = MoneroSeedType(raw: 1, title: 'Polyseed (16 words)', shortTitle: "Polyseed");
static const wowneroSeed = MoneroSeedType(raw: 2, title: 'Wownero');
static const bip39 = MoneroSeedType(raw: 3, title: 'BIP39 (12 words)');
static const bip39 = MoneroSeedType(raw: 3, title: 'BIP39 (12 words)', shortTitle: "BIP39");
static MoneroSeedType deserialize({required int raw}) {
switch (raw) {

View file

@ -47,10 +47,10 @@ class SwapTradeExchangeProvider extends ExchangeProvider {
String get title => 'SwapTrade';
@override
bool get isAvailable => false;
bool get isAvailable => true;
@override
bool get isEnabled => false;
bool get isEnabled => true;
@override
bool get supportsFixedRate => false;
@ -59,7 +59,7 @@ class SwapTradeExchangeProvider extends ExchangeProvider {
ExchangeProviderDescription get description => ExchangeProviderDescription.swapTrade;
@override
Future<bool> checkIsAvailable() async => false;
Future<bool> checkIsAvailable() async => true;
@override
Future<Limits> fetchLimits({

View file

@ -154,6 +154,7 @@ class _AdvancedPrivacySettingsBodyState extends State<_AdvancedPrivacySettingsBo
items: MoneroSeedType.all,
selectedItem: widget.seedTypeViewModel.moneroSeedType,
onItemSelected: widget.seedTypeViewModel.setMoneroSeedType,
displayItem: (seedType) => seedType.shortTitle ?? seedType.toString(),
),
);
}),

View file

@ -97,8 +97,7 @@ class QRWidget extends StatelessWidget {
padding: EdgeInsets.zero,
decoration: BoxDecoration(
border: Border(top: BorderSide.none),
borderRadius:
BorderRadius.all(Radius.circular(5)),
borderRadius: BorderRadius.all(Radius.circular(5)),
color: Colors.white,
),
child: Column(
@ -112,11 +111,10 @@ class QRWidget extends StatelessWidget {
),
),
),
if (addressListViewModel
.payjoinEndpoint.isNotEmpty) ...[
if (addressListViewModel.payjoinEndpoint.isNotEmpty &&
!addressListViewModel.isSilentPayments) ...[
Row(
mainAxisAlignment:
MainAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: EdgeInsets.only(
@ -198,8 +196,10 @@ class QRWidget extends StatelessWidget {
evenTextStyle: TextStyle(
fontSize: 15,
fontWeight: FontWeight.w500,
color:
Theme.of(context).extension<DashboardPageTheme>()!.textColor))),
color: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
),
),
),
Padding(
padding: EdgeInsets.only(left: 12),
child: copyImage,
@ -212,13 +212,12 @@ class QRWidget extends StatelessWidget {
),
Observer(
builder: (_) => Offstage(
offstage: addressListViewModel.payjoinEndpoint.isEmpty,
offstage: addressListViewModel.payjoinEndpoint.isEmpty || addressListViewModel.isSilentPayments,
child: Padding(
padding: EdgeInsets.only(top: 12),
child: PrimaryImageButton(
onPressed: () {
Clipboard.setData(
ClipboardData(text: addressUri.toString()));
Clipboard.setData(ClipboardData(text: addressUri.toString()));
showBar<void>(context, S.of(context).copied_to_clipboard);
},
image: Image.asset(
@ -227,9 +226,7 @@ class QRWidget extends StatelessWidget {
),
text: S.of(context).copy_payjoin_url,
color: Theme.of(context).cardColor,
textColor: Theme.of(context)
.extension<CakeTextTheme>()!
.buttonTextColor,
textColor: Theme.of(context).extension<CakeTextTheme>()!.buttonTextColor,
),
),
),

View file

@ -600,6 +600,8 @@ class SendCardState extends State<SendCard> with AutomaticKeepAliveClientMixin<S
final maxCustomFeeRate = sendViewModel.feesViewModel.maxCustomFeeRate?.toDouble();
double? customFeeRate = isBitcoinWallet ? sendViewModel.feesViewModel.customBitcoinFeeRate.toDouble() : null;
FocusManager.instance.primaryFocus?.unfocus();
await showPopUp<void>(
context: context,
builder: (BuildContext context) {

View file

@ -225,7 +225,7 @@ class ExceptionHandler {
// just ignoring until we find a solution to this issue or migrate from flutter secure storage
"core/auth_service.dart:64",
"core/key_service.dart:14",
"core/wallet_loading_service.dart:134",
"core/wallet_loading_service.dart:139",
];
static Future<void> _addDeviceInfo(File file) async {

View file

@ -82,7 +82,7 @@ class BitcoinURI extends PaymentURI {
final qp = <String, String>{};
if (amount.isNotEmpty) qp['amount'] = amount.replaceAll(',', '.');
if (pjUri.isNotEmpty) {
if (pjUri.isNotEmpty && !address.startsWith("sp")) {
qp['pjos'] = '0';
qp['pj'] = pjUri;
}

View file

@ -14,15 +14,15 @@ TYPES=($MONERO_COM $CAKEWALLET)
APP_ANDROID_TYPE=$1
MONERO_COM_NAME="Monero.com"
MONERO_COM_VERSION="4.27.0"
MONERO_COM_BUILD_NUMBER=121
MONERO_COM_VERSION="4.28.0"
MONERO_COM_BUILD_NUMBER=123
MONERO_COM_BUNDLE_ID="com.monero.app"
MONERO_COM_PACKAGE="com.monero.app"
MONERO_COM_SCHEME="monero.com"
CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="4.27.0"
CAKEWALLET_BUILD_NUMBER=259
CAKEWALLET_VERSION="4.28.0"
CAKEWALLET_BUILD_NUMBER=261
CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet"
CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet"
CAKEWALLET_SCHEME="cakewallet"

View file

@ -12,13 +12,13 @@ TYPES=($MONERO_COM $CAKEWALLET)
APP_IOS_TYPE=$1
MONERO_COM_NAME="Monero.com"
MONERO_COM_VERSION="4.27.1"
MONERO_COM_BUILD_NUMBER=120
MONERO_COM_VERSION="4.28.0"
MONERO_COM_BUILD_NUMBER=122
MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="4.27.1"
CAKEWALLET_BUILD_NUMBER=314
CAKEWALLET_VERSION="4.28.0"
CAKEWALLET_BUILD_NUMBER=318
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"

View file

@ -14,8 +14,8 @@ if [ -n "$1" ]; then
fi
CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="4.27.0"
CAKEWALLET_BUILD_NUMBER=54
CAKEWALLET_VERSION="4.28.0"
CAKEWALLET_BUILD_NUMBER=55
if ! [[ " ${TYPES[*]} " =~ " ${APP_LINUX_TYPE} " ]]; then
echo "Wrong app type."

View file

@ -16,13 +16,13 @@ if [ -n "$1" ]; then
fi
MONERO_COM_NAME="Monero.com"
MONERO_COM_VERSION="4.27.0"
MONERO_COM_BUILD_NUMBER=51
MONERO_COM_VERSION="4.28.0"
MONERO_COM_BUILD_NUMBER=53
MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="4.27.0"
CAKEWALLET_BUILD_NUMBER=113
CAKEWALLET_VERSION="4.28.0"
CAKEWALLET_BUILD_NUMBER=115
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
if ! [[ " ${TYPES[*]} " =~ " ${APP_MACOS_TYPE} " ]]; then

View file

@ -1,5 +1,5 @@
#define MyAppName "Cake Wallet"
#define MyAppVersion "4.27.0"
#define MyAppVersion "4.28.0"
#define MyAppPublisher "Cake Labs LLC"
#define MyAppURL "https://cakewallet.com/"
#define MyAppExeName "CakeWallet.exe"