Merge branch 'end2EndTests' into 'master'

End2end tests

See merge request clients/gecko!28
This commit is contained in:
pokapow 2022-09-05 09:47:27 +02:00
commit 549996578b
62 changed files with 1498 additions and 1436 deletions

1
.env Normal file
View File

@ -0,0 +1 @@
ip_address=127.0.0.1

3
.gitignore vendored
View File

@ -55,4 +55,5 @@ scripts/private/
AppDir/
appimage-builder-cache/
AppImageBuilder.yml
android/app/build.gradle
android/app/build.gradle
integration_test/duniter/data/chains/

View File

@ -5,7 +5,7 @@ stages:
- package
.env:
image: axiomteam/gecko-ci:v0.0.9
image: axiomteam/gecko-ci:v0.0.11
tags:
- redshift

View File

@ -148,7 +148,7 @@
"seeAWallet": "Voir un portefeuille",
"mustWaitXBeforeCertify": "Vous devez attendre\n{} avant\nde pouvoir certifier",
"mustConfirmHisIdentity": "Cette personne doit confirmer\nson identité avant de pouvoir\nêtre certifié",
"canRenewCertInX": "Vous pourrez renouveller\ncette certification\ndans {}",
"canRenewCertInX": "Vous pourrez renouveler\ncette certification\ndans {}",
"executeATransfer": "Effectuer un virement",
"executeTheTransfer": "Effectuer le virement",
"doATransfer": "Faire un\nvirement",

128
integration_test/README.md Normal file
View File

@ -0,0 +1,128 @@
# Context des tests
Chaque test est précédé par le lancement d'un noeud Duniter v2s en docker [dont voici le compose](https://git.duniter.org/clients/gecko/-/blob/end2EndTests/integration_test/duniter/docker-compose.yml).
Voici le yaml de configuration de la monnaie de test éphémère: https://git.duniter.org/clients/gecko/-/blob/end2EndTests/integration_test/duniter/data/gecko_tests.json
Voici le mnemonic de test utilisé:
`pipe paddle ketchup filter life ice feel embody glide quantum ride usage`
Et les 5 premiers portefeuilles Gecko associés:
```
test1: 5FeggKqw2AbnGZF9Y9WPM2QTgzENS3Hit94Ewgmzdg5a3LNa
test2: 5E4i8vcNjnrDp21Sbnp32WHm2gz8YP3GGFwmdpfg5bHd8Whb
test3: 5FhTLzXLNBPmtXtDBFECmD7fvKmTtTQDtvBTfVr97tachA1p
test4: 5DXJ4CusmCg8S1yF6JGVn4fxgk5oFx42WctXqHZ17mykgje5
test5: 5Dq3giahrBfykJogPetZJ2jjSmhw49Fa7i6qKkseUvRJ2T3R
```
Seul les 4 premiers sont membres au démarrage.
Voici le scénario de test principal que j'ai réalisé pour le moment
Scénario 1
- Changer le noeud Duniter pour se connecter au nœud local (l'ip local est récupéré automatiquement, car le nœud est sur le host (votre pc), alors que l'app est dans son émulateur)
- Importer le coffre de test
- Effectuer une transaction du Portefeuille 1 (test1) vers le portefeuille 5 (test5)
- Vérifier que les frais de créations de compte ont bien été prélevés
- Certifier test5 avec test1, test2 et test3 et vérifier qu'il deviens bien membre
- Créer 10 blocs, puis encore 10, puis 30 de plus et vérifier à chaque fois si le compte génère bien ses DU à la bonne valeur, réévaluation comprise au bloc 50.
Des vérifications sur l'état du texte affiché à l'écran ou des widgets affichés ou non sont fait entre chaque étapes pour vérifier que tout ce passe toujours bien.
Si la moindre erreur intervient, le test s'arrête et vous informe de l'erreur en question.
Voici le code du test contenant ce scénario: https://git.duniter.org/clients/gecko/-/blob/end2EndTests/integration_test/gecko_complete.dart
Ce test dur environ 1 minutes et 15 seconds, compilation et lancement de nœud au démarrage inclus.
Voici le rendu (attention ça va assez vite ^^) :
https://tube.p2p.legal/w/kMc5c8KnLi9BpwJrM4EnKX
On remarque notamment que des blocs sont créés uniquement et directement après un extrinsic lancé depuis l'app
---
# Tuto contributeurs
**Il n'est nécessaire ni de connaître le code de Ğecko, ni de connaître Dart/flutter pour écrire un nouveau scénario de test !**
Il vous suffit de comprendre par exemple cet extrait de code:
```
// Copy test mnemonic in clipboard
await clipCopy(testMnemonic);
// Open screen import chest
await goKey(keyRestoreChest, duration: 0);
// Tap on button to paste mnemonic
await goKey(keyPastMnemonic);
// Tap on next button 4 times to skip 3 screen
await goKey(keyGoNext);
await goKey(keyGoNext);
await goKey(keyGoNext);
await goKey(keyGoNext);
// Check if cached password checkbox is checked
final isCached = await isIconPresent(Icons.check_box);
// If not, tap on to cache password
if (!isCached) await goKey(keyCachePassword, duration: 0);
// Enter password
await enterText(keyPinForm, 'AAAAA', 0);
// Check if string "Accéder à mon coffre" is present in screen
await waitFor('Accéder à mon coffre');
// Go to wallets home
await goKey(keyGoWalletsHome, duration: 0);
// Check if string "ĞD" is present in screen
await waitFor('ĞD');
// Tap on add a new derivation button
await addDerivation();
// Tap on Wallet 5
await goKey(keyOpenWallet(test5.address));
// Copy address of Wallet 5
await goKey(keyCopyAddress);
// Check if string "Cette adresse a été copié" is present in screen
await waitFor('Cette adresse a été copié');
// Pop screen 2 time to go back home
await goBack();
await goBack();
// Create a new bloc (useless here, just to show you the method)
await spawnBlock();
// Check if string "y'a pas de lézard" is present in screen
await waitFor("y'a pas de lézard");
```
Vous avez dans ce bout de code commenté tous ce dont vous avez besoin pour effectuer un test d'intégration dans Ğecko :slight_smile:
Vous trouverez toutes les clés de widgets disponibles dans l'app dans ce fichier: https://git.duniter.org/clients/gecko/-/blob/end2EndTests/lib/models/widgets_keys.dart
Ce sont ces clés qui vous permette dinteragir avec les widgets de l'app depuis votre test.
Pour créer un nouveau test **à partir de zero**, voici la marche à suivre:
- Suivez [le readme](https://git.duniter.org/clients/gecko/-/blob/master/README.md) pour configurer votre environnement de développement et ainsi pouvoir lancer Ğecko en mode debug dans un émulateur.
- Créer un nouveau fichier pour votre test dans le dossier `integration_test` (ici nous lappellerons `mon_test.dart`)
- Prenez exemple sur le fichier `gecko_complete.dart` pour écrire votre test
- Lancer un émulateur android (1 seul)
- Exécutez votre test ainsi: `./integration_test/launch_test.sh mon_test`
Créer toute sorte de tests imaginable dans Ğecko est très utile pour éviter un maximum les régressions de bugs entre les différentes versions.
Si vous avez envie de nous aider, que vous ne savez presque pas coder mais que vous êtes prêt à mettre un peu les mains dans la sauce, et que vous avez une idée de scénario à tester, alors n'hésitez pas, je répondrais à toutes vos questions :slight_smile:
A noter que ces tests permettent de tester Gecko mais aussi partiellement Duniter et l'indexer d'une même pierre.

View File

@ -1,447 +0,0 @@
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:gecko/main.dart' as app;
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
int globalTimeout = 2;
group(
'Gecko end-to-end tests',
() {
// First, define the Finders and use them to locate widgets from the
// test suite. Note: the Strings provided to the `byValueKey` method must
// be the same as the Strings we used for the Keys in step 1.
// final manageWalletsFinder = find.byKey(Key('manageWallets'));
// final buttonFinder = find.byValueKey('increment');
// FlutterDriver driver;
WidgetTester tester;
String pinCode;
// *** Global functions *** //
// Easy get text
Future<String> getText(String text) async {
Text resultText = tester.firstWidget(find.byKey(Key(text)));
// Text pinCodeText = generatedPinFinder.evaluate().single.widget as Text;
return resultText.data;
}
// Function to tap the widget by key
Future tapOn(String key) async {
await tester.tap(find.byKey(Key(key)));
}
// Function to go back to previous screen
Future goBack() async {
await Process.run(
'adb',
<String>['shell', 'input', 'keyevent', 'KEYCODE_BACK'],
runInShell: true,
);
}
// Easy sleep
Future sleep(int _time) async {
await Future.delayed(Duration(milliseconds: _time));
}
// Test if widget exist on screen, return a boolean
Future<bool> isPresent(String text,
{Duration timeout = const Duration(seconds: 1)}) async {
try {
expect(text, findsOneWidget);
return true;
} catch (exception) {
return false;
}
}
// Create a derivation
Future createDerivation(String _name) async {
await tapOn('addDerivation');
await sleep(100);
await tester.enterText(find.byKey(Key('DerivationNameKey')), _name);
await tapOn('validDerivation');
await sleep(300);
}
// Delete a derivation
Future deleteWallet(bool _confirm) async {
await tapOn('deleteWallet');
await sleep(100);
_confirm
? await tapOn('confirmDeleting')
: await tapOn('cancelDeleting');
await sleep(300);
}
// Delete all wallets
Future deleteAllWallets() async {
await tester.tap(find.byKey(Key('drawerMenu')));
await sleep(300);
await tester.tap(find.byKey(Key('parameters')));
await sleep(300);
await tester.tap(find.byKey(Key('deleteAllWallets')));
await sleep(300);
await tester.tap(find.byKey(Key('confirmDeletingAllWallets')));
await sleep(300);
}
// Fast creation of new Keychain
Future<String> createNewKeychain(String name) async {
await tapOn('drawerMenu');
await sleep(300);
await tapOn('parameters');
await sleep(300);
await tapOn('generateKeychain');
expect(find.text(''), findsOneWidget);
pinCode = await getText('generatedPin');
await tapOn('storeKeychain');
await sleep(100);
await tester.enterText(find.byKey(Key('askedWord')), 'triche');
await tapOn('walletName');
await tester.enterText(find.byKey(Key('walletName')), 'name');
await tapOn('confirmStorage');
await sleep(300);
return pinCode;
}
// *** Begin of tests *** //
testWidgets('OnBoarding - Open wallets management', (
WidgetTester tester, {
timeout: Timeout.none,
}) async {
app.main();
await tester.pumpAndSettle();
// expect("y'a pas de lézard !", findsOneWidget);
await tester.tap(find.byKey(Key('manageWallets')));
print(
'####################################################################');
// If a wallet exist, go to delete theme all
await tester.pumpAndSettle();
if (!await isPresent(
"Je ne connais pour linstant aucun de vos portefeuilles.\n\nVous pouvez en créer un nouveau, ou bien importer un portefeuille Cesium existant.")) {
await tester.pumpAndSettle();
// await tester.pageBack();
await goBack();
await sleep(500);
await deleteAllWallets();
await sleep(300);
await tester.tap(find.byKey(Key('manageWallets')));
}
await tester.pumpAndSettle();
// Verify onboarding is starting, with text
expect(
"Je ne connais pour linstant aucun de vos portefeuilles.\n\nVous pouvez en créer un nouveau, ou bien importer un portefeuille Cesium existant.",
findsOneWidget);
});
// test('OnBoarding - Go to create restore sentance', (
// {timeout: Timeout.none}) async {
// await tapOn('goStep1');
// await tapOn('goStep2');
// await tapOn('goStep3');
// await tapOn('goStep4');
// await tapOn('goStep5');
// await tapOn('goStep6');
// expect(
// "Jai généré votre phrase de restauration !\nTâchez de la garder bien secrète, car elle permet à quiconque la connaît daccéder à tous vos portefeuilles.",
// findsOneWidget);
// });
// test('OnBoarding - Generate sentance and confirme it', (
// {timeout: Timeout.none}) async {
// await tapOn('goStep7');
// await tester.pumpAndSettle();
// Future selectWord() async {
// List words = [for (var i = 1; i <= 13; i += 1) i];
// for (var j = 1; j < 13; j++) {
// words[j] = await getText('word$j');
// }
// expect(await getText('step7'),
// "C'est le moment de noter votre phrase !");
// await tapOn('goStep8');
// await sleep(200);
// String goodWord = words[int.parse(
// await getText('askedWord'),
// )];
// // Enter the expected word
// await tester.enterText(find.byKey(Key('inputWord')), goodWord);
// // Check if word is valid
// expect(find.text("C'est le bon mot !"), findsOneWidget);
// // Continue onboarding workflow
// await tapOn('goStep9');
// }
// await selectWord();
// //Go back 2 times to mnemonic generation screen
// await goBack();
// await goBack();
// await sleep(100);
// // Generate 3 times mnemonic
// await tapOn('generateMnemonic');
// await tapOn('generateMnemonic');
// await tapOn('generateMnemonic');
// await sleep(500);
// await selectWord();
// });
// test('OnBoarding - Generate secret code and confirm it', (
// {timeout: Timeout.none}) async {
// expect(await getText('step9'),
// "Super !\n\nJe vais maintenant créer votre code secret. \n\nVotre code secret chiffre votre trousseau de clefs, ce qui le rend inutilisable par dautres, par exemple si vous perdez votre téléphone ou si on vous le vole.");
// await tapOn('goStep10');
// await tapOn('goStep11');
// while (await getText('generatedPin') == '') {
// print('Waiting for pin code generation...');
// await sleep(100);
// }
// // Change secret code 4 times
// for (int i = 0; i < 4; i++) await tapOn('changeSecretCode');
// await sleep(500);
// pinCode = await getText('generatedPin');
// await tapOn('goStep12');
// await sleep(300);
// // //Enter bad secret code
// // await tester.enterText('abcde');
// // await tapOn('formKey');
// // await sleep(1500);
// // await tapOn('formKey2');
// //Enter good secret code
// await tester.enterText(find.byKey(Key('formKey2')), pinCode);
// expect(await getText('step13'),
// "Top !\n\nVotre trousseau de clef et votre portefeuille ont été créés avec un immense succès.\n\nFélicitations !");
// });
// test('My wallets - Rename first derivation', (
// {timeout: const Duration(seconds: 2)}) async {
// await tapOn('goWalletHome');
// expect(await getText('myWallets'), "Mes portefeuilles");
// await sleep(300);
// // Go to first derivation and rename it
// await tester.tap(find.text('Mon portefeuille courant'));
// await sleep(300);
// await tapOn('renameWallet');
// await sleep(100);
// await tapOn('walletName');
// await sleep(100);
// await tester.enterText(
// find.byKey(Key('walletName')), 'Renommage wallet 1');
// await sleep(300);
// await tapOn('renameWallet');
// await sleep(400);
// expect('Renommage wallet 1', findsOneWidget);
// await goBack();
// });
// test('My wallets - Create a derivations, open thems, tap all buttons', (
// {timeout: const Duration(seconds: 2)}) async {
// expect('Renommage wallet 1', findsOneWidget);
// // Add a second derivation
// await createDerivation('Derivation 2');
// // Go to second derivation options
// await tester.tap(find.text('Derivation 2'));
// await sleep(100);
// // Test options
// await tapOn('displayBalance');
// await tapOn('displayHistory');
// await sleep(300);
// await goBack();
// await tapOn('displayBalance');
// await sleep(100);
// await tapOn('displayBalance');
// await sleep(100);
// await tapOn('displayBalance');
// await tapOn('setDefaultWallet');
// await sleep(50);
// await tapOn('copyPubkey');
// expect('Cette clé publique a été copié dans votre presse-papier.',
// findsOneWidget);
// await goBack();
// // Add a third derivation
// await createDerivation('Derivation 3');
// // Add a fourth derivation
// await createDerivation('Derivation 4');
// await sleep(50);
// // Go to third derivation options
// await tester.tap(find.text('Derivation 3'));
// await sleep(100);
// await tapOn('displayBalance');
// // Delete third derivation
// await deleteWallet(true);
// });
// test('My wallets - Extra tests', (
// {timeout: const Duration(seconds: 2)}) async {
// // Add derivation 5,6 and 7
// expect('Derivation 4', findsOneWidget);
// await createDerivation('Derivation 5');
// await createDerivation('Derivation 6');
// await createDerivation('Derivation 7');
// // Go home and come back to my wallets view
// await goBack();
// await sleep(100);
// await tapOn('manageWallets');
// await sleep(200);
// //Enter secret code
// await tester.enterText(find.byKey(Key('formKey')), pinCode);
// await sleep(200);
// // Go to derivation 6 and delete it
// await tester.tap(find.text('Derivation 6'));
// await sleep(100);
// await deleteWallet(true);
// // Go to 2nd derivation and check if it's de default
// await tester.tap(find.text('Derivation 2'));
// expect('Ce portefeuille est celui par defaut', findsOneWidget);
// await tapOn('setDefaultWallet');
// await sleep(100);
// expect('Ce portefeuille est celui par defaut', findsOneWidget);
// await sleep(300);
// // Display history, copy pubkey, go back and rename wallet name
// await tapOn('displayHistory');
// await sleep(400);
// await tapOn('copyPubkey');
// expect('Cette clé publique a été copié dans votre presse-papier.',
// findsOneWidget);
// await sleep(800);
// await goBack();
// await sleep(300);
// await tapOn('renameWallet');
// await sleep(100);
// await tapOn('walletName');
// await sleep(100);
// await tester.enterText(
// find.byKey(Key('walletName')), 'Renommage wallet 2');
// await sleep(300);
// await tapOn('renameWallet');
// await sleep(400);
// await goBack();
// expect('Renommage wallet 2', findsOneWidget);
// await createDerivation('Derivation 8');
// await createDerivation('Derivation 9');
// await createDerivation('Derivation 10');
// await createDerivation('Derivation 11');
// await createDerivation('Derivation 12');
// await createDerivation('Derivation 13');
// await createDerivation('Derivation 14');
// await createDerivation('Derivation 15');
// await createDerivation('Derivation 16');
// await createDerivation('Derivation 17');
// await createDerivation('Derivation 18');
// await createDerivation('Derivation 19');
// await createDerivation('Derivation 20');
// await sleep(400);
// // Scroll the wallet screen until Derivation 20 and open it
// await tester.scrollUntilVisible(find.byKey(Key('listWallets')), -300.0);
// expect('Derivation 20', findsOneWidget);
// await sleep(400);
// await tester.tap(find.text('Derivation 20'));
// await tapOn('copyPubkey');
// });
// test('Search - Search Pi profile, navigate in history transactions', (
// {timeout: const Duration(seconds: 2)}) async {
// expect('Derivation 20', findsOneWidget);
// await goBack();
// await goBack();
// await sleep(200);
// await tapOn('searchIcon');
// await sleep(400);
// await tester.enterText(find.byKey(Key('searchInput')),
// 'D2meevcAHFTS2gQMvmRW5Hzi25jDdikk4nC4u1FkwRaU');
// await sleep(100);
// await tapOn('copyPubkey');
// await sleep(500);
// await tapOn('switchPayHistory');
// await sleep(1200);
// // await tester.scrollIntoView(find.byValueKey('listTransactions'));
// await tester.scrollUntilVisible(
// find.byKey(Key('listTransactions')),
// -600.0,
// );
// await sleep(100);
// await tapOn('transaction33');
// expect('Commentaire:', findsOneWidget);
// // Want to paste pubkey copied, but doesn't work actualy with flutter driver: https://github.com/flutter/flutter/issues/47448
// // final ClipboardData pubkeyCopied =
// // await Clipboard.getData(Clipboard.kTextPlain);
// // await tester.enterText(pubkeyCopied.text);
// await sleep(300);
// }, timeout: Timeout(Duration(minutes: globalTimeout)));
// test('Wallet generation - Fast wallets generations', (
// {timeout: const Duration(seconds: 2)}) async {
// expect('Commentaire:', findsOneWidget);
// await goBack();
// await goBack();
// await deleteAllWallets();
// await sleep(100);
// final String pincode = await createNewKeychain('Fast wallet');
// await sleep(100);
// await tapOn('manageWallets');
// await sleep(200);
// await tester.enterText(find.byKey(Key('formKey')), pinCode);
// await sleep(100);
// await createDerivation('Derivation 2');
// await sleep(100);
// await tester.tap(find.text('Fast wallet'));
// expect('Fast wallet', findsOneWidget);
// // Wait 3 seconds at the end
// await sleep(3000);
// });
},
);
}

