From aeedfac0a4393e88136d30c0bd4d46ded30a390d Mon Sep 17 00:00:00 2001 From: jld3103 Date: Sat, 4 Nov 2023 10:48:37 +0100 Subject: [PATCH] fix(neon_dashboard): Remove scrolling inside dashboard widgets Signed-off-by: jld3103 --- .../neon_dashboard/lib/src/pages/main.dart | 145 +++++++++++++++++- .../lib/src/widgets/dry_intrinsic_height.dart | 33 ++++ .../lib/src/widgets/widget.dart | 85 +--------- .../neon_dashboard/test/goldens/widget.png | Bin 4792 -> 4705 bytes .../test/goldens/widget_not_round.png | Bin 4792 -> 4705 bytes .../test/goldens/widget_with_empty.png | Bin 4885 -> 4805 bytes .../test/goldens/widget_with_half_empty.png | Bin 4890 -> 4805 bytes .../test/goldens/widget_without_buttons.png | Bin 3746 -> 3804 bytes .../test/goldens/widget_without_items.png | Bin 4782 -> 4711 bytes .../neon/neon_dashboard/test/widget_test.dart | 88 ++++++++--- 10 files changed, 249 insertions(+), 102 deletions(-) create mode 100644 packages/neon/neon_dashboard/lib/src/widgets/dry_intrinsic_height.dart diff --git a/packages/neon/neon_dashboard/lib/src/pages/main.dart b/packages/neon/neon_dashboard/lib/src/pages/main.dart index d06b21e2d87..a4b722a8f0e 100644 --- a/packages/neon/neon_dashboard/lib/src/pages/main.dart +++ b/packages/neon/neon_dashboard/lib/src/pages/main.dart @@ -1,9 +1,17 @@ +import 'dart:math'; + import 'package:flutter/material.dart'; import 'package:neon/blocs.dart'; +import 'package:neon/theme.dart'; import 'package:neon/utils.dart'; import 'package:neon/widgets.dart'; +import 'package:neon_dashboard/l10n/localizations.dart'; import 'package:neon_dashboard/src/blocs/dashboard.dart'; +import 'package:neon_dashboard/src/widgets/dry_intrinsic_height.dart'; import 'package:neon_dashboard/src/widgets/widget.dart'; +import 'package:neon_dashboard/src/widgets/widget_button.dart'; +import 'package:neon_dashboard/src/widgets/widget_item.dart'; +import 'package:nextcloud/dashboard.dart' as dashboard; /// Displays the whole dashboard page layout. class DashboardMainPage extends StatelessWidget { @@ -21,15 +29,37 @@ class DashboardMainPage extends StatelessWidget { builder: (final context, final snapshot) { Widget? child; if (snapshot.hasData) { + var minHeight = 504.0; + + final children = []; + for (final widget in snapshot.requireData.entries) { + final items = _buildWidgetItems( + context: context, + widget: widget.key, + items: widget.value, + ); + + final height = items.map((final i) => i.height!).reduce((final a, final b) => a + b); + minHeight = max(minHeight, height); + + children.add( + DashboardWidget( + widget: widget.key, + children: items.toList(), + ), + ); + } + child = Wrap( alignment: WrapAlignment.center, spacing: 8, runSpacing: 8, - children: snapshot.requireData.entries + children: children .map( - (final widget) => DashboardWidget( - widget: widget.key, - items: widget.value, + (final widget) => SizedBox( + width: 320, + height: minHeight + 24, + child: widget, ), ) .toList(), @@ -53,4 +83,111 @@ class DashboardMainPage extends StatelessWidget { }, ); } + + @visibleForTesting + // ignore: public_member_api_docs + static Iterable buildWidgetItems({ + required final BuildContext context, + required final dashboard.Widget widget, + required final dashboard.WidgetItems? items, + }) => + _buildWidgetItems( + context: context, + widget: widget, + items: items, + ); + + static Iterable _buildWidgetItems({ + required final BuildContext context, + required final dashboard.Widget widget, + required final dashboard.WidgetItems? items, + }) sync* { + yield SizedBox( + height: 64, + child: DryIntrinsicHeight( + child: ListTile( + title: Text( + widget.title, + style: const TextStyle( + fontWeight: FontWeight.bold, + ), + ), + leading: SizedBox.square( + dimension: largeIconSize, + child: NeonUrlImage( + url: widget.iconUrl, + svgColorFilter: ColorFilter.mode(Theme.of(context).colorScheme.primary, BlendMode.srcIn), + size: const Size.square(largeIconSize), + ), + ), + ), + ), + ); + + yield const SizedBox( + height: 20, + ); + + final halfEmptyContentMessage = _buildMessage(items?.halfEmptyContentMessage); + final emptyContentMessage = _buildMessage(items?.emptyContentMessage); + if (halfEmptyContentMessage != null) { + yield halfEmptyContentMessage; + } + if (emptyContentMessage != null) { + yield emptyContentMessage; + } + if (halfEmptyContentMessage == null && emptyContentMessage == null && (items?.items.isEmpty ?? true)) { + yield _buildMessage(DashboardLocalizations.of(context).noEntries)!; + } + + if (items?.items != null) { + for (final item in items!.items) { + yield SizedBox( + height: 64, + child: DryIntrinsicHeight( + child: DashboardWidgetItem( + item: item, + roundIcon: widget.itemIconsRound, + ), + ), + ); + } + } + + yield const SizedBox( + height: 20, + ); + + if (widget.buttons != null) { + for (final button in widget.buttons!) { + yield SizedBox( + height: 32, + child: DashboardWidgetButton( + button: button, + ), + ); + } + } + } + + static SizedBox? _buildMessage(final String? message) { + if (message == null || message.isEmpty) { + return null; + } + + return SizedBox( + height: 60, + child: Center( + child: Column( + children: [ + const Icon( + Icons.check, + size: largeIconSize, + ), + Text(message), + ], + ), + ), + ); + } } diff --git a/packages/neon/neon_dashboard/lib/src/widgets/dry_intrinsic_height.dart b/packages/neon/neon_dashboard/lib/src/widgets/dry_intrinsic_height.dart new file mode 100644 index 00000000000..896a07f9dee --- /dev/null +++ b/packages/neon/neon_dashboard/lib/src/widgets/dry_intrinsic_height.dart @@ -0,0 +1,33 @@ +// ignore_for_file: public_member_api_docs +import 'package:flutter/rendering.dart'; +import 'package:flutter/widgets.dart'; + +/// NOTE ref: https://github.com/flutter/flutter/issues/71687 & https://gist.github.com/matthew-carroll/65411529a5fafa1b527a25b7130187c6 +/// Same as `IntrinsicHeight` except that when this widget is instructed +/// to `computeDryLayout()`, it doesn't invoke that on its child, instead +/// it computes the child's intrinsic height. +/// +/// This widget is useful in situations where the `child` does not +/// support dry layout, e.g., `TextField` as of 01/02/2021. +class DryIntrinsicHeight extends SingleChildRenderObjectWidget { + const DryIntrinsicHeight({ + super.key, + super.child, + }); + + @override + RenderDryIntrinsicHeight createRenderObject(final BuildContext context) => RenderDryIntrinsicHeight(); +} + +class RenderDryIntrinsicHeight extends RenderIntrinsicHeight { + @override + Size computeDryLayout(final BoxConstraints constraints) { + if (child != null) { + final height = child!.computeMinIntrinsicHeight(constraints.maxWidth); + final width = child!.computeMinIntrinsicWidth(height); + return Size(width, height); + } else { + return Size.zero; + } + } +} diff --git a/packages/neon/neon_dashboard/lib/src/widgets/widget.dart b/packages/neon/neon_dashboard/lib/src/widgets/widget.dart index d2559c62a30..3680a3c598b 100644 --- a/packages/neon/neon_dashboard/lib/src/widgets/widget.dart +++ b/packages/neon/neon_dashboard/lib/src/widgets/widget.dart @@ -1,10 +1,5 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; -import 'package:neon/theme.dart'; -import 'package:neon/widgets.dart'; -import 'package:neon_dashboard/l10n/localizations.dart'; -import 'package:neon_dashboard/src/widgets/widget_button.dart'; -import 'package:neon_dashboard/src/widgets/widget_item.dart'; import 'package:nextcloud/dashboard.dart' as dashboard; /// Displays a single dashboard widget and its items. @@ -12,7 +7,7 @@ class DashboardWidget extends StatelessWidget { /// Creates a new dashboard widget items. const DashboardWidget({ required this.widget, - required this.items, + required this.children, super.key, }); @@ -20,83 +15,19 @@ class DashboardWidget extends StatelessWidget { final dashboard.Widget widget; /// The items of the widget to be displayed. - final dashboard.WidgetItems? items; + final List children; @override - Widget build(final BuildContext context) { - final halfEmptyContentMessage = _renderMessage(items?.halfEmptyContentMessage); - final emptyContentMessage = _renderMessage(items?.emptyContentMessage); - - return SizedBox( - width: 320, - height: 560, - child: Card( + Widget build(final BuildContext context) => Card( child: InkWell( onTap: widget.widgetUrl != null && widget.widgetUrl!.isNotEmpty ? () => context.go(widget.widgetUrl!) : null, borderRadius: const BorderRadius.all(Radius.circular(12)), - child: ListView( + child: Padding( padding: const EdgeInsets.all(8), - key: PageStorageKey('dashboard-${widget.id}'), - children: [ - ListTile( - title: Text( - widget.title, - style: const TextStyle( - fontWeight: FontWeight.bold, - ), - ), - leading: SizedBox.square( - dimension: largeIconSize, - child: NeonUrlImage( - url: widget.iconUrl, - svgColorFilter: ColorFilter.mode(Theme.of(context).colorScheme.primary, BlendMode.srcIn), - size: const Size.square(largeIconSize), - ), - ), - ), - const SizedBox( - height: 20, - ), - if (halfEmptyContentMessage != null) halfEmptyContentMessage, - if (emptyContentMessage != null) emptyContentMessage, - if (halfEmptyContentMessage == null && emptyContentMessage == null && (items?.items.isEmpty ?? true)) - _renderMessage(DashboardLocalizations.of(context).noEntries)!, - ...?items?.items.map( - (final item) => DashboardWidgetItem( - item: item, - roundIcon: widget.itemIconsRound, - ), - ), - const SizedBox( - height: 20, - ), - ...?widget.buttons?.map( - (final button) => DashboardWidgetButton( - button: button, - ), - ), - ], + child: Column( + children: children, + ), ), ), - ), - ); - } - - Widget? _renderMessage(final String? message) { - if (message == null || message.isEmpty) { - return null; - } - - return Center( - child: Column( - children: [ - const Icon( - Icons.check, - size: largeIconSize, - ), - Text(message), - ], - ), - ); - } + ); } diff --git a/packages/neon/neon_dashboard/test/goldens/widget.png b/packages/neon/neon_dashboard/test/goldens/widget.png index dd66e350fcef529f27bd3ef1548d3b1f37291800..a5e629e8ccc489634fae6145c35bdd1cf8d9a3b7 100644 GIT binary patch delta 1810 zcmV+t2krQ{CE+BHL4ONLL_t(|obBCRh@}M`$MOHOJ9Bo{U1vu{6128$i^`>>te^se zN-8x_sffahAbVR1LQ$`xi!M~$f=KN`BBYm#LPdPL(3=P(VJs?0)iC0dnINS6p%PO*h?CyLRoWiHV6*JsW0AMIxb=6gM-+lLevZ@|? zW7&qTpSk|V8%A%;P6Yq}45g!Oaoy5o-A6zUOixcwY}@9t4*&pQb!KK}YGPvIUsZMf z8_T)_q;1S(uSQ4=_v)9z0l6Q&WAfKRY{H zRaINIY_WcycI?-`(->kj~|4^ER%1yDk1x*oS}+YV%qVQ}!^!J3+y>U;g!+1aY9+OlPf z_4~AA$Br5wAMa~j@84iwe*j=OHBD2sq&ox%003~xbO(r2u(Qz$VF4nH40?cJvvcRp zL65Mm?c29+RqLg0bng~1d~w%PZg%=dfc{cJCH#D0D$4sG)>i#?r;Q? zQ3Dwxn2|vbFl=tP;f6tvFjQ{6_13=D8}|3X>#{!e`@RFf>BJF}aRWsZny$xf+qMH4 z1ONaSK26h9E$I$NlaT|Ee`aLR0{{$zN1t1)hxRSj-}WD={c~*{m}_fpanMt-8kv7w*?LY+2`_A>? z%uZ8Zyl|wx_5Mz6+tmFl6o6xCnx<+=cL)%G6L-))e>L-}edc+6rq)#J~g=4@P(S_5SnZr}C&8X zfei!iv{@+nukRf{9oQe?I@N(Hiyf9zajsx9Mox*1gLC z-tf|)wl4X_Y`wbrOF>u%Hf^l>{WV+aoXzfn1@MNZX{wfVhtFsLj^o@jn)=eN(Ls;F z8u69)cEkt3G6V>~GQRu4PQA-rjabI}-n6m4^MTHw#{f9(`Hc#&jIEufes?HU6+m3m@6v*mL)&{PQZCvUyqQj9TCF+J8P_|pI<&!XN}o508WI9&;eH9 zz+79`K0H@XzTm2Ksy=$b#`^K4;sfA#x-UW(AOI_Lq^K$iqsLOVa)FG(%*+gA5C8yRxEyVZ7nd&U4v?pw zefHVdKmY*1@H*NSe_Xn(J3#i_a?35TfdBx2;dQhvZd9O8BtLnO{`gB#j`4lqG z2mk;KkEyD9w5s-0)n5lZ3jhEB000000KhQ$A54u6Z<{>V>i_@%07*qoM6N<$f`m_& Ay8r+H literal 4792 zcmeHLX;f2L621w61YDqD#DFMqr$q)t1u+C7g5by^VgP}VwBjHdQQEK=2#GL)w2a`^ zEucZ=C>n+YvBQ$cqBsy`i3?c-F|sR6CwAqIaZhISGesz(OPorn%9qiD@ANv zOT2fU4Ft z=iKQp!C}_e+8rX(*l&LaGW_mlMDr%%V5v@a96uup#ocBk6eRePE%tm2LZN>^6K z00-%9?&d%ei%inCCYXY&96T|)YOL+hNX1ZD`$1(jQ&3W3WNAQMzt+Y^+F6$loxu;^ zN?*cw)5jHxRNlaD*g;P$;)#ZZtSaraCU35e-C8+?#U#9|)nNsav`-nP02^ttC|sEY z6_-1hp{SQQgmNZVWieyQV^1bUMMZU<+mSS=gS9F2y}~_t^5p8G0mBdp5_Hq{u|G1E zj$mbnE(O6UK9oZqvb>Z*jNM-fQJ|(0C3yb zaNz4ci|VD@GM&tGy}i95VPO^tn&*XnK_uy!#dwfytL2f_HbLB)=?ymZ>TWKd*OmLKOpjFS(Y^>o6&s%mA(h@e-@Fq zUo2t^9TZLiM|gL@x`n4YvxDJK?0BrMb^B5 zSR7|c)|E{ZC1n^&_v6bAf7LJ;f+GZT+t*z=ytw9g0o0YzwoxgamV3+EwMR=$|1Odh zAOKB&5&xHo>i84wj~}gPPEEzj23%|6d7Mvg8BmPE{YbLZy{fzPHba|N2uW>CmKW2> zL9w034FSd&7g{@G(s4~HREtBd5abN=w5VwAfUVj`?y0n2?rv^`15Y?0$}1t0Pe~X1 z1W8&O`@;+i;r@6)lKy1To>2Zo*YYBjRJ+i!`^{h_m+w**$kMQi1bxwXK+OzBM7{2h z)J%wLE*E>UlB!i!G(-?(^B&4^_2rA%zszxXKXK{=yC+kBg_&w_C{_DA= ztDJVj-M8&nrAeHo&bljgj`N3t(OCGgxB&p{W(h)nqODT^yWVzsTHWA!=U71U2q%&A z;(|84b0#42`^Oo=7$qI@2OzE9z)KtuIWh5(H9p7Dc5uD6YS(H>#XMtxB_mh#j4DHl z7sQ9Z$6qD{sd~2-&Hll>oT{6|I$ky1`Q~(uYM^qmy4?S;Y$&vcIVBEZ4z4j=g96*m zFUV%wx|D|WcaZ8%)5pT33#<1pKmn{zAQ3tLio(S&_wLW7m3mW1wwC#9iUDd5lp^gT z8h({QpPr5B8PVsti?d*c=rHRk2hxY1q&*EEO zUWzYiUuKdTGYCL|ctK0{5c$$A!W@&>q_=9;5;07**#mbPI?;61!I6|2Ls-d^jS4&V zqKAlhmh$F>`Ku_E4#4_PKQw=L!j;2&@kka>LT>U6WFFAcp>^<{xUo@#x%syY!=0Wp z=9Xo^YXHAO>_|m`g6-^oBy|nE6(-bsthA-|dk5v;Ya2iVJ0Z$T{O|STspkBavL&fD z!*}IPGT&QgCBBR zW69E!{RDvXV$%=}zsVqLWq6T>6I>)1dS6S|+py6;c52a0XkUm*& zto*kSXKRrv%Ts=^HwlVTc-!U;4=|79at$d?0l!U5`mO&{wY6Y%i`ahTsc5MgG|vs5g!y!3q14YBJI2- zoc8$wjt;2rs0Wpr7W@d!9#d;aNQ~BmK~8}B(kD8BIrzT8k~Q)Ae(H#D@j&9e|1>k?a^bK_XEGlk&M-S3Z|KJ1*Hvno1;f lkV$?UIPe(aTM(-Cr>te^se zN-8x_sffahAbVR1LQ$`xi!M~$f=KN`BBYm#LPdPL(3=P(VJs?0)iC0dnINS6p%PO*h?CyLRoWiHV6*JsW0AMIxb=6gM-+lLevZ@|? zW7&qTpSk|V8%A%;P6Yq}45g!Oaoy5o-A6zUOixcwY}@9t4*&pQb!KK}YGPvIUsZMf z8_T)_q;1S(uSQ4=_v)9z0l6Q&WAfKRY{H zRaINIY_WcycI?-`(->kj~|4^ER%1yDk1x*oS}+YV%qVQ}!^!J3+y>U;g!+1aY9+OlPf z_4~AA$Br5wAMa~j@84iwe*j=OHBD2sq&ox%003~xbO(r2u(Qz$VF4nH40?cJvvcRp zL65Mm?c29+RqLg0bng~1d~w%PZg%=dfc{cJCH#D0D$4sG)>i#?r;Q? zQ3Dwxn2|vbFl=tP;f6tvFjQ{6_13=D8}|3X>#{!e`@RFf>BJF}aRWsZny$xf+qMH4 z1ONaSK26h9E$I$NlaT|Ee`aLR0{{$zN1t1)hxRSj-}WD={c~*{m}_fpanMt-8kv7w*?LY+2`_A>? z%uZ8Zyl|wx_5Mz6+tmFl6o6xCnx<+=cL)%G6L-))e>L-}edc+6rq)#J~g=4@P(S_5SnZr}C&8X zfei!iv{@+nukRf{9oQe?I@N(Hiyf9zajsx9Mox*1gLC z-tf|)wl4X_Y`wbrOF>u%Hf^l>{WV+aoXzfn1@MNZX{wfVhtFsLj^o@jn)=eN(Ls;F z8u69)cEkt3G6V>~GQRu4PQA-rjabI}-n6m4^MTHw#{f9(`Hc#&jIEufes?HU6+m3m@6v*mL)&{PQZCvUyqQj9TCF+J8P_|pI<&!XN}o508WI9&;eH9 zz+79`K0H@XzTm2Ksy=$b#`^K4;sfA#x-UW(AOI_Lq^K$iqsLOVa)FG(%*+gA5C8yRxEyVZ7nd&U4v?pw zefHVdKmY*1@H*NSe_Xn(J3#i_a?35TfdBx2;dQhvZd9O8BtLnO{`gB#j`4lqG z2mk;KkEyD9w5s-0)n5lZ3jhEB000000KhQ$A54u6Z<{>V>i_@%07*qoM6N<$f`m_& Ay8r+H literal 4792 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 diff --git a/packages/neon/neon_dashboard/test/goldens/widget_with_half_empty.png b/packages/neon/neon_dashboard/test/goldens/widget_with_half_empty.png index 9e65ba60b1f82b92c821cc3d7c99cc18853d4d2c..4d480eecf9e0ea5820280c90920c4817220cb551 100644 GIT binary patch delta 2002 zcmZ`)c{CgN7XC$ObTq~2=G0o#Wu|Y?*IHU4MUCg7c||Y?Ic1`TphM7*L`PLSRBCcs zJy9{;sD#8)p;Ad|trA*mDr0Yp1gW+Wgm^J?`sds~@ABR6+4(}5-gKoTc%5+# zNV~f*8gb!aYE#FOytb$t$CJd3`0X0-A3ir=9kQFx*=f6lN?@A;;O>vwog ztDeosd8&n)cLY}OU}ow+q5rLHdR3HV@m2YrO3dp!2aXI$<7@CK{ojms=+ztK6pL^* ztIkE8GJ*rmxwA0ZjPVvBxP)U;z!%$h?)Y2vW(CtG04-qdeAf;EAf=&=NoO&8g9eo_ zK^hl4U09QG1k=ls1df$w{y=wkcZ$9)0D0H5v$Kiw)g97&r^UxG^NbHkXo7N$qrdG1 zFTP>&YL1*I=l^*H0AX((Rm(ekGJ0p?c?;b6fUWSU{yp^-f`mk! zw=2!f&E5ChtyLO&T-?Qr)i@kZ9e}nWs`<}BjD#yXtD|XLSsKF}B6Li6S8b);piROP zLvZ(HkoL~&Mu&eUlgV!v3UA+LGNr=HP_Fsw$(Ed0B9ZtIk06gOQUEs9z+&&K_4SO= zvbbLBog^?+1uM2jV4S8Ark8BhshQ@1Om~=H50@uk-(NgFD(xlHr3JwKy04{nK~Fu zI|f(m* zMl+C^>#ZpuYJ>JWTdBKt`y5Z?;U!#}D*%~G{U>|}8yBmzXcyr&CO*jsAZ%lg%Tp1} zTzXN_{uth8va#|cBt`Eitr~874CMyHdhS!A9>T=mS7d6&cWjH|HA4#kPX7~ZwuJ^( z*f6J5VW?Fskw}D(QH`os-cUwIq-t1ZvG6Ne0UY&@tc(wIpBaYc6@?}=)yWLoUt&^6 z?fO!t)sA8tUjJjN6A1IEpuL8B?CRg~XS{^F5M=-WcKw8}e;wOtD{zytRS)vA%w4Jj z^+lC~3DjbCWEb8vB0ly~rL0{1+lCRk(ASQzsxA#DzhMwlDfh>g{3!MiF7wOQfRkvd z7EjtJxV6?38B6$O@M)4m!;|3w6^HQ{)x;0VS%#~(>rBLb*&3D>hzcU93R#N5H@7Gu z8AB(N98Nvql%oXqg3O7cC|}~S^VY;Rbm!nKTdUQmC@~_fzDD^}}zDuht|uC%KY$O3IM6W&Blh|G|>#U0R7- zrxLe4(JbGlUQv+KW8)&myzil0nXC3^2%(PVTH07>Y#GaC?bR=c>LV_Wyw&V}#ZpdT ztjJQU%2Iwc zF5jLvqS!ZY5J8EmQ@?){3}&Kqv?ol|vgo6APuyLmTV8f%+r8XR0nW93LxmKsUqptA zkH4dfbqsO?>#fi9<6e}g-b zZ<;x&tqUl?!0I%(+VJuBQkkLno{1A^(M;Zw{jBxd-~R&mCCZ@=V3dAwv79l zzJ1~T@=NccNXlVW(b)1&<7v44ht5+Dr^#7|V*C2jfjgY<>nY)m@k}Nzp^D>V_|4jY z-uMkagOtmpbQXF29+c2Vmj9~r;n`mjl{0feGwGM!^fh5YC%Xfiv+^M}eF}<&ZY{Ee zV zPR)~%pC%Wsay094`rFjhiAd z9cSwZ8BZ(yV=<_9zc>GCHyCUAnYUeWvNtBlf>x;(tN30BBvYa0B3v&{d-m>iGS-OFKAY%~sZNCwzU{>WDpH*mr_m^EMsZAT2}h7%dwP-o zsmCc2s`*#bGM~_lm<>`oj32!?`}zT@x2K0MW3t%Hxw$zyo&FnK^R4FN^z`)XoSZ@( z#xs%-AB517O6DeJQ-OPt!l__}GNt1z>A@2cXDa|~UEZ^#IcP#EdZTpuM~z1QZS9@o YkQ<*5di5$QytX`E9%s+6-LSv@AJ5C=m;e9( literal 4890 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 diff --git a/packages/neon/neon_dashboard/test/goldens/widget_without_buttons.png b/packages/neon/neon_dashboard/test/goldens/widget_without_buttons.png index 5239eddf56a12893d91c7c9ea0f0527489fe1961..f6c6ab114eac4ef49488c0f60e7c46866b46293f 100644 GIT binary patch literal 3804 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefq}2h)5S5QV$R#!hTT(s${zT5Uq$KApnGXw1dg9FpV>^J@UJ@aQ(+BDVDpMl}Q|KhqjJ9l^Y|8r)>*Y4jYsqp%1)m^ZLwMUZ-i!&H~hPgCOz{i=MVsf`r?~B0{sb$G!I6)#TQW)t$SO=z)+UHGv?is za({pS@=v=N-pmsQhKGW(0|P@t4+AhjjF?y$7*14h$~OG}7`$I$-)ix@j6X~)8R1f( z@WW6~4Z-5v>&y%vG9&e-@0Me1uzkh?atOM?-Mzs4vG?9dU_LnTFH%R$IDFS(PSSD) zC}}g;m7acT^mp&&%a_-FyITC|@V3464D-3wfyPprz2K=5==>Y@kThpOhu}kxLiCUW z$LpvdT0$QUkkJ64ebF|WHxX6KXpS4raicj7OVehARM4{-KfV9_`SV;JVE^UKbYQ1w z{pxI>*!S)E_tThx3FG%`=jcCgU)@S;u&Ms_CDRPp+}yC=Zp+d6>(>1(dThP?{k^@v z-=92rQha;f-C4k%$j-vYZf3xC+lS9(Wo2gS>gu0AJUm?a_0?7Rv}fnT?c@KP*mwWT znd!!#chCI!)qS2IuvI3%dgjm5XKZHAtbbD>#sCEkwV!0$Rz1JGN=s)xNXXOG&t;uc GLK6Vip9FaT literal 3746 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 literal 4782 zcmeHLX;4$y5&~#02JKON^(t3Wa26Lf(SoozY~;ntR9tbP~kiG9zx3{ z79EfbfTsK2UABj!a|QiQDLzqg4+lBfQ-mPX2=+Ks!jw z%a=obs28O0+T1|X<7lYjtV@ns2NfrJ_Ly zmZNv9bKV1*??n6;>7C0NpG=`poXEnbPYx(O0QG^*h>NwzgDx)LSp)-;y3{skUx)E!hJoY4>Z1R`3)jupTM$f z+`YY1q^w)FZY3}rJ6mt5&4>|zA92`bKIk*bsDCeEg_)w+Wker0;@Cgc0lGrrJ9F|I zrLd)&1U3oc$xq-0tGL4a9WjOEiWhLaRhVZiP zNI5HBXkpY;QpZFzjatD>_Dr7nNYhVq>ToTRq3(5jK}_&HYuS-8lPev0r8Bcyx}qqY zd#RdR9|9b?zsLcJ!@;m$tiT&9tyC?x_gAiwwzbZ@JTpvBLb)Rl&?L&?x%d%P-RdKS zH2cT&fUN%QwsfLQvWfQ7$!m7&Y{0*;MV9_iSmt``nwBH7n8Np@h+>g80Cpqh7+XIp z=7Fg-ebKEl>3#dD&~_pA6eqlITxRSo*WNklYjU7kKQ|P+2(TZ!BUECBgZ&C-^BYc0 zyp|3Zz}zm6Oj`wT(-BIFow>lP8g4TpUk)FkNe5d2@fOmjo9{7y z<9sxw3Yf8!`ptTMchvnxY|jDqu?hvv57`fUc!{(V(HG|+kgV}kM1Vc%%hMpk4N;xx z!}Q$XQriYFAaSYlRR`Kmhi%RWA3s{@Oy}nV|DYY^6&{Y0x`2REN&7+4JTC4rEOYFQ z0?>iAayv60@`H}k{06=yV82_6v71Z@vM|O-mH^{RsFpNrc#mJX&RpZza~0^AZn(O* zjfDg$1_;xD%5?qp$^bMN*qrD8o*(!Kn)C3ZCdO`f?KRua?%(WvXUFi_a5dl6nk;Wn z#+T^O;$B_9!Ht2&lX`%#%)CjbB8p$#a-Z<|*VE^>1W;79hy?!|&h**gPNcaUYP+oD z{sDI5u8o_fB>)(cP!4Q0H>V}bFdLKe^9J({;{deutqUCyKQlaJ)WDhq^EzzZ)^!QQp(ECsDemE+ue@Jx^fXd57^dg~z)ruM7QtZvRCH62k zu{w^vKN4S1@6UJ@e;Mt>{m)If)+Q3tGP*9RT@%uUbP4HdejiP+K<4D!VTz}UculYq zoS>+hcKi$7EL%GBc|4XOPxN+3w<@wwv^BUW(RveM?OdhRMPag zW9cioG+88z9C4!ZFg#;%uLtIOZr&eR)7wfF_m&I?F`2)X(5k)7J%k>)bi2~=M?sbe zV2*fb%!Qy8V4;e01`AE>* z|0V-=bg>q{sl1@Rh75PR`T0ytOl&hVg9D5qPET9gK0WK$n$S7{gET#OLB^!Ax=8DR zc2vLW?5rAIR8A#D;RWrNk!8ghH12ggF$|CGj$R>uT=+i_C~qKB!)mQr@+$BAxp4OG LcHUL8laTmtx0@Ul diff --git a/packages/neon/neon_dashboard/test/widget_test.dart b/packages/neon/neon_dashboard/test/widget_test.dart index c05d5ddb934..df6724c5abd 100644 --- a/packages/neon/neon_dashboard/test/widget_test.dart +++ b/packages/neon/neon_dashboard/test/widget_test.dart @@ -8,6 +8,7 @@ import 'package:neon/theme.dart'; import 'package:neon/utils.dart'; import 'package:neon/widgets.dart'; import 'package:neon_dashboard/l10n/localizations.dart'; +import 'package:neon_dashboard/src/pages/main.dart'; import 'package:neon_dashboard/src/widgets/widget.dart'; import 'package:neon_dashboard/src/widgets/widget_button.dart'; import 'package:neon_dashboard/src/widgets/widget_item.dart'; @@ -258,9 +259,15 @@ void main() { await tester.pumpWidget( wrapWidget( accountsBloc, - DashboardWidget( - widget: widget, - items: items, + Builder( + builder: (final context) => DashboardWidget( + widget: widget, + children: DashboardMainPage.buildWidgetItems( + context: context, + widget: widget, + items: items, + ).toList(), + ), ), ), ); @@ -294,12 +301,19 @@ void main() { }); testWidgets('Without widgetUrl', (final tester) async { + final widgetEmptyURL = widget.rebuild((final b) => b.widgetUrl = ''); await tester.pumpWidget( wrapWidget( accountsBloc, - DashboardWidget( - widget: widget.rebuild((final b) => b.widgetUrl = ''), - items: items, + Builder( + builder: (final context) => DashboardWidget( + widget: widgetEmptyURL, + children: DashboardMainPage.buildWidgetItems( + context: context, + widget: widgetEmptyURL, + items: items, + ).toList(), + ), ), ), ); @@ -315,12 +329,19 @@ void main() { }); testWidgets('Not round', (final tester) async { + final widgetNotRound = widget.rebuild((final b) => b.itemIconsRound = false); await tester.pumpWidget( wrapWidget( accountsBloc, - DashboardWidget( - widget: widget.rebuild((final b) => b.itemIconsRound = false), - items: items, + Builder( + builder: (final context) => DashboardWidget( + widget: widgetNotRound, + children: DashboardMainPage.buildWidgetItems( + context: context, + widget: widgetNotRound, + items: items, + ).toList(), + ), ), ), ); @@ -341,9 +362,15 @@ void main() { await tester.pumpWidget( wrapWidget( accountsBloc, - DashboardWidget( - widget: widget, - items: items.rebuild((final b) => b.halfEmptyContentMessage = 'Half empty'), + Builder( + builder: (final context) => DashboardWidget( + widget: widget, + children: DashboardMainPage.buildWidgetItems( + context: context, + widget: widget, + items: items.rebuild((final b) => b.halfEmptyContentMessage = 'Half empty'), + ).toList(), + ), ), ), ); @@ -358,9 +385,15 @@ void main() { await tester.pumpWidget( wrapWidget( accountsBloc, - DashboardWidget( - widget: widget, - items: items.rebuild((final b) => b.emptyContentMessage = 'Empty'), + Builder( + builder: (final context) => DashboardWidget( + widget: widget, + children: DashboardMainPage.buildWidgetItems( + context: context, + widget: widget, + items: items.rebuild((final b) => b.emptyContentMessage = 'Empty'), + ).toList(), + ), ), ), ); @@ -375,9 +408,15 @@ void main() { await tester.pumpWidget( wrapWidget( accountsBloc, - DashboardWidget( - widget: widget, - items: null, + Builder( + builder: (final context) => DashboardWidget( + widget: widget, + children: DashboardMainPage.buildWidgetItems( + context: context, + widget: widget, + items: null, + ).toList(), + ), ), ), ); @@ -389,12 +428,19 @@ void main() { }); testWidgets('Without buttons', (final tester) async { + final widgetWithoutButtons = widget.rebuild((final b) => b.buttons.clear()); await tester.pumpWidget( wrapWidget( accountsBloc, - DashboardWidget( - widget: widget.rebuild((final b) => b.buttons.clear()), - items: items, + Builder( + builder: (final context) => DashboardWidget( + widget: widgetWithoutButtons, + children: DashboardMainPage.buildWidgetItems( + context: context, + widget: widgetWithoutButtons, + items: null, + ).toList(), + ), ), ), );