diff --git a/lib/core/widgets/refreshable_empty_state.dart b/lib/core/widgets/refreshable_empty_state.dart new file mode 100644 index 0000000..78726c8 --- /dev/null +++ b/lib/core/widgets/refreshable_empty_state.dart @@ -0,0 +1,24 @@ +import 'package:flutter/material.dart'; + +/// A wrapper widget to make empty states pull-to-refreshable inside a RefreshIndicator. +class RefreshableEmptyState extends StatelessWidget { + const RefreshableEmptyState({ + super.key, + required this.child, + }); + + final Widget child; + + @override + Widget build(BuildContext context) { + return LayoutBuilder( + builder: (context, constraints) => SingleChildScrollView( + physics: const AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints(minHeight: constraints.maxHeight), + child: child, + ), + ), + ); + } +} diff --git a/lib/features/dns/presentation/pages/dns_records_page.dart b/lib/features/dns/presentation/pages/dns_records_page.dart index 47c7996..3b3bf85 100644 --- a/lib/features/dns/presentation/pages/dns_records_page.dart +++ b/lib/features/dns/presentation/pages/dns_records_page.dart @@ -10,6 +10,7 @@ import '../widgets/dns_record_item.dart'; import '../widgets/dns_record_edit_dialog.dart'; import '../../../../core/theme/app_theme.dart'; import '../../../../core/widgets/error_view.dart'; +import '../../../../core/widgets/refreshable_empty_state.dart'; /// DNS Records page with list and filters class DnsRecordsPage extends ConsumerStatefulWidget { @@ -85,16 +86,8 @@ class _DnsRecordsPageState extends ConsumerState { onRefresh: () => ref.read(dnsRecordsNotifierProvider.notifier).refresh(), child: filteredRecords.isEmpty - ? LayoutBuilder( - builder: (context, constraints) => SingleChildScrollView( - physics: const AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: constraints.maxHeight, - ), - child: _buildEmptyState(state, l10n), - ), - ), + ? RefreshableEmptyState( + child: _buildEmptyState(state, l10n), ) : ListView.builder( key: const ValueKey('list'), diff --git a/lib/features/pages/presentation/pages/pages_list_page.dart b/lib/features/pages/presentation/pages/pages_list_page.dart index db0a6e2..ecce1b9 100644 --- a/lib/features/pages/presentation/pages/pages_list_page.dart +++ b/lib/features/pages/presentation/pages/pages_list_page.dart @@ -13,6 +13,7 @@ import '../../domain/models/pages_deployment.dart'; import '../../../../l10n/app_localizations.dart'; import '../../../../core/router/app_router.dart'; import '../../../../core/widgets/error_view.dart'; +import '../../../../core/widgets/refreshable_empty_state.dart'; /// Pages projects list screen with auto-refresh when builds are active class PagesListPage extends ConsumerStatefulWidget { @@ -91,21 +92,15 @@ class _PagesListPageState extends ConsumerState { onRefresh: () => ref.read(pagesProjectsNotifierProvider.notifier).refresh(), child: state.projects.isEmpty - ? LayoutBuilder( - builder: (context, constraints) => SingleChildScrollView( - physics: const AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints(minHeight: constraints.maxHeight), - child: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Icon(Symbols.electric_bolt, size: 64, color: Colors.grey), - const SizedBox(height: 16), - Text(l10n.pages_noProjects), - ], - ), - ), + ? RefreshableEmptyState( + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon(Symbols.electric_bolt, size: 64, color: Colors.grey), + const SizedBox(height: 16), + Text(l10n.pages_noProjects), + ], ), ), ) diff --git a/lib/features/workers/presentation/pages/workers_list_page.dart b/lib/features/workers/presentation/pages/workers_list_page.dart index d54ed17..69a399b 100644 --- a/lib/features/workers/presentation/pages/workers_list_page.dart +++ b/lib/features/workers/presentation/pages/workers_list_page.dart @@ -10,6 +10,7 @@ import '../../domain/models/worker.dart'; import '../../../../l10n/app_localizations.dart'; import '../../../../core/router/app_router.dart'; import '../../../../core/widgets/error_view.dart'; +import '../../../../core/widgets/refreshable_empty_state.dart'; class WorkersListPage extends ConsumerWidget { const WorkersListPage({super.key}); @@ -62,24 +63,12 @@ class WorkersListPage extends ConsumerWidget { child: RefreshIndicator( onRefresh: () => ref.read(workersNotifierProvider.notifier).refresh(), child: (state.workers.isEmpty && !state.isRefreshing) - ? LayoutBuilder( - builder: (context, constraints) => SingleChildScrollView( - physics: const AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints(minHeight: constraints.maxHeight), - child: _buildEmptyState(context, l10n), - ), - ), + ? RefreshableEmptyState( + child: _buildEmptyState(context, l10n), ) : (filteredWorkersList.isEmpty && !state.isRefreshing) - ? LayoutBuilder( - builder: (context, constraints) => SingleChildScrollView( - physics: const AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints(minHeight: constraints.maxHeight), - child: Center(child: Text(l10n.emptyState_tryAdjustingSearch)), - ), - ), + ? RefreshableEmptyState( + child: Center(child: Text(l10n.emptyState_tryAdjustingSearch)), ) : ListView.builder( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), diff --git a/pubspec.lock b/pubspec.lock index 87012a4..9acbcca 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -601,10 +601,10 @@ packages: dependency: transitive description: name: matcher - sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861 + sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6" url: "https://pub.dev" source: hosted - version: "0.12.19" + version: "0.12.18" material_color_utilities: dependency: transitive description: @@ -633,10 +633,10 @@ packages: dependency: transitive description: name: meta - sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349" + sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.17.0" mime: dependency: transitive description: @@ -1110,10 +1110,10 @@ packages: dependency: transitive description: name: test_api - sha256: "949a932224383300f01be9221c39180316445ecb8e7547f70a41a35bf421fb9e" + sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636" url: "https://pub.dev" source: hosted - version: "0.7.11" + version: "0.7.9" timing: dependency: transitive description: