From a4725285b337e06a6102c04047b729c910dd4751 Mon Sep 17 00:00:00 2001 From: Rui Miguel Alonso Date: Wed, 22 Nov 2023 14:37:27 +0100 Subject: [PATCH] feat: initial screen (#9) --- lib/app/view/app.dart | 4 +- lib/counter/counter.dart | 1 - lib/counter/view/counter_page.dart | 53 ----- lib/home/home.dart | 2 + lib/home/view/home_page.dart | 61 ++++++ lib/home/widgets/background.dart | 141 ++++++++++++ lib/home/widgets/logo.dart | 36 ++++ lib/home/widgets/welcome_view.dart | 36 ++++ lib/home/widgets/widgets.dart | 3 + lib/l10n/arb/app_en.arb | 18 +- lib/l10n/arb/app_es.arb | 7 - .../app_ui/assets/icons/arrow_forward.png | Bin 0 -> 196 bytes packages/app_ui/assets/icons/asterisk.png | Bin 0 -> 300 bytes packages/app_ui/lib/app_ui.dart | 5 + .../app_ui/lib/src/generated/assets.gen.dart | 105 +++++++++ .../app_ui/lib/src/widgets/cta_button.dart | 59 ++++++ packages/app_ui/lib/src/widgets/widgets.dart | 1 + packages/app_ui/pubspec.yaml | 14 ++ .../app_ui/test/src/analysis_options.yaml | 4 + packages/app_ui/test/src/helpers/helpers.dart | 1 + .../app_ui/test/src/helpers/pump_app.dart | 12 ++ .../test/src/widgets/cta_button_test.dart | 37 ++++ pubspec.lock | 200 ++++++++++++++++++ pubspec.yaml | 6 + test/analysis_options.yaml | 4 + test/app/view/app_test.dart | 6 +- test/counter/view/counter_page_test.dart | 13 -- test/home/view/home_page_test.dart | 18 ++ test/home/widgets/background_test.dart | 27 +++ test/home/widgets/logo_test.dart | 22 ++ test/home/widgets/welcome_view_test.dart | 21 ++ 31 files changed, 835 insertions(+), 82 deletions(-) delete mode 100644 lib/counter/counter.dart delete mode 100644 lib/counter/view/counter_page.dart create mode 100644 lib/home/home.dart create mode 100644 lib/home/view/home_page.dart create mode 100644 lib/home/widgets/background.dart create mode 100644 lib/home/widgets/logo.dart create mode 100644 lib/home/widgets/welcome_view.dart create mode 100644 lib/home/widgets/widgets.dart delete mode 100644 lib/l10n/arb/app_es.arb create mode 100644 packages/app_ui/assets/icons/arrow_forward.png create mode 100644 packages/app_ui/assets/icons/asterisk.png create mode 100644 packages/app_ui/lib/src/generated/assets.gen.dart create mode 100644 packages/app_ui/lib/src/widgets/cta_button.dart create mode 100644 packages/app_ui/test/src/analysis_options.yaml create mode 100644 packages/app_ui/test/src/helpers/helpers.dart create mode 100644 packages/app_ui/test/src/helpers/pump_app.dart create mode 100644 packages/app_ui/test/src/widgets/cta_button_test.dart create mode 100644 test/analysis_options.yaml delete mode 100644 test/counter/view/counter_page_test.dart create mode 100644 test/home/view/home_page_test.dart create mode 100644 test/home/widgets/background_test.dart create mode 100644 test/home/widgets/logo_test.dart create mode 100644 test/home/widgets/welcome_view_test.dart diff --git a/lib/app/view/app.dart b/lib/app/view/app.dart index 246797c..47e10f4 100644 --- a/lib/app/view/app.dart +++ b/lib/app/view/app.dart @@ -1,5 +1,5 @@ import 'package:api_client/api_client.dart'; -import 'package:dash_ai_search/counter/counter.dart'; +import 'package:dash_ai_search/home/home.dart'; import 'package:dash_ai_search/l10n/l10n.dart'; import 'package:flutter/material.dart'; @@ -22,7 +22,7 @@ class App extends StatelessWidget { ), localizationsDelegates: AppLocalizations.localizationsDelegates, supportedLocales: AppLocalizations.supportedLocales, - home: const CounterPage(), + home: const HomePage(), ); } } diff --git a/lib/counter/counter.dart b/lib/counter/counter.dart deleted file mode 100644 index c1f6927..0000000 --- a/lib/counter/counter.dart +++ /dev/null @@ -1 +0,0 @@ -export 'view/counter_page.dart'; diff --git a/lib/counter/view/counter_page.dart b/lib/counter/view/counter_page.dart deleted file mode 100644 index 3a131ad..0000000 --- a/lib/counter/view/counter_page.dart +++ /dev/null @@ -1,53 +0,0 @@ -import 'package:app_ui/app_ui.dart'; -import 'package:dash_ai_search/l10n/l10n.dart'; -import 'package:flutter/material.dart'; - -class CounterPage extends StatelessWidget { - const CounterPage({super.key}); - - @override - Widget build(BuildContext context) { - return const CounterView(); - } -} - -class CounterView extends StatelessWidget { - const CounterView({super.key}); - - @override - Widget build(BuildContext context) { - final l10n = context.l10n; - final screenSize = MediaQuery.sizeOf(context); - return Scaffold( - appBar: AppBar(title: Text(l10n.counterAppBarTitle)), - body: Center( - child: Container( - alignment: Alignment.center, - height: screenSize.height / 2, - width: screenSize.height / 2, - child: const DashAnimation(), - ), - ), - ); - } -} - -class DashAnimation extends StatelessWidget { - @visibleForTesting - const DashAnimation({super.key}); - - static const dashSize = Size(800, 800); - - @override - Widget build(BuildContext context) { - return const AnimatedSprite( - showLoadingIndicator: false, - sprites: Sprites( - asset: 'dash_animation.png', - size: dashSize, - frames: 34, - stepTime: 0.07, - ), - ); - } -} diff --git a/lib/home/home.dart b/lib/home/home.dart new file mode 100644 index 0000000..4434705 --- /dev/null +++ b/lib/home/home.dart @@ -0,0 +1,2 @@ +export 'view/home_page.dart'; +export 'widgets/widgets.dart'; diff --git a/lib/home/view/home_page.dart b/lib/home/view/home_page.dart new file mode 100644 index 0000000..f516626 --- /dev/null +++ b/lib/home/view/home_page.dart @@ -0,0 +1,61 @@ +import 'package:app_ui/app_ui.dart'; +import 'package:dash_ai_search/home/home.dart'; +import 'package:flutter/material.dart'; + +class HomePage extends StatelessWidget { + const HomePage({super.key}); + + @override + Widget build(BuildContext context) { + return const Scaffold( + backgroundColor: Color(0xFFF8FAFF), + body: Stack( + children: [ + Positioned( + top: 0, + bottom: 0, + child: Background(), + ), + Positioned( + top: 40, + left: 48, + child: Logo(), + ), + WelcomeView(), + Positioned( + bottom: 50, + left: 50, + child: DashAnimation(), + ), + ], + ), + ); + } +} + +class DashAnimation extends StatelessWidget { + @visibleForTesting + const DashAnimation({super.key}); + + static const dashSize = Size(800, 800); + + @override + Widget build(BuildContext context) { + final screenSize = MediaQuery.sizeOf(context); + + return Container( + alignment: Alignment.center, + height: screenSize.height / 3, + width: screenSize.height / 3, + child: const AnimatedSprite( + showLoadingIndicator: false, + sprites: Sprites( + asset: 'dash_animation.png', + size: dashSize, + frames: 34, + stepTime: 0.07, + ), + ), + ); + } +} diff --git a/lib/home/widgets/background.dart b/lib/home/widgets/background.dart new file mode 100644 index 0000000..e224545 --- /dev/null +++ b/lib/home/widgets/background.dart @@ -0,0 +1,141 @@ +import 'package:flutter/material.dart'; +import 'package:path_drawing/path_drawing.dart'; + +class Background extends StatelessWidget { + const Background({super.key}); + + @override + Widget build(BuildContext context) { + const leftOffset = -50.0; + const baseRadius = 303.0; + const baseMediumRadius = 255.0; + const baseSmallRadius = 185.0; + const horizontalOffset = baseRadius * 2; + + return const SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + children: [ + Circle( + offset: Offset(leftOffset, 0), + ), + Circle( + offset: Offset(horizontalOffset + leftOffset, 0), + child: Circle( + offset: Offset(horizontalOffset + leftOffset, 0), + radius: baseMediumRadius, + borderColor: Color(0xFFDDE2F6), + child: Circle( + offset: Offset(horizontalOffset + leftOffset, 0), + radius: baseSmallRadius, + borderColor: Color(0xFFDDE2F6), + dotted: true, + ), + ), + ), + Circle( + offset: Offset(horizontalOffset * 2 + leftOffset, 0), + ), + Circle( + offset: Offset(horizontalOffset * 3 + leftOffset, 0), + ), + ], + ), + ); + } +} + +class Circle extends StatelessWidget { + @visibleForTesting + const Circle({ + this.offset = Offset.zero, + this.radius = 303, + this.borderColor = Colors.white, + this.dotted = false, + this.child, + super.key, + }); + + final Offset offset; + final double radius; + final Color borderColor; + final bool dotted; + final Widget? child; + + @override + Widget build(BuildContext context) { + return CustomPaint( + painter: CirclePainter( + offset: offset, + radius: radius, + borderColor: borderColor, + dotted: dotted, + ), + child: child, + ); + } +} + +class CirclePainter extends CustomPainter { + CirclePainter({ + required this.offset, + required this.radius, + required this.borderColor, + required this.dotted, + }) { + _paintCircle = Paint() + ..color = Colors.white + ..style = PaintingStyle.fill; + _paintBorder = Paint() + ..color = borderColor + ..strokeWidth = 2 + ..strokeCap = StrokeCap.butt + ..style = PaintingStyle.stroke; + } + + final Offset offset; + final double radius; + final Color borderColor; + final bool dotted; + + late final Paint _paintCircle; + late final Paint _paintBorder; + + @override + void paint(Canvas canvas, Size size) { + canvas.drawCircle( + offset, + radius, + _paintCircle, + ); + + if (dotted) { + const dashPattern = [4, 4]; + final s = radius * 2; + + var path = Path() + ..addRRect( + RRect.fromRectAndRadius( + Rect.fromLTWH( + offset.dx - s / 2, + offset.dy / 2 - s / 2, + s, + s, + ), + Radius.circular(s / 2), + ), + ); + path = dashPath(path, dashArray: CircularIntervalList(dashPattern)); + canvas.drawPath(path, _paintBorder); + } else { + canvas.drawCircle( + offset, + radius, + _paintBorder, + ); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) => false; +} diff --git a/lib/home/widgets/logo.dart b/lib/home/widgets/logo.dart new file mode 100644 index 0000000..c72a584 --- /dev/null +++ b/lib/home/widgets/logo.dart @@ -0,0 +1,36 @@ +import 'package:app_ui/app_ui.dart'; +import 'package:dash_ai_search/l10n/l10n.dart'; +import 'package:flutter/material.dart'; + +class Logo extends StatelessWidget { + const Logo({super.key}); + + @override + Widget build(BuildContext context) { + final l10n = context.l10n; + + return Row( + children: [ + Text( + l10n.vertexAI, + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.w400, + color: Colors.black, + ), + ), + const SizedBox(width: 4), + vertexIcons.asterisk.image(), + const SizedBox(width: 4), + Text( + l10n.flutter, + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.w400, + color: Colors.black, + ), + ), + ], + ); + } +} diff --git a/lib/home/widgets/welcome_view.dart b/lib/home/widgets/welcome_view.dart new file mode 100644 index 0000000..8633644 --- /dev/null +++ b/lib/home/widgets/welcome_view.dart @@ -0,0 +1,36 @@ +import 'package:app_ui/app_ui.dart'; +import 'package:dash_ai_search/l10n/l10n.dart'; +import 'package:flutter/material.dart'; + +class WelcomeView extends StatelessWidget { + const WelcomeView({super.key}); + + @override + Widget build(BuildContext context) { + final l10n = context.l10n; + + return Center( + child: SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + l10n.initialScreenTitle, + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: 72, + fontWeight: FontWeight.w700, + color: Color(0xFF020F30), + ), + ), + const SizedBox(height: 40), + CTAButton( + icon: vertexIcons.arrowForward.image(), + label: l10n.startAsking, + ), + ], + ), + ), + ); + } +} diff --git a/lib/home/widgets/widgets.dart b/lib/home/widgets/widgets.dart new file mode 100644 index 0000000..47cbead --- /dev/null +++ b/lib/home/widgets/widgets.dart @@ -0,0 +1,3 @@ +export 'background.dart'; +export 'logo.dart'; +export 'welcome_view.dart'; diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index a5484a0..364c612 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -1,7 +1,19 @@ { "@@locale": "en", - "counterAppBarTitle": "Counter", - "@counterAppBarTitle": { - "description": "Text shown in the AppBar of the Counter Page" + "vertexAI": "Vertex AI", + "@vertexAI": { + "description": "Vertex AI text on logo" + }, + "flutter": "Flutter", + "@flutter": { + "description": "Flutter text on logo" + }, + "initialScreenTitle": "Ask a question, get \nthe right answer, with \nGoogle Vertex AI", + "@initialScreenTitle": { + "description": "Title shown on Initial screen" + }, + "startAsking": "Start asking", + "@startAsking": { + "description": "Button text for start asking" } } \ No newline at end of file diff --git a/lib/l10n/arb/app_es.arb b/lib/l10n/arb/app_es.arb deleted file mode 100644 index f1405f0..0000000 --- a/lib/l10n/arb/app_es.arb +++ /dev/null @@ -1,7 +0,0 @@ -{ - "@@locale": "es", - "counterAppBarTitle": "Contador", - "@counterAppBarTitle": { - "description": "Texto mostrado en la AppBar de la página del contador" - } -} \ No newline at end of file diff --git a/packages/app_ui/assets/icons/arrow_forward.png b/packages/app_ui/assets/icons/arrow_forward.png new file mode 100644 index 0000000000000000000000000000000000000000..00caafe03eb907ec67e70d0a47da2eba219f187c GIT binary patch literal 196 zcmeAS@N?(olHy`uVBq!ia0vp^l0YoM!3HGxw}u@9Qk(@Ik;M!Q+`=Ht$S`Y;1W=H% zILO_JVcj{Imp~3nx}&cn1H;CC?mvmFKz^jBi(^Oy``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eB{y|R{$B+ufqmv!^nhXS7>p6S9J@&ZAR&keC zdEBjJDc5^x>vPJlafwl8)-At49`3qBi{}39Kl3NV#yWeW1FP68?FYY@@?`%p&qz?X zdz>M;p5fNU#QzMl=9#}bcs0m_Wd%#Y%En-6=Myz1>%zJv6pAz}4zDYDo>q_++Vqln zLF>yW>r33Na*{Srde_%$5dKhNv%5w3lW4kJ;UJX>gTe~DWM4fd3|qa literal 0 HcmV?d00001 diff --git a/packages/app_ui/lib/app_ui.dart b/packages/app_ui/lib/app_ui.dart index 9ef06cd..fbff115 100644 --- a/packages/app_ui/lib/app_ui.dart +++ b/packages/app_ui/lib/app_ui.dart @@ -1 +1,6 @@ +import 'package:app_ui/src/generated/assets.gen.dart'; + export 'src/widgets/widgets.dart'; + +/// Global reference to actual app_ui icons. +const vertexIcons = Assets.icons; diff --git a/packages/app_ui/lib/src/generated/assets.gen.dart b/packages/app_ui/lib/src/generated/assets.gen.dart new file mode 100644 index 0000000..b05f67f --- /dev/null +++ b/packages/app_ui/lib/src/generated/assets.gen.dart @@ -0,0 +1,105 @@ +/// GENERATED CODE - DO NOT MODIFY BY HAND +/// ***************************************************** +/// FlutterGen +/// ***************************************************** + +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: directives_ordering,unnecessary_import,implicit_dynamic_list_literal,deprecated_member_use + +import 'package:flutter/widgets.dart'; + +class $AssetsIconsGen { + const $AssetsIconsGen(); + + /// File path: assets/icons/arrow_forward.png + AssetGenImage get arrowForward => + const AssetGenImage('assets/icons/arrow_forward.png'); + + /// File path: assets/icons/asterisk.png + AssetGenImage get asterisk => + const AssetGenImage('assets/icons/asterisk.png'); + + /// List of all assets + List get values => [arrowForward, asterisk]; +} + +class Assets { + Assets._(); + + static const $AssetsIconsGen icons = $AssetsIconsGen(); +} + +class AssetGenImage { + const AssetGenImage(this._assetName); + + final String _assetName; + + Image image({ + Key? key, + AssetBundle? bundle, + ImageFrameBuilder? frameBuilder, + ImageErrorWidgetBuilder? errorBuilder, + String? semanticLabel, + bool excludeFromSemantics = false, + double? scale, + double? width, + double? height, + Color? color, + Animation? opacity, + BlendMode? colorBlendMode, + BoxFit? fit, + AlignmentGeometry alignment = Alignment.center, + ImageRepeat repeat = ImageRepeat.noRepeat, + Rect? centerSlice, + bool matchTextDirection = false, + bool gaplessPlayback = false, + bool isAntiAlias = false, + String? package = 'app_ui', + FilterQuality filterQuality = FilterQuality.low, + int? cacheWidth, + int? cacheHeight, + }) { + return Image.asset( + _assetName, + key: key, + bundle: bundle, + frameBuilder: frameBuilder, + errorBuilder: errorBuilder, + semanticLabel: semanticLabel, + excludeFromSemantics: excludeFromSemantics, + scale: scale, + width: width, + height: height, + color: color, + opacity: opacity, + colorBlendMode: colorBlendMode, + fit: fit, + alignment: alignment, + repeat: repeat, + centerSlice: centerSlice, + matchTextDirection: matchTextDirection, + gaplessPlayback: gaplessPlayback, + isAntiAlias: isAntiAlias, + package: package, + filterQuality: filterQuality, + cacheWidth: cacheWidth, + cacheHeight: cacheHeight, + ); + } + + ImageProvider provider({ + AssetBundle? bundle, + String? package = 'app_ui', + }) { + return AssetImage( + _assetName, + bundle: bundle, + package: package, + ); + } + + String get path => _assetName; + + String get keyName => 'packages/app_ui/$_assetName'; +} diff --git a/packages/app_ui/lib/src/widgets/cta_button.dart b/packages/app_ui/lib/src/widgets/cta_button.dart new file mode 100644 index 0000000..79f3b9c --- /dev/null +++ b/packages/app_ui/lib/src/widgets/cta_button.dart @@ -0,0 +1,59 @@ +import 'package:flutter/material.dart'; + +/// {@template cta_button} +/// A button that displays an image on the left side and a text on the right +/// side. +/// {@endtemplate} +class CTAButton extends StatelessWidget { + /// {@macro cta_button} + const CTAButton({ + required this.label, + this.icon, + this.onPressed, + super.key, + }); + + /// The image that will be displayed on the left side of the button. + final Image? icon; + + /// The text that will be displayed on the right side of the button. + final String label; + + /// The callback that will be called when the button is tapped. + final VoidCallback? onPressed; + + @override + Widget build(BuildContext context) { + return ElevatedButton( + onPressed: onPressed, + style: const ButtonStyle( + backgroundColor: MaterialStatePropertyAll( + Color(0xFF0273E6), + ), + padding: MaterialStatePropertyAll( + EdgeInsets.only( + left: 24, + top: 20, + bottom: 20, + right: 32, + ), + ), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + if (icon != null) icon!, + Text( + label, + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.w500, + color: Colors.white, + ), + ), + ], + ), + ); + } +} diff --git a/packages/app_ui/lib/src/widgets/widgets.dart b/packages/app_ui/lib/src/widgets/widgets.dart index 08e3705..036ed92 100644 --- a/packages/app_ui/lib/src/widgets/widgets.dart +++ b/packages/app_ui/lib/src/widgets/widgets.dart @@ -1,3 +1,4 @@ export 'animated_sprite.dart'; export 'app_animated_cross_fade.dart'; export 'app_circular_progress_indicator.dart'; +export 'cta_button.dart'; diff --git a/packages/app_ui/pubspec.yaml b/packages/app_ui/pubspec.yaml index e7109d2..f2802c4 100644 --- a/packages/app_ui/pubspec.yaml +++ b/packages/app_ui/pubspec.yaml @@ -13,7 +13,21 @@ dependencies: sdk: flutter dev_dependencies: + build_runner: ^2.4.6 flutter_test: sdk: flutter + flutter_gen_runner: ^5.3.2 mocktail: ^1.0.0 very_good_analysis: ^5.1.0 + +flutter_gen: + assets: + outputs: + package_parameter_enabled: true + output: lib/src/generated/ + line_length: 80 + +flutter: + uses-material-design: true + assets: + - assets/icons/ diff --git a/packages/app_ui/test/src/analysis_options.yaml b/packages/app_ui/test/src/analysis_options.yaml new file mode 100644 index 0000000..453605c --- /dev/null +++ b/packages/app_ui/test/src/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:very_good_analysis/analysis_options.5.1.0.yaml +linter: + rules: + prefer_const_constructors: false \ No newline at end of file diff --git a/packages/app_ui/test/src/helpers/helpers.dart b/packages/app_ui/test/src/helpers/helpers.dart new file mode 100644 index 0000000..b15fe65 --- /dev/null +++ b/packages/app_ui/test/src/helpers/helpers.dart @@ -0,0 +1 @@ +export 'pump_app.dart'; diff --git a/packages/app_ui/test/src/helpers/pump_app.dart b/packages/app_ui/test/src/helpers/pump_app.dart new file mode 100644 index 0000000..461f44a --- /dev/null +++ b/packages/app_ui/test/src/helpers/pump_app.dart @@ -0,0 +1,12 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +extension PumpApp on WidgetTester { + Future pumpApp(Widget widget) { + return pumpWidget( + MaterialApp( + home: widget, + ), + ); + } +} diff --git a/packages/app_ui/test/src/widgets/cta_button_test.dart b/packages/app_ui/test/src/widgets/cta_button_test.dart new file mode 100644 index 0000000..c529ada --- /dev/null +++ b/packages/app_ui/test/src/widgets/cta_button_test.dart @@ -0,0 +1,37 @@ +import 'package:app_ui/app_ui.dart'; +import 'package:app_ui/src/generated/assets.gen.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../helpers/helpers.dart'; + +void main() { + group('CTAButton', () { + testWidgets('renders correctly', (tester) async { + await tester.pumpApp( + CTAButton( + icon: Assets.icons.arrowForward.image(), + label: 'label', + ), + ); + + expect(find.text('label'), findsOneWidget); + }); + + testWidgets('calls onPressed when tap', (tester) async { + var called = false; + + await tester.pumpApp( + CTAButton( + icon: Assets.icons.arrowForward.image(), + label: 'label', + onPressed: () { + called = true; + }, + ), + ); + + await tester.tap(find.byType(CTAButton)); + expect(called, isTrue); + }); + }); +} diff --git a/pubspec.lock b/pubspec.lock index e6e07b6..3faf121 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -71,6 +71,70 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.1" + build: + dependency: transitive + description: + name: build + sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + build_config: + dependency: transitive + description: + name: build_config + sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 + url: "https://pub.dev" + source: hosted + version: "1.1.1" + build_daemon: + dependency: transitive + description: + name: build_daemon + sha256: "0343061a33da9c5810b2d6cee51945127d8f4c060b7fbdd9d54917f0a3feaaa1" + url: "https://pub.dev" + source: hosted + version: "4.0.1" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + sha256: "64e12b0521812d1684b1917bc80945625391cb9bdd4312536b1d69dcb6133ed8" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + build_runner: + dependency: "direct dev" + description: + name: build_runner + sha256: "10c6bcdbf9d049a0b666702cf1cee4ddfdc38f02a19d35ae392863b47519848b" + url: "https://pub.dev" + source: hosted + version: "2.4.6" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + sha256: c9e32d21dd6626b5c163d48b037ce906bbe428bc23ab77bcd77bb21e593b6185 + url: "https://pub.dev" + source: hosted + version: "7.2.11" + built_collection: + dependency: transitive + description: + name: built_collection + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + sha256: "723b4021e903217dfc445ec4cf5b42e27975aece1fc4ebbc1ca6329c2d9fb54e" + url: "https://pub.dev" + source: hosted + version: "8.7.0" characters: dependency: transitive description: @@ -79,6 +143,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.0" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + url: "https://pub.dev" + source: hosted + version: "2.0.3" clock: dependency: transitive description: @@ -87,6 +159,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.1" + code_builder: + dependency: transitive + description: + name: code_builder + sha256: b2151ce26a06171005b379ecff6e08d34c470180ffe16b8e14b6d52be292b55f + url: "https://pub.dev" + source: hosted + version: "4.8.0" collection: dependency: transitive description: @@ -95,6 +175,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.18.0" + color: + dependency: transitive + description: + name: color + sha256: ddcdf1b3badd7008233f5acffaf20ca9f5dc2cd0172b75f68f24526a5f5725cb + url: "https://pub.dev" + source: hosted + version: "3.0.0" convert: dependency: transitive description: @@ -119,6 +207,22 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.3" + dart_style: + dependency: transitive + description: + name: dart_style + sha256: "40ae61a5d43feea6d24bd22c0537a6629db858963b99b4bc1c3db80676f32368" + url: "https://pub.dev" + source: hosted + version: "2.3.4" + dartx: + dependency: transitive + description: + name: dartx + sha256: "8b25435617027257d43e6508b5fe061012880ddfdaa75a71d607c3de2a13d244" + url: "https://pub.dev" + source: hosted + version: "1.2.0" diff_match_patch: dependency: transitive description: @@ -151,6 +255,14 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.0" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + url: "https://pub.dev" + source: hosted + version: "1.1.0" flame: dependency: "direct main" description: @@ -172,6 +284,22 @@ packages: url: "https://pub.dev" source: hosted version: "8.1.3" + flutter_gen_core: + dependency: transitive + description: + name: flutter_gen_core + sha256: "8b4ff1d45d125e576e26ea99d15e0419bb3c45b53696e022880866b78bb6b830" + url: "https://pub.dev" + source: hosted + version: "5.3.2" + flutter_gen_runner: + dependency: "direct dev" + description: + name: flutter_gen_runner + sha256: fd197f8c657e79313d53d3934de602ebe604ba722a84c88ae3a43cd90428c67a + url: "https://pub.dev" + source: hosted + version: "5.3.2" flutter_localizations: dependency: "direct main" description: flutter @@ -198,6 +326,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.2" + graphs: + dependency: transitive + description: + name: graphs + sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 + url: "https://pub.dev" + source: hosted + version: "2.3.1" http: dependency: transitive description: @@ -342,6 +478,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.8.3" + path_drawing: + dependency: "direct main" + description: + name: path_drawing + sha256: bbb1934c0cbb03091af082a6389ca2080345291ef07a5fa6d6e078ba8682f977 + url: "https://pub.dev" + source: hosted + version: "1.0.1" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf + url: "https://pub.dev" + source: hosted + version: "1.0.1" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: eeb2d1428ee7f4170e2bd498827296a18d4e7fc462b71727d111c0ac7707cfa6 + url: "https://pub.dev" + source: hosted + version: "6.0.1" pool: dependency: transitive description: @@ -366,6 +526,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367 + url: "https://pub.dev" + source: hosted + version: "1.2.3" shelf: dependency: transitive description: @@ -443,6 +611,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.2" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + url: "https://pub.dev" + source: hosted + version: "2.1.0" string_scanner: dependency: transitive description: @@ -483,6 +659,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.5.9" + time: + dependency: transitive + description: + name: time + sha256: "83427e11d9072e038364a5e4da559e85869b227cf699a541be0da74f14140124" + url: "https://pub.dev" + source: hosted + version: "2.1.3" + timing: + dependency: transitive + description: + name: timing + sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" + url: "https://pub.dev" + source: hosted + version: "1.0.1" typed_data: dependency: transitive description: @@ -547,6 +739,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.1" + xml: + dependency: transitive + description: + name: xml + sha256: af5e77e9b83f2f4adc5d3f0a4ece1c7f45a2467b695c2540381bac793e34e556 + url: "https://pub.dev" + source: hosted + version: "6.4.2" yaml: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 3e9da00..ed40e79 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -20,14 +20,20 @@ dependencies: flutter_localizations: sdk: flutter intl: ^0.18.0 + path_drawing: ^1.0.1 dev_dependencies: bloc_test: ^9.1.4 + build_runner: ^2.4.6 + flutter_gen_runner: ^5.3.2 flutter_test: sdk: flutter mocktail: ^1.0.0 very_good_analysis: ^5.1.0 +flutter_gen: + line_length: 80 # + flutter: uses-material-design: true generate: true diff --git a/test/analysis_options.yaml b/test/analysis_options.yaml new file mode 100644 index 0000000..453605c --- /dev/null +++ b/test/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:very_good_analysis/analysis_options.5.1.0.yaml +linter: + rules: + prefer_const_constructors: false \ No newline at end of file diff --git a/test/app/view/app_test.dart b/test/app/view/app_test.dart index 8052a14..5fcad3e 100644 --- a/test/app/view/app_test.dart +++ b/test/app/view/app_test.dart @@ -1,6 +1,6 @@ import 'package:api_client/api_client.dart'; import 'package:dash_ai_search/app/app.dart'; -import 'package:dash_ai_search/counter/counter.dart'; +import 'package:dash_ai_search/home/home.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; @@ -14,13 +14,13 @@ void main() { apiClient = _MockApiClient(); }); - testWidgets('renders CounterPage', (tester) async { + testWidgets('renders HomePage', (tester) async { await tester.pumpWidget( App( apiClient: apiClient, ), ); - expect(find.byType(CounterPage), findsOneWidget); + expect(find.byType(HomePage), findsOneWidget); }); }); } diff --git a/test/counter/view/counter_page_test.dart b/test/counter/view/counter_page_test.dart deleted file mode 100644 index f2b98a4..0000000 --- a/test/counter/view/counter_page_test.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'package:dash_ai_search/counter/counter.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../../helpers/helpers.dart'; - -void main() { - group('CounterPage', () { - testWidgets('renders CounterView', (tester) async { - await tester.pumpApp(const CounterPage()); - expect(find.byType(CounterView), findsOneWidget); - }); - }); -} diff --git a/test/home/view/home_page_test.dart b/test/home/view/home_page_test.dart new file mode 100644 index 0000000..d51ff18 --- /dev/null +++ b/test/home/view/home_page_test.dart @@ -0,0 +1,18 @@ +import 'package:dash_ai_search/home/home.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../../helpers/helpers.dart'; + +void main() { + group('HomePage', () { + testWidgets('renders correctly', (tester) async { + await tester.pumpApp( + HomePage(), + ); + + expect(find.byType(Background), findsOneWidget); + expect(find.byType(Logo), findsOneWidget); + expect(find.byType(WelcomeView), findsOneWidget); + }); + }); +} diff --git a/test/home/widgets/background_test.dart b/test/home/widgets/background_test.dart new file mode 100644 index 0000000..cdc446f --- /dev/null +++ b/test/home/widgets/background_test.dart @@ -0,0 +1,27 @@ +import 'package:dash_ai_search/home/home.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../../helpers/helpers.dart'; + +void main() { + group('Background', () { + testWidgets('renders correctly', (tester) async { + await tester.pumpApp( + Background(), + ); + + expect(find.byType(Circle), findsNWidgets(6)); + }); + + test('verifies should not repaint', () async { + final circlePainter = CirclePainter( + offset: Offset.zero, + radius: 10, + borderColor: Colors.white, + dotted: false, + ); + expect(circlePainter.shouldRepaint(circlePainter), false); + }); + }); +} diff --git a/test/home/widgets/logo_test.dart b/test/home/widgets/logo_test.dart new file mode 100644 index 0000000..19b3df9 --- /dev/null +++ b/test/home/widgets/logo_test.dart @@ -0,0 +1,22 @@ +import 'package:dash_ai_search/home/home.dart'; +import 'package:dash_ai_search/l10n/l10n.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../../helpers/helpers.dart'; + +void main() { + group('Logo', () { + testWidgets('renders correctly', (tester) async { + await tester.pumpApp( + Logo(), + ); + + final l10n = tester.element(find.byType(Logo)).l10n; + + expect(find.text(l10n.vertexAI), findsOneWidget); + expect(find.byType(Image), findsOneWidget); + expect(find.text(l10n.flutter), findsOneWidget); + }); + }); +} diff --git a/test/home/widgets/welcome_view_test.dart b/test/home/widgets/welcome_view_test.dart new file mode 100644 index 0000000..562d9c5 --- /dev/null +++ b/test/home/widgets/welcome_view_test.dart @@ -0,0 +1,21 @@ +import 'package:app_ui/app_ui.dart'; +import 'package:dash_ai_search/home/home.dart'; +import 'package:dash_ai_search/l10n/l10n.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../../helpers/helpers.dart'; + +void main() { + group('WelcomeView', () { + testWidgets('renders correctly', (tester) async { + await tester.pumpApp( + WelcomeView(), + ); + + final l10n = tester.element(find.byType(WelcomeView)).l10n; + + expect(find.text(l10n.initialScreenTitle), findsOneWidget); + expect(find.byType(CTAButton), findsOneWidget); + }); + }); +}