From f7734ce4ef98f37b73c4593ee5bc8a2441e9ca8c Mon Sep 17 00:00:00 2001
From: vjrj <vjrj@ourproject.org>
Date: Sun, 26 Feb 2023 21:35:26 +0100
Subject: [PATCH] Intro and user search

---
 README.md                                     |   8 ++
 assets/translations/en.json                   |   2 +-
 lib/config/config.dart                        |  24 ++++
 lib/main.dart                                 |  86 +++++++++++-
 lib/ui/screens/first_screen.dart              |   2 +-
 lib/ui/screens/pay_form.dart                  |   7 +-
 .../first_screen/pay_contact_search_bar.dart  |  69 +++++-----
 pubspec.lock                                  | 122 +++++++++++++++++-
 pubspec.yaml                                  |  10 ++
 9 files changed, 292 insertions(+), 38 deletions(-)

diff --git a/README.md b/README.md
index 22f408fc..52b31488 100644
--- a/README.md
+++ b/README.md
@@ -141,6 +141,14 @@ following code:
 |------------------------------------------------------------------------------|-----------------------------------------------------------------------------|
 | ![Home Dark](./assets/img/home_dark.png "The info page with a light theme.") | ![Info Dark](./assets/img/info_dark.png "The info page with a dark theme.") |
 
+
+## Credits
+
+- G1 logo
+- undraw intro images: https://undraw.co/license 
+
+Thanks!
+
 ## License
 
 MIT
diff --git a/assets/translations/en.json b/assets/translations/en.json
index 521d0f0e..edbeb767 100644
--- a/assets/translations/en.json
+++ b/assets/translations/en.json
@@ -19,7 +19,7 @@
   "g1_form_pay_hint": "Enter a description (optional)",
   "code_card_title": "Code repository",
   "intro_1_title": "Welcome to our Äž1 wallet!",
-  "intro_1_description": "With our app, you can easily and securely store, send, and receive Äž1 currency (also known as 'Juna').",
+  "intro_1_description": "With this wallet, you can easily and securely store, send, and receive Äž1 currency (also known as 'June').",
   "intro_2_title": "A digital currency created by the people, for the people",
   "intro_2_description": "Äž1 does not depend on any government or corporation and is eco-friendly (as it is low-energy consumption), transparent, and fair to all.",
   "intro_3_title": "Äž1 currency works on the Duniter network",
diff --git a/lib/config/config.dart b/lib/config/config.dart
index f482557a..d9fcb03b 100644
--- a/lib/config/config.dart
+++ b/lib/config/config.dart
@@ -1,5 +1,29 @@
 import 'package:flutter_dotenv/flutter_dotenv.dart';
+import 'package:http/http.dart' as http;
+import 'package:http/http.dart';
 
 String get duniterNet {
   return dotenv.get('NET');
 }
+
+String get duniterLookupUrl {
+  return '${duniterNet}wot/lookup/';
+}
+
+String get duniterNetworkPeers {
+  return '${duniterNet}network/peers';
+}
+
+String duniterAccountAvatar(String publickey) {
+  return '${duniterNet}node/peers/$publickey/avatar';
+}
+
+Future<String> getAvatar(String publicKey) async {
+  final String url = duniterAccountAvatar(publicKey);
+  final Response response = await http.get(Uri.parse(url));
+  if (response.statusCode == 200) {
+    return response.body;
+  } else {
+    throw Exception('Failed to load avatar');
+  }
+}
diff --git a/lib/main.dart b/lib/main.dart
index 49a9a56b..b6ab05f5 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,6 +1,7 @@
 import 'dart:io';
 
 import 'package:easy_localization/easy_localization.dart';
+import 'package:easy_logger/easy_logger.dart';
 import 'package:flutter/foundation.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
@@ -8,13 +9,29 @@ import 'package:flutter_displaymode/flutter_displaymode.dart';
 import 'package:flutter_dotenv/flutter_dotenv.dart';
 import 'package:hive_flutter/hive_flutter.dart';
 import 'package:hydrated_bloc/hydrated_bloc.dart';
+import 'package:introduction_screen/introduction_screen.dart';
 import 'package:path_provider/path_provider.dart';
 
 import 'config/theme.dart';
 import 'cubit/theme_cubit.dart';
 import 'ui/screens/skeleton_screen.dart';
 
-/// Try using const constructors as much as possible!
+// logs
+final EasyLogger logger = EasyLogger(
+  name: tr('app_name'),
+  defaultLevel: LevelMessages.debug,
+  enableBuildModes: <BuildMode>[
+    BuildMode.debug,
+    BuildMode.profile,
+    BuildMode.release
+  ],
+  enableLevels: <LevelMessages>[
+    LevelMessages.debug,
+    LevelMessages.info,
+    LevelMessages.error,
+    LevelMessages.warning
+  ],
+);
 
 void main() async {
   /// Initialize packages
@@ -25,6 +42,7 @@ void main() async {
     await FlutterDisplayMode.setHighRefreshRate();
   }
 
+  // .env
   await dotenv.load(
       fileName: kReleaseMode
           ? 'assets/env.production.txt'
@@ -55,6 +73,70 @@ void main() async {
   );
 }
 
+class AppIntro extends StatefulWidget {
+  const AppIntro({super.key});
+
+  @override
+  State<AppIntro> createState() => _AppIntro();
+}
+
+class _AppIntro extends State<AppIntro> {
+  final GlobalKey<IntroductionScreenState> introKey =
+      GlobalKey<IntroductionScreenState>();
+
+  void _onIntroEnd(BuildContext context) {
+    // Navegar a la pantalla de inicio de la aplicación después de que se complete la introducción
+    Navigator.of(context).pushReplacement(
+      MaterialPageRoute(builder: (_) => const SkeletonScreen()),
+    );
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return IntroductionScreen(
+      key: introKey,
+      pages: <PageViewModel>[
+        for (int i = 1; i <= 5; i++)
+          createPageViewModel('intro_${i}_title', 'intro_${i}_description',
+              'assets/img/undraw_intro_$i.png')
+      ],
+      onDone: () => _onIntroEnd(context),
+      showSkipButton: true,
+      skipOrBackFlex: 0,
+      nextFlex: 0,
+      // FIXME
+      skip: const Text('Saltar'),
+      next: const Icon(Icons.arrow_forward),
+      // FIXME
+      done:
+          const Text('Empezar', style: TextStyle(fontWeight: FontWeight.w600)),
+      dotsDecorator: const DotsDecorator(
+        size: Size(10.0, 10.0),
+        color: Color(0xFFBDBDBD),
+        activeColor: Colors.blueAccent,
+        activeSize: Size(22.0, 10.0),
+        activeShape: RoundedRectangleBorder(
+          borderRadius: BorderRadius.all(Radius.circular(25.0)),
+        ),
+      ),
+    );
+  }
+}
+
+PageViewModel createPageViewModel(
+    String title, String body, String imageAsset) {
+  return PageViewModel(
+    title: tr(title),
+    body: tr(body),
+    image: Image.asset(imageAsset),
+    decoration: const PageDecoration(
+      pageColor: Colors.white,
+      bodyTextStyle: TextStyle(fontSize: 18),
+      titleTextStyle: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
+    ),
+  );
+}
+
 class MyApp extends StatelessWidget {
   const MyApp({super.key});
 
@@ -78,7 +160,7 @@ class MyApp extends StatelessWidget {
             supportedLocales: context.supportedLocales,
             locale: context.locale,
             debugShowCheckedModeBanner: false,
-            home: const SkeletonScreen(),
+            home: const MediaQuery(data: MediaQueryData(), child: AppIntro()),
           );
         },
       ),
diff --git a/lib/ui/screens/first_screen.dart b/lib/ui/screens/first_screen.dart
index 908b058c..f5db04b4 100644
--- a/lib/ui/screens/first_screen.dart
+++ b/lib/ui/screens/first_screen.dart
@@ -27,7 +27,7 @@ class FirstScreen extends StatelessWidget {
               ),
             ),
             const SizedBox(height: 10),
-            const PayContactSearchBar(),
+            const PayContactSearchWidget(),
             const SizedBox(height: 10),
             const PayForm(),
           ]),
diff --git a/lib/ui/screens/pay_form.dart b/lib/ui/screens/pay_form.dart
index 2ce1bdf8..1692f3ab 100644
--- a/lib/ui/screens/pay_form.dart
+++ b/lib/ui/screens/pay_form.dart
@@ -12,7 +12,8 @@ class PayForm extends StatefulWidget {
 
 class _PayFormState extends State<PayForm> {
   final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
-  final TextEditingController _controller = TextEditingController();
+  final TextEditingController _amountController = TextEditingController();
+  final TextEditingController _descController = TextEditingController();
 
   @override
   Widget build(BuildContext context) {
@@ -21,10 +22,10 @@ class _PayFormState extends State<PayForm> {
       child: Column(
         crossAxisAlignment: CrossAxisAlignment.stretch,
         children: <Widget>[
-          G1PayAmountField(controller: _controller),
+          G1PayAmountField(controller: _amountController),
           const SizedBox(height: 10.0),
           TextField(
-            controller: _controller,
+            controller: _descController,
             decoration: InputDecoration(
               labelText: tr('g1_form_pay_desc'),
               hintText: tr('g1_form_pay_hint'),
diff --git a/lib/ui/widgets/first_screen/pay_contact_search_bar.dart b/lib/ui/widgets/first_screen/pay_contact_search_bar.dart
index bf268da2..8dac72a7 100644
--- a/lib/ui/widgets/first_screen/pay_contact_search_bar.dart
+++ b/lib/ui/widgets/first_screen/pay_contact_search_bar.dart
@@ -1,45 +1,54 @@
 import 'package:easy_localization/easy_localization.dart';
 import 'package:flutter/material.dart';
 
-class PayContactSearchBar extends StatefulWidget {
-  const PayContactSearchBar({super.key});
+import 'contact_search_dialog.dart';
+
+class PayContactSearchWidget extends StatefulWidget {
+  const PayContactSearchWidget({super.key});
 
   @override
-  State<PayContactSearchBar> createState() => _PayContactSearchBarState();
+  State<PayContactSearchWidget> createState() => _PayContactSearchWidgetState();
 }
 
-class _PayContactSearchBarState extends State<PayContactSearchBar> {
+class _PayContactSearchWidgetState extends State<PayContactSearchWidget> {
   @override
   Widget build(BuildContext context) {
-    return Container(
-      padding: const EdgeInsets.symmetric(horizontal: 16.0),
-      // color: Colors.grey[200],
-      height: 60,
-      decoration: ShapeDecoration(
-        shape: RoundedRectangleBorder(
-          borderRadius: BorderRadius.circular(4),
-          side: const BorderSide(color: Colors.grey),
-        ),
-      ),
-      child: Row(
+    return ElevatedButton.icon(
+      onPressed: () {
+        showDialog(
+          context: context,
+          builder: (BuildContext context) {
+            return const SearchDialog();
+          },
+        );
+      },
+      icon: Row(
         children: <Widget>[
           const Icon(Icons.search),
-          const SizedBox(width: 10.0),
-          Expanded(
-            child: TextField(
-              decoration:
-                  InputDecoration.collapsed(hintText: tr('search_user')),
-            ),
-          ),
-          const SizedBox(width: 10.0),
-          IconButton(
-            icon: const Icon(Icons.qr_code_scanner),
-            onPressed: () {
-              // Acción a realizar al presionar el botón de escanear código de barras
-            },
-          ),
+          const SizedBox(width: 8.0),
+          Text(tr('search_user_btn')),
         ],
       ),
+      label: const Icon(Icons.qr_code_scanner),
+      style: ElevatedButton.styleFrom(
+        backgroundColor: Colors.blue,
+        padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
+        shape: RoundedRectangleBorder(
+          borderRadius: BorderRadius.circular(6.0),
+        ),
+      ),
     );
   }
-}
+} /*
+              Expanded(
+                child: ListView.builder(
+                  itemCount: 20,
+                  itemBuilder: (BuildContext context, int index) {
+                    return ListTile(
+                      title: Text('Resultado $index'),
+                    );
+                  },
+                ),
+              ),
+
+    */
diff --git a/pubspec.lock b/pubspec.lock
index 35e866f2..6e73e760 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -73,6 +73,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "3.0.2"
+  dots_indicator:
+    dependency: transitive
+    description:
+      name: dots_indicator
+      sha256: e59dfc90030ee5a4fd4c53144a8ce97cc7a823c2067b8fb9814960cd1ae63f89
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.1.0"
   easy_localization:
     dependency: "direct main"
     description:
@@ -82,7 +90,7 @@ packages:
     source: hosted
     version: "3.0.1"
   easy_logger:
-    dependency: transitive
+    dependency: "direct main"
     description:
       name: easy_logger
       sha256: c764a6e024846f33405a2342caf91c62e357c24b02c04dbc712ef232bf30ffb7
@@ -134,6 +142,14 @@ packages:
     description: flutter
     source: sdk
     version: "0.0.0"
+  flutter_barcode_scanner:
+    dependency: transitive
+    description:
+      name: flutter_barcode_scanner
+      sha256: a4ba37daf9933f451a5e812c753ddd045d6354e4a3280342d895b07fecaab3fa
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.0.0"
   flutter_bloc:
     dependency: "direct main"
     description:
@@ -171,6 +187,14 @@ packages:
     description: flutter
     source: sdk
     version: "0.0.0"
+  flutter_plugin_android_lifecycle:
+    dependency: transitive
+    description:
+      name: flutter_plugin_android_lifecycle
+      sha256: "4bef634684b2c7f3468c77c766c831229af829a0cd2d4ee6c1b99558bd14e5d2"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.0.8"
   flutter_svg:
     dependency: "direct main"
     description:
@@ -205,6 +229,22 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.1.0"
+  http:
+    dependency: "direct main"
+    description:
+      name: http
+      sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482"
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.13.5"
+  http_parser:
+    dependency: transitive
+    description:
+      name: http_parser
+      sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
+      url: "https://pub.dev"
+    source: hosted
+    version: "4.0.2"
   hydrated_bloc:
     dependency: "direct main"
     description:
@@ -221,6 +261,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "0.17.0"
+  introduction_screen:
+    dependency: "direct main"
+    description:
+      name: introduction_screen
+      sha256: ffbae2e9e1e21e1d8d6a898385f11513c23f6e83436f78c26664f7f002a58caa
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.1.6"
   ionicons:
     dependency: "direct main"
     description:
@@ -357,6 +405,46 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "2.1.3"
+  permission_handler:
+    dependency: transitive
+    description:
+      name: permission_handler
+      sha256: "33c6a1253d1f95fd06fa74b65b7ba907ae9811f9d5c1d3150e51417d04b8d6a8"
+      url: "https://pub.dev"
+    source: hosted
+    version: "10.2.0"
+  permission_handler_android:
+    dependency: transitive
+    description:
+      name: permission_handler_android
+      sha256: "8028362b40c4a45298f1cbfccd227c8dd6caf0e27088a69f2ba2ab15464159e2"
+      url: "https://pub.dev"
+    source: hosted
+    version: "10.2.0"
+  permission_handler_apple:
+    dependency: transitive
+    description:
+      name: permission_handler_apple
+      sha256: "9c370ef6a18b1c4b2f7f35944d644a56aa23576f23abee654cf73968de93f163"
+      url: "https://pub.dev"
+    source: hosted
+    version: "9.0.7"
+  permission_handler_platform_interface:
+    dependency: transitive
+    description:
+      name: permission_handler_platform_interface
+      sha256: "68abbc472002b5e6dfce47fe9898c6b7d8328d58b5d2524f75e277c07a97eb84"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.9.0"
+  permission_handler_windows:
+    dependency: transitive
+    description:
+      name: permission_handler_windows
+      sha256: f67cab14b4328574938ecea2db3475dad7af7ead6afab6338772c5f88963e38b
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.1.2"
   petitparser:
     dependency: transitive
     description:
@@ -397,6 +485,22 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "6.0.5"
+  qr:
+    dependency: transitive
+    description:
+      name: qr
+      sha256: "5c4208b4dc0d55c3184d10d83ee0ded6212dc2b5e2ba17c5a0c0aab279128d21"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.1.0"
+  qr_flutter:
+    dependency: "direct main"
+    description:
+      name: qr_flutter
+      sha256: c5c121c54cb6dd837b9b9d57eb7bc7ec6df4aee741032060c8833a678c80b87e
+      url: "https://pub.dev"
+    source: hosted
+    version: "4.0.0"
   shared_preferences:
     dependency: transitive
     description:
@@ -453,6 +557,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "2.1.2"
+  simple_barcode_scanner:
+    dependency: "direct main"
+    description:
+      name: simple_barcode_scanner
+      sha256: "2549a5a1426e2e3edb4fa2cd876fcf8463e09220cd36b5207742bc53e1d10fa6"
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.0.8"
   sky_engine:
     dependency: transitive
     description: flutter
@@ -618,6 +730,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "2.1.4"
+  webview_windows:
+    dependency: transitive
+    description:
+      name: webview_windows
+      sha256: a6d76f9f020e638c2e5417f473e2907c097d1fe3eac8bd4be7517bc3a0df6b86
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.2.2"
   win32:
     dependency: transitive
     description:
diff --git a/pubspec.yaml b/pubspec.yaml
index 3928ae39..5adec464 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -39,6 +39,11 @@ dependencies:
   material_design_icons_flutter: ^6.0.7096
   flutter_svg: ^2.0.2
   flutter_dotenv: ^5.0.2
+  http: ^0.13.5
+  easy_logger: ^0.0.2
+  qr_flutter: ^4.0.0
+  simple_barcode_scanner: ^0.0.8
+  introduction_screen: ^3.1.6
 
 dev_dependencies:
   flutter_test:
@@ -61,6 +66,11 @@ flutter:
     - assets/img/gbrevedot.svg
     - assets/.env.development
     - assets/.env.production
+    - assets/img/undraw_intro_1.png
+    - assets/img/undraw_intro_2.png
+    - assets/img/undraw_intro_3.png
+    - assets/img/undraw_intro_4.png
+    - assets/img/undraw_intro_5.png
 
   fonts:
     - family: Nunito
-- 
GitLab