diff --git a/lib/models/generateWallets.dart b/lib/models/generateWallets.dart index a95dde0..6629b21 100644 --- a/lib/models/generateWallets.dart +++ b/lib/models/generateWallets.dart @@ -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 changePinCode({bool reload}) async { + Future 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 printWallet(String _title) async { diff --git a/lib/models/walletOptions.dart b/lib/models/walletOptions.dart index 0b708c0..c9cab0f 100644 --- a/lib/models/walletOptions.dart +++ b/lib/models/walletOptions.dart @@ -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'; } } diff --git a/lib/screens/commonElements.dart b/lib/screens/commonElements.dart index 42a633e..13776e2 100644 --- a/lib/screens/commonElements.dart +++ b/lib/screens/commonElements.dart @@ -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: [ - new TextSpan(text: "Munissez-vous d'"), - new TextSpan( - text: 'un papier et d’un 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(); + bool hasError = false; + var pinColor = Color(0xffF9F9F1); + // var _walletPin = ''; +// ignore: close_sinks + StreamController errorController = + StreamController(); + TextEditingController _enterPin = TextEditingController(); + + WalletOptionsProvider _walletOptions = + Provider.of(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 { diff --git a/lib/screens/myWallets/walletOptions.dart b/lib/screens/myWallets/walletOptions.dart index 91e44c3..056cf5e 100644 --- a/lib/screens/myWallets/walletOptions.dart +++ b/lib/screens/myWallets/walletOptions.dart @@ -232,7 +232,6 @@ class WalletOptions extends StatelessWidget with ChangeNotifier { final resultWallet = await _walletOptions.readLocalWallet( this.walletNbr, - this.walletName, _pin.toUpperCase(), _pinLenght, this.derivation); diff --git a/lib/screens/myWallets/walletsHome.dart b/lib/screens/myWallets/walletsHome.dart index e7a4963..a6ca0d3 100644 --- a/lib/screens/myWallets/walletsHome.dart +++ b/lib/screens/myWallets/walletsHome.dart @@ -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) { diff --git a/lib/screens/onBoarding/10_stepTen.dart b/lib/screens/onBoarding/10_stepTen.dart new file mode 100644 index 0000000..0e94656 --- /dev/null +++ b/lib/screens/onBoarding/10_stepTen.dart @@ -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(context); + CommonElements common = CommonElements(); + this._mnemonicController.text = generatedMnemonic; + + return WillPopScope( + onWillPop: () { + _generateWalletProvider.isAskedWordValid = false; + _generateWalletProvider.askedWordColor = Colors.black; + return Future.value(true); + }, + child: Scaffold( + extendBodyBehindAppBar: true, + body: SafeArea( + child: Column(children: [ + common.onboardingProgressBar( + 'Valider ma phrase de restauration', progress), + common.bubbleSpeakRich([ + 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), + ]), + ))); + } +} diff --git a/lib/screens/onBoarding/11_stepEleven.dart b/lib/screens/onBoarding/11_stepEleven.dart new file mode 100644 index 0000000..c2419f2 --- /dev/null +++ b/lib/screens/onBoarding/11_stepEleven.dart @@ -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: [ + common.onboardingProgressBar('Ma phrase de restauration', progress), + common.bubbleSpeakRich([ + 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 d’autres, 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), + ]), + )); + } +} diff --git a/lib/screens/onBoarding/12_stepTwelve.dart b/lib/screens/onBoarding/12_stepTwelve.dart new file mode 100644 index 0000000..4458ad0 --- /dev/null +++ b/lib/screens/onBoarding/12_stepTwelve.dart @@ -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: [ + 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), + ]), + )); + } +} diff --git a/lib/screens/onBoarding/13_stepThirteen.dart b/lib/screens/onBoarding/13_stepThirteen.dart new file mode 100644 index 0000000..c3514cf --- /dev/null +++ b/lib/screens/onBoarding/13_stepThirteen.dart @@ -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(context); + MyWalletsProvider myWalletProvider = + Provider.of(context); + CommonElements common = CommonElements(); + + return Scaffold( + extendBodyBehindAppBar: true, + body: SafeArea( + child: Column(children: [ + common.onboardingProgressBar('Ma phrase de restauration', progress), + common.bubbleSpeakRich([ + 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: [ + 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), + ]), + )); + } +} diff --git a/lib/screens/onBoarding/14_stepFourteen.dart b/lib/screens/onBoarding/14_stepFourteen.dart new file mode 100644 index 0000000..9ddde6f --- /dev/null +++ b/lib/screens/onBoarding/14_stepFourteen.dart @@ -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(context); + CommonElements common = CommonElements(); + + return Scaffold( + extendBodyBehindAppBar: true, + body: SafeArea( + child: Column(children: [ + 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 c’est fini, promis-juré-gecko)."), + SizedBox(height: 80), + common.pinForm(context, 5, 1, 3) + ]), + )); + } +} diff --git a/lib/screens/onBoarding/9_stepNine.dart b/lib/screens/onBoarding/9_stepNine.dart index b103faf..2014f0a 100644 --- a/lib/screens/onBoarding/9_stepNine.dart +++ b/lib/screens/onBoarding/9_stepNine.dart @@ -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))), diff --git a/pubspec.yaml b/pubspec.yaml index bfe7ebd..7116d16 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -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"