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: |------------------------------------------------------------------------------|-----------------------------------------------------------------------------| |  |  | + +## 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