View File

@ -0,0 +1,55 @@
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:gecko/globals.dart';
import 'package:gecko/models/widgets_keys.dart';
import 'package:integration_test/integration_test.dart';
import 'general_actions.dart';
import 'tests_utility.dart';
void main() async {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
await dotenv.load();
testWidgets('Certifications state', (testerLoc) async {
tester = testerLoc;
// Connect local node and import test chest in background
await bkFastStart();
// Open chest
await firstOpenChest();
await goBack();
// Go wallet 5 view
await tapKey(keyOpenSearch);
await enterText(keySearchField, test5.address);
await tapKey(keyConfirmSearch);
await waitFor(test5.shortAddress());
await tapKey(keySearchResult(test5.address));
await waitFor('Certifier');
await waitFor('Vous devez ', reverse: true);
await waitFor('Vous pourrez renouveler ', reverse: true);
// Background pay 25
await bkPay(
fromAddress: test1.address, destAddress: test5.address, amount: 25);
await waitFor('25.0 $currencyName');
await spawnBlock();
await waitFor('22.0 $currencyName');
await bkCertify(fromAddress: test1.address, destAddress: test5.address);
await waitFor('1', exactMatch: true);
await bkConfirmIdentity(fromAddress: test5.address, name: test5.name);
await bkCertify(fromAddress: test2.address, destAddress: test5.address);
await waitFor('2', exactMatch: true);
await bkCertify(fromAddress: test3.address, destAddress: test5.address);
await waitFor('3', exactMatch: true);
await bkCertify(fromAddress: test4.address, destAddress: test5.address);
await waitFor('4', exactMatch: true);
await bkPay(
fromAddress: test2.address, destAddress: test5.address, amount: 40);
await waitFor('61.99 $currencyName');
await spawnBlock(until: 10);
await waitFor('161.99 $currencyName');
await spawnBlock(until: 20);
await waitFor('261.99 $currencyName');
}, timeout: testTimeout());
}

View File

@ -0,0 +1,79 @@
{
"first_ud": 10000,
"first_ud_reeval": 50,
"genesis_parameters": {
"genesis_certs_expire_on": 500,
"genesis_certs_min_received": 3,
"genesis_memberships_expire_on": 1051200,
"genesis_smith_certs_expire_on": 2102400,
"genesis_smith_certs_min_received": 3,
"genesis_smith_memberships_expire_on": 1051200
},
"identities": {
"test1": {
"balance": 10000,
"certs": ["test2", "test3", "test4"],
"pubkey": "5FeggKqw2AbnGZF9Y9WPM2QTgzENS3Hit94Ewgmzdg5a3LNa"
},
"test2": {
"balance": 10000,
"certs": ["test1", "test3", "test4"],
"pubkey": "5E4i8vcNjnrDp21Sbnp32WHm2gz8YP3GGFwmdpfg5bHd8Whb"
},
"test3": {
"balance": 10000,
"certs": ["test1", "test2", "test4"],
"pubkey": "5FhTLzXLNBPmtXtDBFECmD7fvKmTtTQDtvBTfVr97tachA1p"
},
"test4": {
"balance": 10000,
"certs": ["test1", "test2", "test3"],
"pubkey": "5DXJ4CusmCg8S1yF6JGVn4fxgk5oFx42WctXqHZ17mykgje5"
},
"testCesium1": {
"balance": 10000,
"certs": ["test1", "test2", "test3"],
"pubkey": "5GAT6CJW8yVKwUuQc7sM5Kk9GZVTpbZYk9PfjNXtvnNgAJZ1"
}
},
"parameters": {
"babe_epoch_duration": 30,
"cert_period": 15,
"cert_max_by_issuer": 10,
"cert_min_received_cert_to_issue_cert": 2,
"cert_validity_period": 1000,
"idty_confirm_period": 40,
"idty_creation_period": 50,
"membership_period": 1000,
"pending_membership_period": 500,
"ud_creation_period": 10,
"ud_reeval_period": 50,
"smith_cert_period": 15,
"smith_cert_max_by_issuer": 8,
"smith_cert_min_received_cert_to_issue_cert": 2,
"smith_cert_validity_period": 1000,
"smith_membership_period": 1000,
"smith_pending_membership_period": 500,
"smiths_wot_first_cert_issuable_on": 20,
"smiths_wot_min_cert_for_membership": 3,
"wot_first_cert_issuable_on": 0,
"wot_min_cert_for_create_idty_right": 3,
"wot_min_cert_for_membership": 3
},
"smiths": {
"test1": {
"certs": ["test2", "test3", "test4"]
},
"test2": {
"certs": ["test1", "test3", "test4"]
},
"test3": {
"certs": ["test1", "test2", "test4"]
},
"test4": {
"certs": ["test1", "test2", "test3"]
}
},
"sudo_key": "5FeggKqw2AbnGZF9Y9WPM2QTgzENS3Hit94Ewgmzdg5a3LNa",
"technical_committee": ["test1", "test2", "test3"]
}

View File

@ -0,0 +1,18 @@
version: "3.5"
services:
duniter-v2s-gecko-tests:
container_name: duniter-v2s-gecko-tests
image: duniter/duniter-v2s:debug-latest
command: --sealing=manual
ports:
- "127.0.0.1:9615:9615"
- "127.0.0.1:9933:9933"
- "0.0.0.0:9944:9944"
- "30333:30333"
environment:
DUNITER_INSTANCE_NAME: "gecko_tests"
DUNITER_CHAIN_NAME: "dev"
DUNITER_GENESIS_CONFIG: "/var/lib/duniter/gecko_tests.json"
volumes:
- ./data:/var/lib/duniter

View File

@ -0,0 +1,139 @@
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:gecko/models/widgets_keys.dart';
import 'package:integration_test/integration_test.dart';
import 'general_actions.dart';
import 'tests_utility.dart';
void main() async {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
await dotenv.load();
testWidgets('Gecko complete', (testerLoc) async {
// Share WidgetTester to test provider
tester = testerLoc;
// Start app and wait finish starting
await startWait();
// Change Duniter endpoint to local
await changeNode();
// Delete all existing chests is exists
await deleteAllWallets();
// Restore the test chest
await restoreChest();
// Execute a transaction to test5
await payTest2();
// Certify test5 account with 3 accounts to become member
await certifyTest5();
}, timeout: testTimeout());
}
Future payTest2() async {
await waitFor('Rechercher');
await tapKey(keyOpenSearch);
final addressToSearch = await clipPaste();
final endAddress = addressToSearch.substring(addressToSearch.length - 6);
expect(addressToSearch, test5.address);
await enterText(keySearchField, addressToSearch);
await tapKey(keyConfirmSearch);
await waitFor(endAddress);
await tapKey(keySearchResult(addressToSearch));
await waitFor(endAddress);
await waitFor('0.0 ĞD');
await tapKey(keyPay);
await enterText(keyAmountField, '12.14');
await tapKey(keyConfirmPayment);
spawnBlock(duration: 500);
await waitFor('validé !', timeout: const Duration(seconds: 1));
await tapKey(keyCloseTransactionScreen, duration: 0);
await waitFor('12.14');
spawnBlock(duration: 500);
await waitFor('9.14');
humanRead(2);
}
Future certifyTest5() async {
// Create identity with Test1 account
await tapKey(keyCertify);
await tapKey(keyConfirm);
spawnBlock(duration: 500);
await waitFor('validé !', timeout: const Duration(seconds: 1));
await tapKey(keyCloseTransactionScreen);
await waitFor('Identité créée');
// Confirm Identity Test5
await tapKey(keyAppBarChest, duration: 300);
await tapKey(keyOpenWallet(test5.address));
await tapKey(keyCopyAddress);
humanRead(3);
await tapKey(keyConfirmIdentity);
await enterText(keyEnterIdentityUsername, test5.name);
await tapKey(keyConfirm);
spawnBlock(duration: 500);
await waitFor('validé !', timeout: const Duration(seconds: 1));
await tapKey(keyCloseTransactionScreen);
await waitFor('Identité confirmée');
humanRead(2);
// Set wallet 2 as default wallet
await goBack();
await tapKey(keyOpenWallet(test2.address));
await tapKey(keySetDefaultWallet);
await waitFor('Ce portefeuille est celui par defaut');
// Search Wallet 5 again
await tapKey(keyAppBarSearch);
final addressToSearch = await clipPaste();
final endAddress = addressToSearch.substring(addressToSearch.length - 6);
expect(addressToSearch, test5.address);
await enterText(keySearchField, addressToSearch);
await tapKey(keyConfirmSearch);
await waitFor(endAddress);
await tapKey(keySearchResult(addressToSearch));
await waitFor(endAddress);
await waitFor('1');
// Certify with test2 account
await tapKey(keyCertify);
await tapKey(keyConfirm);
spawnBlock(duration: 500);
await waitFor('validé !', timeout: const Duration(seconds: 1));
await tapKey(keyCloseTransactionScreen);
await waitFor('2');
// Change default wallet to test3
await tapKey(keyPay);
await tapKey(keyChangeChest);
await tapKey(keySelectThisWallet(test3.address));
await tapKey(keyConfirm);
await sleep();
// Certify with test3 account
await tapKey(keyCertify);
await tapKey(keyConfirm);
spawnBlock(duration: 500);
await waitFor('validé !', timeout: const Duration(seconds: 1));
await tapKey(keyCloseTransactionScreen);
await waitFor('Vous devez attendre');
// Check if test5 is member
await tapKey(keyAppBarChest, duration: 300);
await tapKey(keyOpenWallet(test5.address));
await waitFor('Membre validé !');
// spawn 20 blocs and check if ud is creating
await spawnBlock(until: 10);
await waitFor('109.13');
await spawnBlock(until: 20);
await waitFor('209.13');
// Check UD reval
await spawnBlock(until: 50);
await waitFor('509.36');
humanRead(5);
}

View File

@ -0,0 +1,163 @@
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:gecko/globals.dart';
import 'package:gecko/models/widgets_keys.dart';
import 'package:gecko/providers/generate_wallets.dart';
import 'package:provider/provider.dart';
import 'tests_utility.dart';
// GENERAL ACTIONS
Future changeNode() async {
final ipAddress = dotenv.env['ip_address'] ?? '127.0.0.1';
log.d('ip address: $ipAddress');
await tapKey(keyDrawerMenu);
await tapKey(keyParameters);
await tapKey(keySelectDuniterNodeDropDown, duration: 5);
await tapKey(keySelectDuniterNode('Personnalisé'), selectLast: true);
await enterText(keyCustomDuniterEndpoint, 'ws://$ipAddress:9944');
await tapKey(keyConnectToEndpoint);
await isIconPresent(Icons.add_card_sharp,
timeout: const Duration(seconds: 8));
await goBack();
}
Future deleteAllWallets() async {
if (await isPresent('Rechercher')) {
await tapKey(keyDrawerMenu);
await tapKey(keyParameters);
await tapKey(keyDeleteAllWallets);
await tapKey(keyConfirm);
await tester.pumpAndSettle();
}
}
Future restoreChest() async {
// Copy test mnemonic in clipboard
await clipCopy(testMnemonic);
// Open screen import chest
await tapKey(keyRestoreChest, duration: 0);
// Tap on button to paste mnemonic
await tapKey(keyPastMnemonic);
// Tap on next button 4 times to skip 3 screen
await tapKey(keyGoNext);
await tapKey(keyGoNext);
await tapKey(keyGoNext);
await tapKey(keyGoNext);
// Check if cached password checkbox is checked
final isCached = await isIconPresent(Icons.check_box);
// If not, tap on to cache password
if (!isCached) await tapKey(keyCachePassword, duration: 0);
// Enter password
await enterText(keyPinForm, 'AAAAA', 0);
// Check if string "Accéder à mon coffre" is present in screen
await waitFor('Accéder à mon coffre');
// Go to wallets home
await tapKey(keyGoWalletsHome, duration: 0);
// Check if string "ĞD" is present in screen
await waitFor('ĞD');
// Tap on add a new derivation button
await addDerivation();
// Tap on Wallet 5
await tapKey(keyOpenWallet(test5.address));
// Copy address of Wallet 5
await tapKey(keyCopyAddress);
// Check if string "Cette adresse a été copié" is present in screen
await waitFor('Cette adresse a été copié');
// Pop screen 2 time to go back home
await goBack();
await goBack();
}
Future onboardingNewChest() async {
final generateWalletProvider =
Provider.of<GenerateWalletsProvider>(homeContext, listen: false);
// Open screen create new wallet
await tapKey(keyOnboardingNewChest);
// Tap on next button 4 times to skip 3 screen
await tapKey(keyGoNext);
await tapKey(keyGoNext);
await tapKey(keyGoNext);
await tapKey(keyGoNext);
await waitFor('7', exactMatch: true);
final word41 = getWidgetText(keyMnemonicWord('4'));
// Change 2 times mnemonic
await tapKey(keyGenerateMnemonic);
await tester.pumpAndSettle();
final word42 = getWidgetText(keyMnemonicWord('4'));
expect(word41, isNot(word42));
await tapKey(keyGenerateMnemonic, duration: 500);
await tester.pumpAndSettle();
final word43 = getWidgetText(keyMnemonicWord('4'));
expect(word42, isNot(word43));
// Go next screen
await tapKey(keyGoNext);
await tester.pumpAndSettle();
// Enter asked word
final askedWordNumber = int.parse(getWidgetText(keyAskedWord));
List mnemonic = generateWalletProvider.generatedMnemonic!.split(' ');
final askedWord = mnemonic[askedWordNumber - 1];
await enterText(keyInputWord, askedWord);
await waitFor('Continuer', exactMatch: true);
await tapKey(keyGoNext);
await tapKey(keyGoNext);
await tapKey(keyGoNext);
await waitFor('AAAAA', exactMatch: true);
await tapKey(keyGoNext);
// Check if cached password checkbox is checked
final isCached = await isIconPresent(Icons.check_box);
// If not, tap on to cache password
if (!isCached) await tapKey(keyCachePassword, duration: 0);
// Enter password
await enterText(keyPinForm, 'AAAAA', 0);
// Check if string "Accéder à mon coffre" is present in screen
await waitFor('Accéder à mon coffre');
// Go to wallets home
await tapKey(keyGoWalletsHome, duration: 0);
// Check if string "ĞD" is present in screen
await waitFor('Mon portefeuille co');
await waitFor('0.0 $currencyName');
// await waitFor('Scanner un');
}
Future addDerivation() async {
await tapKey(keyAddDerivation);
await waitFor('Portefeuille 5');
}
Future firstOpenChest() async {
await tapKey(keyOpenWalletsHomme);
sleep(300);
final isCached = await isIconPresent(Icons.check_box);
if (!isCached) await tapKey(keyCachePassword, duration: 0);
await enterText(keyPinForm, 'AAAAA', 0);
await waitFor('100.0 $currencyName');
}

29
integration_test/launch_test.sh Executable file
View File

@ -0,0 +1,29 @@
#!/bin/bash
testName=$1
option=$2
[[ ! $testName ]] && testName='gecko_complete'
# Get local IP and set .env
ip_address=$(hostname -I | awk '{print $1}')
echo "ip_address=$ip_address" > .env
[[ $option == 'human' ]] && echo "isHumanReading=true" >> .env
## Start local Duniter node
cd integration_test/duniter
docker compose down
rm -rf data/chains
docker compose up -d
cd ../..
# Start integration test
flutter test integration_test/$testName.dart && echo '0' > /tmp/geckoTestResult || echo '1' > /tmp/geckoTestResult
# Reset .env
echo "ip_address=127.0.0.1" > .env
# Stop Duniter
cd integration_test/duniter
docker compose down

View File

