Add Initial flow for payment

Remove buy provider and get XMR values from monero API
Separate alert content widgets
This commit is contained in:
OmarHatem28 2022-07-12 15:43:35 +02:00
parent da910ee0be
commit bee69c02ba
9 changed files with 372 additions and 359 deletions

View file

@ -0,0 +1,13 @@
class TopUp {
const TopUp({this.id, this.address, this.amount});
final String id;
final String address;
final double amount;
@override
bool operator ==(Object other) => other is TopUp && other.id == id;
@override
int get hashCode => id.hashCode;
}

View file

@ -1,12 +1,9 @@
import 'dart:ui'; import 'dart:ui';
import 'package:cake_wallet/buy/buy_amount.dart';
import 'package:cake_wallet/buy/moonpay/moonpay_buy_provider.dart';
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/entities/fiat_currency.dart'; import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cake_wallet/src/screens/cake_phone/widgets/confirm_sending_content.dart';
import 'package:cake_wallet/src/screens/cake_phone/widgets/confirmation_alert_content.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/src/widgets/info_alert_dialog.dart';
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart'; import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
import 'package:cake_wallet/store/app_store.dart';
import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -14,7 +11,6 @@ import 'package:flutter/services.dart';
import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:keyboard_actions/keyboard_actions.dart'; import 'package:keyboard_actions/keyboard_actions.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/cake_phone/widgets/receipt_row.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart'; import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
@ -180,44 +176,7 @@ class AddBalancePage extends BasePage {
alertContent: S.of(context).confirm_delete_template, alertContent: S.of(context).confirm_delete_template,
contentWidget: Material( contentWidget: Material(
color: Colors.transparent, color: Colors.transparent,
child: Column( child: ConfirmSendingContent(addBalanceViewModel.buyAmountViewModel.doubleAmount),
mainAxisSize: MainAxisSize.min,
children: [
ReceiptRow(
title: S.of(context).amount,
value: cryptoAmount(addBalanceViewModel.buyAmountViewModel.doubleAmount)),
ReceiptRow(
title: S.of(context).send_fee,
value: cryptoAmount(getIt
.get<AppStore>()
.wallet
.calculateEstimatedFee(
getIt.get<AppStore>().settingsStore.priority[getIt.get<AppStore>().wallet.type],
addBalanceViewModel.buyAmountViewModel.doubleAmount.floor(),
)
.toDouble())),
const SizedBox(height: 45),
Text(
S.of(context).recipient_address,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Theme.of(context).primaryTextTheme.title.color,
),
),
const SizedBox(height: 16),
Text(
//TODO: remove static address if it will be generated everytime
"4B6c5ApfayzRN8jYxXyprv9me1vttSjF21WAz4HQ8JvS13RgRbgfQg7PPgvm2QMA8N1ed7izqPFsnCKGWWwFoGyjTFstzXm",
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.w600,
color: Theme.of(context).accentTextTheme.subhead.color,
),
textAlign: TextAlign.center,
),
],
),
), ),
isDividerExists: true, isDividerExists: true,
rightButtonText: S.of(context).ok, rightButtonText: S.of(context).ok,
@ -226,7 +185,12 @@ class AddBalancePage extends BasePage {
leftActionButtonColor: Theme.of(context).primaryTextTheme.body2.backgroundColor, leftActionButtonColor: Theme.of(context).primaryTextTheme.body2.backgroundColor,
actionRightButton: () { actionRightButton: () {
Navigator.of(dialogContext).pop(); Navigator.of(dialogContext).pop();
showPaymentConfirmationPopup(context); // TODO: Replace with the transaction id
showPopUp<void>(
context: context,
builder: (dialogContext) {
return ConfirmationAlertContent("dsyf5ind7akwryewkmf5nf4eakdrm4infd4i8rm4fd8nrmsein");
});
}, },
actionLeftButton: () => Navigator.of(dialogContext).pop()); actionLeftButton: () => Navigator.of(dialogContext).pop());
}); });
@ -242,135 +206,4 @@ class AddBalancePage extends BasePage {
), ),
); );
} }
// TODO: Make it reusable after finding the models related and use it here and in phone_number_product_page.dart
Widget cryptoAmount(double totalPrice) {
return FutureBuilder<BuyAmount>(
future: MoonPayBuyProvider(wallet: getIt.get<AppStore>().wallet)
.calculateAmount(totalPrice.toString(), FiatCurrency.usd.title),
builder: (context, AsyncSnapshot<BuyAmount> snapshot) {
double sourceAmount;
double destAmount;
if (snapshot.hasData) {
sourceAmount = snapshot.data.sourceAmount;
destAmount = snapshot.data.destAmount;
} else {
sourceAmount = 0.0;
destAmount = 0.0;
}
return Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
"${sourceAmount} ${getIt.get<AppStore>().wallet.currency.toString()}",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w700,
color: Theme.of(context).primaryTextTheme.title.color,
),
),
Text(
"${destAmount} ${FiatCurrency.usd.title}",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Theme.of(context).accentTextTheme.subhead.color,
),
),
],
);
},
);
}
// TODO: Make it reusable after finding the models related and use it here and in phone_number_product_page.dart
void showPaymentConfirmationPopup(BuildContext context) {
showPopUp<void>(
context: context,
builder: (dialogContext) {
return InfoAlertDialog(
alertTitle: S.of(context).awaiting_payment_confirmation,
alertTitleColor: Theme.of(context).primaryTextTheme.title.decorationColor,
alertContentPadding: EdgeInsets.zero,
alertContent: Padding(
padding: const EdgeInsets.only(top: 8, bottom: 32),
child: Material(
color: Colors.transparent,
child: Column(
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: 24),
child: Text(
S.of(context).transaction_sent_popup_info,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Theme.of(context).primaryTextTheme.title.color,
),
),
),
Padding(
padding: EdgeInsets.symmetric(vertical: 24),
child: Container(
height: 1,
color: Theme.of(context).dividerColor,
),
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"${S.of(context).transaction_details_transaction_id}:",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Theme.of(context).accentTextTheme.subhead.color,
),
),
Padding(
padding: const EdgeInsets.only(top: 4, bottom: 16),
child: Text(
// TODO: Replace with the transaction id
"dsyf5ind7akwryewkmf5nf4eakdrm4infd4i8rm4fd8nrmsein",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Theme.of(context).primaryTextTheme.title.color,
),
),
),
Text(
"${S.of(context).view_in_block_explorer}:",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Theme.of(context).accentTextTheme.subhead.color,
),
),
Padding(
padding: const EdgeInsets.only(top: 4),
child: Text(
// TODO: get it from transaction details view model
S.of(context).view_transaction_on,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Theme.of(context).primaryTextTheme.title.color,
),
),
),
],
),
),
],
),
),
),
);
});
}
} }

