Fix wallet list view; Continue onboarding workflow until pin validation

This commit is contained in:
poka 2021-03-02 07:05:47 +01:00
parent 1be9b2c44a
commit f536b3fab8
12 changed files with 541 additions and 31 deletions

View File

@ -22,6 +22,7 @@ class GenerateWalletsProvider with ChangeNotifier {
bool isAskedWordValid = false;
int nbrWord;
String nbrWordAlpha;
String generatedMnemonic;
bool walletIsGenerated = true;
@ -46,6 +47,7 @@ class GenerateWalletsProvider with ChangeNotifier {
} else {
nbrWallet = 1;
}
Directory walletNbrDirectory;
do {
nbrWallet++;
@ -69,7 +71,9 @@ class GenerateWalletsProvider with ChangeNotifier {
await configFile
.writeAsString('$nbrWallet:$_name:$_derivationNbr:$_pubkey');
Navigator.pop(context, true);
print('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa');
print('${wallet.pin} : $_name : $isHD');
// Navigator.pop(context, true);
} else {
final int _derivationNbr = -1;
String _pubkey = await DubpRust.getDewifPublicKey(
@ -80,10 +84,7 @@ class GenerateWalletsProvider with ChangeNotifier {
.writeAsString('$nbrWallet:$_name:$_derivationNbr:$_pubkey');
}
print('CODE PIN :::');
print(wallet.pin);
Navigator.pop(context, true);
// Navigator.pop(context, true);
return _name;
}
@ -113,7 +114,7 @@ class GenerateWalletsProvider with ChangeNotifier {
print('Word is OK');
isAskedWordValid = true;
askedWordColor = Colors.green[600];
walletNameFocus.nextFocus();
// walletNameFocus.nextFocus();
notifyListeners();
} else {
isAskedWordValid = false;
@ -139,6 +140,26 @@ class GenerateWalletsProvider with ChangeNotifier {
return rng.nextInt(12);
}
String intToString(int _nbr) {
Map nbrToString = {};
nbrToString[1] = 'Premier';
nbrToString[2] = 'Deuxième';
nbrToString[3] = 'Troisième';
nbrToString[4] = 'Quatrième';
nbrToString[5] = 'Cinquième';
nbrToString[6] = 'Sixième';
nbrToString[7] = 'Septième';
nbrToString[8] = 'Huitième';
nbrToString[9] = 'Neuvième';
nbrToString[10] = 'Dixième';
nbrToString[11] = 'Onzième';
nbrToString[12] = 'Douzième';
nbrWordAlpha = nbrToString[_nbr];
return nbrWordAlpha;
}
void nameChanged() {
notifyListeners();
}
@ -174,7 +195,7 @@ class GenerateWalletsProvider with ChangeNotifier {
return this.actualWallet;
}
Future<void> changePinCode({bool reload}) async {
Future<NewWallet> changePinCode({bool reload}) async {
actualWallet = await DubpRust.changeDewifPin(
dewif: actualWallet.dewif,
oldPin: actualWallet.pin,
@ -185,6 +206,7 @@ class GenerateWalletsProvider with ChangeNotifier {
if (reload) {
notifyListeners();
}
return actualWallet;
}
Future<Uint8List> printWallet(String _title) async {

View File

@ -6,8 +6,8 @@ import 'dart:async';
import 'package:gecko/globals.dart';
class WalletOptionsProvider with ChangeNotifier {
TextEditingController pubkey = new TextEditingController();
TextEditingController _newWalletName = new TextEditingController();
TextEditingController pubkey = TextEditingController();
TextEditingController _newWalletName = TextEditingController();
bool isWalletUnlock = false;
bool ischangedPin = false;
TextEditingController newPin = new TextEditingController();
@ -61,8 +61,8 @@ class WalletOptionsProvider with ChangeNotifier {
}
}
Future readLocalWallet(int _walletNbr, String _name, String _pin,
int _pinLenght, int derivation) async {
Future readLocalWallet(
int _walletNbr, String _pin, int _pinLenght, int derivation) async {
isWalletUnlock = false;
try {
File _walletFile =
@ -84,6 +84,7 @@ class WalletOptionsProvider with ChangeNotifier {
} catch (e) {
print('ERROR READING FILE: $e');
this.pubkey.clear();
notifyListeners();
return 'bad';
}
}

View File

@ -1,5 +1,10 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:bubble/bubble.dart';
import 'package:gecko/models/walletOptions.dart';
import 'package:pin_code_fields/pin_code_fields.dart';
import 'package:provider/provider.dart';
class CommonElements {
// Exemple de Widget
@ -32,19 +37,12 @@ class CommonElements {
margin: BubbleEdges.fromLTRB(10, 0, 20, 10),
// nip: BubbleNip.leftTop,
child: RichText(
text: new TextSpan(
style: new TextStyle(
text: TextSpan(
style: TextStyle(
fontSize: 18.0,
color: Colors.black,
),
children: <TextSpan>[
new TextSpan(text: "Munissez-vous d'"),
new TextSpan(
text: 'un papier et dun crayon\n',
style: new TextStyle(fontWeight: FontWeight.bold)),
new TextSpan(
text: "afin de pouvoir noter votre phrase de restauration."),
],
children: text,
)),
);
}
@ -121,6 +119,94 @@ class CommonElements {
),
);
}
Widget pinForm(context, _pinLenght, int _walletNbr, int _derivation) {
final formKey = GlobalKey<FormState>();
bool hasError = false;
var pinColor = Color(0xffF9F9F1);
// var _walletPin = '';
// ignore: close_sinks
StreamController<ErrorAnimationType> errorController =
StreamController<ErrorAnimationType>();
TextEditingController _enterPin = TextEditingController();
WalletOptionsProvider _walletOptions =
Provider.of<WalletOptionsProvider>(context);
return 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: _pinLenght,
obscureText: false,
obscuringCharacter: '*',
animationType: AnimationType.fade,
validator: (v) {
if (v.length < _pinLenght) {
return "Votre code PIN fait $_pinLenght 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(
_walletNbr, _pin.toUpperCase(), _pinLenght, _derivation);
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));
// _walletPin = _pin.toUpperCase();
// isWalletUnlock = true;
// notifyListeners();
}
},
onChanged: (value) {
if (pinColor != Color(0xffF9F9F1)) {
pinColor = Color(0xffF9F9F1);
}
print(value);
},
)),
);
}
}
class SmoothTransition extends PageRouteBuilder {

View File

@ -232,7 +232,6 @@ class WalletOptions extends StatelessWidget with ChangeNotifier {
final resultWallet =
await _walletOptions.readLocalWallet(
this.walletNbr,
this.walletName,
_pin.toUpperCase(),
_pinLenght,
this.derivation);

View File

@ -49,15 +49,15 @@ class WalletsHome extends StatelessWidget {
});
},
child: Container(
height: 40.0,
width: 40.0,
height: 40,
width: 40,
child: Icon(Icons.person_add_alt_1_rounded,
color: Colors.grey[850])),
backgroundColor: Color(0xffEFEFBF))))),
body: SafeArea(
child: !isWalletsExists
? NoKeyChainScreen()
: Text('Wallet list screen')));
: myWalletsList(context)));
}
Widget myWalletsList(BuildContext context) {

View File

@ -0,0 +1,126 @@
import 'dart:ui';
import 'package:dubp/dubp.dart';
import 'package:flutter/services.dart';
import 'package:flutter/material.dart';
import 'package:gecko/models/generateWallets.dart';
import 'package:gecko/screens/commonElements.dart';
import 'package:gecko/screens/onBoarding/11_stepEleven.dart';
import 'package:provider/provider.dart';
// ignore: must_be_immutable
class OnboardingStepTen extends StatelessWidget {
OnboardingStepTen({
Key validationKey,
@required this.generatedMnemonic,
@required this.generatedWallet,
}) : super(key: validationKey);
String generatedMnemonic;
NewWallet generatedWallet;
TextEditingController tplController = TextEditingController();
TextEditingController wordController = TextEditingController();
TextEditingController _mnemonicController = TextEditingController();
final int progress = 58;
@override
Widget build(BuildContext context) {
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
GenerateWalletsProvider _generateWalletProvider =
Provider.of<GenerateWalletsProvider>(context);
CommonElements common = CommonElements();
this._mnemonicController.text = generatedMnemonic;
return WillPopScope(
onWillPop: () {
_generateWalletProvider.isAskedWordValid = false;
_generateWalletProvider.askedWordColor = Colors.black;
return Future<bool>.value(true);
},
child: Scaffold(
extendBodyBehindAppBar: true,
body: SafeArea(
child: Column(children: <Widget>[
common.onboardingProgressBar(
'Valider ma phrase de restauration', progress),
common.bubbleSpeakRich(<TextSpan>[
TextSpan(
text:
"Avez-vous bien noté votre phrase de restauration ?\n\nPour en être sûr, veuillez taper dans le champ ci-dessous le "),
TextSpan(
text: '${_generateWalletProvider.nbrWord + 1}ème mot',
style: TextStyle(fontWeight: FontWeight.bold)),
TextSpan(text: " de votre phrase de restauration :"),
]),
SizedBox(height: 70),
Text('${_generateWalletProvider.nbrWord + 1}',
style: TextStyle(
fontSize: 17,
color: Color(0xffD28928),
fontWeight: FontWeight.w400)),
SizedBox(height: 7),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(7),
border: Border.all(
color: Colors.grey[600],
width: 3,
)),
width: 430,
child: TextFormField(
autofocus: true,
enabled: !_generateWalletProvider.isAskedWordValid,
controller: this.wordController,
textInputAction: TextInputAction.next,
onChanged: (value) {
_generateWalletProvider.checkAskedWord(
value, _mnemonicController.text);
},
maxLines: 1,
textAlign: TextAlign.center,
decoration: InputDecoration(
labelStyle: TextStyle(
fontSize: 22.0,
color: Colors.grey[500],
fontWeight: FontWeight.w500),
labelText: _generateWalletProvider.isAskedWordValid
? "C'est le bon mot !"
: "${_generateWalletProvider.nbrWordAlpha} mot de votre phrase de restauration",
fillColor: Colors.grey[300],
filled: true,
contentPadding: EdgeInsets.all(12),
),
style: TextStyle(
fontSize: 40.0,
color: _generateWalletProvider.askedWordColor,
fontWeight: FontWeight.w500))),
Visibility(
visible: _generateWalletProvider.isAskedWordValid,
child: Expanded(
child: Align(
alignment: Alignment.bottomCenter,
child: SizedBox(
width: 400,
height: 62,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 5,
primary: Color(0xffD28928),
onPrimary: Colors.white, // foreground
),
onPressed: () {
Navigator.push(
context,
SmoothTransition(
page: OnboardingStepEleven()),
);
},
child: Text("Continuer",
style: TextStyle(fontSize: 20))),
)))),
SizedBox(height: 80),
]),
)));
}
}

View File

@ -0,0 +1,60 @@
import 'package:flutter/services.dart';
import 'package:flutter/material.dart';
import 'package:gecko/screens/commonElements.dart';
import 'package:gecko/screens/onBoarding/12_stepTwelve.dart';
// ignore: must_be_immutable
class OnboardingStepEleven extends StatelessWidget {
TextEditingController tplController = TextEditingController();
final int progress = 67;
@override
Widget build(BuildContext context) {
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
CommonElements common = CommonElements();
return Scaffold(
extendBodyBehindAppBar: true,
body: SafeArea(
child: Column(children: <Widget>[
common.onboardingProgressBar('Ma phrase de restauration', progress),
common.bubbleSpeakRich(<TextSpan>[
TextSpan(text: "Super !\n\nJe vais maintenant créer votre "),
TextSpan(
text: 'code secret.',
style: TextStyle(fontWeight: FontWeight.bold)),
TextSpan(
text:
" \n\nVotre code secret chiffre votre trousseau de clefs, ce qui le rend inutilisable par dautres, par exemple si vous perdez votre téléphone ou si on vous le vole."),
]),
SizedBox(height: 10),
Image.asset(
'assets/onBoarding/treasure-chest-gecko-souligne.png',
height: 400,
),
Expanded(
child: Align(
alignment: Alignment.bottomCenter,
child: SizedBox(
width: 400,
height: 62,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 5,
primary: Color(0xffD28928),
onPrimary: Colors.white, // foreground
),
onPressed: () {
Navigator.push(
context,
SmoothTransition(page: OnboardingStepTwelve()),
);
},
child: Text("J'ai compris",
style: TextStyle(fontSize: 20))),
))),
SizedBox(height: 80),
]),
));
}
}