@ -0,0 +1,65 @@
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:gecko/globals.dart';
import 'package:gecko/models/widgets_keys.dart';
import 'package:integration_test/integration_test.dart';
import 'general_actions.dart';
import 'tests_utility.dart';
void main() async {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
await dotenv.load();
testWidgets('Migrate Cesium identity and balance', (testerLoc) async {
tester = testerLoc;
// Connect local node and import test chest in background
await bkFastStart();
// Open chest
await firstOpenChest();
// Go to test1 options and check if balance growup with UDs creations
await tapKey(keyAddDerivation);
await waitFor('Portefeuille 6');
await scrollUntil(keyImportG1v1);
await tapKey(keyImportG1v1);
await enterText(keyCesiumId, 'test');
await enterText(keyCesiumPassword, 'test');
await waitFor(cesiumTest1.shortAddress());
await waitFor('100.0 $currencyName');
await waitFor('3', exactMatch: true);
isObscureText();
await tapKey(keyCesiumIdVisible);
await tester.pumpAndSettle();
isObscureText(false);
await tapKey(keyCesiumIdVisible);
await tester.pumpAndSettle();
isObscureText();
await tapKey(keySelectWallet);
await tapKey(keySelectThisWallet(test6.address), selectLast: true);
await waitForButtonEnabled(keyConfirm);
await tapKey(keyConfirm);
spawnBlock(duration: 2000);
await waitFor('validé !');
await tapKey(keyCloseTransactionScreen, duration: 0);
await tapKey(keyOpenWallet(test6.address), duration: 300);
await waitFor('3', exactMatch: true);
await waitFor('Membre validé !');
await waitFor('99.98 $currencyName');
}, timeout: testTimeout());
}
isObscureText([bool isObscure = true]) {
final passwordTextFormField = find.descendant(
of: find.byKey(keyCesiumId),
matching: find.byType(EditableText),
);
final input = tester.widget<EditableText>(passwordTextFormField);
expect(input.obscureText, isObscure ? isTrue : isFalse);
}

View File

@ -0,0 +1,16 @@
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'general_actions.dart';
import 'tests_utility.dart';
void main() async {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
await dotenv.load();
testWidgets('Onboarding and multi chest', (testerLoc) async {
tester = testerLoc;
await bkFastStart(false);
await onboardingNewChest();
}, timeout: testTimeout());
}

View File

@ -0,0 +1,318 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:gecko/globals.dart';
import 'package:gecko/models/wallet_data.dart';
import 'package:gecko/providers/generate_wallets.dart';
import 'package:gecko/providers/my_wallets.dart';
import 'package:gecko/providers/substrate_sdk.dart';
import 'package:provider/provider.dart';
import 'dart:io' as io;
import 'package:gecko/main.dart' as app;
final bool isHumanReading =
dotenv.env['isHumanReading'] == 'true' ? true : false;
Timeout testTimeout([int seconds = 120]) =>
Timeout(Duration(seconds: isHumanReading ? 600 : seconds));
final sub = Provider.of<SubstrateSdk>(homeContext, listen: false);
late WidgetTester tester;
// TEST WALLETS CONSTS
const testMnemonic =
'pipe paddle ketchup filter life ice feel embody glide quantum ride usage';
final test1 =
TestWallet('5FeggKqw2AbnGZF9Y9WPM2QTgzENS3Hit94Ewgmzdg5a3LNa', 'test1');
final test2 =
TestWallet('5E4i8vcNjnrDp21Sbnp32WHm2gz8YP3GGFwmdpfg5bHd8Whb', 'test2');
final test3 =
TestWallet('5FhTLzXLNBPmtXtDBFECmD7fvKmTtTQDtvBTfVr97tachA1p', 'test3');
final test4 =
TestWallet('5DXJ4CusmCg8S1yF6JGVn4fxgk5oFx42WctXqHZ17mykgje5', 'test4');
final test5 =
TestWallet('5Dq3giahrBfykJogPetZJ2jjSmhw49Fa7i6qKkseUvRJ2T3R', 'test5');
final test6 =
TestWallet('5GxEp3do81j97kNaH4JyZgDXuPoKWoTuxXXWGyyNXeKeVLHb', 'test6');
final test7 =
TestWallet('5FZ1sSvREbQLCtSSCvMUx7KCAnpJkB7q5mfz2oixiZq2ChET', 'test7');
final test8 =
TestWallet('5CoKV9EEgwb2NmWamTXUAa6ycfNb2k1iNfVGvJAkg7dLq9RH', 'test8');
final cesiumTest1 = TestWallet(
'5GAT6CJW8yVKwUuQc7sM5Kk9GZVTpbZYk9PfjNXtvnNgAJZ1', 'cesiumTest1');
final cesiumTest2 = TestWallet(
'5DTnny1tTkUs1SXHZTx98RUAj76Z88FfFhsQjd48dXnk8gHR', 'cesiumTest2');
final cesiumTest3 = TestWallet(
'5EJct9jTDNKco4YiYfETAseq1gaduBtsJUcNnFicfvh3bTV6', 'cesiumTest3');
final cesiumTest4 = TestWallet(
'5HD1oSv6A7VNxPYos6F86JFZ3bhz5LnEaWC4hkwLMj84v4ww', 'cesiumTest4');
// CUSTOM FUNCTIONS
Future sleep([int time = 1000]) async {
await Future.delayed(Duration(milliseconds: time));
}
Future<String> clipPaste() async =>
(await Clipboard.getData('text/plain'))?.text ?? '';
clipCopy(String text) async =>
await Clipboard.setData(ClipboardData(text: text));
Future humanRead([int time = 1, bool force = false]) async {
if (isHumanReading || force) io.sleep(Duration(seconds: time));
}
Future tapKey(Key buttonKey,
{Finder? customFinder, int duration = 100, bool selectLast = false}) async {
if (duration != 0) {
await tester.pumpAndSettle(Duration(milliseconds: duration));
}
final Finder finder = customFinder ?? find.byKey(buttonKey);
log.d('INTEGRATION TEST: Tap on ${finder.description}}');
await tester.tap(selectLast ? finder.last : finder);
humanRead();
}
Finder findByKey(Key key) {
return find.byKey(key);
}
bool isButtonEnabled(Key key) {
return tester.widget<ElevatedButton>(findByKey(key)).enabled;
}
Future scrollUntil(Key element) async {
final findList = find.byType(Scrollable);
final findElement = findByKey(element);
await tester.scrollUntilVisible(
findElement,
500.0,
scrollable: findList,
);
}
Future<void> waitForButtonEnabled(Key key,
{Duration timeout = const Duration(seconds: 5),
bool reverse = false}) async {
final end = DateTime.now().add(timeout);
log.d('INTEGRATION TEST: Wait for $key to be enabled');
do {
if (DateTime.now().isAfter(end)) {
throw Exception('Timed out waiting for button enabled: $key');
}
await tester.pumpAndSettle();
await Future.delayed(const Duration(milliseconds: 100));
} while (reverse ? isButtonEnabled(key) : !isButtonEnabled(key));
humanRead();
}
Future goBack() async {
final NavigatorState navigator = tester.state(find.byType(Navigator));
log.d('INTEGRATION TEST: Go back');
navigator.pop();
await tester.pump();
humanRead();
}
Future enterText(Key fieldKey, String textIn, [int duration = 200]) async {
if (duration != 0) {
await tester.pumpAndSettle(Duration(milliseconds: duration));
}
log.d('INTEGRATION TEST: Enter text: $textIn');
await tester.enterText(find.byKey(fieldKey), textIn);
humanRead();
}
Future<void> waitFor(String text,
{Duration timeout = const Duration(seconds: 5),
bool reverse = false,
bool exactMatch = false}) async {
final end = DateTime.now().add(timeout);
Finder finder = exactMatch ? find.text(text) : find.textContaining(text);
log.d('INTEGRATION TEST: Wait for: $text');
do {
if (DateTime.now().isAfter(end)) {
throw Exception('Timed out waiting for text $text');
}
await tester.pumpAndSettle();
await Future.delayed(const Duration(milliseconds: 100));
} while (reverse ? finder.evaluate().isNotEmpty : finder.evaluate().isEmpty);
humanRead();
}
// Test if text is visible on screen, return a boolean
Future<bool> isPresent(String text,
{Duration timeout = const Duration(seconds: 1)}) async {
try {
await waitFor(text, timeout: timeout);
humanRead();
return true;
} catch (exception) {
humanRead();
return false;
}
}
// Test if widget exist on screen, return a boolean
Future<bool> isIconPresent(IconData icon,
{Duration timeout = const Duration(seconds: 1)}) async {
await tester.pumpAndSettle();
final finder = find.byIcon(icon);
log.d('tatatatatatata: ${finder.evaluate()}');
humanRead();
return finder.evaluate().isEmpty ? false : true;
}
Future spawnBlock({int number = 1, int duration = 200, int? until}) async {
if (duration != 0) {
await sleep(duration);
}
if (until != null) {
number = until - sub.blocNumber;
}
await sub.spawnBlock(number);
await sleep(200);
}
// Pay in background
Future bkPay(
{required String fromAddress,
required String destAddress,
required double amount}) async {
sub.pay(
fromAddress: fromAddress,
destAddress: destAddress,
amount: amount,
password: 'AAAAA');
await spawnBlock();
await sleep(500);
}
// Certify in background
Future bkCertify(
{required String fromAddress, required String destAddress}) async {
sub.certify(fromAddress, destAddress, 'AAAAA');
await spawnBlock();
await sleep(500);
}
// Confirm my identity in background
Future bkConfirmIdentity(
{required String fromAddress, required String name}) async {
sub.confirmIdentity(fromAddress, name, 'AAAAA');
await spawnBlock();
await sleep(500);
}
// Change node in background
Future bkSetNode([String? endpoint]) async {
if (endpoint == null) {
final ipAddress = dotenv.env['ip_address'] ?? '127.0.0.1';
endpoint = 'ws://$ipAddress:9944';
}
configBox.put('customEndpoint', endpoint);
sub.connectNode(homeContext);
}
// Restore chest in background
Future bkRestoreChest([String mnemonic = testMnemonic]) async {
final myWalletProvider =
Provider.of<MyWalletsProvider>(homeContext, listen: false);
final generateWalletProvider =
Provider.of<GenerateWalletsProvider>(homeContext, listen: false);
await generateWalletProvider.storeHDWChest(homeContext);
for (int number = 0; number <= 4; number++) {
await _addImportAccount(
mnemonic: mnemonic,
chest: 0,
number: number,
name: 'test${number + 1}',
derivation: (number + 1) * 2);
}
myWalletProvider.rebuildWidget();
}
Future<WalletData> _addImportAccount(
{required String mnemonic,
required int chest,
required int number,
required String name,
required int derivation}) async {
final address = await sub.importAccount(
mnemonic: mnemonic, derivePath: '//$derivation', password: 'AAAAA');
final myWallet = WalletData(
version: dataVersion,
chest: chest,
address: address,
number: number,
name: name,
derivation: derivation,
imageDefaultPath: '${number % 4}.png');
await walletBox.add(myWallet);
return myWallet;
}
// Delete all wallets in background
Future bkDeleteAllWallets() async {
final myWalletProvider =
Provider.of<MyWalletsProvider>(homeContext, listen: false);
final isWalletsPresents =
await isPresent('Scanner un', timeout: const Duration(milliseconds: 300));
if (isWalletsPresents) {
await walletBox.clear();
await chestBox.clear();
await configBox.delete('defaultWallet');
await sub.deleteAllAccounts();
myWalletProvider.pinCode = '';
myWalletProvider.rebuildWidget();
}
}
Future bkFastStart([bool restoreChest = true]) async {
// Start app and wait finish starting
await startWait();
// Connect to local endpoint
await bkSetNode();
await sleep();
// Delete all existing chests is exists
await bkDeleteAllWallets();
if (restoreChest) {
// Restore the test chest
await bkRestoreChest();
await waitFor("y'a pas de lézard");
}
}
Future startWait() async {
app.main();
await waitFor('Test starting...', reverse: true);
await tester.pumpAndSettle(const Duration(milliseconds: 300));
await sleep(3000);
}
String getWidgetText(Key key) {
final word4Finder = find.byKey(key);
return (word4Finder.evaluate().single.widget as Text).data!;
}
class TestWallet {
String address;
String name;
TestWallet(this.address, this.name);
endAddress() => address.substring(address.length - 6);
shortAddress() => getShortPubkey(address);
}

View File

@ -0,0 +1,29 @@
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:gecko/globals.dart';
import 'package:gecko/models/widgets_keys.dart';
import 'package:integration_test/integration_test.dart';
import 'general_actions.dart';
import 'tests_utility.dart';
void main() async {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
await dotenv.load();
testWidgets('UDs creation state', (testerLoc) async {
tester = testerLoc;
// Connect local node and import test chest in background
await bkFastStart();
// Open chest
await firstOpenChest();
// Go to test1 options and check if balance growup with UDs creations
await tapKey(keyOpenWallet(test1.address));
await waitFor('100.0 $currencyName');
await spawnBlock(until: 10);
await waitFor('200.0 $currencyName');
await spawnBlock(until: 20);
await waitFor('300.0 $currencyName');
}, timeout: testTimeout());
}

View File

@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
import 'package:gecko/models/chest_data.dart';
import 'package:gecko/models/g1_wallets_list.dart';
import 'package:gecko/models/wallet_data.dart';
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:logger/logger.dart';
import 'package:shared_preferences/shared_preferences.dart';

View File