View file

@ -1,20 +1,20 @@
import 'package:cake_wallet/buy/buy_amount.dart'; import 'package:cake_wallet/core/execution_state.dart';
import 'package:cake_wallet/buy/moonpay/moonpay_buy_provider.dart';
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/entities/cake_phone_entities/phone_number_service.dart'; import 'package:cake_wallet/entities/cake_phone_entities/phone_number_service.dart';
import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/cake_phone/widgets/cake_phone_settings_tile.dart'; import 'package:cake_wallet/src/screens/cake_phone/widgets/cake_phone_settings_tile.dart';
import 'package:cake_wallet/src/screens/cake_phone/widgets/confirm_sending_content.dart';
import 'package:cake_wallet/src/screens/cake_phone/widgets/confirmation_alert_content.dart';
import 'package:cake_wallet/src/screens/cake_phone/widgets/plan_card.dart'; import 'package:cake_wallet/src/screens/cake_phone/widgets/plan_card.dart';
import 'package:cake_wallet/src/screens/cake_phone/widgets/receipt_row.dart'; import 'package:cake_wallet/src/screens/cake_phone/widgets/receipt_row.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/src/widgets/info_alert_dialog.dart';
import 'package:cake_wallet/src/widgets/picker.dart'; import 'package:cake_wallet/src/widgets/picker.dart';
import 'package:cake_wallet/store/app_store.dart'; import 'package:cake_wallet/utils/show_bar.dart';
import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/cake_phone/phone_plan_view_model.dart'; import 'package:cake_wallet/view_model/cake_phone/phone_plan_view_model.dart';
import 'package:country_pickers/country.dart'; import 'package:country_pickers/country.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:dotted_border/dotted_border.dart'; import 'package:dotted_border/dotted_border.dart';
import 'package:flushbar/flushbar.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:country_pickers/country_pickers.dart'; import 'package:country_pickers/country_pickers.dart';
@ -24,6 +24,7 @@ import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:mobx/mobx.dart';
class PhoneNumberProductPage extends BasePage { class PhoneNumberProductPage extends BasePage {
PhoneNumberProductPage(this.phonePlanViewModel, {this.phoneNumberService}); PhoneNumberProductPage(this.phonePlanViewModel, {this.phoneNumberService});
@ -58,6 +59,55 @@ class PhoneNumberProductBody extends StatefulWidget {
} }
class PhoneNumberProductBodyState extends State<PhoneNumberProductBody> { class PhoneNumberProductBodyState extends State<PhoneNumberProductBody> {
ReactionDisposer _reaction;
Flushbar<void> _progressBar;
@override
void initState() {
super.initState();
_reaction ??= autorun((_) {
if (widget.phonePlanViewModel.payWithXMRState is ExecutedSuccessfullyState ||
widget.phonePlanViewModel.payWithCakeBalanceState is ExecutedSuccessfullyState) {
WidgetsBinding.instance.addPostFrameCallback((_) {
_progressBar?.dismiss();
Navigator.pushNamedAndRemoveUntil(
context,
Routes.cakePhoneActiveServices,
ModalRoute.withName(Routes.cakePhoneWelcome),
);
});
}
/// if its loading payment with xmr show the confirmation popup
if (widget.phonePlanViewModel.payWithXMRState is IsExecutingState) {
WidgetsBinding.instance.addPostFrameCallback((_) {
// TODO: Replace with the transaction id
showPopUp<void>(
context: context,
builder: (dialogContext) {
return ConfirmationAlertContent("dsyf5ind7akwryewkmf5nf4eakdrm4infd4i8rm4fd8nrmsein");
});
});
}
/// if its loading payment with cake balance show loading bar
if (widget.phonePlanViewModel.payWithCakeBalanceState is IsExecutingState) {
WidgetsBinding.instance.addPostFrameCallback((_) {
_progressBar = createBar<void>(S.of(context).loading, duration: null)..show(context);
});
}
if (widget.phonePlanViewModel.payWithXMRState is FailureState ||
widget.phonePlanViewModel.payWithCakeBalanceState is FailureState) {
WidgetsBinding.instance.addPostFrameCallback((_) {
_progressBar?.dismiss();
showBar<void>(context, S.of(context).payment_failed);
});
}
});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Padding( return Padding(
@ -321,7 +371,9 @@ class PhoneNumberProductBodyState extends State<PhoneNumberProductBody> {
children: [ children: [
ReceiptRow( ReceiptRow(
title: S.of(context).amount, value: amountText(widget.phonePlanViewModel.totalPrice)), title: S.of(context).amount, value: amountText(widget.phonePlanViewModel.totalPrice)),
ReceiptRow(title: "${S.of(context).cake_pay_balance}: ", value: amountText(100)), ReceiptRow(
title: "${S.of(context).cake_pay_balance}: ",
value: amountText(100)), // TODO: Remove hard coded balance
], ],
), ),
isDividerExists: true, isDividerExists: true,
@ -331,11 +383,12 @@ class PhoneNumberProductBodyState extends State<PhoneNumberProductBody> {
leftActionButtonColor: Theme.of(context).primaryTextTheme.body2.backgroundColor, leftActionButtonColor: Theme.of(context).primaryTextTheme.body2.backgroundColor,
actionRightButton: () { actionRightButton: () {
Navigator.of(dialogContext).pop(); Navigator.of(dialogContext).pop();
Navigator.pushNamedAndRemoveUntil( if (widget.phoneNumberService == null ||
context, widget.phoneNumberService.planId != widget.phonePlanViewModel.selectedPlan.id) {
Routes.cakePhoneActiveServices, widget.phonePlanViewModel.purchasePlan();
ModalRoute.withName(Routes.cakePhoneWelcome), } else {
); widget.phonePlanViewModel.buyAdditionalSMS();
}
}, },
actionLeftButton: () => Navigator.of(dialogContext).pop()); actionLeftButton: () => Navigator.of(dialogContext).pop());
}); });
@ -354,46 +407,7 @@ class PhoneNumberProductBodyState extends State<PhoneNumberProductBody> {
alertTitle: S.of(context).confirm_sending, alertTitle: S.of(context).confirm_sending,
alertTitleColor: Theme.of(context).primaryTextTheme.title.decorationColor, alertTitleColor: Theme.of(context).primaryTextTheme.title.decorationColor,
alertContent: S.of(context).confirm_delete_template, alertContent: S.of(context).confirm_delete_template,
contentWidget: Column( contentWidget: ConfirmSendingContent(widget.phonePlanViewModel.totalPrice),
mainAxisSize: MainAxisSize.min,
children: [
ReceiptRow(
title: S.of(context).amount,
value: cryptoAmount(widget.phonePlanViewModel.totalPrice),
),
ReceiptRow(
title: S.of(context).send_fee,
value: cryptoAmount(getIt
.get<AppStore>()
.wallet
.calculateEstimatedFee(
getIt.get<AppStore>().settingsStore.priority[getIt.get<AppStore>().wallet.type],
widget.phonePlanViewModel.totalPrice.floor(),
)
.toDouble()),
),
const SizedBox(height: 45),
Text(
S.of(context).recipient_address,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Theme.of(context).primaryTextTheme.title.color,
),
),
const SizedBox(height: 16),
Text(
//TODO: remove static address if it will be generated everytime
"4B6c5ApfayzRN8jYxXyprv9me1vttSjF21WAz4HQ8JvS13RgRbgfQg7PPgvm2QMA8N1ed7izqPFsnCKGWWwFoGyjTFstzXm",
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.w600,
color: Theme.of(context).accentTextTheme.subhead.color,
),
textAlign: TextAlign.center,
),
],
),
isDividerExists: true, isDividerExists: true,
rightButtonText: S.of(context).ok, rightButtonText: S.of(context).ok,
leftButtonText: S.of(context).cancel, leftButtonText: S.of(context).cancel,
@ -401,12 +415,11 @@ class PhoneNumberProductBodyState extends State<PhoneNumberProductBody> {
leftActionButtonColor: Theme.of(context).primaryTextTheme.body2.backgroundColor, leftActionButtonColor: Theme.of(context).primaryTextTheme.body2.backgroundColor,
actionRightButton: () { actionRightButton: () {
Navigator.of(dialogContext).pop(); Navigator.of(dialogContext).pop();
showPaymentConfirmationPopup();
}, },
actionLeftButton: () => Navigator.of(dialogContext).pop()); actionLeftButton: () => Navigator.of(dialogContext).pop());
}); });
}, },
text: "${S.of(context).pay_with} ${getIt.get<AppStore>().wallet.currency.toString()}", text: "${S.of(context).pay_with} ${CryptoCurrency.xmr.toString()}",
color: Theme.of(context).accentTextTheme.body2.color, color: Theme.of(context).accentTextTheme.body2.color,
textColor: Colors.white, textColor: Colors.white,
), ),
@ -457,130 +470,4 @@ class PhoneNumberProductBodyState extends State<PhoneNumberProductBody> {
), ),
); );
} }
Widget cryptoAmount(double totalPrice) {
return FutureBuilder<BuyAmount>(
future: MoonPayBuyProvider(wallet: getIt.get<AppStore>().wallet)
.calculateAmount(totalPrice.toString(), FiatCurrency.usd.title),
builder: (context, AsyncSnapshot<BuyAmount> snapshot) {
double sourceAmount;
double destAmount;
if (snapshot.hasData) {
sourceAmount = snapshot.data.sourceAmount;
destAmount = snapshot.data.destAmount;
} else {
sourceAmount = 0.0;
destAmount = 0.0;
}
return Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
"${sourceAmount} ${getIt.get<AppStore>().wallet.currency.toString()}",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w700,
color: Theme.of(context).primaryTextTheme.title.color,
),
),
Text(
"${destAmount} ${FiatCurrency.usd.title}",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Theme.of(context).accentTextTheme.subhead.color,
),
),
],
);
},
);
}
void showPaymentConfirmationPopup() {
showPopUp<void>(
context: context,
builder: (dialogContext) {
return InfoAlertDialog(
alertTitle: S.of(context).awaiting_payment_confirmation,
alertTitleColor: Theme.of(context).primaryTextTheme.title.decorationColor,
alertContentPadding: EdgeInsets.zero,
alertContent: Padding(
padding: const EdgeInsets.only(top: 8, bottom: 32),
child: Column(
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: 24),
child: Text(
S.of(context).transaction_sent_popup_info,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Theme.of(context).primaryTextTheme.title.color,
),
),
),
Padding(
padding: EdgeInsets.symmetric(vertical: 24),
child: Container(
height: 1,
color: Theme.of(context).dividerColor,
),
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"${S.of(context).transaction_details_transaction_id}:",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Theme.of(context).accentTextTheme.subhead.color,
),
),
Padding(
padding: const EdgeInsets.only(top: 4, bottom: 16),
child: Text(
// TODO: Replace with the transaction id
"dsyf5ind7akwryewkmf5nf4eakdrm4infd4i8rm4fd8nrmsein",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Theme.of(context).primaryTextTheme.title.color,
),
),
),
Text(
"${S.of(context).view_in_block_explorer}:",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Theme.of(context).accentTextTheme.subhead.color,
),
),
Padding(
padding: const EdgeInsets.only(top: 4),
child: Text(
// TODO: get it from transaction details view model
S.of(context).view_transaction_on,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Theme.of(context).primaryTextTheme.title.color,
),
),
),
],
),
),
],
),
),
);
});
}
} }

