From 0b9eedd6862ed72cda8e72fbda6a0c5a5d2f8474 Mon Sep 17 00:00:00 2001 From: MohammadTaha Basiri Date: Fri, 8 Apr 2022 15:59:29 +0430 Subject: [PATCH 01/18] studio finished --- .../images/empty_states/studio-dark.svg | 48 ---------------- .../images/empty_states/studio-light.svg | 55 ------------------- lib/constants/app_strings.dart | 1 - lib/constants/assets.dart | 2 - 4 files changed, 106 deletions(-) delete mode 100644 lib/assets/images/empty_states/studio-dark.svg delete mode 100644 lib/assets/images/empty_states/studio-light.svg delete mode 100644 lib/constants/app_strings.dart diff --git a/lib/assets/images/empty_states/studio-dark.svg b/lib/assets/images/empty_states/studio-dark.svg deleted file mode 100644 index 392039b..0000000 --- a/lib/assets/images/empty_states/studio-dark.svg +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/assets/images/empty_states/studio-light.svg b/lib/assets/images/empty_states/studio-light.svg deleted file mode 100644 index 5808670..0000000 --- a/lib/assets/images/empty_states/studio-light.svg +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/constants/app_strings.dart b/lib/constants/app_strings.dart deleted file mode 100644 index e8f4321..0000000 --- a/lib/constants/app_strings.dart +++ /dev/null @@ -1 +0,0 @@ -class AppStrings {} diff --git a/lib/constants/assets.dart b/lib/constants/assets.dart index e19e386..602abbb 100644 --- a/lib/constants/assets.dart +++ b/lib/constants/assets.dart @@ -42,8 +42,6 @@ class Assets { _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'; From dc7a26c64440ff42f7aafa14a853fd6213a914a2 Mon Sep 17 00:00:00 2001 From: MohammadTaha Basiri Date: Fri, 8 Apr 2022 16:26:36 +0430 Subject: [PATCH 02/18] dev deployment config + web video bug fixed --- .fandogh/fandogh.yaml | 8 ++++---- .../home/studio/studio_details/studio_details.web.dart | 7 +++++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/.fandogh/fandogh.yaml b/.fandogh/fandogh.yaml index 45fc5be..f3f18c9 100644 --- a/.fandogh/fandogh.yaml +++ b/.fandogh/fandogh.yaml @@ -1,13 +1,13 @@ kind: ExternalService -name: app-test +name: app-dev spec: allow_http: false disable_default_domains: true - image: app:1.2.0 + image: app-dev:1.5.11 image_pull_policy: IfNotPresent path: / replicas: 1 resources: - memory: 150Mi + memory: 100Mi domains: - - name: web.didvan.app \ No newline at end of file + - name: dev.didvan.app \ No newline at end of file diff --git a/lib/views/home/studio/studio_details/studio_details.web.dart b/lib/views/home/studio/studio_details/studio_details.web.dart index b944905..95aa28f 100644 --- a/lib/views/home/studio/studio_details/studio_details.web.dart +++ b/lib/views/home/studio/studio_details/studio_details.web.dart @@ -87,9 +87,12 @@ class _StudioDetailsState extends State { height: d.size.height - d.padding.top - 56, child: Column( children: [ - const AspectRatio( + AspectRatio( aspectRatio: 16 / 9, - child: HtmlElementView(viewType: 'video'), + child: HtmlElementView( + viewType: 'video', + key: ValueKey(state.studio.id), + ), ), Expanded( child: StudioDetailsWidget( From bba9e2d3647bc30439739fb600f3e7f17a536824 Mon Sep 17 00:00:00 2001 From: MohammadTaha Basiri Date: Sun, 10 Apr 2022 02:47:23 +0430 Subject: [PATCH 03/18] statistics basic skeletun --- lib/models/category.dart | 3 +- lib/models/view/radar_category.dart | 7 - lib/routes/route_generator.dart | 4 + lib/views/home/home.dart | 2 +- lib/views/home/news/news.dart | 100 +++++---- lib/views/home/radar/radar.dart | 44 +++- lib/views/home/radar/radar_state.dart | 30 +-- lib/views/home/statistics/statistics.dart | 196 ++++++++++++++++-- .../home/statistics/statistics_state.dart | 96 +++++++++ .../{radar => }/widgets/categories_gird.dart | 40 ++-- .../{radar => }/widgets/categories_list.dart | 66 +++--- .../{radar => }/widgets/category_item.dart | 21 +- 12 files changed, 455 insertions(+), 154 deletions(-) delete mode 100644 lib/models/view/radar_category.dart create mode 100644 lib/views/home/statistics/statistics_state.dart rename lib/views/home/{radar => }/widgets/categories_gird.dart (65%) rename lib/views/home/{radar => }/widgets/categories_list.dart (65%) rename lib/views/home/{radar => }/widgets/category_item.dart (83%) 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, ), From 4d774423370c7962ebdd3a8bdf7f93690c0e216d Mon Sep 17 00:00:00 2001 From: MohammadTaha Basiri Date: Thu, 14 Apr 2022 13:33:39 +0430 Subject: [PATCH 04/18] callout & in-app links --- lib/views/widgets/didvan/page_view.dart | 33 ++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/lib/views/widgets/didvan/page_view.dart b/lib/views/widgets/didvan/page_view.dart index a7cb236..54384af 100644 --- a/lib/views/widgets/didvan/page_view.dart +++ b/lib/views/widgets/didvan/page_view.dart @@ -2,10 +2,13 @@ import 'package:carousel_slider/carousel_slider.dart'; import 'package:didvan/config/design_config.dart'; import 'package:didvan/config/theme_data.dart'; import 'package:didvan/constants/app_icons.dart'; +import 'package:didvan/routes/routes.dart'; +import 'package:didvan/utils/action_sheet.dart'; import 'package:didvan/utils/date_time.dart'; import 'package:didvan/views/home/widgets/overview/multitype.dart'; import 'package:didvan/views/home/widgets/tag_item.dart'; import 'package:didvan/views/widgets/animated_visibility.dart'; +import 'package:didvan/views/widgets/didvan/button.dart'; import 'package:didvan/views/widgets/didvan/card.dart'; import 'package:didvan/views/widgets/didvan/divider.dart'; import 'package:didvan/views/widgets/didvan/text.dart'; @@ -190,7 +193,35 @@ class _DidvanPageViewState extends State { if (content.text != null) { return Html( data: content.text, - onAnchorTap: (href, context, map, element) => launch(href!), + onAnchorTap: (href, context, map, element) { + if (href!.contains('navigate-')) { + Navigator.of(ActionSheetUtils.context) + .pushNamed(Routes.statisticDetails, arguments: { + 'onMarkChanged': (value) {}, + 'label': href.split('-')[1], + 'title': href.split('-').last, + 'marked': false, + }); + } else if (href.contains('popup-')) { + showDialog( + context: ActionSheetUtils.context, + builder: (context) => DidvanCard( + child: Column( + children: [ + DidvanText(href.split('-').last), + const DidvanDivider(), + const DidvanButton( + title: 'بستن', + onPressed: ActionSheetUtils.pop, + ), + ], + ), + ), + ); + } else { + launch(href); + } + }, style: { '*': Style( direction: TextDirection.rtl, From 06e828b8c61377acace5c8a0a16e271206104a79 Mon Sep 17 00:00:00 2001 From: MohammadTaha Basiri Date: Fri, 15 Apr 2022 02:30:37 +0430 Subject: [PATCH 05/18] statistics base version --- lib/config/theme_data.dart | 1 + lib/models/statistic_data/data.dart | 64 ++++ lib/models/statistic_data/statistic_data.dart | 29 ++ lib/providers/user.dart | 17 + lib/routes/route_generator.dart | 17 +- lib/routes/routes.dart | 1 + lib/services/network/request_helper.dart | 16 + lib/views/home/home.dart | 4 +- lib/views/home/news/news.dart | 25 +- lib/views/home/radar/radar.dart | 4 +- .../statistic.dart} | 117 +++---- .../statistic_details/statistic_details.dart | 298 ++++++++++++++++++ .../statistic_details_state.dart | 168 ++++++++++ lib/views/home/statistic/statistic_state.dart | 115 +++++++ .../statistic/widgets/statistic_overview.dart | 135 ++++++++ .../home/statistics/statistics_state.dart | 96 ------ lib/views/home/widgets/categories_gird.dart | 6 +- lib/views/home/widgets/categories_list.dart | 104 +++--- .../widgets/state_handlers/state_handler.dart | 11 +- pubspec.lock | 14 + pubspec.yaml | 1 + 21 files changed, 1019 insertions(+), 224 deletions(-) create mode 100644 lib/models/statistic_data/data.dart create mode 100644 lib/models/statistic_data/statistic_data.dart rename lib/views/home/{statistics/statistics.dart => statistic/statistic.dart} (61%) create mode 100644 lib/views/home/statistic/statistic_details/statistic_details.dart create mode 100644 lib/views/home/statistic/statistic_details/statistic_details_state.dart create mode 100644 lib/views/home/statistic/statistic_state.dart create mode 100644 lib/views/home/statistic/widgets/statistic_overview.dart delete mode 100644 lib/views/home/statistics/statistics_state.dart diff --git a/lib/config/theme_data.dart b/lib/config/theme_data.dart index b1e6db7..5bbab96 100644 --- a/lib/config/theme_data.dart +++ b/lib/config/theme_data.dart @@ -192,6 +192,7 @@ extension DidvanColorScheme on ColorScheme { Color get overlay => brightness == Brightness.dark ? const Color(0xFF0F1011) : const Color(0xFF292929); + Color get yellow => const Color(0XFFEAA92A); // Error and success colors Color get errorBack => brightness == Brightness.dark diff --git a/lib/models/statistic_data/data.dart b/lib/models/statistic_data/data.dart new file mode 100644 index 0000000..0e46084 --- /dev/null +++ b/lib/models/statistic_data/data.dart @@ -0,0 +1,64 @@ +class Data { + final String p; + final String h; + final String l; + final String d; + final double dp; + final String dt; + final String t; + final String? tEn; + final String tG; + final String ts; + + Data({ + required this.p, + required this.h, + required this.l, + required this.d, + required this.dp, + required this.dt, + required this.t, + required this.tEn, + required this.tG, + required this.ts, + }); + + factory Data.fromJson(Map json) => Data( + p: json['p'], + h: json['h'], + l: json['l'], + d: json['d'], + dp: double.parse(json['dp'].toString()), + dt: json['dt'], + t: json['t'], + tEn: json['t_en'], + tG: json['t-g'], + ts: json['ts'], + ); + + factory Data.fromList(List list) => Data( + p: list[0], + h: list[1], + l: list[2], + d: list[3], + dp: double.parse(list[4].toString().replaceAll('-', '0')), + dt: list[5], + t: list[6], + tEn: list[7], + tG: '', + ts: '', + ); + + Map toJson() => { + 'p': p, + 'h': h, + 'l': l, + 'd': d, + 'dp': dp, + 'dt': dt, + 't': t, + 't_en': tEn, + 't-g': tG, + 'ts': ts, + }; +} diff --git a/lib/models/statistic_data/statistic_data.dart b/lib/models/statistic_data/statistic_data.dart new file mode 100644 index 0000000..5d720e7 --- /dev/null +++ b/lib/models/statistic_data/statistic_data.dart @@ -0,0 +1,29 @@ +import 'data.dart'; + +class StatisticData { + final int id; + final String label; + final String title; + final Data data; + + StatisticData({ + required this.id, + required this.label, + required this.title, + required this.data, + }); + + factory StatisticData.fromJson(Map json) => StatisticData( + id: json['id'], + label: json['label'], + title: json['title'], + data: Data.fromJson(json['data']), + ); + + Map toJson() => { + 'id': id, + 'label': label, + 'title': title, + 'data': data.toJson(), + }; +} diff --git a/lib/providers/user.dart b/lib/providers/user.dart index d87e0ce..f0341e8 100644 --- a/lib/providers/user.dart +++ b/lib/providers/user.dart @@ -16,6 +16,7 @@ class UserProvider extends CoreProvier { static final List _radarMarkQueue = []; static final List _newsMarkQueue = []; static final List _studioMarkQueue = []; + static final List _statisticMarkQueue = []; Future setAndGetToken({String? newToken}) async { if (newToken == null) { @@ -184,4 +185,20 @@ class UserProvider extends CoreProvier { _newsMarkQueue.removeWhere((element) => element.key == id); }); } + + static Future changeStatisticMark(int id, bool value) async { + _statisticMarkQueue.add(MapEntry(id, value)); + Future.delayed(const Duration(milliseconds: 500), () async { + final MapEntry? lastChange = + _statisticMarkQueue.lastWhereOrNull((item) => item.key == id); + if (lastChange == null) return; + final service = RequestService(RequestHelper.mark(id, 'statistic')); + if (lastChange.value) { + await service.post(); + } else { + await service.delete(); + } + _statisticMarkQueue.removeWhere((element) => element.key == id); + }); + } } diff --git a/lib/routes/route_generator.dart b/lib/routes/route_generator.dart index 3340685..47cf367 100644 --- a/lib/routes/route_generator.dart +++ b/lib/routes/route_generator.dart @@ -24,7 +24,9 @@ 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/statistic/statistic_details/statistic_details.dart'; +import 'package:didvan/views/home/statistic/statistic_details/statistic_details_state.dart'; +import 'package:didvan/views/home/statistic/statistic_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'; @@ -65,8 +67,8 @@ class RouteGenerator { ChangeNotifierProvider( create: (context) => StudioState(), ), - ChangeNotifierProvider( - create: (context) => StatisticsState(), + ChangeNotifierProvider( + create: (context) => StatisticState(), ), ], child: const Home(), @@ -111,6 +113,15 @@ class RouteGenerator { pageData: settings.arguments as Map, ), ); + case Routes.statisticDetails: + return _createRoute( + ChangeNotifierProvider( + create: (context) => StatisticDetailsState(), + child: StatisticDetails( + pageData: settings.arguments as Map, + ), + ), + ); case Routes.directList: return _createRoute( ChangeNotifierProvider( diff --git a/lib/routes/routes.dart b/lib/routes/routes.dart index fe94d78..23657ab 100644 --- a/lib/routes/routes.dart +++ b/lib/routes/routes.dart @@ -9,6 +9,7 @@ class Routes { static const String radarDetails = '/radar-details'; static const String newsDetails = '/news-details'; static const String studioDetails = '/studio-details'; + static const String statisticDetails = '/statistic-details'; static const String directList = '/direct-list'; static const String direct = '/direct'; static const String comments = '/comments'; diff --git a/lib/services/network/request_helper.dart b/lib/services/network/request_helper.dart index 525622e..6583f1d 100644 --- a/lib/services/network/request_helper.dart +++ b/lib/services/network/request_helper.dart @@ -8,6 +8,7 @@ class RequestHelper { static const String _baseRadarUrl = baseUrl + '/radar'; static const String _baseNewsUrl = baseUrl + '/news'; static const String _baseStudioUrl = baseUrl + '/studio'; + static const String _baseStatisticUrl = baseUrl + '/statistic'; static const String _baseDirectUrl = _baseUserUrl + '/direct'; static const String confirmUsername = _baseUserUrl + '/confirmUsername'; @@ -118,6 +119,21 @@ class RequestHelper { MapEntry('asc', args.asc), ]); + static String statisticOverviews(int? category) => + _baseStatisticUrl + + _urlConcatGenerator( + [MapEntry('category', category)], + ); + static String statisticDetails( + String label, + String period, + ) => + _baseStatisticUrl + + '/$label' + + _urlConcatGenerator([ + MapEntry('period', period), + ]); + static String mark(int id, String type) => baseUrl + '/$type/$id/mark'; static String tracking(int id, String type) => baseUrl + '/$type/$id/tracking'; diff --git a/lib/views/home/home.dart b/lib/views/home/home.dart index 914bb5e..aec1a56 100644 --- a/lib/views/home/home.dart +++ b/lib/views/home/home.dart @@ -3,7 +3,7 @@ import 'package:didvan/views/home/home_state.dart'; import 'package:didvan/views/home/news/news.dart'; import 'package:didvan/views/home/radar/radar.dart'; import 'package:didvan/views/home/settings/settings.dart'; -import 'package:didvan/views/home/statistics/statistics.dart'; +import 'package:didvan/views/home/statistic/statistic.dart'; import 'package:didvan/views/home/studio/studio.dart'; import 'package:didvan/views/widgets/didvan/bnb.dart'; import 'package:flutter/material.dart'; @@ -37,7 +37,7 @@ class _HomeState extends State with SingleTickerProviderStateMixin { controller: _tabController, children: const [ News(), - Statistics(), + Statistic(), Radar(), Studio(), Settings(), diff --git a/lib/views/home/news/news.dart b/lib/views/home/news/news.dart index c09916c..29cc5d8 100644 --- a/lib/views/home/news/news.dart +++ b/lib/views/home/news/news.dart @@ -37,7 +37,7 @@ class _NewsState extends State { onRetry: () => state.getNews(page: state.page), state: state, builder: (context, state) => ListView.builder( - cacheExtent: 1000, + cacheExtent: 1500, itemBuilder: (context, index) { if (index == 0) { return const LogoAppBar(); @@ -68,14 +68,21 @@ class _NewsState extends State { 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, + return Padding( + padding: const EdgeInsets.only( + left: 16, + right: 16, + bottom: 16, + ), + child: NewsOverview( + news: news, + onMarkChanged: state.onMarkChanged, + newsRequestArgs: NewsRequestArgs( + page: state.page, + endDate: state.endDate, + startDate: state.startDate, + search: state.search, + ), ), ); }, diff --git a/lib/views/home/radar/radar.dart b/lib/views/home/radar/radar.dart index b68a108..78ebc55 100644 --- a/lib/views/home/radar/radar.dart +++ b/lib/views/home/radar/radar.dart @@ -164,6 +164,7 @@ class _RadarState extends State { if (state.appState != AppState.failed) CategoriesRow1( topPadding: 300, + rightPadding: 124, onSelected: _onCategorySelected, categories: state.categories, isColapsed: @@ -180,11 +181,10 @@ class _RadarState extends State { !state.searching && !state.filtering) CategoriesList( - isRadar: true, categories: state.categories, isColapsed: state.isColapsed || state.searching || state.filtering, - onSelected: () => state.getRadars(page: 1), + onSelected: (_) => state.getRadars(page: 1), selectedCats: state.selectedCats, ), ], diff --git a/lib/views/home/statistics/statistics.dart b/lib/views/home/statistic/statistic.dart similarity index 61% rename from lib/views/home/statistics/statistics.dart rename to lib/views/home/statistic/statistic.dart index 565c41a..1651395 100644 --- a/lib/views/home/statistics/statistics.dart +++ b/lib/views/home/statistic/statistic.dart @@ -2,30 +2,29 @@ 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/models/statistic_data/statistic_data.dart'; +import 'package:didvan/views/home/statistic/statistic_state.dart'; +import 'package:didvan/views/home/statistic/widgets/statistic_overview.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/empty_list.dart'; import 'package:didvan/views/widgets/state_handlers/sliver_state_handler.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -class Statistics extends StatefulWidget { - const Statistics({Key? key}) : super(key: key); +class Statistic extends StatefulWidget { + const Statistic({Key? key}) : super(key: key); @override - State createState() => _RadarState(); + State createState() => _StatisticState(); } -class _RadarState extends State { +class _StatisticState extends State { final ScrollController _scrollController = ScrollController(); bool _isAnimating = false; @@ -35,7 +34,7 @@ class _RadarState extends State { _scrollController.addListener(() { _handleAnimations(); }); - final state = context.read(); + final state = context.read(); state.addListener(() { if (state.shouldColapse && mounted) { _handleAnimations(true); @@ -48,7 +47,7 @@ class _RadarState extends State { @override Widget build(BuildContext context) { - return Consumer( + return Consumer( builder: (context, state, child) => Stack( children: [ CustomScrollView( @@ -60,7 +59,7 @@ class _RadarState extends State { const SliverToBoxAdapter(child: LogoAppBar()), if (state.appState != AppState.failed) const SliverToBoxAdapter( - child: SizedBox(height: 156), + child: SizedBox(height: 180), ), if (state.appState != AppState.failed) SliverPadding( @@ -80,85 +79,89 @@ class _RadarState extends State { ), ), ), - SliverStateHandler( - onRetry: () => state.getStatistics(page: state.page), + SliverStateHandler( + onRetry: () => state.getStatistic(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, + emptyState: const EmptyList(), + enableEmptyState: _itemCount(state) == 0, + placeholder: StatisticOverview.placeHolder, builder: (context, state, index) { - index += 2; - if (index % 15 == 0 && state.lastPage != state.page) { - state.getStatistics(page: state.page + 1); + bool isMarked = false; + StatisticData statistic; + if (index < state.markedStatistics.length) { + isMarked = true; + statistic = state.markedStatistics[index]; + } else { + statistic = + state.statistics[index - state.markedStatistics.length]; } - index -= 2; - if (index >= state.statistics.length) { - return RadarOverview.placeholder; - } - final radar = state.statistics[index]; - return RadarOverview( - radar: radar, + return StatisticOverview( + statistic: statistic, + isMarked: isMarked, 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), + childCount: _itemCount(state), ), - if (state.statistics.length == 1) - const SliverToBoxAdapter( - child: SizedBox(height: 320), + SliverToBoxAdapter( + child: SizedBox( + height: state.appState == AppState.busy + ? 300 + : _itemCount(state) == 0 + ? 150 + : max( + MediaQuery.of(context).size.height - + _itemCount(state) * 120, + 0), ), + ), ], ), if (state.appState != AppState.failed) CategoriesRow1( onSelected: _onCategorySelected, - categories: state.categories, + categories: List.from(state.categories)..removeAt(0), isColapsed: state.isColapsed, - topPadding: 120, + topPadding: 144, + rightPadding: 300, ), if (state.appState != AppState.failed) CategoriesList( - isRadar: false, categories: state.categories, isColapsed: state.isColapsed, - onSelected: () => state.getStatistics(page: 1), - selectedCats: state.selectedCats, + onSelected: (id) { + state.selectedCategoryId = id; + state.getStatistic(page: 1); + }, + selectedCats: state.selectedCategory == null + ? [] + : [state.selectedCategory!], ), ], ), ); } + int _itemCount(state) => + state.markedStatistics.length + + (state.selectedCategoryId == 1 ? 0 : state.statistics.length); + void _onCategorySelected(CategoryData category) { - final state = context.read(); - state.selectedCats.clear(); + final state = context.read(); + state.selectedCategoryId = 0; if (category.id != 0) { - state.selectedCats.add(category); + state.selectedCategoryId = category.id; } - state.getStatistics(page: 1); + state.getStatistic(page: 1); } void _handleAnimations([bool forceAnimate = false]) async { - final state = context.read(); + final state = context.read(); if (_isAnimating) return; final double position = _scrollController.offset; if (position > 5 && !state.isColapsed || forceAnimate) { @@ -166,14 +169,14 @@ class _RadarState extends State { _isAnimating = true; setState(() {}); await _scrollController.animateTo( - 200, + 228, duration: DesignConfig.mediumAnimationDuration, curve: Curves.easeIn, ); _isAnimating = false; setState(() {}); } else if (position < - min(_scrollController.position.maxScrollExtent, 200) && + min(_scrollController.position.maxScrollExtent, 228) && state.isColapsed) { state.isScrolled = false; _isAnimating = true; diff --git a/lib/views/home/statistic/statistic_details/statistic_details.dart b/lib/views/home/statistic/statistic_details/statistic_details.dart new file mode 100644 index 0000000..bc7fdcf --- /dev/null +++ b/lib/views/home/statistic/statistic_details/statistic_details.dart @@ -0,0 +1,298 @@ +import 'package:didvan/config/theme_data.dart'; +import 'package:didvan/constants/app_icons.dart'; +import 'package:didvan/models/enums.dart'; +import 'package:didvan/models/view/app_bar_data.dart'; +import 'package:didvan/views/home/statistic/statistic_details/statistic_details_state.dart'; +import 'package:didvan/views/home/widgets/categories_list.dart'; +import 'package:didvan/views/home/widgets/overview/multitype.dart'; +import 'package:didvan/views/home/widgets/tag_item.dart'; +import 'package:didvan/views/widgets/didvan/card.dart'; +import 'package:didvan/views/widgets/didvan/divider.dart'; +import 'package:didvan/views/widgets/didvan/icon_button.dart'; +import 'package:didvan/views/widgets/didvan/scaffold.dart'; +import 'package:didvan/views/widgets/didvan/text.dart'; +import 'package:didvan/views/widgets/state_handlers/state_handler.dart'; +import 'package:fl_chart/fl_chart.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_spinkit/flutter_spinkit.dart'; +import 'package:provider/provider.dart'; +import 'package:intl/intl.dart' as intl; + +class StatisticDetails extends StatefulWidget { + final Map pageData; + const StatisticDetails({Key? key, required this.pageData}) : super(key: key); + + @override + State createState() => _StatisticDetailsState(); +} + +class _StatisticDetailsState extends State { + @override + void initState() { + final state = context.read(); + state.label = widget.pageData['label']; + state.marked = widget.pageData['marked']; + state.currentDateRangeId = 0; + Future.delayed(Duration.zero, state.getStatisticDetails); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Consumer( + builder: (context, state, child) => DidvanScaffold( + padding: EdgeInsets.zero, + appBarData: AppBarData( + title: widget.pageData['title'], + hasBack: true, + subtitle: 'رادار قیمت‌ها', + trailing: DidvanIconButton( + icon: state.marked ? Icons.star : Icons.star_border, + color: state.marked + ? Theme.of(context).colorScheme.yellow + : Theme.of(context).colorScheme.focusedBorder, + size: 32, + onPressed: () { + state.marked = !state.marked; + state.update(); + widget.pageData['onMarkChanged'](state.marked); + }, + ), + ), + children: [ + StateHandler( + topPadding: MediaQuery.of(context).size.height / 3, + builder: (context, state) => Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 20), + const Padding( + padding: EdgeInsets.symmetric(horizontal: 16), + child: DidvanText('نمودار تغییرات'), + ), + const SizedBox(height: 20), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: SizedBox( + width: double.infinity, + height: 120, + child: state.chartState == AppState.busy + ? SpinKitThreeBounce( + color: Theme.of(context).colorScheme.primary, + size: 24, + ) + : LineChart( + LineChartData( + lineTouchData: LineTouchData( + touchTooltipData: LineTouchTooltipData( + tooltipBgColor: + Theme.of(context).colorScheme.navigation, + getTooltipItems: (data) => [ + LineTooltipItem( + state.datas[data.first.spotIndex].tEn! + + '\n' + + intl.NumberFormat("###,000", "en_US") + .format( + data.first.bar + .spots[data.first.spotIndex].y, + ), + Theme.of(context) + .textTheme + .caption! + .copyWith( + color: Colors.white, + ), + ), + ], + ), + ), + minX: 0, + maxX: state.datas.length.toDouble() - 1, + maxY: state.maxValue * 1.001, + minY: state.minValue, + gridData: FlGridData(show: false), + borderData: FlBorderData(show: false), + titlesData: FlTitlesData(show: false), + lineBarsData: [ + LineChartBarData( + spots: [ + for (var i = 0; i < state.datas.length; i++) + FlSpot( + i.toDouble(), + _stringToDouble(state.datas[i].p), + ) + ], + barWidth: 2, + dotData: FlDotData( + getDotPainter: (p0, p1, p2, p3) => + FlDotCirclePainter( + color: Colors.transparent, + strokeWidth: 1, + strokeColor: + Theme.of(context).colorScheme.success, + ), + ), + color: Theme.of(context).colorScheme.success, + belowBarData: BarAreaData( + show: true, + gradient: LinearGradient( + begin: Alignment.bottomCenter, + end: Alignment.topCenter, + tileMode: TileMode.decal, + colors: [ + Theme.of(context) + .colorScheme + .background, + const Color(0XFFF5B763) + .withOpacity(0.2), + ], + ), + ), + ), + ], + ), + ), + ), + ), + const SizedBox(height: 20), + const Padding( + padding: EdgeInsets.symmetric(horizontal: 16), + child: DidvanText('بازه نمایش:'), + ), + const SizedBox(height: 20), + CategoriesList( + isColapsed: false, + isAppBar: false, + selectedCats: [state.currentDateRange], + categories: state.dateRanges, + onSelected: (id) { + state.currentDateRangeId = id; + state.getStatisticDetails(); + }, + ), + const SizedBox(height: 16), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: DidvanCard( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildDataItem('قیمت لحظه‌ای', state.data!.p), + const DidvanDivider(verticalPadding: 8), + _buildDataItem('بالاترین قیمت روز', state.data!.h), + const SizedBox(height: 8), + _buildDataItem('پایین‌ترین قیمت روز', state.data!.l), + const SizedBox(height: 8), + _buildDataItem( + 'درصد تغییر نسبت به دیروز', + '${state.data!.dp}%', + icon: _diffIcon(state), + color: _diffColor(state), + ), + const SizedBox(height: 8), + _buildDataItem( + 'میزان تغییر نسبت به دیروز', + state.data!.d, + icon: _diffIcon(state), + color: _diffColor(state), + ), + const SizedBox(height: 16), + Wrap( + spacing: 8, + runSpacing: 8, + children: [ + for (var i = 0; i < state.tags.length; i++) + TagItem( + tag: state.tags[i], + onMarkChanged: (_, __) {}, + type: 'statistic', + ), + ], + ), + ], + ), + ), + ), + const SizedBox(height: 16), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: DidvanCard( + child: Column( + children: [ + if (state.relatedContents.isEmpty) + for (var i = 0; i < 3; i++) ...[ + MultitypeOverview.placeholder, + if (i != 2) const SizedBox(height: 16) + ], + for (var i = 0; + i < state.relatedContents.length; + i++) ...[ + MultitypeOverview( + item: state.relatedContents[i], + onMarkChanged: (id, value) {}, + ), + if (i != state.relatedContents.length - 1) + const SizedBox(height: 16) + ] + ], + ), + ), + ), + const SizedBox(height: 16), + ], + ), + onRetry: state.getStatisticDetails, + state: state, + ) + ], + ), + ); + } + + double _stringToDouble(String value) => + double.parse(value.replaceAll(',', '')); + + Color? _diffColor(StatisticDetailsState state) { + if (state.data!.dp == 0) { + return null; + } + if (state.data!.dt == 'low') { + return Theme.of(context).colorScheme.success; + } else { + return Theme.of(context).colorScheme.error; + } + } + + IconData? _diffIcon(StatisticDetailsState state) { + if (state.data!.dp == 0) { + return null; + } + if (state.data!.dt == 'low') { + return DidvanIcons.angle_up_regular; + } else { + return DidvanIcons.angle_down_regular; + } + } + + Widget _buildDataItem( + String title, + String value, { + IconData? icon, + bool isBold = false, + Color? color, + }) { + return Row( + children: [ + DidvanText( + title, + style: isBold + ? Theme.of(context).textTheme.bodyText1 + : Theme.of(context).textTheme.bodyText2, + ), + const Spacer(), + if (icon != null) Icon(icon, color: color), + DidvanText(value, color: color), + ], + ); + } +} diff --git a/lib/views/home/statistic/statistic_details/statistic_details_state.dart b/lib/views/home/statistic/statistic_details/statistic_details_state.dart new file mode 100644 index 0000000..9d22e04 --- /dev/null +++ b/lib/views/home/statistic/statistic_details/statistic_details_state.dart @@ -0,0 +1,168 @@ +import 'package:didvan/models/category.dart'; +import 'package:didvan/models/enums.dart'; +import 'package:didvan/models/overview_data.dart'; +import 'package:didvan/models/statistic_data/data.dart'; +import 'package:didvan/models/tag.dart'; +import 'package:didvan/providers/core.dart'; +import 'package:didvan/services/network/request.dart'; +import 'package:didvan/services/network/request_helper.dart'; +import 'package:collection/collection.dart'; + +class StatisticDetailsState extends CoreProvier { + late bool marked; + late String label; + String? startDate; + String? endDate; + int currentDateRangeId = 0; + final List datas = []; + final List relatedContents = []; + final List tags = []; + Data? data; + double maxValue = 0; + double? minValue; + + AppState chartState = AppState.idle; + + final dateRanges = [ + CategoryData( + id: 0, + label: 'هفتگی', + asset: 'weekly', + ), + CategoryData( + id: 1, + label: 'ماهانه', + asset: 'monthly', + ), + CategoryData( + id: 2, + label: 'شش ماهه', + asset: 'semiyearly', + ), + CategoryData( + id: 3, + label: 'سالانه', + asset: 'yearly', + ), + ]; + + CategoryData get currentDateRange => dateRanges.firstWhere( + (element) => element.id == currentDateRangeId, + ); + + Future getStatisticDetails() async { + if (data == null) { + final result = await getStatisticCurrentDetails(); + if (!result) { + appState = AppState.failed; + return; + } + } + minValue = null; + maxValue = 0; + if (datas.isEmpty) { + appState = AppState.busy; + } else { + chartState = AppState.busy; + notifyListeners(); + } + datas.clear(); + final service = RequestService( + RequestHelper.statisticDetails( + label, + dateRanges[currentDateRangeId].asset!, + ), + ); + await service.httpGet(); + if (service.isSuccess) { + final result = service.result['data']; + tags.clear(); + for (var i = 0; i < service.result['tags'].length; i++) { + tags.add(Tag.fromJson(service.result['tags'][i])); + } + for (var i = 0; i < result.length; i++) { + datas.add(Data.fromList(result[i])); + final highest = _stringToDouble(datas.last.h); + final lowest = _stringToDouble(datas.last.l); + if (highest > maxValue) { + maxValue = highest; + } + if (lowest < (minValue ?? _stringToDouble(datas.last.p))) { + minValue = lowest; + } + } + if (currentDateRangeId != 0 && currentDateRangeId != 1) { + final grouped = + datas.groupListsBy((element) => element.tEn!.split('/')[1]); + datas.clear(); + grouped.forEach((key, value) { + datas.add( + Data( + p: _average(value), + h: maxValue.toString(), + l: minValue.toString(), + d: '', + dp: 0, + dt: '', + t: '', + tEn: value.first.tEn!.substring(0, 7), + tG: '', + ts: '', + ), + ); + }); + } + getRelatedContents(); + datas.replaceRange(0, datas.length, datas.reversed); + chartState = AppState.idle; + appState = AppState.idle; + return; + } + if (datas.isEmpty) { + appState = AppState.failed; + } else { + chartState = AppState.failed; + notifyListeners(); + } + } + + Future getStatisticCurrentDetails() async { + final service = RequestService( + RequestHelper.statisticDetails( + label, + 'current', + ), + ); + await service.httpGet(); + if (service.isSuccess) { + data = Data.fromJson(service.result['data']); + } + return service.isSuccess; + } + + String _average(List inputs) { + double sum = 0; + for (var i = 0; i < inputs.length; i++) { + sum += _stringToDouble(inputs[i].p); + } + return (sum / inputs.length).toString(); + } + + double _stringToDouble(String value) => + double.parse(value.replaceAll(',', '')); + + Future getRelatedContents() async { + if (relatedContents.isNotEmpty) return; + final service = RequestService(RequestHelper.tag( + ids: tags.map((tag) => tag.id).toList(), + )); + await service.httpGet(); + if (service.isSuccess) { + final relateds = service.result['contents']; + for (var i = 0; i < relateds.length; i++) { + relatedContents.add(OverviewData.fromJson(relateds[i])); + } + notifyListeners(); + } + } +} diff --git a/lib/views/home/statistic/statistic_state.dart b/lib/views/home/statistic/statistic_state.dart new file mode 100644 index 0000000..2cbcaca --- /dev/null +++ b/lib/views/home/statistic/statistic_state.dart @@ -0,0 +1,115 @@ +import 'package:didvan/constants/assets.dart'; +import 'package:collection/collection.dart'; +import 'package:didvan/models/category.dart'; +import 'package:didvan/models/enums.dart'; +import 'package:didvan/models/statistic_data/statistic_data.dart'; +import 'package:didvan/providers/core.dart'; +import 'package:didvan/providers/user.dart'; +import 'package:didvan/services/network/request.dart'; +import 'package:didvan/services/network/request_helper.dart'; + +class StatisticState extends CoreProvier { + int page = 1; + bool isScrolled = false; + bool shouldColapse = false; + int selectedCategoryId = -1; + List categories = []; + final List statistics = []; + final List markedStatistics = []; + + bool get isColapsed => (isCategorySelected && isScrolled) || isScrolled; + + CategoryData? get selectedCategory => categories.firstWhereOrNull( + (element) => element.id == selectedCategoryId, + ); + + bool get isCategorySelected => selectedCategoryId != 0; + + void resetFilters(bool isInit) { + selectedCategoryId = 0; + isScrolled = false; + if (!isInit) { + getStatistic(page: 1); + } + } + + Future getStatistic({ + required int page, + }) async { + this.page = page; + if (this.page == page) { + statistics.clear(); + } + if (page == 1) { + appState = AppState.busy; + } + final RequestService service = RequestService( + RequestHelper.statisticOverviews( + selectedCategoryId == 0 || selectedCategoryId == 1 + ? null + : selectedCategoryId - 1, + ), + ); + await service.httpGet(); + if (service.isSuccess) { + final others = service.result['others']; + for (var i = 0; i < others.length; i++) { + statistics.add(StatisticData.fromJson(others[i])); + } + final marked = service.result['marked']; + for (var i = 0; i < marked.length; i++) { + statistics.add(StatisticData.fromJson(marked[i])); + } + if (isColapsed || isCategorySelected) { + shouldColapse = true; + } + appState = AppState.idle; + return; + } + + appState = AppState.failed; + } + + Future changeMark(int id, bool value) async { + final item = statistics.firstWhereOrNull((element) => element.id == id) ?? + markedStatistics.firstWhere((element) => element.id == id); + if (value) { + markedStatistics.add(item); + statistics.remove(item); + } else { + markedStatistics.remove(item); + statistics.add(item); + } + UserProvider.changeStatisticMark(id, value); + notifyListeners(); + } + + void init() { + resetFilters(true); + Future.delayed(Duration.zero, () { + getStatistic(page: 1); + }); + categories = [ + CategoryData( + id: 1, + label: 'منتخب', + asset: Assets.economicCategoryIcon, + ), + CategoryData( + id: 2, + label: 'اقتصاد کلان', + asset: Assets.economicCategoryIcon, + ), + CategoryData( + id: 3, + label: 'صنعت فولاد', + asset: Assets.politicalCategoryIcon, + ), + CategoryData( + id: 4, + label: 'بازار سرمایه', + asset: Assets.techCategoryIcon, + ), + ]; + } +} diff --git a/lib/views/home/statistic/widgets/statistic_overview.dart b/lib/views/home/statistic/widgets/statistic_overview.dart new file mode 100644 index 0000000..52906e5 --- /dev/null +++ b/lib/views/home/statistic/widgets/statistic_overview.dart @@ -0,0 +1,135 @@ +import 'package:didvan/config/theme_data.dart'; +import 'package:didvan/constants/app_icons.dart'; +import 'package:didvan/models/statistic_data/statistic_data.dart'; +import 'package:didvan/routes/routes.dart'; +import 'package:didvan/views/widgets/didvan/card.dart'; +import 'package:didvan/views/widgets/didvan/text.dart'; +import 'package:didvan/views/widgets/shimmer_placeholder.dart'; +import 'package:flutter/material.dart'; + +class StatisticOverview extends StatelessWidget { + final StatisticData statistic; + final bool isMarked; + final void Function(int id, bool value) onMarkChanged; + const StatisticOverview({ + Key? key, + required this.statistic, + required this.isMarked, + required this.onMarkChanged, + }) : super(key: key); + + Color _diffColor(context) => statistic.data.dt == 'low' + ? Theme.of(context).colorScheme.success + : Theme.of(context).colorScheme.error; + + bool get _hasDiff => statistic.data.d != '0'; + + @override + Widget build(BuildContext context) { + return DidvanCard( + onTap: () => + Navigator.of(context).pushNamed(Routes.statisticDetails, arguments: { + 'onMarkChanged': (value) => onMarkChanged(statistic.id, value), + 'label': statistic.label, + 'title': statistic.title, + 'marked': isMarked, + }), + child: Column( + children: [ + Row( + children: [ + if (isMarked) + Icon( + Icons.star, + color: Theme.of(context).colorScheme.yellow, + size: 18, + ), + DidvanText( + statistic.title, + style: Theme.of(context).textTheme.bodyText1, + ), + const Spacer(), + if (_hasDiff) + DidvanText( + '(${statistic.data.d})', + color: _diffColor(context), + ), + if (_hasDiff) const SizedBox(width: 8), + DidvanText( + statistic.data.p, + style: Theme.of(context).textTheme.bodyText1, + ) + ], + ), + const SizedBox(height: 8), + Row( + children: [ + Icon( + Icons.trending_down, + size: 18, + color: Theme.of(context).colorScheme.hint, + ), + DidvanText( + statistic.data.l, + style: Theme.of(context).textTheme.caption, + color: Theme.of(context).colorScheme.hint, + ), + const SizedBox(width: 8), + Icon( + Icons.trending_up, + size: 18, + color: Theme.of(context).colorScheme.hint, + ), + DidvanText( + statistic.data.h, + style: Theme.of(context).textTheme.caption, + color: Theme.of(context).colorScheme.hint, + ), + const Spacer(), + if (_hasDiff) + Icon( + statistic.data.dt == 'low' + ? DidvanIcons.angle_up_regular + : DidvanIcons.angle_down_regular, + size: 18, + color: _diffColor(context), + ), + if (_hasDiff) const SizedBox(width: 4), + if (_hasDiff) + DidvanText( + statistic.data.dp.toString() + '%', + style: Theme.of(context).textTheme.caption, + color: _diffColor(context), + ), + ], + ), + ], + ), + ); + } + + static Widget get placeHolder => DidvanCard( + child: Column( + children: [ + const SizedBox(height: 4), + Row( + children: const [ + ShimmerPlaceholder(width: 80, height: 16), + Spacer(), + ShimmerPlaceholder(width: 50, height: 14), + SizedBox(width: 8), + ShimmerPlaceholder(width: 50, height: 16), + ], + ), + const SizedBox(height: 16), + Row( + children: const [ + ShimmerPlaceholder(width: 150, height: 12), + Spacer(), + ShimmerPlaceholder(width: 80, height: 12), + ], + ), + ], + ), + ); +} diff --git a/lib/views/home/statistics/statistics_state.dart b/lib/views/home/statistics/statistics_state.dart deleted file mode 100644 index 6ebcaf7..0000000 --- a/lib/views/home/statistics/statistics_state.dart +++ /dev/null @@ -1,96 +0,0 @@ -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/widgets/categories_gird.dart b/lib/views/home/widgets/categories_gird.dart index f63c745..564ad03 100644 --- a/lib/views/home/widgets/categories_gird.dart +++ b/lib/views/home/widgets/categories_gird.dart @@ -7,6 +7,7 @@ class CategoriesRow1 extends StatelessWidget { final List categories; final bool isColapsed; final double topPadding; + final double rightPadding; final void Function(CategoryData data) onSelected; const CategoriesRow1({ Key? key, @@ -14,6 +15,7 @@ class CategoriesRow1 extends StatelessWidget { required this.isColapsed, required this.onSelected, required this.topPadding, + required this.rightPadding, }) : super(key: key); @override @@ -23,8 +25,8 @@ class CategoriesRow1 extends StatelessWidget { curve: Curves.easeIn, duration: DesignConfig.mediumAnimationDuration, top: isColapsed ? -60 : topPadding + d.padding.top, - left: isColapsed ? -80 : 0, - right: isColapsed ? 124 : 0, + left: isColapsed ? -rightPadding : 0, + right: isColapsed ? rightPadding : 0, child: Row( children: categories .sublist(0, 3) diff --git a/lib/views/home/widgets/categories_list.dart b/lib/views/home/widgets/categories_list.dart index 5322119..5a718be 100644 --- a/lib/views/home/widgets/categories_list.dart +++ b/lib/views/home/widgets/categories_list.dart @@ -7,17 +7,17 @@ import 'package:flutter/material.dart'; class CategoriesList extends StatefulWidget { final bool isColapsed; + final bool isAppBar; final List selectedCats; final List categories; - final VoidCallback onSelected; - final bool isRadar; + final void Function(int id) onSelected; const CategoriesList({ Key? key, required this.isColapsed, required this.selectedCats, required this.categories, required this.onSelected, - required this.isRadar, + this.isAppBar = true, }) : super(key: key); @override @@ -46,54 +46,60 @@ class _CategoriesListState extends State { @override Widget build(BuildContext context) { final MediaQueryData d = MediaQuery.of(context); - return Positioned( - top: 0, - left: 0, - right: 0, - child: AnimatedCrossFade( - crossFadeState: widget.isColapsed - ? CrossFadeState.showSecond - : CrossFadeState.showFirst, - duration: DesignConfig.mediumAnimationDuration, - reverseDuration: DesignConfig.lowAnimationDuration, - sizeCurve: Curves.easeIn, - firstChild: const SizedBox(), - secondChild: Container( - height: 60 + d.padding.top, - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surface, - boxShadow: DesignConfig.defaultShadow, - ), - child: AnimatedVisibility( - isVisible: widget.isColapsed, - duration: DesignConfig.mediumAnimationDuration, - child: SingleChildScrollView( - controller: _scrollController, - // physics: const BouncingScrollPhysics(), - scrollDirection: Axis.horizontal, - padding: EdgeInsets.only( - top: d.padding.top + 12, - bottom: 12, - right: 12, - ), - child: Row( - children: [ - _itemBuilder( - CategoryData( - label: widget.isRadar ? 'همه' : 'منتخب', - id: 0, - ), - context, - ), - for (var i = 0; i < widget.categories.length; i++) - _itemBuilder(widget.categories[i], context), - ], + final child = SingleChildScrollView( + controller: _scrollController, + scrollDirection: Axis.horizontal, + padding: widget.isAppBar + ? EdgeInsets.only( + top: d.padding.top + 12, + bottom: 12, + ) + : null, + child: Row( + children: [ + const SizedBox(width: 12), + if (widget.isAppBar) + _itemBuilder( + CategoryData( + label: 'همه', + id: 0, ), + context, + ), + for (var i = 0; i < widget.categories.length; i++) + _itemBuilder(widget.categories[i], context), + ], + ), + ); + if (widget.isAppBar) { + return Positioned( + top: 0, + left: 0, + right: 0, + child: AnimatedCrossFade( + crossFadeState: widget.isColapsed + ? CrossFadeState.showSecond + : CrossFadeState.showFirst, + duration: DesignConfig.mediumAnimationDuration, + reverseDuration: DesignConfig.lowAnimationDuration, + sizeCurve: Curves.easeIn, + firstChild: const SizedBox(), + secondChild: Container( + height: 60 + d.padding.top, + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, + boxShadow: DesignConfig.defaultShadow, + ), + child: AnimatedVisibility( + isVisible: widget.isColapsed, + duration: DesignConfig.mediumAnimationDuration, + child: child, ), ), ), - ), - ); + ); + } + return child; } Widget _itemBuilder(CategoryData category, BuildContext context) { @@ -108,7 +114,7 @@ class _CategoriesListState extends State { duration: DesignConfig.lowAnimationDuration, curve: Curves.easeIn, ); - widget.onSelected(); + widget.onSelected(category.id); }, child: Container( margin: const EdgeInsets.only(left: 12), @@ -127,7 +133,7 @@ class _CategoriesListState extends State { color: widget.selectedCats.length == 1 && widget.selectedCats.contains(category) || category.id == 0 && widget.selectedCats.isEmpty - ? Theme.of(context).colorScheme.focused + ? Theme.of(context).colorScheme.splash : null, border: Border.all( color: Theme.of(context).colorScheme.focusedBorder, diff --git a/lib/views/widgets/state_handlers/state_handler.dart b/lib/views/widgets/state_handlers/state_handler.dart index 0addd30..c54c651 100644 --- a/lib/views/widgets/state_handlers/state_handler.dart +++ b/lib/views/widgets/state_handlers/state_handler.dart @@ -38,10 +38,13 @@ class StateHandler extends StatelessWidget { case AppState.idle: return builder(context, state); case AppState.busy: - return placeholder ?? - SpinKitSpinningLines( - color: Theme.of(context).colorScheme.primary, - ); + return Padding( + padding: EdgeInsets.only(top: topPadding), + child: placeholder ?? + SpinKitSpinningLines( + color: Theme.of(context).colorScheme.primary, + ), + ); case AppState.failed: return Center(child: EmptyConnection(onRetry: onRetry)); default: diff --git a/pubspec.lock b/pubspec.lock index f08bc28..737d1d4 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -141,6 +141,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.5" + equatable: + dependency: transitive + description: + name: equatable + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.3" expandable_bottom_sheet: dependency: "direct main" description: @@ -211,6 +218,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.2.10" + fl_chart: + dependency: "direct main" + description: + name: fl_chart + url: "https://pub.dartlang.org" + source: hosted + version: "0.50.1" flutter: dependency: "direct main" description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index dfc7dfa..adebac7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -66,6 +66,7 @@ dependencies: permission_handler: ^9.2.0 better_player: ^0.0.81 assets_audio_player: ^3.0.4+1 + fl_chart: ^0.50.1 dev_dependencies: From 27e44fb764e1a04cfa628ae111854ef685b91eff Mon Sep 17 00:00:00 2001 From: MohammadTaha Basiri Date: Sat, 16 Apr 2022 14:37:51 +0430 Subject: [PATCH 06/18] statistic category icons added --- lib/assets/images/categories/glob-dark.svg | 54 +++++++++++++++++++ lib/assets/images/categories/glob-light.svg | 54 +++++++++++++++++++ lib/assets/images/categories/steel-dark.svg | 9 ++++ lib/assets/images/categories/steel-light.svg | 9 ++++ lib/assets/images/categories/stock-dark.svg | 42 +++++++++++++++ lib/assets/images/categories/stock-light.svg | 42 +++++++++++++++ lib/constants/assets.dart | 27 ++++++---- lib/views/home/statistic/statistic_state.dart | 6 +-- 8 files changed, 230 insertions(+), 13 deletions(-) create mode 100644 lib/assets/images/categories/glob-dark.svg create mode 100644 lib/assets/images/categories/glob-light.svg create mode 100644 lib/assets/images/categories/steel-dark.svg create mode 100644 lib/assets/images/categories/steel-light.svg create mode 100644 lib/assets/images/categories/stock-dark.svg create mode 100644 lib/assets/images/categories/stock-light.svg diff --git a/lib/assets/images/categories/glob-dark.svg b/lib/assets/images/categories/glob-dark.svg new file mode 100644 index 0000000..a70de82 --- /dev/null +++ b/lib/assets/images/categories/glob-dark.svg @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/assets/images/categories/glob-light.svg b/lib/assets/images/categories/glob-light.svg new file mode 100644 index 0000000..3888540 --- /dev/null +++ b/lib/assets/images/categories/glob-light.svg @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/assets/images/categories/steel-dark.svg b/lib/assets/images/categories/steel-dark.svg new file mode 100644 index 0000000..6b56bc0 --- /dev/null +++ b/lib/assets/images/categories/steel-dark.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/lib/assets/images/categories/steel-light.svg b/lib/assets/images/categories/steel-light.svg new file mode 100644 index 0000000..1c1cc9b --- /dev/null +++ b/lib/assets/images/categories/steel-light.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/lib/assets/images/categories/stock-dark.svg b/lib/assets/images/categories/stock-dark.svg new file mode 100644 index 0000000..818f6e5 --- /dev/null +++ b/lib/assets/images/categories/stock-dark.svg @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/assets/images/categories/stock-light.svg b/lib/assets/images/categories/stock-light.svg new file mode 100644 index 0000000..22ccde7 --- /dev/null +++ b/lib/assets/images/categories/stock-light.svg @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/constants/assets.dart b/lib/constants/assets.dart index 602abbb..f582dff 100644 --- a/lib/constants/assets.dart +++ b/lib/constants/assets.dart @@ -4,11 +4,12 @@ import 'package:flutter/cupertino.dart'; 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 _baseCategoriesPath = _baseImagesPath + '/categories'; + static const String _baseThemesPath = _baseImagesPath + '/themes'; + static const String _baseEmptyStatesPath = _baseImagesPath + '/empty_states'; static const String _baseAnimationsPath = _basePath + '/animations'; - static const String _baseRecordsPath = _basePath + '/images/records'; - static const String _baseLogosPath = _basePath + '/images/logos'; + static const String _baseRecordsPath = _baseImagesPath + '/records'; + static const String _baseLogosPath = _baseImagesPath + '/logos'; static String get verticalLogoWithText => _baseLogosPath + '/logo-vertical-$_themeSuffix.svg'; @@ -20,17 +21,23 @@ class Assets { _baseAnimationsPath + '/indicator-$_themeSuffix.riv'; static String get businessCategoryIcon => - _baseImagesPath + '/categories/business-$_themeSuffix.svg'; + _baseCategoriesPath + '/business-$_themeSuffix.svg'; static String get economicCategoryIcon => - _baseImagesPath + '/categories/economic-$_themeSuffix.svg'; + _baseCategoriesPath + '/economic-$_themeSuffix.svg'; static String get enviromentalCategoryIcon => - _baseImagesPath + '/categories/enviromental-$_themeSuffix.svg'; + _baseCategoriesPath + '/enviromental-$_themeSuffix.svg'; static String get politicalCategoryIcon => - _baseImagesPath + '/categories/political-$_themeSuffix.svg'; + _baseCategoriesPath + '/political-$_themeSuffix.svg'; static String get socialCategoryIcon => - _baseImagesPath + '/categories/social-$_themeSuffix.svg'; + _baseCategoriesPath + '/social-$_themeSuffix.svg'; static String get techCategoryIcon => - _baseImagesPath + '/categories/tech-$_themeSuffix.svg'; + _baseCategoriesPath + '/tech-$_themeSuffix.svg'; + static String get steelCategoryIcon => + _baseCategoriesPath + '/steel-$_themeSuffix.svg'; + static String get stockCategoryIcon => + _baseCategoriesPath + '/stock-$_themeSuffix.svg'; + static String get globCategoryIcon => + _baseCategoriesPath + '/glob-$_themeSuffix.svg'; static String get emptyBookmark => _baseEmptyStatesPath + '/bookmark-$_themeSuffix.svg'; diff --git a/lib/views/home/statistic/statistic_state.dart b/lib/views/home/statistic/statistic_state.dart index 2cbcaca..19d7883 100644 --- a/lib/views/home/statistic/statistic_state.dart +++ b/lib/views/home/statistic/statistic_state.dart @@ -98,17 +98,17 @@ class StatisticState extends CoreProvier { CategoryData( id: 2, label: 'اقتصاد کلان', - asset: Assets.economicCategoryIcon, + asset: Assets.globCategoryIcon, ), CategoryData( id: 3, label: 'صنعت فولاد', - asset: Assets.politicalCategoryIcon, + asset: Assets.steelCategoryIcon, ), CategoryData( id: 4, label: 'بازار سرمایه', - asset: Assets.techCategoryIcon, + asset: Assets.stockCategoryIcon, ), ]; } From e865f15f7073b0d8610746ed50d6727b31a1cc56 Mon Sep 17 00:00:00 2001 From: MohammadTaha Basiri Date: Sun, 17 Apr 2022 13:37:57 +0430 Subject: [PATCH 07/18] bug fixes --- lib/providers/server_data.dart | 12 +- lib/services/media/media.dart | 3 +- lib/views/home/news/news.dart | 108 +++++++++--------- lib/views/home/settings/settings.dart | 5 +- .../statistic/widgets/statistic_overview.dart | 67 ++++++++--- .../state_handlers/sliver_state_handler.dart | 9 +- 6 files changed, 121 insertions(+), 83 deletions(-) diff --git a/lib/providers/server_data.dart b/lib/providers/server_data.dart index 4ef71bb..3468d29 100644 --- a/lib/providers/server_data.dart +++ b/lib/providers/server_data.dart @@ -9,12 +9,18 @@ class ServerDataProvider { await _getDirectTypes(); } - static int labelToTypeId(String label) => label.contains('پشتیبانی') - ? 7 - : directTypes + static int labelToTypeId(String label) { + if (label.contains('پشتیبانی اپلیکیشن')) { + return 8; + } else if (label.contains('پشتیبانی')) { + return 7; + } else { + return directTypes .firstWhereOrNull((element) => element.value.contains(label)) ?.key ?? 7; + } + } static Future _getDirectTypes() async { final service = RequestService(RequestHelper.directTypes); diff --git a/lib/services/media/media.dart b/lib/services/media/media.dart index a783e23..2342acd 100644 --- a/lib/services/media/media.dart +++ b/lib/services/media/media.dart @@ -14,7 +14,8 @@ class MediaService { static StudioDetailsData? currentPodcast; static StudioRequestArgs? podcastPlaylistArgs; - static Duration? get duration => audioPlayer.current.value?.audio.duration; + static Duration? get duration => + audioPlayer.current.valueOrNull?.audio.duration; static Future handleAudioPlayback({ required dynamic audioSource, diff --git a/lib/views/home/news/news.dart b/lib/views/home/news/news.dart index 29cc5d8..bbfed23 100644 --- a/lib/views/home/news/news.dart +++ b/lib/views/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/requests/news.dart'; import 'package:didvan/models/view/action_sheet_data.dart'; import 'package:didvan/utils/action_sheet.dart'; @@ -10,7 +11,8 @@ 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/state_handler.dart'; +import 'package:didvan/views/widgets/state_handlers/empty_result.dart'; +import 'package:didvan/views/widgets/state_handlers/sliver_state_handler.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -32,62 +34,58 @@ class _NewsState extends State { @override Widget build(BuildContext context) { - return Consumer( - builder: (context, state, child) => StateHandler( + 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( + centerEmptyState: false, onRetry: () => state.getNews(page: state.page), state: state, - builder: (context, state) => ListView.builder( - cacheExtent: 1500, - 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 Padding( - padding: const EdgeInsets.only( - left: 16, - right: 16, - bottom: 16, - ), - child: 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, - )), + 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, + ), + ], ); } diff --git a/lib/views/home/settings/settings.dart b/lib/views/home/settings/settings.dart index e923da5..eae023f 100644 --- a/lib/views/home/settings/settings.dart +++ b/lib/views/home/settings/settings.dart @@ -94,7 +94,10 @@ class Settings extends StatelessWidget { icon: DidvanIcons.support_regular, title: 'پیام به پشتیبانی', onTap: () { - launch('mailto:info@didvan.app'); + Navigator.of(context).pushNamed( + Routes.direct, + arguments: {'type': 'پشتیبانی اپلیکیشن'}, + ); }, ), const DidvanDivider(), diff --git a/lib/views/home/statistic/widgets/statistic_overview.dart b/lib/views/home/statistic/widgets/statistic_overview.dart index 52906e5..cfa585e 100644 --- a/lib/views/home/statistic/widgets/statistic_overview.dart +++ b/lib/views/home/statistic/widgets/statistic_overview.dart @@ -108,28 +108,57 @@ class StatisticOverview extends StatelessWidget { ); } - static Widget get placeHolder => DidvanCard( - child: Column( - children: [ - const SizedBox(height: 4), - Row( - children: const [ - ShimmerPlaceholder(width: 80, height: 16), - Spacer(), - ShimmerPlaceholder(width: 50, height: 14), - SizedBox(width: 8), - ShimmerPlaceholder(width: 50, height: 16), + static Widget get placeHolder => Column( + children: [ + DidvanCard( + child: Column( + children: [ + const SizedBox(height: 4), + Row( + children: const [ + ShimmerPlaceholder(width: 80, height: 16), + Spacer(), + ShimmerPlaceholder(width: 50, height: 14), + SizedBox(width: 8), + ShimmerPlaceholder(width: 50, height: 16), + ], + ), + const SizedBox(height: 16), + Row( + children: const [ + ShimmerPlaceholder(width: 150, height: 12), + Spacer(), + ShimmerPlaceholder(width: 80, height: 12), + ], + ), ], ), - const SizedBox(height: 16), - Row( - children: const [ - ShimmerPlaceholder(width: 150, height: 12), - Spacer(), - ShimmerPlaceholder(width: 80, height: 12), + ), + const SizedBox(height: 20), + DidvanCard( + child: Column( + children: [ + const SizedBox(height: 4), + Row( + children: const [ + ShimmerPlaceholder(width: 80, height: 16), + Spacer(), + ShimmerPlaceholder(width: 50, height: 14), + SizedBox(width: 8), + ShimmerPlaceholder(width: 50, height: 16), + ], + ), + const SizedBox(height: 16), + Row( + children: const [ + ShimmerPlaceholder(width: 150, height: 12), + Spacer(), + ShimmerPlaceholder(width: 80, height: 12), + ], + ), ], ), - ], - ), + ), + ], ); } diff --git a/lib/views/widgets/state_handlers/sliver_state_handler.dart b/lib/views/widgets/state_handlers/sliver_state_handler.dart index 1e70ddb..8338a49 100644 --- a/lib/views/widgets/state_handlers/sliver_state_handler.dart +++ b/lib/views/widgets/state_handlers/sliver_state_handler.dart @@ -13,6 +13,7 @@ class SliverStateHandler extends SliverList { final Widget? placeholder; final EdgeInsets? itemPadding; final bool centerEmptyState; + final bool hasConstraints; SliverStateHandler({ Key? key, required this.state, @@ -24,14 +25,16 @@ class SliverStateHandler extends SliverList { this.emptyState, this.enableEmptyState = false, this.centerEmptyState = true, + this.hasConstraints = false, }) : super( key: key, delegate: SliverChildBuilderDelegate( (context, index) { + final deviceHight = MediaQuery.of(context).size.height; if (state.appState == AppState.failed) { return Padding( padding: EdgeInsets.only( - top: centerEmptyState ? 120 : 20, + top: centerEmptyState ? deviceHight / 4 : deviceHight / 8, bottom: 20, ), child: EmptyConnection(onRetry: onRetry), @@ -40,9 +43,7 @@ class SliverStateHandler extends SliverList { if (enableEmptyState && state.appState == AppState.idle) { return Padding( padding: EdgeInsets.only( - top: centerEmptyState - ? MediaQuery.of(context).size.height / 4 - : 20, + top: centerEmptyState ? deviceHight / 4 : deviceHight / 8, bottom: 20, ), child: emptyState, From 6e8fe074da5479df870777821c4f689ce7892039 Mon Sep 17 00:00:00 2001 From: MohammadTaha Basiri Date: Sun, 17 Apr 2022 14:25:39 +0430 Subject: [PATCH 08/18] bug fixes --- .../statistic_details/statistic_details.dart | 4 ++-- .../statistic_details_state.dart | 21 ++++++++++--------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/lib/views/home/statistic/statistic_details/statistic_details.dart b/lib/views/home/statistic/statistic_details/statistic_details.dart index bc7fdcf..b8dd16f 100644 --- a/lib/views/home/statistic/statistic_details/statistic_details.dart +++ b/lib/views/home/statistic/statistic_details/statistic_details.dart @@ -108,8 +108,8 @@ class _StatisticDetailsState extends State { ), minX: 0, maxX: state.datas.length.toDouble() - 1, - maxY: state.maxValue * 1.001, - minY: state.minValue, + maxY: state.maxValue * 1.02, + minY: state.minValue! * 0.98, gridData: FlGridData(show: false), borderData: FlBorderData(show: false), titlesData: FlTitlesData(show: false), diff --git a/lib/views/home/statistic/statistic_details/statistic_details_state.dart b/lib/views/home/statistic/statistic_details/statistic_details_state.dart index 9d22e04..a87ef8c 100644 --- a/lib/views/home/statistic/statistic_details/statistic_details_state.dart +++ b/lib/views/home/statistic/statistic_details/statistic_details_state.dart @@ -82,14 +82,6 @@ class StatisticDetailsState extends CoreProvier { } for (var i = 0; i < result.length; i++) { datas.add(Data.fromList(result[i])); - final highest = _stringToDouble(datas.last.h); - final lowest = _stringToDouble(datas.last.l); - if (highest > maxValue) { - maxValue = highest; - } - if (lowest < (minValue ?? _stringToDouble(datas.last.p))) { - minValue = lowest; - } } if (currentDateRangeId != 0 && currentDateRangeId != 1) { final grouped = @@ -99,8 +91,8 @@ class StatisticDetailsState extends CoreProvier { datas.add( Data( p: _average(value), - h: maxValue.toString(), - l: minValue.toString(), + h: '', + l: '', d: '', dp: 0, dt: '', @@ -112,6 +104,15 @@ class StatisticDetailsState extends CoreProvier { ); }); } + for (var i = 0; i < datas.length; i++) { + final current = _stringToDouble(datas[i].p); + if (maxValue < current) { + maxValue = current; + } + if (minValue == null || minValue! > current) { + minValue = current; + } + } getRelatedContents(); datas.replaceRange(0, datas.length, datas.reversed); chartState = AppState.idle; From 0c47465d2a240980d0596e97ed01a4ba04075284 Mon Sep 17 00:00:00 2001 From: MohammadTaha Basiri Date: Wed, 20 Apr 2022 03:11:21 +0430 Subject: [PATCH 09/18] bug fixes --- lib/views/home/direct/direct.dart | 4 +++- lib/views/home/widgets/search_field.dart | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/views/home/direct/direct.dart b/lib/views/home/direct/direct.dart index d47be3c..5673434 100644 --- a/lib/views/home/direct/direct.dart +++ b/lib/views/home/direct/direct.dart @@ -56,7 +56,9 @@ class _DirectState extends State { backgroundColor: Theme.of(context).colorScheme.surface, appBarData: AppBarData( hasBack: true, - subtitle: 'ارتباط با سردبیر', + subtitle: widget.pageData['type'] == null + ? null + : 'ارتباط با سردبیر', title: widget.pageData['type'] ?? 'پشتیبانی اپلیکیشن', ), slivers: [ diff --git a/lib/views/home/widgets/search_field.dart b/lib/views/home/widgets/search_field.dart index 9a979b7..d0fb92d 100644 --- a/lib/views/home/widgets/search_field.dart +++ b/lib/views/home/widgets/search_field.dart @@ -78,7 +78,7 @@ class _SearchFieldState extends State { right: 12, ), border: InputBorder.none, - hintText: 'جستجو مطلب در ${widget.title}', + hintText: 'جستجو در ${widget.title}', hintStyle: TextStyle( color: Theme.of(context).colorScheme.disabledText, ), From 5072704b86d0e903a41a965c15027966ef8a28aa Mon Sep 17 00:00:00 2001 From: MohammadTaha Basiri Date: Wed, 20 Apr 2022 21:28:03 +0430 Subject: [PATCH 10/18] delete direct messages + bug fixes --- lib/providers/server_data.dart | 2 +- lib/services/network/request_helper.dart | 2 + lib/views/home/direct/direct.dart | 43 ++++- lib/views/home/direct/direct_state.dart | 13 ++ .../home/direct/widgets/audio_widget.dart | 30 ++-- lib/views/home/direct/widgets/message.dart | 169 ++++++++++-------- 6 files changed, 171 insertions(+), 88 deletions(-) diff --git a/lib/providers/server_data.dart b/lib/providers/server_data.dart index 3468d29..4aac55f 100644 --- a/lib/providers/server_data.dart +++ b/lib/providers/server_data.dart @@ -12,7 +12,7 @@ class ServerDataProvider { static int labelToTypeId(String label) { if (label.contains('پشتیبانی اپلیکیشن')) { return 8; - } else if (label.contains('پشتیبانی')) { + } else if (label.contains('پشتیبانی محتوا')) { return 7; } else { return directTypes diff --git a/lib/services/network/request_helper.dart b/lib/services/network/request_helper.dart index 6583f1d..cbf4411 100644 --- a/lib/services/network/request_helper.dart +++ b/lib/services/network/request_helper.dart @@ -40,6 +40,8 @@ class RequestHelper { static String direct(int id) => _baseDirectUrl + '/$id'; static String sendDirectMessage(int id) => _baseDirectUrl + '/$id/sendMessage'; + static String deleteDirect(int id, int messageId) => + _baseDirectUrl + '/$id/message/$messageId'; static String tag({ required List ids, String? type, diff --git a/lib/views/home/direct/direct.dart b/lib/views/home/direct/direct.dart index 5673434..2c0ba84 100644 --- a/lib/views/home/direct/direct.dart +++ b/lib/views/home/direct/direct.dart @@ -1,3 +1,4 @@ +import 'package:didvan/constants/app_icons.dart'; import 'package:didvan/constants/assets.dart'; import 'package:didvan/models/enums.dart'; import 'package:didvan/models/view/app_bar_data.dart'; @@ -6,7 +7,9 @@ import 'package:didvan/services/media/media.dart'; import 'package:didvan/views/home/direct/direct_state.dart'; import 'package:didvan/views/home/direct/widgets/message.dart'; import 'package:didvan/views/home/direct/widgets/message_box.dart'; +import 'package:didvan/views/widgets/didvan/icon_button.dart'; import 'package:didvan/views/widgets/didvan/scaffold.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'; @@ -52,11 +55,12 @@ class _DirectState extends State { left: 0, right: 0, child: DidvanScaffold( + padding: EdgeInsets.zero, reverse: true, backgroundColor: Theme.of(context).colorScheme.surface, appBarData: AppBarData( hasBack: true, - subtitle: widget.pageData['type'] == null + subtitle: widget.pageData['type'].contains('پشتیبانی') ? null : 'ارتباط با سردبیر', title: widget.pageData['type'] ?? 'پشتیبانی اپلیکیشن', @@ -105,6 +109,43 @@ class _DirectState extends State { left: 0, child: const MessageBox(), ), + if (state.deletionQueue.isNotEmpty) + Positioned( + left: 0, + right: 0, + top: d.padding.top, + child: Container( + height: 72, + color: Theme.of(context).colorScheme.surface, + child: Row( + children: [ + DidvanIconButton( + icon: DidvanIcons.close_solid, + size: 32, + gestureSize: 48, + color: Theme.of(context).colorScheme.secondary, + onPressed: () { + state.deletionQueue.clear(); + state.update(); + }, + ), + DidvanText( + '${state.deletionQueue.length} مورد انتخاب شد', + style: Theme.of(context).textTheme.subtitle1, + color: Theme.of(context).colorScheme.secondary, + ), + const Spacer(), + DidvanIconButton( + icon: DidvanIcons.trash_solid, + size: 32, + gestureSize: 48, + color: Theme.of(context).colorScheme.primary, + onPressed: state.delete, + ), + ], + ), + ), + ), ], ), ), diff --git a/lib/views/home/direct/direct_state.dart b/lib/views/home/direct/direct_state.dart index 20964d5..ba1e98c 100644 --- a/lib/views/home/direct/direct_state.dart +++ b/lib/views/home/direct/direct_state.dart @@ -16,6 +16,7 @@ class DirectState extends CoreProvier { final List messages = []; late final int typeId; final Map> dailyMessages = {}; + final List deletionQueue = []; String? text; RadarAttachment? replyRadar; @@ -77,6 +78,18 @@ class DirectState extends CoreProvier { } } + void delete() { + for (var i = 0; i < deletionQueue.length; i++) { + final service = RequestService( + RequestHelper.deleteDirect(typeId, deletionQueue[i]), + ); + service.delete(); + messages.removeWhere((element) => element.id == deletionQueue[i]); + } + deletionQueue.clear(); + notifyListeners(); + } + void _addToDailyGrouped(MessageData message) { String createdAt = message.createdAt.replaceAll('T', ' ').split(' ').first; if (!dailyMessages.containsKey(createdAt)) { diff --git a/lib/views/home/direct/widgets/audio_widget.dart b/lib/views/home/direct/widgets/audio_widget.dart index 5f1c8bd..7e55bd4 100644 --- a/lib/views/home/direct/widgets/audio_widget.dart +++ b/lib/views/home/direct/widgets/audio_widget.dart @@ -20,24 +20,24 @@ class AudioWidget extends StatelessWidget { @override Widget build(BuildContext context) { - return StreamBuilder( - stream: MediaService.audioPlayer.isPlaying, - builder: (context, snapshot) { - return Row( - children: [ - Expanded( - child: AudioSlider( - tag: 'message-$id', - ), - ), - _AudioControllerButton( + return Row( + children: [ + Expanded( + child: AudioSlider( + tag: 'message-$id', + ), + ), + StreamBuilder( + stream: MediaService.audioPlayer.isPlaying, + builder: (context, snapshot) { + return _AudioControllerButton( audioFile: audioFile, audioUrl: audioUrl, id: id, - ), - ], - ); - }, + ); + }, + ), + ], ); } } diff --git a/lib/views/home/direct/widgets/message.dart b/lib/views/home/direct/widgets/message.dart index ff90eb1..d1c5e6a 100644 --- a/lib/views/home/direct/widgets/message.dart +++ b/lib/views/home/direct/widgets/message.dart @@ -18,85 +18,109 @@ class Message extends StatelessWidget { @override Widget build(BuildContext context) { - final firstMessageOfGroupId = context - .read() + final state = context.read(); + final firstMessageOfGroupId = state .dailyMessages[message.createdAt.replaceAll('T', ' ').split(' ').first]! .last; - return Column( - crossAxisAlignment: message.writedByAdmin - ? CrossAxisAlignment.end - : CrossAxisAlignment.start, - children: [ - if (message.id == firstMessageOfGroupId) - Center( - child: Container( - margin: const EdgeInsets.only(bottom: 12), - padding: const EdgeInsets.all(4), - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.splash, - borderRadius: DesignConfig.lowBorderRadius, - ), - child: DidvanText( - DateTime.parse(message.createdAt).toPersianDateStr(), - style: Theme.of(context).textTheme.overline, - color: DesignConfig.isDark - ? Theme.of(context).colorScheme.white - : Theme.of(context).colorScheme.black, - ), - ), - ), - Padding( - padding: EdgeInsets.only( - right: message.writedByAdmin ? 20 : 0, - left: !message.writedByAdmin ? 20 : 0, - ), - child: Column( - crossAxisAlignment: message.writedByAdmin - ? CrossAxisAlignment.start - : CrossAxisAlignment.end, - children: [ - _MessageContainer( - writedByAdmin: message.writedByAdmin, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (message.text != null) DidvanText(message.text!), - if (message.audio != null || message.audioFile != null) - AudioWidget( - audioFile: message.audioFile, - audioUrl: message.audio, - id: message.id, - ), - if (message.radar != null) const DidvanDivider(), - if (message.radar != null) const SizedBox(height: 4), - if (message.radar != null) - _ReplyRadarOverview(message: message), - if (message.radar != null) const SizedBox(height: 4), - ], + return GestureDetector( + onLongPress: () { + if (state.deletionQueue.contains(message.id) || message.writedByAdmin) { + return; + } + state.deletionQueue.add(message.id); + state.update(); + }, + onTap: () { + if (state.deletionQueue.isEmpty || message.writedByAdmin) return; + if (!state.deletionQueue.contains(message.id)) { + state.deletionQueue.add(message.id); + } else { + state.deletionQueue.remove(message.id); + } + state.update(); + }, + child: Container( + color: state.deletionQueue.contains(message.id) + ? Theme.of(context).colorScheme.secondaryDisabled.withOpacity(0.5) + : null, + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + child: Column( + crossAxisAlignment: message.writedByAdmin + ? CrossAxisAlignment.end + : CrossAxisAlignment.start, + children: [ + if (message.id == firstMessageOfGroupId) + Center( + child: Container( + margin: const EdgeInsets.only(bottom: 12), + padding: const EdgeInsets.all(4), + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.splash, + borderRadius: DesignConfig.lowBorderRadius, + ), + child: DidvanText( + DateTime.parse(message.createdAt).toPersianDateStr(), + style: Theme.of(context).textTheme.overline, + color: DesignConfig.isDark + ? Theme.of(context).colorScheme.white + : Theme.of(context).colorScheme.black, + ), ), ), - const SizedBox(height: 4), - Row( - mainAxisSize: MainAxisSize.min, + Padding( + padding: EdgeInsets.only( + right: message.writedByAdmin ? 20 : 0, + left: !message.writedByAdmin ? 20 : 0, + ), + child: Column( + crossAxisAlignment: message.writedByAdmin + ? CrossAxisAlignment.start + : CrossAxisAlignment.end, children: [ - DidvanText( - DateTimeUtils.timeWithAmPm(message.createdAt), - style: Theme.of(context).textTheme.overline, - color: Theme.of(context).colorScheme.caption, + _MessageContainer( + writedByAdmin: message.writedByAdmin, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (message.text != null) DidvanText(message.text!), + if (message.audio != null || message.audioFile != null) + AudioWidget( + audioFile: message.audioFile, + audioUrl: message.audio, + id: message.id, + ), + if (message.radar != null) const DidvanDivider(), + if (message.radar != null) const SizedBox(height: 4), + if (message.radar != null) + _ReplyRadarOverview(message: message), + if (message.radar != null) const SizedBox(height: 4), + ], + ), + ), + const SizedBox(height: 4), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + DidvanText( + DateTimeUtils.timeWithAmPm(message.createdAt), + style: Theme.of(context).textTheme.overline, + color: Theme.of(context).colorScheme.caption, + ), + if (!message.writedByAdmin) + Icon( + message.readed + ? DidvanIcons.check_double_light + : DidvanIcons.check_light, + size: 16, + ) + ], ), - if (!message.writedByAdmin) - Icon( - message.readed - ? DidvanIcons.check_double_light - : DidvanIcons.check_light, - size: 16, - ) ], ), - ], - ), + ), + ], ), - ], + ), ); } } @@ -177,7 +201,10 @@ class _MessageContainer extends StatelessWidget { bottomLeft: writedByAdmin ? Radius.zero : null, bottomRight: !writedByAdmin ? Radius.zero : null, ), - color: writedByAdmin ? null : Theme.of(context).colorScheme.focused, + color: (writedByAdmin + ? Theme.of(context).colorScheme.surface + : Theme.of(context).colorScheme.focused) + .withOpacity(0.9), border: Border.all( color: Theme.of(context).colorScheme.border, width: 0.5, From a52ac7cdaebbc583116e618e0654934a9d09074d Mon Sep 17 00:00:00 2001 From: MohammadTaha Basiri Date: Wed, 20 Apr 2022 22:56:33 +0430 Subject: [PATCH 11/18] terms of service & privacy pokicy updates --- lib/routes/route_generator.dart | 5 ---- .../authentication/screens/username.dart | 14 +++++------ .../home/settings/about_us/about_us.dart | 25 ------------------- lib/views/home/settings/settings.dart | 7 +++--- 4 files changed, 11 insertions(+), 40 deletions(-) delete mode 100644 lib/views/home/settings/about_us/about_us.dart diff --git a/lib/routes/route_generator.dart b/lib/routes/route_generator.dart index 47cf367..95aa9f4 100644 --- a/lib/routes/route_generator.dart +++ b/lib/routes/route_generator.dart @@ -14,7 +14,6 @@ import 'package:didvan/views/home/news/news_state.dart'; import 'package:didvan/views/home/radar/radar_details/radar_details.dart'; import 'package:didvan/views/home/radar/radar_details/radar_details_state.dart'; import 'package:didvan/views/home/radar/radar_state.dart'; -import 'package:didvan/views/home/settings/about_us/about_us.dart'; import 'package:didvan/views/home/settings/bookmarks/bookmarks.dart'; import 'package:didvan/views/home/settings/bookmarks/bookmark_state.dart'; import 'package:didvan/views/home/settings/bookmarks/filtered_bookmark/filtered_bookmark.dart'; @@ -78,10 +77,6 @@ class RouteGenerator { return _createRoute( const Profile(), ); - case Routes.aboutUs: - return _createRoute( - const AboutUs(), - ); case Routes.generalSettings: return _createRoute( ChangeNotifierProvider( diff --git a/lib/views/authentication/screens/username.dart b/lib/views/authentication/screens/username.dart index 6c5cf8c..cd28681 100644 --- a/lib/views/authentication/screens/username.dart +++ b/lib/views/authentication/screens/username.dart @@ -65,14 +65,16 @@ class _UsernameInputState extends State { text: TextSpan( style: Theme.of(context).textTheme.caption, children: [ - const TextSpan(text: 'با و ورود به دیدوان،'), + const TextSpan(text: 'با ورود به دیدوان،'), TextSpan( text: ' شرایط ', style: Theme.of(context) .textTheme .caption! .copyWith(color: Theme.of(context).colorScheme.primary), - recognizer: TapGestureRecognizer()..onTap = _openTermsOfUse, + recognizer: TapGestureRecognizer() + ..onTap = () => + launch('https://didvan.app/termsOfUse.html#conditions'), ), const TextSpan(text: 'و\n'), TextSpan( @@ -81,7 +83,9 @@ class _UsernameInputState extends State { .textTheme .caption! .copyWith(color: Theme.of(context).colorScheme.primary), - recognizer: TapGestureRecognizer()..onTap = _openTermsOfUse, + recognizer: TapGestureRecognizer() + ..onTap = () => + launch('https://didvan.app/termsOfUse.html#privacy'), ), const TextSpan(text: 'را می‌پذیرم'), ], @@ -94,8 +98,4 @@ class _UsernameInputState extends State { ], ); } - - void _openTermsOfUse() { - launch('https://didvan.app/termsOfUse.html'); - } } diff --git a/lib/views/home/settings/about_us/about_us.dart b/lib/views/home/settings/about_us/about_us.dart deleted file mode 100644 index 6cc17f9..0000000 --- a/lib/views/home/settings/about_us/about_us.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'package:didvan/models/view/app_bar_data.dart'; -import 'package:didvan/views/widgets/didvan/scaffold.dart'; -import 'package:didvan/views/widgets/didvan/text.dart'; -import 'package:flutter/material.dart'; - -class AboutUs extends StatelessWidget { - const AboutUs({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return DidvanScaffold( - appBarData: AppBarData( - hasBack: true, - title: 'معرفی دیدوان', - ), - children: const [ - DidvanText( - '''برای سفر مطمئن در جغرافیای مکانی به ابزارهایی مانند نقشه، قطب نما، سیستم ناوبری، علائم کنار جاده و یا حتی علائم طبیعی نیاز داریم. اما برای سفر در جغرافیای زمانی چه؟ -همه ما آدمیان و همه‌ی سازمان‌ها و شرکت‌هایمان، لاجرم مسافران جغرافیای زمانی هستند. ما همواره در مسیری رو به مقصدی در آینده در حرکت هستیم. اما فراموش نکنیم که سفر زمانی یک تفاوت بنیادین با طی مسیر در جغرافیای مکانی دارد. جغرافیای زمانی هیچ‌گاه نمی‌ایستد و سفر به آینده یک سفر شگفت‌انگیز به جایی است که قسمت‌هایی از آن را قبلاً در گذشته دیده‌ایم، قسمت‌هایی از آن را طی مسیر به تدریج می‌بینیم و قسمت‌هایی از آن کاملاً بدیع هستند. -برای سفر مطمئن در جغرافیای زمانی ما به سیستم‌های پیش‌نگر نیاز داریم و یکی از ارکان این سیستم‌ها، سامانه‌های رصد راهبردی هستند. دیدوان با شعار "چشم همیشه باز مدیران" سامانه رصد راهبردی شرکت فولاد مبارکه است تا سفری مطمئن به آینده را برای این شرکت رقم بزند.\nدر پارسی کهن دیدوان به این شکل معنی شده است: شخصی را گویند که بر جای بلند مانند سر کوه و بالای کشتی نشیند و هرچه از دور بیند خبر دهد. دیدوان چشمی است که آینده را می‌بیند. ما در دیدوان تلاش داریم که با رویکردی آینده‌پژوهانه مسیر پیش‌روی صنایع را تحلیل کنیم و با تحویل آن به مدیران صنایع، راهنمایی باشیم برای اخذ تصمیمات درست.''', - ), - ], - ); - } -} diff --git a/lib/views/home/settings/settings.dart b/lib/views/home/settings/settings.dart index eae023f..b205e5a 100644 --- a/lib/views/home/settings/settings.dart +++ b/lib/views/home/settings/settings.dart @@ -87,7 +87,7 @@ class Settings extends StatelessWidget { MenuItem( icon: DidvanIcons.didvan_solid, title: 'معرفی دیدوان', - onTap: () => launch('https://didvan.app/'), + onTap: () => launch('https://didvan.app/#info'), ), const DidvanDivider(), MenuItem( @@ -104,14 +104,15 @@ class Settings extends StatelessWidget { MenuItem( icon: DidvanIcons.alert_regular, title: 'حریم خصوصی', - onTap: () => launch('https://didvan.app/'), + onTap: () => + launch('https://didvan.app/termsOfUse.html#privacy'), ), ], ), ), const SizedBox(height: 16), DidvanText( - 'نسخه نرم‌افزار: 1.5.0', + 'نسخه نرم‌افزار: 2.0.0', style: Theme.of(context).textTheme.caption, ), ], From 257e4b6a594174a4ad04f41f7e3399e6b5d3f880 Mon Sep 17 00:00:00 2001 From: MohammadTaha Basiri Date: Wed, 20 Apr 2022 23:00:30 +0430 Subject: [PATCH 12/18] comments delete and report + bug fixes --- lib/services/network/request_helper.dart | 2 + lib/views/home/comments/comments.dart | 2 +- lib/views/home/comments/comments_state.dart | 40 +++++++++++++++ .../{comment_item.dart => comment.dart} | 50 ++++++++++++++++++- .../studio_details/studio_details.mobile.dart | 1 - 5 files changed, 92 insertions(+), 3 deletions(-) rename lib/views/home/comments/widgets/{comment_item.dart => comment.dart} (83%) diff --git a/lib/services/network/request_helper.dart b/lib/services/network/request_helper.dart index cbf4411..56ec7da 100644 --- a/lib/services/network/request_helper.dart +++ b/lib/services/network/request_helper.dart @@ -145,6 +145,8 @@ class RequestHelper { baseUrl + '/$type/$id/comments/$commentId/feedback'; static String addComment(int id, String type) => baseUrl + '/$type/$id/comments/add'; + static String deleteComment(int id) => baseUrl + '/comment/$id'; + static String reportComment(int id) => baseUrl + '/comment/$id/report'; static String _urlConcatGenerator(List> additions) { String result = ''; diff --git a/lib/views/home/comments/comments.dart b/lib/views/home/comments/comments.dart index 6e03d73..7803230 100644 --- a/lib/views/home/comments/comments.dart +++ b/lib/views/home/comments/comments.dart @@ -4,7 +4,7 @@ import 'package:didvan/constants/app_icons.dart'; import 'package:didvan/constants/assets.dart'; import 'package:didvan/models/view/app_bar_data.dart'; import 'package:didvan/views/home/comments/comments_state.dart'; -import 'package:didvan/views/home/comments/widgets/comment_item.dart'; +import 'package:didvan/views/home/comments/widgets/comment.dart'; import 'package:didvan/views/widgets/animated_visibility.dart'; import 'package:didvan/views/widgets/didvan/icon_button.dart'; import 'package:didvan/views/widgets/didvan/scaffold.dart'; diff --git a/lib/views/home/comments/comments_state.dart b/lib/views/home/comments/comments_state.dart index 4b02d00..c71b79e 100644 --- a/lib/views/home/comments/comments_state.dart +++ b/lib/views/home/comments/comments_state.dart @@ -4,10 +4,12 @@ import 'package:didvan/models/comment/feedback.dart'; import 'package:didvan/models/comment/reply.dart'; import 'package:didvan/models/comment/user.dart'; import 'package:didvan/models/enums.dart'; +import 'package:didvan/models/view/alert_data.dart'; import 'package:didvan/providers/core.dart'; import 'package:didvan/providers/user.dart'; import 'package:didvan/services/network/request.dart'; import 'package:didvan/services/network/request_helper.dart'; +import 'package:didvan/utils/action_sheet.dart'; import 'package:provider/provider.dart'; class CommentsState extends CoreProvier { @@ -158,4 +160,42 @@ class CommentsState extends CoreProvier { replyingTo = null; } } + + void reportComment(int id) { + final service = RequestService(RequestHelper.reportComment(id)); + service.post(); + ActionSheetUtils.showAlert( + AlertData( + message: 'گزارش شما با موفقیت ثبت شد و به زودی بررسی میگردد.', + aLertType: ALertType.success, + ), + ); + } + + void deleteComment(int id, int? rootId) { + final service = RequestService(RequestHelper.deleteComment(id)); + service.delete(); + if (rootId == null) { + final comment = comments.firstWhere((element) => element.id == id); + if (comment.replies.isNotEmpty) { + comments.insertAll( + comments.indexOf(comment), + comment.replies.map( + (rep) => CommentData( + id: rep.id, + text: rep.text, + createdAt: rep.createdAt, + liked: rep.liked, + disliked: rep.disliked, + feedback: rep.feedback, + user: rep.user, + replies: [], + ), + ), + ); + } + comments.remove(comment); + } + notifyListeners(); + } } diff --git a/lib/views/home/comments/widgets/comment_item.dart b/lib/views/home/comments/widgets/comment.dart similarity index 83% rename from lib/views/home/comments/widgets/comment_item.dart rename to lib/views/home/comments/widgets/comment.dart index 4748031..cc50380 100644 --- a/lib/views/home/comments/widgets/comment_item.dart +++ b/lib/views/home/comments/widgets/comment.dart @@ -2,8 +2,13 @@ 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/comment/comment.dart'; +import 'package:didvan/models/comment/reply.dart'; +import 'package:didvan/models/view/action_sheet_data.dart'; +import 'package:didvan/providers/user.dart'; +import 'package:didvan/utils/action_sheet.dart'; import 'package:didvan/utils/date_time.dart'; import 'package:didvan/views/home/comments/comments_state.dart'; +import 'package:didvan/views/home/widgets/menu_item.dart'; import 'package:didvan/views/widgets/animated_visibility.dart'; import 'package:didvan/views/widgets/didvan/icon_button.dart'; import 'package:didvan/views/widgets/didvan/text.dart'; @@ -84,17 +89,24 @@ class CommentState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ DidvanText( comment.user.fullName, style: Theme.of(context).textTheme.bodyText1, ), + const Spacer(), DidvanText( DateTimeUtils.momentGenerator(comment.createdAt), style: Theme.of(context).textTheme.caption, color: Theme.of(context).colorScheme.caption, ), + const SizedBox(width: 4), + DidvanIconButton( + size: 18, + gestureSize: 24, + icon: DidvanIcons.menu_light, + onPressed: () => _showCommentActions(comment), + ), ], ), const SizedBox(height: 8), @@ -171,6 +183,42 @@ class CommentState extends State { ], ), ); + + Future _showCommentActions(comment) async { + ActionSheetUtils.showBottomSheet( + data: ActionSheetData( + title: 'گزینه‌های نظر', + content: Column( + children: [ + if (comment.user.id != context.read().user.id) + MenuItem( + title: 'گزارش محتوای نامناسب', + onTap: () { + state.reportComment(comment.id); + ActionSheetUtils.pop(); + }, + icon: DidvanIcons.alert_regular, + ), + if (comment.user.id == context.read().user.id) + MenuItem( + title: 'حذف نظر', + color: Theme.of(context).colorScheme.secondary, + onTap: () { + state.deleteComment( + comment.id, + comment.runtimeType == Reply ? _comment.id : null, + ); + ActionSheetUtils.pop(); + }, + icon: DidvanIcons.trash_solid, + ), + ], + ), + hasConfirmButton: false, + hasDismissButton: false, + ), + ); + } } class _FeedbackButtons extends StatefulWidget { diff --git a/lib/views/home/studio/studio_details/studio_details.mobile.dart b/lib/views/home/studio/studio_details/studio_details.mobile.dart index 2c34596..b42266c 100644 --- a/lib/views/home/studio/studio_details/studio_details.mobile.dart +++ b/lib/views/home/studio/studio_details/studio_details.mobile.dart @@ -88,7 +88,6 @@ class _StudioDetailsState extends State { ), ), body: SingleChildScrollView( - physics: const NeverScrollableScrollPhysics(), child: SizedBox( height: d.size.height - d.padding.top - 56, child: Column( From 6853af3d21ef93953e75989c237977d94d0e6e54 Mon Sep 17 00:00:00 2001 From: MohammadTaha Basiri Date: Thu, 21 Apr 2022 15:17:48 +0430 Subject: [PATCH 13/18] bug fixes --- lib/views/home/comments/comments_state.dart | 5 +++ lib/views/home/statistic/statistic.dart | 16 ++++++--- lib/views/home/statistic/statistic_state.dart | 33 ++++++------------- lib/views/widgets/didvan/app_bar.dart | 1 + lib/views/widgets/didvan/scaffold.dart | 10 ++++-- 5 files changed, 34 insertions(+), 31 deletions(-) diff --git a/lib/views/home/comments/comments_state.dart b/lib/views/home/comments/comments_state.dart index c71b79e..03e04bc 100644 --- a/lib/views/home/comments/comments_state.dart +++ b/lib/views/home/comments/comments_state.dart @@ -195,6 +195,11 @@ class CommentsState extends CoreProvier { ); } comments.remove(comment); + } else { + comments + .firstWhere((element) => element.id == rootId) + .replies + .removeWhere((element) => element.id == id); } notifyListeners(); } diff --git a/lib/views/home/statistic/statistic.dart b/lib/views/home/statistic/statistic.dart index 1651395..6496e79 100644 --- a/lib/views/home/statistic/statistic.dart +++ b/lib/views/home/statistic/statistic.dart @@ -11,6 +11,7 @@ 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/widgets/animated_visibility.dart'; +import 'package:didvan/views/widgets/didvan/divider.dart'; import 'package:didvan/views/widgets/didvan/text.dart'; import 'package:didvan/views/widgets/state_handlers/empty_list.dart'; import 'package:didvan/views/widgets/state_handlers/sliver_state_handler.dart'; @@ -61,7 +62,8 @@ class _StatisticState extends State { const SliverToBoxAdapter( child: SizedBox(height: 180), ), - if (state.appState != AppState.failed) + if (state.appState != AppState.failed && + state.markedStatistics.isNotEmpty) SliverPadding( padding: const EdgeInsets.only(right: 16, bottom: 20), sliver: SliverToBoxAdapter( @@ -80,7 +82,7 @@ class _StatisticState extends State { ), ), SliverStateHandler( - onRetry: () => state.getStatistic(page: state.page), + onRetry: state.getStatistic, state: state, itemPadding: const EdgeInsets.only( bottom: 20, @@ -91,12 +93,16 @@ class _StatisticState extends State { enableEmptyState: _itemCount(state) == 0, placeholder: StatisticOverview.placeHolder, builder: (context, state, index) { + if (index == state.markedStatistics.length) { + return const DidvanDivider(verticalPadding: 8); + } bool isMarked = false; StatisticData statistic; if (index < state.markedStatistics.length) { isMarked = true; statistic = state.markedStatistics[index]; } else { + index--; statistic = state.statistics[index - state.markedStatistics.length]; } @@ -106,7 +112,7 @@ class _StatisticState extends State { onMarkChanged: state.changeMark, ); }, - childCount: _itemCount(state), + childCount: _itemCount(state) + 1, ), SliverToBoxAdapter( child: SizedBox( @@ -136,7 +142,7 @@ class _StatisticState extends State { isColapsed: state.isColapsed, onSelected: (id) { state.selectedCategoryId = id; - state.getStatistic(page: 1); + state.getStatistic(); }, selectedCats: state.selectedCategory == null ? [] @@ -157,7 +163,7 @@ class _StatisticState extends State { if (category.id != 0) { state.selectedCategoryId = category.id; } - state.getStatistic(page: 1); + state.getStatistic(); } void _handleAnimations([bool forceAnimate = false]) async { diff --git a/lib/views/home/statistic/statistic_state.dart b/lib/views/home/statistic/statistic_state.dart index 19d7883..00f6c9f 100644 --- a/lib/views/home/statistic/statistic_state.dart +++ b/lib/views/home/statistic/statistic_state.dart @@ -9,7 +9,6 @@ import 'package:didvan/services/network/request.dart'; import 'package:didvan/services/network/request_helper.dart'; class StatisticState extends CoreProvier { - int page = 1; bool isScrolled = false; bool shouldColapse = false; int selectedCategoryId = -1; @@ -25,24 +24,10 @@ class StatisticState extends CoreProvier { bool get isCategorySelected => selectedCategoryId != 0; - void resetFilters(bool isInit) { - selectedCategoryId = 0; - isScrolled = false; - if (!isInit) { - getStatistic(page: 1); - } - } - - Future getStatistic({ - required int page, - }) async { - this.page = page; - if (this.page == page) { - statistics.clear(); - } - if (page == 1) { - appState = AppState.busy; - } + Future getStatistic() async { + statistics.clear(); + markedStatistics.clear(); + appState = AppState.busy; final RequestService service = RequestService( RequestHelper.statisticOverviews( selectedCategoryId == 0 || selectedCategoryId == 1 @@ -58,7 +43,7 @@ class StatisticState extends CoreProvier { } final marked = service.result['marked']; for (var i = 0; i < marked.length; i++) { - statistics.add(StatisticData.fromJson(marked[i])); + markedStatistics.add(StatisticData.fromJson(marked[i])); } if (isColapsed || isCategorySelected) { shouldColapse = true; @@ -66,7 +51,6 @@ class StatisticState extends CoreProvier { appState = AppState.idle; return; } - appState = AppState.failed; } @@ -85,9 +69,12 @@ class StatisticState extends CoreProvier { } void init() { - resetFilters(true); + selectedCategoryId = 0; + isScrolled = false; + markedStatistics.clear(); + statistics.clear(); Future.delayed(Duration.zero, () { - getStatistic(page: 1); + getStatistic(); }); categories = [ CategoryData( diff --git a/lib/views/widgets/didvan/app_bar.dart b/lib/views/widgets/didvan/app_bar.dart index 81770c8..ab7a949 100644 --- a/lib/views/widgets/didvan/app_bar.dart +++ b/lib/views/widgets/didvan/app_bar.dart @@ -29,6 +29,7 @@ class DidvanAppBar extends StatelessWidget { ), ) : null, + color: backgroundColor ?? Theme.of(context).colorScheme.background, ), child: Row( children: [ diff --git a/lib/views/widgets/didvan/scaffold.dart b/lib/views/widgets/didvan/scaffold.dart index 38f9dde..879e240 100644 --- a/lib/views/widgets/didvan/scaffold.dart +++ b/lib/views/widgets/didvan/scaffold.dart @@ -59,11 +59,15 @@ class _DidvanScaffoldState extends State { SliverAppBar( toolbarHeight: (widget.appBarData!.isSmall ? 56 : 72) - statusBarHeight, - backgroundColor: widget.backgroundColor ?? - Theme.of(context).colorScheme.background, automaticallyImplyLeading: false, pinned: true, - flexibleSpace: DidvanAppBar(appBarData: widget.appBarData!), + backgroundColor: widget.backgroundColor ?? + Theme.of(context).colorScheme.background, + flexibleSpace: DidvanAppBar( + appBarData: widget.appBarData!, + backgroundColor: widget.backgroundColor ?? + Theme.of(context).colorScheme.background, + ), ), if (widget.children != null && !widget.showSliversFirst) SliverPadding( From 744409d31e49e750274d9f6caba6d4d4ae721f3a Mon Sep 17 00:00:00 2001 From: MohammadTaha Basiri Date: Thu, 21 Apr 2022 15:28:47 +0430 Subject: [PATCH 14/18] bug fixes --- lib/views/home/radar/radar_state.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/views/home/radar/radar_state.dart b/lib/views/home/radar/radar_state.dart index a4c483f..2b57c88 100644 --- a/lib/views/home/radar/radar_state.dart +++ b/lib/views/home/radar/radar_state.dart @@ -46,11 +46,9 @@ class RadarState extends CoreProvier { required int page, }) async { this.page = page; - if (this.page == page) { - radars.clear(); - } lastSearch = search; if (page == 1) { + radars.clear(); appState = AppState.busy; } final RequestService service = RequestService( From fc73d5452ca7f5f988bb9e1296f14af169cdb83b Mon Sep 17 00:00:00 2001 From: MohammadTaha Basiri Date: Thu, 21 Apr 2022 15:29:32 +0430 Subject: [PATCH 15/18] pub version updated --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index adebac7..31924b7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.5.0+10 +version: 2.0.0+11 environment: sdk: ">=2.12.0 <3.0.0" From 1bd33a834d360e283d7cff6fdc3c39769814fc87 Mon Sep 17 00:00:00 2001 From: MohammadTaha Basiri Date: Fri, 22 Apr 2022 03:51:48 +0430 Subject: [PATCH 16/18] bug fixes --- .../home/statistic/statistic_details/statistic_details.dart | 4 ++-- lib/views/home/statistic/widgets/statistic_overview.dart | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/views/home/statistic/statistic_details/statistic_details.dart b/lib/views/home/statistic/statistic_details/statistic_details.dart index b8dd16f..ae78195 100644 --- a/lib/views/home/statistic/statistic_details/statistic_details.dart +++ b/lib/views/home/statistic/statistic_details/statistic_details.dart @@ -256,7 +256,7 @@ class _StatisticDetailsState extends State { if (state.data!.dp == 0) { return null; } - if (state.data!.dt == 'low') { + if (state.data!.dt == 'high') { return Theme.of(context).colorScheme.success; } else { return Theme.of(context).colorScheme.error; @@ -267,7 +267,7 @@ class _StatisticDetailsState extends State { if (state.data!.dp == 0) { return null; } - if (state.data!.dt == 'low') { + if (state.data!.dt == 'high') { return DidvanIcons.angle_up_regular; } else { return DidvanIcons.angle_down_regular; diff --git a/lib/views/home/statistic/widgets/statistic_overview.dart b/lib/views/home/statistic/widgets/statistic_overview.dart index cfa585e..acb392b 100644 --- a/lib/views/home/statistic/widgets/statistic_overview.dart +++ b/lib/views/home/statistic/widgets/statistic_overview.dart @@ -18,7 +18,7 @@ class StatisticOverview extends StatelessWidget { required this.onMarkChanged, }) : super(key: key); - Color _diffColor(context) => statistic.data.dt == 'low' + Color _diffColor(context) => statistic.data.dt == 'high' ? Theme.of(context).colorScheme.success : Theme.of(context).colorScheme.error; @@ -88,7 +88,7 @@ class StatisticOverview extends StatelessWidget { const Spacer(), if (_hasDiff) Icon( - statistic.data.dt == 'low' + statistic.data.dt == 'high' ? DidvanIcons.angle_up_regular : DidvanIcons.angle_down_regular, size: 18, From 77dd06264d6012c696772e294bdd26dec2c57175 Mon Sep 17 00:00:00 2001 From: MohammadTaha Basiri Date: Fri, 22 Apr 2022 15:26:03 +0430 Subject: [PATCH 17/18] bug fixes + package upgrades --- lib/utils/date_time.dart | 7 ++++ .../home/direct/widgets/audio_widget.dart | 30 +++++++------- lib/views/home/news/news.dart | 2 +- lib/views/home/radar/radar.dart | 2 +- .../home/settings/bookmarks/bookmarks.dart | 2 +- lib/views/home/studio/studio.dart | 2 +- pubspec.lock | 40 +++++++++++++------ 7 files changed, 53 insertions(+), 32 deletions(-) diff --git a/lib/utils/date_time.dart b/lib/utils/date_time.dart index 41be0c6..3e50c93 100644 --- a/lib/utils/date_time.dart +++ b/lib/utils/date_time.dart @@ -47,6 +47,13 @@ class DateTimeUtils { initialDate: initialJalali, firstDate: firstDate, lastDate: lastDate, + builder: (context, child) => Theme( + data: Theme.of(context).copyWith( + textTheme: Theme.of(context) + .textTheme + .copyWith(headline4: Theme.of(context).textTheme.headline3)), + child: child!, + ), ); return result?.toDateTime().toString(); diff --git a/lib/views/home/direct/widgets/audio_widget.dart b/lib/views/home/direct/widgets/audio_widget.dart index 7e55bd4..5f1c8bd 100644 --- a/lib/views/home/direct/widgets/audio_widget.dart +++ b/lib/views/home/direct/widgets/audio_widget.dart @@ -20,24 +20,24 @@ class AudioWidget extends StatelessWidget { @override Widget build(BuildContext context) { - return Row( - children: [ - Expanded( - child: AudioSlider( - tag: 'message-$id', - ), - ), - StreamBuilder( - stream: MediaService.audioPlayer.isPlaying, - builder: (context, snapshot) { - return _AudioControllerButton( + return StreamBuilder( + stream: MediaService.audioPlayer.isPlaying, + builder: (context, snapshot) { + return Row( + children: [ + Expanded( + child: AudioSlider( + tag: 'message-$id', + ), + ), + _AudioControllerButton( audioFile: audioFile, audioUrl: audioUrl, id: id, - ); - }, - ), - ], + ), + ], + ); + }, ); } } diff --git a/lib/views/home/news/news.dart b/lib/views/home/news/news.dart index bbfed23..afa9c9e 100644 --- a/lib/views/home/news/news.dart +++ b/lib/views/home/news/news.dart @@ -91,7 +91,7 @@ class _NewsState extends State { void _onChanged(String value) { final state = context.read(); - if (value.length < 4 && value.isNotEmpty || state.lastSearch == value) { + if (value.length < 3 && value.isNotEmpty || state.lastSearch == value) { return; } _timer?.cancel(); diff --git a/lib/views/home/radar/radar.dart b/lib/views/home/radar/radar.dart index 78ebc55..42f3b08 100644 --- a/lib/views/home/radar/radar.dart +++ b/lib/views/home/radar/radar.dart @@ -203,7 +203,7 @@ class _RadarState extends State { void _onChanged(String value) { final state = context.read(); - if (value.length < 4 && value.isNotEmpty || state.lastSearch == value) { + if (value.length < 3 && value.isNotEmpty || state.lastSearch == value) { return; } _timer?.cancel(); diff --git a/lib/views/home/settings/bookmarks/bookmarks.dart b/lib/views/home/settings/bookmarks/bookmarks.dart index 81ddeab..01ae4fe 100644 --- a/lib/views/home/settings/bookmarks/bookmarks.dart +++ b/lib/views/home/settings/bookmarks/bookmarks.dart @@ -144,7 +144,7 @@ class _BookmarksState extends State { void _onChanged(String value) { final state = context.read(); - if (value.length < 4 && value.isNotEmpty || state.lastSearch == value) { + if (value.length < 3 && value.isNotEmpty || state.lastSearch == value) { return; } _timer?.cancel(); diff --git a/lib/views/home/studio/studio.dart b/lib/views/home/studio/studio.dart index 296a552..f437719 100644 --- a/lib/views/home/studio/studio.dart +++ b/lib/views/home/studio/studio.dart @@ -165,7 +165,7 @@ class _StudioState extends State { void _onChanged(String value) { final state = context.read(); - if (value.length < 4 && value.isNotEmpty || state.lastSearch == value) { + if (value.length < 3 && value.isNotEmpty || state.lastSearch == value) { return; } _timer?.cancel(); diff --git a/pubspec.lock b/pubspec.lock index 737d1d4..3823c80 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -182,7 +182,7 @@ packages: name: firebase_core url: "https://pub.dartlang.org" source: hosted - version: "1.14.0" + version: "1.15.0" firebase_core_platform_interface: dependency: transitive description: @@ -196,28 +196,28 @@ packages: name: firebase_core_web url: "https://pub.dartlang.org" source: hosted - version: "1.6.1" + version: "1.6.2" firebase_messaging: dependency: "direct main" description: name: firebase_messaging url: "https://pub.dartlang.org" source: hosted - version: "11.2.12" + version: "11.2.14" firebase_messaging_platform_interface: dependency: transitive description: name: firebase_messaging_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "3.2.2" + version: "3.3.0" firebase_messaging_web: dependency: transitive description: name: firebase_messaging_web url: "https://pub.dartlang.org" source: hosted - version: "2.2.10" + version: "2.2.12" fl_chart: dependency: "direct main" description: @@ -236,7 +236,7 @@ packages: name: flutter_blurhash url: "https://pub.dartlang.org" source: hosted - version: "0.6.4" + version: "0.6.8" flutter_cache_manager: dependency: transitive description: @@ -250,7 +250,7 @@ packages: name: flutter_html url: "https://pub.dartlang.org" source: hosted - version: "3.0.0-alpha.2" + version: "3.0.0-alpha.3" flutter_lints: dependency: "direct dev" description: @@ -398,6 +398,13 @@ packages: name: image_picker url: "https://pub.dartlang.org" source: hosted + version: "0.8.5" + image_picker_android: + dependency: transitive + description: + name: image_picker_android + url: "https://pub.dartlang.org" + source: hosted version: "0.8.4+11" image_picker_for_web: dependency: transitive @@ -406,6 +413,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.6" + image_picker_ios: + dependency: transitive + description: + name: image_picker_ios + url: "https://pub.dartlang.org" + source: hosted + version: "0.8.4+11" image_picker_platform_interface: dependency: transitive description: @@ -615,7 +629,7 @@ packages: name: pin_code_fields url: "https://pub.dartlang.org" source: hosted - version: "7.3.0" + version: "7.4.0" platform: dependency: transitive description: @@ -704,14 +718,14 @@ packages: name: sqflite url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.0.2+1" sqflite_common: dependency: transitive description: name: sqflite_common url: "https://pub.dartlang.org" source: hosted - version: "2.2.1" + version: "2.2.1+1" stack_trace: dependency: transitive description: @@ -893,14 +907,14 @@ packages: name: webview_flutter url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.0.2" webview_flutter_android: dependency: transitive description: name: webview_flutter_android url: "https://pub.dartlang.org" source: hosted - version: "2.8.4" + version: "2.8.5" webview_flutter_platform_interface: dependency: transitive description: @@ -914,7 +928,7 @@ packages: name: webview_flutter_wkwebview url: "https://pub.dartlang.org" source: hosted - version: "2.7.1" + version: "2.7.2" win32: dependency: transitive description: From 0deddebbd10a4b987809102213ac93ab1f1695b4 Mon Sep 17 00:00:00 2001 From: MohammadTaha Basiri Date: Fri, 22 Apr 2022 18:23:44 +0430 Subject: [PATCH 18/18] signing configs --- .fandogh/fandogh.yaml | 2 +- android/app/build.gradle | 26 +++++++++++++++++++------- keystore.jks | Bin 0 -> 2243 bytes 3 files changed, 20 insertions(+), 8 deletions(-) create mode 100644 keystore.jks diff --git a/.fandogh/fandogh.yaml b/.fandogh/fandogh.yaml index f3f18c9..4d58d75 100644 --- a/.fandogh/fandogh.yaml +++ b/.fandogh/fandogh.yaml @@ -3,7 +3,7 @@ name: app-dev spec: allow_http: false disable_default_domains: true - image: app-dev:1.5.11 + image: app-dev:2.0.1.11 image_pull_policy: IfNotPresent path: / replicas: 1 diff --git a/android/app/build.gradle b/android/app/build.gradle index efe0f78..db1ece1 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -25,6 +25,12 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" +def keystoreProperties = new Properties() +def keystorePropertiesFile = rootProject.file('key.properties') +if (keystorePropertiesFile.exists()) { + keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) +} + android { compileSdkVersion 31 @@ -51,13 +57,19 @@ android { versionName flutterVersionName } - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } + signingConfigs { + release { + keyAlias keystoreProperties['keyAlias'] + keyPassword keystoreProperties['keyPassword'] + storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null + storePassword keystoreProperties['storePassword'] + } + } + buildTypes { + release { + signingConfig signingConfigs.release + } + } } flutter { diff --git a/keystore.jks b/keystore.jks new file mode 100644 index 0000000000000000000000000000000000000000..5b06703cccfdccfdbb3a0feecdb0032272e7e7d8 GIT binary patch literal 2243 zcmchYS5VW58pZQZLMV~YMNmMR1r$PrAWCs*Lcm0%h!Bd>ENmze2{=+hZwg{iT#*t$ zx&$$i5-=K2st5$>pooezg9<@NSZ3$mJ3Hh1eK-&2_w>z~Gv^a53Kl^i5O`a_KY|g1 z1B1@{Zrd1#1QrYg5(1E9C?AP{iD|*_Byj>I!X?h~ZUF&QtyILc8#4hf|+`5;UYrEBeML$K?twTuv&E z*Yd4S_m5+04V1@L;U?b-{U^fR4HR+$MD8HZ2WGyZHO$CwC63d<0t~o%af#f;9<(D) zMBzzR-@O;3E>ui*U5*$Zpf1}w@2cNQ%{TbGLmg4W{waLHyA5XPE~@?BMsiUwM4U41 zhM)@Bm-Z%SH*w(8bA2+UA~PGC@k>-QR-?%7Vn}8#L_AD;ZpdGP)cUoWcVCBgB@k}U z%IB<`!BV)((golr#Zy_XzzgbrDX$^8RP3o|0iAl6FTJeHM!B34({1+`wDt3azpoWH z&|T#X6|eC=$1CdVLN$Z`Sjk)t-boNOntc_Fk;g`=g;!dxLRWdxtDc|KMHHnW zlh?_HNf#799Z(Y{x>QTtDsmOw6We5wV92!LG@nkkQyCqWDGBUb={{z>5{c(v8`_Ra zm}R7vaJ!FOX9UrmuD&Dk9};b3&KQ9$RnB%jS~EKL^SupY`V)gGk`qd=!gH}%j}bwj zmk&$YYkvGyehBTeseWnl_E+BA=3sE#%>3FT*E1Z&C1t-u7P#aoax?TtkZhgqe4B-k z{xtfDZa-^)k>>2r^hXEpK4vw!XLq5?0xK!iS}&f!Ha9~%jhnt5T>Ai_$Hl=&iqNI~ zW|YxR_t;H>jaIDoImi2aEau|8hdJN+?g^*VbOk2A`GP7L!ax4k`TK{(UMjD(%6!c8 z5QzKTz&@Puaf?^nhhAe63FCrY{U2GW=o_Qh2m;+F}#=Yo!ven28){GxbJT705nzj zgLcUh)9wbb~cJ2c6oO1|Hoxn(4%&f3!Iu?^@< z9~JzH-gu)D?C|UMV&yzKd4#WlX&1;ygXZ9JJesPc(+Kn3oa!XI9HafU|NeoN(aA=C zhn6C0rO#WN$le5QP}yKFv_a##nm^q8d5r_at}4{D3sKf<}hDVXFX=T%ZMZ9;_; zJO3m{Ydq-C1NWTmqI5{gFiVwxJWJf!Oh%*Crx{~6&#bBZ_%=;S?l{>z`{Oj)e&lKU*%Vd_bcE3pHQQ3& zmK&Nk3fmxv9ZYIC5O5uQ?c4s7lY7CNW&unm`^12EPmnK}FZgE|g^00u)Z<-@Na#bKgai8hIA;s5{_0wDwSB)1n6;tYk!2s;z55Q4%9|0N>7 z5#is6*lz^>8-e_fAeH6CQ7EK73Z-{M-@riMOohV24XW ziskM{>lUw@TgAg=mnHVKQb;gfkSscTk*L>NZxZ@8>L|Cuu{EOH1>taa-v|67N$438 zTRq8sS*}rK@>$dYIo~;Bu!9<&o1QdJ=&57TO#~u64#n2t z=|!c{ESeL)q7O6ab?1#;_w+3OVeI&_hdzl5vih3U*WarPBkaPq(9Kb?kqla`-a_ke z8P-sCP}7P#k;hW8BUAic~==Z8t;-0o@6e%}J)@GWCabva6MA&3-KHx^`wl=-(l3cWOIC093A= zMWNn7SJ%;ejpx=P5FQ^Hfv0ElRYD}|U`E!$87i2liUb zmN|qSH;2Df7(WT98_xEt>6=LrTX^lbpxQPal}1ZE_)}(&nw&k+!pjW1FlLjr{-8h^ z?3Ch_%ZVhNwqh>NE~1-dE16U!u4n89)O|`rRIbVSBEOPp?A$TVF$dO% ze(ke-H6)8pH^InOXQ@yf_6A|DaZJ&5tW%CSN9kzh+fVs%p^87unZmN4!#eVs;