diff --git a/assets/chests/1.png b/assets/chests/1.png index 327ce15..419b1ac 100644 Binary files a/assets/chests/1.png and b/assets/chests/1.png differ diff --git a/assets/chests/2.png b/assets/chests/2.png index bfb1a08..4ed6b34 100644 Binary files a/assets/chests/2.png and b/assets/chests/2.png differ diff --git a/assets/chests/3.png b/assets/chests/3.png index fb93100..66add24 100644 Binary files a/assets/chests/3.png and b/assets/chests/3.png differ diff --git a/assets/chests/4.png b/assets/chests/4.png index a759503..7bc245f 100644 Binary files a/assets/chests/4.png and b/assets/chests/4.png differ diff --git a/assets/chests/5.png b/assets/chests/5.png index 84d1490..8852a69 100644 Binary files a/assets/chests/5.png and b/assets/chests/5.png differ diff --git a/assets/chests/6.png b/assets/chests/6.png index 8f1556b..1de8739 100644 Binary files a/assets/chests/6.png and b/assets/chests/6.png differ diff --git a/assets/chests/7.png b/assets/chests/7.png index c34e084..06bae0e 100644 Binary files a/assets/chests/7.png and b/assets/chests/7.png differ diff --git a/assets/chests/secret_code.png b/assets/chests/secret_code.png old mode 100755 new mode 100644 index 10ef999..495717e Binary files a/assets/chests/secret_code.png and b/assets/chests/secret_code.png differ diff --git a/assets/chests/vector.png b/assets/chests/vector.png old mode 100755 new mode 100644 index 3fb42db..9eb11a7 Binary files a/assets/chests/vector.png and b/assets/chests/vector.png differ diff --git a/assets/copy_key.png b/assets/copy_key.png new file mode 100644 index 0000000..8957f50 Binary files /dev/null and b/assets/copy_key.png differ diff --git a/assets/home/background.jpg b/assets/home/background.jpg new file mode 100644 index 0000000..fed2fc8 Binary files /dev/null and b/assets/home/background.jpg differ diff --git a/assets/home/background.png b/assets/home/background.png new file mode 100755 index 0000000..55f24c7 Binary files /dev/null and b/assets/home/background.png differ diff --git a/assets/home/bout_de_bulle.png b/assets/home/bout_de_bulle.png new file mode 100755 index 0000000..30b6325 Binary files /dev/null and b/assets/home/bout_de_bulle.png differ diff --git a/assets/home/gecko-bienvenue.png b/assets/home/gecko-bienvenue.png new file mode 100644 index 0000000..aad8e6a Binary files /dev/null and b/assets/home/gecko-bienvenue.png differ diff --git a/assets/home/header.png b/assets/home/header.png new file mode 100755 index 0000000..9d66bb0 Binary files /dev/null and b/assets/home/header.png differ diff --git a/assets/home/header.svg b/assets/home/header.svg new file mode 100755 index 0000000..171ccc8 --- /dev/null +++ b/assets/home/header.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/assets/home/loupe.png b/assets/home/loupe.png new file mode 100644 index 0000000..79293d6 Binary files /dev/null and b/assets/home/loupe.png differ diff --git a/assets/home/loupe.svg b/assets/home/loupe.svg new file mode 100755 index 0000000..a9fc7ef --- /dev/null +++ b/assets/home/loupe.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/home/qrcode.png b/assets/home/qrcode.png new file mode 100644 index 0000000..407a5be Binary files /dev/null and b/assets/home/qrcode.png differ diff --git a/assets/home/wallet.png b/assets/home/wallet.png new file mode 100755 index 0000000..ddadaec Binary files /dev/null and b/assets/home/wallet.png differ diff --git a/assets/home/wallet.svg b/assets/home/wallet.svg new file mode 100644 index 0000000..7fa9217 --- /dev/null +++ b/assets/home/wallet.svg @@ -0,0 +1,92 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + Created by counloucon + from the Noun Project + diff --git a/assets/loupe-noire.png b/assets/loupe-noire.png new file mode 100644 index 0000000..bb8773d Binary files /dev/null and b/assets/loupe-noire.png differ diff --git a/assets/printer.png b/assets/printer.png old mode 100755 new mode 100644 index ced5f5d..aab7940 Binary files a/assets/printer.png and b/assets/printer.png differ diff --git a/assets/vector_white.png b/assets/vector_white.png new file mode 100644 index 0000000..347caaa Binary files /dev/null and b/assets/vector_white.png differ diff --git a/assets/walletOptions/android-checkmark.png b/assets/walletOptions/android-checkmark.png old mode 100755 new mode 100644 index 578859d..ef913f5 Binary files a/assets/walletOptions/android-checkmark.png and b/assets/walletOptions/android-checkmark.png differ diff --git a/assets/walletOptions/camera.png b/assets/walletOptions/camera.png old mode 100755 new mode 100644 index ce9ad0f..49fe6ba Binary files a/assets/walletOptions/camera.png and b/assets/walletOptions/camera.png differ diff --git a/assets/walletOptions/clock.png b/assets/walletOptions/clock.png old mode 100755 new mode 100644 index cf9a802..a4a684f Binary files a/assets/walletOptions/clock.png and b/assets/walletOptions/clock.png differ diff --git a/assets/walletOptions/copy-white.png b/assets/walletOptions/copy-white.png old mode 100755 new mode 100644 index 819e852..d085408 Binary files a/assets/walletOptions/copy-white.png and b/assets/walletOptions/copy-white.png differ diff --git a/assets/walletOptions/edit.png b/assets/walletOptions/edit.png old mode 100755 new mode 100644 index a45788d..3963753 Binary files a/assets/walletOptions/edit.png and b/assets/walletOptions/edit.png differ diff --git a/assets/walletOptions/icon_oeuil.png b/assets/walletOptions/icon_oeuil.png old mode 100755 new mode 100644 index f707647..75c12ec Binary files a/assets/walletOptions/icon_oeuil.png and b/assets/walletOptions/icon_oeuil.png differ diff --git a/assets/walletOptions/icon_oeuil_close.png b/assets/walletOptions/icon_oeuil_close.png index 4a13e67..db1dc51 100644 Binary files a/assets/walletOptions/icon_oeuil_close.png and b/assets/walletOptions/icon_oeuil_close.png differ diff --git a/assets/walletOptions/key.png b/assets/walletOptions/key.png old mode 100755 new mode 100644 index 45c0e85..bfabc3d Binary files a/assets/walletOptions/key.png and b/assets/walletOptions/key.png differ diff --git a/assets/walletOptions/trash.png b/assets/walletOptions/trash.png old mode 100755 new mode 100644 index 6dc972b..e2c1cbc Binary files a/assets/walletOptions/trash.png and b/assets/walletOptions/trash.png differ diff --git a/lib/globals.dart b/lib/globals.dart index 115be3d..70cd2ae 100644 --- a/lib/globals.dart +++ b/lib/globals.dart @@ -1,6 +1,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:gecko/models/chest_data.dart'; +import 'package:gecko/models/g1_wallets_list.dart'; import 'package:gecko/models/wallet_data.dart'; import 'package:hive/hive.dart'; import 'package:logger/logger.dart'; @@ -16,9 +17,10 @@ int ramSys; Box walletBox; Box chestBox; Box configBox; +Box g1WalletsBox; -// String cesiumPod = "https://g1.data.le-sou.org"; -String cesiumPod = "https://g1.data.e-is.pro"; +String cesiumPod = "https://g1.data.le-sou.org"; +// String cesiumPod = "https://g1.data.e-is.pro"; // Responsive ratios bool isTall; diff --git a/lib/main.dart b/lib/main.dart index d53b367..3377e3a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -23,16 +23,20 @@ import 'package:gecko/models/cesium_plus.dart'; import 'package:gecko/models/change_pin.dart'; import 'package:gecko/models/chest_data.dart'; import 'package:gecko/models/chest_provider.dart'; +import 'package:gecko/models/g1_wallets_list.dart'; import 'package:gecko/models/generate_wallets.dart'; -import 'package:gecko/models/history.dart'; +import 'package:gecko/models/wallets_profiles.dart'; import 'package:gecko/models/home.dart'; import 'package:gecko/models/my_wallets.dart'; +import 'package:gecko/models/search.dart'; import 'package:gecko/models/wallet_data.dart'; import 'package:gecko/models/wallet_options.dart'; import 'package:gecko/screens/home.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:gecko/screens/myWallets/wallets_home.dart'; +import 'package:gecko/screens/search.dart'; +import 'package:gecko/screens/search_result.dart'; import 'package:graphql_flutter/graphql_flutter.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'package:path_provider/path_provider.dart'; @@ -41,17 +45,14 @@ import 'package:flutter/foundation.dart'; import 'package:responsive_framework/responsive_framework.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; -import 'package:flutter_driver/driver_extension.dart'; const bool enableSentry = true; Future main() async { - enableFlutterDriverExtension(); WidgetsFlutterBinding.ensureInitialized(); HomeProvider _homeProvider = HomeProvider(); appPath = await getApplicationDocumentsDirectory(); - await _homeProvider.createDefaultAvatar(); appVersion = await _homeProvider.getAppVersion(); prefs = await SharedPreferences.getInstance(); @@ -59,15 +60,21 @@ Future main() async { await Hive.initFlutter(appPath.path); Hive.registerAdapter(WalletDataAdapter()); Hive.registerAdapter(ChestDataAdapter()); + Hive.registerAdapter(G1WalletsListAdapter()); + Hive.registerAdapter(IdAdapter()); walletBox = await Hive.openBox("walletBox"); chestBox = await Hive.openBox("chestBox"); configBox = await Hive.openBox("configBox"); + g1WalletsBox = await Hive.openBox("g1WalletsBox"); + + 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://g1.librelois.fr/gva'; + endPointGVA = 'https://duniter-g1.p2p.legal/gva'; // await _homeProvider.getValidEndpoint(); // if (endPointGVA == 'HS') { @@ -76,6 +83,8 @@ Future main() async { // _homeProvider.playSound('start', 0.2); // } + HttpOverrides.global = MyHttpOverrides(); + if (kReleaseMode && enableSentry) { // CatcherOptions debugOptions = CatcherOptions(DialogReportMode(), [ // SentryHandler(SentryClient(SentryOptions( @@ -107,8 +116,6 @@ Future main() async { } else { print('Debug mode enabled: No sentry alerte'); - HttpOverrides.global = MyHttpOverrides(); - runApp(Gecko(endPointGVA)); } } @@ -134,54 +141,58 @@ class Gecko extends StatelessWidget { // HistoryProvider _historyProvider = Provider.of(context); // HistoryProvider('').snackNode(context); return MultiProvider( - providers: [ - // Provider(create: (context) => HistoryProvider()), - ChangeNotifierProvider(create: (_) => HomeProvider()), - ChangeNotifierProvider(create: (_) => HistoryProvider('')), - ChangeNotifierProvider(create: (_) => MyWalletsProvider()), - ChangeNotifierProvider(create: (_) => ChestProvider()), - ChangeNotifierProvider(create: (_) => GenerateWalletsProvider()), - ChangeNotifierProvider(create: (_) => WalletOptionsProvider()), - ChangeNotifierProvider(create: (_) => ChangePinProvider()), - ChangeNotifierProvider(create: (_) => CesiumPlusProvider()) - ], - child: GraphQLProvider( - client: _client, - child: MaterialApp( - builder: (context, widget) => ResponsiveWrapper.builder( - BouncingScrollWrapper.builder(context, widget), - maxWidth: 1200, - minWidth: 480, - defaultScale: true, - breakpoints: [ - const ResponsiveBreakpoint.resize(480, name: MOBILE), - const ResponsiveBreakpoint.autoScale(800, name: TABLET), - const ResponsiveBreakpoint.resize(1000, name: DESKTOP), - ], - background: Container(color: backgroundColor)), - title: 'Ğecko', - theme: ThemeData( - appBarTheme: const AppBarTheme( - color: Color(0xffFFD58D), - foregroundColor: Color(0xFF000000), - ), - primaryColor: const Color(0xffFFD58D), - textTheme: const TextTheme( - bodyText1: TextStyle(), - bodyText2: TextStyle(), - ).apply( - bodyColor: const Color(0xFF000000), - ), - colorScheme: ColorScheme.fromSwatch() - .copyWith(secondary: Colors.grey[850]), + providers: [ + // Provider(create: (context) => HistoryProvider()), + ChangeNotifierProvider(create: (_) => HomeProvider()), + ChangeNotifierProvider(create: (_) => WalletsProfilesProvider('')), + ChangeNotifierProvider(create: (_) => MyWalletsProvider()), + ChangeNotifierProvider(create: (_) => ChestProvider()), + ChangeNotifierProvider(create: (_) => GenerateWalletsProvider()), + ChangeNotifierProvider(create: (_) => WalletOptionsProvider()), + ChangeNotifierProvider(create: (_) => ChangePinProvider()), + ChangeNotifierProvider(create: (_) => SearchProvider()), + ChangeNotifierProvider(create: (_) => CesiumPlusProvider()) + ], + child: GraphQLProvider( + client: _client, + child: MaterialApp( + builder: (context, widget) => ResponsiveWrapper.builder( + BouncingScrollWrapper.builder(context, widget), + maxWidth: 1200, + minWidth: 480, + defaultScale: true, + breakpoints: [ + const ResponsiveBreakpoint.resize(480, name: MOBILE), + const ResponsiveBreakpoint.autoScale(800, name: TABLET), + const ResponsiveBreakpoint.resize(1000, name: DESKTOP), + ], + background: Container(color: backgroundColor)), + title: 'Ğecko', + theme: ThemeData( + appBarTheme: const AppBarTheme( + color: Color(0xffFFD58D), + foregroundColor: Color(0xFF000000), ), - home: const HomeScreen(), - initialRoute: "/", - routes: { - '/mywallets': (context) => WalletsHome(), - }, + primaryColor: const Color(0xffFFD58D), + textTheme: const TextTheme( + bodyText1: TextStyle(), + bodyText2: TextStyle(), + ).apply( + bodyColor: const Color(0xFF000000), + ), + colorScheme: + ColorScheme.fromSwatch().copyWith(secondary: Colors.grey[850]), ), - )); + home: const HomeScreen(), + initialRoute: "/", + routes: { + '/mywallets': (context) => WalletsHome(), + '/search': (context) => const SearchScreen(), + '/searchResult': (context) => const SearchResultScreen(), + }, + ), + ), + ); } } diff --git a/lib/models/bip39_words.dart b/lib/models/bip39_words.dart new file mode 100644 index 0000000..0809642 --- /dev/null +++ b/lib/models/bip39_words.dart @@ -0,0 +1,2050 @@ +List bip39Words = [ + 'abaisser', + 'abandon', + 'abdiquer', + 'abeille', + 'abolir', + 'aborder', + 'aboutir', + 'aboyer', + 'abrasif', + 'abreuver', + 'abriter', + 'abroger', + 'abrupt', + 'absence', + 'absolu', + 'absurde', + 'abusif', + 'abyssal', + 'académie', + 'acajou', + 'acarien', + 'accabler', + 'accepter', + 'acclamer', + 'accolade', + 'accroche', + 'accuser', + 'acerbe', + 'achat', + 'acheter', + 'aciduler', + 'acier', + 'acompte', + 'acquérir', + 'acronyme', + 'acteur', + 'actif', + 'actuel', + 'adepte', + 'adéquat', + 'adhésif', + 'adjectif', + 'adjuger', + 'admettre', + 'admirer', + 'adopter', + 'adorer', + 'adoucir', + 'adresse', + 'adroit', + 'adulte', + 'adverbe', + 'aérer', + 'aéronef', + 'affaire', + 'affecter', + 'affiche', + 'affreux', + 'affubler', + 'agacer', + 'agencer', + 'agile', + 'agiter', + 'agrafer', + 'agréable', + 'agrume', + 'aider', + 'aiguille', + 'ailier', + 'aimable', + 'aisance', + 'ajouter', + 'ajuster', + 'alarmer', + 'alchimie', + 'alerte', + 'algèbre', + 'algue', + 'aliéner', + 'aliment', + 'alléger', + 'alliage', + 'allouer', + 'allumer', + 'alourdir', + 'alpaga', + 'altesse', + 'alvéole', + 'amateur', + 'ambigu', + 'ambre', + 'aménager', + 'amertume', + 'amidon', + 'amiral', + 'amorcer', + 'amour', + 'amovible', + 'amphibie', + 'ampleur', + 'amusant', + 'analyse', + 'anaphore', + 'anarchie', + 'anatomie', + 'ancien', + 'anéantir', + 'angle', + 'angoisse', + 'anguleux', + 'animal', + 'annexer', + 'annonce', + 'annuel', + 'anodin', + 'anomalie', + 'anonyme', + 'anormal', + 'antenne', + 'antidote', + 'anxieux', + 'apaiser', + 'apéritif', + 'aplanir', + 'apologie', + 'appareil', + 'appeler', + 'apporter', + 'appuyer', + 'aquarium', + 'aqueduc', + 'arbitre', + 'arbuste', + 'ardeur', + 'ardoise', + 'argent', + 'arlequin', + 'armature', + 'armement', + 'armoire', + 'armure', + 'arpenter', + 'arracher', + 'arriver', + 'arroser', + 'arsenic', + 'artériel', + 'article', + 'aspect', + 'asphalte', + 'aspirer', + 'assaut', + 'asservir', + 'assiette', + 'associer', + 'assurer', + 'asticot', + 'astre', + 'astuce', + 'atelier', + 'atome', + 'atrium', + 'atroce', + 'attaque', + 'attentif', + 'attirer', + 'attraper', + 'aubaine', + 'auberge', + 'audace', + 'audible', + 'augurer', + 'aurore', + 'automne', + 'autruche', + 'avaler', + 'avancer', + 'avarice', + 'avenir', + 'averse', + 'aveugle', + 'aviateur', + 'avide', + 'avion', + 'aviser', + 'avoine', + 'avouer', + 'avril', + 'axial', + 'axiome', + 'badge', + 'bafouer', + 'bagage', + 'baguette', + 'baignade', + 'balancer', + 'balcon', + 'baleine', + 'balisage', + 'bambin', + 'bancaire', + 'bandage', + 'banlieue', + 'bannière', + 'banquier', + 'barbier', + 'baril', + 'baron', + 'barque', + 'barrage', + 'bassin', + 'bastion', + 'bataille', + 'bateau', + 'batterie', + 'baudrier', + 'bavarder', + 'belette', + 'bélier', + 'belote', + 'bénéfice', + 'berceau', + 'berger', + 'berline', + 'bermuda', + 'besace', + 'besogne', + 'bétail', + 'beurre', + 'biberon', + 'bicycle', + 'bidule', + 'bijou', + 'bilan', + 'bilingue', + 'billard', + 'binaire', + 'biologie', + 'biopsie', + 'biotype', + 'biscuit', + 'bison', + 'bistouri', + 'bitume', + 'bizarre', + 'blafard', + 'blague', + 'blanchir', + 'blessant', + 'blinder', + 'blond', + 'bloquer', + 'blouson', + 'bobard', + 'bobine', + 'boire', + 'boiser', + 'bolide', + 'bonbon', + 'bondir', + 'bonheur', + 'bonifier', + 'bonus', + 'bordure', + 'borne', + 'botte', + 'boucle', + 'boueux', + 'bougie', + 'boulon', + 'bouquin', + 'bourse', + 'boussole', + 'boutique', + 'boxeur', + 'branche', + 'brasier', + 'brave', + 'brebis', + 'brèche', + 'breuvage', + 'bricoler', + 'brigade', + 'brillant', + 'brioche', + 'brique', + 'brochure', + 'broder', + 'bronzer', + 'brousse', + 'broyeur', + 'brume', + 'brusque', + 'brutal', + 'bruyant', + 'buffle', + 'buisson', + 'bulletin', + 'bureau', + 'burin', + 'bustier', + 'butiner', + 'butoir', + 'buvable', + 'buvette', + 'cabanon', + 'cabine', + 'cachette', + 'cadeau', + 'cadre', + 'caféine', + 'caillou', + 'caisson', + 'calculer', + 'calepin', + 'calibre', + 'calmer', + 'calomnie', + 'calvaire', + 'camarade', + 'caméra', + 'camion', + 'campagne', + 'canal', + 'caneton', + 'canon', + 'cantine', + 'canular', + 'capable', + 'caporal', + 'caprice', + 'capsule', + 'capter', + 'capuche', + 'carabine', + 'carbone', + 'caresser', + 'caribou', + 'carnage', + 'carotte', + 'carreau', + 'carton', + 'cascade', + 'casier', + 'casque', + 'cassure', + 'causer', + 'caution', + 'cavalier', + 'caverne', + 'caviar', + 'cédille', + 'ceinture', + 'céleste', + 'cellule', + 'cendrier', + 'censurer', + 'central', + 'cercle', + 'cérébral', + 'cerise', + 'cerner', + 'cerveau', + 'cesser', + 'chagrin', + 'chaise', + 'chaleur', + 'chambre', + 'chance', + 'chapitre', + 'charbon', + 'chasseur', + 'chaton', + 'chausson', + 'chavirer', + 'chemise', + 'chenille', + 'chéquier', + 'chercher', + 'cheval', + 'chien', + 'chiffre', + 'chignon', + 'chimère', + 'chiot', + 'chlorure', + 'chocolat', + 'choisir', + 'chose', + 'chouette', + 'chrome', + 'chute', + 'cigare', + 'cigogne', + 'cimenter', + 'cinéma', + 'cintrer', + 'circuler', + 'cirer', + 'cirque', + 'citerne', + 'citoyen', + 'citron', + 'civil', + 'clairon', + 'clameur', + 'claquer', + 'classe', + 'clavier', + 'client', + 'cligner', + 'climat', + 'clivage', + 'cloche', + 'clonage', + 'cloporte', + 'cobalt', + 'cobra', + 'cocasse', + 'cocotier', + 'coder', + 'codifier', + 'coffre', + 'cogner', + 'cohésion', + 'coiffer', + 'coincer', + 'colère', + 'colibri', + 'colline', + 'colmater', + 'colonel', + 'combat', + 'comédie', + 'commande', + 'compact', + 'concert', + 'conduire', + 'confier', + 'congeler', + 'connoter', + 'consonne', + 'contact', + 'convexe', + 'copain', + 'copie', + 'corail', + 'corbeau', + 'cordage', + 'corniche', + 'corpus', + 'correct', + 'cortège', + 'cosmique', + 'costume', + 'coton', + 'coude', + 'coupure', + 'courage', + 'couteau', + 'couvrir', + 'coyote', + 'crabe', + 'crainte', + 'cravate', + 'crayon', + 'créature', + 'créditer', + 'crémeux', + 'creuser', + 'crevette', + 'cribler', + 'crier', + 'cristal', + 'critère', + 'croire', + 'croquer', + 'crotale', + 'crucial', + 'cruel', + 'crypter', + 'cubique', + 'cueillir', + 'cuillère', + 'cuisine', + 'cuivre', + 'culminer', + 'cultiver', + 'cumuler', + 'cupide', + 'curatif', + 'curseur', + 'cyanure', + 'cycle', + 'cylindre', + 'cynique', + 'daigner', + 'damier', + 'danger', + 'danseur', + 'dauphin', + 'débattre', + 'débiter', + 'déborder', + 'débrider', + 'débutant', + 'décaler', + 'décembre', + 'déchirer', + 'décider', + 'déclarer', + 'décorer', + 'décrire', + 'décupler', + 'dédale', + 'déductif', + 'déesse', + 'défensif', + 'défiler', + 'défrayer', + 'dégager', + 'dégivrer', + 'déglutir', + 'dégrafer', + 'déjeuner', + 'délice', + 'déloger', + 'demander', + 'demeurer', + 'démolir', + 'dénicher', + 'dénouer', + 'dentelle', + 'dénuder', + 'départ', + 'dépenser', + 'déphaser', + 'déplacer', + 'déposer', + 'déranger', + 'dérober', + 'désastre', + 'descente', + 'désert', + 'désigner', + 'désobéir', + 'dessiner', + 'destrier', + 'détacher', + 'détester', + 'détourer', + 'détresse', + 'devancer', + 'devenir', + 'deviner', + 'devoir', + 'diable', + 'dialogue', + 'diamant', + 'dicter', + 'différer', + 'digérer', + 'digital', + 'digne', + 'diluer', + 'dimanche', + 'diminuer', + 'dioxyde', + 'directif', + 'diriger', + 'discuter', + 'disposer', + 'dissiper', + 'distance', + 'divertir', + 'diviser', + 'docile', + 'docteur', + 'dogme', + 'doigt', + 'domaine', + 'domicile', + 'dompter', + 'donateur', + 'donjon', + 'donner', + 'dopamine', + 'dortoir', + 'dorure', + 'dosage', + 'doseur', + 'dossier', + 'dotation', + 'douanier', + 'double', + 'douceur', + 'douter', + 'doyen', + 'dragon', + 'draper', + 'dresser', + 'dribbler', + 'droiture', + 'duperie', + 'duplexe', + 'durable', + 'durcir', + 'dynastie', + 'éblouir', + 'écarter', + 'écharpe', + 'échelle', + 'éclairer', + 'éclipse', + 'éclore', + 'écluse', + 'école', + 'économie', + 'écorce', + 'écouter', + 'écraser', + 'écrémer', + 'écrivain', + 'écrou', + 'écume', + 'écureuil', + 'édifier', + 'éduquer', + 'effacer', + 'effectif', + 'effigie', + 'effort', + 'effrayer', + 'effusion', + 'égaliser', + 'égarer', + 'éjecter', + 'élaborer', + 'élargir', + 'électron', + 'élégant', + 'éléphant', + 'élève', + 'éligible', + 'élitisme', + 'éloge', + 'élucider', + 'éluder', + 'emballer', + 'embellir', + 'embryon', + 'émeraude', + 'émission', + 'emmener', + 'émotion', + 'émouvoir', + 'empereur', + 'employer', + 'emporter', + 'emprise', + 'émulsion', + 'encadrer', + 'enchère', + 'enclave', + 'encoche', + 'endiguer', + 'endosser', + 'endroit', + 'enduire', + 'énergie', + 'enfance', + 'enfermer', + 'enfouir', + 'engager', + 'engin', + 'englober', + 'énigme', + 'enjamber', + 'enjeu', + 'enlever', + 'ennemi', + 'ennuyeux', + 'enrichir', + 'enrobage', + 'enseigne', + 'entasser', + 'entendre', + 'entier', + 'entourer', + 'entraver', + 'énumérer', + 'envahir', + 'enviable', + 'envoyer', + 'enzyme', + 'éolien', + 'épaissir', + 'épargne', + 'épatant', + 'épaule', + 'épicerie', + 'épidémie', + 'épier', + 'épilogue', + 'épine', + 'épisode', + 'épitaphe', + 'époque', + 'épreuve', + 'éprouver', + 'épuisant', + 'équerre', + 'équipe', + 'ériger', + 'érosion', + 'erreur', + 'éruption', + 'escalier', + 'espadon', + 'espèce', + 'espiègle', + 'espoir', + 'esprit', + 'esquiver', + 'essayer', + 'essence', + 'essieu', + 'essorer', + 'estime', + 'estomac', + 'estrade', + 'étagère', + 'étaler', + 'étanche', + 'étatique', + 'éteindre', + 'étendoir', + 'éternel', + 'éthanol', + 'éthique', + 'ethnie', + 'étirer', + 'étoffer', + 'étoile', + 'étonnant', + 'étourdir', + 'étrange', + 'étroit', + 'étude', + 'euphorie', + 'évaluer', + 'évasion', + 'éventail', + 'évidence', + 'éviter', + 'évolutif', + 'évoquer', + 'exact', + 'exagérer', + 'exaucer', + 'exceller', + 'excitant', + 'exclusif', + 'excuse', + 'exécuter', + 'exemple', + 'exercer', + 'exhaler', + 'exhorter', + 'exigence', + 'exiler', + 'exister', + 'exotique', + 'expédier', + 'explorer', + 'exposer', + 'exprimer', + 'exquis', + 'extensif', + 'extraire', + 'exulter', + 'fable', + 'fabuleux', + 'facette', + 'facile', + 'facture', + 'faiblir', + 'falaise', + 'fameux', + 'famille', + 'farceur', + 'farfelu', + 'farine', + 'farouche', + 'fasciner', + 'fatal', + 'fatigue', + 'faucon', + 'fautif', + 'faveur', + 'favori', + 'fébrile', + 'féconder', + 'fédérer', + 'félin', + 'femme', + 'fémur', + 'fendoir', + 'féodal', + 'fermer', + 'féroce', + 'ferveur', + 'festival', + 'feuille', + 'feutre', + 'février', + 'fiasco', + 'ficeler', + 'fictif', + 'fidèle', + 'figure', + 'filature', + 'filetage', + 'filière', + 'filleul', + 'filmer', + 'filou', + 'filtrer', + 'financer', + 'finir', + 'fiole', + 'firme', + 'fissure', + 'fixer', + 'flairer', + 'flamme', + 'flasque', + 'flatteur', + 'fléau', + 'flèche', + 'fleur', + 'flexion', + 'flocon', + 'flore', + 'fluctuer', + 'fluide', + 'fluvial', + 'folie', + 'fonderie', + 'fongible', + 'fontaine', + 'forcer', + 'forgeron', + 'formuler', + 'fortune', + 'fossile', + 'foudre', + 'fougère', + 'fouiller', + 'foulure', + 'fourmi', + 'fragile', + 'fraise', + 'franchir', + 'frapper', + 'frayeur', + 'frégate', + 'freiner', + 'frelon', + 'frémir', + 'frénésie', + 'frère', + 'friable', + 'friction', + 'frisson', + 'frivole', + 'froid', + 'fromage', + 'frontal', + 'frotter', + 'fruit', + 'fugitif', + 'fuite', + 'fureur', + 'furieux', + 'furtif', + 'fusion', + 'futur', + 'gagner', + 'galaxie', + 'galerie', + 'gambader', + 'garantir', + 'gardien', + 'garnir', + 'garrigue', + 'gazelle', + 'gazon', + 'géant', + 'gélatine', + 'gélule', + 'gendarme', + 'général', + 'génie', + 'genou', + 'gentil', + 'géologie', + 'géomètre', + 'géranium', + 'germe', + 'gestuel', + 'geyser', + 'gibier', + 'gicler', + 'girafe', + 'givre', + 'glace', + 'glaive', + 'glisser', + 'globe', + 'gloire', + 'glorieux', + 'golfeur', + 'gomme', + 'gonfler', + 'gorge', + 'gorille', + 'goudron', + 'gouffre', + 'goulot', + 'goupille', + 'gourmand', + 'goutte', + 'graduel', + 'graffiti', + 'graine', + 'grand', + 'grappin', + 'gratuit', + 'gravir', + 'grenat', + 'griffure', + 'griller', + 'grimper', + 'grogner', + 'gronder', + 'grotte', + 'groupe', + 'gruger', + 'grutier', + 'gruyère', + 'guépard', + 'guerrier', + 'guide', + 'guimauve', + 'guitare', + 'gustatif', + 'gymnaste', + 'gyrostat', + 'habitude', + 'hachoir', + 'halte', + 'hameau', + 'hangar', + 'hanneton', + 'haricot', + 'harmonie', + 'harpon', + 'hasard', + 'hélium', + 'hématome', + 'herbe', + 'hérisson', + 'hermine', + 'héron', + 'hésiter', + 'heureux', + 'hiberner', + 'hibou', + 'hilarant', + 'histoire', + 'hiver', + 'homard', + 'hommage', + 'homogène', + 'honneur', + 'honorer', + 'honteux', + 'horde', + 'horizon', + 'horloge', + 'hormone', + 'horrible', + 'houleux', + 'housse', + 'hublot', + 'huileux', + 'humain', + 'humble', + 'humide', + 'humour', + 'hurler', + 'hydromel', + 'hygiène', + 'hymne', + 'hypnose', + 'idylle', + 'ignorer', + 'iguane', + 'illicite', + 'illusion', + 'image', + 'imbiber', + 'imiter', + 'immense', + 'immobile', + 'immuable', + 'impact', + 'impérial', + 'implorer', + 'imposer', + 'imprimer', + 'imputer', + 'incarner', + 'incendie', + 'incident', + 'incliner', + 'incolore', + 'indexer', + 'indice', + 'inductif', + 'inédit', + 'ineptie', + 'inexact', + 'infini', + 'infliger', + 'informer', + 'infusion', + 'ingérer', + 'inhaler', + 'inhiber', + 'injecter', + 'injure', + 'innocent', + 'inoculer', + 'inonder', + 'inscrire', + 'insecte', + 'insigne', + 'insolite', + 'inspirer', + 'instinct', + 'insulter', + 'intact', + 'intense', + 'intime', + 'intrigue', + 'intuitif', + 'inutile', + 'invasion', + 'inventer', + 'inviter', + 'invoquer', + 'ironique', + 'irradier', + 'irréel', + 'irriter', + 'isoler', + 'ivoire', + 'ivresse', + 'jaguar', + 'jaillir', + 'jambe', + 'janvier', + 'jardin', + 'jauger', + 'jaune', + 'javelot', + 'jetable', + 'jeton', + 'jeudi', + 'jeunesse', + 'joindre', + 'joncher', + 'jongler', + 'joueur', + 'jouissif', + 'journal', + 'jovial', + 'joyau', + 'joyeux', + 'jubiler', + 'jugement', + 'junior', + 'jupon', + 'juriste', + 'justice', + 'juteux', + 'juvénile', + 'kayak', + 'kimono', + 'kiosque', + 'label', + 'labial', + 'labourer', + 'lacérer', + 'lactose', + 'lagune', + 'laine', + 'laisser', + 'laitier', + 'lambeau', + 'lamelle', + 'lampe', + 'lanceur', + 'langage', + 'lanterne', + 'lapin', + 'largeur', + 'larme', + 'laurier', + 'lavabo', + 'lavoir', + 'lecture', + 'légal', + 'léger', + 'légume', + 'lessive', + 'lettre', + 'levier', + 'lexique', + 'lézard', + 'liasse', + 'libérer', + 'libre', + 'licence', + 'licorne', + 'liège', + 'lièvre', + 'ligature', + 'ligoter', + 'ligue', + 'limer', + 'limite', + 'limonade', + 'limpide', + 'linéaire', + 'lingot', + 'lionceau', + 'liquide', + 'lisière', + 'lister', + 'lithium', + 'litige', + 'littoral', + 'livreur', + 'logique', + 'lointain', + 'loisir', + 'lombric', + 'loterie', + 'louer', + 'lourd', + 'loutre', + 'louve', + 'loyal', + 'lubie', + 'lucide', + 'lucratif', + 'lueur', + 'lugubre', + 'luisant', + 'lumière', + 'lunaire', + 'lundi', + 'luron', + 'lutter', + 'luxueux', + 'machine', + 'magasin', + 'magenta', + 'magique', + 'maigre', + 'maillon', + 'maintien', + 'mairie', + 'maison', + 'majorer', + 'malaxer', + 'maléfice', + 'malheur', + 'malice', + 'mallette', + 'mammouth', + 'mandater', + 'maniable', + 'manquant', + 'manteau', + 'manuel', + 'marathon', + 'marbre', + 'marchand', + 'mardi', + 'maritime', + 'marqueur', + 'marron', + 'marteler', + 'mascotte', + 'massif', + 'matériel', + 'matière', + 'matraque', + 'maudire', + 'maussade', + 'mauve', + 'maximal', + 'méchant', + 'méconnu', + 'médaille', + 'médecin', + 'méditer', + 'méduse', + 'meilleur', + 'mélange', + 'mélodie', + 'membre', + 'mémoire', + 'menacer', + 'mener', + 'menhir', + 'mensonge', + 'mentor', + 'mercredi', + 'mérite', + 'merle', + 'messager', + 'mesure', + 'métal', + 'météore', + 'méthode', + 'métier', + 'meuble', + 'miauler', + 'microbe', + 'miette', + 'mignon', + 'migrer', + 'milieu', + 'million', + 'mimique', + 'mince', + 'minéral', + 'minimal', + 'minorer', + 'minute', + 'miracle', + 'miroiter', + 'missile', + 'mixte', + 'mobile', + 'moderne', + 'moelleux', + 'mondial', + 'moniteur', + 'monnaie', + 'monotone', + 'monstre', + 'montagne', + 'monument', + 'moqueur', + 'morceau', + 'morsure', + 'mortier', + 'moteur', + 'motif', + 'mouche', + 'moufle', + 'moulin', + 'mousson', + 'mouton', + 'mouvant', + 'multiple', + 'munition', + 'muraille', + 'murène', + 'murmure', + 'muscle', + 'muséum', + 'musicien', + 'mutation', + 'muter', + 'mutuel', + 'myriade', + 'myrtille', + 'mystère', + 'mythique', + 'nageur', + 'nappe', + 'narquois', + 'narrer', + 'natation', + 'nation', + 'nature', + 'naufrage', + 'nautique', + 'navire', + 'nébuleux', + 'nectar', + 'néfaste', + 'négation', + 'négliger', + 'négocier', + 'neige', + 'nerveux', + 'nettoyer', + 'neurone', + 'neutron', + 'neveu', + 'niche', + 'nickel', + 'nitrate', + 'niveau', + 'noble', + 'nocif', + 'nocturne', + 'noirceur', + 'noisette', + 'nomade', + 'nombreux', + 'nommer', + 'normatif', + 'notable', + 'notifier', + 'notoire', + 'nourrir', + 'nouveau', + 'novateur', + 'novembre', + 'novice', + 'nuage', + 'nuancer', + 'nuire', + 'nuisible', + 'numéro', + 'nuptial', + 'nuque', + 'nutritif', + 'obéir', + 'objectif', + 'obliger', + 'obscur', + 'observer', + 'obstacle', + 'obtenir', + 'obturer', + 'occasion', + 'occuper', + 'océan', + 'octobre', + 'octroyer', + 'octupler', + 'oculaire', + 'odeur', + 'odorant', + 'offenser', + 'officier', + 'offrir', + 'ogive', + 'oiseau', + 'oisillon', + 'olfactif', + 'olivier', + 'ombrage', + 'omettre', + 'onctueux', + 'onduler', + 'onéreux', + 'onirique', + 'opale', + 'opaque', + 'opérer', + 'opinion', + 'opportun', + 'opprimer', + 'opter', + 'optique', + 'orageux', + 'orange', + 'orbite', + 'ordonner', + 'oreille', + 'organe', + 'orgueil', + 'orifice', + 'ornement', + 'orque', + 'ortie', + 'osciller', + 'osmose', + 'ossature', + 'otarie', + 'ouragan', + 'ourson', + 'outil', + 'outrager', + 'ouvrage', + 'ovation', + 'oxyde', + 'oxygène', + 'ozone', + 'paisible', + 'palace', + 'palmarès', + 'palourde', + 'palper', + 'panache', + 'panda', + 'pangolin', + 'paniquer', + 'panneau', + 'panorama', + 'pantalon', + 'papaye', + 'papier', + 'papoter', + 'papyrus', + 'paradoxe', + 'parcelle', + 'paresse', + 'parfumer', + 'parler', + 'parole', + 'parrain', + 'parsemer', + 'partager', + 'parure', + 'parvenir', + 'passion', + 'pastèque', + 'paternel', + 'patience', + 'patron', + 'pavillon', + 'pavoiser', + 'payer', + 'paysage', + 'peigne', + 'peintre', + 'pelage', + 'pélican', + 'pelle', + 'pelouse', + 'peluche', + 'pendule', + 'pénétrer', + 'pénible', + 'pensif', + 'pénurie', + 'pépite', + 'péplum', + 'perdrix', + 'perforer', + 'période', + 'permuter', + 'perplexe', + 'persil', + 'perte', + 'peser', + 'pétale', + 'petit', + 'pétrir', + 'peuple', + 'pharaon', + 'phobie', + 'phoque', + 'photon', + 'phrase', + 'physique', + 'piano', + 'pictural', + 'pièce', + 'pierre', + 'pieuvre', + 'pilote', + 'pinceau', + 'pipette', + 'piquer', + 'pirogue', + 'piscine', + 'piston', + 'pivoter', + 'pixel', + 'pizza', + 'placard', + 'plafond', + 'plaisir', + 'planer', + 'plaque', + 'plastron', + 'plateau', + 'pleurer', + 'plexus', + 'pliage', + 'plomb', + 'plonger', + 'pluie', + 'plumage', + 'pochette', + 'poésie', + 'poète', + 'pointe', + 'poirier', + 'poisson', + 'poivre', + 'polaire', + 'policier', + 'pollen', + 'polygone', + 'pommade', + 'pompier', + 'ponctuel', + 'pondérer', + 'poney', + 'portique', + 'position', + 'posséder', + 'posture', + 'potager', + 'poteau', + 'potion', + 'pouce', + 'poulain', + 'poumon', + 'pourpre', + 'poussin', + 'pouvoir', + 'prairie', + 'pratique', + 'précieux', + 'prédire', + 'préfixe', + 'prélude', + 'prénom', + 'présence', + 'prétexte', + 'prévoir', + 'primitif', + 'prince', + 'prison', + 'priver', + 'problème', + 'procéder', + 'prodige', + 'profond', + 'progrès', + 'proie', + 'projeter', + 'prologue', + 'promener', + 'propre', + 'prospère', + 'protéger', + 'prouesse', + 'proverbe', + 'prudence', + 'pruneau', + 'psychose', + 'public', + 'puceron', + 'puiser', + 'pulpe', + 'pulsar', + 'punaise', + 'punitif', + 'pupitre', + 'purifier', + 'puzzle', + 'pyramide', + 'quasar', + 'querelle', + 'question', + 'quiétude', + 'quitter', + 'quotient', + 'racine', + 'raconter', + 'radieux', + 'ragondin', + 'raideur', + 'raisin', + 'ralentir', + 'rallonge', + 'ramasser', + 'rapide', + 'rasage', + 'ratisser', + 'ravager', + 'ravin', + 'rayonner', + 'réactif', + 'réagir', + 'réaliser', + 'réanimer', + 'recevoir', + 'réciter', + 'réclamer', + 'récolter', + 'recruter', + 'reculer', + 'recycler', + 'rédiger', + 'redouter', + 'refaire', + 'réflexe', + 'réformer', + 'refrain', + 'refuge', + 'régalien', + 'région', + 'réglage', + 'régulier', + 'réitérer', + 'rejeter', + 'rejouer', + 'relatif', + 'relever', + 'relief', + 'remarque', + 'remède', + 'remise', + 'remonter', + 'remplir', + 'remuer', + 'renard', + 'renfort', + 'renifler', + 'renoncer', + 'rentrer', + 'renvoi', + 'replier', + 'reporter', + 'reprise', + 'reptile', + 'requin', + 'réserve', + 'résineux', + 'résoudre', + 'respect', + 'rester', + 'résultat', + 'rétablir', + 'retenir', + 'réticule', + 'retomber', + 'retracer', + 'réunion', + 'réussir', + 'revanche', + 'revivre', + 'révolte', + 'révulsif', + 'richesse', + 'rideau', + 'rieur', + 'rigide', + 'rigoler', + 'rincer', + 'riposter', + 'risible', + 'risque', + 'rituel', + 'rival', + 'rivière', + 'rocheux', + 'romance', + 'rompre', + 'ronce', + 'rondin', + 'roseau', + 'rosier', + 'rotatif', + 'rotor', + 'rotule', + 'rouge', + 'rouille', + 'rouleau', + 'routine', + 'royaume', + 'ruban', + 'rubis', + 'ruche', + 'ruelle', + 'rugueux', + 'ruiner', + 'ruisseau', + 'ruser', + 'rustique', + 'rythme', + 'sabler', + 'saboter', + 'sabre', + 'sacoche', + 'safari', + 'sagesse', + 'saisir', + 'salade', + 'salive', + 'salon', + 'saluer', + 'samedi', + 'sanction', + 'sanglier', + 'sarcasme', + 'sardine', + 'saturer', + 'saugrenu', + 'saumon', + 'sauter', + 'sauvage', + 'savant', + 'savonner', + 'scalpel', + 'scandale', + 'scélérat', + 'scénario', + 'sceptre', + 'schéma', + 'science', + 'scinder', + 'score', + 'scrutin', + 'sculpter', + 'séance', + 'sécable', + 'sécher', + 'secouer', + 'sécréter', + 'sédatif', + 'séduire', + 'seigneur', + 'séjour', + 'sélectif', + 'semaine', + 'sembler', + 'semence', + 'séminal', + 'sénateur', + 'sensible', + 'sentence', + 'séparer', + 'séquence', + 'serein', + 'sergent', + 'sérieux', + 'serrure', + 'sérum', + 'service', + 'sésame', + 'sévir', + 'sevrage', + 'sextuple', + 'sidéral', + 'siècle', + 'siéger', + 'siffler', + 'sigle', + 'signal', + 'silence', + 'silicium', + 'simple', + 'sincère', + 'sinistre', + 'siphon', + 'sirop', + 'sismique', + 'situer', + 'skier', + 'social', + 'socle', + 'sodium', + 'soigneux', + 'soldat', + 'soleil', + 'solitude', + 'soluble', + 'sombre', + 'sommeil', + 'somnoler', + 'sonde', + 'songeur', + 'sonnette', + 'sonore', + 'sorcier', + 'sortir', + 'sosie', + 'sottise', + 'soucieux', + 'soudure', + 'souffle', + 'soulever', + 'soupape', + 'source', + 'soutirer', + 'souvenir', + 'spacieux', + 'spatial', + 'spécial', + 'sphère', + 'spiral', + 'stable', + 'station', + 'sternum', + 'stimulus', + 'stipuler', + 'strict', + 'studieux', + 'stupeur', + 'styliste', + 'sublime', + 'substrat', + 'subtil', + 'subvenir', + 'succès', + 'sucre', + 'suffixe', + 'suggérer', + 'suiveur', + 'sulfate', + 'superbe', + 'supplier', + 'surface', + 'suricate', + 'surmener', + 'surprise', + 'sursaut', + 'survie', + 'suspect', + 'syllabe', + 'symbole', + 'symétrie', + 'synapse', + 'syntaxe', + 'système', + 'tabac', + 'tablier', + 'tactile', + 'tailler', + 'talent', + 'talisman', + 'talonner', + 'tambour', + 'tamiser', + 'tangible', + 'tapis', + 'taquiner', + 'tarder', + 'tarif', + 'tartine', + 'tasse', + 'tatami', + 'tatouage', + 'taupe', + 'taureau', + 'taxer', + 'témoin', + 'temporel', + 'tenaille', + 'tendre', + 'teneur', + 'tenir', + 'tension', + 'terminer', + 'terne', + 'terrible', + 'tétine', + 'texte', + 'thème', + 'théorie', + 'thérapie', + 'thorax', + 'tibia', + 'tiède', + 'timide', + 'tirelire', + 'tiroir', + 'tissu', + 'titane', + 'titre', + 'tituber', + 'toboggan', + 'tolérant', + 'tomate', + 'tonique', + 'tonneau', + 'toponyme', + 'torche', + 'tordre', + 'tornade', + 'torpille', + 'torrent', + 'torse', + 'tortue', + 'totem', + 'toucher', + 'tournage', + 'tousser', + 'toxine', + 'traction', + 'trafic', + 'tragique', + 'trahir', + 'train', + 'trancher', + 'travail', + 'trèfle', + 'tremper', + 'trésor', + 'treuil', + 'triage', + 'tribunal', + 'tricoter', + 'trilogie', + 'triomphe', + 'tripler', + 'triturer', + 'trivial', + 'trombone', + 'tronc', + 'tropical', + 'troupeau', + 'tuile', + 'tulipe', + 'tumulte', + 'tunnel', + 'turbine', + 'tuteur', + 'tutoyer', + 'tuyau', + 'tympan', + 'typhon', + 'typique', + 'tyran', + 'ubuesque', + 'ultime', + 'ultrason', + 'unanime', + 'unifier', + 'union', + 'unique', + 'unitaire', + 'univers', + 'uranium', + 'urbain', + 'urticant', + 'usage', + 'usine', + 'usuel', + 'usure', + 'utile', + 'utopie', + 'vacarme', + 'vaccin', + 'vagabond', + 'vague', + 'vaillant', + 'vaincre', + 'vaisseau', + 'valable', + 'valise', + 'vallon', + 'valve', + 'vampire', + 'vanille', + 'vapeur', + 'varier', + 'vaseux', + 'vassal', + 'vaste', + 'vecteur', + 'vedette', + 'végétal', + 'véhicule', + 'veinard', + 'véloce', + 'vendredi', + 'vénérer', + 'venger', + 'venimeux', + 'ventouse', + 'verdure', + 'vérin', + 'vernir', + 'verrou', + 'verser', + 'vertu', + 'veston', + 'vétéran', + 'vétuste', + 'vexant', + 'vexer', + 'viaduc', + 'viande', + 'victoire', + 'vidange', + 'vidéo', + 'vignette', + 'vigueur', + 'vilain', + 'village', + 'vinaigre', + 'violon', + 'vipère', + 'virement', + 'virtuose', + 'virus', + 'visage', + 'viseur', + 'vision', + 'visqueux', + 'visuel', + 'vital', + 'vitesse', + 'viticole', + 'vitrine', + 'vivace', + 'vivipare', + 'vocation', + 'voguer', + 'voile', + 'voisin', + 'voiture', + 'volaille', + 'volcan', + 'voltiger', + 'volume', + 'vorace', + 'vortex', + 'voter', + 'vouloir', + 'voyage', + 'voyelle', + 'wagon', + 'xénon', + 'yacht', + 'zèbre', + 'zénith', + 'zeste', + 'zoologie' +]; diff --git a/lib/models/cesium_plus.dart b/lib/models/cesium_plus.dart index 8d73d00..e2659c1 100644 --- a/lib/models/cesium_plus.dart +++ b/lib/models/cesium_plus.dart @@ -1,15 +1,18 @@ import 'dart:convert'; import 'dart:io'; +import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:gecko/globals.dart'; -import 'package:http/http.dart' as http; import 'package:path_provider/path_provider.dart'; +// import 'package:http/http.dart' as http; class CesiumPlusProvider with ChangeNotifier { TextEditingController cesiumName = TextEditingController(); - int iAvatar = 0; - bool isComplete = false; + Image defaultAvatar(double size) => + Image.asset(('assets/icon_user.png'), height: size); + + CancelToken avatarCancelToken = CancelToken(); Future _buildQuery(_pubkey) async { var queryGetAvatar = json.encode({ @@ -61,45 +64,95 @@ class CesiumPlusProvider with ChangeNotifier { Future getName(String _pubkey) async { String _name; + if (g1WalletsBox.get(_pubkey).csName != null) { + return g1WalletsBox.get(_pubkey).csName; + } + List queryOptions = await _buildQuery(_pubkey); - final response = await http.post((Uri.parse(queryOptions[0])), - body: queryOptions[1], headers: queryOptions[2]); - final responseJson = json.decode(response.body); - if (responseJson['hits']['hits'].toString() == '[]') { + + var dio = Dio(); + Response response; + try { + response = await dio.post( + queryOptions[0], + data: queryOptions[1], + options: Options( + headers: queryOptions[2], + sendTimeout: 3000, + receiveTimeout: 5000, + ), + ); + // response = await http.post((Uri.parse(queryOptions[0])), + // body: queryOptions[1], headers: queryOptions[2]); + } catch (e) { + log.e(e); + } + + if (response.data['hits']['hits'].toString() == '[]') { return ''; } final bool _nameExist = - responseJson['hits']['hits'][0]['_source'].containsKey("title"); + response.data['hits']['hits'][0]['_source'].containsKey("title"); if (!_nameExist) { return ''; } - _name = responseJson['hits']['hits'][0]['_source']['title']; + _name = response.data['hits']['hits'][0]['_source']['title']; + + g1WalletsBox.get(_pubkey).csName = _name; return _name; } - Future getAvatar(String _pubkey) async { + Future getAvatar(String _pubkey, double size) async { + if (g1WalletsBox.get(_pubkey).avatar != null) { + return g1WalletsBox.get(_pubkey).avatar; + } + var dio = Dio(); + + // log.d(_pubkey); + List queryOptions = await _buildQuery(_pubkey); - final response = await http.post((Uri.parse(queryOptions[0])), - body: queryOptions[1], headers: queryOptions[2]); - final responseJson = json.decode(response.body); - if (responseJson['hits']['hits'].toString() == '[]') { - return [File(appPath.path + '/default_avatar.png')]; + + Response response; + try { + response = await dio + .post(queryOptions[0], + data: queryOptions[1], + options: Options( + headers: queryOptions[2], + sendTimeout: 4000, + receiveTimeout: 15000, + ), + cancelToken: avatarCancelToken) + .timeout( + const Duration(seconds: 15), + ); + // response = await http.post((Uri.parse(queryOptions[0])), + // body: queryOptions[1], headers: queryOptions[2]); + } catch (e) { + log.e(e); } - final bool avatarExist = - responseJson['hits']['hits'][0]['_source'].containsKey("avatar"); - if (!avatarExist) { - return [File(appPath.path + '/default_avatar.png')]; + + if (response.data['hits']['hits'].toString() == '[]' || + !response.data['hits']['hits'][0]['_source'].containsKey("avatar")) { + return defaultAvatar(size); } + final _avatar = - responseJson['hits']['hits'][0]['_source']['avatar']['_content']; + response.data['hits']['hits'][0]['_source']['avatar']['_content']; var avatarFile = - File('${(await getTemporaryDirectory()).path}/avatar$iAvatar.png'); + File('${(await getTemporaryDirectory()).path}/avatar_$_pubkey.png'); await avatarFile.writeAsBytes(base64.decode(_avatar)); - iAvatar++; - isComplete = true; - return [avatarFile]; + final finalAvatar = Image.file( + avatarFile, + height: size, + fit: BoxFit.fitWidth, + ); + + g1WalletsBox.get(_pubkey).avatar = finalAvatar; + + return finalAvatar; } } diff --git a/lib/models/g1_wallets_list.dart b/lib/models/g1_wallets_list.dart new file mode 100644 index 0000000..98fef2b --- /dev/null +++ b/lib/models/g1_wallets_list.dart @@ -0,0 +1,74 @@ +import 'package:flutter/material.dart'; +import 'package:hive_flutter/hive_flutter.dart'; + +part 'g1_wallets_list.g.dart'; + +@HiveType(typeId: 2) +class G1WalletsList { + @HiveField(0) + String pubkey; + + @HiveField(1) + double balance; + + @HiveField(3) + Id id; + + @HiveField(4) + Image avatar; + + @HiveField(5) + String username; + + @HiveField(6) + String csName; + + @HiveField(7) + bool isMembre; + + G1WalletsList({ + this.pubkey, + this.balance, + this.id, + this.avatar, + this.username, + this.csName, + this.isMembre, + }); + + G1WalletsList.fromJson(Map json) { + pubkey = json['pubkey']; + balance = json['balance']; + id = json['id'] != null ? Id.fromJson(json['id']) : null; + } + + Map toJson() { + final Map data = {}; + data['pubkey'] = pubkey; + data['balance'] = balance; + if (id != null) { + data['id'] = id.toJson(); + } + return data; + } +} + +@HiveType(typeId: 3) +class Id { + bool isMember; + String username; + + Id({this.isMember, this.username}); + + Id.fromJson(Map json) { + isMember = json['isMember']; + username = json['username']; + } + + Map toJson() { + final Map data = {}; + data['isMember'] = isMember; + data['username'] = username; + return data; + } +} diff --git a/lib/models/g1_wallets_list.g.dart b/lib/models/g1_wallets_list.g.dart new file mode 100644 index 0000000..266daed --- /dev/null +++ b/lib/models/g1_wallets_list.g.dart @@ -0,0 +1,90 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +// ignore_for_file: unused_local_variable + +part of 'g1_wallets_list.dart'; + +// ************************************************************************** +// TypeAdapterGenerator +// ************************************************************************** + +class G1WalletsListAdapter extends TypeAdapter { + @override + final int typeId = 2; + + @override + G1WalletsList read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = { + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + 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, + ); + } + + @override + void write(BinaryWriter writer, G1WalletsList obj) { + writer + ..writeByte(7) + ..writeByte(0) + ..write(obj.pubkey) + ..writeByte(1) + ..write(obj.balance) + ..writeByte(3) + ..write(obj.id) + ..writeByte(4) + ..write(obj.avatar) + ..writeByte(5) + ..write(obj.username) + ..writeByte(6) + ..write(obj.csName) + ..writeByte(7) + ..write(obj.isMembre); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is G1WalletsListAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} + +class IdAdapter extends TypeAdapter { + @override + final int typeId = 3; + + @override + Id read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = { + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return Id(); + } + + @override + void write(BinaryWriter writer, Id obj) { + writer.writeByte(0); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is IdAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} diff --git a/lib/models/generate_wallets.dart b/lib/models/generate_wallets.dart index 1266dfc..c75e255 100644 --- a/lib/models/generate_wallets.dart +++ b/lib/models/generate_wallets.dart @@ -5,6 +5,7 @@ import 'package:flutter/foundation.dart'; 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:pdf/pdf.dart'; @@ -39,6 +40,21 @@ class GenerateWalletsProvider with ChangeNotifier { bool canImport = false; bool isPinChanged = false; + // Import Chest + TextEditingController cellController0 = TextEditingController(); + TextEditingController cellController1 = TextEditingController(); + TextEditingController cellController2 = TextEditingController(); + TextEditingController cellController3 = TextEditingController(); + TextEditingController cellController4 = TextEditingController(); + TextEditingController cellController5 = TextEditingController(); + TextEditingController cellController6 = TextEditingController(); + TextEditingController cellController7 = TextEditingController(); + TextEditingController cellController8 = TextEditingController(); + TextEditingController cellController9 = TextEditingController(); + TextEditingController cellController10 = TextEditingController(); + TextEditingController cellController11 = TextEditingController(); + bool isFirstTimeSentenceComplete = true; + Future storeHDWChest( NewWallet _wallet, String _name, BuildContext context) async { int chestNumber = 0; @@ -140,7 +156,7 @@ class GenerateWalletsProvider with ChangeNotifier { Future generateMnemonic() async { try { generatedMnemonic = await DubpRust.genMnemonic(language: Language.french); - actualWallet = await generateWallet(generatedMnemonic); + actualWallet = await generateWallet(generatedMnemonic, isImport: false); walletIsGenerated = true; } catch (e) { log.e(e); @@ -148,7 +164,8 @@ class GenerateWalletsProvider with ChangeNotifier { return generatedMnemonic; } - Future generateWallet(generatedMnemonic) async { + Future generateWallet(String generatedMnemonic, + {@required bool isImport}) async { try { actualWallet = await DubpRust.genWalletFromMnemonic( language: Language.french, @@ -159,8 +176,10 @@ class GenerateWalletsProvider with ChangeNotifier { log.e(e); } - mnemonicController.text = generatedMnemonic; - pin.text = actualWallet.pin; + if (!isImport) { + mnemonicController.text = generatedMnemonic; + pin.text = actualWallet.pin; + } // notifyListeners(); return actualWallet; @@ -288,15 +307,9 @@ class GenerateWalletsProvider with ChangeNotifier { notifyListeners(); } - void resetImportView() { - cesiumID.text = ''; - cesiumPWD.text = ''; - cesiumPubkey.text = ''; - pin.text = ''; - canImport = false; - isPinChanged = false; - isCesiumIDVisible = false; - isCesiumPWDVisible = false; + void resetCesiumImportView() { + cesiumID.text = cesiumPWD.text = cesiumPubkey.text = pin.text = ''; + canImport = isPinChanged = isCesiumIDVisible = isCesiumPWDVisible = false; actualWallet = null; notifyListeners(); } @@ -315,6 +328,83 @@ class GenerateWalletsProvider with ChangeNotifier { return _wordsList; } + bool isBipWord(String word) { + notifyListeners(); + + // Needed for bad encoding of UTF-8 + word = word.replaceAll('é', 'é'); + word = word.replaceAll('è', 'è'); + return bip39Words.contains(word); + } + + bool isBipWordsList(List words) { + bool isValid = true; + for (String word in words) { + // Needed for bad encoding of UTF-8 + word = word.replaceAll('é', 'é'); + word = word.replaceAll('è', 'è'); + if (!bip39Words.contains(word)) { + isValid = false; + } + } + return isValid; + } + + void resetImportView() { + cellController0.text = cellController1.text = cellController2.text = + cellController3.text = cellController4.text = cellController5.text = + cellController6.text = cellController7.text = cellController8.text = + cellController9.text = + cellController10.text = cellController11.text = ''; + isFirstTimeSentenceComplete = true; + notifyListeners(); + } + + bool isSentenceComplete(BuildContext context) { + if (isBipWordsList( + [ + cellController0.text, + cellController1.text, + cellController2.text, + cellController3.text, + cellController4.text, + cellController5.text, + cellController6.text, + cellController7.text, + cellController8.text, + cellController9.text, + cellController10.text, + cellController11.text + ], + )) { + if (isFirstTimeSentenceComplete) { + FocusScope.of(context).unfocus(); + } + isFirstTimeSentenceComplete = false; + return true; + } else { + return false; + } + } + + 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}'; + + // Needed for bad encoding of UTF-8 + inputMnemonic = inputMnemonic.replaceAll('é', 'é'); + inputMnemonic = inputMnemonic.replaceAll('è', 'è'); + + NewWallet generatedWallet = + await generateWallet(inputMnemonic, isImport: true); + + if (generatedWallet == null) { + return false; + } else { + return true; + } + } + void reloadBuild() { notifyListeners(); } diff --git a/lib/models/home.dart b/lib/models/home.dart index 69fe956..f661211 100644 --- a/lib/models/home.dart +++ b/lib/models/home.dart @@ -8,7 +8,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'dart:async'; import 'package:gecko/globals.dart'; -import 'package:gecko/screens/history.dart'; +import 'package:gecko/screens/old_history_pay.dart'; import 'package:gecko/screens/myWallets/wallets_home.dart'; import 'package:package_info/package_info.dart'; @@ -21,7 +21,8 @@ class HomeProvider with ChangeNotifier { Widget appBarExplorer = Text('Explorateur', style: TextStyle(color: Colors.grey[850])); - List currentTab = [HistoryScreen(), WalletsHome()]; + List currentTab = [OldHistoryScreen(), WalletsHome()]; + bool isFirstBuild = true; // AudioCache player = AudioCache(prefix: 'sounds/'); get currentIndex => _currentIndex; @@ -99,16 +100,6 @@ class HomeProvider with ChangeNotifier { return _endpoint; } - Future createDefaultAvatar() async { - File defaultAvatar = File(appPath.path + '/default_avatar.png'); - final bool isAvatarExist = await defaultAvatar.exists(); - if (!isAvatarExist) { - final byteData = await rootBundle.load('assets/icon_user.png'); - await defaultAvatar.writeAsBytes(byteData.buffer - .asUint8List(byteData.offsetInBytes, byteData.lengthInBytes)); - } - } - T getRandomElement(List list) { final random = Random(); var i = random.nextInt(list.length); @@ -139,6 +130,22 @@ 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/models/my_wallets.dart b/lib/models/my_wallets.dart index 6953108..e8a6305 100644 --- a/lib/models/my_wallets.dart +++ b/lib/models/my_wallets.dart @@ -71,8 +71,13 @@ class MyWalletsProvider with ChangeNotifier { await walletBox.clear(); await chestBox.clear(); await configBox.delete('defaultWallet'); + // await Future.delayed(const Duration(milliseconds: 50)); + // notifyListeners(); - Navigator.pop(context); + await Navigator.of(context).pushNamedAndRemoveUntil( + '/', + ModalRoute.withName('/'), + ); } return 0; } catch (e) { diff --git a/lib/models/queries.dart b/lib/models/queries.dart index 72ba0e9..ed47ac8 100644 --- a/lib/models/queries.dart +++ b/lib/models/queries.dart @@ -29,14 +29,12 @@ const String getHistory = r''' issuers comment outputs - writtenTime } sending { currency issuers comment outputs - writtenTime } } currentUd { @@ -62,3 +60,36 @@ const String getBalance = r''' } } '''; + +const String getWallets = r''' +query ($number: Int!, $cursor: String) { + wallets(pagination: {ord: ASC, pageSize: $number, cursor: $cursor}) { + pageInfo { + hasNextPage + endCursor + } + edges { + node { + script + balance { + amount + base + } + idty { + isMember + username + } + } + } + } +} +'''; + +const String getId = r''' +query ($pubkey: PubKeyGva!) { + idty(pubkey: $pubkey) { + isMember + username + } +} +'''; diff --git a/lib/models/search.dart b/lib/models/search.dart new file mode 100644 index 0000000..5fdbb61 --- /dev/null +++ b/lib/models/search.dart @@ -0,0 +1,80 @@ +import 'package:dio/dio.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:gecko/globals.dart'; +import 'package:gecko/models/g1_wallets_list.dart'; +import 'package:gecko/models/wallets_profiles.dart'; + +class SearchProvider with ChangeNotifier { + TextEditingController searchController = TextEditingController(); + List searchResult = []; + final cacheDuring = 20 * 60 * 1000; //First number is minutes + int cacheTime = 0; + + void rebuildWidget() { + notifyListeners(); + } + + Future searchBlockchain() async { + searchResult.clear(); + int searchTime = DateTime.now().millisecondsSinceEpoch; + WalletsProfilesProvider _walletProfiles = WalletsProfilesProvider('pubkey'); + + if (cacheTime + cacheDuring <= searchTime) { + g1WalletsBox.clear(); + // final url = Uri.parse('https://g1-stats.axiom-team.fr/data/forbes.json'); + // final response = await http.get(url); + + var dio = Dio(); + Response response; + try { + response = await dio.get( + 'https://g1-stats.axiom-team.fr/data/forbes.json', + options: Options( + sendTimeout: 5000, + receiveTimeout: 10000, + ), + ); + // response = await http.post((Uri.parse(queryOptions[0])), + // body: queryOptions[1], headers: queryOptions[2]); + } catch (e) { + log.e(e); + } + + List _listWallets = _parseG1Wallets(response.data); + Map _mapWallets = { + for (var e in _listWallets) e.pubkey: e + }; + + await g1WalletsBox.putAll(_mapWallets); + cacheTime = DateTime.now().millisecondsSinceEpoch; + } + + g1WalletsBox.toMap().forEach((key, value) { + if ((value.id != null && + value.id.username != null && + value.id.username + .toLowerCase() + .contains(searchController.text)) || + value.pubkey.contains(searchController.text)) { + searchResult.add(value); + return; + } + }); + + if (searchResult.isEmpty && + _walletProfiles.isPubkey(searchController.text)) { + searchResult = [G1WalletsList(pubkey: searchController.text)]; + } + + return searchResult; + } +} + +List _parseG1Wallets(var responseBody) { + final parsed = responseBody.cast>(); + + return parsed + .map((json) => G1WalletsList.fromJson(json)) + .toList(); +} diff --git a/lib/models/history.dart b/lib/models/wallets_profiles.dart similarity index 78% rename from lib/models/history.dart rename to lib/models/wallets_profiles.dart index 19a15fa..bb13f7c 100644 --- a/lib/models/history.dart +++ b/lib/models/wallets_profiles.dart @@ -2,14 +2,12 @@ import 'package:dubp/dubp.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:gecko/globals.dart'; -import 'package:gecko/models/home.dart'; import 'package:gecko/models/my_wallets.dart'; import 'package:gecko/models/wallet_data.dart'; -import 'package:gecko/screens/history.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'; @@ -17,13 +15,13 @@ import 'package:truncate/truncate.dart'; import 'package:crypto/crypto.dart'; import 'package:fast_base58/fast_base58.dart'; -class HistoryProvider with ChangeNotifier { +class WalletsProfilesProvider with ChangeNotifier { + WalletsProfilesProvider(this.pubkey); + String pubkey = ''; String pubkeyShort = ''; - HistoryProvider(this.pubkey); final TextEditingController outputPubkey = TextEditingController(); List transBC; - bool isFirstBuild = true; String fetchMoreCursor; Map pageInfo; bool isHistoryScreen = false; @@ -31,6 +29,9 @@ class HistoryProvider with ChangeNotifier { String rawSvg; TextEditingController payAmount = TextEditingController(); TextEditingController payComment = TextEditingController(); + num balance; + int nRepositories = 20; + int nPage = 1; Future scan(context) async { await Permission.camera.request(); @@ -41,9 +42,14 @@ class HistoryProvider with ChangeNotifier { log.e(e); return 'false'; } - if (barcode != null) { + if (barcode != null && isPubkey(barcode)) { outputPubkey.text = barcode; - isPubkey(context, barcode); + Navigator.push( + context, + MaterialPageRoute(builder: (context) { + return WalletViewScreen(pubkey: pubkey); + }), + ); } else { return 'false'; } @@ -56,10 +62,17 @@ class HistoryProvider with ChangeNotifier { WalletData defaultWallet = _myWalletModel.getDefaultWallet(currentChest); String dewif = chestBox.get(currentChest).dewif; + int derivation; + + if (chestBox.get(currentChest).isCesium) { + derivation = 0; + } else { + derivation = defaultWallet.derivation; + } try { await DubpRust.simplePaymentFromTransparentAccount( - accountIndex: defaultWallet.derivation, + accountIndex: derivation, amount: double.parse(payAmount.text), txComment: payComment.text, dewif: dewif, @@ -74,9 +87,7 @@ class HistoryProvider with ChangeNotifier { } } - String isPubkey(context, pubkey, {bool goHistory}) { - HomeProvider _homeProvider = - Provider.of(context, listen: false); + bool isPubkey(pubkey) { final RegExp regExp = RegExp( r'^[a-zA-Z0-9]+$', caseSensitive: false, @@ -86,36 +97,25 @@ class HistoryProvider with ChangeNotifier { if (regExp.hasMatch(pubkey) == true && pubkey.length > 42 && pubkey.length < 45) { - log.d("C'est une pubkey !!!"); + log.d("C'est une pubkey !"); this.pubkey = pubkey; - getShortPubkey(pubkey); + // getShortPubkey(pubkey); - outputPubkey.text = pubkey; + // outputPubkey.text = pubkey; - goHistory ??= false; + // Navigator.push( + // context, + // MaterialPageRoute(builder: (context) { + // return const WalletViewScreen(); + // }), + // ); + // notifyListeners(); - if (goHistory) { - isHistoryScreen = true; - historySwitchButtun = "Payer"; - } else { - isHistoryScreen = false; - historySwitchButtun = "Voir l'historique"; - } - - _homeProvider.handleSearchEnd(); - Navigator.push( - context, - MaterialPageRoute(builder: (context) { - return HistoryScreen(); - }), - ); - notifyListeners(); - - return pubkey; + return true; + } else { + return false; } - - return ''; } String getShortPubkey(String pubkey) { @@ -200,13 +200,25 @@ class HistoryProvider with ChangeNotifier { FetchMoreOptions checkQueryResult(result, opts, _pubkey) { final List blockchainTX = (result.data['txsHistoryBc']['both']['edges'] as List); + // final List mempoolTX = + // (result.data['txsHistoryMp']['receiving'] as List); pageInfo = result.data['txsHistoryBc']['both']['pageInfo']; - fetchMoreCursor = pageInfo['endCursor']; + if (fetchMoreCursor == null) nPage = 1; + + if (nPage == 1) { + nRepositories = 40; + } else if (nPage == 2) { + nRepositories = 100; + } + log.d(nPage); + log.d(nRepositories); + nPage++; + if (fetchMoreCursor != null) { opts = FetchMoreOptions( - variables: {'cursor': fetchMoreCursor}, + variables: {'cursor': fetchMoreCursor, 'number': nRepositories}, updateQuery: (previousResultData, fetchMoreResultData) { final List repos = [ ...previousResultData['txsHistoryBc']['both']['edges'] @@ -232,22 +244,6 @@ class HistoryProvider with ChangeNotifier { return opts; } - 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 resetdHistory() { outputPubkey.text = ''; notifyListeners(); @@ -260,6 +256,7 @@ class HistoryProvider with ChangeNotifier { 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)); @@ -279,4 +276,27 @@ class HistoryProvider with ChangeNotifier { String generateIdenticon(String _pubkey) { return Jdenticon.toSvg(_pubkey); } + + // Future getBalance(String _pubkey) async { + // final url = Uri.parse( + // '$endPointGVA?query={%20balance(script:%20%22$_pubkey%22)%20{%20amount%20base%20}%20}'); + // final response = await http.get(url); + // final result = json.decode(response.body); + + // if (result['data']['balance'] == null) { + // balance = 0.0; + // } else { + // balance = removeDecimalZero(result['data']['balance']['amount'] / 100); + // } + + // return balance; + // } + + Future getBalance(String _pubkey) async { + while (balance == null) { + await Future.delayed(const Duration(milliseconds: 50)); + } + + return balance; + } } diff --git a/lib/screens/avatar_fullscreen.dart b/lib/screens/avatar_fullscreen.dart new file mode 100644 index 0000000..8f833dc --- /dev/null +++ b/lib/screens/avatar_fullscreen.dart @@ -0,0 +1,54 @@ +import 'package:flutter/services.dart'; +import 'package:gecko/globals.dart'; +import 'package:flutter/material.dart'; +// import 'package:gecko/models/home.dart'; +// import 'package:provider/provider.dart'; + +// ignore: must_be_immutable +class AvatarFullscreen extends StatelessWidget { + TextEditingController tplController = TextEditingController(); + + AvatarFullscreen(this.avatar, {this.title, this.color, Key key}) + : super(key: key); + final Image avatar; + final String title; + final Color color; + + @override + Widget build(BuildContext context) { + SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); + // HomeProvider _homeProvider = Provider.of(context); + return Scaffold( + appBar: AppBar( + elevation: 0, + backgroundColor: color ?? Colors.black, + toolbarHeight: 60 * ratio, + leading: IconButton( + icon: Icon(Icons.arrow_back, color: orangeC), + onPressed: () { + Navigator.pop(context); + }), + title: SizedBox( + height: 22, + child: Text( + title ?? 'Photo de profil', + style: TextStyle(color: orangeC), + ), + )), + body: SafeArea( + child: SizedBox.expand( + child: Container( + color: color ?? Colors.black, + // alignment: Alignment.center, + // height: MediaQuery.of(context).size.height, + // width: MediaQuery.of(context).size.width, + child: Image( + image: avatar.image, + height: avatar.height, + fit: BoxFit.fitWidth), + ), + ), + ), + ); + } +} diff --git a/lib/screens/common_elements.dart b/lib/screens/common_elements.dart index b9f2654..bb36379 100644 --- a/lib/screens/common_elements.dart +++ b/lib/screens/common_elements.dart @@ -34,14 +34,15 @@ class CommonElements { 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, - )), + key: textKey, + text: TextSpan( + style: const TextStyle( + fontSize: 18.0, + color: Colors.black, + ), + children: text, + ), + ), ); } diff --git a/lib/screens/history.dart b/lib/screens/history.dart index 7701a56..d8a3fe1 100644 --- a/lib/screens/history.dart +++ b/lib/screens/history.dart @@ -1,124 +1,64 @@ -import 'dart:io'; import 'package:flutter/services.dart'; import 'package:gecko/globals.dart'; import 'package:gecko/models/cesium_plus.dart'; -import 'package:gecko/models/home.dart'; -import 'package:gecko/models/my_wallets.dart'; import 'package:gecko/models/queries.dart'; -import 'package:gecko/models/history.dart'; +import 'package:gecko/models/wallets_profiles.dart'; import 'package:flutter/material.dart'; import 'package:flutter/foundation.dart'; -import 'package:gecko/models/wallet_data.dart'; -import 'package:gecko/screens/myWallets/unlocking_wallet.dart'; +import 'package:gecko/screens/avatar_fullscreen.dart'; +import 'package:gecko/screens/wallet_view.dart'; import 'dart:ui'; import 'package:graphql_flutter/graphql_flutter.dart'; +import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; -import 'package:flutter_svg/flutter_svg.dart'; // ignore: must_be_immutable class HistoryScreen extends StatelessWidget with ChangeNotifier { - final TextEditingController _outputPubkey = TextEditingController(); - ScrollController scrollController = ScrollController(); - final nRepositories = 20; - // HistoryProvider _historyProvider; - final _formKey = GlobalKey(); - final FocusNode _pubkeyFocus = FocusNode(); - List cesiumData; + HistoryScreen({@required this.pubkey, this.avatar, this.username, Key key}) + : super(key: key); + final ScrollController scrollController = ScrollController(); final double avatarsSize = 80; + final String pubkey; + final String username; + final Image avatar; FetchMore fetchMore; FetchMoreOptions opts; - final GlobalKey _scaffoldKey = GlobalKey(); - HistoryScreen({Key key}) : super(key: key); + final GlobalKey _scaffoldKey = GlobalKey(); @override Widget build(BuildContext context) { SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); - HistoryProvider _historyProvider = Provider.of(context); - HomeProvider _homeProvider = Provider.of(context); - _outputPubkey.text = _historyProvider.pubkey; - log.i('Build pubkey : ' + _historyProvider.pubkey); + WalletsProfilesProvider _historyProvider = + Provider.of(context, listen: false); + CesiumPlusProvider _cesiumPlusProvider = + Provider.of(context, listen: false); + log.i('Build pubkey : ' + pubkey); WidgetsBinding.instance.addPostFrameCallback((_) {}); + _historyProvider.balance = _historyProvider.transBC = null; + return Scaffold( key: _scaffoldKey, appBar: AppBar( + elevation: 0, toolbarHeight: 60 * ratio, - title: _homeProvider.appBarExplorer, - actions: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: IconButton( - icon: _homeProvider.searchIcon, - color: Colors.grey[850], - onPressed: () { - if (_homeProvider.searchIcon.icon == Icons.search) { - _homeProvider.searchIcon = Icon( - Icons.close, - color: Colors.grey[850], - ); - _homeProvider.appBarExplorer = TextField( - autofocus: true, - controller: _homeProvider.searchQuery, - onChanged: (text) { - log.d("Clé tappé: $text"); - final String searchResult = - _historyProvider.isPubkey(context, text); - if (searchResult != '') { - _homeProvider.currentIndex = 0; - } - }, - style: TextStyle( - color: Colors.grey[850], - ), - decoration: InputDecoration( - prefixIcon: - Icon(Icons.search, color: Colors.grey[850]), - hintText: "Rechercher ...", - hintStyle: TextStyle(color: Colors.grey[850])), - ); - _homeProvider.handleSearchStart(); - } else { - _homeProvider.handleSearchEnd(); - } - })) - ], - backgroundColor: const Color(0xffFFD58D), - ), - floatingActionButton: SizedBox( - height: 80.0, - width: 80.0, - child: FittedBox( - child: FloatingActionButton( - heroTag: "buttonScan", - onPressed: () async { - await _historyProvider.scan(context); - }, - child: SizedBox( - height: 40.0, - width: 40.0, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 3), - child: Image.asset('assets/qrcode-scan.png'))), - backgroundColor: - floattingYellow, //smoothYellow, //Color.fromARGB(500, 204, 255, 255), - ), + title: const SizedBox( + height: 22, + child: Text('Historique des transactions'), ), ), body: Column(children: [ - const SizedBox(height: 0), - if (_historyProvider.pubkey != '') - historyQuery(context, _historyProvider), + headerProfileView(context, _historyProvider, _cesiumPlusProvider), + historyQuery(context, _cesiumPlusProvider), ])); } - Widget historyQuery(context, HistoryProvider _historyProvider) { - _pubkeyFocus.unfocus(); - // HistoryProvider _historyProvider = Provider.of(context); - CesiumPlusProvider _cesiumPlusProvider = - Provider.of(context); - bool _isFirstExec = true; + Widget historyQuery(context, CesiumPlusProvider _cesiumPlusProvider) { + WalletsProfilesProvider _historyProvider = + Provider.of(context, listen: true); + return Expanded( child: Column( mainAxisAlignment: MainAxisAlignment.start, @@ -128,8 +68,8 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier { options: QueryOptions( document: gql(getHistory), variables: { - 'pubkey': _historyProvider.pubkey, - 'number': nRepositories, + 'pubkey': pubkey, + 'number': 10, 'cursor': null }, ), @@ -146,182 +86,47 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier { SizedBox(height: 50), Text( "Aucun noeud GVA valide n'a pu être trouvé.\nVeuillez réessayer ultérieurement.", - style: TextStyle(fontSize: 17.0), + style: TextStyle(fontSize: 18), + ) + ]); + } else if (result.data == null) { + return Column(children: const [ + SizedBox(height: 50), + Text( + "Aucune donnée à afficher.", + style: TextStyle(fontSize: 18), ) ]); } - if (result.data == null && result.exception.toString() == null) { - return const Text('Aucune donnée à afficher.'); - } - - num balance; - if (result.data['balance'] == null) { - balance = 0.0; + _historyProvider.balance = 0.0; } else { - balance = _historyProvider + _historyProvider.balance = _historyProvider .removeDecimalZero(result.data['balance']['amount'] / 100); } - opts = _historyProvider.checkQueryResult( - result, opts, _outputPubkey.text); - - // _historyProvider.transBC = null; + if (result.isNotLoading) { + // log.d(result.data); + opts = _historyProvider.checkQueryResult(result, opts, pubkey); + } // Build history list return NotificationListener( child: Builder( - builder: (context) => Expanded( - child: ListView( - key: const Key('listTransactions'), - controller: scrollController, - children: [ - const SizedBox(height: 20), - if (_historyProvider.pubkey != '') - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - if (_isFirstExec) - Container( - padding: const EdgeInsets.fromLTRB( - 20, 0, 30, 0), - child: FutureBuilder( - future: - _cesiumPlusProvider.getAvatar( - _historyProvider.pubkey), - initialData: [ - File(appPath.path + - '/default_avatar.png') - ], - builder: (BuildContext context, - AsyncSnapshot _avatar) { - cesiumData = _avatar.data; - // _cesiumPlusProvider.isComplete = true; - if (_avatar.connectionState != - ConnectionState.done) { - return Image.file( - File(appPath.path + - '/default_avatar.png'), - height: avatarsSize); - } - if (_avatar.hasError) { - return Image.file( - File(appPath.path + - '/default_avatar.png'), - height: avatarsSize); - } - if (_avatar.hasData) { - return SingleChildScrollView( - padding: - const EdgeInsets.all( - 0.0), - child: Image.file( - _avatar.data[0], - height: avatarsSize)); - } - return Image.file( - File(appPath.path + - '/default_avatar.png'), - height: avatarsSize); - })), - GestureDetector( - key: const Key('copyPubkey'), - onTap: () { - Clipboard.setData(ClipboardData( - text: _historyProvider.pubkey)); - _historyProvider.snackCopyKey(context); - }, - child: Text( - _historyProvider.getShortPubkey( - _historyProvider.pubkey), - style: const TextStyle( - fontSize: 22, - fontWeight: FontWeight.w800, - fontFamily: 'Monospace')), - ), - Container( - padding: const EdgeInsets.fromLTRB( - 30, 0, 5, 0), // .only(right: 15), - child: Card( - child: Column( - children: [ - SvgPicture.string( - _historyProvider - .generateIdenticon( - _historyProvider - .pubkey), - fit: BoxFit.contain, - height: 64, - width: 64, - ), - ], - ), - )), - const SizedBox(width: 0) - ]), - if (_isFirstExec) - Row( - mainAxisAlignment: - MainAxisAlignment.spaceAround, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Container( - padding: const EdgeInsets.fromLTRB( - 0, 0, 0, 0), - // padding: const EdgeInsets., - child: FutureBuilder( - future: _cesiumPlusProvider.getName( - _historyProvider.pubkey), - initialData: '...', - builder: (context, snapshot) { - return Text(snapshot.data ?? '-', - style: const TextStyle( - fontSize: 20)); - })) - ]), - const SizedBox(height: 18), - if (_isFirstExec) - Container( - padding: - const EdgeInsets.fromLTRB(0, 0, 0, 0), - child: Text(balance.toString() + ' Ğ1', - textAlign: TextAlign.center, - style: const TextStyle(fontSize: 18.0))), - const SizedBox(height: 20), - ElevatedButton( - key: const Key('switchPayHistory'), - style: ElevatedButton.styleFrom( - elevation: 1, - primary: Colors.grey[50], // background - onPrimary: Colors.black, // foreground - ), - onPressed: () { - _historyProvider.switchProfileView(); - }, - child: Text( - _historyProvider.historySwitchButtun, - style: TextStyle( - fontSize: 15, color: orangeC))), - // const Divider( - // color: Colors.grey, - // height: 5, - // thickness: 0.5, - // indent: 0, - // endIndent: 0, - // ), - _historyProvider.isHistoryScreen - ? historyView(context, result) - : payView(context, _historyProvider), - ], - ))), + builder: (context) => Expanded( + child: ListView( + key: const Key('listTransactions'), + controller: scrollController, + children: [historyView(context, result)], + ), + ), + ), onNotification: (t) { if (t is ScrollEndNotification && scrollController.position.pixels >= - scrollController.position.maxScrollExtent * 0.7) { + scrollController.position.maxScrollExtent * 0.7 && + _historyProvider.pageInfo['hasPreviousPage']) { fetchMore(opts); } return true; @@ -332,125 +137,28 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier { )); } - Widget payView(context, HistoryProvider _historyProvider) { - MyWalletsProvider _myWalletProvider = MyWalletsProvider(); - WalletData defaultWallet = - _myWalletProvider.getDefaultWallet(configBox.get('currentChest')); - - return Stack( - clipBehavior: Clip.hardEdge, - children: [ - Form( - key: _formKey, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - const SizedBox(height: 20), - const Text('Commentaire:', style: TextStyle(fontSize: 20.0)), - Padding( - padding: const EdgeInsets.all(8.0), - child: TextField( - controller: _historyProvider.payComment, - maxLines: 2, - textAlign: TextAlign.center, - decoration: const InputDecoration(), - style: const TextStyle( - fontSize: 22, - color: Colors.black, - fontWeight: FontWeight.bold))), - const SizedBox(height: 20), - const Text('Montant (DU/Ğ1):', style: TextStyle(fontSize: 20.0)), - Padding( - padding: const EdgeInsets.all(8.0), - child: TextFormField( - style: const TextStyle(fontSize: 22), - controller: _historyProvider.payAmount, - textAlign: TextAlign.center, - maxLines: 1, - keyboardType: TextInputType.number, - decoration: InputDecoration( - contentPadding: const EdgeInsets.symmetric( - vertical: 25.0, horizontal: 10.0), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(10.0)), - ), - inputFormatters: [ - FilteringTextInputFormatter.allow(RegExp(r'(^\d*\.?\d*)')) - ], - ), - ), - Padding( - padding: const EdgeInsets.only(top: 15), - child: OutlinedButton( - style: OutlinedButton.styleFrom( - side: BorderSide(width: 2, color: orangeC)), - onPressed: () { - // if (_formKey.currentState.validate()) { - // _formKey.currentState.save(); - // } - // _historyProvider.pay(payAmount.text, payComment.text); - Navigator.push(context, - MaterialPageRoute(builder: (context) { - return UnlockingWallet( - wallet: defaultWallet, action: "pay"); - })); - }, - child: Padding( - padding: const EdgeInsets.all(12), - child: Text("PAYER", - style: TextStyle( - fontSize: 25, color: Colors.grey[850]))), - )) - ], - ), - ), - ], - ); - } - Widget historyView(context, result) { - HistoryProvider _historyProvider = Provider.of(context); - int keyID = 0; + WalletsProfilesProvider _historyProvider = + Provider.of(context, listen: false); return _historyProvider.transBC == null - ? const Text('Aucune transaction à afficher.') + ? Column(children: const [ + SizedBox(height: 50), + Text( + "Aucune transaction à afficher.", + style: TextStyle(fontSize: 18), + ) + ]) : Column(children: [ - for (var repository in _historyProvider.transBC) - Padding( - padding: const EdgeInsets.symmetric(horizontal: 5.0), - child: ListTile( - key: Key('transaction${keyID++}'), - contentPadding: const EdgeInsets.all(5.0), - leading: Text(repository[1].toString(), - style: TextStyle( - fontSize: 12, - color: Colors.grey[800], - fontWeight: FontWeight.w700), - textAlign: TextAlign.center), - title: Text(repository[3], - style: const TextStyle( - fontSize: 15.0, fontFamily: 'Monospace'), - textAlign: TextAlign.center), - subtitle: Text(repository[6] != '' ? repository[6] : '-', - style: const TextStyle(fontSize: 12.0), - textAlign: TextAlign.center), - trailing: Text("${repository[4]} Ğ1", - style: const TextStyle(fontSize: 14.0), - textAlign: TextAlign.justify), - dense: true, - isThreeLine: false, - onTap: () { - // this._outputPubkey.text = repository[2]; - _historyProvider.isPubkey(context, repository[2]); - })), - if (result.isLoading) + getTransactionTile(context, _historyProvider), + if (result.isLoading && + _historyProvider.pageInfo['hasPreviousPage']) Row( mainAxisAlignment: MainAxisAlignment.center, children: const [ CircularProgressIndicator(), ], ), - // if (_historyProvider.isTheEnd) // What I did before ... if (!_historyProvider.pageInfo['hasPreviousPage']) Column( children: const [ @@ -463,4 +171,384 @@ class HistoryScreen extends StatelessWidget with ChangeNotifier { ) ]); } + + Widget getTransactionTile( + BuildContext context, WalletsProfilesProvider _historyProvider) { + CesiumPlusProvider _cesiumPlusProvider = + Provider.of(context, listen: false); + int keyID = 0; + String dateDelimiter; + String lastDateDelimiter; + const double _avatarSize = 200; + + bool isTody = false; + bool isYesterday = false; + bool isThisWeek = false; + + const Map monthsInYear = { + 1: "Janvier", + 2: "Février", + 3: "Mars", + 4: "Avril", + 5: "Mai", + 6: "Juin", + 7: "Juillet", + 8: "Aout", + 9: "Septembre", + 10: "Octobre", + 11: "Novembre", + 12: "Décembre" + }; + + return Column( + children: _historyProvider.transBC.map((repository) { + DateTime now = DateTime.now(); + DateTime date = DateTime.fromMillisecondsSinceEpoch(repository[0] * 1000); + + String dateForm; + if ({4, 10, 11, 12}.contains(date.month)) { + dateForm = "${date.day} ${monthsInYear[date.month].substring(0, 3)}."; + } else if ({1, 2, 7, 9}.contains(date.month)) { + dateForm = "${date.day} ${monthsInYear[date.month].substring(0, 4)}."; + } else { + dateForm = "${date.day} ${monthsInYear[date.month]}"; + } + + int weekNumber(DateTime date) { + int dayOfYear = int.parse(DateFormat("D").format(date)); + return ((dayOfYear - date.weekday + 10) / 7).floor(); + } + + if (DateTime(date.year, date.month, date.day) == + DateTime(now.year, now.month, now.day) && + !isTody) { + dateDelimiter = lastDateDelimiter = "Aujourd'hui"; + isTody = true; + } else if (DateTime(date.year, date.month, date.day) == + DateTime(now.year, now.month, now.day - 1) && + !isYesterday) { + dateDelimiter = lastDateDelimiter = "Hier"; + isYesterday = true; + } else if (weekNumber(date) == weekNumber(now) && + date.year == now.year && + lastDateDelimiter != "Cette semaine" && + DateTime(date.year, date.month, date.day) != + DateTime(now.year, now.month, now.day - 1) && + !isThisWeek) { + dateDelimiter = lastDateDelimiter = "Cette semaine"; + isThisWeek = true; + } else if (lastDateDelimiter != monthsInYear[date.month] && + lastDateDelimiter != "${monthsInYear[date.month]} ${date.year}" && + DateTime(date.year, date.month, date.day) != + DateTime(now.year, now.month, now.day) && + DateTime(date.year, date.month, date.day) != + DateTime(now.year, now.month, now.day - 1) && + !(weekNumber(date) == weekNumber(now) && date.year == now.year)) { + if (date.year == now.year) { + dateDelimiter = lastDateDelimiter = monthsInYear[date.month]; + } else { + dateDelimiter = + lastDateDelimiter = "${monthsInYear[date.month]} ${date.year}"; + } + } else { + dateDelimiter = null; + } + + return Column(children: [ + if (dateDelimiter != null) + Padding( + padding: const EdgeInsets.symmetric(vertical: 30), + child: Text( + dateDelimiter, + style: TextStyle( + fontSize: 23, color: orangeC, fontWeight: FontWeight.w300), + ), + ), + Padding( + padding: const EdgeInsets.only(right: 0), + child: + // Row(children: [Column(children: [],)],) + ListTile( + key: Key('transaction${keyID++}'), + contentPadding: const EdgeInsets.only( + left: 20, right: 30, top: 15, bottom: 15), + leading: g1WalletsBox.get(repository[2])?.avatar == null + ? FutureBuilder( + future: _cesiumPlusProvider.getAvatar( + repository[2], _avatarSize), + builder: (BuildContext context, + AsyncSnapshot _avatar) { + if (_avatar.connectionState != + ConnectionState.done || + _avatar.hasError) { + return Stack(children: [ + _cesiumPlusProvider.defaultAvatar(_avatarSize), + Positioned( + top: 8, + right: 0, + width: 12, + height: 12, + child: CircularProgressIndicator( + strokeWidth: 1, + color: orangeC, + ), + ), + ]); + } + if (_avatar.hasData) { + g1WalletsBox.get(repository[2]).avatar = + _avatar.data; + return ClipOval(child: _avatar.data); + } else { + g1WalletsBox.get(repository[2]).avatar = + _cesiumPlusProvider + .defaultAvatar(repository[2]); + return _cesiumPlusProvider + .defaultAvatar(_avatarSize); + } + }) + : ClipOval( + child: Image( + image: g1WalletsBox.get(repository[2]).avatar.image, + height: _avatarSize, + ), + ), + title: Padding( + padding: EdgeInsets.only( + bottom: 5, top: repository[6] != '' ? 0 : 0), + child: Text(repository[3], + style: const TextStyle( + fontSize: 18, fontFamily: 'Monospace')), + ), + subtitle: RichText( + text: TextSpan( + style: TextStyle( + fontSize: 16, + color: Colors.grey[700], + ), + children: [ + TextSpan( + text: dateForm, + ), + if (repository[6] != '') + TextSpan( + text: ' · ', + style: TextStyle( + fontSize: 20, + color: Colors.grey[550], + ), + ), + TextSpan( + text: repository[6], + style: TextStyle( + fontStyle: FontStyle.italic, + color: Colors.grey[600], + ), + ), + ], + ), + ), + trailing: Text("${repository[4]} Ğ1", + style: const TextStyle( + fontSize: 18, fontWeight: FontWeight.w500), + textAlign: TextAlign.justify), + dense: false, + isThreeLine: false, + onTap: () { + _historyProvider.nPage = 1; + // _cesiumPlusProvider.avatarCancelToken.cancel('cancelled'); + Navigator.push( + context, + MaterialPageRoute(builder: (context) { + return WalletViewScreen(pubkey: repository[2]); + }), + ); + // Navigator.pop(context); + }), + ), + ]); + }).toList()); + } + + Widget headerProfileView( + BuildContext context, + WalletsProfilesProvider _historyProvider, + CesiumPlusProvider _cesiumPlusProvider) { + const double _avatarSize = 140; + + return Column(children: [ + Container( + height: 10, + color: yellowC, + ), + Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + yellowC, + const Color(0xFFE7811A), + ], + )), + child: Padding( + padding: const EdgeInsets.only(left: 30, right: 40), + child: Row(children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row(children: [ + GestureDetector( + key: const Key('copyPubkey'), + onTap: () { + Clipboard.setData(ClipboardData(text: pubkey)); + _historyProvider.snackCopyKey(context); + }, + child: Text( + _historyProvider.getShortPubkey(pubkey), + style: const TextStyle( + fontSize: 30, + fontWeight: FontWeight.w800, + ), + ), + ), + ]), + const SizedBox(height: 10), + if (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) { + return const Text(''); + } else { + return SizedBox( + width: 230, + child: Text( + result?.data['idty']['username'] ?? '', + style: const TextStyle( + fontSize: 27, + color: Color(0xff814C00), + ), + ), + ); + } + }, + ), + if (username != null) + SizedBox( + width: 230, + child: Text( + username, + style: const TextStyle( + fontSize: 27, + color: Color(0xff814C00), + ), + ), + ), + const SizedBox(height: 25), + ]), + FutureBuilder( + future: _historyProvider.getBalance(pubkey), + builder: + (BuildContext context, AsyncSnapshot _balance) { + if (_balance.connectionState != ConnectionState.done || + _balance.hasError) { + return const Text('...'); + } + return Text( + "${_balance.data.toString()} Ğ1", + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: 22, fontWeight: FontWeight.w500), + ); + }), + const SizedBox(height: 30), + ]), + const Spacer(), + Column(children: [ + if (avatar == null) + FutureBuilder( + future: _cesiumPlusProvider.getAvatar(pubkey, _avatarSize), + builder: + (BuildContext context, AsyncSnapshot _avatar) { + if (_avatar.connectionState != ConnectionState.done) { + return Stack(children: [ + ClipOval( + child: + _cesiumPlusProvider.defaultAvatar(_avatarSize), + ), + Positioned( + top: 15, + right: 45, + width: 51, + height: 51, + child: CircularProgressIndicator( + strokeWidth: 5, + color: orangeC, + ), + ), + ]); + } + if (_avatar.hasData) { + return GestureDetector( + key: const Key('openAvatar'), + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) { + return AvatarFullscreen(_avatar.data); + }), + ); + }, + child: ClipOval( + child: Image( + image: _avatar.data.image, + height: _avatarSize, + fit: BoxFit.cover, + ), + ), + ); + } + return ClipOval( + child: _cesiumPlusProvider.defaultAvatar(_avatarSize), + ); + }), + if (avatar != null) + GestureDetector( + key: const Key('openAvatar'), + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) { + return AvatarFullscreen(avatar); + }), + ); + }, + child: ClipOval( + child: Image( + image: avatar.image, + height: _avatarSize, + fit: BoxFit.cover, + ), + ), + ), + const SizedBox(height: 25), + ]), + ]), + ), + ), + ]); + } } diff --git a/lib/screens/home.dart b/lib/screens/home.dart index f305064..c79723e 100644 --- a/lib/screens/home.dart +++ b/lib/screens/home.dart @@ -1,13 +1,16 @@ +import 'package:bubble/bubble.dart'; import 'package:dubp/dubp.dart'; import 'package:gecko/globals.dart'; import 'package:gecko/models/chest_provider.dart'; -import 'package:gecko/models/history.dart'; -import 'package:gecko/models/home.dart'; +import 'package:gecko/models/wallets_profiles.dart'; import 'package:flutter/material.dart'; +import 'package:gecko/models/home.dart'; import 'package:gecko/models/my_wallets.dart'; import 'package:gecko/models/wallet_data.dart'; +import 'package:gecko/screens/myWallets/restore_chest.dart'; import 'package:gecko/screens/myWallets/unlocking_wallet.dart'; -import 'package:gecko/screens/onBoarding/0_no_keychain_found.dart'; +import 'package:gecko/screens/onBoarding/1.dart'; +import 'package:gecko/screens/search.dart'; import 'dart:ui'; import 'package:gecko/screens/settings.dart'; import 'package:flutter/services.dart'; @@ -19,21 +22,14 @@ class HomeScreen extends StatelessWidget { @override Widget build(BuildContext context) { SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); - HomeProvider _homeProvider = Provider.of(context); - HistoryProvider _historyProvider = Provider.of(context); - HistoryProvider _historyStatic = HistoryProvider(''); + // HomeProvider _homeProvider = Provider.of(context); MyWalletsProvider _myWalletProvider = Provider.of(context); Provider.of(context); + HomeProvider homeClass = HomeProvider(); final bool isWalletsExists = _myWalletProvider.checkIfWalletExist(); - // walletBox.toMap().forEach((key, value) { - // if (value.chest == 0) { - // print('$key: ${value.derivation}'); - // } - // }); - isTall = false; ratio = 1; if (MediaQuery.of(context).size.height >= 930) { @@ -86,95 +82,225 @@ class HomeScreen extends StatelessWidget { ], ), ), - appBar: AppBar( - toolbarHeight: 60 * ratio, - leading: Builder( - builder: (context) => IconButton( - key: const Key('drawerMenu'), - icon: Icon(Icons.menu, color: Colors.grey[850]), - onPressed: () => Scaffold.of(context).openDrawer(), - )), - title: _homeProvider.appBarTitle, - actions: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: IconButton( - key: const Key('searchIcon'), - icon: _homeProvider.searchIcon, - color: Colors.grey[850], - onPressed: () { - if (_homeProvider.searchIcon.icon == Icons.search) { - _homeProvider.searchIcon = Icon( - Icons.close, - color: Colors.grey[850], - ); - _homeProvider.appBarTitle = TextField( - key: const Key('searchInput'), - autofocus: true, - controller: _homeProvider.searchQuery, - onChanged: (text) { - log.d("Clé tappé: $text"); - final String searchResult = - _historyProvider.isPubkey(context, text); - if (searchResult != '') { - _homeProvider.currentIndex = 0; - } - }, - style: TextStyle( - color: Colors.grey[850], - ), - decoration: InputDecoration( - prefixIcon: - Icon(Icons.search, color: Colors.grey[850]), - hintText: "Rechercher ...", - hintStyle: TextStyle(color: Colors.grey[850])), - ); - _homeProvider.handleSearchStart(); - } else { - _homeProvider.handleSearchEnd(); - } - })) - ], - backgroundColor: const Color(0xffFFD58D), - ), backgroundColor: const Color(0xffF9F9F1), body: Builder( builder: (ctx) => StatefulWrapper( - onInit: () { - WidgetsBinding.instance.addPostFrameCallback((_) { - DubpRust.setup(); - _historyStatic.snackNode(ctx); - }); - }, + onInit: () { + WidgetsBinding.instance.addPostFrameCallback((_) { + DubpRust.setup(); + if (isWalletsExists) homeClass.snackNode(ctx); + }); + }, + child: isWalletsExists ? geckHome(context) : welcomeHome(context) + // bottomNavigationBar: BottomNavigationBar( + // backgroundColor: backgroundColor, + // fixedColor: Colors.grey[850], + // unselectedItemColor: const Color(0xffBD935C), + // type: BottomNavigationBarType.fixed, + // onTap: (index) { + // _homeProvider.currentIndex = index; + // }, + // currentIndex: _homeProvider.currentIndex, + // items: [ + // BottomNavigationBarItem( + // icon: Image.asset('assets/block-space-disabled.png', height: 26), + // activeIcon: Image.asset('assets/blockchain.png', height: 26), + // label: 'Explorateur', + // ), + // const BottomNavigationBarItem( + // icon: Icon(Icons.lock), + // label: 'Mes portefeuilles', + // ), + // ], + // ), + ), + ), + ); + } +} + +Widget geckHome(context) { + MyWalletsProvider _myWalletProvider = Provider.of(context); + Provider.of(context); + + WalletsProfilesProvider _historyProvider = + Provider.of(context); + final double statusBarHeight = MediaQuery.of(context).padding.top; + return Container( + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage("assets/home/background.jpg"), + fit: BoxFit.cover, + ), + ), + child: + Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + Stack(children: [ + Positioned( + top: statusBarHeight + 10, + left: 15, + child: Builder( + builder: (context) => IconButton( + key: const Key('drawerMenu'), + icon: const Icon( + Icons.menu, + color: Colors.white, + size: 35, + ), + onPressed: () => Scaffold.of(context).openDrawer(), + ), + ), + ), + const Align( + child: + Image(image: AssetImage('assets/home/header.png'), height: 210), + ), + ]), + Padding( + padding: EdgeInsets.only(top: 15 * ratio), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: const [ + Text( + "y'a pas de lézard ;-)", + 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, + ), + ], + ), + ) + ]), + ), + Expanded( + flex: 1, + child: Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Colors.transparent, + Colors.black.withOpacity(0.9), + ], + ), + ), child: Column(children: [ + const Spacer(), + Row(mainAxisAlignment: MainAxisAlignment.center, children: [ + Column(children: [ + Container( + child: ClipOval( + child: Material( + color: orangeC, // button color + child: InkWell( + child: const Padding( + padding: EdgeInsets.all(18), + child: Image( + image: AssetImage('assets/home/loupe.png'), + height: 70), + ), + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) { + return const SearchScreen(); + }), + ); + }), + ), + ), + decoration: const BoxDecoration( + shape: BoxShape.circle, + color: Colors.black, + boxShadow: [ + BoxShadow( + blurRadius: 2, + offset: Offset(1, 1.5), + spreadRadius: 0.5) + ], + ), + ), + const SizedBox(height: 12), + const Text( + "Rechercher un\nportefeuille", + textAlign: TextAlign.center, + style: TextStyle( + color: Colors.white, + fontSize: 17, + fontWeight: FontWeight.w500), + ) + ]), + const SizedBox(width: 120), + Column(children: [ + Container( + child: ClipOval( + key: const Key('manageWallets'), + child: Material( + color: orangeC, // button color + child: InkWell( + child: const Padding( + padding: EdgeInsets.all(18), + child: Image( + image: AssetImage('assets/home/wallet.png'), + height: 75)), + onTap: () { + WalletData defaultWallet = + _myWalletProvider.getDefaultWallet( + configBox.get('currentChest')); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return UnlockingWallet( + wallet: defaultWallet, + action: "mywallets", + ); + }, + ), + ); + + // Navigator.pushNamed( + // context, '/mywallets'))); + }), + ), + ), + decoration: const BoxDecoration( + shape: BoxShape.circle, + color: Colors.black, + boxShadow: [ + BoxShadow( + blurRadius: 2, + offset: Offset(1, 1.5), + spreadRadius: 0.5) + ], + ), + ), + const SizedBox(height: 12), + const Text( + "Gérer mes\nportefeuilles", + textAlign: TextAlign.center, + style: TextStyle( + color: Colors.white, + fontSize: 17, + fontWeight: FontWeight.w500), + ) + ]) + ]), Padding( - padding: const EdgeInsets.only(top: 20), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: const [ - SizedBox(width: 7), - Image( - image: AssetImage('assets/icon/gecko_final.png'), - height: 180), - ]), - ), - Padding( - padding: const EdgeInsets.only(top: 15), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: const [ - Text( - "y'a pas de lézard !", - textAlign: TextAlign.center, - style: TextStyle( - color: Colors.black, - fontSize: 17, - fontStyle: FontStyle.italic), - ) - ]), - ), - Padding( - padding: EdgeInsets.only(top: isTall ? 100 : 60), + padding: const EdgeInsets.only(top: 40), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ @@ -182,15 +308,14 @@ class HomeScreen extends StatelessWidget { Container( child: ClipOval( child: Material( - color: const Color(0xffFFD58D), // button color + color: orangeC, // button color child: InkWell( - splashColor: orangeC, // inkwell color child: const Padding( - padding: EdgeInsets.all(22), + padding: EdgeInsets.all(18), child: Image( image: AssetImage( - 'assets/qrcode-scan.png'), - height: 60)), + 'assets/home/qrcode.png'), + height: 75)), onTap: () async { await _historyProvider.scan(context); }), @@ -198,157 +323,194 @@ class HomeScreen extends StatelessWidget { ), decoration: const BoxDecoration( shape: BoxShape.circle, - color: Colors.white, + color: Colors.black, boxShadow: [ BoxShadow( - color: Colors.grey, - blurRadius: 4.0, - offset: Offset(2.0, 2.5), + blurRadius: 2, + offset: Offset(1, 1.5), spreadRadius: 0.5) ], ), ), const SizedBox(height: 12), const Text( - "Payer par QR-Code", + "Scanner un\nQR code", textAlign: TextAlign.center, - style: TextStyle(color: Colors.black, fontSize: 16), + style: TextStyle( + color: Colors.white, + fontSize: 17, + fontWeight: FontWeight.w500), ) ]) ]), ), - Padding( - padding: const EdgeInsets.only(top: 50), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Column(children: [ - Container( - child: ClipOval( - child: Material( - color: const Color(0xffFFD58D), // button color - child: InkWell( - splashColor: orangeC, // inkwell color - child: const Padding( - padding: EdgeInsets.symmetric( - horizontal: 20, vertical: 16), - child: Image( - image: - AssetImage('assets/blockchain.png'), - height: 70)), - onTap: () { - // Navigator.push( - // context, - // MaterialPageRoute( - // builder: (context) { - // return TemplateScreen(); - // }), - // ); - }), - ), - ), - 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: 12), - const Text( - "Explorer\n", - textAlign: TextAlign.center, - style: TextStyle(color: Colors.black, fontSize: 16), - ) - ]), - const SizedBox(width: 140), - Column(children: [ - Container( - child: ClipOval( - key: const Key('manageWallets'), - child: Material( - color: const Color(0xffFFD58D), // button color - child: InkWell( - splashColor: orangeC, // inkwell color - child: const Padding( - padding: EdgeInsets.all(23), - child: Image( - image: AssetImage('assets/lock.png'), - height: 57)), - onTap: () { - WalletData defaultWallet = - _myWalletProvider.getDefaultWallet( - configBox.get('currentChest')); - isWalletsExists - ? Navigator.push(context, - MaterialPageRoute(builder: (context) { - return UnlockingWallet( - wallet: defaultWallet, - action: "mywallets", - ); - })) - - // Navigator.pushNamed( - // context, '/mywallets') - : Navigator.push(context, - MaterialPageRoute(builder: (context) { - return const NoKeyChainScreen(); - })); - }), - ), - ), - 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: 12), - const Text( - "Gérer mes\nportefeuilles", - textAlign: TextAlign.center, - style: TextStyle(color: Colors.black, fontSize: 16), - ) - ]) - ]), - ) + SizedBox(height: isTall ? 80 : 40) ]), - // bottomNavigationBar: BottomNavigationBar( - // backgroundColor: Color(0xffFFD58D), - // fixedColor: Colors.grey[850], - // unselectedItemColor: Color(0xffBD935C), - // type: BottomNavigationBarType.fixed, - // onTap: (index) { - // _homeProvider.currentIndex = index; - // }, - // currentIndex: _homeProvider.currentIndex, - // items: [ - // BottomNavigationBarItem( - // icon: Image.asset('assets/block-space-disabled.png', height: 26), - // activeIcon: Image.asset('assets/blockchain.png', height: 26), - // label: 'Explorateur', - // ), - // BottomNavigationBarItem( - // icon: Icon(Icons.lock), - // label: 'Mes portefeuilles', - // ), - // ], - // ), ), + ) + ]), + ); +} + +Widget welcomeHome(context) { + final double statusBarHeight = MediaQuery.of(context).padding.top; + + return Container( + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage("assets/home/background.jpg"), + fit: BoxFit.cover, ), - ); - } + ), + child: + Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + Stack(children: [ + Positioned( + top: statusBarHeight + 10, + left: 15, + child: Builder( + builder: (context) => IconButton( + key: const Key('drawerMenu'), + icon: const Icon( + Icons.menu, + color: Colors.white, + size: 35, + ), + onPressed: () => Scaffold.of(context).openDrawer(), + ), + ), + ), + const Align( + child: + Image(image: AssetImage('assets/home/header.png'), height: 210), + ), + ]), + 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, + ), + ], + ), + ) + ]), + ), + Expanded( + flex: 1, + child: Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Colors.transparent, + Colors.black.withOpacity(0.9), + ], + ), + ), + child: Center( + child: Column(children: [ + const Spacer(), + Row(children: [ + Expanded( + child: Stack(children: [ + const Padding( + padding: EdgeInsets.only(top: 55), + child: Image( + image: AssetImage('assets/home/gecko-bienvenue.png'), + height: 220, + ), + ), + Positioned( + left: 180, + child: bubbleSpeak("y'a pas de lézard !"), + ), + const Positioned( + left: 200, + top: 60, + child: Image( + image: AssetImage('assets/home/bout_de_bulle.png'), + ), + ), + ]), + ), + ]), + SizedBox( + width: 410, + height: 70, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + elevation: 4, + primary: orangeC, // background + onPrimary: Colors.white, // foreground + ), + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return OnboardingStepOne(); + }, + ), + ); + }, + child: const Text( + 'Créer un portefeuille', + style: + TextStyle(fontSize: 24, fontWeight: FontWeight.w600), + ), + ), + ), + SizedBox(height: 25 * ratio), + SizedBox( + width: 410, + height: 70, + child: OutlinedButton( + style: OutlinedButton.styleFrom( + side: BorderSide(width: 4, color: orangeC)), + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return const RestoreChest(); + }, + ), + ); + }, + child: Text( + "Restaurer mes portefeuilles", + style: TextStyle( + fontSize: 24, + color: orangeC, + fontWeight: FontWeight.w600), + ), + ), + ), + SizedBox(height: isTall ? 100 : 50) + ]), + ), + )) + ]), + ); } class StatefulWrapper extends StatefulWidget { @@ -374,3 +536,19 @@ class _StatefulWrapperState extends State { return widget.child; } } + +Widget bubbleSpeak(String text, {double long, Key textKey}) { + return Bubble( + padding: long == null + ? const BubbleEdges.all(20) + : BubbleEdges.symmetric(horizontal: long, vertical: 30), + elevation: 5, + color: Colors.white, + child: Text( + text, + key: textKey, + style: const TextStyle( + color: Colors.black, fontSize: 21, fontWeight: FontWeight.w400), + ), + ); +} diff --git a/lib/screens/myWallets/cesium_wallet_options.dart b/lib/screens/myWallets/cesium_wallet_options.dart index 1d8854d..ac7ffed 100644 --- a/lib/screens/myWallets/cesium_wallet_options.dart +++ b/lib/screens/myWallets/cesium_wallet_options.dart @@ -5,10 +5,11 @@ import 'package:flutter/material.dart'; import 'package:gecko/globals.dart'; import 'package:gecko/models/chest_data.dart'; import 'package:gecko/models/chest_provider.dart'; -import 'package:gecko/models/history.dart'; +import 'package:gecko/models/wallets_profiles.dart'; import 'package:gecko/models/my_wallets.dart'; import 'package:gecko/models/queries.dart'; import 'package:gecko/models/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'; @@ -17,336 +18,404 @@ import 'package:flutter/services.dart'; int _nbrLinesName = 1; bool _isNewNameValid = false; -Widget cesiumWalletOptions(BuildContext context, ChestData cesiumWallet, - MyWalletsProvider _myWalletProvider) { - SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); - WalletOptionsProvider _walletOptions = - Provider.of(context); - ChestProvider _chestProvider = - Provider.of(context, listen: false); - HistoryProvider _historyProvider = Provider.of(context); +class CesiumWalletOptions extends StatelessWidget { + const CesiumWalletOptions( + {Key key, Key keyMyWallets, @required this.cesiumWallet}) + : super(key: key); - final String shortPubkey = - _walletOptions.getShortPubkey(_walletOptions.pubkey.text); + final ChestData cesiumWallet; - if (_walletOptions.nameController.text == null || _isNewNameValid == false) { - _walletOptions.nameController.text = cesiumWallet.name; - } else { - cesiumWallet.name = _walletOptions.nameController.text; - } + @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); - _walletOptions.nameController.text.length >= 15 - ? _nbrLinesName = 2 - : _nbrLinesName = 1; - if (_walletOptions.nameController.text.length >= 26 && isTall) { - _nbrLinesName = 3; - } + final String shortPubkey = + _walletOptions.getShortPubkey(_walletOptions.pubkey.text); - return Scaffold( - resizeToAvoidBottomInset: false, - body: Builder( - builder: (ctx) => SafeArea( - child: Column(children: [ - Container( - height: isTall ? 30 : 15, - color: yellowC, - ), - Container( - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - yellowC, - const Color(0xfffafafa), - ], - )), - child: Row(children: [ - const SizedBox(width: 25), - InkWell( - onTap: () async { - File newAvatar = await _walletOptions.changeAvatar(); - if (newAvatar != null) { - 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(); - if (newAvatar != null) { - cesiumWallet.imageFile = newAvatar; - } - _walletOptions.reloadBuild(); - }, - child: Column(children: [ - Image.asset( - 'assets/walletOptions/camera.png', - ), - const SizedBox(height: 100) - ])), - Column(children: [ - Row(children: [ - Column(children: [ - SizedBox( - width: 260, - child: TextField( - key: const Key('walletName'), - autofocus: false, - focusNode: _walletOptions.walletNameFocus, - enabled: _walletOptions.isEditing, - controller: _walletOptions.nameController, - maxLines: _nbrLinesName, - 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, - fontFamily: 'Monospace')), - ), - 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 (_walletOptions.nameController.text == null || + _isNewNameValid == false) { + _walletOptions.nameController.text = cesiumWallet.name; + } else { + cesiumWallet.name = _walletOptions.nameController.text; + } - if (result.isLoading) { - return const Text('Loading'); - } + _walletOptions.nameController.text.length >= 15 + ? _nbrLinesName = 2 + : _nbrLinesName = 1; + if (_walletOptions.nameController.text.length >= 26 && isTall) { + _nbrLinesName = 3; + } - // 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, - sigmaY: _walletOptions.isBalanceBlur ? 5 : 0), - 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', - )), - ]), - const SizedBox(width: 0), - 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, - ) - ]) - ]), - ]), - ])), - SizedBox(height: 4 * ratio), - FutureBuilder( - future: _walletOptions.generateQRcode(_walletOptions.pubkey.text), - builder: (context, snapshot) { - return snapshot.data != null - ? Image.memory(snapshot.data, height: isTall ? 300 : 270) - : const Text('-', style: TextStyle(fontSize: 20)); + 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('/'), + ); }), - SizedBox(height: 15 * ratio), - GestureDetector( - key: const Key('copyPubkey'), - onTap: () { - Clipboard.setData( - ClipboardData(text: _walletOptions.pubkey.text)); - _walletOptions.snackCopyKey(ctx); - }, - child: SizedBox( - height: 50, + 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(children: [ - const SizedBox(width: 30), - Image.asset( - 'assets/walletOptions/key.png', + const SizedBox(width: 25), + InkWell( + onTap: () async { + File newAvatar = await _walletOptions.changeAvatar(); + if (newAvatar != null) { + cesiumWallet.imageFile = newAvatar; + } + _walletOptions.reloadBuild(); + }, + child: cesiumWallet.imageFile == null + ? Image.asset( + 'assets/chests/${cesiumWallet.imageName}', + width: 110, + ) + : Image.file(cesiumWallet.imageFile, width: 110), ), - 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 + InkWell( + onTap: () async { + File newAvatar = await _walletOptions.changeAvatar(); + if (newAvatar != null) { + cesiumWallet.imageFile = newAvatar; + } + _walletOptions.reloadBuild(); + }, + child: Column(children: [ + Image.asset( + 'assets/walletOptions/camera.png', + height: 40, + ), + const SizedBox(height: 80) + ])), + Column(children: [ + Row(children: [ + Column(children: [ + SizedBox( + width: 260, + child: TextField( + key: const Key('walletName'), + autofocus: false, + focusNode: _walletOptions.walletNameFocus, + enabled: _walletOptions.isEditing, + controller: _walletOptions.nameController, + maxLines: _nbrLinesName, + 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, + fontFamily: 'Monospace')), + ), + SizedBox(height: isTall ? 5 : 0), + Query( + options: QueryOptions( + document: gql(getBalance), + variables: { + 'pubkey': _walletOptions.pubkey.text, + }, + // pollInterval: Duration(seconds: 1), ), - onPressed: () { - Clipboard.setData(ClipboardData( - text: _walletOptions.pubkey.text)); - _walletOptions.snackCopyKey(ctx); + 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, + sigmaY: + _walletOptions.isBalanceBlur ? 5 : 0), + 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), + // ); }, - child: Row(children: [ - Image.asset( - 'assets/walletOptions/copy-white.png', - ), - 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.isPubkey(ctx, _walletOptions.pubkey.text, - goHistory: true); - }, - child: SizedBox( - height: 50, - child: Row(children: [ - const SizedBox(width: 30), - Image.asset( - 'assets/walletOptions/clock.png', - ), - 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); - _myWalletProvider.pinCode = await Navigator.push( - context, - MaterialPageRoute( - builder: (context) { - return ChangePinScreen( - walletName: cesiumWallet.name, - walletProvider: _myWalletProvider, + ), + 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, + ), + ), + ]), + const SizedBox(width: 0), + 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, + ) + ]) + ]), + ]), + ]), + ); + }), + SizedBox(height: 4 * ratio), + FutureBuilder( + future: + _walletOptions.generateQRcode(_walletOptions.pubkey.text), + builder: (context, snapshot) { + return snapshot.data != null + ? Image.memory(snapshot.data, + height: isTall ? 300 : 270) + : const Text('-', style: TextStyle(fontSize: 20)); + }), + 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)), + ]), ), - ); - }, - child: SizedBox( - height: 50, - child: Row(children: [ - const SizedBox(width: 28), - Image.asset( - 'assets/chests/secret_code.png', - ), - const SizedBox(width: 18), - 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), + ), + ), + ]), + ), + ), + ]), ), - 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', - ), - const SizedBox(width: 25), - 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 25ba873..5abfca4 100644 --- a/lib/screens/myWallets/change_pin.dart +++ b/lib/screens/myWallets/change_pin.dart @@ -34,20 +34,28 @@ class ChangePinScreen extends StatelessWidget with ChangeNotifier { child: Scaffold( resizeToAvoidBottomInset: false, appBar: AppBar( - toolbarHeight: 60 * ratio, - leading: IconButton( - icon: const Icon(Icons.arrow_back, color: Colors.black), - onPressed: () { - _changePin.newPin.text = ''; - Navigator.of(context).pop(); - }), - title: SizedBox( - height: 22, - child: Text(walletName), - )), + toolbarHeight: 60 * ratio, + leading: IconButton( + icon: const Icon(Icons.arrow_back, color: Colors.black), + onPressed: () { + _changePin.newPin.text = ''; + Navigator.of(context).pop(); + }), + title: SizedBox( + height: 22, + child: Text(walletName), + ), + ), body: Center( child: SafeArea( child: Column(children: [ + StatefulWrapper( + onInit: () async { + _newWalletFile = + await _changePin.changePin(walletProvider.pinCode); + }, + child: Container(), + ), const SizedBox(height: 80), Text( 'Choisissez un code secret autogénéré :', @@ -111,3 +119,27 @@ 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() { + if (widget.onInit != null) { + 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 dfae9b7..cc7eb68 100644 --- a/lib/screens/myWallets/chest_options.dart +++ b/lib/screens/myWallets/chest_options.dart @@ -46,7 +46,7 @@ class ChestOptions extends StatelessWidget { key: const Key('changePin'), onTap: () async { // await _chestProvider.changePin(context, cesiumWallet); - walletProvider.pinCode = await Navigator.push( + String pinResult = await Navigator.push( context, MaterialPageRoute( builder: (context) { @@ -57,6 +57,10 @@ class ChestOptions extends StatelessWidget { }, ), ); + + if (pinResult != null) { + walletProvider.pinCode = pinResult; + } }, child: SizedBox( height: 50, @@ -64,6 +68,7 @@ class ChestOptions extends StatelessWidget { const SizedBox(width: 28), Image.asset( 'assets/chests/secret_code.png', + height: 25, ), const SizedBox(width: 18), const Text('Changer mon code secret', @@ -79,11 +84,12 @@ class ChestOptions extends StatelessWidget { child: SizedBox( height: 50, child: Row(children: [ - const SizedBox(width: 33), + const SizedBox(width: 30), Image.asset( 'assets/walletOptions/trash.png', + height: 45, ), - const SizedBox(width: 24), + const SizedBox(width: 20), const Text( 'Supprimer ce coffre', style: TextStyle( diff --git a/lib/screens/myWallets/choose_chest.dart b/lib/screens/myWallets/choose_chest.dart index 6377d2e..7179903 100644 --- a/lib/screens/myWallets/choose_chest.dart +++ b/lib/screens/myWallets/choose_chest.dart @@ -9,7 +9,8 @@ import 'package:carousel_slider/carousel_slider.dart'; import 'package:provider/provider.dart'; class ChooseChest extends StatefulWidget { - const ChooseChest({Key key}) : super(key: key); + const ChooseChest({this.action, Key key}) : super(key: key); + final String action; @override State createState() { @@ -29,6 +30,8 @@ class _ChooseChestState extends State { MyWalletsProvider _myWalletProvider = Provider.of(context); + log.d(widget.action); + return Scaffold( appBar: AppBar( toolbarHeight: 60 * ratio, @@ -113,13 +116,16 @@ class _ChooseChestState extends State { WalletData defaultWallet = _myWalletProvider.getDefaultWallet(currentChest); _myWalletProvider.rebuildWidget(); - Navigator.pushAndRemoveUntil(context, - MaterialPageRoute(builder: (context) { - return UnlockingWallet( - wallet: defaultWallet, - action: "mywallets", - ); - }), ModalRoute.withName('/')); + Navigator.pushAndRemoveUntil( + context, + MaterialPageRoute(builder: (context) { + return UnlockingWallet( + wallet: defaultWallet, + action: widget.action ?? "mywallets", + ); + }), + ModalRoute.withName('/'), + ); }, child: Text( 'Ouvrir ce coffre', diff --git a/lib/screens/myWallets/confirm_wallet_storage.dart b/lib/screens/myWallets/confirm_wallet_storage.dart index e822f19..fe7dc15 100644 --- a/lib/screens/myWallets/confirm_wallet_storage.dart +++ b/lib/screens/myWallets/confirm_wallet_storage.dart @@ -6,7 +6,7 @@ import 'package:flutter/services.dart'; import 'package:gecko/globals.dart'; import 'package:gecko/models/generate_wallets.dart'; import 'package:gecko/models/my_wallets.dart'; -import 'package:gecko/models/wallet_options.dart'; +import 'package:gecko/screens/myWallets/unlocking_wallet.dart'; import 'package:provider/provider.dart'; // ignore: must_be_immutable @@ -32,8 +32,6 @@ class ConfirmStoreWallet extends StatelessWidget with ChangeNotifier { Provider.of(context); MyWalletsProvider _myWalletProvider = Provider.of(context); - WalletOptionsProvider _walletOptions = - Provider.of(context); final int _currentChest = _myWalletProvider.getCurrentChest(); _mnemonicController.text = generatedMnemonic; @@ -136,7 +134,7 @@ class ConfirmStoreWallet extends StatelessWidget with ChangeNotifier { onPressed: (_generateWalletProvider .isAskedWordValid && walletName.text != '') - ? () { + ? () async { _generateWalletProvider.storeHDWChest( generatedWallet, walletName.text, @@ -148,12 +146,19 @@ class ConfirmStoreWallet extends StatelessWidget with ChangeNotifier { _myWalletProvider.listWallets = _myWalletProvider .readAllWallets(_currentChest); - scheduleMicrotask(() { - _walletOptions.reloadBuild(); - _myWalletProvider.rebuildWidget(); - }); - Navigator.popUntil( - context, ModalRoute.withName('/')); + await Future.delayed( + const Duration(milliseconds: 50)); + _myWalletProvider.rebuildWidget(); + Navigator.pushAndRemoveUntil(context, + MaterialPageRoute(builder: (context) { + return UnlockingWallet( + wallet: + _myWalletProvider.getDefaultWallet( + configBox.get('currentChest'), + ), + action: "mywallets", + ); + }), ModalRoute.withName('/')); } : null, child: const Text('Confirmer', diff --git a/lib/screens/myWallets/generate_wallets.dart b/lib/screens/myWallets/generate_wallets.dart index b85fdba..0adf9d5 100644 --- a/lib/screens/myWallets/generate_wallets.dart +++ b/lib/screens/myWallets/generate_wallets.dart @@ -1,10 +1,8 @@ import 'package:flutter/services.dart'; import 'package:gecko/globals.dart'; import 'package:gecko/models/generate_wallets.dart'; -import 'package:gecko/models/my_wallets.dart'; import 'package:gecko/screens/myWallets/confirm_wallet_storage.dart'; import 'package:flutter/material.dart'; -import 'package:gecko/screens/myWallets/unlocking_wallet.dart'; import 'package:printing/printing.dart'; import 'package:provider/provider.dart'; import 'package:super_tooltip/super_tooltip.dart'; @@ -29,8 +27,6 @@ class GenerateFastChestScreen extends StatelessWidget { Provider.of(context); _generateWalletProvider.generateMnemonic(); - MyWalletsProvider _myWalletClass = MyWalletsProvider(); - return Scaffold( appBar: AppBar( toolbarHeight: 60 * ratio, @@ -122,14 +118,17 @@ class GenerateFastChestScreen extends StatelessWidget { ); await Future.delayed( const Duration(milliseconds: 20)); - await Navigator.pushAndRemoveUntil(context, - MaterialPageRoute(builder: (context) { - return UnlockingWallet( - wallet: _myWalletClass.getDefaultWallet( - configBox.get('currentChest')), - action: "mywallets", - ); - }), ModalRoute.withName('/')); + // if (_generateWalletProvider.hasBeenStored) { + // _generateWalletProvider.hasBeenStored = false; + // await Navigator.pushAndRemoveUntil(context, + // MaterialPageRoute(builder: (context) { + // return UnlockingWallet( + // wallet: _myWalletClass.getDefaultWallet( + // configBox.get('currentChest')), + // action: "mywallets", + // ); + // }), ModalRoute.withName('/')); + // } } : null, child: const Text('Enregistrer ce trousseau', diff --git a/lib/screens/myWallets/import_wallet.dart b/lib/screens/myWallets/import_cesium_wallet.dart similarity index 97% rename from lib/screens/myWallets/import_wallet.dart rename to lib/screens/myWallets/import_cesium_wallet.dart index 5a86fc8..84e2fea 100644 --- a/lib/screens/myWallets/import_wallet.dart +++ b/lib/screens/myWallets/import_cesium_wallet.dart @@ -24,7 +24,7 @@ class ImportWalletScreen extends StatelessWidget { return WillPopScope( onWillPop: () { - _generateWalletProvider.resetImportView(); + _generateWalletProvider.resetCesiumImportView(); return Future.value(true); }, child: Scaffold( @@ -33,7 +33,7 @@ class ImportWalletScreen extends StatelessWidget { leading: IconButton( icon: const Icon(Icons.arrow_back, color: Colors.black), onPressed: () { - _generateWalletProvider.resetImportView(); + _generateWalletProvider.resetCesiumImportView(); Navigator.of(context).pop(); }), title: const SizedBox( @@ -171,7 +171,8 @@ class ImportWalletScreen extends StatelessWidget { .importCesiumWallet() .then((value) { _myWalletProvider.rebuildWidget(); - _generateWalletProvider.resetImportView(); + _generateWalletProvider + .resetCesiumImportView(); Navigator.popUntil( context, ModalRoute.withName('/'), diff --git a/lib/screens/myWallets/restore_chest.dart b/lib/screens/myWallets/restore_chest.dart new file mode 100644 index 0000000..9f8b1eb --- /dev/null +++ b/lib/screens/myWallets/restore_chest.dart @@ -0,0 +1,184 @@ +import 'package:bubble/bubble.dart'; +import 'package:flutter/services.dart'; +import 'package:gecko/globals.dart'; +import 'package:flutter/material.dart'; +import 'package:gecko/models/generate_wallets.dart'; +import 'package:gecko/screens/common_elements.dart'; +import 'package:gecko/screens/onBoarding/11.dart'; +import 'package:provider/provider.dart'; +// import 'package:gecko/models/home.dart'; +// import 'package:provider/provider.dart'; + +class RestoreChest extends StatelessWidget { + const RestoreChest({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); + GenerateWalletsProvider generateWalletProvider = + Provider.of(context, listen: false); + + generateWalletProvider.actualWallet = null; + + return WillPopScope( + onWillPop: () { + generateWalletProvider.resetImportView(); + return Future.value(true); + }, + child: Scaffold( + appBar: AppBar( + toolbarHeight: 60 * ratio, + leading: IconButton( + icon: const Icon(Icons.arrow_back, color: Colors.black), + onPressed: () { + generateWalletProvider.resetImportView(); + Navigator.of(context).pop(); + }), + title: const SizedBox( + height: 22, + child: Text('Restaurer un coffre'), + )), + body: SafeArea( + child: Column(children: [ + SizedBox(height: isTall ? 30 : 15), + bubbleSpeak( + 'Pour restaurer vos portefeuilles Gecko, rentrez dans les champs ci-dessous les 12 mots qui constituent votre phrase de restauration :'), + SizedBox(height: isTall ? 30 : 15), + Column(children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + arrayCell(context, generateWalletProvider.cellController0), + arrayCell(context, generateWalletProvider.cellController1), + arrayCell(context, generateWalletProvider.cellController2), + arrayCell(context, generateWalletProvider.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), + ]), + 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), + ]), + ]), + // const Spacer(), + if (generateWalletProvider.isSentenceComplete(context)) + Expanded( + child: Align( + alignment: Alignment.center, + child: SizedBox( + width: 410, + height: 70, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + elevation: 4, + primary: orangeC, // background + onPrimary: Colors.white, // foreground + ), + onPressed: () async { + if (await generateWalletProvider.isSentenceValid()) { + generateWalletProvider.resetImportView(); + await Navigator.push( + context, + FaderTransition( + page: OnboardingStepThirteen(), isFast: true), + ); + } else { + await badMnemonicPopup(context); + } + }, + child: const Text( + 'Restaurer ce coffre', + style: + TextStyle(fontSize: 24, fontWeight: FontWeight.w600), + ), + ), + ), + // SizedBox(height: isTall ? 80 : 80), + )) + ]), + ), + ), + ); + } + + Widget bubbleSpeak(String text) { + return Bubble( + margin: const BubbleEdges.symmetric(horizontal: 20), + padding: BubbleEdges.all(isTall ? 25 : 15), + borderWidth: 1, + borderColor: Colors.black, + radius: Radius.zero, + color: Colors.white, + child: Text( + text, + key: const Key('importText'), + textAlign: TextAlign.justify, + style: const TextStyle( + color: Colors.black, fontSize: 19, fontWeight: FontWeight.w400), + ), + ); + } + + Widget arrayCell(BuildContext context, TextEditingController cellCtl) { + GenerateWalletsProvider generateWalletProvider = + Provider.of(context); + + return Container( + width: 102, + height: 40 * ratio, + child: TextField( + autofocus: true, + controller: cellCtl, + textInputAction: TextInputAction.next, + onChanged: (v) { + bool isValid = generateWalletProvider.isBipWord(v); + + if (isValid && generateWalletProvider.cellController11.text.isEmpty) { + FocusScope.of(context).nextFocus(); + } + }, + textAlign: TextAlign.center, + style: const TextStyle(fontSize: 20), + ), + decoration: BoxDecoration( + border: Border.all(color: Colors.grey), + color: Colors.white, + borderRadius: BorderRadius.circular(3), + ), + ); + } + + Future badMnemonicPopup(BuildContext context) async { + return showDialog( + context: context, + barrierDismissible: true, // user must tap button! + builder: (BuildContext context) { + return AlertDialog( + title: const Text('Phrase incorrecte'), + content: const Text( + 'Votre phrase de restauration semble incorrecte, veuillez la corriger.'), + actions: [ + TextButton( + child: const Text("OK"), + onPressed: () { + Navigator.pop(context); + }, + ), + ], + ); + }, + ); + } +} diff --git a/lib/screens/myWallets/unlocking_wallet.dart b/lib/screens/myWallets/unlocking_wallet.dart index 65c1b5f..77701af 100644 --- a/lib/screens/myWallets/unlocking_wallet.dart +++ b/lib/screens/myWallets/unlocking_wallet.dart @@ -2,11 +2,12 @@ import 'dart:async'; import 'package:dubp/dubp.dart'; import 'package:flutter/services.dart'; import 'package:gecko/models/chest_data.dart'; -import 'package:gecko/models/history.dart'; +import 'package:gecko/models/wallets_profiles.dart'; import 'package:gecko/models/my_wallets.dart'; import 'package:gecko/models/wallet_data.dart'; import 'package:gecko/models/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:pin_code_fields/pin_code_fields.dart'; import 'package:provider/provider.dart'; @@ -36,7 +37,6 @@ class UnlockingWallet extends StatelessWidget { Provider.of(context); int _pinLenght; - ChestData currentChest = chestBox.get(configBox.get('currentChest')); if (currentChest.isCesium) { @@ -53,7 +53,7 @@ class UnlockingWallet extends StatelessWidget { child: Column(children: [ Expanded( child: Column(children: [ - SizedBox(height: isTall ? 80 : 20), + SizedBox(height: isTall ? 100 : 20), Row(mainAxisAlignment: MainAxisAlignment.center, children: [ currentChest.imageFile == null ? Image.asset( @@ -87,7 +87,7 @@ class UnlockingWallet extends StatelessWidget { fontWeight: FontWeight.w400), )), SizedBox(height: 40 * ratio), - pinForm(context, _pinLenght), + pinForm(context, _pinLenght, currentChest), SizedBox(height: 3 * ratio), InkWell( key: const Key('chooseChest'), @@ -95,7 +95,7 @@ class UnlockingWallet extends StatelessWidget { Navigator.push( context, MaterialPageRoute(builder: (context) { - return const ChooseChest(); + return ChooseChest(action: action); }), ); }, @@ -103,11 +103,14 @@ class UnlockingWallet extends StatelessWidget { width: 400, height: 70, child: Center( - child: Text('Changer de coffre', - style: TextStyle( - fontSize: 22, - color: orangeC, - fontWeight: FontWeight.w600))), + child: Text( + 'Changer de coffre', + style: TextStyle( + fontSize: 22, + color: orangeC, + fontWeight: FontWeight.w600), + ), + ), )), ]), ), @@ -115,7 +118,7 @@ class UnlockingWallet extends StatelessWidget { )); } - Widget pinForm(context, _pinLenght) { + Widget pinForm(context, _pinLenght, ChestData currentChest) { // var _walletPin = ''; // ignore: close_sinks StreamController errorController = @@ -125,7 +128,8 @@ class UnlockingWallet extends StatelessWidget { Provider.of(context); MyWalletsProvider _myWalletProvider = Provider.of(context); - HistoryProvider _historyProvider = Provider.of(context); + WalletsProfilesProvider _historyProvider = + Provider.of(context); FocusNode pinFocus = FocusNode(); @@ -194,7 +198,16 @@ class UnlockingWallet extends StatelessWidget { pinColor = Colors.green[400]; // await Future.delayed(Duration(milliseconds: 50)); if (action == "mywallets") { - Navigator.pushNamed(formKey.currentContext, '/mywallets'); + currentChest.isCesium + ? Navigator.push( + context, + MaterialPageRoute(builder: (context) { + return CesiumWalletOptions( + cesiumWallet: currentChest); + }), + ) + : Navigator.pushNamed( + formKey.currentContext, '/mywallets'); } else if (action == "pay") { resultPay = await _historyProvider.pay(context, _pin.toUpperCase()); @@ -212,6 +225,7 @@ class UnlockingWallet extends StatelessWidget { } Future _paymentsResult(context) { + if (resultPay != "Success") log.i(resultPay); return showDialog( context: context, barrierDismissible: true, // user must tap button! diff --git a/lib/screens/myWallets/wallet_options.dart b/lib/screens/myWallets/wallet_options.dart index 1e0ca91..ca8d7ed 100644 --- a/lib/screens/myWallets/wallet_options.dart +++ b/lib/screens/myWallets/wallet_options.dart @@ -3,11 +3,12 @@ import 'dart:ui'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:gecko/globals.dart'; -import 'package:gecko/models/history.dart'; import 'package:gecko/models/my_wallets.dart'; import 'package:gecko/models/queries.dart'; import 'package:gecko/models/wallet_data.dart'; import 'package:gecko/models/wallet_options.dart'; +import 'package:gecko/models/wallets_profiles.dart'; +import 'package:gecko/screens/history.dart'; import 'package:graphql_flutter/graphql_flutter.dart'; import 'package:provider/provider.dart'; import 'package:flutter/services.dart'; @@ -24,10 +25,12 @@ class WalletOptions extends StatelessWidget { Widget build(BuildContext context) { SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); WalletOptionsProvider _walletOptions = - Provider.of(context); + Provider.of(context, listen: false); + WalletsProfilesProvider _historyProvider = + Provider.of(context, listen: false); + MyWalletsProvider _myWalletProvider = Provider.of(context); - HistoryProvider _historyProvider = Provider.of(context); final int _currentChest = _myWalletProvider.getCurrentChest(); final String shortPubkey = @@ -57,299 +60,340 @@ class WalletOptions extends StatelessWidget { log.d("Wallet options: $currentChest:${wallet.number}"); return WillPopScope( - onWillPop: () { - _walletOptions.isEditing = false; - _walletOptions.isBalanceBlur = true; - Navigator.popUntil( - context, - ModalRoute.withName('/mywallets'), - ); - return Future.value(true); - }, - child: Scaffold( - resizeToAvoidBottomInset: false, - appBar: AppBar( - toolbarHeight: 60 * ratio, - leading: IconButton( - icon: const Icon(Icons.arrow_back, color: Colors.black), - onPressed: () { - _walletOptions.isEditing = false; - _walletOptions.isBalanceBlur = true; - Navigator.popUntil( - context, - ModalRoute.withName('/mywallets'), - ); - }), - title: SizedBox( - height: 22, - child: Text(_walletOptions.nameController.text), - )), - body: Builder( - builder: (ctx) => SafeArea( - child: Column(children: [ - Container( - height: isTall ? 15 : 0, - color: yellowC, - ), - Container( - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - yellowC, - const Color(0xfffafafa), - ], - )), - child: Row(children: [ - const SizedBox(width: 25), - InkWell( - onTap: () async { - File newAvatar = - await _walletOptions.changeAvatar(); - if (newAvatar != null) { - wallet.imageFile = newAvatar; - } - _walletOptions.reloadBuild(); - }, - child: wallet.imageFile == null - ? Image.asset( - 'assets/avatars/${wallet.imageName}', - width: 110, - ) - : Image.file( - wallet.imageFile, - width: 110, - )), - InkWell( - onTap: () async { - File newAvatar = - await _walletOptions.changeAvatar(); - if (newAvatar != null) { - wallet.imageFile = newAvatar; - } - _walletOptions.reloadBuild(); - }, - child: Column(children: [ - Image.asset( - 'assets/walletOptions/camera.png', - ), - const SizedBox(height: 100) - ])), - Column(children: [ - Row(children: [ - Column(children: [ - SizedBox( - width: 260, - child: TextField( - key: const Key('walletName'), - autofocus: false, - focusNode: _walletOptions.walletNameFocus, - enabled: _walletOptions.isEditing, - controller: _walletOptions.nameController, - maxLines: _nbrLinesName, - 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, - fontFamily: 'Monospace')), - ), - 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, - sigmaY: _walletOptions.isBalanceBlur - ? 5 - : 0), - 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', - )), - ]), - const SizedBox(width: 0), - Column(children: [ - InkWell( - key: const Key('renameWallet'), - onTap: () async { - _isNewNameValid = - _walletOptions.editWalletName(wallet.id(), - isCesium: false); - 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, + onWillPop: () { + _walletOptions.isEditing = false; + _walletOptions.isBalanceBlur = true; + Navigator.popUntil( + context, + ModalRoute.withName('/mywallets'), + ); + 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('/mywallets'), + ); + }), + title: SizedBox( + height: 22, + child: Consumer( + builder: (context, walletProvider, _) { + return Text(_walletOptions.nameController.text); + }), + ), + ), + body: Builder( + builder: (ctx) => SafeArea( + child: Column(children: [ + Container( + height: isTall ? 5 : 0, + color: yellowC, + ), + Consumer( + builder: (context, walletProvider, _) { + return Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + yellowC, + const Color(0xfffafafa), + ], + )), + child: Row(children: [ + const SizedBox(width: 25), + InkWell( + onTap: () async { + File newAvatar = await walletProvider.changeAvatar(); + if (newAvatar != null) { + wallet.imageFile = newAvatar; + } + walletProvider.reloadBuild(); + }, + child: wallet.imageFile == null + ? Image.asset( + 'assets/avatars/${wallet.imageName}', + width: 110, ) - ]) + : Image.file( + wallet.imageFile, + width: 110, + ), + ), + InkWell( + onTap: () async { + File newAvatar = await walletProvider.changeAvatar(); + if (newAvatar != null) { + wallet.imageFile = newAvatar; + } + walletProvider.reloadBuild(); + }, + child: Column(children: [ + Image.asset( + 'assets/walletOptions/camera.png', + height: 40, + ), + const SizedBox(height: 80) + ])), + Column(children: [ + Row(children: [ + Column(children: [ + SizedBox( + width: 260, + child: TextField( + key: const Key('walletName'), + autofocus: false, + focusNode: walletProvider.walletNameFocus, + enabled: walletProvider.isEditing, + controller: walletProvider.nameController, + maxLines: _nbrLinesName, + 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, + fontFamily: 'Monospace')), + ), + SizedBox(height: isTall ? 5 : 0), + Query( + options: QueryOptions( + document: gql(getBalance), + variables: { + 'pubkey': walletProvider.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 if (result.hasException) { + wBalanceUD = '?'; + } 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: + walletProvider.isBalanceBlur ? 6 : 0, + sigmaY: + walletProvider.isBalanceBlur ? 5 : 0), + 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: () { + walletProvider.bluringBalance(); + }, + child: Image.asset( + walletProvider.isBalanceBlur + ? 'assets/walletOptions/icon_oeuil.png' + : 'assets/walletOptions/icon_oeuil_close.png', + height: 35, + ), + ), ]), + const SizedBox(width: 0), + Column(children: [ + InkWell( + key: const Key('renameWallet'), + onTap: () async { + _isNewNameValid = walletProvider.editWalletName( + wallet.id(), + isCesium: false); + await Future.delayed( + const Duration(milliseconds: 30)); + walletProvider.walletNameFocus.requestFocus(); + }, + child: ClipRRect( + child: Image.asset( + walletProvider.isEditing + ? 'assets/walletOptions/android-checkmark.png' + : 'assets/walletOptions/edit.png', + width: 20, + height: 20), + )), + const SizedBox( + height: 60, + ) + ]) ]), - ])), - SizedBox(height: 4 * ratio), - FutureBuilder( - future: _walletOptions - .generateQRcode(_walletOptions.pubkey.text), - builder: (context, snapshot) { - return snapshot.data != null - ? Image.memory(snapshot.data, - height: isTall ? 300 : 270) - : const Text('-', style: TextStyle(fontSize: 20)); - }), - SizedBox(height: 15 * ratio), - GestureDetector( + ]), + ]), + ); + }), + SizedBox(height: 4 * ratio), + FutureBuilder( + future: + _walletOptions.generateQRcode(_walletOptions.pubkey.text), + builder: (context, snapshot) { + return snapshot.data != null + ? Image.memory(snapshot.data, height: isTall ? 300 : 270) + : const Text('-', style: TextStyle(fontSize: 20)); + }, + ), + SizedBox(height: 15 * ratio), + Consumer( + builder: (context, walletProvider, _) { + return Column(children: [ + GestureDetector( key: const Key('copyPubkey'), onTap: () { Clipboard.setData( - ClipboardData(text: _walletOptions.pubkey.text)); - _walletOptions.snackCopyKey(ctx); + ClipboardData(text: walletProvider.pubkey.text)); + walletProvider.snackCopyKey(ctx); }, child: SizedBox( - height: 50, - child: Row(children: [ - const SizedBox(width: 30), - Image.asset( - 'assets/walletOptions/key.png', + 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: walletProvider.pubkey.text)); + walletProvider.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]), + ) + ]), ), - 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', - ), - const SizedBox(width: 7), - Text('Copier', - style: TextStyle( - fontSize: 15, - color: Colors.grey[50])) - ]))), - ]))), - SizedBox(height: 10 * ratio), - InkWell( + ), + ]), + ), + ), + SizedBox(height: 10 * ratio), + InkWell( key: const Key('displayHistory'), onTap: () { - _historyProvider.isPubkey(ctx, _walletOptions.pubkey.text, - goHistory: true); + _historyProvider.nPage = 1; + Navigator.push( + context, + MaterialPageRoute(builder: (context) { + return HistoryScreen( + pubkey: walletProvider.pubkey.text, + avatar: wallet.imageFile == null + ? Image.asset( + 'assets/avatars/${wallet.imageName}', + width: 110, + ) + : Image.file( + wallet.imageFile, + width: 110, + )); + }), + ); }, child: SizedBox( - height: 50, - child: Row(children: [ - const SizedBox(width: 30), - Image.asset( - 'assets/walletOptions/clock.png', - ), - const SizedBox(width: 22), - const Text('Historique des transactions', - style: - TextStyle(fontSize: 20, color: Colors.black)), - ]))), - SizedBox(height: 12 * ratio), - InkWell( + 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: 12 * ratio), + InkWell( key: const Key('setDefaultWallet'), - onTap: !_walletOptions.isDefaultWallet + onTap: !walletProvider.isDefaultWallet ? () { defaultWallet = wallet; chestBox.get(currentChest).defaultWallet = @@ -359,33 +403,37 @@ class WalletOptions extends StatelessWidget { } : null, child: SizedBox( - height: 50, - child: Row(children: [ - const SizedBox(width: 31), - CircleAvatar( - backgroundColor: Colors.grey[ - _walletOptions.isDefaultWallet ? 300 : 500], - child: Image.asset( - 'assets/walletOptions/android-checkmark.png', - )), - const SizedBox(width: 22), - Text( - _walletOptions.isDefaultWallet - ? 'Ce portefeuille est celui par defaut' - : 'Définir comme portefeuille par défaut', - style: TextStyle( - fontSize: 20, - color: _walletOptions.isDefaultWallet - ? Colors.grey[500] - : Colors.black)), - ]))), - SizedBox(height: 17 * ratio), - if (!_walletOptions.isDefaultWallet) - InkWell( + height: 50, + child: Row(children: [ + const SizedBox(width: 31), + CircleAvatar( + backgroundColor: Colors + .grey[walletProvider.isDefaultWallet ? 300 : 500], + child: Image.asset( + 'assets/walletOptions/android-checkmark.png', + height: 25, + ), + ), + const SizedBox(width: 22), + Text( + walletProvider.isDefaultWallet + ? 'Ce portefeuille est celui par defaut' + : 'Définir comme portefeuille par défaut', + style: TextStyle( + fontSize: 20, + color: walletProvider.isDefaultWallet + ? Colors.grey[500] + : Colors.black)), + ]), + ), + ), + SizedBox(height: 17 * ratio), + if (!walletProvider.isDefaultWallet) + InkWell( key: const Key('deleteWallet'), - onTap: !_walletOptions.isDefaultWallet + onTap: !walletProvider.isDefaultWallet ? () async { - await _walletOptions.deleteWallet( + await walletProvider.deleteWallet( context, wallet); WidgetsBinding.instance.addPostFrameCallback((_) { _myWalletProvider.listWallets = @@ -396,18 +444,23 @@ class WalletOptions extends StatelessWidget { } : null, child: Row(children: [ - const SizedBox(width: 33), + const SizedBox(width: 30), Image.asset( 'assets/walletOptions/trash.png', + height: 45, ), - const SizedBox(width: 24), + const SizedBox(width: 19), const Text('Supprimer ce portefeuille', style: TextStyle( fontSize: 20, color: Color(0xffD80000))), - ])), - ]), - ), + ]), + ), + ]); + }), + ]), ), - )); + ), + ), + ); } } diff --git a/lib/screens/myWallets/wallets_home.dart b/lib/screens/myWallets/wallets_home.dart index c323c1e..4d18027 100644 --- a/lib/screens/myWallets/wallets_home.dart +++ b/lib/screens/myWallets/wallets_home.dart @@ -7,11 +7,9 @@ import 'package:gecko/models/wallet_data.dart'; import 'package:gecko/models/wallet_options.dart'; import 'package:flutter/material.dart'; import 'package:gecko/screens/common_elements.dart'; -import 'package:gecko/screens/myWallets/cesium_wallet_options.dart'; import 'package:gecko/screens/myWallets/chest_options.dart'; import 'package:gecko/screens/myWallets/choose_chest.dart'; import 'package:gecko/screens/myWallets/wallet_options.dart'; -import 'package:gecko/screens/onBoarding/0_no_keychain_found.dart'; import 'package:graphql_flutter/graphql_flutter.dart'; import 'package:provider/provider.dart'; @@ -28,13 +26,8 @@ class WalletsHome extends StatelessWidget { final int _currentChestNumber = myWalletProvider.getCurrentChest(); final ChestData _currentChest = chestBox.get(_currentChestNumber); - bool isWalletsExists; - - if (!_currentChest.isCesium) { - myWalletProvider.listWallets = - myWalletProvider.readAllWallets(_currentChestNumber); - } - isWalletsExists = myWalletProvider.checkIfWalletExist(); + myWalletProvider.listWallets = + myWalletProvider.readAllWallets(_currentChestNumber); return WillPopScope( onWillPop: () { @@ -61,12 +54,7 @@ class WalletsHome extends StatelessWidget { backgroundColor: const Color(0xffFFD58D), ), body: SafeArea( - child: !isWalletsExists - ? const NoKeyChainScreen() - : _currentChest.isCesium - ? cesiumWalletOptions( - context, _currentChest, myWalletProvider) - : myWalletsTiles(context), + child: myWalletsTiles(context), ), ), ); diff --git a/lib/screens/old_history_pay.dart b/lib/screens/old_history_pay.dart new file mode 100644 index 0000000..12571bf --- /dev/null +++ b/lib/screens/old_history_pay.dart @@ -0,0 +1,485 @@ +import 'package:flutter/services.dart'; +import 'package:gecko/globals.dart'; +import 'package:gecko/models/cesium_plus.dart'; +import 'package:gecko/models/home.dart'; +import 'package:gecko/models/my_wallets.dart'; +import 'package:gecko/models/queries.dart'; +import 'package:gecko/models/wallets_profiles.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/foundation.dart'; +import 'package:gecko/models/wallet_data.dart'; +import 'package:gecko/screens/myWallets/unlocking_wallet.dart'; +import 'package:gecko/screens/wallet_view.dart'; +import 'dart:ui'; +import 'package:graphql_flutter/graphql_flutter.dart'; +import 'package:provider/provider.dart'; +import 'package:flutter_svg/flutter_svg.dart'; + +// ignore: must_be_immutable +class OldHistoryScreen extends StatelessWidget with ChangeNotifier { + final TextEditingController _outputPubkey = TextEditingController(); + ScrollController scrollController = ScrollController(); + final nRepositories = 20; + // HistoryProvider _historyProvider; + final _formKey = GlobalKey(); + final FocusNode _pubkeyFocus = FocusNode(); + final double avatarsSize = 80; + + FetchMore fetchMore; + FetchMoreOptions opts; + final GlobalKey _scaffoldKey = GlobalKey(); + + OldHistoryScreen({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); + WalletsProfilesProvider _historyProvider = + Provider.of(context); + HomeProvider _homeProvider = Provider.of(context); + _outputPubkey.text = _historyProvider.pubkey; + log.i('Build pubkey : ' + _historyProvider.pubkey); + WidgetsBinding.instance.addPostFrameCallback((_) {}); + + return Scaffold( + key: _scaffoldKey, + appBar: AppBar( + toolbarHeight: 60 * ratio, + title: _homeProvider.appBarExplorer, + actions: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: IconButton( + icon: _homeProvider.searchIcon, + color: Colors.grey[850], + onPressed: () { + if (_homeProvider.searchIcon.icon == Icons.search) { + _homeProvider.searchIcon = Icon( + Icons.close, + color: Colors.grey[850], + ); + _homeProvider.appBarExplorer = TextField( + autofocus: true, + controller: _homeProvider.searchQuery, + onChanged: (text) { + log.d("Clé tappé: $text"); + if (_historyProvider.isPubkey(text)) { + _homeProvider.currentIndex = 0; + Navigator.push( + context, + MaterialPageRoute(builder: (context) { + return WalletViewScreen(pubkey: text); + }), + ); + } + }, + style: TextStyle( + color: Colors.grey[850], + ), + decoration: InputDecoration( + prefixIcon: + Icon(Icons.search, color: Colors.grey[850]), + hintText: "Rechercher ...", + hintStyle: TextStyle(color: Colors.grey[850])), + ); + _homeProvider.handleSearchStart(); + } else { + _homeProvider.handleSearchEnd(); + } + })) + ], + backgroundColor: const Color(0xffFFD58D), + ), + floatingActionButton: SizedBox( + height: 80.0, + width: 80.0, + child: FittedBox( + child: FloatingActionButton( + heroTag: "buttonScan", + onPressed: () async { + await _historyProvider.scan(context); + }, + child: SizedBox( + height: 40.0, + width: 40.0, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 3), + child: Image.asset('assets/qrcode-scan.png'))), + backgroundColor: + floattingYellow, //smoothYellow, //Color.fromARGB(500, 204, 255, 255), + ), + ), + ), + body: Column(children: [ + const SizedBox(height: 0), + if (_historyProvider.pubkey != '') + historyQuery(context, _historyProvider), + ])); + } + + Widget historyQuery(context, WalletsProfilesProvider _historyProvider) { + _pubkeyFocus.unfocus(); + // HistoryProvider _historyProvider = Provider.of(context); + CesiumPlusProvider _cesiumPlusProvider = + Provider.of(context); + bool _isFirstExec = true; + return Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Query( + options: QueryOptions( + document: gql(getHistory), + variables: { + 'pubkey': _historyProvider.pubkey, + 'number': nRepositories, + 'cursor': null + }, + ), + builder: (QueryResult result, {fetchMore, refetch}) { + if (result.isLoading && result.data == null) { + return const Center( + child: CircularProgressIndicator(), + ); + } + + if (result.hasException) { + log.e('Error GVA: ' + result.exception.toString()); + return Column(children: const [ + SizedBox(height: 50), + Text( + "Aucun noeud GVA valide n'a pu être trouvé.\nVeuillez réessayer ultérieurement.", + style: TextStyle(fontSize: 17.0), + ) + ]); + } + + if (result.data == null && result.exception.toString() == null) { + return const Text('Aucune donnée à afficher.'); + } + + num balance; + + if (result.data['balance'] == null) { + balance = 0.0; + } else { + balance = _historyProvider + .removeDecimalZero(result.data['balance']['amount'] / 100); + } + + opts = _historyProvider.checkQueryResult( + result, opts, _outputPubkey.text); + + // _historyProvider.transBC = null; + + // Build history list + return NotificationListener( + child: Builder( + builder: (context) => Expanded( + child: ListView( + key: const Key('listTransactions'), + controller: scrollController, + children: [ + const SizedBox(height: 20), + if (_historyProvider.pubkey != '') + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + if (_isFirstExec) + Container( + padding: const EdgeInsets.fromLTRB( + 20, 0, 30, 0), + child: FutureBuilder( + future: + _cesiumPlusProvider.getAvatar( + _historyProvider.pubkey, + 55), + builder: (BuildContext context, + AsyncSnapshot _avatar) { + if (_avatar.connectionState != + ConnectionState.done || + _avatar.hasError) { + return Stack(children: [ + _cesiumPlusProvider + .defaultAvatar(55), + Positioned( + top: 8, + right: 0, + width: 12, + height: 12, + child: + CircularProgressIndicator( + strokeWidth: 1, + color: orangeC, + ), + ), + ]); + } + if (_avatar.hasData) { + return ClipOval( + child: _avatar.data, + ); + } + return _cesiumPlusProvider + .defaultAvatar(55); + }), + ), + GestureDetector( + key: const Key('copyPubkey'), + onTap: () { + Clipboard.setData(ClipboardData( + text: _historyProvider.pubkey)); + _historyProvider.snackCopyKey(context); + }, + child: Text( + _historyProvider.getShortPubkey( + _historyProvider.pubkey), + style: const TextStyle( + fontSize: 22, + fontWeight: FontWeight.w800, + fontFamily: 'Monospace')), + ), + Container( + padding: const EdgeInsets.fromLTRB( + 30, 0, 5, 0), // .only(right: 15), + child: Card( + child: Column( + children: [ + SvgPicture.string( + _historyProvider + .generateIdenticon( + _historyProvider + .pubkey), + fit: BoxFit.contain, + height: 64, + width: 64, + ), + ], + ), + )), + const SizedBox(width: 0) + ]), + if (_isFirstExec) + Row( + mainAxisAlignment: + MainAxisAlignment.spaceAround, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + padding: + const EdgeInsets.fromLTRB(0, 0, 0, 0), + // padding: const EdgeInsets., + child: FutureBuilder( + future: _cesiumPlusProvider + .getName(_historyProvider.pubkey), + initialData: '...', + builder: (context, snapshot) { + return Text(snapshot.data ?? '-', + style: const TextStyle( + fontSize: 20)); + }), + ) + ]), + const SizedBox(height: 18), + if (_isFirstExec) + Container( + padding: + const EdgeInsets.fromLTRB(0, 0, 0, 0), + child: Text(balance.toString() + ' Ğ1', + textAlign: TextAlign.center, + style: const TextStyle(fontSize: 18.0))), + const SizedBox(height: 20), + ElevatedButton( + key: const Key('switchPayHistory'), + style: ElevatedButton.styleFrom( + elevation: 1, + primary: Colors.grey[50], // background + onPrimary: Colors.black, // foreground + ), + onPressed: () { + _historyProvider.switchProfileView(); + }, + child: Text( + _historyProvider.historySwitchButtun, + style: TextStyle( + fontSize: 15, color: orangeC))), + // const Divider( + // color: Colors.grey, + // height: 5, + // thickness: 0.5, + // indent: 0, + // endIndent: 0, + // ), + _historyProvider.isHistoryScreen + ? historyView(context, result) + : payView(context, _historyProvider), + ], + ))), + onNotification: (t) { + if (t is ScrollEndNotification && + scrollController.position.pixels >= + scrollController.position.maxScrollExtent * 0.7) { + fetchMore(opts); + } + return true; + }); + }, + ), + ], + )); + } + + Widget payView(context, WalletsProfilesProvider _historyProvider) { + MyWalletsProvider _myWalletProvider = MyWalletsProvider(); + WalletData defaultWallet = + _myWalletProvider.getDefaultWallet(configBox.get('currentChest')); + + return Stack( + clipBehavior: Clip.hardEdge, + children: [ + Form( + key: _formKey, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const SizedBox(height: 20), + const Text('Commentaire:', style: TextStyle(fontSize: 20.0)), + Padding( + padding: const EdgeInsets.all(8.0), + child: TextField( + controller: _historyProvider.payComment, + maxLines: 2, + textAlign: TextAlign.center, + decoration: const InputDecoration(), + style: const TextStyle( + fontSize: 22, + color: Colors.black, + fontWeight: FontWeight.bold))), + const SizedBox(height: 20), + const Text('Montant (DU/Ğ1):', style: TextStyle(fontSize: 20.0)), + Padding( + padding: const EdgeInsets.all(8.0), + child: TextFormField( + style: const TextStyle(fontSize: 22), + controller: _historyProvider.payAmount, + textAlign: TextAlign.center, + maxLines: 1, + keyboardType: TextInputType.number, + decoration: InputDecoration( + contentPadding: const EdgeInsets.symmetric( + vertical: 25.0, horizontal: 10.0), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10.0)), + ), + inputFormatters: [ + FilteringTextInputFormatter.allow(RegExp(r'(^\d*\.?\d*)')) + ], + ), + ), + Padding( + padding: const EdgeInsets.only(top: 15), + child: OutlinedButton( + style: OutlinedButton.styleFrom( + side: BorderSide(width: 2, color: orangeC)), + onPressed: () { + // if (_formKey.currentState.validate()) { + // _formKey.currentState.save(); + // } + // _historyProvider.pay(payAmount.text, payComment.text); + Navigator.push( + context, + MaterialPageRoute(builder: (context) { + return UnlockingWallet( + wallet: defaultWallet, action: "pay"); + }), + ); + }, + child: Padding( + padding: const EdgeInsets.all(12), + child: Text( + "PAYER", + style: TextStyle(fontSize: 25, color: Colors.grey[850]), + ), + ), + ), + ) + ], + ), + ), + ], + ); + } + + Widget historyView(context, result) { + WalletsProfilesProvider _historyProvider = + Provider.of(context); + HomeProvider _homeProvider = + Provider.of(context, listen: false); + int keyID = 0; + + return _historyProvider.transBC == null + ? const Text('Aucune transaction à afficher.') + : Column(children: [ + for (var repository in _historyProvider.transBC) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 5.0), + child: ListTile( + key: Key('transaction${keyID++}'), + contentPadding: const EdgeInsets.all(5.0), + leading: Text(repository[1].toString(), + style: TextStyle( + fontSize: 12, + color: Colors.grey[800], + fontWeight: FontWeight.w700), + textAlign: TextAlign.center), + title: Text(repository[3], + style: const TextStyle( + fontSize: 15.0, fontFamily: 'Monospace'), + textAlign: TextAlign.center), + subtitle: Text(repository[6] != '' ? repository[6] : '-', + style: const TextStyle(fontSize: 12.0), + textAlign: TextAlign.center), + trailing: Text("${repository[4]} Ğ1", + style: const TextStyle(fontSize: 14.0), + textAlign: TextAlign.justify), + dense: true, + isThreeLine: false, + onTap: () { + if (_historyProvider.isPubkey(repository[2])) { + _homeProvider.currentIndex = 0; + Navigator.push( + context, + MaterialPageRoute(builder: (context) { + return WalletViewScreen(pubkey: repository[2]); + }), + ); + } + Navigator.pop(context); + }), + ), + if (result.isLoading && + _historyProvider.pageInfo['hasPreviousPage']) + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: const [ + CircularProgressIndicator(), + ], + ), + // if (_historyProvider.isTheEnd) // What I did before ... + if (!_historyProvider.pageInfo['hasPreviousPage']) + Column( + children: const [ + SizedBox(height: 15), + Text("Début de l'historique.", + textAlign: TextAlign.center, + style: TextStyle(fontSize: 20)), + SizedBox(height: 15) + ], + ) + ]); + } +} diff --git a/lib/screens/onBoarding/0_no_keychain_found.dart b/lib/screens/onBoarding/0_no_keychain_found.dart index 31745a7..685bc27 100644 --- a/lib/screens/onBoarding/0_no_keychain_found.dart +++ b/lib/screens/onBoarding/0_no_keychain_found.dart @@ -4,7 +4,7 @@ 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_wallet.dart'; +import 'package:gecko/screens/myWallets/import_cesium_wallet.dart'; import 'package:gecko/screens/onBoarding/1.dart'; class NoKeyChainScreen extends StatelessWidget { diff --git a/lib/screens/onBoarding/13_congratulations.dart b/lib/screens/onBoarding/13_congratulations.dart index ac73743..ae2ec6f 100644 --- a/lib/screens/onBoarding/13_congratulations.dart +++ b/lib/screens/onBoarding/13_congratulations.dart @@ -46,13 +46,10 @@ class OnboardingStepFiveteen extends StatelessWidget { onPrimary: Colors.white, // foreground ), onPressed: () { - Navigator.popUntil( - context, - ModalRoute.withName('/'), - ); - Navigator.pushNamed( + Navigator.pushNamedAndRemoveUntil( context, '/mywallets', + ModalRoute.withName('/'), ); }, child: const Text("Accéder à mes portefeuilles", diff --git a/lib/screens/onBoarding/7.dart b/lib/screens/onBoarding/7.dart index 756f046..6604b5b 100644 --- a/lib/screens/onBoarding/7.dart +++ b/lib/screens/onBoarding/7.dart @@ -51,6 +51,7 @@ class OnboardingStepNine extends StatelessWidget { }, child: Image.asset( 'assets/printer.png', + height: 35, ), ), Expanded( @@ -133,55 +134,63 @@ Widget sentanceArray(BuildContext context) { builder: (context, formatedArray) { // print(formatedArray.data); return Container( - padding: const EdgeInsets.symmetric(horizontal: 12), - child: Container( - 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.data[0]), - arrayCell(formatedArray.data[1]), - arrayCell(formatedArray.data[2]), - arrayCell(formatedArray.data[3]), - ]), - const SizedBox(height: 15), - Row(children: [ - arrayCell(formatedArray.data[4]), - arrayCell(formatedArray.data[5]), - arrayCell(formatedArray.data[6]), - arrayCell(formatedArray.data[7]), - ]), - const SizedBox(height: 15), - Row(children: [ - arrayCell(formatedArray.data[8]), - arrayCell(formatedArray.data[9]), - arrayCell(formatedArray.data[10]), - arrayCell(formatedArray.data[11]), - ]), - ]))); + padding: const EdgeInsets.symmetric(horizontal: 12), + child: Container( + 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.data[0]), + arrayCell(formatedArray.data[1]), + arrayCell(formatedArray.data[2]), + arrayCell(formatedArray.data[3]), + ]), + const SizedBox(height: 15), + Row(children: [ + arrayCell(formatedArray.data[4]), + arrayCell(formatedArray.data[5]), + arrayCell(formatedArray.data[6]), + arrayCell(formatedArray.data[7]), + ]), + const SizedBox(height: 15), + Row(children: [ + arrayCell(formatedArray.data[8]), + arrayCell(formatedArray.data[9]), + arrayCell(formatedArray.data[10]), + arrayCell(formatedArray.data[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)), - ])); + 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 diff --git a/lib/screens/search.dart b/lib/screens/search.dart new file mode 100644 index 0000000..39e4337 --- /dev/null +++ b/lib/screens/search.dart @@ -0,0 +1,109 @@ +import 'package:flutter/services.dart'; +import 'package:gecko/globals.dart'; +import 'package:flutter/material.dart'; +import 'package:gecko/models/search.dart'; +import 'package:gecko/screens/search_result.dart'; +import 'package:provider/provider.dart'; +// import 'package:gecko/models/home.dart'; +// import 'package:provider/provider.dart'; + +class SearchScreen extends StatelessWidget { + const SearchScreen({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); + SearchProvider _searchProvider = Provider.of(context); + + return WillPopScope( + onWillPop: () { + _searchProvider.searchController.text = ''; + return Future.value(true); + }, + child: Scaffold( + appBar: AppBar( + toolbarHeight: 60 * ratio, + title: const SizedBox( + height: 22, + child: Text('Rechercher'), + ), + leading: IconButton( + icon: const Icon(Icons.arrow_back, color: Colors.black), + onPressed: () { + _searchProvider.searchController.text = ''; + Navigator.of(context).pop(); + }), + ), + body: SafeArea( + child: Column(children: [ + SizedBox(height: isTall ? 200 : 100), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 17), + child: TextField( + controller: _searchProvider.searchController, + autofocus: true, + maxLines: 1, + textAlign: TextAlign.left, + onChanged: (v) => _searchProvider.rebuildWidget(), + decoration: InputDecoration( + filled: true, + fillColor: Colors.white, + prefixIconConstraints: const BoxConstraints( + minHeight: 32, + ), + prefixIcon: const Padding( + padding: EdgeInsets.symmetric(horizontal: 17), + child: Image( + image: AssetImage('assets/loupe-noire.png'), + height: 35), + ), + border: OutlineInputBorder( + borderSide: + BorderSide(color: Colors.grey[500], width: 2), + borderRadius: BorderRadius.circular(8)), + focusedBorder: OutlineInputBorder( + borderSide: + BorderSide(color: Colors.grey[500], width: 2.5), + borderRadius: BorderRadius.circular(8), + ), + contentPadding: const EdgeInsets.all(20), + ), + style: const TextStyle( + fontSize: 20, + color: Colors.black, + fontWeight: FontWeight.w400, + ), + ), + ), + const Spacer(flex: 1), + SizedBox( + width: 410, + height: 70, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + elevation: 4, + primary: orangeC, // background + onPrimary: Colors.white, // foreground + ), + onPressed: _searchProvider.searchController.text.length >= 2 + ? () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) { + return const SearchResultScreen(); + }), + ); + } + : null, + child: const Text( + 'Rechercher', + style: TextStyle(fontSize: 24, fontWeight: FontWeight.w600), + ), + ), + ), + const Spacer(flex: 1), + ]), + ), + )); + } +} diff --git a/lib/screens/search_result.dart b/lib/screens/search_result.dart new file mode 100644 index 0000000..bcaa6c0 --- /dev/null +++ b/lib/screens/search_result.dart @@ -0,0 +1,184 @@ +import 'package:flutter/services.dart'; +import 'package:gecko/globals.dart'; +import 'package:flutter/material.dart'; +import 'package:gecko/models/cesium_plus.dart'; +import 'package:gecko/models/g1_wallets_list.dart'; +import 'package:gecko/models/wallets_profiles.dart'; +import 'package:gecko/models/search.dart'; +import 'package:gecko/screens/wallet_view.dart'; +import 'package:provider/provider.dart'; + +class SearchResultScreen extends StatelessWidget { + const SearchResultScreen({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); + SearchProvider _searchProvider = + Provider.of(context, listen: false); + CesiumPlusProvider _cesiumPlusProvider = + Provider.of(context, listen: false); + WalletsProfilesProvider _walletsProfilesClass = + Provider.of(context, listen: false); + + int keyID = 0; + double _avatarSize = 55; + + return Scaffold( + appBar: AppBar( + toolbarHeight: 60 * ratio, + title: const SizedBox( + height: 22, + child: Text('Résultats de votre recherche'), + ), + ), + body: SafeArea( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: + Column(crossAxisAlignment: CrossAxisAlignment.start, children: < + Widget>[ + const SizedBox(height: 30), + RichText( + text: TextSpan( + style: TextStyle( + fontSize: 18, + color: Colors.grey[700], + ), + children: [ + const TextSpan( + text: "Résultats pour ", + ), + TextSpan( + text: '"${_searchProvider.searchController.text}"', + style: const TextStyle(fontStyle: FontStyle.italic), + ), + ], + ), + ), + const SizedBox(height: 40), + const Text( + 'Dans la blockchain Ğ1', + style: TextStyle(fontSize: 20), + ), + const SizedBox(height: 20), + FutureBuilder( + future: _searchProvider.searchBlockchain(), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.done) { + return Expanded( + child: ListView(children: [ + for (G1WalletsList g1Wallet in snapshot.data) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 5), + child: ListTile( + key: Key('searchResult${keyID++}'), + horizontalTitleGap: 40, + contentPadding: const EdgeInsets.all(5), + leading: g1WalletsBox + .get(g1Wallet.pubkey) + ?.avatar != + null + ? ClipOval( + child: g1WalletsBox + .get(g1Wallet.pubkey) + .avatar) + : FutureBuilder( + future: _cesiumPlusProvider.getAvatar( + g1Wallet.pubkey, _avatarSize), + builder: (BuildContext context, + AsyncSnapshot _avatar) { + if (_avatar.connectionState != + ConnectionState.done || + _avatar.hasError) { + return Stack(children: [ + _cesiumPlusProvider + .defaultAvatar(_avatarSize), + Positioned( + top: 8, + right: 0, + width: 12, + height: 12, + child: CircularProgressIndicator( + strokeWidth: 1, + color: orangeC, + ), + ), + ]); + } + if (_avatar.hasData) { + g1WalletsBox + .get(g1Wallet.pubkey) + .avatar = _avatar.data; + return ClipOval(child: _avatar.data); + } else { + g1WalletsBox + .get(g1Wallet.pubkey) + .avatar = + _cesiumPlusProvider + .defaultAvatar(_avatarSize); + return _cesiumPlusProvider + .defaultAvatar(_avatarSize); + } + }), + title: Row(children: [ + Text( + _walletsProfilesClass + .getShortPubkey(g1Wallet.pubkey), + style: const TextStyle( + fontSize: 18, + fontFamily: 'Monospace', + fontWeight: FontWeight.w500), + textAlign: TextAlign.center), + ]), + subtitle: Row(children: [ + Text(g1Wallet?.id?.username ?? '', + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.w500), + textAlign: TextAlign.center), + ]), + dense: false, + isThreeLine: false, + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) { + _walletsProfilesClass.pubkey = + g1Wallet.pubkey; + return WalletViewScreen( + pubkey: g1Wallet.pubkey, + username: g1WalletsBox + .get(g1Wallet.pubkey) + ?.id + ?.username, + avatar: g1WalletsBox + .get(g1Wallet.pubkey) + ?.avatar, + ); + }), + ); + }), + ), + ]), + ); + } + return Center( + heightFactor: 5, + child: CircularProgressIndicator( + strokeWidth: 3, + backgroundColor: yellowC, + color: orangeC, + ), + ); + }, + ), + // Text( + // _searchProvider.searchResult.toString(), + // ) + ]), + ), + ), + ); + } +} diff --git a/lib/screens/settings.dart b/lib/screens/settings.dart index 9494df2..8211062 100644 --- a/lib/screens/settings.dart +++ b/lib/screens/settings.dart @@ -1,13 +1,11 @@ import 'package:flutter/material.dart'; import 'package:dubp/dubp.dart'; import 'package:flutter/services.dart'; -import 'package:gecko/models/home.dart'; import 'package:gecko/models/my_wallets.dart'; import 'package:gecko/screens/myWallets/generate_wallets.dart'; import 'dart:io'; -import 'package:gecko/screens/myWallets/import_wallet.dart'; +import 'package:gecko/screens/myWallets/import_cesium_wallet.dart'; import 'package:gecko/globals.dart'; -import 'package:provider/provider.dart'; // ignore: must_be_immutable class SettingsScreen extends StatelessWidget { @@ -29,7 +27,6 @@ class SettingsScreen extends StatelessWidget { @override Widget build(BuildContext context) { SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); - HomeProvider _homeProvider = Provider.of(context); // getAppDirectory(); return Scaffold( @@ -94,9 +91,7 @@ class SettingsScreen extends StatelessWidget { ), onPressed: () async => { log.i('Suppression de tous les wallets'), - await _myWallets - .deleteAllWallet(context) - .then((v) => _homeProvider.rebuildWidget()) + await _myWallets.deleteAllWallet(context) }, child: const Text("EFFACER TOUS MES PORTEFEUILLES", style: TextStyle(fontSize: 20)))))), diff --git a/lib/screens/template_screen.dart b/lib/screens/template_screen.dart index 4759e7b..e8858c7 100644 --- a/lib/screens/template_screen.dart +++ b/lib/screens/template_screen.dart @@ -1,6 +1,5 @@ import 'package:flutter/services.dart'; import 'package:gecko/globals.dart'; -import 'package:gecko/screens/home.dart'; import 'package:flutter/material.dart'; // import 'package:gecko/models/home.dart'; // import 'package:provider/provider.dart'; @@ -22,26 +21,6 @@ class TemplateScreen extends StatelessWidget { height: 22, child: Text('Template screen'), )), - floatingActionButton: SizedBox( - height: 80.0, - width: 80.0, - child: FittedBox( - child: FloatingActionButton( - heroTag: "tplButton", - onPressed: () => Navigator.push( - context, - MaterialPageRoute(builder: (context) { - return const HomeScreen(); - }), - ), - child: SizedBox( - height: 40.0, - width: 40.0, - child: Icon(Icons.home, color: Colors.grey[850]), - ), - backgroundColor: - floattingYellow, //smoothYellow, //Color.fromARGB(500, 204, 255, 255), - ))), body: SafeArea( child: Column(children: [ const SizedBox(height: 20), @@ -58,30 +37,6 @@ class TemplateScreen extends StatelessWidget { color: Colors.black, fontWeight: FontWeight.w400)), const SizedBox(height: 20), - ElevatedButton( - style: ElevatedButton.styleFrom( - primary: yellowC, // background - onPrimary: Colors.black, // foreground - ), - onPressed: () { - Navigator.push( - context, - MaterialPageRoute(builder: (context) { - return const HomeScreen(); - }), - ); - }, - child: const Text('Retour Accueil', - style: TextStyle(fontSize: 20))), - const SizedBox(height: 20), - GestureDetector( - onTap: () { - Navigator.popUntil( - context, - ModalRoute.withName('/'), - ); - }, - child: const Icon(Icons.home)) ]), )); } diff --git a/lib/screens/wallet_view.dart b/lib/screens/wallet_view.dart new file mode 100644 index 0000000..c765b64 --- /dev/null +++ b/lib/screens/wallet_view.dart @@ -0,0 +1,502 @@ +import 'dart:ui'; +import 'package:flutter/services.dart'; +import 'package:gecko/globals.dart'; +import 'package:flutter/material.dart'; +import 'package:gecko/models/cesium_plus.dart'; +import 'package:gecko/models/my_wallets.dart'; +import 'package:gecko/models/wallet_data.dart'; +import 'package:gecko/models/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 { + const WalletViewScreen( + {@required this.pubkey, this.username, this.avatar, Key key}) + : super(key: key); + final String pubkey; + final String username; + final Image avatar; + final double buttonSize = 100; + final double buttonFontSize = 18; + + @override + Widget build(BuildContext context) { + SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); + WalletsProfilesProvider _historyProvider = + Provider.of(context, listen: false); + CesiumPlusProvider _cesiumPlusProvider = + Provider.of(context, listen: false); + + return Scaffold( + resizeToAvoidBottomInset: true, + appBar: AppBar( + elevation: 0, + toolbarHeight: 60 * ratio, + title: const SizedBox( + height: 22, + child: Text('Voir un portefeuille'), + ), + ), + body: SafeArea( + child: Column(children: [ + headerProfileView(context, _historyProvider, _cesiumPlusProvider), + SizedBox(height: isTall ? 120 : 70), + Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ + Column(children: [ + SizedBox( + height: buttonSize, + child: ClipOval( + child: Material( + color: const Color(0xffFFD58D), // button color + child: InkWell( + key: const Key('viewHistory'), + splashColor: orangeC, // inkwell color + child: const Padding( + padding: EdgeInsets.all(13), + child: Image( + image: AssetImage( + '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), + ); + }), + ), + ), + ), + const SizedBox(height: 9), + Text( + "Voir\nl'historique", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: buttonFontSize, fontWeight: FontWeight.w500), + ), + ]), + Column(children: [ + SizedBox( + height: buttonSize, + child: ClipOval( + child: Material( + color: const Color(0xffFFD58D), // button color + child: InkWell( + key: const Key('copyKey'), + splashColor: orangeC, // inkwell color + child: const Padding( + padding: EdgeInsets.all(20), + child: Image( + image: AssetImage('assets/copy_key.png'), + height: 90)), + onTap: () { + Clipboard.setData(ClipboardData(text: pubkey)); + _historyProvider.snackCopyKey(context); + }), + ), + ), + ), + const SizedBox(height: 9), + Text( + "Copier\nla clef", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: buttonFontSize, fontWeight: FontWeight.w500), + ), + ]), + ]), + // FutureBuilder( + // future: _walletOptions.generateQRcode(_historyProvider.pubkey), + // builder: (context, snapshot) { + // return snapshot.data != null + // ? GestureDetector( + // key: const Key('openQrcode'), + // onTap: () { + // Navigator.push( + // context, + // MaterialPageRoute(builder: (context) { + // return AvatarFullscreen( + // Image.memory(snapshot.data), + // title: 'QrCode du profil', + // color: Colors.white, + // ); + // }), + // ); + // }, + // child: Image.memory(snapshot.data, height: 60 * ratio), + // ) + // : const Text('-', style: TextStyle(fontSize: 20)); + // }, + // ), + const Spacer(), + Container( + height: buttonSize, + decoration: BoxDecoration( + color: const Color(0xff7c94b6), + borderRadius: const BorderRadius.all(Radius.circular(100)), + border: Border.all( + color: const Color(0xFF6c4204), + width: 4, + ), + ), + child: ClipOval( + child: Material( + color: orangeC, // button color + child: InkWell( + key: const Key('pay'), + splashColor: yellowC, // inkwell color + child: const Padding( + padding: EdgeInsets.all(14), + child: Image( + image: AssetImage('assets/vector_white.png'), + )), + onTap: () { + paymentPopup(context, _historyProvider); + }), + ), + ), + ), + const SizedBox(height: 9), + Text( + "Faire un\nvirement", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: buttonFontSize, fontWeight: FontWeight.w500), + ), + SizedBox(height: isTall ? 120 : 70) + ]), + )); + } + + void paymentPopup( + BuildContext context, WalletsProfilesProvider _walletViewProvider) { + // WalletsProfilesProvider _walletViewProvider = + // Provider.of(context); + const double shapeSize = 20; + MyWalletsProvider _myWalletProvider = MyWalletsProvider(); + WalletData defaultWallet = + _myWalletProvider.getDefaultWallet(configBox.get('currentChest')); + + showModalBottomSheet( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topRight: Radius.circular(shapeSize), + topLeft: Radius.circular(shapeSize), + ), + ), + isScrollControlled: true, + context: context, + builder: (BuildContext context) { + return Padding( + padding: EdgeInsets.only( + bottom: MediaQuery.of(context).viewInsets.bottom), + child: Container( + height: 400, + decoration: const ShapeDecoration( + color: Color(0xffffeed1), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topRight: Radius.circular(shapeSize), + topLeft: Radius.circular(shapeSize), + ), + ), + ), + child: Padding( + padding: const EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Effectuer un virement', + style: TextStyle( + fontSize: 26, fontWeight: FontWeight.w700), + ), + const SizedBox(height: 20), + Text( + 'Saisissez dans le champ ci-dessous le montant à virer de ... vers ...', + style: TextStyle( + fontSize: 19, + fontWeight: FontWeight.w500, + color: Colors.grey[600]), + ), + const Spacer(), + Center( + child: Column(children: [ + TextField( + controller: _walletViewProvider.payAmount, + autofocus: true, + maxLines: 1, + textAlign: TextAlign.center, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.allow( + RegExp(r'^\d+\.?\d{0,2}')), + ], + // onChanged: (v) => _searchProvider.rebuildWidget(), + decoration: InputDecoration( + hintText: '0.00', + suffix: const Text('DU/Ğ1'), + filled: true, + fillColor: Colors.transparent, + // border: OutlineInputBorder( + // borderSide: + // BorderSide(color: Colors.grey[500], width: 2), + // borderRadius: BorderRadius.circular(8)), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.grey[500], width: 2), + borderRadius: BorderRadius.circular(8), + ), + contentPadding: const EdgeInsets.all(20), + ), + style: const TextStyle( + fontSize: 40, + color: Colors.black, + fontWeight: FontWeight.w600, + ), + ), + const SizedBox(height: 40), + // const Spacer(), + SizedBox( + width: double.infinity, + height: 60, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + elevation: 4, + primary: orangeC, // background + onPrimary: Colors.white, // foreground + ), + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return UnlockingWallet( + wallet: defaultWallet, action: "pay"); + }, + ), + ); + }, + child: const Text( + 'Effectuer le virement', + style: TextStyle( + fontSize: 20, fontWeight: FontWeight.w600), + ), + ), + ), + const SizedBox(height: 20), + ]), + ), + ]), + ), + ), + ); + }).then((value) => _walletViewProvider.payAmount.text = ''); + } + + Widget headerProfileView( + BuildContext context, + WalletsProfilesProvider _historyProvider, + CesiumPlusProvider _cesiumPlusProvider) { + const double _avatarSize = 140; + + return Column(children: [ + Container( + height: 10, + color: yellowC, + ), + Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + yellowC, + const Color(0xFFE7811A), + ], + )), + child: Padding( + padding: const EdgeInsets.only(left: 30, right: 40), + child: Row(children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row(children: [ + GestureDetector( + key: const Key('copyPubkey'), + onTap: () { + Clipboard.setData(ClipboardData(text: pubkey)); + _historyProvider.snackCopyKey(context); + }, + child: Text( + _historyProvider.getShortPubkey(pubkey), + style: const TextStyle( + fontSize: 30, + fontWeight: FontWeight.w800, + ), + ), + ), + ]), + 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), + ), + ), + ); + } + }, + ), + if (username == null && + g1WalletsBox.get(pubkey)?.username != null) + SizedBox( + width: 230, + child: Text( + g1WalletsBox.get(pubkey)?.username, + style: const TextStyle( + fontSize: 27, + color: Color(0xff814C00), + ), + ), + ), + if (username != null) + SizedBox( + width: 230, + child: Text( + username, + style: const TextStyle( + fontSize: 27, + color: Color(0xff814C00), + ), + ), + ), + const SizedBox(height: 25), + FutureBuilder( + future: _cesiumPlusProvider.getName(pubkey), + initialData: '...', + builder: (context, snapshot) { + return SizedBox( + width: 230, + child: Text( + snapshot.data ?? '-', + style: const TextStyle( + fontSize: 18, color: Colors.black), + ), + ); + }), + const SizedBox(height: 30), + ]), + const Spacer(), + Column(children: [ + if (avatar == null) + FutureBuilder( + future: _cesiumPlusProvider.getAvatar(pubkey, _avatarSize), + builder: + (BuildContext context, AsyncSnapshot _avatar) { + if (_avatar.connectionState != ConnectionState.done) { + return Stack(children: [ + ClipOval( + child: + _cesiumPlusProvider.defaultAvatar(_avatarSize), + ), + Positioned( + top: 15, + right: 45, + width: 51, + height: 51, + child: CircularProgressIndicator( + strokeWidth: 5, + color: orangeC, + ), + ), + ]); + } + if (_avatar.hasData) { + return GestureDetector( + key: const Key('openAvatar'), + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) { + return AvatarFullscreen(_avatar.data); + }), + ); + }, + child: ClipOval( + child: Image( + image: _avatar.data.image, + height: _avatarSize, + fit: BoxFit.cover, + ), + ), + ); + } + return ClipOval( + child: _cesiumPlusProvider.defaultAvatar(_avatarSize), + ); + }), + if (avatar != null) + GestureDetector( + key: const Key('openAvatar'), + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) { + return AvatarFullscreen(avatar); + }), + ); + }, + child: ClipOval( + child: Image( + image: avatar.image, + height: _avatarSize, + fit: BoxFit.cover, + ), + ), + ), + const SizedBox(height: 25), + ]), + ]), + ), + ), + ]); + } +} diff --git a/pubspec.lock b/pubspec.lock index 49c04fe..d5101a8 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -267,6 +267,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.5.6" + dio: + dependency: "direct main" + description: + name: dio + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.4" dubp: dependency: "direct main" description: @@ -544,6 +551,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.4.1" + infinite_scroll_pagination: + dependency: "direct main" + description: + name: infinite_scroll_pagination + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" integration_test: dependency: "direct dev" description: flutter @@ -878,6 +892,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.0" + pull_to_refresh: + dependency: "direct main" + description: + name: pull_to_refresh + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" qr: dependency: transitive description: @@ -1002,6 +1023,13 @@ packages: description: flutter source: sdk version: "0.0.99" + sliver_tools: + dependency: transitive + description: + name: sliver_tools + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.5" source_gen: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 7de7c38..b5124f7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,13 +5,16 @@ 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.2+11 +version: 0.0.3+13 environment: sdk: ">=2.7.0 <3.0.0" dependencies: + assorted_layout_widgets: ^5.2.1 bubble: ^1.2.1 + carousel_slider: ^4.0.0 + confirm_dialog: ^1.0.0 crypto: ^3.0.1 dubp: path: packages/dubp_rs @@ -21,14 +24,16 @@ dependencies: flutter_driver: sdk: flutter 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 hive: ^2.0.4 hive_flutter: ^1.1.0 - http: ^0.13.0 + http: ^0.13.4 image_gallery_saver: ^1.6.9 image_picker: ^0.8.4 + infinite_scroll_pagination: ^3.1.0 intl: ^0.17.0 jdenticon_dart: ^2.0.0 logger: ^1.1.0 @@ -38,7 +43,7 @@ dependencies: permission_handler: 8.1.6 pin_code_fields: ^7.3.0 printing: ^5.6.0 - provider: ^6.0.0 + provider: ^6.0.1 qrscan: ^0.3.2 responsive_builder: ^0.4.1 responsive_framework: ^0.1.4 @@ -48,15 +53,11 @@ dependencies: super_tooltip: ^1.0.1 sync_http: ^0.3.0 test: ^1.17.10 - # test_api: ^0.4.7 - # test: ^1.19.3 truncate: ^3.0.1 unorm_dart: ^0.2.0 xml: ^5.3.0 - assorted_layout_widgets: ^5.2.1 - carousel_slider: ^4.0.0 - flutter_lints: ^1.0.4 - confirm_dialog: ^1.0.0 + pull_to_refresh: ^2.0.0 + dio: ^4.0.4 flutter_icons: android: "ic_launcher" @@ -65,12 +66,12 @@ flutter_icons: cupertino_icons: ^1.0.0 dev_dependencies: + build_runner: ^2.1.2 flutter_test: sdk: flutter + hive_generator: ^1.1.1 integration_test: sdk: flutter - hive_generator: ^1.1.1 - build_runner: ^2.1.2 # The following section is specific to Flutter. flutter: @@ -80,6 +81,7 @@ flutter: - images/ - config/gva_endpoints.json - assets/ + - assets/home/ - assets/customs/ - assets/avatars/ - assets/chests/ diff --git a/scripts/build-apk.sh b/scripts/build-apk.sh index 86a0ac3..368a81e 100755 --- a/scripts/build-apk.sh +++ b/scripts/build-apk.sh @@ -20,8 +20,8 @@ if [[ $1 == "bundle" ]]; then flutter build appbundle --release --target-platform android-arm,android-arm64 --build-name $VERSION --build-number $BUILD else # flutter build apk --release --split-per-abi --target-platform android-arm,android-arm64 --build-name $VERSION --build-number $BUILD -# flutter build apk --release --split-per-abi --build-name $VERSION --build-number $BUILD - flutter build apk --release --build-name $VERSION --build-number $BUILD + flutter build apk --release --split-per-abi --build-name $VERSION --build-number $BUILD +# flutter build apk --release --build-name $VERSION --build-number $BUILD fi if [[ -d $HOME/Téléchargements ]]; then diff --git a/test_driver/app_test.dart b/test_driver/app_test.dart index e9f4c76..0efe479 100644 --- a/test_driver/app_test.dart +++ b/test_driver/app_test.dart @@ -217,8 +217,9 @@ void main() { {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."); - + await sleep(800); await tapOn('goStep10'); + await sleep(50); await tapOn('goStep11'); while (await getText('generatedPin') == '') {