From f5d27ed056035f2e6bc8abf5525e041fa70e02f2 Mon Sep 17 00:00:00 2001 From: mso7nueh Date: Fri, 1 Aug 2025 10:53:28 +0300 Subject: [PATCH] feat(plans): hide for ios --- lib/core/const.dart | 1 + .../feed/presentation/pages/feed_screen.dart | 182 +++--- .../feed/presentation/widgets/chip_group.dart | 9 +- .../presentation/pages/profile_screen.dart | 547 ++++-------------- 4 files changed, 184 insertions(+), 555 deletions(-) diff --git a/lib/core/const.dart b/lib/core/const.dart index 618a9866..f22f79aa 100644 --- a/lib/core/const.dart +++ b/lib/core/const.dart @@ -1,4 +1,5 @@ String baseUrl = 'https://eatvio.ru'; +bool hidePlans = true; const List durationValues = [7, 14, 21]; diff --git a/lib/features/feed/presentation/pages/feed_screen.dart b/lib/features/feed/presentation/pages/feed_screen.dart index b6869040..ce29b884 100644 --- a/lib/features/feed/presentation/pages/feed_screen.dart +++ b/lib/features/feed/presentation/pages/feed_screen.dart @@ -1,4 +1,5 @@ import 'package:easy_debounce/easy_debounce.dart'; +import 'package:eatvio_app/core/const.dart'; import 'package:eatvio_app/core/widgets/add_item_button.dart'; import 'package:eatvio_app/core/widgets/custom_search_bar.dart'; import 'package:eatvio_app/features/create_diet/presentation/create_diet_screen.dart'; @@ -32,24 +33,12 @@ class FeedScreen extends StatelessWidget { Widget build(BuildContext context) { return MultiBlocProvider( providers: [ - BlocProvider( - create: (context) => sl()..loadRecipesList(), - ), - BlocProvider( - create: (context) => sl()..getProfile(), - ), - BlocProvider( - create: (context) => sl()..loadFeedBlogPostList(), - ), - BlocProvider( - create: (context) => sl()..loadDiets(), - ), - BlocProvider( - create: (context) => sl()..loadPlans(), - ), - BlocProvider( - create: (context) => sl()..getConsultants(), - ), + BlocProvider(create: (context) => sl()..loadRecipesList()), + BlocProvider(create: (context) => sl()..getProfile()), + BlocProvider(create: (context) => sl()..loadFeedBlogPostList()), + BlocProvider(create: (context) => sl()..loadDiets()), + if (!hidePlans) BlocProvider(create: (context) => sl()..loadPlans()), + BlocProvider(create: (context) => sl()..getConsultants()), ], child: const FeedScreenContent(), ); @@ -69,7 +58,8 @@ class _FeedScreenContentState extends State { final dietsController = TextEditingController(); final plansController = TextEditingController(); final consultantsController = TextEditingController(); - final List chipsLabelList = ['Все', 'Рецепты', 'Диеты', 'Планы питания', 'Консультанты']; + + late final List chipsLabelList; int _selectedChipIndex = 0; final blogPostsScrollController = ScrollController(); final recipesScrollController = ScrollController(); @@ -78,12 +68,13 @@ class _FeedScreenContentState extends State { final consultantsScrollController = ScrollController(); @override - void initState() { + void initState() { + // Initialize chipsLabelList based on hidePlans setting + chipsLabelList = hidePlans ? ['Все', 'Рецепты', 'Диеты', 'Консультанты'] : ['Все', 'Рецепты', 'Диеты', 'Планы питания', 'Консультанты']; + consultantsScrollController.addListener(_onScrollConsultants); super.initState(); - } - - + } void _onScrollConsultants() { if (consultantsScrollController.offset >= consultantsScrollController.position.maxScrollExtent && !consultantsScrollController.position.outOfRange) {} @@ -108,45 +99,36 @@ class _FeedScreenContentState extends State { heroTag: 'recipesTagsFilter', backgroundColor: appTheme.blueA400, shape: const CircleBorder(), - child: const Icon( - Icons.filter_list_rounded, - color: Colors.white, - ), + child: const Icon(Icons.filter_list_rounded, color: Colors.white), onPressed: () async { final recipesCubit = context.read(); await showModalBottomSheet( useRootNavigator: true, context: context, - builder: (context) => TagsModalWidget( - recipesCubit: recipesCubit, - ), + builder: (context) => TagsModalWidget(recipesCubit: recipesCubit), ); recipesCubit.loadRecipesList(); }, ) : null, - appBar: AppBar( - backgroundColor: Colors.white, - toolbarHeight: 0, - ), + appBar: AppBar(backgroundColor: Colors.white, toolbarHeight: 0), backgroundColor: Colors.grey.shade200, body: NestedScrollView( controller: switch (_selectedChipIndex) { 0 => blogPostsScrollController, 1 => recipesScrollController, 2 => dietsScrollController, - 3 => plansScrollController, - 4 => consultantsScrollController, - _ => blogPostsScrollController + 3 when !hidePlans => plansScrollController, + 3 when hidePlans => consultantsScrollController, + 4 when !hidePlans => consultantsScrollController, + _ => blogPostsScrollController, }, headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { return [ BlocBuilder( builder: (context, state) { return SliverAppBar( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.vertical(bottom: Radius.circular(12)), - ), + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.vertical(bottom: Radius.circular(12))), backgroundColor: Colors.white, foregroundColor: Colors.white, automaticallyImplyLeading: false, @@ -172,78 +154,71 @@ class _FeedScreenContentState extends State { searchController: switch (_selectedChipIndex) { 1 => recipesController, 2 => dietsController, - 3 => plansController, - 4 => consultantsController, + 3 when !hidePlans => plansController, + 3 when hidePlans => consultantsController, + 4 when !hidePlans => consultantsController, _ => postsController, }, onChanged: (query) { if (query.length > 2) { - EasyDebounce.debounce( - 'searchFeed', - const Duration(milliseconds: 500), - () { - switch (_selectedChipIndex) { - case 0: - context.read().loadFeedBlogPostList(query: query); - break; - case 1: - context.read().loadRecipesList(query: query); - break; - case 2: - context.read().loadDiets(query: query); - break; - case 3: - context.read().loadPlans(query: query); - break; - case 4: - context.read().getConsultants(); - break; - } - }, - ); + EasyDebounce.debounce('searchFeed', const Duration(milliseconds: 500), () { + switch (_selectedChipIndex) { + case 0: + context.read().loadFeedBlogPostList(query: query); + break; + case 1: + context.read().loadRecipesList(query: query); + break; + case 2: + context.read().loadDiets(query: query); + break; + case 3 when !hidePlans: + context.read().loadPlans(query: query); + break; + case 3 when hidePlans: + case 4 when !hidePlans: + context.read().getConsultants(); + break; + } + }); } else { - EasyDebounce.debounce( - 'searchFeed', - const Duration(milliseconds: 500), - () { - switch (_selectedChipIndex) { - case 0: - context.read().loadFeedBlogPostList(); - break; - case 1: - context.read().loadRecipesList(); - break; - case 2: - context.read().loadDiets(); - break; - case 3: - context.read().loadPlans(); - break; - case 4: - context.read().getConsultants(); - break; - } - }, - ); + EasyDebounce.debounce('searchFeed', const Duration(milliseconds: 500), () { + switch (_selectedChipIndex) { + case 0: + context.read().loadFeedBlogPostList(); + break; + case 1: + context.read().loadRecipesList(); + break; + case 2: + context.read().loadDiets(); + break; + case 3 when !hidePlans: + context.read().loadPlans(); + break; + case 3 when hidePlans: + case 4 when !hidePlans: + context.read().getConsultants(); + break; + } + }); } }, ), const SizedBox(width: 12), switch (_selectedChipIndex) { - 1 => AddItemButton( - onTap: () => GoRouter.of(context).pushNamed(RecipeCreateScreen.name), - ), + 1 => AddItemButton(onTap: () => GoRouter.of(context).pushNamed(RecipeCreateScreen.name)), 2 => AddItemButton( - onTap: state.profile?.roles.contains('consultant') ?? false - ? () async { - await GoRouter.of(context).pushNamed(CreateDietScreen.name); - } - : null, - ), - 3 => AddItemButton( - onTap: state.profile?.roles.contains('consultant') ?? false ? () => GoRouter.of(context).pushNamed(CreatePlanScreen.name) : null, - ), - _ => const AddItemButton() + onTap: state.profile?.roles.contains('consultant') ?? false + ? () async { + await GoRouter.of(context).pushNamed(CreateDietScreen.name); + } + : null, + ), + 3 when !hidePlans => AddItemButton( + onTap: state.profile?.roles.contains('consultant') ?? false ? () => GoRouter.of(context).pushNamed(CreatePlanScreen.name) : null, + ), + _ => const AddItemButton(), }, ], ), @@ -256,8 +231,9 @@ class _FeedScreenContentState extends State { 0 => const BlogPosts(), 1 => const Recipes(), 2 => const Diets(), - 3 => const Plans(), - 4 => const Consultants(), + 3 when !hidePlans => const Plans(), + 3 when hidePlans => const Consultants(), + 4 when !hidePlans => const Consultants(), _ => Center(child: Text(chipsLabelList[_selectedChipIndex])), }, ), diff --git a/lib/features/feed/presentation/widgets/chip_group.dart b/lib/features/feed/presentation/widgets/chip_group.dart index a8d88da1..183a5a76 100644 --- a/lib/features/feed/presentation/widgets/chip_group.dart +++ b/lib/features/feed/presentation/widgets/chip_group.dart @@ -2,12 +2,7 @@ import 'package:eatvio_app/features/feed/presentation/widgets/choice_chip_widget import 'package:flutter/widgets.dart'; class ChipGroup extends StatelessWidget { - const ChipGroup({ - super.key, - required this.selectedChipIndex, - required this.chipsLabelList, - required this.setSelectedChipIndex, - }); + const ChipGroup({super.key, required this.selectedChipIndex, required this.chipsLabelList, required this.setSelectedChipIndex}); final int selectedChipIndex; final List chipsLabelList; final void Function(int) setSelectedChipIndex; @@ -22,7 +17,7 @@ class ChipGroup extends StatelessWidget { child: Row( children: [ ...List.generate( - 5, + chipsLabelList.length, (index) => Padding( padding: const EdgeInsets.only(right: 8.0), child: ChoiceChipWidget( diff --git a/lib/features/profile/presentation/pages/profile_screen.dart b/lib/features/profile/presentation/pages/profile_screen.dart index 68213da5..211543a9 100644 --- a/lib/features/profile/presentation/pages/profile_screen.dart +++ b/lib/features/profile/presentation/pages/profile_screen.dart @@ -45,10 +45,7 @@ import 'package:url_launcher/url_launcher.dart'; class ProfileScreen extends StatefulWidget { final Author? author; - const ProfileScreen({ - super.key, - this.author, - }); + const ProfileScreen({super.key, this.author}); @override State createState() => _ProfileScreenState(); @@ -91,7 +88,7 @@ class _ProfileScreenState extends State { } if (isFirstFetch) { canSub = !state.profile.isEntitySubscribedByMe; - if (state.profile.roles.contains('consultant')) { + if (state.profile.roles.contains('consultant') && !hidePlans) { plansCubit.getPlans(state.profile.slug); } isFirstFetch = false; @@ -109,10 +106,7 @@ class _ProfileScreenState extends State { ), ); } else { - return Scaffold( - appBar: AppBar(), - body: const Loader(), - ); + return Scaffold(appBar: AppBar(), body: const Loader()); } }, ), @@ -130,9 +124,7 @@ class _ProfileScreenState extends State { Container( decoration: const BoxDecoration( color: Colors.white, - borderRadius: BorderRadius.vertical( - bottom: Radius.circular(16), - ), + borderRadius: BorderRadius.vertical(bottom: Radius.circular(16)), ), child: Column( crossAxisAlignment: CrossAxisAlignment.center, @@ -147,28 +139,15 @@ class _ProfileScreenState extends State { const SizedBox(width: 16), const Text( 'Консультант', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: Color( - 0xFF323F4B, - ), - ), + style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Color(0xFF323F4B)), ), const SizedBox(width: 12), Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), - decoration: BoxDecoration( - color: const Color(0xFFF6FAFF), - borderRadius: BorderRadius.circular(12), - ), + decoration: BoxDecoration(color: const Color(0xFFF6FAFF), borderRadius: BorderRadius.circular(12)), child: Text( '${state.consultantInfo!.ratingPlace}-й в рейтинге', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: appTheme.blueA400, - ), + style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: appTheme.blueA400), ), ), ], @@ -177,17 +156,10 @@ class _ProfileScreenState extends State { const Row( children: [ SizedBox(width: 16), - Icon( - Icons.done_rounded, - color: Colors.green, - ), + Icon(Icons.done_rounded, color: Colors.green), Text( 'Медицинское образование', - style: TextStyle( - color: Color(0xFF323F4B), - fontSize: 14, - fontWeight: FontWeight.w600, - ), + style: TextStyle(color: Color(0xFF323F4B), fontSize: 14, fontWeight: FontWeight.w600), ), ], ), @@ -205,7 +177,7 @@ class _ProfileScreenState extends State { if (state.profile.roles.contains('consultant') && state.consultantInfo != null) _socialLinks(state), if (state.profile.roles.contains('consultant') && state.consultantInfo != null) _education(state), if (state.profile.roles.contains('consultant') && state.consultantInfo != null) _diplomasAndCertificates(state), - if (state.profile.roles.contains('consultant') && state.consultantInfo != null) _activePlans(state), + if (state.profile.roles.contains('consultant') && state.consultantInfo != null && !hidePlans) _activePlans(state), _blogPosts(state), ], ), @@ -216,9 +188,7 @@ class _ProfileScreenState extends State { Scaffold _myProfileScreen(ProfileStateLoaded state) { return Scaffold( backgroundColor: Colors.grey.shade200, - appBar: AppBar( - toolbarHeight: widget.author == null ? 0 : null, - ), + appBar: AppBar(toolbarHeight: widget.author == null ? 0 : null), body: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -226,9 +196,7 @@ class _ProfileScreenState extends State { Container( decoration: const BoxDecoration( color: Colors.white, - borderRadius: BorderRadius.vertical( - bottom: Radius.circular(16), - ), + borderRadius: BorderRadius.vertical(bottom: Radius.circular(16)), ), child: Column( crossAxisAlignment: CrossAxisAlignment.center, @@ -243,28 +211,15 @@ class _ProfileScreenState extends State { const SizedBox(width: 16), const Text( 'Консультант', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: Color( - 0xFF323F4B, - ), - ), + style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Color(0xFF323F4B)), ), const SizedBox(width: 12), Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), - decoration: BoxDecoration( - color: const Color(0xFFF6FAFF), - borderRadius: BorderRadius.circular(12), - ), + decoration: BoxDecoration(color: const Color(0xFFF6FAFF), borderRadius: BorderRadius.circular(12)), child: Text( '${state.consultantInfo!.ratingPlace}-й в рейтинге', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: appTheme.blueA400, - ), + style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: appTheme.blueA400), ), ), ], @@ -273,17 +228,10 @@ class _ProfileScreenState extends State { const Row( children: [ SizedBox(width: 16), - Icon( - Icons.done_rounded, - color: Colors.green, - ), + Icon(Icons.done_rounded, color: Colors.green), Text( 'Медицинское образование', - style: TextStyle( - color: Color(0xFF323F4B), - fontSize: 14, - fontWeight: FontWeight.w600, - ), + style: TextStyle(color: Color(0xFF323F4B), fontSize: 14, fontWeight: FontWeight.w600), ), ], ), @@ -299,7 +247,7 @@ class _ProfileScreenState extends State { if (state.profile.roles.contains('consultant')) _education(state), if (state.profile.roles.contains('consultant')) _diplomasAndCertificates(state), Padding(padding: const EdgeInsets.only(bottom: 16), child: _charts()), - if (state.profile.roles.contains('consultant')) _activePlans(state), + if (state.profile.roles.contains('consultant') && !hidePlans) _activePlans(state), _newBlogPostButton(), _blogPosts(state), ], @@ -309,7 +257,7 @@ class _ProfileScreenState extends State { } Widget _activePlans(ProfileStateLoaded state) { - if (!state.profile.roles.contains('consultant')) { + if (!state.profile.roles.contains('consultant') || hidePlans) { return const SizedBox.shrink(); } return BlocBuilder( @@ -328,12 +276,7 @@ class _ProfileScreenState extends State { children: [ Text( 'Активные планы', - style: TextStyle( - color: Color(0xFF323F4B), - fontSize: 24, - height: 1, - fontWeight: FontWeight.w600, - ), + style: TextStyle(color: Color(0xFF323F4B), fontSize: 24, height: 1, fontWeight: FontWeight.w600), ), ], ), @@ -343,10 +286,7 @@ class _ProfileScreenState extends State { height: 781, child: PageView.builder( itemBuilder: (BuildContext context, int index) { - return PlanWidget( - plan: state.plansList[index], - index: index, - ); + return PlanWidget(plan: state.plansList[index], index: index); }, onPageChanged: (bullet) { setState(() { @@ -370,17 +310,11 @@ class _ProfileScreenState extends State { Container _bullets(int currentBullet, int bulletCount) { return Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(20), - ), + decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(20)), child: Row( mainAxisSize: MainAxisSize.min, children: [ - for (int i = 0; i < bulletCount; i++) ...[ - _bullet(i == currentBullet), - i < bulletCount - 1 ? const SizedBox(width: 4) : const SizedBox.shrink(), - ], + for (int i = 0; i < bulletCount; i++) ...[_bullet(i == currentBullet), i < bulletCount - 1 ? const SizedBox(width: 4) : const SizedBox.shrink()], ], ), ); @@ -391,10 +325,7 @@ class _ProfileScreenState extends State { width: isActive ? 10 : 8, height: isActive ? 10 : 8, duration: const Duration(milliseconds: 150), - decoration: BoxDecoration( - color: isActive ? appTheme.blueA400 : const Color(0xFFD7D9DC), - shape: BoxShape.circle, - ), + decoration: BoxDecoration(color: isActive ? appTheme.blueA400 : const Color(0xFFD7D9DC), shape: BoxShape.circle), ); } @@ -411,25 +342,15 @@ class _ProfileScreenState extends State { borderRadius: BorderRadius.circular(8), child: Ink( padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: const Color(0xFFF6FAFF), - borderRadius: BorderRadius.circular(8), - ), + decoration: BoxDecoration(color: const Color(0xFFF6FAFF), borderRadius: BorderRadius.circular(8)), child: const Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon( - Icons.add_circle_outline_rounded, - color: Color(0xFF2F80ED), - ), + Icon(Icons.add_circle_outline_rounded, color: Color(0xFF2F80ED)), SizedBox(width: 12), Text( 'Новая запись', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, - color: Color(0xFF2F80ED), - ), + style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600, color: Color(0xFF2F80ED)), ), ], ), @@ -454,12 +375,7 @@ class _ProfileScreenState extends State { children: [ const Text( 'Дипломы\nи сертификаты', - style: TextStyle( - color: Color(0xFF323F4B), - fontSize: 24, - height: 1, - fontWeight: FontWeight.w600, - ), + style: TextStyle(color: Color(0xFF323F4B), fontSize: 24, height: 1, fontWeight: FontWeight.w600), ), GestureDetector( onTap: () { @@ -467,11 +383,7 @@ class _ProfileScreenState extends State { }, child: Text( widget.author == null || widget.author!.authorIsMe ? 'Редактировать' : '', - style: const TextStyle( - color: Color(0xFF2F80ED), - fontSize: 16, - fontWeight: FontWeight.w500, - ), + style: const TextStyle(color: Color(0xFF2F80ED), fontSize: 16, fontWeight: FontWeight.w500), ), ), ], @@ -491,17 +403,14 @@ class _ProfileScreenState extends State { child: Row( children: [ if (state.consultantInfo!.photos.isNotEmpty) - ...List.generate( - state.consultantInfo!.photos.length * 2 - 1, - (index) { - if (index.isEven) { - final photo = state.consultantInfo!.photos[index ~/ 2]; - return _diplomaImage(photo.url); - } else { - return const SizedBox(width: 8); - } - }, - ), + ...List.generate(state.consultantInfo!.photos.length * 2 - 1, (index) { + if (index.isEven) { + final photo = state.consultantInfo!.photos[index ~/ 2]; + return _diplomaImage(photo.url); + } else { + return const SizedBox(width: 8); + } + }), ], ), ), @@ -515,24 +424,13 @@ class _ProfileScreenState extends State { GestureDetector _diplomaImage(String url) { return GestureDetector( onTap: () { - context.pushTransparentRoute( - rootNavigator: true, - PhotoViewScreen( - imageUrls: [url], - index: 0, - ), - ); + context.pushTransparentRoute(rootNavigator: true, PhotoViewScreen(imageUrls: [url], index: 0)); }, child: Hero( tag: url, child: ClipRRect( borderRadius: BorderRadius.circular(8), - child: CachedNetworkImage( - imageUrl: url, - fit: BoxFit.fitHeight, - width: MediaQuery.of(context).size.width / 3 - (60 / 3), - height: 160, - ), + child: CachedNetworkImage(imageUrl: url, fit: BoxFit.fitHeight, width: MediaQuery.of(context).size.width / 3 - (60 / 3), height: 160), ), ), ); @@ -555,11 +453,7 @@ class _ProfileScreenState extends State { children: [ const Text( 'Образование', - style: TextStyle( - color: Color(0xFF323F4B), - fontSize: 24, - fontWeight: FontWeight.w600, - ), + style: TextStyle(color: Color(0xFF323F4B), fontSize: 24, fontWeight: FontWeight.w600), ), GestureDetector( onTap: () { @@ -567,11 +461,7 @@ class _ProfileScreenState extends State { }, child: Text( widget.author == null || widget.author!.authorIsMe ? 'Редактировать' : '', - style: const TextStyle( - color: Color(0xFF2F80ED), - fontSize: 16, - fontWeight: FontWeight.w500, - ), + style: const TextStyle(color: Color(0xFF2F80ED), fontSize: 16, fontWeight: FontWeight.w500), ), ), ], @@ -590,8 +480,10 @@ class _ProfileScreenState extends State { ListView.separated( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - itemBuilder: (context, index) => _educationBlock(state.consultantInfo!.educationModel.completedCourses![index].values.first.title, - state.consultantInfo!.educationModel.completedCourses![index].values.first.date), + itemBuilder: (context, index) => _educationBlock( + state.consultantInfo!.educationModel.completedCourses![index].values.first.title, + state.consultantInfo!.educationModel.completedCourses![index].values.first.date, + ), separatorBuilder: (context, index) => const SizedBox(height: 8), itemCount: state.consultantInfo!.educationModel.completedCourses!.length, ), @@ -621,22 +513,12 @@ class _ProfileScreenState extends State { children: [ Text( title, - style: const TextStyle( - height: 1, - color: Color(0xFF323F4B), - fontWeight: FontWeight.w500, - fontSize: 16, - ), + style: const TextStyle(height: 1, color: Color(0xFF323F4B), fontWeight: FontWeight.w500, fontSize: 16), ), const SizedBox(height: 4), Text( formattedDate, - style: const TextStyle( - height: 1, - color: Color(0xFF6D6F71), - fontWeight: FontWeight.w500, - fontSize: 14, - ), + style: const TextStyle(height: 1, color: Color(0xFF6D6F71), fontWeight: FontWeight.w500, fontSize: 14), ), ], ), @@ -660,12 +542,7 @@ class _ProfileScreenState extends State { children: [ _socialLinkButton( () { - launchUrl( - Uri.parse( - state.consultantInfo!.educationModel.vkLink ?? '', - ), - mode: LaunchMode.externalApplication, - ); + launchUrl(Uri.parse(state.consultantInfo!.educationModel.vkLink ?? ''), mode: LaunchMode.externalApplication); }, 'assets/icons/vk.svg', state.consultantInfo!.educationModel.vkLink!.isEmpty ? true : false, @@ -673,12 +550,7 @@ class _ProfileScreenState extends State { const SizedBox(width: 12), _socialLinkButton( () { - launchUrl( - Uri.parse( - state.consultantInfo!.educationModel.tgLink ?? '', - ), - mode: LaunchMode.externalApplication, - ); + launchUrl(Uri.parse(state.consultantInfo!.educationModel.tgLink ?? ''), mode: LaunchMode.externalApplication); }, 'assets/icons/telegram.svg', state.consultantInfo!.educationModel.tgLink!.isEmpty ? true : false, @@ -686,12 +558,7 @@ class _ProfileScreenState extends State { const SizedBox(width: 12), _socialLinkButton( () { - launchUrl( - Uri.parse( - state.consultantInfo!.educationModel.personalSiteLink ?? '', - ), - mode: LaunchMode.externalApplication, - ); + launchUrl(Uri.parse(state.consultantInfo!.educationModel.personalSiteLink ?? ''), mode: LaunchMode.externalApplication); }, 'assets/icons/web.svg', state.consultantInfo!.educationModel.personalSiteLink!.isEmpty ? true : false, @@ -709,10 +576,7 @@ class _ProfileScreenState extends State { borderRadius: BorderRadius.circular(20), child: Ink( width: MediaQuery.of(context).size.width / 3 - (56 / 3), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - color: const Color(0xFFF6F6F6), - ), + decoration: BoxDecoration(borderRadius: BorderRadius.circular(20), color: const Color(0xFFF6F6F6)), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 16), child: SvgPicture.asset( @@ -734,20 +598,13 @@ class _ProfileScreenState extends State { child: Ink( padding: const EdgeInsets.all(8), width: MediaQuery.of(context).size.width, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(12), - color: Colors.white, - ), + decoration: BoxDecoration(borderRadius: BorderRadius.circular(12), color: Colors.white), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Достижения', - style: TextStyle( - color: Color(0xFF6D6F71), - fontSize: 14, - fontWeight: FontWeight.w600, - ), + style: TextStyle(color: Color(0xFF6D6F71), fontSize: 14, fontWeight: FontWeight.w600), ), const SizedBox(height: 8), SingleChildScrollView( @@ -759,51 +616,25 @@ class _ProfileScreenState extends State { ? Tooltip( message: state.profile.badges[i].description, triggerMode: TooltipTriggerMode.tap, - textStyle: const TextStyle( - color: Colors.black, - fontSize: 16, - fontWeight: FontWeight.w500, - ), + textStyle: const TextStyle(color: Colors.black, fontSize: 16, fontWeight: FontWeight.w500), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(4), - boxShadow: [ - BoxShadow( - color: Colors.black.withAlpha((255 * 0.2).toInt()), - blurRadius: 32, - ) - ], - ), - child: SvgPicture.network( - '$baseUrl/storage/${state.profile.badges[i].image}', - width: 40, - height: 40, + boxShadow: [BoxShadow(color: Colors.black.withAlpha((255 * 0.2).toInt()), blurRadius: 32)], ), + child: SvgPicture.network('$baseUrl/storage/${state.profile.badges[i].image}', width: 40, height: 40), ) : Tooltip( message: state.profile.badges[i].description, margin: const EdgeInsets.symmetric(horizontal: 32), triggerMode: TooltipTriggerMode.tap, - textStyle: const TextStyle( - color: Colors.black, - fontSize: 16, - fontWeight: FontWeight.w500, - ), + textStyle: const TextStyle(color: Colors.black, fontSize: 16, fontWeight: FontWeight.w500), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(4), - boxShadow: [ - BoxShadow( - color: Colors.black.withAlpha((255 * 0.2).toInt()), - blurRadius: 32, - ) - ], - ), - child: CachedNetworkImage( - imageUrl: '$baseUrl/storage/${state.profile.badges[i].image}', - width: 40, - height: 40, + boxShadow: [BoxShadow(color: Colors.black.withAlpha((255 * 0.2).toInt()), blurRadius: 32)], ), + child: CachedNetworkImage(imageUrl: '$baseUrl/storage/${state.profile.badges[i].image}', width: 40, height: 40), ), i < state.profile.badges.length - 1 ? const SizedBox(width: 8) : const SizedBox.shrink(), ], @@ -823,21 +654,12 @@ class _ProfileScreenState extends State { child: Row( children: [ InkWell( - onTap: () => GoRouter.of(context).pushNamed( - 'subsScreen', - extra: SubType.subscriptions, - pathParameters: { - 'slug': state.profile.slug, - }, - ), + onTap: () => GoRouter.of(context).pushNamed('subsScreen', extra: SubType.subscriptions, pathParameters: {'slug': state.profile.slug}), borderRadius: BorderRadius.circular(12), child: Ink( padding: const EdgeInsets.all(8), width: MediaQuery.of(context).size.width / 2 - 6, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(12), - color: Colors.white, - ), + decoration: BoxDecoration(borderRadius: BorderRadius.circular(12), color: Colors.white), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.end, @@ -847,47 +669,27 @@ class _ProfileScreenState extends State { children: [ const Text( 'Подписки', - style: TextStyle( - color: Color(0xFF6D6F71), - fontSize: 14, - fontWeight: FontWeight.w600, - ), + style: TextStyle(color: Color(0xFF6D6F71), fontSize: 14, fontWeight: FontWeight.w600), ), Text( '${state.profile.subscriptions.length}', - style: const TextStyle( - color: Color(0xFF323F4B), - fontSize: 22, - fontWeight: FontWeight.w700, - ), + style: const TextStyle(color: Color(0xFF323F4B), fontSize: 22, fontWeight: FontWeight.w700), ), ], ), - Padding( - padding: const EdgeInsets.only(right: 8), - child: _miniAvatars(state.profile.subscriptions), - ), + Padding(padding: const EdgeInsets.only(right: 8), child: _miniAvatars(state.profile.subscriptions)), ], ), ), ), const SizedBox(width: 4), InkWell( - onTap: () => GoRouter.of(context).pushNamed( - 'subsScreen', - extra: SubType.subscribers, - pathParameters: { - 'slug': state.profile.slug, - }, - ), + onTap: () => GoRouter.of(context).pushNamed('subsScreen', extra: SubType.subscribers, pathParameters: {'slug': state.profile.slug}), borderRadius: BorderRadius.circular(12), child: Ink( padding: const EdgeInsets.all(8), width: MediaQuery.of(context).size.width / 2 - 6, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(12), - color: Colors.white, - ), + decoration: BoxDecoration(borderRadius: BorderRadius.circular(12), color: Colors.white), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.end, @@ -897,26 +699,15 @@ class _ProfileScreenState extends State { children: [ const Text( 'Подписчики', - style: TextStyle( - color: Color(0xFF6D6F71), - fontSize: 14, - fontWeight: FontWeight.w600, - ), + style: TextStyle(color: Color(0xFF6D6F71), fontSize: 14, fontWeight: FontWeight.w600), ), Text( '${state.profile.subscribers.length}', - style: const TextStyle( - color: Color(0xFF323F4B), - fontSize: 22, - fontWeight: FontWeight.w700, - ), + style: const TextStyle(color: Color(0xFF323F4B), fontSize: 22, fontWeight: FontWeight.w700), ), ], ), - Padding( - padding: const EdgeInsets.only(right: 8), - child: _miniAvatars(state.profile.subscribers), - ), + Padding(padding: const EdgeInsets.only(right: 8), child: _miniAvatars(state.profile.subscribers)), ], ), ), @@ -934,13 +725,7 @@ class _ProfileScreenState extends State { for (int i = 0; i < maxLength; i++) Align( widthFactor: 0.8, - child: CircleAvatar( - radius: 14, - foregroundImage: NetworkImage( - urls[i], - ), - backgroundImage: const AssetImage('assets/images/no_avatar.png'), - ), + child: CircleAvatar(radius: 14, foregroundImage: NetworkImage(urls[i]), backgroundImage: const AssetImage('assets/images/no_avatar.png')), ), ], ); @@ -951,10 +736,7 @@ class _ProfileScreenState extends State { padding: const EdgeInsets.symmetric(vertical: 16), shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - itemBuilder: (context, index) => ProfileBlogPostWidget( - index: index, - profileCubit: profileCubit, - ), + itemBuilder: (context, index) => ProfileBlogPostWidget(index: index, profileCubit: profileCubit), separatorBuilder: (context, index) => const SizedBox(height: 8), itemCount: state.blogPosts.length, ); @@ -968,13 +750,7 @@ class _ProfileScreenState extends State { return Container( alignment: Alignment.centerLeft, padding: const EdgeInsets.all(16), - child: Text( - text, - style: TextStyle( - color: Colors.black.withValues(alpha: 0.4), - height: 1, - ), - ), + child: Text(text, style: TextStyle(color: Colors.black.withValues(alpha: 0.4), height: 1)), ); } @@ -986,13 +762,7 @@ class _ProfileScreenState extends State { PopupMenuButton( onSelected: (value) async { if (value == 'view') { - context.pushTransparentRoute( - rootNavigator: true, - PhotoViewScreen( - imageUrls: [baseUrl + state.profile.profilePhotoUrl], - index: 0, - ), - ); + context.pushTransparentRoute(rootNavigator: true, PhotoViewScreen(imageUrls: [baseUrl + state.profile.profilePhotoUrl], index: 0)); } if (value == 'replace') { showCupertinoModalPopup( @@ -1019,13 +789,7 @@ class _ProfileScreenState extends State { context: context, ); }, - child: const Row( - children: [ - Icon(Icons.photo_camera), - SizedBox(width: 8), - Text('Фото'), - ], - ), + child: const Row(children: [Icon(Icons.photo_camera), SizedBox(width: 8), Text('Фото')]), ), CupertinoActionSheetAction( onPressed: () async { @@ -1045,13 +809,7 @@ class _ProfileScreenState extends State { context: context, ); }, - child: const Row( - children: [ - Icon(Icons.photo), - SizedBox(width: 8), - Text('Галерея'), - ], - ), + child: const Row(children: [Icon(Icons.photo), SizedBox(width: 8), Text('Галерея')]), ), ], cancelButton: CupertinoActionSheetAction( @@ -1069,20 +827,9 @@ class _ProfileScreenState extends State { } }, itemBuilder: (context) => [ - const PopupMenuItem( - value: 'view', - child: Text('Посмотреть'), - ), - if (widget.author == null || widget.author!.authorIsMe) - const PopupMenuItem( - value: 'replace', - child: Text('Заменить'), - ), - if (widget.author == null || widget.author!.authorIsMe) - const PopupMenuItem( - value: 'delete', - child: Text('Удалить'), - ), + const PopupMenuItem(value: 'view', child: Text('Посмотреть')), + if (widget.author == null || widget.author!.authorIsMe) const PopupMenuItem(value: 'replace', child: Text('Заменить')), + if (widget.author == null || widget.author!.authorIsMe) const PopupMenuItem(value: 'delete', child: Text('Удалить')), ], child: Hero( tag: state.profile.profilePhotoUrl, @@ -1101,12 +848,7 @@ class _ProfileScreenState extends State { children: [ Text( '${state.profileDetails.firstName} ${state.profileDetails.lastName}', - style: const TextStyle( - color: Colors.black, - fontWeight: FontWeight.w600, - fontSize: 16, - height: 1, - ), + style: const TextStyle(color: Colors.black, fontWeight: FontWeight.w600, fontSize: 16, height: 1), ), const SizedBox(height: 8), GestureDetector( @@ -1124,11 +866,7 @@ class _ProfileScreenState extends State { children: [ const Text( 'Подробнее', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.w700, - color: Color(0xFF323F4B), - ), + style: TextStyle(fontSize: 20, fontWeight: FontWeight.w700, color: Color(0xFF323F4B)), ), const SizedBox(height: 16), _additional('Дата рожденя: ', state.profileDetails.birthdate), @@ -1148,19 +886,11 @@ class _ProfileScreenState extends State { }, child: const Row( children: [ - Icon( - Icons.info_outline, - size: 20, - color: Color(0xFF6D6F71), - ), + Icon(Icons.info_outline, size: 20, color: Color(0xFF6D6F71)), SizedBox(width: 4), Text( 'Дополнительно', - style: TextStyle( - color: Color(0xFF6D6F71), - fontSize: 14, - fontWeight: FontWeight.w500, - ), + style: TextStyle(color: Color(0xFF6D6F71), fontSize: 14, fontWeight: FontWeight.w500), ), ], ), @@ -1173,10 +903,7 @@ class _ProfileScreenState extends State { if (value == 'share') { final box = context.findRenderObject() as RenderBox?; SharePlus.instance.share( - ShareParams( - uri: Uri.parse('$baseUrl/ru/profile/${state.profile.slug}'), - sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size, - ), + ShareParams(uri: Uri.parse('$baseUrl/ru/profile/${state.profile.slug}'), sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size), ); } else if (value == 'block') { isFirstFetch = true; @@ -1198,33 +925,15 @@ class _ProfileScreenState extends State { showModalBottomSheet( context: context, isScrollControlled: true, - builder: (context) => ComplainingBottomSheet( - complainedContentType: ComplainedContent.profile, - slug: widget.author?.authorSlug, - ), + builder: (context) => ComplainingBottomSheet(complainedContentType: ComplainedContent.profile, slug: widget.author?.authorSlug), ); } }, itemBuilder: (context) => [ - const PopupMenuItem( - value: 'share', - child: Text('Поделиться'), - ), - if (widget.author != null) - const PopupMenuItem( - value: 'complain', - child: Text('Пожаловаться'), - ), - if (widget.author != null && !state.profile.isBlockedByMe) - const PopupMenuItem( - value: 'block', - child: Text('Заблокировать'), - ), - if (widget.author != null && state.profile.isBlockedByMe) - const PopupMenuItem( - value: 'unblock', - child: Text('Разблокировать'), - ), + const PopupMenuItem(value: 'share', child: Text('Поделиться')), + if (widget.author != null) const PopupMenuItem(value: 'complain', child: Text('Пожаловаться')), + if (widget.author != null && !state.profile.isBlockedByMe) const PopupMenuItem(value: 'block', child: Text('Заблокировать')), + if (widget.author != null && state.profile.isBlockedByMe) const PopupMenuItem(value: 'unblock', child: Text('Разблокировать')), ], child: const Icon(Icons.more_horiz_rounded), ), @@ -1238,19 +947,11 @@ class _ProfileScreenState extends State { children: [ Text( title, - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - color: Color(0xFF6D6F71), - ), + style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w500, color: Color(0xFF6D6F71)), ), Text( value, - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - color: Color(0xFF323F4B), - ), + style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w500, color: Color(0xFF323F4B)), ), ], ); @@ -1266,16 +967,8 @@ class _ProfileScreenState extends State { alignment: Alignment.center, padding: const EdgeInsets.all(8), width: (MediaQuery.of(context).size.width - 40) / 2, - decoration: BoxDecoration( - color: appTheme.blueA400.withValues(alpha: 0.1), - borderRadius: BorderRadius.circular(16), - ), - child: Text( - 'Сообщение', - style: TextStyle( - color: appTheme.blueA400, - ), - ), + decoration: BoxDecoration(color: appTheme.blueA400.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(16)), + child: Text('Сообщение', style: TextStyle(color: appTheme.blueA400)), ), ), const SizedBox(width: 8), @@ -1290,16 +983,8 @@ class _ProfileScreenState extends State { alignment: Alignment.center, padding: const EdgeInsets.all(8), width: (MediaQuery.of(context).size.width - 40) / 2, - decoration: BoxDecoration( - color: !canSub ? Colors.grey.shade200 : appTheme.blueA400, - borderRadius: BorderRadius.circular(16), - ), - child: Text( - !canSub ? 'Отписаться' : 'Подписаться', - style: TextStyle( - color: !canSub ? Colors.black : Colors.white, - ), - ), + decoration: BoxDecoration(color: !canSub ? Colors.grey.shade200 : appTheme.blueA400, borderRadius: BorderRadius.circular(16)), + child: Text(!canSub ? 'Отписаться' : 'Подписаться', style: TextStyle(color: !canSub ? Colors.black : Colors.white)), ), ), const SizedBox(width: 16), @@ -1318,33 +1003,17 @@ class _ProfileScreenState extends State { SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 16), scrollDirection: Axis.horizontal, - child: Row( - children: [ - _choiceChipWidget(0), - const SizedBox(width: 8), - _choiceChipWidget(1), - const SizedBox(width: 8), - _choiceChipWidget(2), - ], - ), + child: Row(children: [_choiceChipWidget(0), const SizedBox(width: 8), _choiceChipWidget(1), const SizedBox(width: 8), _choiceChipWidget(2)]), ), Builder( builder: (context) { switch (_selectedChipIndex) { case 0: - return WeightChartWidget( - weightPoints: weightPoints, - profileCubit: profileCubit, - ); + return WeightChartWidget(weightPoints: weightPoints, profileCubit: profileCubit); case 1: - return CircumferenceChartWidget( - circumferencePoints: circumferencePoints, - profileCubit: profileCubit, - ); + return CircumferenceChartWidget(circumferencePoints: circumferencePoints, profileCubit: profileCubit); case 2: - return ImtChartWidget( - weightPoints: weightPoints, - ); + return ImtChartWidget(weightPoints: weightPoints); default: return const SizedBox.shrink(); } @@ -1377,16 +1046,10 @@ class _ProfileScreenState extends State { pressElevation: 0, showCheckmark: false, side: BorderSide.none, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), - ), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), label: Text(chipsIntervalLabelList[index]), - labelStyle: TextStyle( - color: appTheme.gray600, - fontWeight: FontWeight.w500, - fontSize: 12, - ), + labelStyle: TextStyle(color: appTheme.gray600, fontWeight: FontWeight.w500, fontSize: 12), selected: _selectedIntervalChipIndex == index, onSelected: (bool selected) { profileCubit.getMyProfile(period: chipsIntervalList[index]); @@ -1403,16 +1066,10 @@ class _ProfileScreenState extends State { pressElevation: 0, showCheckmark: false, side: BorderSide.none, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), - ), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), label: Text(chipsLabelList[index]), - labelStyle: TextStyle( - color: index == _selectedChipIndex ? Colors.white : appTheme.gray600, - fontWeight: FontWeight.w500, - fontSize: 12, - ), + labelStyle: TextStyle(color: index == _selectedChipIndex ? Colors.white : appTheme.gray600, fontWeight: FontWeight.w500, fontSize: 12), selected: _selectedChipIndex == index, backgroundColor: appTheme.gray100, onSelected: (bool selected) {