diff --git a/.DS_Store b/.DS_Store index 4bd8225b..b237a450 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml index cd6a3eae..e825f143 100644 --- a/.gitea/workflows/build.yml +++ b/.gitea/workflows/build.yml @@ -3,7 +3,7 @@ name: Eatvio App Android Test on: [ pull_request ] env: - flutter_version: "3.27.0" + flutter_version: "3.27.3" java_version: "21.x" flutter_channel: "stable" diff --git a/.gitea/workflows/docker-run-tests.yml b/.gitea/workflows/docker-run-tests.yml index 52b8e53c..4d7d972b 100644 --- a/.gitea/workflows/docker-run-tests.yml +++ b/.gitea/workflows/docker-run-tests.yml @@ -3,7 +3,7 @@ name: Eatvio App Android Test on custom docker on: [ pull_request ] env: - flutter_version: "3.27.0" + flutter_version: "3.27.3" java_version: "21.x" flutter_channel: "stable" my_local_cache_dir: "/opt/hostedtoolcache/" diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index b7b386f9..f72206e1 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -3,7 +3,7 @@ name: Eatvio App Android Test on: [ pull_request ] env: - flutter_version: "3.27.0" + flutter_version: "3.27.3" java_version: "21.x" flutter_channel: "stable" my_local_cache_dir: "/opt/hostedtoolcache/" diff --git a/lib/core/app_router.dart b/lib/core/app_router.dart index dc4f8c99..ff26e3bb 100644 --- a/lib/core/app_router.dart +++ b/lib/core/app_router.dart @@ -1,4 +1,4 @@ -import 'package:eatvio_app/core/initialization_cubit/initialization_cubit.dart'; +import 'package:eatvio_app/core/initialization_cubit/ws_manager.dart'; import 'package:eatvio_app/core/locator_service.dart'; import 'package:eatvio_app/core/token_storage.dart'; import 'package:eatvio_app/features/auth/auth_screen/auth_screen.dart'; @@ -15,6 +15,7 @@ import 'package:eatvio_app/features/consultant/become_consultant/presentation/pa import 'package:eatvio_app/features/create_diet/presentation/create_diet_screen.dart'; import 'package:eatvio_app/features/create_diet/presentation/diet_preview_screen.dart'; import 'package:eatvio_app/features/create_plan/presentation/create_plan_screen.dart'; +import 'package:eatvio_app/features/dev_tools/presentation/dev_tools_screen.dart'; import 'package:eatvio_app/features/diary/presentation/pages/diary_screen.dart'; import 'package:eatvio_app/features/diets/presentation/pages/about_diet_screen.dart'; import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart'; @@ -80,7 +81,7 @@ class AppRouter { path: '/my-profile-screen', name: 'myProfileScreen', redirect: (context, state) async { - await sl().runInitialization(); + await sl().initialize(); return null; }, pageBuilder: (context, state) => NoTransitionPage(child: ProfileScreen()), @@ -308,6 +309,11 @@ class AppRouter { slug: state.extra as String, ), ), + GoRoute( + path: DevToolsScreen.path, + name: DevToolsScreen.name, + builder: (context, state) => DevToolsScreen(), + ), ], ); } diff --git a/lib/core/const.dart b/lib/core/const.dart index 8eea1db0..4e8b3650 100644 --- a/lib/core/const.dart +++ b/lib/core/const.dart @@ -1,7 +1,11 @@ -String baseUrl = 'https://eatvio.ru'; -// String baseUrl = 'https://dev2.eatvio.com'; +// String baseUrl = 'https://eatvio.ru'; +String baseUrl = 'https://dev2.eatvio.com'; const List durationValues = [7, 14, 21]; const List dietTypeValues = ['veg', 'light', 'carb', 'meat']; const List planTypeValues = ['fit', 'slim', 'wellness', 'behavior']; + +const newMessagesChannelName = 'private-new-chat-messages'; +const newNotificationsChannelName = 'private-message-events'; +const directChatChannelName = 'private-direct-chat'; diff --git a/lib/core/initialization_cubit/initialization_cubit.dart b/lib/core/initialization_cubit/initialization_cubit.dart index 2bdc881f..e69de29b 100644 --- a/lib/core/initialization_cubit/initialization_cubit.dart +++ b/lib/core/initialization_cubit/initialization_cubit.dart @@ -1,105 +0,0 @@ -import 'package:dart_pusher_channels/dart_pusher_channels.dart'; -import 'package:eatvio_app/core/const.dart'; -import 'package:eatvio_app/core/initialization_cubit/initialization_state.dart'; -import 'package:eatvio_app/core/token_storage.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/chat/repositories/chat_repository.dart'; -import 'package:eatvio_app/core/locator_service.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; - -class InitializationCubit extends Cubit { - final ChatRepository chatRepository; - bool wasInitialized = false; - - InitializationCubit({required this.chatRepository}) : super(const InitializationState.loading()); - - Future subscribeNotifications(int userId, PusherChannelsClient client) async { - final privateNotificationChannel = await client.privateChannel( - 'private-message-events.$userId', - authorizationDelegate: EndpointAuthorizableChannelTokenAuthorizationDelegate.forPrivateChannel( - authorizationEndpoint: Uri.parse(baseUrl + '/broadcasting/auth'), - headers: { - 'Authorization': 'Bearer ${await TokenStorage.getTokenFromStorage()}', - }, - ), - ); - - privateNotificationChannel.subscribe(); - - privateNotificationChannel.bindToAll().listen((event) { - sl().incrementCounter(event.name); - }); - } - - Future subscribeChatMessages(int userId, PusherChannelsClient client) async { - final privateMessagesChannel = await client.privateChannel( - 'private-new-chat-messages.$userId', - authorizationDelegate: EndpointAuthorizableChannelTokenAuthorizationDelegate.forPrivateChannel( - authorizationEndpoint: Uri.parse(baseUrl + '/broadcasting/auth'), - headers: { - 'Authorization': 'Bearer ${await TokenStorage.getTokenFromStorage()}', - }, - ), - ); - - privateMessagesChannel.subscribe(); - - privateMessagesChannel.bindToAll().listen((event) { - sl().incrementCounter(); - }); - } - - Future runInitialization() async { - if (!wasInitialized) { - wasInitialized = true; - try { - await TokenStorage.haveTokenInStorage(); - final wsUrl = await chatRepository.getWebsocket(); - final options = PusherChannelsOptions.fromHost( - scheme: 'wss', - key: wsUrl.key, - host: wsUrl.host, - shouldSupplyMetadataQueries: true, - metadata: PusherChannelsOptionsMetadata.byDefault(), - port: 443, - ); - final client = PusherChannelsClient.websocket( - options: options, - connectionErrorHandler: (exception, trace, refresh) { - refresh(); - }, - minimumReconnectDelayDuration: const Duration( - seconds: 1, - ), - defaultActivityDuration: const Duration( - seconds: 120, - ), - activityDurationOverride: const Duration( - seconds: 120, - ), - waitForPongDuration: const Duration( - seconds: 30, - ), - ); - await client.connect(); - - await subscribeNotifications(wsUrl.userId, client); - await subscribeChatMessages(wsUrl.userId, client); - - emit( - InitializationState.success( - client: client, - ), - ); - } catch (e) { - emit( - InitializationState.error( - errorMessage: e.toString(), - ), - ); - rethrow; - } - } - } -} diff --git a/lib/core/initialization_cubit/initialization_state.dart b/lib/core/initialization_cubit/initialization_state.dart deleted file mode 100644 index 43318d07..00000000 --- a/lib/core/initialization_cubit/initialization_state.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'package:dart_pusher_channels/dart_pusher_channels.dart'; -import 'package:freezed_annotation/freezed_annotation.dart'; - -part 'initialization_state.freezed.dart'; - -@freezed -abstract class InitializationState with _$InitializationState { - const factory InitializationState() = _InitializationState; - - const factory InitializationState.loading() = InitializationStateLoading; - - const factory InitializationState.success({ - required PusherChannelsClient client, - }) = InitializationStateSuccess; - - const factory InitializationState.error({ - required String errorMessage, - }) = InitializationStateError; -} diff --git a/lib/core/initialization_cubit/initialization_state.freezed.dart b/lib/core/initialization_cubit/initialization_state.freezed.dart deleted file mode 100644 index b0535c68..00000000 --- a/lib/core/initialization_cubit/initialization_state.freezed.dart +++ /dev/null @@ -1,645 +0,0 @@ -// 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 'initialization_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 _$InitializationState { - @optionalTypeArgs - TResult when( - TResult Function() $default, { - required TResult Function() loading, - required TResult Function(PusherChannelsClient client) success, - required TResult Function(String errorMessage) error, - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult? whenOrNull( - TResult? Function()? $default, { - TResult? Function()? loading, - TResult? Function(PusherChannelsClient client)? success, - TResult? Function(String errorMessage)? error, - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult maybeWhen( - TResult Function()? $default, { - TResult Function()? loading, - TResult Function(PusherChannelsClient client)? success, - TResult Function(String errorMessage)? error, - required TResult orElse(), - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult map( - TResult Function(_InitializationState value) $default, { - required TResult Function(InitializationStateLoading value) loading, - required TResult Function(InitializationStateSuccess value) success, - required TResult Function(InitializationStateError value) error, - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult? mapOrNull( - TResult? Function(_InitializationState value)? $default, { - TResult? Function(InitializationStateLoading value)? loading, - TResult? Function(InitializationStateSuccess value)? success, - TResult? Function(InitializationStateError value)? error, - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult maybeMap( - TResult Function(_InitializationState value)? $default, { - TResult Function(InitializationStateLoading value)? loading, - TResult Function(InitializationStateSuccess value)? success, - TResult Function(InitializationStateError value)? error, - required TResult orElse(), - }) => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $InitializationStateCopyWith<$Res> { - factory $InitializationStateCopyWith( - InitializationState value, $Res Function(InitializationState) then) = - _$InitializationStateCopyWithImpl<$Res, InitializationState>; -} - -/// @nodoc -class _$InitializationStateCopyWithImpl<$Res, $Val extends InitializationState> - implements $InitializationStateCopyWith<$Res> { - _$InitializationStateCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - /// Create a copy of InitializationState - /// with the given fields replaced by the non-null parameter values. -} - -/// @nodoc -abstract class _$$InitializationStateImplCopyWith<$Res> { - factory _$$InitializationStateImplCopyWith(_$InitializationStateImpl value, - $Res Function(_$InitializationStateImpl) then) = - __$$InitializationStateImplCopyWithImpl<$Res>; -} - -/// @nodoc -class __$$InitializationStateImplCopyWithImpl<$Res> - extends _$InitializationStateCopyWithImpl<$Res, _$InitializationStateImpl> - implements _$$InitializationStateImplCopyWith<$Res> { - __$$InitializationStateImplCopyWithImpl(_$InitializationStateImpl _value, - $Res Function(_$InitializationStateImpl) _then) - : super(_value, _then); - - /// Create a copy of InitializationState - /// with the given fields replaced by the non-null parameter values. -} - -/// @nodoc - -class _$InitializationStateImpl implements _InitializationState { - const _$InitializationStateImpl(); - - @override - String toString() { - return 'InitializationState()'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$InitializationStateImpl); - } - - @override - int get hashCode => runtimeType.hashCode; - - @override - @optionalTypeArgs - TResult when( - TResult Function() $default, { - required TResult Function() loading, - required TResult Function(PusherChannelsClient client) success, - required TResult Function(String errorMessage) error, - }) { - return $default(); - } - - @override - @optionalTypeArgs - TResult? whenOrNull( - TResult? Function()? $default, { - TResult? Function()? loading, - TResult? Function(PusherChannelsClient client)? success, - TResult? Function(String errorMessage)? error, - }) { - return $default?.call(); - } - - @override - @optionalTypeArgs - TResult maybeWhen( - TResult Function()? $default, { - TResult Function()? loading, - TResult Function(PusherChannelsClient client)? success, - TResult Function(String errorMessage)? error, - required TResult orElse(), - }) { - if ($default != null) { - return $default(); - } - return orElse(); - } - - @override - @optionalTypeArgs - TResult map( - TResult Function(_InitializationState value) $default, { - required TResult Function(InitializationStateLoading value) loading, - required TResult Function(InitializationStateSuccess value) success, - required TResult Function(InitializationStateError value) error, - }) { - return $default(this); - } - - @override - @optionalTypeArgs - TResult? mapOrNull( - TResult? Function(_InitializationState value)? $default, { - TResult? Function(InitializationStateLoading value)? loading, - TResult? Function(InitializationStateSuccess value)? success, - TResult? Function(InitializationStateError value)? error, - }) { - return $default?.call(this); - } - - @override - @optionalTypeArgs - TResult maybeMap( - TResult Function(_InitializationState value)? $default, { - TResult Function(InitializationStateLoading value)? loading, - TResult Function(InitializationStateSuccess value)? success, - TResult Function(InitializationStateError value)? error, - required TResult orElse(), - }) { - if ($default != null) { - return $default(this); - } - return orElse(); - } -} - -abstract class _InitializationState implements InitializationState { - const factory _InitializationState() = _$InitializationStateImpl; -} - -/// @nodoc -abstract class _$$InitializationStateLoadingImplCopyWith<$Res> { - factory _$$InitializationStateLoadingImplCopyWith( - _$InitializationStateLoadingImpl value, - $Res Function(_$InitializationStateLoadingImpl) then) = - __$$InitializationStateLoadingImplCopyWithImpl<$Res>; -} - -/// @nodoc -class __$$InitializationStateLoadingImplCopyWithImpl<$Res> - extends _$InitializationStateCopyWithImpl<$Res, - _$InitializationStateLoadingImpl> - implements _$$InitializationStateLoadingImplCopyWith<$Res> { - __$$InitializationStateLoadingImplCopyWithImpl( - _$InitializationStateLoadingImpl _value, - $Res Function(_$InitializationStateLoadingImpl) _then) - : super(_value, _then); - - /// Create a copy of InitializationState - /// with the given fields replaced by the non-null parameter values. -} - -/// @nodoc - -class _$InitializationStateLoadingImpl implements InitializationStateLoading { - const _$InitializationStateLoadingImpl(); - - @override - String toString() { - return 'InitializationState.loading()'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$InitializationStateLoadingImpl); - } - - @override - int get hashCode => runtimeType.hashCode; - - @override - @optionalTypeArgs - TResult when( - TResult Function() $default, { - required TResult Function() loading, - required TResult Function(PusherChannelsClient client) success, - required TResult Function(String errorMessage) error, - }) { - return loading(); - } - - @override - @optionalTypeArgs - TResult? whenOrNull( - TResult? Function()? $default, { - TResult? Function()? loading, - TResult? Function(PusherChannelsClient client)? success, - TResult? Function(String errorMessage)? error, - }) { - return loading?.call(); - } - - @override - @optionalTypeArgs - TResult maybeWhen( - TResult Function()? $default, { - TResult Function()? loading, - TResult Function(PusherChannelsClient client)? success, - TResult Function(String errorMessage)? error, - required TResult orElse(), - }) { - if (loading != null) { - return loading(); - } - return orElse(); - } - - @override - @optionalTypeArgs - TResult map( - TResult Function(_InitializationState value) $default, { - required TResult Function(InitializationStateLoading value) loading, - required TResult Function(InitializationStateSuccess value) success, - required TResult Function(InitializationStateError value) error, - }) { - return loading(this); - } - - @override - @optionalTypeArgs - TResult? mapOrNull( - TResult? Function(_InitializationState value)? $default, { - TResult? Function(InitializationStateLoading value)? loading, - TResult? Function(InitializationStateSuccess value)? success, - TResult? Function(InitializationStateError value)? error, - }) { - return loading?.call(this); - } - - @override - @optionalTypeArgs - TResult maybeMap( - TResult Function(_InitializationState value)? $default, { - TResult Function(InitializationStateLoading value)? loading, - TResult Function(InitializationStateSuccess value)? success, - TResult Function(InitializationStateError value)? error, - required TResult orElse(), - }) { - if (loading != null) { - return loading(this); - } - return orElse(); - } -} - -abstract class InitializationStateLoading implements InitializationState { - const factory InitializationStateLoading() = _$InitializationStateLoadingImpl; -} - -/// @nodoc -abstract class _$$InitializationStateSuccessImplCopyWith<$Res> { - factory _$$InitializationStateSuccessImplCopyWith( - _$InitializationStateSuccessImpl value, - $Res Function(_$InitializationStateSuccessImpl) then) = - __$$InitializationStateSuccessImplCopyWithImpl<$Res>; - @useResult - $Res call({PusherChannelsClient client}); -} - -/// @nodoc -class __$$InitializationStateSuccessImplCopyWithImpl<$Res> - extends _$InitializationStateCopyWithImpl<$Res, - _$InitializationStateSuccessImpl> - implements _$$InitializationStateSuccessImplCopyWith<$Res> { - __$$InitializationStateSuccessImplCopyWithImpl( - _$InitializationStateSuccessImpl _value, - $Res Function(_$InitializationStateSuccessImpl) _then) - : super(_value, _then); - - /// Create a copy of InitializationState - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? client = null, - }) { - return _then(_$InitializationStateSuccessImpl( - client: null == client - ? _value.client - : client // ignore: cast_nullable_to_non_nullable - as PusherChannelsClient, - )); - } -} - -/// @nodoc - -class _$InitializationStateSuccessImpl implements InitializationStateSuccess { - const _$InitializationStateSuccessImpl({required this.client}); - - @override - final PusherChannelsClient client; - - @override - String toString() { - return 'InitializationState.success(client: $client)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$InitializationStateSuccessImpl && - (identical(other.client, client) || other.client == client)); - } - - @override - int get hashCode => Object.hash(runtimeType, client); - - /// Create a copy of InitializationState - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - @override - @pragma('vm:prefer-inline') - _$$InitializationStateSuccessImplCopyWith<_$InitializationStateSuccessImpl> - get copyWith => __$$InitializationStateSuccessImplCopyWithImpl< - _$InitializationStateSuccessImpl>(this, _$identity); - - @override - @optionalTypeArgs - TResult when( - TResult Function() $default, { - required TResult Function() loading, - required TResult Function(PusherChannelsClient client) success, - required TResult Function(String errorMessage) error, - }) { - return success(client); - } - - @override - @optionalTypeArgs - TResult? whenOrNull( - TResult? Function()? $default, { - TResult? Function()? loading, - TResult? Function(PusherChannelsClient client)? success, - TResult? Function(String errorMessage)? error, - }) { - return success?.call(client); - } - - @override - @optionalTypeArgs - TResult maybeWhen( - TResult Function()? $default, { - TResult Function()? loading, - TResult Function(PusherChannelsClient client)? success, - TResult Function(String errorMessage)? error, - required TResult orElse(), - }) { - if (success != null) { - return success(client); - } - return orElse(); - } - - @override - @optionalTypeArgs - TResult map( - TResult Function(_InitializationState value) $default, { - required TResult Function(InitializationStateLoading value) loading, - required TResult Function(InitializationStateSuccess value) success, - required TResult Function(InitializationStateError value) error, - }) { - return success(this); - } - - @override - @optionalTypeArgs - TResult? mapOrNull( - TResult? Function(_InitializationState value)? $default, { - TResult? Function(InitializationStateLoading value)? loading, - TResult? Function(InitializationStateSuccess value)? success, - TResult? Function(InitializationStateError value)? error, - }) { - return success?.call(this); - } - - @override - @optionalTypeArgs - TResult maybeMap( - TResult Function(_InitializationState value)? $default, { - TResult Function(InitializationStateLoading value)? loading, - TResult Function(InitializationStateSuccess value)? success, - TResult Function(InitializationStateError value)? error, - required TResult orElse(), - }) { - if (success != null) { - return success(this); - } - return orElse(); - } -} - -abstract class InitializationStateSuccess implements InitializationState { - const factory InitializationStateSuccess( - {required final PusherChannelsClient client}) = - _$InitializationStateSuccessImpl; - - PusherChannelsClient get client; - - /// Create a copy of InitializationState - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - _$$InitializationStateSuccessImplCopyWith<_$InitializationStateSuccessImpl> - get copyWith => throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class _$$InitializationStateErrorImplCopyWith<$Res> { - factory _$$InitializationStateErrorImplCopyWith( - _$InitializationStateErrorImpl value, - $Res Function(_$InitializationStateErrorImpl) then) = - __$$InitializationStateErrorImplCopyWithImpl<$Res>; - @useResult - $Res call({String errorMessage}); -} - -/// @nodoc -class __$$InitializationStateErrorImplCopyWithImpl<$Res> - extends _$InitializationStateCopyWithImpl<$Res, - _$InitializationStateErrorImpl> - implements _$$InitializationStateErrorImplCopyWith<$Res> { - __$$InitializationStateErrorImplCopyWithImpl( - _$InitializationStateErrorImpl _value, - $Res Function(_$InitializationStateErrorImpl) _then) - : super(_value, _then); - - /// Create a copy of InitializationState - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? errorMessage = null, - }) { - return _then(_$InitializationStateErrorImpl( - errorMessage: null == errorMessage - ? _value.errorMessage - : errorMessage // ignore: cast_nullable_to_non_nullable - as String, - )); - } -} - -/// @nodoc - -class _$InitializationStateErrorImpl implements InitializationStateError { - const _$InitializationStateErrorImpl({required this.errorMessage}); - - @override - final String errorMessage; - - @override - String toString() { - return 'InitializationState.error(errorMessage: $errorMessage)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$InitializationStateErrorImpl && - (identical(other.errorMessage, errorMessage) || - other.errorMessage == errorMessage)); - } - - @override - int get hashCode => Object.hash(runtimeType, errorMessage); - - /// Create a copy of InitializationState - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - @override - @pragma('vm:prefer-inline') - _$$InitializationStateErrorImplCopyWith<_$InitializationStateErrorImpl> - get copyWith => __$$InitializationStateErrorImplCopyWithImpl< - _$InitializationStateErrorImpl>(this, _$identity); - - @override - @optionalTypeArgs - TResult when( - TResult Function() $default, { - required TResult Function() loading, - required TResult Function(PusherChannelsClient client) success, - required TResult Function(String errorMessage) error, - }) { - return error(errorMessage); - } - - @override - @optionalTypeArgs - TResult? whenOrNull( - TResult? Function()? $default, { - TResult? Function()? loading, - TResult? Function(PusherChannelsClient client)? success, - TResult? Function(String errorMessage)? error, - }) { - return error?.call(errorMessage); - } - - @override - @optionalTypeArgs - TResult maybeWhen( - TResult Function()? $default, { - TResult Function()? loading, - TResult Function(PusherChannelsClient client)? success, - TResult Function(String errorMessage)? error, - required TResult orElse(), - }) { - if (error != null) { - return error(errorMessage); - } - return orElse(); - } - - @override - @optionalTypeArgs - TResult map( - TResult Function(_InitializationState value) $default, { - required TResult Function(InitializationStateLoading value) loading, - required TResult Function(InitializationStateSuccess value) success, - required TResult Function(InitializationStateError value) error, - }) { - return error(this); - } - - @override - @optionalTypeArgs - TResult? mapOrNull( - TResult? Function(_InitializationState value)? $default, { - TResult? Function(InitializationStateLoading value)? loading, - TResult? Function(InitializationStateSuccess value)? success, - TResult? Function(InitializationStateError value)? error, - }) { - return error?.call(this); - } - - @override - @optionalTypeArgs - TResult maybeMap( - TResult Function(_InitializationState value)? $default, { - TResult Function(InitializationStateLoading value)? loading, - TResult Function(InitializationStateSuccess value)? success, - TResult Function(InitializationStateError value)? error, - required TResult orElse(), - }) { - if (error != null) { - return error(this); - } - return orElse(); - } -} - -abstract class InitializationStateError implements InitializationState { - const factory InitializationStateError({required final String errorMessage}) = - _$InitializationStateErrorImpl; - - String get errorMessage; - - /// Create a copy of InitializationState - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - _$$InitializationStateErrorImplCopyWith<_$InitializationStateErrorImpl> - get copyWith => throw _privateConstructorUsedError; -} diff --git a/lib/core/initialization_cubit/ws_manager.dart b/lib/core/initialization_cubit/ws_manager.dart new file mode 100644 index 00000000..3a72512e --- /dev/null +++ b/lib/core/initialization_cubit/ws_manager.dart @@ -0,0 +1,139 @@ +import 'dart:developer'; + +import 'package:dart_pusher_channels/dart_pusher_channels.dart'; +import 'package:eatvio_app/core/const.dart'; +import 'package:eatvio_app/core/initialization_cubit/ws_service.dart'; +import 'package:eatvio_app/core/token_storage.dart'; + +class WsManager { + final WsService wsService; + + WsManager({required this.wsService}); + + PusherChannelsClient? client; + int? userId; + + PrivateChannel? _privateNotificationChannel; + PrivateChannel? _privateMessagesChannel; + PrivateChannel? _privateDirectChatChannel; + + Stream? get newMessagesStream => _privateMessagesChannel?.bind('App\\Events\\ChatMessageUpdated'); + + // TODO: change name of event to a right one + Stream? get newNotificationsStream => _privateNotificationChannel?.bind('App\\Events\\ChatMessageUpdated'); + + Stream? get directChatStream => _privateDirectChatChannel?.bind('App\\Events\\ChatMessageUpdated'); + + Stream? get clientTypingStream => _privateDirectChatChannel?.bind('client-typing'); + + Future initialize() async { + if (this.client == null) { + try { + await TokenStorage.haveTokenInStorage(); + final wsUrl = await wsService.getWebsocket(); + + final options = PusherChannelsOptions.fromHost( + scheme: 'wss', + key: wsUrl.key, + host: wsUrl.host, + shouldSupplyMetadataQueries: true, + metadata: PusherChannelsOptionsMetadata.byDefault(), + port: 443, + ); + client = PusherChannelsClient.websocket( + options: options, + connectionErrorHandler: (exception, trace, refresh) { + refresh(); + }, + minimumReconnectDelayDuration: const Duration( + seconds: 1, + ), + defaultActivityDuration: const Duration( + seconds: 30, + ), + waitForPongDuration: const Duration( + seconds: 30, + ), + ); + + await client?.connect(); + + this.client = client; + userId = wsUrl.userId; + + await _initPrivateNotificationsChannel(); + await _initPrivateMessagesChannel(); + + client?.lifecycleStream.listen((data) { + if (data == PusherChannelsClientLifeCycleState.establishedConnection) { + _unsubscribe(); + _subscribe(); + } + }); + client?.eventStream.listen((event) { + log(event.rootObject.toString()); + }); + _subscribe(); + } catch (e, st) { + log(e.toString(), stackTrace: st); + } + } + } + + Future _initPrivateNotificationsChannel() async { + final token = await TokenStorage.getTokenFromStorage(); + _privateNotificationChannel = await client?.privateChannel( + '$newNotificationsChannelName.$userId', + authorizationDelegate: EndpointAuthorizableChannelTokenAuthorizationDelegate.forPrivateChannel( + authorizationEndpoint: Uri.parse(baseUrl + '/broadcasting/auth'), + headers: { + 'Authorization': 'Bearer $token', + }, + ), + ); + } + + Future _initPrivateMessagesChannel() async { + final token = await TokenStorage.getTokenFromStorage(); + _privateMessagesChannel = await client?.privateChannel( + '$newMessagesChannelName.$userId', + authorizationDelegate: EndpointAuthorizableChannelTokenAuthorizationDelegate.forPrivateChannel( + authorizationEndpoint: Uri.parse(baseUrl + '/broadcasting/auth'), + headers: { + 'Authorization': 'Bearer $token', + }, + ), + ); + } + + Future initPrivateDirectChatChannel(String chatId) async { + final token = await TokenStorage.getTokenFromStorage(); + _privateDirectChatChannel = await client?.privateChannel( + '$directChatChannelName.$chatId', + authorizationDelegate: EndpointAuthorizableChannelTokenAuthorizationDelegate.forPrivateChannel( + authorizationEndpoint: Uri.parse(baseUrl + '/broadcasting/auth'), + headers: { + 'Authorization': 'Bearer $token', + }, + ), + ); + } + + void _subscribe() { + _privateMessagesChannel?.subscribe(); + _privateNotificationChannel?.subscribe(); + } + + void _unsubscribe() { + _privateMessagesChannel?.unsubscribe(); + _privateNotificationChannel?.unsubscribe(); + } + + void subscribeDirectChatChannel() { + _privateDirectChatChannel?.subscribe(); + } + + void unsubscribeDirectChatChannel() { + _privateDirectChatChannel?.unsubscribe(); + } +} diff --git a/lib/core/initialization_cubit/ws_service.dart b/lib/core/initialization_cubit/ws_service.dart new file mode 100644 index 00000000..92d326f0 --- /dev/null +++ b/lib/core/initialization_cubit/ws_service.dart @@ -0,0 +1,15 @@ +import 'package:dio/dio.dart'; +import 'package:eatvio_app/features/chat/models/websocket_info_model.dart'; +import 'package:retrofit/retrofit.dart'; + +part 'ws_service.g.dart'; + + +@RestApi() +abstract class WsService { + + factory WsService(Dio dio, {String baseUrl}) = _WsService; + + @GET('/api/profile/ws/params') + Future getWebsocket(); +} \ No newline at end of file diff --git a/lib/core/initialization_cubit/ws_service.g.dart b/lib/core/initialization_cubit/ws_service.g.dart new file mode 100644 index 00000000..c5a42eeb --- /dev/null +++ b/lib/core/initialization_cubit/ws_service.g.dart @@ -0,0 +1,86 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'ws_service.dart'; + +// ************************************************************************** +// RetrofitGenerator +// ************************************************************************** + +// ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element,unnecessary_string_interpolations + +class _WsService implements WsService { + _WsService( + this._dio, { + this.baseUrl, + this.errorLogger, + }); + + final Dio _dio; + + String? baseUrl; + + final ParseErrorLogger? errorLogger; + + @override + Future getWebsocket() async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + const Map? _data = null; + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/profile/ws/params', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); + final _result = await _dio.fetch>(_options); + late WebsocketInfoModel _value; + try { + _value = WebsocketInfoModel.fromJson(_result.data!); + } on Object catch (e, s) { + errorLogger?.logError(e, s, _options); + rethrow; + } + return _value; + } + + RequestOptions _setStreamType(RequestOptions requestOptions) { + if (T != dynamic && + !(requestOptions.responseType == ResponseType.bytes || + requestOptions.responseType == ResponseType.stream)) { + if (T == String) { + requestOptions.responseType = ResponseType.plain; + } else { + requestOptions.responseType = ResponseType.json; + } + } + return requestOptions; + } + + String _combineBaseUrls( + String dioBaseUrl, + String? baseUrl, + ) { + if (baseUrl == null || baseUrl.trim().isEmpty) { + return dioBaseUrl; + } + + final url = Uri.parse(baseUrl); + + if (url.isAbsolute) { + return url.toString(); + } + + return Uri.parse(dioBaseUrl).resolveUri(url).toString(); + } +} diff --git a/lib/core/locator_service.dart b/lib/core/locator_service.dart index 4787fbff..6c62f438 100644 --- a/lib/core/locator_service.dart +++ b/lib/core/locator_service.dart @@ -1,12 +1,13 @@ import 'package:dio/dio.dart'; import 'package:eatvio_app/core/const.dart'; +import 'package:eatvio_app/core/initialization_cubit/ws_manager.dart'; +import 'package:eatvio_app/core/initialization_cubit/ws_service.dart'; import 'package:eatvio_app/features/create_diet/presentation/cubit/create_diet_cubit.dart'; import 'package:eatvio_app/features/create_diet/repositories/create_diet_repository.dart'; import 'package:eatvio_app/features/create_diet/services/create_diet_service.dart'; import 'package:eatvio_app/features/create_plan/presentation/cubit/create_plan_cubit.dart'; import 'package:eatvio_app/features/diets/repositories/diet_repository.dart'; import 'package:eatvio_app/features/diets/services/diet_service.dart'; -import 'package:eatvio_app/core/initialization_cubit/initialization_cubit.dart'; import 'package:eatvio_app/features/blog_post_create/bloc/blog_post_create_cubit/blog_post_create_cubit.dart'; import 'package:eatvio_app/features/blog_post_create/repositories/blog_post_repository.dart'; import 'package:eatvio_app/features/blog_post_create/services/blog_post_service.dart'; @@ -70,15 +71,15 @@ final sl = GetIt.instance; Future init() async { // Cubit singletons - sl.registerLazySingleton(() => InitializationCubit(chatRepository: sl())); + sl.registerLazySingleton(() => WsManager(wsService: sl())); sl.registerLazySingleton(() => NewMessagesCubit()); - sl.registerLazySingleton(() => NotificationsCubit()); + sl.registerLazySingleton(() => NotificationsCubit(wsManager: sl())); sl.registerLazySingleton(() => FeedCubit(feedRepository: sl())); sl.registerLazySingleton(() => ProfileAvatarCubit(profileRepository: sl())); // Cubit factories sl.registerFactory(() => RegistrationCubit(registrationRepository: sl())); - sl.registerFactory(() => ChatRoomCubit(chatRepository: sl(), initializationCubit: sl())); + sl.registerFactory(() => ChatRoomCubit(chatRepository: sl(), wsManager: sl())); sl.registerFactory(() => RecipesCubit(feedRepository: sl(), recipeRepository: sl())); sl.registerFactory(() => CalendarCubit(calendarRepository: sl())); sl.registerFactory(() => ProfileCubit(profileRepository: sl(), chatRepository: sl())); @@ -140,6 +141,7 @@ Future init() async { sl.registerLazySingleton(() => PlanService(sl())); sl.registerLazySingleton(() => MyDietsService(sl())); sl.registerLazySingleton(() => MyPlansService(sl())); + sl.registerLazySingleton(() => WsService(sl())); // External sl.registerLazySingleton( diff --git a/lib/core/theme/custom_text_style.dart b/lib/core/theme/custom_text_style.dart index a4e2539d..6837e186 100644 --- a/lib/core/theme/custom_text_style.dart +++ b/lib/core/theme/custom_text_style.dart @@ -220,6 +220,12 @@ abstract class TextStyles { height: 1.255, ); + static const textFS13FW400 = TextStyle( + fontSize: 14, + fontWeight: FontWeight.w400, + height: 1.255, + ); + static const textXSSemibold = TextStyle( fontSize: 12, fontWeight: FontWeight.w500, diff --git a/lib/core/theme/theme_helper.dart b/lib/core/theme/theme_helper.dart index 615e33df..5abec056 100644 --- a/lib/core/theme/theme_helper.dart +++ b/lib/core/theme/theme_helper.dart @@ -186,6 +186,8 @@ class PrimaryColors { Color get red => Color(0xFFCD4141); Color get transparentBlack => Color(0xFF1313264).withValues(alpha: 0.3); + + Color get gray60004 => Color(0xFFD4DAE2).withValues(alpha: 0.2); } PrimaryColors get appTheme => ThemeHelper().themeColor(); diff --git a/lib/core/utils/toasts.dart b/lib/core/utils/toasts.dart index 2730d6ce..7a0f3db9 100644 --- a/lib/core/utils/toasts.dart +++ b/lib/core/utils/toasts.dart @@ -26,3 +26,15 @@ void showErrorToast(String message) { fontSize: 16.0, ); } + +void showSuccessToast(String message) { + Fluttertoast.showToast( + msg: message, + toastLength: Toast.LENGTH_SHORT, + gravity: ToastGravity.TOP, + timeInSecForIosWeb: _toastDuration, + backgroundColor: appTheme.greenA70001, + textColor: appTheme.whiteA700, + fontSize: 16.0, + ); +} \ No newline at end of file diff --git a/lib/features/blog_post_create/services/blog_post_service.g.dart b/lib/features/blog_post_create/services/blog_post_service.g.dart index 1f338526..33f4251a 100644 --- a/lib/features/blog_post_create/services/blog_post_service.g.dart +++ b/lib/features/blog_post_create/services/blog_post_service.g.dart @@ -9,7 +9,11 @@ part of 'blog_post_service.dart'; // ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element,unnecessary_string_interpolations class _BlogPostService implements BlogPostService { - _BlogPostService(this._dio, {this.baseUrl, this.errorLogger}); + _BlogPostService( + this._dio, { + this.baseUrl, + this.errorLogger, + }); final Dio _dio; @@ -23,21 +27,23 @@ class _BlogPostService implements BlogPostService { final queryParameters = {}; final _headers = {}; final _data = formData; - final _options = _setStreamType( - Options( - method: 'POST', - headers: _headers, - extra: _extra, - contentType: 'multipart/form-data', - ) - .compose( - _dio.options, - '/api/blogPosts/create', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + contentType: 'multipart/form-data', + ) + .compose( + _dio.options, + '/api/blogPosts/create', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } @@ -50,21 +56,23 @@ class _BlogPostService implements BlogPostService { final queryParameters = {}; final _headers = {}; final _data = formData; - final _options = _setStreamType( - Options( - method: 'POST', - headers: _headers, - extra: _extra, - contentType: 'multipart/form-data', - ) - .compose( - _dio.options, - '/api/blogPosts/update/${id}', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + contentType: 'multipart/form-data', + ) + .compose( + _dio.options, + '/api/blogPosts/update/${id}', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } @@ -74,16 +82,22 @@ class _BlogPostService implements BlogPostService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'POST', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/blogPosts/delete/${id}', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/blogPosts/delete/${id}', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } @@ -100,7 +114,10 @@ class _BlogPostService implements BlogPostService { return requestOptions; } - String _combineBaseUrls(String dioBaseUrl, String? baseUrl) { + String _combineBaseUrls( + String dioBaseUrl, + String? baseUrl, + ) { if (baseUrl == null || baseUrl.trim().isEmpty) { return dioBaseUrl; } diff --git a/lib/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_cubit.dart b/lib/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_cubit.dart index d862efa7..5d9a27f6 100644 --- a/lib/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_cubit.dart +++ b/lib/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_cubit.dart @@ -1,11 +1,16 @@ +import 'package:eatvio_app/core/initialization_cubit/ws_manager.dart'; import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_state.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; class NotificationsCubit extends Cubit { int _notificationsCount = 0; List notifications = []; - - NotificationsCubit() : super(const NotificationsState.empty()); + final WsManager wsManager; + NotificationsCubit({required this.wsManager}) : super(const NotificationsState.empty()) { + wsManager.newNotificationsStream?.listen((event) { + incrementCounter(event.data); + }); + } incrementCounter(String data) { _notificationsCount++; diff --git a/lib/features/calendar/services/calendar_service.g.dart b/lib/features/calendar/services/calendar_service.g.dart index 5055d002..787983c8 100644 --- a/lib/features/calendar/services/calendar_service.g.dart +++ b/lib/features/calendar/services/calendar_service.g.dart @@ -9,7 +9,11 @@ part of 'calendar_service.dart'; // ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element,unnecessary_string_interpolations class _CalendarService implements CalendarService { - _CalendarService(this._dio, {this.baseUrl, this.errorLogger}); + _CalendarService( + this._dio, { + this.baseUrl, + this.errorLogger, + }); final Dio _dio; @@ -23,23 +27,27 @@ class _CalendarService implements CalendarService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType>( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/calendar/index', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType>(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/calendar/index', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late List _value; try { _value = _result.data! - .map( - (dynamic i) => CalendarModel.fromJson(i as Map), - ) + .map((dynamic i) => CalendarModel.fromJson(i as Map)) .toList(); } on Object catch (e, s) { errorLogger?.logError(e, s, _options); @@ -61,7 +69,10 @@ class _CalendarService implements CalendarService { return requestOptions; } - String _combineBaseUrls(String dioBaseUrl, String? baseUrl) { + String _combineBaseUrls( + String dioBaseUrl, + String? baseUrl, + ) { if (baseUrl == null || baseUrl.trim().isEmpty) { return dioBaseUrl; } diff --git a/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_cubit.dart b/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_cubit.dart index 194f4da9..a072ad50 100644 --- a/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_cubit.dart +++ b/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_cubit.dart @@ -2,13 +2,9 @@ import 'dart:convert'; import 'dart:io'; import 'package:audioplayers/audioplayers.dart'; -import 'package:dart_pusher_channels/dart_pusher_channels.dart'; import 'package:easy_debounce/easy_debounce.dart'; -import 'package:eatvio_app/core/const.dart'; import 'package:eatvio_app/core/image_compressing/image_compress_utility.dart'; -import 'package:eatvio_app/core/initialization_cubit/initialization_cubit.dart'; -import 'package:eatvio_app/core/initialization_cubit/initialization_state.dart'; -import 'package:eatvio_app/core/token_storage.dart'; +import 'package:eatvio_app/core/initialization_cubit/ws_manager.dart'; import 'package:eatvio_app/features/chat/models/chat_message_model.dart'; import 'package:eatvio_app/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.dart'; import 'package:eatvio_app/features/chat/repositories/chat_repository.dart'; @@ -16,41 +12,42 @@ import 'package:flutter_bloc/flutter_bloc.dart'; class ChatRoomCubit extends Cubit { final ChatRepository chatRepository; - final InitializationCubit initializationCubit; + final WsManager wsManager; int currentPage = 1; late final int lastPage; bool isLoading = false; - late final PusherChannelsClient client; - late final PrivateChannel privateChatChannel; - ChatRoomCubit({ required this.chatRepository, - required this.initializationCubit, + required this.wsManager, }) : super(ChatRoomState.loading()); loadNextPage(String chatId) async { if (currentPage < lastPage && !isLoading) { isLoading = true; - emit(ChatRoomState.loaded( - chatRoom: (state as ChatRoomStateLoaded).chatRoom, - chatMessages: (state as ChatRoomStateLoaded).chatMessages, - isTyping: (state as ChatRoomStateLoaded).isTyping, - isLoading: isLoading, - ),); + emit( + ChatRoomState.loaded( + chatRoom: (state as ChatRoomStateLoaded).chatRoom, + chatMessages: (state as ChatRoomStateLoaded).chatMessages, + isTyping: (state as ChatRoomStateLoaded).isTyping, + isLoading: isLoading, + ), + ); try { final chatMessages = await chatRepository.getChatMessages(chatId, currentPage + 1); isLoading = false; - emit(ChatRoomState.loaded( - chatRoom: (state as ChatRoomStateLoaded).chatRoom, - chatMessages: [...(state as ChatRoomStateLoaded).chatMessages, ...chatMessages.messagesList], - isTyping: (state as ChatRoomStateLoaded).isTyping, - isLoading: isLoading, - ),); + emit( + ChatRoomState.loaded( + chatRoom: (state as ChatRoomStateLoaded).chatRoom, + chatMessages: [...(state as ChatRoomStateLoaded).chatMessages, ...chatMessages.messagesList], + isTyping: (state as ChatRoomStateLoaded).isTyping, + isLoading: isLoading, + ), + ); currentPage++; } catch (e) { @@ -66,38 +63,29 @@ class ChatRoomCubit extends Cubit { final chatMessages = await chatRepository.getChatMessages(chatId, currentPage); lastPage = chatMessages.meta.lastPage; - await _subscribeToChatChannel(initCubit: initializationCubit, chatId: chatId); + await _subscribeToChatChannel(chatId: chatId); - emit(ChatRoomState.loaded( - chatRoom: chatRoom, - chatMessages: chatMessages.messagesList, - isTyping: false, - isLoading: isLoading, - ),); + emit( + ChatRoomState.loaded( + chatRoom: chatRoom, + chatMessages: chatMessages.messagesList, + isTyping: false, + isLoading: isLoading, + ), + ); } catch (e) { emit(ChatRoomState.error(errorMessage: 'Ошибка получеия данных')); } } Future _subscribeToChatChannel({ - required InitializationCubit initCubit, required String chatId, }) async { - client = (initCubit.state as InitializationStateSuccess).client; - - privateChatChannel = await client.privateChannel( - 'private-direct-chat.$chatId', - authorizationDelegate: EndpointAuthorizableChannelTokenAuthorizationDelegate.forPrivateChannel( - authorizationEndpoint: Uri.parse(baseUrl + '/broadcasting/auth'), - headers: { - 'Authorization': 'Bearer ${await TokenStorage.getTokenFromStorage()}', - }, - ), - ); - - privateChatChannel.subscribe(); - - privateChatChannel.bind('App\\Events\\ChatMessageUpdated').listen((event) { + final client = wsManager.client; + if (client == null) return; + await wsManager.initPrivateDirectChatChannel(chatId); + wsManager.subscribeDirectChatChannel(); + wsManager.directChatStream?.listen((event) { AudioPlayer().play((AssetSource('audio/recive_message.wav'))); List messagesList = [ ChatMessageModel.fromJson(jsonDecode(event.data)['message']), @@ -113,7 +101,7 @@ class ChatRoomCubit extends Cubit { ); }); - privateChatChannel.bind('client-typing').listen((event) { + wsManager.clientTypingStream?.listen((event) { emit( ChatRoomState.loaded( chatRoom: (state as ChatRoomStateLoaded).chatRoom, @@ -152,7 +140,7 @@ class ChatRoomCubit extends Cubit { @override Future close() async { - privateChatChannel.unsubscribe(); + wsManager.unsubscribeDirectChatChannel(); super.close(); } } diff --git a/lib/features/chat/presentation/pages/chat_screen.dart b/lib/features/chat/presentation/pages/chat_screen.dart index 0a6d1b5a..3b76cb7c 100644 --- a/lib/features/chat/presentation/pages/chat_screen.dart +++ b/lib/features/chat/presentation/pages/chat_screen.dart @@ -1,4 +1,5 @@ import 'dart:io'; +import 'dart:math'; import 'package:eatvio_app/core/widgets/loader.dart'; import 'package:eatvio_app/features/chat/presentation/bloc/chat_room_cubit/chat_room_cubit.dart'; @@ -78,6 +79,7 @@ class _ChatScreenState extends State { resizeToAvoidBottomInset: true, appBar: AppBar( titleSpacing: 0, + backgroundColor: appTheme.gray100, centerTitle: false, title: Row( children: [ @@ -136,7 +138,7 @@ class _ChatScreenState extends State { children: [ Expanded( child: Container( - color: Color(0xFFF0F2F5), + color: appTheme.whiteA700, width: double.maxFinite, child: CustomScrollView( physics: BouncingScrollPhysics(), @@ -149,20 +151,16 @@ class _ChatScreenState extends State { delegate: SliverChildBuilderDelegate( (context, index) { if (index < state.chatMessages.length) { - return Column( - children: [ - if ((index + 1 != state.chatMessages.length && - DateTime.parse(state.chatMessages[index].updatedAt).day != - DateTime.parse(state.chatMessages[index + 1].updatedAt).day) || - index + 1 == state.chatMessages.length) - _messageDate(state.chatMessages[index].updatedAt), - ChatBubbleWidget( - sendTime: state.chatMessages[index].updatedAt, - text: state.chatMessages[index].data.trim(), - isCurrentUser: state.chatRoom.users['to_chat_user']!.id != state.chatMessages[index].authorId, - mediaData: state.chatMessages[index].mediaData ?? [], - ), - ], + if ((index + 1 != state.chatMessages.length && + DateTime.parse(state.chatMessages[index].updatedAt).day != DateTime.parse(state.chatMessages[index + 1].updatedAt).day) || + index + 1 == state.chatMessages.length) { + return _messageDate(state.chatMessages[index].updatedAt); + } + return ChatBubbleWidget( + sendTime: state.chatMessages[index].updatedAt, + text: state.chatMessages[index].data.trim(), + isCurrentUser: state.chatRoom.users['to_chat_user']!.id != state.chatMessages[index].authorId, + mediaData: state.chatMessages[index].mediaData ?? [], ); } else { return Padding( @@ -181,13 +179,6 @@ class _ChatScreenState extends State { ), Container( padding: EdgeInsets.symmetric(vertical: 8), - decoration: BoxDecoration( - border: Border( - top: BorderSide( - color: Colors.black.withValues(alpha: 0.1), - ), - ), - ), child: Row( crossAxisAlignment: CrossAxisAlignment.end, children: [ @@ -231,57 +222,60 @@ class _ChatScreenState extends State { }, customBorder: CircleBorder(), child: Ink( - height: 32, - width: 32, + height: 40, + width: 40, child: Transform.rotate( - angle: 3.8, + angle: pi / 4, child: Icon( Icons.attach_file_rounded, - size: 24, + size: 30, color: Color(0xFF858E99), ), ), ), ), SizedBox(width: 8), - SizedBox( - width: MediaQuery.of(context).size.width - 96, - child: TextFormField( - controller: textEditingController, - maxLines: 5, - minLines: 1, - keyboardType: TextInputType.multiline, - style: TextStyle(fontSize: 16, fontWeight: FontWeight.w400, color: Colors.black, height: 1), - decoration: InputDecoration( - isDense: true, - contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 8), - hintText: 'Сообщение', - hintStyle: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w400, - height: 1, - color: Color(0xFFAEAEB2), - ), - filled: true, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(16), - borderSide: BorderSide( - color: Color(0xFFD1D1D6), - width: 1, + Expanded( + child: SizedBox( + height: 40, + child: TextFormField( + expands: true, + controller: textEditingController, + maxLines: null, + minLines: null, + keyboardType: TextInputType.multiline, + style: TextStyle(fontSize: 16, fontWeight: FontWeight.w400, color: Colors.black, height: 1), + decoration: InputDecoration( + isDense: true, + contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 10), + hintText: 'Сообщение', + hintStyle: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w400, + height: 1, + color: Color(0xFFAEAEB2), ), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(16), - borderSide: BorderSide( - color: Color(0xFFD1D1D6), - width: 1, + filled: true, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(100), + borderSide: BorderSide( + color: Color(0xFFD1D1D6), + width: 1, + ), ), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(16), - borderSide: BorderSide( - color: Color(0xFFD1D1D6), - width: 1, + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(100), + borderSide: BorderSide( + color: Color(0xFFD1D1D6), + width: 1, + ), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(100), + borderSide: BorderSide( + color: Color(0xFFD1D1D6), + width: 1, + ), ), ), ), @@ -306,11 +300,11 @@ class _ChatScreenState extends State { color: appTheme.blueA400, shape: BoxShape.circle, ), - height: 32, - width: 32, + height: 40, + width: 40, child: Icon( Icons.arrow_upward_rounded, - size: 20, + size: 24, color: Colors.white, ), ), @@ -326,16 +320,18 @@ class _ChatScreenState extends State { } _messageDate(String date) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: Text( - DateFormat.MMMMd('RU').format( - DateTime.parse(date), - ), - style: const TextStyle( - height: 1, - color: Color(0xFF8393A1), - fontWeight: FontWeight.w500, + return Center( + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: Text( + DateFormat.yMMMMd('RU').format( + DateTime.parse(date), + ), + style: const TextStyle( + height: 1, + color: Color(0xFF8393A1), + fontWeight: FontWeight.w500, + ), ), ), ); diff --git a/lib/features/chat/presentation/widgets/chat_bubble_widget.dart b/lib/features/chat/presentation/widgets/chat_bubble_widget.dart index 8ef43e8b..ca94dbf9 100644 --- a/lib/features/chat/presentation/widgets/chat_bubble_widget.dart +++ b/lib/features/chat/presentation/widgets/chat_bubble_widget.dart @@ -1,6 +1,8 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:dismissible_page/dismissible_page.dart'; import 'package:eatvio_app/core/const.dart'; +import 'package:eatvio_app/core/theme/custom_text_style.dart'; +import 'package:eatvio_app/core/theme/theme_helper.dart'; import 'package:eatvio_app/core/utils/date_time_utils.dart'; import 'package:eatvio_app/features/chat/presentation/pages/photo_view_screen.dart'; import 'package:flutter/material.dart'; @@ -28,7 +30,7 @@ class ChatBubbleWidget extends StatelessWidget { alignment: isCurrentUser ? Alignment.centerRight : Alignment.centerLeft, child: DecoratedBox( decoration: BoxDecoration( - color: isCurrentUser ? Color(0xFF7F9CF5) : Colors.white, + color: isCurrentUser ? appTheme.gray50 : appTheme.gray60004, borderRadius: mediaData.length > 0 ? BorderRadius.circular(24) : BorderRadius.horizontal( @@ -108,15 +110,15 @@ class ChatBubbleWidget extends StatelessWidget { if (text.isNotEmpty) Text( text, - style: TextStyle(color: isCurrentUser ? Colors.white : Color(0xFF323F4B), height: 1), + style: TextStyles.textFS13FW400.copyWith(color: appTheme.black), ), - SizedBox(height: 4), + SizedBox(height: 8), Padding( padding: mediaData.length > 0 ? const EdgeInsets.only(right: 8, top: 4, left: 8) : EdgeInsets.zero, child: Text( DateTime.parse(sendTime).format('hh:mm'), style: TextStyle( - color: isCurrentUser ? Colors.white.withValues(alpha: 0.4) : Color(0xFF323F4B).withValues(alpha: 0.4), + color: Color(0xFF7B8794), height: 1, fontSize: 10, ), diff --git a/lib/features/chat/repositories/chat_repository.dart b/lib/features/chat/repositories/chat_repository.dart index 228709f6..67b49b73 100644 --- a/lib/features/chat/repositories/chat_repository.dart +++ b/lib/features/chat/repositories/chat_repository.dart @@ -4,7 +4,6 @@ import 'package:dio/dio.dart'; import 'package:eatvio_app/features/chat/models/chat_messages_model.dart'; import 'package:eatvio_app/features/chat/models/chat_room_model.dart'; import 'package:eatvio_app/features/chat/models/chat_room_preview_model.dart'; -import 'package:eatvio_app/features/chat/models/websocket_info_model.dart'; import 'package:eatvio_app/features/chat/services/chat_service.dart'; import 'package:http_parser/http_parser.dart'; @@ -67,15 +66,7 @@ class ChatRepository { } catch (e) { rethrow; } - } - - Future getWebsocket() async { - try { - return (await chatService.getWebsocket()); - } catch (e) { - rethrow; - } - } + } Future getChatRoomIdByUserSlug({required String slug}) async { try { diff --git a/lib/features/chat/services/chat_service.dart b/lib/features/chat/services/chat_service.dart index f572b117..499f2584 100644 --- a/lib/features/chat/services/chat_service.dart +++ b/lib/features/chat/services/chat_service.dart @@ -2,7 +2,6 @@ import 'package:dio/dio.dart'; import 'package:eatvio_app/features/chat/models/chat_messages_model.dart'; import 'package:eatvio_app/features/chat/models/chat_room_model.dart'; import 'package:eatvio_app/features/chat/models/chat_room_preview_model.dart'; -import 'package:eatvio_app/features/chat/models/websocket_info_model.dart'; import 'package:retrofit/retrofit.dart'; part 'chat_service.g.dart'; @@ -35,9 +34,6 @@ abstract class ChatService { @Path() required int page, }); - @GET('/api/profile/ws/params') - Future getWebsocket(); - @GET('/api/chat/get_by_user/{user}') Future getChatRoomIdByUserSlug({ @Path() required String user, diff --git a/lib/features/chat/services/chat_service.g.dart b/lib/features/chat/services/chat_service.g.dart index 37ae5e65..5034c597 100644 --- a/lib/features/chat/services/chat_service.g.dart +++ b/lib/features/chat/services/chat_service.g.dart @@ -9,7 +9,11 @@ part of 'chat_service.dart'; // ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element,unnecessary_string_interpolations class _ChatService implements ChatService { - _ChatService(this._dio, {this.baseUrl, this.errorLogger}); + _ChatService( + this._dio, { + this.baseUrl, + this.errorLogger, + }); final Dio _dio; @@ -24,16 +28,22 @@ class _ChatService implements ChatService { queryParameters.removeWhere((k, v) => v == null); final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/chat/index', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/chat/index', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late ChatRoomPreviewModel _value; try { @@ -51,23 +61,27 @@ class _ChatService implements ChatService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType>( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/chat/show/${id}', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType>(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/chat/show/${id}', + 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, ChatRoomModel.fromJson(v as Map)), - ); + _value = _result.data!.map((k, dynamic v) => + MapEntry(k, ChatRoomModel.fromJson(v as Map))); } on Object catch (e, s) { errorLogger?.logError(e, s, _options); rethrow; @@ -87,26 +101,31 @@ class _ChatService implements ChatService { final _headers = {}; final _data = FormData(); if (data != null) { - _data.fields.add(MapEntry('data', data)); + _data.fields.add(MapEntry( + 'data', + data, + )); } if (media_data != null) { _data.files.addAll(media_data.map((i) => MapEntry('media_data[]', i))); } - final _options = _setStreamType( - Options( - method: 'POST', - headers: _headers, - extra: _extra, - contentType: 'multipart/form-data', - ) - .compose( - _dio.options, - '/api/chat/${id}/message/send', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + contentType: 'multipart/form-data', + ) + .compose( + _dio.options, + '/api/chat/${id}/message/send', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } @@ -119,16 +138,22 @@ class _ChatService implements ChatService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/chat/show/${id}/messages?page=${page}', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/chat/show/${id}/messages?page=${page}', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late ChatMessagesModel _value; try { @@ -140,49 +165,28 @@ class _ChatService implements ChatService { return _value; } - @override - Future getWebsocket() async { - final _extra = {}; - final queryParameters = {}; - final _headers = {}; - const Map? _data = null; - final _options = _setStreamType( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/profile/ws/params', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); - final _result = await _dio.fetch>(_options); - late WebsocketInfoModel _value; - try { - _value = WebsocketInfoModel.fromJson(_result.data!); - } on Object catch (e, s) { - errorLogger?.logError(e, s, _options); - rethrow; - } - return _value; - } - @override Future getChatRoomIdByUserSlug({required String user}) async { final _extra = {}; final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/chat/get_by_user/${user}', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/chat/get_by_user/${user}', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late ChatRoomModel _value; try { @@ -207,7 +211,10 @@ class _ChatService implements ChatService { return requestOptions; } - String _combineBaseUrls(String dioBaseUrl, String? baseUrl) { + String _combineBaseUrls( + String dioBaseUrl, + String? baseUrl, + ) { if (baseUrl == null || baseUrl.trim().isEmpty) { return dioBaseUrl; } diff --git a/lib/features/consultant/become_consultant/services/consultant_service.g.dart b/lib/features/consultant/become_consultant/services/consultant_service.g.dart index 79dd924e..d895b861 100644 --- a/lib/features/consultant/become_consultant/services/consultant_service.g.dart +++ b/lib/features/consultant/become_consultant/services/consultant_service.g.dart @@ -9,7 +9,11 @@ part of 'consultant_service.dart'; // ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element,unnecessary_string_interpolations class _ConsultantService implements ConsultantService { - _ConsultantService(this._dio, {this.baseUrl, this.errorLogger}); + _ConsultantService( + this._dio, { + this.baseUrl, + this.errorLogger, + }); final Dio _dio; @@ -18,23 +22,28 @@ class _ConsultantService implements ConsultantService { final ParseErrorLogger? errorLogger; @override - Future consultantRegistration({ - required ConsultantProfileModel consultantModel, - }) async { + Future consultantRegistration( + {required ConsultantProfileModel consultantModel}) async { final _extra = {}; final queryParameters = {}; final _headers = {}; final _data = consultantModel; - final _options = _setStreamType( - Options(method: 'POST', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/consultant_request/registration', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/consultant_request/registration', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } @@ -48,21 +57,23 @@ class _ConsultantService implements ConsultantService { if (photos != null) { _data.files.addAll(photos.map((i) => MapEntry('photos[]', i))); } - final _options = _setStreamType>( - Options( - method: 'POST', - headers: _headers, - extra: _extra, - contentType: 'multipart/form-data', - ) - .compose( - _dio.options, - '/api/consultant_request/photos/upload', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType>(Options( + method: 'POST', + headers: _headers, + extra: _extra, + contentType: 'multipart/form-data', + ) + .compose( + _dio.options, + '/api/consultant_request/photos/upload', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late List _value; try { @@ -87,7 +98,10 @@ class _ConsultantService implements ConsultantService { return requestOptions; } - String _combineBaseUrls(String dioBaseUrl, String? baseUrl) { + String _combineBaseUrls( + String dioBaseUrl, + String? baseUrl, + ) { if (baseUrl == null || baseUrl.trim().isEmpty) { return dioBaseUrl; } diff --git a/lib/features/create_diet/services/create_diet_service.g.dart b/lib/features/create_diet/services/create_diet_service.g.dart index 84a8c9a1..0c5a4606 100644 --- a/lib/features/create_diet/services/create_diet_service.g.dart +++ b/lib/features/create_diet/services/create_diet_service.g.dart @@ -9,7 +9,11 @@ part of 'create_diet_service.dart'; // ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element,unnecessary_string_interpolations class _CreateDietService implements CreateDietService { - _CreateDietService(this._dio, {this.baseUrl, this.errorLogger}); + _CreateDietService( + this._dio, { + this.baseUrl, + this.errorLogger, + }); final Dio _dio; @@ -35,57 +39,81 @@ class _CreateDietService implements CreateDietService { final _headers = {}; final _data = FormData(); if (name != null) { - _data.fields.add(MapEntry('name', name)); + _data.fields.add(MapEntry( + 'name', + name, + )); } if (duration != null) { - _data.fields.add(MapEntry('duration', duration.toString())); + _data.fields.add(MapEntry( + 'duration', + duration.toString(), + )); } if (state != null) { - _data.fields.add(MapEntry('state', state)); + _data.fields.add(MapEntry( + 'state', + state, + )); } if (meatType != null) { - _data.fields.add(MapEntry('type[meat]', meatType)); + _data.fields.add(MapEntry( + 'type[meat]', + meatType, + )); } if (carbType != null) { - _data.fields.add(MapEntry('type[carb]', carbType)); + _data.fields.add(MapEntry( + 'type[carb]', + carbType, + )); } if (vegType != null) { - _data.fields.add(MapEntry('type[veg]', vegType)); + _data.fields.add(MapEntry( + 'type[veg]', + vegType, + )); } if (lightType != null) { - _data.fields.add(MapEntry('type[light]', lightType)); + _data.fields.add(MapEntry( + 'type[light]', + lightType, + )); } if (details != null) { - _data.fields.add(MapEntry('details', details)); + _data.fields.add(MapEntry( + 'details', + details, + )); } if (image != null) { if (image != null) { - _data.files.add( - MapEntry( - 'image', - MultipartFile.fromFileSync( - image.path, - filename: image.path.split(Platform.pathSeparator).last, - ), + _data.files.add(MapEntry( + 'image', + MultipartFile.fromFileSync( + image.path, + filename: image.path.split(Platform.pathSeparator).last, ), - ); + )); } } - final _options = _setStreamType( - Options( - method: 'POST', - headers: _headers, - extra: _extra, - contentType: 'multipart/form-data', - ) - .compose( - _dio.options, - '/api/diets/create', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + contentType: 'multipart/form-data', + ) + .compose( + _dio.options, + '/api/diets/create', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late CreatedDiet _value; try { @@ -107,16 +135,22 @@ class _CreateDietService implements CreateDietService { final _headers = {}; final _data = {}; _data.addAll(model); - final _options = _setStreamType( - Options(method: 'POST', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/diets/create/${id}/daily_schedule', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diets/create/${id}/daily_schedule', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } @@ -133,7 +167,10 @@ class _CreateDietService implements CreateDietService { return requestOptions; } - String _combineBaseUrls(String dioBaseUrl, String? baseUrl) { + String _combineBaseUrls( + String dioBaseUrl, + String? baseUrl, + ) { if (baseUrl == null || baseUrl.trim().isEmpty) { return dioBaseUrl; } diff --git a/lib/features/create_plan/services/create_plan_service.g.dart b/lib/features/create_plan/services/create_plan_service.g.dart index c93251e7..af44f549 100644 --- a/lib/features/create_plan/services/create_plan_service.g.dart +++ b/lib/features/create_plan/services/create_plan_service.g.dart @@ -9,7 +9,11 @@ part of 'create_plan_service.dart'; // ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element,unnecessary_string_interpolations class _CreatePlanService implements CreatePlanService { - _CreatePlanService(this._dio, {this.baseUrl, this.errorLogger}); + _CreatePlanService( + this._dio, { + this.baseUrl, + this.errorLogger, + }); final Dio _dio; @@ -24,21 +28,23 @@ class _CreatePlanService implements CreatePlanService { final _headers = {}; final _data = {}; _data.addAll(model); - final _options = _setStreamType( - Options( - method: 'POST', - headers: _headers, - extra: _extra, - contentType: 'multipart/form-data', - ) - .compose( - _dio.options, - '/api/plans/create', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + contentType: 'multipart/form-data', + ) + .compose( + _dio.options, + '/api/plans/create', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } @@ -52,16 +58,22 @@ class _CreatePlanService implements CreatePlanService { final _headers = {}; final _data = {}; _data.addAll(model); - final _options = _setStreamType( - Options(method: 'POST', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/plans/create/${slug}/packet_option', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/plans/create/${slug}/packet_option', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } @@ -75,16 +87,22 @@ class _CreatePlanService implements CreatePlanService { final _headers = {}; final _data = {}; _data.addAll(model); - final _options = _setStreamType( - Options(method: 'POST', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/plans/create/${slug}/packet_options', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/plans/create/${slug}/packet_options', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } @@ -101,7 +119,10 @@ class _CreatePlanService implements CreatePlanService { return requestOptions; } - String _combineBaseUrls(String dioBaseUrl, String? baseUrl) { + String _combineBaseUrls( + String dioBaseUrl, + String? baseUrl, + ) { if (baseUrl == null || baseUrl.trim().isEmpty) { return dioBaseUrl; } diff --git a/lib/features/dev_tools/presentation/dev_tools_screen.dart b/lib/features/dev_tools/presentation/dev_tools_screen.dart new file mode 100644 index 00000000..9b18107a --- /dev/null +++ b/lib/features/dev_tools/presentation/dev_tools_screen.dart @@ -0,0 +1,156 @@ +import 'package:eatvio_app/core/const.dart'; +import 'package:eatvio_app/core/utils/toasts.dart'; +import 'package:eatvio_app/core/widgets/custom_outlined_button.dart'; +import 'package:eatvio_app/core/widgets/custom_text_form_field.dart'; +import 'package:eatvio_app/features/dev_tools/test_cases.dart'; +import 'package:flutter/material.dart'; + +class DevToolsScreen extends StatelessWidget { + const DevToolsScreen({super.key}); + static const name = 'devToolsScreen'; + static const path = '/dev-tools-screen'; + + @override + Widget build(BuildContext context) { + return const DevToolsScreenContent(); + } +} + +class DevToolsScreenContent extends StatefulWidget { + const DevToolsScreenContent({super.key}); + + @override + State createState() => _DevToolsScreenContentState(); +} + +class _DevToolsScreenContentState extends State { + String baseUrlForTest = ''; + final List testCases = [Test850task()]; + final controller = TextEditingController(); + late final List testsStates; + @override + void initState() { + super.initState(); + setState(() { + this.baseUrlForTest = baseUrl; + }); + testsStates = List.generate(testCases.length, (index) => TestState.notRun); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(), + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 10), + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + children: [ + Text('BaseUrl: ${baseUrlForTest}'), + ], + ), + ), + Row( + children: [ + Expanded( + child: CustomTextFormField( + controller: controller, + hintText: 'type new base url', + ), + ), + IconButton( + onPressed: () { + setState(() { + baseUrlForTest = controller.text; + controller.clear(); + }); + }, + icon: const Icon(Icons.done), + ), + ], + ), + SizedBox( + height: 10, + ), + if (baseUrlForTest != 'https://eatvio.ru') + ListView.builder( + shrinkWrap: true, + itemCount: testCases.length, + itemBuilder: (context, index) => Row( + children: [ + Text('${index + 1}. ${testCases[index].name}'), + SizedBox( + width: 50, + ), + Expanded( + child: CustomOutlinedButton( + text: 'run', + height: 20, + width: 60, + onPressed: () async { + if (testsStates[index] == TestState.loading) return; + + setState(() { + testsStates[index] = TestState.loading; + }); + final result = await testCases[index].run(baseUrl: baseUrlForTest); + if (result) { + setState(() { + testsStates[index] = TestState.success; + }); + showSuccessToast('${testCases[index].name} passed'); + } else { + setState(() { + testsStates[index] = TestState.fail; + }); + showErrorToast('${testCases[index].name} failed'); + } + }, + buttonStyle: ButtonStyle(), + ), + ), + SizedBox( + width: 30, + ), + switch (testsStates[index]) { + TestState.success => Expanded( + child: Container( + height: 20, + color: Colors.green, + ), + ), + TestState.fail => Expanded( + child: Container( + height: 20, + color: Colors.red, + ), + ), + TestState.notRun => Expanded( + child: Container( + height: 20, + color: Colors.grey, + ), + ), + TestState.loading => Expanded( + child: Container( + height: 20, + child: SizedBox(height: 20, width: 20, child: Center(child: CircularProgressIndicator())), + ), + ), + }, + ], + ), + ), + ], + ), + ), + ), + ); + } +} + +enum TestState { success, fail, notRun, loading } diff --git a/lib/features/dev_tools/test_cases.dart b/lib/features/dev_tools/test_cases.dart new file mode 100644 index 00000000..3f0891b7 --- /dev/null +++ b/lib/features/dev_tools/test_cases.dart @@ -0,0 +1,115 @@ +import 'dart:async'; +import 'dart:developer'; + +import 'package:dio/dio.dart'; +import 'package:eatvio_app/core/locator_service.dart'; +import 'package:eatvio_app/core/utils/date_time_utils.dart'; +import 'package:eatvio_app/features/diets/services/diet_service.dart'; +import 'package:eatvio_app/features/feed/services/feed_service.dart'; +import 'package:eatvio_app/features/profile/services/profile_service.dart'; + +sealed class TestCases { + String get name => throw UnimplementedError(); + + Future run({required String baseUrl}) async => throw UnimplementedError(); +} + +class Test850task implements TestCases { + @override + String get name => 'task #850'; + + @override + Future run({required String baseUrl}) async { + try { + // get all of needed services + final dio = sl(); + final feedService = FeedService(dio, baseUrl: baseUrl); + final profileService = ProfileService(dio, baseUrl: baseUrl); + final dietsService = DietService(dio, baseUrl: baseUrl); + + // get all of needed data + final dietsPaginationModel = await feedService.getDiets(page: 1); + final chosenDietsPaginationModel = await profileService.getChosenDiets(); + final lastChosenDiet = chosenDietsPaginationModel.diets.firstOrNull; + final today = DateTime.now(); + final yesterday = today.subtract(const Duration(days: 1)); + final tomorrow = today.add(const Duration(days: 1)); + + // run test case + for (final diet in dietsPaginationModel.data) { + if (!diet.author.authorIsMe) { + if (lastChosenDiet?.state == 'started' || lastChosenDiet?.state == 'inited') { + try { + await dietsService.cancelDiet(id: lastChosenDiet?.dietId ?? 0); + } catch (e) { + log('unexpected error7: $e'); + return false; + } + await Future.delayed(Duration(seconds: 3)); + } + try { + await dietsService.startDiet( + id: diet.id, + body: { + 'date': yesterday.format('yyyy-MM-dd'), + }, + ); + + return false; + } catch (e) { + log('expect ot have error: $e'); + } + + // test start diet with correct date + try { + await dietsService.startDiet( + id: diet.id, + body: { + 'date': today.format('yyyy-MM-dd'), + }, + ); + } catch (e) { + log('unexpected error2: $e'); + return false; + } + + // test cancelation of diet + try { + await dietsService.cancelDiet(id: diet.id); + } catch (e) { + log('unexpected error3: $e'); + return false; + } + + await Future.delayed(Duration(seconds: 3)); + + // test start diet with correct date + try { + await dietsService.startDiet( + id: diet.id, + body: { + 'date': tomorrow.format('yyyy-MM-dd'), + }, + ); + } catch (e) { + log('unexpected error4: $e'); + return false; + } + + // test cancelation of diet + try { + await dietsService.cancelDiet(id: diet.id); + } catch (e) { + log('unexpected error5: $e'); + } + break; + } + } + + return true; + } catch (e) { + log('unexpected error6: $e'); + return false; + } + } +} diff --git a/lib/features/diary/presentation/pages/diary_screen.dart b/lib/features/diary/presentation/pages/diary_screen.dart index c6c8e291..d0ef5bcb 100644 --- a/lib/features/diary/presentation/pages/diary_screen.dart +++ b/lib/features/diary/presentation/pages/diary_screen.dart @@ -1,3 +1,5 @@ +import 'dart:developer'; + import 'package:eatvio_app/core/widgets/loader.dart'; import 'package:eatvio_app/features/diary/presentation/bloc/diary_cubit.dart'; import 'package:eatvio_app/features/diary/presentation/bloc/diary_state.dart'; @@ -22,6 +24,9 @@ class _DiaryScreenState extends State { create: (BuildContext context) => sl()..fetchDiary(true), child: BlocBuilder( builder: (BuildContext context, DiaryState state) { + if (state is DiaryStateLoaded) { + log(state.diary.id.toString()); + } return Scaffold( backgroundColor: Colors.grey.shade200, appBar: AppBar( diff --git a/lib/features/diary/services/diary_service.g.dart b/lib/features/diary/services/diary_service.g.dart index c7b3820f..4544f6bf 100644 --- a/lib/features/diary/services/diary_service.g.dart +++ b/lib/features/diary/services/diary_service.g.dart @@ -9,7 +9,11 @@ part of 'diary_service.dart'; // ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element,unnecessary_string_interpolations class _DiaryService implements DiaryService { - _DiaryService(this._dio, {this.baseUrl, this.errorLogger}); + _DiaryService( + this._dio, { + this.baseUrl, + this.errorLogger, + }); final Dio _dio; @@ -18,30 +22,33 @@ class _DiaryService implements DiaryService { final ParseErrorLogger? errorLogger; @override - Future> getDiaryIndexByDate({ - required String date, - }) async { + Future> getDiaryIndexByDate( + {required String date}) async { final _extra = {}; final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType>( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/diary/index/${date}', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType>(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diary/index/${date}', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late List _value; try { _value = _result.data! - .map( - (dynamic i) => DiaryDayModel.fromJson(i as Map), - ) + .map((dynamic i) => DiaryDayModel.fromJson(i as Map)) .toList(); } on Object catch (e, s) { errorLogger?.logError(e, s, _options); @@ -56,16 +63,22 @@ class _DiaryService implements DiaryService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/diary/${diary}/show', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diary/${diary}/show', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late DiaryDayWrapperModel _value; try { @@ -83,16 +96,22 @@ class _DiaryService implements DiaryService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/diary/${diary}/dailyNutritionData', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diary/${diary}/dailyNutritionData', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late NutritionDataModel _value; try { @@ -114,30 +133,30 @@ class _DiaryService implements DiaryService { final queryParameters = {}; final _headers = {}; final _data = FormData(); - _data.files.add( - MapEntry( - 'photo', - MultipartFile.fromFileSync( - photo.path, - filename: photo.path.split(Platform.pathSeparator).last, - ), + _data.files.add(MapEntry( + 'photo', + MultipartFile.fromFileSync( + photo.path, + filename: photo.path.split(Platform.pathSeparator).last, ), - ); - final _options = _setStreamType( - Options( - method: 'POST', - headers: _headers, - extra: _extra, - contentType: 'multipart/form-data', - ) - .compose( - _dio.options, - '/api/diary/${diary}/meals/${typeNo}/photo/upload', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + )); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + contentType: 'multipart/form-data', + ) + .compose( + _dio.options, + '/api/diary/${diary}/meals/${typeNo}/photo/upload', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } @@ -151,16 +170,22 @@ class _DiaryService implements DiaryService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'DELETE', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/diary/${diaryId}/meals/${typeNo}/photo/${userAttachment}/delete', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'DELETE', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diary/${diaryId}/meals/${typeNo}/photo/${userAttachment}/delete', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } @@ -178,27 +203,40 @@ class _DiaryService implements DiaryService { queryParameters.removeWhere((k, v) => v == null); final _headers = {}; final _data = FormData(); - _data.fields.add(MapEntry('product_name', productName)); - _data.fields.add(MapEntry('portion', portion)); - _data.fields.add(MapEntry('quantity', quantity.toString())); + _data.fields.add(MapEntry( + 'product_name', + productName, + )); + _data.fields.add(MapEntry( + 'portion', + portion, + )); + _data.fields.add(MapEntry( + 'quantity', + quantity.toString(), + )); if (productNutritionalValueId != null) { - _data.fields.add( - MapEntry( - 'product_nutritional_value_id', - productNutritionalValueId.toString(), - ), - ); + _data.fields.add(MapEntry( + 'product_nutritional_value_id', + productNutritionalValueId.toString(), + )); } - final _options = _setStreamType( - Options(method: 'POST', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/diary/${diary}/meals/${typeNo}/portion/create', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diary/${diary}/meals/${typeNo}/portion/create', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } @@ -214,16 +252,22 @@ class _DiaryService implements DiaryService { final _headers = {}; final _data = {}; _data.addAll(productInMeal); - final _options = _setStreamType( - Options(method: 'PUT', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/diary/${diary}/meals/${typeNo}/portions/${portionModel}/update', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'PUT', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diary/${diary}/meals/${typeNo}/portions/${portionModel}/update', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } @@ -237,16 +281,22 @@ class _DiaryService implements DiaryService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'POST', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/diary/${diary}/meals/${typeNo}/${portionModel}/mark_eaten', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diary/${diary}/meals/${typeNo}/${portionModel}/mark_eaten', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } @@ -260,16 +310,22 @@ class _DiaryService implements DiaryService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'POST', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/diary/${diary}/meals/${typeNo}/${portionModel}/unmark_eaten', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diary/${diary}/meals/${typeNo}/${portionModel}/unmark_eaten', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } @@ -283,16 +339,22 @@ class _DiaryService implements DiaryService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'POST', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/diary/${diary}/meals/${typeNo}/portions/${portionModel}/restore', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diary/${diary}/meals/${typeNo}/portions/${portionModel}/restore', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } @@ -306,16 +368,22 @@ class _DiaryService implements DiaryService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'DELETE', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/diary/${diary}/meals/${typeNo}/portions/${portionModel}/delete', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'DELETE', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diary/${diary}/meals/${typeNo}/portions/${portionModel}/delete', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } @@ -328,16 +396,22 @@ class _DiaryService implements DiaryService { final queryParameters = {}; final _headers = {}; final _data = finishDiaryDayModel; - final _options = _setStreamType( - Options(method: 'POST', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/diary/${diary}/finishDay', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diary/${diary}/finishDay', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } @@ -351,16 +425,22 @@ class _DiaryService implements DiaryService { final queryParameters = {}; final _headers = {}; final _data = {'satiety': satiety}; - final _options = _setStreamType( - Options(method: 'POST', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/diary/${diary}/meals/${typeNo}/satiety/fill', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diary/${diary}/meals/${typeNo}/satiety/fill', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } @@ -374,38 +454,49 @@ class _DiaryService implements DiaryService { final queryParameters = {}; final _headers = {}; final _data = {'time': time}; - final _options = _setStreamType( - Options(method: 'POST', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/diary/${diary}/meals/${typeNo}/time/fill', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diary/${diary}/meals/${typeNo}/time/fill', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } @override - Future sendProductToModeration({ - required Map data, - }) async { + Future sendProductToModeration( + {required Map data}) async { final _extra = {}; final queryParameters = {}; final _headers = {}; final _data = {}; _data.addAll(data); - final _options = _setStreamType( - Options(method: 'POST', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/diary/product_nutritional_values/sendToModeration', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diary/product_nutritional_values/sendToModeration', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late GlossaryModerationModel _value; try { @@ -430,7 +521,10 @@ class _DiaryService implements DiaryService { return requestOptions; } - String _combineBaseUrls(String dioBaseUrl, String? baseUrl) { + String _combineBaseUrls( + String dioBaseUrl, + String? baseUrl, + ) { if (baseUrl == null || baseUrl.trim().isEmpty) { return dioBaseUrl; } diff --git a/lib/features/diets/services/diet_service.dart b/lib/features/diets/services/diet_service.dart index 0d9aebc3..c93e3296 100644 --- a/lib/features/diets/services/diet_service.dart +++ b/lib/features/diets/services/diet_service.dart @@ -28,4 +28,15 @@ abstract class DietService { Future getDiet({ @Path() required int id, }); + + @POST('/api/diets/{id}/start') + Future startDiet({ + @Path() required int id, + @Body() required Map body, + }); + + @POST('/api/diets/{id}/cancel') + Future cancelDiet({ + @Path() required int id, + }); } diff --git a/lib/features/diets/services/diet_service.g.dart b/lib/features/diets/services/diet_service.g.dart index c23dded7..b701c1a3 100644 --- a/lib/features/diets/services/diet_service.g.dart +++ b/lib/features/diets/services/diet_service.g.dart @@ -9,7 +9,11 @@ part of 'diet_service.dart'; // ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element,unnecessary_string_interpolations class _DietService implements DietService { - _DietService(this._dio, {this.baseUrl, this.errorLogger}); + _DietService( + this._dio, { + this.baseUrl, + this.errorLogger, + }); final Dio _dio; @@ -23,16 +27,22 @@ class _DietService implements DietService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'POST', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/diets/${id}/like', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diets/${id}/like', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late DietLikesModel _value; try { @@ -50,16 +60,22 @@ class _DietService implements DietService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'POST', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/diets/${id}/add_to_favorite', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diets/${id}/add_to_favorite', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late Diet _value; try { @@ -77,16 +93,22 @@ class _DietService implements DietService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'POST', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/diets/${id}/remove_from_favorite', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diets/${id}/remove_from_favorite', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late Diet _value; try { @@ -104,16 +126,22 @@ class _DietService implements DietService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/diets/show/${id}', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diets/show/${id}', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late Diet _value; try { @@ -125,6 +153,60 @@ class _DietService implements DietService { return _value; } + @override + Future startDiet({ + required int id, + required Map body, + }) async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + final _data = {}; + _data.addAll(body); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diets/${id}/start', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); + await _dio.fetch(_options); + } + + @override + Future cancelDiet({required int id}) async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + const Map? _data = null; + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diets/${id}/cancel', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); + await _dio.fetch(_options); + } + RequestOptions _setStreamType(RequestOptions requestOptions) { if (T != dynamic && !(requestOptions.responseType == ResponseType.bytes || @@ -138,7 +220,10 @@ class _DietService implements DietService { return requestOptions; } - String _combineBaseUrls(String dioBaseUrl, String? baseUrl) { + String _combineBaseUrls( + String dioBaseUrl, + String? baseUrl, + ) { if (baseUrl == null || baseUrl.trim().isEmpty) { return dioBaseUrl; } diff --git a/lib/features/feed/models/plan_pagination_model.dart b/lib/features/feed/models/plan_pagination_model.dart index 083bb162..09c2129f 100644 --- a/lib/features/feed/models/plan_pagination_model.dart +++ b/lib/features/feed/models/plan_pagination_model.dart @@ -39,7 +39,7 @@ class PlanModel with _$PlanModel { @JsonKey(name: "is_favorite") required bool isFavorite, @JsonKey(name: "min_price_of_options") required double minPriceOfOptions, @JsonKey(name: "max_price_of_options") required double maxPriceOfOptions, - @Default(false) bool wasLikedByMe, + @JsonKey(name: "was_liked_by_me") required bool wasLikedByMe, }) = _PlanModel; factory PlanModel.fromJson(Map json) => _$PlanModelFromJson(json); diff --git a/lib/features/feed/models/plan_pagination_model.freezed.dart b/lib/features/feed/models/plan_pagination_model.freezed.dart index 0a338d10..6df539a9 100644 --- a/lib/features/feed/models/plan_pagination_model.freezed.dart +++ b/lib/features/feed/models/plan_pagination_model.freezed.dart @@ -298,6 +298,7 @@ mixin _$PlanModel { double get minPriceOfOptions => throw _privateConstructorUsedError; @JsonKey(name: "max_price_of_options") double get maxPriceOfOptions => throw _privateConstructorUsedError; + @JsonKey(name: "was_liked_by_me") bool get wasLikedByMe => throw _privateConstructorUsedError; /// Serializes this PlanModel to a JSON map. @@ -335,7 +336,7 @@ abstract class $PlanModelCopyWith<$Res> { @JsonKey(name: "is_favorite") bool isFavorite, @JsonKey(name: "min_price_of_options") double minPriceOfOptions, @JsonKey(name: "max_price_of_options") double maxPriceOfOptions, - bool wasLikedByMe}); + @JsonKey(name: "was_liked_by_me") bool wasLikedByMe}); $PlanTypeCopyWith<$Res> get type; $PacketOptionsCopyWith<$Res>? get packet1Options; @@ -555,7 +556,7 @@ abstract class _$$PlanModelImplCopyWith<$Res> @JsonKey(name: "is_favorite") bool isFavorite, @JsonKey(name: "min_price_of_options") double minPriceOfOptions, @JsonKey(name: "max_price_of_options") double maxPriceOfOptions, - bool wasLikedByMe}); + @JsonKey(name: "was_liked_by_me") bool wasLikedByMe}); @override $PlanTypeCopyWith<$Res> get type; @@ -711,7 +712,7 @@ class _$PlanModelImpl implements _PlanModel { @JsonKey(name: "is_favorite") required this.isFavorite, @JsonKey(name: "min_price_of_options") required this.minPriceOfOptions, @JsonKey(name: "max_price_of_options") required this.maxPriceOfOptions, - this.wasLikedByMe = false}); + @JsonKey(name: "was_liked_by_me") required this.wasLikedByMe}); factory _$PlanModelImpl.fromJson(Map json) => _$$PlanModelImplFromJson(json); @@ -774,7 +775,7 @@ class _$PlanModelImpl implements _PlanModel { @JsonKey(name: "max_price_of_options") final double maxPriceOfOptions; @override - @JsonKey() + @JsonKey(name: "was_liked_by_me") final bool wasLikedByMe; @override @@ -865,29 +866,30 @@ class _$PlanModelImpl implements _PlanModel { abstract class _PlanModel implements PlanModel { const factory _PlanModel( - {@JsonKey(name: "id") required final int id, - @JsonKey(name: "slug") required final String slug, - @JsonKey(name: "name") required final String name, - @JsonKey(name: "image") required final String image, - @JsonKey(name: "duration") required final int duration, - @JsonKey(name: "state") required final String state, - @JsonKey(name: "type", fromJson: planTypeFromJson) - required final PlanType type, - @JsonKey(name: "details") required final String details, - @JsonKey(name: "packets_count") required final int packetsCount, - @JsonKey(name: "packet1_options") final PacketOptions? packet1Options, - @JsonKey(name: "packet2_options") final PacketOptions? packet2Options, - @JsonKey(name: "packet3_options") final PacketOptions? packet3Options, - @JsonKey(name: "author") required final Author author, - @JsonKey(name: "total_likes") required final int totalLikes, - @JsonKey(name: "total_views") required final int totalViews, - @JsonKey(name: "total_comments") required final int totalComments, - @JsonKey(name: "is_favorite") required final bool isFavorite, - @JsonKey(name: "min_price_of_options") - required final double minPriceOfOptions, - @JsonKey(name: "max_price_of_options") - required final double maxPriceOfOptions, - final bool wasLikedByMe}) = _$PlanModelImpl; + {@JsonKey(name: "id") required final int id, + @JsonKey(name: "slug") required final String slug, + @JsonKey(name: "name") required final String name, + @JsonKey(name: "image") required final String image, + @JsonKey(name: "duration") required final int duration, + @JsonKey(name: "state") required final String state, + @JsonKey(name: "type", fromJson: planTypeFromJson) + required final PlanType type, + @JsonKey(name: "details") required final String details, + @JsonKey(name: "packets_count") required final int packetsCount, + @JsonKey(name: "packet1_options") final PacketOptions? packet1Options, + @JsonKey(name: "packet2_options") final PacketOptions? packet2Options, + @JsonKey(name: "packet3_options") final PacketOptions? packet3Options, + @JsonKey(name: "author") required final Author author, + @JsonKey(name: "total_likes") required final int totalLikes, + @JsonKey(name: "total_views") required final int totalViews, + @JsonKey(name: "total_comments") required final int totalComments, + @JsonKey(name: "is_favorite") required final bool isFavorite, + @JsonKey(name: "min_price_of_options") + required final double minPriceOfOptions, + @JsonKey(name: "max_price_of_options") + required final double maxPriceOfOptions, + @JsonKey(name: "was_liked_by_me") required final bool wasLikedByMe}) = + _$PlanModelImpl; factory _PlanModel.fromJson(Map json) = _$PlanModelImpl.fromJson; @@ -950,6 +952,7 @@ abstract class _PlanModel implements PlanModel { @JsonKey(name: "max_price_of_options") double get maxPriceOfOptions; @override + @JsonKey(name: "was_liked_by_me") bool get wasLikedByMe; /// Create a copy of PlanModel diff --git a/lib/features/feed/models/plan_pagination_model.g.dart b/lib/features/feed/models/plan_pagination_model.g.dart index abfe3930..0db54936 100644 --- a/lib/features/feed/models/plan_pagination_model.g.dart +++ b/lib/features/feed/models/plan_pagination_model.g.dart @@ -54,7 +54,7 @@ _$PlanModelImpl _$$PlanModelImplFromJson(Map json) => isFavorite: json['is_favorite'] as bool, minPriceOfOptions: (json['min_price_of_options'] as num).toDouble(), maxPriceOfOptions: (json['max_price_of_options'] as num).toDouble(), - wasLikedByMe: json['wasLikedByMe'] as bool? ?? false, + wasLikedByMe: json['was_liked_by_me'] as bool, ); Map _$$PlanModelImplToJson(_$PlanModelImpl instance) => @@ -78,7 +78,7 @@ Map _$$PlanModelImplToJson(_$PlanModelImpl instance) => 'is_favorite': instance.isFavorite, 'min_price_of_options': instance.minPriceOfOptions, 'max_price_of_options': instance.maxPriceOfOptions, - 'wasLikedByMe': instance.wasLikedByMe, + 'was_liked_by_me': instance.wasLikedByMe, }; _$PacketOptionsImpl _$$PacketOptionsImplFromJson(Map json) => diff --git a/lib/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart b/lib/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart index 87cdd95d..1f585375 100644 --- a/lib/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart +++ b/lib/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart @@ -9,7 +9,7 @@ import 'package:eatvio_app/features/feed/presentation/bloc/diets_cubit/diets_sta import 'package:eatvio_app/features/feed/repositories/feed_repository.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -class DietsCubit extends Cubit{ +class DietsCubit extends Cubit { final FeedRepository feedRepository; final DietRepository dietsRepository; int currentPage = 1; @@ -52,7 +52,6 @@ class DietsCubit extends Cubit{ super.close(); } - void changeTypeFilter(int index) { emit(state.copyWith(filterState: state.filterState.copyWith(typeIndex: index), errorMessage: null)); EasyDebounce.debounce( @@ -64,7 +63,6 @@ class DietsCubit extends Cubit{ ); } - void changeSortingType(int index) { emit(state.copyWith(filterState: state.filterState.copyWith(sortingIndex: index), errorMessage: null)); EasyDebounce.debounce( @@ -76,7 +74,6 @@ class DietsCubit extends Cubit{ ); } - void changeDurationFilter(int index) { emit(state.copyWith(filterState: state.filterState.copyWith(durationIndex: index), errorMessage: null)); EasyDebounce.debounce( @@ -153,6 +150,7 @@ class DietsCubit extends Cubit{ Future likeDiet(int id, int index) async { final currentDiets = state.dietsList; + // if (currentDiets.isEmpty) return; final dietsForModification = [...currentDiets]; final currentDiet = currentDiets[index]; if (currentDiet.wasLikedByMe) { diff --git a/lib/features/feed/presentation/bloc/plans_cubit/plans_cubit.dart b/lib/features/feed/presentation/bloc/plans_cubit/plans_cubit.dart index 10f5b8ab..5c2f28fd 100644 --- a/lib/features/feed/presentation/bloc/plans_cubit/plans_cubit.dart +++ b/lib/features/feed/presentation/bloc/plans_cubit/plans_cubit.dart @@ -284,4 +284,58 @@ class PlansCubit extends Cubit { }, ); } + + Future likePlan(String slug, int index) async { + final currentPlans = state.plans; + final plansForModification = [...currentPlans]; + final currentPlan = currentPlans[index]; + if (currentPlan.wasLikedByMe) { + plansForModification[index] = currentPlan.copyWith( + totalLikes: currentPlan.totalLikes - 1, + wasLikedByMe: false, + ); + emit( + state.copyWith( + plans: [ + ...plansForModification, + ], + isLoading: isLoading, + errorMessage: null, + ), + ); + } else { + plansForModification[index] = currentPlan.copyWith( + totalLikes: currentPlan.totalLikes + 1, + wasLikedByMe: true, + ); + emit( + state.copyWith( + plans: [ + ...plansForModification, + ], + isLoading: isLoading, + errorMessage: null, + ), + ); + } + EasyDebounce.debounce( + 'like_plan', + Duration(milliseconds: 200), + () async { + try { + await planRepository.likePlan(slug); + } catch (e) { + log(e.toString()); + emit( + state.copyWith( + plans: [ + ...currentPlans, + ], + isLoading: isLoading, + ), + ); + } + }, + ); + } } diff --git a/lib/features/feed/presentation/bloc/recipes_cubit/recipes_cubit.dart b/lib/features/feed/presentation/bloc/recipes_cubit/recipes_cubit.dart index 5147445a..d3a6a47e 100644 --- a/lib/features/feed/presentation/bloc/recipes_cubit/recipes_cubit.dart +++ b/lib/features/feed/presentation/bloc/recipes_cubit/recipes_cubit.dart @@ -28,13 +28,16 @@ class RecipesCubit extends Cubit { query: query, ); final recipesTags = (await recipeRepository.getRecipesTags()); - emit(RecipesState.loaded( - recipesList: recipesList, - recipesTags: recipesTags, - selectedTags: _selectedTags, - selectedTagsCounter: _selectedTags.length, - isLoading: isLoading, - ),); + emit( + RecipesState.loaded( + recipesList: recipesList, + recipesTags: recipesTags, + selectedTags: _selectedTags, + selectedTagsCounter: _selectedTags.length, + isLoading: isLoading, + ), + ); + lastPage = currentPage; } catch (e) { emit(RecipesState.error(errorMessage: e.toString())); } @@ -55,14 +58,17 @@ class RecipesCubit extends Cubit { query: _query, ); isLoading = false; - emit((state as RecipesStateLoaded).copyWith( - recipesList: [ - ...(state as RecipesStateLoaded).recipesList, - ...recipesList, - ], - isLoading: isLoading, - ),); + emit( + (state as RecipesStateLoaded).copyWith( + recipesList: [ + ...(state as RecipesStateLoaded).recipesList, + ...recipesList, + ], + isLoading: isLoading, + ), + ); } + lastPage = currentPage; } catch (e) { emit(RecipesState.error(errorMessage: e.toString())); } @@ -71,9 +77,11 @@ class RecipesCubit extends Cubit { updateTags(RecipeTag tag) { _selectedTags.contains(tag.id) ? _selectedTags.remove(tag.id) : _selectedTags.add(tag.id); - emit((state as RecipesStateLoaded).copyWith( - selectedTags: _selectedTags, - selectedTagsCounter: _selectedTags.length, - ),); + emit( + (state as RecipesStateLoaded).copyWith( + selectedTags: _selectedTags, + selectedTagsCounter: _selectedTags.length, + ), + ); } } diff --git a/lib/features/feed/presentation/pages/feed_screen.dart b/lib/features/feed/presentation/pages/feed_screen.dart index d921fb9f..4ff555a1 100644 --- a/lib/features/feed/presentation/pages/feed_screen.dart +++ b/lib/features/feed/presentation/pages/feed_screen.dart @@ -2,53 +2,74 @@ import 'package:easy_debounce/easy_debounce.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'; -import 'package:eatvio_app/core/widgets/loader.dart'; import 'package:eatvio_app/features/create_plan/presentation/create_plan_screen.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/consultants_cubit/consultants_cubit.dart'; -import 'package:eatvio_app/features/feed/presentation/bloc/consultants_cubit/consultants_state.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart'; -import 'package:eatvio_app/features/feed/presentation/bloc/diets_cubit/diets_state.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart'; -import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_state.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/profile_cubit/profile_cubit.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/profile_cubit/profile_state.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/recipes_cubit/recipes_cubit.dart'; -import 'package:eatvio_app/features/feed/presentation/bloc/recipes_cubit/recipes_state.dart'; -import 'package:eatvio_app/features/feed/presentation/widgets/blog_post_widget.dart'; +import 'package:eatvio_app/features/feed/presentation/widgets/blog_posts.dart'; import 'package:eatvio_app/features/feed/presentation/widgets/choice_chip_widget.dart'; -import 'package:eatvio_app/features/feed/presentation/widgets/consultant_widget.dart'; -import 'package:eatvio_app/features/feed/presentation/widgets/diet_filter_bottom_sheet.dart'; -import 'package:eatvio_app/features/feed/presentation/widgets/diets_widget.dart'; -import 'package:eatvio_app/features/feed/presentation/widgets/filter_badge.dart'; -import 'package:eatvio_app/features/feed/presentation/widgets/plan_widget.dart'; -import 'package:eatvio_app/features/feed/presentation/widgets/plans_filter_bottom_sheet.dart'; -import 'package:eatvio_app/features/feed/presentation/widgets/recipes_widget.dart'; +import 'package:eatvio_app/features/feed/presentation/widgets/consultants.dart'; +import 'package:eatvio_app/features/feed/presentation/widgets/diets.dart'; +import 'package:eatvio_app/features/feed/presentation/widgets/plans.dart'; import 'package:eatvio_app/features/feed/presentation/widgets/tags_modal_widget.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/plans_cubit/plans_cubit.dart'; -import 'package:eatvio_app/features/feed/presentation/bloc/plans_cubit/plans_state.dart'; import 'package:eatvio_app/core/locator_service.dart'; import 'package:eatvio_app/core/theme/theme_helper.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; +import '../widgets/recipes.dart'; + final bucket = PageStorageBucket(); -class FeedScreen extends StatefulWidget { +class FeedScreen extends StatelessWidget { const FeedScreen({super.key}); @override - State createState() => _FeedScreenState(); + 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(), + ), + ], + child: const FeedScreenContent(), + ); + } } -class _FeedScreenState extends State { - final FeedCubit feedCubit = sl(); - final RecipesCubit recipesCubit = sl()..loadRecipesList(); - final DietsCubit dietsCubit = sl()..loadDiets(); - final PlansCubit plansCubit = sl()..loadPlans(); - final ConsultantsCubit consultantsCubit = sl()..getConsultants(); +class FeedScreenContent extends StatefulWidget { + const FeedScreenContent({super.key}); - final searchController = TextEditingController(); + @override + State createState() => _FeedScreenContentState(); +} + +class _FeedScreenContentState extends State { + final postsController = TextEditingController(); + final recipesController = TextEditingController(); + final dietsController = TextEditingController(); + final plansController = TextEditingController(); + final consultantsController = TextEditingController(); final List chipsLabelList = ['Все', 'Рецепты', 'Диеты', 'Планы питания', 'Консультанты']; int _selectedChipIndex = 0; final blogPostsScrollController = ScrollController(); @@ -59,7 +80,6 @@ class _FeedScreenState extends State { @override void initState() { - feedCubit.loadFeedBlogPostList(); blogPostsScrollController.addListener(_onScrollBlogPosts); recipesScrollController.addListener(_onScrollRecipes); dietsScrollController.addListener(_onScrollDiets); @@ -70,25 +90,25 @@ class _FeedScreenState extends State { _onScrollBlogPosts() { if (blogPostsScrollController.offset >= blogPostsScrollController.position.maxScrollExtent && !blogPostsScrollController.position.outOfRange) { - feedCubit.loadNextPage(); + context.read().loadNextPage(); } } _onScrollRecipes() { if (recipesScrollController.offset >= recipesScrollController.position.maxScrollExtent && !recipesScrollController.position.outOfRange) { - recipesCubit.loadNextPage(); + context.read().loadNextPage(); } } _onScrollDiets() { if (dietsScrollController.offset >= dietsScrollController.position.maxScrollExtent && !dietsScrollController.position.outOfRange) { - dietsCubit.loadNextPage(); + context.read().loadNextPage(); } } _onScrollPlans() { if (plansScrollController.offset >= plansScrollController.position.maxScrollExtent && !plansScrollController.position.outOfRange) { - plansCubit.loadNextPage(); + context.read().loadNextPage(); } } @@ -107,402 +127,148 @@ class _FeedScreenState extends State { @override Widget build(BuildContext context) { - return MultiBlocProvider( - providers: [ - BlocProvider( - create: (context) => sl()..getProfile(), - ), - BlocProvider( - create: (context) => sl()..loadRecipesList(), - ), - BlocProvider( - create: (context) => sl()..loadDiets(), - ), - BlocProvider( - create: (context) => sl()..loadPlans(), - ), - BlocProvider( - create: (context) => sl()..getConsultants(), - ), - ], - child: Scaffold( - floatingActionButton: _selectedChipIndex == 1 - ? FloatingActionButton.small( - heroTag: 'recipesTagsFilter', - backgroundColor: appTheme.blueA400, - shape: CircleBorder(), - child: Icon( - Icons.filter_list_rounded, - color: Colors.white, - ), - onPressed: () async { - await showModalBottomSheet( - useRootNavigator: true, - context: context, - builder: (context) => TagsModalWidget( - recipesCubit: recipesCubit, - ), - ); - recipesCubit.loadRecipesList(); - }, - ) - : null, - 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 - }, - headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { - return [ - BlocBuilder( - builder: (context, state) { - return SliverAppBar( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.vertical(bottom: Radius.circular(12)), - ), - backgroundColor: Colors.white, - foregroundColor: Colors.white, - automaticallyImplyLeading: false, - stretchTriggerOffset: 1, - floating: true, - snap: true, - scrolledUnderElevation: 0, - bottom: _chipGroup(), - title: Row( - children: [ - CustomSearchBar( - searchController: searchController, - onChanged: (query) { - if (query.length > 2) { - EasyDebounce.debounce( - 'searchFeed', - Duration(milliseconds: 500), - () { - switch (_selectedChipIndex) { - case 0: - feedCubit.loadFeedBlogPostList(query: query); - break; - case 1: - recipesCubit.loadRecipesList(query: query); - break; - case 2: - dietsCubit.loadDiets(query: query); - break; - case 3: - plansCubit.loadPlans(query: query); - break; - case 4: - consultantsCubit.getConsultants(); - break; - } - }, - ); - } else { - EasyDebounce.debounce( - 'searchFeed', - Duration(milliseconds: 500), - () { - switch (_selectedChipIndex) { - case 0: - feedCubit.loadFeedBlogPostList(); - break; - case 1: - recipesCubit.loadRecipesList(); - break; - case 2: - dietsCubit.loadDiets(); - break; - case 3: - plansCubit.loadPlans(); - break; - case 4: - consultantsCubit.getConsultants(); - break; - } - }, - ); - } - }, - ), - SizedBox(width: 12), - switch (_selectedChipIndex) { - 1 => AddItemButton( - onTap: () => GoRouter.of(context).pushNamed('recipeCreateScreen'), - ), - 2 => AddItemButton( - onTap: state.profile?.role == 'consultant' ? () => GoRouter.of(context).pushNamed(CreateDietScreen.name) : null, - ), - 3 => AddItemButton( - onTap: state.profile?.role == 'consultant' ? () => GoRouter.of(context).pushNamed(CreatePlanScreen.name) : null, - ), - _ => AddItemButton() - }, - ], - ), - ); - }, - ), - ]; - }, - body: switch (_selectedChipIndex) { - 0 => _buildAllBlogPosts(), - 1 => _buildAllRecipes(), - 2 => _buildDiets(), - 3 => _buildPlans(), - 4 => _buildConsultants(), - _ => Center(child: Text(chipsLabelList[_selectedChipIndex])), - }, - ), - ), - ); - } - - _buildAllBlogPosts() { - return RefreshIndicator( - onRefresh: () => feedCubit.loadFeedBlogPostList(), - child: BlocBuilder( - builder: (BuildContext context, FeedState state) { - if (state is FeedStateLoaded) { - return ListView.separated( - padding: EdgeInsets.symmetric(vertical: 8), - shrinkWrap: true, - physics: BouncingScrollPhysics(), - itemBuilder: (context, index) { - if (index == state.feedBlogPostList.length) { - return const Loader(); - } - return BlogPostWidget(index: index); - }, - separatorBuilder: (context, index) { - return SizedBox(height: 8); - }, - itemCount: state.isLoading ? state.feedBlogPostList.length + 1 : state.feedBlogPostList.length, - ); - } else if (state is FeedStateError) { - return Scaffold( - backgroundColor: Colors.grey.shade200, - body: Padding( - padding: const EdgeInsets.all(16), - child: Center( - child: Text(state.errorMessage), - ), - ), - ); - } else { - return Scaffold( - backgroundColor: Colors.grey.shade200, - body: const Loader(), - ); - } - }, - ), - ); - } - - _buildConsultants() { - return RefreshIndicator( - onRefresh: () => consultantsCubit.getConsultants(), - child: BlocBuilder( - bloc: consultantsCubit, - builder: (BuildContext context, ConsultantsState state) { - if (state is ConsultantsStateLoaded) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: Material( + return Scaffold( + floatingActionButton: _selectedChipIndex == 1 + ? FloatingActionButton.small( + heroTag: 'recipesTagsFilter', + backgroundColor: appTheme.blueA400, + shape: CircleBorder(), + child: Icon( + Icons.filter_list_rounded, color: Colors.white, - borderRadius: BorderRadius.circular(12), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: ListView.separated( - padding: EdgeInsets.symmetric(vertical: 16), - shrinkWrap: true, - physics: BouncingScrollPhysics(), - itemBuilder: (context, index) { - return ConsultantWidget(consultant: state.consultantsList[index]); - }, - separatorBuilder: (context, index) { - return SizedBox(height: 12); - }, - itemCount: state.consultantsList.length, + ), + onPressed: () async { + final recipesCubit = context.read(); + await showModalBottomSheet( + useRootNavigator: true, + context: context, + builder: (context) => TagsModalWidget( + recipesCubit: recipesCubit, ), - ), - ), - ); - } else if (state is ConsultantsStateError) { - return Scaffold( - backgroundColor: Colors.grey.shade200, - body: Padding( - padding: const EdgeInsets.all(16), - child: Center( - child: Text(state.errorMessage), - ), - ), - ); - } else { - return Scaffold( - backgroundColor: Colors.grey.shade200, - body: const Loader(), - ); - } - }, - ), - ); - } - - _buildAllRecipes() { - return RefreshIndicator( - onRefresh: () => recipesCubit.loadRecipesList(), - child: BlocBuilder( - bloc: recipesCubit, - builder: (BuildContext context, RecipesState state) { - if (state is RecipesStateLoaded) { - return ListView.separated( - padding: EdgeInsets.symmetric(vertical: 8), - shrinkWrap: true, - physics: BouncingScrollPhysics(), - itemBuilder: (context, index) { - return RecipesWidget(recipes: state.recipesList[index]); + ); + recipesCubit.loadRecipesList(); }, - separatorBuilder: (context, index) { - return SizedBox(height: 8); + ) + : null, + 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 + }, + headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { + return [ + BlocBuilder( + builder: (context, state) { + return SliverAppBar( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(bottom: Radius.circular(12)), + ), + backgroundColor: Colors.white, + foregroundColor: Colors.white, + automaticallyImplyLeading: false, + stretchTriggerOffset: 1, + floating: true, + snap: true, + scrolledUnderElevation: 0, + bottom: _chipGroup(), + title: Row( + children: [ + CustomSearchBar( + searchController: switch (_selectedChipIndex) { + 1 => recipesController, + 2 => dietsController, + 3 => plansController, + 4 => consultantsController, + _ => postsController, + }, + onChanged: (query) { + if (query.length > 2) { + EasyDebounce.debounce( + 'searchFeed', + 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; + } + }, + ); + } else { + EasyDebounce.debounce( + 'searchFeed', + 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; + } + }, + ); + } + }, + ), + SizedBox(width: 12), + switch (_selectedChipIndex) { + 1 => AddItemButton( + onTap: () => GoRouter.of(context).pushNamed('recipeCreateScreen'), + ), + 2 => AddItemButton( + onTap: state.profile?.role == 'consultant' ? () => GoRouter.of(context).pushNamed(CreateDietScreen.name) : null, + ), + 3 => AddItemButton( + onTap: state.profile?.role == 'consultant' ? () => GoRouter.of(context).pushNamed(CreatePlanScreen.name) : null, + ), + _ => AddItemButton() + }, + ], + ), + ); }, - itemCount: state.recipesList.length, - ); - } else if (state is RecipesStateError) { - return Scaffold( - backgroundColor: Colors.grey.shade200, - body: Padding( - padding: const EdgeInsets.all(16), - child: Center( - child: Text(state.errorMessage), - ), - ), - ); - } else { - return Scaffold( - backgroundColor: Colors.grey.shade200, - body: const Loader(), - ); - } + ), + ]; }, - ), - ); - } - - _buildDiets() { - return RefreshIndicator( - onRefresh: () => dietsCubit.loadDiets(), - child: BlocBuilder( - bloc: dietsCubit, - builder: (BuildContext context, DietsState state) { - if (state.isLoading) { - return Scaffold( - backgroundColor: Colors.grey.shade200, - body: const Loader(), - ); - } else if (state.errorMessage != null) { - return Scaffold( - backgroundColor: Colors.grey.shade200, - body: Padding( - padding: const EdgeInsets.all(16), - child: Center( - child: Text(state.errorMessage ?? ''), - ), - ), - ); - } else { - return Stack( - children: [ - SizedBox.expand(), - ListView.separated( - padding: EdgeInsets.symmetric(vertical: 8), - shrinkWrap: true, - physics: BouncingScrollPhysics(), - itemBuilder: (context, index) { - return DietsWidget(diet: state.dietsList[index], index: index); - }, - separatorBuilder: (context, index) { - return SizedBox(height: 8); - }, - itemCount: state.dietsList.length, - ), - Positioned( - right: 0, - bottom: 74, - child: FilterBadge( - filterBottomSheet: DietFilterBottomSheet( - dietsCubit: dietsCubit, - ), - ), - ), - ], - ); - } - }, - ), - ); - } - - _buildPlans() { - return RefreshIndicator( - onRefresh: () => plansCubit.loadPlans(), - child: BlocBuilder( - bloc: plansCubit, - builder: (BuildContext context, PlansState state) { - if (state.isLoading) { - return Scaffold( - backgroundColor: Colors.grey.shade200, - body: const Loader(), - ); - } else if (state.errorMessage != null) { - return Scaffold( - backgroundColor: Colors.grey.shade200, - body: Padding( - padding: const EdgeInsets.all(16), - child: Center( - child: Text(state.errorMessage ?? ''), - ), - ), - ); - } - return Stack( - children: [ - SizedBox.expand(), - ListView.separated( - padding: EdgeInsets.symmetric(vertical: 8), - shrinkWrap: true, - physics: BouncingScrollPhysics(), - itemBuilder: (context, index) { - return PlanWidget( - plan: state.plans[index], - index: index, - ); - }, - separatorBuilder: (context, index) { - return SizedBox(height: 8); - }, - itemCount: state.plans.length, - ), - Positioned( - right: 0, - bottom: 74, - child: FilterBadge( - filterBottomSheet: PlansFilterBottomSheet( - plansCubit: plansCubit, - ), - ), - ), - ], - ); + body: switch (_selectedChipIndex) { + 0 => BlogPosts(), + 1 => Recipes(), + 2 => Diets(), + 3 => Plans(), + 4 => Consultants(), + _ => Center(child: Text(chipsLabelList[_selectedChipIndex])), }, ), ); @@ -525,7 +291,6 @@ class _FeedScreenState extends State { onSelected: (bool selected) { setState(() { _selectedChipIndex = 0; - searchController.clear(); FocusScope.of(context).requestFocus(new FocusNode()); }); }, @@ -538,7 +303,6 @@ class _FeedScreenState extends State { onSelected: (bool selected) { setState(() { _selectedChipIndex = 1; - searchController.clear(); FocusScope.of(context).requestFocus(new FocusNode()); }); }, @@ -551,7 +315,6 @@ class _FeedScreenState extends State { onSelected: (bool selected) { setState(() { _selectedChipIndex = 2; - searchController.clear(); FocusScope.of(context).requestFocus(new FocusNode()); }); }, @@ -564,7 +327,6 @@ class _FeedScreenState extends State { onSelected: (bool selected) { setState(() { _selectedChipIndex = 3; - searchController.clear(); FocusScope.of(context).requestFocus(new FocusNode()); }); }, @@ -577,7 +339,6 @@ class _FeedScreenState extends State { onSelected: (bool selected) { setState(() { _selectedChipIndex = 4; - searchController.clear(); FocusScope.of(context).requestFocus(new FocusNode()); }); }, diff --git a/lib/features/feed/presentation/widgets/blog_posts.dart b/lib/features/feed/presentation/widgets/blog_posts.dart new file mode 100644 index 00000000..f76e35ce --- /dev/null +++ b/lib/features/feed/presentation/widgets/blog_posts.dart @@ -0,0 +1,53 @@ +import 'package:eatvio_app/core/widgets/loader.dart'; +import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart'; +import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_state.dart'; +import 'package:eatvio_app/features/feed/presentation/widgets/blog_post_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +class BlogPosts extends StatelessWidget { + const BlogPosts({super.key}); + + @override + Widget build(BuildContext context) { + return RefreshIndicator( + onRefresh: () => context.read().loadFeedBlogPostList(), + child: BlocBuilder( + builder: (BuildContext context, FeedState state) { + if (state is FeedStateLoaded) { + return ListView.separated( + padding: EdgeInsets.symmetric(vertical: 8), + shrinkWrap: true, + physics: BouncingScrollPhysics(), + itemBuilder: (context, index) { + if (index == state.feedBlogPostList.length) { + return const Loader(); + } + return BlogPostWidget(index: index); + }, + separatorBuilder: (context, index) { + return SizedBox(height: 8); + }, + itemCount: state.isLoading ? state.feedBlogPostList.length + 1 : state.feedBlogPostList.length, + ); + } else if (state is FeedStateError) { + return Scaffold( + backgroundColor: Colors.grey.shade200, + body: Padding( + padding: const EdgeInsets.all(16), + child: Center( + child: Text(state.errorMessage), + ), + ), + ); + } else { + return Scaffold( + backgroundColor: Colors.grey.shade200, + body: const Loader(), + ); + } + }, + ), + ); + } +} \ No newline at end of file diff --git a/lib/features/feed/presentation/widgets/consultants.dart b/lib/features/feed/presentation/widgets/consultants.dart new file mode 100644 index 00000000..01c4e816 --- /dev/null +++ b/lib/features/feed/presentation/widgets/consultants.dart @@ -0,0 +1,62 @@ + import 'package:eatvio_app/core/widgets/loader.dart'; +import 'package:eatvio_app/features/feed/presentation/bloc/consultants_cubit/consultants_cubit.dart'; +import 'package:eatvio_app/features/feed/presentation/bloc/consultants_cubit/consultants_state.dart'; +import 'package:eatvio_app/features/feed/presentation/widgets/consultant_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +class Consultants extends StatelessWidget { + const Consultants({super.key}); + + @override + Widget build(BuildContext context) { + return RefreshIndicator( + onRefresh: () => context.read().getConsultants(), + child: BlocBuilder( + builder: (BuildContext context, ConsultantsState state) { + if (state is ConsultantsStateLoaded) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: Material( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: ListView.separated( + padding: EdgeInsets.symmetric(vertical: 16), + shrinkWrap: true, + physics: BouncingScrollPhysics(), + itemBuilder: (context, index) { + return ConsultantWidget(consultant: state.consultantsList[index]); + }, + separatorBuilder: (context, index) { + return SizedBox(height: 12); + }, + itemCount: state.consultantsList.length, + ), + ), + ), + ); + } else if (state is ConsultantsStateError) { + return Scaffold( + backgroundColor: Colors.grey.shade200, + body: Padding( + padding: const EdgeInsets.all(16), + child: Center( + child: Text(state.errorMessage), + ), + ), + ); + } else { + return Scaffold( + backgroundColor: Colors.grey.shade200, + body: const Loader(), + ); + } + }, + ), + ); + } +} + + \ No newline at end of file diff --git a/lib/features/feed/presentation/widgets/diets.dart b/lib/features/feed/presentation/widgets/diets.dart new file mode 100644 index 00000000..4d1ca2f3 --- /dev/null +++ b/lib/features/feed/presentation/widgets/diets.dart @@ -0,0 +1,66 @@ +import 'package:eatvio_app/core/widgets/loader.dart'; +import 'package:eatvio_app/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart'; +import 'package:eatvio_app/features/feed/presentation/bloc/diets_cubit/diets_state.dart'; +import 'package:eatvio_app/features/feed/presentation/widgets/diet_filter_bottom_sheet.dart'; +import 'package:eatvio_app/features/feed/presentation/widgets/diets_widget.dart'; +import 'package:eatvio_app/features/feed/presentation/widgets/filter_badge.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +class Diets extends StatelessWidget { + const Diets({super.key}); + + @override + Widget build(BuildContext context) { + return RefreshIndicator( + onRefresh: () => context.read().loadDiets(), + child: BlocBuilder( + builder: (BuildContext context, DietsState state) { + if (state.isLoading) { + return Scaffold( + backgroundColor: Colors.grey.shade200, + body: const Loader(), + ); + } else if (state.errorMessage != null) { + return Scaffold( + backgroundColor: Colors.grey.shade200, + body: Padding( + padding: const EdgeInsets.all(16), + child: Center( + child: Text(state.errorMessage ?? ''), + ), + ), + ); + } else { + return Stack( + children: [ + SizedBox.expand(), + ListView.separated( + padding: EdgeInsets.symmetric(vertical: 8), + shrinkWrap: true, + physics: BouncingScrollPhysics(), + itemBuilder: (context, index) { + return DietsWidget(diet: state.dietsList[index], index: index); + }, + separatorBuilder: (context, index) { + return SizedBox(height: 8); + }, + itemCount: state.dietsList.length, + ), + Positioned( + right: 0, + bottom: 74, + child: FilterBadge( + filterBottomSheet: DietFilterBottomSheet( + dietsCubit: context.read(), + ), + ), + ), + ], + ); + } + }, + ), + ); + } +} \ No newline at end of file diff --git a/lib/features/feed/presentation/widgets/plan_widget.dart b/lib/features/feed/presentation/widgets/plan_widget.dart index bc3baf86..a77c9b3e 100644 --- a/lib/features/feed/presentation/widgets/plan_widget.dart +++ b/lib/features/feed/presentation/widgets/plan_widget.dart @@ -5,7 +5,6 @@ import 'package:eatvio_app/core/widgets/info_row.dart'; import 'package:eatvio_app/core/widgets/feed_icon_button.dart'; import 'package:eatvio_app/features/diets/presentation/widgets/info_bouble.dart'; import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart'; -import 'package:eatvio_app/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart'; import 'package:eatvio_app/core/theme/custom_text_style.dart'; import 'package:eatvio_app/core/theme/theme_helper.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/plans_cubit/plans_cubit.dart'; @@ -183,7 +182,7 @@ class _PlanWidgetState extends State { iconColor: widget.plan.wasLikedByMe ? appTheme.blueA400 : null, backgroundColor: widget.plan.wasLikedByMe ? appTheme.transparentBlue : null, onTap: () async { - await context.read().likeDiet(widget.plan.id, widget.index); + await context.read().likePlan(widget.plan.slug, widget.index); }, ), SizedBox( diff --git a/lib/features/feed/presentation/widgets/plans.dart b/lib/features/feed/presentation/widgets/plans.dart new file mode 100644 index 00000000..940e677b --- /dev/null +++ b/lib/features/feed/presentation/widgets/plans.dart @@ -0,0 +1,68 @@ +import 'package:eatvio_app/core/widgets/loader.dart'; +import 'package:eatvio_app/features/feed/presentation/bloc/plans_cubit/plans_cubit.dart'; +import 'package:eatvio_app/features/feed/presentation/bloc/plans_cubit/plans_state.dart'; +import 'package:eatvio_app/features/feed/presentation/widgets/filter_badge.dart'; +import 'package:eatvio_app/features/feed/presentation/widgets/plan_widget.dart'; +import 'package:eatvio_app/features/feed/presentation/widgets/plans_filter_bottom_sheet.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +class Plans extends StatelessWidget { + const Plans({super.key}); + + @override + Widget build(BuildContext context) { + return RefreshIndicator( + onRefresh: () => context.read().loadPlans(), + child: BlocBuilder( + builder: (BuildContext context, PlansState state) { + if (state.isLoading) { + return Scaffold( + backgroundColor: Colors.grey.shade200, + body: const Loader(), + ); + } else if (state.errorMessage != null) { + return Scaffold( + backgroundColor: Colors.grey.shade200, + body: Padding( + padding: const EdgeInsets.all(16), + child: Center( + child: Text(state.errorMessage ?? ''), + ), + ), + ); + } + return Stack( + children: [ + SizedBox.expand(), + ListView.separated( + padding: EdgeInsets.symmetric(vertical: 8), + shrinkWrap: true, + physics: BouncingScrollPhysics(), + itemBuilder: (context, index) { + return PlanWidget( + plan: state.plans[index], + index: index, + ); + }, + separatorBuilder: (context, index) { + return SizedBox(height: 8); + }, + itemCount: state.plans.length, + ), + Positioned( + right: 0, + bottom: 74, + child: FilterBadge( + filterBottomSheet: PlansFilterBottomSheet( + plansCubit: context.read(), + ), + ), + ), + ], + ); + }, + ), + ); + } +} \ No newline at end of file diff --git a/lib/features/feed/presentation/widgets/recipes.dart b/lib/features/feed/presentation/widgets/recipes.dart new file mode 100644 index 00000000..9679e81c --- /dev/null +++ b/lib/features/feed/presentation/widgets/recipes.dart @@ -0,0 +1,50 @@ +import 'package:eatvio_app/core/widgets/loader.dart'; +import 'package:eatvio_app/features/feed/presentation/bloc/recipes_cubit/recipes_cubit.dart'; +import 'package:eatvio_app/features/feed/presentation/bloc/recipes_cubit/recipes_state.dart'; +import 'package:eatvio_app/features/feed/presentation/widgets/recipes_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +class Recipes extends StatelessWidget { + const Recipes({super.key}); + + @override + Widget build(BuildContext context) { + return RefreshIndicator( + onRefresh: () => context.read().loadRecipesList(), + child: BlocBuilder( + builder: (BuildContext context, RecipesState state) { + if (state is RecipesStateLoaded) { + return ListView.separated( + padding: EdgeInsets.symmetric(vertical: 8), + shrinkWrap: true, + physics: BouncingScrollPhysics(), + itemBuilder: (context, index) { + return RecipesWidget(recipes: state.recipesList[index]); + }, + separatorBuilder: (context, index) { + return SizedBox(height: 8); + }, + itemCount: state.recipesList.length, + ); + } else if (state is RecipesStateError) { + return Scaffold( + backgroundColor: Colors.grey.shade200, + body: Padding( + padding: const EdgeInsets.all(16), + child: Center( + child: Text(state.errorMessage), + ), + ), + ); + } else { + return Scaffold( + backgroundColor: Colors.grey.shade200, + body: const Loader(), + ); + } + }, + ), + ); + } +} \ No newline at end of file diff --git a/lib/features/feed/services/feed_service.g.dart b/lib/features/feed/services/feed_service.g.dart index 17825316..c6668b66 100644 --- a/lib/features/feed/services/feed_service.g.dart +++ b/lib/features/feed/services/feed_service.g.dart @@ -9,7 +9,11 @@ part of 'feed_service.dart'; // ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element,unnecessary_string_interpolations class _FeedService implements FeedService { - _FeedService(this._dio, {this.baseUrl, this.errorLogger}); + _FeedService( + this._dio, { + this.baseUrl, + this.errorLogger, + }); final Dio _dio; @@ -30,16 +34,22 @@ class _FeedService implements FeedService { queryParameters.removeWhere((k, v) => v == null); final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/blogPosts/index', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/blogPosts/index', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late FeedBlogPostSettingsModel _value; try { @@ -66,16 +76,22 @@ class _FeedService implements FeedService { queryParameters.removeWhere((k, v) => v == null); final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/recipes/index', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/recipes/index', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late RecipesPagination _value; try { @@ -106,16 +122,22 @@ class _FeedService implements FeedService { queryParameters.removeWhere((k, v) => v == null); final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/diets/index', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diets/index', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late DietsPagination _value; try { @@ -148,16 +170,22 @@ class _FeedService implements FeedService { queryParameters.removeWhere((k, v) => v == null); final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/plans/index', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/plans/index', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late PlanPaginationModel _value; try { @@ -175,16 +203,22 @@ class _FeedService implements FeedService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/blogPosts/${id}/comments/show', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/blogPosts/${id}/comments/show', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late CommentModel _value; try { @@ -207,20 +241,32 @@ class _FeedService implements FeedService { queryParameters.removeWhere((k, v) => v == null); final _headers = {}; final _data = FormData(); - _data.fields.add(MapEntry('body', body)); + _data.fields.add(MapEntry( + 'body', + body, + )); if (parentCommentId != null) { - _data.fields.add(MapEntry('parentCommentId', parentCommentId.toString())); + _data.fields.add(MapEntry( + 'parentCommentId', + parentCommentId.toString(), + )); } - final _options = _setStreamType( - Options(method: 'POST', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/blogPosts/${id}/comment/create', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/blogPosts/${id}/comment/create', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } @@ -230,16 +276,22 @@ class _FeedService implements FeedService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/diets/${id}/comments/show', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diets/${id}/comments/show', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late CommentModel _value; try { @@ -262,20 +314,32 @@ class _FeedService implements FeedService { queryParameters.removeWhere((k, v) => v == null); final _headers = {}; final _data = FormData(); - _data.fields.add(MapEntry('body', body)); + _data.fields.add(MapEntry( + 'body', + body, + )); if (parentCommentId != null) { - _data.fields.add(MapEntry('parentCommentId', parentCommentId.toString())); + _data.fields.add(MapEntry( + 'parentCommentId', + parentCommentId.toString(), + )); } - final _options = _setStreamType( - Options(method: 'POST', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/diets/${id}/comment/create', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diets/${id}/comment/create', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } @@ -285,16 +349,22 @@ class _FeedService implements FeedService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/plans/${slug}/comments/show', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/plans/${slug}/comments/show', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late CommentModel _value; try { @@ -317,20 +387,32 @@ class _FeedService implements FeedService { queryParameters.removeWhere((k, v) => v == null); final _headers = {}; final _data = FormData(); - _data.fields.add(MapEntry('body', body)); + _data.fields.add(MapEntry( + 'body', + body, + )); if (parentCommentId != null) { - _data.fields.add(MapEntry('parentCommentId', parentCommentId.toString())); + _data.fields.add(MapEntry( + 'parentCommentId', + parentCommentId.toString(), + )); } - final _options = _setStreamType( - Options(method: 'POST', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/plans/${slug}/comment/create', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/plans/${slug}/comment/create', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } @@ -340,16 +422,22 @@ class _FeedService implements FeedService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/recipes/${id}/comments/show', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/recipes/${id}/comments/show', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late CommentModel _value; try { @@ -372,20 +460,32 @@ class _FeedService implements FeedService { queryParameters.removeWhere((k, v) => v == null); final _headers = {}; final _data = FormData(); - _data.fields.add(MapEntry('body', body)); + _data.fields.add(MapEntry( + 'body', + body, + )); if (parentCommentId != null) { - _data.fields.add(MapEntry('parentCommentId', parentCommentId.toString())); + _data.fields.add(MapEntry( + 'parentCommentId', + parentCommentId.toString(), + )); } - final _options = _setStreamType( - Options(method: 'POST', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/recipes/${id}/comment/create', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/recipes/${id}/comment/create', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } @@ -395,16 +495,22 @@ class _FeedService implements FeedService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'POST', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/blogPosts/${id}/like', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/blogPosts/${id}/like', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } @@ -414,16 +520,22 @@ class _FeedService implements FeedService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'POST', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/blogPosts/${id}/unliked', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/blogPosts/${id}/unliked', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } @@ -433,16 +545,22 @@ class _FeedService implements FeedService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/consultants/index', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/consultants/index', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late FeedConsultantPaginationModel _value; try { @@ -467,7 +585,10 @@ class _FeedService implements FeedService { return requestOptions; } - String _combineBaseUrls(String dioBaseUrl, String? baseUrl) { + String _combineBaseUrls( + String dioBaseUrl, + String? baseUrl, + ) { if (baseUrl == null || baseUrl.trim().isEmpty) { return dioBaseUrl; } diff --git a/lib/features/glossary/services/glossary_service.g.dart b/lib/features/glossary/services/glossary_service.g.dart index cd6584f6..bd3a1137 100644 --- a/lib/features/glossary/services/glossary_service.g.dart +++ b/lib/features/glossary/services/glossary_service.g.dart @@ -9,7 +9,11 @@ part of 'glossary_service.dart'; // ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element,unnecessary_string_interpolations class _GlossaryService implements GlossaryService { - _GlossaryService(this._dio, {this.baseUrl, this.errorLogger}); + _GlossaryService( + this._dio, { + this.baseUrl, + this.errorLogger, + }); final Dio _dio; @@ -18,23 +22,28 @@ class _GlossaryService implements GlossaryService { final ParseErrorLogger? errorLogger; @override - Future getGlossaryByQuery({ - required String query, - }) async { + Future getGlossaryByQuery( + {required String query}) async { final _extra = {}; final queryParameters = {r'search': query}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/glossaries/search', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/glossaries/search', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late GlossaryPaginationModel _value; try { @@ -59,7 +68,10 @@ class _GlossaryService implements GlossaryService { return requestOptions; } - String _combineBaseUrls(String dioBaseUrl, String? baseUrl) { + String _combineBaseUrls( + String dioBaseUrl, + String? baseUrl, + ) { if (baseUrl == null || baseUrl.trim().isEmpty) { return dioBaseUrl; } diff --git a/lib/features/menu/presentation/pages/menu_screen.dart b/lib/features/menu/presentation/pages/menu_screen.dart index 777b8233..7f784c9d 100644 --- a/lib/features/menu/presentation/pages/menu_screen.dart +++ b/lib/features/menu/presentation/pages/menu_screen.dart @@ -4,6 +4,7 @@ import 'package:eatvio_app/core/token_storage.dart'; import 'package:eatvio_app/core/utils/image_constant.dart'; import 'package:eatvio_app/core/locator_service.dart'; import 'package:eatvio_app/core/theme/theme_helper.dart'; +import 'package:eatvio_app/features/dev_tools/presentation/dev_tools_screen.dart'; import 'package:eatvio_app/features/my_diets/presentation/my_diets_screen.dart'; import 'package:eatvio_app/features/my_plans/presentation/my_plans_screen.dart'; import 'package:flutter/material.dart'; @@ -65,6 +66,14 @@ class MenuScreen extends StatelessWidget { onTap: () => GoRouter.of(context).push('/support-screen'), ), _divider(context), + _tile( + leading: ImageConstant.icnSupport, + title: 'Для разработчиков', + onTap: () { + GoRouter.of(context).pushNamed(DevToolsScreen.name); + }, + ), + _divider(context), _tile( leading: ImageConstant.icnExit, title: 'Выход', diff --git a/lib/features/my_diets/services/my_diets_service.dart b/lib/features/my_diets/services/my_diets_service.dart index e2bba8a0..3a78d25e 100644 --- a/lib/features/my_diets/services/my_diets_service.dart +++ b/lib/features/my_diets/services/my_diets_service.dart @@ -9,7 +9,7 @@ abstract class MyDietsService { factory MyDietsService(Dio dio, {String baseUrl}) = _MyDietsService; - @GET('/api/diets/index') + @GET('/api/profile/my_diets') Future getDiets({ @Query('page') required int page, @Query('filters[name][\$startsWith]') String? query, diff --git a/lib/features/my_diets/services/my_diets_service.g.dart b/lib/features/my_diets/services/my_diets_service.g.dart index 3588c0ac..61371ae2 100644 --- a/lib/features/my_diets/services/my_diets_service.g.dart +++ b/lib/features/my_diets/services/my_diets_service.g.dart @@ -9,7 +9,11 @@ part of 'my_diets_service.dart'; // ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element,unnecessary_string_interpolations class _MyDietsService implements MyDietsService { - _MyDietsService(this._dio, {this.baseUrl, this.errorLogger}); + _MyDietsService( + this._dio, { + this.baseUrl, + this.errorLogger, + }); final Dio _dio; @@ -36,16 +40,22 @@ class _MyDietsService implements MyDietsService { queryParameters.removeWhere((k, v) => v == null); final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/diets/index', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/profile/my_diets', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late DietsPagination _value; try { @@ -63,16 +73,22 @@ class _MyDietsService implements MyDietsService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'POST', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/diets/delete/${dietId}', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diets/delete/${dietId}', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } @@ -89,7 +105,10 @@ class _MyDietsService implements MyDietsService { return requestOptions; } - String _combineBaseUrls(String dioBaseUrl, String? baseUrl) { + String _combineBaseUrls( + String dioBaseUrl, + String? baseUrl, + ) { if (baseUrl == null || baseUrl.trim().isEmpty) { return dioBaseUrl; } diff --git a/lib/features/my_plans/services/my_plans_service.g.dart b/lib/features/my_plans/services/my_plans_service.g.dart index 4e4804e0..dd70281f 100644 --- a/lib/features/my_plans/services/my_plans_service.g.dart +++ b/lib/features/my_plans/services/my_plans_service.g.dart @@ -9,7 +9,11 @@ part of 'my_plans_service.dart'; // ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element,unnecessary_string_interpolations class _MyPlansService implements MyPlansService { - _MyPlansService(this._dio, {this.baseUrl, this.errorLogger}); + _MyPlansService( + this._dio, { + this.baseUrl, + this.errorLogger, + }); final Dio _dio; @@ -38,16 +42,22 @@ class _MyPlansService implements MyPlansService { queryParameters.removeWhere((k, v) => v == null); final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/plans/index', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/plans/index', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late PlanPaginationModel _value; try { @@ -65,16 +75,22 @@ class _MyPlansService implements MyPlansService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'POST', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/plans/delete/${slug}', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/plans/delete/${slug}', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } @@ -91,7 +107,10 @@ class _MyPlansService implements MyPlansService { return requestOptions; } - String _combineBaseUrls(String dioBaseUrl, String? baseUrl) { + String _combineBaseUrls( + String dioBaseUrl, + String? baseUrl, + ) { if (baseUrl == null || baseUrl.trim().isEmpty) { return dioBaseUrl; } diff --git a/lib/features/plans/presentation/pages/about_plan_screen.dart b/lib/features/plans/presentation/pages/about_plan_screen.dart index 3392e523..db415e15 100644 --- a/lib/features/plans/presentation/pages/about_plan_screen.dart +++ b/lib/features/plans/presentation/pages/about_plan_screen.dart @@ -363,13 +363,11 @@ class _AboutPlanScreenState extends State { 'assets/icons/heart.svg', width: 14, height: 12, - - /// TODO задача для бека на добавление wasLokedByMe? - colorFilter: ColorFilter.mode(appTheme.blueA400, BlendMode.srcIn), + colorFilter: state.planModel?.wasLikedByMe == true ? ColorFilter.mode(appTheme.blueA400, BlendMode.srcIn) : null, ), SizedBox(width: 8), Text( - widget.plan.totalLikes.toString(), + state.planModel?.totalLikes.toString() ?? '0', style: TextStyles.textXSSemibold.copyWith(color: appTheme.black), ), ], diff --git a/lib/features/plans/services/plan_service.g.dart b/lib/features/plans/services/plan_service.g.dart index 09f90b41..71abb5af 100644 --- a/lib/features/plans/services/plan_service.g.dart +++ b/lib/features/plans/services/plan_service.g.dart @@ -9,7 +9,11 @@ part of 'plan_service.dart'; // ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element,unnecessary_string_interpolations class _PlanService implements PlanService { - _PlanService(this._dio, {this.baseUrl, this.errorLogger}); + _PlanService( + this._dio, { + this.baseUrl, + this.errorLogger, + }); final Dio _dio; @@ -23,16 +27,22 @@ class _PlanService implements PlanService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/plans/show/${slug}', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/plans/show/${slug}', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late PlanModel _value; try { @@ -50,16 +60,22 @@ class _PlanService implements PlanService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'POST', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/plans/${slug}/like', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/plans/${slug}/like', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } @@ -69,16 +85,22 @@ class _PlanService implements PlanService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'POST', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/plans/${slug}/add_to_favorite', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/plans/${slug}/add_to_favorite', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } @@ -88,16 +110,22 @@ class _PlanService implements PlanService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'POST', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/plans/${slug}/remove_from_favorite', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/plans/${slug}/remove_from_favorite', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } @@ -114,7 +142,10 @@ class _PlanService implements PlanService { return requestOptions; } - String _combineBaseUrls(String dioBaseUrl, String? baseUrl) { + String _combineBaseUrls( + String dioBaseUrl, + String? baseUrl, + ) { if (baseUrl == null || baseUrl.trim().isEmpty) { return dioBaseUrl; } diff --git a/lib/features/plans/services/plans_service.g.dart b/lib/features/plans/services/plans_service.g.dart index 3e4ebdf1..7fe37d3d 100644 --- a/lib/features/plans/services/plans_service.g.dart +++ b/lib/features/plans/services/plans_service.g.dart @@ -9,7 +9,11 @@ part of 'plans_service.dart'; // ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element,unnecessary_string_interpolations class _PlansService implements PlansService { - _PlansService(this._dio, {this.baseUrl, this.errorLogger}); + _PlansService( + this._dio, { + this.baseUrl, + this.errorLogger, + }); final Dio _dio; @@ -23,16 +27,22 @@ class _PlansService implements PlansService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/plans/get_by_author/${author}', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/plans/get_by_author/${author}', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late PlanPaginationModel _value; try { @@ -57,7 +67,10 @@ class _PlansService implements PlansService { return requestOptions; } - String _combineBaseUrls(String dioBaseUrl, String? baseUrl) { + String _combineBaseUrls( + String dioBaseUrl, + String? baseUrl, + ) { if (baseUrl == null || baseUrl.trim().isEmpty) { return dioBaseUrl; } diff --git a/lib/features/profile/models/chosen_diets_pagination_model.dart b/lib/features/profile/models/chosen_diets_pagination_model.dart new file mode 100644 index 00000000..7f025d5f --- /dev/null +++ b/lib/features/profile/models/chosen_diets_pagination_model.dart @@ -0,0 +1,32 @@ +import 'package:eatvio_app/features/feed/models/feed_blog_post_model.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'chosen_diets_pagination_model.freezed.dart'; +part 'chosen_diets_pagination_model.g.dart'; + +@freezed +class ChosenDietsPaginationModel with _$ChosenDietsPaginationModel { + factory ChosenDietsPaginationModel({ + @JsonKey(name: 'data') required List diets, + }) = _ChosenDietsPaginationModel; + + factory ChosenDietsPaginationModel.fromJson(Map json) => _$ChosenDietsPaginationModelFromJson(json); +} + +@freezed +class ChosenDietModel with _$ChosenDietModel { + factory ChosenDietModel({ + @JsonKey(name: 'id') required int chosenDietID, + @JsonKey(name: 'chosen_plan_id') required int chosenPlanId, + @JsonKey() required String state, + @JsonKey(name: 'start_date', fromJson: parseDate) required DateTime startDate, + @JsonKey(name: 'diet', fromJson: _parseDietId) required int? dietId, + }) = _ChosenDietModel; + + factory ChosenDietModel.fromJson(Map json) => _$ChosenDietModelFromJson(json); +} + +int? _parseDietId(json) { + if (json == null) return null; + return json['id'] as int?; +} diff --git a/lib/features/profile/models/chosen_diets_pagination_model.freezed.dart b/lib/features/profile/models/chosen_diets_pagination_model.freezed.dart new file mode 100644 index 00000000..3514c6a3 --- /dev/null +++ b/lib/features/profile/models/chosen_diets_pagination_model.freezed.dart @@ -0,0 +1,441 @@ +// 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 'chosen_diets_pagination_model.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'); + +ChosenDietsPaginationModel _$ChosenDietsPaginationModelFromJson( + Map json) { + return _ChosenDietsPaginationModel.fromJson(json); +} + +/// @nodoc +mixin _$ChosenDietsPaginationModel { + @JsonKey(name: 'data') + List get diets => throw _privateConstructorUsedError; + + /// Serializes this ChosenDietsPaginationModel to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of ChosenDietsPaginationModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $ChosenDietsPaginationModelCopyWith + get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ChosenDietsPaginationModelCopyWith<$Res> { + factory $ChosenDietsPaginationModelCopyWith(ChosenDietsPaginationModel value, + $Res Function(ChosenDietsPaginationModel) then) = + _$ChosenDietsPaginationModelCopyWithImpl<$Res, + ChosenDietsPaginationModel>; + @useResult + $Res call({@JsonKey(name: 'data') List diets}); +} + +/// @nodoc +class _$ChosenDietsPaginationModelCopyWithImpl<$Res, + $Val extends ChosenDietsPaginationModel> + implements $ChosenDietsPaginationModelCopyWith<$Res> { + _$ChosenDietsPaginationModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of ChosenDietsPaginationModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? diets = null, + }) { + return _then(_value.copyWith( + diets: null == diets + ? _value.diets + : diets // ignore: cast_nullable_to_non_nullable + as List, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$ChosenDietsPaginationModelImplCopyWith<$Res> + implements $ChosenDietsPaginationModelCopyWith<$Res> { + factory _$$ChosenDietsPaginationModelImplCopyWith( + _$ChosenDietsPaginationModelImpl value, + $Res Function(_$ChosenDietsPaginationModelImpl) then) = + __$$ChosenDietsPaginationModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({@JsonKey(name: 'data') List diets}); +} + +/// @nodoc +class __$$ChosenDietsPaginationModelImplCopyWithImpl<$Res> + extends _$ChosenDietsPaginationModelCopyWithImpl<$Res, + _$ChosenDietsPaginationModelImpl> + implements _$$ChosenDietsPaginationModelImplCopyWith<$Res> { + __$$ChosenDietsPaginationModelImplCopyWithImpl( + _$ChosenDietsPaginationModelImpl _value, + $Res Function(_$ChosenDietsPaginationModelImpl) _then) + : super(_value, _then); + + /// Create a copy of ChosenDietsPaginationModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? diets = null, + }) { + return _then(_$ChosenDietsPaginationModelImpl( + diets: null == diets + ? _value._diets + : diets // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$ChosenDietsPaginationModelImpl implements _ChosenDietsPaginationModel { + _$ChosenDietsPaginationModelImpl( + {@JsonKey(name: 'data') required final List diets}) + : _diets = diets; + + factory _$ChosenDietsPaginationModelImpl.fromJson( + Map json) => + _$$ChosenDietsPaginationModelImplFromJson(json); + + final List _diets; + @override + @JsonKey(name: 'data') + List get diets { + if (_diets is EqualUnmodifiableListView) return _diets; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_diets); + } + + @override + String toString() { + return 'ChosenDietsPaginationModel(diets: $diets)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ChosenDietsPaginationModelImpl && + const DeepCollectionEquality().equals(other._diets, _diets)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => + Object.hash(runtimeType, const DeepCollectionEquality().hash(_diets)); + + /// Create a copy of ChosenDietsPaginationModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$ChosenDietsPaginationModelImplCopyWith<_$ChosenDietsPaginationModelImpl> + get copyWith => __$$ChosenDietsPaginationModelImplCopyWithImpl< + _$ChosenDietsPaginationModelImpl>(this, _$identity); + + @override + Map toJson() { + return _$$ChosenDietsPaginationModelImplToJson( + this, + ); + } +} + +abstract class _ChosenDietsPaginationModel + implements ChosenDietsPaginationModel { + factory _ChosenDietsPaginationModel( + {@JsonKey(name: 'data') required final List diets}) = + _$ChosenDietsPaginationModelImpl; + + factory _ChosenDietsPaginationModel.fromJson(Map json) = + _$ChosenDietsPaginationModelImpl.fromJson; + + @override + @JsonKey(name: 'data') + List get diets; + + /// Create a copy of ChosenDietsPaginationModel + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$ChosenDietsPaginationModelImplCopyWith<_$ChosenDietsPaginationModelImpl> + get copyWith => throw _privateConstructorUsedError; +} + +ChosenDietModel _$ChosenDietModelFromJson(Map json) { + return _ChosenDietModel.fromJson(json); +} + +/// @nodoc +mixin _$ChosenDietModel { + @JsonKey(name: 'id') + int get chosenDietID => throw _privateConstructorUsedError; + @JsonKey(name: 'chosen_plan_id') + int get chosenPlanId => throw _privateConstructorUsedError; + @JsonKey() + String get state => throw _privateConstructorUsedError; + @JsonKey(name: 'start_date', fromJson: parseDate) + DateTime get startDate => throw _privateConstructorUsedError; + @JsonKey(name: 'diet', fromJson: _parseDietId) + int? get dietId => throw _privateConstructorUsedError; + + /// Serializes this ChosenDietModel to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of ChosenDietModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $ChosenDietModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ChosenDietModelCopyWith<$Res> { + factory $ChosenDietModelCopyWith( + ChosenDietModel value, $Res Function(ChosenDietModel) then) = + _$ChosenDietModelCopyWithImpl<$Res, ChosenDietModel>; + @useResult + $Res call( + {@JsonKey(name: 'id') int chosenDietID, + @JsonKey(name: 'chosen_plan_id') int chosenPlanId, + @JsonKey() String state, + @JsonKey(name: 'start_date', fromJson: parseDate) DateTime startDate, + @JsonKey(name: 'diet', fromJson: _parseDietId) int? dietId}); +} + +/// @nodoc +class _$ChosenDietModelCopyWithImpl<$Res, $Val extends ChosenDietModel> + implements $ChosenDietModelCopyWith<$Res> { + _$ChosenDietModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of ChosenDietModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? chosenDietID = null, + Object? chosenPlanId = null, + Object? state = null, + Object? startDate = null, + Object? dietId = freezed, + }) { + return _then(_value.copyWith( + chosenDietID: null == chosenDietID + ? _value.chosenDietID + : chosenDietID // ignore: cast_nullable_to_non_nullable + as int, + chosenPlanId: null == chosenPlanId + ? _value.chosenPlanId + : chosenPlanId // ignore: cast_nullable_to_non_nullable + as int, + state: null == state + ? _value.state + : state // ignore: cast_nullable_to_non_nullable + as String, + startDate: null == startDate + ? _value.startDate + : startDate // ignore: cast_nullable_to_non_nullable + as DateTime, + dietId: freezed == dietId + ? _value.dietId + : dietId // ignore: cast_nullable_to_non_nullable + as int?, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$ChosenDietModelImplCopyWith<$Res> + implements $ChosenDietModelCopyWith<$Res> { + factory _$$ChosenDietModelImplCopyWith(_$ChosenDietModelImpl value, + $Res Function(_$ChosenDietModelImpl) then) = + __$$ChosenDietModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {@JsonKey(name: 'id') int chosenDietID, + @JsonKey(name: 'chosen_plan_id') int chosenPlanId, + @JsonKey() String state, + @JsonKey(name: 'start_date', fromJson: parseDate) DateTime startDate, + @JsonKey(name: 'diet', fromJson: _parseDietId) int? dietId}); +} + +/// @nodoc +class __$$ChosenDietModelImplCopyWithImpl<$Res> + extends _$ChosenDietModelCopyWithImpl<$Res, _$ChosenDietModelImpl> + implements _$$ChosenDietModelImplCopyWith<$Res> { + __$$ChosenDietModelImplCopyWithImpl( + _$ChosenDietModelImpl _value, $Res Function(_$ChosenDietModelImpl) _then) + : super(_value, _then); + + /// Create a copy of ChosenDietModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? chosenDietID = null, + Object? chosenPlanId = null, + Object? state = null, + Object? startDate = null, + Object? dietId = freezed, + }) { + return _then(_$ChosenDietModelImpl( + chosenDietID: null == chosenDietID + ? _value.chosenDietID + : chosenDietID // ignore: cast_nullable_to_non_nullable + as int, + chosenPlanId: null == chosenPlanId + ? _value.chosenPlanId + : chosenPlanId // ignore: cast_nullable_to_non_nullable + as int, + state: null == state + ? _value.state + : state // ignore: cast_nullable_to_non_nullable + as String, + startDate: null == startDate + ? _value.startDate + : startDate // ignore: cast_nullable_to_non_nullable + as DateTime, + dietId: freezed == dietId + ? _value.dietId + : dietId // ignore: cast_nullable_to_non_nullable + as int?, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$ChosenDietModelImpl implements _ChosenDietModel { + _$ChosenDietModelImpl( + {@JsonKey(name: 'id') required this.chosenDietID, + @JsonKey(name: 'chosen_plan_id') required this.chosenPlanId, + @JsonKey() required this.state, + @JsonKey(name: 'start_date', fromJson: parseDate) required this.startDate, + @JsonKey(name: 'diet', fromJson: _parseDietId) required this.dietId}); + + factory _$ChosenDietModelImpl.fromJson(Map json) => + _$$ChosenDietModelImplFromJson(json); + + @override + @JsonKey(name: 'id') + final int chosenDietID; + @override + @JsonKey(name: 'chosen_plan_id') + final int chosenPlanId; + @override + @JsonKey() + final String state; + @override + @JsonKey(name: 'start_date', fromJson: parseDate) + final DateTime startDate; + @override + @JsonKey(name: 'diet', fromJson: _parseDietId) + final int? dietId; + + @override + String toString() { + return 'ChosenDietModel(chosenDietID: $chosenDietID, chosenPlanId: $chosenPlanId, state: $state, startDate: $startDate, dietId: $dietId)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ChosenDietModelImpl && + (identical(other.chosenDietID, chosenDietID) || + other.chosenDietID == chosenDietID) && + (identical(other.chosenPlanId, chosenPlanId) || + other.chosenPlanId == chosenPlanId) && + (identical(other.state, state) || other.state == state) && + (identical(other.startDate, startDate) || + other.startDate == startDate) && + (identical(other.dietId, dietId) || other.dietId == dietId)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash( + runtimeType, chosenDietID, chosenPlanId, state, startDate, dietId); + + /// Create a copy of ChosenDietModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$ChosenDietModelImplCopyWith<_$ChosenDietModelImpl> get copyWith => + __$$ChosenDietModelImplCopyWithImpl<_$ChosenDietModelImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$ChosenDietModelImplToJson( + this, + ); + } +} + +abstract class _ChosenDietModel implements ChosenDietModel { + factory _ChosenDietModel( + {@JsonKey(name: 'id') required final int chosenDietID, + @JsonKey(name: 'chosen_plan_id') required final int chosenPlanId, + @JsonKey() required final String state, + @JsonKey(name: 'start_date', fromJson: parseDate) + required final DateTime startDate, + @JsonKey(name: 'diet', fromJson: _parseDietId) + required final int? dietId}) = _$ChosenDietModelImpl; + + factory _ChosenDietModel.fromJson(Map json) = + _$ChosenDietModelImpl.fromJson; + + @override + @JsonKey(name: 'id') + int get chosenDietID; + @override + @JsonKey(name: 'chosen_plan_id') + int get chosenPlanId; + @override + @JsonKey() + String get state; + @override + @JsonKey(name: 'start_date', fromJson: parseDate) + DateTime get startDate; + @override + @JsonKey(name: 'diet', fromJson: _parseDietId) + int? get dietId; + + /// Create a copy of ChosenDietModel + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$ChosenDietModelImplCopyWith<_$ChosenDietModelImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/features/profile/models/chosen_diets_pagination_model.g.dart b/lib/features/profile/models/chosen_diets_pagination_model.g.dart new file mode 100644 index 00000000..75d8ffa1 --- /dev/null +++ b/lib/features/profile/models/chosen_diets_pagination_model.g.dart @@ -0,0 +1,41 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'chosen_diets_pagination_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$ChosenDietsPaginationModelImpl _$$ChosenDietsPaginationModelImplFromJson( + Map json) => + _$ChosenDietsPaginationModelImpl( + diets: (json['data'] as List) + .map((e) => ChosenDietModel.fromJson(e as Map)) + .toList(), + ); + +Map _$$ChosenDietsPaginationModelImplToJson( + _$ChosenDietsPaginationModelImpl instance) => + { + 'data': instance.diets, + }; + +_$ChosenDietModelImpl _$$ChosenDietModelImplFromJson( + Map json) => + _$ChosenDietModelImpl( + chosenDietID: (json['id'] as num).toInt(), + chosenPlanId: (json['chosen_plan_id'] as num).toInt(), + state: json['state'] as String, + startDate: parseDate(json['start_date'] as String), + dietId: _parseDietId(json['diet']), + ); + +Map _$$ChosenDietModelImplToJson( + _$ChosenDietModelImpl instance) => + { + 'id': instance.chosenDietID, + 'chosen_plan_id': instance.chosenPlanId, + 'state': instance.state, + 'start_date': instance.startDate.toIso8601String(), + 'diet': instance.dietId, + }; diff --git a/lib/features/profile/presentation/pages/profile_screen.dart b/lib/features/profile/presentation/pages/profile_screen.dart index 98b18d58..19a20315 100644 --- a/lib/features/profile/presentation/pages/profile_screen.dart +++ b/lib/features/profile/presentation/pages/profile_screen.dart @@ -59,7 +59,6 @@ class _ProfileScreenState extends State { late bool canSub; bool isFirstFetch = true; int _currentBullet = 0; - @override void initState() { super.initState(); @@ -338,7 +337,7 @@ class _ProfileScreenState extends State { padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: InkWell( onTap: () { - GoRouter.of(context).pushNamed('blogPostCreateScreen'); + GoRouter.of(context).pushNamed('blogPostCreateScreen'); }, borderRadius: BorderRadius.circular(8), child: Ink( diff --git a/lib/features/profile/services/profile_service.dart b/lib/features/profile/services/profile_service.dart index d357ea3a..c6bed688 100644 --- a/lib/features/profile/services/profile_service.dart +++ b/lib/features/profile/services/profile_service.dart @@ -2,6 +2,7 @@ import 'dart:io'; import 'package:dio/dio.dart'; import 'package:eatvio_app/features/feed/models/feed_blog_post_model.dart'; +import 'package:eatvio_app/features/profile/models/chosen_diets_pagination_model.dart'; import 'package:eatvio_app/features/profile/models/circumference_model.dart'; import 'package:eatvio_app/features/profile/models/profile_model.dart'; import 'package:eatvio_app/features/profile/models/sub_model.dart'; @@ -99,4 +100,7 @@ abstract class ProfileService { @DELETE('/api/profile/photo/delete') Future deletePhoto(); + + @GET('/api/profile/chosen_diets') + Future getChosenDiets(); } diff --git a/lib/features/profile/services/profile_service.g.dart b/lib/features/profile/services/profile_service.g.dart index 532747e6..4d9c61a4 100644 --- a/lib/features/profile/services/profile_service.g.dart +++ b/lib/features/profile/services/profile_service.g.dart @@ -9,7 +9,11 @@ part of 'profile_service.dart'; // ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element,unnecessary_string_interpolations class _ProfileService implements ProfileService { - _ProfileService(this._dio, {this.baseUrl, this.errorLogger}); + _ProfileService( + this._dio, { + this.baseUrl, + this.errorLogger, + }); final Dio _dio; @@ -23,16 +27,22 @@ class _ProfileService implements ProfileService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/profile/show/${slug}', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/profile/show/${slug}', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late ProfileModel _value; try { @@ -50,16 +60,22 @@ class _ProfileService implements ProfileService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/profile/index', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/profile/index', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late ProfileModel _value; try { @@ -77,16 +93,22 @@ class _ProfileService implements ProfileService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/profile/detailz', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/profile/detailz', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late ProfileDetailsModel _value; try { @@ -99,23 +121,28 @@ class _ProfileService implements ProfileService { } @override - Future getProfileDetailsBySlug({ - required String slug, - }) async { + Future getProfileDetailsBySlug( + {required String slug}) async { final _extra = {}; final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/profile/detailz/${slug}', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/profile/detailz/${slug}', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late ProfileDetailsModel _value; try { @@ -137,25 +164,34 @@ class _ProfileService implements ProfileService { 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)), - ); + _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, + ))); await _dio.fetch(_options); } @@ -165,46 +201,58 @@ class _ProfileService implements ProfileService { final queryParameters = {}; final _headers = {}; final _data = FormData(); - _data.fields.add(MapEntry('weight', weight.toString())); - final _options = _setStreamType( - Options(method: 'POST', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/profile/addWeight', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + _data.fields.add(MapEntry( + 'weight', + weight.toString(), + )); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/profile/addWeight', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } @override - Future> getBlogPostByAuthorSlug({ - required String slug, - }) async { + Future> getBlogPostByAuthorSlug( + {required String slug}) async { final _extra = {}; final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType>( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/blogPosts/search_by_author/${slug}', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType>(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/blogPosts/search_by_author/${slug}', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late List _value; try { _value = _result.data! - .map( - (dynamic i) => - FeedBlogPostModel.fromJson(i as Map), - ) + .map((dynamic i) => + FeedBlogPostModel.fromJson(i as Map)) .toList(); } on Object catch (e, s) { errorLogger?.logError(e, s, _options); @@ -219,23 +267,27 @@ class _ProfileService implements ProfileService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType>( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/profile/measure/weight/${period}', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType>(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/profile/measure/weight/${period}', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late List _value; try { _value = _result.data! - .map( - (dynamic i) => WeightModel.fromJson(i as Map), - ) + .map((dynamic i) => WeightModel.fromJson(i as Map)) .toList(); } on Object catch (e, s) { errorLogger?.logError(e, s, _options); @@ -253,23 +305,27 @@ class _ProfileService implements ProfileService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType>( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/profile/measure/weight/${period}/${slug}', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType>(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/profile/measure/weight/${period}/${slug}', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late List _value; try { _value = _result.data! - .map( - (dynamic i) => WeightModel.fromJson(i as Map), - ) + .map((dynamic i) => WeightModel.fromJson(i as Map)) .toList(); } on Object catch (e, s) { errorLogger?.logError(e, s, _options); @@ -279,31 +335,34 @@ class _ProfileService implements ProfileService { } @override - Future> getCircumferences({ - required String period, - }) async { + Future> getCircumferences( + {required String period}) async { final _extra = {}; final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType>( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/profile/measure/circumferences/${period}', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType>(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/profile/measure/circumferences/${period}', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late List _value; try { _value = _result.data! - .map( - (dynamic i) => - CircumferenceModel.fromJson(i as Map), - ) + .map((dynamic i) => + CircumferenceModel.fromJson(i as Map)) .toList(); } on Object catch (e, s) { errorLogger?.logError(e, s, _options); @@ -321,24 +380,28 @@ class _ProfileService implements ProfileService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType>( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/profile/measure/circumferences/${period}/{user}', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType>(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/profile/measure/circumferences/${period}/{user}', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late List _value; try { _value = _result.data! - .map( - (dynamic i) => - CircumferenceModel.fromJson(i as Map), - ) + .map((dynamic i) => + CircumferenceModel.fromJson(i as Map)) .toList(); } on Object catch (e, s) { errorLogger?.logError(e, s, _options); @@ -354,21 +417,27 @@ class _ProfileService implements ProfileService { }) async { final _extra = {}; final queryParameters = { - r'filters[name][$startsWith]': query, + r'filters[name][$startsWith]': query }; queryParameters.removeWhere((k, v) => v == null); final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/profile/${slug}/subscribers', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/profile/${slug}/subscribers', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late SubPaginationModel _value; try { @@ -387,21 +456,27 @@ class _ProfileService implements ProfileService { }) async { final _extra = {}; final queryParameters = { - r'filters[name][$startsWith]': query, + r'filters[name][$startsWith]': query }; queryParameters.removeWhere((k, v) => v == null); final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/profile/${slug}/subscriptions', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/profile/${slug}/subscriptions', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late SubPaginationModel _value; try { @@ -419,16 +494,22 @@ class _ProfileService implements ProfileService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'POST', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/profile/subscribe/${slug}', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/profile/subscribe/${slug}', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } @@ -438,16 +519,22 @@ class _ProfileService implements ProfileService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'POST', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/profile/unsubscribe/${slug}', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/profile/unsubscribe/${slug}', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } @@ -457,30 +544,30 @@ class _ProfileService implements ProfileService { final queryParameters = {}; final _headers = {}; final _data = FormData(); - _data.files.add( - MapEntry( - 'photo', - MultipartFile.fromFileSync( - photo.path, - filename: photo.path.split(Platform.pathSeparator).last, - ), + _data.files.add(MapEntry( + 'photo', + MultipartFile.fromFileSync( + photo.path, + filename: photo.path.split(Platform.pathSeparator).last, ), - ); - final _options = _setStreamType( - Options( - method: 'POST', - headers: _headers, - extra: _extra, - contentType: 'multipart/form-data', - ) - .compose( - _dio.options, - '/api/profile/photo/upload', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + )); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + contentType: 'multipart/form-data', + ) + .compose( + _dio.options, + '/api/profile/photo/upload', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } @@ -490,19 +577,58 @@ class _ProfileService implements ProfileService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'DELETE', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/profile/photo/delete', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'DELETE', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/profile/photo/delete', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); await _dio.fetch(_options); } + @override + Future getChosenDiets() async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + const Map? _data = null; + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/profile/chosen_diets', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); + final _result = await _dio.fetch>(_options); + late ChosenDietsPaginationModel _value; + try { + _value = ChosenDietsPaginationModel.fromJson(_result.data!); + } on Object catch (e, s) { + errorLogger?.logError(e, s, _options); + rethrow; + } + return _value; + } + RequestOptions _setStreamType(RequestOptions requestOptions) { if (T != dynamic && !(requestOptions.responseType == ResponseType.bytes || @@ -516,7 +642,10 @@ class _ProfileService implements ProfileService { return requestOptions; } - String _combineBaseUrls(String dioBaseUrl, String? baseUrl) { + String _combineBaseUrls( + String dioBaseUrl, + String? baseUrl, + ) { if (baseUrl == null || baseUrl.trim().isEmpty) { return dioBaseUrl; } diff --git a/lib/features/recipes/services/recipe_service.g.dart b/lib/features/recipes/services/recipe_service.g.dart index 63de7d2c..20e02b55 100644 --- a/lib/features/recipes/services/recipe_service.g.dart +++ b/lib/features/recipes/services/recipe_service.g.dart @@ -9,7 +9,11 @@ part of 'recipe_service.dart'; // ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element,unnecessary_string_interpolations class _RecipeService implements RecipeService { - _RecipeService(this._dio, {this.baseUrl, this.errorLogger}); + _RecipeService( + this._dio, { + this.baseUrl, + this.errorLogger, + }); final Dio _dio; @@ -23,16 +27,22 @@ class _RecipeService implements RecipeService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/recipes/show/${id}', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/recipes/show/${id}', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late RecipeModel _value; try { @@ -50,27 +60,30 @@ class _RecipeService implements RecipeService { final queryParameters = {r'name': name}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType>>( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/diary/product_nutritional_values/filter', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType>>(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/diary/product_nutritional_values/filter', + 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( + _value = _result.data!.map((k, dynamic v) => MapEntry( k, (v as List) .map((i) => Product.fromJson(i as Map)) - .toList(), - ), - ); + .toList())); } on Object catch (e, s) { errorLogger?.logError(e, s, _options); rethrow; @@ -96,19 +109,34 @@ class _RecipeService implements RecipeService { final _headers = {}; final _data = FormData(); if (type != null) { - _data.fields.add(MapEntry('type', type)); + _data.fields.add(MapEntry( + 'type', + type, + )); } if (state != null) { - _data.fields.add(MapEntry('state', state)); + _data.fields.add(MapEntry( + 'state', + state, + )); } if (title != null) { - _data.fields.add(MapEntry('title', title)); + _data.fields.add(MapEntry( + 'title', + title, + )); } if (description != null) { - _data.fields.add(MapEntry('description', description)); + _data.fields.add(MapEntry( + 'description', + description, + )); } if (video_url != null) { - _data.fields.add(MapEntry('video_url', video_url)); + _data.fields.add(MapEntry( + 'video_url', + video_url, + )); } ingredients.forEach((i) { _data.fields.add(MapEntry('ingredients', jsonEncode(i))); @@ -117,27 +145,34 @@ class _RecipeService implements RecipeService { _data.fields.add(MapEntry('steps', jsonEncode(i))); }); if (cooking_time != null) { - _data.fields.add(MapEntry('cooking_time', cooking_time.toString())); + _data.fields.add(MapEntry( + 'cooking_time', + cooking_time.toString(), + )); } - _data.files.add( - MapEntry( - 'image', - MultipartFile.fromFileSync( - image.path, - filename: image.path.split(Platform.pathSeparator).last, - ), + _data.files.add(MapEntry( + 'image', + MultipartFile.fromFileSync( + image.path, + filename: image.path.split(Platform.pathSeparator).last, ), - ); - final _options = _setStreamType( - Options(method: 'POST', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/recipes/create', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + )); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/recipes/create', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late RecipeModel _value; try { @@ -150,21 +185,30 @@ class _RecipeService implements RecipeService { } @override - Future editRecipe(Map recipe, String id) async { + Future editRecipe( + Map recipe, + String id, + ) async { final _extra = {}; final queryParameters = {}; final _headers = {}; final _data = FormData.fromMap(recipe); - final _options = _setStreamType( - Options(method: 'POST', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/recipes/update/{id}', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/recipes/update/{id}', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late RecipeModel _value; try { @@ -182,16 +226,22 @@ class _RecipeService implements RecipeService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/recipes/tags', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/recipes/tags', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late RecipeTagModel _value; try { @@ -216,7 +266,10 @@ class _RecipeService implements RecipeService { return requestOptions; } - String _combineBaseUrls(String dioBaseUrl, String? baseUrl) { + String _combineBaseUrls( + String dioBaseUrl, + String? baseUrl, + ) { if (baseUrl == null || baseUrl.trim().isEmpty) { return dioBaseUrl; } diff --git a/lib/features/registration/services/registration_service.g.dart b/lib/features/registration/services/registration_service.g.dart index f9560e28..c7b90410 100644 --- a/lib/features/registration/services/registration_service.g.dart +++ b/lib/features/registration/services/registration_service.g.dart @@ -9,7 +9,11 @@ part of 'registration_service.dart'; // ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element,unnecessary_string_interpolations class _RegistrationService implements RegistrationService { - _RegistrationService(this._dio, {this.baseUrl, this.errorLogger}); + _RegistrationService( + this._dio, { + this.baseUrl, + this.errorLogger, + }); final Dio _dio; @@ -18,24 +22,29 @@ class _RegistrationService implements RegistrationService { final ParseErrorLogger? errorLogger; @override - Future> register({ - required Map sheet, - }) async { + Future> register( + {required Map sheet}) async { final _extra = {}; final queryParameters = {}; final _headers = {}; final _data = {}; _data.addAll(sheet); - final _options = _setStreamType>( - Options(method: 'POST', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/register', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType>(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/register', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late Map _value; try { @@ -53,16 +62,22 @@ class _RegistrationService implements RegistrationService { final queryParameters = {r'user_address': query}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/location_by_address', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/location_by_address', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late LocationModel _value; try { @@ -86,16 +101,22 @@ class _RegistrationService implements RegistrationService { }; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/location_by_coordinate', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/location_by_coordinate', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late LocationModel _value; try { @@ -120,7 +141,10 @@ class _RegistrationService implements RegistrationService { return requestOptions; } - String _combineBaseUrls(String dioBaseUrl, String? baseUrl) { + String _combineBaseUrls( + String dioBaseUrl, + String? baseUrl, + ) { if (baseUrl == null || baseUrl.trim().isEmpty) { return dioBaseUrl; } diff --git a/lib/features/settings/services/settings_service.g.dart b/lib/features/settings/services/settings_service.g.dart index 05385077..53d31175 100644 --- a/lib/features/settings/services/settings_service.g.dart +++ b/lib/features/settings/services/settings_service.g.dart @@ -9,7 +9,11 @@ part of 'settings_service.dart'; // ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element,unnecessary_string_interpolations class _SettingsService implements SettingsService { - _SettingsService(this._dio, {this.baseUrl, this.errorLogger}); + _SettingsService( + this._dio, { + this.baseUrl, + this.errorLogger, + }); final Dio _dio; @@ -23,16 +27,22 @@ class _SettingsService implements SettingsService { final queryParameters = {}; final _headers = {}; const Map? _data = null; - final _options = _setStreamType( - Options(method: 'GET', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/profile/settings', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/profile/settings', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late ProfileSettingsModel _value; try { @@ -45,24 +55,29 @@ class _SettingsService implements SettingsService { } @override - Future updateProfileSettings({ - required Map data, - }) async { + Future updateProfileSettings( + {required Map data}) async { final _extra = {}; final queryParameters = {}; final _headers = {}; final _data = {}; _data.addAll(data); - final _options = _setStreamType( - Options(method: 'POST', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/profile/settings/update', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/profile/settings/update', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late ProfileSettingsModel _value; try { @@ -75,24 +90,29 @@ class _SettingsService implements SettingsService { } @override - Future updateProfileDetails({ - required Map data, - }) async { + Future updateProfileDetails( + {required Map data}) async { final _extra = {}; final queryParameters = {}; final _headers = {}; final _data = {}; _data.addAll(data); - final _options = _setStreamType( - Options(method: 'POST', headers: _headers, extra: _extra) - .compose( - _dio.options, - '/api/profile/update', - queryParameters: queryParameters, - data: _data, - ) - .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), - ); + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/profile/update', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); final _result = await _dio.fetch>(_options); late ProfileDetailsModel _value; try { @@ -117,7 +137,10 @@ class _SettingsService implements SettingsService { return requestOptions; } - String _combineBaseUrls(String dioBaseUrl, String? baseUrl) { + String _combineBaseUrls( + String dioBaseUrl, + String? baseUrl, + ) { if (baseUrl == null || baseUrl.trim().isEmpty) { return dioBaseUrl; } diff --git a/lib/main.dart b/lib/main.dart index 4973e7e2..62b91d0e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,4 @@ import 'package:eatvio_app/core/app_router.dart'; -import 'package:eatvio_app/core/initialization_cubit/initialization_cubit.dart'; import 'package:eatvio_app/core/locator_service.dart' as di; import 'package:eatvio_app/core/locator_service.dart'; import 'package:eatvio_app/core/theme/theme_helper.dart'; @@ -27,8 +26,7 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MultiBlocProvider( - providers: [ - BlocProvider(create: (context) => sl()..runInitialization()), + providers: [ BlocProvider(create: (context) => sl()), BlocProvider(create: (context) => sl()), BlocProvider(create: (context) => sl()..loadFeedBlogPostList()), diff --git a/test/features/profile/services/profile_service_test.mocks.dart b/test/features/profile/services/profile_service_test.mocks.dart index 3d08d4ea..194ed8b5 100644 --- a/test/features/profile/services/profile_service_test.mocks.dart +++ b/test/features/profile/services/profile_service_test.mocks.dart @@ -1,20 +1,22 @@ -// Mocks generated by Mockito 5.4.5 from annotations +// Mocks generated by Mockito 5.4.4 from annotations // in eatvio_app/test/features/profile/services/profile_service_test.dart. // Do not manually edit this file. // ignore_for_file: no_leading_underscores_for_library_prefixes -import 'dart:async' as _i5; -import 'dart:io' as _i9; +import 'dart:async' as _i6; +import 'dart:io' as _i10; import 'package:eatvio_app/features/feed/models/feed_blog_post_model.dart' - as _i6; + as _i7; +import 'package:eatvio_app/features/profile/models/chosen_diets_pagination_model.dart' + as _i4; import 'package:eatvio_app/features/profile/models/circumference_model.dart' - as _i8; + as _i9; import 'package:eatvio_app/features/profile/models/profile_model.dart' as _i2; import 'package:eatvio_app/features/profile/models/sub_model.dart' as _i3; -import 'package:eatvio_app/features/profile/models/weight_model.dart' as _i7; +import 'package:eatvio_app/features/profile/models/weight_model.dart' as _i8; import 'package:eatvio_app/features/profile/services/profile_service.dart' - as _i4; + as _i5; import 'package:mockito/mockito.dart' as _i1; // ignore_for_file: type=lint @@ -25,314 +27,427 @@ import 'package:mockito/mockito.dart' as _i1; // ignore_for_file: deprecated_member_use_from_same_package // ignore_for_file: implementation_imports // ignore_for_file: invalid_use_of_visible_for_testing_member -// ignore_for_file: must_be_immutable // ignore_for_file: prefer_const_constructors // ignore_for_file: unnecessary_parenthesis // ignore_for_file: camel_case_types // ignore_for_file: subtype_of_sealed_class class _FakeProfileModel_0 extends _i1.SmartFake implements _i2.ProfileModel { - _FakeProfileModel_0(Object parent, Invocation parentInvocation) - : super(parent, parentInvocation); + _FakeProfileModel_0( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); } class _FakeProfileDetailsModel_1 extends _i1.SmartFake implements _i2.ProfileDetailsModel { - _FakeProfileDetailsModel_1(Object parent, Invocation parentInvocation) - : super(parent, parentInvocation); + _FakeProfileDetailsModel_1( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); } class _FakeSubPaginationModel_2 extends _i1.SmartFake implements _i3.SubPaginationModel { - _FakeSubPaginationModel_2(Object parent, Invocation parentInvocation) - : super(parent, parentInvocation); + _FakeSubPaginationModel_2( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeChosenDietsPaginationModel_3 extends _i1.SmartFake + implements _i4.ChosenDietsPaginationModel { + _FakeChosenDietsPaginationModel_3( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); } /// A class which mocks [ProfileService]. /// /// See the documentation for Mockito's code generation for more information. -class MockProfileService extends _i1.Mock implements _i4.ProfileService { +class MockProfileService extends _i1.Mock implements _i5.ProfileService { @override - _i5.Future<_i2.ProfileModel> getProfileBySlug({required String? slug}) => + _i6.Future<_i2.ProfileModel> getProfileBySlug({required String? slug}) => (super.noSuchMethod( - Invocation.method(#getProfileBySlug, [], {#slug: slug}), - returnValue: _i5.Future<_i2.ProfileModel>.value( - _FakeProfileModel_0( - this, - Invocation.method(#getProfileBySlug, [], {#slug: slug}), - ), - ), - returnValueForMissingStub: _i5.Future<_i2.ProfileModel>.value( - _FakeProfileModel_0( - this, - Invocation.method(#getProfileBySlug, [], {#slug: slug}), - ), - ), - ) - as _i5.Future<_i2.ProfileModel>); + Invocation.method( + #getProfileBySlug, + [], + {#slug: slug}, + ), + returnValue: _i6.Future<_i2.ProfileModel>.value(_FakeProfileModel_0( + this, + Invocation.method( + #getProfileBySlug, + [], + {#slug: slug}, + ), + )), + returnValueForMissingStub: + _i6.Future<_i2.ProfileModel>.value(_FakeProfileModel_0( + this, + Invocation.method( + #getProfileBySlug, + [], + {#slug: slug}, + ), + )), + ) as _i6.Future<_i2.ProfileModel>); @override - _i5.Future<_i2.ProfileModel> getMyProfile() => - (super.noSuchMethod( - Invocation.method(#getMyProfile, []), - returnValue: _i5.Future<_i2.ProfileModel>.value( - _FakeProfileModel_0(this, Invocation.method(#getMyProfile, [])), - ), - returnValueForMissingStub: _i5.Future<_i2.ProfileModel>.value( - _FakeProfileModel_0(this, Invocation.method(#getMyProfile, [])), - ), - ) - as _i5.Future<_i2.ProfileModel>); + _i6.Future<_i2.ProfileModel> getMyProfile() => (super.noSuchMethod( + Invocation.method( + #getMyProfile, + [], + ), + returnValue: _i6.Future<_i2.ProfileModel>.value(_FakeProfileModel_0( + this, + Invocation.method( + #getMyProfile, + [], + ), + )), + returnValueForMissingStub: + _i6.Future<_i2.ProfileModel>.value(_FakeProfileModel_0( + this, + Invocation.method( + #getMyProfile, + [], + ), + )), + ) as _i6.Future<_i2.ProfileModel>); @override - _i5.Future<_i2.ProfileDetailsModel> getMyProfileDetails() => + _i6.Future<_i2.ProfileDetailsModel> getMyProfileDetails() => (super.noSuchMethod( - Invocation.method(#getMyProfileDetails, []), - returnValue: _i5.Future<_i2.ProfileDetailsModel>.value( - _FakeProfileDetailsModel_1( - this, - Invocation.method(#getMyProfileDetails, []), - ), - ), - returnValueForMissingStub: - _i5.Future<_i2.ProfileDetailsModel>.value( - _FakeProfileDetailsModel_1( - this, - Invocation.method(#getMyProfileDetails, []), - ), - ), - ) - as _i5.Future<_i2.ProfileDetailsModel>); + Invocation.method( + #getMyProfileDetails, + [], + ), + returnValue: _i6.Future<_i2.ProfileDetailsModel>.value( + _FakeProfileDetailsModel_1( + this, + Invocation.method( + #getMyProfileDetails, + [], + ), + )), + returnValueForMissingStub: _i6.Future<_i2.ProfileDetailsModel>.value( + _FakeProfileDetailsModel_1( + this, + Invocation.method( + #getMyProfileDetails, + [], + ), + )), + ) as _i6.Future<_i2.ProfileDetailsModel>); @override - _i5.Future<_i2.ProfileDetailsModel> getProfileDetailsBySlug({ - required String? slug, - }) => + _i6.Future<_i2.ProfileDetailsModel> getProfileDetailsBySlug( + {required String? slug}) => (super.noSuchMethod( - Invocation.method(#getProfileDetailsBySlug, [], {#slug: slug}), - returnValue: _i5.Future<_i2.ProfileDetailsModel>.value( - _FakeProfileDetailsModel_1( - this, - Invocation.method(#getProfileDetailsBySlug, [], {#slug: slug}), - ), - ), - returnValueForMissingStub: - _i5.Future<_i2.ProfileDetailsModel>.value( - _FakeProfileDetailsModel_1( - this, - Invocation.method(#getProfileDetailsBySlug, [], { - #slug: slug, - }), - ), - ), - ) - as _i5.Future<_i2.ProfileDetailsModel>); + Invocation.method( + #getProfileDetailsBySlug, + [], + {#slug: slug}, + ), + returnValue: _i6.Future<_i2.ProfileDetailsModel>.value( + _FakeProfileDetailsModel_1( + this, + Invocation.method( + #getProfileDetailsBySlug, + [], + {#slug: slug}, + ), + )), + returnValueForMissingStub: _i6.Future<_i2.ProfileDetailsModel>.value( + _FakeProfileDetailsModel_1( + this, + Invocation.method( + #getProfileDetailsBySlug, + [], + {#slug: slug}, + ), + )), + ) as _i6.Future<_i2.ProfileDetailsModel>); @override - _i5.Future addCircumference({ + _i6.Future addCircumference({ required int? chestCircumference, required int? waistCircumference, required int? hipCircumference, }) => (super.noSuchMethod( - Invocation.method(#addCircumference, [], { - #chestCircumference: chestCircumference, - #waistCircumference: waistCircumference, - #hipCircumference: hipCircumference, - }), - returnValue: _i5.Future.value(), - returnValueForMissingStub: _i5.Future.value(), - ) - as _i5.Future); + Invocation.method( + #addCircumference, + [], + { + #chestCircumference: chestCircumference, + #waistCircumference: waistCircumference, + #hipCircumference: hipCircumference, + }, + ), + returnValue: _i6.Future.value(), + returnValueForMissingStub: _i6.Future.value(), + ) as _i6.Future); @override - _i5.Future addWeight({required double? weight}) => + _i6.Future addWeight({required double? weight}) => (super.noSuchMethod( + Invocation.method( + #addWeight, + [], + {#weight: weight}, + ), + returnValue: _i6.Future.value(), + returnValueForMissingStub: _i6.Future.value(), + ) as _i6.Future); + + @override + _i6.Future> getBlogPostByAuthorSlug( + {required String? slug}) => (super.noSuchMethod( - Invocation.method(#addWeight, [], {#weight: weight}), - returnValue: _i5.Future.value(), - returnValueForMissingStub: _i5.Future.value(), - ) - as _i5.Future); + Invocation.method( + #getBlogPostByAuthorSlug, + [], + {#slug: slug}, + ), + returnValue: _i6.Future>.value( + <_i7.FeedBlogPostModel>[]), + returnValueForMissingStub: + _i6.Future>.value( + <_i7.FeedBlogPostModel>[]), + ) as _i6.Future>); @override - _i5.Future> getBlogPostByAuthorSlug({ - required String? slug, - }) => + _i6.Future> getWeight({required String? period}) => (super.noSuchMethod( - Invocation.method(#getBlogPostByAuthorSlug, [], {#slug: slug}), - returnValue: _i5.Future>.value( - <_i6.FeedBlogPostModel>[], - ), - returnValueForMissingStub: - _i5.Future>.value( - <_i6.FeedBlogPostModel>[], - ), - ) - as _i5.Future>); + Invocation.method( + #getWeight, + [], + {#period: period}, + ), + returnValue: + _i6.Future>.value(<_i8.WeightModel>[]), + returnValueForMissingStub: + _i6.Future>.value(<_i8.WeightModel>[]), + ) as _i6.Future>); @override - _i5.Future> getWeight({required String? period}) => - (super.noSuchMethod( - Invocation.method(#getWeight, [], {#period: period}), - returnValue: _i5.Future>.value( - <_i7.WeightModel>[], - ), - returnValueForMissingStub: _i5.Future>.value( - <_i7.WeightModel>[], - ), - ) - as _i5.Future>); - - @override - _i5.Future> getWeightBySlug({ + _i6.Future> getWeightBySlug({ required String? period, required String? slug, }) => (super.noSuchMethod( - Invocation.method(#getWeightBySlug, [], { - #period: period, - #slug: slug, - }), - returnValue: _i5.Future>.value( - <_i7.WeightModel>[], - ), - returnValueForMissingStub: _i5.Future>.value( - <_i7.WeightModel>[], - ), - ) - as _i5.Future>); + Invocation.method( + #getWeightBySlug, + [], + { + #period: period, + #slug: slug, + }, + ), + returnValue: + _i6.Future>.value(<_i8.WeightModel>[]), + returnValueForMissingStub: + _i6.Future>.value(<_i8.WeightModel>[]), + ) as _i6.Future>); @override - _i5.Future> getCircumferences({ - required String? period, - }) => + _i6.Future> getCircumferences( + {required String? period}) => (super.noSuchMethod( - Invocation.method(#getCircumferences, [], {#period: period}), - returnValue: _i5.Future>.value( - <_i8.CircumferenceModel>[], - ), - returnValueForMissingStub: - _i5.Future>.value( - <_i8.CircumferenceModel>[], - ), - ) - as _i5.Future>); + Invocation.method( + #getCircumferences, + [], + {#period: period}, + ), + returnValue: _i6.Future>.value( + <_i9.CircumferenceModel>[]), + returnValueForMissingStub: + _i6.Future>.value( + <_i9.CircumferenceModel>[]), + ) as _i6.Future>); @override - _i5.Future> getCircumferencesBySlug({ + _i6.Future> getCircumferencesBySlug({ required String? period, required String? slug, }) => (super.noSuchMethod( - Invocation.method(#getCircumferencesBySlug, [], { - #period: period, - #slug: slug, - }), - returnValue: _i5.Future>.value( - <_i8.CircumferenceModel>[], - ), - returnValueForMissingStub: - _i5.Future>.value( - <_i8.CircumferenceModel>[], - ), - ) - as _i5.Future>); + Invocation.method( + #getCircumferencesBySlug, + [], + { + #period: period, + #slug: slug, + }, + ), + returnValue: _i6.Future>.value( + <_i9.CircumferenceModel>[]), + returnValueForMissingStub: + _i6.Future>.value( + <_i9.CircumferenceModel>[]), + ) as _i6.Future>); @override - _i5.Future<_i3.SubPaginationModel> getSubscribers({ + _i6.Future<_i3.SubPaginationModel> getSubscribers({ required String? slug, String? query, }) => (super.noSuchMethod( - Invocation.method(#getSubscribers, [], { + Invocation.method( + #getSubscribers, + [], + { + #slug: slug, + #query: query, + }, + ), + returnValue: + _i6.Future<_i3.SubPaginationModel>.value(_FakeSubPaginationModel_2( + this, + Invocation.method( + #getSubscribers, + [], + { #slug: slug, #query: query, - }), - returnValue: _i5.Future<_i3.SubPaginationModel>.value( - _FakeSubPaginationModel_2( - this, - Invocation.method(#getSubscribers, [], { - #slug: slug, - #query: query, - }), - ), - ), - returnValueForMissingStub: _i5.Future<_i3.SubPaginationModel>.value( - _FakeSubPaginationModel_2( - this, - Invocation.method(#getSubscribers, [], { - #slug: slug, - #query: query, - }), - ), - ), - ) - as _i5.Future<_i3.SubPaginationModel>); + }, + ), + )), + returnValueForMissingStub: + _i6.Future<_i3.SubPaginationModel>.value(_FakeSubPaginationModel_2( + this, + Invocation.method( + #getSubscribers, + [], + { + #slug: slug, + #query: query, + }, + ), + )), + ) as _i6.Future<_i3.SubPaginationModel>); @override - _i5.Future<_i3.SubPaginationModel> getSubscriptions({ + _i6.Future<_i3.SubPaginationModel> getSubscriptions({ required String? slug, String? query, }) => (super.noSuchMethod( - Invocation.method(#getSubscriptions, [], { + Invocation.method( + #getSubscriptions, + [], + { + #slug: slug, + #query: query, + }, + ), + returnValue: + _i6.Future<_i3.SubPaginationModel>.value(_FakeSubPaginationModel_2( + this, + Invocation.method( + #getSubscriptions, + [], + { #slug: slug, #query: query, - }), - returnValue: _i5.Future<_i3.SubPaginationModel>.value( - _FakeSubPaginationModel_2( - this, - Invocation.method(#getSubscriptions, [], { - #slug: slug, - #query: query, - }), - ), - ), - returnValueForMissingStub: _i5.Future<_i3.SubPaginationModel>.value( - _FakeSubPaginationModel_2( - this, - Invocation.method(#getSubscriptions, [], { - #slug: slug, - #query: query, - }), - ), - ), - ) - as _i5.Future<_i3.SubPaginationModel>); + }, + ), + )), + returnValueForMissingStub: + _i6.Future<_i3.SubPaginationModel>.value(_FakeSubPaginationModel_2( + this, + Invocation.method( + #getSubscriptions, + [], + { + #slug: slug, + #query: query, + }, + ), + )), + ) as _i6.Future<_i3.SubPaginationModel>); @override - _i5.Future subscribe({required String? slug}) => - (super.noSuchMethod( - Invocation.method(#subscribe, [], {#slug: slug}), - returnValue: _i5.Future.value(), - returnValueForMissingStub: _i5.Future.value(), - ) - as _i5.Future); + _i6.Future subscribe({required String? slug}) => (super.noSuchMethod( + Invocation.method( + #subscribe, + [], + {#slug: slug}, + ), + returnValue: _i6.Future.value(), + returnValueForMissingStub: _i6.Future.value(), + ) as _i6.Future); @override - _i5.Future unsubscribe({required String? slug}) => - (super.noSuchMethod( - Invocation.method(#unsubscribe, [], {#slug: slug}), - returnValue: _i5.Future.value(), - returnValueForMissingStub: _i5.Future.value(), - ) - as _i5.Future); + _i6.Future unsubscribe({required String? slug}) => (super.noSuchMethod( + Invocation.method( + #unsubscribe, + [], + {#slug: slug}, + ), + returnValue: _i6.Future.value(), + returnValueForMissingStub: _i6.Future.value(), + ) as _i6.Future); @override - _i5.Future uploadPhoto({required _i9.File? photo}) => + _i6.Future uploadPhoto({required _i10.File? photo}) => (super.noSuchMethod( - Invocation.method(#uploadPhoto, [], {#photo: photo}), - returnValue: _i5.Future.value(), - returnValueForMissingStub: _i5.Future.value(), - ) - as _i5.Future); + Invocation.method( + #uploadPhoto, + [], + {#photo: photo}, + ), + returnValue: _i6.Future.value(), + returnValueForMissingStub: _i6.Future.value(), + ) as _i6.Future); @override - _i5.Future deletePhoto() => + _i6.Future deletePhoto() => (super.noSuchMethod( + Invocation.method( + #deletePhoto, + [], + ), + returnValue: _i6.Future.value(), + returnValueForMissingStub: _i6.Future.value(), + ) as _i6.Future); + + @override + _i6.Future<_i4.ChosenDietsPaginationModel> getChosenDiets() => (super.noSuchMethod( - Invocation.method(#deletePhoto, []), - returnValue: _i5.Future.value(), - returnValueForMissingStub: _i5.Future.value(), - ) - as _i5.Future); + Invocation.method( + #getChosenDiets, + [], + ), + returnValue: _i6.Future<_i4.ChosenDietsPaginationModel>.value( + _FakeChosenDietsPaginationModel_3( + this, + Invocation.method( + #getChosenDiets, + [], + ), + )), + returnValueForMissingStub: + _i6.Future<_i4.ChosenDietsPaginationModel>.value( + _FakeChosenDietsPaginationModel_3( + this, + Invocation.method( + #getChosenDiets, + [], + ), + )), + ) as _i6.Future<_i4.ChosenDietsPaginationModel>); }