mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-22 19:49:22 +00:00
Add Initial flow for payment
Remove buy provider and get XMR values from monero API Separate alert content widgets
This commit is contained in:
parent
da910ee0be
commit
bee69c02ba
9 changed files with 372 additions and 359 deletions
13
lib/entities/cake_phone_entities/top_up.dart
Normal file
13
lib/entities/cake_phone_entities/top_up.dart
Normal 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;
|
||||
}
|
|
@ -1,12 +1,9 @@
|
|||
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/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/info_alert_dialog.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:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -14,7 +11,6 @@ import 'package:flutter/services.dart';
|
|||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:keyboard_actions/keyboard_actions.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/scollable_with_bottom_section.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
@ -180,44 +176,7 @@ class AddBalancePage extends BasePage {
|
|||
alertContent: S.of(context).confirm_delete_template,
|
||||
contentWidget: Material(
|
||||
color: Colors.transparent,
|
||||
child: Column(
|
||||
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,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: ConfirmSendingContent(addBalanceViewModel.buyAmountViewModel.doubleAmount),
|
||||
),
|
||||
isDividerExists: true,
|
||||
rightButtonText: S.of(context).ok,
|
||||
|
@ -226,7 +185,12 @@ class AddBalancePage extends BasePage {
|
|||
leftActionButtonColor: Theme.of(context).primaryTextTheme.body2.backgroundColor,
|
||||
actionRightButton: () {
|
||||
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());
|
||||
});
|
||||
|
@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
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/core/execution_state.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/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/receipt_row.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/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/view_model/cake_phone/phone_plan_view_model.dart';
|
||||
import 'package:country_pickers/country.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:dotted_border/dotted_border.dart';
|
||||
import 'package:flushbar/flushbar.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.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/widgets/scollable_with_bottom_section.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
class PhoneNumberProductPage extends BasePage {
|
||||
PhoneNumberProductPage(this.phonePlanViewModel, {this.phoneNumberService});
|
||||
|
@ -58,6 +59,55 @@ class PhoneNumberProductBody extends StatefulWidget {
|
|||
}
|
||||
|
||||
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
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
|
@ -321,7 +371,9 @@ class PhoneNumberProductBodyState extends State<PhoneNumberProductBody> {
|
|||
children: [
|
||||
ReceiptRow(
|
||||
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,
|
||||
|
@ -331,11 +383,12 @@ class PhoneNumberProductBodyState extends State<PhoneNumberProductBody> {
|
|||
leftActionButtonColor: Theme.of(context).primaryTextTheme.body2.backgroundColor,
|
||||
actionRightButton: () {
|
||||
Navigator.of(dialogContext).pop();
|
||||
Navigator.pushNamedAndRemoveUntil(
|
||||
context,
|
||||
Routes.cakePhoneActiveServices,
|
||||
ModalRoute.withName(Routes.cakePhoneWelcome),
|
||||
);
|
||||
if (widget.phoneNumberService == null ||
|
||||
widget.phoneNumberService.planId != widget.phonePlanViewModel.selectedPlan.id) {
|
||||
widget.phonePlanViewModel.purchasePlan();
|
||||
} else {
|
||||
widget.phonePlanViewModel.buyAdditionalSMS();
|
||||
}
|
||||
},
|
||||
actionLeftButton: () => Navigator.of(dialogContext).pop());
|
||||
});
|
||||
|
@ -354,46 +407,7 @@ class PhoneNumberProductBodyState extends State<PhoneNumberProductBody> {
|
|||
alertTitle: S.of(context).confirm_sending,
|
||||
alertTitleColor: Theme.of(context).primaryTextTheme.title.decorationColor,
|
||||
alertContent: S.of(context).confirm_delete_template,
|
||||
contentWidget: Column(
|
||||
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,
|
||||
),
|
||||
],
|
||||
),
|
||||
contentWidget: ConfirmSendingContent(widget.phonePlanViewModel.totalPrice),
|
||||
isDividerExists: true,
|
||||
rightButtonText: S.of(context).ok,
|
||||
leftButtonText: S.of(context).cancel,
|
||||
|
@ -401,12 +415,11 @@ class PhoneNumberProductBodyState extends State<PhoneNumberProductBody> {
|
|||
leftActionButtonColor: Theme.of(context).primaryTextTheme.body2.backgroundColor,
|
||||
actionRightButton: () {
|
||||
Navigator.of(dialogContext).pop();
|
||||
showPaymentConfirmationPopup();
|
||||
},
|
||||
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,
|
||||
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,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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'}",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
35
lib/src/screens/cake_phone/widgets/xmr_amount.dart
Normal file
35
lib/src/screens/cake_phone/widgets/xmr_amount.dart
Normal 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,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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:cw_core/crypto_currency.dart';
|
||||
import 'package:cake_wallet/entities/fiat_currency.dart';
|
||||
|
@ -12,6 +13,8 @@ class AddBalanceViewModel = AddBalanceViewModelBase with _$AddBalanceViewModel;
|
|||
|
||||
abstract class AddBalanceViewModelBase with Store {
|
||||
AddBalanceViewModelBase(this.buyAmountViewModel, {@required this.wallet}) {
|
||||
state = InitialExecutionState();
|
||||
|
||||
isRunning = false;
|
||||
isDisabled = true;
|
||||
}
|
||||
|
@ -19,6 +22,9 @@ abstract class AddBalanceViewModelBase with Store {
|
|||
final BuyAmountViewModel buyAmountViewModel;
|
||||
final WalletBase wallet;
|
||||
|
||||
@observable
|
||||
ExecutionState state;
|
||||
|
||||
@observable
|
||||
bool isRunning;
|
||||
|
||||
|
|
|
@ -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:country_pickers/countries.dart';
|
||||
import 'package:country_pickers/country.dart';
|
||||
|
@ -9,6 +14,9 @@ class PhonePlanViewModel = PhonePlanViewModelBase with _$PhonePlanViewModel;
|
|||
|
||||
abstract class PhonePlanViewModelBase with Store {
|
||||
PhonePlanViewModelBase({this.selectedPlan}) {
|
||||
payWithCakeBalanceState = InitialExecutionState();
|
||||
payWithXMRState = InitialExecutionState();
|
||||
|
||||
additionalSms = 0;
|
||||
rateInCents = 20; // TODO: get from api
|
||||
|
||||
|
@ -26,6 +34,12 @@ abstract class PhonePlanViewModelBase with Store {
|
|||
selectedCountry = countryList.firstWhere((element) => element.iso3Code == "USA");
|
||||
}
|
||||
|
||||
@observable
|
||||
ExecutionState payWithCakeBalanceState;
|
||||
|
||||
@observable
|
||||
ExecutionState payWithXMRState;
|
||||
|
||||
@observable
|
||||
ServicePlan selectedPlan;
|
||||
|
||||
|
@ -42,8 +56,7 @@ abstract class PhonePlanViewModelBase with Store {
|
|||
int rateInCents;
|
||||
|
||||
@computed
|
||||
double get totalPrice => (selectedPlan?.price ?? 0)
|
||||
+ (additionalSms * ((rateInCents ?? 0) / 100)).toDouble();
|
||||
double get totalPrice => (selectedPlan?.price ?? 0) + (additionalSms * ((rateInCents ?? 0) / 100)).toDouble();
|
||||
|
||||
@action
|
||||
void addAdditionalSms() => additionalSms++;
|
||||
|
@ -54,4 +67,67 @@ abstract class PhonePlanViewModelBase with Store {
|
|||
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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -596,5 +596,7 @@
|
|||
"add_balance": "Add Balance",
|
||||
"forwards": "forwards",
|
||||
"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..."
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue