Commit long way after ...

This commit is contained in:
poka 2021-01-26 21:00:26 +01:00
parent 5542a8eea8
commit 5176e76860
11 changed files with 462 additions and 500 deletions

5
lib/globals.dart Normal file
View File

@ -0,0 +1,5 @@
import 'dart:io';
Directory appPath;
Directory walletsDirectory;
String appVersion;

View File

@ -1,5 +1,8 @@
import 'package:dubp/dubp.dart'; 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/history.dart';
import 'package:gecko/models/home.dart';
import 'package:gecko/models/myWallets.dart'; import 'package:gecko/models/myWallets.dart';
import 'package:gecko/ui/home.dart'; import 'package:gecko/ui/home.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
@ -8,10 +11,6 @@ import 'package:graphql_flutter/graphql_flutter.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:flutter/foundation.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; final bool enableSentry = true;
@ -19,35 +18,12 @@ final bool enableSentry = true;
// return rootBundle.loadString('config/gva_endpoints.json'); // return rootBundle.loadString('config/gva_endpoints.json');
// } // }
T getRandomElement<T>(List<T> list) {
final random = new Random();
var i = random.nextInt(list.length);
return list[i];
}
Future<String> 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<void> main() async { Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
HomeProvider _homeProvider = HomeProvider();
await _homeProvider.getAppPath();
appVersion = await _homeProvider.getAppVersion();
String randomEndpoint; // = await getRandomEndpoint(); String randomEndpoint; // = await getRandomEndpoint();
int i = 0; int i = 0;
do { do {
@ -59,7 +35,7 @@ Future<void> main() async {
print(i.toString() + ' ème essai de recherche de endpoint GVA.'); print(i.toString() + ' ème essai de recherche de endpoint GVA.');
await Future.delayed(Duration(milliseconds: 300)); await Future.delayed(Duration(milliseconds: 300));
} }
randomEndpoint = await getRandomEndpoint(); randomEndpoint = await _homeProvider.getRandomEndpoint();
i++; i++;
} while (randomEndpoint == 'HS'); } while (randomEndpoint == 'HS');
@ -73,16 +49,37 @@ Future<void> main() async {
); );
} else { } else {
print('Debug mode enabled: No sentry alerte'); print('Debug mode enabled: No sentry alerte');
runApp(Gecko(randomEndpoint));
runApp(Gecko(
randomEndpoint,
));
} }
} }
// ignore: must_be_immutable
class Gecko extends StatelessWidget { class Gecko extends StatelessWidget {
Gecko(this.randomEndpoint); Gecko(this.randomEndpoint);
final String randomEndpoint; final String randomEndpoint;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// FutureBuilder<dynamic>(
// 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( final _httpLink = HttpLink(
// 'http://192.168.1.91:10060/gva', // 'http://192.168.1.91:10060/gva',
randomEndpoint, randomEndpoint,
@ -119,8 +116,11 @@ class Gecko extends StatelessWidget {
home: MultiProvider( home: MultiProvider(
providers: [ providers: [
// Provider(create: (context) => HistoryProvider()), // Provider(create: (context) => HistoryProvider()),
Provider(create: (context) => MyWalletsProvider()), // Provider(create: (context) => MyWalletsProvider()),
ChangeNotifierProvider(create: (_) => HistoryProvider('')) ChangeNotifierProvider(create: (_) => HomeProvider()),
ChangeNotifierProvider(create: (_) => HistoryProvider('')),
ChangeNotifierProvider(create: (_) => MyWalletsProvider()),
ChangeNotifierProvider(create: (_) => GenerateWalletsProvider())
], ],
child: GraphQLProvider( child: GraphQLProvider(
client: _client, client: _client,

View File

@ -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<String> 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<int> 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<void> _showWalletExistDialog(BuildContext context) async {
return showDialog<void>(
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: <Widget>[
Text('Veuillez choisir un autre nom pour votre portefeuille.'),
],
),
),
actions: <Widget>[
TextButton(
child: Text("J'ai compris"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
Future<String> 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<NewWallet> 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<void> changePinCode() async {
this.actualWallet = await DubpRust.changeDewifPin(
dewif: this.actualWallet.dewif,
oldPin: this.actualWallet.pin,
);
pin.text = actualWallet.pin;
notifyListeners();
}
}

71
lib/models/home.dart Normal file
View File

@ -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<String> 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<T>(List<T> list) {
final random = new Random();
var i = random.nextInt(list.length);
return list[i];
}
}

View File

@ -2,17 +2,18 @@ import 'dart:io';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'dart:async'; import 'dart:async';
import 'package:path_provider/path_provider.dart'; import 'package:gecko/globals.dart';
class MyWalletsProvider with ChangeNotifier { class MyWalletsProvider with ChangeNotifier {
Directory appPath; // Directory appPath;
List listWallets = [];
bool checkIfWalletExist() { bool checkIfWalletExist() {
if (this.appPath == null) { if (appPath == null) {
return false; return false;
} }
var walletsFolder = new Directory("${this.appPath.path}/wallets/"); var walletsFolder = new Directory("${appPath.path}/wallets/");
bool isWalletFolderExist = walletsFolder.existsSync(); bool isWalletFolderExist = walletsFolder.existsSync();
@ -23,12 +24,14 @@ class MyWalletsProvider with ChangeNotifier {
List contents = walletsFolder.listSync(); List contents = walletsFolder.listSync();
if (contents.length == 0) { if (contents.length == 0) {
print('No wallets detected'); print('No wallets detected');
notifyListeners();
return false; return false;
} else { } else {
print('Some wallets have been detected:'); print('Some wallets have been detected:');
for (var _wallets in contents) { for (var _wallets in contents) {
print(_wallets); print(_wallets);
} }
notifyListeners();
return true; return true;
} }
@ -45,10 +48,23 @@ class MyWalletsProvider with ChangeNotifier {
// } // }
} }
Future getAppDirectory() async {
this.appPath = await getApplicationDocumentsDirectory();
notifyListeners();
}
Future importWallet() async {} 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;
}
} }

View File

@ -8,28 +8,22 @@ import 'package:graphql_flutter/graphql_flutter.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:truncate/truncate.dart'; import 'package:truncate/truncate.dart';
//ignore: must_be_immutable // ignore: must_be_immutable
class HistoryScreen extends StatelessWidget with ChangeNotifier { class HistoryScreen extends StatelessWidget with ChangeNotifier {
final TextEditingController _outputPubkey = new TextEditingController(); final TextEditingController _outputPubkey = TextEditingController();
ScrollController scrollController = new ScrollController(); ScrollController scrollController = ScrollController();
final nRepositories = 20; final nRepositories = 20;
HistoryProvider _historyProvider; HistoryProvider _historyProvider;
bool isTheEnd = false;
List _transBC;
FetchMore fetchMore; FetchMore fetchMore;
FetchMoreOptions opts; FetchMoreOptions opts;
// scrollListener() {
// if (scrollController.offset >= scrollController.position.maxScrollExtent &&
// !scrollController.position.outOfRange) {
// print('On est en bas !!');
// print(opts.document);
// fetchMore(opts);
// notifyListeners();
// }
// }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
_historyProvider = Provider.of<HistoryProvider>(context); _historyProvider = Provider.of<HistoryProvider>(context);
this._outputPubkey.text = _historyProvider.pubkey;
print('Build pubkey : ' + _historyProvider.pubkey); print('Build pubkey : ' + _historyProvider.pubkey);
// scrollController.addListener(scrollListener); // scrollController.addListener(scrollListener);
return Scaffold( return Scaffold(
@ -90,7 +84,6 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier {
variables: <String, dynamic>{ variables: <String, dynamic>{
'pubkey': _historyProvider.pubkey, 'pubkey': _historyProvider.pubkey,
'number': nRepositories, 'number': nRepositories,
// set cursor to null so as to start at the beginning
'cursor': null 'cursor': null
}, },
), ),
@ -127,50 +120,32 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier {
final num balance = final num balance =
removeDecimalZero(result.data['balance']['amount'] / 100); removeDecimalZero(result.data['balance']['amount'] / 100);
opts = FetchMoreOptions( if (fetchMoreCursor != null) {
variables: {'cursor': fetchMoreCursor}, opts = FetchMoreOptions(
updateQuery: (previousResultData, fetchMoreResultData) { variables: {'cursor': fetchMoreCursor},
final List<dynamic> repos = [ updateQuery: (previousResultData, fetchMoreResultData) {
...previousResultData['txsHistoryBc']['both']['edges'] final List<dynamic> repos = [
as List<dynamic>, ...previousResultData['txsHistoryBc']['both']['edges']
...fetchMoreResultData['txsHistoryBc']['both']['edges'] as List<dynamic>,
as List<dynamic> ...fetchMoreResultData['txsHistoryBc']['both']['edges']
]; as List<dynamic>
];
fetchMoreResultData['txsHistoryBc']['both']['edges'] = repos; fetchMoreResultData['txsHistoryBc']['both']['edges'] = repos;
return fetchMoreResultData; 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);
print( print(
"###### DEBUG H Parse blockchainTX list. Cursor: $fetchMoreCursor ######"); "###### 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 // Build history list
return NotificationListener( return NotificationListener(
@ -200,9 +175,8 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier {
style: TextStyle(fontSize: 14.0)), style: TextStyle(fontSize: 14.0)),
dense: true, dense: true,
onTap: () { onTap: () {
this._outputPubkey.text = repository[2]; // this._outputPubkey.text = repository[2];
_historyProvider.isPubkey(repository[2]); _historyProvider.isPubkey(repository[2]);
// notifyListeners();
}), }),
if (result.isLoading) if (result.isLoading)
Row( Row(
@ -211,16 +185,21 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier {
CircularProgressIndicator(), CircularProgressIndicator(),
], ],
), ),
if (isTheEnd)
Column(children: <Widget>[
SizedBox(height: 15),
Text("Début de l'historique.",
textAlign: TextAlign.center,
style: TextStyle(fontSize: 20)),
SizedBox(height: 15)
])
], ],
)), )),
onNotification: (t) { onNotification: (t) {
// print(scrollController.position.pixels);
// print(scrollController.position.maxScrollExtent);
if (t is ScrollEndNotification && if (t is ScrollEndNotification &&
scrollController.position.pixels >= scrollController.position.pixels >=
scrollController.position.maxScrollExtent * 0.8) { scrollController.position.maxScrollExtent * 0.8) {
fetchMore(opts); fetchMore(opts);
// notifyListeners();
} }
return true; return true;
}); });

View File

@ -1,39 +1,21 @@
import 'package:gecko/globals.dart';
import 'package:gecko/models/home.dart';
import 'package:gecko/ui/historyScreen.dart'; import 'package:gecko/ui/historyScreen.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'dart:ui'; import 'dart:ui';
import 'package:gecko/ui/myWallets/walletsHome.dart'; import 'package:gecko/ui/myWallets/walletsHome.dart';
import 'package:gecko/ui/settingsScreen.dart'; import 'package:gecko/ui/settingsScreen.dart';
import 'package:package_info/package_info.dart'; import 'package:provider/provider.dart';
//ignore: must_be_immutable // ignore: must_be_immutable
class HomeScreen extends StatefulWidget { class HomeScreen extends StatelessWidget {
HomeScreen({this.screens}); // HomeProvider _homeProvider = HomeProvider();
final List<Widget> screens;
@override var currentTab = [HistoryScreen(), WalletsHome()];
HomeScreenState createState() => HomeScreenState();
}
class HomeScreenState extends State<HomeScreen> {
int currentIndex = 0;
Widget currentScreen;
String appName;
String version;
String buildNumber;
void initState() {
super.initState();
getAppVersion();
}
void onTabTapped(int index) {
setState(() {
currentIndex = index;
});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var _homeProvider = Provider.of<HomeProvider>(context);
return Scaffold( return Scaffold(
drawer: Drawer( drawer: Drawer(
child: Column( child: Column(
@ -74,7 +56,7 @@ class HomeScreenState extends State<HomeScreen> {
Container( Container(
child: Align( child: Align(
alignment: FractionalOffset.bottomCenter, alignment: FractionalOffset.bottomCenter,
child: Text('Ğecko v${this.version}+${this.buildNumber}'))), child: Text('Ğecko v$appVersion'))),
SizedBox(height: 20) SizedBox(height: 20)
], ],
), ),
@ -95,22 +77,16 @@ class HomeScreenState extends State<HomeScreen> {
backgroundColor: Color(0xffFFD58D), backgroundColor: Color(0xffFFD58D),
), ),
backgroundColor: Color(0xffF9F9F1), backgroundColor: Color(0xffF9F9F1),
body: SafeArea( body: currentTab[_homeProvider.currentIndex],
child: IndexedStack(
index: currentIndex,
children: <Widget>[
HistoryScreen(),
WalletsHome(),
],
),
),
bottomNavigationBar: BottomNavigationBar( bottomNavigationBar: BottomNavigationBar(
backgroundColor: Color(0xffFFD58D), backgroundColor: Color(0xffFFD58D),
fixedColor: Colors.grey[850], fixedColor: Colors.grey[850],
unselectedItemColor: Color(0xffBD935C), unselectedItemColor: Color(0xffBD935C),
type: BottomNavigationBarType.fixed, type: BottomNavigationBarType.fixed,
onTap: onTabTapped, onTap: (index) {
currentIndex: currentIndex, _homeProvider.currentIndex = index;
},
currentIndex: _homeProvider.currentIndex,
items: [ items: [
BottomNavigationBarItem( BottomNavigationBarItem(
icon: new Icon(Icons icon: new Icon(Icons
@ -125,14 +101,4 @@ class HomeScreenState extends State<HomeScreen> {
), ),
); );
} }
Future getAppVersion() async {
PackageInfo packageInfo = await PackageInfo.fromPlatform();
this.appName = packageInfo.appName;
this.version = packageInfo.version;
this.buildNumber = packageInfo.buildNumber;
print(this.appName);
setState(() {});
}
} }

View File

@ -1,54 +1,37 @@
import 'dart:io';
import 'dart:math';
import 'package:dubp/dubp.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:path_provider/path_provider.dart'; import 'package:gecko/models/generateWallets.dart';
import 'dart:convert' show utf8; import 'package:provider/provider.dart';
class ConfirmStoreWallet extends StatefulWidget { // ignore: must_be_immutable
final String generatedMnemonic; class ConfirmStoreWallet extends StatelessWidget with ChangeNotifier {
final NewWallet generatedWallet; ConfirmStoreWallet({
Key validationKey,
@required this.generatedMnemonic,
@required generatedWallet,
}) : super(key: validationKey);
ConfirmStoreWallet( String generatedMnemonic;
{Key validationKey,
@required this.generatedMnemonic,
@required this.generatedWallet})
: super(key: validationKey);
@override // @override
ConfirmStoreWalletState createState() => ConfirmStoreWalletState(); // void dispose() {
} // _wordFocus.dispose();
// _walletNameFocus.dispose();
class ConfirmStoreWalletState extends State<ConfirmStoreWallet> { // super.dispose();
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();
}
TextEditingController _mnemonicController = new TextEditingController(); TextEditingController _mnemonicController = new TextEditingController();
TextEditingController _pubkey = new TextEditingController(); TextEditingController _pubkey = new TextEditingController();
TextEditingController _pin = new TextEditingController();
TextEditingController _inputRestoreWord = new TextEditingController(); TextEditingController _inputRestoreWord = new TextEditingController();
TextEditingController walletName = new TextEditingController(); TextEditingController walletName = new TextEditingController();
FocusNode _wordFocus = FocusNode(); FocusNode _wordFocus = FocusNode();
FocusNode _walletNameFocus = FocusNode();
Color askedWordColor;
int nbrWord;
bool isAskedWordValid = false;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var _generateWalletProvider = Provider.of<GenerateWalletsProvider>(context);
this._mnemonicController.text = generatedMnemonic;
this._pubkey.text = _generateWalletProvider.generatedWallet.publicKey;
return Scaffold( return Scaffold(
resizeToAvoidBottomInset: false, resizeToAvoidBottomInset: false,
appBar: AppBar( appBar: AppBar(
@ -79,7 +62,7 @@ class ConfirmStoreWalletState extends State<ConfirmStoreWallet> {
fontWeight: FontWeight.bold)), fontWeight: FontWeight.bold)),
SizedBox(height: 12), SizedBox(height: 12),
Text( 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, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
fontSize: 17.0, fontSize: 17.0,
@ -89,18 +72,19 @@ class ConfirmStoreWalletState extends State<ConfirmStoreWallet> {
TextFormField( TextFormField(
focusNode: _wordFocus, focusNode: _wordFocus,
autofocus: true, autofocus: true,
enabled: !isAskedWordValid, enabled: !_generateWalletProvider.isAskedWordValid,
controller: this._inputRestoreWord, controller: this._inputRestoreWord,
textInputAction: TextInputAction.next, textInputAction: TextInputAction.next,
onChanged: (value) { onChanged: (value) {
checkAskedWord(value); _generateWalletProvider.checkAskedWord(
value, _mnemonicController.text);
}, },
maxLines: 1, maxLines: 1,
textAlign: TextAlign.center, textAlign: TextAlign.center,
decoration: InputDecoration(), decoration: InputDecoration(),
style: TextStyle( style: TextStyle(
fontSize: 30.0, fontSize: 30.0,
color: askedWordColor, color: _generateWalletProvider.askedWordColor,
fontWeight: FontWeight.w500)), fontWeight: FontWeight.w500)),
SizedBox(height: 12), SizedBox(height: 12),
Text( Text(
@ -112,7 +96,7 @@ class ConfirmStoreWalletState extends State<ConfirmStoreWallet> {
fontWeight: FontWeight.w400), fontWeight: FontWeight.w400),
), ),
TextFormField( TextFormField(
focusNode: _walletNameFocus, focusNode: _generateWalletProvider.walletNameFocus,
// autofocus: true, // autofocus: true,
inputFormatters: [ inputFormatters: [
FilteringTextInputFormatter.allow( FilteringTextInputFormatter.allow(
@ -122,7 +106,7 @@ class ConfirmStoreWalletState extends State<ConfirmStoreWallet> {
controller: this.walletName, controller: this.walletName,
textInputAction: TextInputAction.next, textInputAction: TextInputAction.next,
onChanged: (v) { onChanged: (v) {
nameChanged(); _generateWalletProvider.nameChanged();
}, },
maxLines: 1, maxLines: 1,
textAlign: TextAlign.center, textAlign: TextAlign.center,
@ -144,10 +128,11 @@ class ConfirmStoreWalletState extends State<ConfirmStoreWallet> {
.green[400], //Color(0xffFFD68E), // background .green[400], //Color(0xffFFD68E), // background
onPrimary: Colors.black, // foreground onPrimary: Colors.black, // foreground
), ),
onPressed: onPressed: (_generateWalletProvider.isAskedWordValid &&
(isAskedWordValid && this.walletName.text != '') this.walletName.text != '')
? () => storeWallet(this.walletName.text) ? () => _generateWalletProvider.storeWallet(
: null, walletName.text, _pubkey.text, context)
: null,
child: child:
Text('Confirmer', style: TextStyle(fontSize: 28))), Text('Confirmer', style: TextStyle(fontSize: 28))),
))), ))),
@ -161,107 +146,4 @@ class ConfirmStoreWalletState extends State<ConfirmStoreWallet> {
), ),
); );
} }
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<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
void checkAskedWord(String value) {
final runesAsked = _mnemonicController.text.split(' ')[nbrWord].runes;
List<int> 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<void> _showWalletExistDialog() async {
return showDialog<void>(
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: <Widget>[
Text('Veuillez choisir un autre nom pour votre portefeuille.'),
],
),
),
actions: <Widget>[
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(() {});
}
} }

View File

@ -1,30 +1,11 @@
import 'package:gecko/models/generateWallets.dart';
import 'package:gecko/ui/myWallets/confirmWalletStorage.dart'; import 'package:gecko/ui/myWallets/confirmWalletStorage.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:sentry/sentry.dart' as sentry; import 'package:provider/provider.dart';
import 'package:dubp/dubp.dart';
import 'package:super_tooltip/super_tooltip.dart'; import 'package:super_tooltip/super_tooltip.dart';
class GenerateWalletsScreen extends StatefulWidget { // ignore: must_be_immutable
const GenerateWalletsScreen({Key keyGenWallet}) : super(key: keyGenWallet); class GenerateWalletsScreen extends StatelessWidget {
@override
GenerateWalletsState createState() => GenerateWalletsState();
}
class GenerateWalletsState extends State<GenerateWalletsScreen> {
// GlobalKey<MyWalletState> _keyMyWallets = GlobalKey();
// GlobalKey<ValidStoreWalletState> _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;
SuperTooltip tooltip; SuperTooltip tooltip;
// final formKey = GlobalKey<FormState>(); // final formKey = GlobalKey<FormState>();
@ -35,6 +16,8 @@ class GenerateWalletsState extends State<GenerateWalletsScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var _generateWalletProvider = Provider.of<GenerateWalletsProvider>(context);
_generateWalletProvider.generateMnemonic();
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: SizedBox( title: SizedBox(
@ -47,7 +30,7 @@ class GenerateWalletsState extends State<GenerateWalletsScreen> {
child: FittedBox( child: FittedBox(
child: FloatingActionButton( child: FloatingActionButton(
heroTag: "buttonGenerateWallet", heroTag: "buttonGenerateWallet",
onPressed: () => generateMnemonic(), onPressed: () => _generateWalletProvider.generateMnemonic(),
// print(resultScan); // print(resultScan);
// if (resultScan != 'false') { // if (resultScan != 'false') {
// onTabTapped(0); // onTabTapped(0);
@ -76,7 +59,7 @@ class GenerateWalletsState extends State<GenerateWalletsScreen> {
), ),
TextField( TextField(
enabled: false, enabled: false,
controller: this._pubkey, controller: _generateWalletProvider.pubkey,
maxLines: 1, maxLines: 1,
textAlign: TextAlign.center, textAlign: TextAlign.center,
decoration: InputDecoration(), decoration: InputDecoration(),
@ -98,7 +81,7 @@ class GenerateWalletsState extends State<GenerateWalletsScreen> {
), ),
TextField( TextField(
enabled: false, enabled: false,
controller: this._mnemonicController, controller: _generateWalletProvider.mnemonicController,
maxLines: 3, maxLines: 3,
textAlign: TextAlign.center, textAlign: TextAlign.center,
decoration: InputDecoration( decoration: InputDecoration(
@ -126,7 +109,7 @@ class GenerateWalletsState extends State<GenerateWalletsScreen> {
children: <Widget>[ children: <Widget>[
TextField( TextField(
enabled: false, enabled: false,
controller: this._pin, controller: _generateWalletProvider.pin,
maxLines: 1, maxLines: 1,
textAlign: TextAlign.center, textAlign: TextAlign.center,
decoration: InputDecoration(), decoration: InputDecoration(),
@ -138,7 +121,7 @@ class GenerateWalletsState extends State<GenerateWalletsScreen> {
icon: Icon(Icons.replay), icon: Icon(Icons.replay),
color: Color(0xffD28928), color: Color(0xffD28928),
onPressed: () { onPressed: () {
changePinCode(); _generateWalletProvider.changePinCode();
}, },
), ),
], ],
@ -151,15 +134,17 @@ class GenerateWalletsState extends State<GenerateWalletsScreen> {
primary: Color(0xffFFD68E), // background primary: Color(0xffFFD68E), // background
onPrimary: Colors.black, // foreground onPrimary: Colors.black, // foreground
), ),
onPressed: walletIsGenerated onPressed: _generateWalletProvider.walletIsGenerated
? () { ? () {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute(builder: (context) { MaterialPageRoute(builder: (context) {
return ConfirmStoreWallet( return ConfirmStoreWallet(
// validationKey: _keyValidWallets, // validationKey: _keyValidWallets,
generatedMnemonic: this.generatedMnemonic, generatedMnemonic:
generatedWallet: this.actualWallet); _generateWalletProvider.generatedMnemonic,
generatedWallet:
_generateWalletProvider.actualWallet);
}), }),
) )
// .then((value) => setState(() { // .then((value) => setState(() {
@ -181,59 +166,4 @@ class GenerateWalletsState extends State<GenerateWalletsScreen> {
]), ]),
)); ));
} }
Future<String> 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<NewWallet> 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<void> changePinCode() async {
this.actualWallet = await DubpRust.changeDewifPin(
dewif: this.actualWallet.dewif,
oldPin: this.actualWallet.pin,
);
setState(() {
this._pin.text = actualWallet.pin;
});
}
} }

View File

@ -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<MyWalletsList> {
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: <Widget>[
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();
}
}

View File

@ -1,29 +1,20 @@
import 'package:gecko/models/myWallets.dart'; import 'package:gecko/models/myWallets.dart';
import 'package:gecko/ui/myWallets/generateWalletsScreen.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:flutter/material.dart';
import 'package:dubp/dubp.dart'; import 'package:gecko/ui/myWallets/walletOptions.dart';
class WalletsHome extends StatelessWidget with ChangeNotifier { // ignore: must_be_immutable
MyWalletsProvider historyProvider = MyWalletsProvider(); class WalletsHome extends StatelessWidget {
MyWalletsProvider myWalletProvider = MyWalletsProvider();
String generatedMnemonic;
bool walletIsGenerated = false;
NewWallet actualWallet;
String newWalletName;
bool hasError = false;
String validPin = 'NO PIN';
String currentText = "";
var pinColor = Colors.grey[300];
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
historyProvider.getAppDirectory(); print('BUILD: WalletsHome');
myWalletProvider.listWallets = myWalletProvider.getAllWalletsNames();
return Scaffold( return Scaffold(
floatingActionButton: Visibility( floatingActionButton: Visibility(
visible: (historyProvider visible: (myWalletProvider
.checkIfWalletExist()), //!checkIfWalletExist('MonWallet') && .checkIfWalletExist()), //!checkIfWalletExist('MonWallet') &&
child: Container( child: Container(
height: 80.0, height: 80.0,
@ -48,8 +39,7 @@ class WalletsHome extends StatelessWidget with ChangeNotifier {
body: SafeArea( body: SafeArea(
child: Column(children: <Widget>[ child: Column(children: <Widget>[
Visibility( Visibility(
visible: visible: (!myWalletProvider.checkIfWalletExist()),
(!historyProvider.checkIfWalletExist() && !walletIsGenerated),
child: Column(children: <Widget>[ child: Column(children: <Widget>[
SizedBox(height: 120), SizedBox(height: 120),
Center( Center(
@ -83,13 +73,13 @@ class WalletsHome extends StatelessWidget with ChangeNotifier {
primary: Color(0xffFFD68E), // background primary: Color(0xffFFD68E), // background
onPrimary: Colors.black, // foreground onPrimary: Colors.black, // foreground
), ),
onPressed: () => historyProvider.importWallet(), onPressed: () => myWalletProvider.importWallet(),
child: Text('Importer un portefeuille existant', child: Text('Importer un portefeuille existant',
style: TextStyle(fontSize: 20))), style: TextStyle(fontSize: 20))),
])), ])),
Visibility( Visibility(
visible: historyProvider.checkIfWalletExist(), visible: myWalletProvider.checkIfWalletExist(),
child: MyWalletsList()) child: myWalletsList(context))
]))); ])));
} }
@ -105,4 +95,37 @@ class WalletsHome extends StatelessWidget with ChangeNotifier {
// }); // });
// } // }
myWalletsList(BuildContext context) {
return Column(children: <Widget>[
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))))
]);
}
} }