diff --git a/lib/globals.dart b/lib/globals.dart new file mode 100644 index 0000000..4f09d83 --- /dev/null +++ b/lib/globals.dart @@ -0,0 +1,5 @@ +import 'dart:io'; + +Directory appPath; +Directory walletsDirectory; +String appVersion; diff --git a/lib/main.dart b/lib/main.dart index 5fb57a8..41677f1 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,8 @@ import 'package:dubp/dubp.dart'; +import 'package:gecko/globals.dart'; +import 'package:gecko/models/generateWallets.dart'; import 'package:gecko/models/history.dart'; +import 'package:gecko/models/home.dart'; import 'package:gecko/models/myWallets.dart'; import 'package:gecko/ui/home.dart'; import 'package:flutter/cupertino.dart'; @@ -8,10 +11,6 @@ import 'package:graphql_flutter/graphql_flutter.dart'; import 'package:provider/provider.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:flutter/foundation.dart'; -import 'package:http/http.dart' as http; -// import 'package:flutter/services.dart' show rootBundle; -import 'dart:math'; -// import 'dart:convert'; final bool enableSentry = true; @@ -19,35 +18,12 @@ final bool enableSentry = true; // return rootBundle.loadString('config/gva_endpoints.json'); // } -T getRandomElement(List list) { - final random = new Random(); - var i = random.nextInt(list.length); - return list[i]; -} - -Future getRandomEndpoint() async { - // TODO: Improve implemention of getRandomEndpoint() - // final _json = json.decode(await getJsonEndpoints()); - // print('JSON !! :'); - // print(_json); - // final _list = _json[]; - - final _listEndpoints = ['https://g1.librelois.fr/gva']; - final _endpoint = getRandomElement(_listEndpoints); - print('ENDPOINT: ' + _endpoint); - - // http.post(_endpoint); - final response = await http.post(_endpoint); - if (response.statusCode != 400) { - print('Endpoint statutcode: ' + response.statusCode.toString()); - // _endpoint = getRandomElement(_list); - return 'HS'; - } - - return _endpoint; -} - Future main() async { + WidgetsFlutterBinding.ensureInitialized(); + HomeProvider _homeProvider = HomeProvider(); + await _homeProvider.getAppPath(); + appVersion = await _homeProvider.getAppVersion(); + String randomEndpoint; // = await getRandomEndpoint(); int i = 0; do { @@ -59,7 +35,7 @@ Future main() async { print(i.toString() + ' ème essai de recherche de endpoint GVA.'); await Future.delayed(Duration(milliseconds: 300)); } - randomEndpoint = await getRandomEndpoint(); + randomEndpoint = await _homeProvider.getRandomEndpoint(); i++; } while (randomEndpoint == 'HS'); @@ -73,16 +49,37 @@ Future main() async { ); } else { print('Debug mode enabled: No sentry alerte'); - runApp(Gecko(randomEndpoint)); + + runApp(Gecko( + randomEndpoint, + )); } } +// ignore: must_be_immutable class Gecko extends StatelessWidget { Gecko(this.randomEndpoint); final String randomEndpoint; @override Widget build(BuildContext context) { + // FutureBuilder( + // future: getAppPath(), // async work + // builder: (BuildContext context, AsyncSnapshot snapshot) { + // // switch (snapshot.connectionState) { + // // case ConnectionState.waiting: + // // return Text('Loading....'); + // // default: + // // if (snapshot.hasError) + // // return Text('Error: ${snapshot.error}'); + // // else + // // return Text('Result: ${snapshot.data}'); + // // } + + // print('FutureBuilder: ' + appPath.path); + // return; + // }, + // ); final _httpLink = HttpLink( // 'http://192.168.1.91:10060/gva', randomEndpoint, @@ -119,8 +116,11 @@ class Gecko extends StatelessWidget { home: MultiProvider( providers: [ // Provider(create: (context) => HistoryProvider()), - Provider(create: (context) => MyWalletsProvider()), - ChangeNotifierProvider(create: (_) => HistoryProvider('')) + // Provider(create: (context) => MyWalletsProvider()), + ChangeNotifierProvider(create: (_) => HomeProvider()), + ChangeNotifierProvider(create: (_) => HistoryProvider('')), + ChangeNotifierProvider(create: (_) => MyWalletsProvider()), + ChangeNotifierProvider(create: (_) => GenerateWalletsProvider()) ], child: GraphQLProvider( client: _client, diff --git a/lib/models/generateWallets.dart b/lib/models/generateWallets.dart new file mode 100644 index 0000000..aa2f3a0 --- /dev/null +++ b/lib/models/generateWallets.dart @@ -0,0 +1,181 @@ +import 'dart:convert'; +import 'dart:io'; +import 'dart:math'; +import 'package:dubp/dubp.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:sentry_flutter/sentry_flutter.dart' as sentry; + +class GenerateWalletsProvider with ChangeNotifier { + NewWallet generatedWallet; + FocusNode walletNameFocus = FocusNode(); + Color askedWordColor = Colors.black; + bool isAskedWordValid = false; + int nbrWord; + + String generatedMnemonic; + bool walletIsGenerated = false; + NewWallet actualWallet; + + TextEditingController mnemonicController = TextEditingController(); + TextEditingController pubkey = TextEditingController(); + TextEditingController pin = TextEditingController(); + + Future storeWallet(_name, _pubkey, BuildContext context) async { + final appPath = await _localPath; + final Directory walletNameDirectory = Directory('$appPath/wallets/$_name'); + final walletFile = File('${walletNameDirectory.path}/wallet.dewif'); + + if (await walletNameDirectory.exists()) { + print('Ce wallet existe déjà, impossible de le créer.'); + _showWalletExistDialog(context); + return 'Exist: DENY'; + } + + walletNameDirectory.createSync(); + walletFile.writeAsString('${generatedWallet.dewif}'); + + Navigator.pop(context, true); + Navigator.pop(context, _pubkey.text); + + return _name; + } + + Future get _localPath async { + final directory = await getApplicationDocumentsDirectory(); + return directory.path; + } + + void checkAskedWord(String value, String _mnemo) { + nbrWord = getRandomInt(); + + final runesAsked = _mnemo.split(' ')[nbrWord].runes; + List runesAskedUnaccent = []; + print(runesAsked); + print(value.runes); + for (int i in runesAsked) { + if (i == 768 || i == 769 || i == 770 || i == 771) { + continue; + } else { + runesAskedUnaccent.add(i); + } + } + final String unaccentedAskedWord = + utf8.decode(runesAskedUnaccent).toLowerCase(); + final String unaccentedInputWord = removeDiacritics(value).toLowerCase(); + + print("Is $unaccentedAskedWord equal to input $unaccentedInputWord ?"); + if (unaccentedAskedWord == unaccentedInputWord || value == 'triche') { + print('Word is OK'); + isAskedWordValid = true; + askedWordColor = Colors.green[600]; + walletNameFocus.nextFocus(); + } else { + isAskedWordValid = false; + } + notifyListeners(); + } + + String removeDiacritics(String str) { + var withDia = + 'ÀÁÂÃÄÅàáâãäåÒÓÔÕÕÖØòóôõöøÈÉÊËèéêëðÇçÐÌÍÎÏìíîïÙÚÛÜùúûüÑñŠšŸÿýŽž'; + var withoutDia = + 'AAAAAAaaaaaaOOOOOOOooooooEEEEeeeeeCcDIIIIiiiiUUUUuuuuNnSsYyyZz'; + + for (int i = 0; i < withDia.length; i++) { + str = str.replaceAll(withDia[i], withoutDia[i]); + } + + return str; + } + + int getRandomInt() { + var rng = new Random(); + return rng.nextInt(12); + } + + void nameChanged() { + notifyListeners(); + } + + Future _showWalletExistDialog(BuildContext context) 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("J'ai compris"), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ); + }, + ); + } + + Future generateMnemonic() async { + try { + this.generatedMnemonic = + await DubpRust.genMnemonic(language: Language.french); + this.actualWallet = await generateWallet(this.generatedMnemonic); + this.walletIsGenerated = true; + } catch (e, stack) { + print(e); + if (kReleaseMode) { + await sentry.Sentry.captureException( + e, + stackTrace: stack, + ); + } + } + // await checkIfWalletExist(); + return this.generatedMnemonic; + } + + Future generateWallet(generatedMnemonic) async { + try { + this.actualWallet = await DubpRust.genWalletFromMnemonic( + language: Language.french, + mnemonic: generatedMnemonic, + secretCodeType: SecretCodeType.letters); + } catch (e, stack) { + print(e); + if (kReleaseMode) { + await sentry.Sentry.captureException( + e, + stackTrace: stack, + ); + } + } + + mnemonicController.text = generatedMnemonic; + pubkey.text = actualWallet.publicKey; + pin.text = actualWallet.pin; + notifyListeners(); + + return actualWallet; + } + + Future changePinCode() async { + this.actualWallet = await DubpRust.changeDewifPin( + dewif: this.actualWallet.dewif, + oldPin: this.actualWallet.pin, + ); + + pin.text = actualWallet.pin; + notifyListeners(); + } +} diff --git a/lib/models/home.dart b/lib/models/home.dart new file mode 100644 index 0000000..33ac663 --- /dev/null +++ b/lib/models/home.dart @@ -0,0 +1,71 @@ +import 'dart:io'; +import 'dart:math'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'dart:async'; +import 'package:gecko/globals.dart'; +import 'package:package_info/package_info.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:http/http.dart' as http; + +class HomeProvider with ChangeNotifier { + int _currentIndex = 0; + + get currentIndex => _currentIndex; + + set currentIndex(int index) { + _currentIndex = index; + print('current index setter: ' + index.toString()); + notifyListeners(); + } + + Future getAppVersion() async { + PackageInfo packageInfo = await PackageInfo.fromPlatform(); + String appName = packageInfo.appName; + String version = packageInfo.version; + String buildNumber = packageInfo.buildNumber; + print(appName); + + notifyListeners(); + return version + '+' + buildNumber; + } + + // void onTabTapped(int index) { + // currentIndex = index; + // notifyListeners(); + // } + + Future getRandomEndpoint() async { + // TODO: Improve implemention of getRandomEndpoint() + // final _json = json.decode(await getJsonEndpoints()); + // print('JSON !! :'); + // print(_json); + // final _list = _json[]; + + final _listEndpoints = ['https://g1.librelois.fr/gva']; + final _endpoint = getRandomElement(_listEndpoints); + print('ENDPOINT: ' + _endpoint); + + // http.post(_endpoint); + final response = await http.post(_endpoint); + if (response.statusCode != 400) { + print('Endpoint statutcode: ' + response.statusCode.toString()); + // _endpoint = getRandomElement(_list); + return 'HS'; + } + + return _endpoint; + } + + Future getAppPath() async { + appPath = await getApplicationDocumentsDirectory(); + walletsDirectory = Directory('${appPath.path}/wallets'); + print('AAAAPPPATH: ' + appPath.path); + } + + T getRandomElement(List list) { + final random = new Random(); + var i = random.nextInt(list.length); + return list[i]; + } +} diff --git a/lib/models/myWallets.dart b/lib/models/myWallets.dart index ebbed9a..224eb7b 100644 --- a/lib/models/myWallets.dart +++ b/lib/models/myWallets.dart @@ -2,17 +2,18 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'dart:async'; -import 'package:path_provider/path_provider.dart'; +import 'package:gecko/globals.dart'; class MyWalletsProvider with ChangeNotifier { - Directory appPath; + // Directory appPath; + List listWallets = []; bool checkIfWalletExist() { - if (this.appPath == null) { + if (appPath == null) { return false; } - var walletsFolder = new Directory("${this.appPath.path}/wallets/"); + var walletsFolder = new Directory("${appPath.path}/wallets/"); bool isWalletFolderExist = walletsFolder.existsSync(); @@ -23,12 +24,14 @@ class MyWalletsProvider with ChangeNotifier { List contents = walletsFolder.listSync(); if (contents.length == 0) { print('No wallets detected'); + notifyListeners(); return false; } else { print('Some wallets have been detected:'); for (var _wallets in contents) { print(_wallets); } + notifyListeners(); return true; } @@ -45,10 +48,23 @@ class MyWalletsProvider with ChangeNotifier { // } } - Future getAppDirectory() async { - this.appPath = await getApplicationDocumentsDirectory(); - notifyListeners(); - } - Future importWallet() async {} + + List getAllWalletsNames() { + listWallets.clear(); + print('1'); + print(walletsDirectory.path); + print('2'); + + walletsDirectory + .listSync(recursive: false, followLinks: false) + .forEach((wallet) { + String _name = wallet.path.split('/').last; + print(_name); + listWallets.add(_name); + }); + notifyListeners(); + + return listWallets; + } } diff --git a/lib/ui/historyScreen.dart b/lib/ui/historyScreen.dart index 214139b..d8875bb 100644 --- a/lib/ui/historyScreen.dart +++ b/lib/ui/historyScreen.dart @@ -8,28 +8,22 @@ import 'package:graphql_flutter/graphql_flutter.dart'; import 'package:provider/provider.dart'; import 'package:truncate/truncate.dart'; -//ignore: must_be_immutable +// ignore: must_be_immutable class HistoryScreen extends StatelessWidget with ChangeNotifier { - final TextEditingController _outputPubkey = new TextEditingController(); - ScrollController scrollController = new ScrollController(); + final TextEditingController _outputPubkey = TextEditingController(); + ScrollController scrollController = ScrollController(); final nRepositories = 20; HistoryProvider _historyProvider; + bool isTheEnd = false; + List _transBC; FetchMore fetchMore; FetchMoreOptions opts; - // scrollListener() { - // if (scrollController.offset >= scrollController.position.maxScrollExtent && - // !scrollController.position.outOfRange) { - // print('On est en bas !!'); - // print(opts.document); - // fetchMore(opts); - // notifyListeners(); - // } - // } @override Widget build(BuildContext context) { _historyProvider = Provider.of(context); + this._outputPubkey.text = _historyProvider.pubkey; print('Build pubkey : ' + _historyProvider.pubkey); // scrollController.addListener(scrollListener); return Scaffold( @@ -90,7 +84,6 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier { variables: { 'pubkey': _historyProvider.pubkey, 'number': nRepositories, - // set cursor to null so as to start at the beginning 'cursor': null }, ), @@ -127,50 +120,32 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier { final num balance = removeDecimalZero(result.data['balance']['amount'] / 100); - opts = FetchMoreOptions( - variables: {'cursor': fetchMoreCursor}, - updateQuery: (previousResultData, fetchMoreResultData) { - final List repos = [ - ...previousResultData['txsHistoryBc']['both']['edges'] - as List, - ...fetchMoreResultData['txsHistoryBc']['both']['edges'] - as List - ]; + if (fetchMoreCursor != null) { + opts = FetchMoreOptions( + variables: {'cursor': fetchMoreCursor}, + updateQuery: (previousResultData, fetchMoreResultData) { + final List repos = [ + ...previousResultData['txsHistoryBc']['both']['edges'] + as List, + ...fetchMoreResultData['txsHistoryBc']['both']['edges'] + as List + ]; - fetchMoreResultData['txsHistoryBc']['both']['edges'] = repos; - return fetchMoreResultData; - }, - ); - - // _scrollController - // ..addListener(() { - // if (_scrollController.position.pixels == - // _scrollController.position.maxScrollExtent) { - // if (!result.isLoading) { - // print( - // "DEBUG H fetchMoreCursor in scrollController: $fetchMoreCursor"); - // fetchMore(opts); - // } - // } - // }); - - // s/o : https://stackoverflow.com/questions/54065354/how-to-detect-scroll-position-of-listview-in-flutter/54188385#54188385 - // new NotificationListener( - // child: new ListView( - // controller: _scrollController, - // ), - // onNotification: (t) { - // if (t is ScrollEndNotification) { - // fetchMore(opts); - // } - // }, - // ); - - // fetchMore(opts); + fetchMoreResultData['txsHistoryBc']['both']['edges'] = repos; + return fetchMoreResultData; + }, + ); + } print( "###### DEBUG H Parse blockchainTX list. Cursor: $fetchMoreCursor ######"); - List _transBC = parseHistory(blockchainTX); + if (fetchMoreCursor != null) { + _transBC = parseHistory(blockchainTX); + isTheEnd = false; + } else { + print("###### DEBUG H - Début de l'historique"); + isTheEnd = true; + } // Build history list return NotificationListener( @@ -200,9 +175,8 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier { style: TextStyle(fontSize: 14.0)), dense: true, onTap: () { - this._outputPubkey.text = repository[2]; + // this._outputPubkey.text = repository[2]; _historyProvider.isPubkey(repository[2]); - // notifyListeners(); }), if (result.isLoading) Row( @@ -211,16 +185,21 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier { CircularProgressIndicator(), ], ), + if (isTheEnd) + Column(children: [ + SizedBox(height: 15), + Text("Début de l'historique.", + textAlign: TextAlign.center, + style: TextStyle(fontSize: 20)), + SizedBox(height: 15) + ]) ], )), onNotification: (t) { - // print(scrollController.position.pixels); - // print(scrollController.position.maxScrollExtent); if (t is ScrollEndNotification && scrollController.position.pixels >= scrollController.position.maxScrollExtent * 0.8) { fetchMore(opts); - // notifyListeners(); } return true; }); diff --git a/lib/ui/home.dart b/lib/ui/home.dart index 782e2d5..1a8b83f 100644 --- a/lib/ui/home.dart +++ b/lib/ui/home.dart @@ -1,39 +1,21 @@ +import 'package:gecko/globals.dart'; +import 'package:gecko/models/home.dart'; import 'package:gecko/ui/historyScreen.dart'; import 'package:flutter/material.dart'; import 'dart:ui'; import 'package:gecko/ui/myWallets/walletsHome.dart'; import 'package:gecko/ui/settingsScreen.dart'; -import 'package:package_info/package_info.dart'; +import 'package:provider/provider.dart'; -//ignore: must_be_immutable -class HomeScreen extends StatefulWidget { - HomeScreen({this.screens}); - final List screens; +// ignore: must_be_immutable +class HomeScreen extends StatelessWidget { + // HomeProvider _homeProvider = HomeProvider(); - @override - HomeScreenState createState() => HomeScreenState(); -} - -class HomeScreenState extends State { - int currentIndex = 0; - Widget currentScreen; - String appName; - String version; - String buildNumber; - - void initState() { - super.initState(); - getAppVersion(); - } - - void onTabTapped(int index) { - setState(() { - currentIndex = index; - }); - } + var currentTab = [HistoryScreen(), WalletsHome()]; @override Widget build(BuildContext context) { + var _homeProvider = Provider.of(context); return Scaffold( drawer: Drawer( child: Column( @@ -74,7 +56,7 @@ class HomeScreenState extends State { Container( child: Align( alignment: FractionalOffset.bottomCenter, - child: Text('Ğecko v${this.version}+${this.buildNumber}'))), + child: Text('Ğecko v$appVersion'))), SizedBox(height: 20) ], ), @@ -95,22 +77,16 @@ class HomeScreenState extends State { backgroundColor: Color(0xffFFD58D), ), backgroundColor: Color(0xffF9F9F1), - body: SafeArea( - child: IndexedStack( - index: currentIndex, - children: [ - HistoryScreen(), - WalletsHome(), - ], - ), - ), + body: currentTab[_homeProvider.currentIndex], bottomNavigationBar: BottomNavigationBar( backgroundColor: Color(0xffFFD58D), fixedColor: Colors.grey[850], unselectedItemColor: Color(0xffBD935C), type: BottomNavigationBarType.fixed, - onTap: onTabTapped, - currentIndex: currentIndex, + onTap: (index) { + _homeProvider.currentIndex = index; + }, + currentIndex: _homeProvider.currentIndex, items: [ BottomNavigationBarItem( icon: new Icon(Icons @@ -125,14 +101,4 @@ class HomeScreenState extends State { ), ); } - - Future getAppVersion() async { - PackageInfo packageInfo = await PackageInfo.fromPlatform(); - this.appName = packageInfo.appName; - this.version = packageInfo.version; - this.buildNumber = packageInfo.buildNumber; - print(this.appName); - - setState(() {}); - } } diff --git a/lib/ui/myWallets/confirmWalletStorage.dart b/lib/ui/myWallets/confirmWalletStorage.dart index 8bbf99a..64c59a2 100644 --- a/lib/ui/myWallets/confirmWalletStorage.dart +++ b/lib/ui/myWallets/confirmWalletStorage.dart @@ -1,54 +1,37 @@ -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'; -import 'dart:convert' show utf8; +import 'package:gecko/models/generateWallets.dart'; +import 'package:provider/provider.dart'; -class ConfirmStoreWallet extends StatefulWidget { - final String generatedMnemonic; - final NewWallet generatedWallet; +// ignore: must_be_immutable +class ConfirmStoreWallet extends StatelessWidget with ChangeNotifier { + ConfirmStoreWallet({ + Key validationKey, + @required this.generatedMnemonic, + @required generatedWallet, + }) : super(key: validationKey); - ConfirmStoreWallet( - {Key validationKey, - @required this.generatedMnemonic, - @required this.generatedWallet}) - : super(key: validationKey); + String generatedMnemonic; - @override - ConfirmStoreWalletState createState() => ConfirmStoreWalletState(); -} - -class ConfirmStoreWalletState extends State { - void initState() { - super.initState(); - this._mnemonicController.text = widget.generatedMnemonic; - this._pubkey.text = widget.generatedWallet.publicKey; - nbrWord = getRandomInt(); - askedWordColor = Colors.black; - } - - @override - void dispose() { - _wordFocus.dispose(); - _walletNameFocus.dispose(); - super.dispose(); - } + // @override + // void dispose() { + // _wordFocus.dispose(); + // _walletNameFocus.dispose(); + // super.dispose(); + // } TextEditingController _mnemonicController = new TextEditingController(); TextEditingController _pubkey = new TextEditingController(); - TextEditingController _pin = new TextEditingController(); TextEditingController _inputRestoreWord = new TextEditingController(); TextEditingController walletName = new TextEditingController(); FocusNode _wordFocus = FocusNode(); - FocusNode _walletNameFocus = FocusNode(); - Color askedWordColor; - int nbrWord; - bool isAskedWordValid = false; @override Widget build(BuildContext context) { + var _generateWalletProvider = Provider.of(context); + + this._mnemonicController.text = generatedMnemonic; + this._pubkey.text = _generateWalletProvider.generatedWallet.publicKey; return Scaffold( resizeToAvoidBottomInset: false, appBar: AppBar( @@ -79,7 +62,7 @@ class ConfirmStoreWalletState extends State { fontWeight: FontWeight.bold)), SizedBox(height: 12), Text( - 'Quel est le ${nbrWord + 1}ème mot de votre phrase de restauration ?', + 'Quel est le ${_generateWalletProvider.nbrWord + 1}ème mot de votre phrase de restauration ?', textAlign: TextAlign.center, style: TextStyle( fontSize: 17.0, @@ -89,18 +72,19 @@ class ConfirmStoreWalletState extends State { TextFormField( focusNode: _wordFocus, autofocus: true, - enabled: !isAskedWordValid, + enabled: !_generateWalletProvider.isAskedWordValid, controller: this._inputRestoreWord, textInputAction: TextInputAction.next, onChanged: (value) { - checkAskedWord(value); + _generateWalletProvider.checkAskedWord( + value, _mnemonicController.text); }, maxLines: 1, textAlign: TextAlign.center, decoration: InputDecoration(), style: TextStyle( fontSize: 30.0, - color: askedWordColor, + color: _generateWalletProvider.askedWordColor, fontWeight: FontWeight.w500)), SizedBox(height: 12), Text( @@ -112,7 +96,7 @@ class ConfirmStoreWalletState extends State { fontWeight: FontWeight.w400), ), TextFormField( - focusNode: _walletNameFocus, + focusNode: _generateWalletProvider.walletNameFocus, // autofocus: true, inputFormatters: [ FilteringTextInputFormatter.allow( @@ -122,7 +106,7 @@ class ConfirmStoreWalletState extends State { controller: this.walletName, textInputAction: TextInputAction.next, onChanged: (v) { - nameChanged(); + _generateWalletProvider.nameChanged(); }, maxLines: 1, textAlign: TextAlign.center, @@ -144,10 +128,11 @@ class ConfirmStoreWalletState extends State { .green[400], //Color(0xffFFD68E), // background onPrimary: Colors.black, // foreground ), - onPressed: - (isAskedWordValid && this.walletName.text != '') - ? () => storeWallet(this.walletName.text) - : null, + onPressed: (_generateWalletProvider.isAskedWordValid && + this.walletName.text != '') + ? () => _generateWalletProvider.storeWallet( + walletName.text, _pubkey.text, context) + : null, child: Text('Confirmer', style: TextStyle(fontSize: 28))), ))), @@ -161,107 +146,4 @@ class ConfirmStoreWalletState extends State { ), ); } - - Future storeWallet(_name) async { - final appPath = await _localPath; - final Directory walletNameDirectory = Directory('$appPath/wallets/$_name'); - final walletFile = File('${walletNameDirectory.path}/wallet.dewif'); - - if (await walletNameDirectory.exists()) { - print('Ce wallet existe déjà, impossible de le créer.'); - _showWalletExistDialog(); - return 'Exist: DENY'; - } - - walletNameDirectory.createSync(); - walletFile.writeAsString('${widget.generatedWallet.dewif}'); - _pin.clear(); - - Navigator.pop(context, true); - Navigator.pop(context, this._pubkey.text); - - return _name; - } - - Future get _localPath async { - final directory = await getApplicationDocumentsDirectory(); - return directory.path; - } - - void checkAskedWord(String value) { - final runesAsked = _mnemonicController.text.split(' ')[nbrWord].runes; - List runesAskedUnaccent = []; - print(runesAsked); - print(value.runes); - for (int i in runesAsked) { - if (i == 768 || i == 769 || i == 770 || i == 771) { - continue; - } else { - runesAskedUnaccent.add(i); - } - } - final String unaccentedAskedWord = - utf8.decode(runesAskedUnaccent).toLowerCase(); - final String unaccentedInputWord = removeDiacritics(value).toLowerCase(); - - print("Is $unaccentedAskedWord equal to input $unaccentedInputWord ?"); - if (unaccentedAskedWord == unaccentedInputWord || value == 'triche') { - print('Word is OK'); - isAskedWordValid = true; - askedWordColor = Colors.green[600]; - _walletNameFocus.nextFocus(); - } 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("J'ai compris"), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - ], - ); - }, - ); - } - - String removeDiacritics(String str) { - var withDia = - 'ÀÁÂÃÄÅàáâãäåÒÓÔÕÕÖØòóôõöøÈÉÊËèéêëðÇçÐÌÍÎÏìíîïÙÚÛÜùúûüÑñŠšŸÿýŽž'; - var withoutDia = - 'AAAAAAaaaaaaOOOOOOOooooooEEEEeeeeeCcDIIIIiiiiUUUUuuuuNnSsYyyZz'; - - for (int i = 0; i < withDia.length; i++) { - str = str.replaceAll(withDia[i], withoutDia[i]); - } - - return str; - } - - int getRandomInt() { - var rng = new Random(); - return rng.nextInt(12); - } - - void nameChanged() { - setState(() {}); - } } diff --git a/lib/ui/myWallets/generateWalletsScreen.dart b/lib/ui/myWallets/generateWalletsScreen.dart index 931f46f..5cdd130 100644 --- a/lib/ui/myWallets/generateWalletsScreen.dart +++ b/lib/ui/myWallets/generateWalletsScreen.dart @@ -1,30 +1,11 @@ +import 'package:gecko/models/generateWallets.dart'; import 'package:gecko/ui/myWallets/confirmWalletStorage.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:sentry/sentry.dart' as sentry; -import 'package:dubp/dubp.dart'; +import 'package:provider/provider.dart'; import 'package:super_tooltip/super_tooltip.dart'; -class GenerateWalletsScreen extends StatefulWidget { - const GenerateWalletsScreen({Key keyGenWallet}) : super(key: keyGenWallet); - @override - GenerateWalletsState createState() => GenerateWalletsState(); -} - -class GenerateWalletsState extends State { - // GlobalKey _keyMyWallets = GlobalKey(); - // GlobalKey _keyValidWallets = GlobalKey(); - void initState() { - super.initState(); - generateMnemonic(); - } - - TextEditingController _mnemonicController = new TextEditingController(); - TextEditingController _pubkey = new TextEditingController(); - TextEditingController _pin = new TextEditingController(); - String generatedMnemonic; - bool walletIsGenerated = false; - NewWallet actualWallet; +// ignore: must_be_immutable +class GenerateWalletsScreen extends StatelessWidget { SuperTooltip tooltip; // final formKey = GlobalKey(); @@ -35,6 +16,8 @@ class GenerateWalletsState extends State { @override Widget build(BuildContext context) { + var _generateWalletProvider = Provider.of(context); + _generateWalletProvider.generateMnemonic(); return Scaffold( appBar: AppBar( title: SizedBox( @@ -47,7 +30,7 @@ class GenerateWalletsState extends State { child: FittedBox( child: FloatingActionButton( heroTag: "buttonGenerateWallet", - onPressed: () => generateMnemonic(), + onPressed: () => _generateWalletProvider.generateMnemonic(), // print(resultScan); // if (resultScan != 'false') { // onTabTapped(0); @@ -76,7 +59,7 @@ class GenerateWalletsState extends State { ), TextField( enabled: false, - controller: this._pubkey, + controller: _generateWalletProvider.pubkey, maxLines: 1, textAlign: TextAlign.center, decoration: InputDecoration(), @@ -98,7 +81,7 @@ class GenerateWalletsState extends State { ), TextField( enabled: false, - controller: this._mnemonicController, + controller: _generateWalletProvider.mnemonicController, maxLines: 3, textAlign: TextAlign.center, decoration: InputDecoration( @@ -126,7 +109,7 @@ class GenerateWalletsState extends State { children: [ TextField( enabled: false, - controller: this._pin, + controller: _generateWalletProvider.pin, maxLines: 1, textAlign: TextAlign.center, decoration: InputDecoration(), @@ -138,7 +121,7 @@ class GenerateWalletsState extends State { icon: Icon(Icons.replay), color: Color(0xffD28928), onPressed: () { - changePinCode(); + _generateWalletProvider.changePinCode(); }, ), ], @@ -151,15 +134,17 @@ class GenerateWalletsState extends State { primary: Color(0xffFFD68E), // background onPrimary: Colors.black, // foreground ), - onPressed: walletIsGenerated + onPressed: _generateWalletProvider.walletIsGenerated ? () { Navigator.push( context, MaterialPageRoute(builder: (context) { return ConfirmStoreWallet( // validationKey: _keyValidWallets, - generatedMnemonic: this.generatedMnemonic, - generatedWallet: this.actualWallet); + generatedMnemonic: + _generateWalletProvider.generatedMnemonic, + generatedWallet: + _generateWalletProvider.actualWallet); }), ) // .then((value) => setState(() { @@ -181,59 +166,4 @@ class GenerateWalletsState extends State { ]), )); } - - Future generateMnemonic() async { - try { - this.generatedMnemonic = - await DubpRust.genMnemonic(language: Language.french); - this.actualWallet = await generateWallet(this.generatedMnemonic); - this.walletIsGenerated = true; - } catch (e, stack) { - print(e); - if (kReleaseMode) { - await sentry.Sentry.captureException( - e, - stackTrace: stack, - ); - } - } - // await checkIfWalletExist(); - return this.generatedMnemonic; - } - - Future generateWallet(generatedMnemonic) async { - try { - this.actualWallet = await DubpRust.genWalletFromMnemonic( - language: Language.french, - mnemonic: generatedMnemonic, - secretCodeType: SecretCodeType.letters); - } catch (e, stack) { - print(e); - if (kReleaseMode) { - await sentry.Sentry.captureException( - e, - stackTrace: stack, - ); - } - } - - setState(() { - this._mnemonicController.text = generatedMnemonic; - this._pubkey.text = actualWallet.publicKey; - this._pin.text = actualWallet.pin; - }); - - return actualWallet; - } - - Future changePinCode() async { - this.actualWallet = await DubpRust.changeDewifPin( - dewif: this.actualWallet.dewif, - oldPin: this.actualWallet.pin, - ); - - setState(() { - this._pin.text = actualWallet.pin; - }); - } } diff --git a/lib/ui/myWallets/myWalletsList.dart b/lib/ui/myWallets/myWalletsList.dart deleted file mode 100644 index 09ee692..0000000 --- a/lib/ui/myWallets/myWalletsList.dart +++ /dev/null @@ -1,91 +0,0 @@ -// import 'package:gecko/ui/generateWallets.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:gecko/ui/myWallets/walletOptions.dart'; -import 'dart:io'; -import 'package:path_provider/path_provider.dart'; - -class MyWalletsList extends StatefulWidget { - const MyWalletsList({Key keyMyWallets}) : super(key: keyMyWallets); - @override - MyWalletListState createState() => MyWalletListState(); -} - -class MyWalletListState extends State { - Directory walletsDirectory; - List _listWallets = []; - - void initState() { - super.initState(); - initAppDirectory(); - } - - void initAppDirectory() async { - Directory _appPath = await getApplicationDocumentsDirectory(); - walletsDirectory = Directory('${_appPath.path}/wallets'); - _listWallets = getAllWalletsNames(); - } - - @override - Widget build(BuildContext context) { - 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: () { - 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 - ), - onPressed: () { - initAppDirectory(); - setState(() {}); - }, - child: Text('(Refresh)', style: TextStyle(fontSize: 10)))), - ])); - } - - List getAllWalletsNames() { - this._listWallets.clear(); - print(this.walletsDirectory.path); - - this - .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); - // }); - - return _listWallets; - - // final _local = await _appPath.path.list().toList(); - } -} diff --git a/lib/ui/myWallets/walletsHome.dart b/lib/ui/myWallets/walletsHome.dart index 6c37c9d..9fac2bb 100644 --- a/lib/ui/myWallets/walletsHome.dart +++ b/lib/ui/myWallets/walletsHome.dart @@ -1,29 +1,20 @@ import 'package:gecko/models/myWallets.dart'; import 'package:gecko/ui/myWallets/generateWalletsScreen.dart'; -import 'package:gecko/ui/myWallets/myWalletsList.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:dubp/dubp.dart'; +import 'package:gecko/ui/myWallets/walletOptions.dart'; -class WalletsHome extends StatelessWidget with ChangeNotifier { - MyWalletsProvider historyProvider = MyWalletsProvider(); - - String generatedMnemonic; - bool walletIsGenerated = false; - NewWallet actualWallet; - String newWalletName; - - bool hasError = false; - String validPin = 'NO PIN'; - String currentText = ""; - var pinColor = Colors.grey[300]; +// ignore: must_be_immutable +class WalletsHome extends StatelessWidget { + MyWalletsProvider myWalletProvider = MyWalletsProvider(); @override Widget build(BuildContext context) { - historyProvider.getAppDirectory(); + print('BUILD: WalletsHome'); + myWalletProvider.listWallets = myWalletProvider.getAllWalletsNames(); + return Scaffold( floatingActionButton: Visibility( - visible: (historyProvider + visible: (myWalletProvider .checkIfWalletExist()), //!checkIfWalletExist('MonWallet') && child: Container( height: 80.0, @@ -48,8 +39,7 @@ class WalletsHome extends StatelessWidget with ChangeNotifier { body: SafeArea( child: Column(children: [ Visibility( - visible: - (!historyProvider.checkIfWalletExist() && !walletIsGenerated), + visible: (!myWalletProvider.checkIfWalletExist()), child: Column(children: [ SizedBox(height: 120), Center( @@ -83,13 +73,13 @@ class WalletsHome extends StatelessWidget with ChangeNotifier { primary: Color(0xffFFD68E), // background onPrimary: Colors.black, // foreground ), - onPressed: () => historyProvider.importWallet(), + onPressed: () => myWalletProvider.importWallet(), child: Text('Importer un portefeuille existant', style: TextStyle(fontSize: 20))), ])), Visibility( - visible: historyProvider.checkIfWalletExist(), - child: MyWalletsList()) + visible: myWalletProvider.checkIfWalletExist(), + child: myWalletsList(context)) ]))); } @@ -105,4 +95,37 @@ class WalletsHome extends StatelessWidget with ChangeNotifier { // }); // } + myWalletsList(BuildContext context) { + return Column(children: [ + SizedBox(height: 8), + for (var repository in myWalletProvider.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: () { + Navigator.push(context, MaterialPageRoute(builder: (context) { + return WalletOptions(walletName: repository); + })); + }, + ), + 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 + ), + onPressed: () { + myWalletProvider.listWallets = + myWalletProvider.getAllWalletsNames(); + }, + child: Text('(Refresh)', style: TextStyle(fontSize: 10)))) + ]); + } }