enh: refactor Transacation in progress screen with uuid per transaction

This commit is contained in:
poka 2024-01-03 20:26:11 +01:00
parent 8ca0b00a60
commit 007d62054b
22 changed files with 430 additions and 368 deletions

View File

@ -1,7 +1,6 @@
// ignore_for_file: use_build_context_synchronously, body_might_complete_normally_catch_error // ignore_for_file: use_build_context_synchronously, body_might_complete_normally_catch_error
import 'dart:convert'; import 'dart:convert';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:fast_base58/fast_base58.dart'; import 'package:fast_base58/fast_base58.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
@ -26,6 +25,7 @@ import 'package:provider/provider.dart';
import 'package:truncate/truncate.dart'; import 'package:truncate/truncate.dart';
import 'package:pointycastle/pointycastle.dart' as pc; import 'package:pointycastle/pointycastle.dart' as pc;
import "package:hex/hex.dart"; import "package:hex/hex.dart";
import 'package:uuid/uuid.dart' show Uuid;
class SubstrateSdk with ChangeNotifier { class SubstrateSdk with ChangeNotifier {
final WalletSDK sdk = WalletSDK(); final WalletSDK sdk = WalletSDK();
@ -37,8 +37,8 @@ class SubstrateSdk with ChangeNotifier {
bool importIsLoading = false; bool importIsLoading = false;
int blocNumber = 0; int blocNumber = 0;
bool isLoadingEndpoint = false; bool isLoadingEndpoint = false;
String? transactionStatus; Map transactionStatus = {};
final int initSs58 = 42; static const int initSs58 = 42;
Map<String, int> currencyParameters = {}; Map<String, int> currencyParameters = {};
final csSalt = TextEditingController(); final csSalt = TextEditingController();
final csPassword = TextEditingController(); final csPassword = TextEditingController();
@ -52,18 +52,23 @@ class SubstrateSdk with ChangeNotifier {
///////////////////////////////////// /////////////////////////////////////
////////// 1: API METHODS /////////// ////////// 1: API METHODS ///////////
/////////////////////////////////////3 /////////////////////////////////////
Future<String> _executeCall(TxInfoData txInfo, txOptions, String password, Future<String> _executeCall(String currentTransactionId, TxInfoData txInfo,
txOptions, String password,
[String? rawParams]) async { [String? rawParams]) async {
final walletOptions = final walletOptions =
Provider.of<WalletOptionsProvider>(homeContext, listen: false); Provider.of<WalletOptionsProvider>(homeContext, listen: false);
final walletProfiles = final walletProfiles =
Provider.of<WalletsProfilesProvider>(homeContext, listen: false); Provider.of<WalletsProfilesProvider>(homeContext, listen: false);
transactionStatus.putIfAbsent(currentTransactionId, () => 'sending');
notifyListeners();
try { try {
final hash = await sdk.api.tx.signAndSend(txInfo, txOptions, password, final hash = await sdk.api.tx.signAndSend(txInfo, txOptions, password,
rawParam: rawParams, onStatusChange: (p0) { rawParam: rawParams, onStatusChange: (p0) {
transactionStatus = p0; transactionStatus.update(currentTransactionId, (_) => p0,
ifAbsent: () => p0);
notifyListeners(); notifyListeners();
}).timeout( }).timeout(
const Duration(seconds: 18), const Duration(seconds: 18),
@ -71,20 +76,23 @@ class SubstrateSdk with ChangeNotifier {
); );
log.d(hash); log.d(hash);
if (hash.isEmpty) { if (hash.isEmpty) {
transactionStatus = 'Exception: timeout'; transactionStatus.update(
currentTransactionId, (_) => 'Exception: timeout');
notifyListeners(); notifyListeners();
return 'Exception: timeout'; return 'Exception: timeout';
} else { } else {
// Success ! // Success !
transactionStatus = hash.toString(); transactionStatus.update(currentTransactionId, (_) => hash.toString(),
ifAbsent: () => hash.toString());
notifyListeners(); notifyListeners();
walletOptions.reload(); walletOptions.reload();
walletProfiles.reload(); walletProfiles.reload();
return hash.toString(); return hash.toString();
} }
} catch (e) { } catch (e) {
transactionStatus = e.toString(); transactionStatus.update(currentTransactionId, (_) => e.toString(),
ifAbsent: () => e.toString());
notifyListeners(); notifyListeners();
return e.toString(); return e.toString();
} }
@ -909,8 +917,6 @@ class SubstrateSdk with ChangeNotifier {
required String destAddress, required String destAddress,
required double amount, required double amount,
required String password}) async { required String password}) async {
transactionStatus = 'sending';
final sender = await _setSender(fromAddress); final sender = await _setSender(fromAddress);
final globalBalance = await getBalance(fromAddress); final globalBalance = await getBalance(fromAddress);
@ -956,13 +962,13 @@ class SubstrateSdk with ChangeNotifier {
rawParams = '[[$tx1, $tx2]]'; rawParams = '[[$tx1, $tx2]]';
} }
return await _executeCall(txInfo, txOptions, password, rawParams); final transactionId = const Uuid().v4();
_executeCall(transactionId, txInfo, txOptions, password, rawParams);
return transactionId;
} }
Future<String> certify( Future<String> certify(
String fromAddress, String destAddress, String password) async { String fromAddress, String destAddress, String password) async {
transactionStatus = 'sending';
final statusList = await idtyStatus([fromAddress, destAddress]); final statusList = await idtyStatus([fromAddress, destAddress]);
final myIdtyStatus = statusList[0]; final myIdtyStatus = statusList[0];
final toIdtyStatus = statusList[1]; final toIdtyStatus = statusList[1];
@ -973,8 +979,6 @@ class SubstrateSdk with ChangeNotifier {
final toIndex = idtyIndexList[1]; final toIndex = idtyIndexList[1];
if (myIdtyStatus != IdtyStatus.validated) { if (myIdtyStatus != IdtyStatus.validated) {
transactionStatus = 'notMember';
notifyListeners();
return 'notMember'; return 'notMember';
} }
@ -1022,18 +1026,17 @@ class SubstrateSdk with ChangeNotifier {
txOptions = [fromIndex, toIndex]; txOptions = [fromIndex, toIndex];
} }
} else { } else {
transactionStatus = 'cantBeCert';
notifyListeners();
return 'cantBeCert'; return 'cantBeCert';
} }
log.d('Cert action: ${txInfo.call!}'); 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<String> confirmIdentity( Future<String> confirmIdentity(
String fromAddress, String name, String password) async { String fromAddress, String name, String password) async {
transactionStatus = 'sending';
final sender = await _setSender(fromAddress); final sender = await _setSender(fromAddress);
final txInfo = TxInfoData( final txInfo = TxInfoData(
@ -1043,7 +1046,11 @@ class SubstrateSdk with ChangeNotifier {
); );
final txOptions = [name]; final txOptions = [name];
return await _executeCall(txInfo, txOptions, password); final transactionId = const Uuid().v4();
_executeCall(transactionId, txInfo, txOptions, password);
return transactionId;
} }
Future<String> migrateIdentity( Future<String> migrateIdentity(
@ -1053,7 +1060,6 @@ class SubstrateSdk with ChangeNotifier {
required String destPassword, required String destPassword,
required Map fromBalance, required Map fromBalance,
bool withBalance = false}) async { bool withBalance = false}) async {
transactionStatus = 'sending';
final sender = await _setSender(fromAddress); final sender = await _setSender(fromAddress);
TxInfoData txInfo; TxInfoData txInfo;
@ -1111,7 +1117,9 @@ newKeySig: $newKeySigType""");
txOptions = [destAddress, 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 { Future revokeIdentity(String address, String password) async {
@ -1135,10 +1143,12 @@ newKeySig: $newKeySigType""");
); );
final txOptions = [idtyIndex, address, revocationSigTyped]; 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<String> migrateCsToV2(String salt, String password, String destAddress,
{required destPassword, {required destPassword,
required Map balance, required Map balance,
IdtyStatus idtyStatus = IdtyStatus.none}) async { IdtyStatus idtyStatus = IdtyStatus.none}) async {
@ -1171,8 +1181,10 @@ newKeySig: $newKeySigType""");
password: password, password: password,
); );
late String transactionId;
if (idtyStatus != IdtyStatus.none) { if (idtyStatus != IdtyStatus.none) {
await migrateIdentity( transactionId = await migrateIdentity(
fromAddress: keypair.address!, fromAddress: keypair.address!,
destAddress: destAddress, destAddress: destAddress,
fromPassword: 'password', fromPassword: 'password',
@ -1180,14 +1192,17 @@ newKeySig: $newKeySigType""");
withBalance: true, withBalance: true,
fromBalance: balance); fromBalance: balance);
} else if (balance['transferableBalance'] != 0) { } else if (balance['transferableBalance'] != 0) {
await pay( transactionId = await pay(
fromAddress: keypair.address!, fromAddress: keypair.address!,
destAddress: destAddress, destAddress: destAddress,
amount: -1, amount: -1,
password: 'password'); password: 'password');
} else {
transactionId = '';
} }
await sdk.api.keyring.deleteAccount(keyring, keypair); await sdk.api.keyring.deleteAccount(keyring, keypair);
return transactionId;
} }
Future spawnBlock([int number = 1, int until = 0]) async { Future spawnBlock([int number = 1, int until = 0]) async {
@ -1204,6 +1219,10 @@ newKeySig: $newKeySigType""");
void reload() { void reload() {
notifyListeners(); notifyListeners();
} }
void resetTransactionStatus() {
transactionStatus.clear();
}
} }
//////////////////////////////////////////// ////////////////////////////////////////////

View File

@ -217,14 +217,17 @@ class WalletOptionsProvider with ChangeNotifier {
final wallet = myWalletProvider final wallet = myWalletProvider
.getWalletDataByAddress(address.text); .getWalletDataByAddress(address.text);
await sub.setCurrentWallet(wallet!); await sub.setCurrentWallet(wallet!);
sub.confirmIdentity(walletOptions.address.text, final transactionId = await sub.confirmIdentity(
idtyName.text, myWalletProvider.pinCode); walletOptions.address.text,
idtyName.text,
myWalletProvider.pinCode);
Navigator.pop(context); Navigator.pop(context);
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute(builder: (context) { MaterialPageRoute(builder: (context) {
return TransactionInProgress( return TransactionInProgress(
transactionId: transactionId,
transType: 'comfirmIdty', transType: 'comfirmIdty',
fromAddress: fromAddress:
getShortPubkey(wallet.address), getShortPubkey(wallet.address),

View File

@ -39,8 +39,9 @@ class DebugScreen extends StatelessWidget {
width: 250, width: 250,
child: ElevatedButton( child: ElevatedButton(
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
foregroundColor: Colors.white, elevation: 4, foregroundColor: Colors.white,
backgroundColor: orangeC, // foreground elevation: 4,
backgroundColor: orangeC,
), ),
onPressed: () async => await sub.spawnBlock(), onPressed: () async => await sub.spawnBlock(),
child: const Text( child: const Text(

View File

@ -322,8 +322,9 @@ Widget welcomeHome(context) {
child: ElevatedButton( child: ElevatedButton(
key: keyOnboardingNewChest, key: keyOnboardingNewChest,
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
foregroundColor: Colors.white, elevation: 4, foregroundColor: Colors.white,
backgroundColor: orangeC, // foreground elevation: 4,
backgroundColor: orangeC,
), ),
onPressed: () { onPressed: () {
Navigator.push( Navigator.push(

View File

@ -93,8 +93,9 @@ class _ChangePinScreenState extends State<ChangePinScreen> {
height: 50, height: 50,
child: ElevatedButton( child: ElevatedButton(
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
foregroundColor: Colors.black, elevation: 12, foregroundColor: Colors.black,
backgroundColor: Colors.green[400], // foreground elevation: 12,
backgroundColor: Colors.green[400],
), ),
onPressed: () async { onPressed: () async {
WalletData defaultWallet = WalletData defaultWallet =

View File

@ -106,7 +106,7 @@ class _ChooseChestState extends State<ChooseChest> {
child: ElevatedButton( child: ElevatedButton(
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
foregroundColor: Colors.black, foregroundColor: Colors.black,
backgroundColor: orangeC, // foreground backgroundColor: orangeC,
), ),
onPressed: () async { onPressed: () async {
await configBox.put('currentChest', currentChest); await configBox.put('currentChest', currentChest);

View File

@ -22,6 +22,7 @@ import 'package:provider/provider.dart';
class ImportG1v1 extends StatelessWidget { class ImportG1v1 extends StatelessWidget {
const ImportG1v1({Key? key}) : super(key: key); const ImportG1v1({Key? key}) : super(key: key);
static const int debouneTime = 600;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -29,7 +30,6 @@ class ImportG1v1 extends StatelessWidget {
Provider.of<MyWalletsProvider>(context, listen: false); Provider.of<MyWalletsProvider>(context, listen: false);
Timer? debounce; Timer? debounce;
const int debouneTime = 600;
WalletData selectedWallet = myWalletProvider.getDefaultWallet(); WalletData selectedWallet = myWalletProvider.getDefaultWallet();
bool canValidate = false; bool canValidate = false;
String validationStatus = ''; String validationStatus = '';
@ -297,8 +297,10 @@ class ImportG1v1 extends StatelessWidget {
); );
} }
sub.migrateCsToV2(sub.csSalt.text, final transactionId = await sub.migrateCsToV2(
sub.csPassword.text, selectedWallet.address, sub.csSalt.text,
sub.csPassword.text,
selectedWallet.address,
destPassword: destPassword:
pin ?? myWalletProvider.pinCode, pin ?? myWalletProvider.pinCode,
balance: balance, balance: balance,
@ -308,6 +310,7 @@ class ImportG1v1 extends StatelessWidget {
context, context,
MaterialPageRoute(builder: (context) { MaterialPageRoute(builder: (context) {
return TransactionInProgress( return TransactionInProgress(
transactionId: transactionId,
transType: 'identityMigration', transType: 'identityMigration',
fromAddress: fromAddress:
getShortPubkey(sub.g1V1NewAddress), getShortPubkey(sub.g1V1NewAddress),

View File

@ -109,38 +109,41 @@ class ManageMembership extends StatelessWidget {
'Êtes-vous certains de vouloir révoquer définitivement cette identité ?') ?? 'Êtes-vous certains de vouloir révoquer définitivement cette identité ?') ??
false; false;
if (answer) { if (!answer) return;
final myWalletProvider = final myWalletProvider =
Provider.of<MyWalletsProvider>(context, listen: false); Provider.of<MyWalletsProvider>(context, listen: false);
final sub = Provider.of<SubstrateSdk>(context, listen: false); final sub = Provider.of<SubstrateSdk>(context, listen: false);
WalletData? defaultWallet = myWalletProvider.getDefaultWallet(); WalletData? defaultWallet = myWalletProvider.getDefaultWallet();
String? pin; String? pin;
if (myWalletProvider.pinCode == '') { if (myWalletProvider.pinCode == '') {
pin = await Navigator.push( 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(
context, context,
MaterialPageRoute(builder: (context) { MaterialPageRoute(
return TransactionInProgress( builder: (homeContext) {
transType: 'revokeIdty', return UnlockingWallet(wallet: defaultWallet);
fromAddress: getShortPubkey(address), },
toAddress: getShortPubkey(address)); ),
}),
); );
} }
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( child: ScaledSizedBox(
height: 55, height: 55,

View File

@ -190,28 +190,25 @@ class MigrateIdentityScreen extends StatelessWidget {
); );
} }
if (myWalletProvider.pinCode != '') { if (myWalletProvider.pinCode == '') return;
sub.migrateIdentity( final transactionId = await sub.migrateIdentity(
fromAddress: fromAddress, fromAddress: fromAddress,
destAddress: selectedWallet.address, destAddress: selectedWallet.address,
fromPassword: fromPassword: pin ?? myWalletProvider.pinCode,
pin ?? myWalletProvider.pinCode, destPassword: pin ?? myWalletProvider.pinCode,
destPassword: withBalance: true,
pin ?? myWalletProvider.pinCode, fromBalance: balance);
withBalance: true, Navigator.push(
fromBalance: balance); context,
Navigator.push( MaterialPageRoute(builder: (context) {
context, return TransactionInProgress(
MaterialPageRoute(builder: (context) { transactionId: transactionId,
return TransactionInProgress( transType: 'identityMigration',
transType: 'identityMigration', fromAddress: getShortPubkey(fromAddress),
fromAddress: toAddress: getShortPubkey(
getShortPubkey(fromAddress), selectedWallet.address));
toAddress: getShortPubkey( }),
selectedWallet.address)); );
}),
);
}
} }
: null, : null,
child: Text( child: Text(

View File

@ -84,8 +84,9 @@ class RestoreChest extends StatelessWidget {
child: ElevatedButton( child: ElevatedButton(
key: keyGoNext, key: keyGoNext,
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
foregroundColor: Colors.white, elevation: 4, foregroundColor: Colors.white,
backgroundColor: orangeC, // foreground elevation: 4,
backgroundColor: orangeC,
), ),
onPressed: () async { onPressed: () async {
if (await sub if (await sub
@ -125,8 +126,9 @@ class RestoreChest extends StatelessWidget {
child: ElevatedButton( child: ElevatedButton(
key: keyPastMnemonic, key: keyPastMnemonic,
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
foregroundColor: Colors.black, elevation: 4, foregroundColor: Colors.black,
backgroundColor: yellowC, // foreground elevation: 4,
backgroundColor: yellowC,
), ),
onPressed: () { onPressed: () {
genW.pasteMnemonic(context); genW.pasteMnemonic(context);

View File

@ -239,9 +239,7 @@ class WalletOptions extends StatelessWidget {
if (!walletProvider.isDefaultWallet && if (!walletProvider.isDefaultWallet &&
!wallet.isMembre()) !wallet.isMembre())
deleteWallet( deleteWallet(
context, walletProvider, currentChest) context, walletProvider, currentChest),
else
ScaledSizedBox(),
if (wallet.isMembre()) if (wallet.isMembre())
const ManageMembershipButton() const ManageMembershipButton()
]) ])
@ -327,16 +325,10 @@ class WalletOptions extends StatelessWidget {
key: keyConfirmIdentity, key: keyConfirmIdentity,
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
foregroundColor: Colors.white, elevation: 4, foregroundColor: Colors.white, elevation: 4,
backgroundColor: orangeC, // foreground backgroundColor: orangeC,
), ),
onPressed: () async { onPressed: () {
walletProvider.confirmIdentityPopup(context); walletProvider.confirmIdentityPopup(context);
// Navigator.push(
// context,
// MaterialPageRoute(builder: (context) {
// return const SearchResultScreen();
// }),
// );
}, },
child: Text( child: Text(
'confirmMyIdentity'.tr(), 'confirmMyIdentity'.tr(),

View File

@ -221,8 +221,9 @@ Widget nextButton(
child: ElevatedButton( child: ElevatedButton(
key: keyGoNext, key: keyGoNext,
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
foregroundColor: Colors.white, elevation: 4, foregroundColor: Colors.white,
backgroundColor: orangeC, // foreground elevation: 4,
backgroundColor: orangeC,
), ),
onPressed: () { onPressed: () {
generateWalletProvider.nbrWord = generateWalletProvider.getRandomInt(); generateWalletProvider.nbrWord = generateWalletProvider.getRandomInt();

View File

@ -148,8 +148,9 @@ Widget nextButton(BuildContext context, String text, nextScreen, bool isFast) {
child: ElevatedButton( child: ElevatedButton(
key: keyGoNext, key: keyGoNext,
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
foregroundColor: Colors.white, elevation: 4, foregroundColor: Colors.white,
backgroundColor: orangeC, // foreground elevation: 4,
backgroundColor: orangeC,
), ),
onPressed: () { onPressed: () {
Navigator.push( Navigator.push(

View File

@ -81,8 +81,7 @@ class OnboardingStepNine extends StatelessWidget {
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
foregroundColor: Colors.black, foregroundColor: Colors.black,
elevation: 4, elevation: 4,
backgroundColor: backgroundColor: const Color(0xffFFD58D),
const Color(0xffFFD58D), // foreground
), ),
onPressed: () { onPressed: () {
generateWalletProvider.changePinCode( generateWalletProvider.changePinCode(

View File

@ -141,8 +141,9 @@ class _SearchScreenState extends State<SearchScreen> {
child: ElevatedButton( child: ElevatedButton(
key: keyConfirmSearch, key: keyConfirmSearch,
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
foregroundColor: Colors.white, elevation: 4, foregroundColor: Colors.white,
backgroundColor: orangeC, // foreground elevation: 4,
backgroundColor: orangeC,
), ),
onPressed: canValidate onPressed: canValidate
? () { ? () {

View File

@ -18,11 +18,11 @@ class SearchResultScreen extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final searchProvider = Provider.of<SearchProvider>(context, listen: false); final searchProvider = Provider.of<SearchProvider>(context, listen: false);
WalletsProfilesProvider walletsProfilesClass = final walletsProfilesClass =
Provider.of<WalletsProfilesProvider>(context, listen: false); Provider.of<WalletsProfilesProvider>(context, listen: false);
final duniterIndexer = Provider.of<DuniterIndexer>(context, listen: false); final duniterIndexer = Provider.of<DuniterIndexer>(context, listen: false);
double avatarSize = scaleSize(37); final avatarSize = scaleSize(37);
return Scaffold( return Scaffold(
backgroundColor: backgroundColor, backgroundColor: backgroundColor,

View File

@ -1,95 +1,87 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:gecko/globals.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:gecko/globals.dart';
import 'package:gecko/models/scale_functions.dart'; import 'package:gecko/models/scale_functions.dart';
import 'package:gecko/models/widgets_keys.dart'; import 'package:gecko/models/widgets_keys.dart';
import 'package:gecko/providers/my_wallets.dart'; import 'package:gecko/providers/my_wallets.dart';
import 'package:gecko/providers/substrate_sdk.dart'; import 'package:gecko/providers/substrate_sdk.dart';
import 'package:gecko/providers/wallets_profiles.dart'; import 'package:gecko/providers/wallets_profiles.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:easy_localization/easy_localization.dart';
class TransactionInProgress extends StatelessWidget { class TransactionInProgress extends StatelessWidget {
const TransactionInProgress( final String transactionId;
{Key? key,
this.transType = 'pay',
this.fromAddress,
this.toAddress,
this.toUsername})
: super(key: key);
final String transType; final String transType;
final String? fromAddress; final String? fromAddress, toAddress, toUsername;
final String? toAddress;
final String? toUsername; const TransactionInProgress({
Key? key,
required this.transactionId,
this.transType = 'pay',
this.fromAddress,
this.toAddress,
this.toUsername,
}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final sub = Provider.of<SubstrateSdk>(context, listen: true); final sub = Provider.of<SubstrateSdk>(context, listen: true);
final walletProfiles =
Provider.of<WalletsProfilesProvider>(context, listen: false);
final myWalletProvider =
Provider.of<MyWalletsProvider>(context, listen: false);
var txStatus = TransactionStatus.none;
final result = sub.transactionStatus;
final from = fromAddress ?? final transactionDetails = TransactionDetails(
g1WalletsBox transactionId: transactionId,
.get(myWalletProvider.getDefaultWallet().address) fromAddress: fromAddress,
?.username ?? toAddress: toAddress,
myWalletProvider.getDefaultWallet().name!; toUsername: toUsername,
sub: sub,
transType: transType,
);
String to = toAddress ?? walletProfiles.address; Widget getTransactionStatusIcon(TransactionDetails details) {
to = switch (details.txStatus) {
myWalletProvider.getWalletDataByAddress(to)?.name ?? getShortPubkey(to); case TransactionStatus.loading:
return ScaledSizedBox(
final amount = walletProfiles.payAmount.text; height: 17,
final bool isUdUnit = configBox.get('isUdUnit') ?? false; width: 17,
child: const CircularProgressIndicator(
final Map<String, String> actionMap = { color: orangeC,
'pay': 'transaction'.tr(), strokeWidth: 2,
'cert': 'certification'.tr(), ),
'comfirmIdty': 'identityConfirm'.tr(), );
'revokeIdty': 'revokeAdhesion'.tr(), case TransactionStatus.success:
'identityMigration': 'identityMigration'.tr(), return Icon(
}; Icons.done_all,
size: scaleSize(32),
String resultText = ''; color: Colors.greenAccent,
final Map<String, String> resultMap = { );
'sending': 'sending'.tr(), case TransactionStatus.failed:
'Ready': 'propagating'.tr(), return Icon(
'Broadcast': 'validating'.tr(), Icons.close,
'cert.NotRespectCertPeriod': '24hbetweenCerts'.tr(), size: scaleSize(32),
'identity.CreatorNotAllowedToCreateIdty': '24hbetweenCerts'.tr(), color: Colors.redAccent,
'cert.CannotCertifySelf': 'canNotCertifySelf'.tr(), );
'identity.IdtyNameAlreadyExist': 'nameAlreadyExist'.tr(), case TransactionStatus.none:
'balances.KeepAlive': '2GDtoKeepAlive'.tr(), default:
'1010: Invalid Transaction: Inability to pay some fees , e.g. account balance too low': return const SizedBox.shrink();
'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...';
} }
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( return PopScope(
onPopInvoked: (_) { onPopInvoked: (_) {
sub.transactionStatus = null; sub.resetTransactionStatus();
}, },
child: Scaffold( child: Scaffold(
backgroundColor: backgroundColor, backgroundColor: backgroundColor,
@ -102,138 +94,105 @@ class TransactionInProgress extends StatelessWidget {
children: <Widget>[ children: <Widget>[
Text( Text(
'extrinsicInProgress'.tr(args: [ 'extrinsicInProgress'.tr(args: [
actionMap[transType] ?? 'strangeTransaction'.tr() transactionDetails.actionMap[transType] ??
'strangeTransaction'.tr()
]), ]),
style: scaledTextStyle(fontSize: 20), style: scaledTextStyle(fontSize: 20),
) )
])), ])),
body: SafeArea( body: SafeArea(
child: Align( child: Align(
alignment: FractionalOffset.bottomCenter, alignment: FractionalOffset.bottomCenter,
child: Column(children: <Widget>[ child: Column(children: <Widget>[
Container( Container(
width: double.infinity, width: double.infinity,
decoration: const BoxDecoration( decoration: const BoxDecoration(
gradient: LinearGradient( gradient: LinearGradient(
begin: Alignment.topCenter, begin: Alignment.topCenter,
end: Alignment.bottomCenter, end: Alignment.bottomCenter,
colors: [ colors: [
yellowC, yellowC,
backgroundColor, backgroundColor,
], ],
)), )),
child: Column(children: <Widget>[ child: Column(children: <Widget>[
ScaledSizedBox(height: 10), ScaledSizedBox(height: 10),
if (transType == 'pay') 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),
Text( Text(
'fromMinus'.tr(), transactionDetails.isUdUnit
textAlign: TextAlign.center, ? 'ud'.tr(args: ['${transactionDetails.amount} '])
style: scaledTextStyle(fontSize: 16), : '${transactionDetails.amount} $currencyName',
),
Text(
from,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: scaledTextStyle( style: scaledTextStyle(
fontSize: 17, fontWeight: FontWeight.w500), fontSize: 17, fontWeight: FontWeight.w500),
), ),
Visibility( if (transType == 'pay') ScaledSizedBox(height: 10),
visible: from != to, Text(
child: Column( 'fromMinus'.tr(),
children: [ textAlign: TextAlign.center,
ScaledSizedBox(height: 10), style: scaledTextStyle(fontSize: 16),
Text( ),
'toMinus'.tr(), Text(
textAlign: TextAlign.center, transactionDetails.fromAddress!,
style: scaledTextStyle(fontSize: 16), textAlign: TextAlign.center,
), style: scaledTextStyle(
Text( fontSize: 17, fontWeight: FontWeight.w500),
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,
),
),
), ),
Visibility( Visibility(
visible: txStatus == TransactionStatus.success, visible: transactionDetails.fromAddress !=
child: Icon( transactionDetails.toAddress,
Icons.done_all, child: Column(
size: scaleSize(32), children: [
color: Colors.greenAccent, ScaledSizedBox(height: 10),
), Text(
), 'toMinus'.tr(),
Visibility( textAlign: TextAlign.center,
visible: txStatus == TransactionStatus.failed, style: scaledTextStyle(fontSize: 16),
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
), ),
onPressed: () { Text(
sub.transactionStatus = null; transactionDetails.toUsername!,
Navigator.pop(context); textAlign: TextAlign.center,
},
child: Text(
'close'.tr(),
style: scaledTextStyle( 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 } enum TransactionStatus { loading, failed, success, none }
class TransactionDetails {
String? fromAddress, toAddress, toUsername, amount;
bool isUdUnit = false;
String resultText = '';
TransactionStatus txStatus = TransactionStatus.none;
Map<String, String> actionMap = {
'pay': 'transaction'.tr(),
'cert': 'certification'.tr(),
'comfirmIdty': 'identityConfirm'.tr(),
'revokeIdty': 'revokeAdhesion'.tr(),
'identityMigration': 'identityMigration'.tr(),
};
Map<String, String> 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<WalletsProfilesProvider>(homeContext, listen: false);
final myWalletProvider =
Provider.of<MyWalletsProvider>(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';
}
}
}

View File

@ -151,7 +151,7 @@ class WalletViewScreen extends StatelessWidget {
return FutureBuilder( return FutureBuilder(
future: sub.certState(defaultWallet.address, address), future: sub.certState(defaultWallet.address, address),
builder: (context, AsyncSnapshot<Map<String, int>> snapshot) { builder: (context, AsyncSnapshot<Map<String, int>> snapshot) {
if (snapshot.data == null) return ScaledSizedBox(); if (snapshot.data == null) return const SizedBox.shrink();
String duration = ''; String duration = '';
if (snapshot.data!['certDelay'] != null || if (snapshot.data!['certDelay'] != null ||
@ -209,55 +209,53 @@ class WalletViewScreen extends StatelessWidget {
'assets/gecko_certify.png')), 'assets/gecko_certify.png')),
), ),
onTap: () async { onTap: () async {
final bool? result = final result =
await confirmPopupCertification( await confirmPopupCertification(
context, context,
'areYouSureYouWantToCertify1' 'areYouSureYouWantToCertify1'
.tr(), .tr(),
duniterIndexer duniterIndexer
.walletNameIndexer[ .walletNameIndexer[
address] ?? address] ??
"noIdentity".tr(), "noIdentity".tr(),
'areYouSureYouWantToCertify2' 'areYouSureYouWantToCertify2'
.tr(), .tr(),
getShortPubkey(address)); getShortPubkey(address)) ??
false;
if (result ?? false) { if (!result) return;
String? pin; if (myWalletProvider.pinCode == '') {
if (myWalletProvider.pinCode == '') { await Navigator.push(
pin = await Navigator.push( context,
context, MaterialPageRoute(
MaterialPageRoute( builder: (homeContext) {
builder: (homeContext) { return UnlockingWallet(
return UnlockingWallet( wallet: defaultWallet);
wallet: defaultWallet); },
}, ),
), );
);
}
if (pin != null ||
myWalletProvider.pinCode != '') {
WalletsProfilesProvider
walletViewProvider = Provider
.of<WalletsProfilesProvider>(
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 (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');
}),
);
}), }),
), ),
), ),

View File

@ -24,8 +24,9 @@ class NextButton extends StatelessWidget {
child: ElevatedButton( child: ElevatedButton(
key: keyGoNext, key: keyGoNext,
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
foregroundColor: Colors.white, backgroundColor: orangeC, foregroundColor: Colors.white,
elevation: 4, // foreground backgroundColor: orangeC,
elevation: 4,
), ),
onPressed: () { onPressed: () {
Navigator.push( Navigator.push(

View File

@ -33,9 +33,8 @@ void paymentPopup(BuildContext context, String toAddress, String? username) {
walletViewProvider.payAmount.text = ''; walletViewProvider.payAmount.text = '';
Future executeTransfert() async { Future executeTransfert() async {
String? pin;
if (myWalletProvider.pinCode == '') { if (myWalletProvider.pinCode == '') {
pin = await Navigator.push( await Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (homeContext) { builder: (homeContext) {
@ -44,25 +43,26 @@ void paymentPopup(BuildContext context, String toAddress, String? username) {
), ),
); );
} }
if (pin != null || myWalletProvider.pinCode != '') { if (myWalletProvider.pinCode == '') return;
// Payment workflow ! // Payment workflow !
final sub = Provider.of<SubstrateSdk>(context, listen: false); final sub = Provider.of<SubstrateSdk>(context, listen: false);
final acc = sub.getCurrentWallet(); final acc = sub.getCurrentWallet();
log.d( log.d(
"fromAddress: ${acc.address!},destAddress: $toAddress, amount: ${double.parse(walletViewProvider.payAmount.text)}"); "fromAddress: ${acc.address!},destAddress: $toAddress, amount: ${double.parse(walletViewProvider.payAmount.text)}");
sub.pay( final transactionId = await sub.pay(
fromAddress: acc.address!, fromAddress: acc.address!,
destAddress: toAddress, destAddress: toAddress,
amount: double.parse(walletViewProvider.payAmount.text), amount: double.parse(walletViewProvider.payAmount.text),
password: pin ?? myWalletProvider.pinCode); password: myWalletProvider.pinCode);
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute(builder: (context) { MaterialPageRoute(builder: (context) {
return TransactionInProgress( return TransactionInProgress(
toAddress: toAddress, toUsername: username); transactionId: transactionId,
}), toAddress: toAddress,
); toUsername: username);
} }),
);
} }
myWalletProvider.readAllWallets().then((value) => myWalletProvider.listWallets myWalletProvider.readAllWallets().then((value) => myWalletProvider.listWallets

View File

@ -1660,7 +1660,7 @@ packages:
source: hosted source: hosted
version: "3.1.0" version: "3.1.0"
uuid: uuid:
dependency: transitive dependency: "direct main"
description: description:
name: uuid name: uuid
sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313" sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313"

View File

@ -61,6 +61,7 @@ dependencies:
url_launcher: ^6.1.11 url_launcher: ^6.1.11
crypto: ^3.0.3 crypto: ^3.0.3
screen_brightness: ^0.2.2+1 screen_brightness: ^0.2.2+1
uuid: ^3.0.7
dev_dependencies: dev_dependencies:
# flutter_launcher_icons: ^0.9.2 # flutter_launcher_icons: ^0.9.2