From e602e5d23952926ea85e08fd600413ae40dc8b68 Mon Sep 17 00:00:00 2001 From: maxxkim Date: Thu, 18 Apr 2024 14:49:45 +0300 Subject: [PATCH 1/2] feat(app): Added a popup menu to bottom navbar --- assets/images/img_nav_diets.svg | 3 + assets/images/img_nav_exit.svg | 4 ++ assets/images/img_nav_finance.svg | 4 ++ assets/images/img_nav_plans.svg | 3 + assets/images/img_nav_recipes.svg | 3 + assets/images/img_nav_settings.svg | 3 + assets/images/img_nav_support.svg | 6 ++ lib/core/utils/image_constant.dart | 18 ++++++ .../app_bar/appbar_title_circleimage.dart | 8 --- lib/widgets/custom_bottom_bar.dart | 37 ++++++++--- lib/widgets/custom_navigation_menu.dart | 64 +++++++++++++++++++ lib/widgets/custom_navigation_menu_item.dart | 36 +++++++++++ 12 files changed, 171 insertions(+), 18 deletions(-) create mode 100644 assets/images/img_nav_diets.svg create mode 100644 assets/images/img_nav_exit.svg create mode 100644 assets/images/img_nav_finance.svg create mode 100644 assets/images/img_nav_plans.svg create mode 100644 assets/images/img_nav_recipes.svg create mode 100644 assets/images/img_nav_settings.svg create mode 100644 assets/images/img_nav_support.svg create mode 100644 lib/widgets/custom_navigation_menu.dart create mode 100644 lib/widgets/custom_navigation_menu_item.dart diff --git a/assets/images/img_nav_diets.svg b/assets/images/img_nav_diets.svg new file mode 100644 index 00000000..6300006a --- /dev/null +++ b/assets/images/img_nav_diets.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/img_nav_exit.svg b/assets/images/img_nav_exit.svg new file mode 100644 index 00000000..5559649e --- /dev/null +++ b/assets/images/img_nav_exit.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/images/img_nav_finance.svg b/assets/images/img_nav_finance.svg new file mode 100644 index 00000000..79c9d63a --- /dev/null +++ b/assets/images/img_nav_finance.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/images/img_nav_plans.svg b/assets/images/img_nav_plans.svg new file mode 100644 index 00000000..62e0c17a --- /dev/null +++ b/assets/images/img_nav_plans.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/img_nav_recipes.svg b/assets/images/img_nav_recipes.svg new file mode 100644 index 00000000..505da803 --- /dev/null +++ b/assets/images/img_nav_recipes.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/img_nav_settings.svg b/assets/images/img_nav_settings.svg new file mode 100644 index 00000000..619bd4e7 --- /dev/null +++ b/assets/images/img_nav_settings.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/img_nav_support.svg b/assets/images/img_nav_support.svg new file mode 100644 index 00000000..84859d74 --- /dev/null +++ b/assets/images/img_nav_support.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/lib/core/utils/image_constant.dart b/lib/core/utils/image_constant.dart index ca6adbdb..e7dd2b2a 100644 --- a/lib/core/utils/image_constant.dart +++ b/lib/core/utils/image_constant.dart @@ -79,6 +79,8 @@ class ImageConstant { static String imgEllipse3 = '$imagePath/img_ellipse_3.png'; + //------------------NAVIGATION--------------------------------- + static String imgDiary = '$imagePath/img_nav_diary.svg'; static String imgFeed = '$imagePath/img_nav_feed.svg'; @@ -89,6 +91,22 @@ class ImageConstant { static String imgBell = '$imagePath/img_nav_bell.svg'; + static String imgSettings = '$imagePath/img_nav_settings.svg'; + + static String imgRecipes = '$imagePath/img_nav_recipes.svg'; + + static String imgDiets = '$imagePath/img_nav_diets.svg'; + + static String imgPlans = '$imagePath/img_nav_plans.svg'; + + static String imgFinance = '$imagePath/img_nav_finance.svg'; + + static String imgSupport = '$imagePath/img_nav_support.svg'; + + static String imgExit = '$imagePath/img_nav_exit.svg'; + + //------------------------------------------------------------- + static String imgNavBlueGray400 = '$imagePath/img_nav_blue_gray_400.svg'; static String imgNavBlueGray40024x23 = diff --git a/lib/widgets/app_bar/appbar_title_circleimage.dart b/lib/widgets/app_bar/appbar_title_circleimage.dart index 66f82ef9..02224f3c 100644 --- a/lib/widgets/app_bar/appbar_title_circleimage.dart +++ b/lib/widgets/app_bar/appbar_title_circleimage.dart @@ -7,7 +7,6 @@ class AppbarTitleCircleimage extends StatelessWidget { Key? key, this.imagePath, this.margin, - this.onTap, }) : super( key: key, ); @@ -16,13 +15,10 @@ class AppbarTitleCircleimage extends StatelessWidget { EdgeInsetsGeometry? margin; - Function? onTap; - @override Widget build(BuildContext context) { return InkWell( borderRadius: BorderRadiusStyle.circleBorder8, - onTap: onTapCall, child: Padding( padding: margin ?? EdgeInsets.zero, child: CustomImageView( @@ -37,8 +33,4 @@ class AppbarTitleCircleimage extends StatelessWidget { ), ); } - - void onTapCall() { - onTap!.call(); - } } diff --git a/lib/widgets/custom_bottom_bar.dart b/lib/widgets/custom_bottom_bar.dart index 75457b5b..922964b0 100644 --- a/lib/widgets/custom_bottom_bar.dart +++ b/lib/widgets/custom_bottom_bar.dart @@ -1,6 +1,7 @@ import 'package:eatvio_app/core/app_export.dart'; import 'package:flutter/material.dart'; import 'package:eatvio_app/widgets/app_bar/appbar_title_circleimage.dart'; +import 'package:eatvio_app/widgets/custom_navigation_menu.dart'; // ignore: must_be_immutable class CustomBottomBar extends StatefulWidget { @@ -86,7 +87,6 @@ class CustomBottomBarState extends State { Navigator.pushNamed(context, AppRoutes.myProfile); break; case 1: - //Navigator.pushNamed(context, AppRoutes.myProfile); break; case 2: Navigator.pushNamed(context, AppRoutes.diaryEdit); @@ -94,13 +94,6 @@ class CustomBottomBarState extends State { case 3: Navigator.pushNamed(context, '/chat'); break; - case 4: - //Navigator.pushNamed(context, '/chat'); - break; - case 5: - Navigator.pushNamed(context, AppRoutes.mySettings); - break; - default: } } @@ -111,7 +104,7 @@ class CustomBottomBarState extends State { double iconWidth; if (index == 0) { - // Для логотипа + // Для логотипа- iconHeight = 52.v; // Увеличиваем высоту iconWidth = 48.h; // Меняем ширину, чтобы сохранить пропорции } else if (index == bottomMenuList.length - 2) { @@ -141,7 +134,31 @@ class CustomBottomBarState extends State { isSelected ? theme.colorScheme.primary : appTheme.blueGray400, ), if (bottomMenuList[index].image) - AppbarTitleCircleimage(imagePath: ImageConstant.imgEllipse1), + GestureDetector( + onTap: () => showMenu( + context: context, + color: Colors.white, + shadowColor: Colors.white, + surfaceTintColor: Colors.white, + position: RelativeRect.fromLTRB( + // Указываем позицию справа по центру + MediaQuery.of(context).size.width - + 50, // Расположение от правого края + kToolbarHeight + 340, // Расположение от верхнего края + 0, // Не смещаем по горизонтали + 0, // Не смещаем по вертикали + ), + items: [ + PopupMenuItem( + child: + CustomNavigationMenu(), // Используйте ваше меню здесь + ) + ], + ), + child: AppbarTitleCircleimage( + imagePath: ImageConstant.imgEllipse1, + ), + ), if (bottomMenuList[index].title != null) // Проверяем, существует ли title Padding( diff --git a/lib/widgets/custom_navigation_menu.dart b/lib/widgets/custom_navigation_menu.dart new file mode 100644 index 00000000..d817a8f6 --- /dev/null +++ b/lib/widgets/custom_navigation_menu.dart @@ -0,0 +1,64 @@ +import 'package:eatvio_app/core/app_export.dart'; +import 'package:flutter/material.dart'; +import 'package:eatvio_app/widgets/custom_navigation_menu_item.dart'; + +class CustomNavigationMenu extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + color: Colors.white, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + MenuItem( + icon: ImageConstant.imgSettings, + text: 'Настройки профиля', + onTap: () => Navigator.pushNamed(context, AppRoutes.mySettings), + ), + MenuItem( + icon: ImageConstant.imgRecipes, + text: 'Мои рецепты', + onTap: () { + // Действие при нажатии на "Мои рецепты" + }, + ), + MenuItem( + icon: ImageConstant.imgDiets, + text: 'Мои диеты', + onTap: () { + // Действие при нажатии на "Мои диеты" + }, + ), + MenuItem( + icon: ImageConstant.imgPlans, + text: 'Мои планы', + onTap: () { + // Действие при нажатии на "Мои планы" + }, + ), + MenuItem( + icon: ImageConstant.imgFinance, + text: 'Финансы', + onTap: () { + // Действие при нажатии на "Финансы" + }, + ), + MenuItem( + icon: ImageConstant.imgSupport, + text: 'Поддержка', + onTap: () { + // Действие при нажатии на "Поддержка" + }, + ), + MenuItem( + icon: ImageConstant.imgExit, + text: 'Выход', + onTap: () { + // Действие при нажатии на "Выход" + }, + ), + ], + ), + ); + } +} diff --git a/lib/widgets/custom_navigation_menu_item.dart b/lib/widgets/custom_navigation_menu_item.dart new file mode 100644 index 00000000..f33d5342 --- /dev/null +++ b/lib/widgets/custom_navigation_menu_item.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; +import 'package:eatvio_app/widgets/custom_image_view.dart'; + +class MenuItem extends StatelessWidget { + final String icon; + final String text; + final VoidCallback onTap; + + const MenuItem({ + required this.icon, + required this.text, + required this.onTap, + }); + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: onTap, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: + CrossAxisAlignment.center, // Выравнивание по центру вертикально + children: [ + CustomImageView(imagePath: icon), + SizedBox( + width: + 8.0), // Добавляем небольшой отступ между иконкой и текстом + Text(text), + ], + ), + ), + ); + } +} From f93b314a613e550a0cb67564dfd544b92aa0e001 Mon Sep 17 00:00:00 2001 From: maxxkim Date: Thu, 18 Apr 2024 15:32:41 +0300 Subject: [PATCH 2/2] feat(diary): Preloader added when uploading images --- .../bloc/diary_edit_bloc.dart | 2 + .../bloc/diary_edit_state.dart | 7 +- .../diary_edit_screen/diary_edit_screen.dart | 104 +++++++++++------- 3 files changed, 73 insertions(+), 40 deletions(-) diff --git a/lib/presentation/diary/diary_edit_screen/bloc/diary_edit_bloc.dart b/lib/presentation/diary/diary_edit_screen/bloc/diary_edit_bloc.dart index 1bf38360..caa089d9 100644 --- a/lib/presentation/diary/diary_edit_screen/bloc/diary_edit_bloc.dart +++ b/lib/presentation/diary/diary_edit_screen/bloc/diary_edit_bloc.dart @@ -298,6 +298,7 @@ class DiaryEditBloc extends Bloc { carbsController: TextEditingController(), diaryId: diaryId, diaryDate: diaryDate, + isLoading: false, autocompleteList: [], ))); @@ -800,6 +801,7 @@ class DiaryEditBloc extends Bloc { if (state is DiaryEditLoadedState) { var currentState = state as DiaryEditLoadedState; + emit(currentState.copyWith(isLoading: true)); await uploadImageToServer(event.image.path, currentState.diaryId, currentState.currentMeal!.id!, currentState.token); await reloadScreen(event, emit); diff --git a/lib/presentation/diary/diary_edit_screen/bloc/diary_edit_state.dart b/lib/presentation/diary/diary_edit_screen/bloc/diary_edit_state.dart index ebed94bd..80fa5aa7 100644 --- a/lib/presentation/diary/diary_edit_screen/bloc/diary_edit_state.dart +++ b/lib/presentation/diary/diary_edit_screen/bloc/diary_edit_state.dart @@ -39,6 +39,7 @@ class DiaryEditLoadedState extends DiaryEditState { this.fatsController, this.proteinsController, this.carbsController, + this.isLoading = false, required this.recommendedChartValues, required this.consumedChartValues, required this.diaryId, @@ -75,6 +76,7 @@ class DiaryEditLoadedState extends DiaryEditState { bool wakeupExpanded; bool moderationExpanded; bool moodExpanded; + bool isLoading; @override List get props => [ diaryEditModelObj, @@ -103,6 +105,7 @@ class DiaryEditLoadedState extends DiaryEditState { wakeupExpanded, moodExpanded, moderationExpanded, + isLoading, currentMeal ]; DiaryEditLoadedState copyWith({ @@ -133,6 +136,7 @@ class DiaryEditLoadedState extends DiaryEditState { bool? wakeupExpanded, bool? moderationExpanded, bool? moodExpanded, + bool? isLoading, }) { return DiaryEditLoadedState( diaryEditModelObj: diaryEditModelObj ?? this.diaryEditModelObj, @@ -164,7 +168,8 @@ class DiaryEditLoadedState extends DiaryEditState { carbsController: carbsController ?? this.carbsController, wakeupExpanded: wakeupExpanded ?? this.wakeupExpanded, moderationExpanded: moderationExpanded ?? this.moderationExpanded, - moodExpanded: moodExpanded ?? this.moodExpanded); + moodExpanded: moodExpanded ?? this.moodExpanded, + isLoading: isLoading ?? this.isLoading); } } diff --git a/lib/presentation/diary/diary_edit_screen/diary_edit_screen.dart b/lib/presentation/diary/diary_edit_screen/diary_edit_screen.dart index 6f37061c..c7ca1b8c 100644 --- a/lib/presentation/diary/diary_edit_screen/diary_edit_screen.dart +++ b/lib/presentation/diary/diary_edit_screen/diary_edit_screen.dart @@ -176,53 +176,79 @@ class DiaryEditScreen extends StatelessWidget { } /// Section Widget - _buildAddPhoto(BuildContext context) { + _buildAddPhoto(BuildContext context, DiaryEditLoadedState state) { + bool isLoading = state.isLoading; return GestureDetector( - onTap: addImage(context), - child: Container( - margin: EdgeInsets.symmetric(horizontal: 10.h), - padding: EdgeInsets.symmetric( - horizontal: 40.h, - vertical: 80.v, - ), - decoration: AppDecoration.fillGray.copyWith( - borderRadius: BorderRadiusStyle.roundedBorder5, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.end, - mainAxisSize: MainAxisSize.min, - children: [ - Padding( - padding: EdgeInsets.only( - left: 7.h, - top: 5.v, + onTap: addImage(context, isLoading), + child: Stack( + children: [ + if (!isLoading) + Container( + margin: EdgeInsets.symmetric(horizontal: 10.h), + padding: EdgeInsets.symmetric( + horizontal: 40.h, + vertical: 80.v, ), - child: Text( - "Добавить фото", - selectionColor: appTheme.blueA400, + decoration: AppDecoration.fillGray.copyWith( + borderRadius: BorderRadiusStyle.roundedBorder5, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [ + // Показывайте прелоадер, если загрузка активна + + Padding( + padding: EdgeInsets.only( + left: 7.h, + top: 5.v, + ), + child: Text( + "Добавить фото", + selectionColor: appTheme.blueA400, + ), + ), + Spacer(), + Icon( + Icons.photo_library, + color: appTheme.blueGray300, + ) + ], ), ), - Spacer(), - Icon( - Icons.photo_library, - color: appTheme.blueGray300, - ) - ], - ), + if (isLoading) + Container( + margin: EdgeInsets.symmetric(horizontal: 10.h), + padding: EdgeInsets.symmetric( + horizontal: 40.h, + vertical: 80.v, + ), + decoration: AppDecoration.fillGray.copyWith( + borderRadius: BorderRadiusStyle.roundedBorder5, + ), + child: Center( + child: CircularProgressIndicator( + color: appTheme + .blueGray300), // Замените на свой прелоадер при необходимости + ), + ), + ], ), ); } - addImage(BuildContext context) { - return () async { - final picker = ImagePicker(); - List? images = await picker.pickMultiImage(); - if (images.isNotEmpty) { - for (var image in images) { - context.read().add(UploadImages(image)); + addImage(BuildContext context, bool isLoading) { + if (!isLoading) { + return () async { + final picker = ImagePicker(); + List? images = await picker.pickMultiImage(); + if (images.isNotEmpty) { + for (var image in images) { + context.read().add(UploadImages(image)); + } } - } - }; + }; + } } _buildMeal(BuildContext context, DiaryEditLoadedState state) { @@ -411,7 +437,7 @@ class DiaryEditScreen extends StatelessWidget { : [Text('Фото нет')],*/ _buildCarousel(context, state), SizedBox(height: 20.v), - _buildAddPhoto(context), + _buildAddPhoto(context, state), SizedBox(height: 30.v), Text( "Ваша сытость после приёма пищи",