View File

@ -0,0 +1,53 @@
import 'package:flutter/services.dart';
import 'package:flutter/material.dart';
import 'package:gecko/screens/commonElements.dart';
import 'package:gecko/screens/onBoarding/13_stepThirteen.dart';
// ignore: must_be_immutable
class OnboardingStepTwelve extends StatelessWidget {
TextEditingController tplController = TextEditingController();
final int progress = 75;
@override
Widget build(BuildContext context) {
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
CommonElements common = CommonElements();
return Scaffold(
extendBodyBehindAppBar: true,
body: SafeArea(
child: Column(children: <Widget>[
common.onboardingProgressBar('Ma phrase de restauration', progress),
common.bubbleSpeak(
"Si un jour vous changez de téléphone, votre code secret sera différent, mais il vous suffira de me redonner votre phrase de restauration pour recréer votre trousseau."),
SizedBox(height: 10),
Image.asset(
'assets/onBoarding/plusieurs-codes-secrets-un-trousseau.png',
height: 470,
),
Expanded(
child: Align(
alignment: Alignment.bottomCenter,
child: SizedBox(
width: 400,
height: 62,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 5,
primary: Color(0xffD28928),
onPrimary: Colors.white, // foreground
),
onPressed: () {
Navigator.push(
context,
SmoothTransition(page: OnboardingStepThirteen()),
);
},
child: Text("Générer le code secret",
style: TextStyle(fontSize: 20))),
))),
SizedBox(height: 80),
]),
));
}
}

