Compare commits
26 Commits
Author | SHA1 | Date |
---|---|---|
poka | 4aecbd23be | |
poka | 82a17df414 | |
poka | 267a3e0ba1 | |
poka | 45aa28ab70 | |
poka | 2d136f89cf | |
poka | e402be8cca | |
poka | f0417407e0 | |
poka | 807c54b9b5 | |
poka | ba95a262e0 | |
poka | aa320a1587 | |
poka | f50c4d82de | |
poka | c459d5d36c | |
poka | 1bd4dd47b2 | |
poka | caf35fe19f | |
poka | 3d501f4544 | |
poka | 5176e76860 | |
poka | 5542a8eea8 | |
poka | a4b0a099ff | |
poka | df772db864 | |
poka | 63dfee0ebf | |
poka | f8063f67f5 | |
poka | 3de4e7742d | |
poka | dbf6a9d476 | |
poka | 22be4f1de6 | |
poka | 9d07d7373c | |
poka | cc22dd6a08 |
|
@ -53,10 +53,10 @@ android {
|
||||||
|
|
||||||
signingConfigs {
|
signingConfigs {
|
||||||
release {
|
release {
|
||||||
keyAlias keystoreProperties['alias_name']
|
keyAlias keystoreProperties['keyAlias']
|
||||||
keyPassword keystoreProperties['tataestmonpass']
|
keyPassword keystoreProperties['keyPassword']
|
||||||
storeFile keystoreProperties['/home/poka/dev/Flutter/my-release-key.keystore'] ? file(keystoreProperties['/home/poka/dev/Flutter/my-release-key.keystore']) : null
|
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
|
||||||
storePassword keystoreProperties['tataestmonpass']
|
storePassword keystoreProperties['storePassword']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||||
<application
|
<application
|
||||||
android:name="io.flutter.app.FlutterApplication"
|
android:name="io.flutter.app.FlutterApplication"
|
||||||
android:label="gecko">
|
android:label="Ğecko">
|
||||||
<!-- android:icon="@mipmap/ic_launcher"> -->
|
<!-- android:icon="@mipmap/ic_launcher"> -->
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
|
|
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 9.0 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 111 KiB |
After Width: | Height: | Size: 40 KiB |
|
@ -1,3 +1,4 @@
|
||||||
[
|
[
|
||||||
"https://g1.librelois.fr/gva"
|
"https://g1.librelois.fr/gva",
|
||||||
]
|
"http://localhost:30901/gva"
|
||||||
|
]
|
||||||
|
|
Before Width: | Height: | Size: 242 KiB After Width: | Height: | Size: 230 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.0 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 17 KiB |
|
@ -0,0 +1,7 @@
|
||||||
|
import 'dart:io';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
Directory appPath;
|
||||||
|
Directory walletsDirectory;
|
||||||
|
String appVersion;
|
||||||
|
SharedPreferences prefs;
|
104
lib/main.dart
|
@ -1,13 +1,18 @@
|
||||||
import 'package:gecko/ui/home.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/home.dart';
|
||||||
|
import 'package:gecko/models/myWallets.dart';
|
||||||
|
import 'package:gecko/models/walletOptions.dart';
|
||||||
|
import 'package:gecko/screens/home.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:graphql_flutter/graphql_flutter.dart';
|
import 'package:graphql_flutter/graphql_flutter.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:shared_preferences/shared_preferences.dart';
|
||||||
// import 'package:flutter/services.dart' show rootBundle;
|
|
||||||
import 'dart:math';
|
|
||||||
// import 'dart:convert';
|
|
||||||
|
|
||||||
final bool enableSentry = true;
|
final bool enableSentry = true;
|
||||||
|
|
||||||
|
@ -15,39 +20,17 @@ 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();
|
||||||
|
prefs = await SharedPreferences.getInstance();
|
||||||
|
|
||||||
String randomEndpoint; // = await getRandomEndpoint();
|
String randomEndpoint; // = await getRandomEndpoint();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
do {
|
do {
|
||||||
if (i >= 3) {
|
if (i >= 5) {
|
||||||
print('NO VALID ENDPOINT FOUND !');
|
print('NO VALID ENDPOINT FOUND !');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -55,7 +38,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');
|
||||||
|
|
||||||
|
@ -69,10 +52,14 @@ 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;
|
||||||
|
@ -90,23 +77,32 @@ class Gecko extends StatelessWidget {
|
||||||
link: _httpLink,
|
link: _httpLink,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
return MaterialApp(
|
|
||||||
title: 'Ğecko',
|
DubpRust.setup();
|
||||||
theme: ThemeData(
|
return MultiProvider(
|
||||||
primaryColor: Color(0xffD28928),
|
providers: [
|
||||||
accentColor: Color(0xffFFD68E),
|
// Provider(create: (context) => HistoryProvider()),
|
||||||
textTheme: TextTheme(
|
ChangeNotifierProvider(create: (_) => HomeProvider()),
|
||||||
bodyText1: TextStyle(),
|
ChangeNotifierProvider(create: (_) => HistoryProvider('')),
|
||||||
bodyText2: TextStyle(),
|
ChangeNotifierProvider(create: (_) => MyWalletsProvider()),
|
||||||
).apply(
|
ChangeNotifierProvider(create: (_) => GenerateWalletsProvider()),
|
||||||
bodyColor: Color(0xff855F2D),
|
ChangeNotifierProvider(create: (_) => WalletOptionsProvider())
|
||||||
// displayColor: Colors.blue,
|
],
|
||||||
),
|
child: GraphQLProvider(
|
||||||
),
|
client: _client,
|
||||||
home: GraphQLProvider(
|
child: MaterialApp(
|
||||||
client: _client,
|
title: 'Ğecko',
|
||||||
child: HomeScreen(),
|
theme: ThemeData(
|
||||||
),
|
primaryColor: Color(0xffFFD58D),
|
||||||
);
|
accentColor: Colors.grey[850],
|
||||||
|
textTheme: TextTheme(
|
||||||
|
bodyText1: TextStyle(),
|
||||||
|
bodyText2: TextStyle(),
|
||||||
|
).apply(
|
||||||
|
bodyColor: Color(0xff855F2D),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
home: HomeScreen(),
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,235 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
import 'dart:math';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
import 'package:dubp/dubp.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:gecko/globals.dart';
|
||||||
|
import 'package:sentry_flutter/sentry_flutter.dart' as sentry;
|
||||||
|
import 'package:pdf/pdf.dart';
|
||||||
|
import 'package:pdf/widgets.dart' as pw;
|
||||||
|
import 'package:printing/printing.dart';
|
||||||
|
|
||||||
|
class GenerateWalletsProvider with ChangeNotifier {
|
||||||
|
GenerateWalletsProvider();
|
||||||
|
// NewWallet generatedWallet;
|
||||||
|
NewWallet actualWallet;
|
||||||
|
|
||||||
|
FocusNode walletNameFocus = FocusNode();
|
||||||
|
Color askedWordColor = Colors.black;
|
||||||
|
bool isAskedWordValid = false;
|
||||||
|
int nbrWord;
|
||||||
|
|
||||||
|
String generatedMnemonic;
|
||||||
|
bool walletIsGenerated = true;
|
||||||
|
|
||||||
|
TextEditingController mnemonicController = TextEditingController();
|
||||||
|
TextEditingController pubkey = TextEditingController();
|
||||||
|
TextEditingController pin = TextEditingController();
|
||||||
|
|
||||||
|
Future storeWallet(NewWallet wallet, _name, BuildContext context) async {
|
||||||
|
final Directory walletNameDirectory =
|
||||||
|
Directory('${walletsDirectory.path}/$_name');
|
||||||
|
final walletFile = File('${walletNameDirectory.path}/wallet.dewif');
|
||||||
|
final walletPubkey = File('${walletNameDirectory.path}/pubkey');
|
||||||
|
|
||||||
|
if (await walletNameDirectory.exists()) {
|
||||||
|
print('Ce wallet existe déjà, impossible de le créer.');
|
||||||
|
_showWalletExistDialog(context);
|
||||||
|
return 'Exist: DENY';
|
||||||
|
}
|
||||||
|
|
||||||
|
await walletNameDirectory.create();
|
||||||
|
await walletFile.writeAsString('${wallet.dewif}');
|
||||||
|
await walletPubkey.writeAsString('${wallet.publicKey}');
|
||||||
|
|
||||||
|
Navigator.pop(context, true);
|
||||||
|
Navigator.pop(context, wallet.publicKey);
|
||||||
|
// notifyListeners();
|
||||||
|
|
||||||
|
return _name;
|
||||||
|
}
|
||||||
|
|
||||||
|
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' ||
|
||||||
|
value == '3.14') {
|
||||||
|
print('Word is OK');
|
||||||
|
isAskedWordValid = true;
|
||||||
|
askedWordColor = Colors.green[600];
|
||||||
|
walletNameFocus.nextFocus();
|
||||||
|
notifyListeners();
|
||||||
|
} 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();
|
||||||
|
askedWordColor = Colors.green[500];
|
||||||
|
isAskedWordValid = true;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> generateMnemonic() async {
|
||||||
|
try {
|
||||||
|
generatedMnemonic = await DubpRust.genMnemonic(language: Language.french);
|
||||||
|
this.actualWallet = await generateWallet(this.generatedMnemonic);
|
||||||
|
walletIsGenerated = true;
|
||||||
|
// notifyListeners();
|
||||||
|
} catch (e, stack) {
|
||||||
|
print(e);
|
||||||
|
if (kReleaseMode) {
|
||||||
|
await sentry.Sentry.captureException(
|
||||||
|
e,
|
||||||
|
stackTrace: stack,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// await checkIfWalletExist();
|
||||||
|
return 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 = this.actualWallet.publicKey;
|
||||||
|
pin.text = this.actualWallet.pin;
|
||||||
|
// notifyListeners();
|
||||||
|
|
||||||
|
return this.actualWallet;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> changePinCode() async {
|
||||||
|
this.actualWallet = await DubpRust.changeDewifPin(
|
||||||
|
dewif: this.actualWallet.dewif,
|
||||||
|
oldPin: this.actualWallet.pin,
|
||||||
|
);
|
||||||
|
|
||||||
|
pin.text = this.actualWallet.pin;
|
||||||
|
// notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Uint8List> printWallet(String _title, String _pubkey) async {
|
||||||
|
final ByteData fontData =
|
||||||
|
await rootBundle.load("assets/OpenSans-Regular.ttf");
|
||||||
|
final pw.Font ttf = pw.Font.ttf(fontData.buffer.asByteData());
|
||||||
|
final pdf = pw.Document();
|
||||||
|
|
||||||
|
const imageProvider = const AssetImage('assets/icon/gecko_final.png');
|
||||||
|
final geckoLogo = await flutterImageProvider(imageProvider);
|
||||||
|
|
||||||
|
pdf.addPage(
|
||||||
|
pw.Page(
|
||||||
|
pageFormat: PdfPageFormat.a4,
|
||||||
|
build: (context) {
|
||||||
|
return pw.Column(children: <pw.Widget>[
|
||||||
|
pw.Text("Clé publique:",
|
||||||
|
style: pw.TextStyle(fontSize: 20, font: ttf)),
|
||||||
|
pw.SizedBox(height: 10),
|
||||||
|
pw.Text(_pubkey,
|
||||||
|
style: pw.TextStyle(fontSize: 15, font: ttf),
|
||||||
|
textAlign: pw.TextAlign.center),
|
||||||
|
pw.SizedBox(height: 20),
|
||||||
|
pw.Text("Phrase de restauration:",
|
||||||
|
style: pw.TextStyle(fontSize: 20, font: ttf)),
|
||||||
|
pw.SizedBox(height: 10),
|
||||||
|
pw.Text(_title,
|
||||||
|
style: pw.TextStyle(fontSize: 15, font: ttf),
|
||||||
|
textAlign: pw.TextAlign.center),
|
||||||
|
pw.Expanded(
|
||||||
|
child: pw.Align(
|
||||||
|
alignment: pw.Alignment.bottomCenter,
|
||||||
|
child: pw.Text(
|
||||||
|
"Gardez cette feuille en lieu sûr, à l'abris des regards indiscrets.",
|
||||||
|
style: pw.TextStyle(fontSize: 10, font: ttf),
|
||||||
|
))),
|
||||||
|
pw.SizedBox(height: 15),
|
||||||
|
pw.Image(geckoLogo, height: 50)
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return pdf.save();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,160 @@
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:graphql_flutter/graphql_flutter.dart';
|
||||||
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
import 'package:sentry/sentry.dart' as sentry;
|
||||||
|
import 'package:qrscan/qrscan.dart' as scanner;
|
||||||
|
import 'dart:math';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
|
class HistoryProvider with ChangeNotifier {
|
||||||
|
// String pubkey = 'D2meevcAHFTS2gQMvmRW5Hzi25jDdikk4nC4u1FkwRaU'; // For debug
|
||||||
|
String pubkey = '';
|
||||||
|
HistoryProvider(this.pubkey);
|
||||||
|
final TextEditingController _outputPubkey = new TextEditingController();
|
||||||
|
bool isTheEnd = false;
|
||||||
|
List transBC;
|
||||||
|
|
||||||
|
Future scan() async {
|
||||||
|
await Permission.camera.request();
|
||||||
|
String barcode;
|
||||||
|
try {
|
||||||
|
barcode = await scanner.scan();
|
||||||
|
} catch (e, stack) {
|
||||||
|
print(e);
|
||||||
|
if (kReleaseMode) {
|
||||||
|
await sentry.Sentry.captureException(
|
||||||
|
e,
|
||||||
|
stackTrace: stack,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return 'false';
|
||||||
|
}
|
||||||
|
if (barcode != null) {
|
||||||
|
this._outputPubkey.text = barcode;
|
||||||
|
isPubkey(barcode);
|
||||||
|
} else {
|
||||||
|
return 'false';
|
||||||
|
}
|
||||||
|
return barcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
String isPubkey(pubkey) {
|
||||||
|
final RegExp regExp = new RegExp(
|
||||||
|
r'^[a-zA-Z0-9]+$',
|
||||||
|
caseSensitive: false,
|
||||||
|
multiLine: false,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (regExp.hasMatch(pubkey) == true &&
|
||||||
|
pubkey.length > 42 &&
|
||||||
|
pubkey.length < 45) {
|
||||||
|
print("C'est une pubkey !!!");
|
||||||
|
|
||||||
|
this.pubkey = pubkey;
|
||||||
|
this._outputPubkey.text = pubkey;
|
||||||
|
notifyListeners();
|
||||||
|
|
||||||
|
return pubkey;
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
List parseHistory(txs) {
|
||||||
|
var transBC = [];
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
final currentBase = 0;
|
||||||
|
double currentUD = 10.54;
|
||||||
|
|
||||||
|
for (final trans in txs) {
|
||||||
|
var direction = trans['direction'];
|
||||||
|
final transaction = trans['node'];
|
||||||
|
var output = transaction['outputs'][0];
|
||||||
|
|
||||||
|
transBC.add(i);
|
||||||
|
transBC[i] = [];
|
||||||
|
final dateBrut = DateTime.fromMillisecondsSinceEpoch(
|
||||||
|
transaction['writtenTime'] * 1000);
|
||||||
|
final DateFormat formatter = DateFormat('dd-MM-yy\nHH:mm');
|
||||||
|
final date = formatter.format(dateBrut);
|
||||||
|
transBC[i].add(transaction['writtenTime']);
|
||||||
|
transBC[i].add(date);
|
||||||
|
// print(
|
||||||
|
// "DEBUG date et comment: ${date.toString()} -- ${transaction['comment'].toString()}");
|
||||||
|
int amountBrut = int.parse(output.split(':')[0]);
|
||||||
|
final base = int.parse(output.split(':')[1]);
|
||||||
|
final int applyBase = base - currentBase;
|
||||||
|
final num amount =
|
||||||
|
removeDecimalZero(amountBrut * pow(10, applyBase) / 100);
|
||||||
|
num amountUD = amount / currentUD;
|
||||||
|
if (direction == "RECEIVED") {
|
||||||
|
transBC[i].add(transaction['issuers'][0]);
|
||||||
|
transBC[i].add(amount.toString());
|
||||||
|
transBC[i].add(amountUD.toStringAsFixed(2));
|
||||||
|
} else if (direction == "SENT") {
|
||||||
|
final outPubkey = output.split("SIG(")[1].replaceAll(')', '');
|
||||||
|
transBC[i].add(outPubkey);
|
||||||
|
transBC[i].add('- ' + amount.toString());
|
||||||
|
transBC[i].add(amountUD.toStringAsFixed(2));
|
||||||
|
}
|
||||||
|
transBC[i].add(transaction['comment']);
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return transBC;
|
||||||
|
}
|
||||||
|
|
||||||
|
FetchMoreOptions checkQueryResult(result, opts) {
|
||||||
|
final List<dynamic> blockchainTX =
|
||||||
|
(result.data['txsHistoryBc']['both']['edges'] as List<dynamic>);
|
||||||
|
|
||||||
|
final Map pageInfo = result.data['txsHistoryBc']['both']['pageInfo'];
|
||||||
|
|
||||||
|
final String fetchMoreCursor = pageInfo['endCursor'];
|
||||||
|
|
||||||
|
if (fetchMoreCursor != null) {
|
||||||
|
opts = FetchMoreOptions(
|
||||||
|
variables: {'cursor': fetchMoreCursor},
|
||||||
|
updateQuery: (previousResultData, fetchMoreResultData) {
|
||||||
|
final List<dynamic> repos = [
|
||||||
|
...previousResultData['txsHistoryBc']['both']['edges']
|
||||||
|
as List<dynamic>,
|
||||||
|
...fetchMoreResultData['txsHistoryBc']['both']['edges']
|
||||||
|
as List<dynamic>
|
||||||
|
];
|
||||||
|
|
||||||
|
fetchMoreResultData['txsHistoryBc']['both']['edges'] = repos;
|
||||||
|
return fetchMoreResultData;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
print(
|
||||||
|
"###### DEBUG H Parse blockchainTX list. Cursor: $fetchMoreCursor ######");
|
||||||
|
if (fetchMoreCursor != null) {
|
||||||
|
transBC = parseHistory(blockchainTX);
|
||||||
|
isTheEnd = false;
|
||||||
|
} else {
|
||||||
|
print("###### DEBUG H - Début de l'historique");
|
||||||
|
isTheEnd = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return opts;
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetdHistory() {
|
||||||
|
this._outputPubkey.text = '';
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
num removeDecimalZero(double n) {
|
||||||
|
String result = n.toStringAsFixed(n.truncateToDouble() == n ? 0 : 1);
|
||||||
|
return num.parse(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// num getBalance(_pubkey) {
|
||||||
|
// getBalance(_pubkey);
|
||||||
|
// }
|
||||||
|
}
|
|
@ -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;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future getAppVersion() async {
|
||||||
|
PackageInfo packageInfo = await PackageInfo.fromPlatform();
|
||||||
|
String version = packageInfo.version;
|
||||||
|
String buildNumber = packageInfo.buildNumber;
|
||||||
|
|
||||||
|
notifyListeners();
|
||||||
|
return version + '+' + buildNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 _listEndpoints = [
|
||||||
|
'https://g1.librelois.fr/gva',
|
||||||
|
'https://duniter-gva.axiom-team.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());
|
||||||
|
return 'HS';
|
||||||
|
}
|
||||||
|
|
||||||
|
return _endpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future getAppPath() async {
|
||||||
|
appPath = await getApplicationDocumentsDirectory();
|
||||||
|
walletsDirectory = Directory('${appPath.path}/wallets');
|
||||||
|
|
||||||
|
bool isWalletFolderExist = await walletsDirectory.exists();
|
||||||
|
|
||||||
|
if (!isWalletFolderExist) {
|
||||||
|
await Directory(walletsDirectory.path).create();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
T getRandomElement<T>(List<T> list) {
|
||||||
|
final random = new Random();
|
||||||
|
var i = random.nextInt(list.length);
|
||||||
|
return list[i];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,108 @@
|
||||||
|
import 'dart:io';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'dart:async';
|
||||||
|
import 'package:gecko/globals.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class MyWalletsProvider with ChangeNotifier {
|
||||||
|
Map listWallets = Map();
|
||||||
|
|
||||||
|
bool checkIfWalletExist() {
|
||||||
|
if (appPath == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
List contents = walletsDirectory.listSync();
|
||||||
|
if (contents.length == 0) {
|
||||||
|
print('No wallets detected');
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
print('Some wallets have been detected.');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future importWallet() async {}
|
||||||
|
|
||||||
|
Map getAllWalletsNames() {
|
||||||
|
print(listWallets);
|
||||||
|
if (listWallets.isNotEmpty) {
|
||||||
|
listWallets.clear();
|
||||||
|
}
|
||||||
|
print(walletsDirectory.path);
|
||||||
|
|
||||||
|
// int i = 0;
|
||||||
|
walletsDirectory
|
||||||
|
.listSync(recursive: false, followLinks: false)
|
||||||
|
.forEach((wallet) {
|
||||||
|
String _name = wallet.path.split('/').last;
|
||||||
|
List _pubkeyList = File(wallet.path + '/pubkey').readAsLinesSync();
|
||||||
|
String _pubkey = _pubkeyList[0];
|
||||||
|
print("$_name: $_pubkey");
|
||||||
|
listWallets[_name] = _pubkey;
|
||||||
|
// i++;
|
||||||
|
|
||||||
|
// for (var _wallets in listWallets) {
|
||||||
|
// _wallets.pubkey =
|
||||||
|
// }
|
||||||
|
});
|
||||||
|
return listWallets;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<int> deleteAllWallet(context) async {
|
||||||
|
try {
|
||||||
|
print('DELETE THAT ?: $walletsDirectory');
|
||||||
|
|
||||||
|
final bool _answer = await _confirmDeletingAllWallets(context);
|
||||||
|
|
||||||
|
if (_answer) {
|
||||||
|
await walletsDirectory.delete(recursive: true);
|
||||||
|
await walletsDirectory.create();
|
||||||
|
Navigator.pop(context);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
} catch (e) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> _confirmDeletingAllWallets(context) async {
|
||||||
|
return showDialog<bool>(
|
||||||
|
context: context,
|
||||||
|
barrierDismissible: true, // user must tap button!
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
MyWalletsProvider _myWalletProvider =
|
||||||
|
Provider.of<MyWalletsProvider>(context);
|
||||||
|
return AlertDialog(
|
||||||
|
title: Text(
|
||||||
|
'Êtes-vous sûr de vouloir supprimer tous vos portefeuilles ?'),
|
||||||
|
content: SingleChildScrollView(child: Text('')),
|
||||||
|
actions: <Widget>[
|
||||||
|
TextButton(
|
||||||
|
child: Text("Non"),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pop(context, false);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
child: Text("Oui"),
|
||||||
|
onPressed: () {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
_myWalletProvider.listWallets =
|
||||||
|
_myWalletProvider.getAllWalletsNames();
|
||||||
|
_myWalletProvider.rebuildWidget();
|
||||||
|
});
|
||||||
|
Navigator.pop(context, true);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rebuildWidget() {
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,212 @@
|
||||||
|
import 'dart:io';
|
||||||
|
import 'package:dubp/dubp.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'dart:async';
|
||||||
|
import 'package:sentry/sentry.dart' as sentry;
|
||||||
|
import 'package:gecko/globals.dart';
|
||||||
|
|
||||||
|
class WalletOptionsProvider with ChangeNotifier {
|
||||||
|
TextEditingController pubkey = new TextEditingController();
|
||||||
|
TextEditingController _newWalletName = new TextEditingController();
|
||||||
|
bool isWalletUnlock = false;
|
||||||
|
bool ischangedPin = false;
|
||||||
|
TextEditingController newPin = new TextEditingController();
|
||||||
|
|
||||||
|
Future<NewWallet> get badWallet => null;
|
||||||
|
|
||||||
|
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);
|
||||||
|
this.pubkey.text = _pubkey;
|
||||||
|
notifyListeners();
|
||||||
|
|
||||||
|
return _pubkey;
|
||||||
|
} catch (e, stack) {
|
||||||
|
print('Bad PIN code !');
|
||||||
|
print(e);
|
||||||
|
if (kReleaseMode) {
|
||||||
|
await sentry.Sentry.captureException(
|
||||||
|
e,
|
||||||
|
stackTrace: stack,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
notifyListeners();
|
||||||
|
|
||||||
|
return 'false';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future readLocalWallet(String _name, String _pin) async {
|
||||||
|
isWalletUnlock = false;
|
||||||
|
print('NOM: ' + _name);
|
||||||
|
try {
|
||||||
|
File _walletFile = File('${walletsDirectory.path}/$_name/wallet.dewif');
|
||||||
|
String _localDewif = await _walletFile.readAsString();
|
||||||
|
String _localPubkey;
|
||||||
|
|
||||||
|
if ((_localPubkey = await _getPubkeyFromDewif(_localDewif, _pin)) !=
|
||||||
|
'false') {
|
||||||
|
this.pubkey.text = _localPubkey;
|
||||||
|
isWalletUnlock = true;
|
||||||
|
notifyListeners();
|
||||||
|
|
||||||
|
return _localDewif;
|
||||||
|
} else {
|
||||||
|
throw 'Bad pubkey';
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print('ERROR READING FILE: $e');
|
||||||
|
this.pubkey.clear();
|
||||||
|
return 'bad';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future _renameWallet(_walletName, _newName) async {
|
||||||
|
final _walletFile = Directory('${walletsDirectory.path}/$_walletName');
|
||||||
|
|
||||||
|
try {
|
||||||
|
_walletFile.rename('${walletsDirectory.path}/$_newName');
|
||||||
|
} catch (e) {
|
||||||
|
print('ERREUR lors du renommage du wallet: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> renameWalletAlerte(context, _walletName) async {
|
||||||
|
return showDialog<bool>(
|
||||||
|
context: context,
|
||||||
|
barrierDismissible: true, // user must tap button!
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: Text('Choisissez un nouveau nom pour ce portefeuille'),
|
||||||
|
content: SingleChildScrollView(
|
||||||
|
child: ListBody(
|
||||||
|
children: <Widget>[
|
||||||
|
TextField(
|
||||||
|
controller: this._newWalletName,
|
||||||
|
maxLines: 1,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
decoration: InputDecoration(),
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14.0,
|
||||||
|
color: Colors.black,
|
||||||
|
fontWeight: FontWeight.bold)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
actions: <Widget>[
|
||||||
|
TextButton(
|
||||||
|
child: Text("Valider"),
|
||||||
|
onPressed: () {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
_renameWallet(_walletName, this._newWalletName.text);
|
||||||
|
});
|
||||||
|
// notifyListeners();
|
||||||
|
Navigator.pop(context, true);
|
||||||
|
Navigator.pop(context, true);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<int> deleteWallet(context, _name) async {
|
||||||
|
try {
|
||||||
|
final _walletFile = Directory('${walletsDirectory.path}/$_name');
|
||||||
|
print('DELETE THAT ?: $_walletFile');
|
||||||
|
|
||||||
|
final bool _answer = await _confirmDeletingWallet(context, _name);
|
||||||
|
|
||||||
|
if (_answer) {
|
||||||
|
await _walletFile.delete(recursive: true);
|
||||||
|
Navigator.pop(context);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
} catch (e) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> _confirmDeletingWallet(context, _walletName) async {
|
||||||
|
return showDialog<bool>(
|
||||||
|
context: context,
|
||||||
|
barrierDismissible: true, // user must tap button!
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: Text(
|
||||||
|
'Êtes-vous sûr de vouloir supprimer le portefeuille "$_walletName" ?'),
|
||||||
|
content: SingleChildScrollView(
|
||||||
|
child: ListBody(
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
'Vous pourrez restaurer ce portefeuille à tout moment grace à votre phrase de restauration.'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
actions: <Widget>[
|
||||||
|
TextButton(
|
||||||
|
child: Text("Non"),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pop(context, false);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
child: Text("Oui"),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pop(context, true);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<NewWallet> changePin(_name, _oldPin) async {
|
||||||
|
try {
|
||||||
|
final _walletFile = Directory('${walletsDirectory.path}/$_name');
|
||||||
|
final _dewif =
|
||||||
|
File(_walletFile.path + '/wallet.dewif').readAsLinesSync()[0];
|
||||||
|
|
||||||
|
NewWallet newWalletFile = await DubpRust.changeDewifPin(
|
||||||
|
dewif: _dewif,
|
||||||
|
oldPin: _oldPin,
|
||||||
|
);
|
||||||
|
|
||||||
|
newPin.text = newWalletFile.pin;
|
||||||
|
ischangedPin = true;
|
||||||
|
// notifyListeners();
|
||||||
|
return newWalletFile;
|
||||||
|
} catch (e) {
|
||||||
|
print('Impossible de changer le code PIN.');
|
||||||
|
return badWallet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future storeWallet(context, _name, _newWalletFile) async {
|
||||||
|
final Directory walletNameDirectory =
|
||||||
|
Directory('${walletsDirectory.path}/$_name');
|
||||||
|
final walletFile = File('${walletNameDirectory.path}/wallet.dewif');
|
||||||
|
|
||||||
|
walletFile.writeAsString('${_newWalletFile.dewif}');
|
||||||
|
|
||||||
|
Navigator.pop(context);
|
||||||
|
|
||||||
|
return _name;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,54 +0,0 @@
|
||||||
import 'dart:math';
|
|
||||||
import 'package:intl/intl.dart';
|
|
||||||
|
|
||||||
num removeDecimalZero(double n) {
|
|
||||||
String result = n.toStringAsFixed(n.truncateToDouble() == n ? 0 : 1);
|
|
||||||
return num.parse(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
List parseHistory(txs) {
|
|
||||||
var transBC = [];
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
final currentBase = 0;
|
|
||||||
double currentUD = 10.54;
|
|
||||||
|
|
||||||
for (final trans in txs) {
|
|
||||||
var direction = trans['direction'];
|
|
||||||
final transaction = trans['node'];
|
|
||||||
var output = transaction['outputs'][0];
|
|
||||||
|
|
||||||
transBC.add(i);
|
|
||||||
transBC[i] = [];
|
|
||||||
final dateBrut =
|
|
||||||
DateTime.fromMillisecondsSinceEpoch(transaction['writtenTime'] * 1000);
|
|
||||||
final DateFormat formatter = DateFormat('dd-MM-yy - HH:mm');
|
|
||||||
final date = formatter.format(dateBrut);
|
|
||||||
transBC[i].add(transaction['writtenTime']);
|
|
||||||
transBC[i].add(date);
|
|
||||||
print(
|
|
||||||
"DEBUG date et comment: ${date.toString()} -- ${transaction['comment'].toString()}");
|
|
||||||
int amountBrut = int.parse(output.split(':')[0]);
|
|
||||||
final base = int.parse(output.split(':')[1]);
|
|
||||||
final int applyBase = base - currentBase;
|
|
||||||
final num amount = removeDecimalZero(amountBrut * pow(10, applyBase) / 100);
|
|
||||||
num amountUD = amount / currentUD;
|
|
||||||
int padNbr = 14 - amount.toString().length;
|
|
||||||
if (direction == "RECEIVED") {
|
|
||||||
transBC[i].add(transaction['issuers'][0]);
|
|
||||||
transBC[i].add(' ' + amount.toString().padRight(padNbr));
|
|
||||||
transBC[i].add(amountUD.toStringAsFixed(2));
|
|
||||||
} else if (direction == "SENT") {
|
|
||||||
final outPubkey = output.split("SIG(")[1].replaceAll(')', '');
|
|
||||||
transBC[i].add(outPubkey);
|
|
||||||
transBC[i].add(' -' + amount.toString().padRight(padNbr - 1));
|
|
||||||
transBC[i].add(amountUD.toStringAsFixed(2));
|
|
||||||
}
|
|
||||||
transBC[i].add(transaction['comment']);
|
|
||||||
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// transBC.sort((b, a) => Comparable.compare(a[0], b[0]));
|
|
||||||
return transBC;
|
|
||||||
}
|
|
|
@ -0,0 +1,275 @@
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:gecko/models/queries.dart';
|
||||||
|
import 'package:gecko/models/history.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'dart:ui';
|
||||||
|
import 'package:graphql_flutter/graphql_flutter.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:truncate/truncate.dart';
|
||||||
|
|
||||||
|
// ignore: must_be_immutable
|
||||||
|
class HistoryScreen extends StatelessWidget with ChangeNotifier {
|
||||||
|
final TextEditingController _outputPubkey = TextEditingController();
|
||||||
|
ScrollController scrollController = ScrollController();
|
||||||
|
final nRepositories = 20;
|
||||||
|
// HistoryProvider _historyProvider;
|
||||||
|
final _formKey = GlobalKey<FormState>();
|
||||||
|
FocusNode _pubkeyFocus = FocusNode();
|
||||||
|
|
||||||
|
FetchMore fetchMore;
|
||||||
|
FetchMoreOptions opts;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
HistoryProvider _historyProvider = Provider.of<HistoryProvider>(context);
|
||||||
|
this._outputPubkey.text = _historyProvider.pubkey;
|
||||||
|
print('Build pubkey : ' + _historyProvider.pubkey);
|
||||||
|
return Scaffold(
|
||||||
|
floatingActionButton: Container(
|
||||||
|
height: 80.0,
|
||||||
|
width: 80.0,
|
||||||
|
child: FittedBox(
|
||||||
|
child: FloatingActionButton(
|
||||||
|
heroTag: "buttonScan",
|
||||||
|
onPressed: () async {
|
||||||
|
await _historyProvider.scan();
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
height: 40.0,
|
||||||
|
width: 40.0,
|
||||||
|
child: Image.asset('images/scanner.png')),
|
||||||
|
backgroundColor: Color(
|
||||||
|
0xffEFEFBF), //Color(0xffFFD68E), //Color.fromARGB(500, 204, 255, 255),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
body: Column(children: <Widget>[
|
||||||
|
SizedBox(height: 8),
|
||||||
|
TextField(
|
||||||
|
autofocus: false,
|
||||||
|
focusNode: _pubkeyFocus,
|
||||||
|
// Entrée de la pubkey
|
||||||
|
onChanged: (text) {
|
||||||
|
print("Clé tappxé: $text");
|
||||||
|
_historyProvider.isPubkey(text);
|
||||||
|
},
|
||||||
|
controller: this._outputPubkey,
|
||||||
|
maxLines: 1,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: 'Tappez/Collez une clé publique, ou scannez',
|
||||||
|
hintStyle: TextStyle(fontSize: 14),
|
||||||
|
contentPadding:
|
||||||
|
EdgeInsets.symmetric(horizontal: 7, vertical: 15),
|
||||||
|
border: InputBorder.none,
|
||||||
|
focusedBorder: InputBorder.none,
|
||||||
|
enabledBorder: InputBorder.none,
|
||||||
|
errorBorder: InputBorder.none,
|
||||||
|
disabledBorder: InputBorder.none,
|
||||||
|
),
|
||||||
|
style: TextStyle(fontSize: 14.0, fontWeight: FontWeight.bold)),
|
||||||
|
if (_historyProvider.pubkey != '') historyQuery(context),
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
historyQuery(context) {
|
||||||
|
_pubkeyFocus.unfocus();
|
||||||
|
HistoryProvider _historyProvider = Provider.of<HistoryProvider>(context);
|
||||||
|
return Expanded(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: <Widget>[
|
||||||
|
Query(
|
||||||
|
options: QueryOptions(
|
||||||
|
document: gql(getHistory),
|
||||||
|
variables: <String, dynamic>{
|
||||||
|
'pubkey': _historyProvider.pubkey,
|
||||||
|
'number': nRepositories,
|
||||||
|
'cursor': null
|
||||||
|
},
|
||||||
|
),
|
||||||
|
builder: (QueryResult result, {refetch, fetchMore}) {
|
||||||
|
if (result.isLoading && result.data == null) {
|
||||||
|
return const Center(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.hasException) {
|
||||||
|
print('Error GVA: ' + result.exception.toString());
|
||||||
|
return Column(children: <Widget>[
|
||||||
|
SizedBox(height: 50),
|
||||||
|
Text(
|
||||||
|
"Aucun noeud GVA valide n'a pu être trouvé.\nVeuillez réessayer ultérieurement.",
|
||||||
|
style: TextStyle(fontSize: 17.0),
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.data == null && result.exception.toString() == null) {
|
||||||
|
return const Text('Aucune donnée à afficher.');
|
||||||
|
}
|
||||||
|
|
||||||
|
final num balance = _historyProvider
|
||||||
|
.removeDecimalZero(result.data['balance']['amount'] / 100);
|
||||||
|
|
||||||
|
opts = _historyProvider.checkQueryResult(result, opts);
|
||||||
|
|
||||||
|
// Build history list
|
||||||
|
return NotificationListener(
|
||||||
|
child: Expanded(
|
||||||
|
child: ListView(
|
||||||
|
controller: scrollController,
|
||||||
|
children: <Widget>[
|
||||||
|
SizedBox(height: 15),
|
||||||
|
if (_historyProvider.pubkey != '')
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Container(width: 70.0, height: 0.0),
|
||||||
|
Text(balance.toString() + ' Ğ1',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(fontSize: 30.0)),
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.only(right: 15),
|
||||||
|
child: IconButton(
|
||||||
|
icon: Icon(Icons.payments),
|
||||||
|
onPressed: () {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return paymentPopup(context);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
iconSize: 30,
|
||||||
|
color: Color(0xFFB16E16)))
|
||||||
|
]),
|
||||||
|
SizedBox(height: 15),
|
||||||
|
const Divider(
|
||||||
|
color: Colors.grey,
|
||||||
|
height: 5,
|
||||||
|
thickness: 0.5,
|
||||||
|
indent: 0,
|
||||||
|
endIndent: 0,
|
||||||
|
),
|
||||||
|
_historyProvider.transBC == null
|
||||||
|
? Text('Aucune transaction à afficher.')
|
||||||
|
: loopTransactions(context, result),
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
onNotification: (t) {
|
||||||
|
if (t is ScrollEndNotification &&
|
||||||
|
scrollController.position.pixels >=
|
||||||
|
scrollController.position.maxScrollExtent * 0.7) {
|
||||||
|
fetchMore(opts);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget loopTransactions(context, result) {
|
||||||
|
HistoryProvider _historyProvider = Provider.of<HistoryProvider>(context);
|
||||||
|
|
||||||
|
return Column(children: <Widget>[
|
||||||
|
for (var repository in _historyProvider.transBC)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||||
|
child: ListTile(
|
||||||
|
contentPadding: const EdgeInsets.all(5.0),
|
||||||
|
leading: Text(repository[1].toString(),
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
color: Colors.grey[800],
|
||||||
|
fontWeight: FontWeight.w700),
|
||||||
|
textAlign: TextAlign.center),
|
||||||
|
title: Text(repository[5],
|
||||||
|
style: TextStyle(fontSize: 14.0),
|
||||||
|
textAlign: TextAlign.center),
|
||||||
|
subtitle: Text(
|
||||||
|
truncate(repository[2], 20,
|
||||||
|
omission: "...", position: TruncatePosition.end),
|
||||||
|
style: TextStyle(fontSize: 11.0),
|
||||||
|
textAlign: TextAlign.center),
|
||||||
|
trailing: Text("${repository[3]} Ğ1",
|
||||||
|
style: TextStyle(fontSize: 14.0),
|
||||||
|
textAlign: TextAlign.justify),
|
||||||
|
dense: true,
|
||||||
|
isThreeLine: false,
|
||||||
|
onTap: () {
|
||||||
|
// this._outputPubkey.text = repository[2];
|
||||||
|
_historyProvider.isPubkey(repository[2]);
|
||||||
|
})),
|
||||||
|
if (result.isLoading)
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
CircularProgressIndicator(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if (_historyProvider.isTheEnd)
|
||||||
|
Column(children: <Widget>[
|
||||||
|
SizedBox(height: 15),
|
||||||
|
Text("Début de l'historique.",
|
||||||
|
textAlign: TextAlign.center, style: TextStyle(fontSize: 20)),
|
||||||
|
SizedBox(height: 15)
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget paymentPopup(context) {
|
||||||
|
return AlertDialog(
|
||||||
|
content: Stack(
|
||||||
|
overflow: Overflow.visible,
|
||||||
|
children: <Widget>[
|
||||||
|
Form(
|
||||||
|
key: _formKey,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Text('À:'),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.all(8.0),
|
||||||
|
child: Text(this._outputPubkey.text,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style:
|
||||||
|
TextStyle(fontSize: 15, fontWeight: FontWeight.w500)),
|
||||||
|
),
|
||||||
|
SizedBox(height: 20),
|
||||||
|
Text('Montant (Ğ1):'),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.all(8.0),
|
||||||
|
child: TextFormField(
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
autofocus: true,
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
inputFormatters: <TextInputFormatter>[
|
||||||
|
FilteringTextInputFormatter.allow(RegExp(r'(^\d*\.?\d*)'))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: RaisedButton(
|
||||||
|
child: Text("Payer"),
|
||||||
|
color: Color(0xffFFD68E),
|
||||||
|
onPressed: () {
|
||||||
|
if (_formKey.currentState.validate()) {
|
||||||
|
_formKey.currentState.save();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,101 @@
|
||||||
|
import 'package:gecko/globals.dart';
|
||||||
|
import 'package:gecko/models/home.dart';
|
||||||
|
import 'package:gecko/screens/history.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'dart:ui';
|
||||||
|
import 'package:gecko/screens/myWallets/walletsHome.dart';
|
||||||
|
import 'package:gecko/screens/settings.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
// ignore: must_be_immutable
|
||||||
|
class HomeScreen extends StatelessWidget {
|
||||||
|
var currentTab = [HistoryScreen(), WalletsHome()];
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
HomeProvider _homeProvider = Provider.of<HomeProvider>(context);
|
||||||
|
return Scaffold(
|
||||||
|
drawer: Drawer(
|
||||||
|
child: Column(
|
||||||
|
children: <Widget>[
|
||||||
|
Expanded(
|
||||||
|
child: ListView(padding: EdgeInsets.zero, children: <Widget>[
|
||||||
|
DrawerHeader(
|
||||||
|
child: Column(children: <Widget>[
|
||||||
|
SizedBox(height: 0),
|
||||||
|
Image(
|
||||||
|
image: AssetImage('assets/icon/gecko_final.png'),
|
||||||
|
height: 130),
|
||||||
|
]),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Color(0xffD28928),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
title: Text('Paramètres'),
|
||||||
|
onTap: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(builder: (context) {
|
||||||
|
return SettingsScreen();
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
title: Text('A propos'),
|
||||||
|
onTap: () {
|
||||||
|
// Update the state of the app.
|
||||||
|
// ...
|
||||||
|
},
|
||||||
|
),
|
||||||
|
])),
|
||||||
|
Container(
|
||||||
|
child: Align(
|
||||||
|
alignment: FractionalOffset.bottomCenter,
|
||||||
|
child: Text('Ğecko v$appVersion'))),
|
||||||
|
SizedBox(height: 20)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
appBar: AppBar(
|
||||||
|
leading: Builder(
|
||||||
|
builder: (context) => IconButton(
|
||||||
|
icon: new Icon(Icons.menu, color: Colors.grey[850]),
|
||||||
|
onPressed: () => Scaffold.of(context).openDrawer(),
|
||||||
|
)),
|
||||||
|
title: Text('Ğecko', style: TextStyle(color: Colors.grey[850])),
|
||||||
|
actions: [
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||||
|
child: Icon(Icons.search, color: Colors.grey[850]),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
backgroundColor: Color(0xffFFD58D),
|
||||||
|
),
|
||||||
|
backgroundColor: Color(0xffF9F9F1),
|
||||||
|
body: currentTab[_homeProvider.currentIndex],
|
||||||
|
bottomNavigationBar: BottomNavigationBar(
|
||||||
|
backgroundColor: Color(0xffFFD58D),
|
||||||
|
fixedColor: Colors.grey[850],
|
||||||
|
unselectedItemColor: Color(0xffBD935C),
|
||||||
|
type: BottomNavigationBarType.fixed,
|
||||||
|
onTap: (index) {
|
||||||
|
_homeProvider.currentIndex = index;
|
||||||
|
},
|
||||||
|
currentIndex: _homeProvider.currentIndex,
|
||||||
|
items: [
|
||||||
|
BottomNavigationBarItem(
|
||||||
|
icon: new Icon(Icons.format_list_bulleted),
|
||||||
|
label: 'Accueil',
|
||||||
|
),
|
||||||
|
BottomNavigationBarItem(
|
||||||
|
icon: new Icon(Icons.lock),
|
||||||
|
label: 'Mes portefeuilles',
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:dubp/dubp.dart';
|
||||||
|
import 'package:gecko/models/walletOptions.dart';
|
||||||
|
import 'dart:io';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
// ignore: must_be_immutable
|
||||||
|
class ChangePinScreen extends StatelessWidget with ChangeNotifier {
|
||||||
|
ChangePinScreen(
|
||||||
|
{Key keyMyWallets, @required this.walletName, @required this.oldPin})
|
||||||
|
: super(key: keyMyWallets);
|
||||||
|
final String walletName;
|
||||||
|
final oldPin;
|
||||||
|
Directory appPath;
|
||||||
|
NewWallet _newWalletFile;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
WalletOptionsProvider _walletOptions =
|
||||||
|
Provider.of<WalletOptionsProvider>(context);
|
||||||
|
_walletOptions.changePin(walletName, oldPin);
|
||||||
|
return Scaffold(
|
||||||
|
resizeToAvoidBottomInset: false,
|
||||||
|
appBar: AppBar(
|
||||||
|
title: SizedBox(
|
||||||
|
height: 22,
|
||||||
|
child: Text(walletName),
|
||||||
|
)),
|
||||||
|
body: Center(
|
||||||
|
child: SafeArea(
|
||||||
|
child: Column(children: <Widget>[
|
||||||
|
SizedBox(height: 80),
|
||||||
|
Text(
|
||||||
|
'Choisissez un code secret autogénéré :',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 17.0,
|
||||||
|
color: Colors.grey[600],
|
||||||
|
fontWeight: FontWeight.w400),
|
||||||
|
),
|
||||||
|
SizedBox(height: 30),
|
||||||
|
Container(
|
||||||
|
child: Stack(
|
||||||
|
alignment: Alignment.centerRight,
|
||||||
|
children: <Widget>[
|
||||||
|
TextField(
|
||||||
|
enabled: true,
|
||||||
|
controller: _walletOptions.newPin,
|
||||||
|
maxLines: 1,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
decoration: InputDecoration(),
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 30.0,
|
||||||
|
color: Colors.black,
|
||||||
|
fontWeight: FontWeight.bold)),
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.replay),
|
||||||
|
color: Color(0xffD28928),
|
||||||
|
onPressed: () async {
|
||||||
|
_newWalletFile =
|
||||||
|
await _walletOptions.changePin(walletName, oldPin);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 30),
|
||||||
|
SizedBox(
|
||||||
|
width: 200,
|
||||||
|
height: 50,
|
||||||
|
child: ElevatedButton(
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
elevation: 12,
|
||||||
|
primary: Colors.green[400], //Color(0xffFFD68E), // background
|
||||||
|
onPrimary: Colors.black, // foreground
|
||||||
|
),
|
||||||
|
onPressed: () => _walletOptions.storeWallet(
|
||||||
|
context, walletName, _newWalletFile),
|
||||||
|
child: Text('Confirmer', style: TextStyle(fontSize: 28))),
|
||||||
|
)
|
||||||
|
]))));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,175 @@
|
||||||
|
import 'package:dubp/dubp.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:gecko/models/generateWallets.dart';
|
||||||
|
import 'package:gecko/models/myWallets.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
// ignore: must_be_immutable
|
||||||
|
class ConfirmStoreWallet extends StatelessWidget with ChangeNotifier {
|
||||||
|
ConfirmStoreWallet({
|
||||||
|
Key validationKey,
|
||||||
|
@required this.generatedMnemonic,
|
||||||
|
@required this.generatedWallet,
|
||||||
|
}) : super(key: validationKey);
|
||||||
|
|
||||||
|
String generatedMnemonic;
|
||||||
|
NewWallet generatedWallet;
|
||||||
|
|
||||||
|
TextEditingController _mnemonicController = TextEditingController();
|
||||||
|
TextEditingController _pubkey = TextEditingController();
|
||||||
|
TextEditingController _inputRestoreWord = TextEditingController();
|
||||||
|
TextEditingController walletName = TextEditingController();
|
||||||
|
FocusNode _wordFocus = FocusNode();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
GenerateWalletsProvider _generateWalletProvider =
|
||||||
|
Provider.of<GenerateWalletsProvider>(context);
|
||||||
|
MyWalletsProvider _myWalletProvider =
|
||||||
|
Provider.of<MyWalletsProvider>(context);
|
||||||
|
|
||||||
|
this._mnemonicController.text = generatedMnemonic;
|
||||||
|
this._pubkey.text = generatedWallet.publicKey;
|
||||||
|
return WillPopScope(
|
||||||
|
onWillPop: () {
|
||||||
|
_generateWalletProvider.isAskedWordValid = false;
|
||||||
|
_generateWalletProvider.askedWordColor = Colors.black;
|
||||||
|
return Future<bool>.value(true);
|
||||||
|
},
|
||||||
|
child: Scaffold(
|
||||||
|
resizeToAvoidBottomInset: false,
|
||||||
|
appBar: AppBar(
|
||||||
|
leading: IconButton(
|
||||||
|
icon: Icon(Icons.arrow_back, color: Colors.black),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
_generateWalletProvider.isAskedWordValid = false;
|
||||||
|
_generateWalletProvider.askedWordColor = Colors.black;
|
||||||
|
}),
|
||||||
|
title: SizedBox(
|
||||||
|
height: 22,
|
||||||
|
child: Text('Confirmez ce portefeuille'),
|
||||||
|
)),
|
||||||
|
body: Center(
|
||||||
|
child: Column(children: <Widget>[
|
||||||
|
SizedBox(height: 15),
|
||||||
|
Text(
|
||||||
|
'Votre clé publique est :',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 17.0,
|
||||||
|
color: Colors.grey[600],
|
||||||
|
fontWeight: FontWeight.w400),
|
||||||
|
),
|
||||||
|
TextField(
|
||||||
|
enabled: false,
|
||||||
|
controller: this._pubkey,
|
||||||
|
maxLines: 1,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
decoration: InputDecoration(),
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14.0,
|
||||||
|
color: Colors.black,
|
||||||
|
fontWeight: FontWeight.bold)),
|
||||||
|
SizedBox(height: 12),
|
||||||
|
Text(
|
||||||
|
'Quel est le ${_generateWalletProvider.nbrWord + 1}ème mot de votre phrase de restauration ?',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 17.0,
|
||||||
|
color: Colors.grey[600],
|
||||||
|
fontWeight: FontWeight.w400),
|
||||||
|
),
|
||||||
|
TextFormField(
|
||||||
|
focusNode: _wordFocus,
|
||||||
|
autofocus: true,
|
||||||
|
enabled: !_generateWalletProvider.isAskedWordValid,
|
||||||
|
controller: this._inputRestoreWord,
|
||||||
|
textInputAction: TextInputAction.next,
|
||||||
|
onChanged: (value) {
|
||||||
|
_generateWalletProvider.checkAskedWord(
|
||||||
|
value, _mnemonicController.text);
|
||||||
|
},
|
||||||
|
maxLines: 1,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
decoration: InputDecoration(),
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 30.0,
|
||||||
|
color: _generateWalletProvider.askedWordColor,
|
||||||
|
fontWeight: FontWeight.w500)),
|
||||||
|
SizedBox(height: 12),
|
||||||
|
Text(
|
||||||
|
'Choisissez un nom pour votre portefeuille :',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 17.0,
|
||||||
|
color: Colors.grey[600],
|
||||||
|
fontWeight: FontWeight.w400),
|
||||||
|
),
|
||||||
|
TextFormField(
|
||||||
|
focusNode: _generateWalletProvider.walletNameFocus,
|
||||||
|
inputFormatters: [
|
||||||
|
FilteringTextInputFormatter.allow(
|
||||||
|
RegExp('[A-Za-z|0-9|\\-|_| ]')),
|
||||||
|
],
|
||||||
|
controller: this.walletName,
|
||||||
|
textInputAction: TextInputAction.next,
|
||||||
|
onChanged: (v) {
|
||||||
|
_generateWalletProvider.nameChanged();
|
||||||
|
},
|
||||||
|
maxLines: 1,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
decoration: InputDecoration(),
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 30.0,
|
||||||
|
color: Colors.black,
|
||||||
|
fontWeight: FontWeight.w500)),
|
||||||
|
Expanded(
|
||||||
|
child: Align(
|
||||||
|
alignment: Alignment.bottomCenter,
|
||||||
|
child: SizedBox(
|
||||||
|
width: 200,
|
||||||
|
height: 50,
|
||||||
|
child: ElevatedButton(
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
elevation: 12,
|
||||||
|
primary: Colors.green[
|
||||||
|
400], //Color(0xffFFD68E), // background
|
||||||
|
onPrimary: Colors.black, // foreground
|
||||||
|
),
|
||||||
|
onPressed: (_generateWalletProvider
|
||||||
|
.isAskedWordValid &&
|
||||||
|
this.walletName.text != '')
|
||||||
|
? () async {
|
||||||
|
await _generateWalletProvider.storeWallet(
|
||||||
|
generatedWallet,
|
||||||
|
walletName.text,
|
||||||
|
context);
|
||||||
|
_generateWalletProvider.isAskedWordValid =
|
||||||
|
false;
|
||||||
|
_generateWalletProvider.askedWordColor =
|
||||||
|
Colors.black;
|
||||||
|
WidgetsBinding.instance
|
||||||
|
.addPostFrameCallback((_) {
|
||||||
|
_myWalletProvider.listWallets =
|
||||||
|
_myWalletProvider
|
||||||
|
.getAllWalletsNames();
|
||||||
|
_myWalletProvider.rebuildWidget();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
child: Text('Confirmer',
|
||||||
|
style: TextStyle(fontSize: 28))),
|
||||||
|
))),
|
||||||
|
SizedBox(height: 70),
|
||||||
|
Text('TRICHE PENDANT ALPHA: ' + this._mnemonicController.text,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 10.0,
|
||||||
|
color: Colors.black,
|
||||||
|
fontWeight: FontWeight.normal)),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,201 @@
|
||||||
|
import 'package:gecko/models/generateWallets.dart';
|
||||||
|
import 'package:gecko/screens/myWallets/confirmWalletStorage.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:printing/printing.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:super_tooltip/super_tooltip.dart';
|
||||||
|
|
||||||
|
// ignore: must_be_immutable
|
||||||
|
class GenerateWalletsScreen extends StatelessWidget {
|
||||||
|
SuperTooltip tooltip;
|
||||||
|
bool hasError = false;
|
||||||
|
String validPin = 'NO PIN';
|
||||||
|
String currentText = "";
|
||||||
|
var pinColor = Colors.grey[300];
|
||||||
|
|
||||||
|
GlobalKey _toolTipPubkey = GlobalKey();
|
||||||
|
GlobalKey _toolTipSentence = GlobalKey();
|
||||||
|
GlobalKey _toolTipSecret = GlobalKey();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
GenerateWalletsProvider _generateWalletProvider =
|
||||||
|
Provider.of<GenerateWalletsProvider>(context);
|
||||||
|
_generateWalletProvider.generateMnemonic();
|
||||||
|
print('IS GENERATED ? : ' +
|
||||||
|
_generateWalletProvider.walletIsGenerated.toString());
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: SizedBox(
|
||||||
|
height: 22,
|
||||||
|
child: Text('Générer un portefeuille'),
|
||||||
|
)),
|
||||||
|
floatingActionButton: Container(
|
||||||
|
height: 80.0,
|
||||||
|
width: 80.0,
|
||||||
|
child: FittedBox(
|
||||||
|
child: FloatingActionButton(
|
||||||
|
heroTag: "buttonGenerateWallet",
|
||||||
|
onPressed: () => _generateWalletProvider.generateMnemonic(),
|
||||||
|
child: Container(
|
||||||
|
height: 40.0,
|
||||||
|
width: 40.0,
|
||||||
|
child: Icon(Icons.replay, color: Colors.grey[850]),
|
||||||
|
),
|
||||||
|
backgroundColor: Color(
|
||||||
|
0xffEFEFBF), //Color(0xffFFD68E), //Color.fromARGB(500, 204, 255, 255),
|
||||||
|
))),
|
||||||
|
body: SafeArea(
|
||||||
|
child: Column(children: <Widget>[
|
||||||
|
SizedBox(height: 20),
|
||||||
|
toolTips(_toolTipPubkey, 'Clé publique:',
|
||||||
|
"C'est votre RIB en Ğ1, les gens l'utiliseront pour vous payer"),
|
||||||
|
TextField(
|
||||||
|
enabled: false,
|
||||||
|
controller: _generateWalletProvider.pubkey,
|
||||||
|
maxLines: 1,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
decoration: InputDecoration(),
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14.0,
|
||||||
|
color: Colors.black,
|
||||||
|
fontWeight: FontWeight.bold)),
|
||||||
|
SizedBox(height: 8),
|
||||||
|
toolTips(_toolTipSentence, 'Phrase de restauration:',
|
||||||
|
"Notez et gardez cette phrase précieusement sur un papier, elle vous servira à restaurer votre portefeuille sur un autre appareil"),
|
||||||
|
TextField(
|
||||||
|
enabled: false,
|
||||||
|
controller: _generateWalletProvider.mnemonicController,
|
||||||
|
maxLines: 3,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
contentPadding: EdgeInsets.all(15.0),
|
||||||
|
),
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 22.0,
|
||||||
|
color: Colors.black,
|
||||||
|
fontWeight: FontWeight.w400)),
|
||||||
|
SizedBox(height: 8),
|
||||||
|
toolTips(_toolTipSecret, 'Code secret:',
|
||||||
|
"Retenez bien votre code secret, il vous sera demandé à chaque paiement, ainsi que pour configurer votre portefeuille"),
|
||||||
|
Container(
|
||||||
|
child: Stack(
|
||||||
|
alignment: Alignment.centerRight,
|
||||||
|
children: <Widget>[
|
||||||
|
TextField(
|
||||||
|
enabled: false,
|
||||||
|
controller: _generateWalletProvider.pin,
|
||||||
|
maxLines: 1,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
decoration: InputDecoration(),
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 30.0,
|
||||||
|
color: Colors.black,
|
||||||
|
fontWeight: FontWeight.bold)),
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.replay),
|
||||||
|
color: Color(0xffD28928),
|
||||||
|
onPressed: () {
|
||||||
|
_generateWalletProvider.changePinCode();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 20),
|
||||||
|
new ElevatedButton(
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
primary: Color(0xffFFD68E), // background
|
||||||
|
onPrimary: Colors.black, // foreground
|
||||||
|
),
|
||||||
|
onPressed: _generateWalletProvider.walletIsGenerated
|
||||||
|
? () {
|
||||||
|
_generateWalletProvider.nbrWord =
|
||||||
|
_generateWalletProvider.getRandomInt();
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(builder: (context) {
|
||||||
|
return ConfirmStoreWallet(
|
||||||
|
generatedMnemonic:
|
||||||
|
_generateWalletProvider.generatedMnemonic,
|
||||||
|
generatedWallet:
|
||||||
|
_generateWalletProvider.actualWallet);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
child: Text('Enregistrer ce portefeuille',
|
||||||
|
style: TextStyle(fontSize: 20))),
|
||||||
|
SizedBox(height: 20),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(builder: (context) {
|
||||||
|
return PrintWallet(
|
||||||
|
_generateWalletProvider.generatedMnemonic,
|
||||||
|
_generateWalletProvider.actualWallet.publicKey);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: Icon(Icons.print))
|
||||||
|
]),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget toolTips(_key, _text, _message) {
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
final dynamic _toolTip = _key.currentState;
|
||||||
|
_toolTip.ensureTooltipVisible();
|
||||||
|
},
|
||||||
|
child: Tooltip(
|
||||||
|
padding: EdgeInsets.all(10),
|
||||||
|
key: _key,
|
||||||
|
showDuration: Duration(seconds: 5),
|
||||||
|
message: _message,
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
Column(children: <Widget>[
|
||||||
|
SizedBox(
|
||||||
|
width: 30,
|
||||||
|
height: 25,
|
||||||
|
child: Icon(Icons.info_outline,
|
||||||
|
size: 22, color: Color(0xffD28928))),
|
||||||
|
SizedBox(height: 1)
|
||||||
|
]),
|
||||||
|
Text(
|
||||||
|
_text,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 15.0,
|
||||||
|
color: Colors.grey[600],
|
||||||
|
fontWeight: FontWeight.w400),
|
||||||
|
),
|
||||||
|
SizedBox(width: 45)
|
||||||
|
])));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ignore: must_be_immutable
|
||||||
|
class PrintWallet extends StatelessWidget {
|
||||||
|
PrintWallet(this.sentence, this.pubkey);
|
||||||
|
|
||||||
|
final String sentence;
|
||||||
|
final String pubkey;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
GenerateWalletsProvider _generateWalletProvider =
|
||||||
|
Provider.of<GenerateWalletsProvider>(context);
|
||||||
|
return MaterialApp(
|
||||||
|
home: Scaffold(
|
||||||
|
appBar: AppBar(title: Text('Imprimer ce portefeuille')),
|
||||||
|
body: PdfPreview(
|
||||||
|
build: (format) =>
|
||||||
|
_generateWalletProvider.printWallet(sentence, pubkey),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,252 @@
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:dubp/dubp.dart';
|
||||||
|
import 'package:gecko/models/myWallets.dart';
|
||||||
|
import 'package:gecko/models/walletOptions.dart';
|
||||||
|
import 'package:gecko/screens/myWallets/changePin.dart';
|
||||||
|
import 'dart:async';
|
||||||
|
import 'package:pin_code_fields/pin_code_fields.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
// ignore: must_be_immutable
|
||||||
|
class WalletOptions extends StatelessWidget with ChangeNotifier {
|
||||||
|
WalletOptions({Key keyMyWallets, @required this.walletName})
|
||||||
|
: super(key: keyMyWallets);
|
||||||
|
String walletName;
|
||||||
|
|
||||||
|
StreamController<ErrorAnimationType> errorController;
|
||||||
|
TextEditingController _enterPin = new TextEditingController();
|
||||||
|
final formKey = GlobalKey<FormState>();
|
||||||
|
bool hasError = false;
|
||||||
|
var pinColor = Color(0xffF9F9F1);
|
||||||
|
var walletPin = '';
|
||||||
|
|
||||||
|
Future<NewWallet> get badWallet => null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
print("Build walletOptions");
|
||||||
|
WalletOptionsProvider _walletOptions =
|
||||||
|
Provider.of<WalletOptionsProvider>(context);
|
||||||
|
MyWalletsProvider _myWalletProvider =
|
||||||
|
Provider.of<MyWalletsProvider>(context);
|
||||||
|
errorController = StreamController<ErrorAnimationType>();
|
||||||
|
// _walletOptions.isWalletUnlock = false;
|
||||||
|
return WillPopScope(
|
||||||
|
onWillPop: () {
|
||||||
|
_walletOptions.isWalletUnlock = false;
|
||||||
|
return Future<bool>.value(true);
|
||||||
|
},
|
||||||
|
child: Scaffold(
|
||||||
|
resizeToAvoidBottomInset: false,
|
||||||
|
appBar: AppBar(
|
||||||
|
leading: IconButton(
|
||||||
|
icon: Icon(Icons.arrow_back, color: Colors.black),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
_walletOptions.isWalletUnlock = false;
|
||||||
|
}),
|
||||||
|
title: SizedBox(
|
||||||
|
height: 22,
|
||||||
|
child: Text(walletName),
|
||||||
|
)),
|
||||||
|
body: Center(
|
||||||
|
child: SafeArea(
|
||||||
|
child: Column(children: <Widget>[
|
||||||
|
Visibility(
|
||||||
|
visible: _walletOptions.isWalletUnlock,
|
||||||
|
child: Expanded(
|
||||||
|
child: Column(children: <Widget>[
|
||||||
|
SizedBox(height: 15),
|
||||||
|
Text(
|
||||||
|
'Clé publique:',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 15.0,
|
||||||
|
color: Colors.grey[600],
|
||||||
|
fontWeight: FontWeight.w400),
|
||||||
|
),
|
||||||
|
SizedBox(height: 15),
|
||||||
|
Text(
|
||||||
|
_walletOptions.pubkey.text,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14.0,
|
||||||
|
color: Colors.black,
|
||||||
|
fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Align(
|
||||||
|
alignment: Alignment.bottomCenter,
|
||||||
|
child: SizedBox(
|
||||||
|
height: 50,
|
||||||
|
width: 300,
|
||||||
|
child: ElevatedButton(
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
elevation: 5,
|
||||||
|
primary: Color(
|
||||||
|
0xffFFD68E), //Color(0xffFFD68E), // background
|
||||||
|
onPrimary: Colors.black, // foreground
|
||||||
|
),
|
||||||
|
onPressed: () => _walletOptions
|
||||||
|
.renameWalletAlerte(
|
||||||
|
context, walletName)
|
||||||
|
.then((_result) {
|
||||||
|
if (_result == true) {
|
||||||
|
WidgetsBinding.instance
|
||||||
|
.addPostFrameCallback((_) {
|
||||||
|
_myWalletProvider.listWallets =
|
||||||
|
_myWalletProvider
|
||||||
|
.getAllWalletsNames();
|
||||||
|
_myWalletProvider.rebuildWidget();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
child: Text('Renommer ce portefeuille',
|
||||||
|
style: TextStyle(fontSize: 20)))))),
|
||||||
|
SizedBox(height: 30),
|
||||||
|
SizedBox(
|
||||||
|
height: 50,
|
||||||
|
width: 300,
|
||||||
|
child: ElevatedButton(
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
elevation: 5,
|
||||||
|
primary: Color(
|
||||||
|
0xffFFD68E), //Color(0xffFFD68E), // background
|
||||||
|
onPrimary: Colors.black, // foreground
|
||||||
|
),
|
||||||
|
onPressed: () {
|
||||||
|
// changePin(widget.walletName, this.walletPin);
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(builder: (context) {
|
||||||
|
return ChangePinScreen(
|
||||||
|
walletName: walletName,
|
||||||
|
oldPin: this.walletPin);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: Text('Changer mon code secret',
|
||||||
|
style: TextStyle(fontSize: 20)))),
|
||||||
|
SizedBox(height: 30),
|
||||||
|
SizedBox(
|
||||||
|
height: 50,
|
||||||
|
width: 300,
|
||||||
|
child: ElevatedButton(
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
elevation: 6,
|
||||||
|
primary: Colors
|
||||||
|
.redAccent, //Color(0xffFFD68E), // background
|
||||||
|
onPrimary: Colors.black, // foreground
|
||||||
|
),
|
||||||
|
onPressed: () async {
|
||||||
|
await _walletOptions.deleteWallet(
|
||||||
|
context, walletName);
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
_myWalletProvider.listWallets =
|
||||||
|
_myWalletProvider.getAllWalletsNames();
|
||||||
|
_myWalletProvider.rebuildWidget();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Text('Supprimer ce portefeuille',
|
||||||
|
style: TextStyle(fontSize: 20)))),
|
||||||
|
SizedBox(height: 50),
|
||||||
|
Text(
|
||||||
|
'Portefeuille déverrouillé',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.green,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
fontSize: 15),
|
||||||
|
),
|
||||||
|
SizedBox(height: 10)
|
||||||
|
]))),
|
||||||
|
Visibility(
|
||||||
|
visible: !_walletOptions.isWalletUnlock,
|
||||||
|
child: Expanded(
|
||||||
|
child: Column(children: <Widget>[
|
||||||
|
SizedBox(height: 80),
|
||||||
|
Text(
|
||||||
|
'Veuillez tapper votre code secret pour dévérouiller votre portefeuille.',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 15.0,
|
||||||
|
color: Colors.black,
|
||||||
|
fontWeight: FontWeight.w400),
|
||||||
|
),
|
||||||
|
SizedBox(height: 50),
|
||||||
|
Form(
|
||||||
|
key: formKey,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 8.0, horizontal: 30),
|
||||||
|
child: PinCodeTextField(
|
||||||
|
autoFocus: true,
|
||||||
|
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: (_pin) async {
|
||||||
|
print("Completed");
|
||||||
|
final resultWallet =
|
||||||
|
await _walletOptions.readLocalWallet(
|
||||||
|
this.walletName, _pin.toUpperCase());
|
||||||
|
if (resultWallet == 'bad') {
|
||||||
|
errorController.add(ErrorAnimationType
|
||||||
|
.shake); // Triggering error shake animation
|
||||||
|
hasError = true;
|
||||||
|
pinColor = Colors.red[200];
|
||||||
|
notifyListeners();
|
||||||
|
} else {
|
||||||
|
pinColor = Colors.green[200];
|
||||||
|
// setState(() {});
|
||||||
|
// await Future.delayed(Duration(milliseconds: 50));
|
||||||
|
this.walletPin = _pin.toUpperCase();
|
||||||
|
// isWalletUnlock = true;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onChanged: (value) {
|
||||||
|
if (pinColor != Color(0xffF9F9F1)) {
|
||||||
|
pinColor = Color(0xffF9F9F1);
|
||||||
|
}
|
||||||
|
print(value);
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
]))),
|
||||||
|
])))));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,124 @@
|
||||||
|
import 'package:gecko/models/myWallets.dart';
|
||||||
|
import 'package:gecko/models/walletOptions.dart';
|
||||||
|
import 'package:gecko/screens/myWallets/generateWallets.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:gecko/screens/myWallets/walletOptions.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
// ignore: must_be_immutable
|
||||||
|
class WalletsHome extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
MyWalletsProvider myWalletProvider =
|
||||||
|
Provider.of<MyWalletsProvider>(context);
|
||||||
|
WalletOptionsProvider _walletOptions =
|
||||||
|
Provider.of<WalletOptionsProvider>(context);
|
||||||
|
print('BUILD: WalletsHome');
|
||||||
|
_walletOptions.isWalletUnlock = false;
|
||||||
|
myWalletProvider.listWallets = myWalletProvider.getAllWalletsNames();
|
||||||
|
final bool isWalletsExists = myWalletProvider.checkIfWalletExist();
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
floatingActionButton: Visibility(
|
||||||
|
visible: (isWalletsExists),
|
||||||
|
child: Container(
|
||||||
|
height: 80.0,
|
||||||
|
width: 80.0,
|
||||||
|
child: FittedBox(
|
||||||
|
child: FloatingActionButton(
|
||||||
|
heroTag: "buttonGenerateWallet",
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(builder: (context) {
|
||||||
|
return GenerateWalletsScreen();
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
height: 40.0,
|
||||||
|
width: 40.0,
|
||||||
|
child: Icon(Icons.person_add_alt_1_rounded,
|
||||||
|
color: Colors.grey[850])),
|
||||||
|
backgroundColor: Color(0xffEFEFBF))))),
|
||||||
|
body: SafeArea(
|
||||||
|
child: Column(children: <Widget>[
|
||||||
|
Visibility(
|
||||||
|
visible: (!isWalletsExists),
|
||||||
|
child: Column(children: <Widget>[
|
||||||
|
SizedBox(height: 120),
|
||||||
|
Center(
|
||||||
|
child: Text("Vous n'avez encore généré aucun portefeuille.",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 20, fontWeight: FontWeight.w500),
|
||||||
|
textAlign: TextAlign.center)),
|
||||||
|
SizedBox(height: 80),
|
||||||
|
ElevatedButton(
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
primary: Color(0xffFFD68E), // background
|
||||||
|
onPrimary: Colors.black, // foreground
|
||||||
|
),
|
||||||
|
onPressed: () => Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(builder: (context) {
|
||||||
|
return GenerateWalletsScreen();
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
child: Text('Générer un portefeuille',
|
||||||
|
style: TextStyle(fontSize: 20))),
|
||||||
|
SizedBox(height: 15),
|
||||||
|
Center(
|
||||||
|
child: Text("ou",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 20, fontWeight: FontWeight.w500),
|
||||||
|
textAlign: TextAlign.center)),
|
||||||
|
SizedBox(height: 15),
|
||||||
|
ElevatedButton(
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
primary: Color(0xffFFD68E), // background
|
||||||
|
onPrimary: Colors.black, // foreground
|
||||||
|
),
|
||||||
|
onPressed: () => myWalletProvider.importWallet(),
|
||||||
|
child: Text('Importer un portefeuille existant',
|
||||||
|
style: TextStyle(fontSize: 20))),
|
||||||
|
])),
|
||||||
|
Visibility(visible: isWalletsExists, child: myWalletsList(context))
|
||||||
|
])));
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget myWalletsList(BuildContext context) {
|
||||||
|
MyWalletsProvider myWalletProvider =
|
||||||
|
Provider.of<MyWalletsProvider>(context);
|
||||||
|
|
||||||
|
// TODO: Show history of my wallets
|
||||||
|
// HistoryProvider _historyProvider = Provider.of<HistoryProvider>(context);
|
||||||
|
// Map _balance = Map();
|
||||||
|
|
||||||
|
List _listWallets = [];
|
||||||
|
myWalletProvider.listWallets.forEach((_name, _pubkey) {
|
||||||
|
_listWallets.add(_name);
|
||||||
|
// _balance[_name] = _historyProvider.getBalance(_pubkey).toString();
|
||||||
|
print(_name + _pubkey);
|
||||||
|
});
|
||||||
|
|
||||||
|
return Column(children: <Widget>[
|
||||||
|
SizedBox(height: 8),
|
||||||
|
for (String _repository in _listWallets)
|
||||||
|
ListTile(
|
||||||
|
contentPadding: const EdgeInsets.all(5.0),
|
||||||
|
leading: Padding(
|
||||||
|
padding: const EdgeInsets.all(15.0),
|
||||||
|
child: Text("0 Ğ1", style: TextStyle(fontSize: 14.0))),
|
||||||
|
title: Text(_repository, style: TextStyle(fontSize: 16.0)),
|
||||||
|
subtitle: Text(myWalletProvider.listWallets[_repository],
|
||||||
|
style: TextStyle(fontSize: 11.0)),
|
||||||
|
dense: true,
|
||||||
|
onTap: () {
|
||||||
|
Navigator.push(context, MaterialPageRoute(builder: (context) {
|
||||||
|
return WalletOptions(walletName: _repository);
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:dubp/dubp.dart';
|
||||||
|
import 'package:gecko/models/myWallets.dart';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
// ignore: must_be_immutable
|
||||||
|
class SettingsScreen extends StatelessWidget {
|
||||||
|
String generatedMnemonic;
|
||||||
|
bool walletIsGenerated = false;
|
||||||
|
NewWallet actualWallet;
|
||||||
|
String newWalletName;
|
||||||
|
|
||||||
|
bool hasError = false;
|
||||||
|
String validPin = 'NO PIN';
|
||||||
|
String currentText = "";
|
||||||
|
var pinColor = Colors.grey[300];
|
||||||
|
Directory appPath;
|
||||||
|
|
||||||
|
MyWalletsProvider _myWallets = MyWalletsProvider();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
// getAppDirectory();
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: SizedBox(
|
||||||
|
height: 22,
|
||||||
|
child: Text('Paramètres'),
|
||||||
|
)),
|
||||||
|
body: Column(children: <Widget>[
|
||||||
|
SizedBox(height: 20),
|
||||||
|
Expanded(
|
||||||
|
child: Align(
|
||||||
|
alignment: Alignment.bottomCenter,
|
||||||
|
child: SizedBox(
|
||||||
|
height: 100,
|
||||||
|
width: 1000,
|
||||||
|
child: ElevatedButton(
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
elevation: 5,
|
||||||
|
primary: Colors
|
||||||
|
.redAccent, //Color(0xffFFD68E), // background
|
||||||
|
onPrimary: Colors.black, // foreground
|
||||||
|
),
|
||||||
|
onPressed: () => {
|
||||||
|
print('Suppression de tous les wallets'),
|
||||||
|
_myWallets.deleteAllWallet(context)
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
"EFFACER TOUS MES PORTEFEUILLES, LE TEMPS DE L'ALPHA",
|
||||||
|
style: TextStyle(fontSize: 20)))))),
|
||||||
|
SizedBox(height: 50),
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,311 +0,0 @@
|
||||||
import 'package:gecko/parsingGVA.dart';
|
|
||||||
import 'package:gecko/query.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:qrscan/qrscan.dart' as scanner;
|
|
||||||
import 'dart:async';
|
|
||||||
import 'dart:typed_data';
|
|
||||||
import 'dart:ui';
|
|
||||||
import 'package:graphql_flutter/graphql_flutter.dart';
|
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
|
||||||
import 'package:sentry/sentry.dart' as sentry;
|
|
||||||
import 'package:truncate/truncate.dart';
|
|
||||||
|
|
||||||
//ignore: must_be_immutable
|
|
||||||
class HistoryScreen extends StatefulWidget {
|
|
||||||
const HistoryScreen({Key keyHistory}) : super(key: keyHistory);
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<StatefulWidget> createState() => HistoryScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class HistoryScreenState extends State<HistoryScreen> {
|
|
||||||
Widget currentScreen;
|
|
||||||
|
|
||||||
Uint8List bytes = Uint8List(0);
|
|
||||||
final TextEditingController _outputPubkey = new TextEditingController();
|
|
||||||
final nRepositories = 20;
|
|
||||||
|
|
||||||
// String pubkey = 'D2meevcAHFTS2gQMvmRW5Hzi25jDdikk4nC4u1FkwRaU'; // For debug
|
|
||||||
String pubkey = '';
|
|
||||||
bool isBuilding = true;
|
|
||||||
ScrollController _scrollController = new ScrollController();
|
|
||||||
|
|
||||||
_scrollListener() {
|
|
||||||
if (_scrollController.offset >=
|
|
||||||
_scrollController.position.maxScrollExtent &&
|
|
||||||
!_scrollController.position.outOfRange) {
|
|
||||||
setState(() {
|
|
||||||
print("reach the bottom");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_scrollController = ScrollController();
|
|
||||||
_scrollController.addListener(_scrollListener);
|
|
||||||
|
|
||||||
// _scrollController
|
|
||||||
// ..addListener(() {
|
|
||||||
// if (_scrollController.position.pixels ==
|
|
||||||
// _scrollController.position.maxScrollExtent) {
|
|
||||||
// // print(
|
|
||||||
// // "DEBUG H fetchMoreCursor in scrollController: $fetchMoreCursor");
|
|
||||||
// fetchMore(opts);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
print('Build pubkey : ' + pubkey);
|
|
||||||
print('Build this.pubkey : ' + this.pubkey);
|
|
||||||
print('isBuilding: ' + isBuilding.toString());
|
|
||||||
return Scaffold(
|
|
||||||
floatingActionButton: Container(
|
|
||||||
height: 80.0,
|
|
||||||
width: 80.0,
|
|
||||||
child: FittedBox(
|
|
||||||
child: FloatingActionButton(
|
|
||||||
heroTag: "buttonScan",
|
|
||||||
onPressed: () async {
|
|
||||||
await scan();
|
|
||||||
// print(resultScan);
|
|
||||||
// if (resultScan != 'false') {
|
|
||||||
// onTabTapped(0);
|
|
||||||
// }
|
|
||||||
},
|
|
||||||
child: Container(
|
|
||||||
height: 40.0,
|
|
||||||
width: 40.0,
|
|
||||||
child: Image.asset('images/scanner.png')),
|
|
||||||
backgroundColor: Color(
|
|
||||||
0xffEFEFBF), //Color(0xffFFD68E), //Color.fromARGB(500, 204, 255, 255),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
body: Column(children: <Widget>[
|
|
||||||
SizedBox(height: 8),
|
|
||||||
TextField(
|
|
||||||
// Entrée de la pubkey
|
|
||||||
onChanged: (text) {
|
|
||||||
print("Clé tappxé: $text");
|
|
||||||
this.pubkey = text;
|
|
||||||
isPubkey(text);
|
|
||||||
},
|
|
||||||
controller: this._outputPubkey,
|
|
||||||
maxLines: 1,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
hintText: 'Tappez/Collez une clé publique, ou scannez',
|
|
||||||
hintStyle: TextStyle(fontSize: 14),
|
|
||||||
contentPadding:
|
|
||||||
EdgeInsets.symmetric(horizontal: 7, vertical: 15),
|
|
||||||
border: InputBorder.none,
|
|
||||||
focusedBorder: InputBorder.none,
|
|
||||||
enabledBorder: InputBorder.none,
|
|
||||||
errorBorder: InputBorder.none,
|
|
||||||
disabledBorder: InputBorder.none,
|
|
||||||
),
|
|
||||||
style: TextStyle(fontSize: 14.0, fontWeight: FontWeight.bold)),
|
|
||||||
if (this.pubkey != '') historyQuery(),
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
|
|
||||||
historyQuery() {
|
|
||||||
return Expanded(
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
mainAxisSize: MainAxisSize.max,
|
|
||||||
children: <Widget>[
|
|
||||||
Query(
|
|
||||||
options: QueryOptions(
|
|
||||||
document: gql(getHistory),
|
|
||||||
variables: <String, dynamic>{
|
|
||||||
'pubkey': this.pubkey,
|
|
||||||
'number': nRepositories,
|
|
||||||
// set cursor to null so as to start at the beginning
|
|
||||||
'cursor': null
|
|
||||||
},
|
|
||||||
),
|
|
||||||
builder: (QueryResult result, {refetch, FetchMore fetchMore}) {
|
|
||||||
if (result.isLoading && result.data == null) {
|
|
||||||
return const Center(
|
|
||||||
child: CircularProgressIndicator(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result.hasException) {
|
|
||||||
print('Error GVA: ' + result.exception.toString());
|
|
||||||
return Column(children: <Widget>[
|
|
||||||
SizedBox(height: 50),
|
|
||||||
Text(
|
|
||||||
"Aucun noeud GVA valide n'a pu être trouvé.\nVeuillez réessayer ultérieurement.",
|
|
||||||
style: TextStyle(fontSize: 17.0),
|
|
||||||
)
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result.data == null && result.exception.toString() == null) {
|
|
||||||
return const Text('Aucune donnée à afficher.');
|
|
||||||
}
|
|
||||||
|
|
||||||
final List<dynamic> blockchainTX =
|
|
||||||
(result.data['txsHistoryBc']['both']['edges'] as List<dynamic>);
|
|
||||||
|
|
||||||
final Map pageInfo =
|
|
||||||
result.data['txsHistoryBc']['both']['pageInfo'];
|
|
||||||
|
|
||||||
final String fetchMoreCursor = pageInfo['endCursor'];
|
|
||||||
|
|
||||||
final num balance =
|
|
||||||
removeDecimalZero(result.data['balance']['amount'] / 100);
|
|
||||||
|
|
||||||
FetchMoreOptions opts = FetchMoreOptions(
|
|
||||||
variables: {'cursor': fetchMoreCursor},
|
|
||||||
updateQuery: (previousResultData, fetchMoreResultData) {
|
|
||||||
final List<dynamic> repos = [
|
|
||||||
...previousResultData['txsHistoryBc']['both']['edges']
|
|
||||||
as List<dynamic>,
|
|
||||||
...fetchMoreResultData['txsHistoryBc']['both']['edges']
|
|
||||||
as List<dynamic>
|
|
||||||
];
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
print(
|
|
||||||
"###### DEBUG H Parse blockchainTX list. Cursor: $fetchMoreCursor ######");
|
|
||||||
List _transBC = parseHistory(blockchainTX);
|
|
||||||
|
|
||||||
// Build history list
|
|
||||||
return Expanded(
|
|
||||||
child: ListView(
|
|
||||||
controller: _scrollController,
|
|
||||||
children: <Widget>[
|
|
||||||
SizedBox(height: 7),
|
|
||||||
if (this.pubkey != '')
|
|
||||||
Text(balance.toString() + ' Ğ1',
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: TextStyle(fontSize: 30.0)),
|
|
||||||
SizedBox(height: 12),
|
|
||||||
for (var repository in _transBC)
|
|
||||||
ListTile(
|
|
||||||
contentPadding: const EdgeInsets.all(5.0),
|
|
||||||
leading:
|
|
||||||
Text(repository[3], style: TextStyle(fontSize: 14.0)),
|
|
||||||
title: Text(
|
|
||||||
repository[1].toString() +
|
|
||||||
'\n' +
|
|
||||||
truncate(repository[2], 17,
|
|
||||||
omission: "...",
|
|
||||||
position: TruncatePosition.end),
|
|
||||||
style: TextStyle(fontSize: 14.0)),
|
|
||||||
subtitle:
|
|
||||||
Text(repository[5], style: TextStyle(fontSize: 14.0)),
|
|
||||||
dense: true,
|
|
||||||
onTap: () {
|
|
||||||
isPubkey(repository[2]);
|
|
||||||
}),
|
|
||||||
if (result.isLoading)
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: <Widget>[
|
|
||||||
CircularProgressIndicator(),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
));
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
Future scan() async {
|
|
||||||
await Permission.camera.request();
|
|
||||||
String barcode;
|
|
||||||
try {
|
|
||||||
barcode = await scanner.scan();
|
|
||||||
} catch (e, stack) {
|
|
||||||
print(e);
|
|
||||||
if (kReleaseMode) {
|
|
||||||
await sentry.Sentry.captureException(
|
|
||||||
e,
|
|
||||||
stackTrace: stack,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return 'false';
|
|
||||||
}
|
|
||||||
// this._outputPubkey.text = "";
|
|
||||||
if (barcode != null) {
|
|
||||||
this._outputPubkey.text = barcode;
|
|
||||||
isPubkey(barcode);
|
|
||||||
} else {
|
|
||||||
return 'false';
|
|
||||||
}
|
|
||||||
return barcode;
|
|
||||||
}
|
|
||||||
|
|
||||||
String isPubkey(pubkey) {
|
|
||||||
final RegExp regExp = new RegExp(
|
|
||||||
r'^[a-zA-Z0-9]+$',
|
|
||||||
caseSensitive: false,
|
|
||||||
multiLine: false,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (regExp.hasMatch(pubkey) == true &&
|
|
||||||
pubkey.length > 42 &&
|
|
||||||
pubkey.length < 45) {
|
|
||||||
print("C'est une pubkey !!!");
|
|
||||||
|
|
||||||
setState(() {
|
|
||||||
this.pubkey = pubkey;
|
|
||||||
this._outputPubkey.text = pubkey;
|
|
||||||
});
|
|
||||||
|
|
||||||
// setState(() {
|
|
||||||
// this._outputBalance.text = balance.toString();
|
|
||||||
// });
|
|
||||||
|
|
||||||
return pubkey;
|
|
||||||
}
|
|
||||||
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
num removeDecimalZero(double n) {
|
|
||||||
String result = n.toStringAsFixed(n.truncateToDouble() == n ? 0 : 1);
|
|
||||||
return num.parse(result);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,66 +0,0 @@
|
||||||
import 'package:gecko/ui/historyScreen.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'dart:typed_data';
|
|
||||||
import 'dart:ui';
|
|
||||||
import 'package:gecko/ui/myWallets/walletsHome.dart';
|
|
||||||
|
|
||||||
//ignore: must_be_immutable
|
|
||||||
class HomeScreen extends StatefulWidget {
|
|
||||||
HomeScreen({this.screens});
|
|
||||||
final List<Widget> screens;
|
|
||||||
|
|
||||||
@override
|
|
||||||
HomeScreenState createState() => HomeScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class HomeScreenState extends State<HomeScreen> {
|
|
||||||
GlobalKey<HistoryScreenState> _keyHistory = GlobalKey();
|
|
||||||
|
|
||||||
int currentIndex = 0;
|
|
||||||
Widget currentScreen;
|
|
||||||
|
|
||||||
void onTabTapped(int index) {
|
|
||||||
setState(() {
|
|
||||||
currentIndex = index;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Uint8List bytes = Uint8List(0);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
backgroundColor: Color(0xffF9F9F1),
|
|
||||||
body: SafeArea(
|
|
||||||
child: IndexedStack(
|
|
||||||
index: currentIndex,
|
|
||||||
children: <Widget>[
|
|
||||||
HistoryScreen(
|
|
||||||
keyHistory: _keyHistory,
|
|
||||||
),
|
|
||||||
WalletsHome(),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
bottomNavigationBar: BottomNavigationBar(
|
|
||||||
backgroundColor: Color(0xffFFD68E),
|
|
||||||
fixedColor: Color(0xff855F2D),
|
|
||||||
unselectedItemColor: Color(0xffBD935C),
|
|
||||||
type: BottomNavigationBarType.fixed,
|
|
||||||
onTap: onTabTapped,
|
|
||||||
currentIndex: currentIndex,
|
|
||||||
items: [
|
|
||||||
BottomNavigationBarItem(
|
|
||||||
icon: new Icon(Icons
|
|
||||||
.format_list_bulleted), //Icons.person_add_alt_1_rounded //Icons.lock
|
|
||||||
label: 'Accueil',
|
|
||||||
),
|
|
||||||
BottomNavigationBarItem(
|
|
||||||
icon: new Icon(Icons.lock),
|
|
||||||
label: 'Mes portefeuilles',
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,209 +0,0 @@
|
||||||
import 'dart:io';
|
|
||||||
import 'dart:math';
|
|
||||||
import 'package:dubp/dubp.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:path_provider/path_provider.dart';
|
|
||||||
|
|
||||||
class ConfirmStoreWallet extends StatefulWidget {
|
|
||||||
final String generatedMnemonic;
|
|
||||||
final NewWallet generatedWallet;
|
|
||||||
|
|
||||||
ConfirmStoreWallet(
|
|
||||||
{Key validationKey,
|
|
||||||
@required this.generatedMnemonic,
|
|
||||||
@required this.generatedWallet})
|
|
||||||
: super(key: validationKey);
|
|
||||||
|
|
||||||
@override
|
|
||||||
ConfirmStoreWalletState createState() => ConfirmStoreWalletState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class ConfirmStoreWalletState extends State<ConfirmStoreWallet> {
|
|
||||||
// GlobalKey<ValidStoreWalletState> _keyValidWallets = GlobalKey();
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
// DubpRust.setup();
|
|
||||||
this._mnemonicController.text = widget.generatedMnemonic;
|
|
||||||
this._pubkey.text = widget.generatedWallet.publicKey;
|
|
||||||
nbrWord = getRandomInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
TextEditingController _mnemonicController = new TextEditingController();
|
|
||||||
TextEditingController _pubkey = new TextEditingController();
|
|
||||||
TextEditingController _pin = new TextEditingController();
|
|
||||||
TextEditingController _inputRestoreWord = new TextEditingController();
|
|
||||||
TextEditingController walletName = new TextEditingController();
|
|
||||||
// List _listWallets = [];
|
|
||||||
int nbrWord;
|
|
||||||
bool isAskedWordValid = false;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
resizeToAvoidBottomInset: false,
|
|
||||||
appBar: AppBar(),
|
|
||||||
body: Center(
|
|
||||||
child: Column(children: <Widget>[
|
|
||||||
SizedBox(height: 15),
|
|
||||||
Text(
|
|
||||||
'Votre clé publique est :',
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 17.0,
|
|
||||||
color: Colors.grey[600],
|
|
||||||
fontWeight: FontWeight.w400),
|
|
||||||
),
|
|
||||||
TextField(
|
|
||||||
enabled: false,
|
|
||||||
controller: this._pubkey,
|
|
||||||
maxLines: 1,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
decoration: InputDecoration(),
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 14.0,
|
|
||||||
color: Colors.black,
|
|
||||||
fontWeight: FontWeight.bold)),
|
|
||||||
SizedBox(height: 12),
|
|
||||||
Text(
|
|
||||||
'Quel est le ${nbrWord + 1}ème mot de votre phrase de restauration ?',
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 17.0,
|
|
||||||
color: Colors.grey[600],
|
|
||||||
fontWeight: FontWeight.w400),
|
|
||||||
),
|
|
||||||
TextField(
|
|
||||||
enabled: !isAskedWordValid,
|
|
||||||
controller: this._inputRestoreWord,
|
|
||||||
onChanged: (value) {
|
|
||||||
checkAskedWord(value);
|
|
||||||
},
|
|
||||||
maxLines: 2,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
decoration: InputDecoration(),
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 30.0,
|
|
||||||
color: Colors.black,
|
|
||||||
fontWeight: FontWeight.w500)),
|
|
||||||
SizedBox(height: 12),
|
|
||||||
Text(
|
|
||||||
'Choisissez un nom pour votre portefeuille :',
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 17.0,
|
|
||||||
color: Colors.grey[600],
|
|
||||||
fontWeight: FontWeight.w400),
|
|
||||||
),
|
|
||||||
TextField(
|
|
||||||
enabled: isAskedWordValid,
|
|
||||||
controller: this.walletName,
|
|
||||||
onChanged: (v) {
|
|
||||||
nameChanged();
|
|
||||||
},
|
|
||||||
maxLines: 2,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
decoration: InputDecoration(),
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 30.0,
|
|
||||||
color: Colors.black,
|
|
||||||
fontWeight: FontWeight.w500)),
|
|
||||||
Expanded(
|
|
||||||
child: Align(
|
|
||||||
alignment: Alignment.bottomCenter,
|
|
||||||
child: SizedBox(
|
|
||||||
width: 200,
|
|
||||||
height: 50,
|
|
||||||
child: ElevatedButton(
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
elevation: 12,
|
|
||||||
primary: Colors
|
|
||||||
.green[400], //Color(0xffFFD68E), // background
|
|
||||||
onPrimary: Colors.black, // foreground
|
|
||||||
),
|
|
||||||
onPressed:
|
|
||||||
(isAskedWordValid && this.walletName.text != '')
|
|
||||||
? () => storeWallet()
|
|
||||||
: null,
|
|
||||||
child:
|
|
||||||
Text('Confirmer', style: TextStyle(fontSize: 28))),
|
|
||||||
))),
|
|
||||||
SizedBox(height: 70),
|
|
||||||
Text('TRICHE PENDANT ALPHA: ' + this._mnemonicController.text,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 10.0,
|
|
||||||
color: Colors.black,
|
|
||||||
fontWeight: FontWeight.normal)),
|
|
||||||
]),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future storeWallet() 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 isExist = await Directory('$appPath/wallets').exists();
|
|
||||||
if (isExist == false) {
|
|
||||||
new Directory('$appPath/wallets').createSync();
|
|
||||||
}
|
|
||||||
|
|
||||||
new Directory('$appPath/wallets/${this.walletName.text}').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;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<String> get _localPath async {
|
|
||||||
final directory = await getApplicationDocumentsDirectory();
|
|
||||||
return directory.path;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Future<List> 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) {
|
|
||||||
print('Word is OK');
|
|
||||||
isAskedWordValid = true;
|
|
||||||
} else {
|
|
||||||
isAskedWordValid = false;
|
|
||||||
}
|
|
||||||
setState(() {});
|
|
||||||
}
|
|
||||||
|
|
||||||
int getRandomInt() {
|
|
||||||
var rng = new Random();
|
|
||||||
return rng.nextInt(12);
|
|
||||||
}
|
|
||||||
|
|
||||||
void nameChanged() {
|
|
||||||
setState(() {});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,233 +0,0 @@
|
||||||
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:super_tooltip/super_tooltip.dart';
|
|
||||||
|
|
||||||
class GenerateWalletsScreen extends StatefulWidget {
|
|
||||||
const GenerateWalletsScreen({Key keyGenWallet}) : super(key: keyGenWallet);
|
|
||||||
@override
|
|
||||||
GenerateWalletsState createState() => GenerateWalletsState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class GenerateWalletsState extends State<GenerateWalletsScreen> {
|
|
||||||
// GlobalKey<MyWalletState> _keyMyWallets = GlobalKey();
|
|
||||||
// GlobalKey<ValidStoreWalletState> _keyValidWallets = GlobalKey();
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
DubpRust.setup();
|
|
||||||
generateMnemonic();
|
|
||||||
}
|
|
||||||
|
|
||||||
TextEditingController _mnemonicController = new TextEditingController();
|
|
||||||
TextEditingController _pubkey = new TextEditingController();
|
|
||||||
TextEditingController _pin = new TextEditingController();
|
|
||||||
String generatedMnemonic;
|
|
||||||
bool walletIsGenerated = false;
|
|
||||||
NewWallet actualWallet;
|
|
||||||
SuperTooltip tooltip;
|
|
||||||
// final formKey = GlobalKey<FormState>();
|
|
||||||
|
|
||||||
bool hasError = false;
|
|
||||||
String validPin = 'NO PIN';
|
|
||||||
String currentText = "";
|
|
||||||
var pinColor = Colors.grey[300];
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(),
|
|
||||||
floatingActionButton: Container(
|
|
||||||
height: 80.0,
|
|
||||||
width: 80.0,
|
|
||||||
child: FittedBox(
|
|
||||||
child: FloatingActionButton(
|
|
||||||
heroTag: "buttonGenerateWallet",
|
|
||||||
onPressed: () => generateMnemonic(),
|
|
||||||
// print(resultScan);
|
|
||||||
// if (resultScan != 'false') {
|
|
||||||
// onTabTapped(0);
|
|
||||||
// }
|
|
||||||
child: Container(
|
|
||||||
height: 40.0, width: 40.0, child: Icon(Icons.replay)),
|
|
||||||
backgroundColor: Color(
|
|
||||||
0xffEFEFBF), //Color(0xffFFD68E), //Color.fromARGB(500, 204, 255, 255),
|
|
||||||
))),
|
|
||||||
body: SafeArea(
|
|
||||||
child: Column(children: <Widget>[
|
|
||||||
SizedBox(height: 20),
|
|
||||||
Tooltip(
|
|
||||||
message:
|
|
||||||
"C'est votre RIB en Ğ1, les gens l'utiliseront pour vous payer",
|
|
||||||
child: Text(
|
|
||||||
'Clé publique:',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 15.0,
|
|
||||||
color: Colors.grey[600],
|
|
||||||
fontWeight: FontWeight.w400),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
TextField(
|
|
||||||
enabled: false,
|
|
||||||
controller: this._pubkey,
|
|
||||||
maxLines: 1,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
decoration: InputDecoration(),
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 14.0,
|
|
||||||
color: Colors.black,
|
|
||||||
fontWeight: FontWeight.bold)),
|
|
||||||
SizedBox(height: 8),
|
|
||||||
Tooltip(
|
|
||||||
message:
|
|
||||||
"Notez et gardez cette phrase précieusement sur un papier, elle vous servira à restaurer votre portefeuille sur un autre appareil",
|
|
||||||
child: Text(
|
|
||||||
'Phrase de restauration:',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 15.0,
|
|
||||||
color: Colors.grey[600],
|
|
||||||
fontWeight: FontWeight.w400),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
TextField(
|
|
||||||
enabled: false,
|
|
||||||
controller: this._mnemonicController,
|
|
||||||
maxLines: 3,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
contentPadding: EdgeInsets.all(15.0),
|
|
||||||
),
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 22.0,
|
|
||||||
color: Colors.black,
|
|
||||||
fontWeight: FontWeight.w400)),
|
|
||||||
SizedBox(height: 8),
|
|
||||||
Tooltip(
|
|
||||||
message:
|
|
||||||
"Retenez bien votre code secret, il vous sera demandé à chaque paiement, ainsi que pour configurer votre portefeuille",
|
|
||||||
child: Text(
|
|
||||||
'Code secret:',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 15.0,
|
|
||||||
color: Colors.grey[600],
|
|
||||||
fontWeight: FontWeight.w400),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
child: Stack(
|
|
||||||
alignment: Alignment.centerRight,
|
|
||||||
children: <Widget>[
|
|
||||||
TextField(
|
|
||||||
enabled: false,
|
|
||||||
controller: this._pin,
|
|
||||||
maxLines: 1,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
decoration: InputDecoration(),
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 30.0,
|
|
||||||
color: Colors.black,
|
|
||||||
fontWeight: FontWeight.bold)),
|
|
||||||
IconButton(
|
|
||||||
icon: Icon(Icons.replay),
|
|
||||||
color: Color(0xffD28928),
|
|
||||||
onPressed: () {
|
|
||||||
changePinCode();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(height: 20),
|
|
||||||
// Expanded(child: Align(alignment: Alignment.bottomCenter)),
|
|
||||||
new ElevatedButton(
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
primary: Color(0xffFFD68E), // background
|
|
||||||
onPrimary: Colors.black, // foreground
|
|
||||||
),
|
|
||||||
onPressed: walletIsGenerated
|
|
||||||
? () {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(builder: (context) {
|
|
||||||
return ConfirmStoreWallet(
|
|
||||||
// validationKey: _keyValidWallets,
|
|
||||||
generatedMnemonic: this.generatedMnemonic,
|
|
||||||
generatedWallet: this.actualWallet);
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
// .then((value) => setState(() {
|
|
||||||
// if (value != null) {
|
|
||||||
// _pin.clear();
|
|
||||||
// _mnemonicController.clear();
|
|
||||||
// _pubkey.clear();
|
|
||||||
// this.generatedMnemonic = null;
|
|
||||||
// this.actualWallet = null;
|
|
||||||
// this.walletIsGenerated = false;
|
|
||||||
// }
|
|
||||||
// }))
|
|
||||||
;
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
child: Text('Enregistrer ce portefeuille',
|
|
||||||
style: TextStyle(fontSize: 20))),
|
|
||||||
SizedBox(height: 20)
|
|
||||||
]),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,293 +0,0 @@
|
||||||
// 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 '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);
|
|
||||||
@override
|
|
||||||
MyWalletState createState() => MyWalletState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class MyWalletState extends State<MyWalletsScreen> {
|
|
||||||
// GlobalKey<GenerateWalletState> _keyGenWallet = GlobalKey();
|
|
||||||
StreamController<ErrorAnimationType> errorController;
|
|
||||||
Directory appPath;
|
|
||||||
List _listWallets = [];
|
|
||||||
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
errorController = StreamController<ErrorAnimationType>();
|
|
||||||
initAppDirectory();
|
|
||||||
DubpRust.setup();
|
|
||||||
// getAllWalletsNames();
|
|
||||||
// initAppDirectory();
|
|
||||||
// _walletsList = await getAllWalletsNames();
|
|
||||||
// HistoryScreen(
|
|
||||||
// keyHistory: _keyHistory,
|
|
||||||
// );
|
|
||||||
}
|
|
||||||
|
|
||||||
void initAppDirectory() async {
|
|
||||||
appPath = await getApplicationDocumentsDirectory();
|
|
||||||
appPath = Directory('${appPath.path}/wallets');
|
|
||||||
_listWallets = getAllWalletsNames();
|
|
||||||
}
|
|
||||||
|
|
||||||
TextEditingController _pubkey = new TextEditingController();
|
|
||||||
TextEditingController _enterPin = new TextEditingController();
|
|
||||||
final formKey = GlobalKey<FormState>();
|
|
||||||
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: <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: () {
|
|
||||||
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,
|
|
||||||
),
|
|
||||||
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);
|
|
||||||
},
|
|
||||||
)),
|
|
||||||
)
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
|
|
||||||
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<bool> 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);
|
|
||||||
|
|
||||||
this
|
|
||||||
.appPath
|
|
||||||
.list(recursive: false, followLinks: false)
|
|
||||||
.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<int> 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<String> get _localPath async {
|
|
||||||
final directory = await getApplicationDocumentsDirectory();
|
|
||||||
return directory.path;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<File> _localWallet(_name) async {
|
|
||||||
final path = await _localPath;
|
|
||||||
return File('$path/wallets/$_name/wallet.dewif');
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,154 +0,0 @@
|
||||||
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 'dart:io';
|
|
||||||
import 'dart:async';
|
|
||||||
import 'package:path_provider/path_provider.dart';
|
|
||||||
|
|
||||||
class WalletsHome extends StatefulWidget {
|
|
||||||
const WalletsHome({Key keyGenWallet}) : super(key: keyGenWallet);
|
|
||||||
@override
|
|
||||||
WalletsHomeState createState() => WalletsHomeState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class WalletsHomeState extends State<WalletsHome> {
|
|
||||||
GlobalKey<WalletsHomeState> _keyWalletsHome = GlobalKey();
|
|
||||||
// GlobalKey<MyWalletState> _keyMyWallets = GlobalKey();
|
|
||||||
// GlobalKey<ValidStoreWalletState> _keyValidWallets = GlobalKey();
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
DubpRust.setup();
|
|
||||||
getAppDirectory();
|
|
||||||
// _keyWalletsHome.currentState.getAllWalletsNames();
|
|
||||||
// _keyMyWallets.currentState.getAllWalletsNames();
|
|
||||||
}
|
|
||||||
|
|
||||||
String generatedMnemonic;
|
|
||||||
bool walletIsGenerated = false;
|
|
||||||
NewWallet actualWallet;
|
|
||||||
String newWalletName;
|
|
||||||
|
|
||||||
bool hasError = false;
|
|
||||||
String validPin = 'NO PIN';
|
|
||||||
String currentText = "";
|
|
||||||
var pinColor = Colors.grey[300];
|
|
||||||
Directory appPath;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
// getAppDirectory();
|
|
||||||
return Scaffold(
|
|
||||||
floatingActionButton: Visibility(
|
|
||||||
visible: (checkIfWalletExist(
|
|
||||||
'MonWallet')), //!checkIfWalletExist('MonWallet') &&
|
|
||||||
child: Container(
|
|
||||||
height: 80.0,
|
|
||||||
width: 80.0,
|
|
||||||
child: FittedBox(
|
|
||||||
child: FloatingActionButton(
|
|
||||||
heroTag: "buttonGenerateWallet",
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(builder: (context) {
|
|
||||||
return GenerateWalletsScreen();
|
|
||||||
}),
|
|
||||||
).then((value) => setState(() {
|
|
||||||
this.newWalletName = value;
|
|
||||||
checkIfWalletExist(value);
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
child: Container(
|
|
||||||
height: 40.0,
|
|
||||||
width: 40.0,
|
|
||||||
child: Icon(Icons.person_add_alt_1_rounded)),
|
|
||||||
backgroundColor: Color(0xffEFEFBF))))),
|
|
||||||
body: SafeArea(
|
|
||||||
child: Column(children: <Widget>[
|
|
||||||
Visibility(
|
|
||||||
visible: (!checkIfWalletExist('MonWallet') && !walletIsGenerated),
|
|
||||||
child: Column(children: <Widget>[
|
|
||||||
SizedBox(height: 120),
|
|
||||||
Center(
|
|
||||||
child: Text("Vous n'avez encore généré aucun portefeuille.",
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 20, fontWeight: FontWeight.w500),
|
|
||||||
textAlign: TextAlign.center)),
|
|
||||||
SizedBox(height: 80),
|
|
||||||
ElevatedButton(
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
primary: Color(0xffFFD68E), // background
|
|
||||||
onPrimary: Colors.black, // foreground
|
|
||||||
),
|
|
||||||
onPressed: () => Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(builder: (context) {
|
|
||||||
return GenerateWalletsScreen();
|
|
||||||
}),
|
|
||||||
).then((value) => setState(() {
|
|
||||||
this.newWalletName = value;
|
|
||||||
checkIfWalletExist(value);
|
|
||||||
})),
|
|
||||||
child: Text('Générer un portefeuille',
|
|
||||||
style: TextStyle(fontSize: 20))),
|
|
||||||
SizedBox(height: 15),
|
|
||||||
Center(
|
|
||||||
child: Text("ou",
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 20, fontWeight: FontWeight.w500),
|
|
||||||
textAlign: TextAlign.center)),
|
|
||||||
SizedBox(height: 15),
|
|
||||||
ElevatedButton(
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
primary: Color(0xffFFD68E), // background
|
|
||||||
onPrimary: Colors.black, // foreground
|
|
||||||
),
|
|
||||||
onPressed: () => importWallet(),
|
|
||||||
child: Text('Importer un portefeuille existant',
|
|
||||||
style: TextStyle(fontSize: 20))),
|
|
||||||
])),
|
|
||||||
Visibility(
|
|
||||||
visible: checkIfWalletExist('MonWallet'),
|
|
||||||
child: MyWalletsScreen(keyMyWallets: _keyWalletsHome))
|
|
||||||
])));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Future resetWalletState() async {
|
|
||||||
// final bool _isExist = await checkIfWalletExist('MonWallet');
|
|
||||||
// print('The wallet exist in resetWalletState(): ' + _isExist.toString());
|
|
||||||
// // initState();
|
|
||||||
// // _keyMyWallets.currentState.setState(() {});
|
|
||||||
// // _keyMyWallets.currentState.initAppDirectory();
|
|
||||||
// setState(() {
|
|
||||||
// // getAllWalletsNames();
|
|
||||||
// // this.walletIsGenerated = true;
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
bool checkIfWalletExist(_name) {
|
|
||||||
print('Nom du wallet: ' + _name);
|
|
||||||
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 {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future getAppDirectory() async {
|
|
||||||
this.appPath = await getApplicationDocumentsDirectory();
|
|
||||||
setState(() {});
|
|
||||||
}
|
|
||||||
|
|
||||||
Future importWallet() async {}
|
|
||||||
}
|
|
121
pubspec.lock
|
@ -21,42 +21,49 @@ packages:
|
||||||
name: async
|
name: async
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.5.0-nullsafety.3"
|
version: "2.5.0-nullsafety.1"
|
||||||
|
barcode:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: barcode
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.17.1"
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: boolean_selector
|
name: boolean_selector
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0-nullsafety.3"
|
version: "2.1.0-nullsafety.1"
|
||||||
characters:
|
characters:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: characters
|
name: characters
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0-nullsafety.5"
|
version: "1.1.0-nullsafety.3"
|
||||||
charcode:
|
charcode:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: charcode
|
name: charcode
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0-nullsafety.3"
|
version: "1.2.0-nullsafety.1"
|
||||||
clock:
|
clock:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: clock
|
name: clock
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0-nullsafety.3"
|
version: "1.1.0-nullsafety.1"
|
||||||
collection:
|
collection:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: collection
|
name: collection
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.15.0-nullsafety.5"
|
version: "1.15.0-nullsafety.3"
|
||||||
connectivity:
|
connectivity:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -112,7 +119,7 @@ packages:
|
||||||
name: fake_async
|
name: fake_async
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0-nullsafety.3"
|
version: "1.2.0-nullsafety.1"
|
||||||
ffi:
|
ffi:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -288,21 +295,21 @@ packages:
|
||||||
name: js
|
name: js
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.3-nullsafety.3"
|
version: "0.6.2"
|
||||||
matcher:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: matcher
|
name: matcher
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.10-nullsafety.3"
|
version: "0.12.10-nullsafety.1"
|
||||||
meta:
|
meta:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: meta
|
name: meta
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.0-nullsafety.6"
|
version: "1.3.0-nullsafety.3"
|
||||||
nested:
|
nested:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -318,7 +325,7 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.4.5"
|
version: "0.4.5"
|
||||||
package_info:
|
package_info:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: package_info
|
name: package_info
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
|
@ -330,7 +337,14 @@ packages:
|
||||||
name: path
|
name: path
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.8.0-nullsafety.3"
|
version: "1.8.0-nullsafety.1"
|
||||||
|
path_parsing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_parsing
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.4"
|
||||||
path_provider:
|
path_provider:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -366,6 +380,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.0.4+3"
|
version: "0.0.4+3"
|
||||||
|
pdf:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: pdf
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.0"
|
||||||
pedantic:
|
pedantic:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -415,6 +436,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.3"
|
version: "1.0.3"
|
||||||
|
printing:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: printing
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "4.0.0"
|
||||||
process:
|
process:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -429,6 +457,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.3.2+3"
|
version: "4.3.2+3"
|
||||||
|
qr:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: qr
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.0"
|
||||||
qrscan:
|
qrscan:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -457,6 +492,48 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.1"
|
version: "4.0.1"
|
||||||
|
shared_preferences:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: shared_preferences
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.5.12+4"
|
||||||
|
shared_preferences_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_linux
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.0.2+4"
|
||||||
|
shared_preferences_macos:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_macos
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.0.1+11"
|
||||||
|
shared_preferences_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_platform_interface
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.4"
|
||||||
|
shared_preferences_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_web
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.2+7"
|
||||||
|
shared_preferences_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_windows
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.0.2+2"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@ -468,28 +545,28 @@ packages:
|
||||||
name: source_span
|
name: source_span
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.8.0-nullsafety.4"
|
version: "1.8.0-nullsafety.2"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stack_trace
|
name: stack_trace
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.10.0-nullsafety.6"
|
version: "1.10.0-nullsafety.1"
|
||||||
stream_channel:
|
stream_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stream_channel
|
name: stream_channel
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0-nullsafety.3"
|
version: "2.1.0-nullsafety.1"
|
||||||
string_scanner:
|
string_scanner:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: string_scanner
|
name: string_scanner
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0-nullsafety.3"
|
version: "1.1.0-nullsafety.1"
|
||||||
super_tooltip:
|
super_tooltip:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -503,14 +580,14 @@ packages:
|
||||||
name: term_glyph
|
name: term_glyph
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0-nullsafety.3"
|
version: "1.2.0-nullsafety.1"
|
||||||
test_api:
|
test_api:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.19-nullsafety.6"
|
version: "0.2.19-nullsafety.2"
|
||||||
truncate:
|
truncate:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -524,7 +601,7 @@ packages:
|
||||||
name: typed_data
|
name: typed_data
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.0-nullsafety.5"
|
version: "1.3.0-nullsafety.3"
|
||||||
uuid:
|
uuid:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -545,7 +622,7 @@ packages:
|
||||||
name: vector_math
|
name: vector_math
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0-nullsafety.5"
|
version: "2.1.0-nullsafety.3"
|
||||||
websocket:
|
websocket:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -582,5 +659,5 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.1"
|
version: "2.2.1"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=2.12.0-0.0 <3.0.0"
|
dart: ">=2.10.0-110 <2.11.0"
|
||||||
flutter: ">=1.22.0"
|
flutter: ">=1.22.0 <2.0.0"
|
||||||
|
|
12
pubspec.yaml
|
@ -5,7 +5,7 @@ description: A new Flutter project.
|
||||||
# pub.dev using `pub publish`. This is preferred for private packages.
|
# 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
|
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
||||||
|
|
||||||
version: 0.0.0+9
|
version: 0.0.0+15
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.7.0 <3.0.0"
|
sdk: ">=2.7.0 <3.0.0"
|
||||||
|
@ -28,12 +28,15 @@ dependencies:
|
||||||
pin_code_fields: ^6.0.2
|
pin_code_fields: ^6.0.2
|
||||||
http: ^0.12.2
|
http: ^0.12.2
|
||||||
super_tooltip: ^0.9.6
|
super_tooltip: ^0.9.6
|
||||||
|
package_info: ^0.4.3+2
|
||||||
|
printing: ^4.0.0
|
||||||
|
shared_preferences: ^0.5.12+4
|
||||||
|
|
||||||
|
|
||||||
flutter_icons:
|
flutter_icons:
|
||||||
android: "ic_launcher"
|
android: "ic_launcher"
|
||||||
ios: true
|
ios: true
|
||||||
image_path: "assets/icon/gecko5bduniter2.png"
|
image_path: "assets/icon/gecko_final.png"
|
||||||
cupertino_icons: ^1.0.0
|
cupertino_icons: ^1.0.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
|
@ -46,4 +49,7 @@ flutter:
|
||||||
|
|
||||||
assets:
|
assets:
|
||||||
- images/
|
- images/
|
||||||
- config/
|
- config/
|
||||||
|
- assets/icon/gecko_final.png
|
||||||
|
- assets/
|
||||||
|
- assets/OpenSans-Regular.ttf
|
||||||
|
|
|
@ -12,8 +12,12 @@ echo "Nom du build final: ${APPNAME}-${VERSION}+${BUILD}.apk"
|
||||||
|
|
||||||
#flutter build apk --split-per-abi --build-name $VERSION --build-number $BUILD
|
#flutter build apk --split-per-abi --build-name $VERSION --build-number $BUILD
|
||||||
flutter clean
|
flutter clean
|
||||||
flutter build apk --split-per-abi --target-platform android-arm,android-arm64 --build-name $VERSION --build-number $BUILD
|
if [[ $1 == "bundle" ]]; then
|
||||||
|
flutter build appbundle --release --target-platform android-arm,android-arm64 --build-name $VERSION --build-number $BUILD
|
||||||
|
else
|
||||||
|
# flutter build apk --release --split-per-abi --target-platform android-arm,android-arm64 --build-name $VERSION --build-number $BUILD
|
||||||
|
flutter build apk --release --build-name $VERSION --build-number $BUILD
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ -d $HOME/Téléchargements ]]; then
|
if [[ -d $HOME/Téléchargements ]]; then
|
||||||
DL="$HOME/Téléchargements"
|
DL="$HOME/Téléchargements"
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
flutter pub run flutter_launcher_icons:main
|
||||||
|
|
||||||
|
exit 0
|