diff --git a/lib/providers/substrate_sdk.dart b/lib/providers/substrate_sdk.dart index b367ee6..c5023bd 100644 --- a/lib/providers/substrate_sdk.dart +++ b/lib/providers/substrate_sdk.dart @@ -1,7 +1,6 @@ // ignore_for_file: use_build_context_synchronously, body_might_complete_normally_catch_error import 'dart:convert'; - import 'package:easy_localization/easy_localization.dart'; import 'package:fast_base58/fast_base58.dart'; import 'package:flutter/foundation.dart'; @@ -26,6 +25,7 @@ import 'package:provider/provider.dart'; import 'package:truncate/truncate.dart'; import 'package:pointycastle/pointycastle.dart' as pc; import "package:hex/hex.dart"; +import 'package:uuid/uuid.dart' show Uuid; class SubstrateSdk with ChangeNotifier { final WalletSDK sdk = WalletSDK(); @@ -37,8 +37,8 @@ class SubstrateSdk with ChangeNotifier { bool importIsLoading = false; int blocNumber = 0; bool isLoadingEndpoint = false; - String? transactionStatus; - final int initSs58 = 42; + Map transactionStatus = {}; + static const int initSs58 = 42; Map currencyParameters = {}; final csSalt = TextEditingController(); final csPassword = TextEditingController(); @@ -52,18 +52,23 @@ class SubstrateSdk with ChangeNotifier { ///////////////////////////////////// ////////// 1: API METHODS /////////// - /////////////////////////////////////3 + ///////////////////////////////////// - Future _executeCall(TxInfoData txInfo, txOptions, String password, + Future _executeCall(String currentTransactionId, TxInfoData txInfo, + txOptions, String password, [String? rawParams]) async { final walletOptions = Provider.of(homeContext, listen: false); final walletProfiles = Provider.of(homeContext, listen: false); + transactionStatus.putIfAbsent(currentTransactionId, () => 'sending'); + notifyListeners(); + try { final hash = await sdk.api.tx.signAndSend(txInfo, txOptions, password, rawParam: rawParams, onStatusChange: (p0) { - transactionStatus = p0; + transactionStatus.update(currentTransactionId, (_) => p0, + ifAbsent: () => p0); notifyListeners(); }).timeout( const Duration(seconds: 18), @@ -71,20 +76,23 @@ class SubstrateSdk with ChangeNotifier { ); log.d(hash); if (hash.isEmpty) { - transactionStatus = 'Exception: timeout'; + transactionStatus.update( + currentTransactionId, (_) => 'Exception: timeout'); notifyListeners(); return 'Exception: timeout'; } else { // Success ! - transactionStatus = hash.toString(); + transactionStatus.update(currentTransactionId, (_) => hash.toString(), + ifAbsent: () => hash.toString()); notifyListeners(); walletOptions.reload(); walletProfiles.reload(); return hash.toString(); } } catch (e) { - transactionStatus = e.toString(); + transactionStatus.update(currentTransactionId, (_) => e.toString(), + ifAbsent: () => e.toString()); notifyListeners(); return e.toString(); } @@ -909,8 +917,6 @@ class SubstrateSdk with ChangeNotifier { required String destAddress, required double amount, required String password}) async { - transactionStatus = 'sending'; - final sender = await _setSender(fromAddress); final globalBalance = await getBalance(fromAddress); @@ -956,13 +962,13 @@ class SubstrateSdk with ChangeNotifier { rawParams = '[[$tx1, $tx2]]'; } - return await _executeCall(txInfo, txOptions, password, rawParams); + final transactionId = const Uuid().v4(); + _executeCall(transactionId, txInfo, txOptions, password, rawParams); + return transactionId; } Future certify( String fromAddress, String destAddress, String password) async { - transactionStatus = 'sending'; - final statusList = await idtyStatus([fromAddress, destAddress]); final myIdtyStatus = statusList[0]; final toIdtyStatus = statusList[1]; @@ -973,8 +979,6 @@ class SubstrateSdk with ChangeNotifier { final toIndex = idtyIndexList[1]; if (myIdtyStatus != IdtyStatus.validated) { - transactionStatus = 'notMember'; - notifyListeners(); return 'notMember'; } @@ -1022,18 +1026,17 @@ class SubstrateSdk with ChangeNotifier { txOptions = [fromIndex, toIndex]; } } else { - transactionStatus = 'cantBeCert'; - notifyListeners(); return 'cantBeCert'; } log.d('Cert action: ${txInfo.call!}'); - return await _executeCall(txInfo, txOptions, password, rawParams); + final transactionId = const Uuid().v4(); + _executeCall(transactionId, txInfo, txOptions, password, rawParams); + return transactionId; } Future confirmIdentity( String fromAddress, String name, String password) async { - transactionStatus = 'sending'; final sender = await _setSender(fromAddress); final txInfo = TxInfoData( @@ -1043,7 +1046,11 @@ class SubstrateSdk with ChangeNotifier { ); final txOptions = [name]; - return await _executeCall(txInfo, txOptions, password); + final transactionId = const Uuid().v4(); + + _executeCall(transactionId, txInfo, txOptions, password); + + return transactionId; } Future migrateIdentity( @@ -1053,7 +1060,6 @@ class SubstrateSdk with ChangeNotifier { required String destPassword, required Map fromBalance, bool withBalance = false}) async { - transactionStatus = 'sending'; final sender = await _setSender(fromAddress); TxInfoData txInfo; @@ -1111,7 +1117,9 @@ newKeySig: $newKeySigType"""); txOptions = [destAddress, newKeySigType]; } - return await _executeCall(txInfo, txOptions, fromPassword, rawParams); + final transactionId = const Uuid().v4(); + _executeCall(transactionId, txInfo, txOptions, fromPassword, rawParams); + return transactionId; } Future revokeIdentity(String address, String password) async { @@ -1135,10 +1143,12 @@ newKeySig: $newKeySigType"""); ); final txOptions = [idtyIndex, address, revocationSigTyped]; - return await _executeCall(txInfo, txOptions, password); + final transactionId = const Uuid().v4(); + _executeCall(transactionId, txInfo, txOptions, password); + return transactionId; } - Future migrateCsToV2(String salt, String password, String destAddress, + Future migrateCsToV2(String salt, String password, String destAddress, {required destPassword, required Map balance, IdtyStatus idtyStatus = IdtyStatus.none}) async { @@ -1171,8 +1181,10 @@ newKeySig: $newKeySigType"""); password: password, ); + late String transactionId; + if (idtyStatus != IdtyStatus.none) { - await migrateIdentity( + transactionId = await migrateIdentity( fromAddress: keypair.address!, destAddress: destAddress, fromPassword: 'password', @@ -1180,14 +1192,17 @@ newKeySig: $newKeySigType"""); withBalance: true, fromBalance: balance); } else if (balance['transferableBalance'] != 0) { - await pay( + transactionId = await pay( fromAddress: keypair.address!, destAddress: destAddress, amount: -1, password: 'password'); + } else { + transactionId = ''; } await sdk.api.keyring.deleteAccount(keyring, keypair); + return transactionId; } Future spawnBlock([int number = 1, int until = 0]) async { @@ -1204,6 +1219,10 @@ newKeySig: $newKeySigType"""); void reload() { notifyListeners(); } + + void resetTransactionStatus() { + transactionStatus.clear(); + } } //////////////////////////////////////////// diff --git a/lib/providers/wallet_options.dart b/lib/providers/wallet_options.dart index 487bc18..9279c06 100644 --- a/lib/providers/wallet_options.dart +++ b/lib/providers/wallet_options.dart @@ -217,14 +217,17 @@ class WalletOptionsProvider with ChangeNotifier { final wallet = myWalletProvider .getWalletDataByAddress(address.text); await sub.setCurrentWallet(wallet!); - sub.confirmIdentity(walletOptions.address.text, - idtyName.text, myWalletProvider.pinCode); + final transactionId = await sub.confirmIdentity( + walletOptions.address.text, + idtyName.text, + myWalletProvider.pinCode); Navigator.pop(context); Navigator.push( context, MaterialPageRoute(builder: (context) { return TransactionInProgress( + transactionId: transactionId, transType: 'comfirmIdty', fromAddress: getShortPubkey(wallet.address), diff --git a/lib/screens/debug_screen.dart b/lib/screens/debug_screen.dart index 7c6be60..413ca9b 100644 --- a/lib/screens/debug_screen.dart +++ b/lib/screens/debug_screen.dart @@ -39,8 +39,9 @@ class DebugScreen extends StatelessWidget { width: 250, child: ElevatedButton( style: ElevatedButton.styleFrom( - foregroundColor: Colors.white, elevation: 4, - backgroundColor: orangeC, // foreground + foregroundColor: Colors.white, + elevation: 4, + backgroundColor: orangeC, ), onPressed: () async => await sub.spawnBlock(), child: const Text( diff --git a/lib/screens/home.dart b/lib/screens/home.dart index 322faa9..f23c185 100644 --- a/lib/screens/home.dart +++ b/lib/screens/home.dart @@ -322,8 +322,9 @@ Widget welcomeHome(context) { child: ElevatedButton( key: keyOnboardingNewChest, style: ElevatedButton.styleFrom( - foregroundColor: Colors.white, elevation: 4, - backgroundColor: orangeC, // foreground + foregroundColor: Colors.white, + elevation: 4, + backgroundColor: orangeC, ), onPressed: () { Navigator.push( diff --git a/lib/screens/myWallets/change_pin.dart b/lib/screens/myWallets/change_pin.dart index 2e510b0..f334f60 100644 --- a/lib/screens/myWallets/change_pin.dart +++ b/lib/screens/myWallets/change_pin.dart @@ -93,8 +93,9 @@ class _ChangePinScreenState extends State { height: 50, child: ElevatedButton( style: ElevatedButton.styleFrom( - foregroundColor: Colors.black, elevation: 12, - backgroundColor: Colors.green[400], // foreground + foregroundColor: Colors.black, + elevation: 12, + backgroundColor: Colors.green[400], ), onPressed: () async { WalletData defaultWallet = diff --git a/lib/screens/myWallets/choose_chest.dart b/lib/screens/myWallets/choose_chest.dart index 0e82117..c3b8ff8 100644 --- a/lib/screens/myWallets/choose_chest.dart +++ b/lib/screens/myWallets/choose_chest.dart @@ -106,7 +106,7 @@ class _ChooseChestState extends State { child: ElevatedButton( style: ElevatedButton.styleFrom( foregroundColor: Colors.black, - backgroundColor: orangeC, // foreground + backgroundColor: orangeC, ), onPressed: () async { await configBox.put('currentChest', currentChest); diff --git a/lib/screens/myWallets/import_g1_v1.dart b/lib/screens/myWallets/import_g1_v1.dart index 30491a7..8ade0d6 100644 --- a/lib/screens/myWallets/import_g1_v1.dart +++ b/lib/screens/myWallets/import_g1_v1.dart @@ -22,6 +22,7 @@ import 'package:provider/provider.dart'; class ImportG1v1 extends StatelessWidget { const ImportG1v1({Key? key}) : super(key: key); + static const int debouneTime = 600; @override Widget build(BuildContext context) { @@ -29,7 +30,6 @@ class ImportG1v1 extends StatelessWidget { Provider.of(context, listen: false); Timer? debounce; - const int debouneTime = 600; WalletData selectedWallet = myWalletProvider.getDefaultWallet(); bool canValidate = false; String validationStatus = ''; @@ -297,8 +297,10 @@ class ImportG1v1 extends StatelessWidget { ); } - sub.migrateCsToV2(sub.csSalt.text, - sub.csPassword.text, selectedWallet.address, + final transactionId = await sub.migrateCsToV2( + sub.csSalt.text, + sub.csPassword.text, + selectedWallet.address, destPassword: pin ?? myWalletProvider.pinCode, balance: balance, @@ -308,6 +310,7 @@ class ImportG1v1 extends StatelessWidget { context, MaterialPageRoute(builder: (context) { return TransactionInProgress( + transactionId: transactionId, transType: 'identityMigration', fromAddress: getShortPubkey(sub.g1V1NewAddress), diff --git a/lib/screens/myWallets/manage_membership.dart b/lib/screens/myWallets/manage_membership.dart index 02e0aa4..bd6d4ae 100644 --- a/lib/screens/myWallets/manage_membership.dart +++ b/lib/screens/myWallets/manage_membership.dart @@ -109,38 +109,41 @@ class ManageMembership extends StatelessWidget { 'Êtes-vous certains de vouloir révoquer définitivement cette identité ?') ?? false; - if (answer) { - final myWalletProvider = - Provider.of(context, listen: false); - final sub = Provider.of(context, listen: false); + if (!answer) return; + final myWalletProvider = + Provider.of(context, listen: false); + final sub = Provider.of(context, listen: false); - WalletData? defaultWallet = myWalletProvider.getDefaultWallet(); - String? pin; - if (myWalletProvider.pinCode == '') { - pin = await Navigator.push( - context, - MaterialPageRoute( - builder: (homeContext) { - return UnlockingWallet(wallet: defaultWallet); - }, - ), - ); - } - if (pin != null || myWalletProvider.pinCode != '') { - sub.revokeIdentity(address, myWalletProvider.pinCode); - } - Navigator.pop(context); - - Navigator.push( + WalletData? defaultWallet = myWalletProvider.getDefaultWallet(); + String? pin; + if (myWalletProvider.pinCode == '') { + pin = await Navigator.push( context, - MaterialPageRoute(builder: (context) { - return TransactionInProgress( - transType: 'revokeIdty', - fromAddress: getShortPubkey(address), - toAddress: getShortPubkey(address)); - }), + MaterialPageRoute( + builder: (homeContext) { + return UnlockingWallet(wallet: defaultWallet); + }, + ), ); } + + if (pin == null || myWalletProvider.pinCode == '') return; + + final transactionId = + await sub.revokeIdentity(address, myWalletProvider.pinCode); + + Navigator.pop(context); + + Navigator.push( + context, + MaterialPageRoute(builder: (context) { + return TransactionInProgress( + transactionId: transactionId, + transType: 'revokeIdty', + fromAddress: getShortPubkey(address), + toAddress: getShortPubkey(address)); + }), + ); }, child: ScaledSizedBox( height: 55, diff --git a/lib/screens/myWallets/migrate_identity.dart b/lib/screens/myWallets/migrate_identity.dart index 35ba38a..1e6e5b4 100644 --- a/lib/screens/myWallets/migrate_identity.dart +++ b/lib/screens/myWallets/migrate_identity.dart @@ -190,28 +190,25 @@ class MigrateIdentityScreen extends StatelessWidget { ); } - if (myWalletProvider.pinCode != '') { - sub.migrateIdentity( - fromAddress: fromAddress, - destAddress: selectedWallet.address, - fromPassword: - pin ?? myWalletProvider.pinCode, - destPassword: - pin ?? myWalletProvider.pinCode, - withBalance: true, - fromBalance: balance); - Navigator.push( - context, - MaterialPageRoute(builder: (context) { - return TransactionInProgress( - transType: 'identityMigration', - fromAddress: - getShortPubkey(fromAddress), - toAddress: getShortPubkey( - selectedWallet.address)); - }), - ); - } + if (myWalletProvider.pinCode == '') return; + final transactionId = await sub.migrateIdentity( + fromAddress: fromAddress, + destAddress: selectedWallet.address, + fromPassword: pin ?? myWalletProvider.pinCode, + destPassword: pin ?? myWalletProvider.pinCode, + withBalance: true, + fromBalance: balance); + Navigator.push( + context, + MaterialPageRoute(builder: (context) { + return TransactionInProgress( + transactionId: transactionId, + transType: 'identityMigration', + fromAddress: getShortPubkey(fromAddress), + toAddress: getShortPubkey( + selectedWallet.address)); + }), + ); } : null, child: Text( diff --git a/lib/screens/myWallets/restore_chest.dart b/lib/screens/myWallets/restore_chest.dart index d9d6fbc..4036c54 100644 --- a/lib/screens/myWallets/restore_chest.dart +++ b/lib/screens/myWallets/restore_chest.dart @@ -84,8 +84,9 @@ class RestoreChest extends StatelessWidget { child: ElevatedButton( key: keyGoNext, style: ElevatedButton.styleFrom( - foregroundColor: Colors.white, elevation: 4, - backgroundColor: orangeC, // foreground + foregroundColor: Colors.white, + elevation: 4, + backgroundColor: orangeC, ), onPressed: () async { if (await sub @@ -125,8 +126,9 @@ class RestoreChest extends StatelessWidget { child: ElevatedButton( key: keyPastMnemonic, style: ElevatedButton.styleFrom( - foregroundColor: Colors.black, elevation: 4, - backgroundColor: yellowC, // foreground + foregroundColor: Colors.black, + elevation: 4, + backgroundColor: yellowC, ), onPressed: () { genW.pasteMnemonic(context); diff --git a/lib/screens/myWallets/wallet_options.dart b/lib/screens/myWallets/wallet_options.dart index 7764619..1eff106 100644 --- a/lib/screens/myWallets/wallet_options.dart +++ b/lib/screens/myWallets/wallet_options.dart @@ -239,9 +239,7 @@ class WalletOptions extends StatelessWidget { if (!walletProvider.isDefaultWallet && !wallet.isMembre()) deleteWallet( - context, walletProvider, currentChest) - else - ScaledSizedBox(), + context, walletProvider, currentChest), if (wallet.isMembre()) const ManageMembershipButton() ]) @@ -327,16 +325,10 @@ class WalletOptions extends StatelessWidget { key: keyConfirmIdentity, style: ElevatedButton.styleFrom( foregroundColor: Colors.white, elevation: 4, - backgroundColor: orangeC, // foreground + backgroundColor: orangeC, ), - onPressed: () async { + onPressed: () { walletProvider.confirmIdentityPopup(context); - // Navigator.push( - // context, - // MaterialPageRoute(builder: (context) { - // return const SearchResultScreen(); - // }), - // ); }, child: Text( 'confirmMyIdentity'.tr(), diff --git a/lib/screens/onBoarding/5.dart b/lib/screens/onBoarding/5.dart index 5d4e945..c4db23d 100644 --- a/lib/screens/onBoarding/5.dart +++ b/lib/screens/onBoarding/5.dart @@ -221,8 +221,9 @@ Widget nextButton( child: ElevatedButton( key: keyGoNext, style: ElevatedButton.styleFrom( - foregroundColor: Colors.white, elevation: 4, - backgroundColor: orangeC, // foreground + foregroundColor: Colors.white, + elevation: 4, + backgroundColor: orangeC, ), onPressed: () { generateWalletProvider.nbrWord = generateWalletProvider.getRandomInt(); diff --git a/lib/screens/onBoarding/6.dart b/lib/screens/onBoarding/6.dart index 6c22cb7..7915b21 100644 --- a/lib/screens/onBoarding/6.dart +++ b/lib/screens/onBoarding/6.dart @@ -148,8 +148,9 @@ Widget nextButton(BuildContext context, String text, nextScreen, bool isFast) { child: ElevatedButton( key: keyGoNext, style: ElevatedButton.styleFrom( - foregroundColor: Colors.white, elevation: 4, - backgroundColor: orangeC, // foreground + foregroundColor: Colors.white, + elevation: 4, + backgroundColor: orangeC, ), onPressed: () { Navigator.push( diff --git a/lib/screens/onBoarding/9.dart b/lib/screens/onBoarding/9.dart index 62e1037..0b3c9ad 100644 --- a/lib/screens/onBoarding/9.dart +++ b/lib/screens/onBoarding/9.dart @@ -81,8 +81,7 @@ class OnboardingStepNine extends StatelessWidget { style: ElevatedButton.styleFrom( foregroundColor: Colors.black, elevation: 4, - backgroundColor: - const Color(0xffFFD58D), // foreground + backgroundColor: const Color(0xffFFD58D), ), onPressed: () { generateWalletProvider.changePinCode( diff --git a/lib/screens/search.dart b/lib/screens/search.dart index 7b6ebb8..cc984c0 100644 --- a/lib/screens/search.dart +++ b/lib/screens/search.dart @@ -141,8 +141,9 @@ class _SearchScreenState extends State { child: ElevatedButton( key: keyConfirmSearch, style: ElevatedButton.styleFrom( - foregroundColor: Colors.white, elevation: 4, - backgroundColor: orangeC, // foreground + foregroundColor: Colors.white, + elevation: 4, + backgroundColor: orangeC, ), onPressed: canValidate ? () { diff --git a/lib/screens/search_result.dart b/lib/screens/search_result.dart index 267ebcf..3225c05 100644 --- a/lib/screens/search_result.dart +++ b/lib/screens/search_result.dart @@ -18,11 +18,11 @@ class SearchResultScreen extends StatelessWidget { @override Widget build(BuildContext context) { final searchProvider = Provider.of(context, listen: false); - WalletsProfilesProvider walletsProfilesClass = + final walletsProfilesClass = Provider.of(context, listen: false); final duniterIndexer = Provider.of(context, listen: false); - double avatarSize = scaleSize(37); + final avatarSize = scaleSize(37); return Scaffold( backgroundColor: backgroundColor, diff --git a/lib/screens/transaction_in_progress.dart b/lib/screens/transaction_in_progress.dart index ebfc7ea..1759117 100644 --- a/lib/screens/transaction_in_progress.dart +++ b/lib/screens/transaction_in_progress.dart @@ -1,95 +1,87 @@ -import 'package:easy_localization/easy_localization.dart'; -import 'package:gecko/globals.dart'; import 'package:flutter/material.dart'; +import 'package:gecko/globals.dart'; import 'package:gecko/models/scale_functions.dart'; import 'package:gecko/models/widgets_keys.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:easy_localization/easy_localization.dart'; class TransactionInProgress extends StatelessWidget { - const TransactionInProgress( - {Key? key, - this.transType = 'pay', - this.fromAddress, - this.toAddress, - this.toUsername}) - : super(key: key); + final String transactionId; final String transType; - final String? fromAddress; - final String? toAddress; - final String? toUsername; + final String? fromAddress, toAddress, toUsername; + + const TransactionInProgress({ + Key? key, + required this.transactionId, + this.transType = 'pay', + this.fromAddress, + this.toAddress, + this.toUsername, + }) : super(key: key); @override Widget build(BuildContext context) { final sub = Provider.of(context, listen: true); - final walletProfiles = - Provider.of(context, listen: false); - final myWalletProvider = - Provider.of(context, listen: false); - var txStatus = TransactionStatus.none; - final result = sub.transactionStatus; - final from = fromAddress ?? - g1WalletsBox - .get(myWalletProvider.getDefaultWallet().address) - ?.username ?? - myWalletProvider.getDefaultWallet().name!; + final transactionDetails = TransactionDetails( + transactionId: transactionId, + fromAddress: fromAddress, + toAddress: toAddress, + toUsername: toUsername, + sub: sub, + transType: transType, + ); - String to = toAddress ?? walletProfiles.address; - to = - myWalletProvider.getWalletDataByAddress(to)?.name ?? getShortPubkey(to); - - final amount = walletProfiles.payAmount.text; - final bool isUdUnit = configBox.get('isUdUnit') ?? false; - - final Map actionMap = { - 'pay': 'transaction'.tr(), - 'cert': 'certification'.tr(), - 'comfirmIdty': 'identityConfirm'.tr(), - 'revokeIdty': 'revokeAdhesion'.tr(), - 'identityMigration': 'identityMigration'.tr(), - }; - - String resultText = ''; - final Map resultMap = { - 'sending': 'sending'.tr(), - 'Ready': 'propagating'.tr(), - 'Broadcast': 'validating'.tr(), - 'cert.NotRespectCertPeriod': '24hbetweenCerts'.tr(), - 'identity.CreatorNotAllowedToCreateIdty': '24hbetweenCerts'.tr(), - 'cert.CannotCertifySelf': 'canNotCertifySelf'.tr(), - 'identity.IdtyNameAlreadyExist': 'nameAlreadyExist'.tr(), - 'balances.KeepAlive': '2GDtoKeepAlive'.tr(), - '1010: Invalid Transaction: Inability to pay some fees , e.g. account balance too low': - 'youHaveToFeedThisAccountBeforeUsing'.tr(), - 'Token.FundsUnavailable': 'fundsUnavailable'.tr(), - 'Exception: timeout': 'execTimeoutOver'.tr(), - }; - - if (result == null) { - txStatus = TransactionStatus.none; - } else if (result.contains('blockHash: ')) { - txStatus = TransactionStatus.success; - resultText = 'extrinsicValidated' - .tr(args: [actionMap[transType] ?? 'strangeTransaction'.tr()]); - } else if (result.contains('Exception: ')) { - txStatus = TransactionStatus.failed; - resultText = "${"anErrorOccurred".tr()}:\n"; - final String exception = result.split('Exception: ')[1]; - resultText = resultMap[exception] ?? "$resultText\n$exception"; - log.e('Error: $exception'); - } else { - txStatus = TransactionStatus.loading; - resultText = resultMap[result] ?? 'unknown status...'; + Widget getTransactionStatusIcon(TransactionDetails details) { + switch (details.txStatus) { + case TransactionStatus.loading: + return ScaledSizedBox( + height: 17, + width: 17, + child: const CircularProgressIndicator( + color: orangeC, + strokeWidth: 2, + ), + ); + case TransactionStatus.success: + return Icon( + Icons.done_all, + size: scaleSize(32), + color: Colors.greenAccent, + ); + case TransactionStatus.failed: + return Icon( + Icons.close, + size: scaleSize(32), + color: Colors.redAccent, + ); + case TransactionStatus.none: + default: + return const SizedBox.shrink(); + } } - log.d("$transType :: ${actionMap[transType]} :: $result"); + Widget buildTransactionStatus(TransactionDetails details) { + return Column( + children: [ + getTransactionStatusIcon(details), + ScaledSizedBox(height: 7), + if (details.txStatus != TransactionStatus.none) + Text( + transactionDetails.resultText, + textAlign: TextAlign.center, + style: scaledTextStyle(fontSize: 17), + ) + ], + ); + } return PopScope( onPopInvoked: (_) { - sub.transactionStatus = null; + sub.resetTransactionStatus(); }, child: Scaffold( backgroundColor: backgroundColor, @@ -102,138 +94,105 @@ class TransactionInProgress extends StatelessWidget { children: [ Text( 'extrinsicInProgress'.tr(args: [ - actionMap[transType] ?? 'strangeTransaction'.tr() + transactionDetails.actionMap[transType] ?? + 'strangeTransaction'.tr() ]), style: scaledTextStyle(fontSize: 20), ) ])), body: SafeArea( child: Align( - alignment: FractionalOffset.bottomCenter, - child: Column(children: [ - Container( - width: double.infinity, - decoration: const BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - yellowC, - backgroundColor, - ], - )), - child: Column(children: [ - ScaledSizedBox(height: 10), - if (transType == 'pay') - Text( - isUdUnit - ? 'ud'.tr(args: ['$amount ']) - : '$amount $currencyName', - textAlign: TextAlign.center, - style: scaledTextStyle( - fontSize: 17, fontWeight: FontWeight.w500), - ), - if (transType == 'pay') ScaledSizedBox(height: 10), + alignment: FractionalOffset.bottomCenter, + child: Column(children: [ + Container( + width: double.infinity, + decoration: const BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + yellowC, + backgroundColor, + ], + )), + child: Column(children: [ + ScaledSizedBox(height: 10), + if (transType == 'pay') Text( - 'fromMinus'.tr(), - textAlign: TextAlign.center, - style: scaledTextStyle(fontSize: 16), - ), - Text( - from, + transactionDetails.isUdUnit + ? 'ud'.tr(args: ['${transactionDetails.amount} ']) + : '${transactionDetails.amount} $currencyName', textAlign: TextAlign.center, style: scaledTextStyle( fontSize: 17, fontWeight: FontWeight.w500), ), - Visibility( - visible: from != to, - child: Column( - children: [ - ScaledSizedBox(height: 10), - Text( - 'toMinus'.tr(), - textAlign: TextAlign.center, - style: scaledTextStyle(fontSize: 16), - ), - Text( - toUsername ?? to, - textAlign: TextAlign.center, - style: scaledTextStyle( - fontSize: 17, fontWeight: FontWeight.w500), - ), - ], - ), - ), - ScaledSizedBox(height: 20), - ]), - ), - const Spacer(), - Column(children: [ - Visibility( - visible: txStatus == TransactionStatus.loading, - child: ScaledSizedBox( - height: 17, - width: 17, - child: const CircularProgressIndicator( - color: orangeC, - strokeWidth: 2, - ), - ), + if (transType == 'pay') ScaledSizedBox(height: 10), + Text( + 'fromMinus'.tr(), + textAlign: TextAlign.center, + style: scaledTextStyle(fontSize: 16), + ), + Text( + transactionDetails.fromAddress!, + textAlign: TextAlign.center, + style: scaledTextStyle( + fontSize: 17, fontWeight: FontWeight.w500), ), Visibility( - visible: txStatus == TransactionStatus.success, - child: Icon( - Icons.done_all, - size: scaleSize(32), - color: Colors.greenAccent, - ), - ), - Visibility( - visible: txStatus == TransactionStatus.failed, - child: Icon( - Icons.close, - size: scaleSize(32), - color: Colors.redAccent, - ), - ), - ScaledSizedBox(height: 10), - Visibility( - visible: txStatus != TransactionStatus.none, - child: Text( - resultText, - textAlign: TextAlign.center, - style: scaledTextStyle(fontSize: 17), - ), - ), - ]), - const Spacer(), - Expanded( - child: Align( - alignment: Alignment.bottomCenter, - child: ScaledSizedBox( - width: 300, - height: 55, - child: ElevatedButton( - key: keyCloseTransactionScreen, - style: ElevatedButton.styleFrom( - foregroundColor: Colors.white, elevation: 4, - backgroundColor: orangeC, // foreground + visible: transactionDetails.fromAddress != + transactionDetails.toAddress, + child: Column( + children: [ + ScaledSizedBox(height: 10), + Text( + 'toMinus'.tr(), + textAlign: TextAlign.center, + style: scaledTextStyle(fontSize: 16), ), - onPressed: () { - sub.transactionStatus = null; - Navigator.pop(context); - }, - child: Text( - 'close'.tr(), + Text( + transactionDetails.toUsername!, + textAlign: TextAlign.center, style: scaledTextStyle( - fontSize: 20, fontWeight: FontWeight.w600), + fontSize: 17, fontWeight: FontWeight.w500), ), + ], + ), + ), + ScaledSizedBox(height: 20), + ]), + ), + const Spacer(), + buildTransactionStatus(transactionDetails), + const Spacer(), + Expanded( + child: Align( + alignment: Alignment.bottomCenter, + child: ScaledSizedBox( + width: 300, + height: 55, + child: ElevatedButton( + key: keyCloseTransactionScreen, + style: ElevatedButton.styleFrom( + foregroundColor: Colors.white, + elevation: 4, + backgroundColor: orangeC, + ), + onPressed: () { + sub.resetTransactionStatus(); + Navigator.pop(context); + }, + child: Text( + 'close'.tr(), + style: scaledTextStyle( + fontSize: 20, fontWeight: FontWeight.w600), ), ), ), ), - ScaledSizedBox(height: 80) - ])), + ), + ScaledSizedBox(height: 80) + ]), + ), ), ), ); @@ -241,3 +200,82 @@ class TransactionInProgress extends StatelessWidget { } enum TransactionStatus { loading, failed, success, none } + +class TransactionDetails { + String? fromAddress, toAddress, toUsername, amount; + bool isUdUnit = false; + String resultText = ''; + TransactionStatus txStatus = TransactionStatus.none; + + Map actionMap = { + 'pay': 'transaction'.tr(), + 'cert': 'certification'.tr(), + 'comfirmIdty': 'identityConfirm'.tr(), + 'revokeIdty': 'revokeAdhesion'.tr(), + 'identityMigration': 'identityMigration'.tr(), + }; + + Map resultMap = { + 'sending': 'sending'.tr(), + 'Ready': 'propagating'.tr(), + 'Broadcast': 'validating'.tr(), + 'cert.NotRespectCertPeriod': '24hbetweenCerts'.tr(), + 'identity.CreatorNotAllowedToCreateIdty': '24hbetweenCerts'.tr(), + 'cert.CannotCertifySelf': 'canNotCertifySelf'.tr(), + 'identity.IdtyNameAlreadyExist': 'nameAlreadyExist'.tr(), + 'balances.KeepAlive': '2GDtoKeepAlive'.tr(), + '1010: Invalid Transaction: Inability to pay some fees , e.g. account balance too low': + 'youHaveToFeedThisAccountBeforeUsing'.tr(), + 'Token.FundsUnavailable': 'fundsUnavailable'.tr(), + 'Exception: timeout': 'execTimeoutOver'.tr(), + }; + + TransactionDetails({ + required transactionId, + required this.fromAddress, + required this.toAddress, + required this.toUsername, + required SubstrateSdk sub, + required String transType, + }) { + final walletProfiles = + Provider.of(homeContext, listen: false); + final myWalletProvider = + Provider.of(homeContext, listen: false); + String defaultWalletAddress = myWalletProvider.getDefaultWallet().address; + String defaultWalletName = myWalletProvider.getDefaultWallet().name!; + String? walletDataName = + myWalletProvider.getWalletDataByAddress(toAddress ?? '')?.name; + + fromAddress = fromAddress ?? + g1WalletsBox.get(defaultWalletAddress)?.username ?? + defaultWalletName; + toAddress = toAddress ?? walletProfiles.address; + toUsername = toUsername ?? walletDataName ?? getShortPubkey(toAddress!); + + amount = walletProfiles.payAmount.text; + isUdUnit = configBox.get('isUdUnit') ?? false; + + if (sub.transactionStatus.containsKey(transactionId)) { + calculateTransactionStatus( + sub.transactionStatus[transactionId], transType); + } + } + + void calculateTransactionStatus(String? result, String transType) { + if (result == null) { + txStatus = TransactionStatus.none; + } else if (result.contains('blockHash: ')) { + txStatus = TransactionStatus.success; + resultText = 'extrinsicValidated' + .tr(args: [actionMap[transType] ?? 'strangeTransaction']); + } else if (result.contains('Exception: ')) { + txStatus = TransactionStatus.failed; + String exception = result.split('Exception: ')[1]; + resultText = resultMap[exception] ?? exception; + } else { + txStatus = TransactionStatus.loading; + resultText = resultMap[result] ?? 'Unknown status: $result'; + } + } +} diff --git a/lib/screens/wallet_view.dart b/lib/screens/wallet_view.dart index 35895b5..a2339bc 100644 --- a/lib/screens/wallet_view.dart +++ b/lib/screens/wallet_view.dart @@ -151,7 +151,7 @@ class WalletViewScreen extends StatelessWidget { return FutureBuilder( future: sub.certState(defaultWallet.address, address), builder: (context, AsyncSnapshot> snapshot) { - if (snapshot.data == null) return ScaledSizedBox(); + if (snapshot.data == null) return const SizedBox.shrink(); String duration = ''; if (snapshot.data!['certDelay'] != null || @@ -209,55 +209,53 @@ class WalletViewScreen extends StatelessWidget { 'assets/gecko_certify.png')), ), onTap: () async { - final bool? result = + final result = await confirmPopupCertification( - context, - 'areYouSureYouWantToCertify1' - .tr(), - duniterIndexer - .walletNameIndexer[ - address] ?? - "noIdentity".tr(), - 'areYouSureYouWantToCertify2' - .tr(), - getShortPubkey(address)); + context, + 'areYouSureYouWantToCertify1' + .tr(), + duniterIndexer + .walletNameIndexer[ + address] ?? + "noIdentity".tr(), + 'areYouSureYouWantToCertify2' + .tr(), + getShortPubkey(address)) ?? + false; - if (result ?? false) { - String? pin; - if (myWalletProvider.pinCode == '') { - pin = await Navigator.push( - context, - MaterialPageRoute( - builder: (homeContext) { - return UnlockingWallet( - wallet: defaultWallet); - }, - ), - ); - } - if (pin != null || - myWalletProvider.pinCode != '') { - WalletsProfilesProvider - walletViewProvider = Provider - .of( - context, - listen: false); - final acc = sub.getCurrentWallet(); - sub.certify( - acc.address!, - walletViewProvider.address, - pin ?? - myWalletProvider.pinCode); - Navigator.push( - context, - MaterialPageRoute( - builder: (context) { - return const TransactionInProgress( - transType: 'cert'); - }), - ); - } + if (!result) return; + if (myWalletProvider.pinCode == '') { + await Navigator.push( + context, + MaterialPageRoute( + builder: (homeContext) { + return UnlockingWallet( + wallet: defaultWallet); + }, + ), + ); } + if (myWalletProvider.pinCode == '') { + return; + } + WalletsProfilesProvider + walletViewProvider = Provider.of< + WalletsProfilesProvider>( + context, + listen: false); + final acc = sub.getCurrentWallet(); + final transactionId = await sub.certify( + acc.address!, + walletViewProvider.address, + myWalletProvider.pinCode); + Navigator.push( + context, + MaterialPageRoute(builder: (context) { + return TransactionInProgress( + transactionId: transactionId, + transType: 'cert'); + }), + ); }), ), ), diff --git a/lib/widgets/commons/next_button.dart b/lib/widgets/commons/next_button.dart index c838715..dd31354 100644 --- a/lib/widgets/commons/next_button.dart +++ b/lib/widgets/commons/next_button.dart @@ -24,8 +24,9 @@ class NextButton extends StatelessWidget { child: ElevatedButton( key: keyGoNext, style: ElevatedButton.styleFrom( - foregroundColor: Colors.white, backgroundColor: orangeC, - elevation: 4, // foreground + foregroundColor: Colors.white, + backgroundColor: orangeC, + elevation: 4, ), onPressed: () { Navigator.push( diff --git a/lib/widgets/payment_popup.dart b/lib/widgets/payment_popup.dart index eb62d7d..3945cac 100644 --- a/lib/widgets/payment_popup.dart +++ b/lib/widgets/payment_popup.dart @@ -33,9 +33,8 @@ void paymentPopup(BuildContext context, String toAddress, String? username) { walletViewProvider.payAmount.text = ''; Future executeTransfert() async { - String? pin; if (myWalletProvider.pinCode == '') { - pin = await Navigator.push( + await Navigator.push( context, MaterialPageRoute( builder: (homeContext) { @@ -44,25 +43,26 @@ void paymentPopup(BuildContext context, String toAddress, String? username) { ), ); } - if (pin != null || myWalletProvider.pinCode != '') { - // Payment workflow ! - final sub = Provider.of(context, listen: false); - final acc = sub.getCurrentWallet(); - log.d( - "fromAddress: ${acc.address!},destAddress: $toAddress, amount: ${double.parse(walletViewProvider.payAmount.text)}"); - sub.pay( - fromAddress: acc.address!, - destAddress: toAddress, - amount: double.parse(walletViewProvider.payAmount.text), - password: pin ?? myWalletProvider.pinCode); - Navigator.push( - context, - MaterialPageRoute(builder: (context) { - return TransactionInProgress( - toAddress: toAddress, toUsername: username); - }), - ); - } + if (myWalletProvider.pinCode == '') return; + // Payment workflow ! + final sub = Provider.of(context, listen: false); + final acc = sub.getCurrentWallet(); + log.d( + "fromAddress: ${acc.address!},destAddress: $toAddress, amount: ${double.parse(walletViewProvider.payAmount.text)}"); + final transactionId = await sub.pay( + fromAddress: acc.address!, + destAddress: toAddress, + amount: double.parse(walletViewProvider.payAmount.text), + password: myWalletProvider.pinCode); + Navigator.push( + context, + MaterialPageRoute(builder: (context) { + return TransactionInProgress( + transactionId: transactionId, + toAddress: toAddress, + toUsername: username); + }), + ); } myWalletProvider.readAllWallets().then((value) => myWalletProvider.listWallets diff --git a/pubspec.lock b/pubspec.lock index 0d11032..47cfba9 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1660,7 +1660,7 @@ packages: source: hosted version: "3.1.0" uuid: - dependency: transitive + dependency: "direct main" description: name: uuid sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313" diff --git a/pubspec.yaml b/pubspec.yaml index 99dedd3..af9647f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -61,6 +61,7 @@ dependencies: url_launcher: ^6.1.11 crypto: ^3.0.3 screen_brightness: ^0.2.2+1 + uuid: ^3.0.7 dev_dependencies: # flutter_launcher_icons: ^0.9.2