View File

@ -0,0 +1,119 @@
import 'dart:ui';
import 'package:dubp/dubp.dart';
import 'package:flutter/services.dart';
import 'package:flutter/material.dart';
import 'package:gecko/models/generateWallets.dart';
import 'package:gecko/models/myWallets.dart';
import 'package:gecko/screens/commonElements.dart';
import 'package:gecko/screens/onBoarding/14_stepFourteen.dart';
import 'package:provider/provider.dart';
// ignore: must_be_immutable
class OnboardingStepThirteen extends StatelessWidget {
TextEditingController tplController = TextEditingController();
NewWallet generatedWallet;
final int progress = 83;
@override
Widget build(BuildContext context) {
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
GenerateWalletsProvider _generateWalletProvider =
Provider.of<GenerateWalletsProvider>(context);
MyWalletsProvider myWalletProvider =
Provider.of<MyWalletsProvider>(context);
CommonElements common = CommonElements();
return Scaffold(
extendBodyBehindAppBar: true,
body: SafeArea(
child: Column(children: <Widget>[
common.onboardingProgressBar('Ma phrase de restauration', progress),
common.bubbleSpeakRich(<TextSpan>[
TextSpan(
text:
"Et voilà votre code secret !\n\nMémorisez-le ou notez-le, car il vous sera demandé "),
TextSpan(
text: 'à chaque fois',
style: TextStyle(fontWeight: FontWeight.bold)),
TextSpan(
text:
" que vous voudrez effectuer un paiement sur cet appareil."),
]),
SizedBox(height: 100),
Container(
child: Stack(
alignment: Alignment.centerRight,
children: <Widget>[
TextField(
enabled: false,
controller: _generateWalletProvider.pin,
maxLines: 1,
textAlign: TextAlign.center,
decoration: InputDecoration(),
style: TextStyle(
letterSpacing: 5,
fontSize: 35.0,
color: Colors.black,
fontWeight: FontWeight.bold)),
IconButton(
icon: Icon(Icons.replay),
color: Color(0xffD28928),
onPressed: () async {
generatedWallet = await _generateWalletProvider
.changePinCode(reload: false);
},
),
],
),
),
Expanded(
child: Align(
alignment: Alignment.bottomCenter,
child: SizedBox(
width: 400,
height: 62,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 5,
primary: Color(0xffFFD58D),
onPrimary: Colors.black, // foreground
),
onPressed: () {
_generateWalletProvider.changePinCode(
reload: false);
},
child: Text("Choisir un autre code secret",
style: TextStyle(fontSize: 20))),
))),
SizedBox(height: 25),
SizedBox(
width: 400,
height: 62,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 5,
primary: Color(0xffD28928),
onPrimary: Colors.white, // foreground
),
onPressed: () async {
// TODO: Store wallet here !
await _generateWalletProvider.storeWallet(
generatedWallet, 'Mon portefeuille courant', context,
isHD: true);
myWalletProvider.listWallets =
myWalletProvider.getAllWalletsNames();
_generateWalletProvider.isAskedWordValid = false;
_generateWalletProvider.askedWordColor = Colors.black;
Navigator.push(
context,
SmoothTransition(page: OnboardingStepFourteen()),
);
},
child: Text("J'ai noté mon code secret",
style: TextStyle(fontSize: 20))),
),
SizedBox(height: 80),
]),
));
}
}

