mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-01-25 12:06:05 +00:00
lightning receive first pass
This commit is contained in:
parent
038424c5db
commit
ce2a51835d
14 changed files with 1178 additions and 303 deletions
42
lib/di.dart
42
lib/di.dart
|
@ -37,7 +37,10 @@ import 'package:cake_wallet/src/screens/nano_accounts/nano_account_list_page.dar
|
||||||
import 'package:cake_wallet/src/screens/nodes/pow_node_create_or_edit_page.dart';
|
import 'package:cake_wallet/src/screens/nodes/pow_node_create_or_edit_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/receive/anonpay_invoice_page.dart';
|
import 'package:cake_wallet/src/screens/receive/anonpay_invoice_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/receive/anonpay_receive_page.dart';
|
import 'package:cake_wallet/src/screens/receive/anonpay_receive_page.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/receive/lightning_invoice_page.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/receive/lightning_receive_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/restore/wallet_restore_choose_derivation.dart';
|
import 'package:cake_wallet/src/screens/restore/wallet_restore_choose_derivation.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/send/lightning_send_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/settings/display_settings_page.dart';
|
import 'package:cake_wallet/src/screens/settings/display_settings_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/settings/domain_lookups_page.dart';
|
import 'package:cake_wallet/src/screens/settings/domain_lookups_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/settings/manage_nodes_page.dart';
|
import 'package:cake_wallet/src/screens/settings/manage_nodes_page.dart';
|
||||||
|
@ -89,6 +92,8 @@ import 'package:cake_wallet/src/screens/dashboard/pages/balance_page.dart';
|
||||||
import 'package:cake_wallet/view_model/ionia/ionia_account_view_model.dart';
|
import 'package:cake_wallet/view_model/ionia/ionia_account_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/ionia/ionia_gift_cards_list_view_model.dart';
|
import 'package:cake_wallet/view_model/ionia/ionia_gift_cards_list_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/ionia/ionia_purchase_merch_view_model.dart';
|
import 'package:cake_wallet/view_model/ionia/ionia_purchase_merch_view_model.dart';
|
||||||
|
import 'package:cake_wallet/view_model/lightning_invoice_page_view_model.dart';
|
||||||
|
import 'package:cake_wallet/view_model/lightning_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/nano_account_list/nano_account_edit_or_create_view_model.dart';
|
import 'package:cake_wallet/view_model/nano_account_list/nano_account_edit_or_create_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/nano_account_list/nano_account_list_view_model.dart';
|
import 'package:cake_wallet/view_model/nano_account_list/nano_account_list_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/node_list/pow_node_list_view_model.dart';
|
import 'package:cake_wallet/view_model/node_list/pow_node_list_view_model.dart';
|
||||||
|
@ -1195,5 +1200,42 @@ Future<void> setup({
|
||||||
getIt.registerFactory(() => NFTViewModel(appStore, getIt.get<BottomSheetService>()));
|
getIt.registerFactory(() => NFTViewModel(appStore, getIt.get<BottomSheetService>()));
|
||||||
getIt.registerFactory<TorPage>(() => TorPage(getIt.get<AppStore>()));
|
getIt.registerFactory<TorPage>(() => TorPage(getIt.get<AppStore>()));
|
||||||
|
|
||||||
|
getIt.registerFactory<LightningReceiveOnchainPage>(() => LightningReceiveOnchainPage(
|
||||||
|
addressListViewModel: getIt.get<WalletAddressListViewModel>(),
|
||||||
|
receiveOptionViewModel: ReceiveOptionViewModel(getIt.get<AppStore>().wallet!, ReceivePageOption.lightningOnchain),
|
||||||
|
));
|
||||||
|
|
||||||
|
getIt.registerFactoryParam<LightningInvoicePageViewModel, List<dynamic>, void>((args, _) {
|
||||||
|
final address = args.first as String;
|
||||||
|
final pageOption = args.last as ReceivePageOption;
|
||||||
|
return LightningInvoicePageViewModel(
|
||||||
|
address,
|
||||||
|
getIt.get<SettingsStore>(),
|
||||||
|
getIt.get<AppStore>().wallet!,
|
||||||
|
getIt.get<SharedPreferences>(),
|
||||||
|
pageOption,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// getIt.registerFactory<LightningInvoicePage>(() => LightningInvoicePage(
|
||||||
|
// lightningInvoicePageViewModel: getIt.get<LightningInvoicePageViewModel>(),
|
||||||
|
// lightningViewModel: LightningViewModel(),
|
||||||
|
// receiveOptionViewModel: ReceiveOptionViewModel(getIt.get<AppStore>().wallet!, ReceivePageOption.lightningInvoice),
|
||||||
|
// ));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
getIt.registerFactoryParam<LightningInvoicePage, List<dynamic>, void>((List<dynamic> args, _) {
|
||||||
|
final pageOption = args.last as ReceivePageOption;
|
||||||
|
return LightningInvoicePage(
|
||||||
|
lightningInvoicePageViewModel: getIt.get<LightningInvoicePageViewModel>(param1: args),
|
||||||
|
lightningViewModel: LightningViewModel(),
|
||||||
|
receiveOptionViewModel: getIt.get<ReceiveOptionViewModel>(param1: pageOption));
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// getIt.registerFactory<LightningSendPage>(() => LightningSendPage(authService: , sendViewModel: , initialPaymentRequest: ,));
|
||||||
|
|
||||||
_isSetupFinished = true;
|
_isSetupFinished = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:cake_wallet/entities/receive_page_option.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:cake_wallet/routes.dart';
|
import 'package:cake_wallet/routes.dart';
|
||||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||||
|
@ -56,7 +57,11 @@ class MainActions {
|
||||||
image: 'assets/images/received.png',
|
image: 'assets/images/received.png',
|
||||||
onTap: (BuildContext context, DashboardViewModel viewModel) async {
|
onTap: (BuildContext context, DashboardViewModel viewModel) async {
|
||||||
if (viewModel.wallet.type == WalletType.lightning) {
|
if (viewModel.wallet.type == WalletType.lightning) {
|
||||||
Navigator.pushNamed(context, Routes.lightningReceive);
|
Navigator.pushNamed(
|
||||||
|
context,
|
||||||
|
Routes.lightningInvoice,
|
||||||
|
arguments: [viewModel.address, ReceivePageOption.lightningInvoice],
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Navigator.pushNamed(context, Routes.addressPage);
|
Navigator.pushNamed(context, Routes.addressPage);
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
|
|
||||||
enum ReceivePageOption {
|
enum ReceivePageOption {
|
||||||
mainnet,
|
mainnet,
|
||||||
anonPayInvoice,
|
anonPayInvoice,
|
||||||
anonPayDonationLink;
|
anonPayDonationLink,
|
||||||
|
lightningInvoice,
|
||||||
|
lightningOnchain;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
|
@ -17,6 +18,12 @@ enum ReceivePageOption {
|
||||||
case ReceivePageOption.anonPayDonationLink:
|
case ReceivePageOption.anonPayDonationLink:
|
||||||
label = 'Trocador AnonPay Donation Link';
|
label = 'Trocador AnonPay Donation Link';
|
||||||
break;
|
break;
|
||||||
|
case ReceivePageOption.lightningInvoice:
|
||||||
|
label = 'Sats via Invoice';
|
||||||
|
break;
|
||||||
|
case ReceivePageOption.lightningOnchain:
|
||||||
|
label = 'Sats via BTC address';
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,7 +100,7 @@ class CWLightning extends Lightning {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
// @computed
|
@computed
|
||||||
List<ElectrumSubAddress> getSubAddresses(Object wallet) {
|
List<ElectrumSubAddress> getSubAddresses(Object wallet) {
|
||||||
final electrumWallet = wallet as ElectrumWallet;
|
final electrumWallet = wallet as ElectrumWallet;
|
||||||
return electrumWallet.walletAddresses.addresses
|
return electrumWallet.walletAddresses.addresses
|
||||||
|
|
|
@ -18,12 +18,15 @@ import 'package:cake_wallet/src/screens/dashboard/pages/nft_details_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/nano/nano_change_rep_page.dart';
|
import 'package:cake_wallet/src/screens/nano/nano_change_rep_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/nano_accounts/nano_account_edit_or_create_page.dart';
|
import 'package:cake_wallet/src/screens/nano_accounts/nano_account_edit_or_create_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/nodes/pow_node_create_or_edit_page.dart';
|
import 'package:cake_wallet/src/screens/nodes/pow_node_create_or_edit_page.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/receive/lightning_invoice_page.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/receive/lightning_receive_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/restore/sweeping_wallet_page.dart';
|
import 'package:cake_wallet/src/screens/restore/sweeping_wallet_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/receive/anonpay_invoice_page.dart';
|
import 'package:cake_wallet/src/screens/receive/anonpay_invoice_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/receive/anonpay_receive_page.dart';
|
import 'package:cake_wallet/src/screens/receive/anonpay_receive_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_dashboard_actions.dart';
|
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_dashboard_actions.dart';
|
||||||
import 'package:cake_wallet/src/screens/dashboard/pages/transactions_page.dart';
|
import 'package:cake_wallet/src/screens/dashboard/pages/transactions_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/restore/wallet_restore_choose_derivation.dart';
|
import 'package:cake_wallet/src/screens/restore/wallet_restore_choose_derivation.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/send/lightning_send_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/settings/desktop_settings/desktop_settings_page.dart';
|
import 'package:cake_wallet/src/screens/settings/desktop_settings/desktop_settings_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/settings/display_settings_page.dart';
|
import 'package:cake_wallet/src/screens/settings/display_settings_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/settings/domain_lookups_page.dart';
|
import 'package:cake_wallet/src/screens/settings/domain_lookups_page.dart';
|
||||||
|
@ -150,7 +153,8 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
||||||
final walletNewVM = getIt.get<WalletNewVM>(param1: type);
|
final walletNewVM = getIt.get<WalletNewVM>(param1: type);
|
||||||
final seedTypeViewModel = getIt.get<SeedTypeViewModel>();
|
final seedTypeViewModel = getIt.get<SeedTypeViewModel>();
|
||||||
|
|
||||||
return CupertinoPageRoute<void>(builder: (_) => NewWalletPage(walletNewVM, seedTypeViewModel));
|
return CupertinoPageRoute<void>(
|
||||||
|
builder: (_) => NewWalletPage(walletNewVM, seedTypeViewModel));
|
||||||
|
|
||||||
case Routes.setupPin:
|
case Routes.setupPin:
|
||||||
Function(PinCodeState<PinCodeWidget>, String)? callback;
|
Function(PinCodeState<PinCodeWidget>, String)? callback;
|
||||||
|
@ -393,8 +397,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
||||||
|
|
||||||
case Routes.buySellPage:
|
case Routes.buySellPage:
|
||||||
final args = settings.arguments as bool;
|
final args = settings.arguments as bool;
|
||||||
return MaterialPageRoute<void>(
|
return MaterialPageRoute<void>(builder: (_) => getIt.get<BuySellOptionsPage>(param1: args));
|
||||||
builder: (_) => getIt.get<BuySellOptionsPage>(param1: args));
|
|
||||||
|
|
||||||
case Routes.buyWebView:
|
case Routes.buyWebView:
|
||||||
final args = settings.arguments as List;
|
final args = settings.arguments as List;
|
||||||
|
@ -417,8 +420,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
||||||
|
|
||||||
case Routes.preSeedPage:
|
case Routes.preSeedPage:
|
||||||
return MaterialPageRoute<void>(
|
return MaterialPageRoute<void>(
|
||||||
builder: (_) => getIt.get<PreSeedPage>(
|
builder: (_) => getIt.get<PreSeedPage>(param1: settings.arguments as int));
|
||||||
param1: settings.arguments as int));
|
|
||||||
|
|
||||||
case Routes.backup:
|
case Routes.backup:
|
||||||
return CupertinoPageRoute<void>(
|
return CupertinoPageRoute<void>(
|
||||||
|
@ -636,15 +638,20 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
||||||
|
|
||||||
case Routes.lightningSend:
|
case Routes.lightningSend:
|
||||||
return CupertinoPageRoute<void>(
|
return CupertinoPageRoute<void>(
|
||||||
fullscreenDialog: true, builder: (_) => getIt.get<ExchangePage>());
|
fullscreenDialog: true, builder: (_) => getIt.get<LightningSendPage>());
|
||||||
|
|
||||||
case Routes.lightningReceive:
|
case Routes.lightningReceiveOnchain:
|
||||||
return CupertinoPageRoute<void>(
|
return CupertinoPageRoute<void>(
|
||||||
fullscreenDialog: true, builder: (_) => getIt.get<ExchangePage>());
|
fullscreenDialog: true, builder: (_) => getIt.get<LightningReceiveOnchainPage>());
|
||||||
|
|
||||||
case Routes.lightningSettings:
|
case Routes.lightningInvoice:
|
||||||
|
final args = settings.arguments as List;
|
||||||
return CupertinoPageRoute<void>(
|
return CupertinoPageRoute<void>(
|
||||||
fullscreenDialog: true, builder: (_) => getIt.get<ExchangePage>());
|
fullscreenDialog: true, builder: (_) => getIt.get<LightningInvoicePage>(param1: args));
|
||||||
|
|
||||||
|
// case Routes.lightningSettings:
|
||||||
|
// return CupertinoPageRoute<void>(
|
||||||
|
// fullscreenDialog: true, builder: (_) => getIt.get<LightningSendPage>());
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return MaterialPageRoute<void>(
|
return MaterialPageRoute<void>(
|
||||||
|
|
|
@ -107,6 +107,7 @@ class Routes {
|
||||||
static const importNFTPage = '/import_nft_page';
|
static const importNFTPage = '/import_nft_page';
|
||||||
static const torPage = '/tor_page';
|
static const torPage = '/tor_page';
|
||||||
static const lightningSend = '/lightning_send';
|
static const lightningSend = '/lightning_send';
|
||||||
static const lightningReceive = '/lightning_receive';
|
static const lightningInvoice = '/lightning_invoice';
|
||||||
|
static const lightningReceiveOnchain = '/lightning_receive_onchain';
|
||||||
static const lightningSettings = '/lightning_settings';
|
static const lightningSettings = '/lightning_settings';
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,65 +159,6 @@ class AddressPage extends BasePage {
|
||||||
amountController: _amountController,
|
amountController: _amountController,
|
||||||
isLight: dashboardViewModel.settingsStore.currentTheme.type ==
|
isLight: dashboardViewModel.settingsStore.currentTheme.type ==
|
||||||
ThemeType.light))),
|
ThemeType.light))),
|
||||||
SizedBox(height: 16),
|
|
||||||
IconButton(
|
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
constraints: BoxConstraints(),
|
|
||||||
highlightColor: Colors.transparent,
|
|
||||||
splashColor: Colors.transparent,
|
|
||||||
iconSize: 40,
|
|
||||||
onPressed: () async {
|
|
||||||
print("pressed");
|
|
||||||
// ReceivePaymentRequest req = const ReceivePaymentRequest(
|
|
||||||
// amountMsat: 3000000,
|
|
||||||
// description: "Invoice for 3000 sats",
|
|
||||||
// );
|
|
||||||
// ReceivePaymentResponse receivePaymentResponse =
|
|
||||||
// await BreezSDK().receivePayment(req: req);
|
|
||||||
|
|
||||||
// print(receivePaymentResponse.lnInvoice);
|
|
||||||
|
|
||||||
final sdk = await BreezSDK();
|
|
||||||
|
|
||||||
sdk.nodeStateStream.listen((event) {
|
|
||||||
// print("Node state: $event");
|
|
||||||
if (event == null) return;
|
|
||||||
int balanceSat = event.maxPayableMsat ~/ 1000;
|
|
||||||
print("sats: $balanceSat");
|
|
||||||
});
|
|
||||||
|
|
||||||
// ServiceHealthCheckResponse healthCheck = await sdk.serviceHealthCheck();
|
|
||||||
// print("Current service status is: ${healthCheck.status}");
|
|
||||||
|
|
||||||
// ReceivePaymentRequest req = ReceivePaymentRequest(
|
|
||||||
// amountMsat: 123 * 1000,
|
|
||||||
// description: "Invoice for 123 sats",
|
|
||||||
// );
|
|
||||||
// final s = await sdk.receivePayment(req: req);
|
|
||||||
// print(s.lnInvoice.bolt11);
|
|
||||||
|
|
||||||
// ReceiveOnchainRequest req = const ReceiveOnchainRequest();
|
|
||||||
// SwapInfo swapInfo = await sdk.receiveOnchain(req: req);
|
|
||||||
// // Send your funds to the below bitcoin address
|
|
||||||
// String address = swapInfo.bitcoinAddress;
|
|
||||||
// print(address);
|
|
||||||
// print("Minimum amount allowed to deposit in sats: ${swapInfo.minAllowedDeposit}");
|
|
||||||
// print("Maximum amount allowed to deposit in sats: ${swapInfo.maxAllowedDeposit}");
|
|
||||||
|
|
||||||
ListPaymentsRequest lReq = ListPaymentsRequest();
|
|
||||||
|
|
||||||
var list = await sdk.listPayments(req: lReq);
|
|
||||||
print(list[0].amountMsat);
|
|
||||||
|
|
||||||
var data = await sdk.fetchNodeData();
|
|
||||||
print(data);
|
|
||||||
},
|
|
||||||
icon: Icon(
|
|
||||||
Icons.lightbulb_outline_rounded,
|
|
||||||
size: 48,
|
|
||||||
color: pageIconColor(context),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
),
|
),
|
||||||
|
|
227
lib/src/screens/receive/lightning_invoice_page.dart
Normal file
227
lib/src/screens/receive/lightning_invoice_page.dart
Normal file
|
@ -0,0 +1,227 @@
|
||||||
|
import 'package:cake_wallet/src/screens/receive/widgets/lightning_input_form.dart';
|
||||||
|
import 'package:cake_wallet/themes/extensions/exchange_page_theme.dart';
|
||||||
|
import 'package:cake_wallet/themes/extensions/keyboard_theme.dart';
|
||||||
|
import 'package:cake_wallet/anonpay/anonpay_donation_link_info.dart';
|
||||||
|
import 'package:cake_wallet/core/execution_state.dart';
|
||||||
|
import 'package:cake_wallet/di.dart';
|
||||||
|
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||||
|
import 'package:cake_wallet/entities/receive_page_option.dart';
|
||||||
|
import 'package:cake_wallet/routes.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/dashboard/widgets/present_receive_option_picker.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/receive/widgets/anonpay_input_form.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
|
||||||
|
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||||
|
import 'package:cake_wallet/view_model/anon_invoice_page_view_model.dart';
|
||||||
|
import 'package:cake_wallet/view_model/dashboard/receive_option_view_model.dart';
|
||||||
|
import 'package:cake_wallet/view_model/lightning_invoice_page_view_model.dart';
|
||||||
|
import 'package:cake_wallet/view_model/lightning_view_model.dart';
|
||||||
|
import 'package:flutter/material.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/widgets/trail_button.dart';
|
||||||
|
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||||
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
class LightningInvoicePage extends BasePage {
|
||||||
|
LightningInvoicePage({
|
||||||
|
required this.lightningViewModel,
|
||||||
|
required this.lightningInvoicePageViewModel,
|
||||||
|
required this.receiveOptionViewModel,
|
||||||
|
}) : _amountFocusNode = FocusNode() {}
|
||||||
|
|
||||||
|
final _nameController = TextEditingController();
|
||||||
|
final _emailController = TextEditingController();
|
||||||
|
final _descriptionController = TextEditingController();
|
||||||
|
final _amountController = TextEditingController();
|
||||||
|
final FocusNode _amountFocusNode;
|
||||||
|
|
||||||
|
final LightningViewModel lightningViewModel;
|
||||||
|
final LightningInvoicePageViewModel lightningInvoicePageViewModel;
|
||||||
|
final ReceiveOptionViewModel receiveOptionViewModel;
|
||||||
|
final _formKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
|
bool effectsInstalled = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get gradientAll => true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get resizeToAvoidBottomInset => false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get extendBodyBehindAppBar => true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
AppBarStyle get appBarStyle => AppBarStyle.transparent;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onClose(BuildContext context) => Navigator.popUntil(context, (route) => route.isFirst);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget middle(BuildContext context) => PresentReceiveOptionPicker(
|
||||||
|
receiveOptionViewModel: receiveOptionViewModel, color: titleColor(context));
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget trailing(BuildContext context) => TrailButton(
|
||||||
|
caption: S.of(context).clear,
|
||||||
|
onPressed: () {
|
||||||
|
_formKey.currentState?.reset();
|
||||||
|
// lightningViewModel.reset();
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<bool> _onNavigateBack(BuildContext context) async {
|
||||||
|
onClose(context);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget body(BuildContext context) {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) => _setReactions(context));
|
||||||
|
|
||||||
|
return WillPopScope(
|
||||||
|
onWillPop: () => _onNavigateBack(context),
|
||||||
|
child: KeyboardActions(
|
||||||
|
disableScroll: true,
|
||||||
|
config: KeyboardActionsConfig(
|
||||||
|
keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
|
||||||
|
keyboardBarColor: Theme.of(context).extension<KeyboardTheme>()!.keyboardBarColor,
|
||||||
|
nextFocus: false,
|
||||||
|
actions: [
|
||||||
|
KeyboardActionsItem(
|
||||||
|
focusNode: _amountFocusNode,
|
||||||
|
toolbarButtons: [(_) => KeyboardDoneButton()],
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
child: Container(
|
||||||
|
color: Theme.of(context).colorScheme.background,
|
||||||
|
child: ScrollableWithBottomSection(
|
||||||
|
contentPadding: EdgeInsets.only(bottom: 24),
|
||||||
|
content: Container(
|
||||||
|
decoration: responsiveLayoutUtil.shouldRenderMobileUI
|
||||||
|
? BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)),
|
||||||
|
gradient: LinearGradient(
|
||||||
|
colors: [
|
||||||
|
Theme.of(context)
|
||||||
|
.extension<ExchangePageTheme>()!
|
||||||
|
.firstGradientTopPanelColor,
|
||||||
|
Theme.of(context)
|
||||||
|
.extension<ExchangePageTheme>()!
|
||||||
|
.secondGradientTopPanelColor,
|
||||||
|
],
|
||||||
|
begin: Alignment.topLeft,
|
||||||
|
end: Alignment.bottomRight,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
child: Observer(builder: (_) {
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(24, 120, 24, 0),
|
||||||
|
child: LightningInvoiceForm(
|
||||||
|
descriptionController: _descriptionController,
|
||||||
|
amountController: _amountController,
|
||||||
|
depositAmountFocus: _amountFocusNode,
|
||||||
|
formKey: _formKey,
|
||||||
|
lightningInvoicePageViewModel: lightningInvoicePageViewModel,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||||
|
bottomSection: Observer(builder: (_) {
|
||||||
|
return Column(
|
||||||
|
children: <Widget>[
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(bottom: 15),
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
S.of(context).anonpay_description("an invoice", "pay"),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<ExchangePageTheme>()!
|
||||||
|
.receiveAmountColor,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
fontSize: 12),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// LoadingPrimaryButton(
|
||||||
|
// text: isInvoice
|
||||||
|
// ? S.of(context).create_invoice
|
||||||
|
// : S.of(context).create_donation_link,
|
||||||
|
// onPressed: () {
|
||||||
|
// FocusScope.of(context).unfocus();
|
||||||
|
// anonInvoicePageViewModel.setRequestParams(
|
||||||
|
// inputAmount: _amountController.text,
|
||||||
|
// inputName: _nameController.text,
|
||||||
|
// inputEmail: _emailController.text,
|
||||||
|
// inputDescription: _descriptionController.text,
|
||||||
|
// );
|
||||||
|
// if (anonInvoicePageViewModel.receipientEmail.isNotEmpty &&
|
||||||
|
// _formKey.currentState != null &&
|
||||||
|
// !_formKey.currentState!.validate()) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// if (isInvoice) {
|
||||||
|
// anonInvoicePageViewModel.createInvoice();
|
||||||
|
// } else {
|
||||||
|
// anonInvoicePageViewModel.generateDonationLink();
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// color: Theme.of(context).primaryColor,
|
||||||
|
// textColor: Colors.white,
|
||||||
|
// isLoading: anonInvoicePageViewModel.state is IsExecutingState,
|
||||||
|
// ),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _setReactions(BuildContext context) {
|
||||||
|
if (effectsInstalled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
reaction((_) => receiveOptionViewModel.selectedReceiveOption, (ReceivePageOption option) {
|
||||||
|
switch (option) {
|
||||||
|
case ReceivePageOption.lightningInvoice:
|
||||||
|
break;
|
||||||
|
case ReceivePageOption.lightningOnchain:
|
||||||
|
Navigator.popAndPushNamed(context, Routes.lightningReceiveOnchain);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// reaction((_) => anonInvoicePageViewModel.state, (ExecutionState state) {
|
||||||
|
// if (state is ExecutedSuccessfullyState) {
|
||||||
|
// Navigator.pushNamed(context, Routes.anonPayReceivePage, arguments: state.payload);
|
||||||
|
// }
|
||||||
|
// if (state is FailureState) {
|
||||||
|
// showPopUp<void>(
|
||||||
|
// context: context,
|
||||||
|
// builder: (BuildContext context) {
|
||||||
|
// return AlertWithOneAction(
|
||||||
|
// alertTitle: S.of(context).error,
|
||||||
|
// alertContent: state.error.toString(),
|
||||||
|
// buttonText: S.of(context).ok,
|
||||||
|
// buttonAction: () => Navigator.of(context).pop());
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
|
effectsInstalled = true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,32 +1,13 @@
|
||||||
import 'package:cake_wallet/src/screens/nano_accounts/nano_account_list_page.dart';
|
import 'package:cake_wallet/src/screens/dashboard/widgets/present_receive_option_picker.dart';
|
||||||
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
|
|
||||||
import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
|
|
||||||
import 'package:cake_wallet/themes/extensions/keyboard_theme.dart';
|
|
||||||
import 'package:cake_wallet/themes/extensions/receive_page_theme.dart';
|
|
||||||
import 'package:cake_wallet/src/widgets/gradient_background.dart';
|
import 'package:cake_wallet/src/widgets/gradient_background.dart';
|
||||||
import 'package:cake_wallet/src/widgets/section_divider.dart';
|
import 'package:cake_wallet/view_model/dashboard/receive_option_view_model.dart';
|
||||||
import 'package:cake_wallet/themes/theme_base.dart';
|
|
||||||
import 'package:cake_wallet/utils/share_util.dart';
|
|
||||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
|
||||||
import 'package:cw_core/wallet_type.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
|
||||||
import 'package:cake_wallet/routes.dart';
|
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:cake_wallet/di.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/monero_accounts/monero_account_list_page.dart';
|
|
||||||
import 'package:cake_wallet/src/screens/receive/widgets/header_tile.dart';
|
|
||||||
import 'package:cake_wallet/src/screens/receive/widgets/address_cell.dart';
|
|
||||||
import 'package:cake_wallet/view_model/wallet_address_list/wallet_account_list_header.dart';
|
|
||||||
import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_header.dart';
|
|
||||||
import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_item.dart';
|
|
||||||
import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_view_model.dart';
|
import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_view_model.dart';
|
||||||
import 'package:cake_wallet/src/screens/receive/widgets/qr_widget.dart';
|
|
||||||
import 'package:keyboard_actions/keyboard_actions.dart';
|
|
||||||
|
|
||||||
class LightningReceivePage extends BasePage {
|
class LightningReceiveOnchainPage extends BasePage {
|
||||||
LightningReceivePage({required this.addressListViewModel})
|
LightningReceiveOnchainPage({required this.addressListViewModel, required this.receiveOptionViewModel})
|
||||||
: _cryptoAmountFocus = FocusNode(),
|
: _cryptoAmountFocus = FocusNode(),
|
||||||
_amountController = TextEditingController(),
|
_amountController = TextEditingController(),
|
||||||
_formKey = GlobalKey<FormState>() {
|
_formKey = GlobalKey<FormState>() {
|
||||||
|
@ -38,6 +19,7 @@ class LightningReceivePage extends BasePage {
|
||||||
}
|
}
|
||||||
|
|
||||||
final WalletAddressListViewModel addressListViewModel;
|
final WalletAddressListViewModel addressListViewModel;
|
||||||
|
final ReceiveOptionViewModel receiveOptionViewModel;
|
||||||
final TextEditingController _amountController;
|
final TextEditingController _amountController;
|
||||||
final GlobalKey<FormState> _formKey;
|
final GlobalKey<FormState> _formKey;
|
||||||
static const _heroTag = 'receive_page';
|
static const _heroTag = 'receive_page';
|
||||||
|
@ -53,192 +35,28 @@ class LightningReceivePage extends BasePage {
|
||||||
|
|
||||||
final FocusNode _cryptoAmountFocus;
|
final FocusNode _cryptoAmountFocus;
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// Widget middle(BuildContext context) {
|
||||||
|
// return Text(
|
||||||
|
// title,
|
||||||
|
// style: TextStyle(
|
||||||
|
// fontSize: 18.0,
|
||||||
|
// fontWeight: FontWeight.bold,
|
||||||
|
// fontFamily: 'Lato',
|
||||||
|
// color: pageIconColor(context)),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget middle(BuildContext context) {
|
Widget middle(BuildContext context) => PresentReceiveOptionPicker(
|
||||||
return Text(
|
color: titleColor(context), receiveOptionViewModel: receiveOptionViewModel);
|
||||||
title,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 18.0,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
fontFamily: 'Lato',
|
|
||||||
color: pageIconColor(context)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget Function(BuildContext, Widget) get rootWrapper =>
|
Widget Function(BuildContext, Widget) get rootWrapper =>
|
||||||
(BuildContext context, Widget scaffold) =>
|
(BuildContext context, Widget scaffold) => GradientBackground(scaffold: scaffold);
|
||||||
GradientBackground(scaffold: scaffold);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget trailing(BuildContext context) {
|
|
||||||
return Material(
|
|
||||||
color: Colors.transparent,
|
|
||||||
child: Semantics(
|
|
||||||
label: S.of(context).share,
|
|
||||||
child: IconButton(
|
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
constraints: BoxConstraints(),
|
|
||||||
highlightColor: Colors.transparent,
|
|
||||||
splashColor: Colors.transparent,
|
|
||||||
iconSize: 25,
|
|
||||||
onPressed: () {
|
|
||||||
ShareUtil.share(
|
|
||||||
text: addressListViewModel.uri.toString(),
|
|
||||||
context: context,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
icon: Icon(
|
|
||||||
Icons.share,
|
|
||||||
size: 20,
|
|
||||||
color: pageIconColor(context),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) {
|
Widget body(BuildContext context) {
|
||||||
final isElectrumWallet = addressListViewModel.isElectrumWallet;
|
return SizedBox();
|
||||||
return (addressListViewModel.type == WalletType.monero ||
|
|
||||||
addressListViewModel.type == WalletType.haven ||
|
|
||||||
addressListViewModel.type == WalletType.nano ||
|
|
||||||
isElectrumWallet)
|
|
||||||
? KeyboardActions(
|
|
||||||
config: KeyboardActionsConfig(
|
|
||||||
keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
|
|
||||||
keyboardBarColor: Theme.of(context).extension<KeyboardTheme>()!.keyboardBarColor,
|
|
||||||
nextFocus: false,
|
|
||||||
actions: [
|
|
||||||
KeyboardActionsItem(
|
|
||||||
focusNode: _cryptoAmountFocus,
|
|
||||||
toolbarButtons: [(_) => KeyboardDoneButton()],
|
|
||||||
)
|
|
||||||
]),
|
|
||||||
child: SingleChildScrollView(
|
|
||||||
child: Column(
|
|
||||||
children: <Widget>[
|
|
||||||
Padding(
|
|
||||||
padding: EdgeInsets.fromLTRB(24, 50, 24, 24),
|
|
||||||
child: QRWidget(
|
|
||||||
addressListViewModel: addressListViewModel,
|
|
||||||
formKey: _formKey,
|
|
||||||
heroTag: _heroTag,
|
|
||||||
amountTextFieldFocusNode: _cryptoAmountFocus,
|
|
||||||
amountController: _amountController,
|
|
||||||
isLight: currentTheme.type == ThemeType.light),
|
|
||||||
),
|
|
||||||
Observer(
|
|
||||||
builder: (_) => ListView.separated(
|
|
||||||
padding: EdgeInsets.all(0),
|
|
||||||
separatorBuilder: (context, _) => const HorizontalSectionDivider(),
|
|
||||||
shrinkWrap: true,
|
|
||||||
physics: NeverScrollableScrollPhysics(),
|
|
||||||
itemCount: addressListViewModel.items.length,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
final item = addressListViewModel.items[index];
|
|
||||||
Widget cell = Container();
|
|
||||||
|
|
||||||
if (item is WalletAccountListHeader) {
|
|
||||||
cell = HeaderTile(
|
|
||||||
showTrailingButton: true,
|
|
||||||
walletAddressListViewModel: addressListViewModel,
|
|
||||||
trailingButtonTap: () async {
|
|
||||||
if (addressListViewModel.type == WalletType.monero ||
|
|
||||||
addressListViewModel.type == WalletType.haven) {
|
|
||||||
await showPopUp<void>(
|
|
||||||
context: context,
|
|
||||||
builder: (_) => getIt.get<MoneroAccountListPage>());
|
|
||||||
} else {
|
|
||||||
await showPopUp<void>(
|
|
||||||
context: context,
|
|
||||||
builder: (_) => getIt.get<NanoAccountListPage>());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
title: S.of(context).accounts,
|
|
||||||
trailingIcon: Icon(
|
|
||||||
Icons.arrow_forward_ios,
|
|
||||||
size: 14,
|
|
||||||
color: Theme.of(context).extension<ReceivePageTheme>()!.iconsColor,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item is WalletAddressListHeader) {
|
|
||||||
cell = HeaderTile(
|
|
||||||
title: S.of(context).addresses,
|
|
||||||
walletAddressListViewModel: addressListViewModel,
|
|
||||||
showTrailingButton: !addressListViewModel.isAutoGenerateSubaddressEnabled,
|
|
||||||
showSearchButton: true,
|
|
||||||
trailingButtonTap: () =>
|
|
||||||
Navigator.of(context).pushNamed(Routes.newSubaddress),
|
|
||||||
trailingIcon: Icon(
|
|
||||||
Icons.add,
|
|
||||||
size: 20,
|
|
||||||
color: Theme.of(context)
|
|
||||||
.extension<ReceivePageTheme>()!
|
|
||||||
.iconsColor,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item is WalletAddressListItem) {
|
|
||||||
cell = Observer(builder: (_) {
|
|
||||||
final isCurrent =
|
|
||||||
item.address == addressListViewModel.address.address;
|
|
||||||
final backgroundColor = isCurrent
|
|
||||||
? Theme.of(context).extension<ReceivePageTheme>()!.currentTileBackgroundColor
|
|
||||||
: Theme.of(context).extension<ReceivePageTheme>()!.tilesBackgroundColor;
|
|
||||||
final textColor = isCurrent
|
|
||||||
? Theme.of(context).extension<ReceivePageTheme>()!.currentTileTextColor
|
|
||||||
: Theme.of(context).extension<ReceivePageTheme>()!.tilesTextColor;
|
|
||||||
|
|
||||||
return AddressCell.fromItem(item,
|
|
||||||
isCurrent: isCurrent,
|
|
||||||
hasBalance: addressListViewModel.isElectrumWallet,
|
|
||||||
backgroundColor: backgroundColor,
|
|
||||||
textColor: textColor,
|
|
||||||
onTap: (_) => addressListViewModel.setAddress(item),
|
|
||||||
onEdit: () => Navigator.of(context)
|
|
||||||
.pushNamed(Routes.newSubaddress, arguments: item));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return index != 0
|
|
||||||
? cell
|
|
||||||
: ClipRRect(
|
|
||||||
borderRadius: BorderRadius.only(
|
|
||||||
topLeft: Radius.circular(30),
|
|
||||||
topRight: Radius.circular(30)),
|
|
||||||
child: cell,
|
|
||||||
);
|
|
||||||
})),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
))
|
|
||||||
: Padding(
|
|
||||||
padding: EdgeInsets.fromLTRB(24, 24, 24, 32),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
flex: 7,
|
|
||||||
child: QRWidget(
|
|
||||||
formKey: _formKey,
|
|
||||||
heroTag: _heroTag,
|
|
||||||
addressListViewModel: addressListViewModel,
|
|
||||||
amountTextFieldFocusNode: _cryptoAmountFocus,
|
|
||||||
amountController: _amountController,
|
|
||||||
isLight: currentTheme.type == ThemeType.light),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
flex: 2,
|
|
||||||
child: SizedBox(),
|
|
||||||
),
|
|
||||||
Text(S.of(context).electrum_address_disclaimer,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 15,
|
|
||||||
color: Theme.of(context).extension<BalancePageTheme>()!.labelTextColor)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,13 +9,13 @@ import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
|
||||||
class AnonpayCurrencyInputField extends StatelessWidget {
|
class AnonpayCurrencyInputField extends StatelessWidget {
|
||||||
const AnonpayCurrencyInputField(
|
const AnonpayCurrencyInputField(
|
||||||
{super.key,
|
{super.key,
|
||||||
required this.onTapPicker,
|
this.onTapPicker,
|
||||||
required this.selectedCurrency,
|
required this.selectedCurrency,
|
||||||
required this.focusNode,
|
required this.focusNode,
|
||||||
required this.controller,
|
required this.controller,
|
||||||
required this.minAmount,
|
required this.minAmount,
|
||||||
required this.maxAmount});
|
required this.maxAmount});
|
||||||
final Function() onTapPicker;
|
final Function()? onTapPicker;
|
||||||
final Currency selectedCurrency;
|
final Currency selectedCurrency;
|
||||||
final FocusNode focusNode;
|
final FocusNode focusNode;
|
||||||
final TextEditingController controller;
|
final TextEditingController controller;
|
||||||
|
@ -34,40 +34,50 @@ class AnonpayCurrencyInputField extends StatelessWidget {
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: Border(
|
border: Border(
|
||||||
bottom: BorderSide(
|
bottom: BorderSide(
|
||||||
color:
|
color: Theme.of(context)
|
||||||
Theme.of(context).extension<ExchangePageTheme>()!.textFieldBorderBottomPanelColor,
|
.extension<ExchangePageTheme>()!
|
||||||
|
.textFieldBorderBottomPanelColor,
|
||||||
width: 1)),
|
width: 1)),
|
||||||
),
|
),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.only(top: 20),
|
padding: EdgeInsets.only(top: 20),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
if (onTapPicker != null)
|
||||||
padding: EdgeInsets.only(right: 8),
|
Container(
|
||||||
height: 32,
|
padding: EdgeInsets.only(right: 8),
|
||||||
child: InkWell(
|
height: 32,
|
||||||
onTap: onTapPicker,
|
child: InkWell(
|
||||||
child: Row(
|
onTap: onTapPicker,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
child: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: <Widget>[
|
mainAxisSize: MainAxisSize.min,
|
||||||
Padding(
|
children: <Widget>[
|
||||||
padding: EdgeInsets.only(right: 5),
|
Padding(
|
||||||
child: arrowBottomPurple,
|
padding: EdgeInsets.only(right: 5),
|
||||||
),
|
child: arrowBottomPurple,
|
||||||
Text(selectedCurrency.name.toUpperCase(),
|
),
|
||||||
style: TextStyle(
|
Text(selectedCurrency.name.toUpperCase(),
|
||||||
fontWeight: FontWeight.w600, fontSize: 16, color: Colors.white))
|
style: TextStyle(
|
||||||
]),
|
fontWeight: FontWeight.w600,
|
||||||
),
|
fontSize: 16,
|
||||||
),
|
color: Colors.white))
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
else
|
||||||
|
Text(selectedCurrency.name.toUpperCase(),
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.w600, fontSize: 16, color: Colors.white)),
|
||||||
selectedCurrency.tag != null
|
selectedCurrency.tag != null
|
||||||
? Padding(
|
? Padding(
|
||||||
padding: const EdgeInsets.only(right: 3.0),
|
padding: const EdgeInsets.only(right: 3.0),
|
||||||
child: Container(
|
child: Container(
|
||||||
height: 32,
|
height: 32,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).extension<SendPageTheme>()!.textFieldButtonColor,
|
color: Theme.of(context)
|
||||||
|
.extension<SendPageTheme>()!
|
||||||
|
.textFieldButtonColor,
|
||||||
borderRadius: BorderRadius.all(Radius.circular(6))),
|
borderRadius: BorderRadius.all(Radius.circular(6))),
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
|
@ -77,7 +87,9 @@ class AnonpayCurrencyInputField extends StatelessWidget {
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: Theme.of(context).extension<SendPageTheme>()!.textFieldButtonIconColor,
|
color: Theme.of(context)
|
||||||
|
.extension<SendPageTheme>()!
|
||||||
|
.textFieldButtonIconColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -115,7 +127,8 @@ class AnonpayCurrencyInputField extends StatelessWidget {
|
||||||
placeholderTextStyle: TextStyle(
|
placeholderTextStyle: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor,
|
color:
|
||||||
|
Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor,
|
||||||
),
|
),
|
||||||
validator: null,
|
validator: null,
|
||||||
),
|
),
|
||||||
|
|
76
lib/src/screens/receive/widgets/lightning_input_form.dart
Normal file
76
lib/src/screens/receive/widgets/lightning_input_form.dart
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/receive/widgets/anonpay_currency_input_field.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||||
|
import 'package:cake_wallet/themes/extensions/exchange_page_theme.dart';
|
||||||
|
import 'package:cake_wallet/typography.dart';
|
||||||
|
import 'package:cake_wallet/view_model/lightning_invoice_page_view_model.dart';
|
||||||
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||||
|
|
||||||
|
class LightningInvoiceForm extends StatelessWidget {
|
||||||
|
LightningInvoiceForm({
|
||||||
|
super.key,
|
||||||
|
required this.formKey,
|
||||||
|
required this.lightningInvoicePageViewModel,
|
||||||
|
required this.amountController,
|
||||||
|
required this.descriptionController,
|
||||||
|
required this.depositAmountFocus,
|
||||||
|
}) : _descriptionFocusNode = FocusNode() {
|
||||||
|
amountController.text = lightningInvoicePageViewModel.amount;
|
||||||
|
descriptionController.text = lightningInvoicePageViewModel.description;
|
||||||
|
}
|
||||||
|
|
||||||
|
final TextEditingController amountController;
|
||||||
|
final TextEditingController descriptionController;
|
||||||
|
final LightningInvoicePageViewModel lightningInvoicePageViewModel;
|
||||||
|
final FocusNode depositAmountFocus;
|
||||||
|
final FocusNode _descriptionFocusNode;
|
||||||
|
final GlobalKey<FormState> formKey;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Form(
|
||||||
|
key: formKey,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
S.of(context).invoice_details,
|
||||||
|
style: textMediumSemiBold(),
|
||||||
|
),
|
||||||
|
Observer(builder: (_) {
|
||||||
|
return AnonpayCurrencyInputField(
|
||||||
|
controller: amountController,
|
||||||
|
focusNode: depositAmountFocus,
|
||||||
|
maxAmount: lightningInvoicePageViewModel.maximum?.toString() ?? '...',
|
||||||
|
minAmount: lightningInvoicePageViewModel.minimum?.toString() ?? '...',
|
||||||
|
selectedCurrency: CryptoCurrency.btc,
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
SizedBox(
|
||||||
|
height: 24,
|
||||||
|
),
|
||||||
|
BaseTextFormField(
|
||||||
|
controller: descriptionController,
|
||||||
|
focusNode: _descriptionFocusNode,
|
||||||
|
textInputAction: TextInputAction.next,
|
||||||
|
borderColor:
|
||||||
|
Theme.of(context).extension<ExchangePageTheme>()!.textFieldBorderTopPanelColor,
|
||||||
|
suffixIcon: SizedBox(width: 36),
|
||||||
|
hintText: S.of(context).optional_description,
|
||||||
|
placeholderTextStyle: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor,
|
||||||
|
),
|
||||||
|
textStyle: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white),
|
||||||
|
validator: null,
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 52,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
525
lib/src/screens/send/lightning_send_page.dart
Normal file
525
lib/src/screens/send/lightning_send_page.dart
Normal file
|
@ -0,0 +1,525 @@
|
||||||
|
import 'package:cake_wallet/core/auth_service.dart';
|
||||||
|
import 'package:cake_wallet/entities/fiat_currency.dart';
|
||||||
|
import 'package:cake_wallet/entities/template.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/dashboard/widgets/sync_indicator_icon.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/send/widgets/send_card.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/add_template_button.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/picker.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/template_tile.dart';
|
||||||
|
import 'package:cake_wallet/themes/extensions/seed_widget_theme.dart';
|
||||||
|
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
|
||||||
|
import 'package:cake_wallet/themes/theme_base.dart';
|
||||||
|
import 'package:cake_wallet/utils/payment_request.dart';
|
||||||
|
import 'package:cake_wallet/utils/request_review_handler.dart';
|
||||||
|
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||||
|
import 'package:cake_wallet/view_model/send/output.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
|
import 'package:cake_wallet/routes.dart';
|
||||||
|
import 'package:cake_wallet/view_model/send/send_view_model.dart';
|
||||||
|
import 'package:cake_wallet/core/execution_state.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/base_page.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/trail_button.dart';
|
||||||
|
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||||
|
import 'package:cake_wallet/view_model/send/send_view_model_state.dart';
|
||||||
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/send/widgets/confirm_sending_alert.dart';
|
||||||
|
import 'package:smooth_page_indicator/smooth_page_indicator.dart';
|
||||||
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
|
|
||||||
|
class LightningSendPage extends BasePage {
|
||||||
|
LightningSendPage({
|
||||||
|
required this.sendViewModel,
|
||||||
|
required this.authService,
|
||||||
|
this.initialPaymentRequest,
|
||||||
|
}) : _formKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
|
final SendViewModel sendViewModel;
|
||||||
|
final AuthService authService;
|
||||||
|
final GlobalKey<FormState> _formKey;
|
||||||
|
final controller = PageController(initialPage: 0);
|
||||||
|
final PaymentRequest? initialPaymentRequest;
|
||||||
|
|
||||||
|
bool _effectsInstalled = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get title => S.current.send;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get gradientAll => true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get resizeToAvoidBottomInset => false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get extendBodyBehindAppBar => true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget? leading(BuildContext context) {
|
||||||
|
final _backButton = Icon(
|
||||||
|
Icons.arrow_back_ios,
|
||||||
|
color: titleColor(context),
|
||||||
|
size: 16,
|
||||||
|
);
|
||||||
|
final _closeButton =
|
||||||
|
currentTheme.type == ThemeType.dark ? closeButtonImageDarkTheme : closeButtonImage;
|
||||||
|
|
||||||
|
bool isMobileView = responsiveLayoutUtil.shouldRenderMobileUI;
|
||||||
|
|
||||||
|
return MergeSemantics(
|
||||||
|
child: SizedBox(
|
||||||
|
height: isMobileView ? 37 : 45,
|
||||||
|
width: isMobileView ? 37 : 45,
|
||||||
|
child: ButtonTheme(
|
||||||
|
minWidth: double.minPositive,
|
||||||
|
child: Semantics(
|
||||||
|
label: !isMobileView ? S.of(context).close : S.of(context).seed_alert_back,
|
||||||
|
child: TextButton(
|
||||||
|
style: ButtonStyle(
|
||||||
|
overlayColor: MaterialStateColor.resolveWith((states) => Colors.transparent),
|
||||||
|
),
|
||||||
|
onPressed: () => onClose(context),
|
||||||
|
child: !isMobileView ? _closeButton : _backButton,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
AppBarStyle get appBarStyle => AppBarStyle.transparent;
|
||||||
|
|
||||||
|
double _sendCardHeight(BuildContext context) {
|
||||||
|
final double initialHeight = sendViewModel.hasCoinControl ? 500 : 465;
|
||||||
|
|
||||||
|
if (!responsiveLayoutUtil.shouldRenderMobileUI) {
|
||||||
|
return initialHeight - 66;
|
||||||
|
}
|
||||||
|
return initialHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onClose(BuildContext context) {
|
||||||
|
sendViewModel.onClose();
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget? middle(BuildContext context) {
|
||||||
|
final supMiddle = super.middle(context);
|
||||||
|
return Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(right: 8.0),
|
||||||
|
child: Observer(
|
||||||
|
builder: (_) => SyncIndicatorIcon(isSynced: sendViewModel.isReadyForSend),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (supMiddle != null) supMiddle
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget trailing(context) => Observer(builder: (_) {
|
||||||
|
return sendViewModel.isBatchSending
|
||||||
|
? TrailButton(
|
||||||
|
caption: S.of(context).remove,
|
||||||
|
onPressed: () {
|
||||||
|
var pageToJump = (controller.page?.round() ?? 0) - 1;
|
||||||
|
pageToJump = pageToJump > 0 ? pageToJump : 0;
|
||||||
|
final output = _defineCurrentOutput();
|
||||||
|
sendViewModel.removeOutput(output);
|
||||||
|
controller.jumpToPage(pageToJump);
|
||||||
|
})
|
||||||
|
: TrailButton(
|
||||||
|
caption: S.of(context).clear,
|
||||||
|
onPressed: () {
|
||||||
|
final output = _defineCurrentOutput();
|
||||||
|
_formKey.currentState?.reset();
|
||||||
|
output.reset();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget body(BuildContext context) {
|
||||||
|
_setEffects(context);
|
||||||
|
|
||||||
|
return GestureDetector(
|
||||||
|
onLongPress: () =>
|
||||||
|
sendViewModel.balanceViewModel.isReversing = !sendViewModel.balanceViewModel.isReversing,
|
||||||
|
onLongPressUp: () =>
|
||||||
|
sendViewModel.balanceViewModel.isReversing = !sendViewModel.balanceViewModel.isReversing,
|
||||||
|
child: Form(
|
||||||
|
key: _formKey,
|
||||||
|
child: ScrollableWithBottomSection(
|
||||||
|
contentPadding: EdgeInsets.only(bottom: 24),
|
||||||
|
content: FocusTraversalGroup(
|
||||||
|
policy: OrderedTraversalPolicy(),
|
||||||
|
child: Column(
|
||||||
|
children: <Widget>[
|
||||||
|
Container(
|
||||||
|
height: _sendCardHeight(context),
|
||||||
|
child: Observer(
|
||||||
|
builder: (_) {
|
||||||
|
return PageView.builder(
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
controller: controller,
|
||||||
|
itemCount: sendViewModel.outputs.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final output = sendViewModel.outputs[index];
|
||||||
|
|
||||||
|
return SendCard(
|
||||||
|
key: output.key,
|
||||||
|
output: output,
|
||||||
|
sendViewModel: sendViewModel,
|
||||||
|
initialPaymentRequest: initialPaymentRequest,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(top: 10, left: 24, right: 24, bottom: 10),
|
||||||
|
child: Container(
|
||||||
|
height: 10,
|
||||||
|
child: Observer(
|
||||||
|
builder: (_) {
|
||||||
|
final count = sendViewModel.outputs.length;
|
||||||
|
|
||||||
|
return count > 1
|
||||||
|
? SmoothPageIndicator(
|
||||||
|
controller: controller,
|
||||||
|
count: count,
|
||||||
|
effect: ScrollingDotsEffect(
|
||||||
|
spacing: 6.0,
|
||||||
|
radius: 6.0,
|
||||||
|
dotWidth: 6.0,
|
||||||
|
dotHeight: 6.0,
|
||||||
|
dotColor: Theme.of(context)
|
||||||
|
.extension<SendPageTheme>()!
|
||||||
|
.indicatorDotColor,
|
||||||
|
activeDotColor: Theme.of(context)
|
||||||
|
.extension<SendPageTheme>()!
|
||||||
|
.templateBackgroundColor),
|
||||||
|
)
|
||||||
|
: Offstage();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: 40,
|
||||||
|
width: double.infinity,
|
||||||
|
padding: EdgeInsets.only(left: 24),
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
child: Observer(
|
||||||
|
builder: (_) {
|
||||||
|
final templates = sendViewModel.templates;
|
||||||
|
final itemCount = templates.length;
|
||||||
|
|
||||||
|
return Row(
|
||||||
|
children: <Widget>[
|
||||||
|
AddTemplateButton(
|
||||||
|
onTap: () => Navigator.of(context).pushNamed(Routes.sendTemplate),
|
||||||
|
currentTemplatesLength: templates.length,
|
||||||
|
),
|
||||||
|
ListView.builder(
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
shrinkWrap: true,
|
||||||
|
physics: NeverScrollableScrollPhysics(),
|
||||||
|
itemCount: itemCount,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final template = templates[index];
|
||||||
|
return TemplateTile(
|
||||||
|
key: UniqueKey(),
|
||||||
|
to: template.name,
|
||||||
|
hasMultipleRecipients: template.additionalRecipients != null &&
|
||||||
|
template.additionalRecipients!.length > 1,
|
||||||
|
amount: template.isCurrencySelected
|
||||||
|
? template.amount
|
||||||
|
: template.amountFiat,
|
||||||
|
from: template.isCurrencySelected
|
||||||
|
? template.cryptoCurrency
|
||||||
|
: template.fiatCurrency,
|
||||||
|
onTap: () async {
|
||||||
|
if (template.additionalRecipients?.isNotEmpty ?? false) {
|
||||||
|
sendViewModel.clearOutputs();
|
||||||
|
|
||||||
|
for (int i = 0;
|
||||||
|
i < template.additionalRecipients!.length;
|
||||||
|
i++) {
|
||||||
|
Output output;
|
||||||
|
try {
|
||||||
|
output = sendViewModel.outputs[i];
|
||||||
|
} catch (e) {
|
||||||
|
sendViewModel.addOutput();
|
||||||
|
output = sendViewModel.outputs[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
await _setInputsFromTemplate(
|
||||||
|
context,
|
||||||
|
output: output,
|
||||||
|
template: template.additionalRecipients![i],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
final output = _defineCurrentOutput();
|
||||||
|
await _setInputsFromTemplate(
|
||||||
|
context,
|
||||||
|
output: output,
|
||||||
|
template: template,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRemove: () {
|
||||||
|
showPopUp<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (dialogContext) {
|
||||||
|
return AlertWithTwoActions(
|
||||||
|
alertTitle: S.of(context).template,
|
||||||
|
alertContent: S.of(context).confirm_delete_template,
|
||||||
|
rightButtonText: S.of(context).delete,
|
||||||
|
leftButtonText: S.of(context).cancel,
|
||||||
|
actionRightButton: () {
|
||||||
|
Navigator.of(dialogContext).pop();
|
||||||
|
sendViewModel.sendTemplateViewModel
|
||||||
|
.removeTemplate(template: template);
|
||||||
|
},
|
||||||
|
actionLeftButton: () =>
|
||||||
|
Navigator.of(dialogContext).pop());
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||||
|
bottomSection: Column(
|
||||||
|
children: [
|
||||||
|
if (sendViewModel.hasCurrecyChanger)
|
||||||
|
Observer(
|
||||||
|
builder: (_) => Padding(
|
||||||
|
padding: EdgeInsets.only(bottom: 12),
|
||||||
|
child: PrimaryButton(
|
||||||
|
onPressed: () => presentCurrencyPicker(context),
|
||||||
|
text: 'Change your asset (${sendViewModel.selectedCryptoCurrency})',
|
||||||
|
color: Colors.transparent,
|
||||||
|
textColor:
|
||||||
|
Theme.of(context).extension<SeedWidgetTheme>()!.hintTextColor,
|
||||||
|
))),
|
||||||
|
if (sendViewModel.sendTemplateViewModel.hasMultiRecipient)
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(bottom: 12),
|
||||||
|
child: PrimaryButton(
|
||||||
|
onPressed: () {
|
||||||
|
sendViewModel.addOutput();
|
||||||
|
Future.delayed(const Duration(milliseconds: 250), () {
|
||||||
|
controller.jumpToPage(sendViewModel.outputs.length - 1);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
text: S.of(context).add_receiver,
|
||||||
|
color: Colors.transparent,
|
||||||
|
textColor: Theme.of(context).extension<SeedWidgetTheme>()!.hintTextColor,
|
||||||
|
isDottedBorder: true,
|
||||||
|
borderColor:
|
||||||
|
Theme.of(context).extension<SendPageTheme>()!.templateDottedBorderColor,
|
||||||
|
)),
|
||||||
|
Observer(
|
||||||
|
builder: (_) {
|
||||||
|
return LoadingPrimaryButton(
|
||||||
|
onPressed: () async {
|
||||||
|
if (_formKey.currentState != null && !_formKey.currentState!.validate()) {
|
||||||
|
if (sendViewModel.outputs.length > 1) {
|
||||||
|
showErrorValidationAlert(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final notValidItems = sendViewModel.outputs
|
||||||
|
.where((item) => item.address.isEmpty || item.cryptoAmount.isEmpty)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
if (notValidItems.isNotEmpty) {
|
||||||
|
showErrorValidationAlert(context);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final check = sendViewModel.shouldDisplayTotp();
|
||||||
|
authService.authenticateAction(
|
||||||
|
context,
|
||||||
|
conditionToDetermineIfToUse2FA: check,
|
||||||
|
onAuthSuccess: (value) async {
|
||||||
|
if (value) {
|
||||||
|
await sendViewModel.createTransaction();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
text: S.of(context).send,
|
||||||
|
color: Theme.of(context).primaryColor,
|
||||||
|
textColor: Colors.white,
|
||||||
|
isLoading: sendViewModel.state is IsExecutingState ||
|
||||||
|
sendViewModel.state is TransactionCommitting,
|
||||||
|
isDisabled: !sendViewModel.isReadyForSend,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _setEffects(BuildContext context) {
|
||||||
|
if (_effectsInstalled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
reaction((_) => sendViewModel.state, (ExecutionState state) {
|
||||||
|
if (state is FailureState) {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
showPopUp<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AlertWithOneAction(
|
||||||
|
alertTitle: S.of(context).error,
|
||||||
|
alertContent: state.error,
|
||||||
|
buttonText: S.of(context).ok,
|
||||||
|
buttonAction: () => Navigator.of(context).pop());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state is ExecutedSuccessfullyState) {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
if (context.mounted) {
|
||||||
|
showPopUp<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext _dialogContext) {
|
||||||
|
return ConfirmSendingAlert(
|
||||||
|
alertTitle: S.of(_dialogContext).confirm_sending,
|
||||||
|
amount: S.of(_dialogContext).send_amount,
|
||||||
|
amountValue: sendViewModel.pendingTransaction!.amountFormatted,
|
||||||
|
fiatAmountValue: sendViewModel.pendingTransactionFiatAmountFormatted,
|
||||||
|
fee: S.of(_dialogContext).send_fee,
|
||||||
|
feeValue: sendViewModel.pendingTransaction!.feeFormatted,
|
||||||
|
feeFiatAmount: sendViewModel.pendingTransactionFeeFiatAmountFormatted,
|
||||||
|
outputs: sendViewModel.outputs,
|
||||||
|
rightButtonText: S.of(_dialogContext).send,
|
||||||
|
leftButtonText: S.of(_dialogContext).cancel,
|
||||||
|
actionRightButton: () {
|
||||||
|
Navigator.of(_dialogContext).pop();
|
||||||
|
sendViewModel.commitTransaction();
|
||||||
|
showPopUp<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext _dialogContext) {
|
||||||
|
return Observer(builder: (_) {
|
||||||
|
final state = sendViewModel.state;
|
||||||
|
|
||||||
|
if (state is FailureState) {
|
||||||
|
Navigator.of(_dialogContext).pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state is TransactionCommitted) {
|
||||||
|
return AlertWithOneAction(
|
||||||
|
alertTitle: '',
|
||||||
|
alertContent: S.of(_dialogContext).send_success(
|
||||||
|
sendViewModel.selectedCryptoCurrency.toString()),
|
||||||
|
buttonText: S.of(_dialogContext).ok,
|
||||||
|
buttonAction: () {
|
||||||
|
Navigator.of(_dialogContext).pop();
|
||||||
|
RequestReviewHandler.requestReview();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return Offstage();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
actionLeftButton: () => Navigator.of(_dialogContext).pop());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state is TransactionCommitted) {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
sendViewModel.clearOutputs();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
_effectsInstalled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _setInputsFromTemplate(BuildContext context,
|
||||||
|
{required Output output, required Template template}) async {
|
||||||
|
output.address = template.address;
|
||||||
|
|
||||||
|
if (template.isCurrencySelected) {
|
||||||
|
sendViewModel.setSelectedCryptoCurrency(template.cryptoCurrency);
|
||||||
|
output.setCryptoAmount(template.amount);
|
||||||
|
} else {
|
||||||
|
final fiatFromTemplate =
|
||||||
|
FiatCurrency.all.singleWhere((element) => element.title == template.fiatCurrency);
|
||||||
|
|
||||||
|
sendViewModel.setFiatCurrency(fiatFromTemplate);
|
||||||
|
output.setFiatAmount(template.amountFiat);
|
||||||
|
}
|
||||||
|
|
||||||
|
output.resetParsedAddress();
|
||||||
|
await output.fetchParsedAddress(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
Output _defineCurrentOutput() {
|
||||||
|
if (controller.page == null) {
|
||||||
|
throw Exception('Controller page is null');
|
||||||
|
}
|
||||||
|
final itemCount = controller.page!.round();
|
||||||
|
return sendViewModel.outputs[itemCount];
|
||||||
|
}
|
||||||
|
|
||||||
|
void showErrorValidationAlert(BuildContext context) async {
|
||||||
|
await showPopUp<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AlertWithOneAction(
|
||||||
|
alertTitle: S.of(context).error,
|
||||||
|
alertContent: 'Please, check receiver forms',
|
||||||
|
buttonText: S.of(context).ok,
|
||||||
|
buttonAction: () => Navigator.of(context).pop());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void presentCurrencyPicker(BuildContext context) async {
|
||||||
|
await showPopUp<CryptoCurrency>(
|
||||||
|
builder: (_) => Picker(
|
||||||
|
items: sendViewModel.currencies,
|
||||||
|
displayItem: (Object item) => item.toString(),
|
||||||
|
selectedAtIndex:
|
||||||
|
sendViewModel.currencies.indexOf(sendViewModel.selectedCryptoCurrency),
|
||||||
|
title: S.of(context).please_select,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
onItemSelected: (CryptoCurrency cur) => sendViewModel.selectedCryptoCurrency = cur,
|
||||||
|
),
|
||||||
|
context: context);
|
||||||
|
}
|
||||||
|
}
|
140
lib/view_model/lightning_invoice_page_view_model.dart
Normal file
140
lib/view_model/lightning_invoice_page_view_model.dart
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
import 'package:cake_wallet/anonpay/anonpay_api.dart';
|
||||||
|
import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart';
|
||||||
|
import 'package:cake_wallet/anonpay/anonpay_request.dart';
|
||||||
|
import 'package:cake_wallet/core/execution_state.dart';
|
||||||
|
import 'package:cake_wallet/entities/fiat_currency.dart';
|
||||||
|
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||||
|
import 'package:cake_wallet/entities/receive_page_option.dart';
|
||||||
|
import 'package:cake_wallet/store/settings_store.dart';
|
||||||
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
|
import 'package:cw_core/currency.dart';
|
||||||
|
import 'package:cw_core/wallet_base.dart';
|
||||||
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
part 'lightning_invoice_page_view_model.g.dart';
|
||||||
|
|
||||||
|
class LightningInvoicePageViewModel = LightningInvoicePageViewModelBase with _$LightningInvoicePageViewModel;
|
||||||
|
|
||||||
|
abstract class LightningInvoicePageViewModelBase with Store {
|
||||||
|
LightningInvoicePageViewModelBase(
|
||||||
|
this.address,
|
||||||
|
this.settingsStore,
|
||||||
|
this._wallet,
|
||||||
|
// this._anonpayInvoiceInfoSource,
|
||||||
|
this.sharedPreferences,
|
||||||
|
this.pageOption,
|
||||||
|
) : description = '',
|
||||||
|
amount = '',
|
||||||
|
state = InitialExecutionState(),
|
||||||
|
selectedCurrency = walletTypeToCryptoCurrency(_wallet.type),
|
||||||
|
cryptoCurrency = walletTypeToCryptoCurrency(_wallet.type) {
|
||||||
|
// _getPreviousDonationLink();
|
||||||
|
// _fetchLimits();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Currency> get currencies => [walletTypeToCryptoCurrency(_wallet.type), ...FiatCurrency.all];
|
||||||
|
final String address;
|
||||||
|
final SettingsStore settingsStore;
|
||||||
|
final WalletBase _wallet;
|
||||||
|
// final Box<AnonpayInvoiceInfo> _anonpayInvoiceInfoSource;
|
||||||
|
final SharedPreferences sharedPreferences;
|
||||||
|
final ReceivePageOption pageOption;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
Currency selectedCurrency;
|
||||||
|
|
||||||
|
CryptoCurrency cryptoCurrency;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
String description;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
String amount;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
ExecutionState state;
|
||||||
|
|
||||||
|
@computed
|
||||||
|
int get selectedCurrencyIndex => currencies.indexOf(selectedCurrency);
|
||||||
|
|
||||||
|
@observable
|
||||||
|
double? minimum;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
double? maximum;
|
||||||
|
|
||||||
|
@action
|
||||||
|
void selectCurrency(Currency currency) {
|
||||||
|
selectedCurrency = currency;
|
||||||
|
maximum = minimum = null;
|
||||||
|
if (currency is CryptoCurrency) {
|
||||||
|
cryptoCurrency = currency;
|
||||||
|
} else {
|
||||||
|
cryptoCurrency = walletTypeToCryptoCurrency(_wallet.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
_fetchLimits();
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
Future<void> createInvoice() async {
|
||||||
|
state = IsExecutingState();
|
||||||
|
if (amount.isNotEmpty) {
|
||||||
|
final amountInCrypto = double.tryParse(amount);
|
||||||
|
if (amountInCrypto == null) {
|
||||||
|
state = FailureState('Amount is invalid');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (minimum != null && amountInCrypto < minimum!) {
|
||||||
|
state = FailureState('Amount is too small');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (maximum != null && amountInCrypto > maximum!) {
|
||||||
|
state = FailureState('Amount is too big');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// final result = await anonPayApi.createInvoice(AnonPayRequest(
|
||||||
|
// cryptoCurrency: cryptoCurrency,
|
||||||
|
// address: address,
|
||||||
|
// amount: amount.isEmpty ? null : amount,
|
||||||
|
// description: description,
|
||||||
|
// fiatEquivalent:
|
||||||
|
// selectedCurrency is FiatCurrency ? (selectedCurrency as FiatCurrency).raw : null,
|
||||||
|
// ));
|
||||||
|
|
||||||
|
// _anonpayInvoiceInfoSource.add(result);
|
||||||
|
|
||||||
|
// state = ExecutedSuccessfullyState(payload: result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
void setRequestParams({
|
||||||
|
required String inputAmount,
|
||||||
|
required String inputDescription,
|
||||||
|
}) {
|
||||||
|
description = inputDescription;
|
||||||
|
amount = inputAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _fetchLimits() async {
|
||||||
|
// final limit = await anonPayApi.fetchLimits(
|
||||||
|
// cryptoCurrency: cryptoCurrency,
|
||||||
|
// fiatCurrency: selectedCurrency is FiatCurrency ? selectedCurrency as FiatCurrency : null,
|
||||||
|
// );
|
||||||
|
// minimum = limit.min;
|
||||||
|
// maximum = limit.max != null ? limit.max! / 4 : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
void reset() {
|
||||||
|
selectedCurrency = walletTypeToCryptoCurrency(_wallet.type);
|
||||||
|
cryptoCurrency = walletTypeToCryptoCurrency(_wallet.type);
|
||||||
|
description = '';
|
||||||
|
amount = '';
|
||||||
|
_fetchLimits();
|
||||||
|
}
|
||||||
|
}
|
73
lib/view_model/lightning_view_model.dart
Normal file
73
lib/view_model/lightning_view_model.dart
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'package:breez_sdk/breez_sdk.dart';
|
||||||
|
import 'package:breez_sdk/bridge_generated.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
|
import 'package:cake_wallet/view_model/auth_state.dart';
|
||||||
|
import 'package:cake_wallet/core/auth_service.dart';
|
||||||
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
import 'package:cake_wallet/core/execution_state.dart';
|
||||||
|
import 'package:cake_wallet/entities/biometric_auth.dart';
|
||||||
|
import 'package:cake_wallet/store/settings_store.dart';
|
||||||
|
|
||||||
|
part 'lightning_view_model.g.dart';
|
||||||
|
|
||||||
|
class LightningViewModel = LightningViewModelBase with _$LightningViewModel;
|
||||||
|
|
||||||
|
abstract class LightningViewModelBase with Store {
|
||||||
|
LightningViewModelBase() {}
|
||||||
|
|
||||||
|
// @observable
|
||||||
|
// ExecutionState state;
|
||||||
|
|
||||||
|
@action
|
||||||
|
Future<void> receiveOnChain() async {
|
||||||
|
print("pressed");
|
||||||
|
// ReceivePaymentRequest req = const ReceivePaymentRequest(
|
||||||
|
// amountMsat: 3000000,
|
||||||
|
// description: "Invoice for 3000 sats",
|
||||||
|
// );
|
||||||
|
// ReceivePaymentResponse receivePaymentResponse =
|
||||||
|
// await BreezSDK().receivePayment(req: req);
|
||||||
|
|
||||||
|
// print(receivePaymentResponse.lnInvoice);
|
||||||
|
|
||||||
|
final sdk = await BreezSDK();
|
||||||
|
|
||||||
|
sdk.nodeStateStream.listen((event) {
|
||||||
|
// print("Node state: $event");
|
||||||
|
if (event == null) return;
|
||||||
|
int balanceSat = event.maxPayableMsat ~/ 1000;
|
||||||
|
print("sats: $balanceSat");
|
||||||
|
});
|
||||||
|
|
||||||
|
// ServiceHealthCheckResponse healthCheck = await sdk.serviceHealthCheck();
|
||||||
|
// print("Current service status is: ${healthCheck.status}");
|
||||||
|
|
||||||
|
// ReceivePaymentRequest req = ReceivePaymentRequest(
|
||||||
|
// amountMsat: 123 * 1000,
|
||||||
|
// description: "Invoice for 123 sats",
|
||||||
|
// );
|
||||||
|
// final s = await sdk.receivePayment(req: req);
|
||||||
|
// print(s.lnInvoice.bolt11);
|
||||||
|
|
||||||
|
// ReceiveOnchainRequest req = const ReceiveOnchainRequest();
|
||||||
|
// SwapInfo swapInfo = await sdk.receiveOnchain(req: req);
|
||||||
|
// // Send your funds to the below bitcoin address
|
||||||
|
// String address = swapInfo.bitcoinAddress;
|
||||||
|
// print(address);
|
||||||
|
// print("Minimum amount allowed to deposit in sats: ${swapInfo.minAllowedDeposit}");
|
||||||
|
// print("Maximum amount allowed to deposit in sats: ${swapInfo.maxAllowedDeposit}");
|
||||||
|
|
||||||
|
ListPaymentsRequest lReq = ListPaymentsRequest();
|
||||||
|
|
||||||
|
var list = await sdk.listPayments(req: lReq);
|
||||||
|
print(list[0].amountMsat);
|
||||||
|
|
||||||
|
var data = await sdk.fetchNodeData();
|
||||||
|
print(data);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue