From b2c8b32e4907016c587edc82473836fab9c1ef6b Mon Sep 17 00:00:00 2001 From: Omar Hatem Date: Fri, 21 Jul 2023 17:21:37 +0300 Subject: [PATCH 1/8] Free Up GitHub Actions Ubuntu Runner Disk Space (#1009) --- .github/workflows/pr_test_build.yml | 7 +++++++ lib/utils/exception_handler.dart | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pr_test_build.yml b/.github/workflows/pr_test_build.yml index 4ca762c12..16b036344 100644 --- a/.github/workflows/pr_test_build.yml +++ b/.github/workflows/pr_test_build.yml @@ -13,6 +13,13 @@ jobs: KEY_PASS: test@cake_wallet steps: + - name: Free Up GitHub Actions Ubuntu Runner Disk Space + run: | + sudo rm -rf /usr/share/dotnet + sudo rm -rf /opt/ghc + sudo rm -rf "/usr/local/share/boost" + sudo rm -rf "$AGENT_TOOLSDIRECTORY" + - uses: actions/checkout@v2 - uses: actions/setup-java@v1 with: diff --git a/lib/utils/exception_handler.dart b/lib/utils/exception_handler.dart index ce988bf4b..5c0ec49cc 100644 --- a/lib/utils/exception_handler.dart +++ b/lib/utils/exception_handler.dart @@ -132,9 +132,9 @@ class ExceptionHandler { static const List _ignoredErrors = const [ "Bad file descriptor", "No space left on device", - "Write failed (OS Error: Broken pipe", + "OS Error: Broken pipe", "Can't assign requested address", - "Read failed (OS Error: Socket is not connected", + "OS Error: Socket is not connected", "Operation timed out", "No route to host", "Software caused connection abort", From da2f1c62f56de919658170af1f8fae58eba3ee47 Mon Sep 17 00:00:00 2001 From: Konstantin Ullrich Date: Wed, 26 Jul 2023 18:48:53 +0200 Subject: [PATCH 2/8] CW-443 Use networkWallets on OnRamper (#1012) * CW-443 Use networkWallets on OnRamper * CW-443 Normalize XMR --- lib/buy/onramper/onramper_buy_provider.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/buy/onramper/onramper_buy_provider.dart b/lib/buy/onramper/onramper_buy_provider.dart index 33c63df61..68be59f4e 100644 --- a/lib/buy/onramper/onramper_buy_provider.dart +++ b/lib/buy/onramper/onramper_buy_provider.dart @@ -20,6 +20,8 @@ class OnRamperBuyProvider { switch (_wallet.currency) { case CryptoCurrency.ltc: return "LTC_LITECOIN"; + case CryptoCurrency.xmr: + return "XMR_MONERO"; default: return _wallet.currency.title; } @@ -60,11 +62,12 @@ class OnRamperBuyProvider { break; } + final networkName = _wallet.currency.fullName?.toUpperCase().replaceAll(" ", ""); return Uri.https(_baseUrl, '', { 'apiKey': _apiKey, 'defaultCrypto': _normalizeCryptoCurrency, - 'wallets': '${_wallet.currency.title}:${_wallet.walletAddresses.address}', + 'networkWallets': '${networkName}:${_wallet.walletAddresses.address}', 'supportSell': "false", 'supportSwap': "false", 'primaryColor': primaryColor, From b28f85350a659912ac22d9f35d44171ebb169488 Mon Sep 17 00:00:00 2001 From: Matthew Fosse Date: Wed, 26 Jul 2023 21:08:12 -0400 Subject: [PATCH 3/8] CW-441 xmr price issue (#1005) * refactor fiat_rate_update * remove commented line --- lib/reactions/fiat_rate_update.dart | 18 +++++++++++++++++- .../dashboard/balance_view_model.dart | 3 ++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/lib/reactions/fiat_rate_update.dart b/lib/reactions/fiat_rate_update.dart index f9ddbef52..336f04970 100644 --- a/lib/reactions/fiat_rate_update.dart +++ b/lib/reactions/fiat_rate_update.dart @@ -6,6 +6,7 @@ import 'package:cake_wallet/store/app_store.dart'; import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart'; import 'package:cake_wallet/store/settings_store.dart'; import 'package:cw_core/wallet_type.dart'; +import 'package:mobx/mobx.dart'; Timer? _timer; @@ -15,7 +16,7 @@ Future startFiatRateUpdate( return; } - _timer = Timer.periodic(Duration(seconds: 30), (_) async { + final _updateFiat = (_) async { try { if (appStore.wallet == null || settingsStore.fiatApiMode == FiatApiMode.disabled) { return; @@ -33,5 +34,20 @@ Future startFiatRateUpdate( } catch (e) { print(e); } + }; + + _timer = Timer.periodic(Duration(seconds: 30), _updateFiat); + // also run immediately: + _updateFiat(null); + + // setup autorun to listen to changes in fiatApiMode + autorun((_) { + // restart the timer if fiatApiMode was re-enabled + if (settingsStore.fiatApiMode != FiatApiMode.disabled) { + _timer = Timer.periodic(Duration(seconds: 30), _updateFiat); + _updateFiat(null); + } else { + _timer?.cancel(); + } }); } diff --git a/lib/view_model/dashboard/balance_view_model.dart b/lib/view_model/dashboard/balance_view_model.dart index 810d8e415..a36ad609c 100644 --- a/lib/view_model/dashboard/balance_view_model.dart +++ b/lib/view_model/dashboard/balance_view_model.dart @@ -66,7 +66,8 @@ abstract class BalanceViewModelBase with Store { final price = fiatConvertationStore.prices[appStore.wallet!.currency]; if (price == null) { - throw Exception('No price for ${appStore.wallet!.currency} (current wallet)'); + // price should update on next fetch: + return 0; } return price; From 962074c093e14b6db16b7cd4cd4d0f117118f8e9 Mon Sep 17 00:00:00 2001 From: Matthew Fosse Date: Mon, 31 Jul 2023 14:06:45 -0400 Subject: [PATCH 4/8] fix nav-bar issue (#1010) Co-authored-by: fossephate --- lib/src/widgets/nav_bar.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/widgets/nav_bar.dart b/lib/src/widgets/nav_bar.dart index aabe8d9c8..54b11c32f 100644 --- a/lib/src/widgets/nav_bar.dart +++ b/lib/src/widgets/nav_bar.dart @@ -66,6 +66,7 @@ class NavBar extends StatelessWidget implements ObstructingPreferredSizeWidget { leading: leading, automaticallyImplyLeading: false, automaticallyImplyMiddle: false, + transitionBetweenRoutes: false, middle: middle, trailing: trailing, backgroundColor: backgroundColor, From cfaa89d1657f95f25b8061791c1a3ec1599240e0 Mon Sep 17 00:00:00 2001 From: Konstantin Ullrich Date: Tue, 1 Aug 2023 14:00:00 +0200 Subject: [PATCH 5/8] CW-425 use the open alias new line UI (#1004) * CW-425 Display Contact Name in the send view * CW-425 Ignore false positives on OpenAlias --- lib/entities/openalias_record.dart | 2 +- lib/entities/parsed_address.dart | 28 ++++-- .../widgets/extract_address_from_parsed.dart | 3 +- lib/src/screens/send/widgets/send_card.dart | 48 +++++----- lib/src/widgets/address_text_field.dart | 88 +++++++------------ lib/view_model/send/output.dart | 11 ++- pubspec_base.yaml | 3 +- 7 files changed, 89 insertions(+), 94 deletions(-) diff --git a/lib/entities/openalias_record.dart b/lib/entities/openalias_record.dart index 842a711fe..6d8b759f5 100644 --- a/lib/entities/openalias_record.dart +++ b/lib/entities/openalias_record.dart @@ -37,7 +37,7 @@ class OpenaliasRecord { required String ticker, required List txtRecord, }) { - String address = formattedName; + String address = ''; String name = formattedName; String note = ''; diff --git a/lib/entities/parsed_address.dart b/lib/entities/parsed_address.dart index a73b44e33..67caebcb5 100644 --- a/lib/entities/parsed_address.dart +++ b/lib/entities/parsed_address.dart @@ -1,7 +1,7 @@ import 'package:cake_wallet/entities/openalias_record.dart'; import 'package:cake_wallet/entities/yat_record.dart'; -enum ParseFrom { unstoppableDomains, openAlias, yatRecord, fio, notParsed, twitter } +enum ParseFrom { unstoppableDomains, openAlias, yatRecord, fio, notParsed, twitter, contact } class ParsedAddress { ParsedAddress({ @@ -40,13 +40,17 @@ class ParsedAddress { ); } - factory ParsedAddress.fetchOpenAliasAddress({required OpenaliasRecord record, required String name}){ - return ParsedAddress( - addresses: [record.address], - name: record.name, - description: record.description, - parseFrom: ParseFrom.openAlias, - ); + factory ParsedAddress.fetchOpenAliasAddress( + {required OpenaliasRecord record, required String name}) { + if (record.address.isEmpty) { + return ParsedAddress(addresses: [name]); + } + return ParsedAddress( + addresses: [record.address], + name: record.name, + description: record.description, + parseFrom: ParseFrom.openAlias, + ); } factory ParsedAddress.fetchFioAddress({required String address, required String name}){ @@ -65,6 +69,14 @@ class ParsedAddress { ); } + factory ParsedAddress.fetchContactAddress({required String address, required String name}){ + return ParsedAddress( + addresses: [address], + name: name, + parseFrom: ParseFrom.contact, + ); + } + final List addresses; final String name; final String description; diff --git a/lib/src/screens/send/widgets/extract_address_from_parsed.dart b/lib/src/screens/send/widgets/extract_address_from_parsed.dart index a293835a3..d7e0e3d7f 100644 --- a/lib/src/screens/send/widgets/extract_address_from_parsed.dart +++ b/lib/src/screens/send/widgets/extract_address_from_parsed.dart @@ -68,6 +68,7 @@ Future extractAddressFromParsed( } return address; + case ParseFrom.contact: case ParseFrom.notParsed: address = parsedAddress.addresses.first; return address; @@ -85,4 +86,4 @@ Future extractAddressFromParsed( }); return address; -} \ No newline at end of file +} diff --git a/lib/src/screens/send/widgets/send_card.dart b/lib/src/screens/send/widgets/send_card.dart index 2b4b40fa3..d07516f79 100644 --- a/lib/src/screens/send/widgets/send_card.dart +++ b/lib/src/screens/send/widgets/send_card.dart @@ -103,7 +103,7 @@ class SendCardState extends State config: KeyboardActionsConfig( keyboardActionsPlatform: KeyboardActionsPlatform.IOS, keyboardBarColor: Theme.of(context) - .accentTextTheme! + .accentTextTheme .bodyLarge! .backgroundColor!, nextFocus: false, @@ -127,9 +127,9 @@ class SendCardState extends State bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)), gradient: LinearGradient(colors: [ - Theme.of(context).primaryTextTheme!.titleMedium!.color!, + Theme.of(context).primaryTextTheme.titleMedium!.color!, Theme.of(context) - .primaryTextTheme! + .primaryTextTheme .titleMedium! .decorationColor!, ], begin: Alignment.topLeft, end: Alignment.bottomRight), @@ -165,11 +165,11 @@ class SendCardState extends State AddressTextFieldOption.addressBook ], buttonColor: Theme.of(context) - .primaryTextTheme! + .primaryTextTheme .headlineMedium! .color!, borderColor: Theme.of(context) - .primaryTextTheme! + .primaryTextTheme .headlineSmall! .color!, textStyle: TextStyle( @@ -180,7 +180,7 @@ class SendCardState extends State fontSize: 14, fontWeight: FontWeight.w500, color: Theme.of(context) - .primaryTextTheme! + .primaryTextTheme .headlineSmall! .decorationColor!), onPushPasteButton: (context) async { @@ -189,7 +189,9 @@ class SendCardState extends State }, onPushAddressBookButton: (context) async { output.resetParsedAddress(); - await output.fetchParsedAddress(context); + }, + onSelectedContact: (contact) { + output.loadContact(contact); }, validator: validator, selectedCurrency: sendViewModel.currency, @@ -201,7 +203,7 @@ class SendCardState extends State controller: extractedAddressController, readOnly: true, borderColor: Theme.of(context) - .primaryTextTheme! + .primaryTextTheme .headlineSmall! .color!, textStyle: TextStyle( @@ -233,7 +235,7 @@ class SendCardState extends State height: 32, decoration: BoxDecoration( color: Theme.of(context) - .primaryTextTheme! + .primaryTextTheme .headlineMedium! .color!, borderRadius: @@ -246,7 +248,7 @@ class SendCardState extends State fontSize: 12, fontWeight: FontWeight.bold, color: Theme.of(context) - .primaryTextTheme! + .primaryTextTheme .headlineMedium! .decorationColor!)), ), @@ -287,7 +289,7 @@ class SendCardState extends State color: Colors.white), placeholderTextStyle: TextStyle( color: Theme.of(context) - .primaryTextTheme! + .primaryTextTheme .headlineSmall! .decorationColor!, fontWeight: FontWeight.w500, @@ -308,7 +310,7 @@ class SendCardState extends State child: Container( decoration: BoxDecoration( color: Theme.of(context) - .primaryTextTheme! + .primaryTextTheme .headlineMedium! .color!, borderRadius: @@ -325,7 +327,7 @@ class SendCardState extends State FontWeight.bold, color: Theme.of(context) - .primaryTextTheme! + .primaryTextTheme .headlineMedium! .decorationColor!))), ))))]), @@ -334,7 +336,7 @@ class SendCardState extends State ) )), Divider(height: 1,color: Theme.of(context) - .primaryTextTheme! + .primaryTextTheme .headlineSmall! .decorationColor!), Observer( @@ -353,7 +355,7 @@ class SendCardState extends State fontSize: 12, fontWeight: FontWeight.w600, color: Theme.of(context) - .primaryTextTheme! + .primaryTextTheme .headlineSmall! .decorationColor!), )), @@ -363,7 +365,7 @@ class SendCardState extends State fontSize: 12, fontWeight: FontWeight.w600, color: Theme.of(context) - .primaryTextTheme! + .primaryTextTheme .headlineSmall! .decorationColor!), ) @@ -394,7 +396,7 @@ class SendCardState extends State ), hintText: '0.00', borderColor: Theme.of(context) - .primaryTextTheme! + .primaryTextTheme .headlineSmall! .color!, textStyle: TextStyle( @@ -403,7 +405,7 @@ class SendCardState extends State color: Colors.white), placeholderTextStyle: TextStyle( color: Theme.of(context) - .primaryTextTheme!.headlineSmall!.decorationColor!, + .primaryTextTheme.headlineSmall!.decorationColor!, fontWeight: FontWeight.w500, fontSize: 14), )), @@ -414,7 +416,7 @@ class SendCardState extends State keyboardType: TextInputType.multiline, maxLines: null, borderColor: Theme.of(context) - .primaryTextTheme! + .primaryTextTheme .headlineSmall! .color!, textStyle: TextStyle( @@ -426,7 +428,7 @@ class SendCardState extends State fontSize: 14, fontWeight: FontWeight.w500, color: Theme.of(context) - .primaryTextTheme! + .primaryTextTheme .headlineSmall! .decorationColor!), ), @@ -490,7 +492,7 @@ class SendCardState extends State FontWeight.w600, color: Theme .of(context) - .primaryTextTheme! + .primaryTextTheme .headlineSmall! .decorationColor!)) ), @@ -586,7 +588,7 @@ class SendCardState extends State }); noteController.addListener(() { - final note = noteController.text ?? ''; + final note = noteController.text; if (note != output.note) { output.note = note; @@ -676,4 +678,4 @@ class SendCardState extends State @override bool get wantKeepAlive => true; -} \ No newline at end of file +} diff --git a/lib/src/widgets/address_text_field.dart b/lib/src/widgets/address_text_field.dart index 9017aa8b1..3462c7ed4 100644 --- a/lib/src/widgets/address_text_field.dart +++ b/lib/src/widgets/address_text_field.dart @@ -1,4 +1,3 @@ - import 'package:cake_wallet/utils/device_info.dart'; import 'package:cake_wallet/utils/responsive_layout_util.dart'; import 'package:flutter/services.dart'; @@ -16,10 +15,7 @@ class AddressTextField extends StatelessWidget { {required this.controller, this.isActive = true, this.placeholder, - this.options = const [ - AddressTextFieldOption.qrCode, - AddressTextFieldOption.addressBook - ], + this.options = const [AddressTextFieldOption.qrCode, AddressTextFieldOption.addressBook], this.onURIScanned, this.focusNode, this.isBorderExist = true, @@ -31,6 +27,7 @@ class AddressTextField extends StatelessWidget { this.validator, this.onPushPasteButton, this.onPushAddressBookButton, + this.onSelectedContact, this.selectedCurrency}); static const prefixIconWidth = 34.0; @@ -52,6 +49,7 @@ class AddressTextField extends StatelessWidget { final FocusNode? focusNode; final Function(BuildContext context)? onPushPasteButton; final Function(BuildContext context)? onPushAddressBookButton; + final Function(ContactBase contact)? onSelectedContact; final CryptoCurrency? selectedCurrency; @override @@ -66,34 +64,27 @@ class AddressTextField extends StatelessWidget { controller: controller, focusNode: focusNode, style: textStyle ?? - TextStyle( - fontSize: 16, - color: Theme.of(context).primaryTextTheme!.titleLarge!.color!), + TextStyle(fontSize: 16, color: Theme.of(context).primaryTextTheme.titleLarge!.color!), decoration: InputDecoration( suffixIcon: SizedBox( - width: prefixIconWidth * options.length + - (spaceBetweenPrefixIcons * options.length), + width: prefixIconWidth * options.length + (spaceBetweenPrefixIcons * options.length), ), - hintStyle: hintStyle ?? - TextStyle(fontSize: 16, color: Theme.of(context).hintColor), + hintStyle: hintStyle ?? TextStyle(fontSize: 16, color: Theme.of(context).hintColor), hintText: placeholder ?? S.current.widgets_address, focusedBorder: isBorderExist ? UnderlineInputBorder( borderSide: BorderSide( - color: borderColor ?? Theme.of(context).dividerColor, - width: 1.0)) + color: borderColor ?? Theme.of(context).dividerColor, width: 1.0)) : InputBorder.none, disabledBorder: isBorderExist ? UnderlineInputBorder( borderSide: BorderSide( - color: borderColor ?? Theme.of(context).dividerColor, - width: 1.0)) + color: borderColor ?? Theme.of(context).dividerColor, width: 1.0)) : InputBorder.none, enabledBorder: isBorderExist ? UnderlineInputBorder( borderSide: BorderSide( - color: borderColor ?? Theme.of(context).dividerColor, - width: 1.0)) + color: borderColor ?? Theme.of(context).dividerColor, width: 1.0)) : InputBorder.none, ), validator: validator, @@ -102,11 +93,11 @@ class AddressTextField extends StatelessWidget { top: 2, right: 0, child: SizedBox( - width: prefixIconWidth * options.length + - (spaceBetweenPrefixIcons * options.length), + width: prefixIconWidth * options.length + (spaceBetweenPrefixIcons * options.length), child: Row( - mainAxisAlignment: ResponsiveLayoutUtil.instance.isMobile - ? MainAxisAlignment.spaceBetween : MainAxisAlignment.end, + mainAxisAlignment: ResponsiveLayoutUtil.instance.isMobile + ? MainAxisAlignment.spaceBetween + : MainAxisAlignment.end, children: [ SizedBox(width: 5), if (this.options.contains(AddressTextFieldOption.paste)) ...[ @@ -122,20 +113,14 @@ class AddressTextField extends StatelessWidget { padding: EdgeInsets.all(8), decoration: BoxDecoration( color: buttonColor ?? - Theme.of(context) - .accentTextTheme - ! - .titleLarge! - .color!, - borderRadius: - BorderRadius.all(Radius.circular(6))), + Theme.of(context).accentTextTheme.titleLarge!.color!, + borderRadius: BorderRadius.all(Radius.circular(6))), child: Image.asset( 'assets/images/paste_ios.png', color: iconColor ?? Theme.of(context) .primaryTextTheme - ! - .headlineMedium! + .headlineMedium! .decorationColor!, )), ), @@ -155,28 +140,21 @@ class AddressTextField extends StatelessWidget { padding: EdgeInsets.all(8), decoration: BoxDecoration( color: buttonColor ?? - Theme.of(context) - .accentTextTheme - - .titleLarge! - .color!, - borderRadius: - BorderRadius.all(Radius.circular(6))), + Theme.of(context).accentTextTheme.titleLarge!.color!, + borderRadius: BorderRadius.all(Radius.circular(6))), child: Image.asset( 'assets/images/qr_code_icon.png', color: iconColor ?? Theme.of(context) .primaryTextTheme - !.headlineMedium! + .headlineMedium! .decorationColor!, )), ), )) ] else SizedBox(width: 5), - if (this - .options - .contains(AddressTextFieldOption.addressBook)) ...[ + if (this.options.contains(AddressTextFieldOption.addressBook)) ...[ Container( width: prefixIconWidth, height: prefixIconHeight, @@ -184,26 +162,19 @@ class AddressTextField extends StatelessWidget { child: Semantics( label: S.of(context).address_book, child: InkWell( - onTap: () async => - _presetAddressBookPicker(context), + onTap: () async => _presetAddressBookPicker(context), child: Container( padding: EdgeInsets.all(8), decoration: BoxDecoration( color: buttonColor ?? - Theme.of(context) - .accentTextTheme - ! - .titleLarge! - .color!, - borderRadius: - BorderRadius.all(Radius.circular(6))), + Theme.of(context).accentTextTheme.titleLarge!.color!, + borderRadius: BorderRadius.all(Radius.circular(6))), child: Image.asset( 'assets/images/open_book.png', color: iconColor ?? Theme.of(context) .primaryTextTheme - ! - .headlineMedium! + .headlineMedium! .decorationColor!, )), ), @@ -221,30 +192,31 @@ class AddressTextField extends StatelessWidget { if (code.isEmpty) { return; } - + try { final uri = Uri.parse(code); controller?.text = uri.path; onURIScanned?.call(uri); - } catch(_){ + } catch (_) { controller?.text = code; } } Future _presetAddressBookPicker(BuildContext context) async { final contact = await Navigator.of(context) - .pushNamed(Routes.pickerAddressBook,arguments: selectedCurrency); + .pushNamed(Routes.pickerAddressBook, arguments: selectedCurrency); - if (contact is ContactBase && contact.address != null) { + if (contact is ContactBase) { controller?.text = contact.address; onPushAddressBookButton?.call(context); + onSelectedContact?.call(contact); } } Future _pasteAddress(BuildContext context) async { final clipboard = await Clipboard.getData('text/plain'); final address = clipboard?.text ?? ''; - + if (address.isNotEmpty) { controller?.text = address; } diff --git a/lib/view_model/send/output.dart b/lib/view_model/send/output.dart index 74628f24e..f9ec749ab 100644 --- a/lib/view_model/send/output.dart +++ b/lib/view_model/send/output.dart @@ -17,6 +17,8 @@ import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/bitcoin/bitcoin.dart'; +import 'package:cake_wallet/entities/contact_base.dart'; + part 'output.g.dart'; const String cryptoNumberPattern = '0.0'; @@ -70,7 +72,7 @@ abstract class OutputBase with Store { int amount = 0; try { - if (cryptoAmount?.isNotEmpty ?? false) { + if (cryptoAmount.isNotEmpty) { final _cryptoAmount = cryptoAmount.replaceAll(',', '.'); int _amount = 0; switch (walletType) { @@ -240,4 +242,11 @@ abstract class OutputBase with Store { extractedAddress = await extractAddressFromParsed(context, parsedAddress); note = parsedAddress.description; } + + void loadContact(ContactBase contact) { + address = contact.name; + parsedAddress = ParsedAddress.fetchContactAddress(address: contact.address, name: contact.name); + extractedAddress = parsedAddress.addresses.first; + note = parsedAddress.description; + } } diff --git a/pubspec_base.yaml b/pubspec_base.yaml index 2c8908aea..9355dc739 100644 --- a/pubspec_base.yaml +++ b/pubspec_base.yaml @@ -3,7 +3,6 @@ dependencies: sdk: flutter flutter_localizations: sdk: flutter - flutter_cupertino_localizations: ^1.0.1 intl: ^0.17.0 url_launcher: ^6.1.4 qr_flutter: @@ -128,4 +127,4 @@ flutter: - asset: assets/fonts/Lato-Regular.ttf - asset: assets/fonts/Lato-Medium.ttf - asset: assets/fonts/Lato-Semibold.ttf - - asset: assets/fonts/Lato-Bold.ttf \ No newline at end of file + - asset: assets/fonts/Lato-Bold.ttf From c68baf72447001490ce691b0143cf6c992dfca65 Mon Sep 17 00:00:00 2001 From: Konstantin Ullrich Date: Tue, 1 Aug 2023 14:52:03 +0200 Subject: [PATCH 6/8] CW-423 Use SensitiveClipboard for sensitive Stings (#1013) * CW-423 Use SensitiveClipboard for sensitive Stings * CW-423 Bump Android Target and Min SDK * CW-423 Use Helper function for sensitive Clipboard --- android/app/build.gradle | 4 +- lib/src/screens/backup/backup_page.dart | 40 +++++++++---------- lib/src/screens/seed/pre_seed_page.dart | 12 +++--- lib/src/screens/seed/wallet_seed_page.dart | 6 +-- .../screens/setup_2fa/setup_2fa_qr_page.dart | 19 +++++---- .../screens/wallet_keys/wallet_keys_page.dart | 17 ++++---- lib/utils/clipboard_util.dart | 15 +++++++ pubspec_base.yaml | 1 + 8 files changed, 67 insertions(+), 47 deletions(-) create mode 100644 lib/utils/clipboard_util.dart diff --git a/android/app/build.gradle b/android/app/build.gradle index 00cef6393..946c53697 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -45,8 +45,8 @@ android { defaultConfig { applicationId appProperties['id'] - minSdkVersion 21 - targetSdkVersion 31 + minSdkVersion 24 + targetSdkVersion 33 versionCode flutterVersionCode.toInteger() versionName flutterVersionName testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/lib/src/screens/backup/backup_page.dart b/lib/src/screens/backup/backup_page.dart index 6f720ed9a..1b3b7e3d9 100644 --- a/lib/src/screens/backup/backup_page.dart +++ b/lib/src/screens/backup/backup_page.dart @@ -1,21 +1,22 @@ import 'dart:io'; +import 'package:cake_wallet/core/execution_state.dart'; +import 'package:cake_wallet/src/screens/base_page.dart'; +import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; +import 'package:cake_wallet/src/widgets/primary_button.dart'; +import 'package:cake_wallet/src/widgets/trail_button.dart'; +import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/palette.dart'; +import 'package:cake_wallet/routes.dart'; +import 'package:cake_wallet/utils/clipboard_util.dart'; import 'package:cake_wallet/utils/exception_handler.dart'; import 'package:cake_wallet/utils/share_util.dart'; +import 'package:cake_wallet/utils/show_bar.dart'; +import 'package:cake_wallet/utils/show_pop_up.dart'; +import 'package:cake_wallet/view_model/backup_view_model.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; -import 'package:cake_wallet/utils/show_bar.dart'; -import 'package:cake_wallet/routes.dart'; -import 'package:cake_wallet/generated/i18n.dart'; -import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; -import 'package:cake_wallet/src/widgets/primary_button.dart'; -import 'package:cake_wallet/src/widgets/trail_button.dart'; -import 'package:cake_wallet/utils/show_pop_up.dart'; -import 'package:cake_wallet/view_model/backup_view_model.dart'; -import 'package:cake_wallet/core/execution_state.dart'; -import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:permission_handler/permission_handler.dart'; class BackupPage extends BasePage { @@ -52,7 +53,7 @@ class BackupPage extends BasePage { child: Observer( builder: (_) => GestureDetector( onTap: () { - Clipboard.setData( + ClipboardUtil.setSensitiveDataToClipboard( ClipboardData(text: backupViewModelBase.backupPassword)); showBar( context, @@ -75,15 +76,14 @@ class BackupPage extends BasePage { ]))), Positioned( child: Observer( - builder: (_) => LoadingPrimaryButton( - isLoading: backupViewModelBase.state is IsExecutingState, - onPressed: () => onExportBackup(context), - text: S.of(context).export_backup, - color: Theme.of(context) - .accentTextTheme! - .bodyLarge! - .color!, - textColor: Colors.white)), + builder: (_) => LoadingPrimaryButton( + isLoading: backupViewModelBase.state is IsExecutingState, + onPressed: () => onExportBackup(context), + text: S.of(context).export_backup, + color: Theme.of(context).accentTextTheme.bodyLarge!.color!, + textColor: Colors.white, + ), + ), bottom: 24, left: 24, right: 24, diff --git a/lib/src/screens/seed/pre_seed_page.dart b/lib/src/screens/seed/pre_seed_page.dart index 6a8b6aa82..11bae8ac9 100644 --- a/lib/src/screens/seed/pre_seed_page.dart +++ b/lib/src/screens/seed/pre_seed_page.dart @@ -1,11 +1,11 @@ -import 'package:cake_wallet/utils/responsive_layout_util.dart'; -import 'package:cw_core/wallet_type.dart'; +import 'package:cake_wallet/src/screens/base_page.dart'; +import 'package:cake_wallet/src/widgets/primary_button.dart'; +import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/themes/theme_base.dart'; +import 'package:cake_wallet/utils/responsive_layout_util.dart'; +import 'package:cw_core/wallet_type.dart'; import 'package:flutter/material.dart'; -import 'package:cake_wallet/generated/i18n.dart'; -import 'package:cake_wallet/src/widgets/primary_button.dart'; -import 'package:cake_wallet/src/screens/base_page.dart'; class PreSeedPage extends BasePage { PreSeedPage(this.type) @@ -61,7 +61,7 @@ class PreSeedPage extends BasePage { onPressed: () => Navigator.of(context).popAndPushNamed(Routes.seed, arguments: true), text: S.of(context).pre_seed_button_text, - color: Theme.of(context).accentTextTheme!.bodyLarge!.color!, + color: Theme.of(context).accentTextTheme.bodyLarge!.color!, textColor: Colors.white) ], ), diff --git a/lib/src/screens/seed/wallet_seed_page.dart b/lib/src/screens/seed/wallet_seed_page.dart index f37a24dcd..b3128375c 100644 --- a/lib/src/screens/seed/wallet_seed_page.dart +++ b/lib/src/screens/seed/wallet_seed_page.dart @@ -1,6 +1,7 @@ import 'package:cake_wallet/palette.dart'; import 'package:cake_wallet/themes/theme_base.dart'; import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; +import 'package:cake_wallet/utils/clipboard_util.dart'; import 'package:cake_wallet/utils/share_util.dart'; import 'package:cake_wallet/utils/responsive_layout_util.dart'; import 'package:cake_wallet/utils/show_bar.dart'; @@ -92,8 +93,7 @@ class WalletSeedPage extends BasePage { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ ConstrainedBox( - constraints: - BoxConstraints(maxHeight: MediaQuery.of(context).size.height * 0.3), + constraints: BoxConstraints(maxHeight: MediaQuery.of(context).size.height * 0.3), child: AspectRatio(aspectRatio: 1, child: image), ), Observer(builder: (_) { @@ -159,7 +159,7 @@ class WalletSeedPage extends BasePage { child: Builder( builder: (context) => PrimaryButton( onPressed: () { - Clipboard.setData( + ClipboardUtil.setSensitiveDataToClipboard( ClipboardData(text: walletSeedViewModel.seed)); showBar(context, S.of(context).copied_to_clipboard); }, diff --git a/lib/src/screens/setup_2fa/setup_2fa_qr_page.dart b/lib/src/screens/setup_2fa/setup_2fa_qr_page.dart index 90a83041f..b00d0eed8 100644 --- a/lib/src/screens/setup_2fa/setup_2fa_qr_page.dart +++ b/lib/src/screens/setup_2fa/setup_2fa_qr_page.dart @@ -1,16 +1,18 @@ import 'package:cake_wallet/core/totp_request_details.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:cake_wallet/generated/i18n.dart'; -import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/screens/receive/widgets/qr_image.dart'; +import 'package:cake_wallet/src/widgets/primary_button.dart'; +import 'package:cake_wallet/src/widgets/standard_list.dart'; +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/palette.dart'; +import 'package:cake_wallet/routes.dart'; +import 'package:cake_wallet/utils/clipboard_util.dart'; import 'package:cake_wallet/utils/show_bar.dart'; import 'package:cake_wallet/view_model/set_up_2fa_viewmodel.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:qr_flutter/qr_flutter.dart' as qr; -import '../../../palette.dart'; -import '../../widgets/primary_button.dart'; -import '../../widgets/standard_list.dart'; + class Setup2FAQRPage extends BasePage { Setup2FAQRPage({required this.setup2FAViewModel}); @@ -106,7 +108,8 @@ class Setup2FAQRPage extends BasePage { height: 32, child: InkWell( onTap: () { - Clipboard.setData(ClipboardData(text: '${setup2FAViewModel.secretKey}')); + ClipboardUtil.setSensitiveDataToClipboard( + ClipboardData(text: '${setup2FAViewModel.secretKey}')); showBar(context, S.of(context).copied_to_clipboard); }, child: Container( diff --git a/lib/src/screens/wallet_keys/wallet_keys_page.dart b/lib/src/screens/wallet_keys/wallet_keys_page.dart index 5142fb2c2..63efdc5f9 100644 --- a/lib/src/screens/wallet_keys/wallet_keys_page.dart +++ b/lib/src/screens/wallet_keys/wallet_keys_page.dart @@ -1,16 +1,17 @@ import 'package:auto_size_text/auto_size_text.dart'; import 'package:cake_wallet/entities/qr_view_data.dart'; +import 'package:cake_wallet/src/screens/base_page.dart'; +import 'package:cake_wallet/src/widgets/list_row.dart'; import 'package:cake_wallet/src/widgets/section_divider.dart'; +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/routes.dart'; +import 'package:cake_wallet/utils/clipboard_util.dart'; import 'package:cake_wallet/utils/show_bar.dart'; +import 'package:cake_wallet/view_model/wallet_keys_view_model.dart'; import 'package:device_display_brightness/device_display_brightness.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; -import 'package:cake_wallet/generated/i18n.dart'; -import 'package:cake_wallet/src/screens/base_page.dart'; -import 'package:cake_wallet/src/widgets/list_row.dart'; -import 'package:cake_wallet/view_model/wallet_keys_view_model.dart'; -import 'package:cake_wallet/routes.dart'; import 'package:qr_flutter/qr_flutter.dart'; class WalletKeysPage extends BasePage { @@ -56,7 +57,7 @@ class WalletKeysPage extends BasePage { width: double.infinity, decoration: BoxDecoration( borderRadius: BorderRadius.circular(12.0), - color: Theme.of(context).accentTextTheme!.bodySmall!.color!, + color: Theme.of(context).accentTextTheme.bodySmall!.color!, ), child: Center( child: Padding( @@ -84,7 +85,7 @@ class WalletKeysPage extends BasePage { separatorBuilder: (context, index) => Container( height: 1, padding: EdgeInsets.only(left: 24), - color: Theme.of(context).accentTextTheme!.titleLarge!.backgroundColor!, + color: Theme.of(context).accentTextTheme.titleLarge!.backgroundColor!, child: const SectionDivider(), ), itemCount: walletKeysViewModel.items.length, @@ -93,7 +94,7 @@ class WalletKeysPage extends BasePage { return GestureDetector( onTap: () { - Clipboard.setData(ClipboardData(text: item.value)); + ClipboardUtil.setSensitiveDataToClipboard(ClipboardData(text: item.value)); showBar(context, S.of(context).copied_key_to_clipboard(item.title)); }, child: ListRow( diff --git a/lib/utils/clipboard_util.dart b/lib/utils/clipboard_util.dart new file mode 100644 index 000000000..2874e30ef --- /dev/null +++ b/lib/utils/clipboard_util.dart @@ -0,0 +1,15 @@ +import 'package:flutter/services.dart'; + +import 'package:cake_wallet/utils/device_info.dart'; +import 'package:sensitive_clipboard/sensitive_clipboard.dart'; + +class ClipboardUtil { + static Future setSensitiveDataToClipboard(ClipboardData data) async { + if (DeviceInfo.instance.isMobile) { + await SensitiveClipboard.copy(data.text); + return; + } + + return Clipboard.setData(data); + } +} diff --git a/pubspec_base.yaml b/pubspec_base.yaml index 9355dc739..6c0ef5405 100644 --- a/pubspec_base.yaml +++ b/pubspec_base.yaml @@ -81,6 +81,7 @@ dependencies: path_provider_android: 2.0.24 shared_preferences_android: 2.0.17 url_launcher_android: 6.0.24 + sensitive_clipboard: ^1.0.0 bitcoin_flutter: git: url: https://github.com/cake-tech/bitcoin_flutter.git From fcf4fbdc14d2aab9e8c9eda6662dde91c1d3ae7f Mon Sep 17 00:00:00 2001 From: Rafael Saes <76502841+saltrafael@users.noreply.github.com> Date: Tue, 1 Aug 2023 19:19:04 -0300 Subject: [PATCH 7/8] Cw 433 support send templates with multiple recipients (#995) * feat: Support Send templates with multiple recipients * feat: use only first name for template display, and sum total amount * fix: amounts being wiped * feat: make send template card buttons function like send card * feat: replace amount -> name for template name * fix: template name --- lib/entities/template.dart | 23 +- lib/src/screens/send/send_page.dart | 69 ++- lib/src/screens/send/send_template_page.dart | 419 ++++++------------ .../send/widgets/send_template_card.dart | 267 +++++++++++ lib/src/widgets/template_tile.dart | 84 ++-- lib/store/templates/send_template_store.dart | 34 +- .../send/send_template_view_model.dart | 104 ++--- lib/view_model/send/template_view_model.dart | 80 ++++ res/values/strings_ar.arb | 3 +- res/values/strings_bg.arb | 3 +- res/values/strings_cs.arb | 3 +- res/values/strings_de.arb | 3 +- res/values/strings_en.arb | 3 +- res/values/strings_es.arb | 3 +- res/values/strings_fr.arb | 3 +- res/values/strings_ha.arb | 3 +- res/values/strings_hi.arb | 3 +- res/values/strings_hr.arb | 3 +- res/values/strings_id.arb | 3 +- res/values/strings_it.arb | 3 +- res/values/strings_ja.arb | 3 +- res/values/strings_ko.arb | 3 +- res/values/strings_my.arb | 3 +- res/values/strings_nl.arb | 3 +- res/values/strings_pl.arb | 3 +- res/values/strings_pt.arb | 3 +- res/values/strings_ru.arb | 3 +- res/values/strings_th.arb | 3 +- res/values/strings_tr.arb | 3 +- res/values/strings_uk.arb | 3 +- res/values/strings_ur.arb | 3 +- res/values/strings_yo.arb | 3 +- res/values/strings_zh.arb | 3 +- 33 files changed, 716 insertions(+), 439 deletions(-) create mode 100644 lib/src/screens/send/widgets/send_template_card.dart create mode 100644 lib/view_model/send/template_view_model.dart diff --git a/lib/entities/template.dart b/lib/entities/template.dart index c26e3a501..8224ecdd8 100644 --- a/lib/entities/template.dart +++ b/lib/entities/template.dart @@ -4,14 +4,15 @@ part 'template.g.dart'; @HiveType(typeId: Template.typeId) class Template extends HiveObject { - Template({ - required this.nameRaw, - required this.isCurrencySelectedRaw, - required this.addressRaw, - required this.cryptoCurrencyRaw, - required this.amountRaw, - required this.fiatCurrencyRaw, - required this.amountFiatRaw}); + Template( + {required this.nameRaw, + required this.isCurrencySelectedRaw, + required this.addressRaw, + required this.cryptoCurrencyRaw, + required this.amountRaw, + required this.fiatCurrencyRaw, + required this.amountFiatRaw, + this.additionalRecipientsRaw}); static const typeId = 6; static const boxName = 'Template'; @@ -37,6 +38,9 @@ class Template extends HiveObject { @HiveField(6) String? amountFiatRaw; + @HiveField(7) + List