View File

@ -0,0 +1,32 @@
import 'dart:ui';
import 'package:flutter/services.dart';
import 'package:flutter/material.dart';
import 'package:gecko/models/generateWallets.dart';
import 'package:gecko/screens/commonElements.dart';
import 'package:provider/provider.dart';
// ignore: must_be_immutable
class OnboardingStepFourteen extends StatelessWidget {
TextEditingController tplController = TextEditingController();
final int progress = 92;
@override
Widget build(BuildContext context) {
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
GenerateWalletsProvider _generateWalletProvider =
Provider.of<GenerateWalletsProvider>(context);
CommonElements common = CommonElements();
return Scaffold(
extendBodyBehindAppBar: true,
body: SafeArea(
child: Column(children: <Widget>[
common.onboardingProgressBar('Ma phrase de restauration', progress),
common.bubbleSpeak(
"Avez-vous bien mémorisé votre code secret ?\n\nVérifions ça ensemble !\n\nTapez votre code secret dans le champ ci-dessous (après cest fini, promis-juré-gecko)."),
SizedBox(height: 80),
common.pinForm(context, 5, 1, 3)
]),
));
}
}

View File

@ -2,6 +2,7 @@ import 'package:flutter/services.dart';
import 'package:flutter/material.dart';
import 'package:gecko/models/generateWallets.dart';
import 'package:gecko/screens/commonElements.dart';
import 'package:gecko/screens/onBoarding/10_stepTen.dart';
import 'package:printing/printing.dart';
import 'package:provider/provider.dart';
@ -74,10 +75,21 @@ class OnboardingStepNine extends StatelessWidget {
onPrimary: Colors.white, // foreground
),
onPressed: () {
// Navigator.push(
// context,
// SmoothTransition(page: OnboardingStepNince()),
// );
_generateWalletProvider.nbrWord =
_generateWalletProvider.getRandomInt();
_generateWalletProvider.nbrWordAlpha =
_generateWalletProvider
.intToString(_generateWalletProvider.nbrWord + 1);
Navigator.push(
context,
SmoothTransition(
page: OnboardingStepTen(
generatedMnemonic:
_generateWalletProvider.generatedMnemonic,
generatedWallet:
_generateWalletProvider.actualWallet)),
);
},
child: Text("J'ai noté ma phrase",
style: TextStyle(fontSize: 20))),

View File

@ -1,11 +1,11 @@
name: gecko
description: A new Flutter project.
description: Pay with G1.
# The following line prevents the package from being accidentally published to
# pub.dev using `pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 0.0.1+19
version: 0.0.1+20
environment:
sdk: ">=2.7.0 <3.0.0"