Merge branch 'main' into CW-159-Filter-address-book-by-type

This commit is contained in:
Serhii 2022-11-21 22:03:06 +02:00
commit 1a089eaa60
26 changed files with 247 additions and 338 deletions

View file

@ -46,7 +46,7 @@ android {
defaultConfig { defaultConfig {
applicationId appProperties['id'] applicationId appProperties['id']
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 30 targetSdkVersion 31
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

View file

@ -21,7 +21,8 @@
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true" android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize" android:windowSoftInputMode="adjustResize"
android:screenOrientation="portrait"> android:screenOrientation="portrait"
android:exported="true">
<meta-data <meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable" android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background" android:resource="@drawable/launch_background"

View file

@ -36,7 +36,7 @@ class Node extends HiveObject with Keyable {
static const typeId = 1; static const typeId = 1;
static const boxName = 'Nodes'; static const boxName = 'Nodes';
@HiveField(0) @HiveField(0, defaultValue: '')
late String uriRaw; late String uriRaw;
@HiveField(1) @HiveField(1)
@ -45,7 +45,7 @@ class Node extends HiveObject with Keyable {
@HiveField(2) @HiveField(2)
String? password; String? password;
@HiveField(3) @HiveField(3, defaultValue: 0)
late int typeRaw; late int typeRaw;
@HiveField(4) @HiveField(4)

View file

@ -15,16 +15,16 @@ class UnspentCoinsInfo extends HiveObject {
static const boxName = 'Unspent'; static const boxName = 'Unspent';
static const boxKey = 'unspentBoxKey'; static const boxKey = 'unspentBoxKey';
@HiveField(0) @HiveField(0, defaultValue: '')
String walletId; String walletId;
@HiveField(1) @HiveField(1, defaultValue: '')
String hash; String hash;
@HiveField(2) @HiveField(2, defaultValue: false)
bool isFrozen; bool isFrozen;
@HiveField(3) @HiveField(3, defaultValue: false)
bool isSending; bool isSending;
@HiveField(4) @HiveField(4)

View file

@ -33,31 +33,31 @@ class WalletInfo extends HiveObject {
static const typeId = 4; static const typeId = 4;
static const boxName = 'WalletInfo'; static const boxName = 'WalletInfo';
@HiveField(0) @HiveField(0, defaultValue: '')
String id; String id;
@HiveField(1) @HiveField(1, defaultValue: '')
String name; String name;
@HiveField(2) @HiveField(2)
WalletType type; WalletType type;
@HiveField(3) @HiveField(3, defaultValue: false)
bool isRecovery; bool isRecovery;
@HiveField(4) @HiveField(4, defaultValue: 0)
int restoreHeight; int restoreHeight;
@HiveField(5) @HiveField(5, defaultValue: 0)
int timestamp; int timestamp;
@HiveField(6) @HiveField(6, defaultValue: '')
String dirPath; String dirPath;
@HiveField(7) @HiveField(7, defaultValue: '')
String path; String path;
@HiveField(8) @HiveField(8, defaultValue: '')
String address; String address;
@HiveField(10) @HiveField(10)

View file

@ -252,4 +252,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: ae71bdf0eb731a1ffc399c122f6aa4dea0cb5f6f PODFILE CHECKSUM: ae71bdf0eb731a1ffc399c122f6aa4dea0cb5f6f
COCOAPODS: 1.11.2 COCOAPODS: 1.11.3

View file

@ -30,10 +30,10 @@ class Order extends HiveObject {
static const boxName = 'Orders'; static const boxName = 'Orders';
static const boxKey = 'ordersBoxKey'; static const boxKey = 'ordersBoxKey';
@HiveField(0) @HiveField(0, defaultValue: '')
String id; String id;
@HiveField(1) @HiveField(1, defaultValue: '')
String transferId; String transferId;
@HiveField(2) @HiveField(2)
@ -42,7 +42,7 @@ class Order extends HiveObject {
@HiveField(3) @HiveField(3)
String? to; String? to;
@HiveField(4) @HiveField(4, defaultValue: '')
late String stateRaw; late String stateRaw;
TradeState get state => TradeState.deserialize(raw: stateRaw); TradeState get state => TradeState.deserialize(raw: stateRaw);
@ -50,16 +50,16 @@ class Order extends HiveObject {
@HiveField(5) @HiveField(5)
DateTime createdAt; DateTime createdAt;
@HiveField(6) @HiveField(6, defaultValue: '')
String amount; String amount;
@HiveField(7) @HiveField(7, defaultValue: '')
String receiveAddress; String receiveAddress;
@HiveField(8) @HiveField(8, defaultValue: '')
String walletId; String walletId;
@HiveField(9) @HiveField(9, defaultValue: 0)
late int providerRaw; late int providerRaw;
BuyProviderDescription get provider => BuyProviderDescription get provider =>

View file

@ -704,6 +704,7 @@ Future setup(
ioniaAnyPayService: getIt.get<IoniaAnyPay>(), ioniaAnyPayService: getIt.get<IoniaAnyPay>(),
amount: amount, amount: amount,
ioniaMerchant: merchant, ioniaMerchant: merchant,
sendViewModel: getIt.get<SendViewModel>()
); );
}); });

View file

@ -17,13 +17,13 @@ class Contact extends HiveObject with Keyable {
static const typeId = 0; static const typeId = 0;
static const boxName = 'Contacts'; static const boxName = 'Contacts';
@HiveField(0) @HiveField(0, defaultValue: '')
String name; String name;
@HiveField(1) @HiveField(1, defaultValue: '')
String address; String address;
@HiveField(2) @HiveField(2, defaultValue: 0)
late int raw; late int raw;
CryptoCurrency get type => CryptoCurrency.deserialize(raw: raw); CryptoCurrency get type => CryptoCurrency.deserialize(raw: raw);

View file

@ -10,7 +10,7 @@ class TransactionDescription extends HiveObject {
static const boxName = 'TransactionDescriptions'; static const boxName = 'TransactionDescriptions';
static const boxKey = 'transactionDescriptionsBoxKey'; static const boxKey = 'transactionDescriptionsBoxKey';
@HiveField(0) @HiveField(0, defaultValue: '')
String id; String id;
@HiveField(1) @HiveField(1)

View file

@ -232,7 +232,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final fromAmount = double.parse(responseJSON['fromAmount'].toString()); final fromAmount = double.parse(responseJSON['fromAmount'].toString());
final toAmount = double.parse(responseJSON['toAmount'].toString()); final toAmount = double.parse(responseJSON['toAmount'].toString());
final rateId = responseJSON['rateId'] as String ?? ''; final rateId = responseJSON['rateId'] as String? ?? '';
if (rateId.isNotEmpty) { if (rateId.isNotEmpty) {
_lastUsedRateId = rateId; _lastUsedRateId = rateId;

View file

@ -40,26 +40,26 @@ class Trade extends HiveObject {
static const boxName = 'Trades'; static const boxName = 'Trades';
static const boxKey = 'tradesBoxKey'; static const boxKey = 'tradesBoxKey';
@HiveField(0) @HiveField(0, defaultValue: '')
String id; String id;
@HiveField(1) @HiveField(1, defaultValue: 0)
late int providerRaw; late int providerRaw;
ExchangeProviderDescription get provider => ExchangeProviderDescription get provider =>
ExchangeProviderDescription.deserialize(raw: providerRaw); ExchangeProviderDescription.deserialize(raw: providerRaw);
@HiveField(2) @HiveField(2, defaultValue: 0)
late int fromRaw; late int fromRaw;
CryptoCurrency get from => CryptoCurrency.deserialize(raw: fromRaw); CryptoCurrency get from => CryptoCurrency.deserialize(raw: fromRaw);
@HiveField(3) @HiveField(3, defaultValue: 0)
late int toRaw; late int toRaw;
CryptoCurrency get to => CryptoCurrency.deserialize(raw: toRaw); CryptoCurrency get to => CryptoCurrency.deserialize(raw: toRaw);
@HiveField(4) @HiveField(4, defaultValue: '')
late String stateRaw; late String stateRaw;
TradeState get state => TradeState.deserialize(raw: stateRaw); TradeState get state => TradeState.deserialize(raw: stateRaw);
@ -70,7 +70,7 @@ class Trade extends HiveObject {
@HiveField(6) @HiveField(6)
DateTime? expiredAt; DateTime? expiredAt;
@HiveField(7) @HiveField(7, defaultValue: '')
String amount; String amount;
@HiveField(8) @HiveField(8)

View file

@ -36,8 +36,8 @@ class IoniaApi {
throw Exception('Unexpected http status: ${response.statusCode}'); throw Exception('Unexpected http status: ${response.statusCode}');
} }
final bodyJson = json.decode(response.body) as Map<String, Object>; final bodyJson = json.decode(response.body) as Map<String, dynamic>;
final data = bodyJson['Data'] as Map<String, Object>; final data = bodyJson['Data'] as Map<String, dynamic>;
final isSuccessful = bodyJson['Successful'] as bool; final isSuccessful = bodyJson['Successful'] as bool;
if (!isSuccessful) { if (!isSuccessful) {
@ -50,13 +50,11 @@ class IoniaApi {
// Verify email // Verify email
Future<IoniaUserCredentials> verifyEmail({ Future<IoniaUserCredentials> verifyEmail({
required String username,
required String email, required String email,
required String code, required String code,
required String clientId}) async { required String clientId}) async {
final headers = <String, String>{ final headers = <String, String>{
'clientId': clientId, 'clientId': clientId,
'username': username,
'EmailAddress': email}; 'EmailAddress': email};
final query = <String, String>{'verificationCode': code}; final query = <String, String>{'verificationCode': code};
final uri = verifyEmailUri.replace(queryParameters: query); final uri = verifyEmailUri.replace(queryParameters: query);
@ -66,8 +64,8 @@ class IoniaApi {
throw Exception('Unexpected http status: ${response.statusCode}'); throw Exception('Unexpected http status: ${response.statusCode}');
} }
final bodyJson = json.decode(response.body) as Map<String, Object>; final bodyJson = json.decode(response.body) as Map<String, dynamic>;
final data = bodyJson['Data'] as Map<String, Object>; final data = bodyJson['Data'] as Map<String, dynamic>;
final isSuccessful = bodyJson['Successful'] as bool; final isSuccessful = bodyJson['Successful'] as bool;
if (!isSuccessful) { if (!isSuccessful) {
@ -75,13 +73,13 @@ class IoniaApi {
} }
final password = data['password'] as String; final password = data['password'] as String;
username = data['username'] as String; final username = data['username'] as String;
return IoniaUserCredentials(username, password); return IoniaUserCredentials(username, password);
} }
// Sign In // Sign In
Future<String> signIn(String email, {required String clientId}) async { Future<void> signIn(String email, {required String clientId}) async {
final headers = <String, String>{'clientId': clientId}; final headers = <String, String>{'clientId': clientId};
final query = <String, String>{'emailAddress': email}; final query = <String, String>{'emailAddress': email};
final uri = signInUri.replace(queryParameters: query); final uri = signInUri.replace(queryParameters: query);
@ -91,15 +89,13 @@ class IoniaApi {
throw Exception('Unexpected http status: ${response.statusCode}'); throw Exception('Unexpected http status: ${response.statusCode}');
} }
final bodyJson = json.decode(response.body) as Map<String, Object>; final bodyJson = json.decode(response.body) as Map<String, dynamic>;
final data = bodyJson['Data'] as Map<String, Object>; final data = bodyJson['Data'] as Map<String, dynamic>;
final isSuccessful = bodyJson['Successful'] as bool; final isSuccessful = bodyJson['Successful'] as bool;
if (!isSuccessful) { if (!isSuccessful) {
throw Exception(data['ErrorMessage'] as String); throw Exception(data['ErrorMessage'] as String);
} }
return data['username'] as String;
} }
// Get virtual card // Get virtual card
@ -118,15 +114,15 @@ class IoniaApi {
throw Exception('Unexpected http status: ${response.statusCode}'); throw Exception('Unexpected http status: ${response.statusCode}');
} }
final bodyJson = json.decode(response.body) as Map<String, Object>; final bodyJson = json.decode(response.body) as Map<String, dynamic>;
final data = bodyJson['Data'] as Map<String, Object>; final data = bodyJson['Data'] as Map<String, dynamic>;
final isSuccessful = bodyJson['Successful'] as bool; final isSuccessful = bodyJson['Successful'] as bool;
if (!isSuccessful) { if (!isSuccessful) {
throw Exception(data['message'] as String); throw Exception(data['message'] as String);
} }
final virtualCard = data['VirtualCard'] as Map<String, Object>; final virtualCard = data['VirtualCard'] as Map<String, dynamic>;
return IoniaVirtualCard.fromMap(virtualCard); return IoniaVirtualCard.fromMap(virtualCard);
} }
@ -146,8 +142,8 @@ class IoniaApi {
throw Exception('Unexpected http status: ${response.statusCode}'); throw Exception('Unexpected http status: ${response.statusCode}');
} }
final bodyJson = json.decode(response.body) as Map<String, Object>; final bodyJson = json.decode(response.body) as Map<String, dynamic>;
final data = bodyJson['Data'] as Map<String, Object>; final data = bodyJson['Data'] as Map<String, dynamic>;
final isSuccessful = bodyJson['Successful'] as bool? ?? false; final isSuccessful = bodyJson['Successful'] as bool? ?? false;
if (!isSuccessful) { if (!isSuccessful) {

View file

@ -31,9 +31,8 @@ class IoniaService {
// Verify email // Verify email
Future<void> verifyEmail(String code) async { Future<void> verifyEmail(String code) async {
final username = (await secureStorage.read(key: ioniaUsernameStorageKey))!;
final email = (await secureStorage.read(key: ioniaEmailStorageKey))!; 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: ioniaPasswordStorageKey, value: credentials.password);
await secureStorage.write(key: ioniaUsernameStorageKey, value: credentials.username); await secureStorage.write(key: ioniaUsernameStorageKey, value: credentials.username);
} }
@ -41,9 +40,8 @@ class IoniaService {
// Sign In // Sign In
Future<void> signIn(String email) async { Future<void> 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: ioniaEmailStorageKey, value: email);
await secureStorage.write(key: ioniaUsernameStorageKey, value: username);
} }
Future<String> getUserEmail() async { Future<String> getUserEmail() async {

View file

@ -11,7 +11,7 @@ class IoniaVirtualCard {
required this.fundsLimit, required this.fundsLimit,
required this.spendLimit}); required this.spendLimit});
factory IoniaVirtualCard.fromMap(Map<String, Object> source) { factory IoniaVirtualCard.fromMap(Map<String, dynamic> source) {
final created = source['created'] as String; final created = source['created'] as String;
final createdAt = DateTime.tryParse(created); final createdAt = DateTime.tryParse(created);

View file

@ -106,22 +106,22 @@ class AuthPageState extends State<AuthPage> {
_progressBar = null; _progressBar = null;
} }
Future<void> close({String? route}) async { Future<void> close({String? route, dynamic arguments}) async {
if (_key.currentContext == null) { if (_key.currentContext == null) {
throw Exception('Key context is null. Should be not happened'); throw Exception('Key context is null. Should be not happened');
} }
WidgetsBinding.instance.addPostFrameCallback((_) { /// not the best scenario, but WidgetsBinding is not behaving correctly on Android
dismissFlushBar(_authBar); await Future<void>.delayed(Duration(milliseconds: 50));
dismissFlushBar(_progressBar); await _authBar?.dismiss();
WidgetsBinding.instance.addPostFrameCallback((_) { await Future<void>.delayed(Duration(milliseconds: 50));
if (route != null) { await _progressBar?.dismiss();
Navigator.of(_key.currentContext!).pushReplacementNamed(route); await Future<void>.delayed(Duration(milliseconds: 50));
} else { if (route != null) {
Navigator.of(_key.currentContext!).pop(); Navigator.of(_key.currentContext!).pushReplacementNamed(route, arguments: arguments);
} } else {
}); Navigator.of(_key.currentContext!).pop();
}); }
} }
@override @override

View file

@ -3,7 +3,6 @@ import 'package:cake_wallet/ionia/ionia_merchant.dart';
import 'package:cake_wallet/ionia/ionia_tip.dart'; import 'package:cake_wallet/ionia/ionia_tip.dart';
import 'package:cake_wallet/palette.dart'; import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/routes.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/ionia_alert_model.dart';
import 'package:cake_wallet/src/screens/ionia/widgets/text_icon_button.dart'; import 'package:cake_wallet/src/screens/ionia/widgets/text_icon_button.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.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:flutter_mobx/flutter_mobx.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:cake_wallet/src/screens/base_page.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 { class IoniaBuyGiftCardDetailPage extends BasePage {
IoniaBuyGiftCardDetailPage(this.ioniaPurchaseViewModel); IoniaBuyGiftCardDetailPage(this.ioniaPurchaseViewModel);
@ -295,73 +295,35 @@ class IoniaBuyGiftCardDetailPage extends BasePage {
final amount = ioniaPurchaseViewModel.invoice!.totalAmount; final amount = ioniaPurchaseViewModel.invoice!.totalAmount;
final addresses = ioniaPurchaseViewModel.invoice!.outAddresses; final addresses = ioniaPurchaseViewModel.invoice!.outAddresses;
ioniaPurchaseViewModel.sendViewModel.outputs.first.setCryptoAmount(amount);
ioniaPurchaseViewModel.sendViewModel.outputs.first.address = addresses.first;
await showPopUp<void>( await showPopUp<void>(
context: context, context: context,
builder: (_) { builder: (_) {
return IoniaConfirmModal( return ConfirmSendingAlert(
alertTitle: S.of(context).confirm_sending, alertTitle: S.of(context).confirm_sending,
alertContent: Container( paymentId: S.of(context).payment_id,
height: 200, paymentIdValue: ioniaPurchaseViewModel.invoice!.paymentId,
padding: EdgeInsets.all(15), amount: S.of(context).send_amount,
child: Column(children: [ amountValue: '$amount ${ioniaPurchaseViewModel.invoice!.chain}',
Row(children: [ fiatAmountValue:
Text(S.of(context).payment_id, '~ ${ioniaPurchaseViewModel.sendViewModel.outputs.first.fiatAmount} '
textAlign: TextAlign.center, '${ioniaPurchaseViewModel.sendViewModel.fiat.title}',
style: TextStyle( fee: S.of(context).send_fee,
fontSize: 16, feeValue:
fontWeight: FontWeight.w400, '${ioniaPurchaseViewModel.sendViewModel.outputs.first.estimatedFee} '
color: PaletteDark.pigeonBlue, '${ioniaPurchaseViewModel.invoice!.chain}',
decoration: TextDecoration.none)), feeFiatAmount:
Text(ioniaPurchaseViewModel.invoice!.paymentId, '${ioniaPurchaseViewModel.sendViewModel.outputs.first.estimatedFeeFiatAmount} '
style: TextStyle( '${ioniaPurchaseViewModel.sendViewModel.fiat.title}',
fontSize: 16, outputs: ioniaPurchaseViewModel.sendViewModel.outputs,
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()))
])),
rightButtonText: S.of(context).ok, rightButtonText: S.of(context).ok,
leftButtonText: S.of(context).cancel, leftButtonText: S.of(context).cancel,
leftActionColor: Color(0xffFF6600), alertLeftActionButtonTextColor: Colors.white,
rightActionColor: Theme.of(context).accentTextTheme!.bodyText1!.color!, alertRightActionButtonTextColor: Colors.white,
alertLeftActionButtonColor: Palette.brightOrange,
alertRightActionButtonColor: Theme.of(context).textTheme!.subtitle2!.color,
actionRightButton: () async { actionRightButton: () async {
Navigator.of(context).pop(); Navigator.of(context).pop();
await ioniaPurchaseViewModel.commitPaymentInvoice(); await ioniaPurchaseViewModel.commitPaymentInvoice();

View file

@ -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: <Widget>[
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,
),
)),
),
));
}
}

View file

@ -9,7 +9,6 @@ class QrPainter extends CustomPainter {
this.errorCorrectionLevel, this.errorCorrectionLevel,
) : this._qr = QrCode(version, errorCorrectionLevel)..addData(data) { ) : this._qr = QrCode(version, errorCorrectionLevel)..addData(data) {
_p.color = this.color; _p.color = this.color;
_qr.addData(data);
_qrImage = QrImage(_qr); _qrImage = QrImage(_qr);
} }

View file

@ -4,10 +4,13 @@ import 'package:flutter/material.dart';
import 'package:cake_wallet/src/widgets/base_alert_dialog.dart'; import 'package:cake_wallet/src/widgets/base_alert_dialog.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/widgets/cake_scrollbar.dart'; import 'package:cake_wallet/src/widgets/cake_scrollbar.dart';
import 'package:flutter/scheduler.dart';
class ConfirmSendingAlert extends BaseAlertDialog { class ConfirmSendingAlert extends BaseAlertDialog {
ConfirmSendingAlert({ ConfirmSendingAlert({
required this.alertTitle, required this.alertTitle,
this.paymentId,
this.paymentIdValue,
required this.amount, required this.amount,
required this.amountValue, required this.amountValue,
required this.fiatAmountValue, required this.fiatAmountValue,
@ -19,9 +22,15 @@ class ConfirmSendingAlert extends BaseAlertDialog {
required this.rightButtonText, required this.rightButtonText,
required this.actionLeftButton, required this.actionLeftButton,
required this.actionRightButton, required this.actionRightButton,
this.alertBarrierDismissible = true}); this.alertBarrierDismissible = true,
this.alertLeftActionButtonTextColor,
this.alertRightActionButtonTextColor,
this.alertLeftActionButtonColor,
this.alertRightActionButtonColor});
final String alertTitle; final String alertTitle;
final String? paymentId;
final String? paymentIdValue;
final String amount; final String amount;
final String amountValue; final String amountValue;
final String fiatAmountValue; final String fiatAmountValue;
@ -34,6 +43,10 @@ class ConfirmSendingAlert extends BaseAlertDialog {
final VoidCallback actionLeftButton; final VoidCallback actionLeftButton;
final VoidCallback actionRightButton; final VoidCallback actionRightButton;
final bool alertBarrierDismissible; final bool alertBarrierDismissible;
final Color? alertLeftActionButtonTextColor;
final Color? alertRightActionButtonTextColor;
final Color? alertLeftActionButtonColor;
final Color? alertRightActionButtonColor;
@override @override
String get titleText => alertTitle; String get titleText => alertTitle;
@ -56,8 +69,22 @@ class ConfirmSendingAlert extends BaseAlertDialog {
@override @override
bool get barrierDismissible => alertBarrierDismissible; 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 @override
Widget content(BuildContext context) => ConfirmSendingAlertContent( Widget content(BuildContext context) => ConfirmSendingAlertContent(
paymentId: paymentId,
paymentIdValue: paymentIdValue,
amount: amount, amount: amount,
amountValue: amountValue, amountValue: amountValue,
fiatAmountValue: fiatAmountValue, fiatAmountValue: fiatAmountValue,
@ -70,6 +97,8 @@ class ConfirmSendingAlert extends BaseAlertDialog {
class ConfirmSendingAlertContent extends StatefulWidget { class ConfirmSendingAlertContent extends StatefulWidget {
ConfirmSendingAlertContent({ ConfirmSendingAlertContent({
this.paymentId,
this.paymentIdValue,
required this.amount, required this.amount,
required this.amountValue, required this.amountValue,
required this.fiatAmountValue, required this.fiatAmountValue,
@ -78,6 +107,8 @@ class ConfirmSendingAlertContent extends StatefulWidget {
required this.feeFiatAmount, required this.feeFiatAmount,
required this.outputs}); required this.outputs});
final String? paymentId;
final String? paymentIdValue;
final String amount; final String amount;
final String amountValue; final String amountValue;
final String fiatAmountValue; final String fiatAmountValue;
@ -88,6 +119,8 @@ class ConfirmSendingAlertContent extends StatefulWidget {
@override @override
ConfirmSendingAlertContentState createState() => ConfirmSendingAlertContentState( ConfirmSendingAlertContentState createState() => ConfirmSendingAlertContentState(
paymentId: paymentId,
paymentIdValue: paymentIdValue,
amount: amount, amount: amount,
amountValue: amountValue, amountValue: amountValue,
fiatAmountValue: fiatAmountValue, fiatAmountValue: fiatAmountValue,
@ -100,6 +133,8 @@ class ConfirmSendingAlertContent extends StatefulWidget {
class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent> { class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent> {
ConfirmSendingAlertContentState({ ConfirmSendingAlertContentState({
this.paymentId,
this.paymentIdValue,
required this.amount, required this.amount,
required this.amountValue, required this.amountValue,
required this.fiatAmountValue, required this.fiatAmountValue,
@ -115,6 +150,8 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
: S.current.recipient_address; : S.current.recipient_address;
} }
final String? paymentId;
final String? paymentIdValue;
final String amount; final String amount;
final String amountValue; final String amountValue;
final String fiatAmountValue; final String fiatAmountValue;
@ -129,6 +166,7 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
double fromTop = 0; double fromTop = 0;
String recipientTitle; String recipientTitle;
int itemCount; int itemCount;
bool showScrollbar = false;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -140,6 +178,12 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
setState(() {}); setState(() {});
}); });
SchedulerBinding.instance.addPostFrameCallback((_) {
setState(() {
showScrollbar = controller.position.maxScrollExtent > 0;
});
});
return Stack( return Stack(
alignment: Alignment.center, alignment: Alignment.center,
clipBehavior: Clip.none, clipBehavior: Clip.none,
@ -150,6 +194,44 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
controller: controller, controller: controller,
child: Column( child: Column(
children: <Widget>[ children: <Widget>[
if (paymentIdValue != null && paymentId != null)
Padding(
padding: EdgeInsets.only(bottom: 32),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
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( Row(
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -365,7 +447,7 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
) )
) )
), ),
if (itemCount > 1) CakeScrollbar( if (showScrollbar) CakeScrollbar(
backgroundHeight: backgroundHeight, backgroundHeight: backgroundHeight,
thumbHeight: thumbHeight, thumbHeight: thumbHeight,
fromTop: fromTop, fromTop: fromTop,

View file

@ -11,6 +11,10 @@ class BaseAlertDialog extends StatelessWidget {
VoidCallback get actionLeft => () {}; VoidCallback get actionLeft => () {};
VoidCallback get actionRight => () {}; VoidCallback get actionRight => () {};
bool get barrierDismissible => true; bool get barrierDismissible => true;
Color? get leftActionButtonTextColor => null;
Color? get rightActionButtonTextColor => null;
Color? get leftActionButtonColor => null;
Color? get rightActionButtonColor => null;
Widget title(BuildContext context) { Widget title(BuildContext context) {
return Text( return Text(
@ -45,52 +49,64 @@ class BaseAlertDialog extends StatelessWidget {
height: 52, height: 52,
child: Row( child: Row(
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[ children: <Widget>[
Flexible( Expanded(
child: Container( child: TextButton(
width: double.infinity, onPressed: actionLeft,
color: Theme.of(context).accentTextTheme!.bodyText1!.decorationColor!, style: TextButton.styleFrom(
child: TextButton( backgroundColor: leftActionButtonColor ??
onPressed: actionLeft, Theme.of(context)
child: Text( .accentTextTheme!
leftActionButtonText, .bodyText1!
textAlign: TextAlign.center, .decorationColor!,
style: TextStyle( shape: const RoundedRectangleBorder(
fontSize: 15, borderRadius: BorderRadius.all(Radius.zero))),
fontFamily: 'Lato', child: Text(
fontWeight: FontWeight.w600, leftActionButtonText,
color: Theme.of(context).primaryTextTheme!.bodyText1!.backgroundColor!, textAlign: TextAlign.center,
decoration: TextDecoration.none, style: TextStyle(
), fontSize: 15,
)), fontFamily: 'Lato',
), fontWeight: FontWeight.w600,
), color: leftActionButtonTextColor ??
Theme.of(context).primaryTextTheme!
.bodyText1!.backgroundColor!,
decoration: TextDecoration.none,
),
)),
),
Container( Container(
width: 1, width: 1,
color: Theme.of(context).dividerColor, color: Theme.of(context).dividerColor,
), ),
Flexible( Expanded(
child: Container( child: TextButton(
width: double.infinity, onPressed: actionRight,
color: Theme.of(context).accentTextTheme!.bodyText2!.backgroundColor!, style: TextButton.styleFrom(
child: TextButton( backgroundColor: rightActionButtonColor ??
onPressed: actionRight, Theme.of(context).accentTextTheme!
child: Text( .bodyText2!.backgroundColor!,
rightActionButtonText, shape: const RoundedRectangleBorder(
textAlign: TextAlign.center, borderRadius: BorderRadius.all(Radius.zero))),
style: TextStyle( child: Text(
fontSize: 15, rightActionButtonText,
fontFamily: 'Lato', textAlign: TextAlign.center,
fontWeight: FontWeight.w600, style: TextStyle(
color: Theme.of(context).primaryTextTheme!.bodyText2!.backgroundColor!, fontSize: 15,
decoration: TextDecoration.none, fontFamily: 'Lato',
), fontWeight: FontWeight.w600,
)), color: rightActionButtonTextColor ??
), Theme.of(context)
), .primaryTextTheme!
], .bodyText2!
)); .backgroundColor!,
decoration: TextDecoration.none,
),
)),
),
],
));
} }
@override @override

View file

@ -45,7 +45,6 @@ Future<DateTime?> _buildCupertinoDataPicker(
initialDateTime: initialDate, initialDateTime: initialDate,
minimumDate: firstDate, minimumDate: firstDate,
maximumDate: lastDate, maximumDate: lastDate,
backgroundColor: Colors.white,
), ),
); );
} }

View file

@ -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_merchant.dart';
import 'package:cake_wallet/ionia/ionia_tip.dart'; import 'package:cake_wallet/ionia/ionia_tip.dart';
import 'package:cake_wallet/ionia/ionia_any_pay_payment_info.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'; part 'ionia_purchase_merch_view_model.g.dart';
@ -17,6 +18,7 @@ abstract class IoniaMerchPurchaseViewModelBase with Store {
required this.ioniaAnyPayService, required this.ioniaAnyPayService,
required this.amount, required this.amount,
required this.ioniaMerchant, required this.ioniaMerchant,
required this.sendViewModel,
}) : tipAmount = 0.0, }) : tipAmount = 0.0,
percentage = 0.0, percentage = 0.0,
invoiceCreationState = InitialExecutionState(), invoiceCreationState = InitialExecutionState(),
@ -40,6 +42,8 @@ abstract class IoniaMerchPurchaseViewModelBase with Store {
final IoniaMerchant ioniaMerchant; final IoniaMerchant ioniaMerchant;
final SendViewModel sendViewModel;
final IoniaAnyPay ioniaAnyPayService; final IoniaAnyPay ioniaAnyPayService;
IoniaAnyPayPaymentInfo? paymentInfo; IoniaAnyPayPaymentInfo? paymentInfo;

View file

@ -156,13 +156,13 @@ abstract class SettingsViewModelBase with Store {
handler: (BuildContext context) { handler: (BuildContext context) {
Navigator.of(context).pushNamed(Routes.auth, arguments: Navigator.of(context).pushNamed(Routes.auth, arguments:
(bool isAuthenticatedSuccessfully, AuthPageState auth) { (bool isAuthenticatedSuccessfully, AuthPageState auth) {
auth.close(); auth.close(
if (isAuthenticatedSuccessfully) { route: isAuthenticatedSuccessfully ? Routes.setupPin : null,
Navigator.of(context).pushNamed(Routes.setupPin, arguments: arguments: (PinCodeState<PinCodeWidget> setupPinContext,
(PinCodeState<PinCodeWidget> setupPinContext, String _) { String _) {
setupPinContext.close(); setupPinContext.close();
}); },
} );
}); });
}), }),
PickerListItem( PickerListItem(

View file

@ -14,14 +14,14 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
APP_ANDROID_TYPE=$1 APP_ANDROID_TYPE=$1
MONERO_COM_NAME="Monero.com" MONERO_COM_NAME="Monero.com"
MONERO_COM_VERSION="1.2.0" MONERO_COM_VERSION="1.2.1"
MONERO_COM_BUILD_NUMBER=24 MONERO_COM_BUILD_NUMBER=32
MONERO_COM_BUNDLE_ID="com.monero.app" MONERO_COM_BUNDLE_ID="com.monero.app"
MONERO_COM_PACKAGE="com.monero.app" MONERO_COM_PACKAGE="com.monero.app"
CAKEWALLET_NAME="Cake Wallet" CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="4.5.0" CAKEWALLET_VERSION="4.5.1"
CAKEWALLET_BUILD_NUMBER=128 CAKEWALLET_BUILD_NUMBER=136
CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet" CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet"
CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet" CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet"

View file

@ -13,13 +13,13 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
APP_IOS_TYPE=$1 APP_IOS_TYPE=$1
MONERO_COM_NAME="Monero.com" MONERO_COM_NAME="Monero.com"
MONERO_COM_VERSION="1.2.0" MONERO_COM_VERSION="1.2.1"
MONERO_COM_BUILD_NUMBER=24 MONERO_COM_BUILD_NUMBER=29
MONERO_COM_BUNDLE_ID="com.cakewallet.monero" MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
CAKEWALLET_NAME="Cake Wallet" CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="4.5.0" CAKEWALLET_VERSION="4.5.1"
CAKEWALLET_BUILD_NUMBER=128 CAKEWALLET_BUILD_NUMBER=133
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet" CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
HAVEN_NAME="Haven" HAVEN_NAME="Haven"