From 3672f4cd947b0d1088cee001e23f050f9a2697e8 Mon Sep 17 00:00:00 2001 From: poka Date: Thu, 26 May 2022 02:19:29 +0200 Subject: [PATCH] Refactoring of payment workflow UX --- lib/providers/my_wallets.dart | 3 +- lib/providers/substrate_sdk.dart | 25 ++- lib/screens/home.dart | 3 +- lib/screens/myWallets/choose_chest.dart | 2 +- lib/screens/myWallets/choose_wallet.dart | 49 +---- .../myWallets/confirm_wallet_storage.dart | 6 +- lib/screens/myWallets/unlocking_wallet.dart | 20 +- lib/screens/myWallets/wallet_options.dart | 4 +- lib/screens/myWallets/wallets_home.dart | 2 +- lib/screens/transaction_in_progress.dart | 184 ++++++++++++++++++ lib/screens/wallet_view.dart | 28 ++- 11 files changed, 259 insertions(+), 67 deletions(-) create mode 100644 lib/screens/transaction_in_progress.dart diff --git a/lib/providers/my_wallets.dart b/lib/providers/my_wallets.dart index e8a7ded..6760027 100644 --- a/lib/providers/my_wallets.dart +++ b/lib/providers/my_wallets.dart @@ -63,10 +63,11 @@ class MyWalletsProvider with ChangeNotifier { return _targetedWallet; } - WalletData? getDefaultWallet(int? chest) { + WalletData? getDefaultWallet([int? chest]) { if (chestBox.isEmpty) { return WalletData(chest: 0, number: 0); } else { + chest ??= getCurrentChest(); int? defaultWalletNumber = chestBox.get(chest)!.defaultWallet; return getWalletData([chest, defaultWalletNumber]); } diff --git a/lib/providers/substrate_sdk.dart b/lib/providers/substrate_sdk.dart index f6e5bb4..a91d6fb 100644 --- a/lib/providers/substrate_sdk.dart +++ b/lib/providers/substrate_sdk.dart @@ -27,6 +27,7 @@ class SubstrateSdk with ChangeNotifier { int blocNumber = 0; bool isLoadingEndpoint = false; String debugConnection = ''; + String transactionStatus = ''; TextEditingController jsonKeystore = TextEditingController(); TextEditingController keystorePassword = TextEditingController(); @@ -299,6 +300,8 @@ class SubstrateSdk with ChangeNotifier { required String destAddress, required double amount, required String password}) async { + transactionStatus = ''; + setCurrentWallet(fromAddress); log.d(keyring.current.address); @@ -317,15 +320,31 @@ class SubstrateSdk with ChangeNotifier { [destAddress, amount * 100], password, onStatusChange: (status) { - print('status: ' + status); + log.d('Transaction status: ' + status); if (status == 'Ready') { - snack(context, 'Transaction terminé'); + transactionStatus = 'sent'; + notifyListeners(); + // snack(context, 'Transaction terminé'); } }, + ).timeout( + const Duration(seconds: 12), + onTimeout: () => {}, ); print(hash.toString()); - return 'confirmed'; + if (hash.isEmpty) { + transactionStatus = 'timeout'; + notifyListeners(); + + return 'timeout'; + } else { + transactionStatus = hash.toString(); + notifyListeners(); + return hash.toString(); + } } catch (e) { + transactionStatus = e.toString(); + notifyListeners(); return e.toString(); } } diff --git a/lib/screens/home.dart b/lib/screens/home.dart index b4be2fe..6429d7d 100644 --- a/lib/screens/home.dart +++ b/lib/screens/home.dart @@ -275,8 +275,7 @@ Widget geckHome(context) { height: 68 * ratio)), onTap: () { WalletData? defaultWallet = - _myWalletProvider.getDefaultWallet( - configBox.get('currentChest')); + _myWalletProvider.getDefaultWallet(); Navigator.push( context, MaterialPageRoute( diff --git a/lib/screens/myWallets/choose_chest.dart b/lib/screens/myWallets/choose_chest.dart index 58e9478..0f09b48 100644 --- a/lib/screens/myWallets/choose_chest.dart +++ b/lib/screens/myWallets/choose_chest.dart @@ -115,7 +115,7 @@ class _ChooseChestState extends State { onPressed: () { configBox.put('currentChest', currentChest); WalletData? defaultWallet = - _myWalletProvider.getDefaultWallet(currentChest); + _myWalletProvider.getDefaultWallet(); _myWalletProvider.rebuildWidget(); Navigator.pushAndRemoveUntil( context, diff --git a/lib/screens/myWallets/choose_wallet.dart b/lib/screens/myWallets/choose_wallet.dart index a3facaa..4bb756a 100644 --- a/lib/screens/myWallets/choose_wallet.dart +++ b/lib/screens/myWallets/choose_wallet.dart @@ -50,17 +50,7 @@ class ChooseWalletScreen extends StatelessWidget { onPressed: () async { Navigator.pop(context); Navigator.pop(context); - // Payment workflow ! - // final acc = _sub.getCurrentWallet(); - // log.d( - // "fromAddress: ${acc.address!},destAddress: ${_walletViewProvider.outputPubkey.text}, amount: ${double.parse(_walletViewProvider.payAmount.text)}, password: $pin"); - // final resultPay = await _sub.pay(context, - // fromAddress: acc.address!, - // destAddress: _walletViewProvider.outputPubkey.text, - // amount: - // double.parse(_walletViewProvider.payAmount.text), - // password: pin.toUpperCase()); - // await paymentsResult(context, resultPay); + Navigator.pop(context); }, child: const Text( 'Choisir ce portefeuille', @@ -85,7 +75,7 @@ class ChooseWalletScreen extends StatelessWidget { Provider.of(context, listen: false); WalletData? defaultWallet = - _myWalletProvider.getDefaultWallet(currentChest); + _myWalletProvider.getDefaultWallet(); _selectedId ??= defaultWallet!.id(); _derivation ??= defaultWallet!.derivation!; @@ -205,8 +195,10 @@ class ChooseWalletScreen extends StatelessWidget { _selectedId = _repository.id(); chestBox.get(currentChest)!.defaultWallet = _repository.number; + _sub.setCurrentWallet(_repository.address!); - // _myWalletProvider.rebuildWidget(); + _myWalletProvider.rebuildWidget(); + _walletViewProvider.reload(); _sub.reload(); }, ) @@ -218,34 +210,3 @@ class ChooseWalletScreen extends StatelessWidget { ]); } } - -Future paymentsResult(context, String resultPay) { - final bool isValid = resultPay == "confirmed"; - if (!isValid) log.e(resultPay); - - return showDialog( - context: context, - barrierDismissible: true, // user must tap button! - builder: (BuildContext context) { - return AlertDialog( - title: Text(isValid - ? 'Paiement effecuté avec succès !' - : "Une erreur s'est produite lors du paiement:\n$resultPay"), - content: const SingleChildScrollView(child: Text('')), - actions: [ - TextButton( - child: const Text("OK"), - onPressed: () async { - isValid - ? await Navigator.of(context).pushNamedAndRemoveUntil( - '/', - ModalRoute.withName('/'), - ) - : Navigator.pop(context); - }, - ), - ], - ); - }, - ); -} diff --git a/lib/screens/myWallets/confirm_wallet_storage.dart b/lib/screens/myWallets/confirm_wallet_storage.dart index 3f2352c..74d23c0 100644 --- a/lib/screens/myWallets/confirm_wallet_storage.dart +++ b/lib/screens/myWallets/confirm_wallet_storage.dart @@ -164,10 +164,8 @@ class ConfirmStoreWallet extends StatelessWidget with ChangeNotifier { Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (context) { return UnlockingWallet( - wallet: - _myWalletProvider.getDefaultWallet( - configBox.get('currentChest'), - ), + wallet: _myWalletProvider + .getDefaultWallet(), action: "mywallets", ); }), ModalRoute.withName('/')); diff --git a/lib/screens/myWallets/unlocking_wallet.dart b/lib/screens/myWallets/unlocking_wallet.dart index 88e9f29..78a2eb0 100644 --- a/lib/screens/myWallets/unlocking_wallet.dart +++ b/lib/screens/myWallets/unlocking_wallet.dart @@ -8,9 +8,11 @@ import 'package:gecko/providers/my_wallets.dart'; import 'package:gecko/models/wallet_data.dart'; import 'package:gecko/providers/wallet_options.dart'; import 'package:flutter/material.dart'; +import 'package:gecko/providers/wallets_profiles.dart'; import 'package:gecko/screens/myWallets/choose_chest.dart'; import 'package:gecko/screens/myWallets/choose_wallet.dart'; import 'package:gecko/screens/myWallets/wallets_home.dart'; +import 'package:gecko/screens/transaction_in_progress.dart'; import 'package:pin_code_fields/pin_code_fields.dart'; import 'package:provider/provider.dart'; import 'package:gecko/globals.dart'; @@ -231,10 +233,26 @@ class UnlockingWallet extends StatelessWidget { ); break; case "pay": + // Navigator.pop(context); + // Navigator.pop(context); + // Payment workflow ! + WalletsProfilesProvider _walletViewProvider = + Provider.of(context, + listen: false); + final acc = _sub.getCurrentWallet(); + log.d( + "fromAddress: ${acc.address!},destAddress: ${_walletViewProvider.outputPubkey.text}, amount: ${double.parse(_walletViewProvider.payAmount.text)}, password: $_pin"); + _sub.pay(context, + fromAddress: acc.address!, + destAddress: _walletViewProvider.outputPubkey.text, + amount: + double.parse(_walletViewProvider.payAmount.text), + password: _pin.toUpperCase()); + // await paymentsResult(context, resultPay); Navigator.push( context, MaterialPageRoute(builder: (context) { - return ChooseWalletScreen( + return TransactionInProgress( chest: currentChestNumber, pin: _pin.toUpperCase()); }), ); diff --git a/lib/screens/myWallets/wallet_options.dart b/lib/screens/myWallets/wallet_options.dart index fa9bdcf..a740335 100644 --- a/lib/screens/myWallets/wallet_options.dart +++ b/lib/screens/myWallets/wallet_options.dart @@ -29,7 +29,7 @@ class WalletOptions extends StatelessWidget { final int _currentChest = _myWalletProvider.getCurrentChest()!; - // final currentWallet = _myWalletProvider.getDefaultWallet(_currentChest); + // final currentWallet = _myWalletProvider.getDefaultWallet(); // log.d(_walletOptions.getAddress(_currentChest, 3)); log.d("Wallet options: $_currentChest:${wallet.derivation}"); @@ -336,7 +336,7 @@ class WalletOptions extends StatelessWidget { WalletOptionsProvider _walletOptions, int _currentChest) { WalletData defaultWallet = - _myWalletProvider.getDefaultWallet(_currentChest)!; + _myWalletProvider.getDefaultWallet()!; _walletOptions.isDefaultWallet = (defaultWallet.number == wallet.id()[1]); diff --git a/lib/screens/myWallets/wallets_home.dart b/lib/screens/myWallets/wallets_home.dart index eab5beb..98895b3 100644 --- a/lib/screens/myWallets/wallets_home.dart +++ b/lib/screens/myWallets/wallets_home.dart @@ -155,7 +155,7 @@ class WalletsHome extends StatelessWidget { List _listWallets = _myWalletProvider.listWallets; WalletData? defaultWallet = - _myWalletProvider.getDefaultWallet(configBox.get('currentChest')); + _myWalletProvider.getDefaultWallet(); final double screenWidth = MediaQuery.of(context).size.width; int nTule = 2; diff --git a/lib/screens/transaction_in_progress.dart b/lib/screens/transaction_in_progress.dart new file mode 100644 index 0000000..1adb453 --- /dev/null +++ b/lib/screens/transaction_in_progress.dart @@ -0,0 +1,184 @@ +import 'package:flutter/services.dart'; +import 'package:gecko/globals.dart'; +import 'package:flutter/material.dart'; +import 'package:gecko/providers/my_wallets.dart'; +import 'package:gecko/providers/substrate_sdk.dart'; +import 'package:gecko/providers/wallets_profiles.dart'; +import 'package:provider/provider.dart'; +// import 'package:gecko/models/home.dart'; +// import 'package:provider/provider.dart'; + +// ignore: must_be_immutable +class TransactionInProgress extends StatelessWidget { + const TransactionInProgress( + {Key? key, required this.chest, required this.pin}) + : super(key: key); + final int chest; + final String pin; + + @override + Widget build(BuildContext context) { + SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); + SubstrateSdk _sub = Provider.of(context, listen: true); + WalletsProfilesProvider _walletViewProvider = + Provider.of(context, listen: false); + MyWalletsProvider _myWalletProvider = + Provider.of(context, listen: false); + + String _resultText; + bool isLoading = true; + // Map jsonResult; + final _result = _sub.transactionStatus; + + final from = _myWalletProvider.getDefaultWallet()!.name!; + final to = _walletViewProvider + .getShortPubkey(_walletViewProvider.outputPubkey.text); + final amount = _walletViewProvider.payAmount.text; + + switch (_result) { + case '': + { + _resultText = 'Envoi en cours ...'; + } + break; + case 'sent': + { + _resultText = 'En cours de validation ...'; + } + break; + default: + { + isLoading = false; + // jsonResult = json.decode(_result); + log.d(_result); + if (_result.contains('blockHash: ')) { + _resultText = 'Transcation validé !'; + } else { + _resultText = "Une erreur s'est produite:\n\n$_result"; + } + } + } + + return WillPopScope( + onWillPop: () { + _sub.transactionStatus = ''; + Navigator.pop(context); + Navigator.pop(context); + Navigator.pop(context); + return Future.value(true); + }, + child: Scaffold( + appBar: AppBar( + toolbarHeight: 60 * ratio, + elevation: 0, + automaticallyImplyLeading: false, + title: SizedBox( + height: 22, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: const [Text('Transaction en cours')]), + )), + body: SafeArea( + child: Align( + alignment: FractionalOffset.bottomCenter, + child: Column(children: [ + Container( + width: double.infinity, + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + yellowC, + const Color(0xfffafafa), + ], + )), + child: Column(children: [ + const SizedBox(height: 10), + Text( + '$amount $currencyName', + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: 18, fontWeight: FontWeight.w600), + ), + const SizedBox(height: 10), + const Text( + 'de', + textAlign: TextAlign.center, + style: TextStyle(fontSize: 18), + ), + Text( + from, + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: 18, fontWeight: FontWeight.w600), + ), + const SizedBox(height: 10), + const Text( + 'vers', + textAlign: TextAlign.center, + style: TextStyle(fontSize: 18), + ), + Text( + to, + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: 18, fontWeight: FontWeight.w600), + ), + const SizedBox(height: 20), + ]), + ), + // const SizedBox(height: 20, width: double.infinity), + const Spacer(), + Row(mainAxisAlignment: MainAxisAlignment.center, children: [ + Text( + _resultText, + textAlign: TextAlign.center, + style: TextStyle(fontSize: 19 * ratio), + ), + Visibility( + visible: isLoading, + child: SizedBox( + height: 15, + width: 15, + child: CircularProgressIndicator( + color: orangeC, + strokeWidth: 2, + ), + ), + ), + ]), + const Spacer(), + Expanded( + child: Align( + alignment: Alignment.bottomCenter, + child: SizedBox( + width: 380 * ratio, + height: 60 * ratio, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + elevation: 4, + primary: orangeC, // background + onPrimary: Colors.white, // foreground + ), + onPressed: () { + Navigator.pop(context); + Navigator.pop(context); + Navigator.pop(context); + }, + child: Text( + 'Fermer', + style: TextStyle( + fontSize: 23 * ratio, + fontWeight: FontWeight.w600), + ), + ), + ), + ), + ), + SizedBox(height: isTall ? 80 : 20) + ])), + ), + )); + } +} diff --git a/lib/screens/wallet_view.dart b/lib/screens/wallet_view.dart index 6af3721..2eca815 100644 --- a/lib/screens/wallet_view.dart +++ b/lib/screens/wallet_view.dart @@ -184,16 +184,18 @@ class WalletViewScreen extends StatelessWidget { void paymentPopup( BuildContext context, WalletsProfilesProvider _walletViewProvider) { - WalletsProfilesProvider _walletViewProvider = - Provider.of(context, listen: false); + // WalletsProfilesProvider _walletViewProvider = + // Provider.of(context, listen: false); MyWalletsProvider _myWalletProvider = Provider.of(context, listen: false); // SubstrateSdk _sub = Provider.of(context, listen: false); const double shapeSize = 20; - WalletData? defaultWallet = - _myWalletProvider.getDefaultWallet(configBox.get('currentChest')); + WalletData? defaultWallet = _myWalletProvider.getDefaultWallet(); + + bool canValidate = false; + _walletViewProvider.outputPubkey.text = pubkey!; showModalBottomSheet( @@ -208,6 +210,15 @@ class WalletViewScreen extends StatelessWidget { builder: (BuildContext context) { return StatefulBuilder( builder: (BuildContext context, StateSetter setState) { + if (_walletViewProvider.payAmount.text != '' && + double.parse(_walletViewProvider.payAmount.text) <= + double.parse( + balanceCache[defaultWallet!.address]!.split(' ')[0]) && + _walletViewProvider.pubkey != defaultWallet.address) { + canValidate = true; + } else { + canValidate = false; + } return Padding( padding: EdgeInsets.only( bottom: MediaQuery.of(context).viewInsets.bottom), @@ -251,7 +262,8 @@ class WalletViewScreen extends StatelessWidget { MaterialPageRoute( builder: (context) { return UnlockingWallet( - wallet: defaultWallet, action: "pay"); + wallet: defaultWallet, + action: "changeWallet"); }, ), ); @@ -265,8 +277,8 @@ class WalletViewScreen extends StatelessWidget { // BorderSide(color: Colors.grey[500], width: 2), // borderRadius: BorderRadius.circular(8)), border: Border.all( - color: - Colors.grey[500]!, // Set border color + color: Colors.blueAccent + .shade200, // Set border color width: 2), // Set border width borderRadius: const BorderRadius.all( Radius.circular(10.0)), // Set ro @@ -376,7 +388,7 @@ class WalletViewScreen extends StatelessWidget { primary: orangeC, // background onPrimary: Colors.white, // foreground ), - onPressed: _walletViewProvider.payAmount.text != '' + onPressed: canValidate ? () { Navigator.push( context,