From 417b9e45e48733729c4a3504e9ccde63ff5d5335 Mon Sep 17 00:00:00 2001 From: Oscar Date: Wed, 29 Nov 2023 16:28:48 +0100 Subject: [PATCH 1/7] chore: font style --- packages/app_ui/lib/src/widgets/primary_cta.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/app_ui/lib/src/widgets/primary_cta.dart b/packages/app_ui/lib/src/widgets/primary_cta.dart index 7be5440..6852507 100644 --- a/packages/app_ui/lib/src/widgets/primary_cta.dart +++ b/packages/app_ui/lib/src/widgets/primary_cta.dart @@ -47,9 +47,7 @@ class PrimaryCTA extends StatelessWidget { Text( label, textAlign: TextAlign.center, - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.w500, + style: VertexTextStyles.bodyLargeMedium.copyWith( color: VertexColors.white, ), ), From 5961856e95bb9681f18f5777e03fe8714b7beefc Mon Sep 17 00:00:00 2001 From: Oscar Date: Wed, 29 Nov 2023 19:28:13 +0100 Subject: [PATCH 2/7] chore: style --- packages/app_ui/lib/src/widgets/primary_cta.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/app_ui/lib/src/widgets/primary_cta.dart b/packages/app_ui/lib/src/widgets/primary_cta.dart index 6852507..f39cd7b 100644 --- a/packages/app_ui/lib/src/widgets/primary_cta.dart +++ b/packages/app_ui/lib/src/widgets/primary_cta.dart @@ -25,6 +25,7 @@ class PrimaryCTA extends StatelessWidget { @override Widget build(BuildContext context) { + final textTheme = Theme.of(context).textTheme; return ElevatedButton( onPressed: onPressed, style: ButtonStyle( @@ -47,7 +48,7 @@ class PrimaryCTA extends StatelessWidget { Text( label, textAlign: TextAlign.center, - style: VertexTextStyles.bodyLargeMedium.copyWith( + style: textTheme.bodyMedium?.copyWith( color: VertexColors.white, ), ), From 2379259f733a6222a69d7ee292052fbff65599c4 Mon Sep 17 00:00:00 2001 From: Oscar Date: Wed, 29 Nov 2023 20:32:17 +0100 Subject: [PATCH 3/7] feat: cta style --- lib/home/widgets/welcome_view.dart | 8 ++++- .../app_ui/lib/src/theme/vertex_theme.dart | 21 ++++++++++++ .../app_ui/lib/src/widgets/primary_cta.dart | 32 ++++++++----------- .../app_ui/lib/src/widgets/tertiary_cta.dart | 15 ++++----- 4 files changed, 47 insertions(+), 29 deletions(-) diff --git a/lib/home/widgets/welcome_view.dart b/lib/home/widgets/welcome_view.dart index 01d6b8d..460598b 100644 --- a/lib/home/widgets/welcome_view.dart +++ b/lib/home/widgets/welcome_view.dart @@ -84,7 +84,13 @@ class _WelcomeView extends StatelessWidget { ), const SizedBox(height: 40), PrimaryCTA( - icon: vertexIcons.arrowForward.image(), + icon: const CircleAvatar( + backgroundColor: VertexColors.white, + child: Icon( + Icons.arrow_forward, + color: VertexColors.googleBlue, + ), + ), label: l10n.startAsking, onPressed: () => context.read().add(const FromWelcomeToQuestion()), diff --git a/packages/app_ui/lib/src/theme/vertex_theme.dart b/packages/app_ui/lib/src/theme/vertex_theme.dart index d56644b..4a83be5 100644 --- a/packages/app_ui/lib/src/theme/vertex_theme.dart +++ b/packages/app_ui/lib/src/theme/vertex_theme.dart @@ -13,6 +13,8 @@ class VertexTheme { textTheme: _textTheme, inputDecorationTheme: _inputDecorationTheme, useMaterial3: true, + elevatedButtonTheme: _elevatedButtonTheme, + textButtonTheme: _textButtonTheme, ); } @@ -55,4 +57,23 @@ class VertexTheme { contentPadding: const EdgeInsets.symmetric(vertical: 32), ); } + + static ElevatedButtonThemeData get _elevatedButtonTheme { + return ElevatedButtonThemeData( + style: ElevatedButton.styleFrom( + textStyle: _textTheme.bodyMedium, + backgroundColor: VertexColors.googleBlue, + foregroundColor: VertexColors.white, + ), + ); + } + + static TextButtonThemeData get _textButtonTheme { + return TextButtonThemeData( + style: TextButton.styleFrom( + textStyle: _textTheme.bodyMedium, + foregroundColor: VertexColors.white, + ), + ); + } } diff --git a/packages/app_ui/lib/src/widgets/primary_cta.dart b/packages/app_ui/lib/src/widgets/primary_cta.dart index f39cd7b..c063595 100644 --- a/packages/app_ui/lib/src/widgets/primary_cta.dart +++ b/packages/app_ui/lib/src/widgets/primary_cta.dart @@ -1,4 +1,3 @@ -import 'package:app_ui/app_ui.dart'; import 'package:flutter/material.dart'; /// {@template primary_cta} @@ -14,8 +13,8 @@ class PrimaryCTA extends StatelessWidget { super.key, }); - /// The image that will be displayed on the left side of the button. - final Image? icon; + /// The widget that will be displayed on the left side of the button. + final Widget? icon; /// The text that will be displayed on the right side of the button. final String label; @@ -25,32 +24,27 @@ class PrimaryCTA extends StatelessWidget { @override Widget build(BuildContext context) { - final textTheme = Theme.of(context).textTheme; return ElevatedButton( onPressed: onPressed, - style: ButtonStyle( - backgroundColor: const MaterialStatePropertyAll( - VertexColors.googleBlue, - ), - padding: MaterialStatePropertyAll( - EdgeInsets.only( - left: icon != null ? 24 : 32, - top: 20, - bottom: 20, - right: 32, - ), + style: ElevatedButton.styleFrom( + padding: EdgeInsets.only( + left: icon != null ? 8 : 32, + top: 20, + bottom: 20, + right: 32, ), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ - if (icon != null) icon!, + if (icon != null) + Padding( + padding: const EdgeInsets.only(right: 16), + child: icon, + ), Text( label, textAlign: TextAlign.center, - style: textTheme.bodyMedium?.copyWith( - color: VertexColors.white, - ), ), ], ), diff --git a/packages/app_ui/lib/src/widgets/tertiary_cta.dart b/packages/app_ui/lib/src/widgets/tertiary_cta.dart index 8196d3d..2fd7b5b 100644 --- a/packages/app_ui/lib/src/widgets/tertiary_cta.dart +++ b/packages/app_ui/lib/src/widgets/tertiary_cta.dart @@ -1,9 +1,7 @@ -import 'package:app_ui/app_ui.dart'; import 'package:flutter/material.dart'; /// {@template tertiary_cta} /// TertiaryCTA -/// side. /// {@endtemplate} class TertiaryCTA extends StatelessWidget { /// {@macro tertiary_cta} @@ -30,16 +28,15 @@ class TertiaryCTA extends StatelessWidget { child: Row( mainAxisSize: MainAxisSize.min, children: [ - if (icon != null) icon!, - Expanded( + if (icon != null) + Padding( + padding: const EdgeInsets.only(right: 4), + child: icon, + ), + Flexible( child: Text( label, textAlign: TextAlign.center, - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.w500, - color: VertexColors.white, - ), ), ), ], From 3a5b03927b688d4bb285a7c539233541e8890d32 Mon Sep 17 00:00:00 2001 From: Oscar Date: Wed, 29 Nov 2023 21:21:27 +0100 Subject: [PATCH 4/7] chore: decorated box --- .../app_ui/lib/src/widgets/tertiary_cta.dart | 40 +++++++++++++++---- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/packages/app_ui/lib/src/widgets/tertiary_cta.dart b/packages/app_ui/lib/src/widgets/tertiary_cta.dart index 2fd7b5b..5e0ec74 100644 --- a/packages/app_ui/lib/src/widgets/tertiary_cta.dart +++ b/packages/app_ui/lib/src/widgets/tertiary_cta.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; /// {@template tertiary_cta} /// TertiaryCTA /// {@endtemplate} -class TertiaryCTA extends StatelessWidget { +class TertiaryCTA extends StatefulWidget { /// {@macro tertiary_cta} const TertiaryCTA({ required this.label, @@ -21,22 +21,48 @@ class TertiaryCTA extends StatelessWidget { /// The callback that will be called when the button is tapped. final VoidCallback? onPressed; + @override + State createState() => _TertiaryCTAState(); +} + +class _TertiaryCTAState extends State { + bool hovered = false; @override Widget build(BuildContext context) { return TextButton( - onPressed: onPressed, + onPressed: widget.onPressed, + style: const ButtonStyle( + overlayColor: MaterialStatePropertyAll(Colors.transparent), + ), + onHover: (newHovered) { + setState(() { + hovered = newHovered; + }); + }, child: Row( mainAxisSize: MainAxisSize.min, children: [ - if (icon != null) + if (widget.icon != null) Padding( padding: const EdgeInsets.only(right: 4), - child: icon, + child: widget.icon, ), Flexible( - child: Text( - label, - textAlign: TextAlign.center, + child: DecoratedBox( + decoration: BoxDecoration( + border: hovered + ? const Border( + bottom: BorderSide(color: Colors.white, width: 2), + ) + : null, + ), + child: Padding( + padding: const EdgeInsets.only(bottom: 4), + child: Text( + widget.label, + textAlign: TextAlign.center, + ), + ), ), ), ], From 6c9ae126579ad686449230c1c73d0c70abe8772b Mon Sep 17 00:00:00 2001 From: Oscar Date: Thu, 30 Nov 2023 12:04:25 +0100 Subject: [PATCH 5/7] feat: cta tertiary --- .../app_ui/lib/src/widgets/tertiary_cta.dart | 39 ++++++++++++------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/packages/app_ui/lib/src/widgets/tertiary_cta.dart b/packages/app_ui/lib/src/widgets/tertiary_cta.dart index 5e0ec74..3f58cda 100644 --- a/packages/app_ui/lib/src/widgets/tertiary_cta.dart +++ b/packages/app_ui/lib/src/widgets/tertiary_cta.dart @@ -1,3 +1,4 @@ +import 'package:app_ui/app_ui.dart'; import 'package:flutter/material.dart'; /// {@template tertiary_cta} @@ -25,8 +26,22 @@ class TertiaryCTA extends StatefulWidget { State createState() => _TertiaryCTAState(); } -class _TertiaryCTAState extends State { - bool hovered = false; +class _TertiaryCTAState extends State + with SingleTickerProviderStateMixin { + final DecorationTween decorationTween = DecorationTween( + begin: const BoxDecoration(), + end: const BoxDecoration( + border: Border( + bottom: BorderSide(color: VertexColors.white, width: 2), + ), + ), + ); + + late final AnimationController _controller = AnimationController( + vsync: this, + duration: const Duration(milliseconds: 300), + ); + @override Widget build(BuildContext context) { return TextButton( @@ -34,10 +49,12 @@ class _TertiaryCTAState extends State { style: const ButtonStyle( overlayColor: MaterialStatePropertyAll(Colors.transparent), ), - onHover: (newHovered) { - setState(() { - hovered = newHovered; - }); + onHover: (hovered) { + if (hovered) { + _controller.forward(from: 0); + } else { + _controller.reverse(from: 1); + } }, child: Row( mainAxisSize: MainAxisSize.min, @@ -48,14 +65,8 @@ class _TertiaryCTAState extends State { child: widget.icon, ), Flexible( - child: DecoratedBox( - decoration: BoxDecoration( - border: hovered - ? const Border( - bottom: BorderSide(color: Colors.white, width: 2), - ) - : null, - ), + child: DecoratedBoxTransition( + decoration: decorationTween.animate(_controller), child: Padding( padding: const EdgeInsets.only(bottom: 4), child: Text( From c8ea3fc784300d330a893134733859eacbdfe921 Mon Sep 17 00:00:00 2001 From: Oscar Date: Thu, 30 Nov 2023 12:16:51 +0100 Subject: [PATCH 6/7] feat: cta --- lib/home/widgets/results_view.dart | 4 +++- lib/home/widgets/welcome_view.dart | 8 ++------ packages/app_ui/assets/icons/arrow_back.png | Bin 208 -> 768 bytes packages/app_ui/assets/icons/arrow_forward.png | Bin 196 -> 736 bytes .../app_ui/lib/src/widgets/primary_cta.dart | 5 ++++- .../app_ui/lib/src/widgets/tertiary_cta.dart | 9 ++++++--- 6 files changed, 15 insertions(+), 11 deletions(-) diff --git a/lib/home/widgets/results_view.dart b/lib/home/widgets/results_view.dart index 408cb7a..c2e50c7 100644 --- a/lib/home/widgets/results_view.dart +++ b/lib/home/widgets/results_view.dart @@ -660,7 +660,9 @@ class _SeeSourceAnswersButtonState extends State height: 64, child: TertiaryCTA( label: l10n.seeSourceAnswers, - icon: vertexIcons.arrowForward.image(), + icon: vertexIcons.arrowForward.image( + color: VertexColors.white, + ), onPressed: () => context.read().add(const SeeSourceAnswersRequested()), ), diff --git a/lib/home/widgets/welcome_view.dart b/lib/home/widgets/welcome_view.dart index 460598b..f5bc5a6 100644 --- a/lib/home/widgets/welcome_view.dart +++ b/lib/home/widgets/welcome_view.dart @@ -84,12 +84,8 @@ class _WelcomeView extends StatelessWidget { ), const SizedBox(height: 40), PrimaryCTA( - icon: const CircleAvatar( - backgroundColor: VertexColors.white, - child: Icon( - Icons.arrow_forward, - color: VertexColors.googleBlue, - ), + icon: vertexIcons.arrowForward.image( + color: VertexColors.googleBlue, ), label: l10n.startAsking, onPressed: () => diff --git a/packages/app_ui/assets/icons/arrow_back.png b/packages/app_ui/assets/icons/arrow_back.png index 9c675b808bed85bfb4ea41912db74f9c1fc40e41..9d54b13640ac050eb8fa8849098b434c6048a62b 100644 GIT binary patch delta 751 zcmcb>*uZAi8Q|y6%O%Cdz`(%k>ERLtq!U1xgAGVNno({6q&N#aB8wRqbi6^BajEUJ zl@rb6>zSr{x;TbZFuuLBKTp_EfbGN07@3%W9SvP-s!EQZlv~sfEOl+JWbx9PZN6Zs zx73qMnlFQbq7FG~#ws}_&PsSvF+EmN^GScLc;@%KXU~3nPWPBNRpY+;?{zmMm4KEa zKtl=-=hYk4SBuZ>{qo=O^aRVOIdxVl^^HbC8NVa9zu#Z`;d*fW+h40E+gANM{clc< zV&XQB8KFPY3O+wS7cieiDD=Rt5C1bKIwWzO;IzMU*3Uyhko8IH`}r!%ZhL=kV@dii z5~A|w%r5cIn;%YLNs4v2dzk-**aF2r4XKP#hxl)ZF3|kb5XyK9$P`&%_@}{@G3qeC zmVUiM@ejwPtQq|FE7mZy><{u}pd}yK$GotCKs@cJI!fp62rP>X&fq z&HS^z{dt`Z6yG@Isr+R{);XJPyIk&EJhH1Zs-gb$of#qqBJY#UUfCY_H^XPU-230Z zr&unq`edH?|Lfz!-S^)=+q~J*b;2vdk_Yvr^@ru>rdj_pEa^FZLFF^!x0<3!pZzj+ zE`9mN=BE9=KX#p;EYw3cG4f6c@VUe(Ic0+W&kiB48*8RW8cx{|m+4%k@i1?xpXZ{M z+g|d)uAJ9Hjq25Vgw}_gB)0#WQos%a_G(*4f=sJ$Gsv9D&E!@fyc00&q+JU^- z-fcn=@3=38Fx_tTjq*y^Yv}FF`6hhY)x9i&){ncUB&^N+eO-2 z^$SWIm^!T_x36p|xYEiZRBloj%h}hnqkn$G*-d@Fv)+_e+kG*({^ZOViRwKTvT{O* dv;t!Nd9Ods|9SMp`@35}Tu)a&mvv4FO#pKuOI82? delta 186 zcmZo*yTEAH8Q|y6%O%Cdz`(%k>ERLtq$NO@gAGVND7XCqq&N#aB8wRqxP?KOkzv*x ziHT4nJ=y-!L<5Jsc zD<_)C*E5xRx;TbZFuuLL-*0lD%(0Kpw}=*II~|yMQDMe0?H95)CK?!4iRZeTo4LPi z>Z@X1HhXcPV&4ue=H}*&^?mQ(O9(G6v0n20=iKL$O;k-@M$gk%5J@qwprJX$)_VN=hr@b#I|7g4?w)VyKmcq~S7dU2y$|uZyygc3Q=r!BAsLq0#%PFdv`=`V-WYH0zL||jkasTkvV%7fn>v)cP$=k=u`Wg1j zk7JZclC-bi%VlxcWM83ZLvGDuHHODOj=3^i`^a0%@a!XRDZ{sqytxegkEKsB#2qu2 z6_|DY5VwWI{Q|i&T`$(xO-QeCt}@EIdQ*AbN8Z#10dey=0neoG2h`amRF?i*w|Db@ uR>hLp5AU}N%s;CiH_yQZ1^oNQt)hPUiGYm0QYbKSGI+ZBxvX03`lVnctjR6FmMZlFeAgP zIT91i if (widget.icon != null) Padding( padding: const EdgeInsets.only(right: 4), - child: widget.icon, + child: SizedBox.square( + dimension: 24, + child: widget.icon, + ), ), Flexible( child: DecoratedBoxTransition( From 13bc0089fdbd2fd4bc4ef068e0c262250b6c9d79 Mon Sep 17 00:00:00 2001 From: Oscar Date: Thu, 30 Nov 2023 12:29:59 +0100 Subject: [PATCH 7/7] test: coverage --- .../app_ui/lib/src/widgets/primary_cta.dart | 5 ++-- .../test/src/widgets/tertiary_cta_test.dart | 29 +++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/packages/app_ui/lib/src/widgets/primary_cta.dart b/packages/app_ui/lib/src/widgets/primary_cta.dart index 26fb479..9b1bb17 100644 --- a/packages/app_ui/lib/src/widgets/primary_cta.dart +++ b/packages/app_ui/lib/src/widgets/primary_cta.dart @@ -42,8 +42,9 @@ class PrimaryCTA extends StatelessWidget { Padding( padding: const EdgeInsets.only(right: 16), child: CircleAvatar( - backgroundColor: VertexColors.white, - child: SizedBox.square(dimension: 24, child: icon)), + backgroundColor: VertexColors.white, + child: SizedBox.square(dimension: 24, child: icon), + ), ), Text( label, diff --git a/packages/app_ui/test/src/widgets/tertiary_cta_test.dart b/packages/app_ui/test/src/widgets/tertiary_cta_test.dart index c9f0043..668fabd 100644 --- a/packages/app_ui/test/src/widgets/tertiary_cta_test.dart +++ b/packages/app_ui/test/src/widgets/tertiary_cta_test.dart @@ -1,5 +1,7 @@ import 'package:app_ui/app_ui.dart'; import 'package:app_ui/src/generated/assets.gen.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import '../helpers/helpers.dart'; @@ -33,5 +35,32 @@ void main() { await tester.tap(find.byType(TertiaryCTA)); expect(called, isTrue); }); + + testWidgets('animates on hover', (tester) async { + await tester.pumpApp( + TertiaryCTA( + icon: Assets.icons.arrowForward.image(), + label: 'label', + onPressed: () {}, + ), + ); + var status = AnimationStatus.dismissed; + final widget = tester + .widget(find.byType(DecoratedBoxTransition)); + widget.decoration.addStatusListener((newstatus) { + status = newstatus; + }); + final center = tester.getCenter(find.byType(TertiaryCTA)); + final gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); + await gesture.addPointer(); + await gesture.moveTo(center); + expect(status, AnimationStatus.forward); + await tester.pumpAndSettle(); + expect(status, AnimationStatus.completed); + await gesture.moveTo(Offset(1000, 1000)); + expect(status, AnimationStatus.reverse); + await tester.pumpAndSettle(); + expect(status, AnimationStatus.dismissed); + }); }); }