Merge pull request 'main' (#14) from eatvio/eatvio_app:main into main

Reviewed-on: BLoC/eatvio_app#14
This commit is contained in:
BLoC
2025-01-24 09:05:06 +00:00
67 changed files with 4024 additions and 2767 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@@ -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"

View File

@@ -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/"

View File

@@ -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/"

View File

@@ -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<InitializationCubit>().runInitialization();
await sl<WsManager>().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(),
),
],
);
}

View File

@@ -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<int> durationValues = [7, 14, 21];
const List<String> dietTypeValues = ['veg', 'light', 'carb', 'meat'];
const List<String> planTypeValues = ['fit', 'slim', 'wellness', 'behavior'];
const newMessagesChannelName = 'private-new-chat-messages';
const newNotificationsChannelName = 'private-message-events';
const directChatChannelName = 'private-direct-chat';

View File

@@ -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<InitializationState> {
final ChatRepository chatRepository;
bool wasInitialized = false;
InitializationCubit({required this.chatRepository}) : super(const InitializationState.loading());
Future<void> 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<NotificationsCubit>().incrementCounter(event.name);
});
}
Future<void> 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<NewMessagesCubit>().incrementCounter();
});
}
Future<void> 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;
}
}
}
}

View File

@@ -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;
}

View File

