forked from eatvio/eatvio_app
pre merge commit
This commit is contained in:
4
assets/icons/reversed_exclamation_mark.svg
Normal file
4
assets/icons/reversed_exclamation_mark.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="68" height="69" viewBox="0 0 68 69" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M68 34.6406C68 53.2716 52.7777 68.375 34 68.375C15.2223 68.375 0 53.2716 0 34.6406C0 16.0096 15.2223 0.90625 34 0.90625C52.7777 0.90625 68 16.0096 68 34.6406Z" fill="white"/>
|
||||
<path d="M31.6767 54.8812V26.6568H36.2667V54.8812H31.6767ZM31.11 20.2473V15.1309H36.7767V20.2473H31.11Z" fill="#2F80ED"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 409 B |
@@ -241,12 +241,10 @@ class AppRouter {
|
||||
path: '/chat-screen',
|
||||
name: 'chatScreen',
|
||||
builder: (context, state) {
|
||||
final data = state.extra as Map<String, dynamic>;
|
||||
final chatsCubit = data['chatsCubit'] as ChatsCubit;
|
||||
final data = state.extra as Map<String, dynamic>;
|
||||
final chatId = data['chatId'] as String;
|
||||
return ChatScreen(
|
||||
chatId: chatId,
|
||||
chatsCubit: chatsCubit,
|
||||
chatId: chatId,
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
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];
|
||||
|
||||
@@ -8,4 +8,4 @@ const List<String> planTypeValues = ['fit', 'slim', 'wellness', 'behavior'];
|
||||
|
||||
const newMessagesChannelName = 'private-new-chat-messages';
|
||||
const newNotificationsChannelName = 'private-message-events';
|
||||
const directChatChannelName = 'private-direct-chat';
|
||||
const directChatChannelName = 'private-direct-chat';
|
||||
@@ -87,6 +87,7 @@ Future<void> init() async {
|
||||
sl.registerLazySingleton<NotificationsCubit>(() => NotificationsCubit(wsManager: sl()));
|
||||
sl.registerLazySingleton<FeedCubit>(() => FeedCubit(feedRepository: sl()));
|
||||
sl.registerLazySingleton<ProfileAvatarCubit>(() => ProfileAvatarCubit(profileRepository: sl()));
|
||||
sl.registerLazySingleton<ChatsCubit>(() => ChatsCubit(chatRepository: sl(), wsManager: sl(), profileRepository: sl()));
|
||||
|
||||
// Cubit factories
|
||||
sl.registerFactory<RegistrationCubit>(() => RegistrationCubit(registrationRepository: sl()));
|
||||
@@ -96,8 +97,7 @@ Future<void> init() async {
|
||||
sl.registerFactory<ProfileCubit>(() => ProfileCubit(profileRepository: sl(), chatRepository: sl()));
|
||||
sl.registerFactory<profilePlans.PlansCubit>(() => profilePlans.PlansCubit(plansRepository: sl()));
|
||||
sl.registerFactory<DietsCubit>(() => DietsCubit(feedRepository: sl(), dietsRepository: sl()));
|
||||
sl.registerFactory<CommentsCubit>(() => CommentsCubit(feedRepository: sl()));
|
||||
sl.registerFactory<ChatsCubit>(() => ChatsCubit(chatRepository: sl(), wsManager: sl(), profileRepository: sl()));
|
||||
sl.registerFactory<CommentsCubit>(() => CommentsCubit(feedRepository: sl()));
|
||||
sl.registerFactory<PlansCubit>(() => PlansCubit(feedRepository: sl(), planRepository: sl()));
|
||||
sl.registerFactory<SettingsCubit>(() => SettingsCubit(profileRepository: sl(), settingsRepository: sl()));
|
||||
sl.registerFactory<RegisterConsultantCubit>(() => RegisterConsultantCubit(consultantRepository: sl()));
|
||||
|
||||
@@ -11,6 +11,7 @@ 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/notification_banner.dart';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
@@ -19,10 +20,8 @@ import 'package:visibility_detector/visibility_detector.dart';
|
||||
|
||||
class ChatScreen extends StatefulWidget {
|
||||
final String chatId;
|
||||
final ChatsCubit chatsCubit;
|
||||
const ChatScreen({
|
||||
required this.chatId,
|
||||
required this.chatsCubit,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@@ -174,7 +173,9 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
() async {
|
||||
final result = await context.read<ChatRoomCubit>().markMessagesAsRead(state.chatRoom.id, unreadMessagesIdsCopy);
|
||||
if (!result) return;
|
||||
widget.chatsCubit.reduceUnreadMessagesCount(chatId: state.chatRoom.id, count: unreadMessagesIdsCopy.length);
|
||||
context
|
||||
.read<ChatsCubit>()
|
||||
.reduceUnreadMessagesCount(chatId: state.chatRoom.id, count: unreadMessagesIdsCopy.length);
|
||||
unreadMessagesIdsCopy.clear();
|
||||
},
|
||||
);
|
||||
@@ -203,7 +204,7 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
() async {
|
||||
final result = await context.read<ChatRoomCubit>().markMessagesAsRead(state.chatRoom.id, unreadMessagesIds);
|
||||
if (!result) return;
|
||||
widget.chatsCubit.reduceUnreadMessagesCount(chatId: state.chatRoom.id, count: unreadMessagesIds.length);
|
||||
context.read<ChatsCubit>().reduceUnreadMessagesCount(chatId: state.chatRoom.id, count: unreadMessagesIds.length);
|
||||
unreadMessagesIds.clear();
|
||||
},
|
||||
);
|
||||
|
||||
@@ -28,7 +28,6 @@ class _ChatEntryWidgetState extends State<ChatEntryWidget> {
|
||||
'chatScreen',
|
||||
extra: {
|
||||
'chatId': widget.chatRoom.id.toString(),
|
||||
'chatsCubit': context.read<ChatsCubit>(),
|
||||
},
|
||||
),
|
||||
child: Ink(
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
|
||||
class NotificationBanner extends StatelessWidget {
|
||||
const NotificationBanner({super.key, required this.bannerType});
|
||||
final BannerType bannerType;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final size = MediaQuery.sizeOf(context);
|
||||
final s = S.of(context);
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: appTheme.gray50,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 12, right: 8, left: 12),
|
||||
child: SvgPicture.asset('assets/icons/reversed_exclamation_mark.svg', height: 68, width: 68),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 16),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: switch (bannerType) {
|
||||
BannerType.date => [
|
||||
SizedBox(
|
||||
width: size.width * 0.6,
|
||||
child: Text(s.can_not_choose_start_date, style: TextStyles.textMMedium.copyWith(color: appTheme.black)),
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
GestureDetector(
|
||||
onTap: () {},
|
||||
child: Text(s.add_card, style: TextStyles.textLSemibold.copyWith(color: appTheme.blueA400)),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
],
|
||||
BannerType.card => [
|
||||
SizedBox(
|
||||
width: size.width * 0.6,
|
||||
child: Text(s.can_not_choose_start_date, style: TextStyles.textMMedium.copyWith(color: appTheme.black)),
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
GestureDetector(
|
||||
onTap: () {},
|
||||
child: Text(s.add_card, style: TextStyles.textLSemibold.copyWith(color: appTheme.blueA400)),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
],
|
||||
BannerType.payment => [
|
||||
SizedBox(
|
||||
width: size.width * 0.6,
|
||||
child: Text(s.can_not_choose_start_date, style: TextStyles.textMMedium.copyWith(color: appTheme.black)),
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
GestureDetector(
|
||||
onTap: () {},
|
||||
child: Text(s.add_card, style: TextStyles.textLSemibold.copyWith(color: appTheme.blueA400)),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
],
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
enum BannerType { date, card, payment }
|
||||
20
lib/features/plans/models/chosen_plan_model.dart
Normal file
20
lib/features/plans/models/chosen_plan_model.dart
Normal file
@@ -0,0 +1,20 @@
|
||||
import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'chosen_plan_model.freezed.dart';
|
||||
part 'chosen_plan_model.g.dart';
|
||||
|
||||
@freezed
|
||||
class ChosenPlanModel with _$ChosenPlanModel {
|
||||
|
||||
factory ChosenPlanModel({
|
||||
@JsonKey() required int id,
|
||||
@JsonKey(name: 'option_type') required String optionType,
|
||||
@JsonKey(name: 'start_date') required DateTime startDate,
|
||||
@JsonKey(name: 'chat_id') required String chatId,
|
||||
@JsonKey(name: 'plan') required PlanModel plan,
|
||||
|
||||
}) = _ChosenPlanModel;
|
||||
|
||||
factory ChosenPlanModel.fromJson(Map<String, dynamic> json) => _$ChosenPlanModelFromJson(json);
|
||||
}
|
||||
283
lib/features/plans/models/chosen_plan_model.freezed.dart
Normal file
283
lib/features/plans/models/chosen_plan_model.freezed.dart
Normal file
@@ -0,0 +1,283 @@
|
||||
// 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_plan_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');
|
||||
|
||||
ChosenPlanModel _$ChosenPlanModelFromJson(Map<String, dynamic> json) {
|
||||
return _ChosenPlanModel.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$ChosenPlanModel {
|
||||
@JsonKey()
|
||||
int get id => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'option_type')
|
||||
String get optionType => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'start_date')
|
||||
DateTime get startDate => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'chat_id')
|
||||
String get chatId => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'plan')
|
||||
PlanModel get plan => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this ChosenPlanModel to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of ChosenPlanModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$ChosenPlanModelCopyWith<ChosenPlanModel> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $ChosenPlanModelCopyWith<$Res> {
|
||||
factory $ChosenPlanModelCopyWith(
|
||||
ChosenPlanModel value, $Res Function(ChosenPlanModel) then) =
|
||||
_$ChosenPlanModelCopyWithImpl<$Res, ChosenPlanModel>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{@JsonKey() int id,
|
||||
@JsonKey(name: 'option_type') String optionType,
|
||||
@JsonKey(name: 'start_date') DateTime startDate,
|
||||
@JsonKey(name: 'chat_id') String chatId,
|
||||
@JsonKey(name: 'plan') PlanModel plan});
|
||||
|
||||
$PlanModelCopyWith<$Res> get plan;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$ChosenPlanModelCopyWithImpl<$Res, $Val extends ChosenPlanModel>
|
||||
implements $ChosenPlanModelCopyWith<$Res> {
|
||||
_$ChosenPlanModelCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of ChosenPlanModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? id = null,
|
||||
Object? optionType = null,
|
||||
Object? startDate = null,
|
||||
Object? chatId = null,
|
||||
Object? plan = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
id: null == id
|
||||
? _value.id
|
||||
: id // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
optionType: null == optionType
|
||||
? _value.optionType
|
||||
: optionType // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
startDate: null == startDate
|
||||
? _value.startDate
|
||||
: startDate // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,
|
||||
chatId: null == chatId
|
||||
? _value.chatId
|
||||
: chatId // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
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
|
||||
abstract class _$$ChosenPlanModelImplCopyWith<$Res>
|
||||
implements $ChosenPlanModelCopyWith<$Res> {
|
||||
factory _$$ChosenPlanModelImplCopyWith(_$ChosenPlanModelImpl value,
|
||||
$Res Function(_$ChosenPlanModelImpl) then) =
|
||||
__$$ChosenPlanModelImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{@JsonKey() int id,
|
||||
@JsonKey(name: 'option_type') String optionType,
|
||||
@JsonKey(name: 'start_date') DateTime startDate,
|
||||
@JsonKey(name: 'chat_id') String chatId,
|
||||
@JsonKey(name: 'plan') PlanModel plan});
|
||||
|
||||
@override
|
||||
$PlanModelCopyWith<$Res> get plan;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$ChosenPlanModelImplCopyWithImpl<$Res>
|
||||
extends _$ChosenPlanModelCopyWithImpl<$Res, _$ChosenPlanModelImpl>
|
||||
implements _$$ChosenPlanModelImplCopyWith<$Res> {
|
||||
__$$ChosenPlanModelImplCopyWithImpl(
|
||||
_$ChosenPlanModelImpl _value, $Res Function(_$ChosenPlanModelImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of ChosenPlanModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? id = null,
|
||||
Object? optionType = null,
|
||||
Object? startDate = null,
|
||||
Object? chatId = null,
|
||||
Object? plan = null,
|
||||
}) {
|
||||
return _then(_$ChosenPlanModelImpl(
|
||||
id: null == id
|
||||
? _value.id
|
||||
: id // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
optionType: null == optionType
|
||||
? _value.optionType
|
||||
: optionType // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
startDate: null == startDate
|
||||
? _value.startDate
|
||||
: startDate // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,
|
||||
chatId: null == chatId
|
||||
? _value.chatId
|
||||
: chatId // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
plan: null == plan
|
||||
? _value.plan
|
||||
: plan // ignore: cast_nullable_to_non_nullable
|
||||
as PlanModel,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$ChosenPlanModelImpl implements _ChosenPlanModel {
|
||||
_$ChosenPlanModelImpl(
|
||||
{@JsonKey() required this.id,
|
||||
@JsonKey(name: 'option_type') required this.optionType,
|
||||
@JsonKey(name: 'start_date') required this.startDate,
|
||||
@JsonKey(name: 'chat_id') required this.chatId,
|
||||
@JsonKey(name: 'plan') required this.plan});
|
||||
|
||||
factory _$ChosenPlanModelImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$ChosenPlanModelImplFromJson(json);
|
||||
|
||||
@override
|
||||
@JsonKey()
|
||||
final int id;
|
||||
@override
|
||||
@JsonKey(name: 'option_type')
|
||||
final String optionType;
|
||||
@override
|
||||
@JsonKey(name: 'start_date')
|
||||
final DateTime startDate;
|
||||
@override
|
||||
@JsonKey(name: 'chat_id')
|
||||
final String chatId;
|
||||
@override
|
||||
@JsonKey(name: 'plan')
|
||||
final PlanModel plan;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ChosenPlanModel(id: $id, optionType: $optionType, startDate: $startDate, chatId: $chatId, plan: $plan)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$ChosenPlanModelImpl &&
|
||||
(identical(other.id, id) || other.id == id) &&
|
||||
(identical(other.optionType, optionType) ||
|
||||
other.optionType == optionType) &&
|
||||
(identical(other.startDate, startDate) ||
|
||||
other.startDate == startDate) &&
|
||||
(identical(other.chatId, chatId) || other.chatId == chatId) &&
|
||||
(identical(other.plan, plan) || other.plan == plan));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(runtimeType, id, optionType, startDate, chatId, plan);
|
||||
|
||||
/// Create a copy of ChosenPlanModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$ChosenPlanModelImplCopyWith<_$ChosenPlanModelImpl> get copyWith =>
|
||||
__$$ChosenPlanModelImplCopyWithImpl<_$ChosenPlanModelImpl>(
|
||||
this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$ChosenPlanModelImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _ChosenPlanModel implements ChosenPlanModel {
|
||||
factory _ChosenPlanModel(
|
||||
{@JsonKey() required final int id,
|
||||
@JsonKey(name: 'option_type') required final String optionType,
|
||||
@JsonKey(name: 'start_date') required final DateTime startDate,
|
||||
@JsonKey(name: 'chat_id') required final String chatId,
|
||||
@JsonKey(name: 'plan') required final PlanModel plan}) =
|
||||
_$ChosenPlanModelImpl;
|
||||
|
||||
factory _ChosenPlanModel.fromJson(Map<String, dynamic> json) =
|
||||
_$ChosenPlanModelImpl.fromJson;
|
||||
|
||||
@override
|
||||
@JsonKey()
|
||||
int get id;
|
||||
@override
|
||||
@JsonKey(name: 'option_type')
|
||||
String get optionType;
|
||||
@override
|
||||
@JsonKey(name: 'start_date')
|
||||
DateTime get startDate;
|
||||
@override
|
||||
@JsonKey(name: 'chat_id')
|
||||
String get chatId;
|
||||
@override
|
||||
@JsonKey(name: 'plan')
|
||||
PlanModel get plan;
|
||||
|
||||
/// Create a copy of ChosenPlanModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$ChosenPlanModelImplCopyWith<_$ChosenPlanModelImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
27
lib/features/plans/models/chosen_plan_model.g.dart
Normal file
27
lib/features/plans/models/chosen_plan_model.g.dart
Normal file
@@ -0,0 +1,27 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'chosen_plan_model.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$ChosenPlanModelImpl _$$ChosenPlanModelImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$ChosenPlanModelImpl(
|
||||
id: (json['id'] as num).toInt(),
|
||||
optionType: json['option_type'] as String,
|
||||
startDate: DateTime.parse(json['start_date'] as String),
|
||||
chatId: json['chat_id'] as String,
|
||||
plan: PlanModel.fromJson(json['plan'] as Map<String, dynamic>),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$ChosenPlanModelImplToJson(
|
||||
_$ChosenPlanModelImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'option_type': instance.optionType,
|
||||
'start_date': instance.startDate.toIso8601String(),
|
||||
'chat_id': instance.chatId,
|
||||
'plan': instance.plan,
|
||||
};
|
||||
@@ -1,8 +1,10 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:easy_debounce/easy_debounce.dart';
|
||||
import 'package:eatvio_app/core/utils/toasts.dart';
|
||||
import 'package:eatvio_app/features/diets/repositories/diet_repository.dart';
|
||||
import 'package:eatvio_app/features/plans/models/chosen_plan_model.dart';
|
||||
import 'package:eatvio_app/features/plans/presentation/cubit/about_plan_state.dart';
|
||||
import 'package:eatvio_app/features/plans/repositories/plan_repository.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
@@ -125,4 +127,27 @@ class AboutPlanCubit extends Cubit<AboutPlanState> {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<ChosenPlanModel?> chosePlan() async {
|
||||
try {
|
||||
final slug = state.planModel?.slug;
|
||||
final optionIndex = state.chosenOptionIndex;
|
||||
if (slug != null) {
|
||||
final optionName = _getOptionNameFromIndex(optionIndex);
|
||||
final body = {'options_type': optionName};
|
||||
return await planRepository.chosePlan(slug, body);
|
||||
}
|
||||
} on DioException catch (e, st) {
|
||||
log(e.toString(), stackTrace: st);
|
||||
} catch (e, st) {
|
||||
log(e.toString(), stackTrace: st);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
String _getOptionNameFromIndex(int index) => switch (index) {
|
||||
1 => 'options2',
|
||||
2 => 'options3',
|
||||
_ => 'options1',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import 'package:eatvio_app/core/widgets/bookmark_button.dart';
|
||||
import 'package:eatvio_app/core/widgets/data_error_widget.dart';
|
||||
import 'package:eatvio_app/core/widgets/info_row.dart';
|
||||
import 'package:eatvio_app/core/widgets/loader.dart';
|
||||
import 'package:eatvio_app/core/widgets/show_error_dialog.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/author_card.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/expandable_text.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/info_bouble.dart';
|
||||
@@ -30,6 +31,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_portal/flutter_portal.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import '../widgets/option_widget.dart';
|
||||
|
||||
@@ -217,17 +219,21 @@ class _AboutPlanScreenState extends State<AboutPlanScreen> {
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
backgroundColor: appTheme.greenA700,
|
||||
onPressed: () {
|
||||
/// TODO: добавить обработку покупки плана
|
||||
// showModalBottomSheet(
|
||||
// context: context,
|
||||
// builder: (context) => StartDietBottomSheet(
|
||||
// aboutDietCubit: context.read<AboutDietCubit>(),
|
||||
// ),
|
||||
// );
|
||||
onPressed: () async {
|
||||
final chosenPlan = await context.read<AboutPlanCubit>().chosePlan();
|
||||
if (chosenPlan == null) {
|
||||
showErrorDialog(context, title: 'Не удалось заказать план');
|
||||
return;
|
||||
}
|
||||
GoRouter.of(context).pushReplacementNamed(
|
||||
'chatScreen',
|
||||
extra: {
|
||||
'chatId': chosenPlan.chatId,
|
||||
},
|
||||
);
|
||||
},
|
||||
label: Text(
|
||||
s.startDiet,
|
||||
s.to_order,
|
||||
style: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import 'dart:async';
|
||||
import 'package:eatvio_app/features/diets/repositories/diet_repository.dart';
|
||||
import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart';
|
||||
import 'package:eatvio_app/features/plans/models/chosen_plan_model.dart';
|
||||
import 'package:eatvio_app/features/plans/services/plan_service.dart';
|
||||
|
||||
|
||||
class PlanRepository {
|
||||
final PlanService planService;
|
||||
|
||||
@@ -48,9 +48,15 @@ class PlanRepository {
|
||||
}
|
||||
}
|
||||
|
||||
Future<ChosenPlanModel> chosePlan(String slug, Map<String, dynamic> option ) async {
|
||||
try {
|
||||
return await planService.chosePlan(slug: slug, option: option);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
void emitLikesStateToFeed(LikesState state) => _planLikeStateStreamController.add(state);
|
||||
void emitFavoriteStateToFeed(FavoriteState state) => _planFavoriteStateStreamController.add(state);
|
||||
void emitCommentsStateToFeed(CommentsState state) => _planCommentsStateStreamController.add(state);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart';
|
||||
import 'package:eatvio_app/features/plans/models/chosen_plan_model.dart';
|
||||
import 'package:retrofit/retrofit.dart';
|
||||
|
||||
part 'plan_service.g.dart';
|
||||
|
||||
@RestApi()
|
||||
abstract class PlanService {
|
||||
|
||||
factory PlanService(Dio dio, {String baseUrl}) = _PlanService;
|
||||
|
||||
@GET('/api/plans/show/{slug}')
|
||||
Future<PlanModel> getPlan(@Path('slug') String slug);
|
||||
|
||||
@POST('/api/plans/{slug}/like')
|
||||
@POST('/api/plans/{slug}/like')
|
||||
Future<void> likePlan({
|
||||
@Path() required String slug,
|
||||
});
|
||||
@@ -28,4 +26,10 @@ abstract class PlanService {
|
||||
Future<void> removeFromFavorite({
|
||||
@Path() required String slug,
|
||||
});
|
||||
}
|
||||
|
||||
@POST('/api/plans/{slug}/choose')
|
||||
Future<ChosenPlanModel> chosePlan({
|
||||
@Path() required String slug,
|
||||
@Body() required Map<String, dynamic> option,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -101,6 +101,37 @@ class _PlanService implements PlanService {
|
||||
await _dio.fetch<void>(_options);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ChosenPlanModel> chosePlan({
|
||||
required String slug,
|
||||
required Map<String, dynamic> option,
|
||||
}) async {
|
||||
final _extra = <String, dynamic>{};
|
||||
final queryParameters = <String, dynamic>{};
|
||||
final _headers = <String, dynamic>{};
|
||||
final _data = <String, dynamic>{};
|
||||
_data.addAll(option);
|
||||
final _options = _setStreamType<ChosenPlanModel>(
|
||||
Options(method: 'POST', headers: _headers, extra: _extra)
|
||||
.compose(
|
||||
_dio.options,
|
||||
'/api/plans/${slug}/choose',
|
||||
queryParameters: queryParameters,
|
||||
data: _data,
|
||||
)
|
||||
.copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)),
|
||||
);
|
||||
final _result = await _dio.fetch<Map<String, dynamic>>(_options);
|
||||
late ChosenPlanModel _value;
|
||||
try {
|
||||
_value = ChosenPlanModel.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 ||
|
||||
|
||||
@@ -32,6 +32,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"Кол-во активных консультаций"),
|
||||
"active_diet_state": MessageLookupByLibrary.simpleMessage("Активная"),
|
||||
"add": MessageLookupByLibrary.simpleMessage("Добавить"),
|
||||
"add_card": MessageLookupByLibrary.simpleMessage("Привязать карту"),
|
||||
"add_cover": MessageLookupByLibrary.simpleMessage("Добавьте обложку"),
|
||||
"add_measure": MessageLookupByLibrary.simpleMessage("Добавить замер"),
|
||||
"adding_plan": MessageLookupByLibrary.simpleMessage("Добавление плана"),
|
||||
@@ -58,6 +59,8 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"calls_for_bullying":
|
||||
MessageLookupByLibrary.simpleMessage("Призывы к травле"),
|
||||
"calories": MessageLookupByLibrary.simpleMessage("Калории"),
|
||||
"can_not_choose_start_date": MessageLookupByLibrary.simpleMessage(
|
||||
"Дату старта плана невозможно выбрать, пока Вы не привяжите карту"),
|
||||
"can_not_load_data_please_try_again":
|
||||
MessageLookupByLibrary.simpleMessage(
|
||||
"Не удалось загрузить данные. Попробуйте обновить страницу"),
|
||||
@@ -72,10 +75,13 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"chest": MessageLookupByLibrary.simpleMessage("Грудь"),
|
||||
"chest_circumference":
|
||||
MessageLookupByLibrary.simpleMessage("Обхват груди"),
|
||||
"choose_date": MessageLookupByLibrary.simpleMessage("Выбрать дату"),
|
||||
"choose_diet_duration":
|
||||
MessageLookupByLibrary.simpleMessage("Выберите срок диеты"),
|
||||
"choose_plan_duration":
|
||||
MessageLookupByLibrary.simpleMessage("Выберите срок плана"),
|
||||
"choose_plan_start_date": MessageLookupByLibrary.simpleMessage(
|
||||
"Выберите дату старта плана питания"),
|
||||
"choose_start_diet_date": MessageLookupByLibrary.simpleMessage(
|
||||
"Выберите дату старты диеты. Она отобразиться у Вас в дневнике"),
|
||||
"circumference_empty": MessageLookupByLibrary.simpleMessage(
|
||||
@@ -130,6 +136,8 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"create_diet": MessageLookupByLibrary.simpleMessage("Создание диеты"),
|
||||
"customer_price":
|
||||
MessageLookupByLibrary.simpleMessage("Цена для покупателя"),
|
||||
"date_has_ben_set": MessageLookupByLibrary.simpleMessage(
|
||||
"Дата старта начала консультации установлена"),
|
||||
"date_of_birth": MessageLookupByLibrary.simpleMessage("Дата рождения"),
|
||||
"day": MessageLookupByLibrary.simpleMessage("День"),
|
||||
"days": MessageLookupByLibrary.simpleMessage("дней"),
|
||||
@@ -327,6 +335,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"Пароль обязателен для заполнения"),
|
||||
"password_short": MessageLookupByLibrary.simpleMessage(
|
||||
"В пароле должно быть минимум 6 символов"),
|
||||
"pay": MessageLookupByLibrary.simpleMessage("Оплатить"),
|
||||
"pcs": MessageLookupByLibrary.simpleMessage("шт"),
|
||||
"personal": MessageLookupByLibrary.simpleMessage("Персональные"),
|
||||
"personal_diet_state":
|
||||
@@ -424,6 +433,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"time": MessageLookupByLibrary.simpleMessage("Время прохождения"),
|
||||
"toOffer": MessageLookupByLibrary.simpleMessage("Предложить"),
|
||||
"to_draft": MessageLookupByLibrary.simpleMessage("В черновик"),
|
||||
"to_order": MessageLookupByLibrary.simpleMessage("Заказать"),
|
||||
"try_again": MessageLookupByLibrary.simpleMessage("Попробовать снова"),
|
||||
"type_here_your_complaint":
|
||||
MessageLookupByLibrary.simpleMessage("Напишите здесь свою жалобу"),
|
||||
|
||||
@@ -3179,6 +3179,78 @@ class S {
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Заказать`
|
||||
String get to_order {
|
||||
return Intl.message(
|
||||
'Заказать',
|
||||
name: 'to_order',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Дату старта плана невозможно выбрать, пока Вы не привяжите карту`
|
||||
String get can_not_choose_start_date {
|
||||
return Intl.message(
|
||||
'Дату старта плана невозможно выбрать, пока Вы не привяжите карту',
|
||||
name: 'can_not_choose_start_date',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Привязать карту`
|
||||
String get add_card {
|
||||
return Intl.message(
|
||||
'Привязать карту',
|
||||
name: 'add_card',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Выберите дату старта плана питания`
|
||||
String get choose_plan_start_date {
|
||||
return Intl.message(
|
||||
'Выберите дату старта плана питания',
|
||||
name: 'choose_plan_start_date',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Выбрать дату`
|
||||
String get choose_date {
|
||||
return Intl.message(
|
||||
'Выбрать дату',
|
||||
name: 'choose_date',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Дата старта начала консультации установлена`
|
||||
String get date_has_ben_set {
|
||||
return Intl.message(
|
||||
'Дата старта начала консультации установлена',
|
||||
name: 'date_has_ben_set',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
// skipped getter for the 'tap_on_link_to)pay' key
|
||||
|
||||
/// `Оплатить`
|
||||
String get pay {
|
||||
return Intl.message(
|
||||
'Оплатить',
|
||||
name: 'pay',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AppLocalizationDelegate extends LocalizationsDelegate<S> {
|
||||
|
||||
@@ -311,6 +311,15 @@
|
||||
"could_not_update_diet": "Не удалось обновить диету",
|
||||
"could_not_publish_blog_post": "Не удалось опубликовать пост",
|
||||
"could_not_update_blog_post": "Не удалось обновить пост",
|
||||
"could_not_delete_blog_post": "Не удалось удалить пост"
|
||||
"could_not_delete_blog_post": "Не удалось удалить пост",
|
||||
"to_order": "Заказать",
|
||||
"can_not_choose_start_date": "Дату старта плана невозможно выбрать, пока Вы не привяжите карту",
|
||||
"add_card": "Привязать карту",
|
||||
"choose_plan_start_date": "Выберите дату старта плана питания",
|
||||
"choose_date": "Выбрать дату",
|
||||
"date_has_ben_set": "Дата старта начала консультации установлена",
|
||||
"tap_on_link_to)pay": "Перейдите по ссылке для оплаты консультации",
|
||||
"pay": "Оплатить"
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user