diff --git a/android/app/build.gradle b/android/app/build.gradle index 095df97..799e480 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -45,8 +45,8 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "gecko.axiomteam.fr" - minSdkVersion 16 - targetSdkVersion 30 + minSdkVersion 19 + targetSdkVersion 31 versionCode flutterVersionCode.toInteger() versionName flutterVersionName multiDexEnabled true diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml index 39d6a39..2f0961b 100644 --- a/android/app/src/debug/AndroidManifest.xml +++ b/android/app/src/debug/AndroidManifest.xml @@ -1,5 +1,5 @@ + package="gecko.axiomteam.fr"> diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index b6701ee..0cf7229 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,5 +1,5 @@ + package="gecko.axiomteam.fr"> + android:windowSoftInputMode="adjustResize" + android:exported="true"> - + android:icon="@mipmap/ic_launcher" + /> --> - - diff --git a/android/app/src/main/ic_launcher-playstore.png b/android/app/src/main/ic_launcher-playstore.png new file mode 100644 index 0000000..bb34e78 Binary files /dev/null and b/android/app/src/main/ic_launcher-playstore.png differ diff --git a/android/app/src/main/kotlin/com/example/gecko/MainActivity.kt b/android/app/src/main/kotlin/com/example/gecko/MainActivity.kt index 1f87856..de5d149 100644 --- a/android/app/src/main/kotlin/com/example/gecko/MainActivity.kt +++ b/android/app/src/main/kotlin/com/example/gecko/MainActivity.kt @@ -1,4 +1,4 @@ -package com.example.gecko +package gecko.axiomteam.fr import io.flutter.embedding.android.FlutterActivity diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml index 39d6a39..2f0961b 100644 --- a/android/app/src/profile/AndroidManifest.xml +++ b/android/app/src/profile/AndroidManifest.xml @@ -1,5 +1,5 @@ + package="gecko.axiomteam.fr"> diff --git a/assets/onBoarding/coffre-fort-code-secret-dans-telephone.png b/assets/onBoarding/coffre-fort-code-secret-dans-telephone.png new file mode 100644 index 0000000..3cc870e Binary files /dev/null and b/assets/onBoarding/coffre-fort-code-secret-dans-telephone.png differ diff --git a/assets/onBoarding/coffre-fort-protege-les-portefeuilles.png b/assets/onBoarding/coffre-fort-protege-les-portefeuilles.png new file mode 100644 index 0000000..aec07f2 Binary files /dev/null and b/assets/onBoarding/coffre-fort-protege-les-portefeuilles.png differ diff --git a/assets/onBoarding/coffre-voleur-perplexe.png b/assets/onBoarding/coffre-voleur-perplexe.png new file mode 100644 index 0000000..2f5b6ee Binary files /dev/null and b/assets/onBoarding/coffre-voleur-perplexe.png differ diff --git a/assets/onBoarding/fabrication-de-portefeuille-impossible-sans-phrase.png b/assets/onBoarding/fabrication-de-portefeuille-impossible-sans-phrase.png new file mode 100644 index 0000000..7f78701 Binary files /dev/null and b/assets/onBoarding/fabrication-de-portefeuille-impossible-sans-phrase.png differ diff --git a/assets/onBoarding/fabrication-de-portefeuille.png b/assets/onBoarding/fabrication-de-portefeuille.png new file mode 100644 index 0000000..0984ccc Binary files /dev/null and b/assets/onBoarding/fabrication-de-portefeuille.png differ diff --git a/assets/onBoarding/gecko-oublie-aussi.png b/assets/onBoarding/gecko-oublie-aussi.png new file mode 100644 index 0000000..b4e165a Binary files /dev/null and b/assets/onBoarding/gecko-oublie-aussi.png differ diff --git a/assets/onBoarding/good-bad-passphrase.png b/assets/onBoarding/good-bad-passphrase.png deleted file mode 100755 index edbda62..0000000 Binary files a/assets/onBoarding/good-bad-passphrase.png and /dev/null differ diff --git a/assets/onBoarding/keys-and-wallets-horizontal.png b/assets/onBoarding/keys-and-wallets-horizontal.png deleted file mode 100755 index e94e57d..0000000 Binary files a/assets/onBoarding/keys-and-wallets-horizontal.png and /dev/null differ diff --git a/assets/onBoarding/mot-de-passe-oublie.png b/assets/onBoarding/mot-de-passe-oublie.png new file mode 100644 index 0000000..8d80bc9 Binary files /dev/null and b/assets/onBoarding/mot-de-passe-oublie.png differ diff --git a/config/gva_endpoints.json b/config/gva_endpoints.json index 541e9fb..1533920 100644 --- a/config/gva_endpoints.json +++ b/config/gva_endpoints.json @@ -1,5 +1,3 @@ [ - "https://g1.librelois.fr/gva", - "https://duniter-gva.axiom-team.fr/gva", - "https://duniter-g1.p2p.legal/gva" + "https://g1.librelois.fr/gva" ] diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 4297642..1159bf4 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -299,7 +299,7 @@ "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.gecko; + PRODUCT_BUNDLE_IDENTIFIER = gecko.axiomteam.fr; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -431,7 +431,7 @@ "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.gecko; + PRODUCT_BUNDLE_IDENTIFIER = gecko.axiomteam.fr; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -458,7 +458,7 @@ "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.gecko; + PRODUCT_BUNDLE_IDENTIFIER = gecko.axiomteam.fr; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -492,4 +492,4 @@ /* End XCConfigurationList section */ }; rootObject = 97C146E61CF9000F007C117D /* Project object */; -} \ No newline at end of file +} diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png index a65cade..d08d914 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png index c081abb..6cb6241 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png index bdb5fed..3e54e80 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png index 9708740..a544812 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png index 3b4e54e..db4c932 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png index 0506604..4005a0d 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png index 7168d21..852aa31 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png index bdb5fed..3e54e80 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png index 475acee..b6fb505 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png index 9ed9156..aad11e2 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png new file mode 100644 index 0000000..ae24ab9 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png new file mode 100644 index 0000000..3212359 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png new file mode 100644 index 0000000..529052a Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png new file mode 100644 index 0000000..18aa346 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png index 9ed9156..aad11e2 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png index 3f1ee21..afc4220 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png new file mode 100644 index 0000000..797a997 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png new file mode 100644 index 0000000..44f196d Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png index f32e892..3c6974e 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png index f6dd010..7740bbd 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png index 97d30a6..2b683d0 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/lib/globals.dart b/lib/globals.dart index abbaf47..5ff7013 100644 --- a/lib/globals.dart +++ b/lib/globals.dart @@ -14,14 +14,16 @@ late String appVersion; late SharedPreferences prefs; late String endPointGVA; const int pinLength = 5; -const String appLang = 'french'; +const String appLang = 'english'; late Box walletBox; late Box chestBox; late Box configBox; late Box g1WalletsBox; +// late Box keystoreBox; -String cesiumPod = "https://g1.data.le-sou.org"; +// String cesiumPod = "https://g1.data.le-sou.org"; +String cesiumPod = "https://g1.data.presles.fr"; // String cesiumPod = "https://g1.data.e-is.pro"; // Responsive ratios @@ -36,3 +38,10 @@ Color orangeC = const Color(0xffd07316); Color yellowC = const Color(0xffFFD68E); Color floattingYellow = const Color(0xffEFEFBF); Color backgroundColor = const Color(0xFFF5F5F5); + +// Substrate settings +const int ss58 = 42; +String currencyName = 'Ğdev'; + +// Debug +const debugPin = true; diff --git a/lib/main.dart b/lib/main.dart index e59041f..e0b29da 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2020 Axiom-Team. +// Copyright (C) 2022 Axiom-Team. // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as @@ -20,11 +20,11 @@ import 'dart:io'; import 'package:flutter/services.dart'; import 'package:gecko/globals.dart'; import 'package:gecko/providers/cesium_plus.dart'; -import 'package:gecko/providers/change_pin.dart'; import 'package:gecko/models/chest_data.dart'; import 'package:gecko/providers/chest_provider.dart'; import 'package:gecko/models/g1_wallets_list.dart'; import 'package:gecko/providers/generate_wallets.dart'; +import 'package:gecko/providers/substrate_sdk.dart'; import 'package:gecko/providers/wallets_profiles.dart'; import 'package:gecko/providers/home.dart'; import 'package:gecko/providers/my_wallets.dart'; @@ -65,19 +65,23 @@ Future main() async { Hive.registerAdapter(ChestDataAdapter()); Hive.registerAdapter(G1WalletsListAdapter()); Hive.registerAdapter(IdAdapter()); + // Hive.registerAdapter(KeyStoreDataAdapter()); + walletBox = await Hive.openBox("walletBox"); chestBox = await Hive.openBox("chestBox"); configBox = await Hive.openBox("configBox"); + await Hive.deleteBoxFromDisk('g1WalletsBox'); g1WalletsBox = await Hive.openBox("g1WalletsBox"); + // keystoreBox = await Hive.openBox("keystoreBox"); - g1WalletsBox.clear(); + // g1WalletsBox.clear(); // final HiveStore _store = // await HiveStore.open(path: '${appPath.path}/gqlCache'); // Get a valid GVA endpoint - // endPointGVA = 'https://g1.librelois.fr/gva'; - endPointGVA = 'https://duniter-g1.p2p.legal/gva'; + endPointGVA = 'https://g1.librelois.fr/gva'; + // endPointGVA = 'https://duniter-g1.p2p.legal/gva'; // await _homeProvider.getValidEndpoint(); // if (endPointGVA == 'HS') { @@ -152,9 +156,9 @@ class Gecko extends StatelessWidget { ChangeNotifierProvider(create: (_) => ChestProvider()), ChangeNotifierProvider(create: (_) => GenerateWalletsProvider()), ChangeNotifierProvider(create: (_) => WalletOptionsProvider()), - ChangeNotifierProvider(create: (_) => ChangePinProvider()), ChangeNotifierProvider(create: (_) => SearchProvider()), - ChangeNotifierProvider(create: (_) => CesiumPlusProvider()) + ChangeNotifierProvider(create: (_) => CesiumPlusProvider()), + ChangeNotifierProvider(create: (_) => SubstrateSdk()) ], child: GraphQLProvider( client: _client, @@ -178,8 +182,8 @@ class Gecko extends StatelessWidget { ), primaryColor: const Color(0xffFFD58D), textTheme: const TextTheme( - bodyText1: TextStyle(), - bodyText2: TextStyle(), + bodyText1: TextStyle(fontSize: 16), + bodyText2: TextStyle(fontSize: 18), ).apply( bodyColor: const Color(0xFF000000), ), diff --git a/lib/models/bip39_words.dart b/lib/models/bip39_words.dart index 0809642..82ec9c9 100644 --- a/lib/models/bip39_words.dart +++ b/lib/models/bip39_words.dart @@ -1,4 +1,2066 @@ -List bip39Words = [ +List bip39Words(String lang) { + switch (lang) { + case 'english': + return _english; + case 'french': + return _french; + default: + return _english; + } +} + +List _english = [ + 'abandon', + 'ability', + 'able', + 'about', + 'above', + 'absent', + 'absorb', + 'abstract', + 'absurd', + 'abuse', + 'access', + 'accident', + 'account', + 'accuse', + 'achieve', + 'acid', + 'acoustic', + 'acquire', + 'across', + 'act', + 'action', + 'actor', + 'actress', + 'actual', + 'adapt', + 'add', + 'addict', + 'address', + 'adjust', + 'admit', + 'adult', + 'advance', + 'advice', + 'aerobic', + 'affair', + 'afford', + 'afraid', + 'again', + 'age', + 'agent', + 'agree', + 'ahead', + 'aim', + 'air', + 'airport', + 'aisle', + 'alarm', + 'album', + 'alcohol', + 'alert', + 'alien', + 'all', + 'alley', + 'allow', + 'almost', + 'alone', + 'alpha', + 'already', + 'also', + 'alter', + 'always', + 'amateur', + 'amazing', + 'among', + 'amount', + 'amused', + 'analyst', + 'anchor', + 'ancient', + 'anger', + 'angle', + 'angry', + 'animal', + 'ankle', + 'announce', + 'annual', + 'another', + 'answer', + 'antenna', + 'antique', + 'anxiety', + 'any', + 'apart', + 'apology', + 'appear', + 'apple', + 'approve', + 'april', + 'arch', + 'arctic', + 'area', + 'arena', + 'argue', + 'arm', + 'armed', + 'armor', + 'army', + 'around', + 'arrange', + 'arrest', + 'arrive', + 'arrow', + 'art', + 'artefact', + 'artist', + 'artwork', + 'ask', + 'aspect', + 'assault', + 'asset', + 'assist', + 'assume', + 'asthma', + 'athlete', + 'atom', + 'attack', + 'attend', + 'attitude', + 'attract', + 'auction', + 'audit', + 'august', + 'aunt', + 'author', + 'auto', + 'autumn', + 'average', + 'avocado', + 'avoid', + 'awake', + 'aware', + 'away', + 'awesome', + 'awful', + 'awkward', + 'axis', + 'baby', + 'bachelor', + 'bacon', + 'badge', + 'bag', + 'balance', + 'balcony', + 'ball', + 'bamboo', + 'banana', + 'banner', + 'bar', + 'barely', + 'bargain', + 'barrel', + 'base', + 'basic', + 'basket', + 'battle', + 'beach', + 'bean', + 'beauty', + 'because', + 'become', + 'beef', + 'before', + 'begin', + 'behave', + 'behind', + 'believe', + 'below', + 'belt', + 'bench', + 'benefit', + 'best', + 'betray', + 'better', + 'between', + 'beyond', + 'bicycle', + 'bid', + 'bike', + 'bind', + 'biology', + 'bird', + 'birth', + 'bitter', + 'black', + 'blade', + 'blame', + 'blanket', + 'blast', + 'bleak', + 'bless', + 'blind', + 'blood', + 'blossom', + 'blouse', + 'blue', + 'blur', + 'blush', + 'board', + 'boat', + 'body', + 'boil', + 'bomb', + 'bone', + 'bonus', + 'book', + 'boost', + 'border', + 'boring', + 'borrow', + 'boss', + 'bottom', + 'bounce', + 'box', + 'boy', + 'bracket', + 'brain', + 'brand', + 'brass', + 'brave', + 'bread', + 'breeze', + 'brick', + 'bridge', + 'brief', + 'bright', + 'bring', + 'brisk', + 'broccoli', + 'broken', + 'bronze', + 'broom', + 'brother', + 'brown', + 'brush', + 'bubble', + 'buddy', + 'budget', + 'buffalo', + 'build', + 'bulb', + 'bulk', + 'bullet', + 'bundle', + 'bunker', + 'burden', + 'burger', + 'burst', + 'bus', + 'business', + 'busy', + 'butter', + 'buyer', + 'buzz', + 'cabbage', + 'cabin', + 'cable', + 'cactus', + 'cage', + 'cake', + 'call', + 'calm', + 'camera', + 'camp', + 'can', + 'canal', + 'cancel', + 'candy', + 'cannon', + 'canoe', + 'canvas', + 'canyon', + 'capable', + 'capital', + 'captain', + 'car', + 'carbon', + 'card', + 'cargo', + 'carpet', + 'carry', + 'cart', + 'case', + 'cash', + 'casino', + 'castle', + 'casual', + 'cat', + 'catalog', + 'catch', + 'category', + 'cattle', + 'caught', + 'cause', + 'caution', + 'cave', + 'ceiling', + 'celery', + 'cement', + 'census', + 'century', + 'cereal', + 'certain', + 'chair', + 'chalk', + 'champion', + 'change', + 'chaos', + 'chapter', + 'charge', + 'chase', + 'chat', + 'cheap', + 'check', + 'cheese', + 'chef', + 'cherry', + 'chest', + 'chicken', + 'chief', + 'child', + 'chimney', + 'choice', + 'choose', + 'chronic', + 'chuckle', + 'chunk', + 'churn', + 'cigar', + 'cinnamon', + 'circle', + 'citizen', + 'city', + 'civil', + 'claim', + 'clap', + 'clarify', + 'claw', + 'clay', + 'clean', + 'clerk', + 'clever', + 'click', + 'client', + 'cliff', + 'climb', + 'clinic', + 'clip', + 'clock', + 'clog', + 'close', + 'cloth', + 'cloud', + 'clown', + 'club', + 'clump', + 'cluster', + 'clutch', + 'coach', + 'coast', + 'coconut', + 'code', + 'coffee', + 'coil', + 'coin', + 'collect', + 'color', + 'column', + 'combine', + 'come', + 'comfort', + 'comic', + 'common', + 'company', + 'concert', + 'conduct', + 'confirm', + 'congress', + 'connect', + 'consider', + 'control', + 'convince', + 'cook', + 'cool', + 'copper', + 'copy', + 'coral', + 'core', + 'corn', + 'correct', + 'cost', + 'cotton', + 'couch', + 'country', + 'couple', + 'course', + 'cousin', + 'cover', + 'coyote', + 'crack', + 'cradle', + 'craft', + 'cram', + 'crane', + 'crash', + 'crater', + 'crawl', + 'crazy', + 'cream', + 'credit', + 'creek', + 'crew', + 'cricket', + 'crime', + 'crisp', + 'critic', + 'crop', + 'cross', + 'crouch', + 'crowd', + 'crucial', + 'cruel', + 'cruise', + 'crumble', + 'crunch', + 'crush', + 'cry', + 'crystal', + 'cube', + 'culture', + 'cup', + 'cupboard', + 'curious', + 'current', + 'curtain', + 'curve', + 'cushion', + 'custom', + 'cute', + 'cycle', + 'dad', + 'damage', + 'damp', + 'dance', + 'danger', + 'daring', + 'dash', + 'daughter', + 'dawn', + 'day', + 'deal', + 'debate', + 'debris', + 'decade', + 'december', + 'decide', + 'decline', + 'decorate', + 'decrease', + 'deer', + 'defense', + 'define', + 'defy', + 'degree', + 'delay', + 'deliver', + 'demand', + 'demise', + 'denial', + 'dentist', + 'deny', + 'depart', + 'depend', + 'deposit', + 'depth', + 'deputy', + 'derive', + 'describe', + 'desert', + 'design', + 'desk', + 'despair', + 'destroy', + 'detail', + 'detect', + 'develop', + 'device', + 'devote', + 'diagram', + 'dial', + 'diamond', + 'diary', + 'dice', + 'diesel', + 'diet', + 'differ', + 'digital', + 'dignity', + 'dilemma', + 'dinner', + 'dinosaur', + 'direct', + 'dirt', + 'disagree', + 'discover', + 'disease', + 'dish', + 'dismiss', + 'disorder', + 'display', + 'distance', + 'divert', + 'divide', + 'divorce', + 'dizzy', + 'doctor', + 'document', + 'dog', + 'doll', + 'dolphin', + 'domain', + 'donate', + 'donkey', + 'donor', + 'door', + 'dose', + 'double', + 'dove', + 'draft', + 'dragon', + 'drama', + 'drastic', + 'draw', + 'dream', + 'dress', + 'drift', + 'drill', + 'drink', + 'drip', + 'drive', + 'drop', + 'drum', + 'dry', + 'duck', + 'dumb', + 'dune', + 'during', + 'dust', + 'dutch', + 'duty', + 'dwarf', + 'dynamic', + 'eager', + 'eagle', + 'early', + 'earn', + 'earth', + 'easily', + 'east', + 'easy', + 'echo', + 'ecology', + 'economy', + 'edge', + 'edit', + 'educate', + 'effort', + 'egg', + 'eight', + 'either', + 'elbow', + 'elder', + 'electric', + 'elegant', + 'element', + 'elephant', + 'elevator', + 'elite', + 'else', + 'embark', + 'embody', + 'embrace', + 'emerge', + 'emotion', + 'employ', + 'empower', + 'empty', + 'enable', + 'enact', + 'end', + 'endless', + 'endorse', + 'enemy', + 'energy', + 'enforce', + 'engage', + 'engine', + 'enhance', + 'enjoy', + 'enlist', + 'enough', + 'enrich', + 'enroll', + 'ensure', + 'enter', + 'entire', + 'entry', + 'envelope', + 'episode', + 'equal', + 'equip', + 'era', + 'erase', + 'erode', + 'erosion', + 'error', + 'erupt', + 'escape', + 'essay', + 'essence', + 'estate', + 'eternal', + 'ethics', + 'evidence', + 'evil', + 'evoke', + 'evolve', + 'exact', + 'example', + 'excess', + 'exchange', + 'excite', + 'exclude', + 'excuse', + 'execute', + 'exercise', + 'exhaust', + 'exhibit', + 'exile', + 'exist', + 'exit', + 'exotic', + 'expand', + 'expect', + 'expire', + 'explain', + 'expose', + 'express', + 'extend', + 'extra', + 'eye', + 'eyebrow', + 'fabric', + 'face', + 'faculty', + 'fade', + 'faint', + 'faith', + 'fall', + 'false', + 'fame', + 'family', + 'famous', + 'fan', + 'fancy', + 'fantasy', + 'farm', + 'fashion', + 'fat', + 'fatal', + 'father', + 'fatigue', + 'fault', + 'favorite', + 'feature', + 'february', + 'federal', + 'fee', + 'feed', + 'feel', + 'female', + 'fence', + 'festival', + 'fetch', + 'fever', + 'few', + 'fiber', + 'fiction', + 'field', + 'figure', + 'file', + 'film', + 'filter', + 'final', + 'find', + 'fine', + 'finger', + 'finish', + 'fire', + 'firm', + 'first', + 'fiscal', + 'fish', + 'fit', + 'fitness', + 'fix', + 'flag', + 'flame', + 'flash', + 'flat', + 'flavor', + 'flee', + 'flight', + 'flip', + 'float', + 'flock', + 'floor', + 'flower', + 'fluid', + 'flush', + 'fly', + 'foam', + 'focus', + 'fog', + 'foil', + 'fold', + 'follow', + 'food', + 'foot', + 'force', + 'forest', + 'forget', + 'fork', + 'fortune', + 'forum', + 'forward', + 'fossil', + 'foster', + 'found', + 'fox', + 'fragile', + 'frame', + 'frequent', + 'fresh', + 'friend', + 'fringe', + 'frog', + 'front', + 'frost', + 'frown', + 'frozen', + 'fruit', + 'fuel', + 'fun', + 'funny', + 'furnace', + 'fury', + 'future', + 'gadget', + 'gain', + 'galaxy', + 'gallery', + 'game', + 'gap', + 'garage', + 'garbage', + 'garden', + 'garlic', + 'garment', + 'gas', + 'gasp', + 'gate', + 'gather', + 'gauge', + 'gaze', + 'general', + 'genius', + 'genre', + 'gentle', + 'genuine', + 'gesture', + 'ghost', + 'giant', + 'gift', + 'giggle', + 'ginger', + 'giraffe', + 'girl', + 'give', + 'glad', + 'glance', + 'glare', + 'glass', + 'glide', + 'glimpse', + 'globe', + 'gloom', + 'glory', + 'glove', + 'glow', + 'glue', + 'goat', + 'goddess', + 'gold', + 'good', + 'goose', + 'gorilla', + 'gospel', + 'gossip', + 'govern', + 'gown', + 'grab', + 'grace', + 'grain', + 'grant', + 'grape', + 'grass', + 'gravity', + 'great', + 'green', + 'grid', + 'grief', + 'grit', + 'grocery', + 'group', + 'grow', + 'grunt', + 'guard', + 'guess', + 'guide', + 'guilt', + 'guitar', + 'gun', + 'gym', + 'habit', + 'hair', + 'half', + 'hammer', + 'hamster', + 'hand', + 'happy', + 'harbor', + 'hard', + 'harsh', + 'harvest', + 'hat', + 'have', + 'hawk', + 'hazard', + 'head', + 'health', + 'heart', + 'heavy', + 'hedgehog', + 'height', + 'hello', + 'helmet', + 'help', + 'hen', + 'hero', + 'hidden', + 'high', + 'hill', + 'hint', + 'hip', + 'hire', + 'history', + 'hobby', + 'hockey', + 'hold', + 'hole', + 'holiday', + 'hollow', + 'home', + 'honey', + 'hood', + 'hope', + 'horn', + 'horror', + 'horse', + 'hospital', + 'host', + 'hotel', + 'hour', + 'hover', + 'hub', + 'huge', + 'human', + 'humble', + 'humor', + 'hundred', + 'hungry', + 'hunt', + 'hurdle', + 'hurry', + 'hurt', + 'husband', + 'hybrid', + 'ice', + 'icon', + 'idea', + 'identify', + 'idle', + 'ignore', + 'ill', + 'illegal', + 'illness', + 'image', + 'imitate', + 'immense', + 'immune', + 'impact', + 'impose', + 'improve', + 'impulse', + 'inch', + 'include', + 'income', + 'increase', + 'index', + 'indicate', + 'indoor', + 'industry', + 'infant', + 'inflict', + 'inform', + 'inhale', + 'inherit', + 'initial', + 'inject', + 'injury', + 'inmate', + 'inner', + 'innocent', + 'input', + 'inquiry', + 'insane', + 'insect', + 'inside', + 'inspire', + 'install', + 'intact', + 'interest', + 'into', + 'invest', + 'invite', + 'involve', + 'iron', + 'island', + 'isolate', + 'issue', + 'item', + 'ivory', + 'jacket', + 'jaguar', + 'jar', + 'jazz', + 'jealous', + 'jeans', + 'jelly', + 'jewel', + 'job', + 'join', + 'joke', + 'journey', + 'joy', + 'judge', + 'juice', + 'jump', + 'jungle', + 'junior', + 'junk', + 'just', + 'kangaroo', + 'keen', + 'keep', + 'ketchup', + 'key', + 'kick', + 'kid', + 'kidney', + 'kind', + 'kingdom', + 'kiss', + 'kit', + 'kitchen', + 'kite', + 'kitten', + 'kiwi', + 'knee', + 'knife', + 'knock', + 'know', + 'lab', + 'label', + 'labor', + 'ladder', + 'lady', + 'lake', + 'lamp', + 'language', + 'laptop', + 'large', + 'later', + 'latin', + 'laugh', + 'laundry', + 'lava', + 'law', + 'lawn', + 'lawsuit', + 'layer', + 'lazy', + 'leader', + 'leaf', + 'learn', + 'leave', + 'lecture', + 'left', + 'leg', + 'legal', + 'legend', + 'leisure', + 'lemon', + 'lend', + 'length', + 'lens', + 'leopard', + 'lesson', + 'letter', + 'level', + 'liar', + 'liberty', + 'library', + 'license', + 'life', + 'lift', + 'light', + 'like', + 'limb', + 'limit', + 'link', + 'lion', + 'liquid', + 'list', + 'little', + 'live', + 'lizard', + 'load', + 'loan', + 'lobster', + 'local', + 'lock', + 'logic', + 'lonely', + 'long', + 'loop', + 'lottery', + 'loud', + 'lounge', + 'love', + 'loyal', + 'lucky', + 'luggage', + 'lumber', + 'lunar', + 'lunch', + 'luxury', + 'lyrics', + 'machine', + 'mad', + 'magic', + 'magnet', + 'maid', + 'mail', + 'main', + 'major', + 'make', + 'mammal', + 'man', + 'manage', + 'mandate', + 'mango', + 'mansion', + 'manual', + 'maple', + 'marble', + 'march', + 'margin', + 'marine', + 'market', + 'marriage', + 'mask', + 'mass', + 'master', + 'match', + 'material', + 'math', + 'matrix', + 'matter', + 'maximum', + 'maze', + 'meadow', + 'mean', + 'measure', + 'meat', + 'mechanic', + 'medal', + 'media', + 'melody', + 'melt', + 'member', + 'memory', + 'mention', + 'menu', + 'mercy', + 'merge', + 'merit', + 'merry', + 'mesh', + 'message', + 'metal', + 'method', + 'middle', + 'midnight', + 'milk', + 'million', + 'mimic', + 'mind', + 'minimum', + 'minor', + 'minute', + 'miracle', + 'mirror', + 'misery', + 'miss', + 'mistake', + 'mix', + 'mixed', + 'mixture', + 'mobile', + 'model', + 'modify', + 'mom', + 'moment', + 'monitor', + 'monkey', + 'monster', + 'month', + 'moon', + 'moral', + 'more', + 'morning', + 'mosquito', + 'mother', + 'motion', + 'motor', + 'mountain', + 'mouse', + 'move', + 'movie', + 'much', + 'muffin', + 'mule', + 'multiply', + 'muscle', + 'museum', + 'mushroom', + 'music', + 'must', + 'mutual', + 'myself', + 'mystery', + 'myth', + 'naive', + 'name', + 'napkin', + 'narrow', + 'nasty', + 'nation', + 'nature', + 'near', + 'neck', + 'need', + 'negative', + 'neglect', + 'neither', + 'nephew', + 'nerve', + 'nest', + 'net', + 'network', + 'neutral', + 'never', + 'news', + 'next', + 'nice', + 'night', + 'noble', + 'noise', + 'nominee', + 'noodle', + 'normal', + 'north', + 'nose', + 'notable', + 'note', + 'nothing', + 'notice', + 'novel', + 'now', + 'nuclear', + 'number', + 'nurse', + 'nut', + 'oak', + 'obey', + 'object', + 'oblige', + 'obscure', + 'observe', + 'obtain', + 'obvious', + 'occur', + 'ocean', + 'october', + 'odor', + 'off', + 'offer', + 'office', + 'often', + 'oil', + 'okay', + 'old', + 'olive', + 'olympic', + 'omit', + 'once', + 'one', + 'onion', + 'online', + 'only', + 'open', + 'opera', + 'opinion', + 'oppose', + 'option', + 'orange', + 'orbit', + 'orchard', + 'order', + 'ordinary', + 'organ', + 'orient', + 'original', + 'orphan', + 'ostrich', + 'other', + 'outdoor', + 'outer', + 'output', + 'outside', + 'oval', + 'oven', + 'over', + 'own', + 'owner', + 'oxygen', + 'oyster', + 'ozone', + 'pact', + 'paddle', + 'page', + 'pair', + 'palace', + 'palm', + 'panda', + 'panel', + 'panic', + 'panther', + 'paper', + 'parade', + 'parent', + 'park', + 'parrot', + 'party', + 'pass', + 'patch', + 'path', + 'patient', + 'patrol', + 'pattern', + 'pause', + 'pave', + 'payment', + 'peace', + 'peanut', + 'pear', + 'peasant', + 'pelican', + 'pen', + 'penalty', + 'pencil', + 'people', + 'pepper', + 'perfect', + 'permit', + 'person', + 'pet', + 'phone', + 'photo', + 'phrase', + 'physical', + 'piano', + 'picnic', + 'picture', + 'piece', + 'pig', + 'pigeon', + 'pill', + 'pilot', + 'pink', + 'pioneer', + 'pipe', + 'pistol', + 'pitch', + 'pizza', + 'place', + 'planet', + 'plastic', + 'plate', + 'play', + 'please', + 'pledge', + 'pluck', + 'plug', + 'plunge', + 'poem', + 'poet', + 'point', + 'polar', + 'pole', + 'police', + 'pond', + 'pony', + 'pool', + 'popular', + 'portion', + 'position', + 'possible', + 'post', + 'potato', + 'pottery', + 'poverty', + 'powder', + 'power', + 'practice', + 'praise', + 'predict', + 'prefer', + 'prepare', + 'present', + 'pretty', + 'prevent', + 'price', + 'pride', + 'primary', + 'print', + 'priority', + 'prison', + 'private', + 'prize', + 'problem', + 'process', + 'produce', + 'profit', + 'program', + 'project', + 'promote', + 'proof', + 'property', + 'prosper', + 'protect', + 'proud', + 'provide', + 'public', + 'pudding', + 'pull', + 'pulp', + 'pulse', + 'pumpkin', + 'punch', + 'pupil', + 'puppy', + 'purchase', + 'purity', + 'purpose', + 'purse', + 'push', + 'put', + 'puzzle', + 'pyramid', + 'quality', + 'quantum', + 'quarter', + 'question', + 'quick', + 'quit', + 'quiz', + 'quote', + 'rabbit', + 'raccoon', + 'race', + 'rack', + 'radar', + 'radio', + 'rail', + 'rain', + 'raise', + 'rally', + 'ramp', + 'ranch', + 'random', + 'range', + 'rapid', + 'rare', + 'rate', + 'rather', + 'raven', + 'raw', + 'razor', + 'ready', + 'real', + 'reason', + 'rebel', + 'rebuild', + 'recall', + 'receive', + 'recipe', + 'record', + 'recycle', + 'reduce', + 'reflect', + 'reform', + 'refuse', + 'region', + 'regret', + 'regular', + 'reject', + 'relax', + 'release', + 'relief', + 'rely', + 'remain', + 'remember', + 'remind', + 'remove', + 'render', + 'renew', + 'rent', + 'reopen', + 'repair', + 'repeat', + 'replace', + 'report', + 'require', + 'rescue', + 'resemble', + 'resist', + 'resource', + 'response', + 'result', + 'retire', + 'retreat', + 'return', + 'reunion', + 'reveal', + 'review', + 'reward', + 'rhythm', + 'rib', + 'ribbon', + 'rice', + 'rich', + 'ride', + 'ridge', + 'rifle', + 'right', + 'rigid', + 'ring', + 'riot', + 'ripple', + 'risk', + 'ritual', + 'rival', + 'river', + 'road', + 'roast', + 'robot', + 'robust', + 'rocket', + 'romance', + 'roof', + 'rookie', + 'room', + 'rose', + 'rotate', + 'rough', + 'round', + 'route', + 'royal', + 'rubber', + 'rude', + 'rug', + 'rule', + 'run', + 'runway', + 'rural', + 'sad', + 'saddle', + 'sadness', + 'safe', + 'sail', + 'salad', + 'salmon', + 'salon', + 'salt', + 'salute', + 'same', + 'sample', + 'sand', + 'satisfy', + 'satoshi', + 'sauce', + 'sausage', + 'save', + 'say', + 'scale', + 'scan', + 'scare', + 'scatter', + 'scene', + 'scheme', + 'school', + 'science', + 'scissors', + 'scorpion', + 'scout', + 'scrap', + 'screen', + 'script', + 'scrub', + 'sea', + 'search', + 'season', + 'seat', + 'second', + 'secret', + 'section', + 'security', + 'seed', + 'seek', + 'segment', + 'select', + 'sell', + 'seminar', + 'senior', + 'sense', + 'sentence', + 'series', + 'service', + 'session', + 'settle', + 'setup', + 'seven', + 'shadow', + 'shaft', + 'shallow', + 'share', + 'shed', + 'shell', + 'sheriff', + 'shield', + 'shift', + 'shine', + 'ship', + 'shiver', + 'shock', + 'shoe', + 'shoot', + 'shop', + 'short', + 'shoulder', + 'shove', + 'shrimp', + 'shrug', + 'shuffle', + 'shy', + 'sibling', + 'sick', + 'side', + 'siege', + 'sight', + 'sign', + 'silent', + 'silk', + 'silly', + 'silver', + 'similar', + 'simple', + 'since', + 'sing', + 'siren', + 'sister', + 'situate', + 'six', + 'size', + 'skate', + 'sketch', + 'ski', + 'skill', + 'skin', + 'skirt', + 'skull', + 'slab', + 'slam', + 'sleep', + 'slender', + 'slice', + 'slide', + 'slight', + 'slim', + 'slogan', + 'slot', + 'slow', + 'slush', + 'small', + 'smart', + 'smile', + 'smoke', + 'smooth', + 'snack', + 'snake', + 'snap', + 'sniff', + 'snow', + 'soap', + 'soccer', + 'social', + 'sock', + 'soda', + 'soft', + 'solar', + 'soldier', + 'solid', + 'solution', + 'solve', + 'someone', + 'song', + 'soon', + 'sorry', + 'sort', + 'soul', + 'sound', + 'soup', + 'source', + 'south', + 'space', + 'spare', + 'spatial', + 'spawn', + 'speak', + 'special', + 'speed', + 'spell', + 'spend', + 'sphere', + 'spice', + 'spider', + 'spike', + 'spin', + 'spirit', + 'split', + 'spoil', + 'sponsor', + 'spoon', + 'sport', + 'spot', + 'spray', + 'spread', + 'spring', + 'spy', + 'square', + 'squeeze', + 'squirrel', + 'stable', + 'stadium', + 'staff', + 'stage', + 'stairs', + 'stamp', + 'stand', + 'start', + 'state', + 'stay', + 'steak', + 'steel', + 'stem', + 'step', + 'stereo', + 'stick', + 'still', + 'sting', + 'stock', + 'stomach', + 'stone', + 'stool', + 'story', + 'stove', + 'strategy', + 'street', + 'strike', + 'strong', + 'struggle', + 'student', + 'stuff', + 'stumble', + 'style', + 'subject', + 'submit', + 'subway', + 'success', + 'such', + 'sudden', + 'suffer', + 'sugar', + 'suggest', + 'suit', + 'summer', + 'sun', + 'sunny', + 'sunset', + 'super', + 'supply', + 'supreme', + 'sure', + 'surface', + 'surge', + 'surprise', + 'surround', + 'survey', + 'suspect', + 'sustain', + 'swallow', + 'swamp', + 'swap', + 'swarm', + 'swear', + 'sweet', + 'swift', + 'swim', + 'swing', + 'switch', + 'sword', + 'symbol', + 'symptom', + 'syrup', + 'system', + 'table', + 'tackle', + 'tag', + 'tail', + 'talent', + 'talk', + 'tank', + 'tape', + 'target', + 'task', + 'taste', + 'tattoo', + 'taxi', + 'teach', + 'team', + 'tell', + 'ten', + 'tenant', + 'tennis', + 'tent', + 'term', + 'test', + 'text', + 'thank', + 'that', + 'theme', + 'then', + 'theory', + 'there', + 'they', + 'thing', + 'this', + 'thought', + 'three', + 'thrive', + 'throw', + 'thumb', + 'thunder', + 'ticket', + 'tide', + 'tiger', + 'tilt', + 'timber', + 'time', + 'tiny', + 'tip', + 'tired', + 'tissue', + 'title', + 'toast', + 'tobacco', + 'today', + 'toddler', + 'toe', + 'together', + 'toilet', + 'token', + 'tomato', + 'tomorrow', + 'tone', + 'tongue', + 'tonight', + 'tool', + 'tooth', + 'top', + 'topic', + 'topple', + 'torch', + 'tornado', + 'tortoise', + 'toss', + 'total', + 'tourist', + 'toward', + 'tower', + 'town', + 'toy', + 'track', + 'trade', + 'traffic', + 'tragic', + 'train', + 'transfer', + 'trap', + 'trash', + 'travel', + 'tray', + 'treat', + 'tree', + 'trend', + 'trial', + 'tribe', + 'trick', + 'trigger', + 'trim', + 'trip', + 'trophy', + 'trouble', + 'truck', + 'true', + 'truly', + 'trumpet', + 'trust', + 'truth', + 'try', + 'tube', + 'tuition', + 'tumble', + 'tuna', + 'tunnel', + 'turkey', + 'turn', + 'turtle', + 'twelve', + 'twenty', + 'twice', + 'twin', + 'twist', + 'two', + 'type', + 'typical', + 'ugly', + 'umbrella', + 'unable', + 'unaware', + 'uncle', + 'uncover', + 'under', + 'undo', + 'unfair', + 'unfold', + 'unhappy', + 'uniform', + 'unique', + 'unit', + 'universe', + 'unknown', + 'unlock', + 'until', + 'unusual', + 'unveil', + 'update', + 'upgrade', + 'uphold', + 'upon', + 'upper', + 'upset', + 'urban', + 'urge', + 'usage', + 'use', + 'used', + 'useful', + 'useless', + 'usual', + 'utility', + 'vacant', + 'vacuum', + 'vague', + 'valid', + 'valley', + 'valve', + 'van', + 'vanish', + 'vapor', + 'various', + 'vast', + 'vault', + 'vehicle', + 'velvet', + 'vendor', + 'venture', + 'venue', + 'verb', + 'verify', + 'version', + 'very', + 'vessel', + 'veteran', + 'viable', + 'vibrant', + 'vicious', + 'victory', + 'video', + 'view', + 'village', + 'vintage', + 'violin', + 'virtual', + 'virus', + 'visa', + 'visit', + 'visual', + 'vital', + 'vivid', + 'vocal', + 'voice', + 'void', + 'volcano', + 'volume', + 'vote', + 'voyage', + 'wage', + 'wagon', + 'wait', + 'walk', + 'wall', + 'walnut', + 'want', + 'warfare', + 'warm', + 'warrior', + 'wash', + 'wasp', + 'waste', + 'water', + 'wave', + 'way', + 'wealth', + 'weapon', + 'wear', + 'weasel', + 'weather', + 'web', + 'wedding', + 'weekend', + 'weird', + 'welcome', + 'west', + 'wet', + 'whale', + 'what', + 'wheat', + 'wheel', + 'when', + 'where', + 'whip', + 'whisper', + 'wide', + 'width', + 'wife', + 'wild', + 'will', + 'win', + 'window', + 'wine', + 'wing', + 'wink', + 'winner', + 'winter', + 'wire', + 'wisdom', + 'wise', + 'wish', + 'witness', + 'wolf', + 'woman', + 'wonder', + 'wood', + 'wool', + 'word', + 'work', + 'world', + 'worry', + 'worth', + 'wrap', + 'wreck', + 'wrestle', + 'wrist', + 'write', + 'wrong', + 'yard', + 'year', + 'yellow', + 'you', + 'young', + 'youth', + 'zebra', + 'zero', + 'zone', + 'zoo' +]; + +List _french = [ 'abaisser', 'abandon', 'abdiquer', diff --git a/lib/models/chest_data.dart b/lib/models/chest_data.dart index 48f5579..cd9ab30 100644 --- a/lib/models/chest_data.dart +++ b/lib/models/chest_data.dart @@ -7,7 +7,10 @@ part 'chest_data.g.dart'; @HiveType(typeId: 1) class ChestData extends HiveObject { @HiveField(0) - String? dewif; + String? address; + + @HiveField(1) + String? rootAddress; @HiveField(2) String? name; @@ -25,7 +28,8 @@ class ChestData extends HiveObject { bool? isCesium; ChestData({ - this.dewif, + this.address, + this.rootAddress, this.name, this.defaultWallet, this.imageName, diff --git a/lib/models/chest_data.g.dart b/lib/models/chest_data.g.dart index 33cbaf3..b853f39 100644 --- a/lib/models/chest_data.g.dart +++ b/lib/models/chest_data.g.dart @@ -17,7 +17,8 @@ class ChestDataAdapter extends TypeAdapter { for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), }; return ChestData( - dewif: fields[0] as String?, + address: fields[0] as String?, + rootAddress: fields[1] as String?, name: fields[2] as String?, defaultWallet: fields[3] as int?, imageName: fields[4] as String?, @@ -29,9 +30,11 @@ class ChestDataAdapter extends TypeAdapter { @override void write(BinaryWriter writer, ChestData obj) { writer - ..writeByte(6) + ..writeByte(7) ..writeByte(0) - ..write(obj.dewif) + ..write(obj.address) + ..writeByte(1) + ..write(obj.rootAddress) ..writeByte(2) ..write(obj.name) ..writeByte(3) diff --git a/lib/models/g1_wallets_list.dart b/lib/models/g1_wallets_list.dart index 1cc62ab..b98a699 100644 --- a/lib/models/g1_wallets_list.dart +++ b/lib/models/g1_wallets_list.dart @@ -11,19 +11,19 @@ class G1WalletsList { @HiveField(1) double? balance; - @HiveField(3) + @HiveField(2) Id? id; - @HiveField(4) + @HiveField(3) Image? avatar; - @HiveField(5) + @HiveField(4) String? username; - @HiveField(6) + @HiveField(5) String? csName; - @HiveField(7) + @HiveField(6) bool? isMembre; G1WalletsList({ diff --git a/lib/models/g1_wallets_list.g.dart b/lib/models/g1_wallets_list.g.dart index bb7c15d..1fcbb43 100644 --- a/lib/models/g1_wallets_list.g.dart +++ b/lib/models/g1_wallets_list.g.dart @@ -1,7 +1,5 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: unused_local_variable - part of 'g1_wallets_list.dart'; // ************************************************************************** @@ -21,11 +19,11 @@ class G1WalletsListAdapter extends TypeAdapter { return G1WalletsList( pubkey: fields[0] as String?, balance: fields[1] as double?, - id: fields[3] as Id?, - avatar: fields[4] as Image?, - username: fields[5] as String?, - csName: fields[6] as String?, - isMembre: fields[7] as bool?, + id: fields[2] as Id?, + avatar: fields[3] as Image?, + username: fields[4] as String?, + csName: fields[5] as String?, + isMembre: fields[6] as bool?, ); } @@ -37,15 +35,15 @@ class G1WalletsListAdapter extends TypeAdapter { ..write(obj.pubkey) ..writeByte(1) ..write(obj.balance) - ..writeByte(3) + ..writeByte(2) ..write(obj.id) - ..writeByte(4) + ..writeByte(3) ..write(obj.avatar) - ..writeByte(5) + ..writeByte(4) ..write(obj.username) - ..writeByte(6) + ..writeByte(5) ..write(obj.csName) - ..writeByte(7) + ..writeByte(6) ..write(obj.isMembre); } @@ -66,10 +64,6 @@ class IdAdapter extends TypeAdapter { @override Id read(BinaryReader reader) { - final numOfFields = reader.readByte(); - final fields = { - for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), - }; return Id(); } diff --git a/lib/models/keystore_data.dart b/lib/models/keystore_data.dart new file mode 100644 index 0000000..9081969 --- /dev/null +++ b/lib/models/keystore_data.dart @@ -0,0 +1,28 @@ +import 'package:hive_flutter/hive_flutter.dart'; +import 'package:polkawallet_sdk/storage/types/keyPairData.dart'; +part 'keystore_data.g.dart'; + +@HiveType(typeId: 4) +class KeyStoreData extends HiveObject { + @HiveField(0) + KeyPairData? keystore; + + KeyStoreData({this.keystore}); + + @override + String toString() { + return keystore!.address!; + } + + String name() { + return keystore!.name!; + } + + String pubkey() { + return keystore!.pubKey!; + } + + Map indexInfo() { + return keystore!.indexInfo!; + } +} diff --git a/lib/models/keystore_data.g.dart b/lib/models/keystore_data.g.dart new file mode 100644 index 0000000..8c8e011 --- /dev/null +++ b/lib/models/keystore_data.g.dart @@ -0,0 +1,41 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'keystore_data.dart'; + +// ************************************************************************** +// TypeAdapterGenerator +// ************************************************************************** + +class KeyStoreDataAdapter extends TypeAdapter { + @override + final int typeId = 4; + + @override + KeyStoreData read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = { + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return KeyStoreData( + keystore: fields[0] as KeyPairData?, + ); + } + + @override + void write(BinaryWriter writer, KeyStoreData obj) { + writer + ..writeByte(1) + ..writeByte(0) + ..write(obj.keystore); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is KeyStoreDataAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} diff --git a/lib/models/stateful_wrapper.dart b/lib/models/stateful_wrapper.dart new file mode 100644 index 0000000..5706812 --- /dev/null +++ b/lib/models/stateful_wrapper.dart @@ -0,0 +1,23 @@ +import 'package:flutter/material.dart'; + +class StatefulWrapper extends StatefulWidget { + final Function onInit; + final Widget child; + const StatefulWrapper({Key? key, required this.onInit, required this.child}) + : super(key: key); + @override + _StatefulWrapperState createState() => _StatefulWrapperState(); +} + +class _StatefulWrapperState extends State { + @override + void initState() { + widget.onInit(); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/models/wallet_data.dart b/lib/models/wallet_data.dart index fc7cf51..4943f51 100644 --- a/lib/models/wallet_data.dart +++ b/lib/models/wallet_data.dart @@ -1,7 +1,5 @@ import 'dart:io'; - import 'package:hive_flutter/hive_flutter.dart'; - part 'wallet_data.g.dart'; @HiveType(typeId: 0) @@ -10,22 +8,26 @@ class WalletData extends HiveObject { int? chest; @HiveField(1) - int? number; + String? address; @HiveField(2) - String? name; + int? number; @HiveField(3) - int? derivation; + String? name; @HiveField(4) - String? imageName; + int? derivation; @HiveField(5) + String? imageName; + + @HiveField(6) File? imageFile; WalletData( {this.chest, + this.address, this.number, this.name, this.derivation, @@ -48,3 +50,10 @@ class WalletData extends HiveObject { return [chest, number]; } } + +class NewWallet { + final String address; + final String password; + + NewWallet._(this.address, this.password); +} diff --git a/lib/models/wallet_data.g.dart b/lib/models/wallet_data.g.dart index 56f2ce8..d6ba5ef 100644 --- a/lib/models/wallet_data.g.dart +++ b/lib/models/wallet_data.g.dart @@ -18,29 +18,32 @@ class WalletDataAdapter extends TypeAdapter { }; return WalletData( chest: fields[0] as int?, - number: fields[1] as int?, - name: fields[2] as String?, - derivation: fields[3] as int?, - imageName: fields[4] as String?, - imageFile: fields[5] as File?, + address: fields[1] as String?, + number: fields[2] as int?, + name: fields[3] as String?, + derivation: fields[4] as int?, + imageName: fields[5] as String?, + imageFile: fields[6] as File?, ); } @override void write(BinaryWriter writer, WalletData obj) { writer - ..writeByte(6) + ..writeByte(7) ..writeByte(0) ..write(obj.chest) ..writeByte(1) - ..write(obj.number) + ..write(obj.address) ..writeByte(2) - ..write(obj.name) + ..write(obj.number) ..writeByte(3) - ..write(obj.derivation) + ..write(obj.name) ..writeByte(4) - ..write(obj.imageName) + ..write(obj.derivation) ..writeByte(5) + ..write(obj.imageName) + ..writeByte(6) ..write(obj.imageFile); } diff --git a/lib/providers/cesium_plus.dart b/lib/providers/cesium_plus.dart index 72c35cc..a50277b 100644 --- a/lib/providers/cesium_plus.dart +++ b/lib/providers/cesium_plus.dart @@ -63,7 +63,7 @@ class CesiumPlusProvider with ChangeNotifier { Future getName(String? _pubkey) async { String? _name; - if (g1WalletsBox.get(_pubkey)!.csName != null) { + if (g1WalletsBox.get(_pubkey)?.csName != null) { return g1WalletsBox.get(_pubkey)!.csName!; } diff --git a/lib/providers/change_pin.dart b/lib/providers/change_pin.dart deleted file mode 100644 index 422cf2b..0000000 --- a/lib/providers/change_pin.dart +++ /dev/null @@ -1,48 +0,0 @@ -import 'package:durt/durt.dart'; -import 'package:flutter/material.dart'; -import 'package:gecko/globals.dart'; - -class ChangePinProvider with ChangeNotifier { - bool ischangedPin = false; - TextEditingController newPin = TextEditingController(); - String? pinToGive; - - NewWallet? get badWallet => null; - - Future changePin(String _oldPin, {String? newCustomPin}) async { - final NewWallet newWalletFile; - try { - final _chest = chestBox.get(configBox.get('currentChest'))!; - - if (_chest.isCesium!) { - newWalletFile = await Dewif().changeCesiumPassword( - dewif: _chest.dewif!, - oldPassword: _oldPin.toUpperCase(), - newPassword: newCustomPin); - } else { - newWalletFile = await Dewif().changePassword( - dewif: _chest.dewif!, - oldPassword: _oldPin.toUpperCase(), - newPassword: newCustomPin); - } - newPin.text = pinToGive = newWalletFile.password; - ischangedPin = true; - // notifyListeners(); - return newWalletFile; - } catch (e) { - log.e('Impossible de changer le code PIN: $e'); - return badWallet; - } - } - - void storeNewPinChest(context, NewWallet _newWalletFile) { - // ChestData currentChest = chestBox.getAt(configBox.get('currentChest')); - // currentChest.dewif = _newWalletFile.dewif; - // await chestBox.add(currentChest); - - chestBox.get(configBox.get('currentChest'))!.dewif = _newWalletFile.dewif; - - Navigator.pop(context, pinToGive); - pinToGive = ''; - } -} diff --git a/lib/providers/generate_wallets.dart b/lib/providers/generate_wallets.dart index 43a389a..ffa30da 100644 --- a/lib/providers/generate_wallets.dart +++ b/lib/providers/generate_wallets.dart @@ -1,21 +1,22 @@ import 'dart:math'; import 'dart:typed_data'; -import 'package:durt/durt.dart'; +import 'package:durt/durt.dart' as durt; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:gecko/globals.dart'; import 'package:gecko/models/bip39_words.dart'; import 'package:gecko/models/chest_data.dart'; import 'package:gecko/models/wallet_data.dart'; +import 'package:gecko/providers/substrate_sdk.dart'; import 'package:pdf/pdf.dart'; import 'package:pdf/widgets.dart' as pw; -import 'package:printing/printing.dart'; +import 'package:provider/provider.dart'; import "package:unorm_dart/unorm_dart.dart" as unorm; class GenerateWalletsProvider with ChangeNotifier { GenerateWalletsProvider(); // NewWallet generatedWallet; - NewWallet? actualWallet; + durt.NewWallet? actualWallet; FocusNode walletNameFocus = FocusNode(); Color? askedWordColor = Colors.black; @@ -37,7 +38,7 @@ class GenerateWalletsProvider with ChangeNotifier { bool isCesiumIDVisible = false; bool isCesiumPWDVisible = false; bool canImport = false; - late CesiumWallet cesiumWallet; + late durt.CesiumWallet cesiumWallet; // Import Chest TextEditingController cellController0 = TextEditingController(); @@ -55,7 +56,7 @@ class GenerateWalletsProvider with ChangeNotifier { bool isFirstTimeSentenceComplete = true; Future storeHDWChest( - NewWallet _wallet, String _name, BuildContext context) async { + String address, String _name, BuildContext context) async { int chestNumber = 0; chestBox.toMap().forEach((key, value) { if (!value.isCesium!) { @@ -70,7 +71,7 @@ class GenerateWalletsProvider with ChangeNotifier { chestName = 'Coffre à Ğecko ${chestNumber + 1}'; } ChestData thisChest = ChestData( - dewif: _wallet.dewif, + address: address, name: chestName, defaultWallet: 0, imageName: '${chestNumber % 8}.png', @@ -81,9 +82,10 @@ class GenerateWalletsProvider with ChangeNotifier { WalletData myWallet = WalletData( chest: chestKey, + address: address, number: 0, name: _name, - derivation: 3, + derivation: 2, imageName: '0.png'); await walletBox.add(myWallet); @@ -152,64 +154,78 @@ class GenerateWalletsProvider with ChangeNotifier { notifyListeners(); } - Future generateWallet(String generatedMnemonic, - {required bool isImport}) async { - try { - actualWallet = await Dewif().generateDewif( - generatedMnemonic, randomSecretCode(pinLength), - lang: appLang); - } catch (e) { - log.e(e); - } - - if (!isImport) { - mnemonicController.text = generatedMnemonic; - pin.text = actualWallet!.password; - } - // notifyListeners(); - - return actualWallet; - } - String changePinCode({required bool reload}) { - pin.text = randomSecretCode(pinLength); + pin.text = durt.randomSecretCode(pinLength); if (reload) { notifyListeners(); } return pin.text; } - Future printWallet(String? _title) async { + Future printWallet(AsyncSnapshot? mnemoList) 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 = AssetImage('assets/icon/gecko_final.png'); - final geckoLogo = await flutterImageProvider(imageProvider); + // const imageProvider = AssetImage('assets/icon/gecko_final.png'); + // final geckoLogo = await flutterImageProvider(imageProvider); + + pw.Widget arrayCell(dataWord) { + return pw.SizedBox( + width: 120, + child: pw.Column(children: [ + pw.Text( + dataWord.split(':')[0], + style: pw.TextStyle( + fontSize: 15, color: const PdfColor(0.5, 0, 0), font: ttf), + ), + pw.Text( + dataWord.split(':')[1], + style: pw.TextStyle( + fontSize: 20, color: const PdfColor(0, 0, 0), font: ttf), + ), + pw.SizedBox(height: 10) + ]), + ); + } pdf.addPage( pw.Page( pageFormat: PdfPageFormat.a4, build: (context) { - return pw.Column(children: [ - 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 pw.Column( + // mainAxisAlignment: pw.MainAxisAlignment.center, + // mainAxisSize: pw.MainAxisSize.max, + // crossAxisAlignment: pw.CrossAxisAlignment.center, + children: [ + pw.Row(children: [ + arrayCell(mnemoList!.data![0]), + arrayCell(mnemoList.data![1]), + arrayCell(mnemoList.data![2]), + arrayCell(mnemoList.data![3]), + ]), + pw.Row(children: [ + arrayCell(mnemoList.data![4]), + arrayCell(mnemoList.data![5]), + arrayCell(mnemoList.data![6]), + arrayCell(mnemoList.data![7]), + ]), + pw.Row(children: [ + arrayCell(mnemoList.data![8]), + arrayCell(mnemoList.data![9]), + arrayCell(mnemoList.data![10]), + arrayCell(mnemoList.data![11]) + ]), + pw.Expanded( + child: pw.Align( + alignment: pw.Alignment.bottomCenter, + child: pw.Text( + "Gardez cette feuille préciseusement, à l’abri des lézards indiscrets.", + style: pw.TextStyle(fontSize: 15, font: ttf), + ))) + ], + ); }, ), ); @@ -219,63 +235,13 @@ class GenerateWalletsProvider with ChangeNotifier { Future generateCesiumWalletPubkey( String _cesiumID, String _cesiumPWD) async { - cesiumWallet = CesiumWallet(_cesiumID, _cesiumPWD); + cesiumWallet = durt.CesiumWallet(_cesiumID, _cesiumPWD); String _walletPubkey = cesiumWallet.pubkey; cesiumPubkey.text = _walletPubkey; log.d(_walletPubkey); } - Future importCesiumWallet() async { - // String _walletPubkey = await DubpRust.getLegacyPublicKey( - // salt: _cesiumID, password: _cesiumPWD); - // String shortPubkey = truncate(_walletPubkey, 9, - // omission: "...", position: TruncatePosition.end); - // await storeWallet( - // actualWallet, 'Portefeuille Cesium - $shortPubkey', context); - // NewWallet myCesiumWallet = await DubpRust.genWalletFromDeprecatedSaltPassword(salt: _cesiumID, password: _cesiumPWD); - - cesiumID.text = ''; - cesiumPWD.text = ''; - cesiumPubkey.text = ''; - canImport = false; - isCesiumIDVisible = false; - isCesiumPWDVisible = false; - - int chestNumber = 0; - chestBox.toMap().forEach((key, value) { - if (value.isCesium!) { - chestNumber++; - } - }); - - String chestName; - if (chestNumber == 0) { - chestName = 'Coffre à Césium'; - } else { - chestName = 'Coffre à Césium ${chestNumber + 1}'; - } - - log.d(pin.text); - NewWallet cesiumDewif = - await Dewif().generateCesiumDewif(cesiumWallet.seed, pin.text); - - ChestData cesiumChest = ChestData( - dewif: cesiumDewif.dewif, - name: chestName, - imageName: 'cesium.png', - defaultWallet: 0, - isCesium: true); - - await chestBox.add(cesiumChest).then((value) => null); - int? chestKey = await chestBox.toMap().keys.last; - // chestBox.toMap(). - await configBox.put('currentChest', chestKey); - - pin.text = ''; - return chestKey; - } - void cesiumIDisVisible() { isCesiumIDVisible = !isCesiumIDVisible; notifyListeners(); @@ -293,8 +259,10 @@ class GenerateWalletsProvider with ChangeNotifier { notifyListeners(); } - List generateWordList() { - generatedMnemonic = generateMnemonic(lang: appLang); + Future> generateWordList(BuildContext context) async { + SubstrateSdk _sub = Provider.of(context, listen: false); + + generatedMnemonic = await _sub.generateMnemonic(lang: appLang); List _wordsList = []; String word; int _nbr = 1; @@ -313,7 +281,7 @@ class GenerateWalletsProvider with ChangeNotifier { // Needed for bad encoding of UTF-8 word = word.replaceAll('é', 'é'); word = word.replaceAll('è', 'è'); - return bip39Words.contains(word); + return bip39Words(appLang).contains(word); } bool isBipWordsList(List words) { @@ -322,7 +290,7 @@ class GenerateWalletsProvider with ChangeNotifier { // Needed for bad encoding of UTF-8 word = word.replaceAll('é', 'é'); word = word.replaceAll('è', 'è'); - if (!bip39Words.contains(word)) { + if (!bip39Words(appLang).contains(word)) { isValid = false; } } @@ -333,8 +301,8 @@ class GenerateWalletsProvider with ChangeNotifier { cellController0.text = cellController1.text = cellController2.text = cellController3.text = cellController4.text = cellController5.text = cellController6.text = cellController7.text = cellController8.text = - cellController9.text = cellController10.text = - cellController11.text = ''; + cellController9.text = + cellController10.text = cellController11.text = ''; isFirstTimeSentenceComplete = true; notifyListeners(); } @@ -366,22 +334,31 @@ class GenerateWalletsProvider with ChangeNotifier { } } - Future isSentenceValid() async { - String inputMnemonic = - '${cellController0.text} ${cellController1.text} ${cellController2.text} ${cellController3.text} ${cellController4.text} ${cellController5.text} ${cellController6.text} ${cellController7.text} ${cellController8.text} ${cellController9.text} ${cellController10.text} ${cellController11.text}'; + Future pasteMnemonic(BuildContext context) async { + final sentence = await Clipboard.getData('text/plain'); + int nbr = 0; - // Needed for bad encoding of UTF-8 - inputMnemonic = inputMnemonic.replaceAll('é', 'é'); - inputMnemonic = inputMnemonic.replaceAll('è', 'è'); + List cells = [ + cellController0, + cellController1, + cellController2, + cellController3, + cellController4, + cellController5, + cellController6, + cellController7, + cellController8, + cellController9, + cellController10, + cellController11 + ]; + for (var word in sentence!.text!.split(' ')) { + bool isValid = isBipWord(word); - NewWallet? generatedWallet = - await generateWallet(inputMnemonic, isImport: true); - - if (generatedWallet == null) { - return false; - } else { - generatedMnemonic = inputMnemonic; - return true; + if (isValid) { + cells[nbr].text = word; + } + nbr++; } } diff --git a/lib/providers/home.dart b/lib/providers/home.dart index 07f0a6b..2f59221 100644 --- a/lib/providers/home.dart +++ b/lib/providers/home.dart @@ -139,22 +139,6 @@ class HomeProvider with ChangeNotifier { notifyListeners(); } - void snackNode(context) { - if (isFirstBuild) { - String _message; - if (endPointGVA == 'HS') { - _message = - "Aucun noeud Duniter disponible, veuillez réessayer ultérieurement"; - } else { - _message = "Vous êtes connecté au noeud\n${endPointGVA.split('/')[2]}"; - } - final snackBar = SnackBar( - content: Text(_message), duration: const Duration(seconds: 2)); - isFirstBuild = false; - ScaffoldMessenger.of(context).showSnackBar(snackBar); - } - } - void rebuildWidget() { notifyListeners(); } diff --git a/lib/providers/my_wallets.dart b/lib/providers/my_wallets.dart index e826a83..2f12bae 100644 --- a/lib/providers/my_wallets.dart +++ b/lib/providers/my_wallets.dart @@ -1,10 +1,11 @@ import 'dart:typed_data'; - -import 'package:durt/durt.dart'; import 'package:flutter/material.dart'; import 'dart:async'; import 'package:gecko/globals.dart'; +import 'package:gecko/models/chest_data.dart'; import 'package:gecko/models/wallet_data.dart'; +import 'package:gecko/providers/substrate_sdk.dart'; +import 'package:provider/provider.dart'; class MyWalletsProvider with ChangeNotifier { List listWallets = []; @@ -21,25 +22,13 @@ class MyWalletsProvider with ChangeNotifier { return configBox.get('currentChest'); } - String dewifToMnemonic(context, WalletData _wallet, String _pin) { - String _mnemonic; - - try { - String _localDewif = chestBox.get(_wallet.chest)!.dewif!; - _mnemonic = Dewif() - .mnemonicFromDewif(_localDewif, _pin.toUpperCase(), lang: appLang); - } on ChecksumException catch (e) { - log.e(e.cause); - return 'bad'; - } catch (e) { - // _homeProvider.playSound('non', 0.6); - log.e('ERROR READING FILE: $e'); - return 'bad'; - } - return _mnemonic; - } - bool checkIfWalletExist() { + // configBox.delete('endpoint'); + if (!configBox.containsKey('endpoint') || configBox.get('endpoint') == '') { + log.d('No endpoint, configure...'); + configBox.put('endpoint', 'ws://127.0.0.1:9944'); + } + if (chestBox.isEmpty) { log.i('No wallets detected'); return false; @@ -85,6 +74,7 @@ class MyWalletsProvider with ChangeNotifier { } Future deleteAllWallet(context) async { + SubstrateSdk _sub = Provider.of(context, listen: false); try { log.w('DELETE ALL WALLETS ?'); @@ -93,9 +83,7 @@ class MyWalletsProvider with ChangeNotifier { await walletBox.clear(); await chestBox.clear(); await configBox.delete('defaultWallet'); - // await Future.delayed(const Duration(milliseconds: 50)); - // notifyListeners(); - + await _sub.deleteAllAccounts(); await Navigator.of(context).pushNamedAndRemoveUntil( '/', ModalRoute.withName('/'), @@ -113,23 +101,42 @@ class MyWalletsProvider with ChangeNotifier { barrierDismissible: true, // user must tap button! builder: (BuildContext context) { return AlertDialog( - title: const Text( - 'Êtes-vous sûr de vouloir supprimer tous vos trousseaux ?'), - content: const SingleChildScrollView(child: Text('')), + backgroundColor: backgroundColor, + content: const Text( + 'Êtes-vous sûr de vouloir oublier tous vos coffres ?', + textAlign: TextAlign.center, + style: TextStyle(fontSize: 18, fontWeight: FontWeight.w500), + ), actions: [ - TextButton( - child: const Text("Non"), - onPressed: () { - Navigator.pop(context, false); - }, - ), - TextButton( - key: const Key('confirmDeletingAllWallets'), - child: const Text("Oui"), - onPressed: () { - Navigator.pop(context, true); - }, - ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + TextButton( + key: const Key('confirmDeletingAllWallets'), + child: const Text( + "Oui", + style: TextStyle( + fontSize: 20, + color: Color(0xffD80000), + ), + ), + onPressed: () { + Navigator.pop(context, true); + }, + ), + const SizedBox(width: 20), + TextButton( + child: const Text( + "Non", + style: TextStyle(fontSize: 20), + ), + onPressed: () { + Navigator.pop(context, false); + }, + ), + const SizedBox(height: 120) + ], + ) ], ); }, @@ -143,15 +150,27 @@ class MyWalletsProvider with ChangeNotifier { List _walletConfig = readAllWallets(_chest); if (_walletConfig.isEmpty) { - _newDerivationNbr = 3; + _newDerivationNbr = 2; _newWalletNbr = 0; } else { - _newDerivationNbr = _walletConfig.last.derivation! + 3; + _newDerivationNbr = _walletConfig.last.derivation! + 2; _newWalletNbr = _walletConfig.last.number! + 1; } + MyWalletsProvider myWalletProvider = + Provider.of(context, listen: false); + + SubstrateSdk _sub = Provider.of(context, listen: false); + + final int? _currentChestNumber = myWalletProvider.getCurrentChest(); + final ChestData _currentChest = chestBox.get(_currentChestNumber)!; + + final address = await _sub.derive( + context, _currentChest.address!, _newDerivationNbr, pinCode); + WalletData newWallet = WalletData( chest: _chest, + address: address, number: _newWalletNbr, name: _name, derivation: _newDerivationNbr, diff --git a/lib/providers/substrate_sdk.dart b/lib/providers/substrate_sdk.dart new file mode 100644 index 0000000..c41d9c7 --- /dev/null +++ b/lib/providers/substrate_sdk.dart @@ -0,0 +1,371 @@ +// ignore_for_file: avoid_print + +import 'package:crypto/crypto.dart'; +import 'package:fast_base58/fast_base58.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:gecko/globals.dart'; +import 'package:polkawallet_sdk/api/apiKeyring.dart'; +import 'package:polkawallet_sdk/api/types/networkParams.dart'; +import 'package:polkawallet_sdk/api/types/txInfoData.dart'; +import 'package:polkawallet_sdk/polkawallet_sdk.dart'; +import 'package:polkawallet_sdk/storage/keyring.dart'; +import 'package:polkawallet_sdk/storage/types/keyPairData.dart'; +import 'package:truncate/truncate.dart'; + +class SubstrateSdk with ChangeNotifier { + final int ss58 = 42; + + final WalletSDK sdk = WalletSDK(); + final Keyring keyring = Keyring(); + String generatedMnemonic = ''; + bool sdkReady = false; + bool sdkLoading = false; + bool nodeConnected = false; + bool importIsLoading = false; + int blocNumber = 0; + bool isLoadingEndpoint = false; + + TextEditingController jsonKeystore = TextEditingController(); + TextEditingController keystorePassword = TextEditingController(); + + Future initApi() async { + sdkLoading = true; + await keyring.init([ss58]); + keyring.setSS58(ss58); + + await sdk.init(keyring); + sdkReady = true; + sdkLoading = false; + notifyListeners(); + } + + Future connectNode(BuildContext ctx) async { + List node = []; + final n = NetworkParams(); + n.name = currencyName; + n.endpoint = configBox.get('endpoint'); + n.ss58 = ss58; + node.add(n); + + if (sdk.api.connectedNode?.endpoint != null) { + await sdk.api.setting.unsubscribeBestNumber(); + } + + isLoadingEndpoint = true; + notifyListeners(); + final res = await sdk.api.connectNode(keyring, node).timeout( + const Duration(seconds: 7), + onTimeout: () => null, + ); + isLoadingEndpoint = false; + notifyListeners(); + if (res != null) { + nodeConnected = true; + notifyListeners(); + snackNode(ctx, true); + } else { + nodeConnected = false; + notifyListeners(); + snackNode(ctx, false); + } + + // Subscribe bloc number + if (nodeConnected) { + sdk.api.setting.subscribeBestNumber((res) { + blocNumber = int.parse(res.toString()); + notifyListeners(); + }); + } + + log.d(sdk.api.connectedNode?.endpoint); + } + + Future importAccount( + {String mnemonic = '', + bool fromMnemonic = false, + String derivePath = '', + String password = ''}) async { + // toy exercise immense month enter answer table prefer speed cycle gold phone + final clipboardData = await Clipboard.getData(Clipboard.kTextPlain); + if (mnemonic != '') { + fromMnemonic = true; + generatedMnemonic = mnemonic; + } else if (clipboardData!.text!.split(' ').length == 12) { + fromMnemonic = true; + generatedMnemonic = clipboardData.text!; + } + + if (password == '') { + password = keystorePassword.text; + } + + final KeyType keytype; + final String keyToImport; + if (fromMnemonic) { + keytype = KeyType.mnemonic; + keyToImport = generatedMnemonic; + } else { + keytype = KeyType.keystore; + keyToImport = jsonKeystore.text.replaceAll("'", "\\'"); + } + + importIsLoading = true; + notifyListeners(); + if (clipboardData?.text != null) jsonKeystore.text = clipboardData!.text!; + var json = await sdk.api.keyring + .importAccount(keyring, + keyType: keytype, + key: keyToImport, + name: derivePath, + password: password, + derivePath: derivePath, + cryptoType: CryptoType.sr25519) + .catchError((e) { + importIsLoading = false; + notifyListeners(); + }); + if (json == null) return ''; + print(json); + try { + await sdk.api.keyring.addAccount( + keyring, + keyType: keytype, + acc: json, + password: password, + ); + // Clipboard.setData(ClipboardData(text: jsonEncode(acc.toJson()))); + } catch (e) { + print(e); + importIsLoading = false; + notifyListeners(); + } + + importIsLoading = false; + await Future.delayed(const Duration(milliseconds: 20)); + notifyListeners(); + final bakedAddress = keyring.allAccounts.last.address; + return bakedAddress!; + } + + void reload() { + notifyListeners(); + } + + Future> getKeyStoreAddress() async { + List result = []; + + // sdk.api.account.unsubscribeBalance(); + for (var element in keyring.allAccounts) { + // Clipboard.setData(ClipboardData(text: jsonEncode(element))); + final account = AddressInfo(address: element.address); + // await sdk.api.account.subscribeBalance(element.address, (p0) { + // account.balance = int.parse(p0.freeBalance) / 100; + // }); + // sdk.api.setting.unsubscribeBestNumber(); + account.balance = await getBalance(element.address!); + result.add(account); + } + + return result; + } + + Future getBalance(String address, {bool isUd = false}) async { + double balance = 0.0; + if (nodeConnected) { + final brutBalance = await sdk.api.account.queryBalance(address); + balance = int.parse(brutBalance!.freeBalance) / 100; + } + return balance; + } + + KeyPairData getKeypair(String address) { + return keyring.keyPairs.firstWhere((kp) => kp.address == address, + orElse: (() => KeyPairData())); + } + + Future checkPassword(String address, String pass) async { + final account = getKeypair(address); + return await sdk.api.keyring.checkPassword(account, pass); + } + + int getDerivationNumber(String address) { + final account = getKeypair(address); + final deriveNbr = account.name!.split('//')[1]; + return int.parse(deriveNbr); + } + + Future changePassword( + String address, String passOld, String? passNew) async { + final account = getKeypair(address); + keyring.setCurrent(account); + + return await sdk.api.keyring.changePassword(keyring, passOld, passNew); + } + + Future deleteAllAccounts() async { + for (var account in keyring.allAccounts) { + await sdk.api.keyring.deleteAccount(keyring, account); + } + } + + Future generateMnemonic({String lang = appLang}) async { + final gen = await sdk.api.keyring.generateMnemonic(ss58); + generatedMnemonic = gen.mnemonic!; + + // final res = await importAccount(fromMnemonic: true); + // await Clipboard.setData(ClipboardData(text: generatedMnemonic)); + return gen.mnemonic!; + } + + // Future pay(BuildContext context, String address, double amount, + // String password) async { + // final sender = TxSenderData( + // keyring.current.address, + // keyring.current.pubKey, + // ); + // final txInfo = TxInfoData('balances', 'transfer', sender); + // try { + // final hash = await sdk.api.tx.signAndSend( + // txInfo, + // [address, amount * 100], + // password, + // onStatusChange: (status) { + // print('status: ' + status); + // if (status == 'Ready') { + // snack(context, 'Transaction terminé'); + // } + // }, + // ); + // print(hash.toString()); + // return true; + // } catch (err) { + // print(err.toString()); + // return false; + // } + // } + + String setCurrentWallet(String address) { + try { + final acc = getKeypair(address); + keyring.setCurrent(acc); + return acc.address!; + } catch (e) { + return (e.toString()); + } + } + + KeyPairData getCurrentWallet() { + try { + final acc = keyring.current; + return acc; + } catch (e) { + return KeyPairData(); + } + } + + Future pay(BuildContext context, + {required String fromAddress, + required String destAddress, + required double amount, + required String password}) async { + setCurrentWallet(fromAddress); + + final sender = TxSenderData( + keyring.current.address, + keyring.current.pubKey, + ); + final txInfo = TxInfoData('balances', 'transfer', sender); + try { + final hash = await sdk.api.tx.signAndSend( + txInfo, + [destAddress, amount * 100], + password, + onStatusChange: (status) { + print('status: ' + status); + if (status == 'Ready') { + snack(context, 'Transaction terminé'); + } + }, + ); + print(hash.toString()); + return 'confirmed'; + } catch (e) { + return e.toString(); + } + } + + Future derive( + BuildContext context, String address, int number, String password) async { + final keypair = getKeypair(address); + + final seedMap = + await keyring.store.getDecryptedSeed(keypair.pubKey, password); + print(seedMap); + + if (seedMap?['type'] != 'mnemonic') return ''; + final List seedList = seedMap!['seed'].split('//'); + generatedMnemonic = seedList[0]; + int sourceDerivation = -1; // To get derivation number of this account + if (seedList.length > 1) { + sourceDerivation = int.parse(seedList[1]); + } + print(generatedMnemonic); + print(sourceDerivation); + + return await importAccount(fromMnemonic: true, derivePath: '//$number'); + } + + Future isMnemonicValid(String mnemonic) async { + // Needed for bad encoding of UTF-8 + mnemonic = mnemonic.replaceAll('é', 'é'); + mnemonic = mnemonic.replaceAll('è', 'è'); + + return await sdk.api.keyring.checkMnemonicValid(mnemonic); + } +} + +void snack(BuildContext context, String message, {int duration = 2}) { + final snackBar = + SnackBar(content: Text(message), duration: Duration(seconds: duration)); + ScaffoldMessenger.of(context).showSnackBar(snackBar); +} + +class AddressInfo { + final String? address; + double balance; + + AddressInfo({@required this.address, this.balance = 0}); +} + +void snackNode(BuildContext context, bool isConnected) { + String _message; + if (!isConnected) { + _message = + "Aucun noeud Duniter disponible, veuillez réessayer ultérieurement"; + } else { + _message = + "Vous êtes connecté au noeud\n${configBox.get('endpoint').split('//')[1]}"; + } + final snackBar = SnackBar( + padding: const EdgeInsets.all(20), + content: Text(_message, style: const TextStyle(fontSize: 16)), + duration: const Duration(seconds: 2)); + ScaffoldMessenger.of(context).showSnackBar(snackBar); +} + +String getShortPubkey(String pubkey) { + List pubkeyByte = Base58Decode(pubkey); + Digest pubkeyS256 = sha256.convert(sha256.convert(pubkeyByte).bytes); + String pubkeyCheksum = Base58Encode(pubkeyS256.bytes); + String pubkeyChecksumShort = + truncate(pubkeyCheksum, 3, omission: "", position: TruncatePosition.end); + + String pubkeyShort = truncate(pubkey, 5, + omission: String.fromCharCode(0x2026), + position: TruncatePosition.end) + + truncate(pubkey, 4, omission: "", position: TruncatePosition.start) + + ':$pubkeyChecksumShort'; + + return pubkeyShort; +} diff --git a/lib/providers/wallet_options.dart b/lib/providers/wallet_options.dart index 1056d7c..9f2c4a1 100644 --- a/lib/providers/wallet_options.dart +++ b/lib/providers/wallet_options.dart @@ -1,139 +1,41 @@ import 'dart:io'; import 'package:crypto/crypto.dart'; -import 'package:durt/durt.dart'; import 'package:fast_base58/fast_base58.dart'; import 'package:flutter/material.dart'; import 'dart:async'; import 'package:gecko/globals.dart'; -import 'package:gecko/models/chest_data.dart'; import 'package:gecko/providers/my_wallets.dart'; import 'package:gecko/models/wallet_data.dart'; +import 'package:gecko/providers/substrate_sdk.dart'; import 'package:image_picker/image_picker.dart'; +import 'package:provider/provider.dart'; import 'package:truncate/truncate.dart'; class WalletOptionsProvider with ChangeNotifier { - TextEditingController pubkey = TextEditingController(); + TextEditingController address = TextEditingController(); final TextEditingController _newWalletName = TextEditingController(); bool isWalletUnlock = false; bool ischangedPin = false; TextEditingController newPin = TextEditingController(); bool isEditing = false; - bool isBalanceBlur = true; + bool isBalanceBlur = false; FocusNode walletNameFocus = FocusNode(); TextEditingController nameController = TextEditingController(); late bool isDefaultWallet; Future? get badWallet => null; - String _getPubkeyFromDewif( - String? _dewif, _pin, int _pinLenght, int? derivation) { - RegExp regExp = RegExp( - r'^[A-Z0-9]+$', - caseSensitive: false, - multiLine: false, - ); - - if (regExp.hasMatch(_pin) == true && _pin.length == _pinLenght) { - } else { - return 'false'; - } - if (derivation != -1) { - try { - final _wallet = HdWallet.fromDewif(_dewif!, _pin, lang: appLang); - pubkey.text = _wallet.getPubkey(derivation!); - log.d(pubkey.text); - notifyListeners(); - - return pubkey.text; - } catch (e) { - log.w('Bad PIN code !\n' + e.toString()); - notifyListeners(); - - return 'false'; - } - } else { - try { - pubkey.text = CesiumWallet.fromDewif(_dewif!, _pin).pubkey; - notifyListeners(); - return pubkey.text; - } catch (e) { - log.w('Bad PIN code !\n' + e.toString()); - notifyListeners(); - - return 'false'; - } - } - } - - String? readLocalWallet( - context, WalletData _wallet, String _pin, int _pinLenght, - {String? mnemonic}) { - isWalletUnlock = false; - final String _localPubkey; - - try { - String? _localDewif = chestBox.get(_wallet.chest)!.dewif; - - if (mnemonic == null) { - _localPubkey = _getPubkeyFromDewif( - _localDewif, _pin.toUpperCase(), _pinLenght, _wallet.derivation); - } else { - final _hdwallet = HdWallet.fromMnemonic(mnemonic); - _localPubkey = _hdwallet.getPubkey(_wallet.derivation!); - } - - if (_localPubkey != 'false') { - pubkey.text = _localPubkey; - isWalletUnlock = true; - log.d(pubkey.text); - return _localDewif; - } else { - throw 'Bad pubkey'; - } - } on ChecksumException catch (e) { - log.e(e.cause); - return 'bad'; - } catch (e) { - // _homeProvider.playSound('non', 0.6); - log.e('ERROR READING FILE: $e'); - pubkey.clear(); - return 'bad'; - } - } - int getPinLenght(_walletNbr) { - // TODOo: Get real Dewif lenght - // String _localDewif; - // if (_walletNbr is int || _walletNbr == null) { - // _localDewif = chestBox.get(configBox.get('currentChest')).dewif; - // } else { - // _localDewif = _walletNbr; - // } - - // final int _pinLenght = DubpRust.getDewifSecretCodeLen( - // dewif: _localDewif, secretCodeType: SecretCodeType.letters); - return pinLength; } - Future getBalance(String pubkey, {bool isUd = false}) async { - final node = Gva(node: endPointGVA); - return await node.balance(pubkey, ud: isUd); - } - - void _renameWallet(List _walletID, _newName, + void _renameWallet(List _walletID, String _newName, {required bool isCesium}) async { - if (isCesium) { - ChestData _chestTarget = chestBox.get(_walletID[0])!; - _chestTarget.name = _newName; - await chestBox.put(_chestTarget.key, _chestTarget); - } else { - MyWalletsProvider myWalletClass = MyWalletsProvider(); + MyWalletsProvider myWalletClass = MyWalletsProvider(); - WalletData _walletTarget = myWalletClass.getWalletData(_walletID)!; - _walletTarget.name = _newName; - await walletBox.put(_walletTarget.key, _walletTarget); - } + WalletData _walletTarget = myWalletClass.getWalletData(_walletID)!; + _walletTarget.name = _newName; + await walletBox.put(_walletTarget.key, _walletTarget); _newWalletName.text = ''; } @@ -161,12 +63,13 @@ class WalletOptionsProvider with ChangeNotifier { final bool? _answer = await (_confirmDeletingWallet(context, wallet.name)); if (_answer!) { - walletBox.delete(wallet.key); + await walletBox.delete(wallet.key); - Navigator.popUntil( - context, - ModalRoute.withName('/mywallets'), - ); + // Navigator.popUntil( + // context, + // ModalRoute.withName('/mywallets'), + // ); + Navigator.pop(context); } return 0; } @@ -205,14 +108,6 @@ class WalletOptionsProvider with ChangeNotifier { ); } - snackCopyKey(context) { - const snackBar = SnackBar( - content: - Text("Cette clé publique a été copié dans votre presse-papier."), - duration: Duration(seconds: 2)); - ScaffoldMessenger.of(context).showSnackBar(snackBar); - } - String getShortPubkey(String pubkey) { List pubkeyByte = Base58Decode(pubkey); Digest pubkeyS256 = sha256.convert(sha256.convert(pubkeyByte).bytes); @@ -242,14 +137,59 @@ class WalletOptionsProvider with ChangeNotifier { if (pickedFile != null) { _image = File(pickedFile.path); + + ////TODO: Store image on disk, store path in walletBox.imagePath + log.i(pickedFile.path); return _image; } else { log.w('No image selected.'); + return null; } } void reloadBuild() { notifyListeners(); } + + String? getAddress(int chest, int derivation) { + String? _address; + walletBox.toMap().forEach((key, value) { + if (value.chest == chest && value.derivation == derivation) { + _address = value.address!; + return; + } + }); + + address.text = _address ?? ''; + + return _address; + } +} + +Widget balance(BuildContext context, String address, double size) { + String balanceCache = ''; + + return Column(children: [ + Consumer(builder: (context, _sdk, _) { + return FutureBuilder( + future: _sdk.getBalance(address), + builder: (BuildContext context, AsyncSnapshot _balance) { + if (_balance.connectionState != ConnectionState.done || + _balance.hasError) { + return Text(balanceCache, + style: TextStyle( + fontSize: isTall ? size : size * 0.9, + )); + } + balanceCache = "${_balance.data.toString()} $currencyName"; + return Text( + balanceCache, + style: TextStyle( + fontSize: isTall ? size : 18, + ), + ); + }); + }), + ]); } diff --git a/lib/providers/wallets_profiles.dart b/lib/providers/wallets_profiles.dart index 3e09355..e26291e 100644 --- a/lib/providers/wallets_profiles.dart +++ b/lib/providers/wallets_profiles.dart @@ -1,14 +1,10 @@ import 'dart:io'; - -import 'package:durt/durt.dart'; import 'package:flutter/material.dart'; import 'package:gecko/globals.dart'; -import 'package:gecko/providers/my_wallets.dart'; import 'package:gecko/screens/wallet_view.dart'; import 'package:graphql_flutter/graphql_flutter.dart'; import 'package:jdenticon_dart/jdenticon_dart.dart'; import 'package:permission_handler/permission_handler.dart'; -import 'package:provider/provider.dart'; import 'package:qrscan/qrscan.dart' as scanner; import 'dart:math'; import 'package:intl/intl.dart'; @@ -59,34 +55,24 @@ class WalletsProfilesProvider with ChangeNotifier { return barcode; } - Future pay(BuildContext context, {int? derivation}) async { - MyWalletsProvider _myWalletProvider = - Provider.of(context, listen: false); - int? currentChest = configBox.get('currentChest'); - String result; + // Future pay(BuildContext context, {int? derivation}) async { + // MyWalletsProvider _myWalletProvider = + // Provider.of(context, listen: false); + // int? currentChest = configBox.get('currentChest'); + // String result; - if (chestBox.get(currentChest)!.isCesium!) { - result = await Gva(node: endPointGVA).pay( - recipient: pubkey!, - amount: double.parse(payAmount.text), - cesiumSeed: _myWalletProvider.cesiumSeed, - comment: payComment.text, - derivation: -1, - lang: appLang); - } else { - derivation ??= - _myWalletProvider.getDefaultWallet(currentChest)!.derivation!; - result = await Gva(node: endPointGVA).pay( - recipient: pubkey!, - amount: double.parse(payAmount.text), - mnemonic: _myWalletProvider.mnemonic, - comment: payComment.text, - derivation: derivation, - lang: appLang); - } + // derivation ??= + // _myWalletProvider.getDefaultWallet(currentChest)!.derivation!; + // result = await Gva(node: endPointGVA).pay( + // recipient: pubkey!, + // amount: double.parse(payAmount.text), + // mnemonic: _myWalletProvider.mnemonic, + // comment: payComment.text, + // derivation: derivation, + // lang: appLang); - return result; - } + // return result; + // } bool isPubkey(pubkey) { final RegExp regExp = RegExp( @@ -97,7 +83,7 @@ class WalletsProfilesProvider with ChangeNotifier { if (regExp.hasMatch(pubkey) == true && pubkey.length > 42 && - pubkey.length < 45) { + pubkey.length < 50) { log.d("C'est une pubkey !"); this.pubkey = pubkey; @@ -253,25 +239,6 @@ class WalletsProfilesProvider with ChangeNotifier { return num.parse(result); } - snackCopyKey(context) { - const snackBar = SnackBar( - padding: EdgeInsets.all(20), - content: - Text("Cette clé publique a été copié dans votre presse-papier."), - duration: Duration(seconds: 2)); - ScaffoldMessenger.of(context).showSnackBar(snackBar); - } - - void switchProfileView() { - isHistoryScreen = !isHistoryScreen; - if (isHistoryScreen) { - historySwitchButtun = "Payer"; - } else { - historySwitchButtun = "Voir l'historique"; - } - notifyListeners(); - } - String generateIdenticon(String _pubkey) { return Jdenticon.toSvg(_pubkey); } @@ -299,3 +266,12 @@ class WalletsProfilesProvider with ChangeNotifier { return balance; } } + +snackCopyKey(context) { + const snackBar = SnackBar( + padding: EdgeInsets.all(20), + content: Text("Cette clé publique a été copié dans votre presse-papier.", + style: TextStyle(fontSize: 16)), + duration: Duration(seconds: 2)); + ScaffoldMessenger.of(context).showSnackBar(snackBar); +} diff --git a/lib/screens/common_elements.dart b/lib/screens/common_elements.dart index 009eb48..df3231d 100644 --- a/lib/screens/common_elements.dart +++ b/lib/screens/common_elements.dart @@ -1,5 +1,5 @@ +import 'package:dots_indicator/dots_indicator.dart'; import 'package:flutter/material.dart'; -import 'package:bubble/bubble.dart'; import 'package:gecko/globals.dart'; class CommonElements { @@ -8,95 +8,104 @@ class CommonElements { return const Text('Coucou'); } - Widget bubbleSpeak(String text, - {double? long, Key? textKey, bool isMaxWidth = true}) { + Widget buildImage(String assetName, + [double boxHeight = 440, double imageWidth = 350]) { + return Container( + padding: const EdgeInsets.all(0), + width: 440, + height: boxHeight, + decoration: BoxDecoration( + gradient: const LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + Color(0xffd2d4cf), + Color(0xffeaeae7), + ], + ), + border: Border.all(color: Colors.grey[900]!)), + child: Image.asset('assets/onBoarding/$assetName', width: imageWidth)); + } + + Widget buildText(List text, [double size = 20]) { + return Container( + padding: const EdgeInsets.all(12), + width: 440, + decoration: BoxDecoration( + color: Colors.white, border: Border.all(color: Colors.grey[900]!)), + child: RichText( + textAlign: TextAlign.justify, + text: TextSpan( + style: TextStyle( + fontSize: size, color: Colors.black, letterSpacing: 0.3), + children: text, + ), + ), + ); + } + + Widget nextButton( + BuildContext context, String text, nextScreen, bool isFast) { return SizedBox( - width: isMaxWidth ? double.infinity : 300, - child: Bubble( - padding: long == null - ? const BubbleEdges.all(18) - : BubbleEdges.symmetric(horizontal: long, vertical: 30), - elevation: 5, - color: Colors.white, - margin: const BubbleEdges.fromLTRB(10, 0, 20, 10), - // nip: BubbleNip.leftTop, + width: 410, + height: 70, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + elevation: 4, + primary: orangeC, // background + onPrimary: Colors.white, // foreground + ), + onPressed: () { + Navigator.push( + context, FaderTransition(page: nextScreen, isFast: isFast)); + }, child: Text( text, - key: textKey, - style: const TextStyle( - color: Colors.black, fontSize: 18, fontWeight: FontWeight.w400), + style: const TextStyle(fontSize: 24, fontWeight: FontWeight.w600), ), ), ); } - Widget bubbleSpeakRich(List text, {Key? textKey}) { - return SizedBox( - width: double.infinity, - child: Bubble( - padding: const BubbleEdges.all(18), - elevation: 5, - color: Colors.white, - margin: const BubbleEdges.fromLTRB(10, 0, 20, 10), - // nip: BubbleNip.leftTop, - child: RichText( - key: textKey, - text: TextSpan( - style: const TextStyle( - fontSize: 18.0, - color: Colors.black, - ), - children: text, - ), - ), + Widget buildProgressBar(double pagePosition) { + return DotsIndicator( + dotsCount: 10, + position: pagePosition, + decorator: DotsDecorator( + spacing: const EdgeInsets.symmetric(horizontal: 10), + color: Colors.grey[300]!, // Inactive color + activeColor: orangeC, ), ); } - Widget onboardingProgressBar( - BuildContext context, String screenTitle, int progress) { - return Stack(children: [ - Container(height: 100), - Positioned( - top: 0, left: 0, right: 0, child: GeckoSpeechAppBar(screenTitle)), - Positioned( - top: 0, - left: 0, - child: GestureDetector( - onTap: () { - Navigator.popUntil( - context, - ModalRoute.withName('/'), - ); - }, - child: Image.asset( - 'assets/onBoarding/gecko_bar.png', - ), + Widget infoIntro( + BuildContext context, + List text, + String assetName, + String buttonText, + nextScreen, + double pagePosition, { + bool isFast = false, + double boxHeight = 440, + double imageWidth = 350, + double textSize = 20, + }) { + return Column(children: [ + SizedBox(height: isTall ? 40 : 20), + buildProgressBar(pagePosition), + SizedBox(height: isTall ? 40 : 20), + + buildText(text, textSize), + buildImage(assetName, boxHeight, imageWidth), + Expanded( + child: Align( + alignment: Alignment.bottomCenter, + child: nextButton(context, buttonText, nextScreen, false), ), ), - if (progress != 0) - Positioned( - top: 75, - left: 90, - child: Image.asset( - 'assets/onBoarding/progress_bar/total.png', - ), - ), - if (progress != 0) - Positioned( - top: 75, - left: 90, - child: Image.asset( - 'assets/onBoarding/progress_bar/$progress.png', - ), - ), - if (progress != 0) - Positioned( - top: 70, - right: 90, - child: Text(progress == 12 ? '11/11' : '$progress/11', - style: const TextStyle(fontSize: 12, color: Colors.black)), - ), + // const SizedBox(height: 40), + SizedBox(height: isTall ? 40 : 10), ]); } diff --git a/lib/screens/history.dart b/lib/screens/history.dart index 88f133c..a3b5c44 100644 --- a/lib/screens/history.dart +++ b/lib/screens/history.dart @@ -33,7 +33,7 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier { CesiumPlusProvider _cesiumPlusProvider = Provider.of(context, listen: false); log.i('Build pubkey : ' + pubkey!); - WidgetsBinding.instance!.addPostFrameCallback((_) {}); + // WidgetsBinding.instance.addPostFrameCallback((_) {}); _historyProvider.balance = _historyProvider.transBC = null; @@ -346,7 +346,7 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier { ], ), ), - trailing: Text("${repository[4]} Ğ1", + trailing: Text("${repository[4]} $currencyName", style: const TextStyle( fontSize: 18, fontWeight: FontWeight.w500), textAlign: TextAlign.justify), @@ -403,7 +403,7 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier { key: const Key('copyPubkey'), onTap: () { Clipboard.setData(ClipboardData(text: pubkey)); - _historyProvider.snackCopyKey(context); + snackCopyKey(context); }, child: Text( _historyProvider.getShortPubkey(pubkey!), @@ -466,7 +466,7 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier { return const Text('...'); } return Text( - "${_balance.data.toString()} Ğ1", + "${_balance.data.toString()} $currencyName", textAlign: TextAlign.center, style: const TextStyle( fontSize: 22, fontWeight: FontWeight.w500), diff --git a/lib/screens/home.dart b/lib/screens/home.dart index 23d4759..f796033 100644 --- a/lib/screens/home.dart +++ b/lib/screens/home.dart @@ -1,9 +1,10 @@ import 'package:bubble/bubble.dart'; import 'package:gecko/globals.dart'; +import 'package:gecko/models/stateful_wrapper.dart'; import 'package:gecko/providers/chest_provider.dart'; +import 'package:gecko/providers/substrate_sdk.dart'; import 'package:gecko/providers/wallets_profiles.dart'; import 'package:flutter/material.dart'; -import 'package:gecko/providers/home.dart'; import 'package:gecko/providers/my_wallets.dart'; import 'package:gecko/models/wallet_data.dart'; import 'package:gecko/screens/myWallets/restore_chest.dart'; @@ -12,6 +13,7 @@ import 'package:gecko/screens/onBoarding/1.dart'; import 'package:gecko/screens/search.dart'; import 'package:gecko/screens/settings.dart'; import 'package:flutter/services.dart'; +import 'package:gecko/screens/substrate_sandbox.dart'; import 'package:provider/provider.dart'; class HomeScreen extends StatelessWidget { @@ -24,7 +26,7 @@ class HomeScreen extends StatelessWidget { MyWalletsProvider _myWalletProvider = Provider.of(context); Provider.of(context); - HomeProvider homeClass = HomeProvider(); + SubstrateSdk _sub = Provider.of(context, listen: false); final bool isWalletsExists = _myWalletProvider.checkIfWalletExist(); @@ -65,6 +67,20 @@ class HomeScreen extends StatelessWidget { ); }, ), + ListTile( + key: const Key('substrateSandbox'), + title: const Text('Substrate debug'), + onTap: () { + Navigator.pop(context); + Navigator.push( + context, + MaterialPageRoute(builder: (context) { + return const SubstrateSandBox(); + }), + ); + }, + ), + // ListTile( // title: const Text('A propos'), // onTap: () { @@ -82,8 +98,11 @@ class HomeScreen extends StatelessWidget { body: Builder( builder: (ctx) => StatefulWrapper( onInit: () { - WidgetsBinding.instance!.addPostFrameCallback((_) { - if (isWalletsExists) homeClass.snackNode(ctx); + WidgetsBinding.instance.addPostFrameCallback((_) async { + if (!_sub.sdkReady && !_sub.sdkLoading) await _sub.initApi(); + if (_sub.sdkReady && !_sub.nodeConnected) { + await _sub.connectNode(ctx); //kopa + } }); }, child: isWalletsExists ? geckHome(context) : welcomeHome(context) @@ -176,9 +195,10 @@ Widget geckHome(context) { ), ], ), - ) + ), ]), ), + const SizedBox(height: 15), Expanded( flex: 1, child: Container( @@ -382,31 +402,30 @@ Widget welcomeHome(context) { ]), Padding( padding: EdgeInsets.only(top: 1 * ratio), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: const [ - Text( - "L’application de paiement Ğ1\nplus rapide qu’un reptile du Vietnam", - textAlign: TextAlign.center, - style: TextStyle( - color: Colors.white, - fontSize: 24, - fontWeight: FontWeight.w700, - shadows: [ - Shadow( - offset: Offset(0, 0), - blurRadius: 20, - color: Colors.black, - ), - Shadow( - offset: Offset(0, 0), - blurRadius: 20, - color: Colors.black, - ), - ], + child: + Row(mainAxisAlignment: MainAxisAlignment.center, children: [ + Text( + "L’application de paiement $currencyName\nplus rapide qu’un reptile du Vietnam", + textAlign: TextAlign.center, + style: const TextStyle( + color: Colors.white, + fontSize: 24, + fontWeight: FontWeight.w700, + shadows: [ + Shadow( + offset: Offset(0, 0), + blurRadius: 20, + color: Colors.black, ), - ) - ]), + Shadow( + offset: Offset(0, 0), + blurRadius: 20, + color: Colors.black, + ), + ], + ), + ) + ]), ), Expanded( flex: 1, @@ -464,7 +483,7 @@ Widget welcomeHome(context) { context, MaterialPageRoute( builder: (context) { - return OnboardingStepOne(); + return const OnboardingStepOne(); }, ), ); @@ -512,28 +531,6 @@ Widget welcomeHome(context) { ); } -class StatefulWrapper extends StatefulWidget { - final Function onInit; - final Widget child; - const StatefulWrapper({Key? key, required this.onInit, required this.child}) - : super(key: key); - @override - _StatefulWrapperState createState() => _StatefulWrapperState(); -} - -class _StatefulWrapperState extends State { - @override - void initState() { - widget.onInit(); - super.initState(); - } - - @override - Widget build(BuildContext context) { - return widget.child; - } -} - Widget bubbleSpeak(String text, {double? long, Key? textKey}) { return Bubble( padding: long == null diff --git a/lib/screens/myWallets/cesium_wallet_options.dart b/lib/screens/myWallets/cesium_wallet_options.dart deleted file mode 100644 index 0c01801..0000000 --- a/lib/screens/myWallets/cesium_wallet_options.dart +++ /dev/null @@ -1,410 +0,0 @@ -import 'dart:async'; -import 'dart:io'; -import 'dart:ui'; -import 'package:flutter/material.dart'; -import 'package:gecko/globals.dart'; -import 'package:gecko/models/chest_data.dart'; -import 'package:gecko/providers/chest_provider.dart'; -import 'package:gecko/providers/wallets_profiles.dart'; -import 'package:gecko/providers/my_wallets.dart'; -import 'package:gecko/models/queries.dart'; -import 'package:gecko/providers/wallet_options.dart'; -import 'package:gecko/screens/history.dart'; -import 'package:gecko/screens/myWallets/change_pin.dart'; -import 'package:graphql_flutter/graphql_flutter.dart'; -import 'package:provider/provider.dart'; -import 'package:flutter/services.dart'; -import 'package:qr_flutter/qr_flutter.dart'; - -bool _isNewNameValid = false; - -class CesiumWalletOptions extends StatelessWidget { - const CesiumWalletOptions( - {Key? key, Key? keyMyWallets, required this.cesiumWallet}) - : super(key: key); - - final ChestData cesiumWallet; - - @override - Widget build(BuildContext context) { - SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); - WalletOptionsProvider _walletOptions = - Provider.of(context, listen: false); - ChestProvider _chestProvider = - Provider.of(context, listen: false); - WalletsProfilesProvider _historyProvider = - Provider.of(context, listen: false); - MyWalletsProvider _myWalletProvider = - Provider.of(context, listen: false); - - final String shortPubkey = - _walletOptions.getShortPubkey(_walletOptions.pubkey.text); - - if (_isNewNameValid == false) { - _walletOptions.nameController.text = cesiumWallet.name!; - } else { - cesiumWallet.name = _walletOptions.nameController.text; - } - - return WillPopScope( - onWillPop: () { - _walletOptions.isEditing = false; - _walletOptions.isBalanceBlur = true; - Navigator.popUntil( - context, - ModalRoute.withName('/'), - ); - return Future.value(true); - }, - child: Scaffold( - resizeToAvoidBottomInset: false, - appBar: AppBar( - toolbarHeight: 60 * ratio, - elevation: 0, - leading: IconButton( - icon: const Icon(Icons.arrow_back, color: Colors.black), - onPressed: () { - _walletOptions.isEditing = false; - _walletOptions.isBalanceBlur = true; - Navigator.popUntil( - context, - ModalRoute.withName('/'), - ); - }), - title: SizedBox( - height: 22, - child: Consumer( - builder: (context, walletProvider, _) { - return Text(_walletOptions.nameController.text); - }), - ), - ), - body: Builder( - builder: (ctx) => SafeArea( - child: Column(children: [ - Consumer( - builder: (context, walletProvider, _) { - return Container( - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - yellowC, - const Color(0xfffafafa), - ], - )), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - const Spacer(flex: 1), - InkWell( - onTap: () async { - File newAvatar = - await (_walletOptions.changeAvatar()); - cesiumWallet.imageFile = newAvatar; - _walletOptions.reloadBuild(); - }, - child: cesiumWallet.imageFile == null - ? Image.asset( - 'assets/chests/${cesiumWallet.imageName}', - width: 110, - ) - : Image.file(cesiumWallet.imageFile!, width: 110), - ), - InkWell( - onTap: () async { - File newAvatar = - await (_walletOptions.changeAvatar()); - cesiumWallet.imageFile = newAvatar; - _walletOptions.reloadBuild(); - }, - child: Column(children: [ - Image.asset( - 'assets/walletOptions/camera.png', - height: 40, - ), - const SizedBox(height: 80) - ])), - const Spacer(flex: 1), - Column(children: [ - SizedBox( - width: 260, - child: TextField( - key: const Key('walletName'), - autofocus: false, - focusNode: _walletOptions.walletNameFocus, - enabled: _walletOptions.isEditing, - controller: _walletOptions.nameController, - minLines: 1, - maxLines: 3, - textAlign: TextAlign.center, - decoration: const InputDecoration( - border: InputBorder.none, - focusedBorder: InputBorder.none, - enabledBorder: InputBorder.none, - disabledBorder: InputBorder.none, - contentPadding: EdgeInsets.all(15.0), - ), - style: TextStyle( - fontSize: isTall ? 27 : 23, - color: Colors.black, - fontWeight: FontWeight.w400, - )), - ), - SizedBox(height: isTall ? 5 : 0), - Query( - options: QueryOptions( - document: gql(getBalance), - variables: { - 'pubkey': _walletOptions.pubkey.text, - }, - // pollInterval: Duration(seconds: 1), - ), - builder: (QueryResult result, - {VoidCallback? refetch, FetchMore? fetchMore}) { - if (result.hasException) { - return Text(result.exception.toString()); - } - - if (result.isLoading) { - return const Text('Loading'); - } - - // List repositories = result.data['viewer']['repositories']['nodes']; - String wBalanceUD; - if (result.data!['balance'] == null) { - wBalanceUD = '0.0'; - } else { - int wBalanceG1 = - result.data!['balance']['amount']; - int currentUD = - result.data!['currentUd']['amount']; - double wBalanceUDBrut = - wBalanceG1 / currentUD; // .toString(); - wBalanceUD = double.parse( - (wBalanceUDBrut).toStringAsFixed(2)) - .toString(); - } - return Row(children: [ - ImageFiltered( - imageFilter: ImageFilter.blur( - sigmaX: _walletOptions.isBalanceBlur - ? 6 - : 0.001, - sigmaY: _walletOptions.isBalanceBlur - ? 5 - : 0.001), - child: Text(wBalanceUD, - style: TextStyle( - fontSize: isTall ? 20 : 18, - color: Colors.black)), - ), - Text(' DU', - style: TextStyle( - fontSize: isTall ? 20 : 18, - color: Colors.black)) - ]); - - // Text( - // '$wBalanceUD DU', - // style: TextStyle( - // fontSize: 20, color: Colors.black), - // ); - }, - ), - const SizedBox(height: 5), - InkWell( - key: const Key('displayBalance'), - onTap: () { - _walletOptions.bluringBalance(); - }, - child: Image.asset( - _walletOptions.isBalanceBlur - ? 'assets/walletOptions/icon_oeuil.png' - : 'assets/walletOptions/icon_oeuil_close.png', - height: 35, - ), - ), - ]), - Column(children: [ - InkWell( - key: const Key('renameWallet'), - onTap: () async { - _isNewNameValid = _walletOptions.editWalletName( - [cesiumWallet.key, 0], - isCesium: cesiumWallet.isCesium); - await Future.delayed( - const Duration(milliseconds: 30)); - _walletOptions.walletNameFocus.requestFocus(); - }, - child: ClipRRect( - child: Image.asset( - _walletOptions.isEditing - ? 'assets/walletOptions/android-checkmark.png' - : 'assets/walletOptions/edit.png', - width: 20, - height: 20), - )), - const SizedBox( - height: 60, - ) - ]), - const Spacer(flex: 3), - ]), - ); - }), - SizedBox(height: 4 * ratio), - QrImageWidget( - data: _walletOptions.pubkey.text, - version: QrVersions.auto, - size: isTall ? 300 : 270, - ), - SizedBox(height: 15 * ratio), - GestureDetector( - key: const Key('copyPubkey'), - onTap: () { - Clipboard.setData( - ClipboardData(text: _walletOptions.pubkey.text)); - _walletOptions.snackCopyKey(ctx); - }, - child: SizedBox( - height: 50, - child: Row(children: [ - const SizedBox(width: 30), - Image.asset( - 'assets/walletOptions/key.png', - height: 45, - ), - const SizedBox(width: 20), - Text("${shortPubkey.split(':')[0]}:", - style: const TextStyle( - fontSize: 22, - fontWeight: FontWeight.w800, - fontFamily: 'Monospace', - color: Colors.black)), - Text(shortPubkey.split(':')[1], - style: const TextStyle( - fontSize: 22, - fontWeight: FontWeight.w800, - fontFamily: 'Monospace')), - const SizedBox(width: 15), - SizedBox( - height: 40, - child: ElevatedButton( - style: ElevatedButton.styleFrom( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - elevation: 1, - primary: orangeC, // background - onPrimary: Colors.black, // foreground - ), - onPressed: () { - Clipboard.setData(ClipboardData( - text: _walletOptions.pubkey.text)); - _walletOptions.snackCopyKey(ctx); - }, - child: Row(children: [ - Image.asset( - 'assets/walletOptions/copy-white.png', - height: 25, - ), - const SizedBox(width: 7), - Text('Copier', - style: TextStyle( - fontSize: 15, color: Colors.grey[50])) - ]))), - ]))), - SizedBox(height: 10 * ratio), - InkWell( - key: const Key('displayHistory'), - onTap: () { - _historyProvider.nPage = 1; - Navigator.push( - context, - MaterialPageRoute(builder: (context) { - return HistoryScreen( - pubkey: _walletOptions.pubkey.text); - }), - ); - }, - child: SizedBox( - height: 50, - child: Row(children: [ - const SizedBox(width: 30), - Image.asset( - 'assets/walletOptions/clock.png', - height: 45, - ), - const SizedBox(width: 22), - const Text('Historique des transactions', - style: - TextStyle(fontSize: 20, color: Colors.black)), - ]))), - SizedBox(height: 7 * ratio), - InkWell( - key: const Key('changePin'), - onTap: () async { - // await _chestProvider.changePin(context, cesiumWallet); - String? newPin = await Navigator.push( - context, - MaterialPageRoute( - builder: (context) { - return ChangePinScreen( - walletName: cesiumWallet.name, - walletProvider: _myWalletProvider, - ); - }, - ), - ); - - if (newPin != null) _myWalletProvider.pinCode = newPin; - }, - child: SizedBox( - height: 50, - child: Row(children: [ - const SizedBox(width: 31), - Image.asset( - 'assets/chests/secret_code.png', - height: 24, - ), - const SizedBox(width: 20), - const Text('Changer mon code secret', - style: TextStyle(fontSize: 20, color: Colors.black)), - ]), - ), - ), - SizedBox(height: 7 * ratio), - InkWell( - key: const Key('deleteWallet'), - onTap: () async { - await _chestProvider.deleteChest(context, cesiumWallet); - }, - child: SizedBox( - height: 50, - child: Row(children: [ - const SizedBox(width: 33), - Image.asset( - 'assets/walletOptions/trash.png', - height: 45, - ), - const SizedBox(width: 21), - const Text( - 'Supprimer ce coffre', - style: TextStyle( - fontSize: 20, - color: Color(0xffD80000), - ), - ), - ]), - ), - ), - ]), - ), - ), - ), - ); - } -} diff --git a/lib/screens/myWallets/change_pin.dart b/lib/screens/myWallets/change_pin.dart index 1366e67..fcf51b8 100644 --- a/lib/screens/myWallets/change_pin.dart +++ b/lib/screens/myWallets/change_pin.dart @@ -2,9 +2,11 @@ import 'package:flutter/material.dart'; import 'package:durt/durt.dart'; import 'package:flutter/services.dart'; import 'package:gecko/globals.dart'; -import 'package:gecko/providers/change_pin.dart'; +import 'package:gecko/models/stateful_wrapper.dart'; import 'package:gecko/providers/my_wallets.dart'; +import 'package:gecko/providers/substrate_sdk.dart'; import 'dart:io'; + import 'package:provider/provider.dart'; // ignore: must_be_immutable @@ -18,15 +20,16 @@ class ChangePinScreen extends StatelessWidget with ChangeNotifier { final MyWalletsProvider walletProvider; Directory? appPath; + TextEditingController newPin = TextEditingController(); + @override Widget build(BuildContext context) { SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); - ChangePinProvider _changePin = Provider.of(context); - // _walletOptions.changePin(walletName, oldPin); - // _walletOptions.newPin.text = _tmpPin; + SubstrateSdk _sub = Provider.of(context, listen: false); + return WillPopScope( onWillPop: () { - _changePin.newPin.text = ''; + newPin.text = ''; return Future.value(true); }, child: Scaffold( @@ -36,7 +39,7 @@ class ChangePinScreen extends StatelessWidget with ChangeNotifier { leading: IconButton( icon: const Icon(Icons.arrow_back, color: Colors.black), onPressed: () { - _changePin.newPin.text = ''; + newPin.text = ''; Navigator.of(context).pop(); }), title: SizedBox( @@ -49,7 +52,7 @@ class ChangePinScreen extends StatelessWidget with ChangeNotifier { child: Column(children: [ StatefulWrapper( onInit: () { - _changePin.newPin.text = randomSecretCode(pinLength); + newPin.text = randomSecretCode(pinLength); }, child: Container(), ), @@ -68,7 +71,7 @@ class ChangePinScreen extends StatelessWidget with ChangeNotifier { children: [ TextField( enabled: false, - controller: _changePin.newPin, + controller: newPin, maxLines: 1, textAlign: TextAlign.center, decoration: const InputDecoration(), @@ -80,7 +83,7 @@ class ChangePinScreen extends StatelessWidget with ChangeNotifier { icon: const Icon(Icons.replay), color: orangeC, onPressed: () async { - _changePin.newPin.text = randomSecretCode(pinLength); + newPin.text = randomSecretCode(pinLength); }, ), ], @@ -96,12 +99,12 @@ class ChangePinScreen extends StatelessWidget with ChangeNotifier { onPrimary: Colors.black, // foreground ), onPressed: () async { - NewWallet? _newWalletFile = await _changePin.changePin( - walletProvider.pinCode, - newCustomPin: _changePin.newPin.text); - _changePin.newPin.text = ''; - _changePin.storeNewPinChest(context, _newWalletFile!); - walletProvider.pinCode = _changePin.newPin.text; + final _chest = chestBox.get(configBox.get('currentChest')); + await _sub.changePassword( + _chest!.address!, walletProvider.pinCode, newPin.text); + walletProvider.pinCode = newPin.text; + newPin.text = ''; + Navigator.pop(context); }, child: const Text( 'Confirmer', @@ -116,25 +119,3 @@ class ChangePinScreen extends StatelessWidget with ChangeNotifier { ); } } - -class StatefulWrapper extends StatefulWidget { - final Function onInit; - final Widget child; - const StatefulWrapper({Key? key, required this.onInit, required this.child}) - : super(key: key); - @override - _StatefulWrapperState createState() => _StatefulWrapperState(); -} - -class _StatefulWrapperState extends State { - @override - void initState() { - widget.onInit(); - super.initState(); - } - - @override - Widget build(BuildContext context) { - return widget.child; - } -} diff --git a/lib/screens/myWallets/chest_options.dart b/lib/screens/myWallets/chest_options.dart index 5b6e524..47bb5e1 100644 --- a/lib/screens/myWallets/chest_options.dart +++ b/lib/screens/myWallets/chest_options.dart @@ -24,14 +24,15 @@ class ChestOptions extends StatelessWidget { resizeToAvoidBottomInset: false, appBar: AppBar( toolbarHeight: 60 * ratio, - leading: IconButton( - icon: const Icon(Icons.arrow_back, color: Colors.black), - onPressed: () { - Navigator.popUntil( - context, - ModalRoute.withName('/mywallets'), - ); - }), + // leading: IconButton( + // icon: const Icon(Icons.arrow_back, color: Colors.black), + // onPressed: () { + // // Navigator.popUntil( + // // context, + // // ModalRoute.withName('/mywallets'), + // // ); + // Navigator.pop(context); + // }), title: SizedBox( height: 22, child: Text(currentChest.name!), diff --git a/lib/screens/myWallets/choose_wallet.dart b/lib/screens/myWallets/choose_wallet.dart index fc97230..0c550ff 100644 --- a/lib/screens/myWallets/choose_wallet.dart +++ b/lib/screens/myWallets/choose_wallet.dart @@ -3,6 +3,7 @@ import 'package:gecko/globals.dart'; import 'package:flutter/material.dart'; import 'package:gecko/models/wallet_data.dart'; import 'package:gecko/providers/my_wallets.dart'; +import 'package:gecko/providers/substrate_sdk.dart'; import 'package:gecko/providers/wallets_profiles.dart'; import 'package:gecko/screens/myWallets/wallets_home.dart'; import 'package:provider/provider.dart'; @@ -11,17 +12,20 @@ import 'package:provider/provider.dart'; // ignore: must_be_immutable class ChooseWalletScreen extends StatelessWidget { - ChooseWalletScreen({Key? key}) : super(key: key); + ChooseWalletScreen({Key? key, required this.chest, required this.pin}) + : super(key: key); + final int chest; + final String pin; int? _derivation; List? _selectedId; @override Widget build(BuildContext context) { SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); + SubstrateSdk _sub = Provider.of(context, listen: false); + WalletsProfilesProvider _walletViewProvider = + Provider.of(context, listen: false); // HomeProvider _homeProvider = Provider.of(context); - WalletsProfilesProvider _walletsProfilesProvider = - Provider.of(context); - return Scaffold( appBar: AppBar( toolbarHeight: 60 * ratio, @@ -31,7 +35,7 @@ class ChooseWalletScreen extends StatelessWidget { )), body: SafeArea( child: Stack(children: [ - myWalletsTiles(context), + myWalletsTiles(context, chest), Positioned.fill( bottom: 60, child: Align( @@ -46,8 +50,15 @@ class ChooseWalletScreen extends StatelessWidget { onPrimary: Colors.white, // foreground ), onPressed: () async { - final resultPay = await _walletsProfilesProvider - .pay(context, derivation: _derivation); + final acc = _sub.getCurrentWallet(); + log.d( + "fromAddress: ${acc.address!},destAddress: ${_walletViewProvider.outputPubkey.text}, amount: ${double.parse(_walletViewProvider.payAmount.text)}, password: $pin"); + final resultPay = await _sub.pay(context, + fromAddress: acc.address!, + destAddress: _walletViewProvider.outputPubkey.text, + amount: + double.parse(_walletViewProvider.payAmount.text), + password: pin); await paymentsResult(context, resultPay); }, child: const Text( @@ -64,17 +75,19 @@ class ChooseWalletScreen extends StatelessWidget { )); } - Widget myWalletsTiles(BuildContext context) { + Widget myWalletsTiles(BuildContext context, int? currentChest) { MyWalletsProvider _myWalletProvider = Provider.of(context); final bool isWalletsExists = _myWalletProvider.checkIfWalletExist(); + SubstrateSdk _sub = Provider.of(context, listen: false); WalletData? defaultWallet = - _myWalletProvider.getDefaultWallet(configBox.get('currentChest')); + _myWalletProvider.getDefaultWallet(currentChest); + _selectedId ??= defaultWallet!.id(); _derivation ??= defaultWallet!.derivation!; - - _myWalletProvider.readAllWallets(configBox.get('currentChest')); + _sub.setCurrentWallet(defaultWallet!.address!); + _myWalletProvider.readAllWallets(currentChest); if (!isWalletsExists) { return const Text(''); @@ -116,6 +129,7 @@ class ChooseWalletScreen extends StatelessWidget { onTap: () { _derivation = _repository.derivation!; _selectedId = _repository.id(); + _sub.setCurrentWallet(_repository.address!); _myWalletProvider.rebuildWidget(); }, child: ClipOvalShadow( @@ -182,6 +196,7 @@ class ChooseWalletScreen extends StatelessWidget { onTap: () { _derivation = _repository.derivation!; _selectedId = _repository.id(); + _sub.setCurrentWallet(_repository.address!); _myWalletProvider.rebuildWidget(); }, ) @@ -195,24 +210,28 @@ class ChooseWalletScreen extends StatelessWidget { } Future paymentsResult(context, String resultPay) { - if (resultPay != "success") log.e(resultPay); + final bool isValid = resultPay == "confirmed"; + if (!isValid) log.e(resultPay); + return showDialog( context: context, barrierDismissible: true, // user must tap button! builder: (BuildContext context) { return AlertDialog( - title: Text(resultPay == "success" + title: Text(isValid ? 'Paiement effecuté avec succès !' : "Une erreur s'est produite lors du paiement:\n$resultPay"), content: const SingleChildScrollView(child: Text('')), actions: [ TextButton( child: const Text("OK"), - onPressed: () { - Navigator.popUntil( - context, - ModalRoute.withName('/'), - ); + onPressed: () async { + isValid + ? await Navigator.of(context).pushNamedAndRemoveUntil( + '/', + ModalRoute.withName('/'), + ) + : Navigator.pop(context); }, ), ], diff --git a/lib/screens/myWallets/confirm_wallet_storage.dart b/lib/screens/myWallets/confirm_wallet_storage.dart index 3dab6ad..801ab1c 100644 --- a/lib/screens/myWallets/confirm_wallet_storage.dart +++ b/lib/screens/myWallets/confirm_wallet_storage.dart @@ -5,6 +5,7 @@ import 'package:flutter/services.dart'; import 'package:gecko/globals.dart'; import 'package:gecko/providers/generate_wallets.dart'; import 'package:gecko/providers/my_wallets.dart'; +import 'package:gecko/providers/substrate_sdk.dart'; import 'package:gecko/screens/myWallets/unlocking_wallet.dart'; import 'package:provider/provider.dart'; @@ -32,6 +33,7 @@ class ConfirmStoreWallet extends StatelessWidget with ChangeNotifier { MyWalletsProvider _myWalletProvider = Provider.of(context); final int? _currentChest = _myWalletProvider.getCurrentChest(); + SubstrateSdk _sub = Provider.of(context, listen: false); _mnemonicController.text = generatedMnemonic!; return WillPopScope( @@ -53,7 +55,7 @@ class ConfirmStoreWallet extends StatelessWidget with ChangeNotifier { }), title: const SizedBox( height: 22, - child: Text('Enregistrer ce trousseau'), + child: Text('Enregistrer ce coffre'), )), body: Center( child: Column(children: [ @@ -134,9 +136,16 @@ class ConfirmStoreWallet extends StatelessWidget with ChangeNotifier { .isAskedWordValid && walletName.text != '') ? () async { - _generateWalletProvider.storeHDWChest( - generatedWallet!, - walletName.text, + final address = await _sub.importAccount( + fromMnemonic: true, + mnemonic: _generateWalletProvider + .generatedMnemonic!, + password: + _generateWalletProvider.pin.text, + derivePath: '//2'); + await _generateWalletProvider.storeHDWChest( + address, + 'Mon portefeuille courant', context); _generateWalletProvider.isAskedWordValid = false; diff --git a/lib/screens/myWallets/generate_wallets.dart b/lib/screens/myWallets/generate_wallets.dart index 8851268..fe3a24e 100644 --- a/lib/screens/myWallets/generate_wallets.dart +++ b/lib/screens/myWallets/generate_wallets.dart @@ -1,16 +1,13 @@ -import 'package:durt/durt.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:gecko/globals.dart'; import 'package:gecko/providers/generate_wallets.dart'; import 'package:gecko/screens/myWallets/confirm_wallet_storage.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 GenerateFastChestScreen extends StatelessWidget { - SuperTooltip? tooltip; bool hasError = false; String validPin = 'NO PIN'; String currentText = ""; @@ -25,14 +22,11 @@ class GenerateFastChestScreen extends StatelessWidget { Widget build(BuildContext context) { SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); GenerateWalletsProvider _generateWalletProvider = - Provider.of(context); + Provider.of(context, listen: false); - if (_generateWalletProvider.mnemonicController.text == '') { - _generateWalletProvider.generateWordList(); - _generateWalletProvider.mnemonicController.text = - _generateWalletProvider.generatedMnemonic!; - _generateWalletProvider.pin.text = randomSecretCode(pinLength); - } + _generateWalletProvider.pin.text = kDebugMode && debugPin + ? 'AAAAA' + : _generateWalletProvider.changePinCode(reload: false); return WillPopScope( onWillPop: () { @@ -52,7 +46,7 @@ class GenerateFastChestScreen extends StatelessWidget { }), title: const SizedBox( height: 22, - child: Text('Générer un trousseau'), + child: Text('Générer un coffre'), )), floatingActionButton: SizedBox( height: 80.0, @@ -61,9 +55,7 @@ class GenerateFastChestScreen extends StatelessWidget { child: FloatingActionButton( heroTag: "buttonGenerateWallet", onPressed: () { - _generateWalletProvider.generateWordList(); - _generateWalletProvider.mnemonicController.text = - _generateWalletProvider.generatedMnemonic!; + _generateWalletProvider.reloadBuild(); }, child: SizedBox( height: 40.0, @@ -79,18 +71,23 @@ class GenerateFastChestScreen extends StatelessWidget { const SizedBox(height: 20), 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: const InputDecoration( - contentPadding: EdgeInsets.all(15.0), - ), - style: const TextStyle( - fontSize: 22.0, - color: Colors.black, - fontWeight: FontWeight.w400)), + Consumer(builder: (context, _gWP, _) { + return FutureBuilder( + future: _gWP.generateWordList(context), + builder: (BuildContext context, AsyncSnapshot _data) { + if (!_data.hasData) { + return const Text(''); + } else { + return Text(_gWP.generatedMnemonic!, + maxLines: 3, + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: 22.0, + color: Colors.black, + fontWeight: FontWeight.w400)); + } + }); + }), const SizedBox(height: 8), toolTips(_toolTipSecret, 'Code secret:', "Retenez bien votre code secret, il vous sera demandé à chaque paiement, ainsi que pour configurer votre portefeuille"), @@ -112,7 +109,7 @@ class GenerateFastChestScreen extends StatelessWidget { icon: const Icon(Icons.replay), color: orangeC, onPressed: () { - _generateWalletProvider.changePinCode(reload: true); + _generateWalletProvider.changePinCode(reload: false); }, ), ], @@ -128,11 +125,6 @@ class GenerateFastChestScreen extends StatelessWidget { ? () async { _generateWalletProvider.nbrWord = _generateWalletProvider.getRandomInt(); - _generateWalletProvider.actualWallet = await Dewif() - .generateDewif( - _generateWalletProvider.generatedMnemonic!, - _generateWalletProvider.pin.text, - lang: appLang); await Navigator.push( context, MaterialPageRoute(builder: (context) { @@ -145,20 +137,20 @@ class GenerateFastChestScreen extends StatelessWidget { ); } : null, - child: const Text('Enregistrer ce trousseau', + child: const Text('Enregistrer ce coffre', style: TextStyle(fontSize: 20))), const SizedBox(height: 20), - GestureDetector( - onTap: () { - Navigator.push( - context, - MaterialPageRoute(builder: (context) { - return PrintWallet( - _generateWalletProvider.generatedMnemonic); - }), - ); - }, - child: const Icon(Icons.print)) + // GestureDetector( + // onTap: () { + // Navigator.push( + // context, + // MaterialPageRoute(builder: (context) { + // return PrintWallet( + // _generateWalletProvider.generatedMnemonic); + // }), + // ); + // }, + // child: const Icon(Icons.print)) ]), ), ), @@ -201,30 +193,30 @@ class GenerateFastChestScreen extends StatelessWidget { } } -// ignore: must_be_immutable -class PrintWallet extends StatelessWidget { - const PrintWallet(this.sentence, {Key? key}) : super(key: key); +// // ignore: must_be_immutable +// class PrintWallet extends StatelessWidget { +// const PrintWallet(this.sentence, {Key? key}) : super(key: key); - final String? sentence; +// final String? sentence; - @override - Widget build(BuildContext context) { - GenerateWalletsProvider _generateWalletProvider = - Provider.of(context); - return MaterialApp( - home: Scaffold( - appBar: AppBar( - leading: IconButton( - icon: const Icon(Icons.arrow_back, color: Colors.white), - onPressed: () { - Navigator.pop(context); - }), - toolbarHeight: 60 * ratio, - title: const Text('Imprimer ce trousseau')), - body: PdfPreview( - build: (format) => _generateWalletProvider.printWallet(sentence), - ), - ), - ); - } -} +// @override +// Widget build(BuildContext context) { +// GenerateWalletsProvider _generateWalletProvider = +// Provider.of(context); +// return MaterialApp( +// home: Scaffold( +// appBar: AppBar( +// leading: IconButton( +// icon: const Icon(Icons.arrow_back, color: Colors.white), +// onPressed: () { +// Navigator.pop(context); +// }), +// toolbarHeight: 60 * ratio, +// title: const Text('Imprimer ce coffre')), +// body: PdfPreview( +// build: (format) => _generateWalletProvider.printWallet(sentence), +// ), +// ), +// ); +// } +// } diff --git a/lib/screens/myWallets/import_cesium_wallet.dart b/lib/screens/myWallets/import_cesium_wallet.dart deleted file mode 100644 index bbac4cc..0000000 --- a/lib/screens/myWallets/import_cesium_wallet.dart +++ /dev/null @@ -1,244 +0,0 @@ -import 'dart:async'; -import 'package:durt/durt.dart'; -import 'package:flutter/services.dart'; -import 'package:gecko/globals.dart'; -import 'package:gecko/providers/generate_wallets.dart'; -import 'package:flutter/material.dart'; -import 'package:gecko/providers/my_wallets.dart'; -import 'package:gecko/models/wallet_data.dart'; -import 'package:gecko/providers/wallet_options.dart'; -import 'package:gecko/screens/myWallets/unlocking_wallet.dart'; -import 'package:provider/provider.dart'; - -class ImportWalletScreen extends StatelessWidget { - const ImportWalletScreen({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); - GlobalKey _toolTipSecret = GlobalKey(); - Timer? _debounce; - GenerateWalletsProvider _generateWalletProvider = - Provider.of(context, listen: false); - WalletOptionsProvider _walletOptions = - Provider.of(context, listen: false); - MyWalletsProvider _myWalletProvider = - Provider.of(context, listen: false); - - _generateWalletProvider.pin.text = randomSecretCode(pinLength); - return WillPopScope( - onWillPop: () { - _generateWalletProvider.resetCesiumImportView(); - return Future.value(true); - }, - child: Scaffold( - appBar: AppBar( - toolbarHeight: 60 * ratio, - leading: IconButton( - icon: const Icon(Icons.arrow_back, color: Colors.black), - onPressed: () { - _generateWalletProvider.resetCesiumImportView(); - Navigator.of(context).pop(); - }), - title: const SizedBox( - height: 22, - child: Text('Importer un portefeuille'), - )), - body: Builder( - builder: (ctx) => SafeArea( - child: Column(children: [ - const SizedBox(height: 20), - Consumer( - builder: (context, walletProvider, _) { - return TextFormField( - autofocus: true, - onChanged: (text) { - if (_debounce?.isActive ?? false) { - _debounce!.cancel(); - } - _debounce = Timer(const Duration(milliseconds: 600), () { - walletProvider - .generateCesiumWalletPubkey( - text, walletProvider.cesiumPWD.text) - .then((value) { - walletProvider.canImport = true; - walletProvider.reloadBuild(); - }); - }); - }, - keyboardType: TextInputType.text, - controller: walletProvider.cesiumID, - obscureText: !walletProvider - .isCesiumIDVisible, //This will obscure text dynamically - decoration: InputDecoration( - hintText: 'Entrez votre identifiant Cesium', - suffixIcon: IconButton( - icon: Icon( - walletProvider.isCesiumIDVisible - ? Icons.visibility - : Icons.visibility_off, - color: Colors.black, - ), - onPressed: () { - walletProvider.cesiumIDisVisible(); - }, - ), - ), - ); - }), - const SizedBox(height: 15), - Consumer( - builder: (context, walletProvider, _) { - return TextFormField( - onChanged: (text) { - if (_debounce?.isActive ?? false) { - _debounce!.cancel(); - } - _debounce = Timer(const Duration(milliseconds: 600), () { - walletProvider - .generateCesiumWalletPubkey( - walletProvider.cesiumID.text, text) - .then((value) { - walletProvider.canImport = true; - walletProvider.reloadBuild(); - }); - }); - }, - keyboardType: TextInputType.text, - controller: walletProvider.cesiumPWD, - obscureText: !walletProvider - .isCesiumPWDVisible, //This will obscure text dynamically - decoration: InputDecoration( - hintText: 'Entrez votre mot de passe Cesium', - suffixIcon: IconButton( - icon: Icon( - walletProvider.isCesiumPWDVisible - ? Icons.visibility - : Icons.visibility_off, - color: Colors.black, - ), - onPressed: () { - walletProvider.cesiumPWDisVisible(); - }, - ), - ), - ); - }), - const SizedBox(height: 15), - GestureDetector( - onTap: () { - Clipboard.setData(ClipboardData( - text: _generateWalletProvider.cesiumPubkey.text)); - _walletOptions.snackCopyKey(ctx); - }, - child: Consumer( - builder: (context, walletProvider, _) { - return Text( - _generateWalletProvider.cesiumPubkey.text, - style: const TextStyle( - fontSize: 14.0, - color: Colors.black, - fontWeight: FontWeight.bold, - fontFamily: 'Monospace'), - ); - }), - ), - const SizedBox(height: 20), - toolTips(_toolTipSecret, 'Code secret:', - "Retenez bien votre code secret, il vous sera demandé à chaque paiement, ainsi que pour configurer votre portefeuille"), - Stack( - alignment: Alignment.centerRight, - children: [ - TextField( - enabled: false, - controller: _generateWalletProvider.pin, - maxLines: 1, - textAlign: TextAlign.center, - decoration: const InputDecoration(), - style: const TextStyle( - fontSize: 30.0, - color: Colors.black, - fontWeight: FontWeight.bold)), - IconButton( - icon: const Icon(Icons.replay), - color: orangeC, - onPressed: () { - _generateWalletProvider.changePinCode(reload: true); - }, - ), - ], - ), - const SizedBox(height: 30), - Consumer( - builder: (context, walletProvider, _) { - return ElevatedButton( - style: ElevatedButton.styleFrom( - primary: yellowC, // background - onPrimary: Colors.black, // foreground - ), - onPressed: walletProvider.canImport - ? () async { - final chestKey = - await walletProvider.importCesiumWallet(); - _myWalletProvider.rebuildWidget(); - - await Navigator.pushAndRemoveUntil( - context, - MaterialPageRoute(builder: (context) { - return UnlockingWallet( - wallet: WalletData(chest: chestKey), - action: "mywallets", - ); - }), - ModalRoute.withName('/'), - ); - _generateWalletProvider.resetCesiumImportView(); - } - : null, - child: const Text( - 'Importer ce portefeuille Cesium', - style: TextStyle(fontSize: 20), - ), - ); - }), - ]), - ), - ), - ), - ); - } - - Widget toolTips(_key, _text, _message) { - return GestureDetector( - onTap: () { - final dynamic _toolTip = _key.currentState; - _toolTip.ensureTooltipVisible(); - }, - child: Tooltip( - padding: const EdgeInsets.all(10), - key: _key, - showDuration: const Duration(seconds: 5), - message: _message, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const SizedBox(width: 20), - Column(children: [ - SizedBox( - width: 30, - height: 25, - child: - Icon(Icons.info_outline, size: 22, color: orangeC)), - const SizedBox(height: 1) - ]), - Text( - _text, - style: TextStyle( - fontSize: 15.0, - color: Colors.grey[600], - fontWeight: FontWeight.w400), - ), - const SizedBox(width: 45) - ]))); - } -} diff --git a/lib/screens/myWallets/restore_chest.dart b/lib/screens/myWallets/restore_chest.dart index 79c798e..3772eac 100644 --- a/lib/screens/myWallets/restore_chest.dart +++ b/lib/screens/myWallets/restore_chest.dart @@ -3,8 +3,9 @@ import 'package:flutter/services.dart'; import 'package:gecko/globals.dart'; import 'package:flutter/material.dart'; import 'package:gecko/providers/generate_wallets.dart'; +import 'package:gecko/providers/substrate_sdk.dart'; import 'package:gecko/screens/common_elements.dart'; -import 'package:gecko/screens/onBoarding/11.dart'; +import 'package:gecko/screens/onBoarding/9.dart'; import 'package:provider/provider.dart'; // import 'package:gecko/models/home.dart'; // import 'package:provider/provider.dart'; @@ -15,14 +16,19 @@ class RestoreChest extends StatelessWidget { @override Widget build(BuildContext context) { SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); - GenerateWalletsProvider generateWalletProvider = + GenerateWalletsProvider genW = Provider.of(context, listen: false); + SubstrateSdk _sub = Provider.of(context, listen: false); - generateWalletProvider.actualWallet = null; + genW.actualWallet = null; + if (genW.isSentenceComplete(context)) { + genW.generatedMnemonic = + '${genW.cellController0.text} ${genW.cellController1.text} ${genW.cellController2.text} ${genW.cellController3.text} ${genW.cellController4.text} ${genW.cellController5.text} ${genW.cellController6.text} ${genW.cellController7.text} ${genW.cellController8.text} ${genW.cellController9.text} ${genW.cellController10.text} ${genW.cellController11.text}'; + } return WillPopScope( onWillPop: () { - generateWalletProvider.resetImportView(); + genW.resetImportView(); return Future.value(true); }, child: Scaffold( @@ -31,7 +37,7 @@ class RestoreChest extends StatelessWidget { leading: IconButton( icon: const Icon(Icons.arrow_back, color: Colors.black), onPressed: () { - generateWalletProvider.resetImportView(); + genW.resetImportView(); Navigator.of(context).pop(); }), title: const SizedBox( @@ -48,32 +54,32 @@ class RestoreChest extends StatelessWidget { Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ - arrayCell(context, generateWalletProvider.cellController0), - arrayCell(context, generateWalletProvider.cellController1), - arrayCell(context, generateWalletProvider.cellController2), - arrayCell(context, generateWalletProvider.cellController3), + arrayCell(context, genW.cellController0), + arrayCell(context, genW.cellController1), + arrayCell(context, genW.cellController2), + arrayCell(context, genW.cellController3), ]), const SizedBox(height: 15), Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ - arrayCell(context, generateWalletProvider.cellController4), - arrayCell(context, generateWalletProvider.cellController5), - arrayCell(context, generateWalletProvider.cellController6), - arrayCell(context, generateWalletProvider.cellController7), + arrayCell(context, genW.cellController4), + arrayCell(context, genW.cellController5), + arrayCell(context, genW.cellController6), + arrayCell(context, genW.cellController7), ]), const SizedBox(height: 15), Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ - arrayCell(context, generateWalletProvider.cellController8), - arrayCell(context, generateWalletProvider.cellController9), - arrayCell(context, generateWalletProvider.cellController10), - arrayCell(context, generateWalletProvider.cellController11), + arrayCell(context, genW.cellController8), + arrayCell(context, genW.cellController9), + arrayCell(context, genW.cellController10), + arrayCell(context, genW.cellController11), ]), ]), // const Spacer(), - if (generateWalletProvider.isSentenceComplete(context)) + if (genW.isSentenceComplete(context)) Expanded( child: Align( alignment: Alignment.center, @@ -87,12 +93,13 @@ class RestoreChest extends StatelessWidget { onPrimary: Colors.white, // foreground ), onPressed: () async { - if (await generateWalletProvider.isSentenceValid()) { - generateWalletProvider.resetImportView(); + if (await _sub.isMnemonicValid(genW.generatedMnemonic!)) { + genW.resetImportView(); await Navigator.push( context, FaderTransition( - page: const OnboardingStepThirteen(), isFast: true), + page: const OnboardingStepThirteen(), + isFast: true), ); } else { await badMnemonicPopup(context); @@ -107,6 +114,30 @@ class RestoreChest extends StatelessWidget { ), // SizedBox(height: isTall ? 80 : 80), )) + else + Column(children: [ + const SizedBox(height: 20), + SizedBox( + width: 150, + height: 50, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + elevation: 4, + primary: yellowC, // background + onPrimary: Colors.black, // foreground + ), + onPressed: () { + genW.pasteMnemonic(context); + }, + child: const Text( + 'Coller depuis le\npresse-papier', + textAlign: TextAlign.center, + style: + TextStyle(fontSize: 16, fontWeight: FontWeight.w400), + ), + ), + ) + ]) ]), ), ), @@ -168,7 +199,7 @@ class RestoreChest extends StatelessWidget { return AlertDialog( title: const Text('Phrase incorrecte'), content: const Text( - 'Votre phrase de restauration semble incorrecte, veuillez la corriger.'), + 'Votre phrase de restauration semble incorrecte, les mots ne sont pas dans le bon ordre.\nVeuillez la corriger.'), actions: [ TextButton( child: const Text("OK"), diff --git a/lib/screens/myWallets/unlocking_wallet.dart b/lib/screens/myWallets/unlocking_wallet.dart index d3ed360..a91563b 100644 --- a/lib/screens/myWallets/unlocking_wallet.dart +++ b/lib/screens/myWallets/unlocking_wallet.dart @@ -1,13 +1,13 @@ +// ignore_for_file: avoid_print + import 'dart:async'; -import 'package:durt/durt.dart'; import 'package:flutter/services.dart'; import 'package:gecko/models/chest_data.dart'; -import 'package:gecko/providers/wallets_profiles.dart'; +import 'package:gecko/providers/substrate_sdk.dart'; import 'package:gecko/providers/my_wallets.dart'; import 'package:gecko/models/wallet_data.dart'; import 'package:gecko/providers/wallet_options.dart'; import 'package:flutter/material.dart'; -import 'package:gecko/screens/myWallets/cesium_wallet_options.dart'; import 'package:gecko/screens/myWallets/choose_chest.dart'; import 'package:gecko/screens/myWallets/choose_wallet.dart'; import 'package:gecko/screens/myWallets/wallets_home.dart'; @@ -21,6 +21,8 @@ class UnlockingWallet extends StatelessWidget { {Key? keyUnlockWallet, required this.wallet, required this.action}) : super(key: keyUnlockWallet); WalletData? wallet; + late int currentChestNumber; + late ChestData currentChest; String action; // ignore: close_sinks @@ -34,17 +36,11 @@ class UnlockingWallet extends StatelessWidget { SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); WalletOptionsProvider _walletOptions = Provider.of(context); - final double statusBarHeight = MediaQuery.of(context).padding.top; + // final double statusBarHeight = MediaQuery.of(context).padding.top; - int _pinLenght; - ChestData currentChest = chestBox.get(configBox.get('currentChest'))!; - - if (currentChest.isCesium!) { - _pinLenght = _walletOptions.getPinLenght(currentChest.dewif); - wallet = WalletData(derivation: -1, chest: currentChest.key); - } else { - _pinLenght = _walletOptions.getPinLenght(wallet!.number); - } + currentChestNumber = configBox.get('currentChest'); + currentChest = chestBox.get(currentChestNumber)!; + int _pinLenght = _walletOptions.getPinLenght(wallet!.number); errorController = StreamController(); return Scaffold( @@ -55,7 +51,7 @@ class UnlockingWallet extends StatelessWidget { children: [ Stack(children: [ Positioned( - top: statusBarHeight + 10, + top: 10, //statusBarHeight + 10, left: 15, child: Builder( builder: (context) => IconButton( @@ -63,7 +59,7 @@ class UnlockingWallet extends StatelessWidget { icon: const Icon( Icons.arrow_back, color: Colors.black, - size: 25, + size: 30, ), onPressed: () => Navigator.pop(context), ), @@ -106,7 +102,7 @@ class UnlockingWallet extends StatelessWidget { fontWeight: FontWeight.w400), )), SizedBox(height: 40 * ratio), - pinForm(context, _pinLenght, currentChest), + pinForm(context, _pinLenght), SizedBox(height: 3 * ratio), InkWell( key: const Key('chooseChest'), @@ -137,7 +133,7 @@ class UnlockingWallet extends StatelessWidget { )); } - Widget pinForm(context, _pinLenght, ChestData currentChest) { + Widget pinForm(context, _pinLenght) { // var _walletPin = ''; // ignore: close_sinks StreamController errorController = @@ -147,8 +143,8 @@ class UnlockingWallet extends StatelessWidget { Provider.of(context); MyWalletsProvider _myWalletProvider = Provider.of(context); - WalletsProfilesProvider _historyProvider = - Provider.of(context); + + SubstrateSdk _sub = Provider.of(context, listen: false); FocusNode pinFocus = FocusNode(); @@ -201,30 +197,12 @@ class UnlockingWallet extends StatelessWidget { ], onCompleted: (_pin) async { log.d("Completed"); - _myWalletProvider.pinCode = _pin; + _myWalletProvider.pinCode = _pin.toUpperCase(); - if (currentChest.isCesium!) { - try { - String _localDewif = chestBox.get(wallet!.chest)!.dewif!; - final cesiumWallet = - CesiumWallet.fromDewif(_localDewif, _pin.toUpperCase()); - _walletOptions.pubkey.text = cesiumWallet.pubkey; - _myWalletProvider.cesiumSeed = cesiumWallet.seed; - _myWalletProvider.mnemonic = 'cesium'; - } catch (e) { - log.e(e); - _myWalletProvider.mnemonic = 'bad'; - } - } else { - _myWalletProvider.mnemonic = _myWalletProvider.dewifToMnemonic( - context, wallet!, _pin.toUpperCase()); - } - // final String? resultWallet = _walletOptions.readLocalWallet( - // context, wallet!, _pin.toUpperCase(), _pinLenght); - // _myWalletProvider.pinCode = _pin.toUpperCase(); - _myWalletProvider.pinLenght = _pinLenght; + final isValid = await _sub.checkPassword( + currentChest.address!, _pin.toUpperCase()); - if (_myWalletProvider.mnemonic == 'bad') { + if (!isValid) { await Future.delayed(const Duration(milliseconds: 50)); errorController.add(ErrorAnimationType .shake); // Triggering error shake animation @@ -235,32 +213,20 @@ class UnlockingWallet extends StatelessWidget { } else { pinColor = Colors.green[400]; if (action == "mywallets") { - currentChest.isCesium! - ? Navigator.push( - context, - MaterialPageRoute(builder: (context) { - return CesiumWalletOptions( - cesiumWallet: currentChest); - }), - ).then((value) => _myWalletProvider.mnemonic = '') - : Navigator.push( - context, - MaterialPageRoute(builder: (context) { - return const WalletsHome(); - }), - ).then((value) => _myWalletProvider.cesiumSeed.clear()); + Navigator.push( + context, + MaterialPageRoute(builder: (context) { + return const WalletsHome(); + }), + ); } else if (action == "pay") { - if (currentChest.isCesium!) { - final resultPay = await _historyProvider.pay(context); - await paymentsResult(context, resultPay); - } else { - Navigator.push( - context, - MaterialPageRoute(builder: (context) { - return ChooseWalletScreen(); - }), - ); - } + Navigator.push( + context, + MaterialPageRoute(builder: (context) { + return ChooseWalletScreen( + chest: currentChestNumber, pin: _pin.toUpperCase()); + }), + ); } } }, diff --git a/lib/screens/myWallets/wallet_options.dart b/lib/screens/myWallets/wallet_options.dart index 7799d99..19a39fc 100644 --- a/lib/screens/myWallets/wallet_options.dart +++ b/lib/screens/myWallets/wallet_options.dart @@ -1,6 +1,4 @@ import 'dart:async'; -import 'dart:io'; -import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:gecko/globals.dart'; import 'package:gecko/providers/my_wallets.dart'; @@ -27,16 +25,18 @@ class WalletOptions extends StatelessWidget { MyWalletsProvider _myWalletProvider = Provider.of(context); - log.d(_walletOptions.pubkey.text); + log.d(_walletOptions.address.text); final int _currentChest = _myWalletProvider.getCurrentChest()!; - log.d("Wallet options: $_currentChest:${wallet.number}"); + // final currentWallet = _myWalletProvider.getDefaultWallet(_currentChest); + // log.d(_walletOptions.getAddress(_currentChest, 3)); + log.d("Wallet options: $_currentChest:${wallet.derivation}"); return WillPopScope( onWillPop: () { _walletOptions.isEditing = false; - _walletOptions.isBalanceBlur = true; + _walletOptions.isBalanceBlur = false; Navigator.pop(context); return Future.value(true); }, @@ -49,7 +49,7 @@ class WalletOptions extends StatelessWidget { icon: const Icon(Icons.arrow_back, color: Colors.black), onPressed: () { _walletOptions.isEditing = false; - _walletOptions.isBalanceBlur = true; + _walletOptions.isBalanceBlur = false; Navigator.pop(context); }), title: SizedBox( @@ -89,15 +89,15 @@ class WalletOptions extends StatelessWidget { Column(children: [ walletName(walletProvider, _walletOptions), SizedBox(height: isTall ? 5 : 0), - balance(walletProvider), + balance(context, walletProvider.address.text, 20), ]), const Spacer(flex: 3), ]), ); }), - SizedBox(height: 4 * ratio), + SizedBox(height: 10 * ratio), QrImageWidget( - data: _walletOptions.pubkey.text, + data: _walletOptions.address.text, version: QrVersions.auto, size: isTall ? 300 : 270, ), @@ -129,8 +129,10 @@ class WalletOptions extends StatelessWidget { children: [ InkWell( onTap: () async { - File newAvatar = await (walletProvider.changeAvatar()); - wallet.imageFile = newAvatar; + wallet.imageFile = await (walletProvider.changeAvatar()); + if (wallet.imageFile != null) { + walletBox.put(wallet.key, wallet); + } walletProvider.reloadBuild(); }, child: wallet.imageFile == null @@ -148,8 +150,7 @@ class WalletOptions extends StatelessWidget { top: 0, child: InkWell( onTap: () async { - File newAvatar = await (walletProvider.changeAvatar()); - wallet.imageFile = newAvatar; + wallet.imageFile = await (walletProvider.changeAvatar()); walletProvider.reloadBuild(); }, child: Image.asset( @@ -220,54 +221,14 @@ class WalletOptions extends StatelessWidget { ); } - Widget balance(WalletOptionsProvider walletProvider) { - return Column(children: [ - FutureBuilder( - future: walletProvider.getBalance(walletProvider.pubkey.text), - builder: (BuildContext context, AsyncSnapshot _balance) { - if (_balance.connectionState != ConnectionState.done || - _balance.hasError) { - return Text('', - style: TextStyle( - fontSize: isTall ? 20 : 18, - )); - } - return ImageFiltered( - imageFilter: ImageFilter.blur( - sigmaX: walletProvider.isBalanceBlur ? 6 : 0, - sigmaY: walletProvider.isBalanceBlur ? 5 : 0), - child: Text( - _balance.data.toString() + ' Ğ1', - style: TextStyle( - fontSize: isTall ? 20 : 18, - ), - ), - ); - }), - const SizedBox(height: 5), - InkWell( - key: const Key('displayBalance'), - onTap: () { - walletProvider.bluringBalance(); - }, - child: Image.asset( - walletProvider.isBalanceBlur - ? 'assets/walletOptions/icon_oeuil.png' - : 'assets/walletOptions/icon_oeuil_close.png', - height: 35, - ), - ), - ]); - } - Widget pubkeyWidget(WalletOptionsProvider walletProvider, BuildContext ctx) { final String shortPubkey = - walletProvider.getShortPubkey(walletProvider.pubkey.text); + walletProvider.getShortPubkey(walletProvider.address.text); return GestureDetector( key: const Key('copyPubkey'), onTap: () { - Clipboard.setData(ClipboardData(text: walletProvider.pubkey.text)); - walletProvider.snackCopyKey(ctx); + Clipboard.setData(ClipboardData(text: walletProvider.address.text)); + snackCopyKey(ctx); }, child: SizedBox( height: 50, @@ -303,8 +264,8 @@ class WalletOptions extends StatelessWidget { ), onPressed: () { Clipboard.setData( - ClipboardData(text: walletProvider.pubkey.text)); - walletProvider.snackCopyKey(ctx); + ClipboardData(text: walletProvider.address.text)); + snackCopyKey(ctx); }, child: Row(children: [ Image.asset( @@ -336,7 +297,7 @@ class WalletOptions extends StatelessWidget { context, MaterialPageRoute(builder: (context) { return HistoryScreen( - pubkey: walletProvider.pubkey.text, + pubkey: walletProvider.address.text, avatar: wallet.imageFile == null ? Image.asset( 'assets/avatars/${wallet.imageName}', @@ -422,7 +383,7 @@ class WalletOptions extends StatelessWidget { onTap: !walletProvider.isDefaultWallet ? () async { await walletProvider.deleteWallet(context, wallet); - WidgetsBinding.instance!.addPostFrameCallback((_) { + WidgetsBinding.instance.addPostFrameCallback((_) { _myWalletProvider.listWallets = _myWalletProvider.readAllWallets(_currentChest); _myWalletProvider.rebuildWidget(); diff --git a/lib/screens/myWallets/wallets_home.dart b/lib/screens/myWallets/wallets_home.dart index c751e2d..eab5beb 100644 --- a/lib/screens/myWallets/wallets_home.dart +++ b/lib/screens/myWallets/wallets_home.dart @@ -1,4 +1,3 @@ -import 'package:durt/durt.dart'; import 'package:flutter/services.dart'; import 'package:gecko/globals.dart'; import 'package:gecko/models/chest_data.dart'; @@ -55,7 +54,7 @@ class WalletsHome extends StatelessWidget { backgroundColor: const Color(0xffFFD58D), ), body: SafeArea( - child: myWalletsTiles(context), + child: myWalletsTiles(context, _currentChestNumber!), ), ), ); @@ -132,7 +131,7 @@ class WalletsHome extends StatelessWidget { ]); } - Widget myWalletsTiles(BuildContext context) { + Widget myWalletsTiles(BuildContext context, int _currentChestNumber) { MyWalletsProvider _myWalletProvider = Provider.of(context); WalletOptionsProvider _walletOptions = @@ -182,9 +181,8 @@ class WalletsHome extends StatelessWidget { onTap: () { // _walletOptions.readLocalWallet(context, _repository, // _myWalletProvider.pinCode, pinLength); - _walletOptions.pubkey.text = - HdWallet.fromMnemonic(_myWalletProvider.mnemonic) - .getPubkey(_repository.derivation!); + _walletOptions.getAddress( + _currentChestNumber, _repository.derivation!); Navigator.push( context, SmoothTransition( @@ -275,10 +273,8 @@ class WalletsHome extends StatelessWidget { // _repository, // _myWalletProvider.pinCode, // pinLength); - _walletOptions.pubkey.text = - HdWallet.fromMnemonic( - _myWalletProvider.mnemonic) - .getPubkey(_repository.derivation!); + _walletOptions.getAddress( + _currentChestNumber, _repository.derivation!); Navigator.push( context, SmoothTransition( diff --git a/lib/screens/onBoarding/0_no_keychain_found.dart b/lib/screens/onBoarding/0_no_keychain_found.dart deleted file mode 100644 index 12fe699..0000000 --- a/lib/screens/onBoarding/0_no_keychain_found.dart +++ /dev/null @@ -1,112 +0,0 @@ -// ignore_for_file: file_names -import 'package:flutter/services.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; -import 'package:gecko/globals.dart'; -import 'package:gecko/screens/common_elements.dart'; -import 'package:gecko/screens/myWallets/import_cesium_wallet.dart'; -import 'package:gecko/screens/onBoarding/1.dart'; - -class NoKeyChainScreen extends StatelessWidget { - const NoKeyChainScreen({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); - CommonElements common = CommonElements(); - return Scaffold( - extendBodyBehindAppBar: true, - // backgroundColor: Colors.white, - // appBar: GeckoSpeechAppBar('Mes portefeuilles'), - body: SafeArea( - child: Column(children: [ - common.onboardingProgressBar(context, 'Mes portefeuilles', 0), - common.bubbleSpeak( - "Je ne connais pour l’instant aucun de vos portefeuilles.\n\nVous pouvez en créer un nouveau, ou bien importer un portefeuille Cesium existant.", - textKey: const Key('textOnboarding')), - const SizedBox(height: 90), - Container( - child: ClipOval( - child: Material( - color: const Color(0xffFFD58D), // button color - child: InkWell( - key: const Key('goStep1'), - splashColor: orangeC, // inkwell color - child: const Padding( - padding: EdgeInsets.all(8), - child: Image( - image: AssetImage('assets/onBoarding/wallet.png'), - height: 90)), - onTap: () { - Navigator.push( - context, - FaderTransition( - page: OnboardingStepOne(), isFast: true)); - }), - ), - ), - decoration: const BoxDecoration( - shape: BoxShape.circle, - color: Colors.white, - boxShadow: [ - BoxShadow( - color: Colors.grey, - blurRadius: 4.0, - offset: Offset(2.0, 2.5), - spreadRadius: 0.5) - ], - ), - ), - const SizedBox(height: 15), - const Text( - "Créer un nouveau\nportefeuille", - textAlign: TextAlign.center, - style: TextStyle( - color: Colors.black, - fontSize: 16, - fontWeight: FontWeight.w500), - ), - const SizedBox(height: 70), - Container( - child: ClipOval( - child: Material( - color: const Color(0xffFFD58D), // button color - child: InkWell( - splashColor: orangeC, // inkwell color - child: Padding( - padding: const EdgeInsets.all(12), - child: - // Image( - // image: AssetImage('assets/cesium_bw3.png'), - // height: 60), - SvgPicture.asset('assets/cesium_small.svg', - semanticsLabel: 'Cesium Logo', height: 48), - ), - onTap: () { - Navigator.push(context, - SlideLeftRoute(page: const ImportWalletScreen())); - }), - ), - ), - decoration: const BoxDecoration( - shape: BoxShape.circle, - color: Colors.white, - boxShadow: [ - BoxShadow( - color: Colors.grey, - blurRadius: 4.0, - offset: Offset(2.0, 2.5), - spreadRadius: 0.5) - ], - ), - ), - const SizedBox(height: 10), - const Text( - "Importer un\nportefeuille Cesium", - textAlign: TextAlign.center, - style: TextStyle(color: Colors.black, fontSize: 13), - ) - ]), - )); - } -} diff --git a/lib/screens/onBoarding/1.dart b/lib/screens/onBoarding/1.dart index 9bd7cc5..2d8fba9 100644 --- a/lib/screens/onBoarding/1.dart +++ b/lib/screens/onBoarding/1.dart @@ -1,63 +1,47 @@ // ignore_for_file: file_names - import 'package:flutter/services.dart'; import 'package:flutter/material.dart'; import 'package:gecko/globals.dart'; import 'package:gecko/screens/common_elements.dart'; import 'package:gecko/screens/onBoarding/2.dart'; -// import 'package:gecko/models/home.dart'; -// import 'package:provider/provider.dart'; -// ignore: must_be_immutable class OnboardingStepOne extends StatelessWidget { - TextEditingController tplController = TextEditingController(); - final int progress = 1; - - OnboardingStepOne({Key? key}) : super(key: key); + const OnboardingStepOne({Key? key}) : super(key: key); @override Widget build(BuildContext context) { SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); CommonElements common = CommonElements(); - return Scaffold( - extendBodyBehindAppBar: true, - body: SafeArea( - child: Column(children: [ - common.onboardingProgressBar( - context, 'Nouveau portefeuilles', progress), - common.bubbleSpeak( - "Il semblerait que vous n’ayez pas encore de trousseau.\n\nUn trousseau vous permet de gérer un ou plusieurs portefeuilles.", - textKey: const Key('step1')), - const SizedBox(height: 90), - Image.asset( - 'assets/onBoarding/keys-and-wallets-horizontal.png', - height: 200, - ), - Expanded( - child: Align( - alignment: Alignment.bottomCenter, - child: SizedBox( - width: 400, - height: 62, - child: ElevatedButton( - key: const Key('goStep2'), - style: ElevatedButton.styleFrom( - elevation: 5, - primary: orangeC, - onPrimary: Colors.white, // foreground - ), - onPressed: () { - Navigator.push( - context, - FaderTransition( - page: OnboardingStepTwo(), isFast: true)); - }, - child: const Text('Créer mon trousseau', - style: TextStyle(fontSize: 20))), - ))), - const SizedBox(height: 80), - ]), - )); + appBar: AppBar( + toolbarHeight: 60 * ratio, + title: const SizedBox( + height: 22, + child: Text( + 'Nouveau portefeuille', + style: TextStyle(fontWeight: FontWeight.w600), + ), + ), + ), + extendBodyBehindAppBar: true, + body: SafeArea( + child: common.infoIntro( + context, + [ + const TextSpan( + text: 'Gecko fabrique votre portefeuille à partir d’une '), + const TextSpan( + text: 'phrase de restauration', + style: TextStyle(fontWeight: FontWeight.bold)), + const TextSpan( + text: + '. Elle est un peu comme le plan qui permet de construire votre portefeuille.'), + ], + 'fabrication-de-portefeuille.png', + '>', + const OnboardingStepTwo(), + 0), + ), + ); } } diff --git a/lib/screens/onBoarding/10.dart b/lib/screens/onBoarding/10.dart index 4f4aff0..c4fd8bd 100644 --- a/lib/screens/onBoarding/10.dart +++ b/lib/screens/onBoarding/10.dart @@ -1,64 +1,167 @@ // ignore_for_file: file_names +import 'dart:async'; import 'package:flutter/services.dart'; import 'package:flutter/material.dart'; import 'package:gecko/globals.dart'; +import 'package:gecko/providers/generate_wallets.dart'; +import 'package:gecko/providers/my_wallets.dart'; +import 'package:gecko/providers/substrate_sdk.dart'; +import 'package:gecko/providers/wallet_options.dart'; import 'package:gecko/screens/common_elements.dart'; -import 'package:gecko/screens/onBoarding/11.dart'; +import 'package:gecko/screens/onBoarding/11_congratulations.dart'; +import 'package:pin_code_fields/pin_code_fields.dart'; +import 'package:provider/provider.dart'; // ignore: must_be_immutable -class OnboardingStepTwelve extends StatelessWidget { - TextEditingController tplController = TextEditingController(); - final int progress = 9; +class OnboardingStepFourteen extends StatelessWidget { + OnboardingStepFourteen({ + Key? validationKey, + }) : super(key: validationKey); - OnboardingStepTwelve({Key? key}) : super(key: key); + final formKey = GlobalKey(); + Color? pinColor = const Color(0xFFA4B600); + bool hasError = false; @override Widget build(BuildContext context) { SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); + GenerateWalletsProvider _generateWalletProvider = + Provider.of(context); + WalletOptionsProvider _walletOptions = + Provider.of(context); CommonElements common = CommonElements(); + final int _pinLenght = _generateWalletProvider.pin.text.length; return Scaffold( + appBar: AppBar( + toolbarHeight: 60 * ratio, + title: const SizedBox( + height: 22, + child: Text( + 'Mon code secret', + style: TextStyle(fontWeight: FontWeight.w600), + ), + ), + ), extendBodyBehindAppBar: true, body: SafeArea( child: Column(children: [ - common.onboardingProgressBar( - context, '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.", - textKey: const Key('step10'), - ), - const SizedBox(height: 10), - Image.asset( - 'assets/onBoarding/plusieurs-codes-secrets-un-trousseau.png', - height: isTall ? 410 : 380, - ), - Expanded( - child: Align( - alignment: Alignment.bottomCenter, - child: SizedBox( - width: 400, - height: 62, - child: ElevatedButton( - key: const Key('goStep11'), - style: ElevatedButton.styleFrom( - elevation: 5, - primary: orangeC, - onPrimary: Colors.white, // foreground - ), - onPressed: () { - Navigator.push( - context, - FaderTransition( - page: const OnboardingStepThirteen(), - isFast: true), - ); - }, - child: const Text("Générer le code secret", - style: TextStyle(fontSize: 20))), - ))), - const SizedBox(height: 80), + SizedBox(height: isTall ? 40 : 20), + common.buildProgressBar(9), + SizedBox(height: isTall ? 40 : 20), + common.buildText([ + TextSpan( + text: + "Gecko va vérifier avec vous si vous avez bien mémorisé votre code secret.\n\nTapez votre code secret dans le champ ci-dessous pour vérifier que vous l’avez bien noté.", + style: TextStyle(fontSize: 16 * ratio)) + ]), + SizedBox(height: isTall ? 80 : 20), + pinForm(context, _walletOptions, _pinLenght, 1, 2) ]), )); } + + Widget pinForm(context, WalletOptionsProvider _walletOptions, _pinLenght, + int _walletNbr, int _derivation) { + // var _walletPin = ''; +// ignore: close_sinks + StreamController errorController = + StreamController(); + TextEditingController _enterPin = TextEditingController(); + MyWalletsProvider _myWalletProvider = + Provider.of(context); + GenerateWalletsProvider _generateWalletProvider = + Provider.of(context); + SubstrateSdk _sub = Provider.of(context, listen: false); + + final int? _currentChest = _myWalletProvider.getCurrentChest(); + + return Form( + key: formKey, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 30), + child: PinCodeTextField( + key: const Key('formKey2'), + autoFocus: true, + appContext: context, + pastedTextStyle: TextStyle( + color: Colors.green.shade600, + fontWeight: FontWeight.bold, + ), + length: _pinLenght, + obscureText: true, + obscuringCharacter: '*', + animationType: AnimationType.fade, + validator: (v) { + if (v!.length < _pinLenght) { + return "Votre code PIN fait $_pinLenght caractères"; + } else { + return null; + } + }, + pinTheme: PinTheme( + activeColor: pinColor, + borderWidth: 4, + shape: PinCodeFieldShape.box, + borderRadius: BorderRadius.circular(5), + fieldHeight: 60, + fieldWidth: 50, + activeFillColor: hasError ? Colors.blueAccent : Colors.black, + ), + cursorColor: Colors.black, + animationDuration: const Duration(milliseconds: 300), + textStyle: const TextStyle(fontSize: 20, height: 1.6), + backgroundColor: const Color(0xffF9F9F1), + enableActiveFill: false, + errorAnimationController: errorController, + controller: _enterPin, + keyboardType: TextInputType.text, + boxShadows: const [ + BoxShadow( + offset: Offset(0, 1), + color: Colors.black12, + blurRadius: 10, + ) + ], + onCompleted: (_pin) async { + _myWalletProvider.pinCode = _pin.toUpperCase(); + _myWalletProvider.pinLenght = _pinLenght; + log.d(_pin + ' || ' + _generateWalletProvider.pin.text); + if (_pin.toUpperCase() == _generateWalletProvider.pin.text) { + pinColor = Colors.green[500]; + final address = await _sub.importAccount( + fromMnemonic: true, + mnemonic: _generateWalletProvider.generatedMnemonic!, + derivePath: '//2', + password: _generateWalletProvider.pin.text); + await _generateWalletProvider.storeHDWChest( + address, 'Mon portefeuille courant', context); + _myWalletProvider.readAllWallets(_currentChest); + // scheduleMicrotask(() { + // _walletOptions.reloadBuild(); + _myWalletProvider.rebuildWidget(); + // }); + _generateWalletProvider.generatedMnemonic = ''; + Navigator.push( + context, + FaderTransition( + page: const OnboardingStepFiveteen(), isFast: false), + ); + } else { + errorController.add(ErrorAnimationType + .shake); // Triggering error shake animation + hasError = true; + pinColor = Colors.red[600]; + _walletOptions.reloadBuild(); + } + }, + onChanged: (value) { + if (pinColor != const Color(0xFFA4B600)) { + pinColor = const Color(0xFFA4B600); + } + }, + )), + ); + } } diff --git a/lib/screens/onBoarding/11.dart b/lib/screens/onBoarding/11.dart deleted file mode 100644 index 0c88222..0000000 --- a/lib/screens/onBoarding/11.dart +++ /dev/null @@ -1,118 +0,0 @@ -// ignore_for_file: file_names -import 'package:flutter/services.dart'; -import 'package:flutter/material.dart'; -import 'package:gecko/globals.dart'; -import 'package:gecko/providers/generate_wallets.dart'; -import 'package:gecko/screens/common_elements.dart'; -import 'package:gecko/screens/onBoarding/12.dart'; -import 'package:provider/provider.dart'; - -// ignore: must_be_immutable -class OnboardingStepThirteen extends StatelessWidget { - final int progress = 10; - - const OnboardingStepThirteen({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); - GenerateWalletsProvider _generateWalletProvider = - Provider.of(context); - // MyWalletsProvider myWalletProvider = - // Provider.of(context); - CommonElements common = CommonElements(); - _generateWalletProvider.pin.text = - _generateWalletProvider.changePinCode(reload: false); - - return Scaffold( - extendBodyBehindAppBar: true, - body: SafeArea( - child: Column(children: [ - common.onboardingProgressBar( - context, 'Ma phrase de restauration', progress), - common.bubbleSpeakRich( - [ - const TextSpan( - text: - "Et voilà votre code secret !\n\nMémorisez-le ou notez-le, car il vous sera demandé "), - const TextSpan( - text: 'à chaque fois', - style: TextStyle(fontWeight: FontWeight.bold)), - const TextSpan( - text: - " que vous voudrez effectuer un paiement sur cet appareil."), - ], - textKey: const Key('step11'), - ), - const SizedBox(height: 100), - Stack( - alignment: Alignment.centerRight, - children: [ - TextField( - key: const Key('generatedPin'), - enabled: false, - controller: _generateWalletProvider.pin, - maxLines: 1, - textAlign: TextAlign.center, - decoration: const InputDecoration(), - style: const TextStyle( - letterSpacing: 5, - fontSize: 35.0, - color: Colors.black, - fontWeight: FontWeight.bold)), - IconButton( - icon: const Icon(Icons.replay), - color: orangeC, - onPressed: () { - _generateWalletProvider.changePinCode(reload: true); - }, - ), - ], - ), - Expanded( - child: Align( - alignment: Alignment.bottomCenter, - child: SizedBox( - width: 400, - height: 62, - child: ElevatedButton( - key: const Key('changeSecretCode'), - style: ElevatedButton.styleFrom( - elevation: 5, - primary: const Color(0xffFFD58D), - onPrimary: Colors.black, // foreground - ), - onPressed: () { - _generateWalletProvider.changePinCode(reload: true); - }, - child: const Text("Choisir un autre code secret", - style: TextStyle(fontSize: 20))), - ))), - const SizedBox(height: 25), - SizedBox( - width: 400, - height: 62, - child: ElevatedButton( - key: const Key('goStep12'), - style: ElevatedButton.styleFrom( - elevation: 5, - primary: orangeC, - onPrimary: Colors.white, // foreground - ), - onPressed: () async { - _generateWalletProvider.isAskedWordValid = false; - _generateWalletProvider.askedWordColor = Colors.black; - Navigator.push( - context, - FaderTransition( - page: OnboardingStepFourteen(), isFast: true), - ); - }, - child: const Text("J'ai noté mon code secret", - style: TextStyle(fontSize: 20))), - ), - const SizedBox(height: 80), - ]), - )); - } -} diff --git a/lib/screens/onBoarding/11_congratulations.dart b/lib/screens/onBoarding/11_congratulations.dart new file mode 100644 index 0000000..67f0777 --- /dev/null +++ b/lib/screens/onBoarding/11_congratulations.dart @@ -0,0 +1,78 @@ +// ignore_for_file: file_names + +import 'package:flutter/services.dart'; +import 'package:flutter/material.dart'; +import 'package:gecko/globals.dart'; +import 'package:gecko/screens/common_elements.dart'; +import 'package:gecko/screens/myWallets/wallets_home.dart'; + +// ignore: must_be_immutable +class OnboardingStepFiveteen extends StatelessWidget { + const OnboardingStepFiveteen({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); + CommonElements common = CommonElements(); + + return Scaffold( + appBar: AppBar( + toolbarHeight: 60 * ratio, + title: const SizedBox( + height: 22, + child: Text( + 'C’est tout bon !', + style: TextStyle(fontWeight: FontWeight.w600), + ), + ), + ), + extendBodyBehindAppBar: true, + body: SafeArea( + child: Column(children: [ + const SizedBox(height: 40), + common.buildText([ + const TextSpan( + text: + "Top !\n\nVotre coffre votre premier portefeuille ont été créés avec un immense succès.\n\nFélicitations !", + ) + ]), + SizedBox(height: isTall ? 20 : 10), + Image.asset( + 'assets/onBoarding/gecko-clin.gif', + height: isTall ? 400 : 300, + ), + Expanded( + child: Align( + alignment: Alignment.bottomCenter, + child: finishButton(context)), + ), + const SizedBox(height: 40), + ]), + )); + } +} + +Widget finishButton(BuildContext context) { + return SizedBox( + width: 410, + height: 70, + child: ElevatedButton( + key: const Key('goWalletHome'), + style: ElevatedButton.styleFrom( + elevation: 4, + primary: orangeC, + onPrimary: Colors.white, // foreground + ), + onPressed: () { + Navigator.pushAndRemoveUntil( + context, + MaterialPageRoute(builder: (context) { + return const WalletsHome(); + }), + ModalRoute.withName('/'), + ); + }, + child: const Text("Accéder à mon coffre", + style: TextStyle(fontSize: 24, fontWeight: FontWeight.w600))), + ); +} diff --git a/lib/screens/onBoarding/12.dart b/lib/screens/onBoarding/12.dart deleted file mode 100644 index 3832702..0000000 --- a/lib/screens/onBoarding/12.dart +++ /dev/null @@ -1,153 +0,0 @@ -// ignore_for_file: file_names - -import 'dart:async'; -import 'package:durt/durt.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter/material.dart'; -import 'package:gecko/globals.dart'; -import 'package:gecko/providers/generate_wallets.dart'; -import 'package:gecko/providers/my_wallets.dart'; -import 'package:gecko/providers/wallet_options.dart'; -import 'package:gecko/screens/common_elements.dart'; -import 'package:gecko/screens/onBoarding/13_congratulations.dart'; -import 'package:pin_code_fields/pin_code_fields.dart'; -import 'package:provider/provider.dart'; - -// ignore: must_be_immutable -class OnboardingStepFourteen extends StatelessWidget { - OnboardingStepFourteen({ - Key? validationKey, - }) : super(key: validationKey); - - final int progress = 11; - final formKey = GlobalKey(); - Color? pinColor = const Color(0xFFA4B600); - bool hasError = false; - - @override - Widget build(BuildContext context) { - SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); - GenerateWalletsProvider _generateWalletProvider = - Provider.of(context); - WalletOptionsProvider _walletOptions = - Provider.of(context); - CommonElements common = CommonElements(); - final int _pinLenght = _generateWalletProvider.pin.text.length; - - return Scaffold( - extendBodyBehindAppBar: true, - body: SafeArea( - child: Column(children: [ - common.onboardingProgressBar( - context, '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).", - textKey: const Key('step12'), - ), - SizedBox(height: isTall ? 80 : 10), - pinForm(context, _walletOptions, _pinLenght, 1, 3) - ]), - )); - } - - Widget pinForm(context, WalletOptionsProvider _walletOptions, _pinLenght, - int _walletNbr, int _derivation) { - // var _walletPin = ''; -// ignore: close_sinks - StreamController errorController = - StreamController(); - TextEditingController _enterPin = TextEditingController(); - MyWalletsProvider _myWalletProvider = - Provider.of(context); - GenerateWalletsProvider _generateWalletProvider = - Provider.of(context); - - final int? _currentChest = _myWalletProvider.getCurrentChest(); - - return Form( - key: formKey, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 30), - child: PinCodeTextField( - key: const Key('formKey2'), - autoFocus: true, - appContext: context, - pastedTextStyle: TextStyle( - color: Colors.green.shade600, - fontWeight: FontWeight.bold, - ), - length: _pinLenght, - obscureText: true, - obscuringCharacter: '*', - animationType: AnimationType.fade, - validator: (v) { - if (v!.length < _pinLenght) { - return "Votre code PIN fait $_pinLenght caractères"; - } else { - return null; - } - }, - pinTheme: PinTheme( - activeColor: pinColor, - borderWidth: 4, - shape: PinCodeFieldShape.box, - borderRadius: BorderRadius.circular(5), - fieldHeight: 60, - fieldWidth: 50, - activeFillColor: hasError ? Colors.blueAccent : Colors.black, - ), - cursorColor: Colors.black, - animationDuration: const Duration(milliseconds: 300), - textStyle: const TextStyle(fontSize: 20, height: 1.6), - backgroundColor: const Color(0xffF9F9F1), - enableActiveFill: false, - errorAnimationController: errorController, - controller: _enterPin, - keyboardType: TextInputType.text, - boxShadows: const [ - BoxShadow( - offset: Offset(0, 1), - color: Colors.black12, - blurRadius: 10, - ) - ], - onCompleted: (_pin) async { - _myWalletProvider.pinCode = _pin.toUpperCase(); - _myWalletProvider.pinLenght = _pinLenght; - log.d(_pin + ' || ' + _generateWalletProvider.pin.text); - if (_pin.toUpperCase() == _generateWalletProvider.pin.text) { - pinColor = Colors.green[500]; - NewWallet generatedWallet = await Dewif().generateDewif( - _generateWalletProvider.generatedMnemonic!, - _generateWalletProvider.pin.text, - lang: appLang); - await _generateWalletProvider.storeHDWChest( - generatedWallet, 'Mon portefeuille courant', context); - _myWalletProvider.readAllWallets(_currentChest); - // scheduleMicrotask(() { - // _walletOptions.reloadBuild(); - _myWalletProvider.rebuildWidget(); - // }); - _generateWalletProvider.generatedMnemonic = ''; - Navigator.push( - context, - FaderTransition( - page: OnboardingStepFiveteen(), isFast: false), - ); - } else { - errorController.add(ErrorAnimationType - .shake); // Triggering error shake animation - hasError = true; - pinColor = Colors.red[600]; - _walletOptions.reloadBuild(); - } - }, - onChanged: (value) { - if (pinColor != const Color(0xFFA4B600)) { - pinColor = const Color(0xFFA4B600); - } - }, - )), - ); - } -} diff --git a/lib/screens/onBoarding/13_congratulations.dart b/lib/screens/onBoarding/13_congratulations.dart deleted file mode 100644 index f7189c7..0000000 --- a/lib/screens/onBoarding/13_congratulations.dart +++ /dev/null @@ -1,67 +0,0 @@ -// ignore_for_file: file_names - -import 'package:flutter/services.dart'; -import 'package:flutter/material.dart'; -import 'package:gecko/globals.dart'; -import 'package:gecko/screens/common_elements.dart'; -import 'package:gecko/screens/myWallets/wallets_home.dart'; - -// ignore: must_be_immutable -class OnboardingStepFiveteen extends StatelessWidget { - TextEditingController tplController = TextEditingController(); - final int progress = 12; - - OnboardingStepFiveteen({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); - CommonElements common = CommonElements(); - - return Scaffold( - extendBodyBehindAppBar: true, - body: SafeArea( - child: Column(children: [ - common.onboardingProgressBar( - context, 'Ma phrase de restauration', progress), - common.bubbleSpeak( - "Top !\n\nVotre trousseau de clef et votre portefeuille ont été créés avec un immense succès.\n\nFélicitations !", - textKey: const Key('step13'), - ), - SizedBox(height: isTall ? 20 : 10), - Image.asset( - 'assets/onBoarding/gecko-clin.gif', - height: isTall ? 400 : 300, - ), - Expanded( - child: Align( - alignment: Alignment.bottomCenter, - child: SizedBox( - width: 400, - height: 62, - child: ElevatedButton( - key: const Key('goWalletHome'), - style: ElevatedButton.styleFrom( - elevation: 5, - primary: orangeC, - onPrimary: Colors.white, // foreground - ), - onPressed: () { - Navigator.pushAndRemoveUntil( - context, - MaterialPageRoute(builder: (context) { - return const WalletsHome(); - }), - ModalRoute.withName('/'), - ); - }, - child: const Text("Accéder à mes portefeuilles", - style: TextStyle(fontSize: 20))), - ), - ), - ), - const SizedBox(height: 80), - ]), - )); - } -} diff --git a/lib/screens/onBoarding/2.dart b/lib/screens/onBoarding/2.dart index 04c3495..6f2d496 100644 --- a/lib/screens/onBoarding/2.dart +++ b/lib/screens/onBoarding/2.dart @@ -5,16 +5,9 @@ import 'package:flutter/material.dart'; import 'package:gecko/globals.dart'; import 'package:gecko/screens/common_elements.dart'; import 'package:gecko/screens/onBoarding/3.dart'; -// import 'package:gecko/screens/commonElements.dart'; -// import 'package:gecko/models/home.dart'; -// import 'package:provider/provider.dart'; -// ignore: must_be_immutable class OnboardingStepTwo extends StatelessWidget { - TextEditingController tplController = TextEditingController(); - final int progress = 2; - - OnboardingStepTwo({Key? key}) : super(key: key); + const OnboardingStepTwo({Key? key}) : super(key: key); @override Widget build(BuildContext context) { @@ -22,44 +15,30 @@ class OnboardingStepTwo extends StatelessWidget { CommonElements common = CommonElements(); return Scaffold( - extendBodyBehindAppBar: true, - body: SafeArea( - child: Column(children: [ - common.onboardingProgressBar( - context, 'Nouveau portefeuilles', progress), - common.bubbleSpeak( - "Un trousseau est créé à partir d’une phrase de restauration.", - textKey: const Key('step2'), - ), - const SizedBox(height: 70), - Image.asset( - 'assets/onBoarding/keys-and-wallets-horizontal-plus-phrase.png'), - Expanded( - child: Align( - alignment: Alignment.bottomCenter, - child: SizedBox( - width: 400, - height: 62, - child: ElevatedButton( - key: const Key('goStep3'), - style: ElevatedButton.styleFrom( - elevation: 5, - primary: orangeC, - onPrimary: Colors.white, // foreground - ), - onPressed: () { - Navigator.push( - context, - FaderTransition( - page: OnboardingStepFor(), isFast: true), - ); - }, - child: const Text("D'accord", - style: TextStyle(fontSize: 20)), - ), - ))), - const SizedBox(height: 80), - ]), - )); + appBar: AppBar( + toolbarHeight: 60 * ratio, + title: const SizedBox( + height: 22, + child: Text( + 'Votre phrase de restauration', + style: TextStyle(fontWeight: FontWeight.w600), + ), + ), + ), + extendBodyBehindAppBar: true, + body: SafeArea( + child: common.infoIntro( + context, + [ + const TextSpan( + text: + 'Conservez cette phrase précieusement, car sans elle Gecko ne pourra pas reconstruire vos portefeuilles le jour où vous changez de téléphone.'), + ], + 'fabrication-de-portefeuille-impossible-sans-phrase.png', + '>', + const OnboardingStepThree(), + 1), + ), + ); } } diff --git a/lib/screens/onBoarding/3.dart b/lib/screens/onBoarding/3.dart index 41b9ec3..ebce3a4 100644 --- a/lib/screens/onBoarding/3.dart +++ b/lib/screens/onBoarding/3.dart @@ -6,12 +6,8 @@ import 'package:gecko/globals.dart'; import 'package:gecko/screens/common_elements.dart'; import 'package:gecko/screens/onBoarding/4.dart'; -// ignore: must_be_immutable -class OnboardingStepFor extends StatelessWidget { - TextEditingController tplController = TextEditingController(); - final int progress = 3; - - OnboardingStepFor({Key? key}) : super(key: key); +class OnboardingStepThree extends StatelessWidget { + const OnboardingStepThree({Key? key}) : super(key: key); @override Widget build(BuildContext context) { @@ -19,50 +15,28 @@ class OnboardingStepFor extends StatelessWidget { CommonElements common = CommonElements(); return Scaffold( - extendBodyBehindAppBar: true, - body: SafeArea( - child: Column(children: [ - common.onboardingProgressBar( - context, 'Ma phrase de restauration', progress), - common.bubbleSpeak( - "Si un jour vous changez de téléphone, il vous suffira de me redonner votre phrase de restauration pour recréer votre trousseau.", - textKey: const Key('step3'), - ), - SizedBox(height: isTall ? 15 : 0), - // Row(children: [ - // Align( - // alignment: Alignment.centerRight, - // child: - Image.asset( - 'assets/onBoarding/plusieurs-appareils-un-trousseau.png', - height: 400 * ratio, - ), - // ]), - Expanded( - child: Align( - alignment: Alignment.bottomCenter, - child: SizedBox( - width: 400, - height: 62, - child: ElevatedButton( - key: const Key('goStep4'), - style: ElevatedButton.styleFrom( - elevation: 5, - primary: orangeC, - onPrimary: Colors.white, // foreground - ), - onPressed: () { - Navigator.push( - context, - FaderTransition( - page: OnboardingStepFive(), isFast: true), - ); - }, - child: const Text("J'ai compris", - style: TextStyle(fontSize: 20))), - ))), - const SizedBox(height: 80), - ]), - )); + appBar: AppBar( + toolbarHeight: 60 * ratio, + title: const SizedBox( + height: 22, + child: Text( + 'Votre phrase de restauration', + style: TextStyle(fontWeight: FontWeight.w600), + ), + ), + ), + extendBodyBehindAppBar: true, + body: SafeArea( + child: common.infoIntro( + context, + [ + const TextSpan(text: 'Dans une blockchain, pas de procédure de récupération par mail. Seule votre phrase de restauration peut vous permettre de récupérer vos Ğ1 à tout moment.'), + ], + 'mot-de-passe-oublie.png', + '>', + const OnboardingStepFor(), + 2), + ), + ); } } diff --git a/lib/screens/onBoarding/4.dart b/lib/screens/onBoarding/4.dart index a064231..3b481a4 100644 --- a/lib/screens/onBoarding/4.dart +++ b/lib/screens/onBoarding/4.dart @@ -6,12 +6,8 @@ import 'package:gecko/globals.dart'; import 'package:gecko/screens/common_elements.dart'; import 'package:gecko/screens/onBoarding/5.dart'; -// ignore: must_be_immutable -class OnboardingStepFive extends StatelessWidget { - TextEditingController tplController = TextEditingController(); - final int progress = 4; - - OnboardingStepFive({Key? key}) : super(key: key); +class OnboardingStepFor extends StatelessWidget { + const OnboardingStepFor({Key? key}) : super(key: key); @override Widget build(BuildContext context) { @@ -19,45 +15,33 @@ class OnboardingStepFive extends StatelessWidget { CommonElements common = CommonElements(); return Scaffold( - extendBodyBehindAppBar: true, - body: SafeArea( - child: Column(children: [ - common.onboardingProgressBar( - context, 'Ma phrase de restauration', progress), - common.bubbleSpeak( - "Par contre, attention :\n\nDans une blockchain, il n’y a pas de procédure de récupération de trousseau.\n\nSi vous perdez votre phrase de restauration, je ne pourrai pas vous la communiquer, et vous ne pourrez donc plus jamais accéder à votre compte.", - textKey: const Key('step4'), - ), - SizedBox(height: isTall ? 30 : 10), - Image.asset( - 'assets/onBoarding/maison-qui-brule.png', - width: 320 * ratio, - ), - Expanded( - child: Align( - alignment: Alignment.bottomCenter, - child: SizedBox( - width: 400, - height: 62, - child: ElevatedButton( - key: const Key('goStep5'), - style: ElevatedButton.styleFrom( - elevation: 5, - primary: orangeC, - onPrimary: Colors.white, // foreground - ), - onPressed: () { - Navigator.push( - context, - FaderTransition( - page: OnboardingStepSeven(), isFast: true), - ); - }, - child: const Text("J'ai compris", - style: TextStyle(fontSize: 20))), - ))), - const SizedBox(height: 80), - ]), - )); + appBar: AppBar( + toolbarHeight: 60 * ratio, + title: const SizedBox( + height: 22, + child: Text( + 'Votre phrase de restauration', + style: TextStyle(fontWeight: FontWeight.w600), + ), + ), + ), + extendBodyBehindAppBar: true, + body: SafeArea( + child: common.infoIntro( + context, + [ + const TextSpan(text: 'Il est temps de vous munir d’'), + const TextSpan( + text: 'un d’un papier et d’un crayon', + style: TextStyle(fontWeight: FontWeight.bold)), + const TextSpan( + text: ' afin de pouvoir noter votre phrase de restauration.'), + ], + 'gecko-oublie-aussi.png', + '>', + const OnboardingStepFive(), + 3), + ), + ); } } diff --git a/lib/screens/onBoarding/5.dart b/lib/screens/onBoarding/5.dart index af8c3ad..fca4806 100644 --- a/lib/screens/onBoarding/5.dart +++ b/lib/screens/onBoarding/5.dart @@ -3,78 +3,243 @@ import 'package:flutter/services.dart'; import 'package:flutter/material.dart'; import 'package:gecko/globals.dart'; +import 'package:gecko/providers/generate_wallets.dart'; +import 'package:gecko/providers/my_wallets.dart'; import 'package:gecko/screens/common_elements.dart'; import 'package:gecko/screens/onBoarding/6.dart'; +import 'package:printing/printing.dart'; +import 'package:provider/provider.dart'; -// ignore: must_be_immutable -class OnboardingStepSeven extends StatelessWidget { - TextEditingController tplController = TextEditingController(); - final int progress = 5; +AsyncSnapshot? mnemoList; - OnboardingStepSeven({Key? key}) : super(key: key); +class OnboardingStepFive extends StatelessWidget { + const OnboardingStepFive({Key? key}) : super(key: key); @override Widget build(BuildContext context) { SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); + GenerateWalletsProvider _generateWalletProvider = + Provider.of(context, listen: false); + CommonElements common = CommonElements(); return Scaffold( - extendBodyBehindAppBar: true, - body: SafeArea( - child: Column(children: [ - common.onboardingProgressBar( - context, 'Ma phrase de restauration', progress), - common.bubbleSpeakRich( - [ - const TextSpan(text: "Munissez-vous d'"), - const TextSpan( - text: 'un papier et d’un crayon\n', - style: TextStyle(fontWeight: FontWeight.bold)), - const TextSpan( - text: - "afin de pouvoir noter votre phrase de restauration."), - ], - textKey: const Key('step5'), + appBar: AppBar( + toolbarHeight: 60 * ratio, + title: const SizedBox( + height: 22, + child: Text( + 'Votre phrase de restauration', + style: TextStyle(fontWeight: FontWeight.w600), + ), + ), + ), + extendBodyBehindAppBar: true, + body: SafeArea( + child: Column(children: [ + SizedBox(height: isTall ? 40 : 20), + common.buildProgressBar(4), + SizedBox(height: isTall ? 40 : 20), + common.buildText( + [ + const TextSpan( + text: + 'Gecko a généré votre phrase de restauration ! Tâchez de la garder bien secrète, car elle permet à quiconque la connaît d’accéder à tous vos portefeuilles.'), + ], + ), + const SizedBox(height: 40), + sentanceArray(context), + const SizedBox(height: 20), + GestureDetector( + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) { + return PrintWallet(_generateWalletProvider.generatedMnemonic); + }), + ); + }, + child: Image.asset( + 'assets/printer.png', + height: 45, ), - Expanded( - child: Align( + ), + const SizedBox(height: 40), + Expanded( + child: Align( alignment: Alignment.bottomCenter, - child: Row(mainAxisSize: MainAxisSize.min, children: [ - Container( - padding: const EdgeInsets.only(bottom: 90), - child: common.bubbleSpeak( - "Moi, j’ai déjà essayé de\nmémoriser une phrase de\nrestauration, mais je n’ai\npas une mémoire\nd’éléphant.", - isMaxWidth: false), - ), - Image.asset( - 'assets/onBoarding/chopp-gecko.png', - height: 200, - ), - ]), - )), - SizedBox(height: isTall ? 120 : 50), - SizedBox( - width: 400, - height: 62, - child: ElevatedButton( - key: const Key('goStep6'), - style: ElevatedButton.styleFrom( - elevation: 5, - primary: orangeC, - onPrimary: Colors.white, // foreground - ), - onPressed: () { - Navigator.push( - context, - FaderTransition( - page: OnboardingStepEight(), isFast: true), - ); - }, - child: const Text("J'ai de quoi noter", - style: TextStyle(fontSize: 20))), + child: SizedBox( + width: 410, + height: 70, + child: ElevatedButton( + key: const Key('generateMnemonic'), + style: ElevatedButton.styleFrom( + elevation: 4, + primary: const Color(0xffFFD58D), + onPrimary: Colors.black, // foreground + ), + onPressed: () { + _generateWalletProvider.reloadBuild(); + // setState(() {}); + }, + child: const Text("Choisir une autre phrase", + style: TextStyle( + fontSize: 24, fontWeight: FontWeight.w600))), + ), ), - const SizedBox(height: 80), - ]), - )); + ), + const SizedBox(height: 25), + nextButton(context, "J'ai noté ma phrase", false), + const SizedBox(height: 40), + ]), + ), + ); } } + +Widget sentanceArray(BuildContext context) { + GenerateWalletsProvider _generateWalletProvider = + Provider.of(context); + + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 3), + child: Container( + constraints: const BoxConstraints(maxWidth: 450), + decoration: BoxDecoration( + border: Border.all(color: Colors.black), + color: const Color(0xffeeeedd), + borderRadius: const BorderRadius.all( + Radius.circular(10), + )), + padding: const EdgeInsets.all(20), + child: FutureBuilder( + future: _generateWalletProvider.generateWordList(context), + builder: (BuildContext context, AsyncSnapshot _data) { + if (!_data.hasData) { + return const Text(''); + } else { + mnemoList = _data; + return Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Row(children: [ + arrayCell(_data.data![0]), + arrayCell(_data.data![1]), + arrayCell(_data.data![2]), + arrayCell(_data.data![3]), + ]), + const SizedBox(height: 15), + Row(children: [ + arrayCell(_data.data![4]), + arrayCell(_data.data![5]), + arrayCell(_data.data![6]), + arrayCell(_data.data![7]), + ]), + const SizedBox(height: 15), + Row(children: [ + arrayCell(_data.data![8]), + arrayCell(_data.data![9]), + arrayCell(_data.data![10]), + arrayCell(_data.data![11]), + ]), + ]); + } + }), + ), + ); +} + +Widget arrayCell(dataWord) { + return SizedBox( + width: 100, + child: Column(children: [ + Text( + dataWord.split(':')[0], + style: const TextStyle(fontSize: 15, color: Color(0xff6b6b52)), + ), + Text( + dataWord.split(':')[1], + key: Key('word${dataWord.split(':')[0]}'), + style: const TextStyle(fontSize: 20, color: Colors.black), + ), + ]), + ); +} + +// ignore: must_be_immutable +class PrintWallet extends StatelessWidget { + const PrintWallet(this.sentence, {Key? key}) : super(key: key); + + final String? sentence; + + @override + Widget build(BuildContext context) { + GenerateWalletsProvider _generateWalletProvider = + Provider.of(context); + return MaterialApp( + home: Scaffold( + appBar: AppBar( + leading: IconButton( + icon: const Icon(Icons.arrow_back, color: Colors.black), + onPressed: () { + Navigator.pop(context); + }), + backgroundColor: yellowC, + foregroundColor: Colors.black, + toolbarHeight: 60 * ratio, + title: const SizedBox( + height: 22, + child: Text( + 'Imprimer ma phrase de restauration', + style: TextStyle(fontWeight: FontWeight.w600), + ), + ), + ), + body: PdfPreview( + canDebug: false, + canChangeOrientation: false, + build: (format) => _generateWalletProvider.printWallet(mnemoList), + ), + ), + ); + } +} + +Widget nextButton(BuildContext context, String text, bool isFast) { + GenerateWalletsProvider _generateWalletProvider = + Provider.of(context, listen: false); + MyWalletsProvider _myWalletProvider = + Provider.of(context, listen: false); + return SizedBox( + width: 410, + height: 70, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + elevation: 4, + primary: orangeC, // background + onPrimary: Colors.white, // foreground + ), + onPressed: () { + _generateWalletProvider.nbrWord = + _generateWalletProvider.getRandomInt(); + _generateWalletProvider.nbrWordAlpha = _generateWalletProvider + .intToString(_generateWalletProvider.nbrWord + 1); + _myWalletProvider.mnemonic = _generateWalletProvider.generatedMnemonic!; + + Navigator.push( + context, + FaderTransition( + page: OnboardingStepSix( + generatedMnemonic: _generateWalletProvider.generatedMnemonic), + isFast: true), + ); + }, + child: Text( + text, + style: const TextStyle(fontSize: 24, fontWeight: FontWeight.w600), + ), + ), + ); +} diff --git a/lib/screens/onBoarding/6.dart b/lib/screens/onBoarding/6.dart index dc2b119..ba256c0 100644 --- a/lib/screens/onBoarding/6.dart +++ b/lib/screens/onBoarding/6.dart @@ -1,124 +1,238 @@ // ignore_for_file: file_names -import 'dart:ui'; import 'package:flutter/services.dart'; import 'package:flutter/material.dart'; import 'package:gecko/globals.dart'; +import 'package:gecko/providers/generate_wallets.dart'; import 'package:gecko/screens/common_elements.dart'; import 'package:gecko/screens/onBoarding/7.dart'; +import 'package:provider/provider.dart'; // ignore: must_be_immutable -class OnboardingStepEight extends StatelessWidget { - TextEditingController tplController = TextEditingController(); - final int progress = 6; +class OnboardingStepSix extends StatelessWidget { + OnboardingStepSix({Key? key, required this.generatedMnemonic}) + : super(key: key); - OnboardingStepEight({Key? key}) : super(key: key); + String? generatedMnemonic; + TextEditingController wordController = TextEditingController(); + final TextEditingController _mnemonicController = TextEditingController(); @override Widget build(BuildContext context) { SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); - CommonElements common = CommonElements(); + GenerateWalletsProvider _generateWalletProvider = + Provider.of(context, listen: true); - return Scaffold( + CommonElements common = CommonElements(); + _mnemonicController.text = generatedMnemonic!; + + return WillPopScope( + onWillPop: () { + _generateWalletProvider.isAskedWordValid = false; + _generateWalletProvider.askedWordColor = Colors.black; + return Future.value(true); + }, + child: Scaffold( + resizeToAvoidBottomInset: false, extendBodyBehindAppBar: true, - body: SafeArea( - child: Column(children: [ - common.onboardingProgressBar( - context, 'Ma phrase de restauration', progress), - common.bubbleSpeak( - "J’ai généré votre phrase de restauration !\nTâchez de la garder bien secrète, car elle permet à quiconque la connaît d’accéder à tous vos portefeuilles.", - textKey: const Key('step6'), + appBar: AppBar( + toolbarHeight: 60 * ratio, + title: const SizedBox( + height: 22, + child: Text( + 'Votre phrase de restauration', + style: TextStyle(fontWeight: FontWeight.w600), ), - SizedBox(height: isTall ? 70 : 40), - // SizedBox(height: 30), - sentanceArray(context), - // ), - Expanded( - child: Align( + ), + ), + body: SafeArea( + child: Align( + alignment: Alignment.topCenter, + child: Column(children: [ + SizedBox(height: isTall ? 40 : 20), + common.buildProgressBar(5), + SizedBox(height: isTall ? 40 : 20), + common.buildText( + [ + TextSpan( + text: + "Avez-vous bien noté votre phrase de restauration ?\n\nPour en être sûr, veuillez taper dans le champ ci-dessous le ", + style: TextStyle(fontSize: 16 * ratio)), + TextSpan( + text: '${_generateWalletProvider.nbrWord + 1}ème mot', + style: TextStyle( + fontWeight: FontWeight.bold, fontSize: 16 * ratio)), + TextSpan( + text: " de votre phrase de restauration :", + style: TextStyle(fontSize: 16 * ratio)), + ], + ), + SizedBox(height: isTall ? 70 : 20), + Text('${_generateWalletProvider.nbrWord + 1}', + key: const Key('askedWord'), + style: TextStyle( + fontSize: isTall ? 17 : 15, + color: orangeC, + fontWeight: FontWeight.w400)), + const SizedBox(height: 10), + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(7), + border: Border.all( + color: Colors.grey[600]!, + width: 3, + )), + width: 430, + child: TextFormField( + key: const Key('inputWord'), + autofocus: true, + enabled: !_generateWalletProvider.isAskedWordValid, + controller: 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: const Color(0xffeeeedd), + filled: true, + contentPadding: const 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( - key: const Key('goStep7'), - style: ElevatedButton.styleFrom( - elevation: 5, - primary: orangeC, - onPrimary: Colors.white, // foreground - ), - onPressed: () { - Navigator.push( - context, - FaderTransition( - page: OnboardingStepNine(), isFast: false), - ); - }, - child: const Text("Afficher ma phrase", - style: TextStyle(fontSize: 20))), - ))), - const SizedBox(height: 80), - ]), - )); + child: nextButton(context, 'Continuer', + const OnboardingStepSeven(), false), + ), + ), + ), + // Visibility( + // visible: !_generateWalletProvider.isAskedWordValid, + // child: const Expanded( + // child: Align( + // alignment: Alignment.bottomCenter, + // child: Text(''), + // ), + // ), + // ), + const SizedBox(height: 40), + ]), + ), + ), + ), + ); } } Widget sentanceArray(BuildContext context) { + GenerateWalletsProvider _generateWalletProvider = + Provider.of(context); + return Padding( - padding: const EdgeInsets.symmetric(horizontal: 12), - child: Container( - constraints: const BoxConstraints(maxWidth: 450), - decoration: BoxDecoration( - border: Border.all(color: Colors.black), - color: Colors.grey[300], - borderRadius: const BorderRadius.all( - Radius.circular(10), - )), - // color: Colors.grey[300], - padding: const EdgeInsets.all(20), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.max, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Row(children: [ - arrayCell("1:exquis"), - arrayCell("2:favori"), - arrayCell("3:curseur"), - arrayCell("4:relatif"), - ]), - const SizedBox(height: 15), - Row(children: [ - arrayCell("5:embellir"), - arrayCell("6:cultiver"), - arrayCell("7:bureau"), - arrayCell("8:ossature"), - ]), - const SizedBox(height: 15), - Row(children: [ - arrayCell("9:labial"), - arrayCell("10:science"), - arrayCell("11:théorie"), - arrayCell("12:Monnaie"), - ]), - ]))); + padding: const EdgeInsets.symmetric(horizontal: 3), + child: Container( + constraints: const BoxConstraints(maxWidth: 450), + decoration: BoxDecoration( + border: Border.all(color: Colors.black), + color: const Color(0xffeeeedd), + borderRadius: const BorderRadius.all( + Radius.circular(10), + )), + padding: const EdgeInsets.all(20), + child: FutureBuilder( + future: _generateWalletProvider.generateWordList(context), + builder: (BuildContext context, AsyncSnapshot _data) { + if (!_data.hasData) { + return const Text(''); + } else { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Row(children: [ + arrayCell(_data.data![0]), + arrayCell(_data.data![1]), + arrayCell(_data.data![2]), + arrayCell(_data.data![3]), + ]), + const SizedBox(height: 15), + Row(children: [ + arrayCell(_data.data![4]), + arrayCell(_data.data![5]), + arrayCell(_data.data![6]), + arrayCell(_data.data![7]), + ]), + const SizedBox(height: 15), + Row(children: [ + arrayCell(_data.data![8]), + arrayCell(_data.data![9]), + arrayCell(_data.data![10]), + arrayCell(_data.data![11]), + ]), + ]); + } + }), + ), + ); } Widget arrayCell(dataWord) { return SizedBox( - width: 102, - child: Column( - children: [ - ImageFiltered( - imageFilter: ImageFilter.blur(sigmaX: 1, sigmaY: 1), - child: Text(dataWord.split(':')[0], - style: const TextStyle(fontSize: 14, color: Colors.black)), - ), - const SizedBox(height: 2), - ImageFiltered( - imageFilter: ImageFilter.blur(sigmaX: 4, sigmaY: 4), - child: Text(dataWord.split(':')[1], - style: const TextStyle(fontSize: 19, color: Colors.black)), - ) - ], - )); + width: 100, + child: Column(children: [ + Text( + dataWord.split(':')[0], + style: const TextStyle(fontSize: 15, color: Color(0xff6b6b52)), + ), + Text( + dataWord.split(':')[1], + key: Key('word${dataWord.split(':')[0]}'), + style: const TextStyle(fontSize: 20, color: Colors.black), + ), + ]), + ); +} + +Widget nextButton(BuildContext context, String text, nextScreen, bool isFast) { + GenerateWalletsProvider _generateWalletProvider = + Provider.of(context, listen: false); + + _generateWalletProvider.isAskedWordValid = false; + _generateWalletProvider.askedWordColor = Colors.black; + + return SizedBox( + width: 410, + height: 70, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + elevation: 4, + primary: orangeC, // background + onPrimary: Colors.white, // foreground + ), + onPressed: () { + Navigator.push( + context, FaderTransition(page: nextScreen, isFast: isFast)); + }, + child: Text( + text, + style: const TextStyle(fontSize: 24, fontWeight: FontWeight.w600), + ), + ), + ); } diff --git a/lib/screens/onBoarding/7.dart b/lib/screens/onBoarding/7.dart index 27cc83d..1c0c96c 100644 --- a/lib/screens/onBoarding/7.dart +++ b/lib/screens/onBoarding/7.dart @@ -1,209 +1,43 @@ // ignore_for_file: file_names - import 'package:flutter/services.dart'; import 'package:flutter/material.dart'; import 'package:gecko/globals.dart'; -import 'package:gecko/providers/generate_wallets.dart'; -import 'package:gecko/providers/my_wallets.dart'; import 'package:gecko/screens/common_elements.dart'; import 'package:gecko/screens/onBoarding/8.dart'; -import 'package:printing/printing.dart'; -import 'package:provider/provider.dart'; -// ignore: must_be_immutable -class OnboardingStepNine extends StatelessWidget { - TextEditingController tplController = TextEditingController(); - final int progress = 6; - - OnboardingStepNine({Key? key}) : super(key: key); +class OnboardingStepSeven extends StatelessWidget { + const OnboardingStepSeven({Key? key}) : super(key: key); @override Widget build(BuildContext context) { SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); - GenerateWalletsProvider _generateWalletProvider = - Provider.of(context); - MyWalletsProvider _myWalletProvider = - Provider.of(context); CommonElements common = CommonElements(); - - // _generateWalletProvider.generateMnemonic(); - return Scaffold( - extendBodyBehindAppBar: true, - body: SafeArea( - child: Column(children: [ - common.onboardingProgressBar( - context, 'Ma phrase de restauration', progress), - common.bubbleSpeak( - "C'est le moment de noter votre phrase !", - textKey: const Key('step7'), - long: 60, - ), - SizedBox(height: isTall ? 100 : 70), - sentanceArray(context), - SizedBox(height: isTall ? 20 : 15), - GestureDetector( - onTap: () { - Navigator.push( - context, - MaterialPageRoute(builder: (context) { - return PrintWallet( - _generateWalletProvider.generatedMnemonic); - }), - ); - }, - child: Image.asset( - 'assets/printer.png', - height: 35, - ), - ), - Expanded( - child: Align( - alignment: Alignment.bottomCenter, - child: SizedBox( - width: 400, - height: 62, - child: ElevatedButton( - key: const Key('generateMnemonic'), - style: ElevatedButton.styleFrom( - elevation: 5, - primary: const Color(0xffFFD58D), - onPrimary: Colors.black, // foreground - ), - onPressed: () { - _generateWalletProvider.reloadBuild(); - }, - child: const Text("Choisir une autre phrase", - style: TextStyle(fontSize: 20))), - ))), - const SizedBox(height: 25), - SizedBox( - width: 400, - height: 62, - child: ElevatedButton( - key: const Key('goStep8'), - style: ElevatedButton.styleFrom( - elevation: 5, - primary: orangeC, - onPrimary: Colors.white, // foreground - ), - onPressed: () { - _generateWalletProvider.nbrWord = - _generateWalletProvider.getRandomInt(); - _generateWalletProvider.nbrWordAlpha = - _generateWalletProvider - .intToString(_generateWalletProvider.nbrWord + 1); - _myWalletProvider.mnemonic = - _generateWalletProvider.generatedMnemonic!; - - Navigator.push( - context, - FaderTransition( - page: OnboardingStepTen( - generatedMnemonic: - _generateWalletProvider.generatedMnemonic), - isFast: true), - ); - }, - child: const Text("J'ai noté ma phrase", - style: TextStyle(fontSize: 20))), - ), - const SizedBox(height: 80), - ]), - )); - } -} - -Widget sentanceArray(BuildContext context) { - GenerateWalletsProvider _generateWalletProvider = - Provider.of(context); - - List formatedArray = _generateWalletProvider.generateWordList(); - - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 12), - child: Container( - constraints: const BoxConstraints(maxWidth: 450), - decoration: BoxDecoration( - border: Border.all(color: Colors.black), - color: Colors.grey[300], - borderRadius: const BorderRadius.all( - Radius.circular(10), - )), - // color: Colors.grey[300], - padding: const EdgeInsets.all(20), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.max, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Row(children: [ - arrayCell(formatedArray[0]), - arrayCell(formatedArray[1]), - arrayCell(formatedArray[2]), - arrayCell(formatedArray[3]), - ]), - const SizedBox(height: 15), - Row(children: [ - arrayCell(formatedArray[4]), - arrayCell(formatedArray[5]), - arrayCell(formatedArray[6]), - arrayCell(formatedArray[7]), - ]), - const SizedBox(height: 15), - Row(children: [ - arrayCell(formatedArray[8]), - arrayCell(formatedArray[9]), - arrayCell(formatedArray[10]), - arrayCell(formatedArray[11]), - ]), - ]), - ), - ); -} - -Widget arrayCell(dataWord) { - return SizedBox( - width: 102, - child: Column(children: [ - Text( - dataWord.split(':')[0], - style: const TextStyle(fontSize: 14), - ), - const SizedBox(height: 2), - Text( - dataWord.split(':')[1], - key: Key('word${dataWord.split(':')[0]}'), - style: const TextStyle(fontSize: 19, color: Colors.black), - ), - ]), - ); -} - -// ignore: must_be_immutable -class PrintWallet extends StatelessWidget { - const PrintWallet(this.sentence, {Key? key}) : super(key: key); - - final String? sentence; - - @override - Widget build(BuildContext context) { - GenerateWalletsProvider _generateWalletProvider = - Provider.of(context); - return MaterialApp( - home: Scaffold( - appBar: AppBar( - leading: IconButton( - icon: const Icon(Icons.arrow_back, color: Colors.white), - onPressed: () { - Navigator.pop(context); - }), - toolbarHeight: 60 * ratio, - title: const Text('Imprimer ce trousseau')), - body: PdfPreview( - build: (format) => _generateWalletProvider.printWallet(sentence), + appBar: AppBar( + toolbarHeight: 60 * ratio, + title: const SizedBox( + height: 22, + child: Text( + 'Mon code secret', + style: TextStyle(fontWeight: FontWeight.w600), + ), ), ), + extendBodyBehindAppBar: true, + body: SafeArea( + child: common.infoIntro( + context, + [ + const TextSpan( + text: + 'Gecko va maintenant générer pour vous un code secret court qui vous permettra d’accéder rapidement à vos portefeuilles, sans avoir à taper votre phrase de restauration à chaque fois.'), + ], + 'coffre-fort-code-secret-dans-telephone.png', + '>', + const OnboardingStepEight(), + 6, + boxHeight: 400), + ), ); } } diff --git a/lib/screens/onBoarding/8.dart b/lib/screens/onBoarding/8.dart index c9ec4ca..dd7ce56 100644 --- a/lib/screens/onBoarding/8.dart +++ b/lib/screens/onBoarding/8.dart @@ -2,134 +2,47 @@ import 'package:flutter/services.dart'; import 'package:flutter/material.dart'; import 'package:gecko/globals.dart'; -import 'package:gecko/providers/generate_wallets.dart'; import 'package:gecko/screens/common_elements.dart'; import 'package:gecko/screens/onBoarding/9.dart'; -import 'package:provider/provider.dart'; -// ignore: must_be_immutable -class OnboardingStepTen extends StatelessWidget { - OnboardingStepTen({ - Key? validationKey, - required this.generatedMnemonic, - }) : super(key: validationKey); - - String? generatedMnemonic; - TextEditingController tplController = TextEditingController(); - TextEditingController wordController = TextEditingController(); - final TextEditingController _mnemonicController = TextEditingController(); - - final int progress = 7; +class OnboardingStepEight extends StatelessWidget { + const OnboardingStepEight({Key? key}) : super(key: key); @override Widget build(BuildContext context) { SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); - GenerateWalletsProvider _generateWalletProvider = - Provider.of(context); CommonElements common = CommonElements(); - _mnemonicController.text = generatedMnemonic!; - - return WillPopScope( - onWillPop: () { - _generateWalletProvider.isAskedWordValid = false; - _generateWalletProvider.askedWordColor = Colors.black; - return Future.value(true); - }, - child: Scaffold( - resizeToAvoidBottomInset: false, - extendBodyBehindAppBar: true, - body: SafeArea( - child: Column(children: [ - common.onboardingProgressBar( - context, '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 ", - style: TextStyle(fontSize: 16 * ratio)), - TextSpan( - text: '${_generateWalletProvider.nbrWord + 1}ème mot', - style: TextStyle( - fontWeight: FontWeight.bold, fontSize: 16 * ratio)), - TextSpan( - text: " de votre phrase de restauration :", - style: TextStyle(fontSize: 16 * ratio)), - ], - textKey: const Key('step8'), - ), - SizedBox(height: isTall ? 70 : 10), - Text('${_generateWalletProvider.nbrWord + 1}', - key: const Key('askedWord'), - style: TextStyle( - fontSize: isTall ? 17 : 10, - color: orangeC, - fontWeight: FontWeight.w400)), - SizedBox(height: isTall ? 10 : 0), - Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(7), - border: Border.all( - color: Colors.grey[600]!, - width: 3, - )), - width: 430, - child: TextFormField( - key: const Key('inputWord'), - autofocus: true, - enabled: !_generateWalletProvider.isAskedWordValid, - controller: 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: const 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( - key: const Key('goStep9'), - style: ElevatedButton.styleFrom( - elevation: 5, - primary: orangeC, - onPrimary: Colors.white, // foreground - ), - onPressed: () { - Navigator.push( - context, - FaderTransition( - page: OnboardingStepEleven(), - isFast: true), - ); - }, - child: const Text("Continuer", - style: TextStyle(fontSize: 20))), - )))), - const SizedBox(height: 80), - ]), - ))); + return Scaffold( + appBar: AppBar( + toolbarHeight: 60 * ratio, + title: const SizedBox( + height: 22, + child: Text( + 'Mon code secret', + style: TextStyle(fontWeight: FontWeight.w600), + ), + ), + ), + extendBodyBehindAppBar: true, + body: SafeArea( + child: common.infoIntro( + context, + [ + const TextSpan( + text: + 'Ce code secret protège vos portefeuilles dans un coffre-fort '), + const TextSpan( + text: 'dont vous seul possédez le code', + style: TextStyle(fontWeight: FontWeight.bold)), + const TextSpan( + text: + ', de sorte que vos portefeuilles seront inutilisables par d’autres.'), + ], + 'coffre-fort-protege-les-portefeuilles.png', + '>', + const OnboardingStepThirteen(), + 7), + ), + ); } } diff --git a/lib/screens/onBoarding/9.dart b/lib/screens/onBoarding/9.dart index bf0d938..61dc4f6 100644 --- a/lib/screens/onBoarding/9.dart +++ b/lib/screens/onBoarding/9.dart @@ -1,71 +1,109 @@ // ignore_for_file: file_names - +import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:flutter/material.dart'; import 'package:gecko/globals.dart'; +import 'package:gecko/providers/generate_wallets.dart'; import 'package:gecko/screens/common_elements.dart'; import 'package:gecko/screens/onBoarding/10.dart'; +import 'package:provider/provider.dart'; // ignore: must_be_immutable -class OnboardingStepEleven extends StatelessWidget { - TextEditingController tplController = TextEditingController(); - final int progress = 8; - - OnboardingStepEleven({Key? key}) : super(key: key); +class OnboardingStepThirteen extends StatelessWidget { + const OnboardingStepThirteen({Key? key}) : super(key: key); @override Widget build(BuildContext context) { SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); + GenerateWalletsProvider _generateWalletProvider = + Provider.of(context); + // MyWalletsProvider myWalletProvider = + // Provider.of(context); CommonElements common = CommonElements(); + _generateWalletProvider.pin.text = kDebugMode && debugPin + ? 'AAAAA' + : _generateWalletProvider.changePinCode(reload: false); + return Scaffold( + appBar: AppBar( + toolbarHeight: 60 * ratio, + title: const SizedBox( + height: 22, + child: Text( + 'Mon code secret', + style: TextStyle(fontWeight: FontWeight.w600), + ), + ), + ), extendBodyBehindAppBar: true, body: SafeArea( child: Column(children: [ - common.onboardingProgressBar( - context, 'Ma phrase de restauration', progress), - common.bubbleSpeakRich( + SizedBox(height: isTall ? 40 : 20), + common.buildProgressBar(8), + SizedBox(height: isTall ? 40 : 20), + common.buildText( [ const TextSpan( - text: "Super !\n\nJe vais maintenant créer votre "), + text: + "Et voilà votre code secret !\n\nMémorisez-le ou notez-le, car il vous sera demandé "), const TextSpan( - text: 'code secret.', + text: 'à chaque fois', style: TextStyle(fontWeight: FontWeight.bold)), const 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."), + " que vous voudrez effectuer un paiement sur cet appareil."), ], - textKey: const Key('step9'), ), - SizedBox(height: isTall ? 50 : 10), - Image.asset( - 'assets/onBoarding/treasure-chest-gecko-souligne.png', - height: 280 * ratio, //5": 400 + const SizedBox(height: 100), + Stack( + alignment: Alignment.centerRight, + children: [ + TextField( + key: const Key('generatedPin'), + enabled: false, + controller: _generateWalletProvider.pin, + maxLines: 1, + textAlign: TextAlign.center, + decoration: const InputDecoration(), + style: const TextStyle( + letterSpacing: 5, + fontSize: 35.0, + color: Colors.black, + fontWeight: FontWeight.bold)), + IconButton( + icon: const Icon(Icons.replay), + color: orangeC, + onPressed: () { + _generateWalletProvider.changePinCode(reload: true); + }, + ), + ], ), Expanded( child: Align( alignment: Alignment.bottomCenter, child: SizedBox( - width: 400, - height: 62, + width: 410, + height: 70, child: ElevatedButton( - key: const Key('goStep10'), + key: const Key('changeSecretCode'), style: ElevatedButton.styleFrom( - elevation: 5, - primary: orangeC, - onPrimary: Colors.white, // foreground + elevation: 4, + primary: const Color(0xffFFD58D), + onPrimary: Colors.black, // foreground ), onPressed: () { - Navigator.push( - context, - FaderTransition( - page: OnboardingStepTwelve(), isFast: true), - ); + _generateWalletProvider.changePinCode(reload: true); }, - child: const Text("J'ai compris", - style: TextStyle(fontSize: 20))), + child: const Text("Choisir un autre code secret", + style: TextStyle( + fontSize: 24, fontWeight: FontWeight.w600))), ))), - const SizedBox(height: 80), + const SizedBox(height: 25), + common.nextButton(context, "J'ai noté mon code secret", + OnboardingStepFourteen(), false), + const SizedBox(height: 40), ]), )); } diff --git a/lib/screens/search_result.dart b/lib/screens/search_result.dart index 347aace..d619d70 100644 --- a/lib/screens/search_result.dart +++ b/lib/screens/search_result.dart @@ -3,6 +3,7 @@ import 'package:gecko/globals.dart'; import 'package:flutter/material.dart'; import 'package:gecko/providers/cesium_plus.dart'; import 'package:gecko/models/g1_wallets_list.dart'; +import 'package:gecko/providers/wallet_options.dart'; import 'package:gecko/providers/wallets_profiles.dart'; import 'package:gecko/providers/search.dart'; import 'package:gecko/screens/wallet_view.dart'; @@ -57,9 +58,9 @@ class SearchResultScreen extends StatelessWidget { ), ), const SizedBox(height: 40), - const Text( - 'Dans la blockchain Ğ1', - style: TextStyle(fontSize: 20), + Text( + 'Dans la blockchain $currencyName', + style: const TextStyle(fontSize: 20), ), const SizedBox(height: 20), FutureBuilder( @@ -107,9 +108,11 @@ class SearchResultScreen extends StatelessWidget { ]); } if (_avatar.hasData) { - g1WalletsBox - .get(g1Wallet.pubkey)! - .avatar = _avatar.data; + final _w = + g1WalletsBox.get(g1Wallet.pubkey); + if (_w != null) { + _w.avatar = _avatar.data; + } return ClipOval(child: _avatar.data); } else { g1WalletsBox @@ -131,6 +134,11 @@ class SearchResultScreen extends StatelessWidget { fontWeight: FontWeight.w500), textAlign: TextAlign.center), ]), + trailing: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + balance(context, g1Wallet.pubkey!, 16) + ]), subtitle: Row(children: [ Text(g1Wallet.id?.username ?? '', style: const TextStyle( diff --git a/lib/screens/settings.dart b/lib/screens/settings.dart index f9cdce1..4f4c60a 100644 --- a/lib/screens/settings.dart +++ b/lib/screens/settings.dart @@ -2,11 +2,13 @@ import 'package:flutter/material.dart'; import 'package:durt/durt.dart'; import 'package:flutter/services.dart'; import 'package:gecko/providers/my_wallets.dart'; +import 'package:gecko/providers/substrate_sdk.dart'; import 'package:gecko/screens/myWallets/generate_wallets.dart'; import 'dart:io'; -import 'package:gecko/screens/myWallets/import_cesium_wallet.dart'; +// import 'package:gecko/screens/myWallets/import_cesium_wallet.dart'; import 'package:gecko/globals.dart'; import 'package:gecko/screens/myWallets/restore_chest.dart'; +import 'package:provider/provider.dart'; // ignore: must_be_immutable class SettingsScreen extends StatelessWidget { @@ -29,105 +31,121 @@ class SettingsScreen extends StatelessWidget { Widget build(BuildContext context) { SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); + const double buttonHigh = 50; + const double buttonWidth = 240; + const double fontSize = 16; + TextEditingController _endpointController = + TextEditingController(text: configBox.get('endpoint')); + // getAppDirectory(); return Scaffold( - appBar: AppBar( - toolbarHeight: 60 * ratio, - title: const SizedBox( - height: 22, - child: Text('Paramètres'), - )), - body: Column(children: [ - const SizedBox(height: 40), - SizedBox( - height: 70, - width: 500, - child: ElevatedButton( - style: ElevatedButton.styleFrom( - elevation: 5, - primary: yellowC, // background - onPrimary: Colors.black, // foreground + appBar: AppBar( + toolbarHeight: 60 * ratio, + title: const SizedBox( + height: 22, + child: Text('Paramètres'), + )), + body: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 60), + Row(children: [ + Text(' Noeud $currencyName :'), + const SizedBox(width: 20), + SizedBox( + width: 200, + height: 50, + child: TextField( + controller: _endpointController, + autocorrect: false, + ), ), - onPressed: () => Navigator.push( - context, - MaterialPageRoute(builder: (context) { - return const ImportWalletScreen(); - }), - ).then((value) => { - if (value == true) {Navigator.pop(context)} + const Spacer(), + Consumer(builder: (context, _sub, _) { + return _sub.isLoadingEndpoint + ? CircularProgressIndicator(color: orangeC) + : IconButton( + icon: Icon( + Icons.send, + color: orangeC, + size: 40, + ), + onPressed: () async { + configBox.put('endpoint', _endpointController.text); + await _sub.connectNode(context); + }); + }), + const Spacer(), + ]), + SizedBox(height: isTall ? 50 : 20), + SizedBox( + height: buttonHigh, + width: buttonWidth, + child: ElevatedButton( + key: const Key('generateKeychain'), + style: ElevatedButton.styleFrom( + elevation: 5, + primary: yellowC, // background + onPrimary: Colors.black, // foreground + ), + onPressed: () => Navigator.push( + context, + MaterialPageRoute(builder: (context) { + return GenerateFastChestScreen(); }), - child: const Text( - "Importer un portefeuille Cesium", - style: TextStyle(fontSize: 16), + ), + child: const Text( + "Générer un coffre", + style: TextStyle(fontSize: fontSize), + ), ), ), - ), - const SizedBox(height: 30), - SizedBox( - height: 70, - width: 500, - child: ElevatedButton( - key: const Key('generateKeychain'), - style: ElevatedButton.styleFrom( - elevation: 5, - primary: yellowC, // background - onPrimary: Colors.black, // foreground - ), - onPressed: () => Navigator.push( - context, - MaterialPageRoute(builder: (context) { - return GenerateFastChestScreen(); - }), - ), - child: const Text( - "Générer un nouveau trousseau", - style: TextStyle(fontSize: 16), + const SizedBox(height: 20), + SizedBox( + height: buttonHigh, + width: buttonWidth, + child: ElevatedButton( + key: const Key('generateKeychain'), + style: ElevatedButton.styleFrom( + elevation: 5, + primary: yellowC, // background + onPrimary: Colors.black, // foreground + ), + onPressed: () => Navigator.push( + context, + MaterialPageRoute(builder: (context) { + return const RestoreChest(); + }), + ), + child: const Text( + "Restaurer un coffre", + style: TextStyle(fontSize: fontSize), + ), ), ), - ), - const SizedBox(height: 30), - SizedBox( - height: 70, - width: 500, - child: ElevatedButton( - key: const Key('generateKeychain'), - style: ElevatedButton.styleFrom( - elevation: 5, - primary: yellowC, // background - onPrimary: Colors.black, // foreground - ), - onPressed: () => Navigator.push( - context, - MaterialPageRoute(builder: (context) { - return const RestoreChest(); - }), - ), - child: const Text( - "Restaurer un coffre", - style: TextStyle(fontSize: 16), + const SizedBox(height: 25), + SizedBox( + height: buttonHigh, + width: buttonWidth, + child: Center( + child: InkWell( + key: const Key('deleteChest'), + onTap: () async { + log.i('Oublier tous mes coffres'); + await _myWallets.deleteAllWallet(context); + }, + child: const Text( + 'Oublier tous mes coffres', + style: TextStyle( + fontSize: fontSize + 3, + color: Color(0xffD80000), + fontWeight: FontWeight.w500, + ), + ), + ), ), ), - ), - Expanded( - child: Align( - alignment: Alignment.bottomCenter, - child: SizedBox( - height: 100, - width: 500, - child: ElevatedButton( - key: const Key('deleteAllWallets'), - style: ElevatedButton.styleFrom( - elevation: 5, - primary: Colors.redAccent, // background - onPrimary: Colors.black, // foreground - ), - onPressed: () async => { - log.i('Suppression de tous les wallets'), - await _myWallets.deleteAllWallet(context) - }, - child: const Text("EFFACER TOUS MES PORTEFEUILLES", - style: TextStyle(fontSize: 20)))))), - const SizedBox(height: 50), - ])); + ]), + ); } } diff --git a/lib/screens/substrate_sandbox.dart b/lib/screens/substrate_sandbox.dart new file mode 100644 index 0000000..08136f0 --- /dev/null +++ b/lib/screens/substrate_sandbox.dart @@ -0,0 +1,172 @@ +import 'package:flutter/material.dart'; +import 'package:gecko/globals.dart'; +import 'package:gecko/models/stateful_wrapper.dart'; +import 'package:gecko/providers/substrate_sdk.dart'; +import 'package:provider/provider.dart'; + +class SubstrateSandBox extends StatelessWidget { + const SubstrateSandBox({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + // SubstrateSdk _sub = Provider.of(context, listen: false); + + return StatefulWrapper( + onInit: () async { + // if (!_sub.sdkReady && !_sub.sdkLoading) await _sub.initApi(); + // if (_sub.sdkReady && !_sub.nodeConnected) await _sub.connectNode(); + }, + child: Scaffold( + appBar: AppBar( + toolbarHeight: 60 * ratio, + title: const SizedBox( + height: 22, + child: Text('Substrate Sandbox'), + ), + ), + body: SafeArea( + child: Consumer(builder: (context, _sub, _) { + return SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('js-api chargé ?: ${_sub.sdkReady}'), + InkWell( + onTap: () async { + await _sub.connectNode(context); + }, + child: Text( + 'Noeud connecté ?: ${_sub.nodeConnected} (${configBox.get('endpoint')})')), + if (_sub.nodeConnected) + Text('Noeud "$currencyName", bloc N°${_sub.blocNumber}'), + const SizedBox(height: 20), + Row(children: [ + const Text('Liste des coffres:'), + const Spacer(), + InkWell( + child: Image.asset( + 'assets/walletOptions/trash.png', + height: 35, + ), + onTap: () async { + await _sub.deleteAllAccounts(); + _sub.reload(); + }, + ), + const SizedBox(width: 10), + ]), + FutureBuilder( + future: _sub.getKeyStoreAddress(), + builder: (BuildContext context, + AsyncSnapshot> _data) { + return Column(children: [ + if (_data.data != null) + for (final AddressInfo addressInfo in _data.data!) + Row(children: [ + InkWell( + onTap: () => _sub.keyring.setCurrent(_sub + .keyring.keyPairs + .firstWhere((element) => + element.address == + addressInfo.address!)), + child: Text( + getShortPubkey(addressInfo.address!), + style: const TextStyle( + fontFamily: 'Monospace'), + ), + ), + const SizedBox(width: 20), + // InkWell( + // onTap: () async => await _sub.pay( + // context, + // addressInfo.address!, + // 10, + // _sub.keystorePassword.text), + // child: + Text( + "${addressInfo.balance.toString()} $currencyName"), + // ), + const SizedBox(width: 20), + InkWell( + onTap: () async => await _sub.derive( + context, + addressInfo.address!, + 2, + _sub.keystorePassword.text), + child: const Text("Dériver"), + ) + ]) + ]); + }), + const SizedBox(height: 20), + const Text('Mot de passe du coffre:'), + TextField( + controller: _sub.keystorePassword, + obscureText: true, + obscuringCharacter: '•', + enableSuggestions: false, + autocorrect: false, + onChanged: (_) => _sub.reload(), + ), + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const SizedBox(height: 20, width: double.infinity), + ElevatedButton( + style: ElevatedButton.styleFrom( + primary: yellowC, // background + onPrimary: Colors.black, // foreground + ), + onPressed: _sub.keystorePassword.text.isNotEmpty + ? () async { + final res = await _sub.importAccount(); + _sub.importIsLoading = false; + _sub.reload(); + snack( + context, + res != '' + ? 'Portefeuille importé' + : 'Le format de coffre est invalide'); + } + : null, + child: const Text( + 'Importer depuis le presse-papier', + style: TextStyle(fontSize: 20), + ), + ), + if (_sub.importIsLoading) + const CircularProgressIndicator(), + const SizedBox(height: 20), + ElevatedButton( + style: ElevatedButton.styleFrom( + primary: yellowC, // background + onPrimary: Colors.black, // foreground + ), + onPressed: () async { + await _sub.generateMnemonic(); + _sub.importIsLoading = false; + _sub.reload(); + snack(context, 'Le mnemonic a été copié'); + }, + child: const Text( + "Générer un mnemonic et le copier", + style: TextStyle(fontSize: 20), + ), + ), + const SizedBox(height: 10), + SizedBox( + width: 400, + child: Text( + _sub.generatedMnemonic, + textAlign: TextAlign.center, + ), + ) + ]) + ]), + ); + }), + ), + ), + ); + } +} diff --git a/lib/screens/wallet_view.dart b/lib/screens/wallet_view.dart index 7444fbf..12aa878 100644 --- a/lib/screens/wallet_view.dart +++ b/lib/screens/wallet_view.dart @@ -2,15 +2,12 @@ import 'package:flutter/services.dart'; import 'package:gecko/globals.dart'; import 'package:flutter/material.dart'; import 'package:gecko/providers/cesium_plus.dart'; +import 'package:gecko/providers/wallet_options.dart'; import 'package:gecko/providers/my_wallets.dart'; import 'package:gecko/models/wallet_data.dart'; import 'package:gecko/providers/wallets_profiles.dart'; -import 'package:gecko/models/queries.dart'; import 'package:gecko/screens/avatar_fullscreen.dart'; -import 'package:gecko/screens/common_elements.dart'; -import 'package:gecko/screens/history.dart'; import 'package:gecko/screens/myWallets/unlocking_wallet.dart'; -import 'package:graphql_flutter/graphql_flutter.dart'; import 'package:provider/provider.dart'; class WalletViewScreen extends StatelessWidget { @@ -53,7 +50,8 @@ class WalletViewScreen extends StatelessWidget { height: buttonSize, child: ClipOval( child: Material( - color: const Color(0xffFFD58D), // button color + color: Colors + .grey[300], //const Color(0xffFFD58D), // button color child: InkWell( key: const Key('viewHistory'), splashColor: orangeC, // inkwell color @@ -64,19 +62,20 @@ class WalletViewScreen extends StatelessWidget { 'assets/walletOptions/clock.png'), height: 90)), onTap: () { - _historyProvider.nPage = 1; - Navigator.push( - context, - FaderTransition( - page: HistoryScreen( - pubkey: pubkey, - username: username ?? - g1WalletsBox.get(pubkey)?.username, - avatar: avatar ?? - g1WalletsBox.get(pubkey)?.avatar, - ), - isFast: false), - ); + ////TODO: wait for subsquid indexer + // _historyProvider.nPage = 1; + // Navigator.push( + // context, + // FaderTransition( + // page: HistoryScreen( + // pubkey: pubkey, + // username: username ?? + // g1WalletsBox.get(pubkey)?.username, + // avatar: avatar ?? + // g1WalletsBox.get(pubkey)?.avatar, + // ), + // isFast: false), + // ); }), ), ), @@ -105,7 +104,7 @@ class WalletViewScreen extends StatelessWidget { height: 90)), onTap: () { Clipboard.setData(ClipboardData(text: pubkey)); - _historyProvider.snackCopyKey(context); + snackCopyKey(context); }), ), ), @@ -191,6 +190,7 @@ class WalletViewScreen extends StatelessWidget { Provider.of(context, listen: false); WalletData? defaultWallet = _myWalletProvider.getDefaultWallet(configBox.get('currentChest')); + _walletViewProvider.outputPubkey.text = pubkey!; showModalBottomSheet( shape: const RoundedRectangleBorder( @@ -254,7 +254,7 @@ class WalletViewScreen extends StatelessWidget { // onChanged: (v) => _searchProvider.rebuildWidget(), decoration: InputDecoration( hintText: '0.00', - suffix: const Text('Ğ1'), + suffix: Text(currencyName), filled: true, fillColor: Colors.transparent, // border: OutlineInputBorder( @@ -285,21 +285,21 @@ class WalletViewScreen extends StatelessWidget { primary: orangeC, // background onPrimary: Colors.white, // foreground ), - onPressed: - _walletViewProvider.payAmount.text != '' - ? () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) { - return UnlockingWallet( - wallet: defaultWallet, - action: "pay"); - }, - ), - ); - } - : null, + onPressed: _walletViewProvider.payAmount.text != + '' + ? () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return UnlockingWallet( + wallet: defaultWallet, + action: "pay"); + }, + ), + ); + } + : null, child: const Text( 'Effectuer le virement', style: TextStyle( @@ -351,7 +351,7 @@ class WalletViewScreen extends StatelessWidget { key: const Key('copyPubkey'), onTap: () { Clipboard.setData(ClipboardData(text: pubkey)); - _historyProvider.snackCopyKey(context); + snackCopyKey(context); }, child: Text( _historyProvider.getShortPubkey(pubkey!), @@ -362,40 +362,45 @@ class WalletViewScreen extends StatelessWidget { ), ), ]), - const SizedBox(height: 10), - if (username == null && - g1WalletsBox.get(pubkey)?.username == null) - Query( - options: QueryOptions( - document: gql(getId), - variables: { - 'pubkey': pubkey, - }, - ), - builder: (QueryResult result, - {VoidCallback? refetch, FetchMore? fetchMore}) { - if (result.isLoading || result.hasException) { - return const Text('...'); - } else if (result.data!['idty'] == null || - result.data!['idty']['username'] == null) { - g1WalletsBox.get(pubkey)?.username = ''; - return const Text(''); - } else { - g1WalletsBox.get(pubkey)?.username = - result.data!['idty']['username'] ?? ''; - return SizedBox( - width: 230, - child: Text( - result.data!['idty']['username'] ?? '', - style: const TextStyle( - fontSize: 27, - color: Color(0xff814C00), - ), - ), - ); - } - }, - ), + const SizedBox(height: 25), + Consumer( + builder: (context, walletProvider, _) { + return balance(context, pubkey!, 20); + }), + //// + // if (username == null && + // g1WalletsBox.get(pubkey)?.username == null) + // Query( + // options: QueryOptions( + // document: gql(getId), + // variables: { + // 'pubkey': pubkey, + // }, + // ), + // builder: (QueryResult result, + // {VoidCallback? refetch, FetchMore? fetchMore}) { + // if (result.isLoading || result.hasException) { + // return const Text('...'); + // } else if (result.data!['idty'] == null || + // result.data!['idty']['username'] == null) { + // g1WalletsBox.get(pubkey)?.username = ''; + // return const Text(''); + // } else { + // g1WalletsBox.get(pubkey)?.username = + // result.data!['idty']['username'] ?? ''; + // return SizedBox( + // width: 230, + // child: Text( + // result.data!['idty']['username'] ?? '', + // style: const TextStyle( + // fontSize: 27, + // color: Color(0xff814C00), + // ), + // ), + // ); + // } + // }, + // ), if (username == null && g1WalletsBox.get(pubkey)?.username != null) SizedBox( @@ -420,19 +425,20 @@ class WalletViewScreen extends StatelessWidget { ), ), const SizedBox(height: 25), - FutureBuilder( - future: _cesiumPlusProvider.getName(pubkey), - initialData: '...', - builder: (context, snapshot) { - return SizedBox( - width: 230, - child: Text( - snapshot.data.toString(), - style: const TextStyle( - fontSize: 18, color: Colors.black), - ), - ); - }), + //// To get Cs+ name + // FutureBuilder( + // future: _cesiumPlusProvider.getName(pubkey), + // initialData: '...', + // builder: (context, snapshot) { + // return SizedBox( + // width: 230, + // child: Text( + // snapshot.data.toString(), + // style: const TextStyle( + // fontSize: 18, color: Colors.black), + // ), + // ); + // }), const SizedBox(height: 30), ]), const Spacer(), diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index fc41ebe..77eb7b8 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -6,19 +6,21 @@ import FlutterMacOS import Foundation import connectivity_plus_macos -import package_info +import desktop_window import package_info_plus_macos import path_provider_macos import printing import sentry_flutter import shared_preferences_macos +import window_size func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { ConnectivityPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlugin")) - FLTPackageInfoPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlugin")) + DesktopWindowPlugin.register(with: registry.registrar(forPlugin: "DesktopWindowPlugin")) FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) PrintingPlugin.register(with: registry.registrar(forPlugin: "PrintingPlugin")) SentryFlutterPlugin.register(with: registry.registrar(forPlugin: "SentryFlutterPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) + WindowSizePlugin.register(with: registry.registrar(forPlugin: "WindowSizePlugin")) } diff --git a/macos/Runner/Configs/AppInfo.xcconfig b/macos/Runner/Configs/AppInfo.xcconfig index b374696..a788d2c 100644 --- a/macos/Runner/Configs/AppInfo.xcconfig +++ b/macos/Runner/Configs/AppInfo.xcconfig @@ -8,7 +8,7 @@ PRODUCT_NAME = gecko // The application's bundle identifier -PRODUCT_BUNDLE_IDENTIFIER = com.example.gecko +PRODUCT_BUNDLE_IDENTIFIER = gecko.axiomteam.fr // The copyright displayed in application information -PRODUCT_COPYRIGHT = Copyright © 2021 com.example. All rights reserved. +PRODUCT_COPYRIGHT = Copyright © 2021 gecko.axiomteam.fr. All rights reserved. diff --git a/pubspec.lock b/pubspec.lock index 5d802de..20798a7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,35 +7,35 @@ packages: name: _fe_analyzer_shared url: "https://pub.dartlang.org" source: hosted - version: "30.0.0" + version: "40.0.0" analyzer: dependency: transitive description: name: analyzer url: "https://pub.dartlang.org" source: hosted - version: "2.7.0" + version: "4.1.0" archive: dependency: transitive description: name: archive url: "https://pub.dartlang.org" source: hosted - version: "3.1.6" + version: "3.1.11" args: dependency: transitive description: name: args url: "https://pub.dartlang.org" source: hosted - version: "2.3.0" + version: "2.3.1" assorted_layout_widgets: dependency: "direct main" description: name: assorted_layout_widgets url: "https://pub.dartlang.org" source: hosted - version: "5.2.1" + version: "5.8.5" async: dependency: transitive description: @@ -43,13 +43,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.8.2" + auth_header: + dependency: transitive + description: + name: auth_header + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" barcode: dependency: transitive description: name: barcode url: "https://pub.dartlang.org" source: hosted - version: "2.2.0" + version: "2.2.1" bip32_ed25519: dependency: transitive description: @@ -84,7 +91,7 @@ packages: name: build url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" + version: "2.3.0" build_config: dependency: transitive description: @@ -98,28 +105,28 @@ packages: name: build_daemon url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.1.0" build_resolvers: dependency: transitive description: name: build_resolvers url: "https://pub.dartlang.org" source: hosted - version: "2.0.4" + version: "2.0.8" build_runner: dependency: "direct dev" description: name: build_runner url: "https://pub.dartlang.org" source: hosted - version: "2.1.4" + version: "2.1.11" build_runner_core: dependency: transitive description: name: build_runner_core url: "https://pub.dartlang.org" source: hosted - version: "7.2.2" + version: "7.2.3" built_collection: dependency: transitive description: @@ -133,14 +140,14 @@ packages: name: built_value url: "https://pub.dartlang.org" source: hosted - version: "8.1.3" + version: "8.3.0" carousel_slider: dependency: "direct main" description: name: carousel_slider url: "https://pub.dartlang.org" source: hosted - version: "4.0.0" + version: "4.1.1" characters: dependency: transitive description: @@ -162,13 +169,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.1" - cli_util: - dependency: transitive - description: - name: cli_util - url: "https://pub.dartlang.org" - source: hosted - version: "0.3.5" clock: dependency: transitive description: @@ -189,49 +189,49 @@ packages: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.15.0" + version: "1.16.0" confirm_dialog: dependency: "direct main" description: name: confirm_dialog url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.1" connectivity_plus: dependency: transitive description: name: connectivity_plus url: "https://pub.dartlang.org" source: hosted - version: "1.4.0" + version: "2.3.0" connectivity_plus_linux: dependency: transitive description: name: connectivity_plus_linux url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.3.0" connectivity_plus_macos: dependency: transitive description: name: connectivity_plus_macos url: "https://pub.dartlang.org" source: hosted - version: "1.2.1" + version: "1.2.2" connectivity_plus_platform_interface: dependency: transitive description: name: connectivity_plus_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.2.0" connectivity_plus_web: dependency: transitive description: name: connectivity_plus_web url: "https://pub.dartlang.org" source: hosted - version: "1.1.0+1" + version: "1.2.0" connectivity_plus_windows: dependency: transitive description: @@ -252,14 +252,14 @@ packages: name: coverage url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "1.2.0" cross_file: dependency: transitive description: name: cross_file url: "https://pub.dartlang.org" source: hosted - version: "0.3.2" + version: "0.3.3" crypto: dependency: "direct main" description: @@ -273,14 +273,14 @@ packages: name: dart_style url: "https://pub.dartlang.org" source: hosted - version: "2.2.0" + version: "2.2.3" dbus: dependency: transitive description: name: dbus url: "https://pub.dartlang.org" source: hosted - version: "0.5.6" + version: "0.7.3" desktop_window: dependency: "direct main" description: @@ -294,7 +294,14 @@ packages: name: dio url: "https://pub.dartlang.org" source: hosted - version: "4.0.4" + version: "4.0.6" + dots_indicator: + dependency: "direct main" + description: + name: dots_indicator + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" durt: dependency: "direct main" description: @@ -308,7 +315,7 @@ packages: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.3.0" fast_base58: dependency: "direct main" description: @@ -322,7 +329,7 @@ packages: name: ffi url: "https://pub.dartlang.org" source: hosted - version: "1.1.2" + version: "1.2.1" file: dependency: transitive description: @@ -336,24 +343,38 @@ packages: name: fixnum url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.1" flutter: dependency: "direct main" description: flutter source: sdk version: "0.0.0" + flutter_aes_ecb_pkcs5: + dependency: transitive + description: + name: flutter_aes_ecb_pkcs5 + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.2" flutter_driver: dependency: "direct main" description: flutter source: sdk version: "0.0.0" - flutter_launcher_icons: - dependency: "direct main" + flutter_hooks: + dependency: transitive description: - name: flutter_launcher_icons + name: flutter_hooks url: "https://pub.dartlang.org" source: hosted - version: "0.9.2" + version: "0.18.4" + flutter_inappwebview: + dependency: transitive + description: + name: flutter_inappwebview + url: "https://pub.dartlang.org" + source: hosted + version: "5.4.3+7" flutter_lints: dependency: "direct main" description: @@ -367,14 +388,14 @@ packages: name: flutter_logs url: "https://pub.dartlang.org" source: hosted - version: "2.1.4" + version: "2.1.6" flutter_plugin_android_lifecycle: dependency: transitive description: name: flutter_plugin_android_lifecycle url: "https://pub.dartlang.org" source: hosted - version: "2.0.4" + version: "2.0.6" flutter_svg: dependency: "direct main" description: @@ -398,12 +419,26 @@ packages: name: frontend_server_client url: "https://pub.dartlang.org" source: hosted - version: "2.1.2" + version: "2.1.3" fuchsia_remote_debug_protocol: dependency: transitive description: flutter source: sdk version: "0.0.0" + get: + dependency: transitive + description: + name: get + url: "https://pub.dartlang.org" + source: hosted + version: "4.6.3" + get_storage: + dependency: transitive + description: + name: get_storage + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.3" glob: dependency: transitive description: @@ -417,63 +452,65 @@ packages: name: gql url: "https://pub.dartlang.org" source: hosted - version: "0.13.0" + version: "0.13.1" gql_dedupe_link: dependency: transitive description: name: gql_dedupe_link url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.0.2" gql_error_link: dependency: transitive description: name: gql_error_link url: "https://pub.dartlang.org" source: hosted - version: "0.2.0" + version: "0.2.2" gql_exec: dependency: transitive description: name: gql_exec url: "https://pub.dartlang.org" source: hosted - version: "0.3.0" + version: "0.4.0" gql_http_link: dependency: transitive description: name: gql_http_link url: "https://pub.dartlang.org" source: hosted - version: "0.4.0" + version: "0.4.2" gql_link: dependency: transitive description: name: gql_link url: "https://pub.dartlang.org" source: hosted - version: "0.4.0" + version: "0.4.2" gql_transform_link: dependency: transitive description: name: gql_transform_link url: "https://pub.dartlang.org" source: hosted - version: "0.2.0" + version: "0.2.2" graphql: dependency: transitive description: name: graphql url: "https://pub.dartlang.org" source: hosted - version: "5.0.0" + version: "5.1.1" graphql_flutter: dependency: "direct main" description: - name: graphql_flutter - url: "https://pub.dartlang.org" - source: hosted - version: "5.0.0" + path: "packages/graphql_flutter" + ref: f1ccb2d + resolved-ref: f1ccb2d775826697fa0ab4f6d27d132f8a28f444 + url: "https://github.com/Quantit-Github/graphql-flutter.git" + source: git + version: "5.1.0" graphs: dependency: transitive description: @@ -494,7 +531,7 @@ packages: name: hive url: "https://pub.dartlang.org" source: hosted - version: "2.0.4" + version: "2.2.1" hive_flutter: dependency: "direct main" description: @@ -508,7 +545,7 @@ packages: name: hive_generator url: "https://pub.dartlang.org" source: hosted - version: "1.1.1" + version: "1.1.3" http: dependency: "direct main" description: @@ -522,21 +559,35 @@ packages: name: http_multi_server url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.2.0" http_parser: dependency: transitive description: name: http_parser url: "https://pub.dartlang.org" source: hosted - version: "4.0.0" + version: "4.0.1" + http_server: + dependency: transitive + description: + name: http_server + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + icons_launcher: + dependency: "direct dev" + description: + name: icons_launcher + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.8" image: dependency: transitive description: name: image url: "https://pub.dartlang.org" source: hosted - version: "3.0.8" + version: "3.1.3" image_gallery_saver: dependency: "direct main" description: @@ -550,21 +601,35 @@ packages: name: image_picker url: "https://pub.dartlang.org" source: hosted - version: "0.8.4+4" + version: "0.8.5+3" + image_picker_android: + dependency: transitive + description: + name: image_picker_android + url: "https://pub.dartlang.org" + source: hosted + version: "0.8.4+13" image_picker_for_web: dependency: transitive description: name: image_picker_for_web url: "https://pub.dartlang.org" source: hosted - version: "2.1.4" + version: "2.1.8" + image_picker_ios: + dependency: transitive + description: + name: image_picker_ios + url: "https://pub.dartlang.org" + source: hosted + version: "0.8.5+5" image_picker_platform_interface: dependency: transitive description: name: image_picker_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.4.1" + version: "2.5.0" infinite_scroll_pagination: dependency: "direct main" description: @@ -591,6 +656,27 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.3" + jaguar: + dependency: transitive + description: + name: jaguar + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.3" + jaguar_common: + dependency: transitive + description: + name: jaguar_common + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" + jaguar_flutter_asset: + dependency: transitive + description: + name: jaguar_flutter_asset + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" jdenticon_dart: dependency: "direct main" description: @@ -604,14 +690,14 @@ packages: name: js url: "https://pub.dartlang.org" source: hosted - version: "0.6.3" + version: "0.6.4" json_annotation: dependency: transitive description: name: json_annotation url: "https://pub.dartlang.org" source: hosted - version: "4.3.0" + version: "4.5.0" lints: dependency: transitive description: @@ -646,7 +732,7 @@ packages: name: material_color_utilities url: "https://pub.dartlang.org" source: hosted - version: "0.1.3" + version: "0.1.4" matrix4_transform: dependency: transitive description: @@ -667,7 +753,14 @@ packages: name: mime url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "1.0.2" + mobx: + dependency: transitive + description: + name: mobx + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.7+2" nested: dependency: transitive description: @@ -681,7 +774,7 @@ packages: name: nm url: "https://pub.dartlang.org" source: hosted - version: "0.3.0" + version: "0.5.0" node_preamble: dependency: transitive description: @@ -695,7 +788,7 @@ packages: name: normalize url: "https://pub.dartlang.org" source: hosted - version: "0.5.5" + version: "0.6.0+1" package_config: dependency: transitive description: @@ -709,14 +802,14 @@ packages: name: package_info_plus url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.4.2" package_info_plus_linux: dependency: transitive description: name: package_info_plus_linux url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "1.0.5" package_info_plus_macos: dependency: transitive description: @@ -737,21 +830,21 @@ packages: name: package_info_plus_web url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "1.0.5" package_info_plus_windows: dependency: transitive description: name: package_info_plus_windows url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "1.0.5" path: dependency: transitive description: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.0" + version: "1.8.1" path_drawing: dependency: transitive description: @@ -772,63 +865,63 @@ packages: name: path_provider url: "https://pub.dartlang.org" source: hosted - version: "2.0.9" + version: "2.0.10" path_provider_android: dependency: transitive description: name: path_provider_android url: "https://pub.dartlang.org" source: hosted - version: "2.0.11" + version: "2.0.14" path_provider_ios: dependency: transitive description: name: path_provider_ios url: "https://pub.dartlang.org" source: hosted - version: "2.0.7" + version: "2.0.9" path_provider_linux: dependency: transitive description: name: path_provider_linux url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.1.6" path_provider_macos: dependency: transitive description: name: path_provider_macos url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.0.6" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.0.1" + version: "2.0.4" path_provider_windows: dependency: transitive description: name: path_provider_windows url: "https://pub.dartlang.org" source: hosted - version: "2.0.3" + version: "2.0.6" + path_tree: + dependency: transitive + description: + name: path_tree + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" pdf: dependency: "direct main" description: name: pdf url: "https://pub.dartlang.org" source: hosted - version: "3.7.1" - pedantic: - dependency: transitive - description: - name: pedantic - url: "https://pub.dartlang.org" - source: hosted - version: "1.11.1" + version: "3.8.1" permission_handler: dependency: "direct main" description: @@ -849,21 +942,21 @@ packages: name: petitparser url: "https://pub.dartlang.org" source: hosted - version: "4.4.0" + version: "5.0.0" pin_code_fields: dependency: "direct main" description: name: pin_code_fields url: "https://pub.dartlang.org" source: hosted - version: "7.3.0" + version: "7.4.0" pinenacl: dependency: transitive description: name: pinenacl url: "https://pub.dartlang.org" source: hosted - version: "0.3.3" + version: "0.3.4" platform: dependency: transitive description: @@ -877,14 +970,23 @@ packages: name: plugin_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.1.2" pointycastle: dependency: transitive description: name: pointycastle url: "https://pub.dartlang.org" source: hosted - version: "3.4.0" + version: "3.6.0" + polkawallet_sdk: + dependency: "direct main" + description: + path: "." + ref: fixAndroidActivityVersion + resolved-ref: e33351cde5ea9b55d191772fe3b36f9dbb8277e6 + url: "https://github.com/poka-IT/sdk.git" + source: git + version: "0.4.5" pool: dependency: transitive description: @@ -895,10 +997,12 @@ packages: printing: dependency: "direct main" description: - name: printing - url: "https://pub.dartlang.org" - source: hosted - version: "5.7.2" + path: printing + ref: HEAD + resolved-ref: "95bbc1f33b7cb45f7a4b98088b96bc541fefc495" + url: "https://github.com/DavBfr/dart_pdf.git" + source: git + version: "5.9.1" process: dependency: transitive description: @@ -912,21 +1016,21 @@ packages: name: provider url: "https://pub.dartlang.org" source: hosted - version: "6.0.1" + version: "6.0.2" pub_semver: dependency: transitive description: name: pub_semver url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.1.1" pubspec_parse: dependency: transitive description: name: pubspec_parse url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.2.0" pull_to_refresh: dependency: "direct main" description: @@ -940,14 +1044,14 @@ packages: name: qr url: "https://pub.dartlang.org" source: hosted - version: "3.0.0" + version: "3.0.1" qr_flutter: dependency: "direct main" description: path: "." ref: master resolved-ref: bd3fc334a87e0898bb0092036e74bb99cd7ad4e3 - url: "git://github.com/insinfo/qr.flutter.git" + url: "https://github.com/insinfo/qr.flutter.git" source: git version: "4.0.0" qrscan: @@ -956,7 +1060,7 @@ packages: path: "." ref: master resolved-ref: "1fb6b45541965190d16ac214fa6d8b632d1f711e" - url: "git://github.com/leyan95/qrcode_scanner.git" + url: "https://github.com/leyan95/qrcode_scanner.git" source: git version: "0.3.3" responsive_builder: @@ -965,56 +1069,70 @@ packages: name: responsive_builder url: "https://pub.dartlang.org" source: hosted - version: "0.4.1" + version: "0.4.2" responsive_framework: dependency: "direct main" description: name: responsive_framework url: "https://pub.dartlang.org" source: hosted - version: "0.1.5" + version: "0.1.9" rxdart: dependency: transitive description: name: rxdart url: "https://pub.dartlang.org" source: hosted - version: "0.26.0" + version: "0.27.3" sentry: dependency: "direct main" description: name: sentry url: "https://pub.dartlang.org" source: hosted - version: "6.1.0" + version: "6.5.1" sentry_flutter: dependency: "direct main" description: name: sentry_flutter url: "https://pub.dartlang.org" source: hosted - version: "6.1.0" + version: "6.5.1" shared_preferences: dependency: "direct main" description: name: shared_preferences url: "https://pub.dartlang.org" source: hosted - version: "2.0.8" + version: "2.0.15" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.12" + shared_preferences_ios: + dependency: transitive + description: + name: shared_preferences_ios + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.1" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.1.1" shared_preferences_macos: dependency: transitive description: name: shared_preferences_macos url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.0.4" shared_preferences_platform_interface: dependency: transitive description: @@ -1028,21 +1146,21 @@ packages: name: shared_preferences_web url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.0.4" shared_preferences_windows: dependency: transitive description: name: shared_preferences_windows url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.1.1" shelf: dependency: transitive description: name: shelf url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.3.0" shelf_packages_handler: dependency: transitive description: @@ -1075,21 +1193,21 @@ packages: name: sliver_tools url: "https://pub.dartlang.org" source: hosted - version: "0.2.5" + version: "0.2.6" source_gen: dependency: transitive description: name: source_gen url: "https://pub.dartlang.org" source: hosted - version: "1.1.1" + version: "1.2.2" source_helper: dependency: transitive description: name: source_helper url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.3.2" source_map_stack_trace: dependency: transitive description: @@ -1110,7 +1228,7 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.1" + version: "1.8.2" stack_trace: dependency: transitive description: @@ -1139,13 +1257,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.0" - super_tooltip: - dependency: "direct main" - description: - name: super_tooltip - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" sync_http: dependency: "direct main" description: @@ -1166,21 +1277,21 @@ packages: name: test url: "https://pub.dartlang.org" source: hosted - version: "1.19.5" + version: "1.21.1" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.8" + version: "0.4.9" test_core: dependency: transitive description: name: test_core url: "https://pub.dartlang.org" source: hosted - version: "0.4.9" + version: "0.4.13" timing: dependency: transitive description: @@ -1202,6 +1313,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.0" + universal_io: + dependency: transitive + description: + name: universal_io + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.4" unorm_dart: dependency: "direct main" description: @@ -1215,21 +1333,21 @@ packages: name: uuid url: "https://pub.dartlang.org" source: hosted - version: "3.0.5" + version: "3.0.6" vector_math: dependency: transitive description: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" + version: "2.1.2" vm_service: dependency: transitive description: name: vm_service url: "https://pub.dartlang.org" source: hosted - version: "7.5.0" + version: "8.2.2" watcher: dependency: transitive description: @@ -1243,7 +1361,7 @@ packages: name: web_socket_channel url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.2.0" webdriver: dependency: transitive description: @@ -1257,21 +1375,49 @@ packages: name: webkit_inspection_protocol url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.1.0" + webview_flutter: + dependency: transitive + description: + name: webview_flutter + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.4" + webview_flutter_android: + dependency: transitive + description: + name: webview_flutter_android + url: "https://pub.dartlang.org" + source: hosted + version: "2.8.8" + webview_flutter_platform_interface: + dependency: transitive + description: + name: webview_flutter_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.9.0" + webview_flutter_wkwebview: + dependency: transitive + description: + name: webview_flutter_wkwebview + url: "https://pub.dartlang.org" + source: hosted + version: "2.7.5" win32: dependency: transitive description: name: win32 url: "https://pub.dartlang.org" source: hosted - version: "2.2.10" + version: "2.6.1" window_size: dependency: "direct main" description: path: "plugins/window_size" ref: HEAD - resolved-ref: "03d957e8b5c99fc83cd4a781031b154ab3de8753" - url: "git://github.com/google/flutter-desktop-embedding.git" + resolved-ref: "5c51870ced62a00e809ba4b81a846a052d241c9f" + url: "https://github.com/google/flutter-desktop-embedding.git" source: git version: "0.1.0" xdg_directories: @@ -1280,21 +1426,21 @@ packages: name: xdg_directories url: "https://pub.dartlang.org" source: hosted - version: "0.2.0" + version: "0.2.0+1" xml: dependency: "direct main" description: name: xml url: "https://pub.dartlang.org" source: hosted - version: "5.3.1" + version: "5.4.1" yaml: dependency: transitive description: name: yaml url: "https://pub.dartlang.org" source: hosted - version: "3.1.0" + version: "3.1.1" sdks: - dart: ">=2.14.4 <3.0.0" - flutter: ">=2.5.0" + dart: ">=2.17.0 <3.0.0" + flutter: ">=3.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index ee0dde1..0745de2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,7 +5,7 @@ description: Pay with G1. # 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.4+8 +version: 0.0.5+3 environment: sdk: '>=2.12.0 <3.0.0' @@ -17,7 +17,7 @@ dependencies: sdk: flutter window_size: git: - url: git://github.com/google/flutter-desktop-embedding.git + url: https://github.com/google/flutter-desktop-embedding.git path: plugins/window_size assorted_layout_widgets: ^5.2.1 bubble: ^1.2.1 @@ -25,11 +25,14 @@ dependencies: confirm_dialog: ^1.0.0 crypto: ^3.0.1 fast_base58: ^0.2.0 - flutter_launcher_icons: ^0.9.2 flutter_lints: ^1.0.4 flutter_logs: ^2.1.4 flutter_svg: ^0.22.0 - graphql_flutter: ^5.0.0 + graphql_flutter: #^5.1.0 + git: + url: https://github.com/Quantit-Github/graphql-flutter.git + path: packages/graphql_flutter + ref: f1ccb2d # commit hash hive: ^2.0.4 hive_flutter: ^1.1.0 http: ^0.13.4 @@ -43,25 +46,25 @@ dependencies: pdf: ^3.7.1 permission_handler: ^8.3.0 pin_code_fields: ^7.3.0 - printing: ^5.7.2 + printing: #^5.8.0 + git: + url: https://github.com/DavBfr/dart_pdf.git + path: printing provider: ^6.0.1 - # qrscan: ^0.3.2 - qrscan: + qrscan: #^0.3.2 git: - url: git://github.com/leyan95/qrcode_scanner.git + url: https://github.com/leyan95/qrcode_scanner.git ref: master # branch name # qr_code_scanner: ^0.6.1 - # qr_flutter: ^4.0.0 - qr_flutter: + qr_flutter: #^4.0.0 git: - url: git://github.com/insinfo/qr.flutter.git + url: https://github.com/insinfo/qr.flutter.git ref: master # branch name responsive_builder: ^0.4.1 responsive_framework: ^0.1.4 - sentry: ^6.0.0 - sentry_flutter: ^6.0.0 + sentry: ^6.5.1 + sentry_flutter: ^6.5.1 shared_preferences: ^2.0.7 - super_tooltip: ^1.0.1 sync_http: ^0.3.0 test: ^1.17.10 truncate: ^3.0.1 @@ -71,15 +74,17 @@ dependencies: dio: ^4.0.4 desktop_window: ^0.4.0 durt: ^0.1.6 - package_info_plus: ^1.3.0 - -flutter_icons: - android: "ic_launcher" - ios: true - image_path: "assets/icon/gecko_flat.png" - cupertino_icons: ^1.0.0 + package_info_plus: ^1.4.2 + polkawallet_sdk: #^0.4.5 + git: + url: https://github.com/poka-IT/sdk.git + ref: fixAndroidActivityVersion + dots_indicator: ^2.1.0 dev_dependencies: + # flutter_launcher_icons: ^0.9.2 + # flutter_launcher_icons_maker: ^^0.10.2 + icons_launcher: ^1.1.8 build_runner: ^2.1.2 flutter_test: sdk: flutter @@ -87,6 +92,14 @@ dev_dependencies: integration_test: sdk: flutter +flutter_icons: + android: true + ios: true + image_path: "assets/icon/gecko_flat.png" + remove_alpha_ios: true + +uses-material-design: true + # The following section is specific to Flutter. flutter: uses-material-design: true diff --git a/release/android/build-apk.sh b/release/android/build-apk.sh index 8589f33..6a022b9 100755 --- a/release/android/build-apk.sh +++ b/release/android/build-apk.sh @@ -19,7 +19,7 @@ cargo make # Build APK echo "Build APK..." -flutter clean +#flutter clean flutter build apk --release --build-name $VERSION --build-number $BUILD # Create artifacts folder diff --git a/scripts/build-apk.sh b/scripts/build-apk.sh index 3313821..755a9ba 100755 --- a/scripts/build-apk.sh +++ b/scripts/build-apk.sh @@ -22,7 +22,9 @@ else # flutter build apk --release --build-name $VERSION --build-number $BUILD fi -if [[ -d $HOME/Téléchargements ]]; then +if [[ -d $HOME/Nextcloud/Gecko-APK ]]; then + DL="$HOME/Nextcloud/Gecko-APK" +elif [[ -d $HOME/Téléchargements ]]; then DL="$HOME/Téléchargements" elif [[ -d $HOME/Downloads ]]; then DL="$HOME/Downloads" diff --git a/scripts/generateIcon.sh b/scripts/generateIcon.sh index b43b47e..d81b5f5 100755 --- a/scripts/generateIcon.sh +++ b/scripts/generateIcon.sh @@ -1,5 +1,5 @@ #!/bin/bash -flutter pub run flutter_launcher_icons:main +flutter pub run icons_launcher:main exit 0 diff --git a/test_driver/app_test.dart b/test_driver/app_test.dart index ce2e990..40ba8d5 100644 --- a/test_driver/app_test.dart +++ b/test_driver/app_test.dart @@ -216,7 +216,7 @@ void main() { test('OnBoarding - Generate secret code and confirm it', ( {timeout = Timeout.none}) async { expect(await getText('step9'), - "Super !\n\nJe vais maintenant créer votre code secret. \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."); + "Super !\n\nJe vais maintenant créer votre code secret. \n\nVotre code secret chiffre votre coffre 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."); await sleep(800); await tapOn('goStep10'); await sleep(50); @@ -248,7 +248,7 @@ void main() { await driver!.enterText(pinCode!); expect(await getText('step13'), - "Top !\n\nVotre trousseau de clef et votre portefeuille ont été créés avec un immense succès.\n\nFélicitations !"); + "Top !\n\nVotre coffre et votre portefeuille ont été créés avec un immense succès.\n\nFélicitations !"); }); test('My wallets - Rename first derivation', ( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 7f1ca9d..ebcb3b9 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -10,6 +10,9 @@ list(APPEND FLUTTER_PLUGIN_LIST window_size ) +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + set(PLUGIN_BUNDLED_LIBRARIES) foreach(plugin ${FLUTTER_PLUGIN_LIST}) @@ -18,3 +21,8 @@ foreach(plugin ${FLUTTER_PLUGIN_LIST}) list(APPEND PLUGIN_BUNDLED_LIBRARIES $) list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/windows/runner/Runner.rc b/windows/runner/Runner.rc index ed275d2..557212f 100644 --- a/windows/runner/Runner.rc +++ b/windows/runner/Runner.rc @@ -89,11 +89,11 @@ BEGIN BEGIN BLOCK "040904e4" BEGIN - VALUE "CompanyName", "com.example" "\0" + VALUE "CompanyName", "gecko.axiomteam.fr" "\0" VALUE "FileDescription", "A new Flutter project." "\0" VALUE "FileVersion", VERSION_AS_STRING "\0" VALUE "InternalName", "gecko" "\0" - VALUE "LegalCopyright", "Copyright (C) 2021 com.example. All rights reserved." "\0" + VALUE "LegalCopyright", "Copyright (C) 2021 gecko.axiomteam.fr. All rights reserved." "\0" VALUE "OriginalFilename", "gecko.exe" "\0" VALUE "ProductName", "gecko" "\0" VALUE "ProductVersion", VERSION_AS_STRING "\0"