mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-06-28 12:29:51 +00:00
feat: support LTC and MWEB payments
This commit is contained in:
parent
2086c467b5
commit
acd73d83c4
3 changed files with 179 additions and 51 deletions
|
@ -2,6 +2,7 @@ import 'dart:io';
|
||||||
|
|
||||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||||
import 'package:cake_wallet/cake_pay/src/models/cake_pay_card.dart';
|
import 'package:cake_wallet/cake_pay/src/models/cake_pay_card.dart';
|
||||||
|
import 'package:cake_wallet/cake_pay/src/models/cake_pay_order.dart';
|
||||||
import 'package:cake_wallet/cake_pay/src/services/cake_pay_service.dart';
|
import 'package:cake_wallet/cake_pay/src/services/cake_pay_service.dart';
|
||||||
import 'package:cake_wallet/cake_pay/src/widgets/cake_pay_alert_modal.dart';
|
import 'package:cake_wallet/cake_pay/src/widgets/cake_pay_alert_modal.dart';
|
||||||
import 'package:cake_wallet/cake_pay/src/widgets/denominations_amount_widget.dart';
|
import 'package:cake_wallet/cake_pay/src/widgets/denominations_amount_widget.dart';
|
||||||
|
@ -90,7 +91,6 @@ class CakePayBuyCardPage extends BasePage {
|
||||||
|
|
||||||
final card = cakePayBuyCardViewModel.card;
|
final card = cakePayBuyCardViewModel.card;
|
||||||
final vendor = cakePayBuyCardViewModel.vendor;
|
final vendor = cakePayBuyCardViewModel.vendor;
|
||||||
final baseTitleColor = titleColor(context);
|
|
||||||
|
|
||||||
return KeyboardActions(
|
return KeyboardActions(
|
||||||
disableScroll: true,
|
disableScroll: true,
|
||||||
|
@ -248,25 +248,89 @@ class CakePayBuyCardPage extends BasePage {
|
||||||
),
|
),
|
||||||
SizedBox(height: 8),
|
SizedBox(height: 8),
|
||||||
Observer(builder: (_) {
|
Observer(builder: (_) {
|
||||||
return Padding(
|
final methods = cakePayBuyCardViewModel.availableMethods;
|
||||||
padding: EdgeInsets.only(top: 10, bottom: 34, right: 20, left: 20),
|
final selected = cakePayBuyCardViewModel.selectedPaymentMethod ?? methods.first;
|
||||||
child: LoadingPrimaryButton(
|
|
||||||
onPressed: () {
|
|
||||||
//Request dummy node to get the focus out of the text fields
|
|
||||||
FocusScope.of(context).requestFocus(FocusNode());
|
|
||||||
|
|
||||||
isIOSUnavailable(card)
|
return Column(
|
||||||
? alertIOSAvailability(context, card)
|
children: [
|
||||||
: confirmPurchaseFirst(context);
|
methods.length <= 1
|
||||||
},
|
? const SizedBox.shrink()
|
||||||
text: S.of(context).purchase_gift_card,
|
: Row(
|
||||||
isDisabled: !cakePayBuyCardViewModel.isAmountSufficient ||
|
children: [
|
||||||
cakePayBuyCardViewModel.isPurchasing,
|
Padding(
|
||||||
isLoading: cakePayBuyCardViewModel.sendViewModel.state is IsExecutingState ||
|
padding: const EdgeInsets.only(left: 24, right: 8),
|
||||||
cakePayBuyCardViewModel.isPurchasing,
|
child: Text(
|
||||||
color: Theme.of(context).colorScheme.primary,
|
'Payment Method',
|
||||||
textColor: Theme.of(context).colorScheme.onPrimary,
|
style: TextStyle(
|
||||||
),
|
color: Theme.of(context).textTheme.titleLarge!.color!,
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w900,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(child: const SizedBox()),
|
||||||
|
if (methods.length > 1)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 6),
|
||||||
|
child: ToggleButtons(
|
||||||
|
isSelected: methods.map((m) => m == selected).toList(),
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
onPressed: (index) =>
|
||||||
|
cakePayBuyCardViewModel.chooseMethod(methods[index]),
|
||||||
|
children: methods
|
||||||
|
.map((m) => Padding(
|
||||||
|
padding:
|
||||||
|
const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||||
|
child: Text(m.label),
|
||||||
|
))
|
||||||
|
.toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if (FeatureFlag.hasDevOptions)
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(top: 10, bottom: 0, right: 20, left: 20),
|
||||||
|
child: LoadingPrimaryButton(
|
||||||
|
onPressed: () {
|
||||||
|
//Request dummy node to get the focus out of the text fields
|
||||||
|
FocusScope.of(context).requestFocus(FocusNode());
|
||||||
|
|
||||||
|
cakePayBuyCardViewModel.isSimulatingFlow = true;
|
||||||
|
isIOSUnavailable(card)
|
||||||
|
? alertIOSAvailability(context, card)
|
||||||
|
: confirmPurchaseFirst(context);
|
||||||
|
},
|
||||||
|
text: '(Dev) Simulate Purchasing Gift Card',
|
||||||
|
isDisabled: !cakePayBuyCardViewModel.isAmountSufficient ||
|
||||||
|
cakePayBuyCardViewModel.isPurchasing,
|
||||||
|
isLoading: cakePayBuyCardViewModel.sendViewModel.state is IsExecutingState ||
|
||||||
|
cakePayBuyCardViewModel.isPurchasing,
|
||||||
|
color: Theme.of(context).colorScheme.primary,
|
||||||
|
textColor: Theme.of(context).colorScheme.onPrimary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(top: 10, bottom: 34, right: 20, left: 20),
|
||||||
|
child: LoadingPrimaryButton(
|
||||||
|
onPressed: () {
|
||||||
|
//Request dummy node to get the focus out of the text fields
|
||||||
|
FocusScope.of(context).requestFocus(FocusNode());
|
||||||
|
|
||||||
|
isIOSUnavailable(card)
|
||||||
|
? alertIOSAvailability(context, card)
|
||||||
|
: confirmPurchaseFirst(context);
|
||||||
|
},
|
||||||
|
text: S.of(context).purchase_gift_card,
|
||||||
|
isDisabled: !cakePayBuyCardViewModel.isAmountSufficient ||
|
||||||
|
cakePayBuyCardViewModel.isPurchasing,
|
||||||
|
isLoading: cakePayBuyCardViewModel.sendViewModel.state is IsExecutingState ||
|
||||||
|
cakePayBuyCardViewModel.isPurchasing,
|
||||||
|
color: Theme.of(context).colorScheme.primary,
|
||||||
|
textColor: Theme.of(context).colorScheme.onPrimary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
@ -317,6 +381,7 @@ class CakePayBuyCardPage extends BasePage {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> alertIOSAvailability(BuildContext context, CakePayCard card) async {
|
Future<void> alertIOSAvailability(BuildContext context, CakePayCard card) async {
|
||||||
|
cakePayBuyCardViewModel.isSimulatingFlow = false;
|
||||||
return await showPopUp<void>(
|
return await showPopUp<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
|
@ -334,11 +399,13 @@ class CakePayBuyCardPage extends BasePage {
|
||||||
Future<void> confirmPurchaseFirst(BuildContext context) async {
|
Future<void> confirmPurchaseFirst(BuildContext context) async {
|
||||||
bool isLogged = await cakePayBuyCardViewModel.cakePayService.isLogged();
|
bool isLogged = await cakePayBuyCardViewModel.cakePayService.isLogged();
|
||||||
if (!isLogged) {
|
if (!isLogged) {
|
||||||
|
cakePayBuyCardViewModel.isSimulatingFlow = false;
|
||||||
Navigator.of(context).pushNamed(Routes.cakePayWelcomePage);
|
Navigator.of(context).pushNamed(Routes.cakePayWelcomePage);
|
||||||
} else {
|
} else {
|
||||||
cakePayBuyCardViewModel.isPurchasing = true;
|
cakePayBuyCardViewModel.isPurchasing = true;
|
||||||
await _showconfirmPurchaseFirstAlert(context);
|
await _showconfirmPurchaseFirstAlert(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _showconfirmPurchaseFirstAlert(BuildContext context) async {
|
Future<void> _showconfirmPurchaseFirstAlert(BuildContext context) async {
|
||||||
|
@ -353,6 +420,7 @@ class CakePayBuyCardPage extends BasePage {
|
||||||
rightButtonText: S.of(context).confirm,
|
rightButtonText: S.of(context).confirm,
|
||||||
actionLeftButton: () {
|
actionLeftButton: () {
|
||||||
cakePayBuyCardViewModel.isPurchasing = false;
|
cakePayBuyCardViewModel.isPurchasing = false;
|
||||||
|
cakePayBuyCardViewModel.isSimulatingFlow = false;
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
actionRightButton: (confirmsNoVpn, confirmsVoidedRefund, confirmsTermsAgreed) {
|
actionRightButton: (confirmsNoVpn, confirmsVoidedRefund, confirmsTermsAgreed) {
|
||||||
|
@ -370,17 +438,22 @@ class CakePayBuyCardPage extends BasePage {
|
||||||
cakePayBuyCardViewModel.confirmsVoidedRefund &&
|
cakePayBuyCardViewModel.confirmsVoidedRefund &&
|
||||||
cakePayBuyCardViewModel.confirmsTermsAgreed) {
|
cakePayBuyCardViewModel.confirmsTermsAgreed) {
|
||||||
await purchaseCard(context);
|
await purchaseCard(context);
|
||||||
|
} else {
|
||||||
|
cakePayBuyCardViewModel.isPurchasing = false;
|
||||||
|
cakePayBuyCardViewModel.isSimulatingFlow = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> purchaseCard(BuildContext context) async {
|
Future<void> purchaseCard(BuildContext context) async {
|
||||||
bool isLogged = await cakePayBuyCardViewModel.cakePayService.isLogged();
|
bool isLogged = await cakePayBuyCardViewModel.cakePayService.isLogged();
|
||||||
if (!isLogged) {
|
if (!isLogged) {
|
||||||
|
cakePayBuyCardViewModel.isSimulatingFlow = false;
|
||||||
Navigator.of(context).pushNamed(Routes.cakePayWelcomePage);
|
Navigator.of(context).pushNamed(Routes.cakePayWelcomePage);
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
await cakePayBuyCardViewModel.createOrder();
|
await cakePayBuyCardViewModel.createOrder();
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
|
cakePayBuyCardViewModel.isSimulatingFlow = false;
|
||||||
await cakePayBuyCardViewModel.cakePayService.logout();
|
await cakePayBuyCardViewModel.cakePayService.logout();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -512,11 +585,11 @@ class CakePayBuyCardPage extends BasePage {
|
||||||
.sendViewModel.pendingTransactionFeeFiatAmountFormatted,
|
.sendViewModel.pendingTransactionFeeFiatAmountFormatted,
|
||||||
outputs: displayingOutputs,
|
outputs: displayingOutputs,
|
||||||
footerType: FooterType.slideActionButton,
|
footerType: FooterType.slideActionButton,
|
||||||
slideActionButtonText: 'Swipe to send',
|
slideActionButtonText: cakePayBuyCardViewModel.isSimulating ? 'Swipe to simulate' : 'Swipe to send',
|
||||||
accessibleNavigationModeSlideActionButtonText: S.of(context).send,
|
accessibleNavigationModeSlideActionButtonText: cakePayBuyCardViewModel.isSimulating ? 'Simulate' : S.of(context).send,
|
||||||
onSlideActionComplete: () async {
|
onSlideActionComplete: () async {
|
||||||
Navigator.of(bottomSheetContext).pop(true);
|
Navigator.of(bottomSheetContext).pop(true);
|
||||||
FeatureFlag.hasDevOptions
|
cakePayBuyCardViewModel.isSimulating
|
||||||
? cakePayBuyCardViewModel.simulatePayment()
|
? cakePayBuyCardViewModel.simulatePayment()
|
||||||
: cakePayBuyCardViewModel.sendViewModel.commitTransaction(context);
|
: cakePayBuyCardViewModel.sendViewModel.commitTransaction(context);
|
||||||
},
|
},
|
||||||
|
@ -527,6 +600,7 @@ class CakePayBuyCardPage extends BasePage {
|
||||||
);
|
);
|
||||||
|
|
||||||
confirmBottomSheetContext = null;
|
confirmBottomSheetContext = null;
|
||||||
|
cakePayBuyCardViewModel.isSimulatingFlow = false;
|
||||||
_handleDispose(disposer);
|
_handleDispose(disposer);
|
||||||
if (result == null) cakePayBuyCardViewModel.sendViewModel.dismissTransaction();
|
if (result == null) cakePayBuyCardViewModel.sendViewModel.dismissTransaction();
|
||||||
}
|
}
|
||||||
|
@ -563,9 +637,7 @@ class CakePayBuyCardPage extends BasePage {
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
FeatureFlag.hasDevOptions
|
S.of(bottomSheetContext).cake_pay_save_order,
|
||||||
? cakePayBuyCardViewModel.simulatedResponse
|
|
||||||
: S.of(bottomSheetContext).cake_pay_save_order,
|
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontFamily: 'Lato',
|
fontFamily: 'Lato',
|
||||||
|
|
|
@ -1,3 +1,15 @@
|
||||||
|
enum CakePayPaymentMethod { BTC, BTC_LN, XMR, LTC, LTC_MWEB }
|
||||||
|
|
||||||
|
extension CakePayPaymentMethodLabel on CakePayPaymentMethod {
|
||||||
|
String get label => switch (this) {
|
||||||
|
CakePayPaymentMethod.BTC => 'Bitcoin',
|
||||||
|
CakePayPaymentMethod.BTC_LN => 'Bitcoin Lightning',
|
||||||
|
CakePayPaymentMethod.XMR => 'Monero',
|
||||||
|
CakePayPaymentMethod.LTC => 'Litecoin',
|
||||||
|
CakePayPaymentMethod.LTC_MWEB => 'Litecoin MWEB',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
class CakePayOrder {
|
class CakePayOrder {
|
||||||
final String orderId;
|
final String orderId;
|
||||||
final List<OrderCard> cards;
|
final List<OrderCard> cards;
|
||||||
|
@ -65,14 +77,20 @@ class OrderCard {
|
||||||
|
|
||||||
class PaymentData {
|
class PaymentData {
|
||||||
final CryptoPaymentData btc;
|
final CryptoPaymentData btc;
|
||||||
|
final CryptoPaymentData btc_ln;
|
||||||
final CryptoPaymentData xmr;
|
final CryptoPaymentData xmr;
|
||||||
|
final CryptoPaymentData ltc;
|
||||||
|
final CryptoPaymentData ltc_mweb;
|
||||||
final DateTime invoiceTime;
|
final DateTime invoiceTime;
|
||||||
final DateTime expirationTime;
|
final DateTime expirationTime;
|
||||||
final int? commission;
|
final int? commission;
|
||||||
|
|
||||||
PaymentData({
|
PaymentData({
|
||||||
required this.btc,
|
required this.btc,
|
||||||
|
required this.btc_ln,
|
||||||
required this.xmr,
|
required this.xmr,
|
||||||
|
required this.ltc,
|
||||||
|
required this.ltc_mweb,
|
||||||
required this.invoiceTime,
|
required this.invoiceTime,
|
||||||
required this.expirationTime,
|
required this.expirationTime,
|
||||||
required this.commission,
|
required this.commission,
|
||||||
|
@ -81,7 +99,10 @@ class PaymentData {
|
||||||
factory PaymentData.fromMap(Map<String, dynamic> map) {
|
factory PaymentData.fromMap(Map<String, dynamic> map) {
|
||||||
return PaymentData(
|
return PaymentData(
|
||||||
btc: CryptoPaymentData.fromMap(map['BTC'] as Map<String, dynamic>),
|
btc: CryptoPaymentData.fromMap(map['BTC'] as Map<String, dynamic>),
|
||||||
|
btc_ln: CryptoPaymentData.fromMap(map['BTC_LN'] as Map<String, dynamic>),
|
||||||
xmr: CryptoPaymentData.fromMap(map['XMR'] as Map<String, dynamic>),
|
xmr: CryptoPaymentData.fromMap(map['XMR'] as Map<String, dynamic>),
|
||||||
|
ltc: CryptoPaymentData.fromMap(map['LTC'] as Map<String, dynamic>),
|
||||||
|
ltc_mweb: CryptoPaymentData.fromMap(map['LTC_MWEB'] as Map<String, dynamic>),
|
||||||
invoiceTime: DateTime.fromMillisecondsSinceEpoch(map['invoice_time'] as int),
|
invoiceTime: DateTime.fromMillisecondsSinceEpoch(map['invoice_time'] as int),
|
||||||
expirationTime: DateTime.fromMillisecondsSinceEpoch(map['expiration_time'] as int),
|
expirationTime: DateTime.fromMillisecondsSinceEpoch(map['expiration_time'] as int),
|
||||||
commission: map['commission'] as int?,
|
commission: map['commission'] as int?,
|
||||||
|
|
|
@ -5,6 +5,7 @@ import 'package:cake_wallet/cake_pay/src/models/cake_pay_order.dart';
|
||||||
import 'package:cake_wallet/cake_pay/src/models/cake_pay_vendor.dart';
|
import 'package:cake_wallet/cake_pay/src/models/cake_pay_vendor.dart';
|
||||||
import 'package:cake_wallet/cake_pay/src/services/cake_pay_service.dart';
|
import 'package:cake_wallet/cake_pay/src/services/cake_pay_service.dart';
|
||||||
import 'package:cake_wallet/core/execution_state.dart';
|
import 'package:cake_wallet/core/execution_state.dart';
|
||||||
|
import 'package:cake_wallet/utils/feature_flag.dart';
|
||||||
import 'package:cake_wallet/view_model/send/send_view_model.dart';
|
import 'package:cake_wallet/view_model/send/send_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/send/send_view_model_state.dart';
|
import 'package:cake_wallet/view_model/send/send_view_model_state.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
@ -24,7 +25,9 @@ abstract class CakePayBuyCardViewModelBase with Store {
|
||||||
quantity = 1,
|
quantity = 1,
|
||||||
min = double.parse(vendor.card!.minValue ?? '0'),
|
min = double.parse(vendor.card!.minValue ?? '0'),
|
||||||
max = double.parse(vendor.card!.maxValue ?? '0'),
|
max = double.parse(vendor.card!.maxValue ?? '0'),
|
||||||
card = vendor.card!;
|
card = vendor.card! {
|
||||||
|
selectedPaymentMethod = availableMethods.isNotEmpty ? availableMethods.first : null;
|
||||||
|
}
|
||||||
|
|
||||||
final CakePayVendor vendor;
|
final CakePayVendor vendor;
|
||||||
final SendViewModel sendViewModel;
|
final SendViewModel sendViewModel;
|
||||||
|
@ -55,6 +58,9 @@ abstract class CakePayBuyCardViewModelBase with Store {
|
||||||
@observable
|
@observable
|
||||||
bool isPurchasing = false;
|
bool isPurchasing = false;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
bool isSimulatingFlow = false;
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
bool isOrderExpired = false;
|
bool isOrderExpired = false;
|
||||||
|
|
||||||
|
@ -65,9 +71,32 @@ abstract class CakePayBuyCardViewModelBase with Store {
|
||||||
bool get isAmountSufficient =>
|
bool get isAmountSufficient =>
|
||||||
(amount >= min && amount <= max) || (isDenominationSelected && quantity > 0);
|
(amount >= min && amount <= max) || (isDenominationSelected && quantity > 0);
|
||||||
|
|
||||||
|
@observable
|
||||||
|
CakePayPaymentMethod? selectedPaymentMethod;
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
double get totalAmount => amount * quantity;
|
double get totalAmount => amount * quantity;
|
||||||
|
|
||||||
|
@computed
|
||||||
|
bool get isSimulating => isSimulatingFlow && FeatureFlag.hasDevOptions;
|
||||||
|
|
||||||
|
@computed
|
||||||
|
List<CakePayPaymentMethod> get availableMethods {
|
||||||
|
switch (walletType) {
|
||||||
|
case WalletType.bitcoin:
|
||||||
|
return [CakePayPaymentMethod.BTC];
|
||||||
|
case WalletType.litecoin:
|
||||||
|
return [CakePayPaymentMethod.LTC, CakePayPaymentMethod.LTC_MWEB];
|
||||||
|
case WalletType.monero:
|
||||||
|
return [CakePayPaymentMethod.XMR];
|
||||||
|
default:
|
||||||
|
return const [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
void chooseMethod(CakePayPaymentMethod method) => selectedPaymentMethod = method;
|
||||||
|
|
||||||
@action
|
@action
|
||||||
void onQuantityChanged(int? input) => quantity = input ?? 1;
|
void onQuantityChanged(int? input) => quantity = input ?? 1;
|
||||||
|
|
||||||
|
@ -77,34 +106,39 @@ abstract class CakePayBuyCardViewModelBase with Store {
|
||||||
amount = double.parse(input.replaceAll(',', '.'));
|
amount = double.parse(input.replaceAll(',', '.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
CryptoPaymentData? get cryptoPaymentData {
|
CryptoPaymentData? getPaymentDataFor(CakePayPaymentMethod? method) {
|
||||||
if (order == null) return null;
|
if (order == null || method == null) return null;
|
||||||
|
|
||||||
if (WalletType.monero == walletType) {
|
|
||||||
return order!.paymentData.xmr;
|
final data = switch (method) {
|
||||||
|
CakePayPaymentMethod.BTC => order?.paymentData.btc,
|
||||||
|
CakePayPaymentMethod.XMR => order?.paymentData.xmr,
|
||||||
|
CakePayPaymentMethod.LTC => order?.paymentData.ltc,
|
||||||
|
CakePayPaymentMethod.LTC_MWEB => order?.paymentData.ltc_mweb,
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
|
||||||
|
if (data == null) return null;
|
||||||
|
|
||||||
|
final bip21 = data.paymentUrls?.bip21;
|
||||||
|
if (bip21 != null && bip21.isNotEmpty) {
|
||||||
|
final uri = Uri.parse(bip21);
|
||||||
|
final addr = uri.path;
|
||||||
|
final price = uri.queryParameters['amount'] ?? data.price;
|
||||||
|
|
||||||
|
return CryptoPaymentData(price: price, address: addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WalletType.bitcoin == walletType) {
|
return data;
|
||||||
final paymentUrls = order!.paymentData.btc.paymentUrls!.bip21;
|
|
||||||
|
|
||||||
final uri = Uri.parse(paymentUrls!);
|
|
||||||
|
|
||||||
final address = uri.path;
|
|
||||||
final price = uri.queryParameters['amount'];
|
|
||||||
|
|
||||||
return CryptoPaymentData(
|
|
||||||
address: address,
|
|
||||||
price: price ?? '0',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
Future<void> createOrder() async {
|
Future<void> createOrder() async {
|
||||||
if (walletType != WalletType.bitcoin && walletType != WalletType.monero) {
|
if (walletType != WalletType.bitcoin &&
|
||||||
sendViewModel.state = FailureState('Unsupported wallet type, please use Bitcoin or Monero.');
|
walletType != WalletType.monero &&
|
||||||
|
walletType != WalletType.litecoin) {
|
||||||
|
sendViewModel.state =
|
||||||
|
FailureState('Unsupported wallet type, please use Bitcoin, Monero, or Litecoin.');
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
order = await cakePayService.createOrder(
|
order = await cakePayService.createOrder(
|
||||||
|
@ -129,10 +163,10 @@ abstract class CakePayBuyCardViewModelBase with Store {
|
||||||
|
|
||||||
@action
|
@action
|
||||||
Future<void> confirmSending() async {
|
Future<void> confirmSending() async {
|
||||||
final cryptoPaymentData = this.cryptoPaymentData;
|
final cryptoPaymentData = getPaymentDataFor(selectedPaymentMethod);
|
||||||
try {
|
if (order == null || cryptoPaymentData == null) return;
|
||||||
if (order == null || cryptoPaymentData == null) return;
|
|
||||||
|
|
||||||
|
try {
|
||||||
sendViewModel.clearOutputs();
|
sendViewModel.clearOutputs();
|
||||||
final output = sendViewModel.outputs.first;
|
final output = sendViewModel.outputs.first;
|
||||||
output.address = cryptoPaymentData.address;
|
output.address = cryptoPaymentData.address;
|
||||||
|
@ -190,7 +224,8 @@ abstract class CakePayBuyCardViewModelBase with Store {
|
||||||
final hours = duration.inHours;
|
final hours = duration.inHours;
|
||||||
final minutes = duration.inMinutes.remainder(60);
|
final minutes = duration.inMinutes.remainder(60);
|
||||||
final seconds = duration.inSeconds.remainder(60);
|
final seconds = duration.inSeconds.remainder(60);
|
||||||
return '${hours.toString().padLeft(2, '0')}:${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}';
|
return '${hours.toString().padLeft(2, '0')}:${minutes.toString().padLeft(2, '0')}:${seconds
|
||||||
|
.toString().padLeft(2, '0')}';
|
||||||
}
|
}
|
||||||
|
|
||||||
void disposeExpirationTimer() {
|
void disposeExpirationTimer() {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue