forked from eatvio/eatvio_app
chats have been updated to work with consultatons
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// String baseUrl = 'https://eatvio.ru';
|
||||
String baseUrl = 'http://10.55.5.123:8080';
|
||||
String baseUrl = 'https://dev2.eatvio.com';
|
||||
|
||||
const List<int> durationValues = [7, 14, 21];
|
||||
|
||||
|
||||
@@ -184,6 +184,7 @@ class PrimaryColors {
|
||||
Color get dottedBorder => Color(0xFFE6E6E6);
|
||||
|
||||
Color get red => Color(0xFFCD4141);
|
||||
Color get strongRed => Color(0xFFD01717);
|
||||
|
||||
Color get transparentRed => Color(0xFFCD4141).withValues(alpha: 0.75);
|
||||
|
||||
|
||||
47
lib/core/widgets/item_widget.dart
Normal file
47
lib/core/widgets/item_widget.dart
Normal file
@@ -0,0 +1,47 @@
|
||||
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
|
||||
class ItemWidget extends StatelessWidget {
|
||||
const ItemWidget({super.key, required this.text, this.reversed = false, this.iconSize = 20});
|
||||
final String text;
|
||||
final bool reversed;
|
||||
final double iconSize;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (reversed) {
|
||||
return Row(
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
'assets/icons/ok.svg',
|
||||
width: iconSize,
|
||||
height: iconSize,
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
text,
|
||||
style: TextStyles.textMMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
text,
|
||||
style: TextStyles.textMMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
),
|
||||
SvgPicture.asset(
|
||||
'assets/icons/ok.svg',
|
||||
width: iconSize,
|
||||
height: iconSize,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
import 'package:eatvio_app/core/app_router.dart';
|
||||
import 'package:eatvio_app/core/locator_service.dart';
|
||||
import 'package:eatvio_app/core/token_storage.dart';
|
||||
import 'package:eatvio_app/core/utils/toasts.dart';
|
||||
import 'package:eatvio_app/features/auth/presentation/bloc/auth_state.dart';
|
||||
import 'package:eatvio_app/features/auth/repositories/auth_repository.dart';
|
||||
import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_cubit.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
@@ -15,7 +13,7 @@ class AuthCubit extends Cubit<AuthState> {
|
||||
required this.authRepository,
|
||||
}) : super(AuthState());
|
||||
|
||||
getTokenByCredentials(String email, String password) async {
|
||||
Future<bool> getTokenByCredentials(String email, String password) async {
|
||||
emit(AuthState.loading());
|
||||
try {
|
||||
final token = (await authRepository.getTokenByCredentials(
|
||||
@@ -23,7 +21,6 @@ class AuthCubit extends Cubit<AuthState> {
|
||||
password,
|
||||
))
|
||||
.token;
|
||||
print(token);
|
||||
emit(
|
||||
AuthState.loaded(
|
||||
token: token,
|
||||
@@ -31,12 +28,13 @@ class AuthCubit extends Cubit<AuthState> {
|
||||
);
|
||||
showSuccessToast('Успешный вход');
|
||||
await TokenStorage.saveTokenInStorage(token);
|
||||
await sl<ProfileAvatarCubit>().getMyProfile();
|
||||
AppRouter.navigatorKey.currentContext?.go('/my-profile-screen');
|
||||
return true;
|
||||
} catch (e) {
|
||||
print(e);
|
||||
showErrorToast('Неверный адрес электронной почты или пароль');
|
||||
emit(AuthState.error(errorMessage: '$e'));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/utils/image_constant.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_text_form_field.dart';
|
||||
import 'package:eatvio_app/features/auth/presentation/bloc/auth_cubit.dart';
|
||||
import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_cubit.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/bloc/chats_cubit/chats_cubit.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
@@ -140,10 +142,16 @@ class _AuthScreenState extends State<AuthScreen> {
|
||||
backgroundColor: state is AuthStateLoading ? Colors.black.withAlpha(50) : appTheme.blueA400,
|
||||
onPressed: state is AuthStateLoading
|
||||
? null
|
||||
: () => authCubit.getTokenByCredentials(
|
||||
: () async {
|
||||
final isAuthenticated = await authCubit.getTokenByCredentials(
|
||||
emailController.text,
|
||||
passwordController.text,
|
||||
),
|
||||
);
|
||||
if (isAuthenticated) {
|
||||
context.read<ProfileAvatarCubit>().getMyProfile();
|
||||
context.read<ChatsCubit>().getChatRoomsWithLoading();
|
||||
}
|
||||
},
|
||||
label: state is AuthStateLoading
|
||||
? CupertinoActivityIndicator()
|
||||
: Text(
|
||||
|
||||
@@ -11,16 +11,23 @@ class ChatRoomModel with _$ChatRoomModel {
|
||||
const factory ChatRoomModel({
|
||||
required String id,
|
||||
@JsonKey(name: 'chat_room_setting') required ChatRoomSettingsModel chatRoomSettings,
|
||||
required Map<String, ChatUserModel> users,
|
||||
@JsonKey(name: 'chosen_plan', fromJson: _parseChosenPlan) required ChosenPlanModel? chosenPlan,
|
||||
required Users users,
|
||||
@JsonKey(name: 'chosen_plan', fromJson: parseChosenPlan) required ChosenPlanModel? chosenPlan,
|
||||
}) = _ChatRoomModel;
|
||||
|
||||
factory ChatRoomModel.fromJson(Map<String, Object?> json) => _$ChatRoomModelFromJson(json);
|
||||
}
|
||||
|
||||
ChosenPlanModel? _parseChosenPlan(json) {
|
||||
if (json is Map<String, dynamic>) {
|
||||
return ChosenPlanModel.fromJson(json);
|
||||
}
|
||||
return null;
|
||||
@freezed
|
||||
class Users with _$Users {
|
||||
const factory Users({
|
||||
|
||||
@JsonKey(name: 'from_chat_user') required ChatUserModel sender,
|
||||
@JsonKey(name: 'to_chat_user') required ChatUserModel receiver,
|
||||
|
||||
}) = _Users;
|
||||
|
||||
factory Users.fromJson(Map<String, Object?> json) => _$UsersFromJson(json);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -24,8 +24,8 @@ mixin _$ChatRoomModel {
|
||||
@JsonKey(name: 'chat_room_setting')
|
||||
ChatRoomSettingsModel get chatRoomSettings =>
|
||||
throw _privateConstructorUsedError;
|
||||
Map<String, ChatUserModel> get users => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'chosen_plan', fromJson: _parseChosenPlan)
|
||||
Users get users => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'chosen_plan', fromJson: parseChosenPlan)
|
||||
ChosenPlanModel? get chosenPlan => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this ChatRoomModel to a JSON map.
|
||||
@@ -48,11 +48,12 @@ abstract class $ChatRoomModelCopyWith<$Res> {
|
||||
{String id,
|
||||
@JsonKey(name: 'chat_room_setting')
|
||||
ChatRoomSettingsModel chatRoomSettings,
|
||||
Map<String, ChatUserModel> users,
|
||||
@JsonKey(name: 'chosen_plan', fromJson: _parseChosenPlan)
|
||||
Users users,
|
||||
@JsonKey(name: 'chosen_plan', fromJson: parseChosenPlan)
|
||||
ChosenPlanModel? chosenPlan});
|
||||
|
||||
$ChatRoomSettingsModelCopyWith<$Res> get chatRoomSettings;
|
||||
$UsersCopyWith<$Res> get users;
|
||||
$ChosenPlanModelCopyWith<$Res>? get chosenPlan;
|
||||
}
|
||||
|
||||
@@ -88,7 +89,7 @@ class _$ChatRoomModelCopyWithImpl<$Res, $Val extends ChatRoomModel>
|
||||
users: null == users
|
||||
? _value.users
|
||||
: users // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, ChatUserModel>,
|
||||
as Users,
|
||||
chosenPlan: freezed == chosenPlan
|
||||
? _value.chosenPlan
|
||||
: chosenPlan // ignore: cast_nullable_to_non_nullable
|
||||
@@ -107,6 +108,16 @@ class _$ChatRoomModelCopyWithImpl<$Res, $Val extends ChatRoomModel>
|
||||
});
|
||||
}
|
||||
|
||||
/// Create a copy of ChatRoomModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$UsersCopyWith<$Res> get users {
|
||||
return $UsersCopyWith<$Res>(_value.users, (value) {
|
||||
return _then(_value.copyWith(users: value) as $Val);
|
||||
});
|
||||
}
|
||||
|
||||
/// Create a copy of ChatRoomModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@@ -134,13 +145,15 @@ abstract class _$$ChatRoomModelImplCopyWith<$Res>
|
||||
{String id,
|
||||
@JsonKey(name: 'chat_room_setting')
|
||||
ChatRoomSettingsModel chatRoomSettings,
|
||||
Map<String, ChatUserModel> users,
|
||||
@JsonKey(name: 'chosen_plan', fromJson: _parseChosenPlan)
|
||||
Users users,
|
||||
@JsonKey(name: 'chosen_plan', fromJson: parseChosenPlan)
|
||||
ChosenPlanModel? chosenPlan});
|
||||
|
||||
@override
|
||||
$ChatRoomSettingsModelCopyWith<$Res> get chatRoomSettings;
|
||||
@override
|
||||
$UsersCopyWith<$Res> get users;
|
||||
@override
|
||||
$ChosenPlanModelCopyWith<$Res>? get chosenPlan;
|
||||
}
|
||||
|
||||
@@ -172,9 +185,9 @@ class __$$ChatRoomModelImplCopyWithImpl<$Res>
|
||||
: chatRoomSettings // ignore: cast_nullable_to_non_nullable
|
||||
as ChatRoomSettingsModel,
|
||||
users: null == users
|
||||
? _value._users
|
||||
? _value.users
|
||||
: users // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, ChatUserModel>,
|
||||
as Users,
|
||||
chosenPlan: freezed == chosenPlan
|
||||
? _value.chosenPlan
|
||||
: chosenPlan // ignore: cast_nullable_to_non_nullable
|
||||
@@ -189,10 +202,9 @@ class _$ChatRoomModelImpl implements _ChatRoomModel {
|
||||
const _$ChatRoomModelImpl(
|
||||
{required this.id,
|
||||
@JsonKey(name: 'chat_room_setting') required this.chatRoomSettings,
|
||||
required final Map<String, ChatUserModel> users,
|
||||
@JsonKey(name: 'chosen_plan', fromJson: _parseChosenPlan)
|
||||
required this.chosenPlan})
|
||||
: _users = users;
|
||||
required this.users,
|
||||
@JsonKey(name: 'chosen_plan', fromJson: parseChosenPlan)
|
||||
required this.chosenPlan});
|
||||
|
||||
factory _$ChatRoomModelImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$ChatRoomModelImplFromJson(json);
|
||||
@@ -202,16 +214,10 @@ class _$ChatRoomModelImpl implements _ChatRoomModel {
|
||||
@override
|
||||
@JsonKey(name: 'chat_room_setting')
|
||||
final ChatRoomSettingsModel chatRoomSettings;
|
||||
final Map<String, ChatUserModel> _users;
|
||||
@override
|
||||
Map<String, ChatUserModel> get users {
|
||||
if (_users is EqualUnmodifiableMapView) return _users;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(_users);
|
||||
}
|
||||
|
||||
final Users users;
|
||||
@override
|
||||
@JsonKey(name: 'chosen_plan', fromJson: _parseChosenPlan)
|
||||
@JsonKey(name: 'chosen_plan', fromJson: parseChosenPlan)
|
||||
final ChosenPlanModel? chosenPlan;
|
||||
|
||||
@override
|
||||
@@ -227,15 +233,15 @@ class _$ChatRoomModelImpl implements _ChatRoomModel {
|
||||
(identical(other.id, id) || other.id == id) &&
|
||||
(identical(other.chatRoomSettings, chatRoomSettings) ||
|
||||
other.chatRoomSettings == chatRoomSettings) &&
|
||||
const DeepCollectionEquality().equals(other._users, _users) &&
|
||||
(identical(other.users, users) || other.users == users) &&
|
||||
(identical(other.chosenPlan, chosenPlan) ||
|
||||
other.chosenPlan == chosenPlan));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, id, chatRoomSettings,
|
||||
const DeepCollectionEquality().hash(_users), chosenPlan);
|
||||
int get hashCode =>
|
||||
Object.hash(runtimeType, id, chatRoomSettings, users, chosenPlan);
|
||||
|
||||
/// Create a copy of ChatRoomModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -258,8 +264,8 @@ abstract class _ChatRoomModel implements ChatRoomModel {
|
||||
{required final String id,
|
||||
@JsonKey(name: 'chat_room_setting')
|
||||
required final ChatRoomSettingsModel chatRoomSettings,
|
||||
required final Map<String, ChatUserModel> users,
|
||||
@JsonKey(name: 'chosen_plan', fromJson: _parseChosenPlan)
|
||||
required final Users users,
|
||||
@JsonKey(name: 'chosen_plan', fromJson: parseChosenPlan)
|
||||
required final ChosenPlanModel? chosenPlan}) = _$ChatRoomModelImpl;
|
||||
|
||||
factory _ChatRoomModel.fromJson(Map<String, dynamic> json) =
|
||||
@@ -271,9 +277,9 @@ abstract class _ChatRoomModel implements ChatRoomModel {
|
||||
@JsonKey(name: 'chat_room_setting')
|
||||
ChatRoomSettingsModel get chatRoomSettings;
|
||||
@override
|
||||
Map<String, ChatUserModel> get users;
|
||||
Users get users;
|
||||
@override
|
||||
@JsonKey(name: 'chosen_plan', fromJson: _parseChosenPlan)
|
||||
@JsonKey(name: 'chosen_plan', fromJson: parseChosenPlan)
|
||||
ChosenPlanModel? get chosenPlan;
|
||||
|
||||
/// Create a copy of ChatRoomModel
|
||||
@@ -283,3 +289,208 @@ abstract class _ChatRoomModel implements ChatRoomModel {
|
||||
_$$ChatRoomModelImplCopyWith<_$ChatRoomModelImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
Users _$UsersFromJson(Map<String, dynamic> json) {
|
||||
return _Users.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$Users {
|
||||
@JsonKey(name: 'from_chat_user')
|
||||
ChatUserModel get sender => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'to_chat_user')
|
||||
ChatUserModel get receiver => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this Users to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of Users
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$UsersCopyWith<Users> get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $UsersCopyWith<$Res> {
|
||||
factory $UsersCopyWith(Users value, $Res Function(Users) then) =
|
||||
_$UsersCopyWithImpl<$Res, Users>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{@JsonKey(name: 'from_chat_user') ChatUserModel sender,
|
||||
@JsonKey(name: 'to_chat_user') ChatUserModel receiver});
|
||||
|
||||
$ChatUserModelCopyWith<$Res> get sender;
|
||||
$ChatUserModelCopyWith<$Res> get receiver;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$UsersCopyWithImpl<$Res, $Val extends Users>
|
||||
implements $UsersCopyWith<$Res> {
|
||||
_$UsersCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of Users
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? sender = null,
|
||||
Object? receiver = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
sender: null == sender
|
||||
? _value.sender
|
||||
: sender // ignore: cast_nullable_to_non_nullable
|
||||
as ChatUserModel,
|
||||
receiver: null == receiver
|
||||
? _value.receiver
|
||||
: receiver // ignore: cast_nullable_to_non_nullable
|
||||
as ChatUserModel,
|
||||
) as $Val);
|
||||
}
|
||||
|
||||
/// Create a copy of Users
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$ChatUserModelCopyWith<$Res> get sender {
|
||||
return $ChatUserModelCopyWith<$Res>(_value.sender, (value) {
|
||||
return _then(_value.copyWith(sender: value) as $Val);
|
||||
});
|
||||
}
|
||||
|
||||
/// Create a copy of Users
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$ChatUserModelCopyWith<$Res> get receiver {
|
||||
return $ChatUserModelCopyWith<$Res>(_value.receiver, (value) {
|
||||
return _then(_value.copyWith(receiver: value) as $Val);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$UsersImplCopyWith<$Res> implements $UsersCopyWith<$Res> {
|
||||
factory _$$UsersImplCopyWith(
|
||||
_$UsersImpl value, $Res Function(_$UsersImpl) then) =
|
||||
__$$UsersImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{@JsonKey(name: 'from_chat_user') ChatUserModel sender,
|
||||
@JsonKey(name: 'to_chat_user') ChatUserModel receiver});
|
||||
|
||||
@override
|
||||
$ChatUserModelCopyWith<$Res> get sender;
|
||||
@override
|
||||
$ChatUserModelCopyWith<$Res> get receiver;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$UsersImplCopyWithImpl<$Res>
|
||||
extends _$UsersCopyWithImpl<$Res, _$UsersImpl>
|
||||
implements _$$UsersImplCopyWith<$Res> {
|
||||
__$$UsersImplCopyWithImpl(
|
||||
_$UsersImpl _value, $Res Function(_$UsersImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of Users
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? sender = null,
|
||||
Object? receiver = null,
|
||||
}) {
|
||||
return _then(_$UsersImpl(
|
||||
sender: null == sender
|
||||
? _value.sender
|
||||
: sender // ignore: cast_nullable_to_non_nullable
|
||||
as ChatUserModel,
|
||||
receiver: null == receiver
|
||||
? _value.receiver
|
||||
: receiver // ignore: cast_nullable_to_non_nullable
|
||||
as ChatUserModel,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$UsersImpl implements _Users {
|
||||
const _$UsersImpl(
|
||||
{@JsonKey(name: 'from_chat_user') required this.sender,
|
||||
@JsonKey(name: 'to_chat_user') required this.receiver});
|
||||
|
||||
factory _$UsersImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$UsersImplFromJson(json);
|
||||
|
||||
@override
|
||||
@JsonKey(name: 'from_chat_user')
|
||||
final ChatUserModel sender;
|
||||
@override
|
||||
@JsonKey(name: 'to_chat_user')
|
||||
final ChatUserModel receiver;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Users(sender: $sender, receiver: $receiver)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$UsersImpl &&
|
||||
(identical(other.sender, sender) || other.sender == sender) &&
|
||||
(identical(other.receiver, receiver) ||
|
||||
other.receiver == receiver));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, sender, receiver);
|
||||
|
||||
/// Create a copy of Users
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$UsersImplCopyWith<_$UsersImpl> get copyWith =>
|
||||
__$$UsersImplCopyWithImpl<_$UsersImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$UsersImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _Users implements Users {
|
||||
const factory _Users(
|
||||
{@JsonKey(name: 'from_chat_user') required final ChatUserModel sender,
|
||||
@JsonKey(name: 'to_chat_user')
|
||||
required final ChatUserModel receiver}) = _$UsersImpl;
|
||||
|
||||
factory _Users.fromJson(Map<String, dynamic> json) = _$UsersImpl.fromJson;
|
||||
|
||||
@override
|
||||
@JsonKey(name: 'from_chat_user')
|
||||
ChatUserModel get sender;
|
||||
@override
|
||||
@JsonKey(name: 'to_chat_user')
|
||||
ChatUserModel get receiver;
|
||||
|
||||
/// Create a copy of Users
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$UsersImplCopyWith<_$UsersImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
@@ -11,11 +11,8 @@ _$ChatRoomModelImpl _$$ChatRoomModelImplFromJson(Map<String, dynamic> json) =>
|
||||
id: json['id'] as String,
|
||||
chatRoomSettings: ChatRoomSettingsModel.fromJson(
|
||||
json['chat_room_setting'] as Map<String, dynamic>),
|
||||
users: (json['users'] as Map<String, dynamic>).map(
|
||||
(k, e) =>
|
||||
MapEntry(k, ChatUserModel.fromJson(e as Map<String, dynamic>)),
|
||||
),
|
||||
chosenPlan: _parseChosenPlan(json['chosen_plan']),
|
||||
users: Users.fromJson(json['users'] as Map<String, dynamic>),
|
||||
chosenPlan: parseChosenPlan(json['chosen_plan']),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$ChatRoomModelImplToJson(_$ChatRoomModelImpl instance) =>
|
||||
@@ -25,3 +22,16 @@ Map<String, dynamic> _$$ChatRoomModelImplToJson(_$ChatRoomModelImpl instance) =>
|
||||
'users': instance.users,
|
||||
'chosen_plan': instance.chosenPlan,
|
||||
};
|
||||
|
||||
_$UsersImpl _$$UsersImplFromJson(Map<String, dynamic> json) => _$UsersImpl(
|
||||
sender: ChatUserModel.fromJson(
|
||||
json['from_chat_user'] as Map<String, dynamic>),
|
||||
receiver:
|
||||
ChatUserModel.fromJson(json['to_chat_user'] as Map<String, dynamic>),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$UsersImplToJson(_$UsersImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'from_chat_user': instance.sender,
|
||||
'to_chat_user': instance.receiver,
|
||||
};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:eatvio_app/features/chat/models/chat_message_model.dart';
|
||||
import 'package:eatvio_app/features/plans/models/chosen_plan_model.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'chat_room_pagination_model.freezed.dart';
|
||||
@@ -33,6 +34,7 @@ class ChatRoom with _$ChatRoom {
|
||||
@JsonKey(name: "last_message", fromJson: parseLastMessage) required ChatMessageModel? lastMessage,
|
||||
@JsonKey(name: "users") required Users users,
|
||||
@JsonKey(name: "unread_messages_count") required int unreadMessagesCount,
|
||||
@JsonKey(name: 'chosen_plan', fromJson: parseChosenPlan) required ChosenPlanModel? chosenPlan,
|
||||
}) = _ChatRoom;
|
||||
|
||||
factory ChatRoom.fromJson(Map<String, dynamic> json) => _$ChatRoomFromJson(json);
|
||||
|
||||
@@ -445,6 +445,8 @@ mixin _$ChatRoom {
|
||||
Users get users => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "unread_messages_count")
|
||||
int get unreadMessagesCount => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'chosen_plan', fromJson: parseChosenPlan)
|
||||
ChosenPlanModel? get chosenPlan => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this ChatRoom to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@@ -467,10 +469,13 @@ abstract class $ChatRoomCopyWith<$Res> {
|
||||
@JsonKey(name: "last_message", fromJson: parseLastMessage)
|
||||
ChatMessageModel? lastMessage,
|
||||
@JsonKey(name: "users") Users users,
|
||||
@JsonKey(name: "unread_messages_count") int unreadMessagesCount});
|
||||
@JsonKey(name: "unread_messages_count") int unreadMessagesCount,
|
||||
@JsonKey(name: 'chosen_plan', fromJson: parseChosenPlan)
|
||||
ChosenPlanModel? chosenPlan});
|
||||
|
||||
$ChatMessageModelCopyWith<$Res>? get lastMessage;
|
||||
$UsersCopyWith<$Res> get users;
|
||||
$ChosenPlanModelCopyWith<$Res>? get chosenPlan;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -493,6 +498,7 @@ class _$ChatRoomCopyWithImpl<$Res, $Val extends ChatRoom>
|
||||
Object? lastMessage = freezed,
|
||||
Object? users = null,
|
||||
Object? unreadMessagesCount = null,
|
||||
Object? chosenPlan = freezed,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
id: null == id
|
||||
@@ -515,6 +521,10 @@ class _$ChatRoomCopyWithImpl<$Res, $Val extends ChatRoom>
|
||||
? _value.unreadMessagesCount
|
||||
: unreadMessagesCount // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
chosenPlan: freezed == chosenPlan
|
||||
? _value.chosenPlan
|
||||
: chosenPlan // ignore: cast_nullable_to_non_nullable
|
||||
as ChosenPlanModel?,
|
||||
) as $Val);
|
||||
}
|
||||
|
||||
@@ -541,6 +551,20 @@ class _$ChatRoomCopyWithImpl<$Res, $Val extends ChatRoom>
|
||||
return _then(_value.copyWith(users: value) as $Val);
|
||||
});
|
||||
}
|
||||
|
||||
/// Create a copy of ChatRoom
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$ChosenPlanModelCopyWith<$Res>? get chosenPlan {
|
||||
if (_value.chosenPlan == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $ChosenPlanModelCopyWith<$Res>(_value.chosenPlan!, (value) {
|
||||
return _then(_value.copyWith(chosenPlan: value) as $Val);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -557,12 +581,16 @@ abstract class _$$ChatRoomImplCopyWith<$Res>
|
||||
@JsonKey(name: "last_message", fromJson: parseLastMessage)
|
||||
ChatMessageModel? lastMessage,
|
||||
@JsonKey(name: "users") Users users,
|
||||
@JsonKey(name: "unread_messages_count") int unreadMessagesCount});
|
||||
@JsonKey(name: "unread_messages_count") int unreadMessagesCount,
|
||||
@JsonKey(name: 'chosen_plan', fromJson: parseChosenPlan)
|
||||
ChosenPlanModel? chosenPlan});
|
||||
|
||||
@override
|
||||
$ChatMessageModelCopyWith<$Res>? get lastMessage;
|
||||
@override
|
||||
$UsersCopyWith<$Res> get users;
|
||||
@override
|
||||
$ChosenPlanModelCopyWith<$Res>? get chosenPlan;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -583,6 +611,7 @@ class __$$ChatRoomImplCopyWithImpl<$Res>
|
||||
Object? lastMessage = freezed,
|
||||
Object? users = null,
|
||||
Object? unreadMessagesCount = null,
|
||||
Object? chosenPlan = freezed,
|
||||
}) {
|
||||
return _then(_$ChatRoomImpl(
|
||||
id: null == id
|
||||
@@ -605,6 +634,10 @@ class __$$ChatRoomImplCopyWithImpl<$Res>
|
||||
? _value.unreadMessagesCount
|
||||
: unreadMessagesCount // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
chosenPlan: freezed == chosenPlan
|
||||
? _value.chosenPlan
|
||||
: chosenPlan // ignore: cast_nullable_to_non_nullable
|
||||
as ChosenPlanModel?,
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -618,8 +651,9 @@ class _$ChatRoomImpl implements _ChatRoom {
|
||||
@JsonKey(name: "last_message", fromJson: parseLastMessage)
|
||||
required this.lastMessage,
|
||||
@JsonKey(name: "users") required this.users,
|
||||
@JsonKey(name: "unread_messages_count")
|
||||
required this.unreadMessagesCount});
|
||||
@JsonKey(name: "unread_messages_count") required this.unreadMessagesCount,
|
||||
@JsonKey(name: 'chosen_plan', fromJson: parseChosenPlan)
|
||||
required this.chosenPlan});
|
||||
|
||||
factory _$ChatRoomImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$ChatRoomImplFromJson(json);
|
||||
@@ -639,10 +673,13 @@ class _$ChatRoomImpl implements _ChatRoom {
|
||||
@override
|
||||
@JsonKey(name: "unread_messages_count")
|
||||
final int unreadMessagesCount;
|
||||
@override
|
||||
@JsonKey(name: 'chosen_plan', fromJson: parseChosenPlan)
|
||||
final ChosenPlanModel? chosenPlan;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ChatRoom(id: $id, roomName: $roomName, lastMessage: $lastMessage, users: $users, unreadMessagesCount: $unreadMessagesCount)';
|
||||
return 'ChatRoom(id: $id, roomName: $roomName, lastMessage: $lastMessage, users: $users, unreadMessagesCount: $unreadMessagesCount, chosenPlan: $chosenPlan)';
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -657,13 +694,15 @@ class _$ChatRoomImpl implements _ChatRoom {
|
||||
other.lastMessage == lastMessage) &&
|
||||
(identical(other.users, users) || other.users == users) &&
|
||||
(identical(other.unreadMessagesCount, unreadMessagesCount) ||
|
||||
other.unreadMessagesCount == unreadMessagesCount));
|
||||
other.unreadMessagesCount == unreadMessagesCount) &&
|
||||
(identical(other.chosenPlan, chosenPlan) ||
|
||||
other.chosenPlan == chosenPlan));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType, id, roomName, lastMessage, users, unreadMessagesCount);
|
||||
int get hashCode => Object.hash(runtimeType, id, roomName, lastMessage, users,
|
||||
unreadMessagesCount, chosenPlan);
|
||||
|
||||
/// Create a copy of ChatRoom
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -689,7 +728,9 @@ abstract class _ChatRoom implements ChatRoom {
|
||||
required final ChatMessageModel? lastMessage,
|
||||
@JsonKey(name: "users") required final Users users,
|
||||
@JsonKey(name: "unread_messages_count")
|
||||
required final int unreadMessagesCount}) = _$ChatRoomImpl;
|
||||
required final int unreadMessagesCount,
|
||||
@JsonKey(name: 'chosen_plan', fromJson: parseChosenPlan)
|
||||
required final ChosenPlanModel? chosenPlan}) = _$ChatRoomImpl;
|
||||
|
||||
factory _ChatRoom.fromJson(Map<String, dynamic> json) =
|
||||
_$ChatRoomImpl.fromJson;
|
||||
@@ -709,6 +750,9 @@ abstract class _ChatRoom implements ChatRoom {
|
||||
@override
|
||||
@JsonKey(name: "unread_messages_count")
|
||||
int get unreadMessagesCount;
|
||||
@override
|
||||
@JsonKey(name: 'chosen_plan', fromJson: parseChosenPlan)
|
||||
ChosenPlanModel? get chosenPlan;
|
||||
|
||||
/// Create a copy of ChatRoom
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
|
||||
@@ -43,6 +43,7 @@ _$ChatRoomImpl _$$ChatRoomImplFromJson(Map<String, dynamic> json) =>
|
||||
lastMessage: parseLastMessage(json['last_message']),
|
||||
users: Users.fromJson(json['users'] as Map<String, dynamic>),
|
||||
unreadMessagesCount: (json['unread_messages_count'] as num).toInt(),
|
||||
chosenPlan: parseChosenPlan(json['chosen_plan']),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$ChatRoomImplToJson(_$ChatRoomImpl instance) =>
|
||||
@@ -52,6 +53,7 @@ Map<String, dynamic> _$$ChatRoomImplToJson(_$ChatRoomImpl instance) =>
|
||||
'last_message': instance.lastMessage,
|
||||
'users': instance.users,
|
||||
'unread_messages_count': instance.unreadMessagesCount,
|
||||
'chosen_plan': instance.chosenPlan,
|
||||
};
|
||||
|
||||
_$UsersImpl _$$UsersImplFromJson(Map<String, dynamic> json) => _$UsersImpl(
|
||||
|
||||
@@ -86,11 +86,12 @@ class ChatRoomCubit extends Cubit<ChatRoomState> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> updateChatRoom(String chatId) async{
|
||||
Future<void> cancelChosenPlan({required String chatId, required int planId}) async {
|
||||
try {
|
||||
final chatRoom = await chatRepository.getChatRoom(chatId);
|
||||
await chatRepository.cancelChosenPlan(id: planId);
|
||||
final chatRoom = await chatRepository.getChatRoom(chatId);
|
||||
emit(
|
||||
(state as ChatRoomStateLoaded).copyWith(chatRoom: chatRoom),
|
||||
(state as ChatRoomStateLoaded).copyWith(chatRoom: chatRoom),
|
||||
);
|
||||
} catch (e) {
|
||||
emit(ChatRoomState.error(errorMessage: 'Ошибка получеия данных'));
|
||||
@@ -104,7 +105,7 @@ class ChatRoomCubit extends Cubit<ChatRoomState> {
|
||||
if (client == null) return;
|
||||
await wsManager.initPrivateDirectChatChannel(chatId);
|
||||
wsManager.subscribeDirectChatChannel();
|
||||
wsManager.directChatStream?.listen((event) {
|
||||
messagesSubscription = wsManager.directChatStream?.listen((event) {
|
||||
AudioPlayer().play((AssetSource('audio/recive_message.wav')));
|
||||
final message = ChatMessageModel.fromJson(jsonDecode(event.data)['message']);
|
||||
List<ChatMessageModel> messagesList = [
|
||||
@@ -122,7 +123,7 @@ class ChatRoomCubit extends Cubit<ChatRoomState> {
|
||||
);
|
||||
});
|
||||
|
||||
wsManager.clientTypingStream?.listen((event) {
|
||||
typingSubscription = wsManager.clientTypingStream?.listen((event) {
|
||||
emit(
|
||||
ChatRoomState.loaded(
|
||||
chatRoom: (state as ChatRoomStateLoaded).chatRoom,
|
||||
@@ -191,6 +192,8 @@ class ChatRoomCubit extends Cubit<ChatRoomState> {
|
||||
@override
|
||||
Future<void> close() async {
|
||||
wsManager.unsubscribeDirectChatChannel();
|
||||
messagesSubscription?.cancel();
|
||||
typingSubscription?.cancel();
|
||||
super.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,9 +11,13 @@ import 'package:eatvio_app/features/chat/presentation/widgets/chat_bubble_widget
|
||||
import 'package:eatvio_app/core/locator_service.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/chat/presentation/widgets/order_card.dart';
|
||||
import 'package:eatvio_app/features/plans/enums/chosen_plan_state_enum.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:visibility_detector/visibility_detector.dart';
|
||||
|
||||
@@ -34,6 +38,7 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
final ChatRoomCubit chatRoomCubit = sl<ChatRoomCubit>();
|
||||
final List<({int id, int index})> unreadMessagesIds = [];
|
||||
final List<({int id, int index})> unreadMessagesIdsCopy = [];
|
||||
final showableChatBadgeStates = ChosenPlanStateEnum.getShowableChatBadgeStates();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -51,6 +56,7 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
@override
|
||||
void dispose() {
|
||||
scrollController.dispose();
|
||||
chatRoomCubit.close();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@@ -78,6 +84,9 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
}
|
||||
|
||||
_buildChat(BuildContext context, ChatRoomStateLoaded state) {
|
||||
final chosenPlan = state.chatRoom.chosenPlan;
|
||||
final amIConsultant = chosenPlan?.consultantId == state.chatRoom.users.sender.id;
|
||||
final showAboutOrderButton = showableChatBadgeStates.contains(chosenPlan?.chosenPlanState);
|
||||
return Scaffold(
|
||||
resizeToAvoidBottomInset: true,
|
||||
appBar: AppBar(
|
||||
@@ -86,12 +95,12 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
centerTitle: false,
|
||||
title: Row(
|
||||
children: [
|
||||
if (state.chatRoom.users['to_chat_user']!.profilePhotoUrl != null)
|
||||
if (state.chatRoom.users.receiver.profilePhotoUrl != null)
|
||||
CircleAvatar(
|
||||
radius: 20,
|
||||
foregroundImage: NetworkImage(state.chatRoom.users['to_chat_user']!.profilePhotoUrl!),
|
||||
foregroundImage: NetworkImage(state.chatRoom.users.receiver.profilePhotoUrl!),
|
||||
),
|
||||
if (state.chatRoom.users['to_chat_user']!.profilePhotoUrl == null)
|
||||
if (state.chatRoom.users.receiver.profilePhotoUrl == null)
|
||||
Container(
|
||||
width: 40,
|
||||
height: 40,
|
||||
@@ -101,7 +110,7 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Text(
|
||||
state.chatRoom.users['to_chat_user']!.name.split(' ').first[0] + state.chatRoom.users['to_chat_user']!.name.split(' ')[1][0],
|
||||
state.chatRoom.users.receiver.name.split(' ').first[0] + state.chatRoom.users.receiver.name.split(' ')[1][0],
|
||||
style: TextStyle(
|
||||
color: Color(0xFF7F9CF5),
|
||||
fontWeight: FontWeight.w400,
|
||||
@@ -114,7 +123,7 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
state.chatRoom.users['to_chat_user']!.name,
|
||||
state.chatRoom.users.receiver.name,
|
||||
style: CustomTextStyles.titleSmallBold.copyWith(
|
||||
color: PrimaryColors().black,
|
||||
),
|
||||
@@ -136,28 +145,38 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
),
|
||||
),
|
||||
body: SafeArea(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
child: Stack(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
color: appTheme.whiteA700,
|
||||
width: double.maxFinite,
|
||||
child: CustomScrollView(
|
||||
physics: BouncingScrollPhysics(),
|
||||
controller: scrollController,
|
||||
reverse: true,
|
||||
slivers: [
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.symmetric(vertical: 16),
|
||||
sliver: SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
if (index < state.chatMessages.length) {
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
color: appTheme.whiteA700,
|
||||
width: double.maxFinite,
|
||||
child: SingleChildScrollView(
|
||||
physics: BouncingScrollPhysics(),
|
||||
controller: scrollController,
|
||||
reverse: true,
|
||||
child: Column(
|
||||
children: [
|
||||
SizedBox(height: 16),
|
||||
ListView.builder(
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
reverse: true,
|
||||
shrinkWrap: true,
|
||||
itemBuilder: (context, index) {
|
||||
if (index == state.chatMessages.length) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: const Loader(),
|
||||
);
|
||||
}
|
||||
|
||||
if ((index + 1 != state.chatMessages.length &&
|
||||
state.chatMessages[index].updatedAt.day != state.chatMessages[index + 1].updatedAt.day) ||
|
||||
index + 1 == state.chatMessages.length) {
|
||||
final isCurrentUserAuthor = state.chatRoom.users['to_chat_user']!.id != state.chatMessages[index].authorId;
|
||||
final isCurrentUserAuthor = state.chatRoom.users.receiver.id != state.chatMessages[index].authorId;
|
||||
return Column(
|
||||
children: [
|
||||
_messageDate(state.chatMessages[index].updatedAt),
|
||||
@@ -191,7 +210,7 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
],
|
||||
);
|
||||
}
|
||||
final isCurrentUserAuthor = state.chatRoom.users['to_chat_user']!.id != state.chatMessages[index].authorId;
|
||||
final isCurrentUserAuthor = state.chatRoom.users.receiver.id != state.chatMessages[index].authorId;
|
||||
return VisibilityDetector(
|
||||
key: Key(state.chatMessages[index].id.toString()),
|
||||
onVisibilityChanged: (VisibilityInfo info) {
|
||||
@@ -217,157 +236,238 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
mediaData: state.chatMessages[index].mediaData ?? [],
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: const Loader(),
|
||||
);
|
||||
}
|
||||
},
|
||||
childCount: state.chatMessages.length + (state.isLoading ? 1 : 0),
|
||||
),
|
||||
},
|
||||
itemCount: state.chatMessages.length + (state.isLoading ? 1 : 0),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
if (chosenPlan != null)
|
||||
OrderCard(
|
||||
plan: chosenPlan.plan,
|
||||
isUserView: !amIConsultant,
|
||||
optionType: chosenPlan.optionType,
|
||||
onCancel: () async {
|
||||
await context.read<ChatRoomCubit>().cancelChosenPlan(chatId: state.chatRoom.id, planId: chosenPlan.id);
|
||||
},
|
||||
),
|
||||
// switch (chosenPlan.chosenPlanState) {
|
||||
// // TODO: Handle this case.
|
||||
// ChosenPlanStateEnum.stateInited => throw UnimplementedError(),
|
||||
// // TODO: Handle this case.
|
||||
// ChosenPlanStateEnum.stateStartDateHasBeenSet => throw UnimplementedError(),
|
||||
// // TODO: Handle this case.
|
||||
// ChosenPlanStateEnum.stateInCoordination => throw UnimplementedError(),
|
||||
// // TODO: Handle this case.
|
||||
// ChosenPlanStateEnum.stateStarted => throw UnimplementedError(),
|
||||
// // TODO: Handle this case.
|
||||
// ChosenPlanStateEnum.stateInProgress => throw UnimplementedError(),
|
||||
// // TODO: Handle this case.
|
||||
// ChosenPlanStateEnum.statePendingPayment => throw UnimplementedError(),
|
||||
// // TODO: Handle this case.
|
||||
// ChosenPlanStateEnum.stateConfirmedByConsultant => throw UnimplementedError(),
|
||||
// // TODO: Handle this case.
|
||||
// ChosenPlanStateEnum.statePaid => throw UnimplementedError(),
|
||||
// // TODO: Handle this case.
|
||||
// ChosenPlanStateEnum.stateCanceledByTheInitiator => throw UnimplementedError(),
|
||||
// // TODO: Handle this case.
|
||||
// ChosenPlanStateEnum.stateLastDayStarted => throw UnimplementedError(),
|
||||
// // TODO: Handle this case.
|
||||
// ChosenPlanStateEnum.stateLastDayFinished => throw UnimplementedError(),
|
||||
// // TODO: Handle this case.
|
||||
// ChosenPlanStateEnum.stateComplained => throw UnimplementedError(),
|
||||
// // TODO: Handle this case.
|
||||
// ChosenPlanStateEnum.stateDone => throw UnimplementedError(),
|
||||
// // TODO: Handle this case.
|
||||
// ChosenPlanStateEnum.stateChargeWasCollected => throw UnimplementedError(),
|
||||
// },
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(vertical: 8),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
SizedBox(width: 8),
|
||||
InkWell(
|
||||
onTap: () async {
|
||||
FilePickerResult? result = await FilePicker.platform.pickFiles(
|
||||
allowMultiple: true,
|
||||
type: FileType.custom,
|
||||
allowedExtensions: [
|
||||
'pdf',
|
||||
'doc',
|
||||
'docx',
|
||||
'json',
|
||||
'ppt',
|
||||
'pptx',
|
||||
'rtf',
|
||||
'txt',
|
||||
'xls',
|
||||
'xlsx',
|
||||
'csv',
|
||||
'jpeg',
|
||||
'jpg',
|
||||
'png',
|
||||
'gif',
|
||||
'svg',
|
||||
'xml',
|
||||
'webp',
|
||||
],
|
||||
);
|
||||
|
||||
if (result != null) {
|
||||
List<File> files = result.paths.map((path) => File(path!)).toList();
|
||||
await chatRoomCubit.sendMessage(
|
||||
chatId: widget.chatId,
|
||||
files: files,
|
||||
);
|
||||
} else {
|
||||
// User canceled the picker
|
||||
}
|
||||
},
|
||||
customBorder: CircleBorder(),
|
||||
child: Ink(
|
||||
height: 40,
|
||||
width: 40,
|
||||
child: Transform.rotate(
|
||||
angle: pi / 4,
|
||||
child: Icon(
|
||||
Icons.attach_file_rounded,
|
||||
size: 30,
|
||||
color: Color(0xFF858E99),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
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),
|
||||
),
|
||||
filled: true,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(100),
|
||||
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,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
InkWell(
|
||||
customBorder: CircleBorder(),
|
||||
onTap: () {
|
||||
if (textEditingController.text.isNotEmpty) {
|
||||
chatRoomCubit.sendMessage(
|
||||
chatId: widget.chatId,
|
||||
data: textEditingController.text.trim(),
|
||||
);
|
||||
setState(() {
|
||||
textEditingController.clear();
|
||||
});
|
||||
}
|
||||
},
|
||||
child: Ink(
|
||||
decoration: BoxDecoration(
|
||||
color: appTheme.blueA400,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
height: 40,
|
||||
width: 40,
|
||||
child: Icon(
|
||||
Icons.arrow_upward_rounded,
|
||||
size: 24,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (showAboutOrderButton)
|
||||
Positioned(
|
||||
top: 8,
|
||||
right: 15,
|
||||
left: 16,
|
||||
child: GestureDetector(
|
||||
onTap: () {},
|
||||
child: Container(
|
||||
height: 44,
|
||||
decoration: BoxDecoration(
|
||||
color: appTheme.gray50,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
SizedBox.shrink(),
|
||||
Text(
|
||||
S.current.more_about_order,
|
||||
style: TextStyles.textSMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
Container(
|
||||
margin: EdgeInsets.only(right: 4),
|
||||
width: 36,
|
||||
height: 36,
|
||||
decoration: BoxDecoration(
|
||||
color: appTheme.whiteA700,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Center(
|
||||
child: SvgPicture.asset(
|
||||
'assets/icons/right_arrow.svg',
|
||||
height: 14,
|
||||
width: 8,
|
||||
colorFilter: ColorFilter.mode(
|
||||
appTheme.blueA400,
|
||||
BlendMode.srcIn,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(vertical: 8),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
SizedBox(width: 8),
|
||||
InkWell(
|
||||
onTap: () async {
|
||||
FilePickerResult? result = await FilePicker.platform.pickFiles(
|
||||
allowMultiple: true,
|
||||
type: FileType.custom,
|
||||
allowedExtensions: [
|
||||
'pdf',
|
||||
'doc',
|
||||
'docx',
|
||||
'json',
|
||||
'ppt',
|
||||
'pptx',
|
||||
'rtf',
|
||||
'txt',
|
||||
'xls',
|
||||
'xlsx',
|
||||
'csv',
|
||||
'jpeg',
|
||||
'jpg',
|
||||
'png',
|
||||
'gif',
|
||||
'svg',
|
||||
'xml',
|
||||
'webp',
|
||||
],
|
||||
);
|
||||
|
||||
if (result != null) {
|
||||
List<File> files = result.paths.map((path) => File(path!)).toList();
|
||||
await chatRoomCubit.sendMessage(
|
||||
chatId: widget.chatId,
|
||||
files: files,
|
||||
);
|
||||
} else {
|
||||
// User canceled the picker
|
||||
}
|
||||
},
|
||||
customBorder: CircleBorder(),
|
||||
child: Ink(
|
||||
height: 40,
|
||||
width: 40,
|
||||
child: Transform.rotate(
|
||||
angle: pi / 4,
|
||||
child: Icon(
|
||||
Icons.attach_file_rounded,
|
||||
size: 30,
|
||||
color: Color(0xFF858E99),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
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),
|
||||
),
|
||||
filled: true,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(100),
|
||||
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,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
InkWell(
|
||||
customBorder: CircleBorder(),
|
||||
onTap: () {
|
||||
if (textEditingController.text.isNotEmpty) {
|
||||
chatRoomCubit.sendMessage(
|
||||
chatId: widget.chatId,
|
||||
data: textEditingController.text.trim(),
|
||||
);
|
||||
setState(() {
|
||||
textEditingController.clear();
|
||||
});
|
||||
}
|
||||
},
|
||||
child: Ink(
|
||||
decoration: BoxDecoration(
|
||||
color: appTheme.blueA400,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
height: 40,
|
||||
width: 40,
|
||||
child: Icon(
|
||||
Icons.arrow_upward_rounded,
|
||||
size: 24,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,18 +1,136 @@
|
||||
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/localization_utils.dart';
|
||||
import 'package:eatvio_app/core/utils/string_extentions.dart';
|
||||
import 'package:eatvio_app/core/widgets/item_widget.dart';
|
||||
import 'package:eatvio_app/core/widgets/loader.dart';
|
||||
import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class OrderCard extends StatelessWidget {
|
||||
class OrderCard extends StatefulWidget {
|
||||
final PlanModel plan;
|
||||
final String optionType;
|
||||
final bool isUserView;
|
||||
const OrderCard({super.key, required this.plan, required this.isUserView});
|
||||
final Future<void> Function() onCancel;
|
||||
const OrderCard({super.key, required this.plan, required this.isUserView, required this.optionType, required this.onCancel});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 8, bottom: 12, left: 8, right: 8),
|
||||
child: Column(
|
||||
children: [
|
||||
State<OrderCard> createState() => _OrderCardState();
|
||||
}
|
||||
|
||||
class _OrderCardState extends State<OrderCard> {
|
||||
bool isLoading = false;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final optionIndex = int.parse(widget.optionType.characters.last);
|
||||
final option = switch (optionIndex) {
|
||||
1 => widget.plan.packet1Options,
|
||||
2 => widget.plan.packet2Options,
|
||||
3 => widget.plan.packet3Options,
|
||||
_ => null,
|
||||
};
|
||||
final s = S.of(context);
|
||||
return Container(
|
||||
margin: EdgeInsets.symmetric(horizontal: 16),
|
||||
padding: EdgeInsets.only(top: 8, bottom: 12, left: 8, right: 8),
|
||||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(12), color: appTheme.gray60004),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 200,
|
||||
width: double.infinity,
|
||||
child: Stack(
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Image.network(
|
||||
baseUrl + '/storage/' + widget.plan.image,
|
||||
width: double.infinity,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
left: 0,
|
||||
bottom: 44,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
|
||||
decoration: BoxDecoration(
|
||||
color: appTheme.blueA400,
|
||||
borderRadius: BorderRadius.only(
|
||||
topRight: Radius.circular(12),
|
||||
bottomRight: Radius.circular(12),
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
'${widget.plan.duration} ${getDayForm(widget.plan.duration, s).capitalize()}',
|
||||
style: TextStyles.textSMedium.copyWith(color: appTheme.whiteA700),
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
left: 0,
|
||||
bottom: 12,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
|
||||
decoration: BoxDecoration(
|
||||
color: appTheme.greenA700,
|
||||
borderRadius: BorderRadius.only(
|
||||
topRight: Radius.circular(12),
|
||||
bottomRight: Radius.circular(12),
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
'${s.from} ${widget.plan.minPriceOfOptions.toStringAsFixed(0)}₽',
|
||||
style: TextStyles.textSMedium.copyWith(color: appTheme.whiteA700),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
Text(
|
||||
'${widget.plan.name}',
|
||||
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
Text(
|
||||
'${s.option}: ${option?.short ?? ''}',
|
||||
style: TextStyles.textMSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
if (option != null)
|
||||
...option.items
|
||||
.map(
|
||||
(element) => Padding(
|
||||
padding: const EdgeInsets.only(bottom: 4),
|
||||
child: ItemWidget(
|
||||
reversed: true,
|
||||
iconSize: 12,
|
||||
text: element,
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
if (widget.isUserView) ...[
|
||||
SizedBox(height: 8),
|
||||
isLoading
|
||||
? Loader()
|
||||
: GestureDetector(
|
||||
onTap: () async {
|
||||
setState(() => isLoading = true);
|
||||
await widget.onCancel();
|
||||
setState(() => isLoading = false);
|
||||
},
|
||||
child: Text(
|
||||
'${s.cancel_order}',
|
||||
style: TextStyles.textSMedium.copyWith(color: appTheme.strongRed),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -93,4 +93,14 @@ class ChatRepository {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> cancelChosenPlan({
|
||||
required int id,
|
||||
}) async {
|
||||
try {
|
||||
await chatService.cancelChosenPlan(id: id);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ abstract class ChatService {
|
||||
|
||||
@GET('/api/chat/index')
|
||||
Future<ChatRoomPaginationModel> getChatRooms({
|
||||
@Query('page') required int page,
|
||||
@Query('page') required int page,
|
||||
@Query('find') String? query,
|
||||
});
|
||||
|
||||
@@ -41,5 +41,13 @@ abstract class ChatService {
|
||||
});
|
||||
|
||||
@POST('/api/chat/{id}/messages/markAsRead')
|
||||
Future<void> markMessagesAsRead({@Path() required String id, @Body() required Map<String, List<int>> body});
|
||||
Future<void> markMessagesAsRead({
|
||||
@Path() required String id,
|
||||
@Body() required Map<String, List<int>> body,
|
||||
});
|
||||
|
||||
@POST('/api/chosen_plans/{id}/cancel')
|
||||
Future<void> cancelChosenPlan({
|
||||
@Path() required int id,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -193,6 +193,25 @@ class _ChatService implements ChatService {
|
||||
await _dio.fetch<void>(_options);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> cancelChosenPlan({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/chosen_plans/${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 ||
|
||||
|
||||
@@ -4,12 +4,14 @@ 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/chat/presentation/bloc/chats_cubit/chats_cubit.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:eatvio_app/features/profile/models/profile_model.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
@@ -155,7 +157,7 @@ class MenuScreen extends StatelessWidget {
|
||||
);
|
||||
} catch (e) {
|
||||
} finally {
|
||||
await TokenStorage.removeTokenInStorage();
|
||||
await TokenStorage.removeTokenInStorage();
|
||||
GoRouter.of(context).go('/auth-screen', extra: true);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart';
|
||||
import 'package:eatvio_app/features/plans/enums/chosen_plan_state_enum.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
@@ -13,8 +14,16 @@ class ChosenPlanModel with _$ChosenPlanModel {
|
||||
@JsonKey(name: 'start_date') required DateTime startDate,
|
||||
@JsonKey(name: 'last_state') required ChosenPlanStateEnum chosenPlanState,
|
||||
@JsonKey(name: 'chat_id') required String chatId,
|
||||
|
||||
@JsonKey(name: 'consultant_id') required int consultantId,
|
||||
@JsonKey(name: 'plan') required PlanModel plan,
|
||||
}) = _ChosenPlanModel;
|
||||
|
||||
factory ChosenPlanModel.fromJson(Map<String, dynamic> json) => _$ChosenPlanModelFromJson(json);
|
||||
}
|
||||
|
||||
ChosenPlanModel? parseChosenPlan(json) {
|
||||
if (json is Map<String, dynamic>) {
|
||||
return ChosenPlanModel.fromJson(json);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -30,6 +30,10 @@ mixin _$ChosenPlanModel {
|
||||
ChosenPlanStateEnum get chosenPlanState => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'chat_id')
|
||||
String get chatId => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'consultant_id')
|
||||
int get consultantId => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'plan')
|
||||
PlanModel get plan => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this ChosenPlanModel to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@@ -52,7 +56,11 @@ abstract class $ChosenPlanModelCopyWith<$Res> {
|
||||
@JsonKey(name: 'option_type') String optionType,
|
||||
@JsonKey(name: 'start_date') DateTime startDate,
|
||||
@JsonKey(name: 'last_state') ChosenPlanStateEnum chosenPlanState,
|
||||
@JsonKey(name: 'chat_id') String chatId});
|
||||
@JsonKey(name: 'chat_id') String chatId,
|
||||
@JsonKey(name: 'consultant_id') int consultantId,
|
||||
@JsonKey(name: 'plan') PlanModel plan});
|
||||
|
||||
$PlanModelCopyWith<$Res> get plan;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -75,6 +83,8 @@ class _$ChosenPlanModelCopyWithImpl<$Res, $Val extends ChosenPlanModel>
|
||||
Object? startDate = null,
|
||||
Object? chosenPlanState = null,
|
||||
Object? chatId = null,
|
||||
Object? consultantId = null,
|
||||
Object? plan = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
id: null == id
|
||||
@@ -97,8 +107,26 @@ class _$ChosenPlanModelCopyWithImpl<$Res, $Val extends ChosenPlanModel>
|
||||
? _value.chatId
|
||||
: chatId // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
consultantId: null == consultantId
|
||||
? _value.consultantId
|
||||
: consultantId // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
plan: null == plan
|
||||
? _value.plan
|
||||
: plan // ignore: cast_nullable_to_non_nullable
|
||||
as PlanModel,
|
||||
) as $Val);
|
||||
}
|
||||
|
||||
/// Create a copy of ChosenPlanModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$PlanModelCopyWith<$Res> get plan {
|
||||
return $PlanModelCopyWith<$Res>(_value.plan, (value) {
|
||||
return _then(_value.copyWith(plan: value) as $Val);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -114,7 +142,12 @@ abstract class _$$ChosenPlanModelImplCopyWith<$Res>
|
||||
@JsonKey(name: 'option_type') String optionType,
|
||||
@JsonKey(name: 'start_date') DateTime startDate,
|
||||
@JsonKey(name: 'last_state') ChosenPlanStateEnum chosenPlanState,
|
||||
@JsonKey(name: 'chat_id') String chatId});
|
||||
@JsonKey(name: 'chat_id') String chatId,
|
||||
@JsonKey(name: 'consultant_id') int consultantId,
|
||||
@JsonKey(name: 'plan') PlanModel plan});
|
||||
|
||||
@override
|
||||
$PlanModelCopyWith<$Res> get plan;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -135,6 +168,8 @@ class __$$ChosenPlanModelImplCopyWithImpl<$Res>
|
||||
Object? startDate = null,
|
||||
Object? chosenPlanState = null,
|
||||
Object? chatId = null,
|
||||
Object? consultantId = null,
|
||||
Object? plan = null,
|
||||
}) {
|
||||
return _then(_$ChosenPlanModelImpl(
|
||||
id: null == id
|
||||
@@ -157,6 +192,14 @@ class __$$ChosenPlanModelImplCopyWithImpl<$Res>
|
||||
? _value.chatId
|
||||
: chatId // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
consultantId: null == consultantId
|
||||
? _value.consultantId
|
||||
: consultantId // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
plan: null == plan
|
||||
? _value.plan
|
||||
: plan // ignore: cast_nullable_to_non_nullable
|
||||
as PlanModel,
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -169,7 +212,9 @@ class _$ChosenPlanModelImpl implements _ChosenPlanModel {
|
||||
@JsonKey(name: 'option_type') required this.optionType,
|
||||
@JsonKey(name: 'start_date') required this.startDate,
|
||||
@JsonKey(name: 'last_state') required this.chosenPlanState,
|
||||
@JsonKey(name: 'chat_id') required this.chatId});
|
||||
@JsonKey(name: 'chat_id') required this.chatId,
|
||||
@JsonKey(name: 'consultant_id') required this.consultantId,
|
||||
@JsonKey(name: 'plan') required this.plan});
|
||||
|
||||
factory _$ChosenPlanModelImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$ChosenPlanModelImplFromJson(json);
|
||||
@@ -189,10 +234,16 @@ class _$ChosenPlanModelImpl implements _ChosenPlanModel {
|
||||
@override
|
||||
@JsonKey(name: 'chat_id')
|
||||
final String chatId;
|
||||
@override
|
||||
@JsonKey(name: 'consultant_id')
|
||||
final int consultantId;
|
||||
@override
|
||||
@JsonKey(name: 'plan')
|
||||
final PlanModel plan;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ChosenPlanModel(id: $id, optionType: $optionType, startDate: $startDate, chosenPlanState: $chosenPlanState, chatId: $chatId)';
|
||||
return 'ChosenPlanModel(id: $id, optionType: $optionType, startDate: $startDate, chosenPlanState: $chosenPlanState, chatId: $chatId, consultantId: $consultantId, plan: $plan)';
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -207,13 +258,16 @@ class _$ChosenPlanModelImpl implements _ChosenPlanModel {
|
||||
other.startDate == startDate) &&
|
||||
(identical(other.chosenPlanState, chosenPlanState) ||
|
||||
other.chosenPlanState == chosenPlanState) &&
|
||||
(identical(other.chatId, chatId) || other.chatId == chatId));
|
||||
(identical(other.chatId, chatId) || other.chatId == chatId) &&
|
||||
(identical(other.consultantId, consultantId) ||
|
||||
other.consultantId == consultantId) &&
|
||||
(identical(other.plan, plan) || other.plan == plan));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType, id, optionType, startDate, chosenPlanState, chatId);
|
||||
int get hashCode => Object.hash(runtimeType, id, optionType, startDate,
|
||||
chosenPlanState, chatId, consultantId, plan);
|
||||
|
||||
/// Create a copy of ChosenPlanModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -239,7 +293,9 @@ abstract class _ChosenPlanModel implements ChosenPlanModel {
|
||||
@JsonKey(name: 'start_date') required final DateTime startDate,
|
||||
@JsonKey(name: 'last_state')
|
||||
required final ChosenPlanStateEnum chosenPlanState,
|
||||
@JsonKey(name: 'chat_id') required final String chatId}) =
|
||||
@JsonKey(name: 'chat_id') required final String chatId,
|
||||
@JsonKey(name: 'consultant_id') required final int consultantId,
|
||||
@JsonKey(name: 'plan') required final PlanModel plan}) =
|
||||
_$ChosenPlanModelImpl;
|
||||
|
||||
factory _ChosenPlanModel.fromJson(Map<String, dynamic> json) =
|
||||
@@ -260,6 +316,12 @@ abstract class _ChosenPlanModel implements ChosenPlanModel {
|
||||
@override
|
||||
@JsonKey(name: 'chat_id')
|
||||
String get chatId;
|
||||
@override
|
||||
@JsonKey(name: 'consultant_id')
|
||||
int get consultantId;
|
||||
@override
|
||||
@JsonKey(name: 'plan')
|
||||
PlanModel get plan;
|
||||
|
||||
/// Create a copy of ChosenPlanModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
|
||||
@@ -15,6 +15,8 @@ _$ChosenPlanModelImpl _$$ChosenPlanModelImplFromJson(
|
||||
chosenPlanState:
|
||||
$enumDecode(_$ChosenPlanStateEnumEnumMap, json['last_state']),
|
||||
chatId: json['chat_id'] as String,
|
||||
consultantId: (json['consultant_id'] as num).toInt(),
|
||||
plan: PlanModel.fromJson(json['plan'] as Map<String, dynamic>),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$ChosenPlanModelImplToJson(
|
||||
@@ -25,6 +27,8 @@ Map<String, dynamic> _$$ChosenPlanModelImplToJson(
|
||||
'start_date': instance.startDate.toIso8601String(),
|
||||
'last_state': _$ChosenPlanStateEnumEnumMap[instance.chosenPlanState]!,
|
||||
'chat_id': instance.chatId,
|
||||
'consultant_id': instance.consultantId,
|
||||
'plan': instance.plan,
|
||||
};
|
||||
|
||||
const _$ChosenPlanStateEnumEnumMap = {
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
|
||||
class ItemWidget extends StatelessWidget {
|
||||
const ItemWidget({super.key, required this.text});
|
||||
final String text;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
text,
|
||||
style: TextStyles.textMMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
),
|
||||
SvgPicture.asset(
|
||||
'assets/icons/ok.svg',
|
||||
width: 20,
|
||||
height: 20,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_divider.dart';
|
||||
import 'package:eatvio_app/core/widgets/main_background_bouble.dart';
|
||||
import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart';
|
||||
import 'package:eatvio_app/features/plans/presentation/widgets/item_widget.dart';
|
||||
import 'package:eatvio_app/core/widgets/item_widget.dart';
|
||||
import 'package:eatvio_app/features/plans/presentation/widgets/option_duration_widget.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
MessageLookupByLibrary.simpleMessage(
|
||||
"Не удалось загрузить данные. Попробуйте обновить страницу"),
|
||||
"cancel_diet": MessageLookupByLibrary.simpleMessage("Отменить диету?"),
|
||||
"cancel_order": MessageLookupByLibrary.simpleMessage("Отменить заказ"),
|
||||
"carb_type": MessageLookupByLibrary.simpleMessage("Мучное"),
|
||||
"carb_type_desc": MessageLookupByLibrary.simpleMessage(
|
||||
"Если вы любите мучные продукты, но хотите придерживаться диеты, вам подходит диета с добавленим мучных блюд на основе цельнозерновых вариантов. В них больше сложных углеводов и клетчатки, что способствует длительному чувству сытости и поддерживает здоровье пищеварительной системы."),
|
||||
@@ -288,6 +289,8 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
MessageLookupByLibrary.simpleMessage("Введение в заблуждение"),
|
||||
"misrepresentation_description": MessageLookupByLibrary.simpleMessage(
|
||||
"Новости, которые могут вызвать широкий резонанс или несут угрозу, распространяемые с целью введения людей в заблуждение."),
|
||||
"more_about_order":
|
||||
MessageLookupByLibrary.simpleMessage("Подробнее о заказе"),
|
||||
"most_new": MessageLookupByLibrary.simpleMessage("Самые новые"),
|
||||
"most_old": MessageLookupByLibrary.simpleMessage("Самые старые"),
|
||||
"msg_network_err":
|
||||
@@ -387,6 +390,8 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"recipe_author": MessageLookupByLibrary.simpleMessage("Автор рецепта"),
|
||||
"recipe_publishing":
|
||||
MessageLookupByLibrary.simpleMessage("Публикация рецепта"),
|
||||
"refuse_order":
|
||||
MessageLookupByLibrary.simpleMessage("Отказаться от заказа"),
|
||||
"removeFromActive":
|
||||
MessageLookupByLibrary.simpleMessage("Снять с публикации"),
|
||||
"save": MessageLookupByLibrary.simpleMessage("Сохранить"),
|
||||
|
||||
@@ -3251,6 +3251,36 @@ class S {
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Подробнее о заказе`
|
||||
String get more_about_order {
|
||||
return Intl.message(
|
||||
'Подробнее о заказе',
|
||||
name: 'more_about_order',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Отменить заказ`
|
||||
String get cancel_order {
|
||||
return Intl.message(
|
||||
'Отменить заказ',
|
||||
name: 'cancel_order',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Отказаться от заказа`
|
||||
String get refuse_order {
|
||||
return Intl.message(
|
||||
'Отказаться от заказа',
|
||||
name: 'refuse_order',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AppLocalizationDelegate extends LocalizationsDelegate<S> {
|
||||
|
||||
@@ -319,7 +319,10 @@
|
||||
"choose_date": "Выбрать дату",
|
||||
"date_has_ben_set": "Дата старта начала консультации установлена",
|
||||
"tap_on_link_to)pay": "Перейдите по ссылке для оплаты консультации",
|
||||
"pay": "Оплатить"
|
||||
"pay": "Оплатить",
|
||||
"more_about_order": "Подробнее о заказе",
|
||||
"cancel_order": "Отменить заказ",
|
||||
"refuse_order":"Отказаться от заказа"
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user