diff --git a/lib/models/category.dart b/lib/models/category.dart index 3faf75a..552af8b 100644 --- a/lib/models/category.dart +++ b/lib/models/category.dart @@ -1,8 +1,9 @@ class CategoryData { final int id; final String label; + String? asset; - const CategoryData({required this.id, required this.label}); + CategoryData({required this.id, required this.label, this.asset}); factory CategoryData.fromJson(Map json) => CategoryData( id: json['id'], diff --git a/lib/models/view/radar_category.dart b/lib/models/view/radar_category.dart deleted file mode 100644 index 4312d46..0000000 --- a/lib/models/view/radar_category.dart +++ /dev/null @@ -1,7 +0,0 @@ -class RadarCategory { - final int id; - final String title; - final String asset; - - RadarCategory({required this.id, required this.title, required this.asset}); -} diff --git a/lib/routes/route_generator.dart b/lib/routes/route_generator.dart index 308bc61..3340685 100644 --- a/lib/routes/route_generator.dart +++ b/lib/routes/route_generator.dart @@ -24,6 +24,7 @@ import 'package:didvan/views/home/settings/direct_list/direct_list_state.dart'; import 'package:didvan/views/home/settings/general_settings/settings.dart'; import 'package:didvan/views/home/settings/general_settings/settings_state.dart'; import 'package:didvan/views/home/settings/profile/profile.dart'; +import 'package:didvan/views/home/statistics/statistics_state.dart'; import 'package:didvan/views/home/studio/studio_details/studio_details.mobile.dart' if (dart.library.io) 'package:didvan/views/home/studio/studio_details/studio_details.mobile.dart' if (dart.library.html) 'package:didvan/views/home/studio/studio_details/studio_details.web.dart'; @@ -64,6 +65,9 @@ class RouteGenerator { ChangeNotifierProvider( create: (context) => StudioState(), ), + ChangeNotifierProvider( + create: (context) => StatisticsState(), + ), ], child: const Home(), ), diff --git a/lib/views/home/home.dart b/lib/views/home/home.dart index b9c203e..914bb5e 100644 --- a/lib/views/home/home.dart +++ b/lib/views/home/home.dart @@ -37,7 +37,7 @@ class _HomeState extends State with SingleTickerProviderStateMixin { controller: _tabController, children: const [ News(), - Statictics(), + Statistics(), Radar(), Studio(), Settings(), diff --git a/lib/views/home/news/news.dart b/lib/views/home/news/news.dart index 9387dae..c09916c 100644 --- a/lib/views/home/news/news.dart +++ b/lib/views/home/news/news.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'package:didvan/constants/app_icons.dart'; -import 'package:didvan/models/enums.dart'; import 'package:didvan/models/requests/news.dart'; import 'package:didvan/models/view/action_sheet_data.dart'; import 'package:didvan/utils/action_sheet.dart'; @@ -11,8 +10,7 @@ import 'package:didvan/views/home/widgets/logo_app_bar.dart'; import 'package:didvan/views/home/widgets/overview/news.dart'; import 'package:didvan/views/home/widgets/search_field.dart'; import 'package:didvan/views/widgets/item_title.dart'; -import 'package:didvan/views/widgets/state_handlers/empty_result.dart'; -import 'package:didvan/views/widgets/state_handlers/sliver_state_handler.dart'; +import 'package:didvan/views/widgets/state_handlers/state_handler.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -34,57 +32,55 @@ class _NewsState extends State { @override Widget build(BuildContext context) { - final state = context.watch(); - 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, - isFiltered: state.isFiltering, - ), - ), - ), - SliverStateHandler( + return Consumer( + builder: (context, state, child) => StateHandler( onRetry: () => state.getNews(page: state.page), state: state, - builder: (context, state, index) { - index += 2; - if (index % 15 == 0 && state.lastPage != state.page) { - state.getNews(page: state.page + 1); - } - index -= 2; - if (index >= state.news.length) { - return NewsOverview.placeholder; - } - final news = state.news[index]; - return NewsOverview( - news: news, - onMarkChanged: state.onMarkChanged, - newsRequestArgs: NewsRequestArgs( - page: state.page, - endDate: state.endDate, - startDate: state.startDate, - search: state.search, - ), - ); - }, - enableEmptyState: state.news.isEmpty, - emptyState: EmptyResult( - onNewSearch: () => _focusNode.requestFocus(), - ), - childCount: - state.news.length + (state.lastPage == state.page ? 0 : 3), - itemPadding: const EdgeInsets.only(left: 16, right: 16, bottom: 16), - placeholder: NewsOverview.placeholder, - ), - ], + builder: (context, state) => ListView.builder( + cacheExtent: 1000, + itemBuilder: (context, index) { + if (index == 0) { + return const LogoAppBar(); + } + if (index == 1) { + return Padding( + padding: const EdgeInsets.only( + left: 16, + right: 16, + bottom: 16, + ), + child: SearchField( + focusNode: _focusNode, + title: 'اخبار', + onChanged: _onChanged, + onFilterButtonPressed: _showFilterBottomSheet, + isFiltered: state.isFiltering, + ), + ); + } + index -= 2; + index += 2; + if (index % 15 == 0 && state.lastPage != state.page) { + state.getNews(page: state.page + 1); + } + index -= 2; + if (index >= state.news.length) { + return NewsOverview.placeholder; + } + final news = state.news[index]; + return NewsOverview( + news: news, + onMarkChanged: state.onMarkChanged, + newsRequestArgs: NewsRequestArgs( + page: state.page, + endDate: state.endDate, + startDate: state.startDate, + search: state.search, + ), + ); + }, + itemCount: state.news.length + 2, + )), ); } diff --git a/lib/views/home/radar/radar.dart b/lib/views/home/radar/radar.dart index 6384c96..b68a108 100644 --- a/lib/views/home/radar/radar.dart +++ b/lib/views/home/radar/radar.dart @@ -1,17 +1,16 @@ -// ignore_for_file: prefer_const_constructors - import 'dart:async'; import 'dart:math'; import 'package:didvan/config/design_config.dart'; import 'package:didvan/config/theme_data.dart'; import 'package:didvan/constants/app_icons.dart'; +import 'package:didvan/models/category.dart'; import 'package:didvan/models/enums.dart'; import 'package:didvan/models/requests/radar.dart'; import 'package:didvan/models/view/action_sheet_data.dart'; import 'package:didvan/views/home/radar/radar_state.dart'; -import 'package:didvan/views/home/radar/widgets/categories_gird.dart'; -import 'package:didvan/views/home/radar/widgets/categories_list.dart'; +import 'package:didvan/views/home/widgets/categories_gird.dart'; +import 'package:didvan/views/home/widgets/categories_list.dart'; import 'package:didvan/views/home/widgets/date_picker_button.dart'; import 'package:didvan/views/home/widgets/logo_app_bar.dart'; import 'package:didvan/utils/action_sheet.dart'; @@ -162,17 +161,46 @@ class _RadarState extends State { ), ], ), - if (state.appState != AppState.failed) CategoriesRow1(), - if (state.appState != AppState.failed) CategoriesRow2(), + if (state.appState != AppState.failed) + CategoriesRow1( + topPadding: 300, + onSelected: _onCategorySelected, + categories: state.categories, + isColapsed: + state.isColapsed || state.searching || state.filtering, + ), + if (state.appState != AppState.failed) + CategoriesRow2( + categories: state.categories, + isColapsed: + state.isColapsed || state.searching || state.filtering, + onSelected: _onCategorySelected, + ), if (state.appState != AppState.failed && !state.searching && !state.filtering) - CategoriesList(), + CategoriesList( + isRadar: true, + categories: state.categories, + isColapsed: + state.isColapsed || state.searching || state.filtering, + onSelected: () => state.getRadars(page: 1), + selectedCats: state.selectedCats, + ), ], ), ); } + void _onCategorySelected(CategoryData category) { + final state = context.read(); + state.selectedCats.clear(); + if (category.id != 0) { + state.selectedCats.add(category); + } + state.getRadars(page: 1); + } + void _onChanged(String value) { final state = context.read(); if (value.length < 4 && value.isNotEmpty || state.lastSearch == value) { @@ -268,7 +296,7 @@ class _RadarState extends State { SizedBox( width: (MediaQuery.of(context).size.width - 40) / 2, child: DidvanCheckbox( - title: state.categories[i].title, + title: state.categories[i].label, value: state.selectedCats.contains(state.categories[i]), onChanged: (value) { if (value) { diff --git a/lib/views/home/radar/radar_state.dart b/lib/views/home/radar/radar_state.dart index fb293a2..a4c483f 100644 --- a/lib/views/home/radar/radar_state.dart +++ b/lib/views/home/radar/radar_state.dart @@ -1,8 +1,8 @@ import 'package:didvan/constants/assets.dart'; +import 'package:didvan/models/category.dart'; import 'package:didvan/models/enums.dart'; import 'package:didvan/models/overview_data.dart'; import 'package:didvan/models/requests/radar.dart'; -import 'package:didvan/models/view/radar_category.dart'; import 'package:didvan/providers/core.dart'; import 'package:didvan/services/network/request.dart'; import 'package:didvan/services/network/request_helper.dart'; @@ -16,8 +16,8 @@ class RadarState extends CoreProvier { int lastPage = 1; bool isScrolled = false; bool shouldColapse = false; - final List selectedCats = []; - List categories = []; + final List selectedCats = []; + List categories = []; final List radars = []; bool get filtering => @@ -99,34 +99,34 @@ class RadarState extends CoreProvier { getRadars(page: 1); }); categories = [ - RadarCategory( + CategoryData( id: 1, - title: 'اقتصادی', + label: 'اقتصادی', asset: Assets.economicCategoryIcon, ), - RadarCategory( + CategoryData( id: 2, - title: 'سیاسی', + label: 'سیاسی', asset: Assets.politicalCategoryIcon, ), - RadarCategory( + CategoryData( id: 3, - title: 'فناوری', + label: 'فناوری', asset: Assets.techCategoryIcon, ), - RadarCategory( + CategoryData( id: 4, - title: 'کسب و کار', + label: 'کسب و کار', asset: Assets.businessCategoryIcon, ), - RadarCategory( + CategoryData( id: 5, - title: 'زیست محیطی', + label: 'زیست محیطی', asset: Assets.enviromentalCategoryIcon, ), - RadarCategory( + CategoryData( id: 6, - title: 'اجتماعی', + label: 'اجتماعی', asset: Assets.socialCategoryIcon, ), ]; diff --git a/lib/views/home/statistics/statistics.dart b/lib/views/home/statistics/statistics.dart index eef8150..565c41a 100644 --- a/lib/views/home/statistics/statistics.dart +++ b/lib/views/home/statistics/statistics.dart @@ -1,26 +1,196 @@ +import 'dart:math'; + +import 'package:didvan/config/design_config.dart'; import 'package:didvan/config/theme_data.dart'; import 'package:didvan/constants/assets.dart'; +import 'package:didvan/models/category.dart'; +import 'package:didvan/models/enums.dart'; +import 'package:didvan/models/requests/radar.dart'; +import 'package:didvan/views/home/statistics/statistics_state.dart'; +import 'package:didvan/views/home/widgets/categories_gird.dart'; +import 'package:didvan/views/home/widgets/categories_list.dart'; import 'package:didvan/views/home/widgets/logo_app_bar.dart'; +import 'package:didvan/views/home/widgets/overview/radar.dart'; +import 'package:didvan/views/widgets/animated_visibility.dart'; +import 'package:didvan/views/widgets/didvan/text.dart'; import 'package:didvan/views/widgets/state_handlers/empty_state.dart'; +import 'package:didvan/views/widgets/state_handlers/sliver_state_handler.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; -class Statictics extends StatelessWidget { - const Statictics({Key? key}) : super(key: key); +class Statistics extends StatefulWidget { + const Statistics({Key? key}) : super(key: key); + + @override + State createState() => _RadarState(); +} + +class _RadarState extends State { + final ScrollController _scrollController = ScrollController(); + + bool _isAnimating = false; + + @override + void initState() { + _scrollController.addListener(() { + _handleAnimations(); + }); + final state = context.read(); + state.addListener(() { + if (state.shouldColapse && mounted) { + _handleAnimations(true); + state.shouldColapse = false; + } + }); + state.init(); + super.initState(); + } @override Widget build(BuildContext context) { - return Column( - children: [ - const LogoAppBar(), - Expanded( - child: EmptyState( - asset: Assets.emptyChart, - title: 'قیمت‌ها و شاخص‌های اقتصادی', - subtitle: 'به زودی...', - titleColor: Theme.of(context).colorScheme.title, + return Consumer( + builder: (context, state, child) => Stack( + children: [ + CustomScrollView( + physics: _isAnimating + ? const NeverScrollableScrollPhysics() + : const ClampingScrollPhysics(), + controller: _scrollController, + slivers: [ + const SliverToBoxAdapter(child: LogoAppBar()), + if (state.appState != AppState.failed) + const SliverToBoxAdapter( + child: SizedBox(height: 156), + ), + if (state.appState != AppState.failed) + SliverPadding( + padding: const EdgeInsets.only(right: 16, bottom: 20), + sliver: SliverToBoxAdapter( + child: Align( + alignment: Alignment.centerRight, + child: AnimatedVisibility( + isVisible: !state.isColapsed, + duration: DesignConfig.lowAnimationDuration, + child: DidvanText( + 'شاخص‌های منتخب', + style: Theme.of(context).textTheme.subtitle1, + color: Theme.of(context).colorScheme.title, + ), + ), + ), + ), + ), + SliverStateHandler( + onRetry: () => state.getStatistics(page: state.page), + state: state, + itemPadding: const EdgeInsets.only( + bottom: 20, + left: 16, + right: 16, + ), + enableEmptyState: state.statistics.isEmpty, + emptyState: Padding( + padding: const EdgeInsets.only(bottom: 120), + child: EmptyState( + asset: Assets.emptyResult, + title: 'موردی برای نمایش وجود ندارد.', + ), + ), + placeholder: RadarOverview.placeholder, + builder: (context, state, index) { + index += 2; + if (index % 15 == 0 && state.lastPage != state.page) { + state.getStatistics(page: state.page + 1); + } + index -= 2; + if (index >= state.statistics.length) { + return RadarOverview.placeholder; + } + final radar = state.statistics[index]; + return RadarOverview( + radar: radar, + onMarkChanged: state.changeMark, + onCommentsChanged: (id, count) => {}, + radarRequestArgs: RadarRequestArgs( + page: state.page, + categories: + List.from(state.selectedCats.map((cat) => cat.id)), + isSingleItem: false, + ), + ); + }, + childCount: state.statistics.length + + (state.lastPage == state.page ? 0 : 3), + ), + if (state.statistics.length == 1) + const SliverToBoxAdapter( + child: SizedBox(height: 320), + ), + ], ), - ), - ], + if (state.appState != AppState.failed) + CategoriesRow1( + onSelected: _onCategorySelected, + categories: state.categories, + isColapsed: state.isColapsed, + topPadding: 120, + ), + if (state.appState != AppState.failed) + CategoriesList( + isRadar: false, + categories: state.categories, + isColapsed: state.isColapsed, + onSelected: () => state.getStatistics(page: 1), + selectedCats: state.selectedCats, + ), + ], + ), ); } + + void _onCategorySelected(CategoryData category) { + final state = context.read(); + state.selectedCats.clear(); + if (category.id != 0) { + state.selectedCats.add(category); + } + state.getStatistics(page: 1); + } + + void _handleAnimations([bool forceAnimate = false]) async { + final state = context.read(); + if (_isAnimating) return; + final double position = _scrollController.offset; + if (position > 5 && !state.isColapsed || forceAnimate) { + state.isScrolled = true; + _isAnimating = true; + setState(() {}); + await _scrollController.animateTo( + 200, + duration: DesignConfig.mediumAnimationDuration, + curve: Curves.easeIn, + ); + _isAnimating = false; + setState(() {}); + } else if (position < + min(_scrollController.position.maxScrollExtent, 200) && + state.isColapsed) { + state.isScrolled = false; + _isAnimating = true; + setState(() {}); + await _scrollController.animateTo( + 0, + duration: DesignConfig.mediumAnimationDuration, + curve: Curves.easeIn, + ); + _isAnimating = false; + setState(() {}); + } + } + + @override + void dispose() { + _scrollController.dispose(); + super.dispose(); + } } diff --git a/lib/views/home/statistics/statistics_state.dart b/lib/views/home/statistics/statistics_state.dart new file mode 100644 index 0000000..6ebcaf7 --- /dev/null +++ b/lib/views/home/statistics/statistics_state.dart @@ -0,0 +1,96 @@ +import 'package:didvan/constants/assets.dart'; +import 'package:didvan/models/category.dart'; +import 'package:didvan/models/enums.dart'; +import 'package:didvan/models/overview_data.dart'; +import 'package:didvan/models/requests/radar.dart'; +import 'package:didvan/providers/core.dart'; +import 'package:didvan/services/network/request.dart'; +import 'package:didvan/services/network/request_helper.dart'; + +class StatisticsState extends CoreProvier { + int page = 1; + int lastPage = 1; + bool isScrolled = false; + bool shouldColapse = false; + final List selectedCats = []; + List categories = []; + final List statistics = []; + + bool get isColapsed => (isCategorySelected && isScrolled) || isScrolled; + + bool get isCategorySelected => selectedCats.length == 1; + + void resetFilters(bool isInit) { + selectedCats.clear(); + isScrolled = false; + if (!isInit) { + getStatistics(page: 1); + } + } + + Future getStatistics({ + required int page, + }) async { + this.page = page; + if (this.page == page) { + statistics.clear(); + } + if (page == 1) { + appState = AppState.busy; + } + final RequestService service = RequestService( + RequestHelper.radarOverviews( + args: RadarRequestArgs( + page: page, + categories: selectedCats.map((e) => e.id).toList(), + ), + ), + ); + await service.httpGet(); + if (service.isSuccess) { + lastPage = service.result['lastPage']; + final radarsList = service.result['radars']; + for (var i = 0; i < radarsList.length; i++) { + statistics.add(OverviewData.fromJson(radarsList[i])); + } + if (isColapsed || isCategorySelected) { + shouldColapse = true; + } + appState = AppState.idle; + return; + } + + appState = AppState.failed; + } + + Future changeMark(int id, bool value, bool shouldUpdate) async { + statistics.firstWhere((element) => element.id == id).marked = value; + if (shouldUpdate) { + notifyListeners(); + } + } + + void init() { + resetFilters(true); + Future.delayed(Duration.zero, () { + getStatistics(page: 1); + }); + categories = [ + CategoryData( + id: 1, + label: 'اقتصاد کلان', + asset: Assets.economicCategoryIcon, + ), + CategoryData( + id: 2, + label: 'صنعت فولاد', + asset: Assets.politicalCategoryIcon, + ), + CategoryData( + id: 3, + label: 'بازار سرمایه', + asset: Assets.techCategoryIcon, + ), + ]; + } +} diff --git a/lib/views/home/radar/widgets/categories_gird.dart b/lib/views/home/widgets/categories_gird.dart similarity index 65% rename from lib/views/home/radar/widgets/categories_gird.dart rename to lib/views/home/widgets/categories_gird.dart index abcc0e2..f63c745 100644 --- a/lib/views/home/radar/widgets/categories_gird.dart +++ b/lib/views/home/widgets/categories_gird.dart @@ -1,27 +1,32 @@ import 'package:didvan/config/design_config.dart'; -import 'package:didvan/views/home/radar/radar_state.dart'; -import 'package:didvan/views/home/radar/widgets/category_item.dart'; +import 'package:didvan/models/category.dart'; +import 'package:didvan/views/home/widgets/category_item.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; class CategoriesRow1 extends StatelessWidget { - const CategoriesRow1({Key? key}) : super(key: key); + final List categories; + final bool isColapsed; + final double topPadding; + final void Function(CategoryData data) onSelected; + const CategoriesRow1({ + Key? key, + required this.categories, + required this.isColapsed, + required this.onSelected, + required this.topPadding, + }) : super(key: key); @override Widget build(BuildContext context) { - final state = context.read(); - final isColapsed = state.isColapsed || state.searching || state.filtering; final MediaQueryData d = MediaQuery.of(context); return AnimatedPositioned( curve: Curves.easeIn, duration: DesignConfig.mediumAnimationDuration, - top: isColapsed ? -60 : 300 + d.padding.top, + top: isColapsed ? -60 : topPadding + d.padding.top, left: isColapsed ? -80 : 0, right: isColapsed ? 124 : 0, child: Row( - children: context - .read() - .categories + children: categories .sublist(0, 3) .map( (category) => Expanded( @@ -30,6 +35,7 @@ class CategoriesRow1 extends StatelessWidget { child: CategoryItem( category: category, isColapsed: isColapsed, + onSelected: () => onSelected(category), ), ), ), @@ -41,14 +47,19 @@ class CategoriesRow1 extends StatelessWidget { } class CategoriesRow2 extends StatelessWidget { + final List categories; + final bool isColapsed; + final void Function(CategoryData data) onSelected; + const CategoriesRow2({ Key? key, + required this.categories, + required this.isColapsed, + required this.onSelected, }) : super(key: key); @override Widget build(BuildContext context) { - final state = context.read(); - final isColapsed = state.isColapsed || state.searching || state.filtering; final MediaQueryData d = MediaQuery.of(context); return AnimatedPositioned( curve: Curves.easeIn, @@ -57,14 +68,13 @@ class CategoriesRow2 extends StatelessWidget { left: isColapsed ? -d.size.width : 0, right: isColapsed ? d.size.width : 0, child: Row( - children: context - .read() - .categories + children: categories .sublist(3, 6) .map( (category) => Expanded( child: CategoryItem( category: category, + onSelected: () => onSelected(category), isColapsed: isColapsed, ), ), diff --git a/lib/views/home/radar/widgets/categories_list.dart b/lib/views/home/widgets/categories_list.dart similarity index 65% rename from lib/views/home/radar/widgets/categories_list.dart rename to lib/views/home/widgets/categories_list.dart index bca0187..5322119 100644 --- a/lib/views/home/radar/widgets/categories_list.dart +++ b/lib/views/home/widgets/categories_list.dart @@ -1,14 +1,24 @@ import 'package:didvan/config/design_config.dart'; import 'package:didvan/config/theme_data.dart'; -import 'package:didvan/models/view/radar_category.dart'; -import 'package:didvan/views/home/radar/radar_state.dart'; +import 'package:didvan/models/category.dart'; import 'package:didvan/views/widgets/animated_visibility.dart'; import 'package:didvan/views/widgets/didvan/text.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; class CategoriesList extends StatefulWidget { - const CategoriesList({Key? key}) : super(key: key); + final bool isColapsed; + final List selectedCats; + final List categories; + final VoidCallback onSelected; + final bool isRadar; + const CategoriesList({ + Key? key, + required this.isColapsed, + required this.selectedCats, + required this.categories, + required this.onSelected, + required this.isRadar, + }) : super(key: key); @override State createState() => _CategoriesListState(); @@ -21,12 +31,11 @@ class _CategoriesListState extends State { @override void didUpdateWidget(covariant CategoriesList oldWidget) { - final RadarState state = context.read(); - if (state.selectedCats.isNotEmpty && - _lastSelectedCategoryId != state.selectedCats.first.id) { - _lastSelectedCategoryId = state.selectedCats.first.id; + if (widget.selectedCats.isNotEmpty && + _lastSelectedCategoryId != widget.selectedCats.first.id) { + _lastSelectedCategoryId = widget.selectedCats.first.id; _scrollController.animateTo( - state.selectedCats.first.id * 100, + widget.selectedCats.first.id * 100, duration: DesignConfig.lowAnimationDuration, curve: Curves.easeIn, ); @@ -37,15 +46,14 @@ class _CategoriesListState extends State { @override Widget build(BuildContext context) { final MediaQueryData d = MediaQuery.of(context); - final state = context.read(); - final isColapsed = state.isColapsed || state.searching || state.filtering; return Positioned( top: 0, left: 0, right: 0, child: AnimatedCrossFade( - crossFadeState: - isColapsed ? CrossFadeState.showSecond : CrossFadeState.showFirst, + crossFadeState: widget.isColapsed + ? CrossFadeState.showSecond + : CrossFadeState.showFirst, duration: DesignConfig.mediumAnimationDuration, reverseDuration: DesignConfig.lowAnimationDuration, sizeCurve: Curves.easeIn, @@ -57,7 +65,7 @@ class _CategoriesListState extends State { boxShadow: DesignConfig.defaultShadow, ), child: AnimatedVisibility( - isVisible: isColapsed, + isVisible: widget.isColapsed, duration: DesignConfig.mediumAnimationDuration, child: SingleChildScrollView( controller: _scrollController, @@ -71,11 +79,14 @@ class _CategoriesListState extends State { child: Row( children: [ _itemBuilder( - RadarCategory(title: 'همه', asset: '', id: 0), + CategoryData( + label: widget.isRadar ? 'همه' : 'منتخب', + id: 0, + ), context, ), - for (var i = 0; i < state.categories.length; i++) - _itemBuilder(state.categories[i], context), + for (var i = 0; i < widget.categories.length; i++) + _itemBuilder(widget.categories[i], context), ], ), ), @@ -85,20 +96,19 @@ class _CategoriesListState extends State { ); } - Widget _itemBuilder(RadarCategory category, BuildContext context) { - final state = context.read(); + Widget _itemBuilder(CategoryData category, BuildContext context) { return GestureDetector( onTap: () async { - if (state.selectedCats.isNotEmpty && - state.selectedCats.first.id == category.id) return; - state.selectedCats.clear(); - if (category.id != 0) state.selectedCats.add(category); + if (widget.selectedCats.isNotEmpty && + widget.selectedCats.first.id == category.id) return; + widget.selectedCats.clear(); + if (category.id != 0) widget.selectedCats.add(category); await _scrollController.animateTo( category.id * 100, duration: DesignConfig.lowAnimationDuration, curve: Curves.easeIn, ); - state.getRadars(page: 1); + widget.onSelected(); }, child: Container( margin: const EdgeInsets.only(left: 12), @@ -108,15 +118,15 @@ class _CategoriesListState extends State { child: FittedBox( fit: BoxFit.scaleDown, child: DidvanText( - category.title, + category.label, fontWeight: FontWeight.w600, color: Theme.of(context).colorScheme.focusedBorder, ), ), decoration: BoxDecoration( - color: state.selectedCats.length == 1 && - state.selectedCats.contains(category) || - category.id == 0 && state.selectedCats.isEmpty + color: widget.selectedCats.length == 1 && + widget.selectedCats.contains(category) || + category.id == 0 && widget.selectedCats.isEmpty ? Theme.of(context).colorScheme.focused : null, border: Border.all( diff --git a/lib/views/home/radar/widgets/category_item.dart b/lib/views/home/widgets/category_item.dart similarity index 83% rename from lib/views/home/radar/widgets/category_item.dart rename to lib/views/home/widgets/category_item.dart index faee630..eaf6cf6 100644 --- a/lib/views/home/radar/widgets/category_item.dart +++ b/lib/views/home/widgets/category_item.dart @@ -1,22 +1,22 @@ import 'package:didvan/config/design_config.dart'; import 'package:didvan/config/theme_data.dart'; -import 'package:didvan/models/view/radar_category.dart'; -import 'package:didvan/views/home/radar/radar_state.dart'; +import 'package:didvan/models/category.dart'; import 'package:didvan/views/widgets/animated_visibility.dart'; import 'package:didvan/views/widgets/didvan/text.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; -import 'package:provider/provider.dart'; class CategoryItem extends StatelessWidget { - final RadarCategory category; + final CategoryData category; final bool isColapsed; + final VoidCallback onSelected; const CategoryItem({ Key? key, required this.isColapsed, required this.category, + required this.onSelected, }) : super(key: key); double _width(context) { @@ -40,14 +40,7 @@ class CategoryItem extends StatelessWidget { final Size ds = MediaQuery.of(context).size; return Center( child: GestureDetector( - onTap: () { - final state = context.read(); - state.selectedCats.clear(); - if (category.id != 0) { - state.selectedCats.add(category); - } - state.getRadars(page: 1); - }, + onTap: onSelected, child: AnimatedContainer( duration: DesignConfig.mediumAnimationDuration, padding: isColapsed ? const EdgeInsets.all(4) : EdgeInsets.zero, @@ -77,14 +70,14 @@ class CategoryItem extends StatelessWidget { borderRadius: DesignConfig.mediumBorderRadius, ), padding: const EdgeInsets.all(8), - child: SvgPicture.asset(category.asset), + child: SvgPicture.asset(category.asset!), ), ), const SizedBox( height: 8, ), DidvanText( - category.title, + category.label, style: Theme.of(context).textTheme.subtitle2, color: Theme.of(context).colorScheme.title, ),