diff --git a/.gitea/workflows/docker-run-tests.yml b/.gitea/workflows/docker-run-tests.yml
index ba68a5ef..cf14247c 100644
--- a/.gitea/workflows/docker-run-tests.yml
+++ b/.gitea/workflows/docker-run-tests.yml
@@ -40,7 +40,8 @@ jobs:
run: flutter test
# - name: Build apk
- # run: flutter build apk
+ # run: flutter build apk
+ # some test
# - name: Rename and move apk
# run: |
diff --git a/assets/icons/reversed_exclamation_mark.svg b/assets/icons/reversed_exclamation_mark.svg
new file mode 100644
index 00000000..77b506bc
--- /dev/null
+++ b/assets/icons/reversed_exclamation_mark.svg
@@ -0,0 +1,4 @@
+
diff --git a/lib/core/app_router.dart b/lib/core/app_router.dart
index bd921f0a..1e8a78d0 100644
--- a/lib/core/app_router.dart
+++ b/lib/core/app_router.dart
@@ -7,7 +7,6 @@ import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/prof
import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_state.dart';
import 'package:eatvio_app/features/bottom_navigation_bar/presentation/widgets/bottom_navigation_bar_widget.dart';
import 'package:eatvio_app/features/calendar/presentation/pages/calendar_screen.dart';
-import 'package:eatvio_app/features/chat/presentation/bloc/chats_cubit/chats_cubit.dart';
import 'package:eatvio_app/features/chat/presentation/pages/chat_screen.dart';
import 'package:eatvio_app/features/chat/presentation/pages/chats_screen.dart';
import 'package:eatvio_app/features/chat/presentation/pages/photo_view_screen.dart';
@@ -242,12 +241,10 @@ class AppRouter {
path: '/chat-screen',
name: 'chatScreen',
builder: (context, state) {
- final data = state.extra as Map;
- final chatsCubit = data['chatsCubit'] as ChatsCubit;
+ final data = state.extra as Map;
final chatId = data['chatId'] as String;
return ChatScreen(
- chatId: chatId,
- chatsCubit: chatsCubit,
+ chatId: chatId,
);
},
),
diff --git a/lib/core/const.dart b/lib/core/const.dart
index dfeae1fc..4f38a54e 100644
--- a/lib/core/const.dart
+++ b/lib/core/const.dart
@@ -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 durationValues = [7, 14, 21];
@@ -9,3 +9,4 @@ const List planTypeValues = ['fit', 'slim', 'wellness', 'behavior'];
const newMessagesChannelName = 'private-new-chat-messages';
const newNotificationsChannelName = 'private-message-events';
const directChatChannelName = 'private-direct-chat';
+const thresholdForPagination = 150;
diff --git a/lib/core/locator_service.dart b/lib/core/locator_service.dart
index d88e8746..99846f1a 100644
--- a/lib/core/locator_service.dart
+++ b/lib/core/locator_service.dart
@@ -87,6 +87,7 @@ Future init() async {
sl.registerLazySingleton(() => NotificationsCubit(wsManager: sl()));
sl.registerLazySingleton(() => FeedCubit(feedRepository: sl()));
sl.registerLazySingleton(() => ProfileAvatarCubit(profileRepository: sl()));
+ sl.registerLazySingleton(() => ChatsCubit(chatRepository: sl(), wsManager: sl(), profileRepository: sl()));
// Cubit factories
sl.registerFactory(() => RegistrationCubit(registrationRepository: sl()));
@@ -96,8 +97,7 @@ Future init() async {
sl.registerFactory(() => ProfileCubit(profileRepository: sl(), chatRepository: sl()));
sl.registerFactory(() => profilePlans.PlansCubit(plansRepository: sl()));
sl.registerFactory(() => DietsCubit(feedRepository: sl(), dietsRepository: sl()));
- sl.registerFactory(() => CommentsCubit(feedRepository: sl()));
- sl.registerFactory(() => ChatsCubit(chatRepository: sl(), wsManager: sl(), profileRepository: sl()));
+ sl.registerFactory(() => CommentsCubit(feedRepository: sl()));
sl.registerFactory(() => PlansCubit(feedRepository: sl(), planRepository: sl()));
sl.registerFactory(() => SettingsCubit(profileRepository: sl(), settingsRepository: sl()));
sl.registerFactory(() => RegisterConsultantCubit(consultantRepository: sl()));
diff --git a/lib/core/theme/theme_helper.dart b/lib/core/theme/theme_helper.dart
index 2c319dd8..d4326bf4 100644
--- a/lib/core/theme/theme_helper.dart
+++ b/lib/core/theme/theme_helper.dart
@@ -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);
diff --git a/lib/core/utils/pagination_utils.dart b/lib/core/utils/pagination_utils.dart
new file mode 100644
index 00000000..c6f6da95
--- /dev/null
+++ b/lib/core/utils/pagination_utils.dart
@@ -0,0 +1,8 @@
+import 'package:eatvio_app/core/const.dart';
+import 'package:flutter/material.dart';
+
+void loadNewContent(ScrollNotification notification, Future Function() load) {
+ if (notification.metrics.pixels >= notification.metrics.maxScrollExtent - thresholdForPagination && !notification.metrics.outOfRange) {
+ load();
+ }
+}
diff --git a/lib/core/widgets/item_widget.dart b/lib/core/widgets/item_widget.dart
new file mode 100644
index 00000000..c7af63c5
--- /dev/null
+++ b/lib/core/widgets/item_widget.dart
@@ -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,
+ ),
+ ],
+ );
+ }
+}
diff --git a/lib/features/auth/presentation/bloc/auth_cubit.dart b/lib/features/auth/presentation/bloc/auth_cubit.dart
index da1c3fef..dc521829 100644
--- a/lib/features/auth/presentation/bloc/auth_cubit.dart
+++ b/lib/features/auth/presentation/bloc/auth_cubit.dart
@@ -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 {
required this.authRepository,
}) : super(AuthState());
- getTokenByCredentials(String email, String password) async {
+ Future getTokenByCredentials(String email, String password) async {
emit(AuthState.loading());
try {
final token = (await authRepository.getTokenByCredentials(
@@ -23,7 +21,6 @@ class AuthCubit extends Cubit {
password,
))
.token;
- print(token);
emit(
AuthState.loaded(
token: token,
@@ -31,12 +28,13 @@ class AuthCubit extends Cubit {
);
showSuccessToast('Успешный вход');
await TokenStorage.saveTokenInStorage(token);
- await sl().getMyProfile();
AppRouter.navigatorKey.currentContext?.go('/my-profile-screen');
+ return true;
} catch (e) {
print(e);
showErrorToast('Неверный адрес электронной почты или пароль');
emit(AuthState.error(errorMessage: '$e'));
+ return false;
}
}
}
diff --git a/lib/features/auth/presentation/pages/auth_screen.dart b/lib/features/auth/presentation/pages/auth_screen.dart
index 785edbc6..cce986d6 100644
--- a/lib/features/auth/presentation/pages/auth_screen.dart
+++ b/lib/features/auth/presentation/pages/auth_screen.dart
@@ -6,8 +6,11 @@ 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';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart';
@@ -116,30 +119,30 @@ class _AuthScreenState extends State {
],
),
Spacer(),
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- Text(
- 'Нажимая "Войти", Вы соглашаетесь с ',
+ Center(
+ child: RichText(
+ textAlign: TextAlign.center,
+ text: TextSpan(
+ text: 'Нажимая "Войти", Вы соглашаетесь \n',
style: TextStyle(
fontSize: 12,
+ color: Colors.black,
),
- ),
- GestureDetector(
- onTap: () async {
- await launchUrl(Uri.parse(baseUrl + '/oferta_bs.pdf'));
- },
- child: Text(
- 'Публичной офертой',
- style: TextStyle(
- fontSize: 12,
- color: appTheme.blueA400,
- decorationColor: appTheme.blueA400,
- decoration: TextDecoration.underline,
+ children: [
+ TextSpan(text: 'c '),
+ TextSpan(
+ text: ' Публичной офертой',
+ style: TextStyle(
+ fontSize: 12,
+ color: appTheme.blueA400,
+ decorationColor: appTheme.blueA400,
+ decoration: TextDecoration.underline,
+ ),
+ recognizer: TapGestureRecognizer()..onTap = () async => await launchUrl(Uri.parse(baseUrl + '/oferta_bs.pdf')),
),
- ),
+ ],
),
- ],
+ ),
),
const SizedBox(height: 16),
Container(
@@ -156,10 +159,16 @@ class _AuthScreenState extends State {
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().getMyProfile();
+ context.read().getChatRoomsWithLoading();
+ }
+ },
label: state is AuthStateLoading
? CupertinoActivityIndicator()
: Text(
diff --git a/lib/features/chat/models/chat_room_model.dart b/lib/features/chat/models/chat_room_model.dart
index f9e9a416..9d77fdf0 100644
--- a/lib/features/chat/models/chat_room_model.dart
+++ b/lib/features/chat/models/chat_room_model.dart
@@ -1,5 +1,6 @@
import 'package:eatvio_app/features/chat/models/chat_room_settings_model.dart';
import 'package:eatvio_app/features/chat/models/chat_user_model.dart';
+import 'package:eatvio_app/features/plans/models/chosen_plan_model.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'chat_room_model.freezed.dart';
@@ -10,8 +11,23 @@ class ChatRoomModel with _$ChatRoomModel {
const factory ChatRoomModel({
required String id,
@JsonKey(name: 'chat_room_setting') required ChatRoomSettingsModel chatRoomSettings,
- required Map users,
+ required Users users,
+ @JsonKey(name: 'chosen_plan', fromJson: parseChosenPlan) required ChosenPlanModel? chosenPlan,
}) = _ChatRoomModel;
factory ChatRoomModel.fromJson(Map json) => _$ChatRoomModelFromJson(json);
}
+
+@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 json) => _$UsersFromJson(json);
+}
+
+
diff --git a/lib/features/chat/models/chat_room_model.freezed.dart b/lib/features/chat/models/chat_room_model.freezed.dart
index 6afb3a94..829dd69f 100644
--- a/lib/features/chat/models/chat_room_model.freezed.dart
+++ b/lib/features/chat/models/chat_room_model.freezed.dart
@@ -24,7 +24,9 @@ mixin _$ChatRoomModel {
@JsonKey(name: 'chat_room_setting')
ChatRoomSettingsModel get chatRoomSettings =>
throw _privateConstructorUsedError;
- Map get users => throw _privateConstructorUsedError;
+ Users get users => throw _privateConstructorUsedError;
+ @JsonKey(name: 'chosen_plan', fromJson: parseChosenPlan)
+ ChosenPlanModel? get chosenPlan => throw _privateConstructorUsedError;
/// Serializes this ChatRoomModel to a JSON map.
Map toJson() => throw _privateConstructorUsedError;
@@ -46,9 +48,13 @@ abstract class $ChatRoomModelCopyWith<$Res> {
{String id,
@JsonKey(name: 'chat_room_setting')
ChatRoomSettingsModel chatRoomSettings,
- Map users});
+ Users users,
+ @JsonKey(name: 'chosen_plan', fromJson: parseChosenPlan)
+ ChosenPlanModel? chosenPlan});
$ChatRoomSettingsModelCopyWith<$Res> get chatRoomSettings;
+ $UsersCopyWith<$Res> get users;
+ $ChosenPlanModelCopyWith<$Res>? get chosenPlan;
}
/// @nodoc
@@ -69,6 +75,7 @@ class _$ChatRoomModelCopyWithImpl<$Res, $Val extends ChatRoomModel>
Object? id = null,
Object? chatRoomSettings = null,
Object? users = null,
+ Object? chosenPlan = freezed,
}) {
return _then(_value.copyWith(
id: null == id
@@ -82,7 +89,11 @@ class _$ChatRoomModelCopyWithImpl<$Res, $Val extends ChatRoomModel>
users: null == users
? _value.users
: users // ignore: cast_nullable_to_non_nullable
- as Map,
+ as Users,
+ chosenPlan: freezed == chosenPlan
+ ? _value.chosenPlan
+ : chosenPlan // ignore: cast_nullable_to_non_nullable
+ as ChosenPlanModel?,
) as $Val);
}
@@ -96,6 +107,30 @@ class _$ChatRoomModelCopyWithImpl<$Res, $Val extends ChatRoomModel>
return _then(_value.copyWith(chatRoomSettings: value) as $Val);
});
}
+
+ /// 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
+ @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
@@ -110,10 +145,16 @@ abstract class _$$ChatRoomModelImplCopyWith<$Res>
{String id,
@JsonKey(name: 'chat_room_setting')
ChatRoomSettingsModel chatRoomSettings,
- Map users});
+ 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;
}
/// @nodoc
@@ -132,6 +173,7 @@ class __$$ChatRoomModelImplCopyWithImpl<$Res>
Object? id = null,
Object? chatRoomSettings = null,
Object? users = null,
+ Object? chosenPlan = freezed,
}) {
return _then(_$ChatRoomModelImpl(
id: null == id
@@ -143,9 +185,13 @@ 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,
+ as Users,
+ chosenPlan: freezed == chosenPlan
+ ? _value.chosenPlan
+ : chosenPlan // ignore: cast_nullable_to_non_nullable
+ as ChosenPlanModel?,
));
}
}
@@ -156,8 +202,9 @@ class _$ChatRoomModelImpl implements _ChatRoomModel {
const _$ChatRoomModelImpl(
{required this.id,
@JsonKey(name: 'chat_room_setting') required this.chatRoomSettings,
- required final Map users})
- : _users = users;
+ required this.users,
+ @JsonKey(name: 'chosen_plan', fromJson: parseChosenPlan)
+ required this.chosenPlan});
factory _$ChatRoomModelImpl.fromJson(Map json) =>
_$$ChatRoomModelImplFromJson(json);
@@ -167,17 +214,15 @@ class _$ChatRoomModelImpl implements _ChatRoomModel {
@override
@JsonKey(name: 'chat_room_setting')
final ChatRoomSettingsModel chatRoomSettings;
- final Map _users;
@override
- Map 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)
+ final ChosenPlanModel? chosenPlan;
@override
String toString() {
- return 'ChatRoomModel(id: $id, chatRoomSettings: $chatRoomSettings, users: $users)';
+ return 'ChatRoomModel(id: $id, chatRoomSettings: $chatRoomSettings, users: $users, chosenPlan: $chosenPlan)';
}
@override
@@ -188,13 +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));
+ 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.
@@ -217,7 +264,9 @@ abstract class _ChatRoomModel implements ChatRoomModel {
{required final String id,
@JsonKey(name: 'chat_room_setting')
required final ChatRoomSettingsModel chatRoomSettings,
- required final Map users}) = _$ChatRoomModelImpl;
+ required final Users users,
+ @JsonKey(name: 'chosen_plan', fromJson: parseChosenPlan)
+ required final ChosenPlanModel? chosenPlan}) = _$ChatRoomModelImpl;
factory _ChatRoomModel.fromJson(Map json) =
_$ChatRoomModelImpl.fromJson;
@@ -228,7 +277,10 @@ abstract class _ChatRoomModel implements ChatRoomModel {
@JsonKey(name: 'chat_room_setting')
ChatRoomSettingsModel get chatRoomSettings;
@override
- Map get users;
+ Users get users;
+ @override
+ @JsonKey(name: 'chosen_plan', fromJson: parseChosenPlan)
+ ChosenPlanModel? get chosenPlan;
/// Create a copy of ChatRoomModel
/// with the given fields replaced by the non-null parameter values.
@@ -237,3 +289,208 @@ abstract class _ChatRoomModel implements ChatRoomModel {
_$$ChatRoomModelImplCopyWith<_$ChatRoomModelImpl> get copyWith =>
throw _privateConstructorUsedError;
}
+
+Users _$UsersFromJson(Map 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 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 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 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 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 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;
+}
diff --git a/lib/features/chat/models/chat_room_model.g.dart b/lib/features/chat/models/chat_room_model.g.dart
index 68d3195c..fb9e6257 100644
--- a/lib/features/chat/models/chat_room_model.g.dart
+++ b/lib/features/chat/models/chat_room_model.g.dart
@@ -11,10 +11,8 @@ _$ChatRoomModelImpl _$$ChatRoomModelImplFromJson(Map json) =>
id: json['id'] as String,
chatRoomSettings: ChatRoomSettingsModel.fromJson(
json['chat_room_setting'] as Map),
- users: (json['users'] as Map).map(
- (k, e) =>
- MapEntry(k, ChatUserModel.fromJson(e as Map)),
- ),
+ users: Users.fromJson(json['users'] as Map),
+ chosenPlan: parseChosenPlan(json['chosen_plan']),
);
Map _$$ChatRoomModelImplToJson(_$ChatRoomModelImpl instance) =>
@@ -22,4 +20,18 @@ Map _$$ChatRoomModelImplToJson(_$ChatRoomModelImpl instance) =>
'id': instance.id,
'chat_room_setting': instance.chatRoomSettings,
'users': instance.users,
+ 'chosen_plan': instance.chosenPlan,
+ };
+
+_$UsersImpl _$$UsersImplFromJson(Map json) => _$UsersImpl(
+ sender: ChatUserModel.fromJson(
+ json['from_chat_user'] as Map),
+ receiver:
+ ChatUserModel.fromJson(json['to_chat_user'] as Map),
+ );
+
+Map _$$UsersImplToJson(_$UsersImpl instance) =>
+ {
+ 'from_chat_user': instance.sender,
+ 'to_chat_user': instance.receiver,
};
diff --git a/lib/features/chat/models/chat_room_preview_model.dart b/lib/features/chat/models/chat_room_pagination_model.dart
similarity index 61%
rename from lib/features/chat/models/chat_room_preview_model.dart
rename to lib/features/chat/models/chat_room_pagination_model.dart
index bc6e4b5d..2d7e875d 100644
--- a/lib/features/chat/models/chat_room_preview_model.dart
+++ b/lib/features/chat/models/chat_room_pagination_model.dart
@@ -1,16 +1,29 @@
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_preview_model.freezed.dart';
-part 'chat_room_preview_model.g.dart';
+part 'chat_room_pagination_model.freezed.dart';
+part 'chat_room_pagination_model.g.dart';
@freezed
-class ChatRoomPreviewModel with _$ChatRoomPreviewModel {
- const factory ChatRoomPreviewModel({
- @JsonKey(name: "chatRooms") required List chatRooms,
+class ChatRoomPaginationModel with _$ChatRoomPaginationModel {
+ const factory ChatRoomPaginationModel({
+ @JsonKey(name: "chatRooms") required ChatRooms chatRooms,
+ @JsonKey(name: "number_of_unread_chat_rooms") required int unreadChatsCount,
}) = _ChatRoomPreviewModel;
- factory ChatRoomPreviewModel.fromJson(Map json) => _$ChatRoomPreviewModelFromJson(json);
+ factory ChatRoomPaginationModel.fromJson(Map json) => _$ChatRoomPaginationModelFromJson(json);
+}
+
+@freezed
+class ChatRooms with _$ChatRooms {
+ const factory ChatRooms({
+ @JsonKey(name: "data") required List data,
+ @JsonKey(name: "last_page") required int lastPage,
+ @JsonKey(name: "current_page") required int currentPage,
+ }) = _ChatRooms;
+
+ factory ChatRooms.fromJson(Map json) => _$ChatRoomsFromJson(json);
}
@freezed
@@ -21,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 json) => _$ChatRoomFromJson(json);
diff --git a/lib/features/chat/models/chat_room_preview_model.freezed.dart b/lib/features/chat/models/chat_room_pagination_model.freezed.dart
similarity index 69%
rename from lib/features/chat/models/chat_room_preview_model.freezed.dart
rename to lib/features/chat/models/chat_room_pagination_model.freezed.dart
index 940c3106..54e56ee3 100644
--- a/lib/features/chat/models/chat_room_preview_model.freezed.dart
+++ b/lib/features/chat/models/chat_room_pagination_model.freezed.dart
@@ -3,7 +3,7 @@
// 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 'chat_room_preview_model.dart';
+part of 'chat_room_pagination_model.dart';
// **************************************************************************
// FreezedGenerator
@@ -14,92 +14,125 @@ T _$identity(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
-ChatRoomPreviewModel _$ChatRoomPreviewModelFromJson(Map json) {
+ChatRoomPaginationModel _$ChatRoomPaginationModelFromJson(
+ Map json) {
return _ChatRoomPreviewModel.fromJson(json);
}
/// @nodoc
-mixin _$ChatRoomPreviewModel {
+mixin _$ChatRoomPaginationModel {
@JsonKey(name: "chatRooms")
- List get chatRooms => throw _privateConstructorUsedError;
+ ChatRooms get chatRooms => throw _privateConstructorUsedError;
+ @JsonKey(name: "number_of_unread_chat_rooms")
+ int get unreadChatsCount => throw _privateConstructorUsedError;
- /// Serializes this ChatRoomPreviewModel to a JSON map.
+ /// Serializes this ChatRoomPaginationModel to a JSON map.
Map toJson() => throw _privateConstructorUsedError;
- /// Create a copy of ChatRoomPreviewModel
+ /// Create a copy of ChatRoomPaginationModel
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
- $ChatRoomPreviewModelCopyWith get copyWith =>
+ $ChatRoomPaginationModelCopyWith get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
-abstract class $ChatRoomPreviewModelCopyWith<$Res> {
- factory $ChatRoomPreviewModelCopyWith(ChatRoomPreviewModel value,
- $Res Function(ChatRoomPreviewModel) then) =
- _$ChatRoomPreviewModelCopyWithImpl<$Res, ChatRoomPreviewModel>;
+abstract class $ChatRoomPaginationModelCopyWith<$Res> {
+ factory $ChatRoomPaginationModelCopyWith(ChatRoomPaginationModel value,
+ $Res Function(ChatRoomPaginationModel) then) =
+ _$ChatRoomPaginationModelCopyWithImpl<$Res, ChatRoomPaginationModel>;
@useResult
- $Res call({@JsonKey(name: "chatRooms") List chatRooms});
+ $Res call(
+ {@JsonKey(name: "chatRooms") ChatRooms chatRooms,
+ @JsonKey(name: "number_of_unread_chat_rooms") int unreadChatsCount});
+
+ $ChatRoomsCopyWith<$Res> get chatRooms;
}
/// @nodoc
-class _$ChatRoomPreviewModelCopyWithImpl<$Res,
- $Val extends ChatRoomPreviewModel>
- implements $ChatRoomPreviewModelCopyWith<$Res> {
- _$ChatRoomPreviewModelCopyWithImpl(this._value, this._then);
+class _$ChatRoomPaginationModelCopyWithImpl<$Res,
+ $Val extends ChatRoomPaginationModel>
+ implements $ChatRoomPaginationModelCopyWith<$Res> {
+ _$ChatRoomPaginationModelCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
- /// Create a copy of ChatRoomPreviewModel
+ /// Create a copy of ChatRoomPaginationModel
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? chatRooms = null,
+ Object? unreadChatsCount = null,
}) {
return _then(_value.copyWith(
chatRooms: null == chatRooms
? _value.chatRooms
: chatRooms // ignore: cast_nullable_to_non_nullable
- as List,
+ as ChatRooms,
+ unreadChatsCount: null == unreadChatsCount
+ ? _value.unreadChatsCount
+ : unreadChatsCount // ignore: cast_nullable_to_non_nullable
+ as int,
) as $Val);
}
+
+ /// Create a copy of ChatRoomPaginationModel
+ /// with the given fields replaced by the non-null parameter values.
+ @override
+ @pragma('vm:prefer-inline')
+ $ChatRoomsCopyWith<$Res> get chatRooms {
+ return $ChatRoomsCopyWith<$Res>(_value.chatRooms, (value) {
+ return _then(_value.copyWith(chatRooms: value) as $Val);
+ });
+ }
}
/// @nodoc
abstract class _$$ChatRoomPreviewModelImplCopyWith<$Res>
- implements $ChatRoomPreviewModelCopyWith<$Res> {
+ implements $ChatRoomPaginationModelCopyWith<$Res> {
factory _$$ChatRoomPreviewModelImplCopyWith(_$ChatRoomPreviewModelImpl value,
$Res Function(_$ChatRoomPreviewModelImpl) then) =
__$$ChatRoomPreviewModelImplCopyWithImpl<$Res>;
@override
@useResult
- $Res call({@JsonKey(name: "chatRooms") List chatRooms});
+ $Res call(
+ {@JsonKey(name: "chatRooms") ChatRooms chatRooms,
+ @JsonKey(name: "number_of_unread_chat_rooms") int unreadChatsCount});
+
+ @override
+ $ChatRoomsCopyWith<$Res> get chatRooms;
}
/// @nodoc
class __$$ChatRoomPreviewModelImplCopyWithImpl<$Res>
- extends _$ChatRoomPreviewModelCopyWithImpl<$Res, _$ChatRoomPreviewModelImpl>
+ extends _$ChatRoomPaginationModelCopyWithImpl<$Res,
+ _$ChatRoomPreviewModelImpl>
implements _$$ChatRoomPreviewModelImplCopyWith<$Res> {
__$$ChatRoomPreviewModelImplCopyWithImpl(_$ChatRoomPreviewModelImpl _value,
$Res Function(_$ChatRoomPreviewModelImpl) _then)
: super(_value, _then);
- /// Create a copy of ChatRoomPreviewModel
+ /// Create a copy of ChatRoomPaginationModel
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? chatRooms = null,
+ Object? unreadChatsCount = null,
}) {
return _then(_$ChatRoomPreviewModelImpl(
chatRooms: null == chatRooms
- ? _value._chatRooms
+ ? _value.chatRooms
: chatRooms // ignore: cast_nullable_to_non_nullable
- as List,
+ as ChatRooms,
+ unreadChatsCount: null == unreadChatsCount
+ ? _value.unreadChatsCount
+ : unreadChatsCount // ignore: cast_nullable_to_non_nullable
+ as int,
));
}
}
@@ -108,24 +141,23 @@ class __$$ChatRoomPreviewModelImplCopyWithImpl<$Res>
@JsonSerializable()
class _$ChatRoomPreviewModelImpl implements _ChatRoomPreviewModel {
const _$ChatRoomPreviewModelImpl(
- {@JsonKey(name: "chatRooms") required final List chatRooms})
- : _chatRooms = chatRooms;
+ {@JsonKey(name: "chatRooms") required this.chatRooms,
+ @JsonKey(name: "number_of_unread_chat_rooms")
+ required this.unreadChatsCount});
factory _$ChatRoomPreviewModelImpl.fromJson(Map json) =>
_$$ChatRoomPreviewModelImplFromJson(json);
- final List _chatRooms;
@override
@JsonKey(name: "chatRooms")
- List get chatRooms {
- if (_chatRooms is EqualUnmodifiableListView) return _chatRooms;
- // ignore: implicit_dynamic_type
- return EqualUnmodifiableListView(_chatRooms);
- }
+ final ChatRooms chatRooms;
+ @override
+ @JsonKey(name: "number_of_unread_chat_rooms")
+ final int unreadChatsCount;
@override
String toString() {
- return 'ChatRoomPreviewModel(chatRooms: $chatRooms)';
+ return 'ChatRoomPaginationModel(chatRooms: $chatRooms, unreadChatsCount: $unreadChatsCount)';
}
@override
@@ -133,16 +165,17 @@ class _$ChatRoomPreviewModelImpl implements _ChatRoomPreviewModel {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$ChatRoomPreviewModelImpl &&
- const DeepCollectionEquality()
- .equals(other._chatRooms, _chatRooms));
+ (identical(other.chatRooms, chatRooms) ||
+ other.chatRooms == chatRooms) &&
+ (identical(other.unreadChatsCount, unreadChatsCount) ||
+ other.unreadChatsCount == unreadChatsCount));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
- int get hashCode =>
- Object.hash(runtimeType, const DeepCollectionEquality().hash(_chatRooms));
+ int get hashCode => Object.hash(runtimeType, chatRooms, unreadChatsCount);
- /// Create a copy of ChatRoomPreviewModel
+ /// Create a copy of ChatRoomPaginationModel
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@@ -160,19 +193,23 @@ class _$ChatRoomPreviewModelImpl implements _ChatRoomPreviewModel {
}
}
-abstract class _ChatRoomPreviewModel implements ChatRoomPreviewModel {
+abstract class _ChatRoomPreviewModel implements ChatRoomPaginationModel {
const factory _ChatRoomPreviewModel(
- {@JsonKey(name: "chatRooms")
- required final List chatRooms}) = _$ChatRoomPreviewModelImpl;
+ {@JsonKey(name: "chatRooms") required final ChatRooms chatRooms,
+ @JsonKey(name: "number_of_unread_chat_rooms")
+ required final int unreadChatsCount}) = _$ChatRoomPreviewModelImpl;
factory _ChatRoomPreviewModel.fromJson(Map json) =
_$ChatRoomPreviewModelImpl.fromJson;
@override
@JsonKey(name: "chatRooms")
- List get chatRooms;
+ ChatRooms get chatRooms;
+ @override
+ @JsonKey(name: "number_of_unread_chat_rooms")
+ int get unreadChatsCount;
- /// Create a copy of ChatRoomPreviewModel
+ /// Create a copy of ChatRoomPaginationModel
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
@@ -180,6 +217,218 @@ abstract class _ChatRoomPreviewModel implements ChatRoomPreviewModel {
get copyWith => throw _privateConstructorUsedError;
}
+ChatRooms _$ChatRoomsFromJson(Map json) {
+ return _ChatRooms.fromJson(json);
+}
+
+/// @nodoc
+mixin _$ChatRooms {
+ @JsonKey(name: "data")
+ List get data => throw _privateConstructorUsedError;
+ @JsonKey(name: "last_page")
+ int get lastPage => throw _privateConstructorUsedError;
+ @JsonKey(name: "current_page")
+ int get currentPage => throw _privateConstructorUsedError;
+
+ /// Serializes this ChatRooms to a JSON map.
+ Map toJson() => throw _privateConstructorUsedError;
+
+ /// Create a copy of ChatRooms
+ /// with the given fields replaced by the non-null parameter values.
+ @JsonKey(includeFromJson: false, includeToJson: false)
+ $ChatRoomsCopyWith get copyWith =>
+ throw _privateConstructorUsedError;
+}
+
+/// @nodoc
+abstract class $ChatRoomsCopyWith<$Res> {
+ factory $ChatRoomsCopyWith(ChatRooms value, $Res Function(ChatRooms) then) =
+ _$ChatRoomsCopyWithImpl<$Res, ChatRooms>;
+ @useResult
+ $Res call(
+ {@JsonKey(name: "data") List data,
+ @JsonKey(name: "last_page") int lastPage,
+ @JsonKey(name: "current_page") int currentPage});
+}
+
+/// @nodoc
+class _$ChatRoomsCopyWithImpl<$Res, $Val extends ChatRooms>
+ implements $ChatRoomsCopyWith<$Res> {
+ _$ChatRoomsCopyWithImpl(this._value, this._then);
+
+ // ignore: unused_field
+ final $Val _value;
+ // ignore: unused_field
+ final $Res Function($Val) _then;
+
+ /// Create a copy of ChatRooms
+ /// with the given fields replaced by the non-null parameter values.
+ @pragma('vm:prefer-inline')
+ @override
+ $Res call({
+ Object? data = null,
+ Object? lastPage = null,
+ Object? currentPage = null,
+ }) {
+ return _then(_value.copyWith(
+ data: null == data
+ ? _value.data
+ : data // ignore: cast_nullable_to_non_nullable
+ as List,
+ lastPage: null == lastPage
+ ? _value.lastPage
+ : lastPage // ignore: cast_nullable_to_non_nullable
+ as int,
+ currentPage: null == currentPage
+ ? _value.currentPage
+ : currentPage // ignore: cast_nullable_to_non_nullable
+ as int,
+ ) as $Val);
+ }
+}
+
+/// @nodoc
+abstract class _$$ChatRoomsImplCopyWith<$Res>
+ implements $ChatRoomsCopyWith<$Res> {
+ factory _$$ChatRoomsImplCopyWith(
+ _$ChatRoomsImpl value, $Res Function(_$ChatRoomsImpl) then) =
+ __$$ChatRoomsImplCopyWithImpl<$Res>;
+ @override
+ @useResult
+ $Res call(
+ {@JsonKey(name: "data") List data,
+ @JsonKey(name: "last_page") int lastPage,
+ @JsonKey(name: "current_page") int currentPage});
+}
+
+/// @nodoc
+class __$$ChatRoomsImplCopyWithImpl<$Res>
+ extends _$ChatRoomsCopyWithImpl<$Res, _$ChatRoomsImpl>
+ implements _$$ChatRoomsImplCopyWith<$Res> {
+ __$$ChatRoomsImplCopyWithImpl(
+ _$ChatRoomsImpl _value, $Res Function(_$ChatRoomsImpl) _then)
+ : super(_value, _then);
+
+ /// Create a copy of ChatRooms
+ /// with the given fields replaced by the non-null parameter values.
+ @pragma('vm:prefer-inline')
+ @override
+ $Res call({
+ Object? data = null,
+ Object? lastPage = null,
+ Object? currentPage = null,
+ }) {
+ return _then(_$ChatRoomsImpl(
+ data: null == data
+ ? _value._data
+ : data // ignore: cast_nullable_to_non_nullable
+ as List,
+ lastPage: null == lastPage
+ ? _value.lastPage
+ : lastPage // ignore: cast_nullable_to_non_nullable
+ as int,
+ currentPage: null == currentPage
+ ? _value.currentPage
+ : currentPage // ignore: cast_nullable_to_non_nullable
+ as int,
+ ));
+ }
+}
+
+/// @nodoc
+@JsonSerializable()
+class _$ChatRoomsImpl implements _ChatRooms {
+ const _$ChatRoomsImpl(
+ {@JsonKey(name: "data") required final List data,
+ @JsonKey(name: "last_page") required this.lastPage,
+ @JsonKey(name: "current_page") required this.currentPage})
+ : _data = data;
+
+ factory _$ChatRoomsImpl.fromJson(Map json) =>
+ _$$ChatRoomsImplFromJson(json);
+
+ final List _data;
+ @override
+ @JsonKey(name: "data")
+ List get data {
+ if (_data is EqualUnmodifiableListView) return _data;
+ // ignore: implicit_dynamic_type
+ return EqualUnmodifiableListView(_data);
+ }
+
+ @override
+ @JsonKey(name: "last_page")
+ final int lastPage;
+ @override
+ @JsonKey(name: "current_page")
+ final int currentPage;
+
+ @override
+ String toString() {
+ return 'ChatRooms(data: $data, lastPage: $lastPage, currentPage: $currentPage)';
+ }
+
+ @override
+ bool operator ==(Object other) {
+ return identical(this, other) ||
+ (other.runtimeType == runtimeType &&
+ other is _$ChatRoomsImpl &&
+ const DeepCollectionEquality().equals(other._data, _data) &&
+ (identical(other.lastPage, lastPage) ||
+ other.lastPage == lastPage) &&
+ (identical(other.currentPage, currentPage) ||
+ other.currentPage == currentPage));
+ }
+
+ @JsonKey(includeFromJson: false, includeToJson: false)
+ @override
+ int get hashCode => Object.hash(runtimeType,
+ const DeepCollectionEquality().hash(_data), lastPage, currentPage);
+
+ /// Create a copy of ChatRooms
+ /// with the given fields replaced by the non-null parameter values.
+ @JsonKey(includeFromJson: false, includeToJson: false)
+ @override
+ @pragma('vm:prefer-inline')
+ _$$ChatRoomsImplCopyWith<_$ChatRoomsImpl> get copyWith =>
+ __$$ChatRoomsImplCopyWithImpl<_$ChatRoomsImpl>(this, _$identity);
+
+ @override
+ Map toJson() {
+ return _$$ChatRoomsImplToJson(
+ this,
+ );
+ }
+}
+
+abstract class _ChatRooms implements ChatRooms {
+ const factory _ChatRooms(
+ {@JsonKey(name: "data") required final List data,
+ @JsonKey(name: "last_page") required final int lastPage,
+ @JsonKey(name: "current_page") required final int currentPage}) =
+ _$ChatRoomsImpl;
+
+ factory _ChatRooms.fromJson(Map json) =
+ _$ChatRoomsImpl.fromJson;
+
+ @override
+ @JsonKey(name: "data")
+ List get data;
+ @override
+ @JsonKey(name: "last_page")
+ int get lastPage;
+ @override
+ @JsonKey(name: "current_page")
+ int get currentPage;
+
+ /// Create a copy of ChatRooms
+ /// with the given fields replaced by the non-null parameter values.
+ @override
+ @JsonKey(includeFromJson: false, includeToJson: false)
+ _$$ChatRoomsImplCopyWith<_$ChatRoomsImpl> get copyWith =>
+ throw _privateConstructorUsedError;
+}
+
ChatRoom _$ChatRoomFromJson(Map json) {
return _ChatRoom.fromJson(json);
}
@@ -196,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 toJson() => throw _privateConstructorUsedError;
@@ -218,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
@@ -244,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
@@ -266,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);
}
@@ -292,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
@@ -308,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
@@ -334,6 +611,7 @@ class __$$ChatRoomImplCopyWithImpl<$Res>
Object? lastMessage = freezed,
Object? users = null,
Object? unreadMessagesCount = null,
+ Object? chosenPlan = freezed,
}) {
return _then(_$ChatRoomImpl(
id: null == id
@@ -356,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?,
));
}
}
@@ -369,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 json) =>
_$$ChatRoomImplFromJson(json);
@@ -390,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
@@ -408,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.
@@ -440,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 json) =
_$ChatRoomImpl.fromJson;
@@ -460,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.
diff --git a/lib/features/chat/models/chat_room_preview_model.g.dart b/lib/features/chat/models/chat_room_pagination_model.g.dart
similarity index 73%
rename from lib/features/chat/models/chat_room_preview_model.g.dart
rename to lib/features/chat/models/chat_room_pagination_model.g.dart
index ad812d46..d6f6e057 100644
--- a/lib/features/chat/models/chat_room_preview_model.g.dart
+++ b/lib/features/chat/models/chat_room_pagination_model.g.dart
@@ -1,6 +1,6 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
-part of 'chat_room_preview_model.dart';
+part of 'chat_room_pagination_model.dart';
// **************************************************************************
// JsonSerializableGenerator
@@ -9,15 +9,31 @@ part of 'chat_room_preview_model.dart';
_$ChatRoomPreviewModelImpl _$$ChatRoomPreviewModelImplFromJson(
Map json) =>
_$ChatRoomPreviewModelImpl(
- chatRooms: (json['chatRooms'] as List)
- .map((e) => ChatRoom.fromJson(e as Map))
- .toList(),
+ chatRooms: ChatRooms.fromJson(json['chatRooms'] as Map),
+ unreadChatsCount: (json['number_of_unread_chat_rooms'] as num).toInt(),
);
Map _$$ChatRoomPreviewModelImplToJson(
_$ChatRoomPreviewModelImpl instance) =>
{
'chatRooms': instance.chatRooms,
+ 'number_of_unread_chat_rooms': instance.unreadChatsCount,
+ };
+
+_$ChatRoomsImpl _$$ChatRoomsImplFromJson(Map json) =>
+ _$ChatRoomsImpl(
+ data: (json['data'] as List)
+ .map((e) => ChatRoom.fromJson(e as Map))
+ .toList(),
+ lastPage: (json['last_page'] as num).toInt(),
+ currentPage: (json['current_page'] as num).toInt(),
+ );
+
+Map _$$ChatRoomsImplToJson(_$ChatRoomsImpl instance) =>
+ {
+ 'data': instance.data,
+ 'last_page': instance.lastPage,
+ 'current_page': instance.currentPage,
};
_$ChatRoomImpl _$$ChatRoomImplFromJson(Map json) =>
@@ -27,6 +43,7 @@ _$ChatRoomImpl _$$ChatRoomImplFromJson(Map json) =>
lastMessage: parseLastMessage(json['last_message']),
users: Users.fromJson(json['users'] as Map),
unreadMessagesCount: (json['unread_messages_count'] as num).toInt(),
+ chosenPlan: parseChosenPlan(json['chosen_plan']),
);
Map _$$ChatRoomImplToJson(_$ChatRoomImpl instance) =>
@@ -36,6 +53,7 @@ Map _$$ChatRoomImplToJson(_$ChatRoomImpl instance) =>
'last_message': instance.lastMessage,
'users': instance.users,
'unread_messages_count': instance.unreadMessagesCount,
+ 'chosen_plan': instance.chosenPlan,
};
_$UsersImpl _$$UsersImplFromJson(Map json) => _$UsersImpl(
diff --git a/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_cubit.dart b/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_cubit.dart
index a7f94802..1e456fc6 100644
--- a/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_cubit.dart
+++ b/lib/features/chat/presentation/bloc/chat_room_cubit/chat_room_cubit.dart
@@ -86,6 +86,18 @@ class ChatRoomCubit extends Cubit {
}
}
+ Future cancelChosenPlan({required String chatId, required int planId}) async {
+ try {
+ await chatRepository.cancelChosenPlan(id: planId);
+ final chatRoom = await chatRepository.getChatRoom(chatId);
+ emit(
+ (state as ChatRoomStateLoaded).copyWith(chatRoom: chatRoom),
+ );
+ } catch (e) {
+ emit(ChatRoomState.error(errorMessage: 'Ошибка получеия данных'));
+ }
+ }
+
Future _subscribeToChatChannel({
required String chatId,
}) async {
@@ -93,7 +105,7 @@ class ChatRoomCubit extends Cubit {
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 messagesList = [
@@ -111,7 +123,7 @@ class ChatRoomCubit extends Cubit {
);
});
- wsManager.clientTypingStream?.listen((event) {
+ typingSubscription = wsManager.clientTypingStream?.listen((event) {
emit(
ChatRoomState.loaded(
chatRoom: (state as ChatRoomStateLoaded).chatRoom,
@@ -180,6 +192,8 @@ class ChatRoomCubit extends Cubit {
@override
Future close() async {
wsManager.unsubscribeDirectChatChannel();
+ messagesSubscription?.cancel();
+ typingSubscription?.cancel();
super.close();
}
}
diff --git a/lib/features/chat/presentation/bloc/chats_cubit/chats_cubit.dart b/lib/features/chat/presentation/bloc/chats_cubit/chats_cubit.dart
index f165ca83..a4f0bbf2 100644
--- a/lib/features/chat/presentation/bloc/chats_cubit/chats_cubit.dart
+++ b/lib/features/chat/presentation/bloc/chats_cubit/chats_cubit.dart
@@ -1,5 +1,6 @@
import 'dart:async';
import 'dart:convert';
+import 'dart:developer';
import 'package:eatvio_app/core/enums/base_state.dart';
import 'package:eatvio_app/core/websockets/ws_manager.dart';
@@ -30,21 +31,24 @@ class ChatsCubit extends Cubit {
});
}
String? _query;
+ int page = 1;
+ late int lastPage;
Future getChatRoomsWithLoading({String? query}) async {
+ page = 1;
_query = query;
emit(state.copyWith(state: BaseState.loading));
try {
- final chatRooms = await chatRepository.getChatRoomPreviews(query: query);
- final unreadChats = chatRooms.where(
- (element) => element.unreadMessagesCount > 0,
- );
+ final chatRoomsPaginationModel = await chatRepository.getChatRooms(query: query);
+ final unreadChats = chatRoomsPaginationModel.unreadChatsCount;
+ lastPage = chatRoomsPaginationModel.chatRooms.lastPage + 1;
emit(
state.copyWith(
- chatRooms: chatRooms,
- chatsWithUnreadMessagesCount: unreadChats.length,
+ chatRooms: chatRoomsPaginationModel.chatRooms.data,
+ chatsWithUnreadMessagesCount: unreadChats,
state: BaseState.success,
),
);
+ page++;
} catch (e) {
emit(
state.copyWith(errorMessage: e.toString(), state: BaseState.error),
@@ -53,26 +57,55 @@ class ChatsCubit extends Cubit {
}
Future getChatRooms({String? query}) async {
+ page = 1;
_query = query;
try {
- final chatRooms = await chatRepository.getChatRoomPreviews(query: query);
- final unreadChats = chatRooms.where(
- (element) => element.unreadMessagesCount > 0,
- );
+ final chatRoomsPaginationModel = await chatRepository.getChatRooms(query: query);
+ final unreadChats = chatRoomsPaginationModel.unreadChatsCount;
+ lastPage = chatRoomsPaginationModel.chatRooms.lastPage + 1;
emit(
state.copyWith(
- chatRooms: chatRooms,
- chatsWithUnreadMessagesCount: unreadChats.length,
+ chatRooms: chatRoomsPaginationModel.chatRooms.data,
+ chatsWithUnreadMessagesCount: unreadChats,
state: BaseState.success,
),
);
- } catch (e) {
+ page++;
+ } catch (e, st) {
+ log(e.toString(), stackTrace: st);
emit(
state.copyWith(errorMessage: e.toString(), state: BaseState.error),
);
}
}
+ Future loadMoreChatRooms() async {
+ try {
+ if (state.isLoadingMoreChats || lastPage == page) return;
+ emit(state.copyWith(isLoadingMoreChats: true));
+ final chatRoomsPaginationModel = await chatRepository.getChatRooms(query: _query, page: page);
+ final unreadChats = chatRoomsPaginationModel.unreadChatsCount;
+ emit(
+ state.copyWith(
+ chatRooms: [...state.chatRooms, ...chatRoomsPaginationModel.chatRooms.data],
+ chatsWithUnreadMessagesCount: unreadChats,
+ state: BaseState.success,
+ isLoadingMoreChats: false,
+ ),
+ );
+ page++;
+ } catch (e, st) {
+ log(e.toString(), stackTrace: st);
+ emit(
+ state.copyWith(
+ errorMessage: e.toString(),
+ state: BaseState.error,
+ isLoadingMoreChats: false,
+ ),
+ );
+ }
+ }
+
void reduceUnreadMessagesCount({required String chatId, required int count}) {
bool isChatRead = false;
final updatedChatRooms = state.chatRooms.map((room) {
diff --git a/lib/features/chat/presentation/bloc/chats_cubit/chats_state.dart b/lib/features/chat/presentation/bloc/chats_cubit/chats_state.dart
index 24bde4fa..700542d0 100644
--- a/lib/features/chat/presentation/bloc/chats_cubit/chats_state.dart
+++ b/lib/features/chat/presentation/bloc/chats_cubit/chats_state.dart
@@ -1,5 +1,5 @@
import 'package:eatvio_app/core/enums/base_state.dart';
-import 'package:eatvio_app/features/chat/models/chat_room_preview_model.dart';
+import 'package:eatvio_app/features/chat/models/chat_room_pagination_model.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'chats_state.freezed.dart';
@@ -11,6 +11,7 @@ class ChatsState with _$ChatsState {
@Default(BaseState.initial) BaseState state,
@Default(0) int chatsWithUnreadMessagesCount,
@Default([]) List chatRooms,
+ @Default(false) bool isLoadingMoreChats,
@Default(null) String? errorMessage,
}) = _ChatsState;
diff --git a/lib/features/chat/presentation/bloc/chats_cubit/chats_state.freezed.dart b/lib/features/chat/presentation/bloc/chats_cubit/chats_state.freezed.dart
index 77fd911d..a2271568 100644
--- a/lib/features/chat/presentation/bloc/chats_cubit/chats_state.freezed.dart
+++ b/lib/features/chat/presentation/bloc/chats_cubit/chats_state.freezed.dart
@@ -19,6 +19,7 @@ mixin _$ChatsState {
BaseState get state => throw _privateConstructorUsedError;
int get chatsWithUnreadMessagesCount => throw _privateConstructorUsedError;
List get chatRooms => throw _privateConstructorUsedError;
+ bool get isLoadingMoreChats => throw _privateConstructorUsedError;
String? get errorMessage => throw _privateConstructorUsedError;
/// Create a copy of ChatsState
@@ -38,6 +39,7 @@ abstract class $ChatsStateCopyWith<$Res> {
{BaseState state,
int chatsWithUnreadMessagesCount,
List chatRooms,
+ bool isLoadingMoreChats,
String? errorMessage});
}
@@ -59,6 +61,7 @@ class _$ChatsStateCopyWithImpl<$Res, $Val extends ChatsState>
Object? state = null,
Object? chatsWithUnreadMessagesCount = null,
Object? chatRooms = null,
+ Object? isLoadingMoreChats = null,
Object? errorMessage = freezed,
}) {
return _then(_value.copyWith(
@@ -74,6 +77,10 @@ class _$ChatsStateCopyWithImpl<$Res, $Val extends ChatsState>
? _value.chatRooms
: chatRooms // ignore: cast_nullable_to_non_nullable
as List,
+ isLoadingMoreChats: null == isLoadingMoreChats
+ ? _value.isLoadingMoreChats
+ : isLoadingMoreChats // ignore: cast_nullable_to_non_nullable
+ as bool,
errorMessage: freezed == errorMessage
? _value.errorMessage
: errorMessage // ignore: cast_nullable_to_non_nullable
@@ -94,6 +101,7 @@ abstract class _$$ChatsStateImplCopyWith<$Res>
{BaseState state,
int chatsWithUnreadMessagesCount,
List chatRooms,
+ bool isLoadingMoreChats,
String? errorMessage});
}
@@ -113,6 +121,7 @@ class __$$ChatsStateImplCopyWithImpl<$Res>
Object? state = null,
Object? chatsWithUnreadMessagesCount = null,
Object? chatRooms = null,
+ Object? isLoadingMoreChats = null,
Object? errorMessage = freezed,
}) {
return _then(_$ChatsStateImpl(
@@ -128,6 +137,10 @@ class __$$ChatsStateImplCopyWithImpl<$Res>
? _value._chatRooms
: chatRooms // ignore: cast_nullable_to_non_nullable
as List,
+ isLoadingMoreChats: null == isLoadingMoreChats
+ ? _value.isLoadingMoreChats
+ : isLoadingMoreChats // ignore: cast_nullable_to_non_nullable
+ as bool,
errorMessage: freezed == errorMessage
? _value.errorMessage
: errorMessage // ignore: cast_nullable_to_non_nullable
@@ -143,6 +156,7 @@ class _$ChatsStateImpl implements _ChatsState {
{this.state = BaseState.initial,
this.chatsWithUnreadMessagesCount = 0,
final List chatRooms = const [],
+ this.isLoadingMoreChats = false,
this.errorMessage = null})
: _chatRooms = chatRooms;
@@ -161,13 +175,16 @@ class _$ChatsStateImpl implements _ChatsState {
return EqualUnmodifiableListView(_chatRooms);
}
+ @override
+ @JsonKey()
+ final bool isLoadingMoreChats;
@override
@JsonKey()
final String? errorMessage;
@override
String toString() {
- return 'ChatsState(state: $state, chatsWithUnreadMessagesCount: $chatsWithUnreadMessagesCount, chatRooms: $chatRooms, errorMessage: $errorMessage)';
+ return 'ChatsState(state: $state, chatsWithUnreadMessagesCount: $chatsWithUnreadMessagesCount, chatRooms: $chatRooms, isLoadingMoreChats: $isLoadingMoreChats, errorMessage: $errorMessage)';
}
@override
@@ -182,6 +199,8 @@ class _$ChatsStateImpl implements _ChatsState {
chatsWithUnreadMessagesCount) &&
const DeepCollectionEquality()
.equals(other._chatRooms, _chatRooms) &&
+ (identical(other.isLoadingMoreChats, isLoadingMoreChats) ||
+ other.isLoadingMoreChats == isLoadingMoreChats) &&
(identical(other.errorMessage, errorMessage) ||
other.errorMessage == errorMessage));
}
@@ -192,6 +211,7 @@ class _$ChatsStateImpl implements _ChatsState {
state,
chatsWithUnreadMessagesCount,
const DeepCollectionEquality().hash(_chatRooms),
+ isLoadingMoreChats,
errorMessage);
/// Create a copy of ChatsState
@@ -208,6 +228,7 @@ abstract class _ChatsState implements ChatsState {
{final BaseState state,
final int chatsWithUnreadMessagesCount,
final List chatRooms,
+ final bool isLoadingMoreChats,
final String? errorMessage}) = _$ChatsStateImpl;
@override
@@ -217,6 +238,8 @@ abstract class _ChatsState implements ChatsState {
@override
List get chatRooms;
@override
+ bool get isLoadingMoreChats;
+ @override
String? get errorMessage;
/// Create a copy of ChatsState
diff --git a/lib/features/chat/presentation/pages/chat_screen.dart b/lib/features/chat/presentation/pages/chat_screen.dart
index 4144fbd5..c9a28d32 100644
--- a/lib/features/chat/presentation/pages/chat_screen.dart
+++ b/lib/features/chat/presentation/pages/chat_screen.dart
@@ -11,18 +11,20 @@ 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';
class ChatScreen extends StatefulWidget {
final String chatId;
- final ChatsCubit chatsCubit;
const ChatScreen({
required this.chatId,
- required this.chatsCubit,
super.key,
});
@@ -36,6 +38,7 @@ class _ChatScreenState extends State {
final ChatRoomCubit chatRoomCubit = sl();
final List<({int id, int index})> unreadMessagesIds = [];
final List<({int id, int index})> unreadMessagesIdsCopy = [];
+ final showableChatBadgeStates = ChosenPlanStateEnum.getShowableChatBadgeStates();
@override
void initState() {
@@ -53,6 +56,7 @@ class _ChatScreenState extends State {
@override
void dispose() {
scrollController.dispose();
+ chatRoomCubit.close();
super.dispose();
}
@@ -80,6 +84,9 @@ class _ChatScreenState extends State {
}
_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(
@@ -88,12 +95,12 @@ class _ChatScreenState extends State {
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,
@@ -103,7 +110,7 @@ class _ChatScreenState extends State {
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,
@@ -116,7 +123,7 @@ class _ChatScreenState extends State {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
- state.chatRoom.users['to_chat_user']!.name,
+ state.chatRoom.users.receiver.name,
style: CustomTextStyles.titleSmallBold.copyWith(
color: PrimaryColors().black,
),
@@ -138,28 +145,38 @@ class _ChatScreenState extends State {
),
),
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),
@@ -174,7 +191,9 @@ class _ChatScreenState extends State {
() async {
final result = await context.read().markMessagesAsRead(state.chatRoom.id, unreadMessagesIdsCopy);
if (!result) return;
- widget.chatsCubit.reduceUnreadMessagesCount(chatId: state.chatRoom.id, count: unreadMessagesIdsCopy.length);
+ context
+ .read()
+ .reduceUnreadMessagesCount(chatId: state.chatRoom.id, count: unreadMessagesIdsCopy.length);
unreadMessagesIdsCopy.clear();
},
);
@@ -191,7 +210,7 @@ class _ChatScreenState extends State {
],
);
}
- 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) {
@@ -203,7 +222,7 @@ class _ChatScreenState extends State {
() async {
final result = await context.read().markMessagesAsRead(state.chatRoom.id, unreadMessagesIds);
if (!result) return;
- widget.chatsCubit.reduceUnreadMessagesCount(chatId: state.chatRoom.id, count: unreadMessagesIds.length);
+ context.read().reduceUnreadMessagesCount(chatId: state.chatRoom.id, count: unreadMessagesIds.length);
unreadMessagesIds.clear();
},
);
@@ -217,157 +236,208 @@ class _ChatScreenState extends State {
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().cancelChosenPlan(chatId: state.chatRoom.id, planId: chosenPlan.id);
+ },
+ ),
+ ],
),
),
- ],
+ ),
+ ),
+ 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 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 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),
- ],
- ),
- ),
],
),
),
diff --git a/lib/features/chat/presentation/pages/chats_screen.dart b/lib/features/chat/presentation/pages/chats_screen.dart
index 18f2b581..75882083 100644
--- a/lib/features/chat/presentation/pages/chats_screen.dart
+++ b/lib/features/chat/presentation/pages/chats_screen.dart
@@ -1,5 +1,6 @@
import 'package:easy_debounce/easy_debounce.dart';
import 'package:eatvio_app/core/enums/base_state.dart';
+import 'package:eatvio_app/core/utils/pagination_utils.dart';
import 'package:eatvio_app/core/widgets/data_error_widget.dart';
import 'package:eatvio_app/core/widgets/loader.dart';
import 'package:eatvio_app/features/chat/presentation/bloc/chats_cubit/chats_cubit.dart';
@@ -16,7 +17,7 @@ class ChatsScreen extends StatefulWidget {
State createState() => _ChatsScreenState();
}
-class _ChatsScreenState extends State {
+class _ChatsScreenState extends State {
final searchController = TextEditingController();
Widget build(BuildContext context) {
@@ -65,45 +66,40 @@ class _ChatsScreenState extends State {
),
];
},
- body: stateBuilder(state),
+ body: switch (state.state) {
+ BaseState.error => DataErrorWidget(onReload: () => context.read().getChatRooms()),
+ BaseState.success => _buildChatList(context, state),
+ _ => const Loader(),
+ },
),
);
},
);
}
- stateBuilder(ChatsState state) {
- if (state.state == BaseState.loading) {
- return Scaffold(
- body: const Loader(),
- );
- } else if (state.state == BaseState.success) {
- return _buildChatList(context, state);
- } else if (state.state == BaseState.error) {
- return Scaffold(
- body: DataErrorWidget(onReload: () => context.read().getChatRooms()),
- );
- } else {
- return Scaffold(
- body: const Loader(),
- );
- }
- }
-
_buildChatList(BuildContext context, ChatsState state) {
- return ListView.separated(
- padding: EdgeInsets.all(16),
- shrinkWrap: true,
- physics: NeverScrollableScrollPhysics(),
- separatorBuilder: (context, index) {
- return SizedBox(
- height: 8,
- );
- },
- itemCount: state.chatRooms.length,
- itemBuilder: (context, index) {
- return ChatEntryWidget(chatRoom: state.chatRooms[index]);
+ return NotificationListener(
+ onNotification: (notification) {
+ loadNewContent(notification, context.read().loadMoreChatRooms);
+ return false;
},
+ child: ListView.separated(
+ padding: EdgeInsets.all(16),
+ shrinkWrap: true,
+ physics: NeverScrollableScrollPhysics(),
+ separatorBuilder: (context, index) {
+ return SizedBox(
+ height: 8,
+ );
+ },
+ itemCount: state.isLoadingMoreChats ? state.chatRooms.length + 1 : state.chatRooms.length,
+ itemBuilder: (context, index) {
+ if (index == state.chatRooms.length) {
+ return Center(child: Loader());
+ }
+ return ChatEntryWidget(chatRoom: state.chatRooms[index]);
+ },
+ ),
);
}
}
diff --git a/lib/features/chat/presentation/widgets/chat_entry_widget.dart b/lib/features/chat/presentation/widgets/chat_entry_widget.dart
index 61e6ea17..4e1eea67 100644
--- a/lib/features/chat/presentation/widgets/chat_entry_widget.dart
+++ b/lib/features/chat/presentation/widgets/chat_entry_widget.dart
@@ -1,10 +1,8 @@
import 'package:eatvio_app/core/utils/date_time_utils.dart';
-import 'package:eatvio_app/features/chat/models/chat_room_preview_model.dart';
+import 'package:eatvio_app/features/chat/models/chat_room_pagination_model.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/bloc/chats_cubit/chats_cubit.dart';
import 'package:flutter/material.dart';
-import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
class ChatEntryWidget extends StatefulWidget {
@@ -28,7 +26,6 @@ class _ChatEntryWidgetState extends State {
'chatScreen',
extra: {
'chatId': widget.chatRoom.id.toString(),
- 'chatsCubit': context.read(),
},
),
child: Ink(
diff --git a/lib/features/chat/presentation/widgets/notification_banner.dart b/lib/features/chat/presentation/widgets/notification_banner.dart
new file mode 100644
index 00000000..5d3c8097
--- /dev/null
+++ b/lib/features/chat/presentation/widgets/notification_banner.dart
@@ -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 }
diff --git a/lib/features/chat/presentation/widgets/order_card.dart b/lib/features/chat/presentation/widgets/order_card.dart
new file mode 100644
index 00000000..fdb8180d
--- /dev/null
+++ b/lib/features/chat/presentation/widgets/order_card.dart
@@ -0,0 +1,138 @@
+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 StatefulWidget {
+ final PlanModel plan;
+ final String optionType;
+ final bool isUserView;
+ final Future Function() onCancel;
+ const OrderCard({super.key, required this.plan, required this.isUserView, required this.optionType, required this.onCancel});
+
+ @override
+ State createState() => _OrderCardState();
+}
+
+class _OrderCardState extends State {
+ 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),
+ ),
+ ),
+ ],
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/features/chat/repositories/chat_repository.dart b/lib/features/chat/repositories/chat_repository.dart
index 9458d9f5..c6b1bf8d 100644
--- a/lib/features/chat/repositories/chat_repository.dart
+++ b/lib/features/chat/repositories/chat_repository.dart
@@ -5,7 +5,7 @@ import 'package:dio/dio.dart';
import 'package:eatvio_app/features/chat/models/chat_message_model.dart';
import 'package:eatvio_app/features/chat/models/chat_messages_model.dart';
import 'package:eatvio_app/features/chat/models/chat_room_model.dart';
-import 'package:eatvio_app/features/chat/models/chat_room_preview_model.dart';
+import 'package:eatvio_app/features/chat/models/chat_room_pagination_model.dart';
import 'package:eatvio_app/features/chat/services/chat_service.dart';
import 'package:http_parser/http_parser.dart';
@@ -62,9 +62,9 @@ class ChatRepository {
}
}
- Future> getChatRoomPreviews({String? query}) async {
+ Future getChatRooms({String? query, int page = 1}) async {
try {
- return (await chatService.getChatRoomPreviews(query: query)).chatRooms;
+ return (await chatService.getChatRooms(query: query, page: page));
} catch (e) {
rethrow;
}
@@ -93,4 +93,14 @@ class ChatRepository {
rethrow;
}
}
+
+ Future cancelChosenPlan({
+ required int id,
+ }) async {
+ try {
+ await chatService.cancelChosenPlan(id: id);
+ } catch (e) {
+ rethrow;
+ }
+ }
}
diff --git a/lib/features/chat/services/chat_service.dart b/lib/features/chat/services/chat_service.dart
index 2eb2423f..3eae96fd 100644
--- a/lib/features/chat/services/chat_service.dart
+++ b/lib/features/chat/services/chat_service.dart
@@ -1,7 +1,7 @@
import 'package:dio/dio.dart';
import 'package:eatvio_app/features/chat/models/chat_messages_model.dart';
import 'package:eatvio_app/features/chat/models/chat_room_model.dart';
-import 'package:eatvio_app/features/chat/models/chat_room_preview_model.dart';
+import 'package:eatvio_app/features/chat/models/chat_room_pagination_model.dart';
import 'package:retrofit/retrofit.dart';
part 'chat_service.g.dart';
@@ -11,7 +11,8 @@ abstract class ChatService {
factory ChatService(Dio dio, {String baseUrl}) = _ChatService;
@GET('/api/chat/index')
- Future getChatRoomPreviews({
+ Future getChatRooms({
+ @Query('page') required int page,
@Query('find') String? query,
});
@@ -40,5 +41,13 @@ abstract class ChatService {
});
@POST('/api/chat/{id}/messages/markAsRead')
- Future markMessagesAsRead({@Path() required String id, @Body() required Map> body});
+ Future markMessagesAsRead({
+ @Path() required String id,
+ @Body() required Map> body,
+ });
+
+ @POST('/api/chosen_plans/{id}/cancel')
+ Future cancelChosenPlan({
+ @Path() required int id,
+ });
}
diff --git a/lib/features/chat/services/chat_service.g.dart b/lib/features/chat/services/chat_service.g.dart
index 4cd570df..849f0ac3 100644
--- a/lib/features/chat/services/chat_service.g.dart
+++ b/lib/features/chat/services/chat_service.g.dart
@@ -18,13 +18,16 @@ class _ChatService implements ChatService {
final ParseErrorLogger? errorLogger;
@override
- Future getChatRoomPreviews({String? query}) async {
+ Future getChatRooms({
+ required int page,
+ String? query,
+ }) async {
final _extra = {};
- final queryParameters = {r'find': query};
+ final queryParameters = {r'page': page, r'find': query};
queryParameters.removeWhere((k, v) => v == null);
final _headers = {};
const Map? _data = null;
- final _options = _setStreamType(
+ final _options = _setStreamType(
Options(method: 'GET', headers: _headers, extra: _extra)
.compose(
_dio.options,
@@ -35,9 +38,9 @@ class _ChatService implements ChatService {
.copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)),
);
final _result = await _dio.fetch