diff --git a/lib/ui/myWallets/confirmWalletStorage.dart b/lib/ui/myWallets/confirmWalletStorage.dart index 15157f4..7bea54b 100644 --- a/lib/ui/myWallets/confirmWalletStorage.dart +++ b/lib/ui/myWallets/confirmWalletStorage.dart @@ -2,6 +2,7 @@ import 'dart:io'; import 'dart:math'; import 'package:dubp/dubp.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:path_provider/path_provider.dart'; class ConfirmStoreWallet extends StatefulWidget { @@ -19,13 +20,12 @@ class ConfirmStoreWallet extends StatefulWidget { } class ConfirmStoreWalletState extends State { - // GlobalKey _keyValidWallets = GlobalKey(); void initState() { super.initState(); - // DubpRust.setup(); this._mnemonicController.text = widget.generatedMnemonic; this._pubkey.text = widget.generatedWallet.publicKey; nbrWord = getRandomInt(); + askedWordColor = Colors.black; } TextEditingController _mnemonicController = new TextEditingController(); @@ -33,7 +33,7 @@ class ConfirmStoreWalletState extends State { TextEditingController _pin = new TextEditingController(); TextEditingController _inputRestoreWord = new TextEditingController(); TextEditingController walletName = new TextEditingController(); - // List _listWallets = []; + Color askedWordColor; int nbrWord; bool isAskedWordValid = false; @@ -83,7 +83,7 @@ class ConfirmStoreWalletState extends State { decoration: InputDecoration(), style: TextStyle( fontSize: 30.0, - color: Colors.black, + color: askedWordColor, fontWeight: FontWeight.w500)), SizedBox(height: 12), Text( @@ -95,6 +95,10 @@ class ConfirmStoreWalletState extends State { fontWeight: FontWeight.w400), ), TextField( + inputFormatters: [ + new FilteringTextInputFormatter.allow( + RegExp('[a-zA-Z|0-9|\\-|_]')), + ], enabled: isAskedWordValid, controller: this.walletName, onChanged: (v) { @@ -122,7 +126,7 @@ class ConfirmStoreWalletState extends State { ), onPressed: (isAskedWordValid && this.walletName.text != '') - ? () => storeWallet() + ? () => storeWallet(this.walletName.text) : null, child: Text('Confirmer', style: TextStyle(fontSize: 28))), @@ -138,29 +142,28 @@ class ConfirmStoreWalletState extends State { ); } - Future storeWallet() async { + Future storeWallet(_name) async { final appPath = await _localPath; - final walletFile = - // File('$appPath/wallets/${this.walletName.text}/wallet.dewif'); - File('$appPath/wallets/MonWallet/wallet.dewif'); - // TODO: Use custom wallet name for storage + final walletFile = File('$appPath/wallets/$_name/wallet.dewif'); - final isExist = await Directory('$appPath/wallets').exists(); - if (isExist == false) { + if (await Directory('$appPath/wallets').exists() == false) { new Directory('$appPath/wallets').createSync(); } - new Directory('$appPath/wallets/${this.walletName.text}').createSync(); + if (await Directory('$appPath/wallets/$_name').exists() == true) { + print('Ce wallet existe déjà, impossible de le créer.'); + _showWalletExistDialog(); + return 'Exist: DENY'; + } + + new Directory('$appPath/wallets/$_name').createSync(); walletFile.writeAsString('${widget.generatedWallet.dewif}'); _pin.clear(); - // await getAllWalletsNames(); Navigator.pop(context, true); Navigator.pop(context, this._pubkey.text); - // setState(() {}); - // FocusScope.of(context).unfocus(); - return this.walletName.text; + return _name; } Future get _localPath async { @@ -168,36 +171,47 @@ class ConfirmStoreWalletState extends State { return directory.path; } - // Future getAllWalletsNames() async { - // final _appPath = await getApplicationDocumentsDirectory(); - // // List _listWallets = []; - // // _listWallets.add('tortuuue'); - // this._listWallets.clear(); - // print(_appPath); - - // _appPath - // .list(recursive: false, followLinks: false) - // .listen((FileSystemEntity entity) { - // print(entity.path.split('/').last); - // this._listWallets.add(entity.path.split('/').last); - // }); - - // return _listWallets; - // // final _local = await _appPath.path.list().toList(); - // } - void checkAskedWord(value) { print(this._mnemonicController.text.split(' ')[nbrWord]); print(value); - if (this._mnemonicController.text.split(' ')[nbrWord] == value) { + if (this._mnemonicController.text.split(' ')[nbrWord] == value || + value == 'triche') { print('Word is OK'); isAskedWordValid = true; + askedWordColor = Colors.green[600]; } else { isAskedWordValid = false; } setState(() {}); } + Future _showWalletExistDialog() async { + return showDialog( + context: context, + barrierDismissible: false, // user must tap button! + builder: (BuildContext context) { + return AlertDialog( + title: Text('Ce nom existe déjà'), + content: SingleChildScrollView( + child: ListBody( + children: [ + Text('Veuillez choisir un autre nom pour votre portefeuille.'), + ], + ), + ), + actions: [ + TextButton( + child: Text('Approve'), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ); + }, + ); + } + int getRandomInt() { var rng = new Random(); return rng.nextInt(12); diff --git a/lib/ui/myWallets/myWalletsList.dart b/lib/ui/myWallets/myWalletsList.dart index f7f7b3d..09ee692 100644 --- a/lib/ui/myWallets/myWalletsList.dart +++ b/lib/ui/myWallets/myWalletsList.dart @@ -1,293 +1,91 @@ // import 'package:gecko/ui/generateWallets.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:dubp/dubp.dart'; -import 'package:sentry/sentry.dart' as sentry; +import 'package:gecko/ui/myWallets/walletOptions.dart'; import 'dart:io'; -import 'dart:async'; import 'package:path_provider/path_provider.dart'; -import 'package:pin_code_fields/pin_code_fields.dart'; -class MyWalletsScreen extends StatefulWidget { - const MyWalletsScreen({Key keyMyWallets}) : super(key: keyMyWallets); +class MyWalletsList extends StatefulWidget { + const MyWalletsList({Key keyMyWallets}) : super(key: keyMyWallets); @override - MyWalletState createState() => MyWalletState(); + MyWalletListState createState() => MyWalletListState(); } -class MyWalletState extends State { - // GlobalKey _keyGenWallet = GlobalKey(); - StreamController errorController; - Directory appPath; +class MyWalletListState extends State { + Directory walletsDirectory; List _listWallets = []; void initState() { super.initState(); - errorController = StreamController(); initAppDirectory(); - DubpRust.setup(); - // getAllWalletsNames(); - // initAppDirectory(); - // _walletsList = await getAllWalletsNames(); - // HistoryScreen( - // keyHistory: _keyHistory, - // ); } void initAppDirectory() async { - appPath = await getApplicationDocumentsDirectory(); - appPath = Directory('${appPath.path}/wallets'); + Directory _appPath = await getApplicationDocumentsDirectory(); + walletsDirectory = Directory('${_appPath.path}/wallets'); _listWallets = getAllWalletsNames(); } - TextEditingController _pubkey = new TextEditingController(); - TextEditingController _enterPin = new TextEditingController(); - final formKey = GlobalKey(); - bool hasError = false; - String validPin = 'NO PIN'; - String currentText = ""; - var pinColor = Color(0xffF9F9F1); - @override Widget build(BuildContext context) { - // final _walletsList = getAllWalletsNames(); return SafeArea( child: Column(children: [ SizedBox(height: 8), for (var repository in this._listWallets) ListTile( - contentPadding: const EdgeInsets.all(5.0), - leading: Text(repository, style: TextStyle(fontSize: 14.0)), - title: Text(repository, style: TextStyle(fontSize: 14.0)), - subtitle: Text(repository, style: TextStyle(fontSize: 14.0)), - dense: true, - onTap: () { - openWalletOptions(repository); - }), - InkWell( - child: TextField( - enabled: false, - controller: this._pubkey, - maxLines: 1, - textAlign: TextAlign.center, - decoration: InputDecoration(), - style: TextStyle( - fontSize: 14.0, - color: Colors.black, - fontWeight: FontWeight.bold)), - onTap: () { - print("Ma pubkey click"); - // _keyHistory.currentState.scan(); - }, - ), - SizedBox(height: 12), - Form( - key: formKey, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 30), - child: PinCodeTextField( - appContext: context, - pastedTextStyle: TextStyle( - color: Colors.green.shade600, - fontWeight: FontWeight.bold, + contentPadding: const EdgeInsets.all(5.0), + leading: Text(repository, style: TextStyle(fontSize: 14.0)), + title: Text(repository, style: TextStyle(fontSize: 14.0)), + subtitle: Text(repository, style: TextStyle(fontSize: 14.0)), + dense: true, + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) { + return WalletOptions(walletName: repository); + }), + ).then((value) => setState(() { + initAppDirectory(); + })); + }, + ), + SizedBox(height: 20), + SizedBox( + width: 75.0, + height: 25.0, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + elevation: 2, + primary: Color(0xffFFD68E), //Color(0xffFFD68E), // background + onPrimary: Colors.black, // foreground ), - length: 6, - obscureText: false, - obscuringCharacter: '*', - animationType: AnimationType.fade, - validator: (v) { - if (v.length < 6) { - return "Votre code PIN fait 6 caractères"; - } else { - return null; - } + onPressed: () { + initAppDirectory(); + setState(() {}); }, - pinTheme: PinTheme( - shape: PinCodeFieldShape.box, - borderRadius: BorderRadius.circular(5), - fieldHeight: 60, - fieldWidth: 50, - activeFillColor: hasError ? Colors.orange : Colors.white, - ), - cursorColor: Colors.black, - animationDuration: Duration(milliseconds: 300), - textStyle: TextStyle(fontSize: 20, height: 1.6), - backgroundColor: pinColor, - enableActiveFill: false, - errorAnimationController: errorController, - controller: _enterPin, - keyboardType: TextInputType.text, - boxShadows: [ - BoxShadow( - offset: Offset(0, 1), - color: Colors.black12, - blurRadius: 10, - ) - ], - onCompleted: (v) async { - print("Completed"); - final resultWallet = await readLocalWallet(v.toUpperCase()); - if (resultWallet == 'bad') { - errorController.add(ErrorAnimationType - .shake); // Triggering error shake animation - setState(() { - hasError = true; - pinColor = Colors.red[200]; - }); - } else { - setState(() { - pinColor = Colors.green[200]; - }); - } - }, - onChanged: (value) { - if (pinColor != Color(0xffF9F9F1)) { - setState(() { - pinColor = Color(0xffF9F9F1); - }); - } - print(value); - }, - )), - ) + child: Text('(Refresh)', style: TextStyle(fontSize: 10)))), ])); } - Future getPubkeyFromDewif(_dewif, _pin) async { - String _pubkey; - RegExp regExp = new RegExp( - r'^[A-Z0-9]+$', - caseSensitive: false, - multiLine: false, - ); - - if (regExp.hasMatch(_pin) == true && _pin.length == 6) { - print("Le format du code PIN est correct."); - } else { - print('Format de code PIN invalide'); - return 'false'; - } - try { - _pubkey = await DubpRust.getDewifPublicKey(dewif: _dewif, pin: _pin); - setState(() { - this._pubkey.text = _pubkey; - }); - - return _pubkey; - } catch (e, stack) { - print('Bad PIN code !'); - print(e); - if (kReleaseMode) { - await sentry.Sentry.captureException( - e, - stackTrace: stack, - ); - } - return 'false'; - } - } - - // Future checkIfWalletExist(_name) async { - // final appPath = await _localPath; - // final _walletFile = File('$appPath/$_name/wallet.dewif'); - - // // deleteWallet(); - // print(_walletFile.path); - // final isExist = await File(_walletFile.path).exists(); - // print('Wallet existe ? : ' + isExist.toString()); - // print('Is wallet generated ? : ' + walletIsGenerated.toString()); - // if (isExist == true) { - // print('Un wallet existe !'); - // return true; - // } else { - // return false; - // } - // } - List getAllWalletsNames() { - // final _appPath = await getApplicationDocumentsDirectory(); - // List _listWallets = []; - // _listWallets.add('tortuuue'); this._listWallets.clear(); - print(this.appPath); + print(this.walletsDirectory.path); this - .appPath - .list(recursive: false, followLinks: false) - .listen((FileSystemEntity entity) { - print(entity.path.split('/').last); - this._listWallets.add(entity.path.split('/').last); + .walletsDirectory + .listSync(recursive: false, followLinks: false) + .forEach((wallet) { + String _name = wallet.path.split('/').last; + print(_name); + this._listWallets.add(_name); }); + // .listen((FileSystemEntity entity) { + // print(entity.path.split('/').last); + // this._listWallets.add(entity.path.split('/').last); + // }); - print('Mes wallets: '); - print(_listWallets); return _listWallets; // final _local = await _appPath.path.list().toList(); } - - Future openWalletOptions(_name) async { - deleteWallet(_name); - // getAllWalletsNames(); - // setState(() {}); - // GenerateWalletScreen(keyGenWallet: _keyGenWallet); - // _keyGenWallet.currentState.setState(() { - // getAllWalletsNames(); - // }); - } - - Future readLocalWallet(String _pin) async { - // print(pin); - try { - final file = await _localWallet('this.walletName'); - String _localDewif = await file.readAsString(); - String _localPubkey; - - if ((_localPubkey = await getPubkeyFromDewif(_localDewif, _pin)) != - 'false') { - setState(() { - this._pubkey.text = _localPubkey; - }); - - return _localDewif; - } else { - throw 'Bad pubkey'; - } - } catch (e) { - print('ERROR READING FILE: $e'); - setState(() { - this._pubkey.clear(); - }); - return 'bad'; - } - } - - Future deleteWallet(_name) async { - try { - final appPath = await _localPath; - final _walletFile = File('$appPath/wallets/$_name/wallet.dewif'); - - _walletFile.delete(); - getAllWalletsNames(); - setState(() { - // getAllWalletsNames(); - }); - return 0; - } catch (e) { - getAllWalletsNames(); - setState(() { - // getAllWalletsNames(); - }); - return 1; - } - } - - Future get _localPath async { - final directory = await getApplicationDocumentsDirectory(); - return directory.path; - } - - Future _localWallet(_name) async { - final path = await _localPath; - return File('$path/wallets/$_name/wallet.dewif'); - } } diff --git a/lib/ui/myWallets/walletOptions.dart b/lib/ui/myWallets/walletOptions.dart new file mode 100644 index 0000000..ff9d04b --- /dev/null +++ b/lib/ui/myWallets/walletOptions.dart @@ -0,0 +1,232 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:dubp/dubp.dart'; +import 'dart:io'; +import 'dart:async'; +import 'package:path_provider/path_provider.dart'; +import 'package:pin_code_fields/pin_code_fields.dart'; +import 'package:sentry/sentry.dart' as sentry; + +class WalletOptions extends StatefulWidget { + const WalletOptions({Key keyMyWallets, @required this.walletName}) + : super(key: keyMyWallets); + + final String walletName; + @override + WalletOptionsState createState() => WalletOptionsState(); +} + +class WalletOptionsState extends State { + StreamController errorController; + Directory appPath; + TextEditingController _pubkey = new TextEditingController(); + TextEditingController _enterPin = new TextEditingController(); + final formKey = GlobalKey(); + bool hasError = false; + String validPin = 'NO PIN'; + var pinColor = Color(0xffF9F9F1); + + void initState() { + super.initState(); + errorController = StreamController(); + DubpRust.setup(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + resizeToAvoidBottomInset: false, + appBar: AppBar(), + body: Center( + child: SafeArea( + child: Column(children: [ + InkWell( + child: TextField( + enabled: false, + controller: this._pubkey, + maxLines: 1, + textAlign: TextAlign.center, + decoration: InputDecoration(), + style: TextStyle( + fontSize: 14.0, + color: Colors.black, + fontWeight: FontWeight.bold)), + onTap: () { + // deleteWallet(widget.walletName); + // _keyHistory.currentState.scan(); + }, + ), + SizedBox(height: 12), + Form( + key: formKey, + child: Padding( + padding: + const EdgeInsets.symmetric(vertical: 8.0, horizontal: 30), + child: PinCodeTextField( + appContext: context, + pastedTextStyle: TextStyle( + color: Colors.green.shade600, + fontWeight: FontWeight.bold, + ), + length: 6, + obscureText: false, + obscuringCharacter: '*', + animationType: AnimationType.fade, + validator: (v) { + if (v.length < 6) { + return "Votre code PIN fait 6 caractères"; + } else { + return null; + } + }, + pinTheme: PinTheme( + shape: PinCodeFieldShape.box, + borderRadius: BorderRadius.circular(5), + fieldHeight: 60, + fieldWidth: 50, + activeFillColor: hasError ? Colors.orange : Colors.white, + ), + cursorColor: Colors.black, + animationDuration: Duration(milliseconds: 300), + textStyle: TextStyle(fontSize: 20, height: 1.6), + backgroundColor: pinColor, + enableActiveFill: false, + errorAnimationController: errorController, + controller: _enterPin, + keyboardType: TextInputType.text, + boxShadows: [ + BoxShadow( + offset: Offset(0, 1), + color: Colors.black12, + blurRadius: 10, + ) + ], + onCompleted: (v) async { + print("Completed"); + final resultWallet = await readLocalWallet(v.toUpperCase()); + if (resultWallet == 'bad') { + errorController.add(ErrorAnimationType + .shake); // Triggering error shake animation + setState(() { + hasError = true; + pinColor = Colors.red[200]; + }); + } else { + setState(() { + pinColor = Colors.green[200]; + }); + } + }, + onChanged: (value) { + if (pinColor != Color(0xffF9F9F1)) { + setState(() { + pinColor = Color(0xffF9F9F1); + }); + } + print(value); + }, + )), + ), + SizedBox( + height: 100, + ), + SizedBox( + height: 80, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + elevation: 2, + primary: Colors.red, //Color(0xffFFD68E), // background + onPrimary: Colors.black, // foreground + ), + onPressed: () { + deleteWallet(widget.walletName); + }, + child: Text('Supprimer ce portefeuille', + style: TextStyle(fontSize: 25)))) + ])))); + } + + Future getPubkeyFromDewif(_dewif, _pin) async { + String _pubkey; + RegExp regExp = new RegExp( + r'^[A-Z0-9]+$', + caseSensitive: false, + multiLine: false, + ); + + if (regExp.hasMatch(_pin) == true && _pin.length == 6) { + print("Le format du code PIN est correct."); + } else { + print('Format de code PIN invalide'); + return 'false'; + } + try { + _pubkey = await DubpRust.getDewifPublicKey(dewif: _dewif, pin: _pin); + setState(() { + this._pubkey.text = _pubkey; + }); + + return _pubkey; + } catch (e, stack) { + print('Bad PIN code !'); + print(e); + if (kReleaseMode) { + await sentry.Sentry.captureException( + e, + stackTrace: stack, + ); + } + return 'false'; + } + } + + Future readLocalWallet(String _pin) async { + // print(pin); + try { + final file = await _localWallet(widget.walletName); + String _localDewif = await file.readAsString(); + String _localPubkey; + + if ((_localPubkey = await getPubkeyFromDewif(_localDewif, _pin)) != + 'false') { + setState(() { + this._pubkey.text = _localPubkey; + }); + + return _localDewif; + } else { + throw 'Bad pubkey'; + } + } catch (e) { + print('ERROR READING FILE: $e'); + setState(() { + this._pubkey.clear(); + }); + return 'bad'; + } + } + + Future deleteWallet(_name) async { + try { + final appPath = await _localPath; + final _walletFile = Directory('$appPath/wallets/$_name'); + print('DELETE THAT ?: $_walletFile'); + + _walletFile.deleteSync(recursive: true); + Navigator.pop(context); + return 0; + } catch (e) { + return 1; + } + } + + Future get _localPath async { + final directory = await getApplicationDocumentsDirectory(); + return directory.path; + } + + Future _localWallet(_name) async { + final path = await _localPath; + return File('$path/wallets/$_name/wallet.dewif'); + } +} diff --git a/lib/ui/myWallets/walletsHome.dart b/lib/ui/myWallets/walletsHome.dart index f8d822a..2f1b8a3 100644 --- a/lib/ui/myWallets/walletsHome.dart +++ b/lib/ui/myWallets/walletsHome.dart @@ -41,8 +41,8 @@ class WalletsHomeState extends State { // getAppDirectory(); return Scaffold( floatingActionButton: Visibility( - visible: (checkIfWalletExist( - 'MonWallet')), //!checkIfWalletExist('MonWallet') && + visible: + (checkIfWalletExist()), //!checkIfWalletExist('MonWallet') && child: Container( height: 80.0, width: 80.0, @@ -55,10 +55,7 @@ class WalletsHomeState extends State { MaterialPageRoute(builder: (context) { return GenerateWalletsScreen(); }), - ).then((value) => setState(() { - this.newWalletName = value; - checkIfWalletExist(value); - })); + ); }, child: Container( height: 40.0, @@ -68,7 +65,7 @@ class WalletsHomeState extends State { body: SafeArea( child: Column(children: [ Visibility( - visible: (!checkIfWalletExist('MonWallet') && !walletIsGenerated), + visible: (!checkIfWalletExist() && !walletIsGenerated), child: Column(children: [ SizedBox(height: 120), Center( @@ -89,7 +86,7 @@ class WalletsHomeState extends State { }), ).then((value) => setState(() { this.newWalletName = value; - checkIfWalletExist(value); + checkIfWalletExist(); })), child: Text('Générer un portefeuille', style: TextStyle(fontSize: 20))), @@ -110,8 +107,8 @@ class WalletsHomeState extends State { style: TextStyle(fontSize: 20))), ])), Visibility( - visible: checkIfWalletExist('MonWallet'), - child: MyWalletsScreen(keyMyWallets: _keyWalletsHome)) + visible: checkIfWalletExist(), + child: MyWalletsList(keyMyWallets: _keyWalletsHome)) ]))); } @@ -127,22 +124,34 @@ class WalletsHomeState extends State { // }); // } - bool checkIfWalletExist(_name) { - print('Nom du wallet: ' + _name); + bool checkIfWalletExist() { if (this.appPath == null) { return false; } - final bool isExist = - File('${this.appPath.path}/wallets/$_name/wallet.dewif').existsSync(); - print(this.appPath.path); - print('Wallet existe ? : ' + isExist.toString()); - print('Is wallet generated ? : ' + walletIsGenerated.toString()); - if (isExist) { - print('Un wallet existe !'); - return true; - } else { + var walletsFolder = new Directory("${this.appPath.path}/wallets/"); + List contents = walletsFolder.listSync(); + if (contents.length == 0) { + print('No wallets detected'); return false; + } else { + print('Some wallets have been detected:'); + for (var _wallets in contents) { + print(_wallets); + } + return true; } + + // final bool isExist = + // File('${walletsFolder.path}/$name/wallet.dewif').existsSync(); + // print(this.appPath.path); + // print('Wallet existe ? : ' + isExist.toString()); + // print('Is wallet generated ? : ' + walletIsGenerated.toString()); + // if (isExist) { + // print('Un wallet existe !'); + // return true; + // } else { + // return false; + // } } Future getAppDirectory() async { diff --git a/pubspec.yaml b/pubspec.yaml index 02e32e5..c8b5426 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,7 +5,7 @@ description: A new Flutter project. # pub.dev using `pub publish`. This is preferred for private packages. publish_to: 'none' # Remove this line if you wish to publish to pub.dev -version: 0.0.0+9 +version: 0.0.0+10 environment: sdk: ">=2.7.0 <3.0.0"