From 2908044e96550e6b24291a9a9c95106c8b65212f Mon Sep 17 00:00:00 2001 From: alexdivadi Date: Mon, 16 Feb 2026 21:25:11 -0600 Subject: [PATCH 1/2] feat: add loading shimmers to dashboard --- devtools_options.yaml | 3 ++ lib/core/common/widgets/any_step_shimmer.dart | 8 +++- .../widgets/dashboard_calendar_card.dart | 40 ++++++++++++++----- .../widgets/dashboard_metrics_card.dart | 6 +-- 4 files changed, 42 insertions(+), 15 deletions(-) create mode 100644 devtools_options.yaml diff --git a/devtools_options.yaml b/devtools_options.yaml new file mode 100644 index 0000000..fa0b357 --- /dev/null +++ b/devtools_options.yaml @@ -0,0 +1,3 @@ +description: This file stores settings for Dart & Flutter DevTools. +documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states +extensions: diff --git a/lib/core/common/widgets/any_step_shimmer.dart b/lib/core/common/widgets/any_step_shimmer.dart index 66688a5..97bab95 100644 --- a/lib/core/common/widgets/any_step_shimmer.dart +++ b/lib/core/common/widgets/any_step_shimmer.dart @@ -3,10 +3,11 @@ import 'package:flutter/material.dart'; import 'package:shimmer/shimmer.dart'; class AnyStepShimmer extends StatelessWidget { - const AnyStepShimmer({super.key, this.height, this.width}); + const AnyStepShimmer({super.key, this.height, this.width, this.borderRadius}); final double? height; final double? width; + final BorderRadius? borderRadius; @override Widget build(BuildContext context) { @@ -16,7 +17,10 @@ class AnyStepShimmer extends StatelessWidget { child: Container( height: height ?? 16, width: width ?? double.infinity, - color: AnyStepColors.grayDark.withAlpha(40), + decoration: BoxDecoration( + color: AnyStepColors.grayDark.withAlpha(40), + borderRadius: borderRadius ?? BorderRadius.circular(8), + ), ), ); } diff --git a/lib/core/features/dashboard/presentation/widgets/dashboard_calendar_card.dart b/lib/core/features/dashboard/presentation/widgets/dashboard_calendar_card.dart index b478383..2c4f36c 100644 --- a/lib/core/features/dashboard/presentation/widgets/dashboard_calendar_card.dart +++ b/lib/core/features/dashboard/presentation/widgets/dashboard_calendar_card.dart @@ -1,4 +1,5 @@ import 'package:anystep/core/common/constants/spacing.dart'; +import 'package:anystep/core/common/widgets/any_step_shimmer.dart'; import 'package:anystep/core/features/events/data/event_repository.dart'; import 'package:anystep/core/features/events/domain/event.dart'; import 'package:anystep/l10n/generated/app_localizations.dart'; @@ -41,18 +42,31 @@ class _DashboardCalendarCardState extends ConsumerState { child: Padding( padding: const EdgeInsets.all(AnyStepSpacing.md16), child: eventsAsync.when( - loading: () => const SizedBox( - height: 280, - child: Center(child: CircularProgressIndicator()), - ), - error: (e, st) => SizedBox( - height: 280, - child: Center(child: Text(loc.failedToLoad)), + loading: () => SizedBox( + height: 380, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: const [ + SizedBox(height: AnyStepSpacing.md14), + Center(child: AnyStepShimmer(height: 24, width: 140)), + SizedBox(height: AnyStepSpacing.sm10), + AnyStepShimmer(height: 280), + SizedBox(height: AnyStepSpacing.md12), + AnyStepShimmer(height: 16, width: 220), + SizedBox(height: AnyStepSpacing.sm8), + AnyStepShimmer(height: 16, width: 180), + ], + ), ), + error: (e, st) => SizedBox(height: 380, child: Center(child: Text(loc.failedToLoad))), data: (events) { final eventsByDay = >{}; for (final event in events) { - final dateKey = DateTime(event.startTime.year, event.startTime.month, event.startTime.day); + final dateKey = DateTime( + event.startTime.year, + event.startTime.month, + event.startTime.day, + ); eventsByDay.putIfAbsent(dateKey, () => []).add(event); } final selected = _selectedDay ?? _focusedDay; @@ -98,8 +112,14 @@ class _DashboardCalendarCardState extends ConsumerState { headerStyle: HeaderStyle( titleCentered: true, formatButtonVisible: false, - leftChevronIcon: Icon(Icons.chevron_left, color: Theme.of(context).iconTheme.color), - rightChevronIcon: Icon(Icons.chevron_right, color: Theme.of(context).iconTheme.color), + leftChevronIcon: Icon( + Icons.chevron_left, + color: Theme.of(context).iconTheme.color, + ), + rightChevronIcon: Icon( + Icons.chevron_right, + color: Theme.of(context).iconTheme.color, + ), ), ), const SizedBox(height: AnyStepSpacing.md12), diff --git a/lib/core/features/dashboard/presentation/widgets/dashboard_metrics_card.dart b/lib/core/features/dashboard/presentation/widgets/dashboard_metrics_card.dart index 8bdaf33..64c03d4 100644 --- a/lib/core/features/dashboard/presentation/widgets/dashboard_metrics_card.dart +++ b/lib/core/features/dashboard/presentation/widgets/dashboard_metrics_card.dart @@ -1,5 +1,6 @@ import 'package:anystep/core/common/constants/spacing.dart'; import 'package:anystep/core/common/widgets/any_step_loading_indicator.dart'; +import 'package:anystep/core/common/widgets/any_step_shimmer.dart'; import 'package:anystep/core/features/reports/data/volunteer_hours_providers.dart'; import 'package:anystep/l10n/generated/app_localizations.dart'; import 'package:fl_chart/fl_chart.dart'; @@ -29,8 +30,7 @@ class DashboardMetricsCard extends StatelessWidget { String Function(VolunteerHoursSummary) builder, ) { return summary.when( - loading: () => - const SizedBox(height: 16, width: 16, child: CircularProgressIndicator(strokeWidth: 2)), + loading: () => const AnyStepShimmer(height: 18, width: 52), error: (e, st) => const Text('—'), data: (data) => Text(builder(data)), ); @@ -216,7 +216,7 @@ class _HeroMetric extends StatelessWidget { height: 42, child: Align( alignment: Alignment.centerLeft, - child: CircularProgressIndicator.adaptive(), + child: AnyStepShimmer(height: 24, width: 52), ), ) : Column( From 5661afbc32dfb401999c0b54c2065d4bc51c4bb9 Mon Sep 17 00:00:00 2001 From: alexdivadi Date: Mon, 16 Feb 2026 21:40:41 -0600 Subject: [PATCH 2/2] fix: ui issues --- .../presentation/forgot_password/forgot_password_screen.dart | 2 +- .../presentation/reset_password/reset_password_screen.dart | 2 +- .../events/presentation/event_feed/event_feed_screen.dart | 4 ++-- .../profile/presentation/agreement/sign_agreement_screen.dart | 1 + .../profile/presentation/onboarding/onboarding_screen.dart | 3 ++- .../features/profile/presentation/profile/profile_form.dart | 1 + 6 files changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/core/features/auth/presentation/forgot_password/forgot_password_screen.dart b/lib/core/features/auth/presentation/forgot_password/forgot_password_screen.dart index 84fa338..05322ce 100644 --- a/lib/core/features/auth/presentation/forgot_password/forgot_password_screen.dart +++ b/lib/core/features/auth/presentation/forgot_password/forgot_password_screen.dart @@ -30,7 +30,7 @@ class _ForgotPasswordScreenState extends ConsumerState { final loc = AppLocalizations.of(context); return AnyStepScaffold( - appBar: AnyStepAppBar(title: Text(loc.forgotPasswordTitle)), + appBar: const AnyStepAppBar(), body: MaxWidthContainer( child: Padding( padding: const EdgeInsets.all(AnyStepSpacing.md16), diff --git a/lib/core/features/auth/presentation/reset_password/reset_password_screen.dart b/lib/core/features/auth/presentation/reset_password/reset_password_screen.dart index f013c61..705328e 100644 --- a/lib/core/features/auth/presentation/reset_password/reset_password_screen.dart +++ b/lib/core/features/auth/presentation/reset_password/reset_password_screen.dart @@ -31,7 +31,7 @@ class _ResetPasswordScreenState extends ConsumerState { final loc = AppLocalizations.of(context); return AnyStepScaffold( - appBar: AnyStepAppBar(title: Text(loc.resetPasswordTitle)), + appBar: const AnyStepAppBar(), body: MaxWidthContainer( child: Padding( padding: const EdgeInsets.all(AnyStepSpacing.md16), diff --git a/lib/core/features/events/presentation/event_feed/event_feed_screen.dart b/lib/core/features/events/presentation/event_feed/event_feed_screen.dart index a91e13d..7079a69 100644 --- a/lib/core/features/events/presentation/event_feed/event_feed_screen.dart +++ b/lib/core/features/events/presentation/event_feed/event_feed_screen.dart @@ -184,7 +184,7 @@ class _EventFeedScreenState extends ConsumerState { metricsCard, const DashboardCalendarCard(), ], - aspectRatio: 1.1, + aspectRatio: 0.9, ), ); } else { @@ -211,7 +211,7 @@ class _EventFeedScreenState extends ConsumerState { metricsCard, const DashboardCalendarCard(), ], - aspectRatio: 1.1, + aspectRatio: 0.9, ), ); } else { diff --git a/lib/core/features/profile/presentation/agreement/sign_agreement_screen.dart b/lib/core/features/profile/presentation/agreement/sign_agreement_screen.dart index fe328b5..0820170 100644 --- a/lib/core/features/profile/presentation/agreement/sign_agreement_screen.dart +++ b/lib/core/features/profile/presentation/agreement/sign_agreement_screen.dart @@ -78,6 +78,7 @@ class _SignAgreementScreenState extends ConsumerState { child: Scrollbar( thumbVisibility: true, child: SingleChildScrollView( + primary: true, physics: const ClampingScrollPhysics(), child: Column( children: [ diff --git a/lib/core/features/profile/presentation/onboarding/onboarding_screen.dart b/lib/core/features/profile/presentation/onboarding/onboarding_screen.dart index cf21541..2a031e0 100644 --- a/lib/core/features/profile/presentation/onboarding/onboarding_screen.dart +++ b/lib/core/features/profile/presentation/onboarding/onboarding_screen.dart @@ -168,8 +168,9 @@ class _OnboardingScreenState extends ConsumerState { postalCodeFieldName: 'zipCode', streetSecondaryLabelText: loc.streetAddress2, isUserAddress: true, + disableSearch: true, includeEventAddresses: false, - includeUserAddresses: true, + includeUserAddresses: false, ), const SizedBox(height: AnyStepSpacing.md16), diff --git a/lib/core/features/profile/presentation/profile/profile_form.dart b/lib/core/features/profile/presentation/profile/profile_form.dart index cf1f820..b8fff0b 100644 --- a/lib/core/features/profile/presentation/profile/profile_form.dart +++ b/lib/core/features/profile/presentation/profile/profile_form.dart @@ -88,6 +88,7 @@ class _ProfileFormState extends ConsumerState { formKey: _formKey, initialAddressId: widget.user.addressId ?? widget.user.address?.id, isUserAddress: true, + disableSearch: true, includeEventAddresses: false, includeUserAddresses: true, ),