View file

@ -0,0 +1,80 @@
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/entities/cake_phone_entities/top_up.dart';
import 'package:cake_wallet/src/screens/cake_phone/widgets/receipt_row.dart';
import 'package:cake_wallet/src/screens/cake_phone/widgets/xmr_amount.dart';
import 'package:cake_wallet/store/app_store.dart';
import 'package:cake_wallet/view_model/cake_phone/phone_plan_view_model.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/generated/i18n.dart';
class ConfirmSendingContent extends StatelessWidget {
const ConfirmSendingContent(this.totalPrice, {Key key}) : super(key: key);
final double totalPrice;
@override
Widget build(BuildContext context) {
return FutureBuilder<TopUp>(
future: getIt.get<PhonePlanViewModel>().getMoneroPaymentInfo(totalPrice * 1000),
builder: (context, AsyncSnapshot<TopUp> snapshot) {
double xmrAmount = 0.0;
String address;
if (snapshot.hasData) {
xmrAmount = snapshot.data.amount;
address = snapshot.data.address;
}
return Column(
mainAxisSize: MainAxisSize.min,
children: [
ReceiptRow(
title: S.of(context).amount,
value: XMRAmount(xmrAmount: xmrAmount, fiatAmount: totalPrice),
),
ReceiptRow(
title: S.of(context).send_fee,
// TODO: remove dummy xmrAmount after checking if there will be fees or not and if so from which API
/// since the monero API is only returning the amount and address not the fees
value: XMRAmount(
xmrAmount: 1500,
fiatAmount: getIt
.get<AppStore>()
.wallet
.calculateEstimatedFee(
getIt.get<AppStore>().settingsStore.priority[WalletType.monero],
totalPrice.floor(),
)
.toDouble()),
),
const SizedBox(height: 45),
if (address != null)
Column(
children: [
Text(
S.of(context).recipient_address,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Theme.of(context).primaryTextTheme.title.color,
),
),
const SizedBox(height: 16),
Text(
address,
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.w600,
color: Theme.of(context).accentTextTheme.subhead.color,
),
textAlign: TextAlign.center,
),
],
)
],
);
},
);
}
}

