forked from eatvio/eatvio_app
added unread messages and unread chats counters
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import 'package:eatvio_app/core/initialization_cubit/ws_manager.dart';
|
||||
import 'package:eatvio_app/core/websockets/ws_manager.dart';
|
||||
import 'package:eatvio_app/core/locator_service.dart';
|
||||
import 'package:eatvio_app/core/token_storage.dart';
|
||||
import 'package:eatvio_app/features/auth/auth_screen/auth_screen.dart';
|
||||
@@ -6,8 +6,9 @@ import 'package:eatvio_app/features/blog_post/presentation/pages/blog_post_scree
|
||||
import 'package:eatvio_app/features/blog_post_create/presentation/pages/blog_post_create_screen.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/chat_select_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';
|
||||
import 'package:eatvio_app/features/complaining/presentation/complaining_screen.dart';
|
||||
import 'package:eatvio_app/features/consultant/become_consultant/presentation/pages/become_consultant_screen.dart';
|
||||
@@ -112,7 +113,7 @@ class AppRouter {
|
||||
GoRoute(
|
||||
path: '/chat-select-screen',
|
||||
name: 'chatSelectScreen',
|
||||
pageBuilder: (context, state) => NoTransitionPage(child: ChatSelectScreen()),
|
||||
pageBuilder: (context, state) => NoTransitionPage(child: ChatsScreen()),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/notifications-screen',
|
||||
@@ -204,7 +205,12 @@ class AppRouter {
|
||||
GoRoute(
|
||||
path: '/chat-screen',
|
||||
name: 'chatScreen',
|
||||
builder: (context, state) => ChatScreen(chatId: state.extra as String),
|
||||
builder: (context, state) {
|
||||
final data = state.extra as Map<String, dynamic>;
|
||||
final chatsCubit = data['chatsCubit'] as ChatsCubit;
|
||||
final chatId = data['chatId'] as String;
|
||||
return ChatScreen(chatId: chatId, chatsCubit: chatsCubit,);
|
||||
},
|
||||
),
|
||||
GoRoute(
|
||||
path: '/settings-screen',
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:eatvio_app/core/const.dart';
|
||||
import 'package:eatvio_app/core/initialization_cubit/ws_manager.dart';
|
||||
import 'package:eatvio_app/core/initialization_cubit/ws_service.dart';
|
||||
import 'package:eatvio_app/core/websockets/ws_manager.dart';
|
||||
import 'package:eatvio_app/core/websockets/ws_service.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/cubit/create_diet_cubit.dart';
|
||||
import 'package:eatvio_app/features/create_diet/repositories/create_diet_repository.dart';
|
||||
import 'package:eatvio_app/features/create_diet/services/create_diet_service.dart';
|
||||
@@ -18,7 +18,7 @@ import 'package:eatvio_app/features/calendar/presentation/bloc/calendar_cubit.da
|
||||
import 'package:eatvio_app/features/calendar/repositories/calendar_repository.dart';
|
||||
import 'package:eatvio_app/features/calendar/services/calendar_service.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/bloc/chat_room_cubit/chat_room_cubit.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/bloc/chat_select_cubit/chat_select_cubit.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/bloc/chats_cubit/chats_cubit.dart';
|
||||
import 'package:eatvio_app/features/chat/repositories/chat_repository.dart';
|
||||
import 'package:eatvio_app/features/chat/services/chat_service.dart';
|
||||
import 'package:eatvio_app/features/consultant/become_consultant/presentation/bloc/register_consultant_cubit/register_consultant_cubit.dart';
|
||||
@@ -90,7 +90,7 @@ Future<void> init() async {
|
||||
sl.registerFactory<profilePlans.PlansCubit>(() => profilePlans.PlansCubit(plansRepository: sl()));
|
||||
sl.registerFactory<DietsCubit>(() => DietsCubit(feedRepository: sl(), dietsRepository: sl()));
|
||||
sl.registerFactory<CommentsCubit>(() => CommentsCubit(feedRepository: sl()));
|
||||
sl.registerFactory<ChatSelectCubit>(() => ChatSelectCubit(chatRepository: sl()));
|
||||
sl.registerFactory<ChatsCubit>(() => ChatsCubit(chatRepository: sl(), wsManager: sl(), profileRepository: sl()));
|
||||
sl.registerFactory<PlansCubit>(() => PlansCubit(feedRepository: sl(), planRepository: sl()));
|
||||
sl.registerFactory<SettingsCubit>(() => SettingsCubit(profileRepository: sl(), settingsRepository: sl()));
|
||||
sl.registerFactory<RegisterConsultantCubit>(() => RegisterConsultantCubit(consultantRepository: sl()));
|
||||
|
||||
@@ -230,10 +230,10 @@ abstract class TextStyles {
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 1.255,
|
||||
);
|
||||
);
|
||||
|
||||
static const textFS10FW500 = TextStyle(
|
||||
fontSize: 12,
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 1.255,
|
||||
);
|
||||
|
||||
@@ -3,3 +3,10 @@ enum ProductType {
|
||||
plan,
|
||||
recipe
|
||||
}
|
||||
|
||||
enum BaseState {
|
||||
loading,
|
||||
error,
|
||||
initial,
|
||||
success
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import 'dart:developer';
|
||||
|
||||
import 'package:dart_pusher_channels/dart_pusher_channels.dart';
|
||||
import 'package:eatvio_app/core/const.dart';
|
||||
import 'package:eatvio_app/core/initialization_cubit/ws_service.dart';
|
||||
import 'package:eatvio_app/core/websockets/ws_service.dart';
|
||||
import 'package:eatvio_app/core/token_storage.dart';
|
||||
|
||||
class WsManager {
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:eatvio_app/core/app_router.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/widgets/bottom_sheet_handler_bar.dart';
|
||||
@@ -34,7 +35,7 @@ class SuccessPublishedDietBottomSheet extends StatelessWidget {
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: CustomOutlinedButton(
|
||||
onPressed: () {
|
||||
GoRouter.of(context).pop();
|
||||
AppRouter.navigatorKey.currentContext?.pop();
|
||||
},
|
||||
text: 'Хорошо',
|
||||
height: 52,
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:eatvio_app/core/initialization_cubit/ws_manager.dart';
|
||||
import 'package:eatvio_app/core/websockets/ws_manager.dart';
|
||||
import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_state.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@ import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/noti
|
||||
import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_state.dart';
|
||||
import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_cubit.dart';
|
||||
import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_state.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/bloc/chats_cubit/chats_cubit.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/bloc/chats_cubit/chats_state.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -136,15 +138,19 @@ class _BottomNavigationBarWidgetState extends State<BottomNavigationBarWidget> {
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
label: s.chat,
|
||||
icon: BlocBuilder<NewMessagesCubit, NewMessagesState>(
|
||||
builder: (BuildContext context, NewMessagesState state) {
|
||||
icon: BlocBuilder<ChatsCubit, ChatsState>(
|
||||
builder: (BuildContext context, ChatsState state) {
|
||||
final hasUnreadMessages = state.chatsWithUnreadMessagesCount > 0;
|
||||
return badges.Badge(
|
||||
position: badges.BadgePosition.topEnd(),
|
||||
badgeAnimation: badges.BadgeAnimation.fade(),
|
||||
badgeStyle: badges.BadgeStyle(
|
||||
badgeColor: hasUnreadMessages ? Colors.red : Colors.transparent,
|
||||
),
|
||||
badgeContent: Text(
|
||||
(state is NewMessagesStateLoaded) ? state.messagesCount.toString() : '0',
|
||||
hasUnreadMessages ? state.chatsWithUnreadMessagesCount.toString() : '',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
color: hasUnreadMessages ? Colors.white : Colors.transparent,
|
||||
fontSize: 8,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:eatvio_app/features/feed/models/feed_blog_post_model.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'chat_message_model.freezed.dart';
|
||||
@@ -10,7 +11,10 @@ class ChatMessageModel with _$ChatMessageModel {
|
||||
required String data,
|
||||
@JsonKey(name: 'media_data') required List<dynamic>? mediaData,
|
||||
@JsonKey(name: 'author_id') required int authorId,
|
||||
@JsonKey(name: 'updated_at') required String updatedAt,
|
||||
@JsonKey(name: 'updated_at', fromJson: parseDate) required DateTime updatedAt,
|
||||
@JsonKey(name: 'read_by_to_user', defaultValue: false) required bool isRead,
|
||||
@JsonKey(name: 'is_author_message_auth_user') required bool? isCurrentUserAuthor,
|
||||
@JsonKey(name: 'room_id') required String? roomId,
|
||||
}) = _ChatMessageModel;
|
||||
|
||||
factory ChatMessageModel.fromJson(Map<String, Object?> json) => _$ChatMessageModelFromJson(json);
|
||||
|
||||
@@ -26,8 +26,14 @@ mixin _$ChatMessageModel {
|
||||
List<dynamic>? get mediaData => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'author_id')
|
||||
int get authorId => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'updated_at')
|
||||
String get updatedAt => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'updated_at', fromJson: parseDate)
|
||||
DateTime get updatedAt => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'read_by_to_user', defaultValue: false)
|
||||
bool get isRead => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'is_author_message_auth_user')
|
||||
bool? get isCurrentUserAuthor => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'room_id')
|
||||
String? get roomId => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this ChatMessageModel to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@@ -50,7 +56,10 @@ abstract class $ChatMessageModelCopyWith<$Res> {
|
||||
String data,
|
||||
@JsonKey(name: 'media_data') List<dynamic>? mediaData,
|
||||
@JsonKey(name: 'author_id') int authorId,
|
||||
@JsonKey(name: 'updated_at') String updatedAt});
|
||||
@JsonKey(name: 'updated_at', fromJson: parseDate) DateTime updatedAt,
|
||||
@JsonKey(name: 'read_by_to_user', defaultValue: false) bool isRead,
|
||||
@JsonKey(name: 'is_author_message_auth_user') bool? isCurrentUserAuthor,
|
||||
@JsonKey(name: 'room_id') String? roomId});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -73,6 +82,9 @@ class _$ChatMessageModelCopyWithImpl<$Res, $Val extends ChatMessageModel>
|
||||
Object? mediaData = freezed,
|
||||
Object? authorId = null,
|
||||
Object? updatedAt = null,
|
||||
Object? isRead = null,
|
||||
Object? isCurrentUserAuthor = freezed,
|
||||
Object? roomId = freezed,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
id: null == id
|
||||
@@ -94,7 +106,19 @@ class _$ChatMessageModelCopyWithImpl<$Res, $Val extends ChatMessageModel>
|
||||
updatedAt: null == updatedAt
|
||||
? _value.updatedAt
|
||||
: updatedAt // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
as DateTime,
|
||||
isRead: null == isRead
|
||||
? _value.isRead
|
||||
: isRead // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
isCurrentUserAuthor: freezed == isCurrentUserAuthor
|
||||
? _value.isCurrentUserAuthor
|
||||
: isCurrentUserAuthor // ignore: cast_nullable_to_non_nullable
|
||||
as bool?,
|
||||
roomId: freezed == roomId
|
||||
? _value.roomId
|
||||
: roomId // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
@@ -112,7 +136,10 @@ abstract class _$$ChatMessageModelImplCopyWith<$Res>
|
||||
String data,
|
||||
@JsonKey(name: 'media_data') List<dynamic>? mediaData,
|
||||
@JsonKey(name: 'author_id') int authorId,
|
||||
@JsonKey(name: 'updated_at') String updatedAt});
|
||||
@JsonKey(name: 'updated_at', fromJson: parseDate) DateTime updatedAt,
|
||||
@JsonKey(name: 'read_by_to_user', defaultValue: false) bool isRead,
|
||||
@JsonKey(name: 'is_author_message_auth_user') bool? isCurrentUserAuthor,
|
||||
@JsonKey(name: 'room_id') String? roomId});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -133,6 +160,9 @@ class __$$ChatMessageModelImplCopyWithImpl<$Res>
|
||||
Object? mediaData = freezed,
|
||||
Object? authorId = null,
|
||||
Object? updatedAt = null,
|
||||
Object? isRead = null,
|
||||
Object? isCurrentUserAuthor = freezed,
|
||||
Object? roomId = freezed,
|
||||
}) {
|
||||
return _then(_$ChatMessageModelImpl(
|
||||
id: null == id
|
||||
@@ -154,7 +184,19 @@ class __$$ChatMessageModelImplCopyWithImpl<$Res>
|
||||
updatedAt: null == updatedAt
|
||||
? _value.updatedAt
|
||||
: updatedAt // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
as DateTime,
|
||||
isRead: null == isRead
|
||||
? _value.isRead
|
||||
: isRead // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
isCurrentUserAuthor: freezed == isCurrentUserAuthor
|
||||
? _value.isCurrentUserAuthor
|
||||
: isCurrentUserAuthor // ignore: cast_nullable_to_non_nullable
|
||||
as bool?,
|
||||
roomId: freezed == roomId
|
||||
? _value.roomId
|
||||
: roomId // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -167,7 +209,12 @@ class _$ChatMessageModelImpl implements _ChatMessageModel {
|
||||
required this.data,
|
||||
@JsonKey(name: 'media_data') required final List<dynamic>? mediaData,
|
||||
@JsonKey(name: 'author_id') required this.authorId,
|
||||
@JsonKey(name: 'updated_at') required this.updatedAt})
|
||||
@JsonKey(name: 'updated_at', fromJson: parseDate) required this.updatedAt,
|
||||
@JsonKey(name: 'read_by_to_user', defaultValue: false)
|
||||
required this.isRead,
|
||||
@JsonKey(name: 'is_author_message_auth_user')
|
||||
required this.isCurrentUserAuthor,
|
||||
@JsonKey(name: 'room_id') required this.roomId})
|
||||
: _mediaData = mediaData;
|
||||
|
||||
factory _$ChatMessageModelImpl.fromJson(Map<String, dynamic> json) =>
|
||||
@@ -192,12 +239,21 @@ class _$ChatMessageModelImpl implements _ChatMessageModel {
|
||||
@JsonKey(name: 'author_id')
|
||||
final int authorId;
|
||||
@override
|
||||
@JsonKey(name: 'updated_at')
|
||||
final String updatedAt;
|
||||
@JsonKey(name: 'updated_at', fromJson: parseDate)
|
||||
final DateTime updatedAt;
|
||||
@override
|
||||
@JsonKey(name: 'read_by_to_user', defaultValue: false)
|
||||
final bool isRead;
|
||||
@override
|
||||
@JsonKey(name: 'is_author_message_auth_user')
|
||||
final bool? isCurrentUserAuthor;
|
||||
@override
|
||||
@JsonKey(name: 'room_id')
|
||||
final String? roomId;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ChatMessageModel(id: $id, data: $data, mediaData: $mediaData, authorId: $authorId, updatedAt: $updatedAt)';
|
||||
return 'ChatMessageModel(id: $id, data: $data, mediaData: $mediaData, authorId: $authorId, updatedAt: $updatedAt, isRead: $isRead, isCurrentUserAuthor: $isCurrentUserAuthor, roomId: $roomId)';
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -212,13 +268,25 @@ class _$ChatMessageModelImpl implements _ChatMessageModel {
|
||||
(identical(other.authorId, authorId) ||
|
||||
other.authorId == authorId) &&
|
||||
(identical(other.updatedAt, updatedAt) ||
|
||||
other.updatedAt == updatedAt));
|
||||
other.updatedAt == updatedAt) &&
|
||||
(identical(other.isRead, isRead) || other.isRead == isRead) &&
|
||||
(identical(other.isCurrentUserAuthor, isCurrentUserAuthor) ||
|
||||
other.isCurrentUserAuthor == isCurrentUserAuthor) &&
|
||||
(identical(other.roomId, roomId) || other.roomId == roomId));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, id, data,
|
||||
const DeepCollectionEquality().hash(_mediaData), authorId, updatedAt);
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
id,
|
||||
data,
|
||||
const DeepCollectionEquality().hash(_mediaData),
|
||||
authorId,
|
||||
updatedAt,
|
||||
isRead,
|
||||
isCurrentUserAuthor,
|
||||
roomId);
|
||||
|
||||
/// Create a copy of ChatMessageModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -243,7 +311,13 @@ abstract class _ChatMessageModel implements ChatMessageModel {
|
||||
required final String data,
|
||||
@JsonKey(name: 'media_data') required final List<dynamic>? mediaData,
|
||||
@JsonKey(name: 'author_id') required final int authorId,
|
||||
@JsonKey(name: 'updated_at') required final String updatedAt}) =
|
||||
@JsonKey(name: 'updated_at', fromJson: parseDate)
|
||||
required final DateTime updatedAt,
|
||||
@JsonKey(name: 'read_by_to_user', defaultValue: false)
|
||||
required final bool isRead,
|
||||
@JsonKey(name: 'is_author_message_auth_user')
|
||||
required final bool? isCurrentUserAuthor,
|
||||
@JsonKey(name: 'room_id') required final String? roomId}) =
|
||||
_$ChatMessageModelImpl;
|
||||
|
||||
factory _ChatMessageModel.fromJson(Map<String, dynamic> json) =
|
||||
@@ -260,8 +334,17 @@ abstract class _ChatMessageModel implements ChatMessageModel {
|
||||
@JsonKey(name: 'author_id')
|
||||
int get authorId;
|
||||
@override
|
||||
@JsonKey(name: 'updated_at')
|
||||
String get updatedAt;
|
||||
@JsonKey(name: 'updated_at', fromJson: parseDate)
|
||||
DateTime get updatedAt;
|
||||
@override
|
||||
@JsonKey(name: 'read_by_to_user', defaultValue: false)
|
||||
bool get isRead;
|
||||
@override
|
||||
@JsonKey(name: 'is_author_message_auth_user')
|
||||
bool? get isCurrentUserAuthor;
|
||||
@override
|
||||
@JsonKey(name: 'room_id')
|
||||
String? get roomId;
|
||||
|
||||
/// Create a copy of ChatMessageModel
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
|
||||
@@ -13,7 +13,10 @@ _$ChatMessageModelImpl _$$ChatMessageModelImplFromJson(
|
||||
data: json['data'] as String,
|
||||
mediaData: json['media_data'] as List<dynamic>?,
|
||||
authorId: (json['author_id'] as num).toInt(),
|
||||
updatedAt: json['updated_at'] as String,
|
||||
updatedAt: parseDate(json['updated_at'] as String),
|
||||
isRead: json['read_by_to_user'] as bool? ?? false,
|
||||
isCurrentUserAuthor: json['is_author_message_auth_user'] as bool?,
|
||||
roomId: json['room_id'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$ChatMessageModelImplToJson(
|
||||
@@ -23,5 +26,8 @@ Map<String, dynamic> _$$ChatMessageModelImplToJson(
|
||||
'data': instance.data,
|
||||
'media_data': instance.mediaData,
|
||||
'author_id': instance.authorId,
|
||||
'updated_at': instance.updatedAt,
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'read_by_to_user': instance.isRead,
|
||||
'is_author_message_auth_user': instance.isCurrentUserAuthor,
|
||||
'room_id': instance.roomId,
|
||||
};
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:eatvio_app/features/chat/models/chat_message_model.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'chat_room_preview_model.freezed.dart';
|
||||
@@ -17,26 +18,19 @@ class ChatRoom with _$ChatRoom {
|
||||
const factory ChatRoom({
|
||||
@JsonKey(name: "id") required String id,
|
||||
@JsonKey(name: "room_name") required String roomName,
|
||||
@JsonKey(name: "last_message") required dynamic lastMessage,
|
||||
@JsonKey(name: "last_message", fromJson: parseLastMessage) required ChatMessageModel? lastMessage,
|
||||
@JsonKey(name: "users") required Users users,
|
||||
@JsonKey(name: "unread_messages_count") required int unreadMessagesCount,
|
||||
}) = _ChatRoom;
|
||||
|
||||
factory ChatRoom.fromJson(Map<String, dynamic> json) => _$ChatRoomFromJson(json);
|
||||
}
|
||||
|
||||
@freezed
|
||||
class LastMessageClass with _$LastMessageClass {
|
||||
const factory LastMessageClass({
|
||||
@JsonKey(name: "id") required int id,
|
||||
@JsonKey(name: "data") required String data,
|
||||
@JsonKey(name: "media_data") required List<dynamic> mediaData,
|
||||
@JsonKey(name: "author_id") required int authorId,
|
||||
@JsonKey(name: "is_author_message_auth_user") required bool isAuthorMessageAuthUser,
|
||||
@JsonKey(name: "read_by_to_user") required bool readByToUser,
|
||||
@JsonKey(name: "updated_at") required DateTime updatedAt,
|
||||
}) = _LastMessageClass;
|
||||
|
||||
factory LastMessageClass.fromJson(Map<String, dynamic> json) => _$LastMessageClassFromJson(json);
|
||||
ChatMessageModel? parseLastMessage(dynamic json) {
|
||||
if (json is List) {
|
||||
return null;
|
||||
}
|
||||
return ChatMessageModel.fromJson(json);
|
||||
}
|
||||
|
||||
@freezed
|
||||
|
||||
@@ -190,10 +190,12 @@ mixin _$ChatRoom {
|
||||
String get id => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "room_name")
|
||||
String get roomName => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "last_message")
|
||||
dynamic get lastMessage => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "last_message", fromJson: parseLastMessage)
|
||||
ChatMessageModel? get lastMessage => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "users")
|
||||
Users get users => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "unread_messages_count")
|
||||
int get unreadMessagesCount => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this ChatRoom to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@@ -213,9 +215,12 @@ abstract class $ChatRoomCopyWith<$Res> {
|
||||
$Res call(
|
||||
{@JsonKey(name: "id") String id,
|
||||
@JsonKey(name: "room_name") String roomName,
|
||||
@JsonKey(name: "last_message") dynamic lastMessage,
|
||||
@JsonKey(name: "users") Users users});
|
||||
@JsonKey(name: "last_message", fromJson: parseLastMessage)
|
||||
ChatMessageModel? lastMessage,
|
||||
@JsonKey(name: "users") Users users,
|
||||
@JsonKey(name: "unread_messages_count") int unreadMessagesCount});
|
||||
|
||||
$ChatMessageModelCopyWith<$Res>? get lastMessage;
|
||||
$UsersCopyWith<$Res> get users;
|
||||
}
|
||||
|
||||
@@ -238,6 +243,7 @@ class _$ChatRoomCopyWithImpl<$Res, $Val extends ChatRoom>
|
||||
Object? roomName = null,
|
||||
Object? lastMessage = freezed,
|
||||
Object? users = null,
|
||||
Object? unreadMessagesCount = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
id: null == id
|
||||
@@ -251,14 +257,32 @@ class _$ChatRoomCopyWithImpl<$Res, $Val extends ChatRoom>
|
||||
lastMessage: freezed == lastMessage
|
||||
? _value.lastMessage
|
||||
: lastMessage // ignore: cast_nullable_to_non_nullable
|
||||
as dynamic,
|
||||
as ChatMessageModel?,
|
||||
users: null == users
|
||||
? _value.users
|
||||
: users // ignore: cast_nullable_to_non_nullable
|
||||
as Users,
|
||||
unreadMessagesCount: null == unreadMessagesCount
|
||||
? _value.unreadMessagesCount
|
||||
: unreadMessagesCount // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
) as $Val);
|
||||
}
|
||||
|
||||
/// Create a copy of ChatRoom
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$ChatMessageModelCopyWith<$Res>? get lastMessage {
|
||||
if (_value.lastMessage == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $ChatMessageModelCopyWith<$Res>(_value.lastMessage!, (value) {
|
||||
return _then(_value.copyWith(lastMessage: value) as $Val);
|
||||
});
|
||||
}
|
||||
|
||||
/// Create a copy of ChatRoom
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@@ -281,9 +305,13 @@ abstract class _$$ChatRoomImplCopyWith<$Res>
|
||||
$Res call(
|
||||
{@JsonKey(name: "id") String id,
|
||||
@JsonKey(name: "room_name") String roomName,
|
||||
@JsonKey(name: "last_message") dynamic lastMessage,
|
||||
@JsonKey(name: "users") Users users});
|
||||
@JsonKey(name: "last_message", fromJson: parseLastMessage)
|
||||
ChatMessageModel? lastMessage,
|
||||
@JsonKey(name: "users") Users users,
|
||||
@JsonKey(name: "unread_messages_count") int unreadMessagesCount});
|
||||
|
||||
@override
|
||||
$ChatMessageModelCopyWith<$Res>? get lastMessage;
|
||||
@override
|
||||
$UsersCopyWith<$Res> get users;
|
||||
}
|
||||
@@ -305,6 +333,7 @@ class __$$ChatRoomImplCopyWithImpl<$Res>
|
||||
Object? roomName = null,
|
||||
Object? lastMessage = freezed,
|
||||
Object? users = null,
|
||||
Object? unreadMessagesCount = null,
|
||||
}) {
|
||||
return _then(_$ChatRoomImpl(
|
||||
id: null == id
|
||||
@@ -318,11 +347,15 @@ class __$$ChatRoomImplCopyWithImpl<$Res>
|
||||
lastMessage: freezed == lastMessage
|
||||
? _value.lastMessage
|
||||
: lastMessage // ignore: cast_nullable_to_non_nullable
|
||||
as dynamic,
|
||||
as ChatMessageModel?,
|
||||
users: null == users
|
||||
? _value.users
|
||||
: users // ignore: cast_nullable_to_non_nullable
|
||||
as Users,
|
||||
unreadMessagesCount: null == unreadMessagesCount
|
||||
? _value.unreadMessagesCount
|
||||
: unreadMessagesCount // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -333,8 +366,11 @@ class _$ChatRoomImpl implements _ChatRoom {
|
||||
const _$ChatRoomImpl(
|
||||
{@JsonKey(name: "id") required this.id,
|
||||
@JsonKey(name: "room_name") required this.roomName,
|
||||
@JsonKey(name: "last_message") required this.lastMessage,
|
||||
@JsonKey(name: "users") required this.users});
|
||||
@JsonKey(name: "last_message", fromJson: parseLastMessage)
|
||||
required this.lastMessage,
|
||||
@JsonKey(name: "users") required this.users,
|
||||
@JsonKey(name: "unread_messages_count")
|
||||
required this.unreadMessagesCount});
|
||||
|
||||
factory _$ChatRoomImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$ChatRoomImplFromJson(json);
|
||||
@@ -346,15 +382,18 @@ class _$ChatRoomImpl implements _ChatRoom {
|
||||
@JsonKey(name: "room_name")
|
||||
final String roomName;
|
||||
@override
|
||||
@JsonKey(name: "last_message")
|
||||
final dynamic lastMessage;
|
||||
@JsonKey(name: "last_message", fromJson: parseLastMessage)
|
||||
final ChatMessageModel? lastMessage;
|
||||
@override
|
||||
@JsonKey(name: "users")
|
||||
final Users users;
|
||||
@override
|
||||
@JsonKey(name: "unread_messages_count")
|
||||
final int unreadMessagesCount;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ChatRoom(id: $id, roomName: $roomName, lastMessage: $lastMessage, users: $users)';
|
||||
return 'ChatRoom(id: $id, roomName: $roomName, lastMessage: $lastMessage, users: $users, unreadMessagesCount: $unreadMessagesCount)';
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -365,15 +404,17 @@ class _$ChatRoomImpl implements _ChatRoom {
|
||||
(identical(other.id, id) || other.id == id) &&
|
||||
(identical(other.roomName, roomName) ||
|
||||
other.roomName == roomName) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other.lastMessage, lastMessage) &&
|
||||
(identical(other.users, users) || other.users == users));
|
||||
(identical(other.lastMessage, lastMessage) ||
|
||||
other.lastMessage == lastMessage) &&
|
||||
(identical(other.users, users) || other.users == users) &&
|
||||
(identical(other.unreadMessagesCount, unreadMessagesCount) ||
|
||||
other.unreadMessagesCount == unreadMessagesCount));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, id, roomName,
|
||||
const DeepCollectionEquality().hash(lastMessage), users);
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType, id, roomName, lastMessage, users, unreadMessagesCount);
|
||||
|
||||
/// Create a copy of ChatRoom
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -395,8 +436,11 @@ abstract class _ChatRoom implements ChatRoom {
|
||||
const factory _ChatRoom(
|
||||
{@JsonKey(name: "id") required final String id,
|
||||
@JsonKey(name: "room_name") required final String roomName,
|
||||
@JsonKey(name: "last_message") required final dynamic lastMessage,
|
||||
@JsonKey(name: "users") required final Users users}) = _$ChatRoomImpl;
|
||||
@JsonKey(name: "last_message", fromJson: parseLastMessage)
|
||||
required final ChatMessageModel? lastMessage,
|
||||
@JsonKey(name: "users") required final Users users,
|
||||
@JsonKey(name: "unread_messages_count")
|
||||
required final int unreadMessagesCount}) = _$ChatRoomImpl;
|
||||
|
||||
factory _ChatRoom.fromJson(Map<String, dynamic> json) =
|
||||
_$ChatRoomImpl.fromJson;
|
||||
@@ -408,11 +452,14 @@ abstract class _ChatRoom implements ChatRoom {
|
||||
@JsonKey(name: "room_name")
|
||||
String get roomName;
|
||||
@override
|
||||
@JsonKey(name: "last_message")
|
||||
dynamic get lastMessage;
|
||||
@JsonKey(name: "last_message", fromJson: parseLastMessage)
|
||||
ChatMessageModel? get lastMessage;
|
||||
@override
|
||||
@JsonKey(name: "users")
|
||||
Users get users;
|
||||
@override
|
||||
@JsonKey(name: "unread_messages_count")
|
||||
int get unreadMessagesCount;
|
||||
|
||||
/// Create a copy of ChatRoom
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -422,327 +469,6 @@ abstract class _ChatRoom implements ChatRoom {
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
LastMessageClass _$LastMessageClassFromJson(Map<String, dynamic> json) {
|
||||
return _LastMessageClass.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$LastMessageClass {
|
||||
@JsonKey(name: "id")
|
||||
int get id => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "data")
|
||||
String get data => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "media_data")
|
||||
List<dynamic> get mediaData => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "author_id")
|
||||
int get authorId => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "is_author_message_auth_user")
|
||||
bool get isAuthorMessageAuthUser => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "read_by_to_user")
|
||||
bool get readByToUser => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "updated_at")
|
||||
DateTime get updatedAt => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this LastMessageClass to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of LastMessageClass
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$LastMessageClassCopyWith<LastMessageClass> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $LastMessageClassCopyWith<$Res> {
|
||||
factory $LastMessageClassCopyWith(
|
||||
LastMessageClass value, $Res Function(LastMessageClass) then) =
|
||||
_$LastMessageClassCopyWithImpl<$Res, LastMessageClass>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{@JsonKey(name: "id") int id,
|
||||
@JsonKey(name: "data") String data,
|
||||
@JsonKey(name: "media_data") List<dynamic> mediaData,
|
||||
@JsonKey(name: "author_id") int authorId,
|
||||
@JsonKey(name: "is_author_message_auth_user")
|
||||
bool isAuthorMessageAuthUser,
|
||||
@JsonKey(name: "read_by_to_user") bool readByToUser,
|
||||
@JsonKey(name: "updated_at") DateTime updatedAt});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$LastMessageClassCopyWithImpl<$Res, $Val extends LastMessageClass>
|
||||
implements $LastMessageClassCopyWith<$Res> {
|
||||
_$LastMessageClassCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of LastMessageClass
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? id = null,
|
||||
Object? data = null,
|
||||
Object? mediaData = null,
|
||||
Object? authorId = null,
|
||||
Object? isAuthorMessageAuthUser = null,
|
||||
Object? readByToUser = null,
|
||||
Object? updatedAt = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
id: null == id
|
||||
? _value.id
|
||||
: id // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
data: null == data
|
||||
? _value.data
|
||||
: data // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
mediaData: null == mediaData
|
||||
? _value.mediaData
|
||||
: mediaData // ignore: cast_nullable_to_non_nullable
|
||||
as List<dynamic>,
|
||||
authorId: null == authorId
|
||||
? _value.authorId
|
||||
: authorId // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
isAuthorMessageAuthUser: null == isAuthorMessageAuthUser
|
||||
? _value.isAuthorMessageAuthUser
|
||||
: isAuthorMessageAuthUser // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
readByToUser: null == readByToUser
|
||||
? _value.readByToUser
|
||||
: readByToUser // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
updatedAt: null == updatedAt
|
||||
? _value.updatedAt
|
||||
: updatedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$LastMessageClassImplCopyWith<$Res>
|
||||
implements $LastMessageClassCopyWith<$Res> {
|
||||
factory _$$LastMessageClassImplCopyWith(_$LastMessageClassImpl value,
|
||||
$Res Function(_$LastMessageClassImpl) then) =
|
||||
__$$LastMessageClassImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{@JsonKey(name: "id") int id,
|
||||
@JsonKey(name: "data") String data,
|
||||
@JsonKey(name: "media_data") List<dynamic> mediaData,
|
||||
@JsonKey(name: "author_id") int authorId,
|
||||
@JsonKey(name: "is_author_message_auth_user")
|
||||
bool isAuthorMessageAuthUser,
|
||||
@JsonKey(name: "read_by_to_user") bool readByToUser,
|
||||
@JsonKey(name: "updated_at") DateTime updatedAt});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$LastMessageClassImplCopyWithImpl<$Res>
|
||||
extends _$LastMessageClassCopyWithImpl<$Res, _$LastMessageClassImpl>
|
||||
implements _$$LastMessageClassImplCopyWith<$Res> {
|
||||
__$$LastMessageClassImplCopyWithImpl(_$LastMessageClassImpl _value,
|
||||
$Res Function(_$LastMessageClassImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of LastMessageClass
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? id = null,
|
||||
Object? data = null,
|
||||
Object? mediaData = null,
|
||||
Object? authorId = null,
|
||||
Object? isAuthorMessageAuthUser = null,
|
||||
Object? readByToUser = null,
|
||||
Object? updatedAt = null,
|
||||
}) {
|
||||
return _then(_$LastMessageClassImpl(
|
||||
id: null == id
|
||||
? _value.id
|
||||
: id // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
data: null == data
|
||||
? _value.data
|
||||
: data // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
mediaData: null == mediaData
|
||||
? _value._mediaData
|
||||
: mediaData // ignore: cast_nullable_to_non_nullable
|
||||
as List<dynamic>,
|
||||
authorId: null == authorId
|
||||
? _value.authorId
|
||||
: authorId // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
isAuthorMessageAuthUser: null == isAuthorMessageAuthUser
|
||||
? _value.isAuthorMessageAuthUser
|
||||
: isAuthorMessageAuthUser // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
readByToUser: null == readByToUser
|
||||
? _value.readByToUser
|
||||
: readByToUser // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
updatedAt: null == updatedAt
|
||||
? _value.updatedAt
|
||||
: updatedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$LastMessageClassImpl implements _LastMessageClass {
|
||||
const _$LastMessageClassImpl(
|
||||
{@JsonKey(name: "id") required this.id,
|
||||
@JsonKey(name: "data") required this.data,
|
||||
@JsonKey(name: "media_data") required final List<dynamic> mediaData,
|
||||
@JsonKey(name: "author_id") required this.authorId,
|
||||
@JsonKey(name: "is_author_message_auth_user")
|
||||
required this.isAuthorMessageAuthUser,
|
||||
@JsonKey(name: "read_by_to_user") required this.readByToUser,
|
||||
@JsonKey(name: "updated_at") required this.updatedAt})
|
||||
: _mediaData = mediaData;
|
||||
|
||||
factory _$LastMessageClassImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$LastMessageClassImplFromJson(json);
|
||||
|
||||
@override
|
||||
@JsonKey(name: "id")
|
||||
final int id;
|
||||
@override
|
||||
@JsonKey(name: "data")
|
||||
final String data;
|
||||
final List<dynamic> _mediaData;
|
||||
@override
|
||||
@JsonKey(name: "media_data")
|
||||
List<dynamic> get mediaData {
|
||||
if (_mediaData is EqualUnmodifiableListView) return _mediaData;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_mediaData);
|
||||
}
|
||||
|
||||
@override
|
||||
@JsonKey(name: "author_id")
|
||||
final int authorId;
|
||||
@override
|
||||
@JsonKey(name: "is_author_message_auth_user")
|
||||
final bool isAuthorMessageAuthUser;
|
||||
@override
|
||||
@JsonKey(name: "read_by_to_user")
|
||||
final bool readByToUser;
|
||||
@override
|
||||
@JsonKey(name: "updated_at")
|
||||
final DateTime updatedAt;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'LastMessageClass(id: $id, data: $data, mediaData: $mediaData, authorId: $authorId, isAuthorMessageAuthUser: $isAuthorMessageAuthUser, readByToUser: $readByToUser, updatedAt: $updatedAt)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$LastMessageClassImpl &&
|
||||
(identical(other.id, id) || other.id == id) &&
|
||||
(identical(other.data, data) || other.data == data) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._mediaData, _mediaData) &&
|
||||
(identical(other.authorId, authorId) ||
|
||||
other.authorId == authorId) &&
|
||||
(identical(
|
||||
other.isAuthorMessageAuthUser, isAuthorMessageAuthUser) ||
|
||||
other.isAuthorMessageAuthUser == isAuthorMessageAuthUser) &&
|
||||
(identical(other.readByToUser, readByToUser) ||
|
||||
other.readByToUser == readByToUser) &&
|
||||
(identical(other.updatedAt, updatedAt) ||
|
||||
other.updatedAt == updatedAt));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
id,
|
||||
data,
|
||||
const DeepCollectionEquality().hash(_mediaData),
|
||||
authorId,
|
||||
isAuthorMessageAuthUser,
|
||||
readByToUser,
|
||||
updatedAt);
|
||||
|
||||
/// Create a copy of LastMessageClass
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$LastMessageClassImplCopyWith<_$LastMessageClassImpl> get copyWith =>
|
||||
__$$LastMessageClassImplCopyWithImpl<_$LastMessageClassImpl>(
|
||||
this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$LastMessageClassImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _LastMessageClass implements LastMessageClass {
|
||||
const factory _LastMessageClass(
|
||||
{@JsonKey(name: "id") required final int id,
|
||||
@JsonKey(name: "data") required final String data,
|
||||
@JsonKey(name: "media_data") required final List<dynamic> mediaData,
|
||||
@JsonKey(name: "author_id") required final int authorId,
|
||||
@JsonKey(name: "is_author_message_auth_user")
|
||||
required final bool isAuthorMessageAuthUser,
|
||||
@JsonKey(name: "read_by_to_user") required final bool readByToUser,
|
||||
@JsonKey(name: "updated_at") required final DateTime updatedAt}) =
|
||||
_$LastMessageClassImpl;
|
||||
|
||||
factory _LastMessageClass.fromJson(Map<String, dynamic> json) =
|
||||
_$LastMessageClassImpl.fromJson;
|
||||
|
||||
@override
|
||||
@JsonKey(name: "id")
|
||||
int get id;
|
||||
@override
|
||||
@JsonKey(name: "data")
|
||||
String get data;
|
||||
@override
|
||||
@JsonKey(name: "media_data")
|
||||
List<dynamic> get mediaData;
|
||||
@override
|
||||
@JsonKey(name: "author_id")
|
||||
int get authorId;
|
||||
@override
|
||||
@JsonKey(name: "is_author_message_auth_user")
|
||||
bool get isAuthorMessageAuthUser;
|
||||
@override
|
||||
@JsonKey(name: "read_by_to_user")
|
||||
bool get readByToUser;
|
||||
@override
|
||||
@JsonKey(name: "updated_at")
|
||||
DateTime get updatedAt;
|
||||
|
||||
/// Create a copy of LastMessageClass
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$LastMessageClassImplCopyWith<_$LastMessageClassImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
Users _$UsersFromJson(Map<String, dynamic> json) {
|
||||
return _Users.fromJson(json);
|
||||
}
|
||||
|
||||
@@ -24,8 +24,9 @@ _$ChatRoomImpl _$$ChatRoomImplFromJson(Map<String, dynamic> json) =>
|
||||
_$ChatRoomImpl(
|
||||
id: json['id'] as String,
|
||||
roomName: json['room_name'] as String,
|
||||
lastMessage: json['last_message'],
|
||||
lastMessage: parseLastMessage(json['last_message']),
|
||||
users: Users.fromJson(json['users'] as Map<String, dynamic>),
|
||||
unreadMessagesCount: (json['unread_messages_count'] as num).toInt(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$ChatRoomImplToJson(_$ChatRoomImpl instance) =>
|
||||
@@ -34,30 +35,7 @@ Map<String, dynamic> _$$ChatRoomImplToJson(_$ChatRoomImpl instance) =>
|
||||
'room_name': instance.roomName,
|
||||
'last_message': instance.lastMessage,
|
||||
'users': instance.users,
|
||||
};
|
||||
|
||||
_$LastMessageClassImpl _$$LastMessageClassImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$LastMessageClassImpl(
|
||||
id: (json['id'] as num).toInt(),
|
||||
data: json['data'] as String,
|
||||
mediaData: json['media_data'] as List<dynamic>,
|
||||
authorId: (json['author_id'] as num).toInt(),
|
||||
isAuthorMessageAuthUser: json['is_author_message_auth_user'] as bool,
|
||||
readByToUser: json['read_by_to_user'] as bool,
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$LastMessageClassImplToJson(
|
||||
_$LastMessageClassImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'data': instance.data,
|
||||
'media_data': instance.mediaData,
|
||||
'author_id': instance.authorId,
|
||||
'is_author_message_auth_user': instance.isAuthorMessageAuthUser,
|
||||
'read_by_to_user': instance.readByToUser,
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'unread_messages_count': instance.unreadMessagesCount,
|
||||
};
|
||||
|
||||
_$UsersImpl _$$UsersImplFromJson(Map<String, dynamic> json) => _$UsersImpl(
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:audioplayers/audioplayers.dart';
|
||||
import 'package:easy_debounce/easy_debounce.dart';
|
||||
import 'package:eatvio_app/core/image_compressing/image_compress_utility.dart';
|
||||
import 'package:eatvio_app/core/initialization_cubit/ws_manager.dart';
|
||||
import 'package:eatvio_app/core/websockets/ws_manager.dart';
|
||||
import 'package:eatvio_app/features/chat/models/chat_message_model.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.dart';
|
||||
import 'package:eatvio_app/features/chat/repositories/chat_repository.dart';
|
||||
@@ -87,10 +88,12 @@ class ChatRoomCubit extends Cubit<ChatRoomState> {
|
||||
wsManager.subscribeDirectChatChannel();
|
||||
wsManager.directChatStream?.listen((event) {
|
||||
AudioPlayer().play((AssetSource('audio/recive_message.wav')));
|
||||
final message = ChatMessageModel.fromJson(jsonDecode(event.data)['message']);
|
||||
List<ChatMessageModel> messagesList = [
|
||||
ChatMessageModel.fromJson(jsonDecode(event.data)['message']),
|
||||
message,
|
||||
...(state as ChatRoomStateLoaded).chatMessages,
|
||||
];
|
||||
chatRepository.emitNewMessageToChats(message);
|
||||
emit(
|
||||
ChatRoomState.loaded(
|
||||
chatRoom: (state as ChatRoomStateLoaded).chatRoom,
|
||||
@@ -125,17 +128,46 @@ class ChatRoomCubit extends Cubit<ChatRoomState> {
|
||||
});
|
||||
}
|
||||
|
||||
sendMessage({
|
||||
Future<bool> sendMessage({
|
||||
required String chatId,
|
||||
String? data,
|
||||
List<File>? files,
|
||||
}) async {
|
||||
await chatRepository.sendMessage(
|
||||
chatId: chatId,
|
||||
data: data,
|
||||
files: files != null ? await ImageCompressUtility.compressFilesList(files) : null,
|
||||
);
|
||||
AudioPlayer().play((AssetSource('audio/send_message.wav')));
|
||||
try {
|
||||
await chatRepository.sendMessage(
|
||||
chatId: chatId,
|
||||
data: data,
|
||||
files: files != null ? await ImageCompressUtility.compressFilesList(files) : null,
|
||||
);
|
||||
AudioPlayer().play((AssetSource('audio/send_message.wav')));
|
||||
return true;
|
||||
} catch (e, st) {
|
||||
log(e.toString(), stackTrace: st);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> markMessagesAsRead(String chatId, List<({int id, int index})> messagesIds) async {
|
||||
try {
|
||||
if (state is ChatRoomStateLoaded) {
|
||||
final ids = messagesIds.map((e) => e.id).toList();
|
||||
await chatRepository.markMessagesAsRead(chatId, ids);
|
||||
final currentMessages = [...(state as ChatRoomStateLoaded).chatMessages];
|
||||
messagesIds.forEach((elem) {
|
||||
currentMessages[elem.index] = currentMessages[elem.index].copyWith(isRead: true);
|
||||
});
|
||||
if (!isClosed) {
|
||||
emit(
|
||||
(state as ChatRoomStateLoaded).copyWith(chatMessages: currentMessages),
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (e, st) {
|
||||
log(e.toString(), stackTrace: st);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
import 'package:eatvio_app/features/chat/presentation/bloc/chat_select_cubit/chat_select_state.dart';
|
||||
import 'package:eatvio_app/features/chat/repositories/chat_repository.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class ChatSelectCubit extends Cubit<ChatSelectState> {
|
||||
final ChatRepository chatRepository;
|
||||
|
||||
ChatSelectCubit({
|
||||
required this.chatRepository,
|
||||
}) : super(ChatSelectState());
|
||||
|
||||
getChatRooms({String? query}) async {
|
||||
emit(ChatSelectState.loading());
|
||||
try {
|
||||
final chatRooms = await chatRepository.getChatRoomPreviews(query: query);
|
||||
emit(
|
||||
ChatSelectState.loaded(
|
||||
chatRooms: chatRooms,
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
emit(
|
||||
ChatSelectState.error(errorMessage: e.toString()),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
import 'package:eatvio_app/features/chat/models/chat_room_preview_model.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'chat_select_state.freezed.dart';
|
||||
|
||||
@freezed
|
||||
abstract class ChatSelectState with _$ChatSelectState {
|
||||
const factory ChatSelectState() = _ChatSelectState;
|
||||
|
||||
const factory ChatSelectState.loading() = ChatSelectStateLoading;
|
||||
|
||||
const factory ChatSelectState.error({
|
||||
required String errorMessage,
|
||||
}) = ChatSelectStateError;
|
||||
|
||||
const factory ChatSelectState.loaded({
|
||||
required List<ChatRoom> chatRooms,
|
||||
}) = ChatSelectStateLoaded;
|
||||
}
|
||||
@@ -1,646 +0,0 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'chat_select_state.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||
|
||||
/// @nodoc
|
||||
mixin _$ChatSelectState {
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>(
|
||||
TResult Function() $default, {
|
||||
required TResult Function() loading,
|
||||
required TResult Function(String errorMessage) error,
|
||||
required TResult Function(List<ChatRoom> chatRooms) loaded,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>(
|
||||
TResult? Function()? $default, {
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(String errorMessage)? error,
|
||||
TResult? Function(List<ChatRoom> chatRooms)? loaded,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>(
|
||||
TResult Function()? $default, {
|
||||
TResult Function()? loading,
|
||||
TResult Function(String errorMessage)? error,
|
||||
TResult Function(List<ChatRoom> chatRooms)? loaded,
|
||||
required TResult orElse(),
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>(
|
||||
TResult Function(_ChatSelectState value) $default, {
|
||||
required TResult Function(ChatSelectStateLoading value) loading,
|
||||
required TResult Function(ChatSelectStateError value) error,
|
||||
required TResult Function(ChatSelectStateLoaded value) loaded,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>(
|
||||
TResult? Function(_ChatSelectState value)? $default, {
|
||||
TResult? Function(ChatSelectStateLoading value)? loading,
|
||||
TResult? Function(ChatSelectStateError value)? error,
|
||||
TResult? Function(ChatSelectStateLoaded value)? loaded,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>(
|
||||
TResult Function(_ChatSelectState value)? $default, {
|
||||
TResult Function(ChatSelectStateLoading value)? loading,
|
||||
TResult Function(ChatSelectStateError value)? error,
|
||||
TResult Function(ChatSelectStateLoaded value)? loaded,
|
||||
required TResult orElse(),
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $ChatSelectStateCopyWith<$Res> {
|
||||
factory $ChatSelectStateCopyWith(
|
||||
ChatSelectState value, $Res Function(ChatSelectState) then) =
|
||||
_$ChatSelectStateCopyWithImpl<$Res, ChatSelectState>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$ChatSelectStateCopyWithImpl<$Res, $Val extends ChatSelectState>
|
||||
implements $ChatSelectStateCopyWith<$Res> {
|
||||
_$ChatSelectStateCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of ChatSelectState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$ChatSelectStateImplCopyWith<$Res> {
|
||||
factory _$$ChatSelectStateImplCopyWith(_$ChatSelectStateImpl value,
|
||||
$Res Function(_$ChatSelectStateImpl) then) =
|
||||
__$$ChatSelectStateImplCopyWithImpl<$Res>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$ChatSelectStateImplCopyWithImpl<$Res>
|
||||
extends _$ChatSelectStateCopyWithImpl<$Res, _$ChatSelectStateImpl>
|
||||
implements _$$ChatSelectStateImplCopyWith<$Res> {
|
||||
__$$ChatSelectStateImplCopyWithImpl(
|
||||
_$ChatSelectStateImpl _value, $Res Function(_$ChatSelectStateImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of ChatSelectState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$ChatSelectStateImpl implements _ChatSelectState {
|
||||
const _$ChatSelectStateImpl();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ChatSelectState()';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is _$ChatSelectStateImpl);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => runtimeType.hashCode;
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>(
|
||||
TResult Function() $default, {
|
||||
required TResult Function() loading,
|
||||
required TResult Function(String errorMessage) error,
|
||||
required TResult Function(List<ChatRoom> chatRooms) loaded,
|
||||
}) {
|
||||
return $default();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>(
|
||||
TResult? Function()? $default, {
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(String errorMessage)? error,
|
||||
TResult? Function(List<ChatRoom> chatRooms)? loaded,
|
||||
}) {
|
||||
return $default?.call();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>(
|
||||
TResult Function()? $default, {
|
||||
TResult Function()? loading,
|
||||
TResult Function(String errorMessage)? error,
|
||||
TResult Function(List<ChatRoom> chatRooms)? loaded,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if ($default != null) {
|
||||
return $default();
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>(
|
||||
TResult Function(_ChatSelectState value) $default, {
|
||||
required TResult Function(ChatSelectStateLoading value) loading,
|
||||
required TResult Function(ChatSelectStateError value) error,
|
||||
required TResult Function(ChatSelectStateLoaded value) loaded,
|
||||
}) {
|
||||
return $default(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>(
|
||||
TResult? Function(_ChatSelectState value)? $default, {
|
||||
TResult? Function(ChatSelectStateLoading value)? loading,
|
||||
TResult? Function(ChatSelectStateError value)? error,
|
||||
TResult? Function(ChatSelectStateLoaded value)? loaded,
|
||||
}) {
|
||||
return $default?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>(
|
||||
TResult Function(_ChatSelectState value)? $default, {
|
||||
TResult Function(ChatSelectStateLoading value)? loading,
|
||||
TResult Function(ChatSelectStateError value)? error,
|
||||
TResult Function(ChatSelectStateLoaded value)? loaded,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if ($default != null) {
|
||||
return $default(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _ChatSelectState implements ChatSelectState {
|
||||
const factory _ChatSelectState() = _$ChatSelectStateImpl;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$ChatSelectStateLoadingImplCopyWith<$Res> {
|
||||
factory _$$ChatSelectStateLoadingImplCopyWith(
|
||||
_$ChatSelectStateLoadingImpl value,
|
||||
$Res Function(_$ChatSelectStateLoadingImpl) then) =
|
||||
__$$ChatSelectStateLoadingImplCopyWithImpl<$Res>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$ChatSelectStateLoadingImplCopyWithImpl<$Res>
|
||||
extends _$ChatSelectStateCopyWithImpl<$Res, _$ChatSelectStateLoadingImpl>
|
||||
implements _$$ChatSelectStateLoadingImplCopyWith<$Res> {
|
||||
__$$ChatSelectStateLoadingImplCopyWithImpl(
|
||||
_$ChatSelectStateLoadingImpl _value,
|
||||
$Res Function(_$ChatSelectStateLoadingImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of ChatSelectState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$ChatSelectStateLoadingImpl implements ChatSelectStateLoading {
|
||||
const _$ChatSelectStateLoadingImpl();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ChatSelectState.loading()';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$ChatSelectStateLoadingImpl);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => runtimeType.hashCode;
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>(
|
||||
TResult Function() $default, {
|
||||
required TResult Function() loading,
|
||||
required TResult Function(String errorMessage) error,
|
||||
required TResult Function(List<ChatRoom> chatRooms) loaded,
|
||||
}) {
|
||||
return loading();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>(
|
||||
TResult? Function()? $default, {
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(String errorMessage)? error,
|
||||
TResult? Function(List<ChatRoom> chatRooms)? loaded,
|
||||
}) {
|
||||
return loading?.call();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>(
|
||||
TResult Function()? $default, {
|
||||
TResult Function()? loading,
|
||||
TResult Function(String errorMessage)? error,
|
||||
TResult Function(List<ChatRoom> chatRooms)? loaded,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (loading != null) {
|
||||
return loading();
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>(
|
||||
TResult Function(_ChatSelectState value) $default, {
|
||||
required TResult Function(ChatSelectStateLoading value) loading,
|
||||
required TResult Function(ChatSelectStateError value) error,
|
||||
required TResult Function(ChatSelectStateLoaded value) loaded,
|
||||
}) {
|
||||
return loading(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>(
|
||||
TResult? Function(_ChatSelectState value)? $default, {
|
||||
TResult? Function(ChatSelectStateLoading value)? loading,
|
||||
TResult? Function(ChatSelectStateError value)? error,
|
||||
TResult? Function(ChatSelectStateLoaded value)? loaded,
|
||||
}) {
|
||||
return loading?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>(
|
||||
TResult Function(_ChatSelectState value)? $default, {
|
||||
TResult Function(ChatSelectStateLoading value)? loading,
|
||||
TResult Function(ChatSelectStateError value)? error,
|
||||
TResult Function(ChatSelectStateLoaded value)? loaded,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (loading != null) {
|
||||
return loading(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class ChatSelectStateLoading implements ChatSelectState {
|
||||
const factory ChatSelectStateLoading() = _$ChatSelectStateLoadingImpl;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$ChatSelectStateErrorImplCopyWith<$Res> {
|
||||
factory _$$ChatSelectStateErrorImplCopyWith(_$ChatSelectStateErrorImpl value,
|
||||
$Res Function(_$ChatSelectStateErrorImpl) then) =
|
||||
__$$ChatSelectStateErrorImplCopyWithImpl<$Res>;
|
||||
@useResult
|
||||
$Res call({String errorMessage});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$ChatSelectStateErrorImplCopyWithImpl<$Res>
|
||||
extends _$ChatSelectStateCopyWithImpl<$Res, _$ChatSelectStateErrorImpl>
|
||||
implements _$$ChatSelectStateErrorImplCopyWith<$Res> {
|
||||
__$$ChatSelectStateErrorImplCopyWithImpl(_$ChatSelectStateErrorImpl _value,
|
||||
$Res Function(_$ChatSelectStateErrorImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of ChatSelectState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? errorMessage = null,
|
||||
}) {
|
||||
return _then(_$ChatSelectStateErrorImpl(
|
||||
errorMessage: null == errorMessage
|
||||
? _value.errorMessage
|
||||
: errorMessage // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$ChatSelectStateErrorImpl implements ChatSelectStateError {
|
||||
const _$ChatSelectStateErrorImpl({required this.errorMessage});
|
||||
|
||||
@override
|
||||
final String errorMessage;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ChatSelectState.error(errorMessage: $errorMessage)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$ChatSelectStateErrorImpl &&
|
||||
(identical(other.errorMessage, errorMessage) ||
|
||||
other.errorMessage == errorMessage));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, errorMessage);
|
||||
|
||||
/// Create a copy of ChatSelectState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$ChatSelectStateErrorImplCopyWith<_$ChatSelectStateErrorImpl>
|
||||
get copyWith =>
|
||||
__$$ChatSelectStateErrorImplCopyWithImpl<_$ChatSelectStateErrorImpl>(
|
||||
this, _$identity);
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>(
|
||||
TResult Function() $default, {
|
||||
required TResult Function() loading,
|
||||
required TResult Function(String errorMessage) error,
|
||||
required TResult Function(List<ChatRoom> chatRooms) loaded,
|
||||
}) {
|
||||
return error(errorMessage);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>(
|
||||
TResult? Function()? $default, {
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(String errorMessage)? error,
|
||||
TResult? Function(List<ChatRoom> chatRooms)? loaded,
|
||||
}) {
|
||||
return error?.call(errorMessage);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>(
|
||||
TResult Function()? $default, {
|
||||
TResult Function()? loading,
|
||||
TResult Function(String errorMessage)? error,
|
||||
TResult Function(List<ChatRoom> chatRooms)? loaded,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (error != null) {
|
||||
return error(errorMessage);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>(
|
||||
TResult Function(_ChatSelectState value) $default, {
|
||||
required TResult Function(ChatSelectStateLoading value) loading,
|
||||
required TResult Function(ChatSelectStateError value) error,
|
||||
required TResult Function(ChatSelectStateLoaded value) loaded,
|
||||
}) {
|
||||
return error(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>(
|
||||
TResult? Function(_ChatSelectState value)? $default, {
|
||||
TResult? Function(ChatSelectStateLoading value)? loading,
|
||||
TResult? Function(ChatSelectStateError value)? error,
|
||||
TResult? Function(ChatSelectStateLoaded value)? loaded,
|
||||
}) {
|
||||
return error?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>(
|
||||
TResult Function(_ChatSelectState value)? $default, {
|
||||
TResult Function(ChatSelectStateLoading value)? loading,
|
||||
TResult Function(ChatSelectStateError value)? error,
|
||||
TResult Function(ChatSelectStateLoaded value)? loaded,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (error != null) {
|
||||
return error(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class ChatSelectStateError implements ChatSelectState {
|
||||
const factory ChatSelectStateError({required final String errorMessage}) =
|
||||
_$ChatSelectStateErrorImpl;
|
||||
|
||||
String get errorMessage;
|
||||
|
||||
/// Create a copy of ChatSelectState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$ChatSelectStateErrorImplCopyWith<_$ChatSelectStateErrorImpl>
|
||||
get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$ChatSelectStateLoadedImplCopyWith<$Res> {
|
||||
factory _$$ChatSelectStateLoadedImplCopyWith(
|
||||
_$ChatSelectStateLoadedImpl value,
|
||||
$Res Function(_$ChatSelectStateLoadedImpl) then) =
|
||||
__$$ChatSelectStateLoadedImplCopyWithImpl<$Res>;
|
||||
@useResult
|
||||
$Res call({List<ChatRoom> chatRooms});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$ChatSelectStateLoadedImplCopyWithImpl<$Res>
|
||||
extends _$ChatSelectStateCopyWithImpl<$Res, _$ChatSelectStateLoadedImpl>
|
||||
implements _$$ChatSelectStateLoadedImplCopyWith<$Res> {
|
||||
__$$ChatSelectStateLoadedImplCopyWithImpl(_$ChatSelectStateLoadedImpl _value,
|
||||
$Res Function(_$ChatSelectStateLoadedImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of ChatSelectState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? chatRooms = null,
|
||||
}) {
|
||||
return _then(_$ChatSelectStateLoadedImpl(
|
||||
chatRooms: null == chatRooms
|
||||
? _value._chatRooms
|
||||
: chatRooms // ignore: cast_nullable_to_non_nullable
|
||||
as List<ChatRoom>,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$ChatSelectStateLoadedImpl implements ChatSelectStateLoaded {
|
||||
const _$ChatSelectStateLoadedImpl({required final List<ChatRoom> chatRooms})
|
||||
: _chatRooms = chatRooms;
|
||||
|
||||
final List<ChatRoom> _chatRooms;
|
||||
@override
|
||||
List<ChatRoom> get chatRooms {
|
||||
if (_chatRooms is EqualUnmodifiableListView) return _chatRooms;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_chatRooms);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ChatSelectState.loaded(chatRooms: $chatRooms)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$ChatSelectStateLoadedImpl &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._chatRooms, _chatRooms));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(runtimeType, const DeepCollectionEquality().hash(_chatRooms));
|
||||
|
||||
/// Create a copy of ChatSelectState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$ChatSelectStateLoadedImplCopyWith<_$ChatSelectStateLoadedImpl>
|
||||
get copyWith => __$$ChatSelectStateLoadedImplCopyWithImpl<
|
||||
_$ChatSelectStateLoadedImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>(
|
||||
TResult Function() $default, {
|
||||
required TResult Function() loading,
|
||||
required TResult Function(String errorMessage) error,
|
||||
required TResult Function(List<ChatRoom> chatRooms) loaded,
|
||||
}) {
|
||||
return loaded(chatRooms);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>(
|
||||
TResult? Function()? $default, {
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(String errorMessage)? error,
|
||||
TResult? Function(List<ChatRoom> chatRooms)? loaded,
|
||||
}) {
|
||||
return loaded?.call(chatRooms);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>(
|
||||
TResult Function()? $default, {
|
||||
TResult Function()? loading,
|
||||
TResult Function(String errorMessage)? error,
|
||||
TResult Function(List<ChatRoom> chatRooms)? loaded,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (loaded != null) {
|
||||
return loaded(chatRooms);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>(
|
||||
TResult Function(_ChatSelectState value) $default, {
|
||||
required TResult Function(ChatSelectStateLoading value) loading,
|
||||
required TResult Function(ChatSelectStateError value) error,
|
||||
required TResult Function(ChatSelectStateLoaded value) loaded,
|
||||
}) {
|
||||
return loaded(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>(
|
||||
TResult? Function(_ChatSelectState value)? $default, {
|
||||
TResult? Function(ChatSelectStateLoading value)? loading,
|
||||
TResult? Function(ChatSelectStateError value)? error,
|
||||
TResult? Function(ChatSelectStateLoaded value)? loaded,
|
||||
}) {
|
||||
return loaded?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>(
|
||||
TResult Function(_ChatSelectState value)? $default, {
|
||||
TResult Function(ChatSelectStateLoading value)? loading,
|
||||
TResult Function(ChatSelectStateError value)? error,
|
||||
TResult Function(ChatSelectStateLoaded value)? loaded,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (loaded != null) {
|
||||
return loaded(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class ChatSelectStateLoaded implements ChatSelectState {
|
||||
const factory ChatSelectStateLoaded(
|
||||
{required final List<ChatRoom> chatRooms}) = _$ChatSelectStateLoadedImpl;
|
||||
|
||||
List<ChatRoom> get chatRooms;
|
||||
|
||||
/// Create a copy of ChatSelectState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$ChatSelectStateLoadedImplCopyWith<_$ChatSelectStateLoadedImpl>
|
||||
get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
144
lib/features/chat/presentation/bloc/chats_cubit/chats_cubit.dart
Normal file
144
lib/features/chat/presentation/bloc/chats_cubit/chats_cubit.dart
Normal file
@@ -0,0 +1,144 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:eatvio_app/core/utils/enums.dart';
|
||||
import 'package:eatvio_app/core/websockets/ws_manager.dart';
|
||||
import 'package:eatvio_app/features/chat/models/chat_message_model.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/bloc/chats_cubit/chats_state.dart';
|
||||
import 'package:eatvio_app/features/chat/repositories/chat_repository.dart';
|
||||
import 'package:eatvio_app/features/profile/repositories/profile_repository.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class ChatsCubit extends Cubit<ChatsState> {
|
||||
final ChatRepository chatRepository;
|
||||
final ProfileRepository profileRepository;
|
||||
final WsManager wsManager;
|
||||
late StreamSubscription? newIncomingMessagesSubscription;
|
||||
late StreamSubscription? newLastMessageSubscription;
|
||||
|
||||
ChatsCubit({
|
||||
required this.chatRepository,
|
||||
required this.wsManager,
|
||||
required this.profileRepository,
|
||||
}) : super(ChatsState()) {
|
||||
newIncomingMessagesSubscription = wsManager.newMessagesStream?.listen((event) {
|
||||
_handleNewMessageViaSocket(event.data);
|
||||
});
|
||||
|
||||
newLastMessageSubscription = chatRepository.newUserMessagesStream.listen((message) {
|
||||
_setNewLastMessage(message);
|
||||
});
|
||||
}
|
||||
String? _query;
|
||||
Future<void> getChatRoomsWithLoading({String? query}) async {
|
||||
_query = query;
|
||||
emit(state.copyWith(state: BaseState.loading));
|
||||
try {
|
||||
final chatRooms = await chatRepository.getChatRoomPreviews(query: query);
|
||||
final unreadChats = chatRooms.where(
|
||||
(element) => element.unreadMessagesCount > 0,
|
||||
);
|
||||
emit(
|
||||
state.copyWith(
|
||||
chatRooms: chatRooms,
|
||||
chatsWithUnreadMessagesCount: unreadChats.length,
|
||||
state: BaseState.success,
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
emit(
|
||||
state.copyWith(errorMessage: e.toString(), state: BaseState.error),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> getChatRooms({String? query}) async {
|
||||
_query = query;
|
||||
try {
|
||||
final chatRooms = await chatRepository.getChatRoomPreviews(query: query);
|
||||
final unreadChats = chatRooms.where(
|
||||
(element) => element.unreadMessagesCount > 0,
|
||||
);
|
||||
emit(
|
||||
state.copyWith(
|
||||
chatRooms: chatRooms,
|
||||
chatsWithUnreadMessagesCount: unreadChats.length,
|
||||
state: BaseState.success,
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
emit(
|
||||
state.copyWith(errorMessage: e.toString(), state: BaseState.error),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void reduceUnreadMessagesCount({required String chatId, required int count}) {
|
||||
bool isChatRead = false;
|
||||
final updatedChatRooms = state.chatRooms.map((room) {
|
||||
if (room.id == chatId) {
|
||||
int unreadMessagesCount = room.unreadMessagesCount - count;
|
||||
if (unreadMessagesCount <= 0) {
|
||||
unreadMessagesCount = 0;
|
||||
isChatRead = true;
|
||||
}
|
||||
return room.copyWith(unreadMessagesCount: unreadMessagesCount);
|
||||
}
|
||||
return room;
|
||||
}).toList();
|
||||
emit(
|
||||
state.copyWith(
|
||||
chatRooms: updatedChatRooms,
|
||||
chatsWithUnreadMessagesCount: isChatRead ? state.chatsWithUnreadMessagesCount - 1 : state.chatsWithUnreadMessagesCount,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _handleNewMessageViaSocket(dynamic data) async {
|
||||
final json = jsonDecode(data);
|
||||
final message = ChatMessageModel.fromJson(json['message']);
|
||||
|
||||
final currentChatRooms = [...state.chatRooms];
|
||||
|
||||
bool wasChanged = false;
|
||||
bool willIncrementUnreadChats = false;
|
||||
final updatedChatRooms = currentChatRooms.map((chatRoom) {
|
||||
if (chatRoom.id == message.roomId) {
|
||||
wasChanged = true;
|
||||
if (chatRoom.unreadMessagesCount == 0) {
|
||||
willIncrementUnreadChats = true;
|
||||
}
|
||||
return chatRoom.copyWith(lastMessage: message, unreadMessagesCount: chatRoom.unreadMessagesCount + 1);
|
||||
}
|
||||
return chatRoom;
|
||||
}).toList();
|
||||
|
||||
if (!wasChanged && _query == null) {
|
||||
getChatRooms();
|
||||
} else {
|
||||
emit(
|
||||
state.copyWith(
|
||||
chatRooms: updatedChatRooms,
|
||||
chatsWithUnreadMessagesCount: willIncrementUnreadChats ? state.chatsWithUnreadMessagesCount + 1 : state.chatsWithUnreadMessagesCount,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void _setNewLastMessage(ChatMessageModel message) {
|
||||
final chats = state.chatRooms.map((chat) {
|
||||
if (chat.id == message.roomId) {
|
||||
return chat.copyWith(lastMessage: message);
|
||||
}
|
||||
return chat;
|
||||
}).toList();
|
||||
|
||||
emit(state.copyWith(chatRooms: chats));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
newIncomingMessagesSubscription?.cancel();
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import 'package:eatvio_app/core/utils/enums.dart';
|
||||
import 'package:eatvio_app/features/chat/models/chat_room_preview_model.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'chats_state.freezed.dart';
|
||||
|
||||
@freezed
|
||||
class ChatsState with _$ChatsState {
|
||||
|
||||
factory ChatsState({
|
||||
@Default(BaseState.initial) BaseState state,
|
||||
@Default(0) int chatsWithUnreadMessagesCount,
|
||||
@Default([]) List<ChatRoom> chatRooms,
|
||||
@Default(null) String? errorMessage,
|
||||
}) = _ChatsState;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
// 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 'chats_state.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||
|
||||
/// @nodoc
|
||||
mixin _$ChatsState {
|
||||
BaseState get state => throw _privateConstructorUsedError;
|
||||
int get chatsWithUnreadMessagesCount => throw _privateConstructorUsedError;
|
||||
List<ChatRoom> get chatRooms => throw _privateConstructorUsedError;
|
||||
String? get errorMessage => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of ChatsState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$ChatsStateCopyWith<ChatsState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $ChatsStateCopyWith<$Res> {
|
||||
factory $ChatsStateCopyWith(
|
||||
ChatsState value, $Res Function(ChatsState) then) =
|
||||
_$ChatsStateCopyWithImpl<$Res, ChatsState>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{BaseState state,
|
||||
int chatsWithUnreadMessagesCount,
|
||||
List<ChatRoom> chatRooms,
|
||||
String? errorMessage});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$ChatsStateCopyWithImpl<$Res, $Val extends ChatsState>
|
||||
implements $ChatsStateCopyWith<$Res> {
|
||||
_$ChatsStateCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of ChatsState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? state = null,
|
||||
Object? chatsWithUnreadMessagesCount = null,
|
||||
Object? chatRooms = null,
|
||||
Object? errorMessage = freezed,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
state: null == state
|
||||
? _value.state
|
||||
: state // ignore: cast_nullable_to_non_nullable
|
||||
as BaseState,
|
||||
chatsWithUnreadMessagesCount: null == chatsWithUnreadMessagesCount
|
||||
? _value.chatsWithUnreadMessagesCount
|
||||
: chatsWithUnreadMessagesCount // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
chatRooms: null == chatRooms
|
||||
? _value.chatRooms
|
||||
: chatRooms // ignore: cast_nullable_to_non_nullable
|
||||
as List<ChatRoom>,
|
||||
errorMessage: freezed == errorMessage
|
||||
? _value.errorMessage
|
||||
: errorMessage // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$ChatsStateImplCopyWith<$Res>
|
||||
implements $ChatsStateCopyWith<$Res> {
|
||||
factory _$$ChatsStateImplCopyWith(
|
||||
_$ChatsStateImpl value, $Res Function(_$ChatsStateImpl) then) =
|
||||
__$$ChatsStateImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{BaseState state,
|
||||
int chatsWithUnreadMessagesCount,
|
||||
List<ChatRoom> chatRooms,
|
||||
String? errorMessage});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$ChatsStateImplCopyWithImpl<$Res>
|
||||
extends _$ChatsStateCopyWithImpl<$Res, _$ChatsStateImpl>
|
||||
implements _$$ChatsStateImplCopyWith<$Res> {
|
||||
__$$ChatsStateImplCopyWithImpl(
|
||||
_$ChatsStateImpl _value, $Res Function(_$ChatsStateImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of ChatsState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? state = null,
|
||||
Object? chatsWithUnreadMessagesCount = null,
|
||||
Object? chatRooms = null,
|
||||
Object? errorMessage = freezed,
|
||||
}) {
|
||||
return _then(_$ChatsStateImpl(
|
||||
state: null == state
|
||||
? _value.state
|
||||
: state // ignore: cast_nullable_to_non_nullable
|
||||
as BaseState,
|
||||
chatsWithUnreadMessagesCount: null == chatsWithUnreadMessagesCount
|
||||
? _value.chatsWithUnreadMessagesCount
|
||||
: chatsWithUnreadMessagesCount // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
chatRooms: null == chatRooms
|
||||
? _value._chatRooms
|
||||
: chatRooms // ignore: cast_nullable_to_non_nullable
|
||||
as List<ChatRoom>,
|
||||
errorMessage: freezed == errorMessage
|
||||
? _value.errorMessage
|
||||
: errorMessage // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$ChatsStateImpl implements _ChatsState {
|
||||
_$ChatsStateImpl(
|
||||
{this.state = BaseState.initial,
|
||||
this.chatsWithUnreadMessagesCount = 0,
|
||||
final List<ChatRoom> chatRooms = const [],
|
||||
this.errorMessage = null})
|
||||
: _chatRooms = chatRooms;
|
||||
|
||||
@override
|
||||
@JsonKey()
|
||||
final BaseState state;
|
||||
@override
|
||||
@JsonKey()
|
||||
final int chatsWithUnreadMessagesCount;
|
||||
final List<ChatRoom> _chatRooms;
|
||||
@override
|
||||
@JsonKey()
|
||||
List<ChatRoom> get chatRooms {
|
||||
if (_chatRooms is EqualUnmodifiableListView) return _chatRooms;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_chatRooms);
|
||||
}
|
||||
|
||||
@override
|
||||
@JsonKey()
|
||||
final String? errorMessage;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ChatsState(state: $state, chatsWithUnreadMessagesCount: $chatsWithUnreadMessagesCount, chatRooms: $chatRooms, errorMessage: $errorMessage)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$ChatsStateImpl &&
|
||||
(identical(other.state, state) || other.state == state) &&
|
||||
(identical(other.chatsWithUnreadMessagesCount,
|
||||
chatsWithUnreadMessagesCount) ||
|
||||
other.chatsWithUnreadMessagesCount ==
|
||||
chatsWithUnreadMessagesCount) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._chatRooms, _chatRooms) &&
|
||||
(identical(other.errorMessage, errorMessage) ||
|
||||
other.errorMessage == errorMessage));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
state,
|
||||
chatsWithUnreadMessagesCount,
|
||||
const DeepCollectionEquality().hash(_chatRooms),
|
||||
errorMessage);
|
||||
|
||||
/// Create a copy of ChatsState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$ChatsStateImplCopyWith<_$ChatsStateImpl> get copyWith =>
|
||||
__$$ChatsStateImplCopyWithImpl<_$ChatsStateImpl>(this, _$identity);
|
||||
}
|
||||
|
||||
abstract class _ChatsState implements ChatsState {
|
||||
factory _ChatsState(
|
||||
{final BaseState state,
|
||||
final int chatsWithUnreadMessagesCount,
|
||||
final List<ChatRoom> chatRooms,
|
||||
final String? errorMessage}) = _$ChatsStateImpl;
|
||||
|
||||
@override
|
||||
BaseState get state;
|
||||
@override
|
||||
int get chatsWithUnreadMessagesCount;
|
||||
@override
|
||||
List<ChatRoom> get chatRooms;
|
||||
@override
|
||||
String? get errorMessage;
|
||||
|
||||
/// Create a copy of ChatsState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$ChatsStateImplCopyWith<_$ChatsStateImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@@ -1,9 +1,12 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:easy_debounce/easy_debounce.dart';
|
||||
import 'package:eatvio_app/core/widgets/loader.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/bloc/chat_room_cubit/chat_room_cubit.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/bloc/chats_cubit/chats_cubit.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/widgets/chat_bubble_widget.dart';
|
||||
import 'package:eatvio_app/core/locator_service.dart';
|
||||
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
@@ -12,12 +15,14 @@ import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.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,
|
||||
});
|
||||
|
||||
@@ -29,6 +34,8 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
final scrollController = ScrollController();
|
||||
final TextEditingController textEditingController = TextEditingController();
|
||||
final ChatRoomCubit chatRoomCubit = sl<ChatRoomCubit>();
|
||||
final List<({int id, int index})> unreadMessagesIds = [];
|
||||
final List<({int id, int index})> unreadMessagesIdsCopy = [];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -152,25 +159,65 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
(context, index) {
|
||||
if (index < state.chatMessages.length) {
|
||||
if ((index + 1 != state.chatMessages.length &&
|
||||
DateTime.parse(state.chatMessages[index].updatedAt).day != DateTime.parse(state.chatMessages[index + 1].updatedAt).day) ||
|
||||
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;
|
||||
return Column(
|
||||
children: [
|
||||
_messageDate(state.chatMessages[index].updatedAt),
|
||||
ChatBubbleWidget(
|
||||
sendTime: state.chatMessages[index].updatedAt,
|
||||
text: state.chatMessages[index].data.trim(),
|
||||
isCurrentUser: state.chatRoom.users['to_chat_user']!.id != state.chatMessages[index].authorId,
|
||||
mediaData: state.chatMessages[index].mediaData ?? [],
|
||||
VisibilityDetector(
|
||||
key: Key(state.chatMessages[index].id.toString()),
|
||||
onVisibilityChanged: (VisibilityInfo info) {
|
||||
if (!state.chatMessages[index].isRead && !isCurrentUserAuthor && info.visibleFraction > 0) {
|
||||
unreadMessagesIdsCopy.add((id: state.chatMessages[index].id, index: index));
|
||||
EasyDebounce.debounce(
|
||||
'mark_as_read',
|
||||
Duration(milliseconds: 500),
|
||||
() 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);
|
||||
unreadMessagesIdsCopy.clear();
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
child: ChatBubbleWidget(
|
||||
isRead: state.chatMessages[index].isRead,
|
||||
sendTime: state.chatMessages[index].updatedAt,
|
||||
text: state.chatMessages[index].data.trim(),
|
||||
isCurrentUser: isCurrentUserAuthor,
|
||||
mediaData: state.chatMessages[index].mediaData ?? [],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
return ChatBubbleWidget(
|
||||
sendTime: state.chatMessages[index].updatedAt,
|
||||
text: state.chatMessages[index].data.trim(),
|
||||
isCurrentUser: state.chatRoom.users['to_chat_user']!.id != state.chatMessages[index].authorId,
|
||||
mediaData: state.chatMessages[index].mediaData ?? [],
|
||||
final isCurrentUserAuthor = state.chatRoom.users['to_chat_user']!.id != state.chatMessages[index].authorId;
|
||||
return VisibilityDetector(
|
||||
key: Key(state.chatMessages[index].id.toString()),
|
||||
onVisibilityChanged: (VisibilityInfo info) {
|
||||
if (!state.chatMessages[index].isRead && !isCurrentUserAuthor && info.visibleFraction > 0) {
|
||||
unreadMessagesIds.add((id: state.chatMessages[index].id, index: index));
|
||||
EasyDebounce.debounce(
|
||||
'mark_as_read',
|
||||
Duration(milliseconds: 500),
|
||||
() 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);
|
||||
unreadMessagesIds.clear();
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
child: ChatBubbleWidget(
|
||||
isRead: state.chatMessages[index].isRead,
|
||||
sendTime: state.chatMessages[index].updatedAt,
|
||||
text: state.chatMessages[index].data.trim(),
|
||||
isCurrentUser: isCurrentUserAuthor,
|
||||
mediaData: state.chatMessages[index].mediaData ?? [],
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return Padding(
|
||||
@@ -222,7 +269,7 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
|
||||
if (result != null) {
|
||||
List<File> files = result.paths.map((path) => File(path!)).toList();
|
||||
chatRoomCubit.sendMessage(
|
||||
await chatRoomCubit.sendMessage(
|
||||
chatId: widget.chatId,
|
||||
files: files,
|
||||
);
|
||||
@@ -329,13 +376,13 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
);
|
||||
}
|
||||
|
||||
_messageDate(String date) {
|
||||
_messageDate(DateTime date) {
|
||||
return Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
padding: const EdgeInsets.only(top: 32),
|
||||
child: Text(
|
||||
DateFormat.yMMMMd('RU').format(
|
||||
DateTime.parse(date),
|
||||
date,
|
||||
),
|
||||
style: const TextStyle(
|
||||
height: 1,
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
import 'package:easy_debounce/easy_debounce.dart';
|
||||
import 'package:eatvio_app/core/widgets/loader.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/bloc/chat_select_cubit/chat_select_cubit.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/bloc/chat_select_cubit/chat_select_state.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/widgets/chat_entry_widget.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/widgets/chat_search_bar_widget.dart';
|
||||
import 'package:eatvio_app/core/locator_service.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class ChatSelectScreen extends StatefulWidget {
|
||||
const ChatSelectScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<ChatSelectScreen> createState() => _ChatSelectScreenState();
|
||||
}
|
||||
|
||||
class _ChatSelectScreenState extends State<ChatSelectScreen> {
|
||||
final ChatSelectCubit chatSelectCubit = sl<ChatSelectCubit>();
|
||||
final searchController = TextEditingController();
|
||||
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider<ChatSelectCubit>(
|
||||
create: (context) => chatSelectCubit..getChatRooms(),
|
||||
child: BlocBuilder<ChatSelectCubit, ChatSelectState>(
|
||||
builder: (context, state) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: Colors.white,
|
||||
toolbarHeight: 0,
|
||||
),
|
||||
body: NestedScrollView(
|
||||
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
|
||||
return [
|
||||
SliverPadding(
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
sliver: SliverAppBar(
|
||||
automaticallyImplyLeading: false,
|
||||
stretchTriggerOffset: 1,
|
||||
scrolledUnderElevation: 0,
|
||||
floating: true,
|
||||
snap: true,
|
||||
title: Padding(
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
child: ChatSearchBarWidget(
|
||||
onSuffixIconTap: () => context.read<ChatSelectCubit>().getChatRooms(),
|
||||
onChanged: (query) {
|
||||
if (query.length > 2) {
|
||||
EasyDebounce.debounce(
|
||||
'searchChatRoom',
|
||||
Duration(milliseconds: 300),
|
||||
() => context.read<ChatSelectCubit>().getChatRooms(query: query),
|
||||
);
|
||||
} else {
|
||||
context.read<ChatSelectCubit>().getChatRooms();
|
||||
}
|
||||
},
|
||||
controller: searchController,
|
||||
fillColor: Color(0xFFF0F2F5),
|
||||
hintText: "Поиск",
|
||||
hintStyle: TextStyle(
|
||||
color: Color(0xFF7B8794),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
];
|
||||
},
|
||||
body: stateBuilder(state),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
stateBuilder(state) {
|
||||
if (state is ChatSelectStateLoading) {
|
||||
return Scaffold(
|
||||
body: const Loader(),
|
||||
);
|
||||
} else if (state is ChatSelectStateLoaded) {
|
||||
return _buildChatList(context, state);
|
||||
} else if (state is ChatSelectStateError) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Center(child: Text(state.errorMessage)),
|
||||
);
|
||||
} else {
|
||||
return Scaffold(
|
||||
body: const Loader(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_buildChatList(BuildContext context, ChatSelectStateLoaded 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]);
|
||||
},
|
||||
);
|
||||
}
|
||||
109
lib/features/chat/presentation/pages/chats_screen.dart
Normal file
109
lib/features/chat/presentation/pages/chats_screen.dart
Normal file
@@ -0,0 +1,109 @@
|
||||
import 'package:easy_debounce/easy_debounce.dart';
|
||||
import 'package:eatvio_app/core/utils/enums.dart';
|
||||
import 'package:eatvio_app/core/widgets/loader.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/bloc/chats_cubit/chats_cubit.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/bloc/chats_cubit/chats_state.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/widgets/chat_entry_widget.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/widgets/chat_search_bar_widget.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class ChatsScreen extends StatefulWidget {
|
||||
const ChatsScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<ChatsScreen> createState() => _ChatsScreenState();
|
||||
}
|
||||
|
||||
class _ChatsScreenState extends State<ChatsScreen> {
|
||||
final searchController = TextEditingController();
|
||||
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<ChatsCubit, ChatsState>(
|
||||
builder: (context, state) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: Colors.white,
|
||||
toolbarHeight: 0,
|
||||
),
|
||||
body: NestedScrollView(
|
||||
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
|
||||
return [
|
||||
SliverPadding(
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
sliver: SliverAppBar(
|
||||
automaticallyImplyLeading: false,
|
||||
stretchTriggerOffset: 1,
|
||||
scrolledUnderElevation: 0,
|
||||
floating: true,
|
||||
snap: true,
|
||||
title: Padding(
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
child: ChatSearchBarWidget(
|
||||
onSuffixIconTap: () => context.read<ChatsCubit>().getChatRooms(),
|
||||
onChanged: (query) {
|
||||
if (query.length > 2) {
|
||||
EasyDebounce.debounce(
|
||||
'searchChatRoom',
|
||||
Duration(milliseconds: 300),
|
||||
() => context.read<ChatsCubit>().getChatRooms(query: query),
|
||||
);
|
||||
} else {
|
||||
context.read<ChatsCubit>().getChatRooms();
|
||||
}
|
||||
},
|
||||
controller: searchController,
|
||||
fillColor: Color(0xFFF0F2F5),
|
||||
hintText: "Поиск",
|
||||
hintStyle: TextStyle(
|
||||
color: Color(0xFF7B8794),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
];
|
||||
},
|
||||
body: stateBuilder(state),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
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 Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Center(child: Text(state.errorMessage ?? '')),
|
||||
);
|
||||
} 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]);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -15,118 +15,146 @@ class ChatBubbleWidget extends StatelessWidget {
|
||||
required this.text,
|
||||
required this.isCurrentUser,
|
||||
required this.mediaData,
|
||||
required this.isRead,
|
||||
});
|
||||
|
||||
final String sendTime;
|
||||
final DateTime sendTime;
|
||||
final String text;
|
||||
final bool isCurrentUser;
|
||||
final bool isRead;
|
||||
final List<dynamic> mediaData;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.fromLTRB(isCurrentUser ? 64 : 16, 4, isCurrentUser ? 16 : 64, 4),
|
||||
child: Align(
|
||||
alignment: isCurrentUser ? Alignment.centerRight : Alignment.centerLeft,
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
color: isCurrentUser ? appTheme.gray50 : appTheme.gray60004,
|
||||
borderRadius: mediaData.length > 0
|
||||
? BorderRadius.circular(24)
|
||||
: BorderRadius.horizontal(
|
||||
left: isCurrentUser ? Radius.circular(32) : Radius.circular(16),
|
||||
right: isCurrentUser ? Radius.circular(16) : Radius.circular(24),
|
||||
),
|
||||
),
|
||||
child: Padding(
|
||||
padding: mediaData.length > 0 ? EdgeInsets.all(8) : EdgeInsets.only(top: 8, bottom: 8, left: isCurrentUser ? 16 : 8, right: isCurrentUser ? 8 : 16),
|
||||
child: Column(
|
||||
crossAxisAlignment: isCurrentUser ? CrossAxisAlignment.end : CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (mediaData.isNotEmpty)
|
||||
CustomScrollView(
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
slivers: [
|
||||
SliverList.separated(
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
if (!mediaData[index].toString().contains('.png') &&
|
||||
!mediaData[index].toString().contains('.jpg') &&
|
||||
!mediaData[index].toString().contains('.jpeg')) {
|
||||
return ListTile(
|
||||
contentPadding: EdgeInsets.all(4),
|
||||
horizontalTitleGap: 8,
|
||||
onTap: () async {
|
||||
if (!await launchUrl(Uri.parse(baseUrl + '/storage/' + mediaData[index].toString()))) {
|
||||
throw Exception('Could not launch ${mediaData[index].toString()}');
|
||||
}
|
||||
},
|
||||
leading: Icon(
|
||||
Icons.file_copy_outlined,
|
||||
color: Colors.white,
|
||||
),
|
||||
trailing: Icon(
|
||||
Icons.download_outlined,
|
||||
color: Colors.white,
|
||||
),
|
||||
title: Text(
|
||||
mediaData[index].toString().replaceAll('chat_files/', ''),
|
||||
maxLines: 2,
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 12,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
context.pushTransparentRoute(
|
||||
PhotoViewScreen(
|
||||
imageUrls: mediaData.map((e) => baseUrl + '/storage/' + e.toString()).toList(),
|
||||
index: index,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Hero(
|
||||
tag: baseUrl + '/storage/' + '${mediaData[index]}',
|
||||
transitionOnUserGestures: true,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: baseUrl + '/storage/' + '${mediaData[index]}',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
separatorBuilder: (BuildContext context, int index) => const SizedBox(height: 8),
|
||||
itemCount: mediaData.length,
|
||||
),
|
||||
],
|
||||
),
|
||||
if (mediaData.length > 0 && text.isNotEmpty) SizedBox(height: 8),
|
||||
if (text.isNotEmpty)
|
||||
Text(
|
||||
text,
|
||||
style: TextStyles.textFS13FW400.copyWith(color: appTheme.black, fontSize: 16),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
Padding(
|
||||
padding: mediaData.length > 0 ? const EdgeInsets.only(right: 8, top: 4, left: 8) : EdgeInsets.zero,
|
||||
child: Text(
|
||||
DateTime.parse(sendTime).format('hh:mm'),
|
||||
style: TextStyle(
|
||||
color: Color(0xFF7B8794),
|
||||
height: 1,
|
||||
fontSize: 10,
|
||||
),
|
||||
final size = MediaQuery.sizeOf(context);
|
||||
return Container(
|
||||
width: size.width,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.fromLTRB(isCurrentUser ? 64 : 16, 10, isCurrentUser ? 16 : 64, 4),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
mainAxisAlignment: isCurrentUser ? MainAxisAlignment.end : MainAxisAlignment.start,
|
||||
children: [
|
||||
if (isCurrentUser)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 4, bottom: 4),
|
||||
child: Text(
|
||||
sendTime.format('hh:mm'),
|
||||
style: TextStyle(
|
||||
color: Color(0xFF7B8794),
|
||||
height: 1,
|
||||
fontSize: 10,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Container(
|
||||
constraints: BoxConstraints(maxWidth: size.width * 0.7),
|
||||
decoration: BoxDecoration(
|
||||
color: isCurrentUser ? appTheme.gray50 : appTheme.gray60004,
|
||||
borderRadius: mediaData.length > 0
|
||||
? BorderRadius.circular(24)
|
||||
: BorderRadius.horizontal(
|
||||
left: isCurrentUser ? Radius.circular(32) : Radius.circular(16),
|
||||
right: isCurrentUser ? Radius.circular(16) : Radius.circular(24),
|
||||
),
|
||||
),
|
||||
child: Padding(
|
||||
padding:
|
||||
mediaData.isNotEmpty ? EdgeInsets.all(8) : EdgeInsets.only(top: 8, bottom: 8, left: isCurrentUser ? 16 : 8, right: isCurrentUser ? 8 : 16),
|
||||
child: Column(
|
||||
crossAxisAlignment: isCurrentUser ? CrossAxisAlignment.end : CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (mediaData.isNotEmpty)
|
||||
SizedBox(
|
||||
width: size.width * 0.7,
|
||||
child: CustomScrollView(
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
slivers: [
|
||||
SliverList.separated(
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
if (!mediaData[index].toString().contains('.png') &&
|
||||
!mediaData[index].toString().contains('.jpg') &&
|
||||
!mediaData[index].toString().contains('.jpeg')) {
|
||||
return ListTile(
|
||||
contentPadding: EdgeInsets.all(4),
|
||||
horizontalTitleGap: 8,
|
||||
onTap: () async {
|
||||
if (!await launchUrl(Uri.parse(baseUrl + '/storage/' + mediaData[index].toString()))) {
|
||||
throw Exception('Could not launch ${mediaData[index].toString()}');
|
||||
}
|
||||
},
|
||||
leading: Icon(
|
||||
Icons.file_copy_outlined,
|
||||
color: Colors.white,
|
||||
),
|
||||
trailing: Icon(
|
||||
Icons.download_outlined,
|
||||
color: Colors.white,
|
||||
),
|
||||
title: Text(
|
||||
mediaData[index].toString().replaceAll('chat_files/', ''),
|
||||
maxLines: 2,
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 12,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
context.pushTransparentRoute(
|
||||
PhotoViewScreen(
|
||||
imageUrls: mediaData.map((e) => baseUrl + '/storage/' + e.toString()).toList(),
|
||||
index: index,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Hero(
|
||||
tag: baseUrl + '/storage/' + '${mediaData[index]}',
|
||||
transitionOnUserGestures: true,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: baseUrl + '/storage/' + '${mediaData[index]}',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
separatorBuilder: (BuildContext context, int index) => const SizedBox(height: 8),
|
||||
itemCount: mediaData.length,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (mediaData.isNotEmpty && text.isNotEmpty) SizedBox(height: 8),
|
||||
if (text.isNotEmpty)
|
||||
Text(
|
||||
text,
|
||||
style: TextStyles.textFS13FW400.copyWith(color: appTheme.black, fontSize: 16),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (!isCurrentUser)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 4, bottom: 4),
|
||||
child: Text(
|
||||
sendTime.format('hh:mm'),
|
||||
style: TextStyle(
|
||||
color: Color(0xFF7B8794),
|
||||
height: 1,
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -2,7 +2,9 @@ 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/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 {
|
||||
@@ -18,15 +20,6 @@ class ChatEntryWidget extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _ChatEntryWidgetState extends State<ChatEntryWidget> {
|
||||
LastMessageClass? lastMessage;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (widget.chatRoom.lastMessage is Map<String, dynamic>) {
|
||||
lastMessage = LastMessageClass.fromJson(widget.chatRoom.lastMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -34,10 +27,13 @@ class _ChatEntryWidgetState extends State<ChatEntryWidget> {
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
onTap: () => GoRouter.of(context).pushNamed(
|
||||
'chatScreen',
|
||||
extra: widget.chatRoom.id.toString(),
|
||||
extra: {
|
||||
'chatId': widget.chatRoom.id.toString(),
|
||||
'chatsCubit': context.read<ChatsCubit>(),
|
||||
},
|
||||
),
|
||||
child: Ink(
|
||||
padding: EdgeInsets.all(16),
|
||||
padding: EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
color: Color(0xFFF6FAFF),
|
||||
@@ -54,39 +50,51 @@ class _ChatEntryWidgetState extends State<ChatEntryWidget> {
|
||||
backgroundColor: Colors.white,
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
widget.chatRoom.users.toChatUser.name.length <= 20
|
||||
? widget.chatRoom.users.toChatUser.name
|
||||
: widget.chatRoom.users.toChatUser.name.substring(0, 20) + '...',
|
||||
style: theme.textTheme.titleMedium,
|
||||
),
|
||||
Spacer(),
|
||||
if (lastMessage != null)
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 8),
|
||||
child: Text(
|
||||
lastMessage!.updatedAt.format('dd MMM', 'ru'),
|
||||
style: theme.textTheme.bodyMedium,
|
||||
),
|
||||
),
|
||||
],
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
widget.chatRoom.users.toChatUser.name.length <= 20
|
||||
? widget.chatRoom.users.toChatUser.name
|
||||
: widget.chatRoom.users.toChatUser.name.substring(0, 20) + '...',
|
||||
style: theme.textTheme.titleMedium,
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
if (widget.chatRoom.lastMessage != null)
|
||||
Text(
|
||||
widget.chatRoom.lastMessage!.data.toString().trim(),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: CustomTextStyles.bodyMediumBluegray800,
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
if (lastMessage != null)
|
||||
Text(
|
||||
lastMessage!.data.toString().trim(),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: CustomTextStyles.bodyMediumBluegray800,
|
||||
],
|
||||
),
|
||||
Spacer(),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
if (widget.chatRoom.lastMessage != null)
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 8),
|
||||
child: Text(
|
||||
widget.chatRoom.lastMessage!.updatedAt.format('dd MMM', 'ru'),
|
||||
style: theme.textTheme.bodyMedium,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
if (widget.chatRoom.unreadMessagesCount > 0)
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: appTheme.blueA400,
|
||||
),
|
||||
child: Text(
|
||||
widget.chatRoom.unreadMessagesCount.toString(),
|
||||
style: TextStyles.textXSSemibold.copyWith(color: appTheme.whiteA700),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
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';
|
||||
@@ -10,10 +12,18 @@ import 'package:http_parser/http_parser.dart';
|
||||
class ChatRepository {
|
||||
final ChatService chatService;
|
||||
|
||||
final _newUserMessagesController = StreamController<ChatMessageModel>();
|
||||
|
||||
Stream<ChatMessageModel> get newUserMessagesStream => _newUserMessagesController.stream;
|
||||
|
||||
ChatRepository({
|
||||
required this.chatService,
|
||||
});
|
||||
|
||||
void emitNewMessageToChats(ChatMessageModel message) {
|
||||
_newUserMessagesController.add(message);
|
||||
}
|
||||
|
||||
Future<void> sendMessage({
|
||||
required String chatId,
|
||||
String? data,
|
||||
@@ -66,7 +76,7 @@ class ChatRepository {
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<ChatRoomModel> getChatRoomIdByUserSlug({required String slug}) async {
|
||||
try {
|
||||
@@ -75,4 +85,12 @@ class ChatRepository {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> markMessagesAsRead(String chatId, List<int> messageIds) async {
|
||||
try {
|
||||
await chatService.markMessagesAsRead(id: chatId, body: {'messages_ids': messageIds});
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,4 +38,7 @@ abstract class ChatService {
|
||||
Future<ChatRoomModel> getChatRoomIdByUserSlug({
|
||||
@Path() required String user,
|
||||
});
|
||||
|
||||
@POST('/api/chat/{id}/messages/markAsRead')
|
||||
Future<void> markMessagesAsRead({@Path() required String id, @Body() required Map<String, List<int>> body});
|
||||
}
|
||||
|
||||
@@ -167,6 +167,29 @@ class _ChatService implements ChatService {
|
||||
return _value;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> markMessagesAsRead({
|
||||
required String id,
|
||||
required Map<String, List<int>> body,
|
||||
}) async {
|
||||
final _extra = <String, dynamic>{};
|
||||
final queryParameters = <String, dynamic>{};
|
||||
final _headers = <String, dynamic>{};
|
||||
final _data = <String, dynamic>{};
|
||||
_data.addAll(body);
|
||||
final _options = _setStreamType<void>(
|
||||
Options(method: 'POST', headers: _headers, extra: _extra)
|
||||
.compose(
|
||||
_dio.options,
|
||||
'/api/chat/${id}/messages/markAsRead',
|
||||
queryParameters: queryParameters,
|
||||
data: _data,
|
||||
)
|
||||
.copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)),
|
||||
);
|
||||
await _dio.fetch<void>(_options);
|
||||
}
|
||||
|
||||
RequestOptions _setStreamType<T>(RequestOptions requestOptions) {
|
||||
if (T != dynamic &&
|
||||
!(requestOptions.responseType == ResponseType.bytes ||
|
||||
|
||||
@@ -2,12 +2,12 @@ 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/core/utils/localization_utils.dart';
|
||||
import 'package:eatvio_app/core/widgets/bottom_sheet_handler_bar.dart';
|
||||
import 'package:eatvio_app/core/widgets/bottom_sheet_with_blur.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_outlined_button.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_text_form_field.dart';
|
||||
import 'package:eatvio_app/core/widgets/loader.dart';
|
||||
import 'package:eatvio_app/core/widgets/main_background_bouble.dart';
|
||||
import 'package:eatvio_app/core/widgets/success_published_diet_bottom_sheet.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/cubit/create_diet_cubit.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/cubit/create_diet_state.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/widgets/day_widget.dart';
|
||||
@@ -48,6 +48,7 @@ class CreateDietScreenContent extends StatefulWidget {
|
||||
class _CreateDietScreenContentState extends State<CreateDietScreenContent> {
|
||||
final nameController = TextEditingController();
|
||||
final descriptionController = TextEditingController();
|
||||
final scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -65,49 +66,22 @@ class _CreateDietScreenContentState extends State<CreateDietScreenContent> {
|
||||
builder: (context, state) {
|
||||
if (state.published) {
|
||||
Future.delayed(Duration(milliseconds: 500), () {
|
||||
context.pop('${state.dietData.name ?? 'Диета'}');
|
||||
context.pop();
|
||||
showBottomSheetWithBlur(
|
||||
userRootNavigator: true,
|
||||
context: context,
|
||||
child: SuccessPublishedDietBottomSheet(
|
||||
title: '${state.dietData.name ?? 'Диета'}',
|
||||
),
|
||||
);
|
||||
});
|
||||
} else if (state.drafted) {
|
||||
Future.delayed(Duration(milliseconds: 500), () {
|
||||
context.pop('${state.dietData.name ?? 'Диета'}');
|
||||
context.pop();
|
||||
showBottomSheetWithBlur(
|
||||
context: context,
|
||||
child: Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
BottomSheetHandlerBar(),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Text(
|
||||
'${state.dietData.name ?? 'Диета'} сохраненна в черновиках',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: CustomOutlinedButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context, rootNavigator: true).pop();
|
||||
},
|
||||
text: 'Хорошо',
|
||||
height: 52,
|
||||
buttonTextStyle: TextStyles.textSSemibold.copyWith(color: appTheme.whiteA700),
|
||||
buttonStyle: ButtonStyle(
|
||||
side: WidgetStatePropertyAll(BorderSide.none),
|
||||
backgroundColor: WidgetStatePropertyAll(appTheme.blueA400),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
],
|
||||
child: SuccessPublishedDietBottomSheet(
|
||||
title: '${state.dietData.name ?? 'Диета'} сохраненна в черновиках',
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'package:easy_debounce/easy_debounce.dart';
|
||||
import 'package:eatvio_app/core/widgets/add_item_button.dart';
|
||||
import 'package:eatvio_app/core/widgets/bottom_sheet_with_blur.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_search_bar.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/create_diet_screen.dart';
|
||||
import 'package:eatvio_app/features/create_plan/presentation/create_plan_screen.dart';
|
||||
@@ -15,7 +14,6 @@ import 'package:eatvio_app/features/feed/presentation/widgets/chip_group.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/widgets/consultants.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/widgets/diets.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/widgets/plans.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/widgets/success_published_diet_bottom_sheet.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/widgets/tags_modal_widget.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/plans_cubit/plans_cubit.dart';
|
||||
import 'package:eatvio_app/core/locator_service.dart';
|
||||
@@ -263,16 +261,7 @@ class _FeedScreenContentState extends State<FeedScreenContent> {
|
||||
2 => AddItemButton(
|
||||
onTap: state.profile?.roles.contains('consultant') ?? false
|
||||
? () async {
|
||||
final result = await GoRouter.of(context).pushNamed<String?>(CreateDietScreen.name);
|
||||
if (result != null) {
|
||||
showBottomSheetWithBlur(
|
||||
userRootNavigator: true,
|
||||
context: context,
|
||||
child: SuccessPublishedDietBottomSheet(
|
||||
title: result,
|
||||
),
|
||||
);
|
||||
}
|
||||
await GoRouter.of(context).pushNamed(CreateDietScreen.name);
|
||||
}
|
||||
: null,
|
||||
),
|
||||
|
||||
@@ -278,8 +278,7 @@ class MyDietsCubit extends Cubit<MyDietsState> {
|
||||
|
||||
Future<bool> deleteDiet(int dietId) async {
|
||||
try {
|
||||
await myDietsRepository.deleteDiet(dietId);
|
||||
await loadAllDiets();
|
||||
await myDietsRepository.deleteDiet(dietId);
|
||||
return true;
|
||||
} catch (e) {
|
||||
emit(
|
||||
@@ -289,16 +288,29 @@ class MyDietsCubit extends Cubit<MyDietsState> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<String?> publishDiet(int dietId) async {
|
||||
Future<bool> publishDiet(int dietId) async {
|
||||
try {
|
||||
await createDietRepository.updateDiet(
|
||||
dietId: dietId,
|
||||
state: DietState.active,
|
||||
);
|
||||
return null;
|
||||
);
|
||||
return true;
|
||||
} catch (e, st) {
|
||||
log(e.toString(), stackTrace: st);
|
||||
return 'Произошла непредвиденная ошибка';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> unpublishDiet(int dietId) async {
|
||||
try {
|
||||
await createDietRepository.updateDiet(
|
||||
dietId: dietId,
|
||||
state: DietState.draft,
|
||||
);
|
||||
return true;
|
||||
} catch (e, st) {
|
||||
log(e.toString(), stackTrace: st);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,7 +164,10 @@ class MyDietsScreenContent extends StatelessWidget {
|
||||
shrinkWrap: true,
|
||||
physics: BouncingScrollPhysics(),
|
||||
itemBuilder: (context, index) {
|
||||
return MyDietWidget(diet: diets[index]);
|
||||
return MyDietWidget(
|
||||
diet: diets[index],
|
||||
key: ValueKey(diets[index].id),
|
||||
);
|
||||
},
|
||||
separatorBuilder: (context, index) {
|
||||
return SizedBox(height: 20);
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import 'package:eatvio_app/core/app_router.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/widgets/bottom_sheet_handler_bar.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_outlined_button.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class DietDeletedBottomSheet extends StatelessWidget {
|
||||
const DietDeletedBottomSheet({super.key, required this.title});
|
||||
final String title;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final s = S.of(context);
|
||||
return Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
BottomSheetHandlerBar(),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Text(
|
||||
title,
|
||||
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
Text(
|
||||
s.deleted,
|
||||
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: CustomOutlinedButton(
|
||||
onPressed: () {
|
||||
AppRouter.navigatorKey.currentContext?.pop();
|
||||
},
|
||||
text: 'Хорошо',
|
||||
height: 52,
|
||||
buttonTextStyle: TextStyles.textSSemibold.copyWith(color: appTheme.whiteA700),
|
||||
buttonStyle: ButtonStyle(
|
||||
side: WidgetStatePropertyAll(BorderSide.none),
|
||||
backgroundColor: WidgetStatePropertyAll(appTheme.blueA400),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import 'package:eatvio_app/core/app_router.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/widgets/bottom_sheet_handler_bar.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_outlined_button.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class DietDraftedBottomSheet extends StatelessWidget {
|
||||
const DietDraftedBottomSheet({super.key, required this.title});
|
||||
final String title;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final s = S.of(context);
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
BottomSheetHandlerBar(),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Text(
|
||||
title,
|
||||
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
Text(
|
||||
s.diet_has_been_sent_to_draft,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: CustomOutlinedButton(
|
||||
onPressed: () {
|
||||
AppRouter.navigatorKey.currentContext?.pop();
|
||||
},
|
||||
text: 'Хорошо',
|
||||
height: 52,
|
||||
buttonTextStyle: TextStyles.textSSemibold.copyWith(color: appTheme.whiteA700),
|
||||
buttonStyle: ButtonStyle(
|
||||
side: WidgetStatePropertyAll(BorderSide.none),
|
||||
backgroundColor: WidgetStatePropertyAll(appTheme.blueA400),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,21 @@
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:eatvio_app/core/app_router.dart';
|
||||
import 'package:eatvio_app/core/const.dart';
|
||||
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/utils/enums.dart';
|
||||
import 'package:eatvio_app/core/utils/toasts.dart';
|
||||
import 'package:eatvio_app/core/widgets/bottom_sheet_handler_bar.dart';
|
||||
import 'package:eatvio_app/core/widgets/bottom_sheet_with_blur.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_outlined_button.dart';
|
||||
import 'package:eatvio_app/core/widgets/info_row.dart';
|
||||
import 'package:eatvio_app/core/widgets/success_published_diet_bottom_sheet.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/create_diet_screen.dart';
|
||||
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
|
||||
import 'package:eatvio_app/features/my_diets/presentation/cubit/my_diets_cubit.dart';
|
||||
import 'package:eatvio_app/features/my_diets/presentation/cubit/my_diets_state.dart';
|
||||
import 'package:eatvio_app/features/my_diets/presentation/widgets/diet_deleted_bottom_sheet.dart';
|
||||
import 'package:eatvio_app/features/my_diets/presentation/widgets/diet_drafetd_bottom_sheet.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
@@ -60,12 +65,7 @@ class _MyDietWidgetState extends State<MyDietWidget> {
|
||||
bottom: 16,
|
||||
child: SizedBox(
|
||||
width: MediaQuery.sizeOf(context).width,
|
||||
child: InfoRow(
|
||||
diet: widget.diet,
|
||||
itemsBackgroundColor: appTheme.whiteA700,
|
||||
disableDescriptionOfTypes: true,
|
||||
type: ProductType.diet
|
||||
),
|
||||
child: InfoRow(diet: widget.diet, itemsBackgroundColor: appTheme.whiteA700, disableDescriptionOfTypes: true, type: ProductType.diet),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -113,9 +113,18 @@ class _MyDietWidgetState extends State<MyDietWidget> {
|
||||
children: [
|
||||
Expanded(
|
||||
child: CustomOutlinedButton(
|
||||
onPressed: () {
|
||||
onPressed: () async {
|
||||
if (state.selectedStateIndex == 1) {
|
||||
context.read<MyDietsCubit>().publishDiet(widget.diet.id);
|
||||
final result = await context.read<MyDietsCubit>().publishDiet(widget.diet.id);
|
||||
if (result) {
|
||||
showBottomSheetWithBlur(
|
||||
context: context,
|
||||
child: SuccessPublishedDietBottomSheet(title: '${widget.diet.name}'),
|
||||
);
|
||||
await context.read<MyDietsCubit>().loadAllDiets();
|
||||
} else {
|
||||
showErrorToast('Произошла ошибка. Попробуйте ещё раз через некоторое время');
|
||||
}
|
||||
} else if (state.selectedStateIndex == 2) {
|
||||
} else {
|
||||
GoRouter.of(context).pushNamed(CreateDietScreen.name, extra: widget.diet);
|
||||
@@ -171,8 +180,19 @@ class _MyDietWidgetState extends State<MyDietWidget> {
|
||||
children: [
|
||||
Expanded(
|
||||
child: CustomOutlinedButton(
|
||||
onPressed: () {
|
||||
onPressed: () async {
|
||||
if (state.selectedStateIndex == 0) {
|
||||
final result = await context.read<MyDietsCubit>().unpublishDiet(widget.diet.id);
|
||||
if (result) {
|
||||
showBottomSheetWithBlur(
|
||||
context: context,
|
||||
height: 250,
|
||||
child: DietDraftedBottomSheet(title: '${widget.diet.name}'),
|
||||
);
|
||||
await context.read<MyDietsCubit>().loadAllDiets();
|
||||
} else {
|
||||
showErrorToast('Произошла ошибка. Попробуйте ещё раз через некоторое время');
|
||||
}
|
||||
} else {
|
||||
GoRouter.of(context).pushNamed(CreateDietScreen.name, extra: widget.diet);
|
||||
}
|
||||
@@ -194,50 +214,13 @@ class _MyDietWidgetState extends State<MyDietWidget> {
|
||||
CustomOutlinedButton(
|
||||
onPressed: () async {
|
||||
final result = await context.read<MyDietsCubit>().deleteDiet(widget.diet.id);
|
||||
if (result)
|
||||
if (result) {
|
||||
showBottomSheetWithBlur(
|
||||
context: context,
|
||||
child: Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
BottomSheetHandlerBar(),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Text(
|
||||
'${widget.diet.name}',
|
||||
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
Text(
|
||||
s.deleted,
|
||||
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
|
||||
),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: CustomOutlinedButton(
|
||||
onPressed: () {
|
||||
context.pop();
|
||||
},
|
||||
text: 'Хорошо',
|
||||
height: 52,
|
||||
buttonTextStyle: TextStyles.textSSemibold.copyWith(color: appTheme.whiteA700),
|
||||
buttonStyle: ButtonStyle(
|
||||
side: WidgetStatePropertyAll(BorderSide.none),
|
||||
backgroundColor: WidgetStatePropertyAll(appTheme.blueA400),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: DietDeletedBottomSheet(title: widget.diet.name),
|
||||
);
|
||||
await context.read<MyDietsCubit>().loadAllDiets();
|
||||
}
|
||||
},
|
||||
height: 52,
|
||||
width: 52,
|
||||
|
||||
@@ -22,381 +22,352 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
|
||||
final messages = _notInlinedMessages(_notInlinedMessages);
|
||||
static Map<String, Function> _notInlinedMessages(_) => <String, Function>{
|
||||
"Moscow": MessageLookupByLibrary.simpleMessage("Москва"),
|
||||
"Russia": MessageLookupByLibrary.simpleMessage("Россия"),
|
||||
"about_diet": MessageLookupByLibrary.simpleMessage("Об этой диете"),
|
||||
"about_plan": MessageLookupByLibrary.simpleMessage("Об этом плане"),
|
||||
"active": MessageLookupByLibrary.simpleMessage("Активен"),
|
||||
"active_diet_state": MessageLookupByLibrary.simpleMessage("Активная"),
|
||||
"add": MessageLookupByLibrary.simpleMessage("Добавить"),
|
||||
"add_cover": MessageLookupByLibrary.simpleMessage("Добавьте обложку"),
|
||||
"add_measure": MessageLookupByLibrary.simpleMessage("Добавить замер"),
|
||||
"adding_plan": MessageLookupByLibrary.simpleMessage("Добавление плана"),
|
||||
"additional_information": MessageLookupByLibrary.simpleMessage(
|
||||
"Дополнительная информация",
|
||||
),
|
||||
"admin": MessageLookupByLibrary.simpleMessage("Админ"),
|
||||
"all": MessageLookupByLibrary.simpleMessage("Все"),
|
||||
"allergies_presence": MessageLookupByLibrary.simpleMessage(
|
||||
"Наличие аллергии",
|
||||
),
|
||||
"another_form_of_comment": MessageLookupByLibrary.simpleMessage(
|
||||
"комментария",
|
||||
),
|
||||
"another_form_of_day": MessageLookupByLibrary.simpleMessage("дня"),
|
||||
"answer": MessageLookupByLibrary.simpleMessage("Ответить"),
|
||||
"archived": MessageLookupByLibrary.simpleMessage("В архиве"),
|
||||
"authentificate": MessageLookupByLibrary.simpleMessage("Войти"),
|
||||
"average_pressure": MessageLookupByLibrary.simpleMessage(
|
||||
"Средние показатели давления:",
|
||||
),
|
||||
"bodymass_chart": MessageLookupByLibrary.simpleMessage("График ИМТ"),
|
||||
"by_default": MessageLookupByLibrary.simpleMessage("По умолчянию"),
|
||||
"calories": MessageLookupByLibrary.simpleMessage("Калории"),
|
||||
"cancel_diet": MessageLookupByLibrary.simpleMessage("Отменить диету?"),
|
||||
"carb_type": MessageLookupByLibrary.simpleMessage("Мучное"),
|
||||
"carb_type_desc": MessageLookupByLibrary.simpleMessage(
|
||||
"Если вы любите мучные продукты, но хотите придерживаться диеты, вам подходит диета с добавленим мучных блюд на основе цельнозерновых вариантов. В них больше сложных углеводов и клетчатки, что способствует длительному чувству сытости и поддерживает здоровье пищеварительной системы.",
|
||||
),
|
||||
"carbohydrates": MessageLookupByLibrary.simpleMessage("Углеводы"),
|
||||
"chat": MessageLookupByLibrary.simpleMessage("Чат"),
|
||||
"chest": MessageLookupByLibrary.simpleMessage("Грудь"),
|
||||
"chest_circumference": MessageLookupByLibrary.simpleMessage("Обхват груди"),
|
||||
"choose_diet_duration": MessageLookupByLibrary.simpleMessage(
|
||||
"Выберите срок диеты",
|
||||
),
|
||||
"choose_plan_duration": MessageLookupByLibrary.simpleMessage(
|
||||
"Выберите срок плана",
|
||||
),
|
||||
"choose_start_diet_date": MessageLookupByLibrary.simpleMessage(
|
||||
"Выберите дату старты диеты. Она отобразиться у Вас в дневнике",
|
||||
),
|
||||
"circumference_empty": MessageLookupByLibrary.simpleMessage(
|
||||
"Все замеры обязательны к заполнению",
|
||||
),
|
||||
"circumference_is_not_a_number": MessageLookupByLibrary.simpleMessage(
|
||||
"Все замеры должны быть числами",
|
||||
),
|
||||
"circumferences_chart": MessageLookupByLibrary.simpleMessage(
|
||||
"График обхватов",
|
||||
),
|
||||
"city": MessageLookupByLibrary.simpleMessage("Город"),
|
||||
"city_of_living": MessageLookupByLibrary.simpleMessage("Город проживания"),
|
||||
"comfort": MessageLookupByLibrary.simpleMessage("Комфорт"),
|
||||
"comment": MessageLookupByLibrary.simpleMessage("комментарий"),
|
||||
"comments": MessageLookupByLibrary.simpleMessage("Комментарии"),
|
||||
"comments_plural": MessageLookupByLibrary.simpleMessage("комментариев"),
|
||||
"complain": MessageLookupByLibrary.simpleMessage("Пожаловаться"),
|
||||
"confirm": MessageLookupByLibrary.simpleMessage("Подтвердить"),
|
||||
"continueButton": MessageLookupByLibrary.simpleMessage("Продолжить"),
|
||||
"continue_": MessageLookupByLibrary.simpleMessage("Продолжить"),
|
||||
"copied": MessageLookupByLibrary.simpleMessage("cкопирован"),
|
||||
"copy_link": MessageLookupByLibrary.simpleMessage("Скопировать ссылку"),
|
||||
"could_not_cancel_diet": MessageLookupByLibrary.simpleMessage(
|
||||
"Не удалось отменить диету",
|
||||
),
|
||||
"country": MessageLookupByLibrary.simpleMessage("Страна"),
|
||||
"create_diet": MessageLookupByLibrary.simpleMessage("Создание диеты"),
|
||||
"customer_price": MessageLookupByLibrary.simpleMessage(
|
||||
"Цена для покупателя",
|
||||
),
|
||||
"date_of_birth": MessageLookupByLibrary.simpleMessage("Дата рождения"),
|
||||
"day": MessageLookupByLibrary.simpleMessage("День"),
|
||||
"days": MessageLookupByLibrary.simpleMessage("дней"),
|
||||
"deleted": MessageLookupByLibrary.simpleMessage("Удалена"),
|
||||
"diary": MessageLookupByLibrary.simpleMessage("Дневник"),
|
||||
"diet": MessageLookupByLibrary.simpleMessage("Диета"),
|
||||
"diet_author": MessageLookupByLibrary.simpleMessage("Автор диеты"),
|
||||
"diet_plan": MessageLookupByLibrary.simpleMessage("План диеты"),
|
||||
"diet_started": MessageLookupByLibrary.simpleMessage("Диета уже начата"),
|
||||
"diet_state": MessageLookupByLibrary.simpleMessage("Статус диеты"),
|
||||
"diet_type": MessageLookupByLibrary.simpleMessage("Тип диеты"),
|
||||
"do_you_have_hypertension_tendency": MessageLookupByLibrary.simpleMessage(
|
||||
"Есть ли у вас гипертония?",
|
||||
),
|
||||
"do_you_have_hypotension_tendency": MessageLookupByLibrary.simpleMessage(
|
||||
"Есть ли у вас гипотония?",
|
||||
),
|
||||
"do_you_take_pills": MessageLookupByLibrary.simpleMessage(
|
||||
"Принимаете ли вы лекарства или бады?",
|
||||
),
|
||||
"down_pressure": MessageLookupByLibrary.simpleMessage(
|
||||
"Нижние показатели давления:",
|
||||
),
|
||||
"draft": MessageLookupByLibrary.simpleMessage("Черновик"),
|
||||
"drafted": MessageLookupByLibrary.simpleMessage("Черновики"),
|
||||
"eating_behavior": MessageLookupByLibrary.simpleMessage(
|
||||
"Пищевое поведение",
|
||||
),
|
||||
"eating_behavior_type": MessageLookupByLibrary.simpleMessage(
|
||||
"Формирование пищевого поведения",
|
||||
),
|
||||
"eating_behavior_type_desc": MessageLookupByLibrary.simpleMessage(
|
||||
"Формирование здорового пищевого поведения — это процесс, который включает в себя изменение привычек и отношения к еде. Он направлен на то, чтобы помочь людям научиться правильно питаться и поддерживать здоровый образ жизни.Основные принципы формирования здорового пищевого поведения: \n● Разнообразие продуктов; \n● Сбалансированный рацион; \n● Питьевой режим; \n● Ограничение вредных продуктов; \n● Регулярные приёмы пищи; \n● Умеренность;Осознанное питание; \n● Физическая активность;",
|
||||
),
|
||||
"economy": MessageLookupByLibrary.simpleMessage("Эконом"),
|
||||
"edit": MessageLookupByLibrary.simpleMessage("Редактировать"),
|
||||
"email": MessageLookupByLibrary.simpleMessage("Электронная почта"),
|
||||
"email_empty": MessageLookupByLibrary.simpleMessage(
|
||||
"Необходимо ввести адрес электронной почты",
|
||||
),
|
||||
"email_invalid": MessageLookupByLibrary.simpleMessage(
|
||||
"Некорректный адрес электронной почты",
|
||||
),
|
||||
"enter_additional_information": MessageLookupByLibrary.simpleMessage(
|
||||
"Введите любую дополнительную информацию на своё усмотрение:",
|
||||
),
|
||||
"enter_diet_description": MessageLookupByLibrary.simpleMessage(
|
||||
"Введите описание диеты",
|
||||
),
|
||||
"enter_diet_name": MessageLookupByLibrary.simpleMessage(
|
||||
"Выведите название диеты",
|
||||
),
|
||||
"enter_information": MessageLookupByLibrary.simpleMessage(
|
||||
"Введите информацию...",
|
||||
),
|
||||
"exit": MessageLookupByLibrary.simpleMessage("Выйти"),
|
||||
"expand": MessageLookupByLibrary.simpleMessage("Показать полностью"),
|
||||
"fats": MessageLookupByLibrary.simpleMessage("Жиры"),
|
||||
"favorite_foods": MessageLookupByLibrary.simpleMessage("Любимые продукты"),
|
||||
"favorite_unfavorite_foods": MessageLookupByLibrary.simpleMessage(
|
||||
"Ваши любимые/нелюбимые продукты питания?",
|
||||
),
|
||||
"female": MessageLookupByLibrary.simpleMessage("Женский"),
|
||||
"fill_in_information": MessageLookupByLibrary.simpleMessage(
|
||||
"Заполните информацию:",
|
||||
),
|
||||
"finish": MessageLookupByLibrary.simpleMessage("Завершить"),
|
||||
"first_name": MessageLookupByLibrary.simpleMessage("Имя"),
|
||||
"first_name_empty": MessageLookupByLibrary.simpleMessage(
|
||||
"Имя обязательно для заполнения",
|
||||
),
|
||||
"first_name_short": MessageLookupByLibrary.simpleMessage(
|
||||
"В имени должен быть минимум 1 символ",
|
||||
),
|
||||
"fit_type": MessageLookupByLibrary.simpleMessage("Поддержание формы"),
|
||||
"fit_type_desc": MessageLookupByLibrary.simpleMessage(
|
||||
"План питания для поддержания формы сбалансированный и разнообразный, чтобы обеспечить организм всеми необходимыми питательными веществами. Общие принципы: \n● Дробное питание; \n● Разнообразие продуктов; \n● Контроль порций; \n● Питьевой режим; \n● Ограничение вредных продуктов;",
|
||||
),
|
||||
"fitness": MessageLookupByLibrary.simpleMessage("Поддержка формы"),
|
||||
"from": MessageLookupByLibrary.simpleMessage("от"),
|
||||
"from_a_to_z": MessageLookupByLibrary.simpleMessage("Название: А-Я"),
|
||||
"from_z_to_a": MessageLookupByLibrary.simpleMessage("Название: Я-А"),
|
||||
"gallery": MessageLookupByLibrary.simpleMessage("Галерея"),
|
||||
"general_info": MessageLookupByLibrary.simpleMessage("Общая информация"),
|
||||
"gr": MessageLookupByLibrary.simpleMessage("гр"),
|
||||
"grams": MessageLookupByLibrary.simpleMessage("гр"),
|
||||
"has_alergy": MessageLookupByLibrary.simpleMessage("Наличие аллергии"),
|
||||
"has_hyper": MessageLookupByLibrary.simpleMessage(
|
||||
"Склонность к гипертонии",
|
||||
),
|
||||
"has_hypo": MessageLookupByLibrary.simpleMessage("Склонность к гипотонии"),
|
||||
"height": MessageLookupByLibrary.simpleMessage("Рост"),
|
||||
"height_measurements": MessageLookupByLibrary.simpleMessage("Замер роста"),
|
||||
"hide": MessageLookupByLibrary.simpleMessage("Свернуть"),
|
||||
"hip_circumference": MessageLookupByLibrary.simpleMessage("Обхват бедер"),
|
||||
"hips": MessageLookupByLibrary.simpleMessage("Бедра"),
|
||||
"in_progress": MessageLookupByLibrary.simpleMessage("В процессе"),
|
||||
"inactive_diet_state": MessageLookupByLibrary.simpleMessage("Черновик"),
|
||||
"initial_measurements": MessageLookupByLibrary.simpleMessage(
|
||||
"Первичные замеры",
|
||||
),
|
||||
"label": MessageLookupByLibrary.simpleMessage("Название"),
|
||||
"language": MessageLookupByLibrary.simpleMessage("Язык"),
|
||||
"last_name": MessageLookupByLibrary.simpleMessage("Фамилия"),
|
||||
"last_name_empty": MessageLookupByLibrary.simpleMessage(
|
||||
"Фамилия обязательна для заполнения",
|
||||
),
|
||||
"last_name_short": MessageLookupByLibrary.simpleMessage(
|
||||
"В фамилии должен быть минимум 6 символов",
|
||||
),
|
||||
"lbl_english": MessageLookupByLibrary.simpleMessage("English"),
|
||||
"light_type": MessageLookupByLibrary.simpleMessage("Легкая"),
|
||||
"light_type_desc": MessageLookupByLibrary.simpleMessage(
|
||||
"С некоторыми видами диет можно употреблять алкоголь в умеренных количествах. Рекомендуется совмещать вместе с низкокалорийными закусками.",
|
||||
),
|
||||
"liked_groceries": MessageLookupByLibrary.simpleMessage("Любимые продукты"),
|
||||
"link_was_copied": MessageLookupByLibrary.simpleMessage(
|
||||
"Ссылка успешно скопирована",
|
||||
),
|
||||
"loading": MessageLookupByLibrary.simpleMessage("Загрузка..."),
|
||||
"lower": MessageLookupByLibrary.simpleMessage("Нижнее"),
|
||||
"male": MessageLookupByLibrary.simpleMessage("Мужской"),
|
||||
"meal": MessageLookupByLibrary.simpleMessage("Приём пищи"),
|
||||
"meat": MessageLookupByLibrary.simpleMessage("Мясо"),
|
||||
"meat_type": MessageLookupByLibrary.simpleMessage("С мясом"),
|
||||
"meat_type_desc": MessageLookupByLibrary.simpleMessage(
|
||||
"Диета с мясом полезная и сбалансированная. Включает в себя нежирное мясо: курицу, индейку, кролика или говядину. В сочетании с овощами получаете все необходимые витамины и минералы. Не забывайте о порциях и старайтесь есть медленно, прислушиваясь к своему организму.",
|
||||
),
|
||||
"milliliter": MessageLookupByLibrary.simpleMessage("мл"),
|
||||
"minimal_customer_price": MessageLookupByLibrary.simpleMessage(
|
||||
"Минимальная цена для покупателя: 1200₽",
|
||||
),
|
||||
"most_new": MessageLookupByLibrary.simpleMessage("Самые новые"),
|
||||
"most_old": MessageLookupByLibrary.simpleMessage("Самые старые"),
|
||||
"msg_network_err": MessageLookupByLibrary.simpleMessage("Сетевая ошибка!"),
|
||||
"msg_something_went_wrong": MessageLookupByLibrary.simpleMessage(
|
||||
"Что то пошло не так!",
|
||||
),
|
||||
"my_blog": MessageLookupByLibrary.simpleMessage("Мой блог"),
|
||||
"my_diets": MessageLookupByLibrary.simpleMessage("Мои диеты"),
|
||||
"my_plans": MessageLookupByLibrary.simpleMessage("Мои планы"),
|
||||
"my_settings": MessageLookupByLibrary.simpleMessage("Мои настройки"),
|
||||
"name_empty": MessageLookupByLibrary.simpleMessage(
|
||||
"Имя пользователя обязательно для заполнения",
|
||||
),
|
||||
"name_short": MessageLookupByLibrary.simpleMessage(
|
||||
"В имени пользователя должно быть минимум 6 символов",
|
||||
),
|
||||
"no": MessageLookupByLibrary.simpleMessage("Нет"),
|
||||
"no_account": MessageLookupByLibrary.simpleMessage("У меня нет аккаунта"),
|
||||
"not_liked_groceries": MessageLookupByLibrary.simpleMessage(
|
||||
"Не любимые продукты",
|
||||
),
|
||||
"one_option": MessageLookupByLibrary.simpleMessage("1 опция"),
|
||||
"option": MessageLookupByLibrary.simpleMessage("Опция"),
|
||||
"option_content": MessageLookupByLibrary.simpleMessage("Содержание опции"),
|
||||
"option_content_hint_text": MessageLookupByLibrary.simpleMessage(
|
||||
"На связи 7 дней в неделю",
|
||||
),
|
||||
"option_desc": MessageLookupByLibrary.simpleMessage("Описание опции"),
|
||||
"option_desc_hint_text": MessageLookupByLibrary.simpleMessage(
|
||||
"Этот план питания для похудения на 7 дней сбалансированный и разнообразный",
|
||||
),
|
||||
"option_duration": MessageLookupByLibrary.simpleMessage(
|
||||
"Продолжительность опции",
|
||||
),
|
||||
"option_personal_diet_desc": MessageLookupByLibrary.simpleMessage(
|
||||
"Опция подразумевает создание индивидуальной диеты",
|
||||
),
|
||||
"option_title": MessageLookupByLibrary.simpleMessage("Заголовок опции"),
|
||||
"order": MessageLookupByLibrary.simpleMessage("Порядок"),
|
||||
"other_info": MessageLookupByLibrary.simpleMessage("Прочая информация"),
|
||||
"password": MessageLookupByLibrary.simpleMessage("Пароль"),
|
||||
"password_confirmation": MessageLookupByLibrary.simpleMessage(
|
||||
"Подтвердите пароль",
|
||||
),
|
||||
"password_confirmation_mismatch": MessageLookupByLibrary.simpleMessage(
|
||||
"Пароли не совпадают",
|
||||
),
|
||||
"password_empty": MessageLookupByLibrary.simpleMessage(
|
||||
"Пароль обязателен для заполнения",
|
||||
),
|
||||
"password_short": MessageLookupByLibrary.simpleMessage(
|
||||
"В пароле должно быть минимум 6 символов",
|
||||
),
|
||||
"pcs": MessageLookupByLibrary.simpleMessage("шт"),
|
||||
"personal": MessageLookupByLibrary.simpleMessage("Персональные"),
|
||||
"personal_diet_state": MessageLookupByLibrary.simpleMessage("Персональная"),
|
||||
"photo": MessageLookupByLibrary.simpleMessage("Фото"),
|
||||
"physical_fitness": MessageLookupByLibrary.simpleMessage(
|
||||
"Физическая форма",
|
||||
),
|
||||
"place_of_living": MessageLookupByLibrary.simpleMessage("Место проживания"),
|
||||
"plan_author": MessageLookupByLibrary.simpleMessage("Автор плана"),
|
||||
"plan_desc": MessageLookupByLibrary.simpleMessage("Описание плана"),
|
||||
"plan_desc_example": MessageLookupByLibrary.simpleMessage(
|
||||
"Большое подробное, привлекательное описание плана",
|
||||
),
|
||||
"plan_duration": MessageLookupByLibrary.simpleMessage("Срок плана"),
|
||||
"plan_label_desc": MessageLookupByLibrary.simpleMessage(
|
||||
"План для поддержания формы",
|
||||
),
|
||||
"plan_type": MessageLookupByLibrary.simpleMessage("Тип плана"),
|
||||
"plans_complete": MessageLookupByLibrary.simpleMessage("Пройденные планы"),
|
||||
"popular": MessageLookupByLibrary.simpleMessage("Популярные"),
|
||||
"preferred_language": MessageLookupByLibrary.simpleMessage(
|
||||
"Предпочитаемый язык общения",
|
||||
),
|
||||
"pressure": MessageLookupByLibrary.simpleMessage("Давление"),
|
||||
"pressure_empty": MessageLookupByLibrary.simpleMessage(
|
||||
"Все показатели давления обязательны к заполнению",
|
||||
),
|
||||
"pressure_is_not_a_number": MessageLookupByLibrary.simpleMessage(
|
||||
"Все показатели давления должны быть числами",
|
||||
),
|
||||
"preview": MessageLookupByLibrary.simpleMessage("Превью"),
|
||||
"price": MessageLookupByLibrary.simpleMessage("Цена"),
|
||||
"price_explanation": MessageLookupByLibrary.simpleMessage(
|
||||
"Разница в ценах, это комиссия Итвио",
|
||||
),
|
||||
"profile": MessageLookupByLibrary.simpleMessage("Профиль"),
|
||||
"proteins": MessageLookupByLibrary.simpleMessage("Белки"),
|
||||
"publish": MessageLookupByLibrary.simpleMessage("Опубликовать"),
|
||||
"published": MessageLookupByLibrary.simpleMessage("Опубликованные"),
|
||||
"removeFromActive": MessageLookupByLibrary.simpleMessage(
|
||||
"Снять с публикации",
|
||||
),
|
||||
"save": MessageLookupByLibrary.simpleMessage("Сохранить"),
|
||||
"services": MessageLookupByLibrary.simpleMessage("Оказание услуг"),
|
||||
"settings": MessageLookupByLibrary.simpleMessage("Настройки"),
|
||||
"sex": MessageLookupByLibrary.simpleMessage("Пол"),
|
||||
"share": MessageLookupByLibrary.simpleMessage("Поделиться"),
|
||||
"skip": MessageLookupByLibrary.simpleMessage("Пропустить"),
|
||||
"slim": MessageLookupByLibrary.simpleMessage("Похудение"),
|
||||
"slim_type": MessageLookupByLibrary.simpleMessage("Похудение"),
|
||||
"slim_type_desc": MessageLookupByLibrary.simpleMessage(
|
||||
"План питания для похудения должен быть разработан с учётом индивидуальных особенностей организма, возраста, пола, уровня физической активности и состояния здоровья. Общие принципы: \n● Снижение калорийности; \n● Сбалансированный рацион; \n● Разнообразие продуктов; \n● Питьевой режим; \n● Ограничение вредных продуктов;",
|
||||
),
|
||||
"sport_hobbies": MessageLookupByLibrary.simpleMessage(
|
||||
"Спортивные увлечения",
|
||||
),
|
||||
"standard": MessageLookupByLibrary.simpleMessage("Стандарт"),
|
||||
"startDiet": MessageLookupByLibrary.simpleMessage("Начать диету"),
|
||||
"takes_pills": MessageLookupByLibrary.simpleMessage("Принимает лекарства"),
|
||||
"tell_your_schedule": MessageLookupByLibrary.simpleMessage(
|
||||
"Расскажите в свободной форме о том как просыпаетесь, когда едите, когда ложитесь спать:",
|
||||
),
|
||||
"three_options": MessageLookupByLibrary.simpleMessage("3 опции"),
|
||||
"time": MessageLookupByLibrary.simpleMessage("Время прохождения"),
|
||||
"toOffer": MessageLookupByLibrary.simpleMessage("Предложить"),
|
||||
"to_draft": MessageLookupByLibrary.simpleMessage("В черновик"),
|
||||
"unfavorite_foods": MessageLookupByLibrary.simpleMessage(
|
||||
"Нелюбимые продукты",
|
||||
),
|
||||
"up_pressure": MessageLookupByLibrary.simpleMessage(
|
||||
"Верхние показатели давления:",
|
||||
),
|
||||
"upper": MessageLookupByLibrary.simpleMessage("Верхнее"),
|
||||
"user_authorization": MessageLookupByLibrary.simpleMessage(
|
||||
"Аутентификация",
|
||||
),
|
||||
"user_data": MessageLookupByLibrary.simpleMessage("Данные пользователя"),
|
||||
"user_registration": MessageLookupByLibrary.simpleMessage(
|
||||
"Регистрация пользователя",
|
||||
),
|
||||
"username": MessageLookupByLibrary.simpleMessage("Имя пользователя"),
|
||||
"vegan": MessageLookupByLibrary.simpleMessage("Веган."),
|
||||
"vegan_type": MessageLookupByLibrary.simpleMessage("Вегетарианская"),
|
||||
"vegan_type_desc": MessageLookupByLibrary.simpleMessage(
|
||||
"Диета основана на потреблении растительной пищи и отказе от продуктов животного происхождения. Такой тип питания может быть разнообразным и вкусным, а также полезным для здоровья.",
|
||||
),
|
||||
"waist": MessageLookupByLibrary.simpleMessage("Талия"),
|
||||
"waist_circumference": MessageLookupByLibrary.simpleMessage("Обхват талии"),
|
||||
"weight": MessageLookupByLibrary.simpleMessage("Вес"),
|
||||
"weight_chart": MessageLookupByLibrary.simpleMessage("График веса"),
|
||||
"weight_measurements": MessageLookupByLibrary.simpleMessage("Замер веса"),
|
||||
"wellness": MessageLookupByLibrary.simpleMessage("Улучшение самочувствия"),
|
||||
"wellness_type": MessageLookupByLibrary.simpleMessage(
|
||||
"Улучшение самочувствия",
|
||||
),
|
||||
"wellness_type_desc": MessageLookupByLibrary.simpleMessage(
|
||||
"Если вы любите мучные продукты, но хотите придерживаться диеты, вам подходит диета с добавленим мучных блюд на основе цельнозерновых вариантов. В них больше сложных углеводов и клетчатки, что способствует длительному чувству сытости и поддерживает здоровье пищеварительной системы.",
|
||||
),
|
||||
"what_is_your_name": MessageLookupByLibrary.simpleMessage("Как вас зовут?"),
|
||||
"wrong_credentials": MessageLookupByLibrary.simpleMessage(
|
||||
"Неверные данные пользователя",
|
||||
),
|
||||
"you_will_get": MessageLookupByLibrary.simpleMessage("Вы получите"),
|
||||
"your_blood_pressure": MessageLookupByLibrary.simpleMessage(
|
||||
"Ваше артериальное давление?",
|
||||
),
|
||||
"your_favorite_sports": MessageLookupByLibrary.simpleMessage(
|
||||
"Ваши спортивные увлечения?",
|
||||
),
|
||||
"your_gender": MessageLookupByLibrary.simpleMessage("Ваш пол?"),
|
||||
"your_height": MessageLookupByLibrary.simpleMessage("Ваш рост:"),
|
||||
"your_schedule": MessageLookupByLibrary.simpleMessage("Ваш режим дня?"),
|
||||
"your_weight": MessageLookupByLibrary.simpleMessage("Ваш вес:"),
|
||||
};
|
||||
"Moscow": MessageLookupByLibrary.simpleMessage("Москва"),
|
||||
"Russia": MessageLookupByLibrary.simpleMessage("Россия"),
|
||||
"about_diet": MessageLookupByLibrary.simpleMessage("Об этой диете"),
|
||||
"about_plan": MessageLookupByLibrary.simpleMessage("Об этом плане"),
|
||||
"about_recipe": MessageLookupByLibrary.simpleMessage("Об этом рецепте"),
|
||||
"active": MessageLookupByLibrary.simpleMessage("Активен"),
|
||||
"active_diet_state": MessageLookupByLibrary.simpleMessage("Активная"),
|
||||
"add": MessageLookupByLibrary.simpleMessage("Добавить"),
|
||||
"add_cover": MessageLookupByLibrary.simpleMessage("Добавьте обложку"),
|
||||
"add_measure": MessageLookupByLibrary.simpleMessage("Добавить замер"),
|
||||
"adding_plan": MessageLookupByLibrary.simpleMessage("Добавление плана"),
|
||||
"additional_information":
|
||||
MessageLookupByLibrary.simpleMessage("Дополнительная информация"),
|
||||
"admin": MessageLookupByLibrary.simpleMessage("Админ"),
|
||||
"all": MessageLookupByLibrary.simpleMessage("Все"),
|
||||
"allergies_presence":
|
||||
MessageLookupByLibrary.simpleMessage("Наличие аллергии"),
|
||||
"another_form_of_comment":
|
||||
MessageLookupByLibrary.simpleMessage("комментария"),
|
||||
"another_form_of_day": MessageLookupByLibrary.simpleMessage("дня"),
|
||||
"another_form_of_hour": MessageLookupByLibrary.simpleMessage("часа"),
|
||||
"another_form_of_minute": MessageLookupByLibrary.simpleMessage("минут"),
|
||||
"another_form_of_stage": MessageLookupByLibrary.simpleMessage("этапа"),
|
||||
"answer": MessageLookupByLibrary.simpleMessage("Ответить"),
|
||||
"archived": MessageLookupByLibrary.simpleMessage("В архиве"),
|
||||
"authentificate": MessageLookupByLibrary.simpleMessage("Войти"),
|
||||
"average_pressure": MessageLookupByLibrary.simpleMessage(
|
||||
"Средние показатели давления:"),
|
||||
"bodymass_chart": MessageLookupByLibrary.simpleMessage("График ИМТ"),
|
||||
"by_default": MessageLookupByLibrary.simpleMessage("По умолчянию"),
|
||||
"calories": MessageLookupByLibrary.simpleMessage("Калории"),
|
||||
"cancel_diet": MessageLookupByLibrary.simpleMessage("Отменить диету?"),
|
||||
"carb_type": MessageLookupByLibrary.simpleMessage("Мучное"),
|
||||
"carb_type_desc": MessageLookupByLibrary.simpleMessage(
|
||||
"Если вы любите мучные продукты, но хотите придерживаться диеты, вам подходит диета с добавленим мучных блюд на основе цельнозерновых вариантов. В них больше сложных углеводов и клетчатки, что способствует длительному чувству сытости и поддерживает здоровье пищеварительной системы."),
|
||||
"carbohydrates": MessageLookupByLibrary.simpleMessage("Углеводы"),
|
||||
"chat": MessageLookupByLibrary.simpleMessage("Чат"),
|
||||
"check_out_video_recipe":
|
||||
MessageLookupByLibrary.simpleMessage("Посмотреть видео рецепт"),
|
||||
"chest": MessageLookupByLibrary.simpleMessage("Грудь"),
|
||||
"chest_circumference":
|
||||
MessageLookupByLibrary.simpleMessage("Обхват груди"),
|
||||
"choose_diet_duration":
|
||||
MessageLookupByLibrary.simpleMessage("Выберите срок диеты"),
|
||||
"choose_plan_duration":
|
||||
MessageLookupByLibrary.simpleMessage("Выберите срок плана"),
|
||||
"choose_start_diet_date": MessageLookupByLibrary.simpleMessage(
|
||||
"Выберите дату старты диеты. Она отобразиться у Вас в дневнике"),
|
||||
"circumference_empty": MessageLookupByLibrary.simpleMessage(
|
||||
"Все замеры обязательны к заполнению"),
|
||||
"circumference_is_not_a_number": MessageLookupByLibrary.simpleMessage(
|
||||
"Все замеры должны быть числами"),
|
||||
"circumferences_chart":
|
||||
MessageLookupByLibrary.simpleMessage("График обхватов"),
|
||||
"city": MessageLookupByLibrary.simpleMessage("Город"),
|
||||
"city_of_living":
|
||||
MessageLookupByLibrary.simpleMessage("Город проживания"),
|
||||
"comfort": MessageLookupByLibrary.simpleMessage("Комфорт"),
|
||||
"comment": MessageLookupByLibrary.simpleMessage("комментарий"),
|
||||
"comments": MessageLookupByLibrary.simpleMessage("Комментарии"),
|
||||
"comments_plural": MessageLookupByLibrary.simpleMessage("комментариев"),
|
||||
"complain": MessageLookupByLibrary.simpleMessage("Пожаловаться"),
|
||||
"confirm": MessageLookupByLibrary.simpleMessage("Подтвердить"),
|
||||
"continueButton": MessageLookupByLibrary.simpleMessage("Продолжить"),
|
||||
"continue_": MessageLookupByLibrary.simpleMessage("Продолжить"),
|
||||
"copied": MessageLookupByLibrary.simpleMessage("cкопирован"),
|
||||
"copy_link": MessageLookupByLibrary.simpleMessage("Скопировать ссылку"),
|
||||
"could_not_cancel_diet":
|
||||
MessageLookupByLibrary.simpleMessage("Не удалось отменить диету"),
|
||||
"could_not_launch_video":
|
||||
MessageLookupByLibrary.simpleMessage("Не удалось запустить видео"),
|
||||
"country": MessageLookupByLibrary.simpleMessage("Страна"),
|
||||
"create_diet": MessageLookupByLibrary.simpleMessage("Создание диеты"),
|
||||
"customer_price":
|
||||
MessageLookupByLibrary.simpleMessage("Цена для покупателя"),
|
||||
"date_of_birth": MessageLookupByLibrary.simpleMessage("Дата рождения"),
|
||||
"day": MessageLookupByLibrary.simpleMessage("День"),
|
||||
"days": MessageLookupByLibrary.simpleMessage("дней"),
|
||||
"deleted": MessageLookupByLibrary.simpleMessage("Удалена"),
|
||||
"diary": MessageLookupByLibrary.simpleMessage("Дневник"),
|
||||
"diet": MessageLookupByLibrary.simpleMessage("Диета"),
|
||||
"diet_author": MessageLookupByLibrary.simpleMessage("Автор диеты"),
|
||||
"diet_has_been_sent_to_draft": MessageLookupByLibrary.simpleMessage(
|
||||
"снята с публикации и перенесена в черновик"),
|
||||
"diet_plan": MessageLookupByLibrary.simpleMessage("План диеты"),
|
||||
"diet_started":
|
||||
MessageLookupByLibrary.simpleMessage("Диета уже начата"),
|
||||
"diet_state": MessageLookupByLibrary.simpleMessage("Статус диеты"),
|
||||
"diet_type": MessageLookupByLibrary.simpleMessage("Тип диеты"),
|
||||
"do_you_have_hypertension_tendency":
|
||||
MessageLookupByLibrary.simpleMessage("Есть ли у вас гипертония?"),
|
||||
"do_you_have_hypotension_tendency":
|
||||
MessageLookupByLibrary.simpleMessage("Есть ли у вас гипотония?"),
|
||||
"do_you_take_pills": MessageLookupByLibrary.simpleMessage(
|
||||
"Принимаете ли вы лекарства или бады?"),
|
||||
"down_pressure":
|
||||
MessageLookupByLibrary.simpleMessage("Нижние показатели давления:"),
|
||||
"draft": MessageLookupByLibrary.simpleMessage("Черновик"),
|
||||
"drafted": MessageLookupByLibrary.simpleMessage("Черновики"),
|
||||
"eating_behavior":
|
||||
MessageLookupByLibrary.simpleMessage("Пищевое поведение"),
|
||||
"eating_behavior_type": MessageLookupByLibrary.simpleMessage(
|
||||
"Формирование пищевого поведения"),
|
||||
"eating_behavior_type_desc": MessageLookupByLibrary.simpleMessage(
|
||||
"Формирование здорового пищевого поведения — это процесс, который включает в себя изменение привычек и отношения к еде. Он направлен на то, чтобы помочь людям научиться правильно питаться и поддерживать здоровый образ жизни.Основные принципы формирования здорового пищевого поведения: \n● Разнообразие продуктов; \n● Сбалансированный рацион; \n● Питьевой режим; \n● Ограничение вредных продуктов; \n● Регулярные приёмы пищи; \n● Умеренность;Осознанное питание; \n● Физическая активность;"),
|
||||
"economy": MessageLookupByLibrary.simpleMessage("Эконом"),
|
||||
"edit": MessageLookupByLibrary.simpleMessage("Редактировать"),
|
||||
"email": MessageLookupByLibrary.simpleMessage("Электронная почта"),
|
||||
"email_empty": MessageLookupByLibrary.simpleMessage(
|
||||
"Необходимо ввести адрес электронной почты"),
|
||||
"email_invalid": MessageLookupByLibrary.simpleMessage(
|
||||
"Некорректный адрес электронной почты"),
|
||||
"enter_additional_information": MessageLookupByLibrary.simpleMessage(
|
||||
"Введите любую дополнительную информацию на своё усмотрение:"),
|
||||
"enter_diet_description":
|
||||
MessageLookupByLibrary.simpleMessage("Введите описание диеты"),
|
||||
"enter_diet_name":
|
||||
MessageLookupByLibrary.simpleMessage("Выведите название диеты"),
|
||||
"enter_information":
|
||||
MessageLookupByLibrary.simpleMessage("Введите информацию..."),
|
||||
"exit": MessageLookupByLibrary.simpleMessage("Выйти"),
|
||||
"expand": MessageLookupByLibrary.simpleMessage("Показать полностью"),
|
||||
"fats": MessageLookupByLibrary.simpleMessage("Жиры"),
|
||||
"favorite_foods":
|
||||
MessageLookupByLibrary.simpleMessage("Любимые продукты"),
|
||||
"favorite_unfavorite_foods": MessageLookupByLibrary.simpleMessage(
|
||||
"Ваши любимые/нелюбимые продукты питания?"),
|
||||
"female": MessageLookupByLibrary.simpleMessage("Женский"),
|
||||
"fill_in_information":
|
||||
MessageLookupByLibrary.simpleMessage("Заполните информацию:"),
|
||||
"finish": MessageLookupByLibrary.simpleMessage("Завершить"),
|
||||
"first_name": MessageLookupByLibrary.simpleMessage("Имя"),
|
||||
"first_name_empty": MessageLookupByLibrary.simpleMessage(
|
||||
"Имя обязательно для заполнения"),
|
||||
"first_name_short": MessageLookupByLibrary.simpleMessage(
|
||||
"В имени должен быть минимум 1 символ"),
|
||||
"fit_type": MessageLookupByLibrary.simpleMessage("Поддержание формы"),
|
||||
"fit_type_desc": MessageLookupByLibrary.simpleMessage(
|
||||
"План питания для поддержания формы сбалансированный и разнообразный, чтобы обеспечить организм всеми необходимыми питательными веществами. Общие принципы: \n● Дробное питание; \n● Разнообразие продуктов; \n● Контроль порций; \n● Питьевой режим; \n● Ограничение вредных продуктов;"),
|
||||
"fitness": MessageLookupByLibrary.simpleMessage("Поддержка формы"),
|
||||
"from": MessageLookupByLibrary.simpleMessage("от"),
|
||||
"from_a_to_z": MessageLookupByLibrary.simpleMessage("Название: А-Я"),
|
||||
"from_z_to_a": MessageLookupByLibrary.simpleMessage("Название: Я-А"),
|
||||
"gallery": MessageLookupByLibrary.simpleMessage("Галерея"),
|
||||
"general_info":
|
||||
MessageLookupByLibrary.simpleMessage("Общая информация"),
|
||||
"gr": MessageLookupByLibrary.simpleMessage("гр"),
|
||||
"grams": MessageLookupByLibrary.simpleMessage("гр"),
|
||||
"has_alergy": MessageLookupByLibrary.simpleMessage("Наличие аллергии"),
|
||||
"has_hyper":
|
||||
MessageLookupByLibrary.simpleMessage("Склонность к гипертонии"),
|
||||
"has_hypo":
|
||||
MessageLookupByLibrary.simpleMessage("Склонность к гипотонии"),
|
||||
"height": MessageLookupByLibrary.simpleMessage("Рост"),
|
||||
"height_measurements":
|
||||
MessageLookupByLibrary.simpleMessage("Замер роста"),
|
||||
"hide": MessageLookupByLibrary.simpleMessage("Свернуть"),
|
||||
"hip_circumference":
|
||||
MessageLookupByLibrary.simpleMessage("Обхват бедер"),
|
||||
"hips": MessageLookupByLibrary.simpleMessage("Бедра"),
|
||||
"hour": MessageLookupByLibrary.simpleMessage("час"),
|
||||
"hours": MessageLookupByLibrary.simpleMessage("часов"),
|
||||
"in_progress": MessageLookupByLibrary.simpleMessage("В процессе"),
|
||||
"inactive_diet_state": MessageLookupByLibrary.simpleMessage("Черновик"),
|
||||
"ingredients": MessageLookupByLibrary.simpleMessage("Ингредиенты"),
|
||||
"initial_measurements":
|
||||
MessageLookupByLibrary.simpleMessage("Первичные замеры"),
|
||||
"label": MessageLookupByLibrary.simpleMessage("Название"),
|
||||
"language": MessageLookupByLibrary.simpleMessage("Язык"),
|
||||
"last_name": MessageLookupByLibrary.simpleMessage("Фамилия"),
|
||||
"last_name_empty": MessageLookupByLibrary.simpleMessage(
|
||||
"Фамилия обязательна для заполнения"),
|
||||
"last_name_short": MessageLookupByLibrary.simpleMessage(
|
||||
"В фамилии должен быть минимум 6 символов"),
|
||||
"lbl_english": MessageLookupByLibrary.simpleMessage("English"),
|
||||
"light_type": MessageLookupByLibrary.simpleMessage("Легкая"),
|
||||
"light_type_desc": MessageLookupByLibrary.simpleMessage(
|
||||
"С некоторыми видами диет можно употреблять алкоголь в умеренных количествах. Рекомендуется совмещать вместе с низкокалорийными закусками."),
|
||||
"liked_groceries":
|
||||
MessageLookupByLibrary.simpleMessage("Любимые продукты"),
|
||||
"link_was_copied":
|
||||
MessageLookupByLibrary.simpleMessage("Ссылка успешно скопирована"),
|
||||
"loading": MessageLookupByLibrary.simpleMessage("Загрузка..."),
|
||||
"lower": MessageLookupByLibrary.simpleMessage("Нижнее"),
|
||||
"male": MessageLookupByLibrary.simpleMessage("Мужской"),
|
||||
"meal": MessageLookupByLibrary.simpleMessage("Приём пищи"),
|
||||
"meat": MessageLookupByLibrary.simpleMessage("Мясо"),
|
||||
"meat_type": MessageLookupByLibrary.simpleMessage("С мясом"),
|
||||
"meat_type_desc": MessageLookupByLibrary.simpleMessage(
|
||||
"Диета с мясом полезная и сбалансированная. Включает в себя нежирное мясо: курицу, индейку, кролика или говядину. В сочетании с овощами получаете все необходимые витамины и минералы. Не забывайте о порциях и старайтесь есть медленно, прислушиваясь к своему организму."),
|
||||
"milliliter": MessageLookupByLibrary.simpleMessage("мл"),
|
||||
"minimal_customer_price": MessageLookupByLibrary.simpleMessage(
|
||||
"Минимальная цена для покупателя: 1200₽"),
|
||||
"minute": MessageLookupByLibrary.simpleMessage("минута"),
|
||||
"minutes": MessageLookupByLibrary.simpleMessage("минуты"),
|
||||
"most_new": MessageLookupByLibrary.simpleMessage("Самые новые"),
|
||||
"most_old": MessageLookupByLibrary.simpleMessage("Самые старые"),
|
||||
"msg_network_err":
|
||||
MessageLookupByLibrary.simpleMessage("Сетевая ошибка!"),
|
||||
"msg_something_went_wrong":
|
||||
MessageLookupByLibrary.simpleMessage("Что то пошло не так!"),
|
||||
"my_blog": MessageLookupByLibrary.simpleMessage("Мой блог"),
|
||||
"my_diets": MessageLookupByLibrary.simpleMessage("Мои диеты"),
|
||||
"my_plans": MessageLookupByLibrary.simpleMessage("Мои планы"),
|
||||
"my_settings": MessageLookupByLibrary.simpleMessage("Мои настройки"),
|
||||
"name_empty": MessageLookupByLibrary.simpleMessage(
|
||||
"Имя пользователя обязательно для заполнения"),
|
||||
"name_short": MessageLookupByLibrary.simpleMessage(
|
||||
"В имени пользователя должно быть минимум 6 символов"),
|
||||
"no": MessageLookupByLibrary.simpleMessage("Нет"),
|
||||
"no_account":
|
||||
MessageLookupByLibrary.simpleMessage("У меня нет аккаунта"),
|
||||
"not_liked_groceries":
|
||||
MessageLookupByLibrary.simpleMessage("Не любимые продукты"),
|
||||
"one_option": MessageLookupByLibrary.simpleMessage("1 опция"),
|
||||
"option": MessageLookupByLibrary.simpleMessage("Опция"),
|
||||
"option_content":
|
||||
MessageLookupByLibrary.simpleMessage("Содержание опции"),
|
||||
"option_content_hint_text":
|
||||
MessageLookupByLibrary.simpleMessage("На связи 7 дней в неделю"),
|
||||
"option_desc": MessageLookupByLibrary.simpleMessage("Описание опции"),
|
||||
"option_desc_hint_text": MessageLookupByLibrary.simpleMessage(
|
||||
"Этот план питания для похудения на 7 дней сбалансированный и разнообразный"),
|
||||
"option_duration":
|
||||
MessageLookupByLibrary.simpleMessage("Продолжительность опции"),
|
||||
"option_personal_diet_desc": MessageLookupByLibrary.simpleMessage(
|
||||
"Опция подразумевает создание индивидуальной диеты"),
|
||||
"option_title": MessageLookupByLibrary.simpleMessage("Заголовок опции"),
|
||||
"order": MessageLookupByLibrary.simpleMessage("Порядок"),
|
||||
"other_info": MessageLookupByLibrary.simpleMessage("Прочая информация"),
|
||||
"password": MessageLookupByLibrary.simpleMessage("Пароль"),
|
||||
"password_confirmation":
|
||||
MessageLookupByLibrary.simpleMessage("Подтвердите пароль"),
|
||||
"password_confirmation_mismatch":
|
||||
MessageLookupByLibrary.simpleMessage("Пароли не совпадают"),
|
||||
"password_empty": MessageLookupByLibrary.simpleMessage(
|
||||
"Пароль обязателен для заполнения"),
|
||||
"password_short": MessageLookupByLibrary.simpleMessage(
|
||||
"В пароле должно быть минимум 6 символов"),
|
||||
"pcs": MessageLookupByLibrary.simpleMessage("шт"),
|
||||
"personal": MessageLookupByLibrary.simpleMessage("Персональные"),
|
||||
"personal_diet_state":
|
||||
MessageLookupByLibrary.simpleMessage("Персональная"),
|
||||
"photo": MessageLookupByLibrary.simpleMessage("Фото"),
|
||||
"physical_fitness":
|
||||
MessageLookupByLibrary.simpleMessage("Физическая форма"),
|
||||
"place_of_living":
|
||||
MessageLookupByLibrary.simpleMessage("Место проживания"),
|
||||
"plan_author": MessageLookupByLibrary.simpleMessage("Автор плана"),
|
||||
"plan_desc": MessageLookupByLibrary.simpleMessage("Описание плана"),
|
||||
"plan_desc_example": MessageLookupByLibrary.simpleMessage(
|
||||
"Большое подробное, привлекательное описание плана"),
|
||||
"plan_duration": MessageLookupByLibrary.simpleMessage("Срок плана"),
|
||||
"plan_label_desc":
|
||||
MessageLookupByLibrary.simpleMessage("План для поддержания формы"),
|
||||
"plan_type": MessageLookupByLibrary.simpleMessage("Тип плана"),
|
||||
"plans_complete":
|
||||
MessageLookupByLibrary.simpleMessage("Пройденные планы"),
|
||||
"popular": MessageLookupByLibrary.simpleMessage("Популярные"),
|
||||
"preferred_language":
|
||||
MessageLookupByLibrary.simpleMessage("Предпочитаемый язык общения"),
|
||||
"pressure": MessageLookupByLibrary.simpleMessage("Давление"),
|
||||
"pressure_empty": MessageLookupByLibrary.simpleMessage(
|
||||
"Все показатели давления обязательны к заполнению"),
|
||||
"pressure_is_not_a_number": MessageLookupByLibrary.simpleMessage(
|
||||
"Все показатели давления должны быть числами"),
|
||||
"preview": MessageLookupByLibrary.simpleMessage("Превью"),
|
||||
"price": MessageLookupByLibrary.simpleMessage("Цена"),
|
||||
"price_explanation": MessageLookupByLibrary.simpleMessage(
|
||||
"Разница в ценах, это комиссия Итвио"),
|
||||
"profile": MessageLookupByLibrary.simpleMessage("Профиль"),
|
||||
"proteins": MessageLookupByLibrary.simpleMessage("Белки"),
|
||||
"publish": MessageLookupByLibrary.simpleMessage("Опубликовать"),
|
||||
"published": MessageLookupByLibrary.simpleMessage("Опубликованные"),
|
||||
"recipe_author": MessageLookupByLibrary.simpleMessage("Автор рецепта"),
|
||||
"removeFromActive":
|
||||
MessageLookupByLibrary.simpleMessage("Снять с публикации"),
|
||||
"save": MessageLookupByLibrary.simpleMessage("Сохранить"),
|
||||
"services": MessageLookupByLibrary.simpleMessage("Оказание услуг"),
|
||||
"settings": MessageLookupByLibrary.simpleMessage("Настройки"),
|
||||
"sex": MessageLookupByLibrary.simpleMessage("Пол"),
|
||||
"share": MessageLookupByLibrary.simpleMessage("Поделиться"),
|
||||
"skip": MessageLookupByLibrary.simpleMessage("Пропустить"),
|
||||
"slim": MessageLookupByLibrary.simpleMessage("Похудение"),
|
||||
"slim_type": MessageLookupByLibrary.simpleMessage("Похудение"),
|
||||
"slim_type_desc": MessageLookupByLibrary.simpleMessage(
|
||||
"План питания для похудения должен быть разработан с учётом индивидуальных особенностей организма, возраста, пола, уровня физической активности и состояния здоровья. Общие принципы: \n● Снижение калорийности; \n● Сбалансированный рацион; \n● Разнообразие продуктов; \n● Питьевой режим; \n● Ограничение вредных продуктов;"),
|
||||
"sport_hobbies":
|
||||
MessageLookupByLibrary.simpleMessage("Спортивные увлечения"),
|
||||
"stage": MessageLookupByLibrary.simpleMessage("этап"),
|
||||
"stages": MessageLookupByLibrary.simpleMessage("этапов"),
|
||||
"standard": MessageLookupByLibrary.simpleMessage("Стандарт"),
|
||||
"startDiet": MessageLookupByLibrary.simpleMessage("Начать диету"),
|
||||
"step": MessageLookupByLibrary.simpleMessage("Шаг"),
|
||||
"step_by_step_photo_recipe":
|
||||
MessageLookupByLibrary.simpleMessage("Пошаговый фоторецепт"),
|
||||
"takes_pills":
|
||||
MessageLookupByLibrary.simpleMessage("Принимает лекарства"),
|
||||
"tell_your_schedule": MessageLookupByLibrary.simpleMessage(
|
||||
"Расскажите в свободной форме о том как просыпаетесь, когда едите, когда ложитесь спать:"),
|
||||
"there_is_a_video": MessageLookupByLibrary.simpleMessage("Есть видео"),
|
||||
"three_options": MessageLookupByLibrary.simpleMessage("3 опции"),
|
||||
"time": MessageLookupByLibrary.simpleMessage("Время прохождения"),
|
||||
"toOffer": MessageLookupByLibrary.simpleMessage("Предложить"),
|
||||
"to_draft": MessageLookupByLibrary.simpleMessage("В черновик"),
|
||||
"unfavorite_foods":
|
||||
MessageLookupByLibrary.simpleMessage("Нелюбимые продукты"),
|
||||
"up_pressure": MessageLookupByLibrary.simpleMessage(
|
||||
"Верхние показатели давления:"),
|
||||
"upper": MessageLookupByLibrary.simpleMessage("Верхнее"),
|
||||
"user_authorization":
|
||||
MessageLookupByLibrary.simpleMessage("Аутентификация"),
|
||||
"user_data":
|
||||
MessageLookupByLibrary.simpleMessage("Данные пользователя"),
|
||||
"user_registration":
|
||||
MessageLookupByLibrary.simpleMessage("Регистрация пользователя"),
|
||||
"username": MessageLookupByLibrary.simpleMessage("Имя пользователя"),
|
||||
"vegan": MessageLookupByLibrary.simpleMessage("Веган."),
|
||||
"vegan_type": MessageLookupByLibrary.simpleMessage("Вегетарианская"),
|
||||
"vegan_type_desc": MessageLookupByLibrary.simpleMessage(
|
||||
"Диета основана на потреблении растительной пищи и отказе от продуктов животного происхождения. Такой тип питания может быть разнообразным и вкусным, а также полезным для здоровья."),
|
||||
"waist": MessageLookupByLibrary.simpleMessage("Талия"),
|
||||
"waist_circumference":
|
||||
MessageLookupByLibrary.simpleMessage("Обхват талии"),
|
||||
"weight": MessageLookupByLibrary.simpleMessage("Вес"),
|
||||
"weight_chart": MessageLookupByLibrary.simpleMessage("График веса"),
|
||||
"weight_measurements":
|
||||
MessageLookupByLibrary.simpleMessage("Замер веса"),
|
||||
"wellness":
|
||||
MessageLookupByLibrary.simpleMessage("Улучшение самочувствия"),
|
||||
"wellness_type":
|
||||
MessageLookupByLibrary.simpleMessage("Улучшение самочувствия"),
|
||||
"wellness_type_desc": MessageLookupByLibrary.simpleMessage(
|
||||
"Если вы любите мучные продукты, но хотите придерживаться диеты, вам подходит диета с добавленим мучных блюд на основе цельнозерновых вариантов. В них больше сложных углеводов и клетчатки, что способствует длительному чувству сытости и поддерживает здоровье пищеварительной системы."),
|
||||
"what_is_your_name":
|
||||
MessageLookupByLibrary.simpleMessage("Как вас зовут?"),
|
||||
"wrong_credentials": MessageLookupByLibrary.simpleMessage(
|
||||
"Неверные данные пользователя"),
|
||||
"you_will_get": MessageLookupByLibrary.simpleMessage("Вы получите"),
|
||||
"your_blood_pressure":
|
||||
MessageLookupByLibrary.simpleMessage("Ваше артериальное давление?"),
|
||||
"your_favorite_sports":
|
||||
MessageLookupByLibrary.simpleMessage("Ваши спортивные увлечения?"),
|
||||
"your_gender": MessageLookupByLibrary.simpleMessage("Ваш пол?"),
|
||||
"your_height": MessageLookupByLibrary.simpleMessage("Ваш рост:"),
|
||||
"your_schedule": MessageLookupByLibrary.simpleMessage("Ваш режим дня?"),
|
||||
"your_weight": MessageLookupByLibrary.simpleMessage("Ваш вес:")
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2352,7 +2352,12 @@ class S {
|
||||
|
||||
/// `Подтвердить`
|
||||
String get confirm {
|
||||
return Intl.message('Подтвердить', name: 'confirm', desc: '', args: []);
|
||||
return Intl.message(
|
||||
'Подтвердить',
|
||||
name: 'confirm',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Не удалось отменить диету`
|
||||
@@ -2364,6 +2369,186 @@ class S {
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `часов`
|
||||
String get hours {
|
||||
return Intl.message(
|
||||
'часов',
|
||||
name: 'hours',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `час`
|
||||
String get hour {
|
||||
return Intl.message(
|
||||
'час',
|
||||
name: 'hour',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `часа`
|
||||
String get another_form_of_hour {
|
||||
return Intl.message(
|
||||
'часа',
|
||||
name: 'another_form_of_hour',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `минуты`
|
||||
String get minutes {
|
||||
return Intl.message(
|
||||
'минуты',
|
||||
name: 'minutes',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `минута`
|
||||
String get minute {
|
||||
return Intl.message(
|
||||
'минута',
|
||||
name: 'minute',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `минут`
|
||||
String get another_form_of_minute {
|
||||
return Intl.message(
|
||||
'минут',
|
||||
name: 'another_form_of_minute',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Есть видео`
|
||||
String get there_is_a_video {
|
||||
return Intl.message(
|
||||
'Есть видео',
|
||||
name: 'there_is_a_video',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Автор рецепта`
|
||||
String get recipe_author {
|
||||
return Intl.message(
|
||||
'Автор рецепта',
|
||||
name: 'recipe_author',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Об этом рецепте`
|
||||
String get about_recipe {
|
||||
return Intl.message(
|
||||
'Об этом рецепте',
|
||||
name: 'about_recipe',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `этапов`
|
||||
String get stages {
|
||||
return Intl.message(
|
||||
'этапов',
|
||||
name: 'stages',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `этап`
|
||||
String get stage {
|
||||
return Intl.message(
|
||||
'этап',
|
||||
name: 'stage',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `этапа`
|
||||
String get another_form_of_stage {
|
||||
return Intl.message(
|
||||
'этапа',
|
||||
name: 'another_form_of_stage',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Посмотреть видео рецепт`
|
||||
String get check_out_video_recipe {
|
||||
return Intl.message(
|
||||
'Посмотреть видео рецепт',
|
||||
name: 'check_out_video_recipe',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Не удалось запустить видео`
|
||||
String get could_not_launch_video {
|
||||
return Intl.message(
|
||||
'Не удалось запустить видео',
|
||||
name: 'could_not_launch_video',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Ингредиенты`
|
||||
String get ingredients {
|
||||
return Intl.message(
|
||||
'Ингредиенты',
|
||||
name: 'ingredients',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Шаг`
|
||||
String get step {
|
||||
return Intl.message(
|
||||
'Шаг',
|
||||
name: 'step',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Пошаговый фоторецепт`
|
||||
String get step_by_step_photo_recipe {
|
||||
return Intl.message(
|
||||
'Пошаговый фоторецепт',
|
||||
name: 'step_by_step_photo_recipe',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `снята с публикации и перенесена в черновик`
|
||||
String get diet_has_been_sent_to_draft {
|
||||
return Intl.message(
|
||||
'снята с публикации и перенесена в черновик',
|
||||
name: 'diet_has_been_sent_to_draft',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AppLocalizationDelegate extends LocalizationsDelegate<S> {
|
||||
|
||||
@@ -247,5 +247,6 @@
|
||||
"could_not_launch_video": "Не удалось запустить видео",
|
||||
"ingredients": "Ингредиенты",
|
||||
"step": "Шаг",
|
||||
"step_by_step_photo_recipe": "Пошаговый фоторецепт"
|
||||
"step_by_step_photo_recipe": "Пошаговый фоторецепт",
|
||||
"diet_has_been_sent_to_draft": "снята с публикации и перенесена в черновик"
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/new_messages_cubit/new_messages_cubit.dart';
|
||||
import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_cubit.dart';
|
||||
import 'package:eatvio_app/features/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/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart';
|
||||
import 'package:eatvio_app/features/internet_connection_checker/internet_connection_checker_screen.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
@@ -39,6 +40,7 @@ class MyApp extends StatelessWidget {
|
||||
BlocProvider<NotificationsCubit>(create: (context) => sl<NotificationsCubit>()),
|
||||
BlocProvider<FeedCubit>(create: (context) => sl<FeedCubit>()..loadFeedBlogPostList()),
|
||||
BlocProvider<ProfileAvatarCubit>(create: (context) => sl<ProfileAvatarCubit>()..getMyProfile()),
|
||||
BlocProvider<ChatsCubit>(create: (context) => sl<ChatsCubit>()..getChatRoomsWithLoading()),
|
||||
],
|
||||
child: Portal(
|
||||
child: KeyboardDismisser(
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
name: eatvio_app
|
||||
description: A new Flutter project.
|
||||
version: 1.0.40+40
|
||||
publish_to: "none"
|
||||
publish_to: 'none'
|
||||
|
||||
environment:
|
||||
sdk: ">=3.3.4 <4.0.0"
|
||||
sdk: '>=3.3.4 <4.0.0'
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
@@ -61,6 +61,7 @@ dependencies:
|
||||
webview_flutter: ^4.10.0
|
||||
sentry_flutter: ^8.13.0
|
||||
connectivity_plus: ^6.1.2
|
||||
visibility_detector: ^0.4.0+2
|
||||
|
||||
dev_dependencies:
|
||||
build_runner: ^2.4.14
|
||||
@@ -102,4 +103,4 @@ flutter_native_splash:
|
||||
android_12:
|
||||
image: 'assets/splash/splash.png'
|
||||
image_dark: 'assets/splash/splash.png'
|
||||
branding: 'assets/splash/branding.png'
|
||||
branding: 'assets/splash/branding.png'
|
||||
|
||||
Reference in New Issue
Block a user