From 7e919d8f4c55da2dad608bb6f8f4884488079e26 Mon Sep 17 00:00:00 2001 From: mso7nueh Date: Tue, 27 Aug 2024 16:59:37 +0300 Subject: [PATCH] feat(profile): Replaced the diet and calendar icons, reduced the height of the bottom nav bar, added the first version of the measurements graph, added the time of the chat message and changed the design slightly --- assets/icons/calendar.svg | 29 + assets/icons/diets.svg | 24 + lib/app_router.dart | 3 +- .../profile_avatar_cubit.dart | 22 + .../profile_avatar_state.dart | 19 + .../profile_avatar_state.freezed.dart | 630 ++++++++++++++++++ .../widgets/bottom_navigation_bar_widget.dart | 247 ++++--- .../widgets/chat_bubble_widget.dart | 29 +- .../widgets/chat_search_bar_widget.dart | 1 - .../bloc/profile_cubit/profile_cubit.dart | 16 + .../presentation/pages/profile_screen.dart | 134 +++- .../repositories/profile_repository.dart | 18 + .../profile/services/profile_service.dart | 7 + .../profile/services/profile_service.g.dart | 50 ++ lib/locator_service.dart | 2 + lib/main.dart | 2 + lib/widgets/custom_navigation_menu.dart | 4 +- pubspec.yaml | 3 +- 18 files changed, 1102 insertions(+), 138 deletions(-) create mode 100644 assets/icons/calendar.svg create mode 100644 assets/icons/diets.svg create mode 100644 lib/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_cubit.dart create mode 100644 lib/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_state.dart create mode 100644 lib/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_state.freezed.dart diff --git a/assets/icons/calendar.svg b/assets/icons/calendar.svg new file mode 100644 index 00000000..e9d97952 --- /dev/null +++ b/assets/icons/calendar.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/icons/diets.svg b/assets/icons/diets.svg new file mode 100644 index 00000000..7714b3fa --- /dev/null +++ b/assets/icons/diets.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + diff --git a/lib/app_router.dart b/lib/app_router.dart index 57923180..3a662763 100644 --- a/lib/app_router.dart +++ b/lib/app_router.dart @@ -24,7 +24,6 @@ import 'package:eatvio_app/presentation/diets/diet_select_screen/diet_select_scr import 'package:eatvio_app/presentation/feed/blog_post_edit_screen/blog_post_edit_screen.dart'; import 'package:eatvio_app/presentation/glossary/glossary_screen/glossary_screen.dart'; import 'package:eatvio_app/presentation/plans/plan_select_screen/plan_select_screen.dart'; -import 'package:eatvio_app/presentation/profile/my_profile_screen/my_profile_screen.dart'; import 'package:eatvio_app/presentation/profile/my_profile_screen/my_settings_screen.dart'; import 'package:eatvio_app/presentation/recipe/recipe_select_screen/recipe_select_screen.dart'; import 'package:flutter/material.dart'; @@ -62,7 +61,7 @@ class AppRouter { }, routes: [ GoRoute( - pageBuilder: (context, state) => NoTransitionPage(child: MyProfileScreen()), + pageBuilder: (context, state) => NoTransitionPage(child: ProfileScreen()), path: '/my-profile-screen', name: 'myProfileScreen', redirect: (context, state) async { diff --git a/lib/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_cubit.dart b/lib/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_cubit.dart new file mode 100644 index 00000000..e2bfd48b --- /dev/null +++ b/lib/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_cubit.dart @@ -0,0 +1,22 @@ +import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_state.dart'; +import 'package:eatvio_app/features/profile/repositories/profile_repository.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +class ProfileAvatarCubit extends Cubit { + final ProfileRepository profileRepository; + + ProfileAvatarCubit({ + required this.profileRepository, + }) : super(const ProfileAvatarState.loading()); + + getMyProfile() async { + try { + emit(ProfileAvatarState.loaded( + profile: await profileRepository.getMyProfile(), + )); + } catch (e) { + emit(ProfileAvatarState.error(errorMessage: e.toString())); + print(e); + } + } +} \ No newline at end of file diff --git a/lib/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_state.dart b/lib/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_state.dart new file mode 100644 index 00000000..fe90fb6f --- /dev/null +++ b/lib/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_state.dart @@ -0,0 +1,19 @@ +import 'package:eatvio_app/features/profile/models/profile_model.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'profile_avatar_state.freezed.dart'; + +@freezed +abstract class ProfileAvatarState with _$ProfileAvatarState { + const factory ProfileAvatarState() = _ProfileAvatarState; + + const factory ProfileAvatarState.loading() = ProfileAvatarStateLoading; + + const factory ProfileAvatarState.loaded({ + required ProfileModel profile, + }) = ProfileAvatarStateLoaded; + + const factory ProfileAvatarState.error({ + required String errorMessage, + }) = ProfileAvatarStateError; +} diff --git a/lib/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_state.freezed.dart b/lib/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_state.freezed.dart new file mode 100644 index 00000000..5d8de7ff --- /dev/null +++ b/lib/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_state.freezed.dart @@ -0,0 +1,630 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'profile_avatar_state.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$ProfileAvatarState { + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(ProfileModel profile) loaded, + required TResult Function(String errorMessage) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(ProfileModel profile)? loaded, + TResult? Function(String errorMessage)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(ProfileModel profile)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map( + TResult Function(_ProfileAvatarState value) $default, { + required TResult Function(ProfileAvatarStateLoading value) loading, + required TResult Function(ProfileAvatarStateLoaded value) loaded, + required TResult Function(ProfileAvatarStateError value) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_ProfileAvatarState value)? $default, { + TResult? Function(ProfileAvatarStateLoading value)? loading, + TResult? Function(ProfileAvatarStateLoaded value)? loaded, + TResult? Function(ProfileAvatarStateError value)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap( + TResult Function(_ProfileAvatarState value)? $default, { + TResult Function(ProfileAvatarStateLoading value)? loading, + TResult Function(ProfileAvatarStateLoaded value)? loaded, + TResult Function(ProfileAvatarStateError value)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ProfileAvatarStateCopyWith<$Res> { + factory $ProfileAvatarStateCopyWith( + ProfileAvatarState value, $Res Function(ProfileAvatarState) then) = + _$ProfileAvatarStateCopyWithImpl<$Res, ProfileAvatarState>; +} + +/// @nodoc +class _$ProfileAvatarStateCopyWithImpl<$Res, $Val extends ProfileAvatarState> + implements $ProfileAvatarStateCopyWith<$Res> { + _$ProfileAvatarStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; +} + +/// @nodoc +abstract class _$$ProfileAvatarStateImplCopyWith<$Res> { + factory _$$ProfileAvatarStateImplCopyWith(_$ProfileAvatarStateImpl value, + $Res Function(_$ProfileAvatarStateImpl) then) = + __$$ProfileAvatarStateImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$ProfileAvatarStateImplCopyWithImpl<$Res> + extends _$ProfileAvatarStateCopyWithImpl<$Res, _$ProfileAvatarStateImpl> + implements _$$ProfileAvatarStateImplCopyWith<$Res> { + __$$ProfileAvatarStateImplCopyWithImpl(_$ProfileAvatarStateImpl _value, + $Res Function(_$ProfileAvatarStateImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$ProfileAvatarStateImpl implements _ProfileAvatarState { + const _$ProfileAvatarStateImpl(); + + @override + String toString() { + return 'ProfileAvatarState()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$ProfileAvatarStateImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(ProfileModel profile) loaded, + required TResult Function(String errorMessage) error, + }) { + return $default(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(ProfileModel profile)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return $default?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(ProfileModel profile)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if ($default != null) { + return $default(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_ProfileAvatarState value) $default, { + required TResult Function(ProfileAvatarStateLoading value) loading, + required TResult Function(ProfileAvatarStateLoaded value) loaded, + required TResult Function(ProfileAvatarStateError value) error, + }) { + return $default(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_ProfileAvatarState value)? $default, { + TResult? Function(ProfileAvatarStateLoading value)? loading, + TResult? Function(ProfileAvatarStateLoaded value)? loaded, + TResult? Function(ProfileAvatarStateError value)? error, + }) { + return $default?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_ProfileAvatarState value)? $default, { + TResult Function(ProfileAvatarStateLoading value)? loading, + TResult Function(ProfileAvatarStateLoaded value)? loaded, + TResult Function(ProfileAvatarStateError value)? error, + required TResult orElse(), + }) { + if ($default != null) { + return $default(this); + } + return orElse(); + } +} + +abstract class _ProfileAvatarState implements ProfileAvatarState { + const factory _ProfileAvatarState() = _$ProfileAvatarStateImpl; +} + +/// @nodoc +abstract class _$$ProfileAvatarStateLoadingImplCopyWith<$Res> { + factory _$$ProfileAvatarStateLoadingImplCopyWith( + _$ProfileAvatarStateLoadingImpl value, + $Res Function(_$ProfileAvatarStateLoadingImpl) then) = + __$$ProfileAvatarStateLoadingImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$ProfileAvatarStateLoadingImplCopyWithImpl<$Res> + extends _$ProfileAvatarStateCopyWithImpl<$Res, + _$ProfileAvatarStateLoadingImpl> + implements _$$ProfileAvatarStateLoadingImplCopyWith<$Res> { + __$$ProfileAvatarStateLoadingImplCopyWithImpl( + _$ProfileAvatarStateLoadingImpl _value, + $Res Function(_$ProfileAvatarStateLoadingImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$ProfileAvatarStateLoadingImpl implements ProfileAvatarStateLoading { + const _$ProfileAvatarStateLoadingImpl(); + + @override + String toString() { + return 'ProfileAvatarState.loading()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ProfileAvatarStateLoadingImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(ProfileModel profile) loaded, + required TResult Function(String errorMessage) error, + }) { + return loading(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(ProfileModel profile)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return loading?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(ProfileModel profile)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_ProfileAvatarState value) $default, { + required TResult Function(ProfileAvatarStateLoading value) loading, + required TResult Function(ProfileAvatarStateLoaded value) loaded, + required TResult Function(ProfileAvatarStateError value) error, + }) { + return loading(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_ProfileAvatarState value)? $default, { + TResult? Function(ProfileAvatarStateLoading value)? loading, + TResult? Function(ProfileAvatarStateLoaded value)? loaded, + TResult? Function(ProfileAvatarStateError value)? error, + }) { + return loading?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_ProfileAvatarState value)? $default, { + TResult Function(ProfileAvatarStateLoading value)? loading, + TResult Function(ProfileAvatarStateLoaded value)? loaded, + TResult Function(ProfileAvatarStateError value)? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(this); + } + return orElse(); + } +} + +abstract class ProfileAvatarStateLoading implements ProfileAvatarState { + const factory ProfileAvatarStateLoading() = _$ProfileAvatarStateLoadingImpl; +} + +/// @nodoc +abstract class _$$ProfileAvatarStateLoadedImplCopyWith<$Res> { + factory _$$ProfileAvatarStateLoadedImplCopyWith( + _$ProfileAvatarStateLoadedImpl value, + $Res Function(_$ProfileAvatarStateLoadedImpl) then) = + __$$ProfileAvatarStateLoadedImplCopyWithImpl<$Res>; + @useResult + $Res call({ProfileModel profile}); + + $ProfileModelCopyWith<$Res> get profile; +} + +/// @nodoc +class __$$ProfileAvatarStateLoadedImplCopyWithImpl<$Res> + extends _$ProfileAvatarStateCopyWithImpl<$Res, + _$ProfileAvatarStateLoadedImpl> + implements _$$ProfileAvatarStateLoadedImplCopyWith<$Res> { + __$$ProfileAvatarStateLoadedImplCopyWithImpl( + _$ProfileAvatarStateLoadedImpl _value, + $Res Function(_$ProfileAvatarStateLoadedImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? profile = null, + }) { + return _then(_$ProfileAvatarStateLoadedImpl( + profile: null == profile + ? _value.profile + : profile // ignore: cast_nullable_to_non_nullable + as ProfileModel, + )); + } + + @override + @pragma('vm:prefer-inline') + $ProfileModelCopyWith<$Res> get profile { + return $ProfileModelCopyWith<$Res>(_value.profile, (value) { + return _then(_value.copyWith(profile: value)); + }); + } +} + +/// @nodoc + +class _$ProfileAvatarStateLoadedImpl implements ProfileAvatarStateLoaded { + const _$ProfileAvatarStateLoadedImpl({required this.profile}); + + @override + final ProfileModel profile; + + @override + String toString() { + return 'ProfileAvatarState.loaded(profile: $profile)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ProfileAvatarStateLoadedImpl && + (identical(other.profile, profile) || other.profile == profile)); + } + + @override + int get hashCode => Object.hash(runtimeType, profile); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ProfileAvatarStateLoadedImplCopyWith<_$ProfileAvatarStateLoadedImpl> + get copyWith => __$$ProfileAvatarStateLoadedImplCopyWithImpl< + _$ProfileAvatarStateLoadedImpl>(this, _$identity); + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(ProfileModel profile) loaded, + required TResult Function(String errorMessage) error, + }) { + return loaded(profile); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(ProfileModel profile)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return loaded?.call(profile); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(ProfileModel profile)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (loaded != null) { + return loaded(profile); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_ProfileAvatarState value) $default, { + required TResult Function(ProfileAvatarStateLoading value) loading, + required TResult Function(ProfileAvatarStateLoaded value) loaded, + required TResult Function(ProfileAvatarStateError value) error, + }) { + return loaded(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_ProfileAvatarState value)? $default, { + TResult? Function(ProfileAvatarStateLoading value)? loading, + TResult? Function(ProfileAvatarStateLoaded value)? loaded, + TResult? Function(ProfileAvatarStateError value)? error, + }) { + return loaded?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_ProfileAvatarState value)? $default, { + TResult Function(ProfileAvatarStateLoading value)? loading, + TResult Function(ProfileAvatarStateLoaded value)? loaded, + TResult Function(ProfileAvatarStateError value)? error, + required TResult orElse(), + }) { + if (loaded != null) { + return loaded(this); + } + return orElse(); + } +} + +abstract class ProfileAvatarStateLoaded implements ProfileAvatarState { + const factory ProfileAvatarStateLoaded( + {required final ProfileModel profile}) = _$ProfileAvatarStateLoadedImpl; + + ProfileModel get profile; + @JsonKey(ignore: true) + _$$ProfileAvatarStateLoadedImplCopyWith<_$ProfileAvatarStateLoadedImpl> + get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$ProfileAvatarStateErrorImplCopyWith<$Res> { + factory _$$ProfileAvatarStateErrorImplCopyWith( + _$ProfileAvatarStateErrorImpl value, + $Res Function(_$ProfileAvatarStateErrorImpl) then) = + __$$ProfileAvatarStateErrorImplCopyWithImpl<$Res>; + @useResult + $Res call({String errorMessage}); +} + +/// @nodoc +class __$$ProfileAvatarStateErrorImplCopyWithImpl<$Res> + extends _$ProfileAvatarStateCopyWithImpl<$Res, + _$ProfileAvatarStateErrorImpl> + implements _$$ProfileAvatarStateErrorImplCopyWith<$Res> { + __$$ProfileAvatarStateErrorImplCopyWithImpl( + _$ProfileAvatarStateErrorImpl _value, + $Res Function(_$ProfileAvatarStateErrorImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? errorMessage = null, + }) { + return _then(_$ProfileAvatarStateErrorImpl( + errorMessage: null == errorMessage + ? _value.errorMessage + : errorMessage // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc + +class _$ProfileAvatarStateErrorImpl implements ProfileAvatarStateError { + const _$ProfileAvatarStateErrorImpl({required this.errorMessage}); + + @override + final String errorMessage; + + @override + String toString() { + return 'ProfileAvatarState.error(errorMessage: $errorMessage)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ProfileAvatarStateErrorImpl && + (identical(other.errorMessage, errorMessage) || + other.errorMessage == errorMessage)); + } + + @override + int get hashCode => Object.hash(runtimeType, errorMessage); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ProfileAvatarStateErrorImplCopyWith<_$ProfileAvatarStateErrorImpl> + get copyWith => __$$ProfileAvatarStateErrorImplCopyWithImpl< + _$ProfileAvatarStateErrorImpl>(this, _$identity); + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(ProfileModel profile) loaded, + required TResult Function(String errorMessage) error, + }) { + return error(errorMessage); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(ProfileModel profile)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return error?.call(errorMessage); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(ProfileModel profile)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(errorMessage); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_ProfileAvatarState value) $default, { + required TResult Function(ProfileAvatarStateLoading value) loading, + required TResult Function(ProfileAvatarStateLoaded value) loaded, + required TResult Function(ProfileAvatarStateError value) error, + }) { + return error(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_ProfileAvatarState value)? $default, { + TResult? Function(ProfileAvatarStateLoading value)? loading, + TResult? Function(ProfileAvatarStateLoaded value)? loaded, + TResult? Function(ProfileAvatarStateError value)? error, + }) { + return error?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_ProfileAvatarState value)? $default, { + TResult Function(ProfileAvatarStateLoading value)? loading, + TResult Function(ProfileAvatarStateLoaded value)? loaded, + TResult Function(ProfileAvatarStateError value)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(this); + } + return orElse(); + } +} + +abstract class ProfileAvatarStateError implements ProfileAvatarState { + const factory ProfileAvatarStateError({required final String errorMessage}) = + _$ProfileAvatarStateErrorImpl; + + String get errorMessage; + @JsonKey(ignore: true) + _$$ProfileAvatarStateErrorImplCopyWith<_$ProfileAvatarStateErrorImpl> + get copyWith => throw _privateConstructorUsedError; +} diff --git a/lib/features/bottom_navigation_bar/presentation/widgets/bottom_navigation_bar_widget.dart b/lib/features/bottom_navigation_bar/presentation/widgets/bottom_navigation_bar_widget.dart index b3f74075..a7e12393 100644 --- a/lib/features/bottom_navigation_bar/presentation/widgets/bottom_navigation_bar_widget.dart +++ b/lib/features/bottom_navigation_bar/presentation/widgets/bottom_navigation_bar_widget.dart @@ -4,6 +4,8 @@ import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/new_ import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/new_messages_cubit/new_messages_state.dart'; import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_cubit.dart'; import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_state.dart'; +import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_cubit.dart'; +import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_state.dart'; import 'package:eatvio_app/widgets/custom_navigation_menu.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; @@ -68,119 +70,154 @@ class _BottomNavigationBarWidgetState extends State { Widget build(BuildContext context) { return Scaffold( body: widget.child, - bottomNavigationBar: BottomNavigationBar( - type: BottomNavigationBarType.fixed, - onTap: _onItemTapped, - selectedFontSize: 12, - unselectedFontSize: 12, - selectedItemColor: appTheme.blueA400, - currentIndex: currentBottomNavBarIndex, - items: [ - BottomNavigationBarItem( - label: '', - icon: SvgPicture.asset( - ImageConstant.imgLogo, - ), - ), - BottomNavigationBarItem( - label: 'Лента', - icon: SvgPicture.asset( - colorFilter: ColorFilter.mode(Colors.grey, BlendMode.srcIn), - width: 24, - height: 24, - ImageConstant.icnFeed, - ), - activeIcon: SvgPicture.asset( - ImageConstant.icnFeed, - width: 24, - height: 24, - colorFilter: ColorFilter.mode( - appTheme.blueA400, - BlendMode.srcIn, + bottomNavigationBar: SizedBox( + height: 58, + child: BottomNavigationBar( + type: BottomNavigationBarType.fixed, + onTap: _onItemTapped, + selectedFontSize: 10, + unselectedFontSize: 10, + selectedItemColor: appTheme.blueA400, + currentIndex: currentBottomNavBarIndex, + items: [ + BottomNavigationBarItem( + label: '', + icon: SvgPicture.asset( + ImageConstant.imgLogo, + height: 32, ), ), - ), - BottomNavigationBarItem( - label: "diary".tr, - icon: SvgPicture.asset( - colorFilter: ColorFilter.mode(Colors.grey, BlendMode.srcIn), - ImageConstant.icnDiary, - width: 24, - height: 24, - ), - activeIcon: SvgPicture.asset( - ImageConstant.icnDiary, - width: 24, - height: 24, - colorFilter: ColorFilter.mode( - appTheme.blueA400, - BlendMode.srcIn, + BottomNavigationBarItem( + label: 'Лента', + icon: Padding( + padding: const EdgeInsets.only(bottom: 2), + child: SvgPicture.asset( + colorFilter: ColorFilter.mode(Colors.grey, BlendMode.srcIn), + width: 20, + height: 20, + ImageConstant.icnFeed, + ), + ), + activeIcon: Padding( + padding: const EdgeInsets.only(bottom: 2), + child: SvgPicture.asset( + ImageConstant.icnFeed, + width: 20, + height: 20, + colorFilter: ColorFilter.mode( + appTheme.blueA400, + BlendMode.srcIn, + ), + ), ), ), - ), - BottomNavigationBarItem( - label: "chat".tr, - icon: BlocBuilder( - builder: (BuildContext context, NewMessagesState state) { - return badges.Badge( - position: badges.BadgePosition.topEnd(), - badgeContent: Text( - (state is NewMessagesStateLoaded) ? state.messagesCount.toString() : '0', - style: TextStyle( - color: Colors.white, + BottomNavigationBarItem( + label: "diary".tr, + icon: Padding( + padding: const EdgeInsets.only(bottom: 2), + child: SvgPicture.asset( + colorFilter: ColorFilter.mode(Colors.grey, BlendMode.srcIn), + ImageConstant.icnDiary, + width: 20, + height: 20, + ), + ), + activeIcon: Padding( + padding: const EdgeInsets.only(bottom: 2), + child: SvgPicture.asset( + ImageConstant.icnDiary, + width: 20, + height: 20, + colorFilter: ColorFilter.mode( + appTheme.blueA400, + BlendMode.srcIn, + ), + ), + ), + ), + BottomNavigationBarItem( + label: "chat".tr, + icon: BlocBuilder( + builder: (BuildContext context, NewMessagesState state) { + return badges.Badge( + position: badges.BadgePosition.topEnd(), + badgeAnimation: badges.BadgeAnimation.fade(), + badgeContent: Text( + (state is NewMessagesStateLoaded) ? state.messagesCount.toString() : '0', + style: TextStyle( + color: Colors.white, + fontSize: 8, + ), ), - ), - child: SvgPicture.asset( - ImageConstant.icnChat, - width: 24, - height: 24, - colorFilter: currentBottomNavBarIndex == 3 - ? ColorFilter.mode( - appTheme.blueA400, - BlendMode.srcIn, - ) - : ColorFilter.mode(Colors.grey, BlendMode.srcIn), - ), - ); - }, - ), - ), - BottomNavigationBarItem( - label: '', - icon: BlocBuilder( - builder: (BuildContext context, NotificationsState state) { - return badges.Badge( - position: badges.BadgePosition.topEnd(), - badgeContent: Text( - (state is NotificationsStateLoaded) ? state.notificationsCount.toString() : '0', - style: TextStyle( - color: Colors.white, + child: Padding( + padding: const EdgeInsets.only(bottom: 2), + child: SvgPicture.asset( + ImageConstant.icnChat, + width: 20, + height: 20, + colorFilter: currentBottomNavBarIndex == 3 + ? ColorFilter.mode( + appTheme.blueA400, + BlendMode.srcIn, + ) + : ColorFilter.mode(Colors.grey, BlendMode.srcIn), + ), ), - ), - child: SvgPicture.asset( - ImageConstant.icnBell, - colorFilter: currentBottomNavBarIndex == 4 - ? ColorFilter.mode( - appTheme.blueA400, - BlendMode.srcIn, - ) - : ColorFilter.mode(Colors.grey, BlendMode.srcIn), - width: 24, - height: 24, - ), - ); - }, + ); + }, + ), ), - ), - BottomNavigationBarItem( - label: '', - icon: Image.asset( - ImageConstant.imgEllipse1, - width: 32, - height: 32, + BottomNavigationBarItem( + label: 'Уведомления', + icon: BlocBuilder( + builder: (BuildContext context, NotificationsState state) { + return badges.Badge( + position: badges.BadgePosition.topEnd(), + badgeAnimation: badges.BadgeAnimation.fade(), + badgeContent: Text( + (state is NotificationsStateLoaded) ? state.notificationsCount.toString() : '0', + style: TextStyle( + color: Colors.white, + fontSize: 8, + ), + ), + child: Padding( + padding: const EdgeInsets.only(bottom: 2), + child: SvgPicture.asset( + ImageConstant.icnBell, + colorFilter: currentBottomNavBarIndex == 4 + ? ColorFilter.mode( + appTheme.blueA400, + BlendMode.srcIn, + ) + : ColorFilter.mode(Colors.grey, BlendMode.srcIn), + width: 20, + height: 20, + ), + ), + ); + }, + ), ), - ), - ], + BottomNavigationBarItem( + label: '', + icon: BlocBuilder( + builder: (BuildContext context, ProfileAvatarState state) { + if (state is ProfileAvatarStateLoaded && state.profile.user.profilePhotoUrl.isNotEmpty) { + return CircleAvatar( + backgroundImage: NetworkImage(state.profile.user.profilePhotoUrl), + radius: 16, + ); + } + return CircleAvatar( + radius: 16, + backgroundColor: Colors.black12, + ); + }, + ), + ), + ], + ), ), ); } diff --git a/lib/features/chat/presentation/widgets/chat_bubble_widget.dart b/lib/features/chat/presentation/widgets/chat_bubble_widget.dart index f65fb3bc..eeba8f1e 100644 --- a/lib/features/chat/presentation/widgets/chat_bubble_widget.dart +++ b/lib/features/chat/presentation/widgets/chat_bubble_widget.dart @@ -1,8 +1,7 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:dismissible_page/dismissible_page.dart'; -import 'package:eatvio_app/core/constants/constants.dart'; +import 'package:eatvio_app/core/app_export.dart'; import 'package:eatvio_app/features/chat/presentation/pages/photo_view_screen.dart'; -import 'package:eatvio_app/theme/app_decoration.dart'; import 'package:flutter/material.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -29,12 +28,17 @@ class ChatBubbleWidget extends StatelessWidget { child: DecoratedBox( decoration: BoxDecoration( color: isCurrentUser ? Color(0xFF7F9CF5) : Colors.white, - borderRadius: BorderRadiusStyle.circleBorder17, + borderRadius: mediaData.length > 0 + ? BorderRadius.circular(24) + : BorderRadius.horizontal( + left: isCurrentUser ? Radius.circular(32) : Radius.circular(16), + right: isCurrentUser ? Radius.circular(16) : Radius.circular(24), + ), ), child: Padding( - padding: const EdgeInsets.all(12), + padding: mediaData.length > 0 ? EdgeInsets.all(8) : EdgeInsets.only(top: 8, bottom: 8, left: isCurrentUser ? 16 : 8, right: isCurrentUser ? 8 : 16), child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + crossAxisAlignment: isCurrentUser ? CrossAxisAlignment.end : CrossAxisAlignment.start, children: [ if (mediaData.isNotEmpty) CustomScrollView( @@ -86,7 +90,7 @@ class ChatBubbleWidget extends StatelessWidget { tag: baseUrl + '/storage/' + '${mediaData[index]}', transitionOnUserGestures: true, child: ClipRRect( - borderRadius: BorderRadiusStyle.roundedBorder8, + borderRadius: BorderRadius.circular(16), child: CachedNetworkImage( imageUrl: baseUrl + '/storage/' + '${mediaData[index]}', ), @@ -103,10 +107,17 @@ class ChatBubbleWidget extends StatelessWidget { if (text.isNotEmpty) Text( text, - style: TextStyle( - color: isCurrentUser ? Colors.white : Color(0xFF323F4B), - ), + style: TextStyle(color: isCurrentUser ? Colors.white : Color(0xFF323F4B), height: 1), ), + SizedBox(height: 4), + Text( + DateTime.parse(sendTime).format('hh:mm'), + style: TextStyle( + color: isCurrentUser ? Colors.white.withOpacity(0.4) : Color(0xFF323F4B).withOpacity(0.4), + height: 1, + fontSize: 10, + ), + ), ], ), ), diff --git a/lib/features/chat/presentation/widgets/chat_search_bar_widget.dart b/lib/features/chat/presentation/widgets/chat_search_bar_widget.dart index 62199d0f..4889fdfd 100644 --- a/lib/features/chat/presentation/widgets/chat_search_bar_widget.dart +++ b/lib/features/chat/presentation/widgets/chat_search_bar_widget.dart @@ -1,5 +1,4 @@ import 'package:eatvio_app/core/app_export.dart'; -import 'package:eatvio_app/features/chat/presentation/bloc/chat_select_cubit/chat_select_cubit.dart'; import 'package:flutter/material.dart'; class ChatSearchBarWidget extends StatelessWidget { diff --git a/lib/features/profile/presentation/bloc/profile_cubit/profile_cubit.dart b/lib/features/profile/presentation/bloc/profile_cubit/profile_cubit.dart index a1ee1be7..34f6385e 100644 --- a/lib/features/profile/presentation/bloc/profile_cubit/profile_cubit.dart +++ b/lib/features/profile/presentation/bloc/profile_cubit/profile_cubit.dart @@ -30,4 +30,20 @@ class ProfileCubit extends Cubit { print(e); } } + + addCircumference({ + required int chestCircumference, + required int waistCircumference, + required int hipCircumference, + }) async { + try { + await profileRepository.addCircumference( + chestCircumference: chestCircumference, + waistCircumference: waistCircumference, + hipCircumference: hipCircumference, + ); + } catch (e) { + emit(ProfileState.error(errorMessage: e.toString())); + } + } } diff --git a/lib/features/profile/presentation/pages/profile_screen.dart b/lib/features/profile/presentation/pages/profile_screen.dart index d4cec48f..5bd5154a 100644 --- a/lib/features/profile/presentation/pages/profile_screen.dart +++ b/lib/features/profile/presentation/pages/profile_screen.dart @@ -1,46 +1,84 @@ import 'package:eatvio_app/core/app_export.dart'; import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart'; +import 'package:eatvio_app/features/profile/models/profile_model.dart'; import 'package:eatvio_app/features/profile/presentation/bloc/profile_cubit/profile_cubit.dart'; import 'package:eatvio_app/features/profile/presentation/bloc/profile_cubit/profile_state.dart'; import 'package:eatvio_app/locator_service.dart'; import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'package:syncfusion_flutter_charts/charts.dart'; -class ProfileScreen extends StatelessWidget { - final Author author; +class ProfileScreen extends StatefulWidget { + final Author? author; - const ProfileScreen({super.key, required this.author}); + const ProfileScreen({super.key, this.author}); + + @override + State createState() => _ProfileScreenState(); +} + +class _ProfileScreenState extends State { + List chartData = []; @override Widget build(BuildContext context) { return BlocProvider( - create: (BuildContext context) => sl()..getProfileBySlug(author.authorSlug), + create: (BuildContext context) { + if (widget.author == null) + return sl()..getMyProfile(); + else + return sl()..getProfileBySlug(widget.author!.authorSlug); + }, child: BlocBuilder( builder: (BuildContext context, ProfileState state) { if (state is ProfileStateLoaded) { + chartData = state.profile.circumferences; return Scaffold( appBar: AppBar( - centerTitle: true, - title: Text( - state.profile.user.name, - style: TextStyle( - color: Colors.black, - fontSize: 24, - fontWeight: FontWeight.w400, - height: 1, - ), - ), + centerTitle: false, + title: Text(state.profile.user.name), ), body: SingleChildScrollView( - padding: EdgeInsets.all(16), child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Center( + Padding( + padding: const EdgeInsets.only(left: 16, bottom: 32), child: CircleAvatar( - maxRadius: 128, - minRadius: 128, + radius: 32, backgroundImage: NetworkImage(state.profile.user.profilePhotoUrl), ), ), + SfCartesianChart( + margin: EdgeInsets.zero, + enableAxisAnimation: true, + enableSideBySideSeriesPlacement: true, + legend: const Legend( + isVisible: true, + opacity: 0.7, + position: LegendPosition.bottom, + ), + plotAreaBorderWidth: 0, + trackballBehavior: TrackballBehavior( + enable: true, + activationMode: ActivationMode.singleTap, + ), + primaryXAxis: DateTimeAxis( + dateFormat: DateFormat.MMMd('ru'), + axisLine: AxisLine( + width: 1, + ), + ), + primaryYAxis: NumericAxis( + labelFormat: '{value} см', + axisLine: AxisLine( + width: 1, + ), + majorTickLines: MajorTickLines(size: 0), + ), + series: _getSplineAreaSeries(), + tooltipBehavior: TooltipBehavior(enable: true), + ), ], ), ), @@ -67,4 +105,64 @@ class ProfileScreen extends StatelessWidget { ), ); } + + List> _getSplineAreaSeries() { + final Color seriesColor1 = Colors.red; + final Color seriesColor2 = Colors.blue; + final Color seriesColor3 = Colors.green; + + return >[ + SplineSeries( + markerSettings: MarkerSettings( + isVisible: true, + color: seriesColor1, + height: 12, + width: 12, + ), + dataLabelSettings: DataLabelSettings( + labelAlignment: ChartDataLabelAlignment.top, + isVisible: true, + ), + dataSource: chartData, + color: seriesColor1, + name: 'Грудь', + xValueMapper: (Circumference value, int index) => value.createdAt, + yValueMapper: (Circumference value, int index) => value.chestCircumference, + ), + SplineSeries( + markerSettings: MarkerSettings( + isVisible: true, + color: seriesColor2, + height: 12, + width: 12, + ), + dataLabelSettings: DataLabelSettings( + labelAlignment: ChartDataLabelAlignment.top, + isVisible: true, + ), + dataSource: chartData, + color: seriesColor2, + name: 'Талия', + xValueMapper: (Circumference value, int index) => value.createdAt, + yValueMapper: (Circumference value, int index) => value.waistCircumference, + ), + SplineSeries( + markerSettings: MarkerSettings( + isVisible: true, + color: seriesColor3, + height: 12, + width: 12, + ), + dataLabelSettings: DataLabelSettings( + labelAlignment: ChartDataLabelAlignment.top, + isVisible: true, + ), + dataSource: chartData, + color: seriesColor3, + name: 'Бёдра', + xValueMapper: (Circumference value, int index) => value.createdAt, + yValueMapper: (Circumference value, int index) => value.hipCircumference, + ), + ]; + } } diff --git a/lib/features/profile/repositories/profile_repository.dart b/lib/features/profile/repositories/profile_repository.dart index b9dbdf1e..a57be856 100644 --- a/lib/features/profile/repositories/profile_repository.dart +++ b/lib/features/profile/repositories/profile_repository.dart @@ -21,4 +21,22 @@ class ProfileRepository { rethrow; } } + + Future addCircumference({ + required int chestCircumference, + required int waistCircumference, + required int hipCircumference, + }) async { + try { + return (await profileService.addCircumference( + chestCircumference: chestCircumference, + waistCircumference: waistCircumference, + hipCircumference: hipCircumference, + )) + .values + .first; + } catch (e) { + rethrow; + } + } } diff --git a/lib/features/profile/services/profile_service.dart b/lib/features/profile/services/profile_service.dart index 5f5657b9..dc9f2864 100644 --- a/lib/features/profile/services/profile_service.dart +++ b/lib/features/profile/services/profile_service.dart @@ -15,4 +15,11 @@ abstract class ProfileService { @GET('/api/profile/index') Future getMyProfile(); + + @POST('/api/profile/addCircumference') + Future> addCircumference({ + @Part(name: 'chest_circumference') required int chestCircumference, + @Part(name: 'waist_circumference') required int waistCircumference, + @Part(name: 'hip_circumference') required int hipCircumference, + }); } diff --git a/lib/features/profile/services/profile_service.g.dart b/lib/features/profile/services/profile_service.g.dart index bc096fdf..7b2969ad 100644 --- a/lib/features/profile/services/profile_service.g.dart +++ b/lib/features/profile/services/profile_service.g.dart @@ -87,6 +87,56 @@ class _ProfileService implements ProfileService { return _value; } + @override + Future> addCircumference({ + required int chestCircumference, + required int waistCircumference, + required int hipCircumference, + }) async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + final _data = FormData(); + _data.fields.add(MapEntry( + 'chest_circumference', + chestCircumference.toString(), + )); + _data.fields.add(MapEntry( + 'waist_circumference', + waistCircumference.toString(), + )); + _data.fields.add(MapEntry( + 'hip_circumference', + hipCircumference.toString(), + )); + final _options = _setStreamType>(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/profile/addCircumference', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); + final _result = await _dio.fetch>(_options); + late Map _value; + try { + _value = _result.data!.map((k, dynamic v) => + MapEntry(k, Circumference.fromJson(v as Map))); + } on Object catch (e, s) { + errorLogger?.logError(e, s, _options); + rethrow; + } + return _value; + } + RequestOptions _setStreamType(RequestOptions requestOptions) { if (T != dynamic && !(requestOptions.responseType == ResponseType.bytes || diff --git a/lib/locator_service.dart b/lib/locator_service.dart index f0a28808..a73d21f1 100644 --- a/lib/locator_service.dart +++ b/lib/locator_service.dart @@ -3,6 +3,7 @@ import 'package:eatvio_app/core/constants/constants.dart'; import 'package:eatvio_app/core/initialization_cubit/initialization_cubit.dart'; import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/new_messages_cubit/new_messages_cubit.dart'; import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_cubit.dart'; +import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_cubit.dart'; import 'package:eatvio_app/features/calendar/presentation/bloc/calendar_cubit.dart'; import 'package:eatvio_app/features/calendar/repositories/calendar_repository.dart'; import 'package:eatvio_app/features/calendar/services/calendar_service.dart'; @@ -45,6 +46,7 @@ Future init() async { sl.registerFactory(() => DiaryBloc(diaryRepository: sl())); sl.registerFactory(() => CalendarCubit(calendarRepository: sl())); sl.registerFactory(() => ProfileCubit(profileRepository: sl())); + sl.registerFactory(() => ProfileAvatarCubit(profileRepository: sl())); sl.registerFactory(() => RecipeCreateCubit(recipeRepository: sl())); sl.registerFactory(() => DietsCubit(feedRepository: sl())); sl.registerFactory(() => CommentsCubit(feedRepository: sl())); diff --git a/lib/main.dart b/lib/main.dart index e031d6a6..a0867795 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,6 +3,7 @@ import 'package:eatvio_app/core/initialization_cubit/initialization_cubit.dart'; import 'package:eatvio_app/core/initialization_cubit/initialization_state.dart'; import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/new_messages_cubit/new_messages_cubit.dart'; import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_cubit.dart'; +import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_cubit.dart'; import 'package:eatvio_app/features/calendar/presentation/bloc/calendar_cubit.dart'; import 'package:eatvio_app/features/chat/presentation/bloc/chat_select_cubit/chat_select_cubit.dart'; import 'package:eatvio_app/features/diary/presentation/bloc/diary_bloc.dart'; @@ -42,6 +43,7 @@ class MyApp extends StatelessWidget { BlocProvider(create: (context) => sl()), BlocProvider(create: (context) => sl()), BlocProvider(create: (context) => sl()), + BlocProvider(create: (context) => sl()..getMyProfile()), BlocProvider(create: (context) => sl()..loadFeedBlogPostList()), BlocProvider(create: (context) => sl()..loadRecipesList()), BlocProvider(create: (context) => sl()..loadDiets()), diff --git a/lib/widgets/custom_navigation_menu.dart b/lib/widgets/custom_navigation_menu.dart index 4bc712d8..c3222e62 100644 --- a/lib/widgets/custom_navigation_menu.dart +++ b/lib/widgets/custom_navigation_menu.dart @@ -24,7 +24,7 @@ class CustomNavigationMenu extends StatelessWidget { onTap: () => GoRouter.of(context).push('/recipe-select-screen'), ), MenuItem( - icon: ImageConstant.icnVeggies, + icon: 'assets/icons/diets.svg', text: 'Мои диеты', onTap: () => GoRouter.of(context).push('/diet-select-screen'), ), @@ -34,7 +34,7 @@ class CustomNavigationMenu extends StatelessWidget { onTap: () => GoRouter.of(context).push('/plan-select-screen'), ), MenuItem( - icon: ImageConstant.icnPlans, + icon: 'assets/icons/calendar.svg', text: 'Календарь', onTap: () => GoRouter.of(context).push('/calendar-screen'), ), diff --git a/pubspec.yaml b/pubspec.yaml index e5f44648..514eb4a2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -42,7 +42,7 @@ dependencies: badges: ^3.1.2 google_fonts: ^6.2.1 location: ^6.0.2 - syncfusion_flutter_charts: ^26.2.10 + syncfusion_flutter_charts: ^26.2.11 table_calendar: ^3.1.2 flutter_keyboard_visibility: ^6.0.0 share_plus: ^10.0.0 @@ -65,3 +65,4 @@ flutter: - assets/ - assets/images/ - assets/audio/ + - assets/icons/