View file

@ -0,0 +1,81 @@
import 'package:cake_wallet/src/widgets/info_alert_dialog.dart';
import 'package:cake_wallet/src/widgets/standart_list_row.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:url_launcher/url_launcher.dart';
class ConfirmationAlertContent extends StatelessWidget {
const ConfirmationAlertContent(this.transactionId, {Key key}) : super(key: key);
final String transactionId;
@override
Widget build(BuildContext context) {
return InfoAlertDialog(
alertTitle: S.of(context).awaiting_payment_confirmation,
alertTitleColor: Theme.of(context).primaryTextTheme.title.decorationColor,
alertContentPadding: EdgeInsets.zero,
alertContent: Padding(
padding: const EdgeInsets.only(top: 8, bottom: 32),
child: Column(
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: 24),
child: Text(
S.of(context).transaction_sent_popup_info,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Theme.of(context).primaryTextTheme.title.color,
),
),
),
Padding(
padding: EdgeInsets.symmetric(vertical: 24),
child: Container(
height: 1,
color: Theme.of(context).dividerColor,
),
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"${S.of(context).transaction_details_transaction_id}:",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Theme.of(context).accentTextTheme.subhead.color,
),
),
Padding(
padding: const EdgeInsets.only(top: 4, bottom: 16),
child: Text(
transactionId,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Theme.of(context).primaryTextTheme.title.color,
),
),
),
GestureDetector(
onTap: () {
launch('https://monero.com/tx/${transactionId}');
},
child: StandartListRow(
title: '${S.of(context).view_in_block_explorer}:',
value: "${S.current.view_transaction_on + 'Monero.com'}",
),
),
],
),
),
],
),
),
);
}
}