@@ -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>(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 extends Object?>(
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 extends Object?>(
TResult? Function()? $default, {
TResult? Function()? loading,
TResult? Function(PusherChannelsClient client)? success,
TResult? Function(String errorMessage)? error,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>(
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 extends Object?>(
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 extends Object?>(
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 extends Object?>(
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 extends Object?>(
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 extends Object?>(
TResult? Function()? $default, {
TResult? Function()? loading,
TResult? Function(PusherChannelsClient client)? success,
TResult? Function(String errorMessage)? error,
}) {
return $default?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>(
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 extends Object?>(
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 extends Object?>(
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 extends Object?>(
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 extends Object?>(
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 extends Object?>(
TResult? Function()? $default, {
TResult? Function()? loading,
TResult? Function(PusherChannelsClient client)? success,
TResult? Function(String errorMessage)? error,
}) {
return loading?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>(
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 extends Object?>(
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 extends Object?>(
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 extends Object?>(
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 extends Object?>(
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 extends Object?>(
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 extends Object?>(
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 extends Object?>(
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 extends Object?>(
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 extends Object?>(
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 extends Object?>(
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 extends Object?>(
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 extends Object?>(
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 extends Object?>(
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 extends Object?>(
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 extends Object?>(
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;
}

View File

@@ -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<ChannelReadEvent>? get newMessagesStream => _privateMessagesChannel?.bind('App\\Events\\ChatMessageUpdated');
// TODO: change name of event to a right one
Stream<ChannelReadEvent>? get newNotificationsStream => _privateNotificationChannel?.bind('App\\Events\\ChatMessageUpdated');
Stream<ChannelReadEvent>? get directChatStream => _privateDirectChatChannel?.bind('App\\Events\\ChatMessageUpdated');
Stream<ChannelReadEvent>? get clientTypingStream => _privateDirectChatChannel?.bind('client-typing');
Future<void> 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<void> _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<void> _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<void> 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();
}
}

View File

@@ -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<WebsocketInfoModel> getWebsocket();
}

View File

@@ -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<WebsocketInfoModel> getWebsocket() async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<WebsocketInfoModel>(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<Map<String, dynamic>>(_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<T>(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();
}
}

View File

@@ -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<void> init() async {
// Cubit singletons
sl.registerLazySingleton<InitializationCubit>(() => InitializationCubit(chatRepository: sl()));
sl.registerLazySingleton<WsManager>(() => WsManager(wsService: sl()));
sl.registerLazySingleton<NewMessagesCubit>(() => NewMessagesCubit());
sl.registerLazySingleton<NotificationsCubit>(() => NotificationsCubit());
sl.registerLazySingleton<NotificationsCubit>(() => NotificationsCubit(wsManager: sl()));
sl.registerLazySingleton<FeedCubit>(() => FeedCubit(feedRepository: sl()));
sl.registerLazySingleton<ProfileAvatarCubit>(() => ProfileAvatarCubit(profileRepository: sl()));
// Cubit factories
sl.registerFactory<RegistrationCubit>(() => RegistrationCubit(registrationRepository: sl()));
sl.registerFactory<ChatRoomCubit>(() => ChatRoomCubit(chatRepository: sl(), initializationCubit: sl()));
sl.registerFactory<ChatRoomCubit>(() => ChatRoomCubit(chatRepository: sl(), wsManager: sl()));
sl.registerFactory<RecipesCubit>(() => RecipesCubit(feedRepository: sl(), recipeRepository: sl()));
sl.registerFactory<CalendarCubit>(() => CalendarCubit(calendarRepository: sl()));
sl.registerFactory<ProfileCubit>(() => ProfileCubit(profileRepository: sl(), chatRepository: sl()));
@@ -140,6 +141,7 @@ Future<void> init() async {
sl.registerLazySingleton<PlanService>(() => PlanService(sl()));
sl.registerLazySingleton<MyDietsService>(() => MyDietsService(sl()));
sl.registerLazySingleton<MyPlansService>(() => MyPlansService(sl()));
sl.registerLazySingleton<WsService>(() => WsService(sl()));
// External
sl.registerLazySingleton(

View File

@@ -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,

View File

@@ -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();

View File

@@ -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,
);
}

View File

@@ -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 = <String, dynamic>{};
final _headers = <String, dynamic>{};
final _data = formData;
final _options = _setStreamType<void>(
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<void>(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<void>(_options);
}
@@ -50,21 +56,23 @@ class _BlogPostService implements BlogPostService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
final _data = formData;
final _options = _setStreamType<void>(
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<void>(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<void>(_options);
}
@@ -74,16 +82,22 @@ class _BlogPostService implements BlogPostService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<void>(
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<void>(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<void>(_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;
}

View File

@@ -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<NotificationsState> {
int _notificationsCount = 0;
List<String> 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++;

View File

@@ -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 = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<List<CalendarModel>>(
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<List<CalendarModel>>(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<List<dynamic>>(_options);
late List<CalendarModel> _value;
try {
_value = _result.data!
.map(
(dynamic i) => CalendarModel.fromJson(i as Map<String, dynamic>),
)
.map((dynamic i) => CalendarModel.fromJson(i as Map<String, dynamic>))
.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;
}

View File

@@ -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<ChatRoomState> {
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<ChatRoomState> {
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<void> _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<ChatMessageModel> messagesList = [
ChatMessageModel.fromJson(jsonDecode(event.data)['message']),
@@ -113,7 +101,7 @@ class ChatRoomCubit extends Cubit<ChatRoomState> {
);
});
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<ChatRoomState> {
@override
Future<void> close() async {
privateChatChannel.unsubscribe();
wsManager.unsubscribeDirectChatChannel();
super.close();
}
}

View File

@@ -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<ChatScreen> {
resizeToAvoidBottomInset: true,
appBar: AppBar(
titleSpacing: 0,
backgroundColor: appTheme.gray100,
centerTitle: false,
title: Row(
children: [
@@ -136,7 +138,7 @@ class _ChatScreenState extends State<ChatScreen> {
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<ChatScreen> {
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<ChatScreen> {
),
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<ChatScreen> {
},
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<ChatScreen> {
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<ChatScreen> {
}
_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,
),
),
),
);

View File

@@ -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,
),

View File

@@ -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<WebsocketInfoModel> getWebsocket() async {
try {
return (await chatService.getWebsocket());
} catch (e) {
rethrow;
}
}
}
Future<ChatRoomModel> getChatRoomIdByUserSlug({required String slug}) async {
try {

View File

@@ -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<WebsocketInfoModel> getWebsocket();
@GET('/api/chat/get_by_user/{user}')
Future<ChatRoomModel> getChatRoomIdByUserSlug({
@Path() required String user,

View File

@@ -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 = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<ChatRoomPreviewModel>(
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<ChatRoomPreviewModel>(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<Map<String, dynamic>>(_options);
late ChatRoomPreviewModel _value;
try {
@@ -51,23 +61,27 @@ class _ChatService implements ChatService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<Map<String, ChatRoomModel>>(
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<Map<String, ChatRoomModel>>(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<Map<String, dynamic>>(_options);
late Map<String, ChatRoomModel> _value;
try {
_value = _result.data!.map(
(k, dynamic v) =>
MapEntry(k, ChatRoomModel.fromJson(v as Map<String, dynamic>)),
);
_value = _result.data!.map((k, dynamic v) =>
MapEntry(k, ChatRoomModel.fromJson(v as Map<String, dynamic>)));
} on Object catch (e, s) {
errorLogger?.logError(e, s, _options);
rethrow;
@@ -87,26 +101,31 @@ class _ChatService implements ChatService {
final _headers = <String, dynamic>{};
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<void>(
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<void>(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<void>(_options);
}
@@ -119,16 +138,22 @@ class _ChatService implements ChatService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<ChatMessagesModel>(
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<ChatMessagesModel>(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<Map<String, dynamic>>(_options);
late ChatMessagesModel _value;
try {
@@ -140,49 +165,28 @@ class _ChatService implements ChatService {
return _value;
}
@override
Future<WebsocketInfoModel> getWebsocket() async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<WebsocketInfoModel>(
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<Map<String, dynamic>>(_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<ChatRoomModel> getChatRoomIdByUserSlug({required String user}) async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<ChatRoomModel>(
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<ChatRoomModel>(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<Map<String, dynamic>>(_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;
}

View File

@@ -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<void> consultantRegistration({
required ConsultantProfileModel consultantModel,
}) async {
Future<void> consultantRegistration(
{required ConsultantProfileModel consultantModel}) async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
final _data = consultantModel;
final _options = _setStreamType<void>(
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<void>(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<void>(_options);
}
@@ -48,21 +57,23 @@ class _ConsultantService implements ConsultantService {
if (photos != null) {
_data.files.addAll(photos.map((i) => MapEntry('photos[]', i)));
}
final _options = _setStreamType<List<String>>(
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<List<String>>(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<List<dynamic>>(_options);
late List<String> _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;
}

View File

@@ -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 = <String, dynamic>{};
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<CreatedDiet>(
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<CreatedDiet>(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<Map<String, dynamic>>(_options);
late CreatedDiet _value;
try {
@@ -107,16 +135,22 @@ class _CreateDietService implements CreateDietService {
final _headers = <String, dynamic>{};
final _data = <String, dynamic>{};
_data.addAll(model);
final _options = _setStreamType<void>(
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<void>(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<void>(_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;
}

View File

@@ -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 = <String, dynamic>{};
final _data = <String, dynamic>{};
_data.addAll(model);
final _options = _setStreamType<void>(
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<void>(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<void>(_options);
}
@@ -52,16 +58,22 @@ class _CreatePlanService implements CreatePlanService {
final _headers = <String, dynamic>{};
final _data = <String, dynamic>{};
_data.addAll(model);
final _options = _setStreamType<void>(
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<void>(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<void>(_options);
}
@@ -75,16 +87,22 @@ class _CreatePlanService implements CreatePlanService {
final _headers = <String, dynamic>{};
final _data = <String, dynamic>{};
_data.addAll(model);
final _options = _setStreamType<void>(
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<void>(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<void>(_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;
}

View File

@@ -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<DevToolsScreenContent> createState() => _DevToolsScreenContentState();
}
class _DevToolsScreenContentState extends State<DevToolsScreenContent> {
String baseUrlForTest = '';
final List<TestCases> testCases = [Test850task()];
final controller = TextEditingController();
late final List<TestState> 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 }

View File

@@ -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<bool> run({required String baseUrl}) async => throw UnimplementedError();
}
class Test850task implements TestCases {
@override
String get name => 'task #850';
@override
Future<bool> run({required String baseUrl}) async {
try {
// get all of needed services
final dio = sl<Dio>();
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;
}
}
}

View File

@@ -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<DiaryScreen> {
create: (BuildContext context) => sl<DiaryCubit>()..fetchDiary(true),
child: BlocBuilder<DiaryCubit, DiaryState>(
builder: (BuildContext context, DiaryState state) {
if (state is DiaryStateLoaded) {
log(state.diary.id.toString());
}
return Scaffold(
backgroundColor: Colors.grey.shade200,
appBar: AppBar(

View File

@@ -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<List<DiaryDayModel>> getDiaryIndexByDate({
required String date,
}) async {
Future<List<DiaryDayModel>> getDiaryIndexByDate(
{required String date}) async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<List<DiaryDayModel>>(
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<List<DiaryDayModel>>(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<List<dynamic>>(_options);
late List<DiaryDayModel> _value;
try {
_value = _result.data!
.map(
(dynamic i) => DiaryDayModel.fromJson(i as Map<String, dynamic>),
)
.map((dynamic i) => DiaryDayModel.fromJson(i as Map<String, dynamic>))
.toList();
} on Object catch (e, s) {
errorLogger?.logError(e, s, _options);
@@ -56,16 +63,22 @@ class _DiaryService implements DiaryService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<DiaryDayWrapperModel>(
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<DiaryDayWrapperModel>(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<Map<String, dynamic>>(_options);
late DiaryDayWrapperModel _value;
try {
@@ -83,16 +96,22 @@ class _DiaryService implements DiaryService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<NutritionDataModel>(
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<NutritionDataModel>(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<Map<String, dynamic>>(_options);
late NutritionDataModel _value;
try {
@@ -114,30 +133,30 @@ class _DiaryService implements DiaryService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
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<void>(
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<void>(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<void>(_options);
}
@@ -151,16 +170,22 @@ class _DiaryService implements DiaryService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<void>(
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<void>(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<void>(_options);
}
@@ -178,27 +203,40 @@ class _DiaryService implements DiaryService {
queryParameters.removeWhere((k, v) => v == null);
final _headers = <String, dynamic>{};
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<void>(
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<void>(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<void>(_options);
}
@@ -214,16 +252,22 @@ class _DiaryService implements DiaryService {
final _headers = <String, dynamic>{};
final _data = <String, dynamic>{};
_data.addAll(productInMeal);
final _options = _setStreamType<void>(
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<void>(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<void>(_options);
}
@@ -237,16 +281,22 @@ class _DiaryService implements DiaryService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<void>(
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<void>(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<void>(_options);
}
@@ -260,16 +310,22 @@ class _DiaryService implements DiaryService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<void>(
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<void>(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<void>(_options);
}
@@ -283,16 +339,22 @@ class _DiaryService implements DiaryService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<void>(
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<void>(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<void>(_options);
}
@@ -306,16 +368,22 @@ class _DiaryService implements DiaryService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<void>(
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<void>(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<void>(_options);
}
@@ -328,16 +396,22 @@ class _DiaryService implements DiaryService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
final _data = finishDiaryDayModel;
final _options = _setStreamType<void>(
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<void>(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<void>(_options);
}
@@ -351,16 +425,22 @@ class _DiaryService implements DiaryService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
final _data = {'satiety': satiety};
final _options = _setStreamType<void>(
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<void>(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<void>(_options);
}
@@ -374,38 +454,49 @@ class _DiaryService implements DiaryService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
final _data = {'time': time};
final _options = _setStreamType<void>(
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<void>(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<void>(_options);
}
@override
Future<GlossaryModerationModel> sendProductToModeration({
required Map<String, dynamic> data,
}) async {
Future<GlossaryModerationModel> sendProductToModeration(
{required Map<String, dynamic> data}) async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
final _data = <String, dynamic>{};
_data.addAll(data);
final _options = _setStreamType<GlossaryModerationModel>(
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<GlossaryModerationModel>(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<Map<String, dynamic>>(_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;
}

View File

@@ -28,4 +28,15 @@ abstract class DietService {
Future<Diet> getDiet({
@Path() required int id,
});
@POST('/api/diets/{id}/start')
Future<void> startDiet({
@Path() required int id,
@Body() required Map<String, dynamic> body,
});
@POST('/api/diets/{id}/cancel')
Future<void> cancelDiet({
@Path() required int id,
});
}

View File

@@ -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 = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<DietLikesModel>(
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<DietLikesModel>(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<Map<String, dynamic>>(_options);
late DietLikesModel _value;
try {
@@ -50,16 +60,22 @@ class _DietService implements DietService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<Diet>(
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<Diet>(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<Map<String, dynamic>>(_options);
late Diet _value;
try {
@@ -77,16 +93,22 @@ class _DietService implements DietService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<Diet>(
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<Diet>(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<Map<String, dynamic>>(_options);
late Diet _value;
try {
@@ -104,16 +126,22 @@ class _DietService implements DietService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<Diet>(
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<Diet>(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<Map<String, dynamic>>(_options);
late Diet _value;
try {
@@ -125,6 +153,60 @@ class _DietService implements DietService {
return _value;
}
@override
Future<void> startDiet({
required int id,
required Map<String, dynamic> body,
}) async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
final _data = <String, dynamic>{};
_data.addAll(body);
final _options = _setStreamType<void>(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<void>(_options);
}
@override
Future<void> cancelDiet({required int id}) async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<void>(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<void>(_options);
}
RequestOptions _setStreamType<T>(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;
}

View File

@@ -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<String, dynamic> json) => _$PlanModelFromJson(json);

View File

@@ -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<String, dynamic> 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<String, dynamic> 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

View File

@@ -54,7 +54,7 @@ _$PlanModelImpl _$$PlanModelImplFromJson(Map<String, dynamic> 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<String, dynamic> _$$PlanModelImplToJson(_$PlanModelImpl instance) =>
@@ -78,7 +78,7 @@ Map<String, dynamic> _$$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<String, dynamic> json) =>

View File

@@ -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<DietsState>{
class DietsCubit extends Cubit<DietsState> {
final FeedRepository feedRepository;
final DietRepository dietsRepository;
int currentPage = 1;
@@ -52,7 +52,6 @@ class DietsCubit extends Cubit<DietsState>{
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<DietsState>{
);
}
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<DietsState>{
);
}
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<DietsState>{
Future<void> likeDiet(int id, int index) async {
final currentDiets = state.dietsList;
// if (currentDiets.isEmpty) return;
final dietsForModification = [...currentDiets];
final currentDiet = currentDiets[index];
if (currentDiet.wasLikedByMe) {

View File

@@ -284,4 +284,58 @@ class PlansCubit extends Cubit<PlansState> {
},
);
}
Future<void> 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,
),
);
}
},
);
}
}

View File

@@ -28,13 +28,16 @@ class RecipesCubit extends Cubit<RecipesState> {
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<RecipesState> {
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<RecipesState> {
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,
),
);
}
}

View File

@@ -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<FeedScreen> createState() => _FeedScreenState();
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider<RecipesCubit>(
create: (context) => sl<RecipesCubit>()..loadRecipesList(),
),
BlocProvider<FeedProfileCubit>(
create: (context) => sl<FeedProfileCubit>()..getProfile(),
),
BlocProvider<FeedCubit>(
create: (context) => sl<FeedCubit>()..loadFeedBlogPostList(),
),
BlocProvider<DietsCubit>(
create: (context) => sl<DietsCubit>()..loadDiets(),
),
BlocProvider<PlansCubit>(
create: (context) => sl<PlansCubit>()..loadPlans(),
),
BlocProvider<ConsultantsCubit>(
create: (context) => sl<ConsultantsCubit>()..getConsultants(),
),
],
child: const FeedScreenContent(),
);
}
}
class _FeedScreenState extends State<FeedScreen> {
final FeedCubit feedCubit = sl<FeedCubit>();
final RecipesCubit recipesCubit = sl<RecipesCubit>()..loadRecipesList();
final DietsCubit dietsCubit = sl<DietsCubit>()..loadDiets();
final PlansCubit plansCubit = sl<PlansCubit>()..loadPlans();
final ConsultantsCubit consultantsCubit = sl<ConsultantsCubit>()..getConsultants();
class FeedScreenContent extends StatefulWidget {
const FeedScreenContent({super.key});
final searchController = TextEditingController();
@override
State<FeedScreenContent> createState() => _FeedScreenContentState();
}
class _FeedScreenContentState extends State<FeedScreenContent> {
final postsController = TextEditingController();
final recipesController = TextEditingController();
final dietsController = TextEditingController();
final plansController = TextEditingController();
final consultantsController = TextEditingController();
final List<String> chipsLabelList = ['Все', 'Рецепты', 'Диеты', 'Планы питания', 'Консультанты'];
int _selectedChipIndex = 0;
final blogPostsScrollController = ScrollController();
@@ -59,7 +80,6 @@ class _FeedScreenState extends State<FeedScreen> {
@override
void initState() {
feedCubit.loadFeedBlogPostList();
blogPostsScrollController.addListener(_onScrollBlogPosts);
recipesScrollController.addListener(_onScrollRecipes);
dietsScrollController.addListener(_onScrollDiets);
@@ -70,25 +90,25 @@ class _FeedScreenState extends State<FeedScreen> {
_onScrollBlogPosts() {
if (blogPostsScrollController.offset >= blogPostsScrollController.position.maxScrollExtent && !blogPostsScrollController.position.outOfRange) {
feedCubit.loadNextPage();
context.read<FeedCubit>().loadNextPage();
}
}
_onScrollRecipes() {
if (recipesScrollController.offset >= recipesScrollController.position.maxScrollExtent && !recipesScrollController.position.outOfRange) {
recipesCubit.loadNextPage();
context.read<RecipesCubit>().loadNextPage();
}
}
_onScrollDiets() {
if (dietsScrollController.offset >= dietsScrollController.position.maxScrollExtent && !dietsScrollController.position.outOfRange) {
dietsCubit.loadNextPage();
context.read<DietsCubit>().loadNextPage();
}
}
_onScrollPlans() {
if (plansScrollController.offset >= plansScrollController.position.maxScrollExtent && !plansScrollController.position.outOfRange) {
plansCubit.loadNextPage();
context.read<PlansCubit>().loadNextPage();
}
}
@@ -107,402 +127,148 @@ class _FeedScreenState extends State<FeedScreen> {
@override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider<FeedProfileCubit>(
create: (context) => sl<FeedProfileCubit>()..getProfile(),
),
BlocProvider<RecipesCubit>(
create: (context) => sl<RecipesCubit>()..loadRecipesList(),
),
BlocProvider<DietsCubit>(
create: (context) => sl<DietsCubit>()..loadDiets(),
),
BlocProvider<PlansCubit>(
create: (context) => sl<PlansCubit>()..loadPlans(),
),
BlocProvider<ConsultantsCubit>(
create: (context) => sl<ConsultantsCubit>()..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<FeedProfileCubit, ProfileState>(
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<FeedCubit, FeedState>(
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<ConsultantsCubit, ConsultantsState>(
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<RecipesCubit>();
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<RecipesCubit, RecipesState>(
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<FeedProfileCubit, ProfileState>(
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<FeedCubit>().loadFeedBlogPostList(query: query);
break;
case 1:
context.read<RecipesCubit>().loadRecipesList(query: query);
break;
case 2:
context.read<DietsCubit>().loadDiets(query: query);
break;
case 3:
context.read<PlansCubit>().loadPlans(query: query);
break;
case 4:
context.read<ConsultantsCubit>().getConsultants();
break;
}
},
);
} else {
EasyDebounce.debounce(
'searchFeed',
Duration(milliseconds: 500),
() {
switch (_selectedChipIndex) {
case 0:
context.read<FeedCubit>().loadFeedBlogPostList();
break;
case 1:
context.read<RecipesCubit>().loadRecipesList();
break;
case 2:
context.read<DietsCubit>().loadDiets();
break;
case 3:
context.read<PlansCubit>().loadPlans();
break;
case 4:
context.read<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()
},
],
),
);
},
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<DietsCubit, DietsState>(
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<PlansCubit, PlansState>(
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<FeedScreen> {
onSelected: (bool selected) {
setState(() {
_selectedChipIndex = 0;
searchController.clear();
FocusScope.of(context).requestFocus(new FocusNode());
});
},
@@ -538,7 +303,6 @@ class _FeedScreenState extends State<FeedScreen> {
onSelected: (bool selected) {
setState(() {
_selectedChipIndex = 1;
searchController.clear();
FocusScope.of(context).requestFocus(new FocusNode());
});
},
@@ -551,7 +315,6 @@ class _FeedScreenState extends State<FeedScreen> {
onSelected: (bool selected) {
setState(() {
_selectedChipIndex = 2;
searchController.clear();
FocusScope.of(context).requestFocus(new FocusNode());
});
},
@@ -564,7 +327,6 @@ class _FeedScreenState extends State<FeedScreen> {
onSelected: (bool selected) {
setState(() {
_selectedChipIndex = 3;
searchController.clear();
FocusScope.of(context).requestFocus(new FocusNode());
});
},
@@ -577,7 +339,6 @@ class _FeedScreenState extends State<FeedScreen> {
onSelected: (bool selected) {
setState(() {
_selectedChipIndex = 4;
searchController.clear();
FocusScope.of(context).requestFocus(new FocusNode());
});
},

View File

@@ -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<FeedCubit>().loadFeedBlogPostList(),
child: BlocBuilder<FeedCubit, FeedState>(
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(),
);
}
},
),
);
}
}

View File

@@ -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<ConsultantsCubit>().getConsultants(),
child: BlocBuilder<ConsultantsCubit, ConsultantsState>(
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(),
);
}
},
),
);
}
}

View File

@@ -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<DietsCubit>().loadDiets(),
child: BlocBuilder<DietsCubit, DietsState>(
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<DietsCubit>(),
),
),
),
],
);
}
},
),
);
}
}

View File

@@ -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<PlanWidget> {
iconColor: widget.plan.wasLikedByMe ? appTheme.blueA400 : null,
backgroundColor: widget.plan.wasLikedByMe ? appTheme.transparentBlue : null,
onTap: () async {
await context.read<DietsCubit>().likeDiet(widget.plan.id, widget.index);
await context.read<PlansCubit>().likePlan(widget.plan.slug, widget.index);
},
),
SizedBox(

View File

@@ -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<PlansCubit>().loadPlans(),
child: BlocBuilder<PlansCubit, PlansState>(
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<PlansCubit>(),
),
),
),
],
);
},
),
);
}
}

View File

@@ -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<RecipesCubit>().loadRecipesList(),
child: BlocBuilder<RecipesCubit, RecipesState>(
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(),
);
}
},
),
);
}
}

View File

@@ -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 = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<FeedBlogPostSettingsModel>(
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<FeedBlogPostSettingsModel>(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<Map<String, dynamic>>(_options);
late FeedBlogPostSettingsModel _value;
try {
@@ -66,16 +76,22 @@ class _FeedService implements FeedService {
queryParameters.removeWhere((k, v) => v == null);
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<RecipesPagination>(
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<RecipesPagination>(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<Map<String, dynamic>>(_options);
late RecipesPagination _value;
try {
@@ -106,16 +122,22 @@ class _FeedService implements FeedService {
queryParameters.removeWhere((k, v) => v == null);
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<DietsPagination>(
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<DietsPagination>(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<Map<String, dynamic>>(_options);
late DietsPagination _value;
try {
@@ -148,16 +170,22 @@ class _FeedService implements FeedService {
queryParameters.removeWhere((k, v) => v == null);
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<PlanPaginationModel>(
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<PlanPaginationModel>(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<Map<String, dynamic>>(_options);
late PlanPaginationModel _value;
try {
@@ -175,16 +203,22 @@ class _FeedService implements FeedService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<CommentModel>(
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<CommentModel>(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<Map<String, dynamic>>(_options);
late CommentModel _value;
try {
@@ -207,20 +241,32 @@ class _FeedService implements FeedService {
queryParameters.removeWhere((k, v) => v == null);
final _headers = <String, dynamic>{};
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<void>(
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<void>(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<void>(_options);
}
@@ -230,16 +276,22 @@ class _FeedService implements FeedService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<CommentModel>(
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<CommentModel>(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<Map<String, dynamic>>(_options);
late CommentModel _value;
try {
@@ -262,20 +314,32 @@ class _FeedService implements FeedService {
queryParameters.removeWhere((k, v) => v == null);
final _headers = <String, dynamic>{};
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<void>(
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<void>(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<void>(_options);
}
@@ -285,16 +349,22 @@ class _FeedService implements FeedService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<CommentModel>(
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<CommentModel>(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<Map<String, dynamic>>(_options);
late CommentModel _value;
try {
@@ -317,20 +387,32 @@ class _FeedService implements FeedService {
queryParameters.removeWhere((k, v) => v == null);
final _headers = <String, dynamic>{};
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<void>(
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<void>(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<void>(_options);
}
@@ -340,16 +422,22 @@ class _FeedService implements FeedService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<CommentModel>(
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<CommentModel>(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<Map<String, dynamic>>(_options);
late CommentModel _value;
try {
@@ -372,20 +460,32 @@ class _FeedService implements FeedService {
queryParameters.removeWhere((k, v) => v == null);
final _headers = <String, dynamic>{};
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<void>(
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<void>(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<void>(_options);
}
@@ -395,16 +495,22 @@ class _FeedService implements FeedService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<void>(
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<void>(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<void>(_options);
}
@@ -414,16 +520,22 @@ class _FeedService implements FeedService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<void>(
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<void>(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<void>(_options);
}
@@ -433,16 +545,22 @@ class _FeedService implements FeedService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<FeedConsultantPaginationModel>(
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<FeedConsultantPaginationModel>(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<Map<String, dynamic>>(_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;
}

View File

@@ -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<GlossaryPaginationModel> getGlossaryByQuery({
required String query,
}) async {
Future<GlossaryPaginationModel> getGlossaryByQuery(
{required String query}) async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{r'search': query};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<GlossaryPaginationModel>(
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<GlossaryPaginationModel>(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<Map<String, dynamic>>(_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;
}

View File

@@ -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: 'Выход',

View File

@@ -9,7 +9,7 @@ abstract class MyDietsService {
factory MyDietsService(Dio dio, {String baseUrl}) = _MyDietsService;
@GET('/api/diets/index')
@GET('/api/profile/my_diets')
Future<DietsPagination> getDiets({
@Query('page') required int page,
@Query('filters[name][\$startsWith]') String? query,

View File

@@ -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 = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<DietsPagination>(
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<DietsPagination>(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<Map<String, dynamic>>(_options);
late DietsPagination _value;
try {
@@ -63,16 +73,22 @@ class _MyDietsService implements MyDietsService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<void>(
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<void>(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<void>(_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;
}

View File

@@ -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 = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<PlanPaginationModel>(
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<PlanPaginationModel>(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<Map<String, dynamic>>(_options);
late PlanPaginationModel _value;
try {
@@ -65,16 +75,22 @@ class _MyPlansService implements MyPlansService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<void>(
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<void>(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<void>(_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;
}

View File

@@ -363,13 +363,11 @@ class _AboutPlanScreenState extends State<AboutPlanScreen> {
'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),
),
],

View File

@@ -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 = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<PlanModel>(
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<PlanModel>(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<Map<String, dynamic>>(_options);
late PlanModel _value;
try {
@@ -50,16 +60,22 @@ class _PlanService implements PlanService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<void>(
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<void>(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<void>(_options);
}
@@ -69,16 +85,22 @@ class _PlanService implements PlanService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<void>(
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<void>(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<void>(_options);
}
@@ -88,16 +110,22 @@ class _PlanService implements PlanService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<void>(
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<void>(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<void>(_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;
}

View File

@@ -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 = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<PlanPaginationModel>(
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<PlanPaginationModel>(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<Map<String, dynamic>>(_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;
}

View File

@@ -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<ChosenDietModel> diets,
}) = _ChosenDietsPaginationModel;
factory ChosenDietsPaginationModel.fromJson(Map<String, dynamic> 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<String, dynamic> json) => _$ChosenDietModelFromJson(json);
}
int? _parseDietId(json) {
if (json == null) return null;
return json['id'] as int?;
}

View File

@@ -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>(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<String, dynamic> json) {
return _ChosenDietsPaginationModel.fromJson(json);
}
/// @nodoc
mixin _$ChosenDietsPaginationModel {
@JsonKey(name: 'data')
List<ChosenDietModel> get diets => throw _privateConstructorUsedError;
/// Serializes this ChosenDietsPaginationModel to a JSON map.
Map<String, dynamic> 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<ChosenDietsPaginationModel>
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<ChosenDietModel> 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<ChosenDietModel>,
) 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<ChosenDietModel> 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<ChosenDietModel>,
));
}
}
/// @nodoc
@JsonSerializable()
class _$ChosenDietsPaginationModelImpl implements _ChosenDietsPaginationModel {
_$ChosenDietsPaginationModelImpl(
{@JsonKey(name: 'data') required final List<ChosenDietModel> diets})
: _diets = diets;
factory _$ChosenDietsPaginationModelImpl.fromJson(
Map<String, dynamic> json) =>
_$$ChosenDietsPaginationModelImplFromJson(json);
final List<ChosenDietModel> _diets;
@override
@JsonKey(name: 'data')
List<ChosenDietModel> 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<String, dynamic> toJson() {
return _$$ChosenDietsPaginationModelImplToJson(
this,
);
}
}
abstract class _ChosenDietsPaginationModel
implements ChosenDietsPaginationModel {
factory _ChosenDietsPaginationModel(
{@JsonKey(name: 'data') required final List<ChosenDietModel> diets}) =
_$ChosenDietsPaginationModelImpl;
factory _ChosenDietsPaginationModel.fromJson(Map<String, dynamic> json) =
_$ChosenDietsPaginationModelImpl.fromJson;
@override
@JsonKey(name: 'data')
List<ChosenDietModel> 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<String, dynamic> 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<String, dynamic> 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<ChosenDietModel> 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<String, dynamic> 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<String, dynamic> 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<String, dynamic> 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;
}

View File

@@ -0,0 +1,41 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'chosen_diets_pagination_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$ChosenDietsPaginationModelImpl _$$ChosenDietsPaginationModelImplFromJson(
Map<String, dynamic> json) =>
_$ChosenDietsPaginationModelImpl(
diets: (json['data'] as List<dynamic>)
.map((e) => ChosenDietModel.fromJson(e as Map<String, dynamic>))
.toList(),
);
Map<String, dynamic> _$$ChosenDietsPaginationModelImplToJson(
_$ChosenDietsPaginationModelImpl instance) =>
<String, dynamic>{
'data': instance.diets,
};
_$ChosenDietModelImpl _$$ChosenDietModelImplFromJson(
Map<String, dynamic> 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<String, dynamic> _$$ChosenDietModelImplToJson(
_$ChosenDietModelImpl instance) =>
<String, dynamic>{
'id': instance.chosenDietID,
'chosen_plan_id': instance.chosenPlanId,
'state': instance.state,
'start_date': instance.startDate.toIso8601String(),
'diet': instance.dietId,
};

View File

@@ -59,7 +59,6 @@ class _ProfileScreenState extends State<ProfileScreen> {
late bool canSub;
bool isFirstFetch = true;
int _currentBullet = 0;
@override
void initState() {
super.initState();
@@ -338,7 +337,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
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(

View File

@@ -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<void> deletePhoto();
@GET('/api/profile/chosen_diets')
Future<ChosenDietsPaginationModel> getChosenDiets();
}

View File

@@ -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 = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<ProfileModel>(
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<ProfileModel>(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<Map<String, dynamic>>(_options);
late ProfileModel _value;
try {
@@ -50,16 +60,22 @@ class _ProfileService implements ProfileService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<ProfileModel>(
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<ProfileModel>(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<Map<String, dynamic>>(_options);
late ProfileModel _value;
try {
@@ -77,16 +93,22 @@ class _ProfileService implements ProfileService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<ProfileDetailsModel>(
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<ProfileDetailsModel>(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<Map<String, dynamic>>(_options);
late ProfileDetailsModel _value;
try {
@@ -99,23 +121,28 @@ class _ProfileService implements ProfileService {
}
@override
Future<ProfileDetailsModel> getProfileDetailsBySlug({
required String slug,
}) async {
Future<ProfileDetailsModel> getProfileDetailsBySlug(
{required String slug}) async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<ProfileDetailsModel>(
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<ProfileDetailsModel>(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<Map<String, dynamic>>(_options);
late ProfileDetailsModel _value;
try {
@@ -137,25 +164,34 @@ class _ProfileService implements ProfileService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
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<void>(
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<void>(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<void>(_options);
}
@@ -165,46 +201,58 @@ class _ProfileService implements ProfileService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
final _data = FormData();
_data.fields.add(MapEntry('weight', weight.toString()));
final _options = _setStreamType<void>(
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<void>(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<void>(_options);
}
@override
Future<List<FeedBlogPostModel>> getBlogPostByAuthorSlug({
required String slug,
}) async {
Future<List<FeedBlogPostModel>> getBlogPostByAuthorSlug(
{required String slug}) async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<List<FeedBlogPostModel>>(
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<List<FeedBlogPostModel>>(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<List<dynamic>>(_options);
late List<FeedBlogPostModel> _value;
try {
_value = _result.data!
.map(
(dynamic i) =>
FeedBlogPostModel.fromJson(i as Map<String, dynamic>),
)
.map((dynamic i) =>
FeedBlogPostModel.fromJson(i as Map<String, dynamic>))
.toList();
} on Object catch (e, s) {
errorLogger?.logError(e, s, _options);
@@ -219,23 +267,27 @@ class _ProfileService implements ProfileService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<List<WeightModel>>(
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<List<WeightModel>>(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<List<dynamic>>(_options);
late List<WeightModel> _value;
try {
_value = _result.data!
.map(
(dynamic i) => WeightModel.fromJson(i as Map<String, dynamic>),
)
.map((dynamic i) => WeightModel.fromJson(i as Map<String, dynamic>))
.toList();
} on Object catch (e, s) {
errorLogger?.logError(e, s, _options);
@@ -253,23 +305,27 @@ class _ProfileService implements ProfileService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<List<WeightModel>>(
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<List<WeightModel>>(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<List<dynamic>>(_options);
late List<WeightModel> _value;
try {
_value = _result.data!
.map(
(dynamic i) => WeightModel.fromJson(i as Map<String, dynamic>),
)
.map((dynamic i) => WeightModel.fromJson(i as Map<String, dynamic>))
.toList();
} on Object catch (e, s) {
errorLogger?.logError(e, s, _options);
@@ -279,31 +335,34 @@ class _ProfileService implements ProfileService {
}
@override
Future<List<CircumferenceModel>> getCircumferences({
required String period,
}) async {
Future<List<CircumferenceModel>> getCircumferences(
{required String period}) async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<List<CircumferenceModel>>(
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<List<CircumferenceModel>>(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<List<dynamic>>(_options);
late List<CircumferenceModel> _value;
try {
_value = _result.data!
.map(
(dynamic i) =>
CircumferenceModel.fromJson(i as Map<String, dynamic>),
)
.map((dynamic i) =>
CircumferenceModel.fromJson(i as Map<String, dynamic>))
.toList();
} on Object catch (e, s) {
errorLogger?.logError(e, s, _options);
@@ -321,24 +380,28 @@ class _ProfileService implements ProfileService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<List<CircumferenceModel>>(
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<List<CircumferenceModel>>(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<List<dynamic>>(_options);
late List<CircumferenceModel> _value;
try {
_value = _result.data!
.map(
(dynamic i) =>
CircumferenceModel.fromJson(i as Map<String, dynamic>),
)
.map((dynamic i) =>
CircumferenceModel.fromJson(i as Map<String, dynamic>))
.toList();
} on Object catch (e, s) {
errorLogger?.logError(e, s, _options);
@@ -354,21 +417,27 @@ class _ProfileService implements ProfileService {
}) async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{
r'filters[name][$startsWith]': query,
r'filters[name][$startsWith]': query
};
queryParameters.removeWhere((k, v) => v == null);
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<SubPaginationModel>(
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<SubPaginationModel>(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<Map<String, dynamic>>(_options);
late SubPaginationModel _value;
try {
@@ -387,21 +456,27 @@ class _ProfileService implements ProfileService {
}) async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{
r'filters[name][$startsWith]': query,
r'filters[name][$startsWith]': query
};
queryParameters.removeWhere((k, v) => v == null);
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<SubPaginationModel>(
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<SubPaginationModel>(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<Map<String, dynamic>>(_options);
late SubPaginationModel _value;
try {
@@ -419,16 +494,22 @@ class _ProfileService implements ProfileService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<void>(
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<void>(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<void>(_options);
}
@@ -438,16 +519,22 @@ class _ProfileService implements ProfileService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<void>(
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<void>(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<void>(_options);
}
@@ -457,30 +544,30 @@ class _ProfileService implements ProfileService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
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<void>(
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<void>(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<void>(_options);
}
@@ -490,19 +577,58 @@ class _ProfileService implements ProfileService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<void>(
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<void>(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<void>(_options);
}
@override
Future<ChosenDietsPaginationModel> getChosenDiets() async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<ChosenDietsPaginationModel>(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<Map<String, dynamic>>(_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<T>(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;
}

View File

@@ -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 = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<RecipeModel>(
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<RecipeModel>(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<Map<String, dynamic>>(_options);
late RecipeModel _value;
try {
@@ -50,27 +60,30 @@ class _RecipeService implements RecipeService {
final queryParameters = <String, dynamic>{r'name': name};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<Map<String, List<Product>>>(
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<Map<String, List<Product>>>(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<Map<String, dynamic>>(_options);
late Map<String, List<Product>> _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<String, dynamic>))
.toList(),
),
);
.toList()));
} on Object catch (e, s) {
errorLogger?.logError(e, s, _options);
rethrow;
@@ -96,19 +109,34 @@ class _RecipeService implements RecipeService {
final _headers = <String, dynamic>{};
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<RecipeModel>(
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<RecipeModel>(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<Map<String, dynamic>>(_options);
late RecipeModel _value;
try {
@@ -150,21 +185,30 @@ class _RecipeService implements RecipeService {
}
@override
Future<RecipeModel> editRecipe(Map<String, Object?> recipe, String id) async {
Future<RecipeModel> editRecipe(
Map<String, Object?> recipe,
String id,
) async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
final _data = FormData.fromMap(recipe);
final _options = _setStreamType<RecipeModel>(
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<RecipeModel>(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<Map<String, dynamic>>(_options);
late RecipeModel _value;
try {
@@ -182,16 +226,22 @@ class _RecipeService implements RecipeService {
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<RecipeTagModel>(
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<RecipeTagModel>(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<Map<String, dynamic>>(_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;
}

View File

@@ -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<Map<String, String>> register({
required Map<String, dynamic> sheet,
}) async {
Future<Map<String, String>> register(
{required Map<String, dynamic> sheet}) async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
final _data = <String, dynamic>{};
_data.addAll(sheet);
final _options = _setStreamType<Map<String, String>>(
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<Map<String, String>>(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<Map<String, dynamic>>(_options);
late Map<String, String> _value;
try {
@@ -53,16 +62,22 @@ class _RegistrationService implements RegistrationService {
final queryParameters = <String, dynamic>{r'user_address': query};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<LocationModel>(
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<LocationModel>(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<Map<String, dynamic>>(_options);
late LocationModel _value;
try {
@@ -86,16 +101,22 @@ class _RegistrationService implements RegistrationService {
};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<LocationModel>(
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<LocationModel>(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<Map<String, dynamic>>(_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;
}

View File

@@ -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 = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<ProfileSettingsModel>(
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<ProfileSettingsModel>(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<Map<String, dynamic>>(_options);
late ProfileSettingsModel _value;
try {
@@ -45,24 +55,29 @@ class _SettingsService implements SettingsService {
}
@override
Future<ProfileSettingsModel> updateProfileSettings({
required Map<String, dynamic> data,
}) async {
Future<ProfileSettingsModel> updateProfileSettings(
{required Map<String, dynamic> data}) async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
final _data = <String, dynamic>{};
_data.addAll(data);
final _options = _setStreamType<ProfileSettingsModel>(
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<ProfileSettingsModel>(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<Map<String, dynamic>>(_options);
late ProfileSettingsModel _value;
try {
@@ -75,24 +90,29 @@ class _SettingsService implements SettingsService {
}
@override
Future<ProfileDetailsModel> updateProfileDetails({
required Map<String, dynamic> data,
}) async {
Future<ProfileDetailsModel> updateProfileDetails(
{required Map<String, dynamic> data}) async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
final _data = <String, dynamic>{};
_data.addAll(data);
final _options = _setStreamType<ProfileDetailsModel>(
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<ProfileDetailsModel>(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<Map<String, dynamic>>(_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;
}

View File

@@ -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<InitializationCubit>(create: (context) => sl<InitializationCubit>()..runInitialization()),
providers: [
BlocProvider<NewMessagesCubit>(create: (context) => sl<NewMessagesCubit>()),
BlocProvider<NotificationsCubit>(create: (context) => sl<NotificationsCubit>()),
BlocProvider<FeedCubit>(create: (context) => sl<FeedCubit>()..loadFeedBlogPostList()),

View File

@@ -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<void> addCircumference({
_i6.Future<void> addCircumference({
required int? chestCircumference,
required int? waistCircumference,
required int? hipCircumference,
}) =>
(super.noSuchMethod(
Invocation.method(#addCircumference, [], {
#chestCircumference: chestCircumference,
#waistCircumference: waistCircumference,
#hipCircumference: hipCircumference,
}),
returnValue: _i5.Future<void>.value(),
returnValueForMissingStub: _i5.Future<void>.value(),
)
as _i5.Future<void>);
Invocation.method(
#addCircumference,
[],
{
#chestCircumference: chestCircumference,
#waistCircumference: waistCircumference,
#hipCircumference: hipCircumference,
},
),
returnValue: _i6.Future<void>.value(),
returnValueForMissingStub: _i6.Future<void>.value(),
) as _i6.Future<void>);
@override
_i5.Future<void> addWeight({required double? weight}) =>
_i6.Future<void> addWeight({required double? weight}) => (super.noSuchMethod(
Invocation.method(
#addWeight,
[],
{#weight: weight},
),
returnValue: _i6.Future<void>.value(),
returnValueForMissingStub: _i6.Future<void>.value(),
) as _i6.Future<void>);
@override
_i6.Future<List<_i7.FeedBlogPostModel>> getBlogPostByAuthorSlug(
{required String? slug}) =>
(super.noSuchMethod(
Invocation.method(#addWeight, [], {#weight: weight}),
returnValue: _i5.Future<void>.value(),
returnValueForMissingStub: _i5.Future<void>.value(),
)
as _i5.Future<void>);
Invocation.method(
#getBlogPostByAuthorSlug,
[],
{#slug: slug},
),
returnValue: _i6.Future<List<_i7.FeedBlogPostModel>>.value(
<_i7.FeedBlogPostModel>[]),
returnValueForMissingStub:
_i6.Future<List<_i7.FeedBlogPostModel>>.value(
<_i7.FeedBlogPostModel>[]),
) as _i6.Future<List<_i7.FeedBlogPostModel>>);
@override
_i5.Future<List<_i6.FeedBlogPostModel>> getBlogPostByAuthorSlug({
required String? slug,
}) =>
_i6.Future<List<_i8.WeightModel>> getWeight({required String? period}) =>
(super.noSuchMethod(
Invocation.method(#getBlogPostByAuthorSlug, [], {#slug: slug}),
returnValue: _i5.Future<List<_i6.FeedBlogPostModel>>.value(
<_i6.FeedBlogPostModel>[],
),
returnValueForMissingStub:
_i5.Future<List<_i6.FeedBlogPostModel>>.value(
<_i6.FeedBlogPostModel>[],
),
)
as _i5.Future<List<_i6.FeedBlogPostModel>>);
Invocation.method(
#getWeight,
[],
{#period: period},
),
returnValue:
_i6.Future<List<_i8.WeightModel>>.value(<_i8.WeightModel>[]),
returnValueForMissingStub:
_i6.Future<List<_i8.WeightModel>>.value(<_i8.WeightModel>[]),
) as _i6.Future<List<_i8.WeightModel>>);
@override
_i5.Future<List<_i7.WeightModel>> getWeight({required String? period}) =>
(super.noSuchMethod(
Invocation.method(#getWeight, [], {#period: period}),
returnValue: _i5.Future<List<_i7.WeightModel>>.value(
<_i7.WeightModel>[],
),
returnValueForMissingStub: _i5.Future<List<_i7.WeightModel>>.value(
<_i7.WeightModel>[],
),
)
as _i5.Future<List<_i7.WeightModel>>);
@override
_i5.Future<List<_i7.WeightModel>> getWeightBySlug({
_i6.Future<List<_i8.WeightModel>> getWeightBySlug({
required String? period,
required String? slug,
}) =>
(super.noSuchMethod(
Invocation.method(#getWeightBySlug, [], {
#period: period,
#slug: slug,
}),
returnValue: _i5.Future<List<_i7.WeightModel>>.value(
<_i7.WeightModel>[],
),
returnValueForMissingStub: _i5.Future<List<_i7.WeightModel>>.value(
<_i7.WeightModel>[],
),
)
as _i5.Future<List<_i7.WeightModel>>);
Invocation.method(
#getWeightBySlug,
[],
{
#period: period,
#slug: slug,
},
),
returnValue:
_i6.Future<List<_i8.WeightModel>>.value(<_i8.WeightModel>[]),
returnValueForMissingStub:
_i6.Future<List<_i8.WeightModel>>.value(<_i8.WeightModel>[]),
) as _i6.Future<List<_i8.WeightModel>>);
@override
_i5.Future<List<_i8.CircumferenceModel>> getCircumferences({
required String? period,
}) =>
_i6.Future<List<_i9.CircumferenceModel>> getCircumferences(
{required String? period}) =>
(super.noSuchMethod(
Invocation.method(#getCircumferences, [], {#period: period}),
returnValue: _i5.Future<List<_i8.CircumferenceModel>>.value(
<_i8.CircumferenceModel>[],
),
returnValueForMissingStub:
_i5.Future<List<_i8.CircumferenceModel>>.value(
<_i8.CircumferenceModel>[],
),
)
as _i5.Future<List<_i8.CircumferenceModel>>);
Invocation.method(
#getCircumferences,
[],
{#period: period},
),
returnValue: _i6.Future<List<_i9.CircumferenceModel>>.value(
<_i9.CircumferenceModel>[]),
returnValueForMissingStub:
_i6.Future<List<_i9.CircumferenceModel>>.value(
<_i9.CircumferenceModel>[]),
) as _i6.Future<List<_i9.CircumferenceModel>>);
@override
_i5.Future<List<_i8.CircumferenceModel>> getCircumferencesBySlug({
_i6.Future<List<_i9.CircumferenceModel>> getCircumferencesBySlug({
required String? period,
required String? slug,
}) =>
(super.noSuchMethod(
Invocation.method(#getCircumferencesBySlug, [], {
#period: period,
#slug: slug,
}),
returnValue: _i5.Future<List<_i8.CircumferenceModel>>.value(
<_i8.CircumferenceModel>[],
),
returnValueForMissingStub:
_i5.Future<List<_i8.CircumferenceModel>>.value(
<_i8.CircumferenceModel>[],
),
)
as _i5.Future<List<_i8.CircumferenceModel>>);
Invocation.method(
#getCircumferencesBySlug,
[],
{
#period: period,
#slug: slug,
},
),
returnValue: _i6.Future<List<_i9.CircumferenceModel>>.value(
<_i9.CircumferenceModel>[]),
returnValueForMissingStub:
_i6.Future<List<_i9.CircumferenceModel>>.value(
<_i9.CircumferenceModel>[]),
) as _i6.Future<List<_i9.CircumferenceModel>>);
@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<void> subscribe({required String? slug}) =>
(super.noSuchMethod(
Invocation.method(#subscribe, [], {#slug: slug}),
returnValue: _i5.Future<void>.value(),
returnValueForMissingStub: _i5.Future<void>.value(),
)
as _i5.Future<void>);
_i6.Future<void> subscribe({required String? slug}) => (super.noSuchMethod(
Invocation.method(
#subscribe,
[],
{#slug: slug},
),
returnValue: _i6.Future<void>.value(),
returnValueForMissingStub: _i6.Future<void>.value(),
) as _i6.Future<void>);
@override
_i5.Future<void> unsubscribe({required String? slug}) =>
(super.noSuchMethod(
Invocation.method(#unsubscribe, [], {#slug: slug}),
returnValue: _i5.Future<void>.value(),
returnValueForMissingStub: _i5.Future<void>.value(),
)
as _i5.Future<void>);
_i6.Future<void> unsubscribe({required String? slug}) => (super.noSuchMethod(
Invocation.method(
#unsubscribe,
[],
{#slug: slug},
),
returnValue: _i6.Future<void>.value(),
returnValueForMissingStub: _i6.Future<void>.value(),
) as _i6.Future<void>);
@override
_i5.Future<void> uploadPhoto({required _i9.File? photo}) =>
_i6.Future<void> uploadPhoto({required _i10.File? photo}) =>
(super.noSuchMethod(
Invocation.method(#uploadPhoto, [], {#photo: photo}),
returnValue: _i5.Future<void>.value(),
returnValueForMissingStub: _i5.Future<void>.value(),
)
as _i5.Future<void>);
Invocation.method(
#uploadPhoto,
[],
{#photo: photo},
),
returnValue: _i6.Future<void>.value(),
returnValueForMissingStub: _i6.Future<void>.value(),
) as _i6.Future<void>);
@override
_i5.Future<void> deletePhoto() =>
_i6.Future<void> deletePhoto() => (super.noSuchMethod(
Invocation.method(
#deletePhoto,
[],
),
returnValue: _i6.Future<void>.value(),
returnValueForMissingStub: _i6.Future<void>.value(),
) as _i6.Future<void>);
@override
_i6.Future<_i4.ChosenDietsPaginationModel> getChosenDiets() =>
(super.noSuchMethod(
Invocation.method(#deletePhoto, []),
returnValue: _i5.Future<void>.value(),
returnValueForMissingStub: _i5.Future<void>.value(),
)
as _i5.Future<void>);
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>);
}