diff --git a/android/app/build.gradle b/android/app/build.gradle index 74cd0f8f7..00cef6393 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -46,7 +46,7 @@ android { defaultConfig { applicationId appProperties['id'] minSdkVersion 21 - targetSdkVersion 30 + targetSdkVersion 31 versionCode flutterVersionCode.toInteger() versionName flutterVersionName testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/android/app/src/main/AndroidManifestBase.xml b/android/app/src/main/AndroidManifestBase.xml index f43b0369b..22278d5f1 100644 --- a/android/app/src/main/AndroidManifestBase.xml +++ b/android/app/src/main/AndroidManifestBase.xml @@ -21,7 +21,8 @@ android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize" - android:screenOrientation="portrait"> + android:screenOrientation="portrait" + android:exported="true"> TradeState.deserialize(raw: stateRaw); @@ -50,16 +50,16 @@ class Order extends HiveObject { @HiveField(5) DateTime createdAt; - @HiveField(6) + @HiveField(6, defaultValue: '') String amount; - @HiveField(7) + @HiveField(7, defaultValue: '') String receiveAddress; - @HiveField(8) + @HiveField(8, defaultValue: '') String walletId; - @HiveField(9) + @HiveField(9, defaultValue: 0) late int providerRaw; BuyProviderDescription get provider => diff --git a/lib/di.dart b/lib/di.dart index 01d77b881..b84f98ad9 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -704,6 +704,7 @@ Future setup( ioniaAnyPayService: getIt.get(), amount: amount, ioniaMerchant: merchant, + sendViewModel: getIt.get() ); }); diff --git a/lib/entities/contact.dart b/lib/entities/contact.dart index b76e4de43..e111429ca 100644 --- a/lib/entities/contact.dart +++ b/lib/entities/contact.dart @@ -17,13 +17,13 @@ class Contact extends HiveObject with Keyable { static const typeId = 0; static const boxName = 'Contacts'; - @HiveField(0) + @HiveField(0, defaultValue: '') String name; - @HiveField(1) + @HiveField(1, defaultValue: '') String address; - @HiveField(2) + @HiveField(2, defaultValue: 0) late int raw; CryptoCurrency get type => CryptoCurrency.deserialize(raw: raw); diff --git a/lib/entities/transaction_description.dart b/lib/entities/transaction_description.dart index 868077733..86d6b043a 100644 --- a/lib/entities/transaction_description.dart +++ b/lib/entities/transaction_description.dart @@ -10,7 +10,7 @@ class TransactionDescription extends HiveObject { static const boxName = 'TransactionDescriptions'; static const boxKey = 'transactionDescriptionsBoxKey'; - @HiveField(0) + @HiveField(0, defaultValue: '') String id; @HiveField(1) diff --git a/lib/exchange/changenow/changenow_exchange_provider.dart b/lib/exchange/changenow/changenow_exchange_provider.dart index b663b697c..20f529733 100644 --- a/lib/exchange/changenow/changenow_exchange_provider.dart +++ b/lib/exchange/changenow/changenow_exchange_provider.dart @@ -232,7 +232,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider { final responseJSON = json.decode(response.body) as Map; final fromAmount = double.parse(responseJSON['fromAmount'].toString()); final toAmount = double.parse(responseJSON['toAmount'].toString()); - final rateId = responseJSON['rateId'] as String ?? ''; + final rateId = responseJSON['rateId'] as String? ?? ''; if (rateId.isNotEmpty) { _lastUsedRateId = rateId; diff --git a/lib/exchange/trade.dart b/lib/exchange/trade.dart index 0f6425ecc..99b73e789 100644 --- a/lib/exchange/trade.dart +++ b/lib/exchange/trade.dart @@ -40,26 +40,26 @@ class Trade extends HiveObject { static const boxName = 'Trades'; static const boxKey = 'tradesBoxKey'; - @HiveField(0) + @HiveField(0, defaultValue: '') String id; - @HiveField(1) + @HiveField(1, defaultValue: 0) late int providerRaw; ExchangeProviderDescription get provider => ExchangeProviderDescription.deserialize(raw: providerRaw); - @HiveField(2) + @HiveField(2, defaultValue: 0) late int fromRaw; CryptoCurrency get from => CryptoCurrency.deserialize(raw: fromRaw); - @HiveField(3) + @HiveField(3, defaultValue: 0) late int toRaw; CryptoCurrency get to => CryptoCurrency.deserialize(raw: toRaw); - @HiveField(4) + @HiveField(4, defaultValue: '') late String stateRaw; TradeState get state => TradeState.deserialize(raw: stateRaw); @@ -70,7 +70,7 @@ class Trade extends HiveObject { @HiveField(6) DateTime? expiredAt; - @HiveField(7) + @HiveField(7, defaultValue: '') String amount; @HiveField(8) diff --git a/lib/ionia/ionia_api.dart b/lib/ionia/ionia_api.dart index e9526a47e..274e557c7 100644 --- a/lib/ionia/ionia_api.dart +++ b/lib/ionia/ionia_api.dart @@ -36,8 +36,8 @@ class IoniaApi { throw Exception('Unexpected http status: ${response.statusCode}'); } - final bodyJson = json.decode(response.body) as Map; - final data = bodyJson['Data'] as Map; + final bodyJson = json.decode(response.body) as Map; + final data = bodyJson['Data'] as Map; final isSuccessful = bodyJson['Successful'] as bool; if (!isSuccessful) { @@ -50,13 +50,11 @@ class IoniaApi { // Verify email Future verifyEmail({ - required String username, required String email, required String code, required String clientId}) async { final headers = { 'clientId': clientId, - 'username': username, 'EmailAddress': email}; final query = {'verificationCode': code}; final uri = verifyEmailUri.replace(queryParameters: query); @@ -66,8 +64,8 @@ class IoniaApi { throw Exception('Unexpected http status: ${response.statusCode}'); } - final bodyJson = json.decode(response.body) as Map; - final data = bodyJson['Data'] as Map; + final bodyJson = json.decode(response.body) as Map; + final data = bodyJson['Data'] as Map; final isSuccessful = bodyJson['Successful'] as bool; if (!isSuccessful) { @@ -75,13 +73,13 @@ class IoniaApi { } final password = data['password'] as String; - username = data['username'] as String; + final username = data['username'] as String; return IoniaUserCredentials(username, password); } // Sign In - Future signIn(String email, {required String clientId}) async { + Future signIn(String email, {required String clientId}) async { final headers = {'clientId': clientId}; final query = {'emailAddress': email}; final uri = signInUri.replace(queryParameters: query); @@ -91,15 +89,13 @@ class IoniaApi { throw Exception('Unexpected http status: ${response.statusCode}'); } - final bodyJson = json.decode(response.body) as Map; - final data = bodyJson['Data'] as Map; + final bodyJson = json.decode(response.body) as Map; + final data = bodyJson['Data'] as Map; final isSuccessful = bodyJson['Successful'] as bool; if (!isSuccessful) { throw Exception(data['ErrorMessage'] as String); } - - return data['username'] as String; } // Get virtual card @@ -118,15 +114,15 @@ class IoniaApi { throw Exception('Unexpected http status: ${response.statusCode}'); } - final bodyJson = json.decode(response.body) as Map; - final data = bodyJson['Data'] as Map; + final bodyJson = json.decode(response.body) as Map; + final data = bodyJson['Data'] as Map; final isSuccessful = bodyJson['Successful'] as bool; if (!isSuccessful) { throw Exception(data['message'] as String); } - final virtualCard = data['VirtualCard'] as Map; + final virtualCard = data['VirtualCard'] as Map; return IoniaVirtualCard.fromMap(virtualCard); } @@ -146,8 +142,8 @@ class IoniaApi { throw Exception('Unexpected http status: ${response.statusCode}'); } - final bodyJson = json.decode(response.body) as Map; - final data = bodyJson['Data'] as Map; + final bodyJson = json.decode(response.body) as Map; + final data = bodyJson['Data'] as Map; final isSuccessful = bodyJson['Successful'] as bool? ?? false; if (!isSuccessful) { diff --git a/lib/ionia/ionia_service.dart b/lib/ionia/ionia_service.dart index a18cac5cb..942bc25b5 100644 --- a/lib/ionia/ionia_service.dart +++ b/lib/ionia/ionia_service.dart @@ -31,9 +31,8 @@ class IoniaService { // Verify email Future verifyEmail(String code) async { - final username = (await secureStorage.read(key: ioniaUsernameStorageKey))!; final email = (await secureStorage.read(key: ioniaEmailStorageKey))!; - final credentials = await ioniaApi.verifyEmail(email: email, username: username, code: code, clientId: clientId); + final credentials = await ioniaApi.verifyEmail(email: email, code: code, clientId: clientId); await secureStorage.write(key: ioniaPasswordStorageKey, value: credentials.password); await secureStorage.write(key: ioniaUsernameStorageKey, value: credentials.username); } @@ -41,9 +40,8 @@ class IoniaService { // Sign In Future signIn(String email) async { - final username = await ioniaApi.signIn(email, clientId: clientId); + await ioniaApi.signIn(email, clientId: clientId); await secureStorage.write(key: ioniaEmailStorageKey, value: email); - await secureStorage.write(key: ioniaUsernameStorageKey, value: username); } Future getUserEmail() async { diff --git a/lib/ionia/ionia_virtual_card.dart b/lib/ionia/ionia_virtual_card.dart index 29736c22f..ca3e35dbc 100644 --- a/lib/ionia/ionia_virtual_card.dart +++ b/lib/ionia/ionia_virtual_card.dart @@ -11,7 +11,7 @@ class IoniaVirtualCard { required this.fundsLimit, required this.spendLimit}); - factory IoniaVirtualCard.fromMap(Map source) { + factory IoniaVirtualCard.fromMap(Map source) { final created = source['created'] as String; final createdAt = DateTime.tryParse(created); diff --git a/lib/src/screens/auth/auth_page.dart b/lib/src/screens/auth/auth_page.dart index 0b3b8511a..7a1bd8420 100644 --- a/lib/src/screens/auth/auth_page.dart +++ b/lib/src/screens/auth/auth_page.dart @@ -106,22 +106,22 @@ class AuthPageState extends State { _progressBar = null; } - Future close({String? route}) async { + Future close({String? route, dynamic arguments}) async { if (_key.currentContext == null) { throw Exception('Key context is null. Should be not happened'); } - WidgetsBinding.instance.addPostFrameCallback((_) { - dismissFlushBar(_authBar); - dismissFlushBar(_progressBar); - WidgetsBinding.instance.addPostFrameCallback((_) { - if (route != null) { - Navigator.of(_key.currentContext!).pushReplacementNamed(route); - } else { - Navigator.of(_key.currentContext!).pop(); - } - }); - }); + /// not the best scenario, but WidgetsBinding is not behaving correctly on Android + await Future.delayed(Duration(milliseconds: 50)); + await _authBar?.dismiss(); + await Future.delayed(Duration(milliseconds: 50)); + await _progressBar?.dismiss(); + await Future.delayed(Duration(milliseconds: 50)); + if (route != null) { + Navigator.of(_key.currentContext!).pushReplacementNamed(route, arguments: arguments); + } else { + Navigator.of(_key.currentContext!).pop(); + } } @override diff --git a/lib/src/screens/ionia/cards/ionia_buy_card_detail_page.dart b/lib/src/screens/ionia/cards/ionia_buy_card_detail_page.dart index f3b12e65b..4b9f0a220 100644 --- a/lib/src/screens/ionia/cards/ionia_buy_card_detail_page.dart +++ b/lib/src/screens/ionia/cards/ionia_buy_card_detail_page.dart @@ -3,7 +3,6 @@ import 'package:cake_wallet/ionia/ionia_merchant.dart'; import 'package:cake_wallet/ionia/ionia_tip.dart'; import 'package:cake_wallet/palette.dart'; import 'package:cake_wallet/routes.dart'; -import 'package:cake_wallet/src/screens/ionia/widgets/confirm_modal.dart'; import 'package:cake_wallet/src/screens/ionia/widgets/ionia_alert_model.dart'; import 'package:cake_wallet/src/screens/ionia/widgets/text_icon_button.dart'; import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; @@ -18,6 +17,7 @@ import 'package:cake_wallet/generated/i18n.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:mobx/mobx.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; +import 'package:cake_wallet/src/screens/send/widgets/confirm_sending_alert.dart'; class IoniaBuyGiftCardDetailPage extends BasePage { IoniaBuyGiftCardDetailPage(this.ioniaPurchaseViewModel); @@ -295,73 +295,35 @@ class IoniaBuyGiftCardDetailPage extends BasePage { final amount = ioniaPurchaseViewModel.invoice!.totalAmount; final addresses = ioniaPurchaseViewModel.invoice!.outAddresses; + ioniaPurchaseViewModel.sendViewModel.outputs.first.setCryptoAmount(amount); + ioniaPurchaseViewModel.sendViewModel.outputs.first.address = addresses.first; await showPopUp( context: context, builder: (_) { - return IoniaConfirmModal( + return ConfirmSendingAlert( alertTitle: S.of(context).confirm_sending, - alertContent: Container( - height: 200, - padding: EdgeInsets.all(15), - child: Column(children: [ - Row(children: [ - Text(S.of(context).payment_id, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w400, - color: PaletteDark.pigeonBlue, - decoration: TextDecoration.none)), - Text(ioniaPurchaseViewModel.invoice!.paymentId, - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w400, - color: PaletteDark.pigeonBlue, - decoration: TextDecoration.none)) - ], mainAxisAlignment: MainAxisAlignment.spaceBetween), - SizedBox(height: 10), - Row(children: [ - Text(S.of(context).amount, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w400, - color: PaletteDark.pigeonBlue, - decoration: TextDecoration.none)), - Text('$amount ${ioniaPurchaseViewModel.invoice!.chain}', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w400, - color: PaletteDark.pigeonBlue, - decoration: TextDecoration.none)) - ], mainAxisAlignment: MainAxisAlignment.spaceBetween), - SizedBox(height: 25), - Row(children: [ - Text(S.of(context).recipient_address, - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w400, - color: PaletteDark.pigeonBlue, - decoration: TextDecoration.none)) - ], mainAxisAlignment: MainAxisAlignment.center), - Expanded( - child: ListView.builder( - itemBuilder: (_, int index) { - return Text(addresses[index], - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w400, - color: PaletteDark.pigeonBlue, - decoration: TextDecoration.none)); - }, - itemCount: addresses.length, - physics: NeverScrollableScrollPhysics())) - ])), + paymentId: S.of(context).payment_id, + paymentIdValue: ioniaPurchaseViewModel.invoice!.paymentId, + amount: S.of(context).send_amount, + amountValue: '$amount ${ioniaPurchaseViewModel.invoice!.chain}', + fiatAmountValue: + '~ ${ioniaPurchaseViewModel.sendViewModel.outputs.first.fiatAmount} ' + '${ioniaPurchaseViewModel.sendViewModel.fiat.title}', + fee: S.of(context).send_fee, + feeValue: + '${ioniaPurchaseViewModel.sendViewModel.outputs.first.estimatedFee} ' + '${ioniaPurchaseViewModel.invoice!.chain}', + feeFiatAmount: + '${ioniaPurchaseViewModel.sendViewModel.outputs.first.estimatedFeeFiatAmount} ' + '${ioniaPurchaseViewModel.sendViewModel.fiat.title}', + outputs: ioniaPurchaseViewModel.sendViewModel.outputs, rightButtonText: S.of(context).ok, leftButtonText: S.of(context).cancel, - leftActionColor: Color(0xffFF6600), - rightActionColor: Theme.of(context).accentTextTheme!.bodyText1!.color!, + alertLeftActionButtonTextColor: Colors.white, + alertRightActionButtonTextColor: Colors.white, + alertLeftActionButtonColor: Palette.brightOrange, + alertRightActionButtonColor: Theme.of(context).textTheme!.subtitle2!.color, actionRightButton: () async { Navigator.of(context).pop(); await ioniaPurchaseViewModel.commitPaymentInvoice(); diff --git a/lib/src/screens/ionia/widgets/confirm_modal.dart b/lib/src/screens/ionia/widgets/confirm_modal.dart deleted file mode 100644 index cfc9a1cf1..000000000 --- a/lib/src/screens/ionia/widgets/confirm_modal.dart +++ /dev/null @@ -1,149 +0,0 @@ -import 'dart:ui'; - -import 'package:cake_wallet/palette.dart'; -import 'package:flutter/material.dart'; - -class IoniaConfirmModal extends StatelessWidget { - IoniaConfirmModal({ - required this.alertTitle, - required this.alertContent, - required this.leftButtonText, - required this.rightButtonText, - required this.actionLeftButton, - required this.actionRightButton, - required this.leftActionColor, - required this.rightActionColor, - this.hideActions = false, - }); - - final String alertTitle; - final Widget alertContent; - final String leftButtonText; - final String rightButtonText; - final VoidCallback actionLeftButton; - final VoidCallback actionRightButton; - final Color leftActionColor; - final Color rightActionColor; - final bool hideActions; - - Widget actionButtons(BuildContext context) { - return Row( - mainAxisSize: MainAxisSize.max, - children: [ - IoniaActionButton( - buttonText: leftButtonText, - action: actionLeftButton, - backgoundColor: leftActionColor, - ), - Container( - width: 1, - height: 52, - color: Theme.of(context).dividerColor, - ), - IoniaActionButton( - buttonText: rightButtonText, - action: actionRightButton, - backgoundColor: rightActionColor, - ), - ], - ); - } - - Widget title(BuildContext context) { - return Text( - alertTitle, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 20, - fontFamily: 'Lato', - fontWeight: FontWeight.w600, - color: Theme.of(context).primaryTextTheme!.headline6!.color!, - decoration: TextDecoration.none, - ), - ); - } - - @override - Widget build(BuildContext context) { - return Container( - color: Colors.transparent, - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 3.0, sigmaY: 3.0), - child: Container( - decoration: BoxDecoration(color: PaletteDark.darkNightBlue.withOpacity(0.75)), - child: Center( - child: GestureDetector( - onTap: () => null, - child: ClipRRect( - borderRadius: BorderRadius.all(Radius.circular(30)), - child: Container( - width: 327, - color: Theme.of(context).accentTextTheme!.headline6!.decorationColor!, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Padding( - padding: EdgeInsets.fromLTRB(24, 20, 24, 0), - child: title(context), - ), - Padding( - padding: EdgeInsets.only(top: 16, bottom: 8), - child: Container( - height: 1, - color: Theme.of(context).dividerColor, - ), - ), - alertContent, - actionButtons(context), - ], - ), - ), - ), - ), - ), - ), - ), - ); - } -} - -class IoniaActionButton extends StatelessWidget { - const IoniaActionButton({ - required this.buttonText, - required this.action, - required this.backgoundColor, - }); - - final String buttonText; - final VoidCallback action; - final Color backgoundColor; - - @override - Widget build(BuildContext context) { - return Flexible( - child: Container( - height: 52, - padding: EdgeInsets.only(left: 6, right: 6), - color: backgoundColor, - child: ButtonTheme( - minWidth: double.infinity, - child: TextButton( - onPressed: action, - // FIX-ME: ignored highlightColor and splashColor - //highlightColor: Colors.transparent, - //splashColor: Colors.transparent, - child: Text( - buttonText, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 15, - fontFamily: 'Lato', - fontWeight: FontWeight.w600, - color: backgoundColor != null ? Colors.white : Theme.of(context).primaryTextTheme!.bodyText2!.backgroundColor!, - decoration: TextDecoration.none, - ), - )), - ), - )); - } -} diff --git a/lib/src/screens/receive/widgets/qr_painter.dart b/lib/src/screens/receive/widgets/qr_painter.dart index 90dba73ac..e4af59f1a 100644 --- a/lib/src/screens/receive/widgets/qr_painter.dart +++ b/lib/src/screens/receive/widgets/qr_painter.dart @@ -9,7 +9,6 @@ class QrPainter extends CustomPainter { this.errorCorrectionLevel, ) : this._qr = QrCode(version, errorCorrectionLevel)..addData(data) { _p.color = this.color; - _qr.addData(data); _qrImage = QrImage(_qr); } diff --git a/lib/src/screens/send/widgets/confirm_sending_alert.dart b/lib/src/screens/send/widgets/confirm_sending_alert.dart index 317303442..a034d801e 100644 --- a/lib/src/screens/send/widgets/confirm_sending_alert.dart +++ b/lib/src/screens/send/widgets/confirm_sending_alert.dart @@ -4,10 +4,13 @@ import 'package:flutter/material.dart'; import 'package:cake_wallet/src/widgets/base_alert_dialog.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/src/widgets/cake_scrollbar.dart'; +import 'package:flutter/scheduler.dart'; class ConfirmSendingAlert extends BaseAlertDialog { ConfirmSendingAlert({ required this.alertTitle, + this.paymentId, + this.paymentIdValue, required this.amount, required this.amountValue, required this.fiatAmountValue, @@ -19,9 +22,15 @@ class ConfirmSendingAlert extends BaseAlertDialog { required this.rightButtonText, required this.actionLeftButton, required this.actionRightButton, - this.alertBarrierDismissible = true}); + this.alertBarrierDismissible = true, + this.alertLeftActionButtonTextColor, + this.alertRightActionButtonTextColor, + this.alertLeftActionButtonColor, + this.alertRightActionButtonColor}); final String alertTitle; + final String? paymentId; + final String? paymentIdValue; final String amount; final String amountValue; final String fiatAmountValue; @@ -34,6 +43,10 @@ class ConfirmSendingAlert extends BaseAlertDialog { final VoidCallback actionLeftButton; final VoidCallback actionRightButton; final bool alertBarrierDismissible; + final Color? alertLeftActionButtonTextColor; + final Color? alertRightActionButtonTextColor; + final Color? alertLeftActionButtonColor; + final Color? alertRightActionButtonColor; @override String get titleText => alertTitle; @@ -56,8 +69,22 @@ class ConfirmSendingAlert extends BaseAlertDialog { @override bool get barrierDismissible => alertBarrierDismissible; + @override + Color? get leftActionButtonTextColor => alertLeftActionButtonTextColor; + + @override + Color? get rightActionButtonTextColor => alertRightActionButtonTextColor; + + @override + Color? get leftActionButtonColor => alertLeftActionButtonColor; + + @override + Color? get rightActionButtonColor => alertRightActionButtonColor; + @override Widget content(BuildContext context) => ConfirmSendingAlertContent( + paymentId: paymentId, + paymentIdValue: paymentIdValue, amount: amount, amountValue: amountValue, fiatAmountValue: fiatAmountValue, @@ -70,6 +97,8 @@ class ConfirmSendingAlert extends BaseAlertDialog { class ConfirmSendingAlertContent extends StatefulWidget { ConfirmSendingAlertContent({ + this.paymentId, + this.paymentIdValue, required this.amount, required this.amountValue, required this.fiatAmountValue, @@ -78,6 +107,8 @@ class ConfirmSendingAlertContent extends StatefulWidget { required this.feeFiatAmount, required this.outputs}); + final String? paymentId; + final String? paymentIdValue; final String amount; final String amountValue; final String fiatAmountValue; @@ -88,6 +119,8 @@ class ConfirmSendingAlertContent extends StatefulWidget { @override ConfirmSendingAlertContentState createState() => ConfirmSendingAlertContentState( + paymentId: paymentId, + paymentIdValue: paymentIdValue, amount: amount, amountValue: amountValue, fiatAmountValue: fiatAmountValue, @@ -100,6 +133,8 @@ class ConfirmSendingAlertContent extends StatefulWidget { class ConfirmSendingAlertContentState extends State { ConfirmSendingAlertContentState({ + this.paymentId, + this.paymentIdValue, required this.amount, required this.amountValue, required this.fiatAmountValue, @@ -115,6 +150,8 @@ class ConfirmSendingAlertContentState extends State : S.current.recipient_address; } + final String? paymentId; + final String? paymentIdValue; final String amount; final String amountValue; final String fiatAmountValue; @@ -129,6 +166,7 @@ class ConfirmSendingAlertContentState extends State double fromTop = 0; String recipientTitle; int itemCount; + bool showScrollbar = false; @override Widget build(BuildContext context) { @@ -140,6 +178,12 @@ class ConfirmSendingAlertContentState extends State setState(() {}); }); + SchedulerBinding.instance.addPostFrameCallback((_) { + setState(() { + showScrollbar = controller.position.maxScrollExtent > 0; + }); + }); + return Stack( alignment: Alignment.center, clipBehavior: Clip.none, @@ -150,6 +194,44 @@ class ConfirmSendingAlertContentState extends State controller: controller, child: Column( children: [ + if (paymentIdValue != null && paymentId != null) + Padding( + padding: EdgeInsets.only(bottom: 32), + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + paymentId!, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.normal, + fontFamily: 'Lato', + color: Theme.of(context).primaryTextTheme! + .headline6!.color!, + decoration: TextDecoration.none, + ), + ), + Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Text( + paymentIdValue!, + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.w600, + fontFamily: 'Lato', + color: Theme.of(context).primaryTextTheme! + .headline6!.color!, + decoration: TextDecoration.none, + ), + ), + ], + ) + ], + ), + ), Row( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -365,7 +447,7 @@ class ConfirmSendingAlertContentState extends State ) ) ), - if (itemCount > 1) CakeScrollbar( + if (showScrollbar) CakeScrollbar( backgroundHeight: backgroundHeight, thumbHeight: thumbHeight, fromTop: fromTop, diff --git a/lib/src/widgets/base_alert_dialog.dart b/lib/src/widgets/base_alert_dialog.dart index 7713284f2..70370e227 100644 --- a/lib/src/widgets/base_alert_dialog.dart +++ b/lib/src/widgets/base_alert_dialog.dart @@ -11,6 +11,10 @@ class BaseAlertDialog extends StatelessWidget { VoidCallback get actionLeft => () {}; VoidCallback get actionRight => () {}; bool get barrierDismissible => true; + Color? get leftActionButtonTextColor => null; + Color? get rightActionButtonTextColor => null; + Color? get leftActionButtonColor => null; + Color? get rightActionButtonColor => null; Widget title(BuildContext context) { return Text( @@ -45,52 +49,64 @@ class BaseAlertDialog extends StatelessWidget { height: 52, child: Row( mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - Flexible( - child: Container( - width: double.infinity, - color: Theme.of(context).accentTextTheme!.bodyText1!.decorationColor!, - child: TextButton( - onPressed: actionLeft, - child: Text( - leftActionButtonText, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 15, - fontFamily: 'Lato', - fontWeight: FontWeight.w600, - color: Theme.of(context).primaryTextTheme!.bodyText1!.backgroundColor!, - decoration: TextDecoration.none, - ), - )), - ), - ), + Expanded( + child: TextButton( + onPressed: actionLeft, + style: TextButton.styleFrom( + backgroundColor: leftActionButtonColor ?? + Theme.of(context) + .accentTextTheme! + .bodyText1! + .decorationColor!, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.zero))), + child: Text( + leftActionButtonText, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 15, + fontFamily: 'Lato', + fontWeight: FontWeight.w600, + color: leftActionButtonTextColor ?? + Theme.of(context).primaryTextTheme! + .bodyText1!.backgroundColor!, + decoration: TextDecoration.none, + ), + )), + ), Container( width: 1, color: Theme.of(context).dividerColor, ), - Flexible( - child: Container( - width: double.infinity, - color: Theme.of(context).accentTextTheme!.bodyText2!.backgroundColor!, - child: TextButton( - onPressed: actionRight, - child: Text( - rightActionButtonText, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 15, - fontFamily: 'Lato', - fontWeight: FontWeight.w600, - color: Theme.of(context).primaryTextTheme!.bodyText2!.backgroundColor!, - decoration: TextDecoration.none, - ), - )), - ), - ), - ], - )); + Expanded( + child: TextButton( + onPressed: actionRight, + style: TextButton.styleFrom( + backgroundColor: rightActionButtonColor ?? + Theme.of(context).accentTextTheme! + .bodyText2!.backgroundColor!, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.zero))), + child: Text( + rightActionButtonText, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 15, + fontFamily: 'Lato', + fontWeight: FontWeight.w600, + color: rightActionButtonTextColor ?? + Theme.of(context) + .primaryTextTheme! + .bodyText2! + .backgroundColor!, + decoration: TextDecoration.none, + ), + )), + ), + ], + )); } @override diff --git a/lib/utils/date_picker.dart b/lib/utils/date_picker.dart index f774142bf..99274d8e0 100644 --- a/lib/utils/date_picker.dart +++ b/lib/utils/date_picker.dart @@ -45,7 +45,6 @@ Future _buildCupertinoDataPicker( initialDateTime: initialDate, minimumDate: firstDate, maximumDate: lastDate, - backgroundColor: Colors.white, ), ); } diff --git a/lib/view_model/ionia/ionia_purchase_merch_view_model.dart b/lib/view_model/ionia/ionia_purchase_merch_view_model.dart index da71f31fa..df6a23718 100644 --- a/lib/view_model/ionia/ionia_purchase_merch_view_model.dart +++ b/lib/view_model/ionia/ionia_purchase_merch_view_model.dart @@ -7,6 +7,7 @@ import 'package:cake_wallet/ionia/ionia_anypay.dart'; import 'package:cake_wallet/ionia/ionia_merchant.dart'; import 'package:cake_wallet/ionia/ionia_tip.dart'; import 'package:cake_wallet/ionia/ionia_any_pay_payment_info.dart'; +import 'package:cake_wallet/view_model/send/send_view_model.dart'; part 'ionia_purchase_merch_view_model.g.dart'; @@ -17,6 +18,7 @@ abstract class IoniaMerchPurchaseViewModelBase with Store { required this.ioniaAnyPayService, required this.amount, required this.ioniaMerchant, + required this.sendViewModel, }) : tipAmount = 0.0, percentage = 0.0, invoiceCreationState = InitialExecutionState(), @@ -40,6 +42,8 @@ abstract class IoniaMerchPurchaseViewModelBase with Store { final IoniaMerchant ioniaMerchant; + final SendViewModel sendViewModel; + final IoniaAnyPay ioniaAnyPayService; IoniaAnyPayPaymentInfo? paymentInfo; diff --git a/lib/view_model/settings/settings_view_model.dart b/lib/view_model/settings/settings_view_model.dart index 96b2e7bdd..aabe51ef1 100644 --- a/lib/view_model/settings/settings_view_model.dart +++ b/lib/view_model/settings/settings_view_model.dart @@ -156,13 +156,13 @@ abstract class SettingsViewModelBase with Store { handler: (BuildContext context) { Navigator.of(context).pushNamed(Routes.auth, arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) { - auth.close(); - if (isAuthenticatedSuccessfully) { - Navigator.of(context).pushNamed(Routes.setupPin, arguments: - (PinCodeState setupPinContext, String _) { + auth.close( + route: isAuthenticatedSuccessfully ? Routes.setupPin : null, + arguments: (PinCodeState setupPinContext, + String _) { setupPinContext.close(); - }); - } + }, + ); }); }), PickerListItem( diff --git a/scripts/android/app_env.sh b/scripts/android/app_env.sh index 929d2b444..d361c8dfa 100644 --- a/scripts/android/app_env.sh +++ b/scripts/android/app_env.sh @@ -14,14 +14,14 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN) APP_ANDROID_TYPE=$1 MONERO_COM_NAME="Monero.com" -MONERO_COM_VERSION="1.2.0" -MONERO_COM_BUILD_NUMBER=24 +MONERO_COM_VERSION="1.2.1" +MONERO_COM_BUILD_NUMBER=32 MONERO_COM_BUNDLE_ID="com.monero.app" MONERO_COM_PACKAGE="com.monero.app" CAKEWALLET_NAME="Cake Wallet" -CAKEWALLET_VERSION="4.5.0" -CAKEWALLET_BUILD_NUMBER=128 +CAKEWALLET_VERSION="4.5.1" +CAKEWALLET_BUILD_NUMBER=136 CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet" CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet" diff --git a/scripts/ios/app_env.sh b/scripts/ios/app_env.sh index 43ec68c31..8bb945680 100644 --- a/scripts/ios/app_env.sh +++ b/scripts/ios/app_env.sh @@ -13,13 +13,13 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN) APP_IOS_TYPE=$1 MONERO_COM_NAME="Monero.com" -MONERO_COM_VERSION="1.2.0" -MONERO_COM_BUILD_NUMBER=24 +MONERO_COM_VERSION="1.2.1" +MONERO_COM_BUILD_NUMBER=29 MONERO_COM_BUNDLE_ID="com.cakewallet.monero" CAKEWALLET_NAME="Cake Wallet" -CAKEWALLET_VERSION="4.5.0" -CAKEWALLET_BUILD_NUMBER=128 +CAKEWALLET_VERSION="4.5.1" +CAKEWALLET_BUILD_NUMBER=133 CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet" HAVEN_NAME="Haven"