diff --git a/lib/assets/images/empty_states/bookmark-dark.svg b/lib/assets/images/empty_states/bookmark-dark.svg new file mode 100644 index 0000000..effdb45 --- /dev/null +++ b/lib/assets/images/empty_states/bookmark-dark.svg @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/assets/images/empty_states/bookmark-light.svg b/lib/assets/images/empty_states/bookmark-light.svg new file mode 100644 index 0000000..8bb6d38 --- /dev/null +++ b/lib/assets/images/empty_states/bookmark-light.svg @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/assets/images/empty_states/chart-dark.svg b/lib/assets/images/empty_states/chart-dark.svg new file mode 100644 index 0000000..87e4b6c --- /dev/null +++ b/lib/assets/images/empty_states/chart-dark.svg @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/assets/images/empty_states/chart-light.svg b/lib/assets/images/empty_states/chart-light.svg new file mode 100644 index 0000000..e7287c0 --- /dev/null +++ b/lib/assets/images/empty_states/chart-light.svg @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/assets/images/empty_states/chat-dark.svg b/lib/assets/images/empty_states/chat-dark.svg new file mode 100644 index 0000000..0e79e3f --- /dev/null +++ b/lib/assets/images/empty_states/chat-dark.svg @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/assets/images/empty_states/chat-light.svg b/lib/assets/images/empty_states/chat-light.svg new file mode 100644 index 0000000..164cb68 --- /dev/null +++ b/lib/assets/images/empty_states/chat-light.svg @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/assets/images/empty_states/connection-dark.svg b/lib/assets/images/empty_states/connection-dark.svg new file mode 100644 index 0000000..87ad7a7 --- /dev/null +++ b/lib/assets/images/empty_states/connection-dark.svg @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/assets/images/empty_states/connection-light.svg b/lib/assets/images/empty_states/connection-light.svg new file mode 100644 index 0000000..f0a62b5 --- /dev/null +++ b/lib/assets/images/empty_states/connection-light.svg @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/assets/images/empty_states/result-dark.svg b/lib/assets/images/empty_states/result-dark.svg new file mode 100644 index 0000000..1a8515d --- /dev/null +++ b/lib/assets/images/empty_states/result-dark.svg @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/assets/images/empty_states/result-light.svg b/lib/assets/images/empty_states/result-light.svg new file mode 100644 index 0000000..f56538b --- /dev/null +++ b/lib/assets/images/empty_states/result-light.svg @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/assets/images/empty_states/studio-dark.svg b/lib/assets/images/empty_states/studio-dark.svg new file mode 100644 index 0000000..392039b --- /dev/null +++ b/lib/assets/images/empty_states/studio-dark.svg @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/assets/images/empty_states/studio-light.svg b/lib/assets/images/empty_states/studio-light.svg new file mode 100644 index 0000000..5808670 --- /dev/null +++ b/lib/assets/images/empty_states/studio-light.svg @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/constants/assets.dart b/lib/constants/assets.dart index ec1bea0..a331516 100644 --- a/lib/constants/assets.dart +++ b/lib/constants/assets.dart @@ -5,6 +5,7 @@ class Assets { static const String _basePath = 'lib/assets'; static const String _baseImagesPath = _basePath + '/images'; static const String _baseThemesPath = _basePath + '/images/themes'; + static const String _baseEmptyStatesPath = _basePath + '/images/empty_states'; static const String _baseAnimationsPath = _basePath + '/animations'; static const String _baseRecordsPath = _basePath + '/images/records'; @@ -29,6 +30,19 @@ class Assets { static String get techCategoryIcon => _baseImagesPath + '/categories/tech-$_themeSuffix.svg'; + static String get emptyBookmark => + _baseEmptyStatesPath + '/bookmark-$_themeSuffix.svg'; + static String get emptyChart => + _baseEmptyStatesPath + '/chart-$_themeSuffix.svg'; + static String get emptyChat => + _baseEmptyStatesPath + '/chat-$_themeSuffix.svg'; + static String get emptyConnection => + _baseEmptyStatesPath + '/connection-$_themeSuffix.svg'; + static String get emptyResult => + _baseEmptyStatesPath + '/result-$_themeSuffix.svg'; + static String get emptyStudio => + _baseEmptyStatesPath + '/studio-$_themeSuffix.svg'; + static const String lightTheme = _baseThemesPath + '/theme-light.svg'; static const String darkTheme = _baseThemesPath + '/theme-dark.svg'; diff --git a/lib/pages/home/news/news.dart b/lib/pages/home/news/news.dart index 0e0181d..a054cc0 100644 --- a/lib/pages/home/news/news.dart +++ b/lib/pages/home/news/news.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'package:didvan/constants/app_icons.dart'; +import 'package:didvan/models/enums.dart'; import 'package:didvan/models/view/action_sheet_data.dart'; import 'package:didvan/pages/home/news/news_state.dart'; import 'package:didvan/pages/home/news/widgets/news_item.dart'; @@ -12,7 +13,8 @@ import 'package:didvan/pages/home/widgets/logo_app_bar.dart'; import 'package:didvan/widgets/didvan/card.dart'; import 'package:didvan/widgets/didvan/divider.dart'; import 'package:didvan/widgets/shimmer_placeholder.dart'; -import 'package:didvan/widgets/sliver_state_handler.dart'; +import 'package:didvan/widgets/state_handlers/empty_result.dart'; +import 'package:didvan/widgets/state_handlers/sliver_state_handler.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -25,25 +27,25 @@ class News extends StatefulWidget { class _NewsState extends State { Timer? _timer; + final _focusNode = FocusNode(); @override void initState() { - Future.delayed(Duration.zero, () { - context.read().getNews(page: 1); - }); + context.read().init(); super.initState(); } @override Widget build(BuildContext context) { final state = context.watch(); - return Scaffold( - body: CustomScrollView( - slivers: [ - const SliverToBoxAdapter(child: LogoAppBar()), + return CustomScrollView( + slivers: [ + const SliverToBoxAdapter(child: LogoAppBar()), + if (state.appState != AppState.failed) SliverPadding( padding: const EdgeInsets.only(left: 16, right: 16, bottom: 16), sliver: SliverToBoxAdapter( child: SearchField( + focusNode: _focusNode, title: 'اخبار', onChanged: _onChanged, onFilterButtonPressed: _showFilterBottomSheet, @@ -51,17 +53,21 @@ class _NewsState extends State { ), ), ), - SliverStateHandler( - state: state, - builder: (context, state, index) => NewsItem( - news: state.news[index], - ), - childCount: state.news.length, - itemPadding: const EdgeInsets.only(left: 16, right: 16, bottom: 16), - placeholder: const _NewsItemPlaceholder(), + SliverStateHandler( + onRetry: () => state.getNews(page: state.page), + state: state, + builder: (context, state, index) => NewsItem( + news: state.news[index], ), - ], - ), + enableEmptyState: state.news.isEmpty, + emptyState: EmptyResult( + onNewSearch: () => _focusNode.requestFocus(), + ), + childCount: state.news.length, + itemPadding: const EdgeInsets.only(left: 16, right: 16, bottom: 16), + placeholder: const _NewsItemPlaceholder(), + ), + ], ); } diff --git a/lib/pages/home/radar/radar.dart b/lib/pages/home/radar/radar.dart index a081bc3..3421a68 100644 --- a/lib/pages/home/radar/radar.dart +++ b/lib/pages/home/radar/radar.dart @@ -21,7 +21,8 @@ import 'package:didvan/widgets/didvan/divider.dart'; import 'package:didvan/widgets/didvan/text.dart'; import 'package:didvan/widgets/item_title.dart'; import 'package:didvan/widgets/shimmer_placeholder.dart'; -import 'package:didvan/widgets/sliver_state_handler.dart'; +import 'package:didvan/widgets/state_handlers/empty_result.dart'; +import 'package:didvan/widgets/state_handlers/sliver_state_handler.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -34,7 +35,7 @@ class Radar extends StatefulWidget { class _RadarState extends State { final ScrollController _scrollController = ScrollController(); - // final ScrollController _categoriesScrollController = ScrollController(); + final _focusNode = FocusNode(); bool _isAnimating = false; @@ -58,18 +59,18 @@ class _RadarState extends State { @override Widget build(BuildContext context) { - return Scaffold( - body: Consumer( - builder: (context, state, child) => Stack( - children: [ - CustomScrollView( - physics: _isAnimating || - (state.appState == AppState.busy && state.radars.isEmpty) - ? const NeverScrollableScrollPhysics() - : const ScrollPhysics(), - controller: _scrollController, - slivers: [ - const SliverToBoxAdapter(child: LogoAppBar()), + return Consumer( + builder: (context, state, child) => Stack( + children: [ + CustomScrollView( + physics: _isAnimating || + (state.appState == AppState.busy && state.radars.isEmpty) + ? const NeverScrollableScrollPhysics() + : const ScrollPhysics(), + controller: _scrollController, + slivers: [ + const SliverToBoxAdapter(child: LogoAppBar()), + if (state.appState != AppState.failed) SliverPadding( padding: const EdgeInsets.only( left: 16, @@ -78,6 +79,7 @@ class _RadarState extends State { ), sliver: SliverToBoxAdapter( child: SearchField( + focusNode: _focusNode, isFiltered: state.filtering, title: 'رادار', onChanged: _onChanged, @@ -85,10 +87,13 @@ class _RadarState extends State { ), ), ), - if (!state.filtering && !state.searching) - const SliverToBoxAdapter( - child: SizedBox(height: 276), - ), + if (!state.filtering && + !state.searching && + state.appState != AppState.failed) + const SliverToBoxAdapter( + child: SizedBox(height: 276), + ), + if (state.appState != AppState.failed) SliverPadding( padding: const EdgeInsets.only(right: 16, bottom: 20), sliver: SliverToBoxAdapter( @@ -108,38 +113,44 @@ class _RadarState extends State { ), ), ), - SliverStateHandler( - state: state, - itemPadding: const EdgeInsets.only( - bottom: 20, - left: 16, - right: 16, - ), - placeholder: const _RadarItemPlaceholder(), - builder: (context, state, index) => RadarItem( - radar: state.radars[index], - ), - childCount: state.radars.length, + SliverStateHandler( + onRetry: () => state.getRadarOverviews(page: state.page), + state: state, + itemPadding: const EdgeInsets.only( + bottom: 20, + left: 16, + right: 16, ), - if (state.radars.length == 1) - const SliverToBoxAdapter( - child: SizedBox(height: 320), - ), - ], - ), + enableEmptyState: state.radars.isEmpty, + emptyState: + EmptyResult(onNewSearch: () => _focusNode.requestFocus()), + placeholder: const _RadarItemPlaceholder(), + builder: (context, state, index) => RadarItem( + radar: state.radars[index], + ), + childCount: state.radars.length, + ), + if (state.radars.length == 1) + const SliverToBoxAdapter( + child: SizedBox(height: 320), + ), + ], + ), + if (state.appState != AppState.failed) CategoriesRow1( isColapsed: state.isColapsed || state.searching || state.filtering, ), + if (state.appState != AppState.failed) CategoriesRow2( isColapsed: state.isColapsed || state.searching || state.filtering, ), + if (state.appState != AppState.failed) CategoriesList( isColapsed: state.isColapsed && !state.searching, ), - ], - ), + ], ), ); } diff --git a/lib/pages/home/radar/radar_state.dart b/lib/pages/home/radar/radar_state.dart index 81f4cf4..f6dcd6f 100644 --- a/lib/pages/home/radar/radar_state.dart +++ b/lib/pages/home/radar/radar_state.dart @@ -1,6 +1,7 @@ import 'package:collection/collection.dart'; import 'package:didvan/constants/assets.dart'; import 'package:didvan/models/enums.dart'; +import 'package:didvan/models/requests/radar.dart'; import 'package:didvan/models/view/radar_category.dart'; import 'package:didvan/models/radar_overview.dart'; import 'package:didvan/providers/core_provider.dart'; @@ -12,6 +13,7 @@ class RadarState extends CoreProvier { String lastSearch = ''; String? startDate; String? endDate; + int page = 1; bool isScrolled = false; bool shouldColapse = false; final List _markQueue = []; @@ -44,16 +46,21 @@ class RadarState extends CoreProvier { Future getRadarOverviews({ required int page, }) async { - radars.clear(); + if (this.page == page) { + radars.clear(); + } + this.page = page; lastSearch = search; appState = AppState.busy; final RequestService service = RequestService( RequestHelper.radarOverviews( - page: page, - startDate: startDate?.split(' ').first, - endDate: endDate?.split(' ').first, - search: search == '' ? null : search, - categories: selectedCats.map((e) => e.id).toList(), + args: RadarRequestArgs( + page: page, + startDate: startDate?.split(' ').first, + endDate: endDate?.split(' ').first, + search: search == '' ? null : search, + categories: selectedCats.map((e) => e.id).toList(), + ), ), ); await service.httpGet(); diff --git a/lib/pages/home/settings/general_settings/settings.dart b/lib/pages/home/settings/general_settings/settings.dart index 915241d..18680a3 100644 --- a/lib/pages/home/settings/general_settings/settings.dart +++ b/lib/pages/home/settings/general_settings/settings.dart @@ -15,7 +15,7 @@ import 'package:didvan/widgets/didvan/divider.dart'; import 'package:didvan/widgets/didvan/scaffold.dart'; import 'package:didvan/widgets/didvan/text.dart'; import 'package:didvan/widgets/item_title.dart'; -import 'package:didvan/widgets/state_handler.dart'; +import 'package:didvan/widgets/state_handlers/state_handler.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:provider/provider.dart'; @@ -27,6 +27,7 @@ class GeneralSettings extends StatelessWidget { Widget build(BuildContext context) { return Consumer( builder: (context, state, child) => StateHandler( + onRetry: () {}, state: context.read(), builder: (context, state) => DidvanScaffold( appBarData: AppBarData(hasBack: true, title: 'تنظیمات'), diff --git a/lib/pages/home/statistics/statistics.dart b/lib/pages/home/statistics/statistics.dart index 9544791..e727b5a 100644 --- a/lib/pages/home/statistics/statistics.dart +++ b/lib/pages/home/statistics/statistics.dart @@ -1,3 +1,7 @@ +import 'package:didvan/config/theme_data.dart'; +import 'package:didvan/constants/assets.dart'; +import 'package:didvan/pages/home/widgets/logo_app_bar.dart'; +import 'package:didvan/widgets/state_handlers/empty_state.dart'; import 'package:flutter/material.dart'; class Statictics extends StatelessWidget { @@ -5,6 +9,18 @@ class Statictics extends StatelessWidget { @override Widget build(BuildContext context) { - return Container(); + return Column( + children: [ + const LogoAppBar(), + Expanded( + child: EmptyState( + asset: Assets.emptyChart, + title: 'قیمت‌ها و شاخص‌های اقتصادی', + subtitle: 'به زودی...', + titleColor: Theme.of(context).colorScheme.title, + ), + ), + ], + ); } } diff --git a/lib/pages/home/studio/studio.dart b/lib/pages/home/studio/studio.dart index 3b4a32e..dd7eed3 100644 --- a/lib/pages/home/studio/studio.dart +++ b/lib/pages/home/studio/studio.dart @@ -1,3 +1,7 @@ +import 'package:didvan/config/theme_data.dart'; +import 'package:didvan/constants/assets.dart'; +import 'package:didvan/pages/home/widgets/logo_app_bar.dart'; +import 'package:didvan/widgets/state_handlers/empty_state.dart'; import 'package:flutter/material.dart'; class Studio extends StatelessWidget { @@ -5,6 +9,18 @@ class Studio extends StatelessWidget { @override Widget build(BuildContext context) { - return Container(); + return Column( + children: [ + const LogoAppBar(), + Expanded( + child: EmptyState( + asset: Assets.emptyStudio, + title: 'استودیو آینده', + subtitle: 'به زودی...', + titleColor: Theme.of(context).colorScheme.title, + ), + ), + ], + ); } } diff --git a/lib/widgets/search_field.dart b/lib/widgets/search_field.dart index 9c8fd38..da923b3 100644 --- a/lib/widgets/search_field.dart +++ b/lib/widgets/search_field.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; class SearchField extends StatefulWidget { final String title; + final FocusNode focusNode; final bool? isFiltered; final void Function(String value) onChanged; final VoidCallback? onFilterButtonPressed; @@ -13,6 +14,7 @@ class SearchField extends StatefulWidget { Key? key, required this.title, required this.onChanged, + required this.focusNode, this.onFilterButtonPressed, this.isFiltered, }) : super(key: key); @@ -22,11 +24,9 @@ class SearchField extends StatefulWidget { } class _SearchFieldState extends State { - final FocusNode _focusNode = FocusNode(); - @override void initState() { - _focusNode.addListener(() { + widget.focusNode.addListener(() { setState(() {}); }); super.initState(); @@ -44,8 +44,8 @@ class _SearchFieldState extends State { color: _fillColor(), ), child: TextFormField( - focusNode: _focusNode, - style: Theme.of(context).textTheme.bodyText1, + focusNode: widget.focusNode, + style: Theme.of(context).textTheme.bodyText2, textAlignVertical: TextAlignVertical.center, onChanged: widget.onChanged, keyboardType: TextInputType.text, @@ -117,7 +117,7 @@ class _SearchFieldState extends State { } Color _fillColor() { - if (_focusNode.hasFocus) { + if (widget.focusNode.hasFocus) { return Theme.of(context).colorScheme.surface; } return Theme.of(context).colorScheme.surface; @@ -125,7 +125,7 @@ class _SearchFieldState extends State { @override void dispose() { - _focusNode.dispose(); + widget.focusNode.dispose(); super.dispose(); } } diff --git a/lib/widgets/state_handlers/empty_connection.dart b/lib/widgets/state_handlers/empty_connection.dart new file mode 100644 index 0000000..53e87a6 --- /dev/null +++ b/lib/widgets/state_handlers/empty_connection.dart @@ -0,0 +1,18 @@ +import 'package:didvan/constants/assets.dart'; +import 'package:didvan/widgets/state_handlers/empty_state.dart'; +import 'package:flutter/material.dart'; + +class EmptyConnection extends StatelessWidget { + final VoidCallback onRetry; + const EmptyConnection({Key? key, required this.onRetry}) : super(key: key); + + @override + Widget build(BuildContext context) { + return EmptyState( + asset: Assets.emptyConnection, + title: 'ارتباط با اینترنت قطع شد...', + action: onRetry, + buttonTitle: 'تلاش دوباره', + ); + } +} diff --git a/lib/widgets/state_handlers/empty_result.dart b/lib/widgets/state_handlers/empty_result.dart new file mode 100644 index 0000000..bbb5fbb --- /dev/null +++ b/lib/widgets/state_handlers/empty_result.dart @@ -0,0 +1,18 @@ +import 'package:didvan/constants/assets.dart'; +import 'package:didvan/widgets/state_handlers/empty_state.dart'; +import 'package:flutter/material.dart'; + +class EmptyResult extends StatelessWidget { + final VoidCallback onNewSearch; + const EmptyResult({Key? key, required this.onNewSearch}) : super(key: key); + + @override + Widget build(BuildContext context) { + return EmptyState( + asset: Assets.emptyResult, + title: 'نتیجه‌ای پیدا نشد', + buttonTitle: 'تغییر جستجو', + action: onNewSearch, + ); + } +} diff --git a/lib/widgets/state_handlers/empty_state.dart b/lib/widgets/state_handlers/empty_state.dart new file mode 100644 index 0000000..6d4a883 --- /dev/null +++ b/lib/widgets/state_handlers/empty_state.dart @@ -0,0 +1,54 @@ +import 'package:didvan/config/theme_data.dart'; +import 'package:didvan/widgets/didvan/button.dart'; +import 'package:didvan/widgets/didvan/text.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; + +class EmptyState extends StatelessWidget { + final String asset; + final String title; + final String? subtitle; + final String? buttonTitle; + final VoidCallback? action; + final Color? titleColor; + + const EmptyState({ + Key? key, + required this.asset, + required this.title, + this.action, + this.buttonTitle, + this.subtitle, + this.titleColor, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox(height: 210, child: SvgPicture.asset(asset)), + const SizedBox(height: 16), + DidvanText( + title, + style: Theme.of(context).textTheme.headline3, + color: titleColor ?? Theme.of(context).colorScheme.caption, + ), + if (subtitle != null) const SizedBox(height: 8), + if (subtitle != null) + DidvanText( + subtitle!, + color: Theme.of(context).colorScheme.caption, + ), + if (action != null) const SizedBox(height: 16), + if (action != null) + DidvanButton( + height: 40, + onPressed: action, + title: buttonTitle, + width: 112, + ), + ], + ); + } +} diff --git a/lib/widgets/sliver_state_handler.dart b/lib/widgets/state_handlers/sliver_state_handler.dart similarity index 68% rename from lib/widgets/sliver_state_handler.dart rename to lib/widgets/state_handlers/sliver_state_handler.dart index 1244695..dde4ee4 100644 --- a/lib/widgets/sliver_state_handler.dart +++ b/lib/widgets/state_handlers/sliver_state_handler.dart @@ -1,13 +1,13 @@ import 'package:didvan/models/enums.dart'; import 'package:didvan/providers/core_provider.dart'; -import 'package:didvan/widgets/didvan/text.dart'; +import 'package:didvan/widgets/state_handlers/empty_connection.dart'; import 'package:flutter/material.dart'; class SliverStateHandler extends SliverList { final T state; final Widget Function(BuildContext context, T state, int index) builder; final int childCount; - final VoidCallback? onRefresh; + final VoidCallback onRetry; final bool enableEmptyState; final Widget? emptyState; final Widget? placeholder; @@ -17,20 +17,28 @@ class SliverStateHandler extends SliverList { required this.state, required this.builder, required this.childCount, + required this.onRetry, this.itemPadding, this.placeholder, this.emptyState, this.enableEmptyState = false, - this.onRefresh, }) : super( key: key, delegate: SliverChildBuilderDelegate( (context, index) { if (state.appState == AppState.failed) { - return const DidvanText('مشکل اتصال'); + return SizedBox( + height: MediaQuery.of(context).size.height - 240, + child: EmptyConnection( + onRetry: onRetry, + ), + ); } - if (enableEmptyState) { - return emptyState; + if (enableEmptyState && state.appState == AppState.idle) { + return SizedBox( + height: MediaQuery.of(context).size.height - 240, + child: emptyState, + ); } if (state.appState == AppState.busy) { return Padding( @@ -44,7 +52,9 @@ class SliverStateHandler extends SliverList { ); }, childCount: state.appState == AppState.idle - ? childCount + ? enableEmptyState + ? 1 + : childCount : state.appState == AppState.busy ? 3 : 1, diff --git a/lib/widgets/state_handler.dart b/lib/widgets/state_handlers/state_handler.dart similarity index 88% rename from lib/widgets/state_handler.dart rename to lib/widgets/state_handlers/state_handler.dart index 16ad8ea..bb26748 100644 --- a/lib/widgets/state_handler.dart +++ b/lib/widgets/state_handlers/state_handler.dart @@ -1,12 +1,13 @@ import 'package:didvan/models/enums.dart'; import 'package:didvan/providers/core_provider.dart'; +import 'package:didvan/widgets/state_handlers/empty_connection.dart'; import 'package:flutter/material.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart'; class StateHandler extends StatelessWidget { final T state; final Widget Function(BuildContext context, T state) builder; - final VoidCallback? onRefresh; + final VoidCallback onRetry; final bool enableEmptyState; final Widget? placeholder; final Widget? emptyState; @@ -14,11 +15,11 @@ class StateHandler extends StatelessWidget { const StateHandler({ Key? key, required this.builder, + required this.onRetry, + required this.state, this.emptyState, this.enableEmptyState = false, - this.onRefresh, this.topPadding = 0, - required this.state, this.placeholder, }) : super(key: key); @@ -42,7 +43,7 @@ class StateHandler extends StatelessWidget { color: Theme.of(context).colorScheme.primary, ); case AppState.failed: - return Container(); + return EmptyConnection(onRetry: onRetry); default: return Container(); } diff --git a/pubspec.lock b/pubspec.lock index efe1f1a..01f99dd 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -160,6 +160,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.3.0" + flutter_html: + dependency: "direct main" + description: + name: flutter_html + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0-alpha.2" flutter_lints: dependency: "direct dev" description: @@ -378,6 +385,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.0" + numerus: + dependency: transitive + description: + name: numerus + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.1" octo_image: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 359f899..481f45b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -58,6 +58,7 @@ dependencies: image_cropper: ^1.4.1 bot_toast: ^4.0.1 flutter_secure_storage: ^5.0.2 + flutter_html: ^3.0.0-alpha.2 dev_dependencies: flutter_test: @@ -103,6 +104,18 @@ flutter: - lib/assets/images/themes/theme-dark.svg - lib/assets/images/records/record-dark.svg - lib/assets/images/records/record-light.svg + - lib/assets/images/empty_states/bookmark-light.svg + - lib/assets/images/empty_states/chart-light.svg + - lib/assets/images/empty_states/chat-light.svg + - lib/assets/images/empty_states/connection-light.svg + - lib/assets/images/empty_states/result-light.svg + - lib/assets/images/empty_states/studio-light.svg + - lib/assets/images/empty_states/bookmark-dark.svg + - lib/assets/images/empty_states/chart-dark.svg + - lib/assets/images/empty_states/chat-dark.svg + - lib/assets/images/empty_states/connection-dark.svg + - lib/assets/images/empty_states/result-dark.svg + - lib/assets/images/empty_states/studio-dark.svg - lib/assets/animations/indicator-light.riv - lib/assets/animations/indicator-dark.riv