Compare commits

...

10 Commits

23 changed files with 573 additions and 288 deletions

View File

@ -5,8 +5,7 @@ services:
container_name: duniter-v2s-gecko-tests container_name: duniter-v2s-gecko-tests
# image: duniter/duniter-v2s:debug-sha-4d5e08be # image: duniter/duniter-v2s:debug-sha-4d5e08be
image: duniter/duniter-v2s:debug-sha-44b09061 image: duniter/duniter-v2s:debug-sha-44b09061
command: --alice command: --alice --sealing=manual
# --sealing=manual
ports: ports:
- "127.0.0.1:9615:9615" - "127.0.0.1:9615:9615"
- "127.0.0.1:9933:9933" - "127.0.0.1:9933:9933"

View File

@ -65,10 +65,11 @@ Future payTest2() async {
Future certifyTest5() async { Future certifyTest5() async {
// Create identity with Test1 account // Create identity with Test1 account
await pump(number: 8);
await tapKey(keyCertify); await tapKey(keyCertify);
await tapKey(keyConfirm); await tapKey(keyConfirm);
spawnBlock(duration: 1000); spawnBlock(duration: 1000);
await tester.pump(const Duration(seconds: 2)); await pump(number: 3);
await waitFor('sending'.tr(), await waitFor('sending'.tr(),
reverse: true, settle: false, timeout: const Duration(seconds: 20)); reverse: true, settle: false, timeout: const Duration(seconds: 20));
await tapKey(keyCloseTransactionScreen); await tapKey(keyCloseTransactionScreen);
@ -83,7 +84,7 @@ Future certifyTest5() async {
await enterText(keyEnterIdentityUsername, test5.name); await enterText(keyEnterIdentityUsername, test5.name);
await tapKey(keyConfirm); await tapKey(keyConfirm);
spawnBlock(duration: 1000); spawnBlock(duration: 1000);
await tester.pump(const Duration(seconds: 2)); await pump(number: 3);
await waitFor('sending'.tr(), await waitFor('sending'.tr(),
reverse: true, settle: false, timeout: const Duration(seconds: 20)); reverse: true, settle: false, timeout: const Duration(seconds: 20));
await tapKey(keyCloseTransactionScreen); await tapKey(keyCloseTransactionScreen);
@ -111,7 +112,7 @@ Future certifyTest5() async {
await tapKey(keyCertify); await tapKey(keyCertify);
await tapKey(keyConfirm); await tapKey(keyConfirm);
spawnBlock(duration: 1000); spawnBlock(duration: 1000);
await tester.pump(const Duration(seconds: 2)); await pump(number: 3);
await waitFor('sending'.tr(), await waitFor('sending'.tr(),
reverse: true, settle: false, timeout: const Duration(seconds: 20)); reverse: true, settle: false, timeout: const Duration(seconds: 20));
await tapKey(keyCloseTransactionScreen); await tapKey(keyCloseTransactionScreen);
@ -119,16 +120,16 @@ Future certifyTest5() async {
// Change default wallet to test3 // Change default wallet to test3
await tapKey(keyPay); await tapKey(keyPay);
await tapKey(keyChangeChest); await tapKey(keyDropdownWallets);
await tapKey(keySelectThisWallet(test3.address)); await tapKey(keySelectThisWallet(test3.address));
await tapKey(keyConfirm); await tapKey(keyPopButton);
await sleep(); await sleep();
// Certify with test3 account // Certify with test3 account
await tapKey(keyCertify); await tapKey(keyCertify);
await tapKey(keyConfirm); await tapKey(keyConfirm);
spawnBlock(duration: 1000); spawnBlock(duration: 1000);
await tester.pump(const Duration(seconds: 2)); await pump(number: 3);
await waitFor('sending'.tr(), await waitFor('sending'.tr(),
reverse: true, settle: false, timeout: const Duration(seconds: 20)); reverse: true, settle: false, timeout: const Duration(seconds: 20));
await tapKey(keyCloseTransactionScreen); await tapKey(keyCloseTransactionScreen);

View File

@ -44,6 +44,7 @@ void main() async {
await tapKey(keyConfirm); await tapKey(keyConfirm);
spawnBlock(duration: 1000); spawnBlock(duration: 1000);
await tester.pump(const Duration(seconds: 2)); await tester.pump(const Duration(seconds: 2));
await tester.pump(const Duration(seconds: 1));
await waitFor('sending'.tr(), await waitFor('sending'.tr(),
reverse: true, settle: false, timeout: const Duration(seconds: 20)); reverse: true, settle: false, timeout: const Duration(seconds: 20));
await tapKey(keyCloseTransactionScreen, duration: 0); await tapKey(keyCloseTransactionScreen, duration: 0);
@ -52,7 +53,7 @@ void main() async {
await waitFor('3', exactMatch: true); await waitFor('3', exactMatch: true);
await waitFor('memberValidated'.tr()); await waitFor('memberValidated'.tr());
await waitFor('99.98', exactMatch: true); await waitFor('110.01', exactMatch: true);
}, timeout: testTimeout()); }, timeout: testTimeout());
} }

View File

@ -25,7 +25,7 @@ Future changeNode() async {
} }
Future deleteAllWallets() async { Future deleteAllWallets() async {
if (await isPresent('Rechercher')) { if (await isPresent('searchWallet'.tr())) {
await tapKey(keyDrawerMenu); await tapKey(keyDrawerMenu);
await tapKey(keyParameters); await tapKey(keyParameters);
@ -65,15 +65,17 @@ Future restoreChest() async {
// Enter password // Enter password
await enterText(keyPinForm, 'AAAAA', 0); await enterText(keyPinForm, 'AAAAA', 0);
// pump a few frame
await pump(duration: const Duration(milliseconds: 500), number: 10);
// Check if string "Accéder à mon coffre" is present in screen // Check if string "Accéder à mon coffre" is present in screen
await waitFor('accessMyChest'.tr(), pumpDuration: 30); await waitFor('accessMyChest'.tr(), settle: false);
// Go to wallets home // Go to wallets home
await tapKey(keyGoWalletsHome, duration: 0); await tapKey(keyGoWalletsHome, duration: 0);
// Skip tutorial // Skip tutorial
await sleep(500); await skipWalletDragTutorial();
await tapKey(keyDragAndDrop).timeout(const Duration(seconds: 3));
// Check if string "ĞD" is present in screen // Check if string "ĞD" is present in screen
await waitFor('ĞD'); await waitFor('ĞD');
@ -168,5 +170,15 @@ Future firstOpenChest() async {
final isCached = await isIconPresent(Icons.check_box); final isCached = await isIconPresent(Icons.check_box);
if (!isCached) await tapKey(keyCachePassword, duration: 0); if (!isCached) await tapKey(keyCachePassword, duration: 0);
await enterText(keyPinForm, 'AAAAA', 0); await enterText(keyPinForm, 'AAAAA', 0);
await waitFor('100.0', exactMatch: true); await skipWalletDragTutorial();
await waitFor(test1.name);
}
Future skipWalletDragTutorial() async {
await pump(duration: const Duration(milliseconds: 500), number: 4);
await pump(duration: const Duration(seconds: 2));
if (await isPresent('explainDraggableWallet'.tr().substring(0, 13),
timeout: const Duration(seconds: 5), settle: false)) {
await tapKey(keyDragAndDrop, duration: 0);
}
} }

View File

@ -53,6 +53,15 @@ Future sleep([int time = 1000]) async {
await Future.delayed(Duration(milliseconds: time)); await Future.delayed(Duration(milliseconds: time));
} }
Future pump(
{Duration duration = const Duration(milliseconds: 300),
int number = 1}) async {
for (int i = 0; i < number; i++) {
log.d("pump $i");
await tester.pump(duration = duration);
}
}
Future<String> clipPaste() async => Future<String> clipPaste() async =>
(await Clipboard.getData('text/plain'))?.text ?? ''; (await Clipboard.getData('text/plain'))?.text ?? '';
@ -146,7 +155,8 @@ Future<void> waitFor(String text,
} }
if (settle) { if (settle) {
await tester.pumpAndSettle(Duration(milliseconds: pumpDuration)); await tester.pumpAndSettle(Duration(milliseconds: pumpDuration),
EnginePhase.sendSemanticsUpdate, timeout);
} }
await Future.delayed(const Duration(milliseconds: 100)); await Future.delayed(const Duration(milliseconds: 100));
} while (reverse ? finder.evaluate().isNotEmpty : finder.evaluate().isEmpty); } while (reverse ? finder.evaluate().isNotEmpty : finder.evaluate().isEmpty);
@ -155,9 +165,9 @@ Future<void> waitFor(String text,
// Test if text is visible on screen, return a boolean // Test if text is visible on screen, return a boolean
Future<bool> isPresent(String text, Future<bool> isPresent(String text,
{Duration timeout = const Duration(seconds: 1)}) async { {Duration timeout = const Duration(seconds: 1), bool settle = true}) async {
try { try {
await waitFor(text, timeout: timeout); await waitFor(text, timeout: timeout, settle: settle);
humanRead(); humanRead();
return true; return true;
} catch (exception) { } catch (exception) {
@ -278,8 +288,8 @@ Future<WalletData> _addImportAccount(
Future bkDeleteAllWallets() async { Future bkDeleteAllWallets() async {
final myWalletProvider = final myWalletProvider =
Provider.of<MyWalletsProvider>(homeContext, listen: false); Provider.of<MyWalletsProvider>(homeContext, listen: false);
final isWalletsPresents = final isWalletsPresents = await isPresent('scanQRCode'.tr(),
await isPresent('Scanner un', timeout: const Duration(milliseconds: 300)); timeout: const Duration(milliseconds: 300));
if (isWalletsPresents) { if (isWalletsPresents) {
await walletBox.clear(); await walletBox.clear();
await chestBox.clear(); await chestBox.clear();

View File

@ -61,6 +61,24 @@ class WalletData extends HiveObject {
return "$chest:$number:$name:$derivation:$imageDefaultPath"; return "$chest:$number:$name:$derivation:$imageDefaultPath";
} }
bool hasIdentity() {
return identityStatus == IdtyStatus.created ||
identityStatus == IdtyStatus.confirmed ||
identityStatus == IdtyStatus.validated;
}
bool isMembre() {
return identityStatus == IdtyStatus.validated;
}
bool exist() {
return balance != 0;
}
bool hasCustomImage() {
return imageCustomPath != null;
}
// returns only the id part of the ':'-separated string // returns only the id part of the ':'-separated string
List<int?> id() { List<int?> id() {
return [chest, number]; return [chest, number];

View File

@ -98,6 +98,8 @@ const keyCesiumPassword = Key('keyCesiumPassword');
const keySelectWallet = Key('keySelectWallet'); const keySelectWallet = Key('keySelectWallet');
const keyCesiumIdVisible = Key('keyCesiumIdVisible'); const keyCesiumIdVisible = Key('keyCesiumIdVisible');
const keyDropdownWallets = Key('keyDropdownKey');
// Items keys // Items keys
Key keyTransaction(int keyId) => Key('keyTransaction$keyId'); Key keyTransaction(int keyId) => Key('keyTransaction$keyId');
Key keyMnemonicWord(String word) => Key('keyMnemonicWord$word'); Key keyMnemonicWord(String word) => Key('keyMnemonicWord$word');

View File

@ -35,14 +35,32 @@ class MyWalletsProvider with ChangeNotifier {
} }
} }
List<WalletData> readAllWallets([int? chest]) { Future<List<WalletData>> readAllWallets([int? chest]) async {
final sub = Provider.of<SubstrateSdk>(homeContext, listen: false);
chest = chest ?? configBox.get('currentChest') ?? 0; chest = chest ?? configBox.get('currentChest') ?? 0;
listWallets.clear(); listWallets.clear();
walletBox.toMap().forEach((key, value) { final wallets = walletBox.toMap().values.toList();
if (value.chest == chest) { Map<String, WalletData> walletsToScan = {};
listWallets.add(value); for (var walletFromBox in wallets) {
if (walletFromBox.chest == chest) {
if (walletFromBox.identityStatus == IdtyStatus.unknown) {
walletsToScan.putIfAbsent(
walletFromBox.address, (() => walletFromBox));
} else {
listWallets.add(walletFromBox);
}
} }
}); }
// update all idty status in lists
int n = 0;
final idtyStatusList = await sub.idtyStatus(walletsToScan.keys.toList());
for (final wallet in walletsToScan.values) {
wallet.identityStatus = idtyStatusList[n];
walletBox.put(wallet.address, wallet);
listWallets.add(wallet);
n++;
}
return listWallets; return listWallets;
} }
@ -118,7 +136,7 @@ class MyWalletsProvider with ChangeNotifier {
isNewDerivationLoading = true; isNewDerivationLoading = true;
notifyListeners(); notifyListeners();
final List idList = getNextWalletNumberAndDerivation(); final List idList = await getNextWalletNumberAndDerivation();
int newWalletNbr = idList[0]; int newWalletNbr = idList[0];
int newDerivationNbr = number ?? idList[1]; int newDerivationNbr = number ?? idList[1];
@ -155,7 +173,7 @@ class MyWalletsProvider with ChangeNotifier {
int newWalletNbr; int newWalletNbr;
int? chest = getCurrentChest(); int? chest = getCurrentChest();
List<WalletData> walletConfig = readAllWallets(chest); List<WalletData> walletConfig = await readAllWallets(chest);
walletConfig.sort((p1, p2) { walletConfig.sort((p1, p2) {
return Comparable.compare(p1.number!, p2.number!); return Comparable.compare(p1.number!, p2.number!);
}); });
@ -187,22 +205,21 @@ class MyWalletsProvider with ChangeNotifier {
notifyListeners(); notifyListeners();
} }
List<int> getNextWalletNumberAndDerivation( Future<List<int>> getNextWalletNumberAndDerivation(
{int? chestNumber, bool isOneshoot = false}) { {int? chestNumber, bool isOneshoot = false}) async {
int newDerivationNbr = 0; int newDerivationNbr = 0;
int newWalletNbr = 0; int newWalletNbr = 0;
chestNumber ??= getCurrentChest(); chestNumber ??= getCurrentChest();
List<WalletData> walletConfig = readAllWallets(chestNumber); listWallets.sort((p1, p2) {
walletConfig.sort((p1, p2) {
return Comparable.compare(p1.number!, p2.number!); return Comparable.compare(p1.number!, p2.number!);
}); });
if (walletConfig.isEmpty) { if (listWallets.isEmpty) {
newDerivationNbr = 2; newDerivationNbr = 2;
} else { } else {
WalletData lastWallet = walletConfig.reduce( WalletData lastWallet = listWallets.reduce(
(curr, next) => curr.derivation! > next.derivation! ? curr : next); (curr, next) => curr.derivation! > next.derivation! ? curr : next);
if (lastWallet.derivation == -1) { if (lastWallet.derivation == -1) {
@ -211,7 +228,7 @@ class MyWalletsProvider with ChangeNotifier {
newDerivationNbr = lastWallet.derivation! + (isOneshoot ? 1 : 2); newDerivationNbr = lastWallet.derivation! + (isOneshoot ? 1 : 2);
} }
newWalletNbr = walletConfig.last.number! + 1; newWalletNbr = listWallets.last.number! + 1;
} }
return [newWalletNbr, newDerivationNbr]; return [newWalletNbr, newDerivationNbr];

View File

@ -1,5 +1,7 @@
// 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 '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';
@ -90,10 +92,11 @@ class SubstrateSdk with ChangeNotifier {
Future _getStorage(String call) async { Future _getStorage(String call) async {
try { try {
log.d(call);
return await sdk.webView!.evalJavascript('api.query.$call'); return await sdk.webView!.evalJavascript('api.query.$call');
} catch (e) { } catch (e) {
log.e("_getStorage error: $e"); log.e("_getStorage error: $e");
return Future(() {}); throw Exception("_getStorage error: $e");
} }
} }
@ -141,6 +144,14 @@ class SubstrateSdk with ChangeNotifier {
return await _getStorage('identity.identityIndexOf("$address")'); return await _getStorage('identity.identityIndexOf("$address")');
} }
Future<List<int?>> _getIdentityIndexOfMulti(List<String> addresses) async {
String jsonString = jsonEncode(addresses);
return List<int?>.from(
await _getStorage('identity.identityIndexOf.multi($jsonString)'));
// .map((e) => e as int?)
// .toList() as List<int?>;
}
Future<List<int>?> getCertsCounter(String address) async { Future<List<int>?> getCertsCounter(String address) async {
final idtyIndex = await _getIdentityIndexOf(address); final idtyIndex = await _getIdentityIndexOf(address);
if (idtyIndex == null) { if (idtyIndex == null) {
@ -169,7 +180,7 @@ class SubstrateSdk with ChangeNotifier {
final idtyIndexFrom = await _getIdentityIndexOf(from); final idtyIndexFrom = await _getIdentityIndexOf(from);
final idtyIndexTo = await _getIdentityIndexOf(to); final idtyIndexTo = await _getIdentityIndexOf(to);
if (idtyIndexFrom == 0 || idtyIndexTo == 0) return 0; if (idtyIndexFrom == null || idtyIndexTo == null) return 0;
final List certData = final List certData =
await _getStorage('cert.certsByReceiver($idtyIndexTo)') ?? []; await _getStorage('cert.certsByReceiver($idtyIndexTo)') ?? [];
@ -214,18 +225,23 @@ class SubstrateSdk with ChangeNotifier {
(await _getStorage('system.account.multi($stringifyAddresses)') as List) (await _getStorage('system.account.multi($stringifyAddresses)') as List)
.map((dynamic e) => e as Map<String, dynamic>) .map((dynamic e) => e as Map<String, dynamic>)
.toList(); .toList();
log.d('debug multi: $balanceGlobalMulti');
final List<int?> idtyIndexList = (await _getStorage( final List<int?> idtyIndexList = (await _getStorage(
'identity.identityIndexOf.multi($stringifyAddresses)') as List) 'identity.identityIndexOf.multi($stringifyAddresses)') as List)
.map((dynamic e) => e as int?) .map((dynamic e) => e as int?)
.toList(); .toList();
final List<Map?> idtyDataList = (idtyIndexList.isEmpty
//FIXME: With local dev duniter node only, need to switch null values by unused init as index to have good idtyDataList...
final List<int> idtyIndexListNoNull =
idtyIndexList.map((item) => item ?? 99999999).toList();
final List<Map?> idtyDataList = (idtyIndexListNoNull.isEmpty
? [] ? []
: (await _getStorage('identity.identities.multi($idtyIndexList)')) : (await _getStorage(
as List) 'identity.identities.multi($idtyIndexListNoNull)')) as List)
.map((dynamic e) => e as Map<String, dynamic>?) .map((dynamic e) => e as Map<String, dynamic>?)
.toList(); .toList();
final List pastReevals = final List pastReevals =
await _getStorage('universalDividend.pastReevals()'); await _getStorage('universalDividend.pastReevals()');
@ -311,33 +327,13 @@ class SubstrateSdk with ChangeNotifier {
return totalAmount; return totalAmount;
} }
Future<bool> isMember(String address) async {
final isMember = await idtyStatus(address) == IdtyStatus.validated;
final walletData = walletBox.get(address) ?? WalletData(address: address);
walletData.identityStatus = IdtyStatus.validated;
walletBox.put(address, walletData);
// notifyListeners();
return isMember;
}
Future<bool> isSmithGet(String address) async {
var idtyIndex = await _getIdentityIndexOf(address);
final Map smithExpireOn =
(await _getStorage('smithsMembership.membership($idtyIndex)')) ?? {};
if (smithExpireOn.isEmpty) {
return false;
} else {
return true;
}
}
Future<Map<String, int>> certState(String from, String to) async { Future<Map<String, int>> certState(String from, String to) async {
Map<String, int> result = {}; Map<String, int> result = {};
final toStatus = await idtyStatus(to); final toStatus = (await idtyStatus([to])).first;
if (from != to && await isMember(from)) { final myWallets = MyWalletsProvider();
if (from != to && myWallets.getWalletDataByAddress(from)!.isMembre()) {
final removableOn = await getCertValidityPeriod(from, to); final removableOn = await getCertValidityPeriod(from, to);
final certMeta = await getCertMeta(from); final certMeta = await getCertMeta(from);
final int nextIssuableOn = certMeta['nextIssuableOn'] ?? 0; final int nextIssuableOn = certMeta['nextIssuableOn'] ?? 0;
@ -360,8 +356,6 @@ class SubstrateSdk with ChangeNotifier {
} }
} }
// if (toStatus == 'Created') result.putIfAbsent('toStatus', () => 1);
return result; return result;
} }
@ -379,7 +373,7 @@ class SubstrateSdk with ChangeNotifier {
// Provider.of<WalletOptionsProvider>(homeContext, listen: false); // Provider.of<WalletOptionsProvider>(homeContext, listen: false);
var idtyIndex = await _getIdentityIndexOf(address); var idtyIndex = await _getIdentityIndexOf(address);
if (idtyIndex == 0) return []; if (idtyIndex == null) return [];
final Map? idtyData = await _getStorage('identity.identities($idtyIndex)'); final Map? idtyData = await _getStorage('identity.identities($idtyIndex)');
if (idtyData == null || idtyData['oldOwnerKey'] == null) return []; if (idtyData == null || idtyData['oldOwnerKey'] == null) return [];
@ -397,43 +391,59 @@ class SubstrateSdk with ChangeNotifier {
return startBlockchainTime.add(Duration(seconds: blocNumber * 6)); return startBlockchainTime.add(Duration(seconds: blocNumber * 6));
} }
Future<IdtyStatus> idtyStatus(String address) async { Future<List<IdtyStatus>> idtyStatus(List<String> addresses) async {
// final walletOptions = // final walletOptions =
// Provider.of<WalletOptionsProvider>(homeContext, listen: false); // Provider.of<WalletOptionsProvider>(homeContext, listen: false);
var idtyIndex = await _getIdentityIndexOf(address); log.d(addresses);
final idtyIndexes = (await _getIdentityIndexOfMulti(addresses));
// .map((dynamic e) => e as String)
// .toList();
log.d(idtyIndexes);
final jsonString = jsonEncode(idtyIndexes);
final List idtyStatusList =
await _getStorage('identity.identities.multi($jsonString)');
if (idtyIndex == null) { log.d(idtyStatusList);
return IdtyStatus.none;
}
final idtyStatus = await _getStorage('identity.identities($idtyIndex)'); List<IdtyStatus> resultStatus = [];
for (final idtyStatus in idtyStatusList) {
if (idtyStatus == null) {
resultStatus.add(IdtyStatus.none);
continue;
}
if (idtyStatus != null) {
switch (idtyStatus['status']) { switch (idtyStatus['status']) {
case 'Created': case 'Created':
return IdtyStatus.created; resultStatus.add(IdtyStatus.created);
break;
case 'ConfirmedByOwner': case 'ConfirmedByOwner':
return IdtyStatus.confirmed; resultStatus.add(IdtyStatus.confirmed);
break;
case 'Validated': case 'Validated':
return IdtyStatus.validated; resultStatus.add(IdtyStatus.validated);
break;
case 'Expired':
resultStatus.add(IdtyStatus.expired);
break;
default: default:
return IdtyStatus.unknown; resultStatus.add(IdtyStatus.unknown);
break;
} }
} else {
return IdtyStatus.expired;
} }
return resultStatus;
} }
Future<bool> isSmith(String address) async { Future<bool> isSmith(String address) async {
var idtyIndex = await _getIdentityIndexOf(address); var idtyIndex = await _getIdentityIndexOf(address);
if (idtyIndex == 0) return false; if (idtyIndex == -1) return false;
final isSmith = final isSmith = await _getStorage('smithMembership.membership($idtyIndex)');
await _getStorage('smithsMembership.membership($idtyIndex)');
return isSmith == null ? false : true; return isSmith == null ? false : true;
} }
@ -753,7 +763,6 @@ class SubstrateSdk with ChangeNotifier {
seedText = seed.seed!.split('//')[0]; seedText = seed.seed!.split('//')[0];
} }
log.d(seedText);
return seedText; return seedText;
} }
@ -891,11 +900,12 @@ class SubstrateSdk with ChangeNotifier {
final fromBalance = fromAddress == '' final fromBalance = fromAddress == ''
? {'transferableBalance': 0} ? {'transferableBalance': 0}
: await getBalance(fromAddress); : await getBalance(fromAddress);
final fromIdtyStatus =
fromAddress == '' ? 'noid' : await idtyStatus(fromAddress); final statusList = await idtyStatus([fromAddress, toAddress]);
final fromIdtyStatus = statusList[0];
final fromHasConsumer = final fromHasConsumer =
fromAddress == '' ? false : await hasAccountConsumers(fromAddress); fromAddress == '' ? false : await hasAccountConsumers(fromAddress);
final toIdtyStatus = await idtyStatus(toAddress); final toIdtyStatus = statusList[1];
final isSmithData = await isSmith(fromAddress); final isSmithData = await isSmith(fromAddress);
return [ return [
@ -970,11 +980,14 @@ class SubstrateSdk with ChangeNotifier {
String fromAddress, String destAddress, String password) async { String fromAddress, String destAddress, String password) async {
transactionStatus = ''; transactionStatus = '';
final myIdtyStatus = await idtyStatus(fromAddress); final statusList = await idtyStatus([fromAddress, destAddress]);
final toIdtyStatus = await idtyStatus(destAddress); final myIdtyStatus = statusList[0];
final toIdtyStatus = statusList[1];
final fromIndex = await _getIdentityIndexOf(fromAddress); final idtyIndexList =
final toIndex = await _getIdentityIndexOf(destAddress); await _getIdentityIndexOfMulti([fromAddress, destAddress]);
final fromIndex = idtyIndexList[0];
final toIndex = idtyIndexList[1];
if (myIdtyStatus != IdtyStatus.validated) { if (myIdtyStatus != IdtyStatus.validated) {
transactionStatus = 'notMember'; transactionStatus = 'notMember';
@ -989,8 +1002,6 @@ class SubstrateSdk with ChangeNotifier {
final toCerts = await getCertsCounter(destAddress); final toCerts = await getCertsCounter(destAddress);
// log.d('debug: ${currencyParameters['minCertForMembership']}');
log.d( log.d(
"debug toCert: ${toCerts?[0]} --- ${currencyParameters['minCertForMembership']!} --- $toIdtyStatus"); "debug toCert: ${toCerts?[0]} --- ${currencyParameters['minCertForMembership']!} --- $toIdtyStatus");
@ -1071,6 +1082,7 @@ class SubstrateSdk with ChangeNotifier {
final messageToSignHex = HEX.encode(messageToSign); final messageToSignHex = HEX.encode(messageToSign);
final newKeySig = final newKeySig =
await _signMessage(messageToSign, destAddress, destPassword); await _signMessage(messageToSign, destAddress, destPassword);
final newKeySigType = '{"Sr25519": "$newKeySig"}';
// messageToSign: [105, 99, 111, 107, 7, 193, 18, 255, 106, 185, 215, 208, 213, 49, 235, 229, 159, 152, 179, 83, 24, 178, 129, 59, 22, 85, 87, 115, 128, 129, 157, 56, 214, 24, 45, 153, 21, 0, 0, 0, 181, 82, 178, 99, 198, 4, 156, 190, 78, 35, 102, 137, 255, 7, 162, 31, 16, 79, 255, 132, 130, 237, 230, 222, 176, 88, 245, 217, 237, 78, 196, 239] // messageToSign: [105, 99, 111, 107, 7, 193, 18, 255, 106, 185, 215, 208, 213, 49, 235, 229, 159, 152, 179, 83, 24, 178, 129, 59, 22, 85, 87, 115, 128, 129, 157, 56, 214, 24, 45, 153, 21, 0, 0, 0, 181, 82, 178, 99, 198, 4, 156, 190, 78, 35, 102, 137, 255, 7, 162, 31, 16, 79, 255, 132, 130, 237, 230, 222, 176, 88, 245, 217, 237, 78, 196, 239]
@ -1086,7 +1098,7 @@ oldPubkey: $oldPubkey
messageToSign: $messageToSign messageToSign: $messageToSign
messageToSignHex: $messageToSignHex messageToSignHex: $messageToSignHex
newKeySig: $newKeySig"""); newKeySig: $newKeySigType""");
if (withBalance) { if (withBalance) {
txInfo = TxInfoData( txInfo = TxInfoData(
@ -1097,7 +1109,7 @@ newKeySig: $newKeySig""");
const tx1 = 'api.tx.universalDividend.claimUds()'; const tx1 = 'api.tx.universalDividend.claimUds()';
final tx2 = final tx2 =
'api.tx.identity.changeOwnerKey("$destAddress", "$newKeySig")'; 'api.tx.identity.changeOwnerKey("$destAddress", $newKeySigType)';
final tx3 = 'api.tx.balances.transferAll("$destAddress", false)'; final tx3 = 'api.tx.balances.transferAll("$destAddress", false)';
rawParams = fromBalance['unclaimedUds'] == 0 rawParams = fromBalance['unclaimedUds'] == 0
@ -1110,7 +1122,7 @@ newKeySig: $newKeySig""");
sender, sender,
); );
txOptions = [destAddress, newKeySig]; txOptions = [destAddress, newKeySigType];
} }
return await _executeCall(txInfo, txOptions, fromPassword, rawParams); return await _executeCall(txInfo, txOptions, fromPassword, rawParams);
@ -1143,7 +1155,7 @@ newKeySig: $newKeySig""");
Future migrateCsToV2(String salt, String password, String destAddress, Future migrateCsToV2(String salt, String password, String destAddress,
{required destPassword, {required destPassword,
required Map balance, required Map balance,
String idtyStatus = 'noid'}) async { IdtyStatus idtyStatus = IdtyStatus.none}) async {
final scrypt = pc.KeyDerivator('scrypt'); final scrypt = pc.KeyDerivator('scrypt');
scrypt.init( scrypt.init(
@ -1174,7 +1186,7 @@ newKeySig: $newKeySig""");
); );
log.d('g1migration idtyStatus: $idtyStatus'); log.d('g1migration idtyStatus: $idtyStatus');
if (idtyStatus != 'noid') { if (idtyStatus != IdtyStatus.none) {
await migrateIdentity( await migrateIdentity(
fromAddress: keypair.address!, fromAddress: keypair.address!,
destAddress: destAddress, destAddress: destAddress,

View File

@ -35,9 +35,7 @@ class _CustomDerivationState extends State<CustomDerivation> {
for (var i = 0; i < 51; i += 1) i.toString() for (var i = 0; i < 51; i += 1) i.toString()
]; ];
final listWallets = myWalletProvider.readAllWallets(); for (WalletData wallet in myWalletProvider.listWallets) {
for (WalletData wallet in listWallets) {
derivationList.remove(wallet.derivation.toString()); derivationList.remove(wallet.derivation.toString());
if (wallet.derivation == -1) { if (wallet.derivation == -1) {
derivationList.remove('root'); derivationList.remove('root');

View File

@ -27,11 +27,13 @@ class ImportG1v1 extends StatelessWidget {
Provider.of<MyWalletsProvider>(context, listen: false); Provider.of<MyWalletsProvider>(context, listen: false);
Timer? debounce; Timer? debounce;
const int debouneTime = 300; const int debouneTime = 600;
WalletData selectedWallet = myWalletProvider.getDefaultWallet(); WalletData selectedWallet = myWalletProvider.getDefaultWallet();
bool canValidate = false; bool canValidate = false;
String validationStatus = ''; String validationStatus = '';
log.d(myWalletProvider.listWallets);
return WillPopScope( return WillPopScope(
onWillPop: () { onWillPop: () {
resetScreen(context); resetScreen(context);
@ -58,8 +60,6 @@ class ImportG1v1 extends StatelessWidget {
future: sub.getBalanceAndIdtyStatus( future: sub.getBalanceAndIdtyStatus(
sub.g1V1NewAddress, selectedWallet.address), sub.g1V1NewAddress, selectedWallet.address),
builder: (BuildContext context, AsyncSnapshot<List> status) { builder: (BuildContext context, AsyncSnapshot<List> status) {
// log.d(_certs.data);
if (status.data == null) { if (status.data == null) {
return const Column(children: [ return const Column(children: [
SizedBox(height: 80), SizedBox(height: 80),
@ -79,13 +79,11 @@ class ImportG1v1 extends StatelessWidget {
} }
final Map balance = status.data?[0] ?? {}; final Map balance = status.data?[0] ?? {};
final String idtyStatus = status.data?[1]; final IdtyStatus idtyStatus = status.data?[1];
final String myIdtyStatus = status.data?[2]; final IdtyStatus myIdtyStatus = status.data?[2];
final bool hasConsumer = status.data?[3] ?? false; final bool hasConsumer = status.data?[3] ?? false;
final bool isSmith = status.data?[4] ?? false; final bool isSmith = status.data?[4] ?? false;
// log.d('hasconsumer: $hasConsumer');
if (balance['transferableBalance'] != 0 && !hasConsumer) { if (balance['transferableBalance'] != 0 && !hasConsumer) {
canValidate = true; canValidate = true;
validationStatus = ''; validationStatus = '';
@ -96,7 +94,8 @@ class ImportG1v1 extends StatelessWidget {
: 'thisAccountIsEmpty'.tr(); : 'thisAccountIsEmpty'.tr();
} }
if (idtyStatus != 'noid' && myIdtyStatus != 'noid') { if (idtyStatus != IdtyStatus.none &&
myIdtyStatus != IdtyStatus.none) {
canValidate = false; canValidate = false;
validationStatus = validationStatus =
'youCannotMigrateIdentityToExistingIdentity'.tr(); 'youCannotMigrateIdentityToExistingIdentity'.tr();

View File

@ -43,7 +43,7 @@ class ManageMembership extends StatelessWidget {
migrateIdentity(context), migrateIdentity(context),
const SizedBox(height: 10), const SizedBox(height: 10),
FutureBuilder( FutureBuilder(
future: sub.isSmithGet(address), future: sub.isSmith(address),
builder: (BuildContext context, AsyncSnapshot<bool> isSmith) { builder: (BuildContext context, AsyncSnapshot<bool> isSmith) {
if (isSmith.data ?? false) { if (isSmith.data ?? false) {
return SizedBox( return SizedBox(

View File

@ -96,8 +96,8 @@ class MigrateIdentityScreen extends StatelessWidget {
// log.d('statusData: ${status.data}'); // log.d('statusData: ${status.data}');
final Map balance = status.data?[0] ?? {}; final Map balance = status.data?[0] ?? {};
final String idtyStatus = status.data?[1]; final IdtyStatus idtyStatus = status.data?[1];
final String myIdtyStatus = status.data?[2]; final IdtyStatus myIdtyStatus = status.data?[2];
final bool hasConsumer = status.data?[3] ?? false; final bool hasConsumer = status.data?[3] ?? false;
final bool isSmith = status.data?[4] ?? false; final bool isSmith = status.data?[4] ?? false;
@ -110,7 +110,8 @@ class MigrateIdentityScreen extends StatelessWidget {
!hasConsumer) { !hasConsumer) {
canValidate = true; canValidate = true;
validationStatus = ''; validationStatus = '';
} else if (idtyStatus != 'noid' && myIdtyStatus != 'noid') { } else if (idtyStatus != IdtyStatus.none &&
myIdtyStatus != IdtyStatus.none) {
canValidate = false; canValidate = false;
validationStatus = validationStatus =
'youCannotMigrateIdentityToExistingIdentity'.tr(); 'youCannotMigrateIdentityToExistingIdentity'.tr();

View File

@ -43,14 +43,12 @@ class WalletOptions extends StatelessWidget {
final sub = Provider.of<SubstrateSdk>(context, listen: false); final sub = Provider.of<SubstrateSdk>(context, listen: false);
log.d(walletOptions.address.text); walletOptions.address.text = wallet.address;
final currentChest = myWalletProvider.getCurrentChest(); final currentChest = myWalletProvider.getCurrentChest();
bool isWalletNameIndexed = final isWalletNameIndexed =
duniterIndexer.walletNameIndexer[walletOptions.address.text] != null; duniterIndexer.walletNameIndexer[walletOptions.address.text] != null;
// final currentWallet = _myWalletProvider.getDefaultWallet();
// log.d(_walletOptions.getAddress(_currentChest, 3));
log.d("Wallet options: $currentChest:${wallet.derivation}"); log.d("Wallet options: $currentChest:${wallet.derivation}");
return WillPopScope( return WillPopScope(
@ -184,7 +182,9 @@ class WalletOptions extends StatelessWidget {
address: walletProvider.address.text, size: 24), address: walletProvider.address.text, size: 24),
const SizedBox(width: 30), const SizedBox(width: 30),
InkWell( InkWell(
onTap: () => isWalletNameIndexed onTap: () => sub.certsCounterCache[
walletProvider.address.text] !=
null
? { ? {
Navigator.push( Navigator.push(
context, context,
@ -193,9 +193,10 @@ class WalletOptions extends StatelessWidget {
address: address:
walletProvider.address.text, walletProvider.address.text,
username: duniterIndexer username: duniterIndexer
.walletNameIndexer[ .walletNameIndexer[
walletProvider walletProvider
.address.text]!); .address.text] ??
'');
}), }),
), ),
} }
@ -262,28 +263,16 @@ class WalletOptions extends StatelessWidget {
walletOptions, walletOptions,
currentChest), currentChest),
SizedBox(height: 17 * ratio), SizedBox(height: 17 * ratio),
// walletProvider.isMember(context, _walletOptions.address.text) Column(children: [
FutureBuilder( if (!walletProvider.isDefaultWallet &&
future: !wallet.isMembre())
sub.isMember(walletOptions.address.text), deleteWallet(
builder: (BuildContext context, context, walletProvider, currentChest)
AsyncSnapshot<bool> isMember) { else
if (isMember.connectionState != const SizedBox(),
ConnectionState.done || if (wallet.isMembre())
isMember.hasError) { const ManageMembershipButton()
return const Text(''); ])
}
return Column(children: [
if (!walletProvider.isDefaultWallet &&
!isMember.data!)
deleteWallet(context, walletProvider,
currentChest)
else
const SizedBox(),
if (isMember.data!)
const ManageMembershipButton()
]);
}),
]); ]);
}), }),
]), ]),
@ -351,10 +340,11 @@ class WalletOptions extends StatelessWidget {
Widget confirmIdentityButton(WalletOptionsProvider walletProvider) { Widget confirmIdentityButton(WalletOptionsProvider walletProvider) {
return Consumer<SubstrateSdk>(builder: (context, sub, _) { return Consumer<SubstrateSdk>(builder: (context, sub, _) {
return FutureBuilder( return FutureBuilder(
future: sub.idtyStatus(walletProvider.address.text), future: sub.idtyStatus([walletProvider.address.text]),
initialData: '', initialData: const [IdtyStatus.unknown],
builder: (context, snapshot) { builder:
if (snapshot.data == 'Created') { (BuildContext context, AsyncSnapshot<List<IdtyStatus>> snapshot) {
if (snapshot.data!.first == IdtyStatus.created) {
return Column(children: [ return Column(children: [
SizedBox( SizedBox(
width: 320, width: 320,
@ -553,7 +543,7 @@ class WalletOptions extends StatelessWidget {
// WalletData defaultWallet = _myWalletProvider.getDefaultWallet()!; // WalletData defaultWallet = _myWalletProvider.getDefaultWallet()!;
// defaultWallet = wallet; // defaultWallet = wallet;
await sub.setCurrentWallet(wallet); await sub.setCurrentWallet(wallet);
myWalletProvider.readAllWallets(currentChest); await myWalletProvider.readAllWallets(currentChest);
myWalletProvider.reload(); myWalletProvider.reload();
walletOptions.reload(); walletOptions.reload();
} }
@ -586,9 +576,9 @@ class WalletOptions extends StatelessWidget {
onTap: canDelete onTap: canDelete
? () async { ? () async {
await walletOptions.deleteWallet(context, wallet); await walletOptions.deleteWallet(context, wallet);
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) async {
myWalletProvider.listWallets = myWalletProvider.listWallets =
myWalletProvider.readAllWallets(currentChest); await myWalletProvider.readAllWallets(currentChest);
myWalletProvider.reload(); myWalletProvider.reload();
}); });
} }

View File

@ -10,15 +10,14 @@ import 'package:gecko/providers/my_wallets.dart';
import 'package:gecko/models/wallet_data.dart'; import 'package:gecko/models/wallet_data.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:gecko/providers/substrate_sdk.dart'; import 'package:gecko/providers/substrate_sdk.dart';
import 'package:gecko/providers/wallet_options.dart';
import 'package:gecko/screens/myWallets/chest_options.dart'; import 'package:gecko/screens/myWallets/chest_options.dart';
import 'package:gecko/screens/myWallets/import_g1_v1.dart'; import 'package:gecko/screens/myWallets/import_g1_v1.dart';
import 'package:gecko/screens/myWallets/unlocking_wallet.dart'; import 'package:gecko/screens/myWallets/unlocking_wallet.dart';
import 'package:gecko/widgets/balance.dart';
import 'package:gecko/widgets/bottom_app_bar.dart'; import 'package:gecko/widgets/bottom_app_bar.dart';
import 'package:gecko/widgets/commons/offline_info.dart'; import 'package:gecko/widgets/commons/offline_info.dart';
import 'package:gecko/widgets/payment_popup.dart'; import 'package:gecko/widgets/payment_popup.dart';
import 'package:gecko/widgets/wallet_tile.dart'; import 'package:gecko/widgets/wallet_tile.dart';
import 'package:gecko/widgets/wallet_tile_membre.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:tutorial_coach_mark/tutorial_coach_mark.dart'; import 'package:tutorial_coach_mark/tutorial_coach_mark.dart';
@ -42,8 +41,6 @@ class _WalletsHomeState extends State<WalletsHome> {
final currentChestNumber = myWalletProvider.getCurrentChest(); final currentChestNumber = myWalletProvider.getCurrentChest();
final ChestData currentChest = chestBox.get(currentChestNumber)!; final ChestData currentChest = chestBox.get(currentChestNumber)!;
myWalletProvider.listWallets =
myWalletProvider.readAllWallets(currentChestNumber);
return WillPopScope( return WillPopScope(
onWillPop: () { onWillPop: () {
@ -84,12 +81,29 @@ class _WalletsHomeState extends State<WalletsHome> {
actualRoute: 'safeHome', actualRoute: 'safeHome',
) )
: dragInfo(context), : dragInfo(context),
body: SafeArea( body: FutureBuilder(
child: Stack(children: [ future: myWalletProvider.readAllWallets(currentChestNumber),
myWalletsTiles(context, currentChestNumber), builder: (context, snapshot) {
const OfflineInfo(), if (snapshot.connectionState != ConnectionState.done ||
]), snapshot.hasError) {
), return const Center(
child: SizedBox(
height: 50,
width: 50,
child: CircularProgressIndicator(
color: orangeC,
strokeWidth: 3,
),
),
);
}
return SafeArea(
child: Stack(children: [
myWalletsTiles(context, currentChestNumber),
const OfflineInfo(),
]),
);
}),
), ),
); );
} }
@ -224,8 +238,6 @@ class _WalletsHomeState extends State<WalletsHome> {
Widget myWalletsTiles(BuildContext context, int currentChestNumber) { Widget myWalletsTiles(BuildContext context, int currentChestNumber) {
final myWalletProvider = Provider.of<MyWalletsProvider>(context); final myWalletProvider = Provider.of<MyWalletsProvider>(context);
final walletOptions =
Provider.of<WalletOptionsProvider>(context, listen: false);
final bool isWalletsExists = myWalletProvider.checkIfWalletExist(); final bool isWalletsExists = myWalletProvider.checkIfWalletExist();
final sub = Provider.of<SubstrateSdk>(context, listen: false); final sub = Provider.of<SubstrateSdk>(context, listen: false);
@ -250,6 +262,15 @@ class _WalletsHomeState extends State<WalletsHome> {
return Comparable.compare(p1.number!, p2.number!); return Comparable.compare(p1.number!, p2.number!);
}); });
// Get first wallet with identity
final idtyWallet = listWallets.firstWhere(
(w) => w.hasIdentity(),
orElse: () => WalletData(address: ''),
);
List<WalletData> listWalletsWithoutIdty = listWallets.toList();
listWalletsWithoutIdty.removeWhere((w) => w.address == idtyWallet.address);
WalletData? defaultWallet = myWalletProvider.getDefaultWallet(); WalletData? defaultWallet = myWalletProvider.getDefaultWallet();
final screenWidth = MediaQuery.of(context).size.width; final screenWidth = MediaQuery.of(context).size.width;
int nTule; int nTule;
@ -303,6 +324,10 @@ class _WalletsHomeState extends State<WalletsHome> {
return CustomScrollView(slivers: <Widget>[ return CustomScrollView(slivers: <Widget>[
const SliverToBoxAdapter(child: SizedBox(height: 20)), const SliverToBoxAdapter(child: SizedBox(height: 20)),
if (idtyWallet.address != '')
SliverToBoxAdapter(
child: WalletTileMembre(
repository: idtyWallet, defaultWallet: defaultWallet)),
SliverGrid.count( SliverGrid.count(
key: keyListWallets, key: keyListWallets,
crossAxisCount: nTule, crossAxisCount: nTule,
@ -310,7 +335,7 @@ class _WalletsHomeState extends State<WalletsHome> {
crossAxisSpacing: 0, crossAxisSpacing: 0,
mainAxisSpacing: 0, mainAxisSpacing: 0,
children: <Widget>[ children: <Widget>[
for (WalletData repository in listWallets) for (WalletData repository in listWalletsWithoutIdty)
LongPressDraggable<String>( LongPressDraggable<String>(
delay: const Duration(milliseconds: 200), delay: const Duration(milliseconds: 200),
data: repository.address, data: repository.address,
@ -366,10 +391,7 @@ class _WalletsHomeState extends State<WalletsHome> {
List<dynamic> rejected, List<dynamic> rejected,
) { ) {
return WalletTile( return WalletTile(
repository: repository, repository: repository, defaultWallet: defaultWallet);
walletOptions: walletOptions,
defaultWallet: defaultWallet,
currentChestNumber: currentChestNumber);
}), }),
), ),
Consumer<SubstrateSdk>(builder: (context, sub, _) { Consumer<SubstrateSdk>(builder: (context, sub, _) {
@ -443,95 +465,3 @@ class _WalletsHomeState extends State<WalletsHome> {
]))); ])));
} }
} }
class BalanceBuilder extends StatelessWidget {
const BalanceBuilder({
Key? key,
required this.address,
required this.isDefault,
}) : super(key: key);
final String address;
final bool isDefault;
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
color: isDefault ? orangeC : yellowC,
child: Padding(
padding:
const EdgeInsets.only(left: 5, right: 5, top: 38, bottom: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Opacity(
opacity: 0.7,
child: Balance(
address: address,
size: 16,
color: isDefault ? Colors.white : Colors.black,
loadingColor: isDefault ? yellowC : orangeC),
)
],
)),
);
}
}
class CustomClipperOval extends CustomClipper<Rect> {
@override
Rect getClip(Size size) {
return Rect.fromCircle(
center: Offset(size.width / 2, size.width / 2),
radius: size.width / 2 + 3);
}
@override
bool shouldReclip(CustomClipper<Rect> oldClipper) {
return false;
}
}
class ClipOvalShadow extends StatelessWidget {
final Shadow shadow;
final CustomClipper<Rect> clipper;
final Widget child;
const ClipOvalShadow({
Key? key,
required this.shadow,
required this.clipper,
required this.child,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return CustomPaint(
painter: _ClipOvalShadowPainter(
clipper: clipper,
shadow: shadow,
),
child: ClipRect(clipper: clipper, child: child),
);
}
}
class _ClipOvalShadowPainter extends CustomPainter {
final Shadow shadow;
final CustomClipper<Rect> clipper;
_ClipOvalShadowPainter({required this.shadow, required this.clipper});
@override
void paint(Canvas canvas, Size size) {
var paint = shadow.toPaint();
var clipRect = clipper.getClip(size).shift(const Offset(0, 0));
canvas.drawOval(clipRect, paint);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}

View File

@ -253,7 +253,7 @@ class OnboardingStepTen extends StatelessWidget {
isOwned: true); isOwned: true);
await walletBox.put(myWallet.address, myWallet); await walletBox.put(myWallet.address, myWallet);
} }
myWalletProvider.readAllWallets(currentChest); await myWalletProvider.readAllWallets(currentChest);
myWalletProvider.reload(); myWalletProvider.reload();
generateWalletProvider.generatedMnemonic = ''; generateWalletProvider.generatedMnemonic = '';

View File

@ -194,7 +194,7 @@ class WalletViewScreen extends StatelessWidget {
} }
} }
final toStatus = snapshot.data!['toStatus'] ?? 0; final toStatus = snapshot.data!['toStatus'];
return Visibility( return Visibility(
visible: (snapshot.data != {}), visible: (snapshot.data != {}),
@ -272,7 +272,7 @@ class WalletViewScreen extends StatelessWidget {
), ),
const SizedBox(height: 9), const SizedBox(height: 9),
Text( Text(
toStatus == 0 toStatus == null
? "certify".tr() ? "certify".tr()
: "createIdentity".tr(), : "createIdentity".tr(),
textAlign: TextAlign.center, textAlign: TextAlign.center,

View File

@ -31,6 +31,7 @@ class HeaderProfile extends StatelessWidget {
final duniterIndexer = Provider.of<DuniterIndexer>(context, listen: false); final duniterIndexer = Provider.of<DuniterIndexer>(context, listen: false);
final walletOptions = final walletOptions =
Provider.of<WalletOptionsProvider>(context, listen: false); Provider.of<WalletOptionsProvider>(context, listen: false);
final sub = Provider.of<SubstrateSdk>(context, listen: false);
return Stack(children: <Widget>[ return Stack(children: <Widget>[
Consumer<SubstrateSdk>(builder: (context, sub, _) { Consumer<SubstrateSdk>(builder: (context, sub, _) {
@ -78,7 +79,7 @@ class HeaderProfile extends StatelessWidget {
Balance(address: address, size: 25), Balance(address: address, size: 25),
const SizedBox(height: 9), const SizedBox(height: 9),
InkWell( InkWell(
onTap: () => duniterIndexer.walletNameIndexer[address] != null onTap: () => sub.certsCounterCache[address] != null
? { ? {
Navigator.push( Navigator.push(
context, context,
@ -86,7 +87,8 @@ class HeaderProfile extends StatelessWidget {
return CertificationsScreen( return CertificationsScreen(
address: address, address: address,
username: duniterIndexer username: duniterIndexer
.walletNameIndexer[address]!); .walletNameIndexer[address] ??
'');
}), }),
), ),
} }

View File

@ -24,10 +24,10 @@ class IdentityStatus extends StatelessWidget {
return Consumer<SubstrateSdk>(builder: (context, sub, _) { return Consumer<SubstrateSdk>(builder: (context, sub, _) {
return FutureBuilder( return FutureBuilder(
future: sub.idtyStatus(address), future: sub.idtyStatus([address]),
initialData: walletData.identityStatus, initialData: [walletData.identityStatus],
builder: (context, AsyncSnapshot<IdtyStatus> snapshot) { builder: (context, AsyncSnapshot<List<IdtyStatus>> snapshot) {
final resStatus = snapshot.data!; final resStatus = snapshot.data!.first;
walletData.identityStatus = resStatus; walletData.identityStatus = resStatus;
walletBox.put(address, walletData); walletBox.put(address, walletData);

View File

@ -28,7 +28,6 @@ void paymentPopup(BuildContext context, String toAddress, String username) {
var defaultWallet = myWalletProvider.getDefaultWallet(); var defaultWallet = myWalletProvider.getDefaultWallet();
bool canValidate = false; bool canValidate = false;
final amountFocus = FocusNode(); final amountFocus = FocusNode();
final dropdownKey = GlobalKey();
walletViewProvider.payAmount.text = ''; walletViewProvider.payAmount.text = '';
@ -66,10 +65,8 @@ void paymentPopup(BuildContext context, String toAddress, String username) {
} }
} }
myWalletProvider.readAllWallets(); myWalletProvider.readAllWallets().then((value) => myWalletProvider.listWallets
myWalletProvider.listWallets .sort((a, b) => a.derivation!.compareTo(b.derivation!)));
.sort((a, b) => a.derivation!.compareTo(b.derivation!));
log.d(myWalletProvider.listWallets);
showModalBottomSheet<void>( showModalBottomSheet<void>(
shape: const RoundedRectangleBorder( shape: const RoundedRectangleBorder(
@ -134,6 +131,7 @@ void paymentPopup(BuildContext context, String toAddress, String username) {
fontSize: 26, fontWeight: FontWeight.w700), fontSize: 26, fontWeight: FontWeight.w700),
), ),
IconButton( IconButton(
key: keyPopButton,
iconSize: 40, iconSize: 40,
icon: const Icon(Icons.cancel_outlined), icon: const Icon(Icons.cancel_outlined),
onPressed: () { onPressed: () {
@ -154,7 +152,7 @@ void paymentPopup(BuildContext context, String toAddress, String username) {
return DropdownButton( return DropdownButton(
dropdownColor: const Color(0xffffeed1), dropdownColor: const Color(0xffffeed1),
elevation: 12, elevation: 12,
key: dropdownKey, key: keyDropdownWallets,
value: defaultWallet, value: defaultWallet,
menuMaxHeight: 300, menuMaxHeight: 300,
onTap: () { onTap: () {
@ -199,6 +197,7 @@ void paymentPopup(BuildContext context, String toAddress, String username) {
.map((WalletData wallet) { .map((WalletData wallet) {
return DropdownMenuItem( return DropdownMenuItem(
value: wallet, value: wallet,
key: keySelectThisWallet(wallet.address),
child: Container( child: Container(
color: const Color(0xffffeed1), color: const Color(0xffffeed1),
width: 408, width: 408,

View File

@ -100,8 +100,8 @@ class SearchResult extends StatelessWidget {
walletsProfilesClass.address = g1Wallet.address; walletsProfilesClass.address = g1Wallet.address;
return WalletViewScreen( return WalletViewScreen(
address: g1Wallet.address, address: g1Wallet.address,
username: g1WalletsBox.get(g1Wallet)!.username ?? '', username: g1Wallet.username ?? '',
avatar: g1WalletsBox.get(g1Wallet.address)?.avatar, avatar: g1Wallet.avatar,
); );
}), }),
); );

View File

@ -1,28 +1,22 @@
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:gecko/globals.dart'; import 'package:gecko/globals.dart';
import 'package:gecko/models/wallet_data.dart'; import 'package:gecko/models/wallet_data.dart';
import 'package:gecko/models/widgets_keys.dart'; import 'package:gecko/models/widgets_keys.dart';
import 'package:gecko/providers/wallet_options.dart';
import 'package:gecko/screens/myWallets/wallet_options.dart'; import 'package:gecko/screens/myWallets/wallet_options.dart';
import 'package:gecko/screens/myWallets/wallets_home.dart'; import 'package:gecko/widgets/balance.dart';
import 'package:gecko/widgets/commons/smooth_transition.dart'; import 'package:gecko/widgets/commons/smooth_transition.dart';
import 'package:gecko/widgets/name_by_address.dart'; import 'package:gecko/widgets/name_by_address.dart';
class WalletTile extends StatelessWidget { class WalletTile extends StatelessWidget {
const WalletTile( const WalletTile({
{Key? key, Key? key,
required this.repository, required this.repository,
required this.walletOptions, required this.defaultWallet,
required this.defaultWallet, }) : super(key: key);
required this.currentChestNumber})
: super(key: key);
final WalletData repository; final WalletData repository;
final WalletOptionsProvider walletOptions;
final WalletData defaultWallet; final WalletData defaultWallet;
final int currentChestNumber;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -31,7 +25,6 @@ class WalletTile extends StatelessWidget {
child: GestureDetector( child: GestureDetector(
key: keyOpenWallet(repository.address), key: keyOpenWallet(repository.address),
onTap: () { onTap: () {
walletOptions.getAddress(currentChestNumber, repository.derivation!);
Navigator.push( Navigator.push(
context, context,
SmoothTransition( SmoothTransition(
@ -121,3 +114,95 @@ class WalletTile extends StatelessWidget {
); );
} }
} }
class BalanceBuilder extends StatelessWidget {
const BalanceBuilder({
Key? key,
required this.address,
required this.isDefault,
}) : super(key: key);
final String address;
final bool isDefault;
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
color: isDefault ? orangeC : yellowC,
child: Padding(
padding:
const EdgeInsets.only(left: 5, right: 5, top: 38, bottom: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Opacity(
opacity: 0.7,
child: Balance(
address: address,
size: 16,
color: isDefault ? Colors.white : Colors.black,
loadingColor: isDefault ? yellowC : orangeC),
)
],
)),
);
}
}
class ClipOvalShadow extends StatelessWidget {
final Shadow shadow;
final CustomClipper<Rect> clipper;
final Widget child;
const ClipOvalShadow({
Key? key,
required this.shadow,
required this.clipper,
required this.child,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return CustomPaint(
painter: _ClipOvalShadowPainter(
clipper: clipper,
shadow: shadow,
),
child: ClipRect(clipper: clipper, child: child),
);
}
}
class _ClipOvalShadowPainter extends CustomPainter {
final Shadow shadow;
final CustomClipper<Rect> clipper;
_ClipOvalShadowPainter({required this.shadow, required this.clipper});
@override
void paint(Canvas canvas, Size size) {
var paint = shadow.toPaint();
var clipRect = clipper.getClip(size).shift(const Offset(0, 0));
canvas.drawOval(clipRect, paint);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
class CustomClipperOval extends CustomClipper<Rect> {
@override
Rect getClip(Size size) {
return Rect.fromCircle(
center: Offset(size.width / 2, size.width / 2),
radius: size.width / 2 + 3);
}
@override
bool shouldReclip(CustomClipper<Rect> oldClipper) {
return false;
}
}

View File

@ -0,0 +1,209 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:gecko/globals.dart';
import 'package:gecko/models/wallet_data.dart';
import 'package:gecko/models/widgets_keys.dart';
import 'package:gecko/screens/myWallets/wallet_options.dart';
import 'package:gecko/widgets/balance.dart';
import 'package:gecko/widgets/commons/smooth_transition.dart';
import 'package:gecko/widgets/name_by_address.dart';
class WalletTileMembre extends StatelessWidget {
const WalletTileMembre({
Key? key,
required this.repository,
required this.defaultWallet,
}) : super(key: key);
final WalletData repository;
final WalletData defaultWallet;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 70, vertical: 20),
child: GestureDetector(
key: keyOpenWallet(repository.address),
onTap: () {
Navigator.push(
context,
SmoothTransition(
page: WalletOptions(
wallet: repository,
),
),
);
},
child: SizedBox(
key: repository.number == 1 ? keyDragAndDrop : const Key('nothing'),
height: 240,
child: ClipOvalShadow(
shadow: const Shadow(
color: Colors.transparent,
offset: Offset(0, 0),
blurRadius: 5,
),
clipper: CustomClipperOval(),
child: ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(12)),
child: Column(children: <Widget>[
Expanded(
child: Container(
width: double.infinity,
height: double.infinity,
decoration: const BoxDecoration(
gradient: RadialGradient(
radius: 0.8,
colors: [
Color.fromARGB(255, 255, 255, 211),
yellowC,
],
),
),
child: repository.imageCustomPath == null ||
repository.imageCustomPath == ''
? Image.asset(
'assets/avatars/${repository.imageDefaultPath}',
alignment: Alignment.bottomCenter,
scale: 0.5,
)
: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.transparent,
image: DecorationImage(
fit: BoxFit.fitHeight,
image: FileImage(
File(repository.imageCustomPath!),
),
),
),
),
)),
Stack(children: <Widget>[
BalanceBuilder(
address: repository.address,
isDefault: repository.address == defaultWallet.address),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Column(
children: [
const SizedBox(height: 7),
Opacity(
opacity: 0.7,
child: NameByAddress(
wallet: repository,
size: 20,
color:
defaultWallet.address == repository.address
? Colors.white
: Colors.black,
fontWeight: FontWeight.w600,
fontStyle: FontStyle.normal,
))
],
),
],
),
]),
]),
),
),
),
),
);
}
}
class BalanceBuilder extends StatelessWidget {
const BalanceBuilder({
Key? key,
required this.address,
required this.isDefault,
}) : super(key: key);
final String address;
final bool isDefault;
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
color: isDefault ? orangeC : yellowC,
child: Padding(
padding:
const EdgeInsets.only(left: 5, right: 5, top: 45, bottom: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Opacity(
opacity: 0.7,
child: Balance(
address: address,
size: 16,
color: isDefault ? Colors.white : Colors.black,
loadingColor: isDefault ? yellowC : orangeC),
)
],
)),
);
}
}
class ClipOvalShadow extends StatelessWidget {
final Shadow shadow;
final CustomClipper<Rect> clipper;
final Widget child;
const ClipOvalShadow({
Key? key,
required this.shadow,
required this.clipper,
required this.child,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return CustomPaint(
painter: _ClipOvalShadowPainter(
clipper: clipper,
shadow: shadow,
),
child: ClipRect(clipper: clipper, child: child),
);
}
}
class _ClipOvalShadowPainter extends CustomPainter {
final Shadow shadow;
final CustomClipper<Rect> clipper;
_ClipOvalShadowPainter({required this.shadow, required this.clipper});
@override
void paint(Canvas canvas, Size size) {
var paint = shadow.toPaint();
var clipRect = clipper.getClip(size).shift(const Offset(0, 0));
canvas.drawOval(clipRect, paint);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
class CustomClipperOval extends CustomClipper<Rect> {
@override
Rect getClip(Size size) {
return Rect.fromCircle(
center: Offset(size.width / 2, size.width / 2),
radius: size.width / 2 + 3);
}
@override
bool shouldReclip(CustomClipper<Rect> oldClipper) {
return false;
}
}