View file

@ -0,0 +1,35 @@
import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:flutter/material.dart';
class XMRAmount extends StatelessWidget {
const XMRAmount({Key key, @required this.xmrAmount, @required this.fiatAmount}) : super(key: key);
final double xmrAmount;
final double fiatAmount;
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
"${xmrAmount} ${CryptoCurrency.xmr.toString()}",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w700,
color: Theme.of(context).primaryTextTheme.title.color,
),
),
Text(
"${fiatAmount} ${FiatCurrency.usd.title}",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Theme.of(context).accentTextTheme.subhead.color,
),
),
],
);
}
}

View file

@ -1,3 +1,4 @@
import 'package:cake_wallet/core/execution_state.dart';
import 'package:cake_wallet/view_model/buy/buy_amount_view_model.dart'; import 'package:cake_wallet/view_model/buy/buy_amount_view_model.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cake_wallet/entities/fiat_currency.dart'; import 'package:cake_wallet/entities/fiat_currency.dart';
@ -12,6 +13,8 @@ class AddBalanceViewModel = AddBalanceViewModelBase with _$AddBalanceViewModel;
abstract class AddBalanceViewModelBase with Store { abstract class AddBalanceViewModelBase with Store {
AddBalanceViewModelBase(this.buyAmountViewModel, {@required this.wallet}) { AddBalanceViewModelBase(this.buyAmountViewModel, {@required this.wallet}) {
state = InitialExecutionState();
isRunning = false; isRunning = false;
isDisabled = true; isDisabled = true;
} }
@ -19,6 +22,9 @@ abstract class AddBalanceViewModelBase with Store {
final BuyAmountViewModel buyAmountViewModel; final BuyAmountViewModel buyAmountViewModel;
final WalletBase wallet; final WalletBase wallet;
@observable
ExecutionState state;
@observable @observable
bool isRunning; bool isRunning;

View file

@ -1,3 +1,8 @@
import 'dart:convert';
import 'package:cake_wallet/core/execution_state.dart';
import 'package:cake_wallet/entities/cake_phone_entities/top_up.dart';
import 'package:http/http.dart' as http;
import 'package:cake_wallet/entities/cake_phone_entities/service_plan.dart'; import 'package:cake_wallet/entities/cake_phone_entities/service_plan.dart';
import 'package:country_pickers/countries.dart'; import 'package:country_pickers/countries.dart';
import 'package:country_pickers/country.dart'; import 'package:country_pickers/country.dart';
@ -9,6 +14,9 @@ class PhonePlanViewModel = PhonePlanViewModelBase with _$PhonePlanViewModel;
abstract class PhonePlanViewModelBase with Store { abstract class PhonePlanViewModelBase with Store {
PhonePlanViewModelBase({this.selectedPlan}) { PhonePlanViewModelBase({this.selectedPlan}) {
payWithCakeBalanceState = InitialExecutionState();
payWithXMRState = InitialExecutionState();
additionalSms = 0; additionalSms = 0;
rateInCents = 20; // TODO: get from api rateInCents = 20; // TODO: get from api
@ -26,6 +34,12 @@ abstract class PhonePlanViewModelBase with Store {
selectedCountry = countryList.firstWhere((element) => element.iso3Code == "USA"); selectedCountry = countryList.firstWhere((element) => element.iso3Code == "USA");
} }
@observable
ExecutionState payWithCakeBalanceState;
@observable
ExecutionState payWithXMRState;
@observable @observable
ServicePlan selectedPlan; ServicePlan selectedPlan;
@ -42,8 +56,7 @@ abstract class PhonePlanViewModelBase with Store {
int rateInCents; int rateInCents;
@computed @computed
double get totalPrice => (selectedPlan?.price ?? 0) double get totalPrice => (selectedPlan?.price ?? 0) + (additionalSms * ((rateInCents ?? 0) / 100)).toDouble();
+ (additionalSms * ((rateInCents ?? 0) / 100)).toDouble();
@action @action
void addAdditionalSms() => additionalSms++; void addAdditionalSms() => additionalSms++;
@ -54,4 +67,67 @@ abstract class PhonePlanViewModelBase with Store {
additionalSms--; additionalSms--;
} }
} }
final String _baseUrl = '';
Future<bool> purchasePlan() async {
payWithCakeBalanceState = IsExecutingState();
final headers = {'Content-Type': 'application/json'};
final body = <String, String>{
"country": "US",
"plan_id": "8b23b65a-a465-4d02-819e-9a6054eb4c22",
};
final uri = Uri.https(_baseUrl, '/account/me/service/phone_number');
final response = await http.post(uri, headers: headers, body: json.encode(body));
if (response.statusCode != 200) {
payWithCakeBalanceState = FailureState(response.body);
return false;
}
buyAdditionalSMS();
payWithCakeBalanceState = ExecutedSuccessfullyState();
return true;
}
Future<bool> buyAdditionalSMS() async {
if (additionalSms == 0) {
return true;
}
final headers = {'Content-Type': 'application/json'};
final body = <String, int>{"quantity": additionalSms};
final uri = Uri.https(_baseUrl, '/account/me/service/message_receive');
final response = await http.post(uri, headers: headers, body: json.encode(body));
if (response.statusCode != 200) {
return false;
}
return true;
}
Future<TopUp> getMoneroPaymentInfo(double totalPrice) async {
final headers = {'Content-Type': 'application/json'};
final body = <String, String>{"amount": totalPrice.toString()};
final uri = Uri.https(_baseUrl, '/account/me/topup/moneropay');
final response = await http.post(uri, headers: headers, body: json.encode(body));
if (response.statusCode != 200) {
return null;
}
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
return TopUp(
id: responseJSON['id'] as String,
address: responseJSON['address'] as String,
amount: responseJSON['amount'] as double,
);
}
} }

View file

@ -596,5 +596,7 @@
"add_balance": "Add Balance", "add_balance": "Add Balance",
"forwards": "forwards", "forwards": "forwards",
"invalid_email": "Invalid Email", "invalid_email": "Invalid Email",
"invalid_verification_code": "Invalid verification code" "invalid_verification_code": "Invalid verification code",
"payment_failed": "Payment Failed, please try again later",
"loading": "Loading..."
} }