@ -16,6 +16,7 @@
import 'dart:async';
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:gecko/globals.dart';
import 'package:gecko/providers/cesium_plus.dart';
import 'package:gecko/models/chest_data.dart';
@ -51,6 +52,10 @@ Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await EasyLocalization.ensureInitialized();
if (kDebugMode) {
await dotenv.load();
}
HomeProvider homeProvider = HomeProvider();
// DuniterIndexer _duniterIndexer = DuniterIndexer();
await initHiveForFlutter();
@ -105,7 +110,7 @@ Future<void> main() async {
supportedLocales: const [Locale('en'), Locale('fr'), Locale('es')],
path: 'assets/translations',
fallbackLocale: const Locale('en'),
child: Gecko(indexerEndpoint),
child: const Gecko(),
),
),
);
@ -117,15 +122,14 @@ Future<void> main() async {
supportedLocales: const [Locale('en'), Locale('fr'), Locale('es')],
path: 'assets/translations',
fallbackLocale: const Locale('en'),
child: Gecko(indexerEndpoint),
child: const Gecko(),
),
);
}
}
class Gecko extends StatelessWidget {
const Gecko(this.indexerEndpoint, {Key? key}) : super(key: key);
final String? indexerEndpoint;
const Gecko({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {

View File

@ -0,0 +1,100 @@
import 'package:flutter/material.dart';
// General
const keyInfoPopup = Key('keyInfoPopup');
const keyGoNext = Key('keyGoNext');
const keyCancel = Key('keyCancel');
const keyConfirm = Key('keyConfirm');
const keyAppBarSearch = Key('keyAppBarSearch');
const keyAppBarQrcode = Key('keyAppBarQrcode');
const keyAppBarChest = Key('keyAppBarChest');
// Home
const keyParameters = Key('keyParameters');
const keyContacts = Key('keyContacts');
const keyDrawerMenu = Key('keyDrawerMenu');
const keyOpenWalletsHomme = Key('keyOpenWalletsHomme');
const keyOpenSearch = Key('keyOpenSearch');
const keyRestoreChest = Key('keyRestoreChest');
const keyOnboardingNewChest = Key('keyOnboardingNewChest');
// Wallets home
const keyImportG1v1 = Key('keyImportG1v1');
const keyChangeChest = Key('keyChangeChest');
const keyListWallets = Key('keyListWallets');
const keyAddDerivation = Key('keyAddDerivation');
// Wallet options
const keyCopyAddress = Key('keyCopyAddress');
const keyOpenActivity = Key('keyOpenActivity');
const keyManageMembership = Key('keyManageMembership');
const keySetDefaultWallet = Key('keySetDefaultWallet');
const keyDeleteWallet = Key('keyDeleteWallet');
const keyWalletName = Key('keyWalletName');
const keyRenameWallet = Key('keyRenameWallet');
const keyConfirmIdentity = Key('keyConfirmIdentity');
const keyEnterIdentityUsername = Key('keyEnterIdentityUsername');
// Chest options
const keyShowSeed = Key('keyShowSeed');
const keyChangePin = Key('keyChangePin');
const keycreateRootDerivation = Key('keycreateRootDerivation');
const keyDeleteChest = Key('keyDeleteChest');
// Manage membership
const keyMigrateIdentity = Key('keyMigrateIdentity');
const keyRevokeIdty = Key('keyRevokeIdty');
// Choose chest
const keyCreateNewChest = Key('keyCreateNewChest');
const keyImportChest = Key('keyImportChest');
// Profile view
const keyViewActivity = Key('keyViewActivity');
const keyCertify = Key('keyCertify');
const keyPay = Key('keyPay');
const keyAmountField = Key('keyAmountField');
const keyConfirmPayment = Key('keyConfirmPayment');
const keyCloseTransactionScreen = Key('keyCloseTransactionScreen');
// Activity view
const keyListTransactions = Key('keyListTransactions');
// Unlock wallet
const keyPinForm = Key('keyPinForm');
const keyPopButton = Key('keyPopButton');
const keyCachePassword = Key('keyCachePassword');
// Settings
const keyDeleteAllWallets = Key('keyDeleteAllWallets');
const keySelectDuniterNodeDropDown = Key('keySelectDuniterNodeDropDown');
const keyCustomDuniterEndpoint = Key('keyCustomDuniterEndpoint');
const keyConnectToEndpoint = Key('keyConnectToEndpoint');
// Onboarding
const keyPastMnemonic = Key('keyPastMnemonic');
const keyBubbleSpeak = Key('keyBubbleSpeak');
const keyGenerateMnemonic = Key('keyGenerateMnemonic');
const keyAskedWord = Key('keyAskedWord');
const keyInputWord = Key('keyInputWord');
const keyGeneratedPin = Key('keyGeneratedPin');
const keyGoWalletsHome = Key('keyGoWalletsHome');
// Search
const keySearchField = Key('keySearchField');
const keyConfirmSearch = Key('keyConfirmSearch');
// Import Cesium wallet
const keyCesiumId = Key('keyCesiumId');
const keyCesiumPassword = Key('keyCesiumPassword');
const keySelectWallet = Key('keySelectWallet');
const keyCesiumIdVisible = Key('keyCesiumIdVisible');
// Items keys
Key keyTransaction(int keyId) => Key('keyTransaction$keyId');
Key keyMnemonicWord(String word) => Key('keyMnemonicWord$word');
Key keySearchResult(String address) => Key('keySearchResult$address');
Key keySelectDuniterNode(String endpoint) =>
Key('keySelectDuniterNode$endpoint');
Key keyOpenWallet(String address) => Key('keyOpenWallet$address');
Key keySelectThisWallet(String address) => Key('keySelectThisWallet$address');

View File

@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:gecko/globals.dart';
import 'package:gecko/models/chest_data.dart';
import 'package:gecko/models/wallet_data.dart';
import 'package:gecko/models/widgets_keys.dart';
import 'package:gecko/providers/my_wallets.dart';
import 'package:gecko/providers/substrate_sdk.dart';
import 'package:provider/provider.dart';
@ -59,13 +60,13 @@ class ChestProvider with ChangeNotifier {
title: Text('areYouSureToDeleteWallet'.tr(args: [walletName!])),
actions: <Widget>[
TextButton(
child: Text("no".tr(), key: const Key('cancelDeleting')),
child: Text("no".tr(), key: keyCancel),
onPressed: () {
Navigator.pop(context, false);
},
),
TextButton(
child: Text("yes".tr(), key: const Key('confirmDeleting')),
child: Text("yes".tr(), key: keyConfirm),
onPressed: () {
Navigator.pop(context, true);
},

View File

@ -8,6 +8,7 @@ import 'package:gecko/globals.dart';
import 'package:gecko/models/g1_wallets_list.dart';
import 'package:gecko/models/queries_indexer.dart';
import 'package:gecko/models/wallet_data.dart';
import 'package:gecko/models/widgets_keys.dart';
import 'package:gecko/providers/cesium_plus.dart';
import 'package:gecko/providers/substrate_sdk.dart';
import 'package:gecko/providers/wallet_options.dart';
@ -293,7 +294,6 @@ class DuniterIndexer with ChangeNotifier {
return Text('noResult'.tr());
}
int keyID = 0;
double avatarSize = 55;
return Expanded(
child: ListView(children: <Widget>[
@ -301,7 +301,7 @@ class DuniterIndexer with ChangeNotifier {
Padding(
padding: const EdgeInsets.symmetric(horizontal: 5),
child: ListTile(
key: Key('searchResult${keyID++}'),
key: keySearchResult(profile['id']),
horizontalTitleGap: 40,
contentPadding: const EdgeInsets.all(5),
leading: cesiumPlusProvider.defaultAvatar(avatarSize),

View File

@ -1,5 +1,4 @@
import 'dart:math';
import 'dart:typed_data';
import 'package:durt/durt.dart' as durt;
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
@ -354,6 +353,7 @@ class GenerateWalletsProvider with ChangeNotifier {
cellController10,
cellController11
];
if (sentence?.text == null) return;
for (var word in sentence!.text!.split(' ')) {
bool isValid = isBipWord(word, false);

View File

@ -11,6 +11,7 @@ import 'package:flutter/services.dart';
import 'dart:async';
import 'package:gecko/globals.dart';
import 'package:gecko/models/wallet_data.dart';
import 'package:gecko/models/widgets_keys.dart';
import 'package:gecko/providers/my_wallets.dart';
import 'package:gecko/providers/wallets_profiles.dart';
import 'package:gecko/screens/myWallets/unlocking_wallet.dart';
@ -148,6 +149,7 @@ class HomeProvider with ChangeNotifier {
const Spacer(),
const SizedBox(width: 11),
IconButton(
key: keyAppBarSearch,
iconSize: 40,
icon: const Image(image: AssetImage('assets/loupe-noire.png')),
onPressed: () {
@ -166,6 +168,7 @@ class HomeProvider with ChangeNotifier {
const SizedBox(width: 22),
const Spacer(),
IconButton(
key: keyAppBarQrcode,
iconSize: 70,
icon: const Image(image: AssetImage('assets/qrcode-scan.png')),
onPressed: () async {
@ -179,6 +182,7 @@ class HomeProvider with ChangeNotifier {
const Spacer(),
const SizedBox(width: 15),
IconButton(
key: keyAppBarChest,
iconSize: 60,
icon: const Image(image: AssetImage('assets/wallet.png')),
onPressed: () async {

View File

@ -1,7 +1,7 @@
// ignore_for_file: use_build_context_synchronously
import 'dart:typed_data';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:gecko/globals.dart';
import 'package:gecko/models/chest_data.dart';
@ -37,7 +37,8 @@ class SubstrateSdk with ChangeNotifier {
TextEditingController csSalt = TextEditingController();
TextEditingController csPassword = TextEditingController();
String g1V1NewAddress = '';
bool isCesiumIDVisible = true;
bool isCesiumIDVisible = false;
bool isCesiumAddresLoading = false;
/////////////////////////////////////
////////// 1: API METHODS ///////////
@ -80,10 +81,11 @@ class SubstrateSdk with ChangeNotifier {
[null])[0];
}
TxSenderData _setSender() {
Future<TxSenderData> _setSender(String address) async {
final fromPubkey = await sdk.api.account.decodeAddress([address]);
return TxSenderData(
keyring.current.address,
keyring.current.pubKey,
address,
fromPubkey!.keys.first,
);
}
@ -685,7 +687,7 @@ class SubstrateSdk with ChangeNotifier {
);
const tx1 = 'api.tx.universalDividend.claimUds()';
final tx2 = amount == -1
? 'api.tx.balances.transferAll(false)'
? 'api.tx.balances.transferAll("$destAddress", false)'
: 'api.tx.balances.transferKeepAlive("$destAddress", $amountUnit)';
rawParams = '[[$tx1, $tx2]]';
@ -696,14 +698,14 @@ class SubstrateSdk with ChangeNotifier {
}
Future<String> certify(
String fromAddress, String password, String toAddress) async {
String fromAddress, String destAddress, String password) async {
transactionStatus = '';
final myIdtyStatus = await idtyStatus(fromAddress);
final toIdtyStatus = await idtyStatus(toAddress);
final toIdtyStatus = await idtyStatus(destAddress);
final fromIndex = await _getIdentityIndexOf(fromAddress);
final toIndex = await _getIdentityIndexOf(toAddress);
final toIndex = await _getIdentityIndexOf(destAddress);
if (myIdtyStatus != 'Validated') {
transactionStatus = 'notMember';
@ -711,12 +713,12 @@ class SubstrateSdk with ChangeNotifier {
return 'notMember';
}
final sender = _setSender();
final sender = await _setSender(fromAddress);
TxInfoData txInfo;
List txOptions = [];
String? rawParams;
final toCerts = await getCerts(toAddress);
final toCerts = await getCerts(destAddress);
// log.d('debug: ${currencyParameters['minCertForMembership']}');
@ -726,7 +728,7 @@ class SubstrateSdk with ChangeNotifier {
'createIdentity',
sender,
);
txOptions = [toAddress];
txOptions = [destAddress];
} else if (toIdtyStatus == 'Validated' ||
toIdtyStatus == 'ConfirmedByOwner') {
if (toCerts[0] >= currencyParameters['minCertForMembership']! - 1 &&
@ -776,11 +778,11 @@ class SubstrateSdk with ChangeNotifier {
Future<String> confirmIdentity(
String fromAddress, String name, String password) async {
log.d('me: ${keyring.current.address!}');
final fromPubkey = await sdk.api.account.decodeAddress([fromAddress]);
final sender = TxSenderData(
keyring.current.address,
keyring.current.pubKey,
fromAddress,
fromPubkey!.keys.first,
);
final txInfo = TxInfoData(
@ -848,10 +850,11 @@ newKeySig: $newKeySig""");
const tx1 = 'api.tx.universalDividend.claimUds()';
final tx2 =
'api.tx.identity.changeOwnerKey("$destAddress", "$newKeySig")';
// const tx3 = 'api.tx.balances.transferAll(false)';
final tx3 = 'api.tx.balances.transferAll("$destAddress", false)';
rawParams =
fromBalance['unclaimedUds'] == 0 ? '[[$tx2]]' : '[[$tx1, $tx2]]';
rawParams = fromBalance['unclaimedUds'] == 0
? '[[$tx2, $tx3]]'
: '[[$tx1, $tx2, $tx3]]';
} else {
txInfo = TxInfoData(
'identity',
@ -873,7 +876,6 @@ newKeySig: $newKeySig""");
keyring.current.pubKey,
);
log.d(sender.address);
TxInfoData txInfo;
txInfo = TxInfoData(
@ -940,6 +942,17 @@ newKeySig: $newKeySig""");
await sdk.api.keyring.deleteAccount(keyring, keypair);
}
Future spawnBlock([int number = 1, int until = 0]) async {
if (!kDebugMode) return;
if (blocNumber < until) {
number = until - blocNumber;
}
for (var i = 1; i <= number; i++) {
await sdk.webView!
.evalJavascript('api.rpc.engine.createBlock(true, true)');
}
}
void reload() {
notifyListeners();
}

View File

@ -6,6 +6,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:async';
import 'package:gecko/globals.dart';
import 'package:gecko/models/widgets_keys.dart';
import 'package:gecko/providers/duniter_indexer.dart';
import 'package:gecko/providers/my_wallets.dart';
import 'package:gecko/models/wallet_data.dart';
@ -136,7 +137,7 @@ class WalletOptionsProvider with ChangeNotifier {
DuniterIndexer duniterIndexer =
Provider.of<DuniterIndexer>(context, listen: false);
_showText(String text,
showText(String text,
[double size = 18, bool bold = false, bool smooth = true]) {
log.d('$address $text');
return AnimatedFadeOutIn<String>(
@ -162,16 +163,16 @@ class WalletOptionsProvider with ChangeNotifier {
switch (snapshot.data.toString()) {
case 'noid':
{
return _showText('noIdentity'.tr());
return showText('noIdentity'.tr());
}
case 'Created':
{
return _showText('identityCreated'.tr());
return showText('identityCreated'.tr());
}
case 'ConfirmedByOwner':
{
return isOwner
? _showText('identityConfirmed'.tr())
? showText('identityConfirmed'.tr())
: duniterIndexer.getNameByAddress(
context,
address,
@ -186,7 +187,7 @@ class WalletOptionsProvider with ChangeNotifier {
case 'Validated':
{
return isOwner
? _showText('memberValidated'.tr(), 18, true)
? showText('memberValidated'.tr(), 18, true)
: duniterIndexer.getNameByAddress(
context,
address,
@ -200,11 +201,11 @@ class WalletOptionsProvider with ChangeNotifier {
case 'expired':
{
return _showText('identityExpired'.tr());
return showText('identityExpired'.tr());
}
}
return SizedBox(
child: _showText('', 18, false, false),
child: showText('', 18, false, false),
);
});
});
@ -238,6 +239,7 @@ class WalletOptionsProvider with ChangeNotifier {
child: Column(children: [
const SizedBox(height: 20),
TextField(
key: keyEnterIdentityUsername,
onChanged: (_) => notifyListeners(),
inputFormatters: <TextInputFormatter>[
// FilteringTextInputFormatter.allow(RegExp("[0-9a-zA-Z]")),
@ -258,7 +260,7 @@ class WalletOptionsProvider with ChangeNotifier {
Consumer<WalletOptionsProvider>(
builder: (context, wOptions, _) {
return TextButton(
key: const Key('infoPopup'),
key: keyConfirm,
child: Text(
"validate".tr(),
style: TextStyle(
@ -354,7 +356,7 @@ class WalletOptionsProvider with ChangeNotifier {
Consumer<WalletOptionsProvider>(
builder: (context, wOptions, _) {
return TextButton(
key: const Key('infoPopup'),
key: keyInfoPopup,
child: Text(
"validate".tr(),
style: TextStyle(
@ -381,7 +383,7 @@ class WalletOptionsProvider with ChangeNotifier {
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextButton(
key: const Key('cancel'),
key: keyCancel,
child: Text(
"cancel".tr(),
style: TextStyle(
@ -457,7 +459,7 @@ class WalletOptionsProvider with ChangeNotifier {
width: 260,
child: Stack(children: <Widget>[
TextField(
key: const Key('walletName'),
key: keyWalletName,
autofocus: false,
focusNode: walletNameFocus,
enabled: isEditing,
@ -481,7 +483,7 @@ class WalletOptionsProvider with ChangeNotifier {
Positioned(
right: 0,
child: InkWell(
key: const Key('renameWallet'),
key: keyRenameWallet,
onTap: () async {
// _isNewNameValid =
// walletProvider.editWalletName(wallet.id(), isCesium: false);

View File

@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:gecko/globals.dart';
import 'package:gecko/models/g1_wallets_list.dart';
import 'package:gecko/models/widgets_keys.dart';
import 'package:gecko/providers/cesium_plus.dart';
import 'package:gecko/providers/substrate_sdk.dart';
import 'package:gecko/providers/wallet_options.dart';
@ -166,7 +167,7 @@ class WalletsProfilesProvider with ChangeNotifier {
),
Row(children: [
GestureDetector(
key: const Key('copyPubkey'),
key: keyCopyAddress,
onTap: () {
Clipboard.setData(ClipboardData(text: address));
snackCopyKey(context);

View File

@ -1,7 +1,10 @@
// ignore_for_file: must_be_immutable
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/services.dart';
import 'package:gecko/globals.dart';
import 'package:gecko/models/queries_indexer.dart';
import 'package:gecko/models/widgets_keys.dart';
import 'package:gecko/providers/cesium_plus.dart';
import 'package:gecko/providers/duniter_indexer.dart';
import 'package:gecko/providers/home.dart';
@ -12,7 +15,6 @@ import 'package:gecko/screens/wallet_view.dart';
import 'package:graphql_flutter/graphql_flutter.dart';
import 'package:provider/provider.dart';
// ignore: must_be_immutable
class ActivityScreen extends StatelessWidget with ChangeNotifier {
ActivityScreen({required this.address, this.avatar, this.username, Key? key})
: super(key: key);
@ -132,7 +134,7 @@ class ActivityScreen extends StatelessWidget with ChangeNotifier {
child: Builder(
builder: (context) => Expanded(
child: ListView(
key: const Key('listTransactions'),
key: keyListTransactions,
controller: scrollController,
children: <Widget>[historyView(context, result)],
),
@ -286,7 +288,7 @@ class ActivityScreen extends StatelessWidget with ChangeNotifier {
child:
// Row(children: [Column(children: [],)],)
ListTile(
key: Key('transaction${keyID++}'),
key: keyTransaction(keyID++),
contentPadding: const EdgeInsets.only(
left: 20, right: 30, top: 15, bottom: 15),
leading: ClipOval(

View File

@ -1,14 +1,9 @@
import 'package:flutter/services.dart';
import 'package:gecko/globals.dart';
import 'package:flutter/material.dart';
// import 'package:gecko/models/home.dart';
// import 'package:provider/provider.dart';
// ignore: must_be_immutable
class AvatarFullscreen extends StatelessWidget {
TextEditingController tplController = TextEditingController();
AvatarFullscreen(this.avatar, {this.title, this.color, Key? key})
const AvatarFullscreen(this.avatar, {this.title, this.color, Key? key})
: super(key: key);
final Image? avatar;
final String? title;

View File

@ -3,6 +3,7 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:gecko/globals.dart';
import 'package:gecko/models/widgets_keys.dart';
import 'package:gecko/providers/substrate_sdk.dart';
import 'package:provider/provider.dart';
@ -62,10 +63,10 @@ class CommonElements {
width: 380 * ratio,
height: 60 * ratio,
child: ElevatedButton(
key: keyGoNext,
style: ElevatedButton.styleFrom(
elevation: 4,
primary: orangeC, // background
onPrimary: Colors.white, // foreground
foregroundColor: Colors.white, backgroundColor: orangeC,
elevation: 4, // foreground
),
onPressed: () {
Navigator.push(
@ -247,7 +248,7 @@ Future<bool?> confirmPopup(BuildContext context, String title) async {
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextButton(
key: const Key('confirmPopop'),
key: keyConfirm,
child: Text(
"yes".tr(),
style: const TextStyle(
@ -295,7 +296,7 @@ Future<void> infoPopup(BuildContext context, String title) async {
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextButton(
key: const Key('infoPopup'),
key: keyInfoPopup,
child: const Text(
"D'accord",
style: TextStyle(

View File

@ -5,6 +5,7 @@ import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:gecko/globals.dart';
import 'package:gecko/models/stateful_wrapper.dart';
import 'package:gecko/models/widgets_keys.dart';
import 'package:gecko/providers/chest_provider.dart';
import 'package:gecko/providers/duniter_indexer.dart';
import 'package:gecko/providers/home.dart';
@ -64,7 +65,7 @@ class HomeScreen extends StatelessWidget {
]),
),
ListTile(
key: const Key('parameters'),
key: keyParameters,
title: Text('parameters'.tr()),
onTap: () {
Navigator.pop(context);
@ -77,7 +78,7 @@ class HomeScreen extends StatelessWidget {
},
),
ListTile(
key: const Key('contacts'),
key: keyContacts,
title: Text('contactsManagement'.tr()),
onTap: () {
Navigator.pop(context);
@ -89,26 +90,6 @@ class HomeScreen extends StatelessWidget {
);
},
),
// ListTile(
// key: const Key('substrateSandbox'),
// title: const Text('Substrate debug'),
// onTap: () {
// Navigator.pop(context);
// Navigator.push(
// context,
// MaterialPageRoute(builder: (context) {
// return const SubstrateSandBox();
// }),
// );
// },
// ),
// ListTile(
// title: const Text('A propos'),
// onTap: () {
// },
// ),
])),
Align(
alignment: FractionalOffset.bottomCenter,
@ -141,17 +122,19 @@ class HomeScreen extends StatelessWidget {
myWalletProvider.rebuildWidget();
}
var connectivityResult =
await (Connectivity().checkConnectivity());
// var connectivityResult =
// await (Connectivity().checkConnectivity());
// if (connectivityResult != ConnectivityResult.mobile &&
// connectivityResult != ConnectivityResult.wifi) {
// homeProvider.changeMessage(
// "notConnectedToInternet".tr(), 0);
// sub.nodeConnected = false;
// }
// TODO: fix random bad network status on startup
HomeProvider homeProvider =
Provider.of<HomeProvider>(ctx, listen: false);
if (connectivityResult != ConnectivityResult.mobile &&
connectivityResult != ConnectivityResult.wifi) {
homeProvider.changeMessage(
"notConnectedToInternet".tr(), 0);
sub.nodeConnected = false;
}
Connectivity()
.onConnectivityChanged
.listen((ConnectivityResult result) async {
@ -166,6 +149,7 @@ class HomeScreen extends StatelessWidget {
await sub.connectNode(ctx);
}
});
// await sub.connectNode(ctx);
}
// _duniterIndexer.checkIndexerEndpointBackground();
});
@ -220,7 +204,7 @@ Widget geckHome(context) {
left: 15,
child: Builder(
builder: (context) => IconButton(
key: const Key('drawerMenu'),
key: keyDrawerMenu,
icon: const Icon(
Icons.menu,
color: Colors.white,
@ -301,6 +285,7 @@ Widget geckHome(context) {
child: Material(
color: orangeC, // button color
child: InkWell(
key: keyOpenSearch,
child: Padding(
padding: const EdgeInsets.all(18),
child: Image(
@ -343,7 +328,7 @@ Widget geckHome(context) {
],
),
child: ClipOval(
key: const Key('manageWallets'),
key: keyOpenWalletsHomme,
child: Material(
color: orangeC, // button color
child: InkWell(
@ -466,7 +451,7 @@ Widget welcomeHome(context) {
left: 15,
child: Builder(
builder: (context) => IconButton(
key: const Key('drawerMenu'),
key: keyDrawerMenu,
icon: const Icon(
Icons.menu,
color: Colors.white,
@ -554,10 +539,10 @@ Widget welcomeHome(context) {
width: 410,
height: 70,
child: ElevatedButton(
key: keyOnboardingNewChest,
style: ElevatedButton.styleFrom(
elevation: 4,
primary: orangeC, // background
onPrimary: Colors.white, // foreground
foregroundColor: Colors.white, elevation: 4,
backgroundColor: orangeC, // foreground
),
onPressed: () {
Navigator.push(
@ -581,6 +566,7 @@ Widget welcomeHome(context) {
width: 410,
height: 70,
child: OutlinedButton(
key: keyRestoreChest,
style: OutlinedButton.styleFrom(
side: BorderSide(width: 4, color: orangeC)),
onPressed: () {

View File

@ -1,4 +1,4 @@
// ignore_for_file: use_build_context_synchronously
// ignore_for_file: use_build_context_synchronously, must_be_immutable
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
@ -10,11 +10,9 @@ import 'package:gecko/models/wallet_data.dart';
import 'package:gecko/providers/my_wallets.dart';
import 'package:gecko/providers/substrate_sdk.dart';
import 'package:gecko/screens/myWallets/unlocking_wallet.dart';
import 'dart:io';
import 'package:provider/provider.dart';
// ignore: must_be_immutable
class ChangePinScreen extends StatelessWidget with ChangeNotifier {
ChangePinScreen(
{Key? keyMyWallets,
@ -23,9 +21,8 @@ class ChangePinScreen extends StatelessWidget with ChangeNotifier {
: super(key: keyMyWallets);
final String? walletName;
final MyWalletsProvider walletProvider;
Directory? appPath;
TextEditingController newPin = TextEditingController();
final TextEditingController newPin = TextEditingController();
@override
Widget build(BuildContext context) {
@ -102,9 +99,8 @@ class ChangePinScreen extends StatelessWidget with ChangeNotifier {
height: 50,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 12,
primary: Colors.green[400], //smoothYellow, // background
onPrimary: Colors.black, // foreground
foregroundColor: Colors.black, elevation: 12,
backgroundColor: Colors.green[400], // foreground
),
onPressed: () async {
WalletData defaultWallet =

View File

@ -6,6 +6,7 @@ import 'package:gecko/globals.dart';
import 'package:gecko/models/chest_data.dart';
import 'package:flutter/services.dart';
import 'package:gecko/models/wallet_data.dart';
import 'package:gecko/models/widgets_keys.dart';
import 'package:gecko/providers/chest_provider.dart';
import 'package:gecko/providers/home.dart';
import 'package:gecko/providers/my_wallets.dart';
@ -58,7 +59,7 @@ class ChestOptions extends StatelessWidget {
child: Column(children: <Widget>[
SizedBox(height: 30 * ratio),
InkWell(
key: const Key('showSeed'),
key: keyShowSeed,
onTap: () async {
MyWalletsProvider myWalletProvider =
Provider.of<MyWalletsProvider>(context, listen: false);
@ -108,7 +109,7 @@ class ChestOptions extends StatelessWidget {
SizedBox(height: 10 * ratio),
Consumer<SubstrateSdk>(builder: (context, sub, _) {
return InkWell(
key: const Key('changePin'),
key: keyChangePin,
onTap: sub.nodeConnected
? () async {
// await _chestProvider.changePin(context, cesiumWallet);
@ -152,7 +153,7 @@ class ChestOptions extends StatelessWidget {
SizedBox(height: 10 * ratio),
Consumer<SubstrateSdk>(builder: (context, sub, _) {
return InkWell(
key: const Key('createRootDerivation'),
key: keycreateRootDerivation,
onTap: sub.nodeConnected
? () async {
await Navigator.push(
@ -188,7 +189,7 @@ class ChestOptions extends StatelessWidget {
}),
SizedBox(height: 10 * ratio),
InkWell(
key: const Key('deleteChest'),
key: keyDeleteChest,
onTap: () async {
await chestProvider.deleteChest(context, currentChest);
},

View File

@ -3,6 +3,7 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/services.dart';
import 'package:gecko/globals.dart';
import 'package:gecko/models/widgets_keys.dart';
import 'package:gecko/providers/my_wallets.dart';
import 'package:gecko/models/wallet_data.dart';
import 'package:flutter/material.dart';
@ -22,7 +23,6 @@ class ChooseChest extends StatefulWidget {
}
}
// ignore: must_be_immutable
class _ChooseChestState extends State<ChooseChest> {
TextEditingController tplController = TextEditingController();
CarouselController buttonCarouselController = CarouselController();
@ -111,8 +111,8 @@ class _ChooseChestState extends State<ChooseChest> {
height: 70,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
primary: orangeC, // background
onPrimary: Colors.black, // foreground
foregroundColor: Colors.black,
backgroundColor: orangeC, // foreground
),
onPressed: () async {
await configBox.put('currentChest', currentChest);
@ -156,7 +156,7 @@ class _ChooseChestState extends State<ChooseChest> {
child: Align(
alignment: Alignment.bottomCenter,
child: InkWell(
key: const Key('createNewChest'),
key: keyCreateNewChest,
onTap: () {
Navigator.push(
context,
@ -179,7 +179,7 @@ class _ChooseChestState extends State<ChooseChest> {
),
),
InkWell(
key: const Key('importChest'),
key: keyImportChest,
onTap: () {
Navigator.push(
context,

View File

@ -1,4 +1,4 @@
// ignore_for_file: use_build_context_synchronously
// ignore_for_file: use_build_context_synchronously, must_be_immutable
import 'dart:io';
@ -7,6 +7,7 @@ import 'package:flutter/services.dart';
import 'package:gecko/globals.dart';
import 'package:flutter/material.dart';
import 'package:gecko/models/wallet_data.dart';
import 'package:gecko/models/widgets_keys.dart';
import 'package:gecko/providers/my_wallets.dart';
import 'package:gecko/providers/substrate_sdk.dart';
import 'package:gecko/providers/wallet_options.dart';
@ -15,7 +16,6 @@ import 'package:provider/provider.dart';
// import 'package:gecko/models/home.dart';
// import 'package:provider/provider.dart';
// ignore: must_be_immutable
class ChooseWalletScreen extends StatelessWidget {
ChooseWalletScreen({Key? key, required this.pin}) : super(key: key);
final String pin;
@ -46,10 +46,10 @@ class ChooseWalletScreen extends StatelessWidget {
width: 470,
height: 70,
child: ElevatedButton(
key: keyConfirm,
style: ElevatedButton.styleFrom(
elevation: 4,
primary: orangeC, // background
onPrimary: Colors.white, // foreground
foregroundColor: Colors.white, elevation: 4,
backgroundColor: orangeC, // foreground
),
onPressed: () async {
await sub.setCurrentWallet(selectedWallet!);
@ -112,7 +112,7 @@ class ChooseWalletScreen extends StatelessWidget {
return CustomScrollView(slivers: <Widget>[
const SliverToBoxAdapter(child: SizedBox(height: 20)),
SliverGrid.count(
key: const Key('listWallets'),
key: keyListWallets,
crossAxisCount: nTule,
childAspectRatio: 1,
crossAxisSpacing: 0,
@ -122,6 +122,7 @@ class ChooseWalletScreen extends StatelessWidget {
Padding(
padding: const EdgeInsets.all(16),
child: GestureDetector(
key: keySelectThisWallet(repository.address!),
onTap: () {
selectedWallet = repository;
myWalletProvider.rebuildWidget();

View File

@ -107,9 +107,8 @@ class _CustomDerivationState extends State<CustomDerivation> {
height: 70,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 4,
primary: orangeC, // background
onPrimary: Colors.white, // foreground
foregroundColor: Colors.white, elevation: 4,
backgroundColor: orangeC, // foreground
),
onPressed: () async {
WalletData? defaultWallet =

View File

@ -7,6 +7,7 @@ import 'package:flutter/services.dart';
import 'package:gecko/globals.dart';
import 'package:flutter/material.dart';
import 'package:gecko/models/wallet_data.dart';
import 'package:gecko/models/widgets_keys.dart';
import 'package:gecko/providers/my_wallets.dart';
import 'package:gecko/providers/substrate_sdk.dart';
import 'package:gecko/providers/wallet_options.dart';
@ -21,7 +22,6 @@ class ImportG1v1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
// HomeProvider _homeProvider = Provider.of<HomeProvider>(context);
WalletOptionsProvider walletOptions =
Provider.of<WalletOptionsProvider>(context, listen: false);
MyWalletsProvider myWalletProvider =
@ -109,6 +109,7 @@ class ImportG1v1 extends StatelessWidget {
return Column(children: <Widget>[
const SizedBox(height: 20),
TextFormField(
key: keyCesiumId,
autofocus: true,
onChanged: (text) {
if (debounce?.isActive ?? false) {
@ -116,21 +117,23 @@ class ImportG1v1 extends StatelessWidget {
}
debounce = Timer(
const Duration(milliseconds: debouneTime), () {
sub.reload();
sub.csToV2Address(
sub.csSalt.text, sub.csPassword.text);
});
},
keyboardType: TextInputType.text,
controller: sub.csSalt,
obscureText: sub
obscureText: !sub
.isCesiumIDVisible, //This will obscure text dynamically
decoration: InputDecoration(
hintText: 'enterCesiumId'.tr(),
suffixIcon: IconButton(
key: keyCesiumIdVisible,
icon: Icon(
sub.isCesiumIDVisible
? Icons.visibility
: Icons.visibility_off,
? Icons.visibility_off
: Icons.visibility,
color: Colors.black,
),
onPressed: () {
@ -141,6 +144,7 @@ class ImportG1v1 extends StatelessWidget {
),
const SizedBox(height: 20),
TextFormField(
key: keyCesiumPassword,
autofocus: true,
onChanged: (text) {
if (debounce?.isActive ?? false) {
@ -148,21 +152,23 @@ class ImportG1v1 extends StatelessWidget {
}
debounce = Timer(
const Duration(milliseconds: debouneTime), () {
sub.g1V1NewAddress = '';
sub.reload();
sub.csToV2Address(
sub.csSalt.text, sub.csPassword.text);
});
},
keyboardType: TextInputType.text,
controller: sub.csPassword,
obscureText: sub
obscureText: !sub
.isCesiumIDVisible, //This will obscure text dynamically
decoration: InputDecoration(
hintText: 'enterCesiumPassword'.tr(),
suffixIcon: IconButton(
icon: Icon(
sub.isCesiumIDVisible
? Icons.visibility
: Icons.visibility_off,
? Icons.visibility_off
: Icons.visibility,
color: Colors.black,
),
onPressed: () {
@ -173,7 +179,7 @@ class ImportG1v1 extends StatelessWidget {
),
const SizedBox(height: 20),
GestureDetector(
key: const Key('copyPubkey'),
key: keyCopyAddress,
onTap: () {
Clipboard.setData(
ClipboardData(text: sub.g1V1NewAddress));
@ -187,14 +193,6 @@ class ImportG1v1 extends StatelessWidget {
),
),
),
// Text(
// getShortPubkey(sub.g1V1NewAddress),
// style: const TextStyle(
// fontSize: 18,
// color: Colors.black,
// fontWeight: FontWeight.bold,
// fontFamily: 'Monospace'),
// ),
const SizedBox(height: 20),
Text(
'${balance['transferableBalance']} $currencyName',
@ -213,12 +211,14 @@ class ImportG1v1 extends StatelessWidget {
Text('selectDestWallet'.tr()),
const SizedBox(height: 5),
DropdownButtonHideUnderline(
key: keySelectWallet,
child: DropdownButton(
// alignment: AlignmentDirectional.topStart,
value: selectedWallet,
icon: const Icon(Icons.keyboard_arrow_down),
items: myWalletProvider.listWallets.map((wallet) {
return DropdownMenuItem(
key: keySelectThisWallet(wallet.address!),
value: wallet,
child: Text(
wallet.name!,
@ -237,14 +237,13 @@ class ImportG1v1 extends StatelessWidget {
width: 380 * ratio,
height: 60 * ratio,
child: ElevatedButton(
key: keyConfirm,
style: ElevatedButton.styleFrom(
elevation: 4,
primary: orangeC, // background
onPrimary: Colors.white, // foreground
foregroundColor: Colors.white, elevation: 4,
backgroundColor: orangeC, // foreground
),
onPressed: canValidate
? () async {
log.d('GOOO');
WalletData? defaultWallet =
myWalletProvider.getDefaultWallet();

View File

@ -2,6 +2,7 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/services.dart';
import 'package:gecko/globals.dart';
import 'package:flutter/material.dart';
import 'package:gecko/models/widgets_keys.dart';
import 'package:gecko/screens/myWallets/migrate_identity.dart';
// import 'package:gecko/models/wallet_data.dart';
// import 'package:gecko/providers/my_wallets.dart';
@ -41,7 +42,7 @@ class ManageMembership extends StatelessWidget {
Widget migrateIdentity(BuildContext context) {
return InkWell(
key: const Key('migrateIdentity'),
key: keyMigrateIdentity,
onTap: () async {
Navigator.push(
context,
@ -64,7 +65,7 @@ class ManageMembership extends StatelessWidget {
Widget revokeMyIdentity(BuildContext context) {
return InkWell(
key: const Key('revokeIdty'),
key: keyRevokeIdty,
onTap: () async {
// TODOO: Generate revoke document, and understand extrinsic identity.revokeIdentity options
// final _answer = await confirmPopup(context,

View File

@ -188,9 +188,8 @@ class MigrateIdentityScreen extends StatelessWidget {
height: 60 * ratio,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 4,
primary: orangeC, // background
onPrimary: Colors.white, // foreground
foregroundColor: Colors.white, elevation: 4,
backgroundColor: orangeC, // foreground
),
onPressed: canValidate
? () async {

View File

@ -3,6 +3,7 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/services.dart';
import 'package:gecko/globals.dart';
import 'package:flutter/material.dart';
import 'package:gecko/models/widgets_keys.dart';
import 'package:gecko/providers/generate_wallets.dart';
import 'package:gecko/providers/substrate_sdk.dart';
import 'package:gecko/screens/common_elements.dart';
@ -91,10 +92,10 @@ class RestoreChest extends StatelessWidget {
width: 410,
height: 70,
child: ElevatedButton(
key: keyGoNext,
style: ElevatedButton.styleFrom(
elevation: 4,
primary: orangeC, // background
onPrimary: Colors.white, // foreground
foregroundColor: Colors.white, elevation: 4,
backgroundColor: orangeC, // foreground
),
onPressed: () async {
if (await sub
@ -130,10 +131,10 @@ class RestoreChest extends StatelessWidget {
width: 190,
height: 60,
child: ElevatedButton(
key: keyPastMnemonic,
style: ElevatedButton.styleFrom(
elevation: 4,
primary: yellowC, // background
onPrimary: Colors.black, // foreground
foregroundColor: Colors.black, elevation: 4,
backgroundColor: yellowC, // foreground
),
onPressed: () {
genW.pasteMnemonic(context);
@ -173,7 +174,7 @@ class RestoreChest extends StatelessWidget {
color: Colors.white,
child: Text(
text,
key: const Key('importText'),
key: keyBubbleSpeak,
textAlign: TextAlign.justify,
style: const TextStyle(
color: Colors.black, fontSize: 19, fontWeight: FontWeight.w400),

View File

@ -1,9 +1,9 @@
import 'dart:typed_data';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/services.dart';
import 'package:gecko/globals.dart';
import 'package:flutter/material.dart';
import 'package:gecko/models/wallet_data.dart';
import 'package:gecko/models/widgets_keys.dart';
import 'package:gecko/providers/my_wallets.dart';
import 'package:gecko/providers/substrate_sdk.dart';
import 'package:gecko/screens/common_elements.dart';
@ -73,12 +73,12 @@ class ShowSeed extends StatelessWidget {
height: 40,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
foregroundColor: Colors.black,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
elevation: 1,
primary: orangeC, // background
onPrimary: Colors.black, // foreground
backgroundColor: orangeC,
elevation: 1, // foreground
),
onPressed: () {
Clipboard.setData(
@ -123,9 +123,8 @@ class ShowSeed extends StatelessWidget {
height: 60 * ratio,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 4,
primary: orangeC, // background
onPrimary: Colors.white, // foreground
foregroundColor: Colors.white, elevation: 4,
backgroundColor: orangeC, // foreground
),
onPressed: () {
Navigator.pop(context);
@ -206,7 +205,7 @@ class ShowSeed extends StatelessWidget {
),
Text(
dataWord,
key: Key('word$dataWord'),
key: keyMnemonicWord(dataWord),
style: TextStyle(fontSize: 17 * ratio, color: Colors.black),
),
]),

View File

@ -1,3 +1,5 @@
// ignore_for_file: must_be_immutable
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/services.dart';
import 'package:gecko/globals.dart';
@ -5,7 +7,6 @@ import 'package:flutter/material.dart';
// import 'package:gecko/models/home.dart';
// import 'package:provider/provider.dart';
// ignore: must_be_immutable
class TransactionCommentScreen extends StatelessWidget {
TextEditingController tplController = TextEditingController();

View File

@ -1,7 +1,11 @@
// ignore_for_file: must_be_immutable
import 'dart:async';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:gecko/models/chest_data.dart';
import 'package:gecko/models/widgets_keys.dart';
import 'package:gecko/providers/substrate_sdk.dart';
import 'package:gecko/providers/my_wallets.dart';
import 'package:gecko/models/wallet_data.dart';
@ -12,7 +16,6 @@ import 'package:pin_code_fields/pin_code_fields.dart';
import 'package:provider/provider.dart';
import 'package:gecko/globals.dart';
// ignore: must_be_immutable
class UnlockingWallet extends StatelessWidget {
UnlockingWallet({Key? keyUnlockWallet, required this.wallet})
: super(key: keyUnlockWallet);
@ -23,7 +26,6 @@ class UnlockingWallet extends StatelessWidget {
// ignore: close_sinks
StreamController<ErrorAnimationType>? errorController;
final formKey = GlobalKey<FormState>();
Color? pinColor = const Color(0xffF9F9F1);
var walletPin = '';
@ -52,7 +54,7 @@ class UnlockingWallet extends StatelessWidget {
left: 15,
child: Builder(
builder: (context) => IconButton(
key: const Key('popButton'),
key: keyPopButton,
icon: const Icon(
Icons.arrow_back,
color: Colors.black,
@ -103,6 +105,7 @@ class UnlockingWallet extends StatelessWidget {
SizedBox(height: 3 * ratio),
if (canUnlock)
InkWell(
key: keyCachePassword,
onTap: () {
walletOptions.changePinCacheChoice();
},
@ -127,7 +130,7 @@ class UnlockingWallet extends StatelessWidget {
const SizedBox(height: 10),
// if (canUnlock)
InkWell(
key: const Key('chooseChest'),
key: keyChangeChest,
onTap: () {
Navigator.push(
context,
@ -182,10 +185,11 @@ class UnlockingWallet extends StatelessWidget {
}
return Form(
key: formKey,
// key: keyPinForm,
child: Padding(
padding: EdgeInsets.symmetric(vertical: 5 * ratio, horizontal: 30),
child: PinCodeTextField(
key: keyPinForm,
focusNode: pinFocus,
autoFocus: true,
appContext: context,
@ -213,6 +217,7 @@ class UnlockingWallet extends StatelessWidget {
fieldWidth: 50,
activeFillColor: Colors.black,
),
showCursor: kDebugMode ? false : true,
cursorColor: Colors.black,
animationDuration: const Duration(milliseconds: 300),
textStyle: const TextStyle(fontSize: 20, height: 1.6),

View File

@ -3,6 +3,7 @@ import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:gecko/globals.dart';
import 'package:gecko/models/widgets_keys.dart';
import 'package:gecko/providers/duniter_indexer.dart';
import 'package:gecko/providers/home.dart';
import 'package:gecko/providers/my_wallets.dart';
@ -37,6 +38,10 @@ class WalletOptions extends StatelessWidget {
DuniterIndexer duniterIndexer =
Provider.of<DuniterIndexer>(context, listen: false);
// SubstrateSdk sub = Provider.of<SubstrateSdk>(context, listen: false);
// sub.spawnBlock();
// sub.spawnBlock(0, 20);
log.d(walletOptions.address.text);
final int currentChest = myWalletProvider.getCurrentChest();
@ -213,7 +218,7 @@ class WalletOptions extends StatelessWidget {
else
const SizedBox(),
if (isMember.data!)
manageMemberStatus(context)
manageMembership(context)
]);
}),
]);
@ -292,10 +297,10 @@ class WalletOptions extends StatelessWidget {
width: 320,
height: 60,
child: ElevatedButton(
key: keyConfirmIdentity,
style: ElevatedButton.styleFrom(
elevation: 4,
primary: orangeC, // background
onPrimary: Colors.white, // foreground
foregroundColor: Colors.white, elevation: 4,
backgroundColor: orangeC, // foreground
),
onPressed: () {
walletProvider.confirmIdentityPopup(context);
@ -334,7 +339,7 @@ class WalletOptions extends StatelessWidget {
Widget pubkeyWidget(WalletOptionsProvider walletProvider, BuildContext ctx) {
final String shortPubkey = getShortPubkey(walletProvider.address.text);
return GestureDetector(
key: const Key('copyPubkey'),
key: keyCopyAddress,
onTap: () {
Clipboard.setData(ClipboardData(text: walletProvider.address.text));
snackCopyKey(ctx);
@ -359,12 +364,12 @@ class WalletOptions extends StatelessWidget {
height: 40,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
foregroundColor: Colors.black,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
elevation: 1,
primary: orangeC, // background
onPrimary: Colors.black, // foreground
backgroundColor: orangeC,
elevation: 1, // foreground
),
onPressed: () {
Clipboard.setData(
@ -394,7 +399,7 @@ class WalletOptions extends StatelessWidget {
WalletsProfilesProvider historyProvider,
WalletOptionsProvider walletProvider) {
return InkWell(
key: const Key('displayActivity'),
key: keyOpenActivity,
onTap: () {
// _historyProvider.nPage = 1;
Navigator.push(
@ -431,11 +436,11 @@ class WalletOptions extends StatelessWidget {
);
}
Widget manageMemberStatus(BuildContext context) {
Widget manageMembership(BuildContext context) {
WalletOptionsProvider walletOptions =
Provider.of<WalletOptionsProvider>(context, listen: false);
return InkWell(
key: const Key('manageStatus'),
key: keyManageMembership,
onTap: () {
Navigator.push(
context,
@ -471,7 +476,7 @@ class WalletOptions extends StatelessWidget {
WalletData defaultWallet = myWalletProvider.getDefaultWallet();
walletOptions.isDefaultWallet = (defaultWallet.number == wallet.id()[1]);
return InkWell(
key: const Key('setDefaultWallet'),
key: keySetDefaultWallet,
onTap: !walletProvider.isDefaultWallet
? () async {
await setDefaultWallet(context, currentChest);
@ -544,7 +549,7 @@ class WalletOptions extends StatelessWidget {
!hasConsumers.data! &&
(balance > 2 || balance == 0);
return InkWell(
key: const Key('deleteWallet'),
key: keyDeleteWallet,
onTap: canDelete
? () async {
await walletProvider.deleteWallet(context, wallet);

View File

@ -4,6 +4,7 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/services.dart';
import 'package:gecko/globals.dart';
import 'package:gecko/models/chest_data.dart';
import 'package:gecko/models/widgets_keys.dart';
import 'package:gecko/providers/duniter_indexer.dart';
import 'package:gecko/providers/home.dart';
import 'package:gecko/providers/my_wallets.dart';
@ -59,7 +60,6 @@ class WalletsHome extends StatelessWidget {
);
}),
title: Text(currentChest.name!,
key: const Key('myWallets'),
style: TextStyle(color: Colors.grey[850])),
backgroundColor: const Color(0xffFFD58D),
),
@ -87,9 +87,8 @@ class WalletsHome extends StatelessWidget {
height: 60,
),
style: ElevatedButton.styleFrom(
elevation: 2,
primary: floattingYellow, // background
onPrimary: Colors.black, // foreground
foregroundColor: Colors.black, elevation: 2,
backgroundColor: floattingYellow, // foreground
),
onPressed: () => Navigator.push(
context,
@ -108,7 +107,7 @@ class WalletsHome extends StatelessWidget {
)),
const SizedBox(height: 30),
InkWell(
key: const Key('importG1v1'),
key: keyImportG1v1,
onTap: () {
Navigator.push(
context,
@ -130,7 +129,7 @@ class WalletsHome extends StatelessWidget {
),
const SizedBox(height: 5),
InkWell(
key: const Key('changeChest'),
key: keyChangeChest,
onTap: () {
Navigator.push(
context,
@ -190,7 +189,7 @@ class WalletsHome extends StatelessWidget {
return CustomScrollView(slivers: <Widget>[
const SliverToBoxAdapter(child: SizedBox(height: 20)),
SliverGrid.count(
key: const Key('listWallets'),
key: keyListWallets,
crossAxisCount: nTule,
childAspectRatio: 1,
crossAxisSpacing: 0,
@ -200,6 +199,7 @@ class WalletsHome extends StatelessWidget {
Padding(
padding: const EdgeInsets.all(16),
child: GestureDetector(
key: keyOpenWallet(repository.address!),
onTap: () {
walletOptions.getAddress(
currentChestNumber, repository.derivation!);
@ -366,7 +366,7 @@ class WalletsHome extends StatelessWidget {
child: Column(children: <Widget>[
Expanded(
child: InkWell(
key: const Key('addDerivation'),
key: keyAddDerivation,
onTap: () async {
if (!myWalletProvider.isNewDerivationLoading) {
WalletData? defaultWallet =

View File

@ -2,6 +2,7 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/services.dart';
import 'package:gecko/globals.dart';
import 'package:flutter/material.dart';
import 'package:gecko/models/widgets_keys.dart';
import 'package:gecko/providers/cesium_plus.dart';
import 'package:gecko/models/g1_wallets_list.dart';
import 'package:gecko/providers/duniter_indexer.dart';
@ -28,7 +29,6 @@ class ContactsScreen extends StatelessWidget {
DuniterIndexer duniterIndexer =
Provider.of<DuniterIndexer>(context, listen: false);
int keyID = 0;
double avatarSize = 55;
final myContacts = contactsBox.toMap().values.toList();
@ -71,7 +71,7 @@ class ContactsScreen extends StatelessWidget {
Padding(
padding: const EdgeInsets.symmetric(horizontal: 5),
child: ListTile(
key: Key('searchResult${keyID++}'),
key: keySearchResult('keyID++'),
horizontalTitleGap: 40,
contentPadding: const EdgeInsets.all(5),
leading: cesiumPlusProvider

View File

@ -1,11 +1,14 @@
// ignore_for_file: file_names
// ignore_for_file: must_be_immutable
import 'dart:async';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
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/providers/generate_wallets.dart';
import 'package:gecko/providers/my_wallets.dart';
import 'package:gecko/providers/substrate_sdk.dart';
@ -15,7 +18,6 @@ import 'package:gecko/screens/onBoarding/11_congratulations.dart';
import 'package:pin_code_fields/pin_code_fields.dart';
import 'package:provider/provider.dart';
// ignore: must_be_immutable
class OnboardingStepTen extends StatelessWidget {
OnboardingStepTen({Key? validationKey, this.scanDerivation = false})
: super(key: validationKey);
@ -100,6 +102,7 @@ class OnboardingStepTen extends StatelessWidget {
Consumer<SubstrateSdk>(builder: (context, sub, _) {
return sub.nodeConnected
? InkWell(
key: keyCachePassword,
onTap: () {
walletOptions.changePinCacheChoice();
},
@ -149,7 +152,7 @@ class OnboardingStepTen extends StatelessWidget {
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 30),
child: PinCodeTextField(
key: const Key('formKey2'),
key: keyPinForm,
autoFocus: true,
appContext: context,
pastedTextStyle: TextStyle(
@ -176,6 +179,7 @@ class OnboardingStepTen extends StatelessWidget {
fieldWidth: 50,
activeFillColor: hasError ? Colors.blueAccent : Colors.black,
),
showCursor: kDebugMode ? false : true,
cursorColor: Colors.black,
animationDuration: const Duration(milliseconds: 300),
textStyle: const TextStyle(fontSize: 20, height: 1.6),
@ -224,6 +228,7 @@ class OnboardingStepTen extends StatelessWidget {
generateWalletProvider.generatedMnemonic = '';
myWalletProvider.resetPinCode();
// sleep(const Duration(milliseconds: 500));
Navigator.push(
context,
FaderTransition(

View File

@ -4,10 +4,9 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/services.dart';
import 'package:flutter/material.dart';
import 'package:gecko/globals.dart';
import 'package:gecko/models/widgets_keys.dart';
import 'package:gecko/screens/common_elements.dart';
import 'package:gecko/screens/myWallets/wallets_home.dart';
// ignore: must_be_immutable
class OnboardingStepEleven extends StatelessWidget {
const OnboardingStepEleven({Key? key}) : super(key: key);
@ -54,20 +53,28 @@ Widget finishButton(BuildContext context) {
width: 380 * ratio,
height: 60 * ratio,
child: ElevatedButton(
key: const Key('goWalletHome'),
key: keyGoWalletsHome,
style: ElevatedButton.styleFrom(
elevation: 4,
primary: orangeC,
onPrimary: Colors.white, // foreground
foregroundColor: Colors.white, elevation: 4,
backgroundColor: orangeC, // foreground
),
onPressed: () {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) {
return const WalletsHome();
}),
ModalRoute.withName('/'),
);
//TODO: fix bad widget ancestor when pupUntil (multi_chest test failed)
// Navigator.popUntil(homeContext, ModalRoute.withName('/'));
// Navigator.of(homeContext, rootNavigator: true)
// .popUntil(ModalRoute.withName('/'));
// while (Navigator.of(homeContext).canPop()) {
// Navigator.of(homeContext).pop();
// }
// Navigator.pushNamed(homeContext, '/mywallets');
Navigator.pushNamedAndRemoveUntil(
context, '/mywallets', (route) => route.isFirst);
// Navigator.pushNamedAndRemoveUntil(
// homeContext, '/mywallets', ModalRoute.withName('/'));
},
child: Text("accessMyChest".tr(),
style:

View File

@ -4,6 +4,7 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/services.dart';
import 'package:flutter/material.dart';
import 'package:gecko/globals.dart';
import 'package:gecko/models/widgets_keys.dart';
import 'package:gecko/providers/generate_wallets.dart';
import 'package:gecko/providers/my_wallets.dart';
import 'package:gecko/screens/common_elements.dart';
@ -80,11 +81,10 @@ class _ChooseChestState extends State<OnboardingStepFive> {
width: 380 * ratio,
height: 60 * ratio,
child: ElevatedButton(
key: const Key('generateMnemonic'),
key: keyGenerateMnemonic,
style: ElevatedButton.styleFrom(
elevation: 4,
primary: const Color(0xffFFD58D),
onPrimary: Colors.black, // foreground
foregroundColor: Colors.black, elevation: 4,
backgroundColor: const Color(0xffFFD58D), // foreground
),
onPressed: () {
// _generateWalletProvider.reloadBuild();
@ -101,7 +101,8 @@ class _ChooseChestState extends State<OnboardingStepFive> {
SizedBox(height: 22 * ratio),
nextButton(
context, "iNotedMyMnemonic".tr(), false, widget.skipIntro),
SizedBox(height: 35 * ratio),
const Spacer(),
// SizedBox(height: 35 * ratio),
]),
CommonElements().offlineInfo(context),
]),
@ -174,14 +175,13 @@ Widget arrayCell(dataWord) {
),
Text(
dataWord.split(':')[1],
key: Key('word${dataWord.split(':')[0]}'),
key: keyMnemonicWord(dataWord.split(':')[0]),
style: TextStyle(fontSize: 17 * ratio, color: Colors.black),
),
]),
);
}
// ignore: must_be_immutable
class PrintWallet extends StatelessWidget {
const PrintWallet(this.sentence, {Key? key}) : super(key: key);
@ -230,10 +230,10 @@ Widget nextButton(
width: 380 * ratio,
height: 60 * ratio,
child: ElevatedButton(
key: keyGoNext,
style: ElevatedButton.styleFrom(
elevation: 4,
primary: orangeC, // background
onPrimary: Colors.white, // foreground
foregroundColor: Colors.white, elevation: 4,
backgroundColor: orangeC, // foreground
),
onPressed: () {
generateWalletProvider.nbrWord = generateWalletProvider.getRandomInt();

View File

@ -1,16 +1,17 @@
// ignore_for_file: file_names
// ignore_for_file: must_be_immutable
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/services.dart';
import 'package:flutter/material.dart';
import 'package:gecko/globals.dart';
import 'package:gecko/models/widgets_keys.dart';
import 'package:gecko/providers/generate_wallets.dart';
import 'package:gecko/screens/common_elements.dart';
import 'package:gecko/screens/onBoarding/7.dart';
import 'package:gecko/screens/onBoarding/9.dart';
import 'package:provider/provider.dart';
// ignore: must_be_immutable
class OnboardingStepSix extends StatelessWidget {
OnboardingStepSix(
{Key? key, required this.skipIntro, required this.generatedMnemonic})
@ -66,7 +67,7 @@ class OnboardingStepSix extends StatelessWidget {
true),
SizedBox(height: isTall ? 70 : 20),
Text('${generateWalletProvider.nbrWord + 1}',
key: const Key('askedWord'),
key: keyAskedWord,
style: TextStyle(
fontSize: isTall ? 17 : 15,
color: orangeC,
@ -81,7 +82,7 @@ class OnboardingStepSix extends StatelessWidget {
)),
width: 430,
child: TextFormField(
key: const Key('inputWord'),
key: keyInputWord,
autofocus: true,
enabled: !generateWalletProvider.isAskedWordValid,
controller: wordController,
@ -206,7 +207,7 @@ Widget arrayCell(dataWord) {
),
Text(
dataWord.split(':')[1],
key: Key('word${dataWord.split(':')[0]}'),
key: keyMnemonicWord(dataWord.split(':')[0]),
style: const TextStyle(fontSize: 20, color: Colors.black),
),
]),
@ -224,10 +225,10 @@ Widget nextButton(BuildContext context, String text, nextScreen, bool isFast) {
width: 380 * ratio,
height: 60 * ratio,
child: ElevatedButton(
key: keyGoNext,
style: ElevatedButton.styleFrom(
elevation: 4,
primary: orangeC, // background
onPrimary: Colors.white, // foreground
foregroundColor: Colors.white, elevation: 4,
backgroundColor: orangeC, // foreground
),
onPressed: () {
Navigator.push(

View File

@ -3,12 +3,12 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/services.dart';
import 'package:flutter/material.dart';
import 'package:gecko/globals.dart';
import 'package:gecko/models/widgets_keys.dart';
import 'package:gecko/providers/generate_wallets.dart';
import 'package:gecko/screens/common_elements.dart';
import 'package:gecko/screens/onBoarding/10.dart';
import 'package:provider/provider.dart';
// ignore: must_be_immutable
class OnboardingStepNine extends StatelessWidget {
const OnboardingStepNine({Key? key, this.scanDerivation = false})
: super(key: key);
@ -52,7 +52,7 @@ class OnboardingStepNine extends StatelessWidget {
alignment: Alignment.centerRight,
children: <Widget>[
TextField(
key: const Key('generatedPin'),
key: keyGeneratedPin,
enabled: false,
controller: generateWalletProvider.pin,
maxLines: 1,
@ -79,11 +79,12 @@ class OnboardingStepNine extends StatelessWidget {
width: 380 * ratio,
height: 60 * ratio,
child: ElevatedButton(
key: const Key('changeSecretCode'),
key: keyChangePin,
style: ElevatedButton.styleFrom(
foregroundColor: Colors.black,
elevation: 4,
primary: const Color(0xffFFD58D),
onPrimary: Colors.black, // foreground
backgroundColor:
const Color(0xffFFD58D), // foreground
),
onPressed: () {
generateWalletProvider.changePinCode(

View File

@ -1,3 +1,5 @@
// ignore_for_file: must_be_immutable
import 'package:flutter/services.dart';
import 'package:gecko/globals.dart';
import 'package:flutter/material.dart';
@ -6,7 +8,6 @@ import 'package:qr_flutter/qr_flutter.dart';
// import 'package:gecko/models/home.dart';
// import 'package:provider/provider.dart';
// ignore: must_be_immutable
class QrCodeFullscreen extends StatelessWidget {
TextEditingController tplController = TextEditingController();

View File

@ -2,6 +2,7 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/services.dart';
import 'package:gecko/globals.dart';
import 'package:flutter/material.dart';
import 'package:gecko/models/widgets_keys.dart';
// import 'package:gecko/providers/home.dart';
import 'package:gecko/providers/search.dart';
import 'package:gecko/screens/common_elements.dart';
@ -51,6 +52,7 @@ class SearchScreen extends StatelessWidget {
Padding(
padding: const EdgeInsets.symmetric(horizontal: 17),
child: TextField(
key: keySearchField,
controller: searchProvider.searchController,
autofocus: true,
maxLines: 1,
@ -91,10 +93,10 @@ class SearchScreen extends StatelessWidget {
width: 410,
height: 70,
child: ElevatedButton(
key: keyConfirmSearch,
style: ElevatedButton.styleFrom(
elevation: 4,
primary: orangeC, // background
onPrimary: Colors.white, // foreground
foregroundColor: Colors.white, elevation: 4,
backgroundColor: orangeC, // foreground
),
onPressed: searchProvider.searchController.text.length >= 2
? () {

View File

@ -2,6 +2,7 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/services.dart';
import 'package:gecko/globals.dart';
import 'package:flutter/material.dart';
import 'package:gecko/models/widgets_keys.dart';
import 'package:gecko/providers/cesium_plus.dart';
import 'package:gecko/models/g1_wallets_list.dart';
import 'package:gecko/providers/duniter_indexer.dart';
@ -31,7 +32,6 @@ class SearchResultScreen extends StatelessWidget {
DuniterIndexer duniterIndexer =
Provider.of<DuniterIndexer>(context, listen: false);
int keyID = 0;
double avatarSize = 55;
return Scaffold(
@ -94,7 +94,7 @@ class SearchResultScreen extends StatelessWidget {
padding:
const EdgeInsets.symmetric(horizontal: 5),
child: ListTile(
key: Key('searchResult${keyID++}'),
key: keySearchResult(g1Wallet.pubkey!),
horizontalTitleGap: 40,
contentPadding: const EdgeInsets.all(5),
leading: cesiumPlusProvider

View File

@ -1,6 +1,7 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:gecko/models/widgets_keys.dart';
import 'package:gecko/providers/duniter_indexer.dart';
import 'package:gecko/providers/my_wallets.dart';
import 'package:gecko/providers/settings_provider.dart';
@ -8,9 +9,7 @@ import 'package:gecko/providers/substrate_sdk.dart';
import 'package:gecko/globals.dart';
import 'package:polkawallet_sdk/api/types/networkParams.dart';
import 'package:provider/provider.dart';
// import 'package:dropdown_button2/dropdown_button2.dart';
// ignore: must_be_immutable
class SettingsScreen extends StatelessWidget {
final MyWalletsProvider _myWallets = MyWalletsProvider();
@ -45,7 +44,7 @@ class SettingsScreen extends StatelessWidget {
width: buttonWidth,
child: Center(
child: InkWell(
key: const Key('deleteChest'),
key: keyDeleteAllWallets,
onTap: () async {
log.i('Oublier tous mes coffres');
await _myWallets.deleteAllWallet(context);
@ -115,11 +114,14 @@ class SettingsScreen extends StatelessWidget {
Icon(sub.nodeConnected && !sub.isLoadingEndpoint
? Icons.check
: Icons.close),
if (sub.nodeConnected && !sub.isLoadingEndpoint)
const Icon(Icons.add_card_sharp, size: 0.01),
const Spacer(),
SizedBox(
width: 265,
child: Consumer<SettingsProvider>(builder: (context, set, _) {
return DropdownButtonHideUnderline(
key: keySelectDuniterNodeDropDown,
child: DropdownButton(
// alignment: AlignmentDirectional.topStart,
value: selectedDuniterEndpoint,
@ -127,6 +129,7 @@ class SettingsScreen extends StatelessWidget {
items: duniterBootstrapNodes
.map((NetworkParams endpointParams) {
return DropdownMenuItem(
key: keySelectDuniterNode(endpointParams.endpoint!),
value: endpointParams.endpoint,
child: Text(endpointParams.endpoint!),
);
@ -145,6 +148,7 @@ class SettingsScreen extends StatelessWidget {
? CircularProgressIndicator(color: orangeC)
: Consumer<SettingsProvider>(builder: (context, set, _) {
return IconButton(
key: keyConnectToEndpoint,
icon: Icon(
Icons.send,
color: selectedDuniterEndpoint !=
@ -185,6 +189,7 @@ class SettingsScreen extends StatelessWidget {
width: 200,
height: 50,
child: TextField(
key: keyCustomDuniterEndpoint,
controller: endpointController,
autocorrect: false,
),

View File

@ -2,6 +2,7 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/services.dart';
import 'package:gecko/globals.dart';
import 'package:flutter/material.dart';
import 'package:gecko/models/widgets_keys.dart';
import 'package:gecko/providers/my_wallets.dart';
import 'package:gecko/providers/substrate_sdk.dart';
import 'package:gecko/providers/wallets_profiles.dart';
@ -9,7 +10,6 @@ import 'package:provider/provider.dart';
// import 'package:gecko/models/home.dart';
// import 'package:provider/provider.dart';
// ignore: must_be_immutable
class TransactionInProgress extends StatelessWidget {
const TransactionInProgress(
{Key? key, this.transType = 'pay', this.fromAddress, this.toAddress})
@ -33,6 +33,8 @@ class TransactionInProgress extends StatelessWidget {
// Map jsonResult;
final result = sub.transactionStatus;
// sub.spawnBlock();
log.d(walletViewProvider.address!);
final from = fromAddress ?? myWalletProvider.getDefaultWallet().name!;
@ -263,10 +265,10 @@ class TransactionInProgress extends StatelessWidget {
width: 380 * ratio,
height: 60 * ratio,
child: ElevatedButton(
key: keyCloseTransactionScreen,
style: ElevatedButton.styleFrom(
elevation: 4,
primary: orangeC, // background
onPrimary: Colors.white, // foreground
foregroundColor: Colors.white, elevation: 4,
backgroundColor: orangeC, // foreground
),
onPressed: () {
Navigator.pop(context);

View File

@ -5,6 +5,7 @@ import 'package:flutter/services.dart';
import 'package:gecko/globals.dart';
import 'package:flutter/material.dart';
import 'package:gecko/models/g1_wallets_list.dart';
import 'package:gecko/models/widgets_keys.dart';
import 'package:gecko/providers/cesium_plus.dart';
import 'package:gecko/providers/home.dart';
import 'package:gecko/providers/substrate_sdk.dart';
@ -42,12 +43,15 @@ class WalletViewScreen extends StatelessWidget {
SubstrateSdk sub = Provider.of<SubstrateSdk>(context, listen: false);
HomeProvider homeProvider =
Provider.of<HomeProvider>(context, listen: false);
MyWalletsProvider myWalletProvider =
Provider.of<MyWalletsProvider>(context, listen: false);
WalletData? defaultWallet = myWalletProvider.getDefaultWallet();
sub.setCurrentWallet(defaultWallet);
// sub.spawnBlock();
// sub.spawnBlock(0, 25);
return Scaffold(
backgroundColor: backgroundColor,
resizeToAvoidBottomInset: true,
@ -116,7 +120,7 @@ class WalletViewScreen extends StatelessWidget {
child: Material(
color: yellowC, //const Color(0xffFFD58D), // button color
child: InkWell(
key: const Key('viewHistory'),
key: keyViewActivity,
splashColor: orangeC, // inkwell color
child: const Padding(
padding: EdgeInsets.all(13),
@ -206,7 +210,7 @@ class WalletViewScreen extends StatelessWidget {
color:
const Color(0xffFFD58D), // button color
child: InkWell(
key: const Key('certify'),
key: keyCertify,
splashColor: orangeC, // inkwell color
child: const Padding(
padding: EdgeInsets.only(bottom: 0),
@ -245,8 +249,9 @@ class WalletViewScreen extends StatelessWidget {
final acc = sub.getCurrentWallet();
sub.certify(
acc.address!,
pin ?? myWalletProvider.pinCode,
walletViewProvider.address!);
walletViewProvider.address!,
pin ??
myWalletProvider.pinCode);
Navigator.push(
context,
@ -290,7 +295,7 @@ class WalletViewScreen extends StatelessWidget {
child: Material(
color: const Color(0xffFFD58D), // button color
child: InkWell(
key: const Key('copyKey'),
key: keyCopyAddress,
splashColor: orangeC, // inkwell color
child: const Padding(
padding: EdgeInsets.all(20),
@ -331,7 +336,7 @@ class WalletViewScreen extends StatelessWidget {
child: Material(
color: orangeC, // button color
child: InkWell(
key: const Key('pay'),
key: keyPay,
splashColor: yellowC,
onTap: sub.nodeConnected
? () {
@ -481,6 +486,7 @@ class WalletViewScreen extends StatelessWidget {
const SizedBox(height: 10),
Consumer<SubstrateSdk>(builder: (context, sub, _) {
return InkWell(
key: keyChangeChest,
onTap: () async {
String? pin;
if (myWalletProvider.pinCode == '') {
@ -572,6 +578,7 @@ class WalletViewScreen extends StatelessWidget {
),
const SizedBox(height: 10),
TextField(
key: keyAmountField,
controller: walletViewProvider.payAmount,
autofocus: true,
maxLines: 1,
@ -617,10 +624,10 @@ class WalletViewScreen extends StatelessWidget {
width: double.infinity,
height: 60,
child: ElevatedButton(
key: keyConfirmPayment,
style: ElevatedButton.styleFrom(
elevation: 4,
primary: orangeC, // background
onPrimary: Colors.white, // foreground
foregroundColor: Colors.white, elevation: 4,
backgroundColor: orangeC, // foreground
),
onPressed: canValidate
? () async {

View File

@ -7,21 +7,21 @@ packages:
name: _fe_analyzer_shared
url: "https://pub.dartlang.org"
source: hosted
version: "44.0.0"
version: "47.0.0"
analyzer:
dependency: transitive
description:
name: analyzer
url: "https://pub.dartlang.org"
source: hosted
version: "4.4.0"
version: "4.7.0"
archive:
dependency: transitive
description:
name: archive
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.11"
version: "3.3.0"
args:
dependency: transitive
description:
@ -29,20 +29,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.3.1"
assorted_layout_widgets:
dependency: "direct main"
description:
name: assorted_layout_widgets
url: "https://pub.dartlang.org"
source: hosted
version: "6.1.1"
async:
dependency: transitive
description:
name: async
url: "https://pub.dartlang.org"
source: hosted
version: "2.8.2"
version: "2.9.0"
auth_header:
dependency: transitive
description:
@ -56,7 +49,7 @@ packages:
name: barcode
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.1"
version: "2.2.3"
barcode_scan2:
dependency: "direct main"
description:
@ -147,7 +140,7 @@ packages:
name: built_value
url: "https://pub.dartlang.org"
source: hosted
version: "8.4.0"
version: "8.4.1"
carousel_slider:
dependency: "direct main"
description:
@ -161,7 +154,7 @@ packages:
name: characters
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
version: "1.2.1"
charcode:
dependency: transitive
description:
@ -182,7 +175,7 @@ packages:
name: clock
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
version: "1.1.1"
code_builder:
dependency: transitive
description:
@ -197,20 +190,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.16.0"
confirm_dialog:
dependency: "direct main"
description:
name: confirm_dialog
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
connectivity_plus:
dependency: "direct main"
description:
name: connectivity_plus
url: "https://pub.dartlang.org"
source: hosted
version: "2.3.6"
version: "2.3.6+1"
connectivity_plus_linux:
dependency: transitive
description:
@ -253,13 +239,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.2"
coverage:
dependency: transitive
description:
name: coverage
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
cross_file:
dependency: transitive
description:
@ -268,12 +247,12 @@ packages:
source: hosted
version: "0.3.3+1"
crypto:
dependency: "direct main"
dependency: transitive
description:
name: crypto
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
version: "3.0.2"
dart_style:
dependency: transitive
description:
@ -287,14 +266,7 @@ packages:
name: dbus
url: "https://pub.dartlang.org"
source: hosted
version: "0.7.7"
desktop_window:
dependency: "direct main"
description:
name: desktop_window
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.0"
version: "0.7.8"
dio:
dependency: "direct main"
description:
@ -309,13 +281,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
dropdown_button2:
dependency: "direct main"
description:
name: dropdown_button2
url: "https://pub.dartlang.org"
source: hosted
version: "1.7.1"
durt:
dependency: "direct main"
description:
@ -343,9 +308,9 @@ packages:
name: fake_async
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
version: "1.3.1"
fast_base58:
dependency: "direct main"
dependency: transitive
description:
name: fast_base58
url: "https://pub.dartlang.org"
@ -384,6 +349,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.2"
flutter_dotenv:
dependency: "direct main"
description:
name: flutter_dotenv
url: "https://pub.dartlang.org"
source: hosted
version: "5.0.2"
flutter_driver:
dependency: "direct main"
description: flutter
@ -415,20 +387,13 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_logs:
dependency: "direct main"
description:
name: flutter_logs
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.7"
flutter_markdown:
dependency: "direct main"
description:
name: flutter_markdown
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.10+3"
version: "0.6.10+5"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
@ -436,13 +401,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.7"
flutter_svg:
dependency: "direct main"
description:
name: flutter_svg
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.3"
flutter_test:
dependency: "direct dev"
description: flutter
@ -564,7 +522,7 @@ packages:
source: hosted
version: "0.2.0"
hive:
dependency: "direct main"
dependency: transitive
description:
name: hive
url: "https://pub.dartlang.org"
@ -577,15 +535,8 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
hive_generator:
dependency: "direct dev"
description:
name: hive_generator
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.3"
http:
dependency: "direct main"
dependency: transitive
description:
name: http
url: "https://pub.dartlang.org"
@ -618,7 +569,7 @@ packages:
name: icons_launcher
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
version: "2.0.5"
image:
dependency: transitive
description:
@ -632,21 +583,21 @@ packages:
name: image_cropper
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.3"
version: "3.0.0"
image_cropper_for_web:
dependency: transitive
description:
name: image_cropper_for_web
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.4"
version: "1.0.2"
image_cropper_platform_interface:
dependency: transitive
description:
name: image_cropper_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
version: "3.0.2"
image_picker:
dependency: "direct main"
description:
@ -674,7 +625,7 @@ packages:
name: image_picker_ios
url: "https://pub.dartlang.org"
source: hosted
version: "0.8.5+6"
version: "0.8.6"
image_picker_platform_interface:
dependency: transitive
description:
@ -682,20 +633,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.6.1"
infinite_scroll_pagination:
dependency: "direct main"
description:
name: infinite_scroll_pagination
url: "https://pub.dartlang.org"
source: hosted
version: "3.2.0"
integration_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
intl:
dependency: "direct main"
dependency: transitive
description:
name: intl
url: "https://pub.dartlang.org"
@ -784,28 +728,21 @@ packages:
name: matcher
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.11"
version: "0.12.12"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.4"
matrix4_transform:
dependency: transitive
description:
name: matrix4_transform
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.1"
version: "0.1.5"
meta:
dependency: transitive
description:
name: meta
url: "https://pub.dartlang.org"
source: hosted
version: "1.7.0"
version: "1.8.0"
mime:
dependency: transitive
description:
@ -834,13 +771,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.5.0"
node_preamble:
dependency: transitive
description:
name: node_preamble
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.1"
normalize:
dependency: transitive
description:
@ -861,7 +791,7 @@ packages:
name: package_info_plus
url: "https://pub.dartlang.org"
source: hosted
version: "1.4.3"
version: "1.4.3+1"
package_info_plus_linux:
dependency: transitive
description:
@ -903,14 +833,7 @@ packages:
name: path
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.1"
path_drawing:
dependency: transitive
description:
name: path_drawing
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
version: "1.8.2"
path_parsing:
dependency: transitive
description:
@ -931,7 +854,7 @@ packages:
name: path_provider_android
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.17"
version: "2.0.20"
path_provider_ios:
dependency: transitive
description:
@ -966,7 +889,7 @@ packages:
name: path_provider_windows
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
version: "2.1.3"
path_tree:
dependency: transitive
description:
@ -980,7 +903,7 @@ packages:
name: pdf
url: "https://pub.dartlang.org"
source: hosted
version: "3.8.2"
version: "3.8.3"
permission_handler:
dependency: "direct main"
description:
@ -1115,14 +1038,7 @@ packages:
name: pubspec_parse
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
pull_to_refresh:
dependency: "direct main"
description:
name: pull_to_refresh
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
version: "1.2.1"
qr:
dependency: transitive
description:
@ -1139,13 +1055,6 @@ packages:
url: "https://github.com/insinfo/qr.flutter.git"
source: git
version: "4.0.0"
responsive_builder:
dependency: "direct main"
description:
name: responsive_builder
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.2"
responsive_framework:
dependency: "direct main"
description:
@ -1161,19 +1070,19 @@ packages:
source: hosted
version: "0.27.5"
sentry:
dependency: "direct main"
dependency: transitive
description:
name: sentry
url: "https://pub.dartlang.org"
source: hosted
version: "6.9.0"
version: "6.9.1"
sentry_flutter:
dependency: "direct main"
description:
name: sentry_flutter
url: "https://pub.dartlang.org"
source: hosted
version: "6.9.0"
version: "6.9.1"
shared_preferences:
dependency: "direct main"
description:
@ -1215,7 +1124,7 @@ packages:
name: shared_preferences_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
version: "2.1.0"
shared_preferences_web:
dependency: transitive
description:
@ -1237,20 +1146,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.2"
shelf_packages_handler:
dependency: transitive
description:
name: shelf_packages_handler
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
shelf_static:
dependency: transitive
description:
name: shelf_static
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.1"
shelf_web_socket:
dependency: transitive
description:
@ -1263,48 +1158,13 @@ packages:
description: flutter
source: sdk
version: "0.0.99"
sliver_tools:
dependency: transitive
description:
name: sliver_tools
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.7"
source_gen:
dependency: transitive
description:
name: source_gen
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.2"
source_helper:
dependency: transitive
description:
name: source_helper
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.2"
source_map_stack_trace:
dependency: transitive
description:
name: source_map_stack_trace
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
source_maps:
dependency: transitive
description:
name: source_maps
url: "https://pub.dartlang.org"
source: hosted
version: "0.10.10"
source_span:
dependency: transitive
description:
name: source_span
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.2"
version: "1.9.0"
stack_trace:
dependency: transitive
description:
@ -1332,42 +1192,28 @@ packages:
name: string_scanner
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
version: "1.1.1"
sync_http:
dependency: "direct main"
dependency: transitive
description:
name: sync_http
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.0"
version: "0.3.1"
term_glyph:
dependency: transitive
description:
name: term_glyph
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
test:
dependency: "direct main"
description:
name: test
url: "https://pub.dartlang.org"
source: hosted
version: "1.21.1"
version: "1.2.1"
test_api:
dependency: transitive
description:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.9"
test_core:
dependency: transitive
description:
name: test_core
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.13"
version: "0.4.12"
timing:
dependency: transitive
description:
@ -1388,7 +1234,7 @@ packages:
name: typed_data
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
version: "1.3.1"
universal_io:
dependency: transitive
description:
@ -1423,7 +1269,7 @@ packages:
name: vm_service
url: "https://pub.dartlang.org"
source: hosted
version: "8.2.2"
version: "9.0.0"
watcher:
dependency: transitive
description:
@ -1432,7 +1278,7 @@ packages:
source: hosted
version: "1.0.1"
web_socket_channel:
dependency: "direct main"
dependency: transitive
description:
name: web_socket_channel
url: "https://pub.dartlang.org"
@ -1445,13 +1291,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0"
webkit_inspection_protocol:
dependency: transitive
description:
name: webkit_inspection_protocol
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
webview_flutter:
dependency: transitive
description:
@ -1465,14 +1304,14 @@ packages:
name: webview_flutter_android
url: "https://pub.dartlang.org"
source: hosted
version: "2.9.3"
version: "2.10.0"
webview_flutter_platform_interface:
dependency: transitive
description:
name: webview_flutter_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.9.1"
version: "1.9.3"
webview_flutter_wkwebview:
dependency: transitive
description:
@ -1493,9 +1332,9 @@ packages:
name: xdg_directories
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0+1"
version: "0.2.0+2"
xml:
dependency: "direct main"
dependency: transitive
description:
name: xml
url: "https://pub.dartlang.org"

View File

@ -15,23 +15,12 @@ dependencies:
sdk: flutter
flutter_driver:
sdk: flutter
assorted_layout_widgets: ^6.1.1
bubble: ^1.2.1
carousel_slider: ^4.0.0
confirm_dialog: ^1.0.0
crypto: ^3.0.1
fast_base58: ^0.2.0
flutter_lints: ^2.0.1
flutter_logs: ^2.1.4
flutter_svg: ^1.1.3
graphql_flutter: ^5.1.1-beta.3
hive: ^2.0.4
hive_flutter: ^1.1.0
http: ^0.13.4
# image_gallery_saver: ^1.6.9
image_picker: ^0.8.4
infinite_scroll_pagination: ^3.1.0
intl: ^0.17.0
jdenticon_dart: ^2.0.0
logger: ^1.1.0
path_provider: ^2.0.9
@ -45,19 +34,12 @@ dependencies:
git:
url: https://github.com/insinfo/qr.flutter.git
ref: master
responsive_builder: ^0.4.1
responsive_framework: ^0.2.0
sentry: ^6.5.1
sentry_flutter: ^6.5.1
shared_preferences: ^2.0.7
sync_http: ^0.3.0
test: ^1.17.10
truncate: ^3.0.1
unorm_dart: ^0.2.0
xml: ^6.1.0
pull_to_refresh: ^2.0.0
dio: ^4.0.4
desktop_window: ^0.4.0
durt: ^0.1.6
package_info_plus: ^1.4.2
polkawallet_sdk: #^0.4.9
@ -68,14 +50,13 @@ dependencies:
# ref: gecko-old
ref: gecko-unwrapbytes
dots_indicator: ^2.1.0
web_socket_channel: ^2.2.0
connectivity_plus: ^2.3.3
image_cropper: ^2.0.3
image_cropper: ^3.0.0
easy_localization: ^3.0.1
flutter_markdown: ^0.6.10+2
dropdown_button2: ^1.6.3
pointycastle: ^3.6.1
hex: ^0.2.0
flutter_dotenv: ^5.0.2
dev_dependencies:
# flutter_launcher_icons: ^0.9.2
@ -84,7 +65,6 @@ dev_dependencies:
build_runner: ^2.1.2
flutter_test:
sdk: flutter
hive_generator: ^1.1.1
integration_test:
sdk: flutter
@ -112,3 +92,4 @@ flutter:
- assets/onBoarding/progress_bar/
- assets/walletOptions/
- sounds/
- .env

View File

@ -1,3 +0,0 @@
#!/bin/bash
flutter drive --target=test_driver/app.dart

View File

@ -1,30 +0,0 @@
// // This is a basic Flutter widget test.
// //
// // To perform an interaction with a widget in your test, use the WidgetTester
// // utility that Flutter provides. For example, you can send tap and scroll
// // gestures. You can also use WidgetTester to find child widgets in the widget
// // tree, read text, and verify that the values of widget properties are correct.
// import 'package:flutter/material.dart';
// import 'package:flutter_test/flutter_test.dart';
// import 'package:gecko/main.dart';
// void main() {
// testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// // Build our app and trigger a frame.
// await tester.pumpWidget(Gecko());
// // Verify that our counter starts at 0.
// expect(find.text('0'), findsOneWidget);
// expect(find.text('1'), findsNothing);
// // Tap the '+' icon and trigger a frame.
// await tester.tap(find.byIcon(Icons.add));
// await tester.pump();
// // Verify that our counter has incremented.
// expect(find.text('0'), findsNothing);
// expect(find.text('1'), findsOneWidget);
// });
// }

View File

@ -1,11 +0,0 @@
import 'package:flutter_driver/driver_extension.dart';
import 'package:gecko/main.dart' as app;
void main() {
// This line enables the extension.
enableFlutterDriverExtension();
// Call the `main()` function of the app, or call `runApp` with
// any widget you are interested in testing.
app.main();
}

View File

@ -1,455 +0,0 @@
import 'dart:async';
import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_driver/flutter_driver.dart';
import 'package:gecko/globals.dart';
import 'package:test/test.dart';
// import 'package:flutter/services.dart';
void main() {
int globalTimeout = 2;
group('Gecko App', () {
// First, define the Finders and use them to locate widgets from the
// test suite. Note: the Strings provided to the `byValueKey` method must
// be the same as the Strings we used for the Keys in step 1.
final manageWalletsFinder = find.byValueKey('manageWallets');
// final buttonFinder = find.byValueKey('increment');
FlutterDriver? driver;
String? pinCode;
// Connect to the Flutter driver before running any tests.
setUpAll(() async {
driver = await FlutterDriver.connect();
await driver!.waitUntilFirstFrameRasterized();
});
// Close the connection to the driver after the tests have completed.
tearDownAll(() async {
if (driver != null) {
driver!.close();
}
});
// *** Global functions *** //
// Function to tap the widget by key
Future tapOn(String key) async {
await driver!.tap(find.byValueKey(key));
}
// Easy get text
Future<String> getText(String text) async {
return await driver!.getText(find.byValueKey(
text,
));
}
// Function to go back to previous screen
Future goBack() async {
await Process.run(
'adb',
<String>['shell', 'input', 'keyevent', 'KEYCODE_BACK'],
runInShell: true,
);
}
// Easy sleep
Future sleep(int time) async {
await Future.delayed(Duration(milliseconds: time));
}
// Test if widget exist on screen, return a boolean
Future<bool> isPresent(SerializableFinder byValueKey,
{Duration timeout = const Duration(seconds: 1)}) async {
try {
await driver!.waitFor(byValueKey, timeout: timeout);
return true;
} catch (exception) {
return false;
}
}
// Create a derivation
Future createDerivation() async {
await tapOn('addDerivation');
await sleep(300);
}
// Delete a derivation
Future deleteWallet(bool confirm) async {
await tapOn('deleteWallet');
await sleep(100);
confirm ? await tapOn('confirmDeleting') : await tapOn('cancelDeleting');
await sleep(300);
}
// Delete all wallets
Future deleteAllWallets() async {
await tapOn('drawerMenu');
await sleep(300);
await tapOn('parameters');
await sleep(300);
await tapOn('deleteAllWallets');
await sleep(300);
await tapOn('confirmDeletingAllWallets');
await sleep(300);
}
// Fast creation of new Keychain
Future<String?> createNewKeychain(String name) async {
await tapOn('drawerMenu');
await sleep(300);
await tapOn('parameters');
await sleep(300);
await tapOn('generateKeychain');
while (await getText('generatedPin') == '') {
log.d('Waiting for pin code generation...');
await sleep(100);
}
pinCode = await getText('generatedPin');
await tapOn('storeKeychain');
await sleep(100);
await driver!.enterText('triche');
await tapOn('walletName');
await driver!.enterText(name);
await sleep(50);
await tapOn('confirmStorage');
await sleep(300);
return pinCode;
}
// *** Begin of tests *** //
test('OnBoarding - Open wallets management', (
{timeout = Timeout.none}) async {
// await driver.runUnsynchronized(() async { // Needed if we want to manage async drivers
await driver!.tap(manageWalletsFinder);
// If a wallet exist, go to delete theme all
if (!await isPresent(find.byValueKey('goStep1'))) {
await goBack();
await deleteAllWallets();
await driver!.tap(manageWalletsFinder);
}
// Get the SerializableFinder for text widget with key 'textOnboarding'
SerializableFinder textOnboarding = find.byValueKey(
'textOnboarding',
);
await sleep(100);
// Verify onboarding is starting, with text
expect(await driver!.getText(textOnboarding),
"Je ne connais pour linstant aucun de vos portefeuilles.\n\nVous pouvez en créer un nouveau, ou bien importer un portefeuille Cesium existant.");
});
test('OnBoarding - Go to create restore sentance', (
{timeout = Timeout.none}) async {
await tapOn('goStep1');
await tapOn('goStep2');
await tapOn('goStep3');
await tapOn('goStep4');
await tapOn('goStep5');
await tapOn('goStep6');
expect(
await driver!.getText(find.byValueKey(
'step6',
)),
"iGeneratedYourMnemonicKeepItSecret".tr());
});
test('OnBoarding - Generate sentance and confirme it', (
{timeout = Timeout.none}) async {
await tapOn('goStep7');
while (await getText('word1') == '...') {
log.d('Waiting for Mnemonic generation...');
await sleep(100);
}
Future selectWord() async {
List words = [for (var i = 1; i <= 13; i += 1) i];
for (var j = 1; j < 13; j++) {
words[j] = await getText('word$j');
}
expect(
await getText('step7'), "C'est le moment de noter votre phrase !");
await tapOn('goStep8');
await sleep(200);
String goodWord = words[int.parse(
await getText('askedWord'),
)];
// Enter the expected word
await driver!.enterText(goodWord);
// Check if word is valid
await driver!.waitFor(find.text("C'est le bon mot !"));
// Continue onboarding workflow
await tapOn('goStep9');
}
await selectWord();
//Go back 2 times to mnemonic generation screen
await goBack();
await goBack();
await sleep(100);
// Generate 3 times mnemonic
await tapOn('generateMnemonic');
await tapOn('generateMnemonic');
await tapOn('generateMnemonic');
await sleep(500);
await selectWord();
});
test('OnBoarding - Generate secret code and confirm it', (
{timeout = Timeout.none}) async {
expect(await getText('step9'),
"Super !\n\nJe vais maintenant créer votre code secret. \n\nVotre code secret chiffre votre coffre de clefs, ce qui le rend inutilisable par dautres, par exemple si vous perdez votre téléphone ou si on vous le vole.");
await sleep(800);
await tapOn('goStep10');
await sleep(50);
await tapOn('goStep11');
while (await getText('generatedPin') == '') {
log.d('Waiting for pin code generation...');
await sleep(100);
}
// Change secret code 4 times
for (int i = 0; i < 4; i++) {
await tapOn('changeSecretCode');
}
await sleep(500);
pinCode = await getText('generatedPin');
await tapOn('goStep12');
await sleep(300);
// //Enter bad secret code
// await driver.enterText('abcde');
// await tapOn('formKey');
// await sleep(1500);
// await tapOn('formKey2');
//Enter good secret code
await driver!.enterText(pinCode!);
expect(await getText('step13'),
"Top !\n\nVotre coffre et votre portefeuille ont été créés avec un immense succès.\n\nFélicitations !");
});
test('My wallets - Rename first derivation', (
{timeout = const Duration(seconds: 2)}) async {
await tapOn('goWalletHome');
expect(await getText('myWallets'), "geckoChest".tr());
await sleep(300);
// Go to first derivation and rename it
await driver!.tap(find.text('Mon portefeuille courant'));
await sleep(300);
await tapOn('renameWallet');
await sleep(100);
await tapOn('walletName');
await sleep(100);
await driver!.enterText('Renommage wallet 1');
await sleep(300);
await tapOn('renameWallet');
await sleep(400);
await driver!.waitFor(find.text('Renommage wallet 1'), timeout: timeout);
// expect(await getText('walletName'), "Renommage wallet 1");
await goBack();
});
test('My wallets - Create a derivations, open thems, tap all buttons', (
{timeout = const Duration(seconds: 2)}) async {
await driver!.waitFor(find.text('Renommage wallet 1'), timeout: timeout);
// Add a second derivation
await createDerivation();
// Go to second derivation options
await driver!.tap(find.text('Portefeuille 2'));
await sleep(100);
// Test options
await tapOn('displayBalance');
await tapOn('displayHistory');
await sleep(300);
await goBack();
await tapOn('displayBalance');
await sleep(100);
await tapOn('displayBalance');
await sleep(100);
await tapOn('displayBalance');
await tapOn('setDefaultWallet');
await sleep(50);
await tapOn('copyPubkey');
await driver!.waitFor(find
.text('Cette clé publique a été copié dans votre presse-papier.'));
await goBack();
// Add a third derivation
await createDerivation();
// Add a fourth derivation
await createDerivation();
await sleep(50);
// Go to third derivation options
await driver!.tap(find.text('Portefeuille 3'));
await sleep(100);
await tapOn('displayBalance');
// Delete third derivation
await deleteWallet(true);
});
test('My wallets - Extra tests', (
{timeout = const Duration(seconds: 2)}) async {
// Add derivation 5,6 and 7
await driver!.waitFor(find.text('Portefeuille 4'), timeout: timeout);
await createDerivation();
await createDerivation();
await createDerivation();
// Go home and come back to my wallets view
await goBack();
await sleep(100);
await tapOn('manageWallets');
await sleep(200);
//Enter secret code
await driver!.enterText(pinCode!);
await sleep(200);
// Go to derivation 6 and delete it
await driver!.tap(find.text('Portefeuille 6'));
await sleep(100);
await deleteWallet(true);
// Go to 2nd derivation and check if it's de default
await driver!.tap(find.text('Portefeuille 2'));
await driver!.waitFor(find.text('Ce portefeuille est celui par defaut'));
await tapOn('setDefaultWallet');
await sleep(100);
await driver!.waitFor(find.text('Ce portefeuille est celui par defaut'));
await sleep(300);
// Display history, copy pubkey, go back and rename wallet name
await tapOn('displayHistory');
await sleep(400);
await tapOn('copyPubkey');
await driver!.waitFor(find
.text('Cette clé publique a été copié dans votre presse-papier.'));
await sleep(800);
await goBack();
await sleep(300);
await tapOn('renameWallet');
await sleep(100);
await tapOn('walletName');
await sleep(100);
await driver!.enterText('Renommage wallet 2');
await sleep(300);
await tapOn('renameWallet');
await sleep(400);
await goBack();
await driver!.waitFor(find.text('Renommage wallet 2'));
await driver!.scrollIntoView(find.text('+'));
await createDerivation();
await createDerivation();
await driver!.scrollIntoView(find.text('+'));
await createDerivation();
await createDerivation();
await driver!.scrollIntoView(find.text('+'));
await createDerivation();
await createDerivation();
await driver!.scrollIntoView(find.text('+'));
await createDerivation();
await createDerivation();
await driver!.scrollIntoView(find.text('+'));
await createDerivation();
await createDerivation();
await driver!.scrollIntoView(find.text('+'));
await createDerivation();
await createDerivation();
await driver!.scrollIntoView(find.text('+'));
await createDerivation();
await sleep(400);
// Scroll the wallet screen until Derivation 20 and open it
await driver!.scrollUntilVisible(
find.byValueKey('listWallets'),
find.text('Portefeuille 20'),
dyScroll: -300.0,
);
await driver!.waitFor(find.text('Portefeuille 20'));
await sleep(400);
await driver!.tap(find.text('Portefeuille 20'));
await tapOn('copyPubkey');
});
test('Search - Search Pi profile, navigate in history transactions', (
{timeout = const Duration(seconds: 2)}) async {
await driver!.waitFor(find.text('Portefeuille 20'), timeout: timeout);
await goBack();
await goBack();
await sleep(200);
await tapOn('searchIcon');
await sleep(400);
await driver!.enterText('D2meevcAHFTS2gQMvmRW5Hzi25jDdikk4nC4u1FkwRaU');
await sleep(100);
await tapOn('copyPubkey');
await sleep(500);
await tapOn('switchPayHistory');
await sleep(1200);
// await driver.scrollIntoView(find.byValueKey('listTransactions'));
await driver!.scrollUntilVisible(
find.byValueKey('listTransactions'),
find.byValueKey('transaction35'),
dyScroll: -600.0,
);
await sleep(100);
await tapOn('transaction33');
await driver!.waitFor(find.text('Commentaire:'));
// Want to paste pubkey copied, but doesn't work actualy with flutter driver: https://github.com/flutter/flutter/issues/47448
// final ClipboardData pubkeyCopied =
// await Clipboard.getData(Clipboard.kTextPlain);
// await driver.enterText(pubkeyCopied.text);
await sleep(300);
}, timeout: Timeout(Duration(minutes: globalTimeout)));
test('Wallet generation - Fast wallets generations', (
{timeout = const Duration(seconds: 2)}) async {
await driver!.waitFor(find.text('Commentaire:'), timeout: timeout);
await goBack();
await goBack();
await deleteAllWallets();
await sleep(100);
final String? pincode = await (createNewKeychain('Fast wallet'));
await sleep(200);
await driver!.enterText(pincode!);
await sleep(100);
await createDerivation();
await sleep(100);
await driver!.tap(find.text('Fast wallet'));
await driver!.waitFor(find.text('Fast wallet'));
// Wait 3 seconds at the end
await sleep(3000);
});
}, timeout: Timeout(Duration(minutes: globalTimeout)));
}