diff --git a/.DS_Store b/.DS_Store index 017f6122..3d1c4439 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index 0fd6fdd1..c46ca036 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -23,6 +23,7 @@ jobs: - name: Install Android SDK run: | + date --set="2024-08-19 17:53:59.990" apt-get update apt-get install -y openjdk-11-jdk wget wget https://dl.google.com/android/repository/commandlinetools-linux-7583922_latest.zip -O commandlinetools.zip diff --git a/lib/app_router.dart b/lib/app_router.dart index c8f47968..83485d40 100644 --- a/lib/app_router.dart +++ b/lib/app_router.dart @@ -5,7 +5,7 @@ import 'package:eatvio_app/features/blog_post_create/presentation/pages/blog_pos 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/pages/chat_screen.dart'; -import 'package:eatvio_app/features/chat/presentation/pages/chat_select_screen/chat_select_screen.dart'; +import 'package:eatvio_app/features/chat/presentation/pages/chat_select_screen.dart'; import 'package:eatvio_app/features/chat/presentation/pages/photo_view_screen.dart'; import 'package:eatvio_app/features/diary/presentation/pages/diary_screen.dart'; import 'package:eatvio_app/features/diets/presentation/pages/about_diet_screen.dart'; diff --git a/lib/features/blog_post/presentation/pages/blog_post_screen.dart b/lib/features/blog_post/presentation/pages/blog_post_screen.dart index 099c5f2d..27d8901a 100644 --- a/lib/features/blog_post/presentation/pages/blog_post_screen.dart +++ b/lib/features/blog_post/presentation/pages/blog_post_screen.dart @@ -1,305 +1,452 @@ +import 'dart:io'; + import 'package:cached_network_image/cached_network_image.dart'; import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/features/feed/models/comment_model.dart'; import 'package:eatvio_app/features/feed/models/feed_blog_post_model.dart'; -import 'package:eatvio_app/widgets/custom_edit_text_form_field.dart'; -import 'package:eatvio_app/widgets/custom_outlined_button.dart'; +import 'package:eatvio_app/features/feed/presentation/bloc/comments_cubit/comments_cubit.dart'; +import 'package:eatvio_app/features/feed/presentation/bloc/comments_cubit/comments_state.dart'; +import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart'; +import 'package:eatvio_app/locator_service.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; -import 'package:intl/intl.dart'; +import 'package:share_plus/share_plus.dart'; -class BlogPostScreen extends StatelessWidget { +class BlogPostScreen extends StatefulWidget { final FeedBlogPostModel blogPost; - const BlogPostScreen({super.key, required this.blogPost}); + BlogPostScreen({super.key, required this.blogPost}); + @override + State createState() => _BlogPostScreenState(); +} + +class _BlogPostScreenState extends State { + final CommentsCubit commentsCubit = sl(); + final textEditingController = TextEditingController(); + int? replyId; + late bool isLiked; + late int totalLikes; + + @override + void initState() { + commentsCubit.getBlogPostComments(widget.blogPost.id); + isLiked = widget.blogPost.wasLikedByMe; + totalLikes = widget.blogPost.totalLikes; + super.initState(); + } + + @override Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - actions: [ - InkWell( - borderRadius: BorderRadius.circular(16), - onTap: () => GoRouter.of(context).pushNamed('profileScreen', extra: blogPost.author), - child: Ink( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: Column( + return BlocProvider( + create: (BuildContext context) => commentsCubit, + child: BlocBuilder( + builder: (BuildContext context, CommentsState state) { + return Scaffold( + resizeToAvoidBottomInset: true, + bottomSheet: Container( + padding: EdgeInsets.symmetric(vertical: 12) + (Platform.isIOS ? const EdgeInsets.only(bottom: 16) : EdgeInsets.zero), + decoration: BoxDecoration( + color: Colors.white, + border: Border( + top: BorderSide( + color: Colors.black.withOpacity(0.1), + ), + ), + ), + child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - CircleAvatar( - maxRadius: 16, - minRadius: 16, - backgroundImage: NetworkImage(blogPost.author.authorProfileIcon), + if (replyId != null) + GestureDetector( + onTap: () { + setState(() { + replyId = null; + textEditingController.clear(); + }); + FocusManager.instance.primaryFocus?.unfocus(); + }, + child: Container( + decoration: BoxDecoration( + color: appTheme.blueA400, + shape: BoxShape.circle, + ), + height: 32, + width: 32, + child: Icon( + Icons.close_rounded, + size: 18, + color: Colors.white, + ), + ), + ), + if (replyId != null) SizedBox(width: 8), + SizedBox( + width: mediaQueryData.size.width - (replyId == null ? 64 : 104), + child: TextFormField( + onChanged: (_) { + setState(() {}); + }, + controller: textEditingController, + maxLines: 5, + minLines: 1, + keyboardType: TextInputType.multiline, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w400, + color: Colors.black, + height: 1, + ), + decoration: InputDecoration( + isDense: true, + contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 8), + hintText: 'Комментарий', + hintStyle: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w400, + height: 1, + color: Color(0xFFAEAEB2), + ), + filled: true, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(16), + borderSide: BorderSide( + color: Color(0xFFD1D1D6), + width: 1, + ), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(16), + borderSide: BorderSide( + color: Color(0xFFD1D1D6), + width: 1, + ), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(16), + borderSide: BorderSide( + color: Color(0xFFD1D1D6), + width: 1, + ), + ), + ), + ), ), - SizedBox(height: 4), - Text( - blogPost.author.authorName, - style: TextStyle( - color: Colors.black, - fontSize: 14, - fontWeight: FontWeight.w400, - height: 1, + SizedBox(width: 8), + GestureDetector( + onTap: () { + if (textEditingController.text.length > 2) { + commentsCubit.sendBlogPostComment( + id: widget.blogPost.id, + commentText: textEditingController.text, + parentCommentId: replyId, + ); + setState(() { + textEditingController.clear(); + replyId = null; + }); + FocusManager.instance.primaryFocus?.unfocus(); + } + }, + child: Container( + decoration: BoxDecoration( + color: textEditingController.text.length > 2 ? appTheme.blueA400 : Colors.grey, + shape: BoxShape.circle, + ), + height: 32, + width: 32, + child: Icon( + Icons.send_rounded, + size: 18, + color: Colors.white, + ), ), ), ], ), ), - ), - ], + appBar: AppBar( + title: Text(widget.blogPost.title), + ), + body: SingleChildScrollView( + padding: EdgeInsets.only(bottom: 80), + physics: BouncingScrollPhysics(), + child: Column( + children: [ + GestureDetector( + onTap: () => GoRouter.of(context).pushNamed('profileScreen', extra: widget.blogPost.author), + child: Ink( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + CircleAvatar( + radius: 16, + backgroundImage: NetworkImage(widget.blogPost.author.authorProfileIcon), + ), + SizedBox(width: 8), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + widget.blogPost.author.authorName, + style: TextStyle( + color: Colors.black, + fontSize: 14, + fontWeight: FontWeight.w400, + height: 1, + ), + ), + SizedBox(height: 2), + Text( + widget.blogPost.createdAt.format('dd MMMM', 'ru'), + style: TextStyle( + color: Colors.grey.shade600, + fontSize: 12, + fontWeight: FontWeight.w400, + height: 1, + ), + ), + ], + ), + ], + ), + ), + ), + if (widget.blogPost.description.isNotEmpty) SizedBox(height: 12), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Align( + alignment: Alignment.centerLeft, + child: Text( + widget.blogPost.description, + style: TextStyle( + color: Colors.black, + fontSize: 14, + fontWeight: FontWeight.w400, + height: 1, + ), + ), + ), + ), + SizedBox(height: 8), + CachedNetworkImage( + imageUrl: baseUrl + '/storage/' + (widget.blogPost.image), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + child: Row( + children: [ + _iconButton( + icon: Icons.favorite_border_rounded, + text: totalLikes.toString(), + iconColor: isLiked ? Colors.red.withOpacity(0.8) : null, + backgroundColor: isLiked ? Colors.red.withOpacity(0.1) : null, + textColor: isLiked ? Colors.red.withOpacity(0.8) : null, + onTap: () async { + setState(() { + isLiked = !isLiked; + isLiked ? totalLikes++ : totalLikes--; + }); + isLiked + ? await context.read().likePost(widget.blogPost.id) + : await context.read().unlikedPost(widget.blogPost.id); + await context.read().loadFeedBlogPostList(); + }, + ), + SizedBox(width: 8), + _iconButton( + icon: Icons.reply_rounded, + onTap: () => Share.shareUri( + Uri.parse( + baseUrl + '/ru/blog_post/' + widget.blogPost.id.toString(), + ), + ), + ), + Spacer(), + Icon( + Icons.visibility_rounded, + size: 16, + color: appTheme.gray500, + ), + SizedBox(width: 4), + Text( + widget.blogPost.totalViews.toString(), + style: TextStyle( + fontSize: 12, + color: appTheme.gray500, + fontWeight: FontWeight.w400, + ), + ), + ], + ), + ), + Container( + width: MediaQuery.of(context).size.width - 32, + height: 0.4, + decoration: BoxDecoration( + color: Colors.black.withOpacity(0.2), + borderRadius: BorderRadius.circular(16), + ), + ), + SizedBox(height: 8), + Container( + padding: EdgeInsets.symmetric(horizontal: 16), + alignment: Alignment.centerLeft, + child: Text( + widget.blogPost.totalComments.toString() + ' КОММЕНТАРИЕВ', + style: TextStyle( + fontSize: 12, + color: appTheme.gray500, + fontWeight: FontWeight.w400, + ), + ), + ), + SizedBox(height: 16), + if (state is CommentsStateLoading) + Padding( + padding: const EdgeInsets.all(32), + child: CupertinoActivityIndicator(), + ), + if (state is CommentsStateLoaded) _buildComments(state.comment), + ], + ), + ), + ); + }, ), - resizeToAvoidBottomInset: false, - body: Container( - width: double.maxFinite, - decoration: AppDecoration.fillGray, - child: ListView( + ); + } + + _buildComments(Comment comment) { + return Column( + children: [ + for (int i = 0; i < comment.data.length; i++) ...[ + _comment(comment.data[i]), + if (comment.data[i].childrenComments.isNotEmpty) + for (int j = 0; j < comment.data[i].childrenComments.length; j++) + Padding( + padding: EdgeInsets.only(left: 40), + child: _comment( + comment.data[i].childrenComments[j], + 12, + ), + ), + SizedBox(height: 8), + ], + ], + ); + } + + _comment(Datum datum, [double radius = 16]) { + return Container( + width: MediaQuery.of(context).size.width, + decoration: BoxDecoration( + color: replyId == datum.id ? appTheme.blueA400.withOpacity(0.1) : Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - SizedBox(height: 15.v), - _buildBlogPostData(context), - SizedBox(height: 15.v), - _buildTextField(), - SizedBox(height: 15.v), + CircleAvatar( + foregroundImage: NetworkImage(datum.authorProfileIcon), + radius: radius, + ), + SizedBox(width: 8), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + datum.authorName, + style: TextStyle( + height: 1, + color: Colors.grey.shade600, + fontWeight: FontWeight.w500, + ), + ), + SizedBox(width: 4), + Text( + datum.body, + style: TextStyle( + height: 1, + color: Colors.black, + ), + ), + SizedBox(height: 4), + Row( + children: [ + Text( + widget.blogPost.createdAt.format('dd MMMM', 'ru'), + style: TextStyle( + color: Colors.grey.shade600, + fontSize: 12, + fontWeight: FontWeight.w400, + height: 1, + ), + ), + SizedBox(width: 16), + GestureDetector( + onTap: () { + setState(() { + replyId = datum.id; + }); + }, + child: Text( + 'Ответить', + style: TextStyle( + height: 1, + fontSize: 12, + color: Colors.grey.shade800, + fontWeight: FontWeight.w500, + ), + ), + ), + ], + ), + ], + ), ], ), ), ); } - _buildBlogPostData(BuildContext context) { - return Container( - margin: EdgeInsets.only( - left: 16.h, - right: 20.h, - bottom: 10.h, - ), - padding: EdgeInsets.all(12.h), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: const BorderRadius.all(Radius.circular(12)), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.5), - spreadRadius: 2, - blurRadius: 5, - offset: Offset(0, 3), - ), - ], - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Row( - children: [ + _iconButton({required IconData icon, String? text, Function()? onTap, Color? iconColor, Color? backgroundColor, Color? textColor}) { + return InkWell( + onTap: onTap ?? () {}, + borderRadius: BorderRadius.circular(16), + child: Ink( + padding: EdgeInsets.symmetric(horizontal: 12, vertical: 4), + decoration: BoxDecoration( + color: backgroundColor ?? appTheme.gray100, + borderRadius: BorderRadius.circular(16), + ), + height: 32, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + icon, + size: 20, + color: iconColor ?? appTheme.gray600, + ), + if (text != null) SizedBox(width: 8), + if (text != null) Text( - blogPost.title, - style: CustomTextStyles.titleMediumBlack, - ), - Spacer(), - PopupMenuButton( - onSelected: (value) => tapMenu(value, context), - itemBuilder: (BuildContext context) => >[ - PopupMenuItem( - value: 'edit', - child: Text('Редактировать'), - ), - PopupMenuItem( - value: 'delete', - child: Text('Удалить'), - ), - ], - ), - ], - ), - SizedBox(height: 8.0), - _buildImage(), - SizedBox(height: 16.0), - Text( - blogPost.description, - style: CustomTextStyles.bodyMediumBluegray800, - ), - SizedBox(height: 16.0), - Align( - alignment: Alignment.topLeft, - child: Text( - DateFormat('dd.MM.yyyy').format(blogPost.updatedAt), - style: theme.textTheme.bodyMedium, - ), - ), - SizedBox(height: 8), - Row( - children: [ - Padding( - padding: EdgeInsets.only(left: 24), - child: Row( - children: [ - Padding( - padding: EdgeInsets.only(right: 8), - child: Icon(Icons.favorite_outline), - ), - Text( - "Нравится", - style: CustomTextStyles.titleMediumSemiBold, - ), - ], + text, + style: TextStyle( + color: textColor ?? appTheme.gray600, + fontWeight: FontWeight.w500, ), ), - Spacer(), - Padding( - padding: EdgeInsets.only(right: 24), - child: Row( - children: [ - Padding( - padding: const EdgeInsets.only(right: 8), - child: Icon(Icons.share_outlined), - ), - Text( - "Поделиться", - style: CustomTextStyles.titleMediumSemiBold, - ), - ], - ), - ), - ], - ), - ], - ), - ); - } - - _buildImage() { - return CachedNetworkImage( - imageUrl: baseUrl + '/storage/' + (blogPost.image), - imageBuilder: (context, imageProvider) => Stack( - children: [ - ClipRRect( - borderRadius: const BorderRadius.all(Radius.circular(8.0)), - child: Image( - image: imageProvider, - ), - ), - Positioned( - bottom: 0, - left: 0, - right: 0, - child: Container( - padding: EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Padding( - padding: const EdgeInsets.only(left: 48.0), - child: Row( - children: [ - Icon( - Icons.remove_red_eye, - color: Colors.white, - ), - SizedBox(width: 4.0), - Text( - '24', - style: TextStyle(color: Colors.white), - ), - ], - ), - ), - Row( - children: [ - Icon( - Icons.favorite, - color: Colors.white, - ), - SizedBox(width: 4.0), - Text( - '24', - style: TextStyle(color: Colors.white), - ), - ], - ), - Padding( - padding: const EdgeInsets.only(right: 48.0), - child: Row( - children: [ - Icon( - Icons.comment_outlined, - color: Colors.white, - ), - SizedBox(width: 4.0), - Text( - '42', - style: TextStyle(color: Colors.white), - ), - ], - ), - ), - ], - ), - ), - ), - ], - ), - placeholder: (context, url) => CircularProgressIndicator(), - ); - } - - void tapMenu(String value, BuildContext context) { - if (value == 'edit') { - GoRouter.of(context).pushNamed( - 'blogPostEditScreen', - extra: blogPost.id.toString(), - ); - } else if (value == 'delete') { - // context.read().add(DeleteEntry(state.blog_post?['id'])); - } - } - - _buildTextField() { - return Container( - margin: EdgeInsets.only( - left: 16.h, - right: 20.h, - bottom: 10.h, - ), - padding: EdgeInsets.all(12.h), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: const BorderRadius.all(Radius.circular(12)), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.5), - spreadRadius: 2, - blurRadius: 5, - offset: Offset(0, 3), - ), - ], - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Column( - children: [ - CustomTextFormField( - // controller: state.commentController, - maxLines: 4, - ), - SizedBox(height: 15.h), - CustomOutlinedButton( - text: "Оставить отзыв", - margin: EdgeInsets.only(bottom: 5), - buttonStyle: CustomButtonStyles.outlinePrimaryTL15, - decoration: BoxDecoration( - color: Colors.transparent, - ), - /* onPressed: () => context - .read() - .add(CreateComment(state.commentController!.text)),*/ - // Установите прозрачный фон - ), - ], - ), - ], + ], + ), ), ); } } - -/// Navigates to the previous screen. -onTapArrowleftone(BuildContext context) { - GoRouter.of(context).pop(); -} diff --git a/lib/features/chat/models/chat_room_preview_model.dart b/lib/features/chat/models/chat_room_preview_model.dart new file mode 100644 index 00000000..29c5e3ac --- /dev/null +++ b/lib/features/chat/models/chat_room_preview_model.dart @@ -0,0 +1,62 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'chat_room_preview_model.freezed.dart'; +part 'chat_room_preview_model.g.dart'; + +@freezed +class ChatRoomPreviewModel with _$ChatRoomPreviewModel { + const factory ChatRoomPreviewModel({ + @JsonKey(name: "chatRooms") required List chatRooms, + }) = _ChatRoomPreviewModel; + + factory ChatRoomPreviewModel.fromJson(Map json) => _$ChatRoomPreviewModelFromJson(json); +} + +@freezed +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: "users") required Users users, + }) = _ChatRoom; + + factory ChatRoom.fromJson(Map 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 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 json) => _$LastMessageClassFromJson(json); +} + +@freezed +class Users with _$Users { + const factory Users({ + @JsonKey(name: "from_chat_user") required ChatUser fromChatUser, + @JsonKey(name: "to_chat_user") required ChatUser toChatUser, + }) = _Users; + + factory Users.fromJson(Map json) => _$UsersFromJson(json); +} + +@freezed +class ChatUser with _$ChatUser { + const factory ChatUser({ + @JsonKey(name: "id") required int id, + @JsonKey(name: "name") required String name, + @JsonKey(name: "profile_photo_path") required String? profilePhotoPath, + @JsonKey(name: "profile_photo_url") required String profilePhotoUrl, + }) = _ChatUser; + + factory ChatUser.fromJson(Map json) => _$ChatUserFromJson(json); +} diff --git a/lib/features/chat/models/chat_room_preview_model.freezed.dart b/lib/features/chat/models/chat_room_preview_model.freezed.dart new file mode 100644 index 00000000..8d41bd4b --- /dev/null +++ b/lib/features/chat/models/chat_room_preview_model.freezed.dart @@ -0,0 +1,1108 @@ +// 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_room_preview_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +ChatRoomPreviewModel _$ChatRoomPreviewModelFromJson(Map json) { + return _ChatRoomPreviewModel.fromJson(json); +} + +/// @nodoc +mixin _$ChatRoomPreviewModel { + @JsonKey(name: "chatRooms") + List get chatRooms => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $ChatRoomPreviewModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ChatRoomPreviewModelCopyWith<$Res> { + factory $ChatRoomPreviewModelCopyWith(ChatRoomPreviewModel value, + $Res Function(ChatRoomPreviewModel) then) = + _$ChatRoomPreviewModelCopyWithImpl<$Res, ChatRoomPreviewModel>; + @useResult + $Res call({@JsonKey(name: "chatRooms") List chatRooms}); +} + +/// @nodoc +class _$ChatRoomPreviewModelCopyWithImpl<$Res, + $Val extends ChatRoomPreviewModel> + implements $ChatRoomPreviewModelCopyWith<$Res> { + _$ChatRoomPreviewModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? chatRooms = null, + }) { + return _then(_value.copyWith( + chatRooms: null == chatRooms + ? _value.chatRooms + : chatRooms // ignore: cast_nullable_to_non_nullable + as List, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$ChatRoomPreviewModelImplCopyWith<$Res> + implements $ChatRoomPreviewModelCopyWith<$Res> { + factory _$$ChatRoomPreviewModelImplCopyWith(_$ChatRoomPreviewModelImpl value, + $Res Function(_$ChatRoomPreviewModelImpl) then) = + __$$ChatRoomPreviewModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({@JsonKey(name: "chatRooms") List chatRooms}); +} + +/// @nodoc +class __$$ChatRoomPreviewModelImplCopyWithImpl<$Res> + extends _$ChatRoomPreviewModelCopyWithImpl<$Res, _$ChatRoomPreviewModelImpl> + implements _$$ChatRoomPreviewModelImplCopyWith<$Res> { + __$$ChatRoomPreviewModelImplCopyWithImpl(_$ChatRoomPreviewModelImpl _value, + $Res Function(_$ChatRoomPreviewModelImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? chatRooms = null, + }) { + return _then(_$ChatRoomPreviewModelImpl( + chatRooms: null == chatRooms + ? _value._chatRooms + : chatRooms // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$ChatRoomPreviewModelImpl implements _ChatRoomPreviewModel { + const _$ChatRoomPreviewModelImpl( + {@JsonKey(name: "chatRooms") required final List chatRooms}) + : _chatRooms = chatRooms; + + factory _$ChatRoomPreviewModelImpl.fromJson(Map json) => + _$$ChatRoomPreviewModelImplFromJson(json); + + final List _chatRooms; + @override + @JsonKey(name: "chatRooms") + List get chatRooms { + if (_chatRooms is EqualUnmodifiableListView) return _chatRooms; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_chatRooms); + } + + @override + String toString() { + return 'ChatRoomPreviewModel(chatRooms: $chatRooms)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ChatRoomPreviewModelImpl && + const DeepCollectionEquality() + .equals(other._chatRooms, _chatRooms)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => + Object.hash(runtimeType, const DeepCollectionEquality().hash(_chatRooms)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ChatRoomPreviewModelImplCopyWith<_$ChatRoomPreviewModelImpl> + get copyWith => + __$$ChatRoomPreviewModelImplCopyWithImpl<_$ChatRoomPreviewModelImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$ChatRoomPreviewModelImplToJson( + this, + ); + } +} + +abstract class _ChatRoomPreviewModel implements ChatRoomPreviewModel { + const factory _ChatRoomPreviewModel( + {@JsonKey(name: "chatRooms") + required final List chatRooms}) = _$ChatRoomPreviewModelImpl; + + factory _ChatRoomPreviewModel.fromJson(Map json) = + _$ChatRoomPreviewModelImpl.fromJson; + + @override + @JsonKey(name: "chatRooms") + List get chatRooms; + @override + @JsonKey(ignore: true) + _$$ChatRoomPreviewModelImplCopyWith<_$ChatRoomPreviewModelImpl> + get copyWith => throw _privateConstructorUsedError; +} + +ChatRoom _$ChatRoomFromJson(Map json) { + return _ChatRoom.fromJson(json); +} + +/// @nodoc +mixin _$ChatRoom { + @JsonKey(name: "id") + 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: "users") + Users get users => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $ChatRoomCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ChatRoomCopyWith<$Res> { + factory $ChatRoomCopyWith(ChatRoom value, $Res Function(ChatRoom) then) = + _$ChatRoomCopyWithImpl<$Res, ChatRoom>; + @useResult + $Res call( + {@JsonKey(name: "id") String id, + @JsonKey(name: "room_name") String roomName, + @JsonKey(name: "last_message") dynamic lastMessage, + @JsonKey(name: "users") Users users}); + + $UsersCopyWith<$Res> get users; +} + +/// @nodoc +class _$ChatRoomCopyWithImpl<$Res, $Val extends ChatRoom> + implements $ChatRoomCopyWith<$Res> { + _$ChatRoomCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? roomName = null, + Object? lastMessage = freezed, + Object? users = null, + }) { + return _then(_value.copyWith( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String, + roomName: null == roomName + ? _value.roomName + : roomName // ignore: cast_nullable_to_non_nullable + as String, + lastMessage: freezed == lastMessage + ? _value.lastMessage + : lastMessage // ignore: cast_nullable_to_non_nullable + as dynamic, + users: null == users + ? _value.users + : users // ignore: cast_nullable_to_non_nullable + as Users, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $UsersCopyWith<$Res> get users { + return $UsersCopyWith<$Res>(_value.users, (value) { + return _then(_value.copyWith(users: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$ChatRoomImplCopyWith<$Res> + implements $ChatRoomCopyWith<$Res> { + factory _$$ChatRoomImplCopyWith( + _$ChatRoomImpl value, $Res Function(_$ChatRoomImpl) then) = + __$$ChatRoomImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {@JsonKey(name: "id") String id, + @JsonKey(name: "room_name") String roomName, + @JsonKey(name: "last_message") dynamic lastMessage, + @JsonKey(name: "users") Users users}); + + @override + $UsersCopyWith<$Res> get users; +} + +/// @nodoc +class __$$ChatRoomImplCopyWithImpl<$Res> + extends _$ChatRoomCopyWithImpl<$Res, _$ChatRoomImpl> + implements _$$ChatRoomImplCopyWith<$Res> { + __$$ChatRoomImplCopyWithImpl( + _$ChatRoomImpl _value, $Res Function(_$ChatRoomImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? roomName = null, + Object? lastMessage = freezed, + Object? users = null, + }) { + return _then(_$ChatRoomImpl( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String, + roomName: null == roomName + ? _value.roomName + : roomName // ignore: cast_nullable_to_non_nullable + as String, + lastMessage: freezed == lastMessage + ? _value.lastMessage + : lastMessage // ignore: cast_nullable_to_non_nullable + as dynamic, + users: null == users + ? _value.users + : users // ignore: cast_nullable_to_non_nullable + as Users, + )); + } +} + +/// @nodoc +@JsonSerializable() +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}); + + factory _$ChatRoomImpl.fromJson(Map json) => + _$$ChatRoomImplFromJson(json); + + @override + @JsonKey(name: "id") + final String id; + @override + @JsonKey(name: "room_name") + final String roomName; + @override + @JsonKey(name: "last_message") + final dynamic lastMessage; + @override + @JsonKey(name: "users") + final Users users; + + @override + String toString() { + return 'ChatRoom(id: $id, roomName: $roomName, lastMessage: $lastMessage, users: $users)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ChatRoomImpl && + (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)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, id, roomName, + const DeepCollectionEquality().hash(lastMessage), users); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ChatRoomImplCopyWith<_$ChatRoomImpl> get copyWith => + __$$ChatRoomImplCopyWithImpl<_$ChatRoomImpl>(this, _$identity); + + @override + Map toJson() { + return _$$ChatRoomImplToJson( + this, + ); + } +} + +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; + + factory _ChatRoom.fromJson(Map json) = + _$ChatRoomImpl.fromJson; + + @override + @JsonKey(name: "id") + String get id; + @override + @JsonKey(name: "room_name") + String get roomName; + @override + @JsonKey(name: "last_message") + dynamic get lastMessage; + @override + @JsonKey(name: "users") + Users get users; + @override + @JsonKey(ignore: true) + _$$ChatRoomImplCopyWith<_$ChatRoomImpl> get copyWith => + throw _privateConstructorUsedError; +} + +LastMessageClass _$LastMessageClassFromJson(Map 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 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; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $LastMessageClassCopyWith 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 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; + + @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, + 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 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); + + @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, + 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 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 json) => + _$$LastMessageClassImplFromJson(json); + + @override + @JsonKey(name: "id") + final int id; + @override + @JsonKey(name: "data") + final String data; + final List _mediaData; + @override + @JsonKey(name: "media_data") + List 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(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, + id, + data, + const DeepCollectionEquality().hash(_mediaData), + authorId, + isAuthorMessageAuthUser, + readByToUser, + updatedAt); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$LastMessageClassImplCopyWith<_$LastMessageClassImpl> get copyWith => + __$$LastMessageClassImplCopyWithImpl<_$LastMessageClassImpl>( + this, _$identity); + + @override + Map 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 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 json) = + _$LastMessageClassImpl.fromJson; + + @override + @JsonKey(name: "id") + int get id; + @override + @JsonKey(name: "data") + String get data; + @override + @JsonKey(name: "media_data") + List 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; + @override + @JsonKey(ignore: true) + _$$LastMessageClassImplCopyWith<_$LastMessageClassImpl> get copyWith => + throw _privateConstructorUsedError; +} + +Users _$UsersFromJson(Map json) { + return _Users.fromJson(json); +} + +/// @nodoc +mixin _$Users { + @JsonKey(name: "from_chat_user") + ChatUser get fromChatUser => throw _privateConstructorUsedError; + @JsonKey(name: "to_chat_user") + ChatUser get toChatUser => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $UsersCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $UsersCopyWith<$Res> { + factory $UsersCopyWith(Users value, $Res Function(Users) then) = + _$UsersCopyWithImpl<$Res, Users>; + @useResult + $Res call( + {@JsonKey(name: "from_chat_user") ChatUser fromChatUser, + @JsonKey(name: "to_chat_user") ChatUser toChatUser}); + + $ChatUserCopyWith<$Res> get fromChatUser; + $ChatUserCopyWith<$Res> get toChatUser; +} + +/// @nodoc +class _$UsersCopyWithImpl<$Res, $Val extends Users> + implements $UsersCopyWith<$Res> { + _$UsersCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? fromChatUser = null, + Object? toChatUser = null, + }) { + return _then(_value.copyWith( + fromChatUser: null == fromChatUser + ? _value.fromChatUser + : fromChatUser // ignore: cast_nullable_to_non_nullable + as ChatUser, + toChatUser: null == toChatUser + ? _value.toChatUser + : toChatUser // ignore: cast_nullable_to_non_nullable + as ChatUser, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $ChatUserCopyWith<$Res> get fromChatUser { + return $ChatUserCopyWith<$Res>(_value.fromChatUser, (value) { + return _then(_value.copyWith(fromChatUser: value) as $Val); + }); + } + + @override + @pragma('vm:prefer-inline') + $ChatUserCopyWith<$Res> get toChatUser { + return $ChatUserCopyWith<$Res>(_value.toChatUser, (value) { + return _then(_value.copyWith(toChatUser: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$UsersImplCopyWith<$Res> implements $UsersCopyWith<$Res> { + factory _$$UsersImplCopyWith( + _$UsersImpl value, $Res Function(_$UsersImpl) then) = + __$$UsersImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {@JsonKey(name: "from_chat_user") ChatUser fromChatUser, + @JsonKey(name: "to_chat_user") ChatUser toChatUser}); + + @override + $ChatUserCopyWith<$Res> get fromChatUser; + @override + $ChatUserCopyWith<$Res> get toChatUser; +} + +/// @nodoc +class __$$UsersImplCopyWithImpl<$Res> + extends _$UsersCopyWithImpl<$Res, _$UsersImpl> + implements _$$UsersImplCopyWith<$Res> { + __$$UsersImplCopyWithImpl( + _$UsersImpl _value, $Res Function(_$UsersImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? fromChatUser = null, + Object? toChatUser = null, + }) { + return _then(_$UsersImpl( + fromChatUser: null == fromChatUser + ? _value.fromChatUser + : fromChatUser // ignore: cast_nullable_to_non_nullable + as ChatUser, + toChatUser: null == toChatUser + ? _value.toChatUser + : toChatUser // ignore: cast_nullable_to_non_nullable + as ChatUser, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$UsersImpl implements _Users { + const _$UsersImpl( + {@JsonKey(name: "from_chat_user") required this.fromChatUser, + @JsonKey(name: "to_chat_user") required this.toChatUser}); + + factory _$UsersImpl.fromJson(Map json) => + _$$UsersImplFromJson(json); + + @override + @JsonKey(name: "from_chat_user") + final ChatUser fromChatUser; + @override + @JsonKey(name: "to_chat_user") + final ChatUser toChatUser; + + @override + String toString() { + return 'Users(fromChatUser: $fromChatUser, toChatUser: $toChatUser)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$UsersImpl && + (identical(other.fromChatUser, fromChatUser) || + other.fromChatUser == fromChatUser) && + (identical(other.toChatUser, toChatUser) || + other.toChatUser == toChatUser)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, fromChatUser, toChatUser); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$UsersImplCopyWith<_$UsersImpl> get copyWith => + __$$UsersImplCopyWithImpl<_$UsersImpl>(this, _$identity); + + @override + Map toJson() { + return _$$UsersImplToJson( + this, + ); + } +} + +abstract class _Users implements Users { + const factory _Users( + {@JsonKey(name: "from_chat_user") required final ChatUser fromChatUser, + @JsonKey(name: "to_chat_user") + required final ChatUser toChatUser}) = _$UsersImpl; + + factory _Users.fromJson(Map json) = _$UsersImpl.fromJson; + + @override + @JsonKey(name: "from_chat_user") + ChatUser get fromChatUser; + @override + @JsonKey(name: "to_chat_user") + ChatUser get toChatUser; + @override + @JsonKey(ignore: true) + _$$UsersImplCopyWith<_$UsersImpl> get copyWith => + throw _privateConstructorUsedError; +} + +ChatUser _$ChatUserFromJson(Map json) { + return _ChatUser.fromJson(json); +} + +/// @nodoc +mixin _$ChatUser { + @JsonKey(name: "id") + int get id => throw _privateConstructorUsedError; + @JsonKey(name: "name") + String get name => throw _privateConstructorUsedError; + @JsonKey(name: "profile_photo_path") + String? get profilePhotoPath => throw _privateConstructorUsedError; + @JsonKey(name: "profile_photo_url") + String get profilePhotoUrl => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $ChatUserCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ChatUserCopyWith<$Res> { + factory $ChatUserCopyWith(ChatUser value, $Res Function(ChatUser) then) = + _$ChatUserCopyWithImpl<$Res, ChatUser>; + @useResult + $Res call( + {@JsonKey(name: "id") int id, + @JsonKey(name: "name") String name, + @JsonKey(name: "profile_photo_path") String? profilePhotoPath, + @JsonKey(name: "profile_photo_url") String profilePhotoUrl}); +} + +/// @nodoc +class _$ChatUserCopyWithImpl<$Res, $Val extends ChatUser> + implements $ChatUserCopyWith<$Res> { + _$ChatUserCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? name = null, + Object? profilePhotoPath = freezed, + Object? profilePhotoUrl = null, + }) { + return _then(_value.copyWith( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + profilePhotoPath: freezed == profilePhotoPath + ? _value.profilePhotoPath + : profilePhotoPath // ignore: cast_nullable_to_non_nullable + as String?, + profilePhotoUrl: null == profilePhotoUrl + ? _value.profilePhotoUrl + : profilePhotoUrl // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$ChatUserImplCopyWith<$Res> + implements $ChatUserCopyWith<$Res> { + factory _$$ChatUserImplCopyWith( + _$ChatUserImpl value, $Res Function(_$ChatUserImpl) then) = + __$$ChatUserImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {@JsonKey(name: "id") int id, + @JsonKey(name: "name") String name, + @JsonKey(name: "profile_photo_path") String? profilePhotoPath, + @JsonKey(name: "profile_photo_url") String profilePhotoUrl}); +} + +/// @nodoc +class __$$ChatUserImplCopyWithImpl<$Res> + extends _$ChatUserCopyWithImpl<$Res, _$ChatUserImpl> + implements _$$ChatUserImplCopyWith<$Res> { + __$$ChatUserImplCopyWithImpl( + _$ChatUserImpl _value, $Res Function(_$ChatUserImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? name = null, + Object? profilePhotoPath = freezed, + Object? profilePhotoUrl = null, + }) { + return _then(_$ChatUserImpl( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + profilePhotoPath: freezed == profilePhotoPath + ? _value.profilePhotoPath + : profilePhotoPath // ignore: cast_nullable_to_non_nullable + as String?, + profilePhotoUrl: null == profilePhotoUrl + ? _value.profilePhotoUrl + : profilePhotoUrl // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$ChatUserImpl implements _ChatUser { + const _$ChatUserImpl( + {@JsonKey(name: "id") required this.id, + @JsonKey(name: "name") required this.name, + @JsonKey(name: "profile_photo_path") required this.profilePhotoPath, + @JsonKey(name: "profile_photo_url") required this.profilePhotoUrl}); + + factory _$ChatUserImpl.fromJson(Map json) => + _$$ChatUserImplFromJson(json); + + @override + @JsonKey(name: "id") + final int id; + @override + @JsonKey(name: "name") + final String name; + @override + @JsonKey(name: "profile_photo_path") + final String? profilePhotoPath; + @override + @JsonKey(name: "profile_photo_url") + final String profilePhotoUrl; + + @override + String toString() { + return 'ChatUser(id: $id, name: $name, profilePhotoPath: $profilePhotoPath, profilePhotoUrl: $profilePhotoUrl)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ChatUserImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.name, name) || other.name == name) && + (identical(other.profilePhotoPath, profilePhotoPath) || + other.profilePhotoPath == profilePhotoPath) && + (identical(other.profilePhotoUrl, profilePhotoUrl) || + other.profilePhotoUrl == profilePhotoUrl)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => + Object.hash(runtimeType, id, name, profilePhotoPath, profilePhotoUrl); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ChatUserImplCopyWith<_$ChatUserImpl> get copyWith => + __$$ChatUserImplCopyWithImpl<_$ChatUserImpl>(this, _$identity); + + @override + Map toJson() { + return _$$ChatUserImplToJson( + this, + ); + } +} + +abstract class _ChatUser implements ChatUser { + const factory _ChatUser( + {@JsonKey(name: "id") required final int id, + @JsonKey(name: "name") required final String name, + @JsonKey(name: "profile_photo_path") + required final String? profilePhotoPath, + @JsonKey(name: "profile_photo_url") + required final String profilePhotoUrl}) = _$ChatUserImpl; + + factory _ChatUser.fromJson(Map json) = + _$ChatUserImpl.fromJson; + + @override + @JsonKey(name: "id") + int get id; + @override + @JsonKey(name: "name") + String get name; + @override + @JsonKey(name: "profile_photo_path") + String? get profilePhotoPath; + @override + @JsonKey(name: "profile_photo_url") + String get profilePhotoUrl; + @override + @JsonKey(ignore: true) + _$$ChatUserImplCopyWith<_$ChatUserImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/features/chat/models/chat_room_preview_model.g.dart b/lib/features/chat/models/chat_room_preview_model.g.dart new file mode 100644 index 00000000..5ae3f709 --- /dev/null +++ b/lib/features/chat/models/chat_room_preview_model.g.dart @@ -0,0 +1,90 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'chat_room_preview_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$ChatRoomPreviewModelImpl _$$ChatRoomPreviewModelImplFromJson( + Map json) => + _$ChatRoomPreviewModelImpl( + chatRooms: (json['chatRooms'] as List) + .map((e) => ChatRoom.fromJson(e as Map)) + .toList(), + ); + +Map _$$ChatRoomPreviewModelImplToJson( + _$ChatRoomPreviewModelImpl instance) => + { + 'chatRooms': instance.chatRooms, + }; + +_$ChatRoomImpl _$$ChatRoomImplFromJson(Map json) => + _$ChatRoomImpl( + id: json['id'] as String, + roomName: json['room_name'] as String, + lastMessage: json['last_message'], + users: Users.fromJson(json['users'] as Map), + ); + +Map _$$ChatRoomImplToJson(_$ChatRoomImpl instance) => + { + 'id': instance.id, + 'room_name': instance.roomName, + 'last_message': instance.lastMessage, + 'users': instance.users, + }; + +_$LastMessageClassImpl _$$LastMessageClassImplFromJson( + Map json) => + _$LastMessageClassImpl( + id: (json['id'] as num).toInt(), + data: json['data'] as String, + mediaData: json['media_data'] as List, + 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 _$$LastMessageClassImplToJson( + _$LastMessageClassImpl instance) => + { + '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(), + }; + +_$UsersImpl _$$UsersImplFromJson(Map json) => _$UsersImpl( + fromChatUser: + ChatUser.fromJson(json['from_chat_user'] as Map), + toChatUser: + ChatUser.fromJson(json['to_chat_user'] as Map), + ); + +Map _$$UsersImplToJson(_$UsersImpl instance) => + { + 'from_chat_user': instance.fromChatUser, + 'to_chat_user': instance.toChatUser, + }; + +_$ChatUserImpl _$$ChatUserImplFromJson(Map json) => + _$ChatUserImpl( + id: (json['id'] as num).toInt(), + name: json['name'] as String, + profilePhotoPath: json['profile_photo_path'] as String?, + profilePhotoUrl: json['profile_photo_url'] as String, + ); + +Map _$$ChatUserImplToJson(_$ChatUserImpl instance) => + { + 'id': instance.id, + 'name': instance.name, + 'profile_photo_path': instance.profilePhotoPath, + 'profile_photo_url': instance.profilePhotoUrl, + }; diff --git a/lib/features/chat/presentation/bloc/chat_select_cubit/chat_select_cubit.dart b/lib/features/chat/presentation/bloc/chat_select_cubit/chat_select_cubit.dart new file mode 100644 index 00000000..fc92f22d --- /dev/null +++ b/lib/features/chat/presentation/bloc/chat_select_cubit/chat_select_cubit.dart @@ -0,0 +1,24 @@ +import 'package:eatvio_app/core/app_export.dart'; +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'; + +class ChatSelectCubit extends Cubit { + final ChatRepository chatRepository; + + ChatSelectCubit({ + required this.chatRepository, + }) : super(ChatSelectState()); + + getChatRooms({String? query}) async { + emit(ChatSelectState.loading()); + try { + emit(ChatSelectState.loaded( + chatRooms: (await chatRepository.getChatRoomPreiews(query: query)), + )); + } catch (e) { + emit( + ChatSelectState.error(errorMessage: e.toString()), + ); + } + } +} diff --git a/lib/features/chat/presentation/bloc/chat_select_cubit/chat_select_state.dart b/lib/features/chat/presentation/bloc/chat_select_cubit/chat_select_state.dart new file mode 100644 index 00000000..eae74b97 --- /dev/null +++ b/lib/features/chat/presentation/bloc/chat_select_cubit/chat_select_state.dart @@ -0,0 +1,19 @@ +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 chatRooms, + }) = ChatSelectStateLoaded; +} diff --git a/lib/features/chat/presentation/bloc/chat_select_cubit/chat_select_state.freezed.dart b/lib/features/chat/presentation/bloc/chat_select_cubit/chat_select_state.freezed.dart new file mode 100644 index 00000000..9a05918d --- /dev/null +++ b/lib/features/chat/presentation/bloc/chat_select_cubit/chat_select_state.freezed.dart @@ -0,0 +1,623 @@ +// 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 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 Function() $default, { + required TResult Function() loading, + required TResult Function(String errorMessage) error, + required TResult Function(List chatRooms) loaded, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(String errorMessage)? error, + TResult? Function(List chatRooms)? loaded, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(String errorMessage)? error, + TResult Function(List chatRooms)? loaded, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map( + 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? 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 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; +} + +/// @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); +} + +/// @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 Function() $default, { + required TResult Function() loading, + required TResult Function(String errorMessage) error, + required TResult Function(List chatRooms) loaded, + }) { + return $default(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(String errorMessage)? error, + TResult? Function(List chatRooms)? loaded, + }) { + return $default?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(String errorMessage)? error, + TResult Function(List chatRooms)? loaded, + required TResult orElse(), + }) { + if ($default != null) { + return $default(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + 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? 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 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); +} + +/// @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 Function() $default, { + required TResult Function() loading, + required TResult Function(String errorMessage) error, + required TResult Function(List chatRooms) loaded, + }) { + return loading(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(String errorMessage)? error, + TResult? Function(List chatRooms)? loaded, + }) { + return loading?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(String errorMessage)? error, + TResult Function(List chatRooms)? loaded, + required TResult orElse(), + }) { + if (loading != null) { + return loading(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + 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? 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 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); + + @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); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ChatSelectStateErrorImplCopyWith<_$ChatSelectStateErrorImpl> + get copyWith => + __$$ChatSelectStateErrorImplCopyWithImpl<_$ChatSelectStateErrorImpl>( + this, _$identity); + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(String errorMessage) error, + required TResult Function(List chatRooms) loaded, + }) { + return error(errorMessage); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(String errorMessage)? error, + TResult? Function(List chatRooms)? loaded, + }) { + return error?.call(errorMessage); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(String errorMessage)? error, + TResult Function(List chatRooms)? loaded, + required TResult orElse(), + }) { + if (error != null) { + return error(errorMessage); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + 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? 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 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; + @JsonKey(ignore: true) + _$$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 chatRooms}); +} + +/// @nodoc +class __$$ChatSelectStateLoadedImplCopyWithImpl<$Res> + extends _$ChatSelectStateCopyWithImpl<$Res, _$ChatSelectStateLoadedImpl> + implements _$$ChatSelectStateLoadedImplCopyWith<$Res> { + __$$ChatSelectStateLoadedImplCopyWithImpl(_$ChatSelectStateLoadedImpl _value, + $Res Function(_$ChatSelectStateLoadedImpl) _then) + : super(_value, _then); + + @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, + )); + } +} + +/// @nodoc + +class _$ChatSelectStateLoadedImpl implements ChatSelectStateLoaded { + const _$ChatSelectStateLoadedImpl({required final List chatRooms}) + : _chatRooms = chatRooms; + + final List _chatRooms; + @override + List 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)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ChatSelectStateLoadedImplCopyWith<_$ChatSelectStateLoadedImpl> + get copyWith => __$$ChatSelectStateLoadedImplCopyWithImpl< + _$ChatSelectStateLoadedImpl>(this, _$identity); + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(String errorMessage) error, + required TResult Function(List chatRooms) loaded, + }) { + return loaded(chatRooms); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(String errorMessage)? error, + TResult? Function(List chatRooms)? loaded, + }) { + return loaded?.call(chatRooms); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(String errorMessage)? error, + TResult Function(List chatRooms)? loaded, + required TResult orElse(), + }) { + if (loaded != null) { + return loaded(chatRooms); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + 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? 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 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 chatRooms}) = _$ChatSelectStateLoadedImpl; + + List get chatRooms; + @JsonKey(ignore: true) + _$$ChatSelectStateLoadedImplCopyWith<_$ChatSelectStateLoadedImpl> + get copyWith => throw _privateConstructorUsedError; +} diff --git a/lib/features/chat/presentation/pages/chat_screen.dart b/lib/features/chat/presentation/pages/chat_screen.dart index 25a8fd14..eed575cb 100644 --- a/lib/features/chat/presentation/pages/chat_screen.dart +++ b/lib/features/chat/presentation/pages/chat_screen.dart @@ -163,26 +163,52 @@ class _ChatScreenState extends State { SizedBox(width: 8), InkWell( onTap: () async { - FilePickerResult? result = await FilePicker.platform.pickFiles(); + FilePickerResult? result = await FilePicker.platform.pickFiles( + allowMultiple: true, + type: FileType.custom, + allowedExtensions: [ + 'pdf', + 'doc', + 'docx', + 'json', + 'ppt', + 'pptx', + 'rtf', + 'txt', + 'xls', + 'xlsx', + 'csv', + 'jpeg', + 'jpg', + 'png', + 'gif', + 'svg', + 'xml', + 'webp', + ], + ); if (result != null) { - File file = File(result.files.single.path!); + List files = result.paths.map((path) => File(path!)).toList(); context.read().sendMessage( - chatId: widget.chatId, - files: [file], - ); + chatId: widget.chatId, + files: files, + ); } else { // User canceled the picker } }, - borderRadius: BorderRadius.circular(16), + customBorder: CircleBorder(), child: Ink( height: 32, width: 32, - child: Icon( - Icons.attach_file_rounded, - size: 28, - color: Color(0xFF858E99), + child: Transform.rotate( + angle: 3.8, + child: Icon( + Icons.attach_file_rounded, + size: 24, + color: Color(0xFF858E99), + ), ), ), ), @@ -232,25 +258,29 @@ class _ChatScreenState extends State { ), SizedBox(width: 8), InkWell( - borderRadius: BorderRadius.circular(16), + customBorder: CircleBorder(), onTap: () { if (textEditingController.text.isNotEmpty) { context.read().sendMessage( - chatId: widget.chatId, - data: textEditingController.text.trim(), - ); + chatId: widget.chatId, + data: textEditingController.text.trim(), + ); setState(() { textEditingController.clear(); }); } }, child: Ink( + decoration: BoxDecoration( + color: appTheme.blueA400, + shape: BoxShape.circle, + ), height: 32, width: 32, child: Icon( - Icons.send_outlined, - size: 28, - color: Color(0xFF858E99), + Icons.arrow_upward_rounded, + size: 20, + color: Colors.white, ), ), ), diff --git a/lib/features/chat/presentation/pages/chat_select_screen.dart b/lib/features/chat/presentation/pages/chat_select_screen.dart new file mode 100644 index 00000000..bdb3d9ce --- /dev/null +++ b/lib/features/chat/presentation/pages/chat_select_screen.dart @@ -0,0 +1,111 @@ +import 'package:easy_debounce/easy_debounce.dart'; +import 'package:eatvio_app/core/app_export.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:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class ChatSelectScreen extends StatefulWidget { + const ChatSelectScreen({Key? key}) : super(key: key); + + @override + State createState() => _ChatSelectScreenState(); +} + +class _ChatSelectScreenState extends State { + final searchController = TextEditingController(); + + Widget build(BuildContext context) { + return BlocBuilder( + 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( + onChanged: (query) { + if (query.length > 2) { + EasyDebounce.debounce( + 'searchChatRoom', + Duration(milliseconds: 300), + () => context.read().getChatRooms(query: query), + ); + } else { + context.read().getChatRooms(); + } + }, + controller: searchController, + fillColor: Color(0xFFF0F2F5), + hintText: "Поиск", + hintStyle: TextStyle( + color: Color(0xFF7B8794), + ), + ), + ), + ), + ), + ]; + }, + body: stateBuilder(state), + ), + ); + }, + ); + } + + stateBuilder(state) { + if (state is ChatSelectStateLoading) { + return Scaffold( + body: Center( + child: CupertinoActivityIndicator(), + ), + ); + } 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: Center( + child: CupertinoActivityIndicator(), + ), + ); + } + } +} + +_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]); + }, + ); +} diff --git a/lib/features/chat/presentation/pages/chat_select_screen/bloc/chat_select_bloc.dart b/lib/features/chat/presentation/pages/chat_select_screen/bloc/chat_select_bloc.dart deleted file mode 100644 index 0985a2f0..00000000 --- a/lib/features/chat/presentation/pages/chat_select_screen/bloc/chat_select_bloc.dart +++ /dev/null @@ -1,100 +0,0 @@ -import 'dart:convert'; - -import 'package:eatvio_app/app_router.dart'; -import 'package:eatvio_app/features/chat/presentation/pages/chat_select_screen/models/chat_entry.dart'; -import 'package:eatvio_app/features/chat/presentation/pages/chat_select_screen/models/chat_select_model.dart'; -import 'package:equatable/equatable.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:go_router/go_router.dart'; -import 'package:hive/hive.dart'; -import 'package:http/http.dart' as http; -import 'package:intl/intl.dart'; - -import '/core/app_export.dart'; - -part 'chat_select_event.dart'; -part 'chat_select_state.dart'; - -/// A bloc that manages the state of a ChatSelect according to the event that is dispatched to it. -/// - -class ChatSelectBloc extends Bloc { - ChatSelectBloc(ChatSelectState initialState) : super(initialState) { - on(_onInitialize); - } - - List fillChatEntryList(List chatRooms) { - List chats = []; - for (int i = 0; i < chatRooms.length; i++) { - String text = chatRooms[i]['last_message'] is List ? '' : chatRooms[i]['last_message']['data']; - if (chatRooms[i]['last_message'] is! List && chatRooms[i]['last_message']['is_author_message_auth_user'] != null) { - text = "Вы: " + text; - } - chats.add( - ChatItemModel( - id: chatRooms[i]['id'], - username: chatRooms[i]['users']['to_chat_user']['name'], - dateText: chatRooms[i]['last_message'] is List - ? '' - : DateFormat('dd.MM').format( - DateTime.parse( - chatRooms[i]['last_message']['updated_at'], - ), - ), - greetingText: text, - ), - ); - } - return chats; - } - - Future _onInitialize( - ChatSelectInitialEvent event, - Emitter emit, - ) async { - try { - final box = await Hive.openBox('token'); - final token = box.get('token'); - if (token == null) { - AppRouter.navigatorKey.currentContext?.goNamed('authScreen'); - } - final response = await http.get( - Uri.parse(baseUrl + '/api/chat/index'), - headers: { - 'Authorization': 'Bearer $token', - }, - ); - if (response.statusCode == 200) { - final data = jsonDecode(response.body); - if (data is Map && data.containsKey('chatRooms')) { - if (state is ChatSelectLoadedState) { - var currentState = state as ChatSelectLoadedState; - emit( - currentState.copyWith( - chatSelectModelObj: currentState.chatSelectModelObj, - chatRooms: currentState.chatRooms, - ), - ); - } else { - emit( - ChatSelectLoadedState( - chatRooms: fillChatEntryList(data['chatRooms']), - //chatRooms: [], - ), - ); - } - } else { - // Один или несколько ключевых полей отсутствуют, обрабатываем ошибку - emit(ChatSelectErrorState('Некоторые необходимые данные отсутствуют.')); - } - } else { - // Статус ответа не равен 200, обрабатываем ошибку - emit(ChatSelectErrorState('Ошибка сервера: ${response.statusCode}')); - } - } catch (e) { - // Ошибка при декодировании JSON или другая ошибка выполнения - emit(ChatSelectErrorState('Ошибка при получении данных о чатах: $e')); - } - } -} diff --git a/lib/features/chat/presentation/pages/chat_select_screen/bloc/chat_select_event.dart b/lib/features/chat/presentation/pages/chat_select_screen/bloc/chat_select_event.dart deleted file mode 100644 index 681736b1..00000000 --- a/lib/features/chat/presentation/pages/chat_select_screen/bloc/chat_select_event.dart +++ /dev/null @@ -1,28 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'chat_select_bloc.dart'; - -/// Abstract class for all events that can be dispatched from the -///ChatSelect widget. -/// -/// Events must be immutable and implement the [Equatable] interface. -@immutable -abstract class ChatSelectEvent extends Equatable {} - -/// Event that is dispatched when the ChatSelect widget is first created. -class ChatSelectInitialEvent extends ChatSelectEvent { - @override - List get props => []; -} - -///event for dropdown selection -class ChangeDropDownEvent extends ChatSelectEvent { - ChangeDropDownEvent({required this.value}); - - SelectionPopupModel value; - - @override - List get props => [ - value, - ]; -} diff --git a/lib/features/chat/presentation/pages/chat_select_screen/bloc/chat_select_state.dart b/lib/features/chat/presentation/pages/chat_select_screen/bloc/chat_select_state.dart deleted file mode 100644 index 9484c0f9..00000000 --- a/lib/features/chat/presentation/pages/chat_select_screen/bloc/chat_select_state.dart +++ /dev/null @@ -1,61 +0,0 @@ -// ignore_for_file: must_be_immutable - -part of 'chat_select_bloc.dart'; - -/// Represents the state of ChatSelect in the application. -class ChatSelectState extends Equatable { - ChatSelectState({ - this.chatSelectModelObj, - }); - - ChatSelectModel? chatSelectModelObj; - - @override - List get props => [chatSelectModelObj]; - - ChatSelectState copyWith({ChatSelectModel? chatSelectModelObj}) { - return ChatSelectState( - chatSelectModelObj: chatSelectModelObj ?? this.chatSelectModelObj, - ); - } -} - -class ChatSelectInitialState extends ChatSelectState { - ChatSelectInitialState({required ChatSelectModel chatSelectModelObj}) : super(chatSelectModelObj: chatSelectModelObj); -} - -class ChatSelectLoadedState extends ChatSelectState { - ChatSelectLoadedState({ - this.chatRooms, - this.searchController, - this.chatSelectModelObj, - }) : super(chatSelectModelObj: null); - - List? chatRooms; - TextEditingController? searchController; - ChatSelectModel? chatSelectModelObj; - - @override - List get props => [chatSelectModelObj, chatRooms, searchController]; - - ChatSelectLoadedState copyWith({ - ChatSelectModel? chatSelectModelObj, - TextEditingController? searchController, - List? chatRooms, - }) { - return ChatSelectLoadedState( - chatSelectModelObj: chatSelectModelObj ?? this.chatSelectModelObj, - chatRooms: chatRooms ?? this.chatRooms, - searchController: searchController ?? this.searchController, - ); - } -} - -class ChatSelectErrorState extends ChatSelectState { - final String errorMessage; - - ChatSelectErrorState(this.errorMessage); - - @override - List get props => [errorMessage]; -} diff --git a/lib/features/chat/presentation/pages/chat_select_screen/chat_select_screen.dart b/lib/features/chat/presentation/pages/chat_select_screen/chat_select_screen.dart deleted file mode 100644 index 9fea543a..00000000 --- a/lib/features/chat/presentation/pages/chat_select_screen/chat_select_screen.dart +++ /dev/null @@ -1,100 +0,0 @@ -import 'package:eatvio_app/core/app_export.dart'; -import 'package:eatvio_app/features/chat/presentation/pages/chat_select_screen/models/chat_entry.dart'; -import 'package:eatvio_app/features/chat/presentation/pages/chat_select_screen/widgets/chat_entry_widget.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; - -import 'bloc/chat_select_bloc.dart'; -import 'chat_search_view.dart'; -import 'models/chat_select_model.dart'; - -class ChatSelectScreen extends StatelessWidget { - const ChatSelectScreen({Key? key}) : super(key: key); - - static Widget builder(BuildContext context) { - return BlocProvider( - create: (context) => ChatSelectBloc(ChatSelectState(chatSelectModelObj: ChatSelectModel()))..add(ChatSelectInitialEvent()), - child: ChatSelectScreen(), - ); - } - - Widget build(BuildContext context) { - return BlocBuilder( - builder: (context, state) { - if (state is ChatSelectInitialState) { - return Scaffold( - body: Center( - child: CupertinoActivityIndicator(), - ), - ); - } else if (state is ChatSelectLoadedState) { - 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: CustomSearchView( - controller: state.searchController, - fillColor: Color(0xFFF0F2F5), - hintText: "Поиск", - hintStyle: TextStyle( - color: Color(0xFF7B8794), - ), - ), - ), - ), - ), - ]; - }, - body: _buildChatList(context, state), - ), - ); - } else if (state is ChatSelectErrorState) { - return Padding( - padding: const EdgeInsets.all(16), - child: Center(child: Text(state.errorMessage)), - ); - } else { - return Scaffold( - body: Center( - child: CupertinoActivityIndicator(), - ), - ); - } - }, - ); - } -} - -_buildChatList(BuildContext context, ChatSelectLoadedState state) { - return ListView.separated( - padding: EdgeInsets.all(16), - shrinkWrap: true, - physics: NeverScrollableScrollPhysics(), - separatorBuilder: (context, index) { - return SizedBox( - height: 8, - ); - }, - itemCount: state.chatRooms?.length ?? 0, - itemBuilder: (context, index) { - ChatItemModel model = state.chatRooms?[index]; - return ChatEntryWidget( - chatEntryObj: model, - ); - }, - ); -} diff --git a/lib/features/chat/presentation/pages/chat_select_screen/models/chat_entry.dart b/lib/features/chat/presentation/pages/chat_select_screen/models/chat_entry.dart deleted file mode 100644 index cffee89a..00000000 --- a/lib/features/chat/presentation/pages/chat_select_screen/models/chat_entry.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'package:eatvio_app/core/app_export.dart'; - -/// This class is used in the [userprofile_item_widget] screen. -// ignore_for_file: must_be_immutable - -class ChatItemModel { - String? userImage; - String? username; - String? dateText; - String? greetingText; - String id; - - ChatItemModel({ - this.userImage, - this.username, - this.dateText, - this.greetingText, - required this.id, - }) { - userImage = userImage ?? ImageConstant.imageNotFound; - username = username; - dateText = dateText; - greetingText = greetingText; - id = id; - } -} diff --git a/lib/features/chat/presentation/pages/chat_select_screen/models/chat_select_model.dart b/lib/features/chat/presentation/pages/chat_select_screen/models/chat_select_model.dart deleted file mode 100644 index e87ffa2b..00000000 --- a/lib/features/chat/presentation/pages/chat_select_screen/models/chat_select_model.dart +++ /dev/null @@ -1,22 +0,0 @@ -// ignore_for_file: must_be_immutable - -import 'package:eatvio_app/features/chat/presentation/pages/chat_select_screen/models/chat_entry.dart'; -import 'package:equatable/equatable.dart'; - -/// This class defines the variables used in the [chat_select_screen], -/// and is typically used to hold data that is passed between different parts of the application. - -class ChatSelectModel extends Equatable { - ChatSelectModel({this.chatList = const []}); - - List chatList; - - ChatSelectModel copyWith({List? chatList}) { - return ChatSelectModel( - chatList: chatList ?? this.chatList, - ); - } - - @override - List get props => [chatList]; -} diff --git a/lib/features/chat/presentation/pages/chat_select_screen/widgets/chat_entry_widget.dart b/lib/features/chat/presentation/pages/chat_select_screen/widgets/chat_entry_widget.dart deleted file mode 100644 index 03c8371f..00000000 --- a/lib/features/chat/presentation/pages/chat_select_screen/widgets/chat_entry_widget.dart +++ /dev/null @@ -1,94 +0,0 @@ -// ignore_for_file: must_be_immutable - -import 'package:eatvio_app/core/app_export.dart'; -import 'package:eatvio_app/features/chat/presentation/pages/chat_select_screen/models/chat_entry.dart'; -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; - -class ChatEntryWidget extends StatelessWidget { - ChatEntryWidget({ - required this.chatEntryObj, - super.key, - }); - - ChatItemModel chatEntryObj; - - @override - Widget build(BuildContext context) { - return InkWell( - borderRadius: BorderRadius.circular(16), - onTap: () => GoRouter.of(context).pushNamed( - 'chatScreen', - extra: chatEntryObj.id.toString(), - ), - child: Ink( - padding: EdgeInsets.all(16), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(16), - color: Color(0xFFF6FAFF), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: 48, - height: 48, - alignment: Alignment.center, - decoration: BoxDecoration( - color: Color(0xFFEBF4FF), - shape: BoxShape.circle, - ), - child: Text( - chatEntryObj.username!.split(' ').first[0] + chatEntryObj.username!.split(' ')[1][0], - style: TextStyle( - color: Color(0xFF7F9CF5), - fontWeight: FontWeight.w400, - fontSize: 20, - ), - ), - ), - SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Text( - chatEntryObj.username!.length <= 15 ? chatEntryObj.username! : chatEntryObj.username!.substring(0, 15) + '...', - style: theme.textTheme.titleMedium, - ), - Spacer(), - CustomImageView( - imagePath: ImageConstant.imageNotFound, - height: 9.v, - width: 16.h, - margin: EdgeInsets.only( - top: 4.v, - bottom: 6.v, - ), - ), - Padding( - padding: EdgeInsets.only(left: 6.h), - child: Text( - chatEntryObj.dateText!, - style: theme.textTheme.bodyMedium, - ), - ), - ], - ), - SizedBox(height: 6.v), - Text( - chatEntryObj.greetingText!.trim(), - style: CustomTextStyles.bodyMediumBluegray800, - ), - ], - ), - ), - ], - ), - ), - ); - } -} diff --git a/lib/features/chat/presentation/widgets/chat_entry_widget.dart b/lib/features/chat/presentation/widgets/chat_entry_widget.dart new file mode 100644 index 00000000..0054e8f2 --- /dev/null +++ b/lib/features/chat/presentation/widgets/chat_entry_widget.dart @@ -0,0 +1,116 @@ +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/features/chat/models/chat_room_preview_model.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; + +class ChatEntryWidget extends StatefulWidget { + final ChatRoom chatRoom; + + ChatEntryWidget({ + required this.chatRoom, + super.key, + }); + + @override + State createState() => _ChatEntryWidgetState(); +} + +class _ChatEntryWidgetState extends State { + LastMessageClass? lastMessage; + + @override + void initState() { + super.initState(); + if (widget.chatRoom.lastMessage is Map) { + lastMessage = LastMessageClass.fromJson(widget.chatRoom.lastMessage); + } + } + + @override + Widget build(BuildContext context) { + return InkWell( + borderRadius: BorderRadius.circular(16), + onTap: () => GoRouter.of(context).pushNamed( + 'chatScreen', + extra: widget.chatRoom.id.toString(), + ), + child: Ink( + padding: EdgeInsets.all(16), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(16), + color: Color(0xFFF6FAFF), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + widget.chatRoom.users.toChatUser.profilePhotoPath == null + ? buildAvatarByUsername(widget.chatRoom.users.toChatUser.name) + : CircleAvatar( + radius: 24, + backgroundImage: NetworkImage( + widget.chatRoom.users.toChatUser.profilePhotoUrl, + ), + backgroundColor: Colors.white, + ), + 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, + ), + ), + ], + ), + SizedBox(height: 8), + if (lastMessage != null) + Text( + lastMessage!.data.toString().trim(), + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: CustomTextStyles.bodyMediumBluegray800, + ), + ], + ), + ), + ], + ), + ), + ); + } + + buildAvatarByUsername(String username) { + return Container( + width: 48, + height: 48, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Color(0xFFEBF4FF), + shape: BoxShape.circle, + ), + child: Text( + username.split(' ').first[0] + username.split(' ')[1][0], + style: TextStyle( + color: Color(0xFF7F9CF5), + fontWeight: FontWeight.w400, + fontSize: 20, + ), + ), + ); + } +} diff --git a/lib/features/chat/presentation/pages/chat_select_screen/chat_search_view.dart b/lib/features/chat/presentation/widgets/chat_search_bar_widget.dart similarity index 97% rename from lib/features/chat/presentation/pages/chat_select_screen/chat_search_view.dart rename to lib/features/chat/presentation/widgets/chat_search_bar_widget.dart index 15f6c44b..d2baebb1 100644 --- a/lib/features/chat/presentation/pages/chat_select_screen/chat_search_view.dart +++ b/lib/features/chat/presentation/widgets/chat_search_bar_widget.dart @@ -1,8 +1,8 @@ import 'package:eatvio_app/core/app_export.dart'; import 'package:flutter/material.dart'; -class CustomSearchView extends StatelessWidget { - CustomSearchView({ +class ChatSearchBarWidget extends StatelessWidget { + ChatSearchBarWidget({ Key? key, this.alignment, this.width, diff --git a/lib/features/chat/repositories/chat_repository.dart b/lib/features/chat/repositories/chat_repository.dart index f249f204..0f0be7de 100644 --- a/lib/features/chat/repositories/chat_repository.dart +++ b/lib/features/chat/repositories/chat_repository.dart @@ -1,5 +1,7 @@ import 'dart:io'; - +import 'package:dio/dio.dart'; +import 'package:eatvio_app/features/chat/models/chat_room_preview_model.dart'; +import 'package:http_parser/http_parser.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/websocket_info_model.dart'; @@ -18,10 +20,24 @@ class ChatRepository { List? files, }) async { try { + final multipartFiles = []; + + if (files != null) { + for (final file in files) { + final fileBytes = await file.readAsBytes(); + final multipartFile = MultipartFile.fromBytes( + fileBytes, + filename: file.path.split('/').last, + contentType: MediaType('application', 'octet-stream'), + ); + multipartFiles.add(multipartFile); + } + } + await chatService.sendMessage( id: chatId, data: data, - media_data: files, + media_data: multipartFiles.isEmpty ? null : multipartFiles, ); } catch (e) { print(e); @@ -38,6 +54,15 @@ class ChatRepository { } } + Future> getChatRoomPreiews({String? query}) async { + try { + return (await chatService.getChatRoomPreviews(query: query)).chatRooms; + } catch (e) { + print(e); + rethrow; + } + } + Future getChatMessages(String chatId, int page) async { try { return (await chatService.getChatMessages(id: chatId, page: page)); diff --git a/lib/features/chat/services/chat_service.dart b/lib/features/chat/services/chat_service.dart index 49a8f810..3bbb74ff 100644 --- a/lib/features/chat/services/chat_service.dart +++ b/lib/features/chat/services/chat_service.dart @@ -1,8 +1,7 @@ -import 'dart:io'; - import 'package:dio/dio.dart'; import 'package:eatvio_app/features/chat/models/chat_messages_model.dart'; import 'package:eatvio_app/features/chat/models/chat_room_model.dart'; +import 'package:eatvio_app/features/chat/models/chat_room_preview_model.dart'; import 'package:eatvio_app/features/chat/models/websocket_info_model.dart'; import 'package:retrofit/retrofit.dart'; @@ -12,6 +11,11 @@ part 'chat_service.g.dart'; abstract class ChatService { factory ChatService(Dio dio, {String baseUrl}) = _ChatService; + @GET('/api/chat/index') + Future getChatRoomPreviews({ + @Query('find') String? query, + }); + @GET('/api/chat/show/{id}') Future> getChatRoom({ @Path() required String id, @@ -22,7 +26,7 @@ abstract class ChatService { Future sendMessage({ @Path() required String id, @Part() String? data, - @Part() List? media_data, + @Part(name: 'media_data[]', contentType: 'multipart/form-data') List? media_data, }); @GET('/api/chat/show/{id}/messages?page={page}') diff --git a/lib/features/chat/services/chat_service.g.dart b/lib/features/chat/services/chat_service.g.dart index 8f5b8e61..0a789118 100644 --- a/lib/features/chat/services/chat_service.g.dart +++ b/lib/features/chat/services/chat_service.g.dart @@ -18,6 +18,40 @@ class _ChatService implements ChatService { String? baseUrl; + @override + Future getChatRoomPreviews({String? query}) async { + final _extra = {}; + final queryParameters = {r'find': query}; + queryParameters.removeWhere((k, v) => v == null); + final _headers = {}; + const Map? _data = null; + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/chat/index', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); + final _result = await _dio.fetch>(_options); + late ChatRoomPreviewModel _value; + try { + _value = ChatRoomPreviewModel.fromJson(_result.data!); + } on Object catch (e, s) { + errorLogger?.logError(e, s, _options); + rethrow; + } + return _value; + } + @override Future> getChatRoom({required String id}) async { final _extra = {}; @@ -50,7 +84,7 @@ class _ChatService implements ChatService { Future sendMessage({ required String id, String? data, - List? media_data, + List? media_data, }) async { final _extra = {}; final queryParameters = {}; @@ -64,12 +98,7 @@ class _ChatService implements ChatService { )); } if (media_data != null) { - _data.files.addAll(media_data.map((i) => MapEntry( - 'media_data', - MultipartFile.fromFileSync( - i.path, - filename: i.path.split(Platform.pathSeparator).last, - )))); + _data.files.addAll(media_data.map((i) => MapEntry('media_data[]', i))); } await _dio.fetch(_setStreamType(Options( method: 'POST', diff --git a/lib/features/feed/models/comment_model.dart b/lib/features/feed/models/comment_model.dart new file mode 100644 index 00000000..4c8aa268 --- /dev/null +++ b/lib/features/feed/models/comment_model.dart @@ -0,0 +1,67 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'comment_model.freezed.dart'; +part 'comment_model.g.dart'; + +@freezed +class Comment with _$Comment { + const factory Comment({ + @JsonKey(name: "data") required List data, + @JsonKey(name: "links") required Links links, + @JsonKey(name: "meta") required Meta meta, + }) = _Comment; + + factory Comment.fromJson(Map json) => _$CommentFromJson(json); +} + +@freezed +class Datum with _$Datum { + const factory Datum({ + @JsonKey(name: "id") required int id, + @JsonKey(name: "author_name") required String authorName, + @JsonKey(name: "author_profile_icon") required String authorProfileIcon, + @JsonKey(name: "body") required String body, + @JsonKey(name: "children_comments") required List childrenComments, + }) = _Datum; + + factory Datum.fromJson(Map json) => _$DatumFromJson(json); +} + +@freezed +class Links with _$Links { + const factory Links({ + @JsonKey(name: "first") required String first, + @JsonKey(name: "last") required String last, + @JsonKey(name: "prev") required dynamic prev, + @JsonKey(name: "next") required dynamic next, + }) = _Links; + + factory Links.fromJson(Map json) => _$LinksFromJson(json); +} + +@freezed +class Meta with _$Meta { + const factory Meta({ + @JsonKey(name: "current_page") required int currentPage, + @JsonKey(name: "from") required int from, + @JsonKey(name: "last_page") required int lastPage, + @JsonKey(name: "links") required List links, + @JsonKey(name: "path") required String path, + @JsonKey(name: "per_page") required int perPage, + @JsonKey(name: "to") required int to, + @JsonKey(name: "total") required int total, + }) = _Meta; + + factory Meta.fromJson(Map json) => _$MetaFromJson(json); +} + +@freezed +class Link with _$Link { + const factory Link({ + @JsonKey(name: "url") required String? url, + @JsonKey(name: "label") required String label, + @JsonKey(name: "active") required bool active, + }) = _Link; + + factory Link.fromJson(Map json) => _$LinkFromJson(json); +} diff --git a/lib/features/feed/models/comment_model.freezed.dart b/lib/features/feed/models/comment_model.freezed.dart new file mode 100644 index 00000000..3f088135 --- /dev/null +++ b/lib/features/feed/models/comment_model.freezed.dart @@ -0,0 +1,1188 @@ +// 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 'comment_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +Comment _$CommentFromJson(Map json) { + return _Comment.fromJson(json); +} + +/// @nodoc +mixin _$Comment { + @JsonKey(name: "data") + List get data => throw _privateConstructorUsedError; + @JsonKey(name: "links") + Links get links => throw _privateConstructorUsedError; + @JsonKey(name: "meta") + Meta get meta => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $CommentCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $CommentCopyWith<$Res> { + factory $CommentCopyWith(Comment value, $Res Function(Comment) then) = + _$CommentCopyWithImpl<$Res, Comment>; + @useResult + $Res call( + {@JsonKey(name: "data") List data, + @JsonKey(name: "links") Links links, + @JsonKey(name: "meta") Meta meta}); + + $LinksCopyWith<$Res> get links; + $MetaCopyWith<$Res> get meta; +} + +/// @nodoc +class _$CommentCopyWithImpl<$Res, $Val extends Comment> + implements $CommentCopyWith<$Res> { + _$CommentCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? data = null, + Object? links = null, + Object? meta = null, + }) { + return _then(_value.copyWith( + data: null == data + ? _value.data + : data // ignore: cast_nullable_to_non_nullable + as List, + links: null == links + ? _value.links + : links // ignore: cast_nullable_to_non_nullable + as Links, + meta: null == meta + ? _value.meta + : meta // ignore: cast_nullable_to_non_nullable + as Meta, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $LinksCopyWith<$Res> get links { + return $LinksCopyWith<$Res>(_value.links, (value) { + return _then(_value.copyWith(links: value) as $Val); + }); + } + + @override + @pragma('vm:prefer-inline') + $MetaCopyWith<$Res> get meta { + return $MetaCopyWith<$Res>(_value.meta, (value) { + return _then(_value.copyWith(meta: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$CommentImplCopyWith<$Res> implements $CommentCopyWith<$Res> { + factory _$$CommentImplCopyWith( + _$CommentImpl value, $Res Function(_$CommentImpl) then) = + __$$CommentImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {@JsonKey(name: "data") List data, + @JsonKey(name: "links") Links links, + @JsonKey(name: "meta") Meta meta}); + + @override + $LinksCopyWith<$Res> get links; + @override + $MetaCopyWith<$Res> get meta; +} + +/// @nodoc +class __$$CommentImplCopyWithImpl<$Res> + extends _$CommentCopyWithImpl<$Res, _$CommentImpl> + implements _$$CommentImplCopyWith<$Res> { + __$$CommentImplCopyWithImpl( + _$CommentImpl _value, $Res Function(_$CommentImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? data = null, + Object? links = null, + Object? meta = null, + }) { + return _then(_$CommentImpl( + data: null == data + ? _value._data + : data // ignore: cast_nullable_to_non_nullable + as List, + links: null == links + ? _value.links + : links // ignore: cast_nullable_to_non_nullable + as Links, + meta: null == meta + ? _value.meta + : meta // ignore: cast_nullable_to_non_nullable + as Meta, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$CommentImpl implements _Comment { + const _$CommentImpl( + {@JsonKey(name: "data") required final List data, + @JsonKey(name: "links") required this.links, + @JsonKey(name: "meta") required this.meta}) + : _data = data; + + factory _$CommentImpl.fromJson(Map json) => + _$$CommentImplFromJson(json); + + final List _data; + @override + @JsonKey(name: "data") + List get data { + if (_data is EqualUnmodifiableListView) return _data; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_data); + } + + @override + @JsonKey(name: "links") + final Links links; + @override + @JsonKey(name: "meta") + final Meta meta; + + @override + String toString() { + return 'Comment(data: $data, links: $links, meta: $meta)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$CommentImpl && + const DeepCollectionEquality().equals(other._data, _data) && + (identical(other.links, links) || other.links == links) && + (identical(other.meta, meta) || other.meta == meta)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, const DeepCollectionEquality().hash(_data), links, meta); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$CommentImplCopyWith<_$CommentImpl> get copyWith => + __$$CommentImplCopyWithImpl<_$CommentImpl>(this, _$identity); + + @override + Map toJson() { + return _$$CommentImplToJson( + this, + ); + } +} + +abstract class _Comment implements Comment { + const factory _Comment( + {@JsonKey(name: "data") required final List data, + @JsonKey(name: "links") required final Links links, + @JsonKey(name: "meta") required final Meta meta}) = _$CommentImpl; + + factory _Comment.fromJson(Map json) = _$CommentImpl.fromJson; + + @override + @JsonKey(name: "data") + List get data; + @override + @JsonKey(name: "links") + Links get links; + @override + @JsonKey(name: "meta") + Meta get meta; + @override + @JsonKey(ignore: true) + _$$CommentImplCopyWith<_$CommentImpl> get copyWith => + throw _privateConstructorUsedError; +} + +Datum _$DatumFromJson(Map json) { + return _Datum.fromJson(json); +} + +/// @nodoc +mixin _$Datum { + @JsonKey(name: "id") + int get id => throw _privateConstructorUsedError; + @JsonKey(name: "author_name") + String get authorName => throw _privateConstructorUsedError; + @JsonKey(name: "author_profile_icon") + String get authorProfileIcon => throw _privateConstructorUsedError; + @JsonKey(name: "body") + String get body => throw _privateConstructorUsedError; + @JsonKey(name: "children_comments") + List get childrenComments => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $DatumCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $DatumCopyWith<$Res> { + factory $DatumCopyWith(Datum value, $Res Function(Datum) then) = + _$DatumCopyWithImpl<$Res, Datum>; + @useResult + $Res call( + {@JsonKey(name: "id") int id, + @JsonKey(name: "author_name") String authorName, + @JsonKey(name: "author_profile_icon") String authorProfileIcon, + @JsonKey(name: "body") String body, + @JsonKey(name: "children_comments") List childrenComments}); +} + +/// @nodoc +class _$DatumCopyWithImpl<$Res, $Val extends Datum> + implements $DatumCopyWith<$Res> { + _$DatumCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? authorName = null, + Object? authorProfileIcon = null, + Object? body = null, + Object? childrenComments = null, + }) { + return _then(_value.copyWith( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + authorName: null == authorName + ? _value.authorName + : authorName // ignore: cast_nullable_to_non_nullable + as String, + authorProfileIcon: null == authorProfileIcon + ? _value.authorProfileIcon + : authorProfileIcon // ignore: cast_nullable_to_non_nullable + as String, + body: null == body + ? _value.body + : body // ignore: cast_nullable_to_non_nullable + as String, + childrenComments: null == childrenComments + ? _value.childrenComments + : childrenComments // ignore: cast_nullable_to_non_nullable + as List, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$DatumImplCopyWith<$Res> implements $DatumCopyWith<$Res> { + factory _$$DatumImplCopyWith( + _$DatumImpl value, $Res Function(_$DatumImpl) then) = + __$$DatumImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {@JsonKey(name: "id") int id, + @JsonKey(name: "author_name") String authorName, + @JsonKey(name: "author_profile_icon") String authorProfileIcon, + @JsonKey(name: "body") String body, + @JsonKey(name: "children_comments") List childrenComments}); +} + +/// @nodoc +class __$$DatumImplCopyWithImpl<$Res> + extends _$DatumCopyWithImpl<$Res, _$DatumImpl> + implements _$$DatumImplCopyWith<$Res> { + __$$DatumImplCopyWithImpl( + _$DatumImpl _value, $Res Function(_$DatumImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? authorName = null, + Object? authorProfileIcon = null, + Object? body = null, + Object? childrenComments = null, + }) { + return _then(_$DatumImpl( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + authorName: null == authorName + ? _value.authorName + : authorName // ignore: cast_nullable_to_non_nullable + as String, + authorProfileIcon: null == authorProfileIcon + ? _value.authorProfileIcon + : authorProfileIcon // ignore: cast_nullable_to_non_nullable + as String, + body: null == body + ? _value.body + : body // ignore: cast_nullable_to_non_nullable + as String, + childrenComments: null == childrenComments + ? _value._childrenComments + : childrenComments // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$DatumImpl implements _Datum { + const _$DatumImpl( + {@JsonKey(name: "id") required this.id, + @JsonKey(name: "author_name") required this.authorName, + @JsonKey(name: "author_profile_icon") required this.authorProfileIcon, + @JsonKey(name: "body") required this.body, + @JsonKey(name: "children_comments") + required final List childrenComments}) + : _childrenComments = childrenComments; + + factory _$DatumImpl.fromJson(Map json) => + _$$DatumImplFromJson(json); + + @override + @JsonKey(name: "id") + final int id; + @override + @JsonKey(name: "author_name") + final String authorName; + @override + @JsonKey(name: "author_profile_icon") + final String authorProfileIcon; + @override + @JsonKey(name: "body") + final String body; + final List _childrenComments; + @override + @JsonKey(name: "children_comments") + List get childrenComments { + if (_childrenComments is EqualUnmodifiableListView) + return _childrenComments; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_childrenComments); + } + + @override + String toString() { + return 'Datum(id: $id, authorName: $authorName, authorProfileIcon: $authorProfileIcon, body: $body, childrenComments: $childrenComments)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$DatumImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.authorName, authorName) || + other.authorName == authorName) && + (identical(other.authorProfileIcon, authorProfileIcon) || + other.authorProfileIcon == authorProfileIcon) && + (identical(other.body, body) || other.body == body) && + const DeepCollectionEquality() + .equals(other._childrenComments, _childrenComments)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, + id, + authorName, + authorProfileIcon, + body, + const DeepCollectionEquality().hash(_childrenComments)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$DatumImplCopyWith<_$DatumImpl> get copyWith => + __$$DatumImplCopyWithImpl<_$DatumImpl>(this, _$identity); + + @override + Map toJson() { + return _$$DatumImplToJson( + this, + ); + } +} + +abstract class _Datum implements Datum { + const factory _Datum( + {@JsonKey(name: "id") required final int id, + @JsonKey(name: "author_name") required final String authorName, + @JsonKey(name: "author_profile_icon") + required final String authorProfileIcon, + @JsonKey(name: "body") required final String body, + @JsonKey(name: "children_comments") + required final List childrenComments}) = _$DatumImpl; + + factory _Datum.fromJson(Map json) = _$DatumImpl.fromJson; + + @override + @JsonKey(name: "id") + int get id; + @override + @JsonKey(name: "author_name") + String get authorName; + @override + @JsonKey(name: "author_profile_icon") + String get authorProfileIcon; + @override + @JsonKey(name: "body") + String get body; + @override + @JsonKey(name: "children_comments") + List get childrenComments; + @override + @JsonKey(ignore: true) + _$$DatumImplCopyWith<_$DatumImpl> get copyWith => + throw _privateConstructorUsedError; +} + +Links _$LinksFromJson(Map json) { + return _Links.fromJson(json); +} + +/// @nodoc +mixin _$Links { + @JsonKey(name: "first") + String get first => throw _privateConstructorUsedError; + @JsonKey(name: "last") + String get last => throw _privateConstructorUsedError; + @JsonKey(name: "prev") + dynamic get prev => throw _privateConstructorUsedError; + @JsonKey(name: "next") + dynamic get next => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $LinksCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $LinksCopyWith<$Res> { + factory $LinksCopyWith(Links value, $Res Function(Links) then) = + _$LinksCopyWithImpl<$Res, Links>; + @useResult + $Res call( + {@JsonKey(name: "first") String first, + @JsonKey(name: "last") String last, + @JsonKey(name: "prev") dynamic prev, + @JsonKey(name: "next") dynamic next}); +} + +/// @nodoc +class _$LinksCopyWithImpl<$Res, $Val extends Links> + implements $LinksCopyWith<$Res> { + _$LinksCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? first = null, + Object? last = null, + Object? prev = freezed, + Object? next = freezed, + }) { + return _then(_value.copyWith( + first: null == first + ? _value.first + : first // ignore: cast_nullable_to_non_nullable + as String, + last: null == last + ? _value.last + : last // ignore: cast_nullable_to_non_nullable + as String, + prev: freezed == prev + ? _value.prev + : prev // ignore: cast_nullable_to_non_nullable + as dynamic, + next: freezed == next + ? _value.next + : next // ignore: cast_nullable_to_non_nullable + as dynamic, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$LinksImplCopyWith<$Res> implements $LinksCopyWith<$Res> { + factory _$$LinksImplCopyWith( + _$LinksImpl value, $Res Function(_$LinksImpl) then) = + __$$LinksImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {@JsonKey(name: "first") String first, + @JsonKey(name: "last") String last, + @JsonKey(name: "prev") dynamic prev, + @JsonKey(name: "next") dynamic next}); +} + +/// @nodoc +class __$$LinksImplCopyWithImpl<$Res> + extends _$LinksCopyWithImpl<$Res, _$LinksImpl> + implements _$$LinksImplCopyWith<$Res> { + __$$LinksImplCopyWithImpl( + _$LinksImpl _value, $Res Function(_$LinksImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? first = null, + Object? last = null, + Object? prev = freezed, + Object? next = freezed, + }) { + return _then(_$LinksImpl( + first: null == first + ? _value.first + : first // ignore: cast_nullable_to_non_nullable + as String, + last: null == last + ? _value.last + : last // ignore: cast_nullable_to_non_nullable + as String, + prev: freezed == prev + ? _value.prev + : prev // ignore: cast_nullable_to_non_nullable + as dynamic, + next: freezed == next + ? _value.next + : next // ignore: cast_nullable_to_non_nullable + as dynamic, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$LinksImpl implements _Links { + const _$LinksImpl( + {@JsonKey(name: "first") required this.first, + @JsonKey(name: "last") required this.last, + @JsonKey(name: "prev") required this.prev, + @JsonKey(name: "next") required this.next}); + + factory _$LinksImpl.fromJson(Map json) => + _$$LinksImplFromJson(json); + + @override + @JsonKey(name: "first") + final String first; + @override + @JsonKey(name: "last") + final String last; + @override + @JsonKey(name: "prev") + final dynamic prev; + @override + @JsonKey(name: "next") + final dynamic next; + + @override + String toString() { + return 'Links(first: $first, last: $last, prev: $prev, next: $next)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$LinksImpl && + (identical(other.first, first) || other.first == first) && + (identical(other.last, last) || other.last == last) && + const DeepCollectionEquality().equals(other.prev, prev) && + const DeepCollectionEquality().equals(other.next, next)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, + first, + last, + const DeepCollectionEquality().hash(prev), + const DeepCollectionEquality().hash(next)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$LinksImplCopyWith<_$LinksImpl> get copyWith => + __$$LinksImplCopyWithImpl<_$LinksImpl>(this, _$identity); + + @override + Map toJson() { + return _$$LinksImplToJson( + this, + ); + } +} + +abstract class _Links implements Links { + const factory _Links( + {@JsonKey(name: "first") required final String first, + @JsonKey(name: "last") required final String last, + @JsonKey(name: "prev") required final dynamic prev, + @JsonKey(name: "next") required final dynamic next}) = _$LinksImpl; + + factory _Links.fromJson(Map json) = _$LinksImpl.fromJson; + + @override + @JsonKey(name: "first") + String get first; + @override + @JsonKey(name: "last") + String get last; + @override + @JsonKey(name: "prev") + dynamic get prev; + @override + @JsonKey(name: "next") + dynamic get next; + @override + @JsonKey(ignore: true) + _$$LinksImplCopyWith<_$LinksImpl> get copyWith => + throw _privateConstructorUsedError; +} + +Meta _$MetaFromJson(Map json) { + return _Meta.fromJson(json); +} + +/// @nodoc +mixin _$Meta { + @JsonKey(name: "current_page") + int get currentPage => throw _privateConstructorUsedError; + @JsonKey(name: "from") + int get from => throw _privateConstructorUsedError; + @JsonKey(name: "last_page") + int get lastPage => throw _privateConstructorUsedError; + @JsonKey(name: "links") + List get links => throw _privateConstructorUsedError; + @JsonKey(name: "path") + String get path => throw _privateConstructorUsedError; + @JsonKey(name: "per_page") + int get perPage => throw _privateConstructorUsedError; + @JsonKey(name: "to") + int get to => throw _privateConstructorUsedError; + @JsonKey(name: "total") + int get total => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $MetaCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $MetaCopyWith<$Res> { + factory $MetaCopyWith(Meta value, $Res Function(Meta) then) = + _$MetaCopyWithImpl<$Res, Meta>; + @useResult + $Res call( + {@JsonKey(name: "current_page") int currentPage, + @JsonKey(name: "from") int from, + @JsonKey(name: "last_page") int lastPage, + @JsonKey(name: "links") List links, + @JsonKey(name: "path") String path, + @JsonKey(name: "per_page") int perPage, + @JsonKey(name: "to") int to, + @JsonKey(name: "total") int total}); +} + +/// @nodoc +class _$MetaCopyWithImpl<$Res, $Val extends Meta> + implements $MetaCopyWith<$Res> { + _$MetaCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? currentPage = null, + Object? from = null, + Object? lastPage = null, + Object? links = null, + Object? path = null, + Object? perPage = null, + Object? to = null, + Object? total = null, + }) { + return _then(_value.copyWith( + currentPage: null == currentPage + ? _value.currentPage + : currentPage // ignore: cast_nullable_to_non_nullable + as int, + from: null == from + ? _value.from + : from // ignore: cast_nullable_to_non_nullable + as int, + lastPage: null == lastPage + ? _value.lastPage + : lastPage // ignore: cast_nullable_to_non_nullable + as int, + links: null == links + ? _value.links + : links // ignore: cast_nullable_to_non_nullable + as List, + path: null == path + ? _value.path + : path // ignore: cast_nullable_to_non_nullable + as String, + perPage: null == perPage + ? _value.perPage + : perPage // ignore: cast_nullable_to_non_nullable + as int, + to: null == to + ? _value.to + : to // ignore: cast_nullable_to_non_nullable + as int, + total: null == total + ? _value.total + : total // ignore: cast_nullable_to_non_nullable + as int, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$MetaImplCopyWith<$Res> implements $MetaCopyWith<$Res> { + factory _$$MetaImplCopyWith( + _$MetaImpl value, $Res Function(_$MetaImpl) then) = + __$$MetaImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {@JsonKey(name: "current_page") int currentPage, + @JsonKey(name: "from") int from, + @JsonKey(name: "last_page") int lastPage, + @JsonKey(name: "links") List links, + @JsonKey(name: "path") String path, + @JsonKey(name: "per_page") int perPage, + @JsonKey(name: "to") int to, + @JsonKey(name: "total") int total}); +} + +/// @nodoc +class __$$MetaImplCopyWithImpl<$Res> + extends _$MetaCopyWithImpl<$Res, _$MetaImpl> + implements _$$MetaImplCopyWith<$Res> { + __$$MetaImplCopyWithImpl(_$MetaImpl _value, $Res Function(_$MetaImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? currentPage = null, + Object? from = null, + Object? lastPage = null, + Object? links = null, + Object? path = null, + Object? perPage = null, + Object? to = null, + Object? total = null, + }) { + return _then(_$MetaImpl( + currentPage: null == currentPage + ? _value.currentPage + : currentPage // ignore: cast_nullable_to_non_nullable + as int, + from: null == from + ? _value.from + : from // ignore: cast_nullable_to_non_nullable + as int, + lastPage: null == lastPage + ? _value.lastPage + : lastPage // ignore: cast_nullable_to_non_nullable + as int, + links: null == links + ? _value._links + : links // ignore: cast_nullable_to_non_nullable + as List, + path: null == path + ? _value.path + : path // ignore: cast_nullable_to_non_nullable + as String, + perPage: null == perPage + ? _value.perPage + : perPage // ignore: cast_nullable_to_non_nullable + as int, + to: null == to + ? _value.to + : to // ignore: cast_nullable_to_non_nullable + as int, + total: null == total + ? _value.total + : total // ignore: cast_nullable_to_non_nullable + as int, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$MetaImpl implements _Meta { + const _$MetaImpl( + {@JsonKey(name: "current_page") required this.currentPage, + @JsonKey(name: "from") required this.from, + @JsonKey(name: "last_page") required this.lastPage, + @JsonKey(name: "links") required final List links, + @JsonKey(name: "path") required this.path, + @JsonKey(name: "per_page") required this.perPage, + @JsonKey(name: "to") required this.to, + @JsonKey(name: "total") required this.total}) + : _links = links; + + factory _$MetaImpl.fromJson(Map json) => + _$$MetaImplFromJson(json); + + @override + @JsonKey(name: "current_page") + final int currentPage; + @override + @JsonKey(name: "from") + final int from; + @override + @JsonKey(name: "last_page") + final int lastPage; + final List _links; + @override + @JsonKey(name: "links") + List get links { + if (_links is EqualUnmodifiableListView) return _links; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_links); + } + + @override + @JsonKey(name: "path") + final String path; + @override + @JsonKey(name: "per_page") + final int perPage; + @override + @JsonKey(name: "to") + final int to; + @override + @JsonKey(name: "total") + final int total; + + @override + String toString() { + return 'Meta(currentPage: $currentPage, from: $from, lastPage: $lastPage, links: $links, path: $path, perPage: $perPage, to: $to, total: $total)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$MetaImpl && + (identical(other.currentPage, currentPage) || + other.currentPage == currentPage) && + (identical(other.from, from) || other.from == from) && + (identical(other.lastPage, lastPage) || + other.lastPage == lastPage) && + const DeepCollectionEquality().equals(other._links, _links) && + (identical(other.path, path) || other.path == path) && + (identical(other.perPage, perPage) || other.perPage == perPage) && + (identical(other.to, to) || other.to == to) && + (identical(other.total, total) || other.total == total)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, currentPage, from, lastPage, + const DeepCollectionEquality().hash(_links), path, perPage, to, total); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$MetaImplCopyWith<_$MetaImpl> get copyWith => + __$$MetaImplCopyWithImpl<_$MetaImpl>(this, _$identity); + + @override + Map toJson() { + return _$$MetaImplToJson( + this, + ); + } +} + +abstract class _Meta implements Meta { + const factory _Meta( + {@JsonKey(name: "current_page") required final int currentPage, + @JsonKey(name: "from") required final int from, + @JsonKey(name: "last_page") required final int lastPage, + @JsonKey(name: "links") required final List links, + @JsonKey(name: "path") required final String path, + @JsonKey(name: "per_page") required final int perPage, + @JsonKey(name: "to") required final int to, + @JsonKey(name: "total") required final int total}) = _$MetaImpl; + + factory _Meta.fromJson(Map json) = _$MetaImpl.fromJson; + + @override + @JsonKey(name: "current_page") + int get currentPage; + @override + @JsonKey(name: "from") + int get from; + @override + @JsonKey(name: "last_page") + int get lastPage; + @override + @JsonKey(name: "links") + List get links; + @override + @JsonKey(name: "path") + String get path; + @override + @JsonKey(name: "per_page") + int get perPage; + @override + @JsonKey(name: "to") + int get to; + @override + @JsonKey(name: "total") + int get total; + @override + @JsonKey(ignore: true) + _$$MetaImplCopyWith<_$MetaImpl> get copyWith => + throw _privateConstructorUsedError; +} + +Link _$LinkFromJson(Map json) { + return _Link.fromJson(json); +} + +/// @nodoc +mixin _$Link { + @JsonKey(name: "url") + String? get url => throw _privateConstructorUsedError; + @JsonKey(name: "label") + String get label => throw _privateConstructorUsedError; + @JsonKey(name: "active") + bool get active => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $LinkCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $LinkCopyWith<$Res> { + factory $LinkCopyWith(Link value, $Res Function(Link) then) = + _$LinkCopyWithImpl<$Res, Link>; + @useResult + $Res call( + {@JsonKey(name: "url") String? url, + @JsonKey(name: "label") String label, + @JsonKey(name: "active") bool active}); +} + +/// @nodoc +class _$LinkCopyWithImpl<$Res, $Val extends Link> + implements $LinkCopyWith<$Res> { + _$LinkCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? url = freezed, + Object? label = null, + Object? active = null, + }) { + return _then(_value.copyWith( + url: freezed == url + ? _value.url + : url // ignore: cast_nullable_to_non_nullable + as String?, + label: null == label + ? _value.label + : label // ignore: cast_nullable_to_non_nullable + as String, + active: null == active + ? _value.active + : active // ignore: cast_nullable_to_non_nullable + as bool, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$LinkImplCopyWith<$Res> implements $LinkCopyWith<$Res> { + factory _$$LinkImplCopyWith( + _$LinkImpl value, $Res Function(_$LinkImpl) then) = + __$$LinkImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {@JsonKey(name: "url") String? url, + @JsonKey(name: "label") String label, + @JsonKey(name: "active") bool active}); +} + +/// @nodoc +class __$$LinkImplCopyWithImpl<$Res> + extends _$LinkCopyWithImpl<$Res, _$LinkImpl> + implements _$$LinkImplCopyWith<$Res> { + __$$LinkImplCopyWithImpl(_$LinkImpl _value, $Res Function(_$LinkImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? url = freezed, + Object? label = null, + Object? active = null, + }) { + return _then(_$LinkImpl( + url: freezed == url + ? _value.url + : url // ignore: cast_nullable_to_non_nullable + as String?, + label: null == label + ? _value.label + : label // ignore: cast_nullable_to_non_nullable + as String, + active: null == active + ? _value.active + : active // ignore: cast_nullable_to_non_nullable + as bool, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$LinkImpl implements _Link { + const _$LinkImpl( + {@JsonKey(name: "url") required this.url, + @JsonKey(name: "label") required this.label, + @JsonKey(name: "active") required this.active}); + + factory _$LinkImpl.fromJson(Map json) => + _$$LinkImplFromJson(json); + + @override + @JsonKey(name: "url") + final String? url; + @override + @JsonKey(name: "label") + final String label; + @override + @JsonKey(name: "active") + final bool active; + + @override + String toString() { + return 'Link(url: $url, label: $label, active: $active)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$LinkImpl && + (identical(other.url, url) || other.url == url) && + (identical(other.label, label) || other.label == label) && + (identical(other.active, active) || other.active == active)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, url, label, active); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$LinkImplCopyWith<_$LinkImpl> get copyWith => + __$$LinkImplCopyWithImpl<_$LinkImpl>(this, _$identity); + + @override + Map toJson() { + return _$$LinkImplToJson( + this, + ); + } +} + +abstract class _Link implements Link { + const factory _Link( + {@JsonKey(name: "url") required final String? url, + @JsonKey(name: "label") required final String label, + @JsonKey(name: "active") required final bool active}) = _$LinkImpl; + + factory _Link.fromJson(Map json) = _$LinkImpl.fromJson; + + @override + @JsonKey(name: "url") + String? get url; + @override + @JsonKey(name: "label") + String get label; + @override + @JsonKey(name: "active") + bool get active; + @override + @JsonKey(ignore: true) + _$$LinkImplCopyWith<_$LinkImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/features/feed/models/comment_model.g.dart b/lib/features/feed/models/comment_model.g.dart new file mode 100644 index 00000000..ef471dc6 --- /dev/null +++ b/lib/features/feed/models/comment_model.g.dart @@ -0,0 +1,95 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'comment_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$CommentImpl _$$CommentImplFromJson(Map json) => + _$CommentImpl( + data: (json['data'] as List) + .map((e) => Datum.fromJson(e as Map)) + .toList(), + links: Links.fromJson(json['links'] as Map), + meta: Meta.fromJson(json['meta'] as Map), + ); + +Map _$$CommentImplToJson(_$CommentImpl instance) => + { + 'data': instance.data, + 'links': instance.links, + 'meta': instance.meta, + }; + +_$DatumImpl _$$DatumImplFromJson(Map json) => _$DatumImpl( + id: (json['id'] as num).toInt(), + authorName: json['author_name'] as String, + authorProfileIcon: json['author_profile_icon'] as String, + body: json['body'] as String, + childrenComments: (json['children_comments'] as List) + .map((e) => Datum.fromJson(e as Map)) + .toList(), + ); + +Map _$$DatumImplToJson(_$DatumImpl instance) => + { + 'id': instance.id, + 'author_name': instance.authorName, + 'author_profile_icon': instance.authorProfileIcon, + 'body': instance.body, + 'children_comments': instance.childrenComments, + }; + +_$LinksImpl _$$LinksImplFromJson(Map json) => _$LinksImpl( + first: json['first'] as String, + last: json['last'] as String, + prev: json['prev'], + next: json['next'], + ); + +Map _$$LinksImplToJson(_$LinksImpl instance) => + { + 'first': instance.first, + 'last': instance.last, + 'prev': instance.prev, + 'next': instance.next, + }; + +_$MetaImpl _$$MetaImplFromJson(Map json) => _$MetaImpl( + currentPage: (json['current_page'] as num).toInt(), + from: (json['from'] as num).toInt(), + lastPage: (json['last_page'] as num).toInt(), + links: (json['links'] as List) + .map((e) => Link.fromJson(e as Map)) + .toList(), + path: json['path'] as String, + perPage: (json['per_page'] as num).toInt(), + to: (json['to'] as num).toInt(), + total: (json['total'] as num).toInt(), + ); + +Map _$$MetaImplToJson(_$MetaImpl instance) => + { + 'current_page': instance.currentPage, + 'from': instance.from, + 'last_page': instance.lastPage, + 'links': instance.links, + 'path': instance.path, + 'per_page': instance.perPage, + 'to': instance.to, + 'total': instance.total, + }; + +_$LinkImpl _$$LinkImplFromJson(Map json) => _$LinkImpl( + url: json['url'] as String?, + label: json['label'] as String, + active: json['active'] as bool, + ); + +Map _$$LinkImplToJson(_$LinkImpl instance) => + { + 'url': instance.url, + 'label': instance.label, + 'active': instance.active, + }; diff --git a/lib/features/feed/models/feed_blog_post_model.dart b/lib/features/feed/models/feed_blog_post_model.dart index 43faed61..f904032d 100644 --- a/lib/features/feed/models/feed_blog_post_model.dart +++ b/lib/features/feed/models/feed_blog_post_model.dart @@ -16,12 +16,10 @@ class FeedBlogPostModel with _$FeedBlogPostModel { @JsonKey(name: "created_at") required DateTime createdAt, @JsonKey(name: "updated_at") required DateTime updatedAt, required String title, - @JsonKey(name: "total_likes") - required int totalLikes, - @JsonKey(name: "total_views") - required int totalViews, - @JsonKey(name: "total_comments") - required int totalComments, + @JsonKey(name: "total_likes") required int totalLikes, + @JsonKey(name: "total_views") required int totalViews, + @JsonKey(name: "total_comments") required int totalComments, + @JsonKey(name: "was_liked_by_me") required bool wasLikedByMe, }) = _FeedBlogPostModel; factory FeedBlogPostModel.fromJson(Map json) => _$FeedBlogPostModelFromJson(json); diff --git a/lib/features/feed/models/feed_blog_post_model.freezed.dart b/lib/features/feed/models/feed_blog_post_model.freezed.dart index b6fb79ca..08d5527a 100644 --- a/lib/features/feed/models/feed_blog_post_model.freezed.dart +++ b/lib/features/feed/models/feed_blog_post_model.freezed.dart @@ -38,6 +38,8 @@ mixin _$FeedBlogPostModel { int get totalViews => throw _privateConstructorUsedError; @JsonKey(name: "total_comments") int get totalComments => throw _privateConstructorUsedError; + @JsonKey(name: "was_liked_by_me") + bool get wasLikedByMe => throw _privateConstructorUsedError; Map toJson() => throw _privateConstructorUsedError; @JsonKey(ignore: true) @@ -63,7 +65,8 @@ abstract class $FeedBlogPostModelCopyWith<$Res> { String title, @JsonKey(name: "total_likes") int totalLikes, @JsonKey(name: "total_views") int totalViews, - @JsonKey(name: "total_comments") int totalComments}); + @JsonKey(name: "total_comments") int totalComments, + @JsonKey(name: "was_liked_by_me") bool wasLikedByMe}); $AuthorCopyWith<$Res> get author; } @@ -93,6 +96,7 @@ class _$FeedBlogPostModelCopyWithImpl<$Res, $Val extends FeedBlogPostModel> Object? totalLikes = null, Object? totalViews = null, Object? totalComments = null, + Object? wasLikedByMe = null, }) { return _then(_value.copyWith( id: null == id @@ -143,6 +147,10 @@ class _$FeedBlogPostModelCopyWithImpl<$Res, $Val extends FeedBlogPostModel> ? _value.totalComments : totalComments // ignore: cast_nullable_to_non_nullable as int, + wasLikedByMe: null == wasLikedByMe + ? _value.wasLikedByMe + : wasLikedByMe // ignore: cast_nullable_to_non_nullable + as bool, ) as $Val); } @@ -175,7 +183,8 @@ abstract class _$$FeedBlogPostModelImplCopyWith<$Res> String title, @JsonKey(name: "total_likes") int totalLikes, @JsonKey(name: "total_views") int totalViews, - @JsonKey(name: "total_comments") int totalComments}); + @JsonKey(name: "total_comments") int totalComments, + @JsonKey(name: "was_liked_by_me") bool wasLikedByMe}); @override $AuthorCopyWith<$Res> get author; @@ -204,6 +213,7 @@ class __$$FeedBlogPostModelImplCopyWithImpl<$Res> Object? totalLikes = null, Object? totalViews = null, Object? totalComments = null, + Object? wasLikedByMe = null, }) { return _then(_$FeedBlogPostModelImpl( id: null == id @@ -254,6 +264,10 @@ class __$$FeedBlogPostModelImplCopyWithImpl<$Res> ? _value.totalComments : totalComments // ignore: cast_nullable_to_non_nullable as int, + wasLikedByMe: null == wasLikedByMe + ? _value.wasLikedByMe + : wasLikedByMe // ignore: cast_nullable_to_non_nullable + as bool, )); } } @@ -273,7 +287,8 @@ class _$FeedBlogPostModelImpl implements _FeedBlogPostModel { required this.title, @JsonKey(name: "total_likes") required this.totalLikes, @JsonKey(name: "total_views") required this.totalViews, - @JsonKey(name: "total_comments") required this.totalComments}); + @JsonKey(name: "total_comments") required this.totalComments, + @JsonKey(name: "was_liked_by_me") required this.wasLikedByMe}); factory _$FeedBlogPostModelImpl.fromJson(Map json) => _$$FeedBlogPostModelImplFromJson(json); @@ -308,10 +323,13 @@ class _$FeedBlogPostModelImpl implements _FeedBlogPostModel { @override @JsonKey(name: "total_comments") final int totalComments; + @override + @JsonKey(name: "was_liked_by_me") + final bool wasLikedByMe; @override String toString() { - return 'FeedBlogPostModel(id: $id, state: $state, image: $image, description: $description, author: $author, youtubeUrl: $youtubeUrl, createdAt: $createdAt, updatedAt: $updatedAt, title: $title, totalLikes: $totalLikes, totalViews: $totalViews, totalComments: $totalComments)'; + return 'FeedBlogPostModel(id: $id, state: $state, image: $image, description: $description, author: $author, youtubeUrl: $youtubeUrl, createdAt: $createdAt, updatedAt: $updatedAt, title: $title, totalLikes: $totalLikes, totalViews: $totalViews, totalComments: $totalComments, wasLikedByMe: $wasLikedByMe)'; } @override @@ -337,7 +355,9 @@ class _$FeedBlogPostModelImpl implements _FeedBlogPostModel { (identical(other.totalViews, totalViews) || other.totalViews == totalViews) && (identical(other.totalComments, totalComments) || - other.totalComments == totalComments)); + other.totalComments == totalComments) && + (identical(other.wasLikedByMe, wasLikedByMe) || + other.wasLikedByMe == wasLikedByMe)); } @JsonKey(ignore: true) @@ -355,7 +375,8 @@ class _$FeedBlogPostModelImpl implements _FeedBlogPostModel { title, totalLikes, totalViews, - totalComments); + totalComments, + wasLikedByMe); @JsonKey(ignore: true) @override @@ -385,7 +406,8 @@ abstract class _FeedBlogPostModel implements FeedBlogPostModel { required final String title, @JsonKey(name: "total_likes") required final int totalLikes, @JsonKey(name: "total_views") required final int totalViews, - @JsonKey(name: "total_comments") required final int totalComments}) = + @JsonKey(name: "total_comments") required final int totalComments, + @JsonKey(name: "was_liked_by_me") required final bool wasLikedByMe}) = _$FeedBlogPostModelImpl; factory _FeedBlogPostModel.fromJson(Map json) = @@ -422,6 +444,9 @@ abstract class _FeedBlogPostModel implements FeedBlogPostModel { @JsonKey(name: "total_comments") int get totalComments; @override + @JsonKey(name: "was_liked_by_me") + bool get wasLikedByMe; + @override @JsonKey(ignore: true) _$$FeedBlogPostModelImplCopyWith<_$FeedBlogPostModelImpl> get copyWith => throw _privateConstructorUsedError; diff --git a/lib/features/feed/models/feed_blog_post_model.g.dart b/lib/features/feed/models/feed_blog_post_model.g.dart index 54557324..fadf4302 100644 --- a/lib/features/feed/models/feed_blog_post_model.g.dart +++ b/lib/features/feed/models/feed_blog_post_model.g.dart @@ -21,6 +21,7 @@ _$FeedBlogPostModelImpl _$$FeedBlogPostModelImplFromJson( totalLikes: (json['total_likes'] as num).toInt(), totalViews: (json['total_views'] as num).toInt(), totalComments: (json['total_comments'] as num).toInt(), + wasLikedByMe: json['was_liked_by_me'] as bool, ); Map _$$FeedBlogPostModelImplToJson( @@ -38,4 +39,5 @@ Map _$$FeedBlogPostModelImplToJson( 'total_likes': instance.totalLikes, 'total_views': instance.totalViews, 'total_comments': instance.totalComments, + 'was_liked_by_me': instance.wasLikedByMe, }; diff --git a/lib/features/feed/presentation/bloc/comments_cubit/comments_cubit.dart b/lib/features/feed/presentation/bloc/comments_cubit/comments_cubit.dart new file mode 100644 index 00000000..82918e6c --- /dev/null +++ b/lib/features/feed/presentation/bloc/comments_cubit/comments_cubit.dart @@ -0,0 +1,37 @@ +import 'package:eatvio_app/core/app_export.dart'; +import 'package:eatvio_app/features/feed/presentation/bloc/comments_cubit/comments_state.dart'; +import 'package:eatvio_app/features/feed/repositories/feed_repository.dart'; + +class CommentsCubit extends Cubit { + final FeedRepository feedRepository; + + CommentsCubit({ + required this.feedRepository, + }) : super(CommentsState()); + + getBlogPostComments(int id) async { + emit(CommentsState.loading()); + try { + emit(CommentsState.loaded(comment: await feedRepository.getBlogPostComments(id))); + } catch (e) { + emit(CommentsState.error(errorMessage: e.toString())); + } + } + + sendBlogPostComment({ + required int id, + required String commentText, + int? parentCommentId, + }) async { + try { + await feedRepository.sendBlogPostComment( + id: id, + commentText: commentText, + parentCommentId: parentCommentId, + ); + emit(CommentsState.loaded(comment: await feedRepository.getBlogPostComments(id))); + } catch (e) { + emit(CommentsState.error(errorMessage: e.toString())); + } + } +} diff --git a/lib/features/feed/presentation/bloc/comments_cubit/comments_state.dart b/lib/features/feed/presentation/bloc/comments_cubit/comments_state.dart new file mode 100644 index 00000000..2f910856 --- /dev/null +++ b/lib/features/feed/presentation/bloc/comments_cubit/comments_state.dart @@ -0,0 +1,19 @@ +import 'package:eatvio_app/features/feed/models/comment_model.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'comments_state.freezed.dart'; + +@freezed +abstract class CommentsState with _$CommentsState { + const factory CommentsState() = _CommentsState; + + const factory CommentsState.loading() = CommentsStateLoading; + + const factory CommentsState.loaded({ + required Comment comment, + }) = CommentsStateLoaded; + + const factory CommentsState.error({ + required String errorMessage, + }) = CommentsStateError; +} diff --git a/lib/features/feed/presentation/bloc/comments_cubit/comments_state.freezed.dart b/lib/features/feed/presentation/bloc/comments_cubit/comments_state.freezed.dart new file mode 100644 index 00000000..da3d0345 --- /dev/null +++ b/lib/features/feed/presentation/bloc/comments_cubit/comments_state.freezed.dart @@ -0,0 +1,621 @@ +// 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 'comments_state.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$CommentsState { + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(Comment comment) loaded, + required TResult Function(String errorMessage) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(Comment comment)? loaded, + TResult? Function(String errorMessage)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(Comment comment)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map( + TResult Function(_CommentsState value) $default, { + required TResult Function(CommentsStateLoading value) loading, + required TResult Function(CommentsStateLoaded value) loaded, + required TResult Function(CommentsStateError value) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_CommentsState value)? $default, { + TResult? Function(CommentsStateLoading value)? loading, + TResult? Function(CommentsStateLoaded value)? loaded, + TResult? Function(CommentsStateError value)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap( + TResult Function(_CommentsState value)? $default, { + TResult Function(CommentsStateLoading value)? loading, + TResult Function(CommentsStateLoaded value)? loaded, + TResult Function(CommentsStateError value)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $CommentsStateCopyWith<$Res> { + factory $CommentsStateCopyWith( + CommentsState value, $Res Function(CommentsState) then) = + _$CommentsStateCopyWithImpl<$Res, CommentsState>; +} + +/// @nodoc +class _$CommentsStateCopyWithImpl<$Res, $Val extends CommentsState> + implements $CommentsStateCopyWith<$Res> { + _$CommentsStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; +} + +/// @nodoc +abstract class _$$CommentsStateImplCopyWith<$Res> { + factory _$$CommentsStateImplCopyWith( + _$CommentsStateImpl value, $Res Function(_$CommentsStateImpl) then) = + __$$CommentsStateImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$CommentsStateImplCopyWithImpl<$Res> + extends _$CommentsStateCopyWithImpl<$Res, _$CommentsStateImpl> + implements _$$CommentsStateImplCopyWith<$Res> { + __$$CommentsStateImplCopyWithImpl( + _$CommentsStateImpl _value, $Res Function(_$CommentsStateImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$CommentsStateImpl implements _CommentsState { + const _$CommentsStateImpl(); + + @override + String toString() { + return 'CommentsState()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$CommentsStateImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(Comment comment) loaded, + required TResult Function(String errorMessage) error, + }) { + return $default(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(Comment comment)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return $default?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(Comment comment)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if ($default != null) { + return $default(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_CommentsState value) $default, { + required TResult Function(CommentsStateLoading value) loading, + required TResult Function(CommentsStateLoaded value) loaded, + required TResult Function(CommentsStateError value) error, + }) { + return $default(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_CommentsState value)? $default, { + TResult? Function(CommentsStateLoading value)? loading, + TResult? Function(CommentsStateLoaded value)? loaded, + TResult? Function(CommentsStateError value)? error, + }) { + return $default?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_CommentsState value)? $default, { + TResult Function(CommentsStateLoading value)? loading, + TResult Function(CommentsStateLoaded value)? loaded, + TResult Function(CommentsStateError value)? error, + required TResult orElse(), + }) { + if ($default != null) { + return $default(this); + } + return orElse(); + } +} + +abstract class _CommentsState implements CommentsState { + const factory _CommentsState() = _$CommentsStateImpl; +} + +/// @nodoc +abstract class _$$CommentsStateLoadingImplCopyWith<$Res> { + factory _$$CommentsStateLoadingImplCopyWith(_$CommentsStateLoadingImpl value, + $Res Function(_$CommentsStateLoadingImpl) then) = + __$$CommentsStateLoadingImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$CommentsStateLoadingImplCopyWithImpl<$Res> + extends _$CommentsStateCopyWithImpl<$Res, _$CommentsStateLoadingImpl> + implements _$$CommentsStateLoadingImplCopyWith<$Res> { + __$$CommentsStateLoadingImplCopyWithImpl(_$CommentsStateLoadingImpl _value, + $Res Function(_$CommentsStateLoadingImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$CommentsStateLoadingImpl implements CommentsStateLoading { + const _$CommentsStateLoadingImpl(); + + @override + String toString() { + return 'CommentsState.loading()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$CommentsStateLoadingImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(Comment comment) loaded, + required TResult Function(String errorMessage) error, + }) { + return loading(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(Comment comment)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return loading?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(Comment comment)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_CommentsState value) $default, { + required TResult Function(CommentsStateLoading value) loading, + required TResult Function(CommentsStateLoaded value) loaded, + required TResult Function(CommentsStateError value) error, + }) { + return loading(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_CommentsState value)? $default, { + TResult? Function(CommentsStateLoading value)? loading, + TResult? Function(CommentsStateLoaded value)? loaded, + TResult? Function(CommentsStateError value)? error, + }) { + return loading?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_CommentsState value)? $default, { + TResult Function(CommentsStateLoading value)? loading, + TResult Function(CommentsStateLoaded value)? loaded, + TResult Function(CommentsStateError value)? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(this); + } + return orElse(); + } +} + +abstract class CommentsStateLoading implements CommentsState { + const factory CommentsStateLoading() = _$CommentsStateLoadingImpl; +} + +/// @nodoc +abstract class _$$CommentsStateLoadedImplCopyWith<$Res> { + factory _$$CommentsStateLoadedImplCopyWith(_$CommentsStateLoadedImpl value, + $Res Function(_$CommentsStateLoadedImpl) then) = + __$$CommentsStateLoadedImplCopyWithImpl<$Res>; + @useResult + $Res call({Comment comment}); + + $CommentCopyWith<$Res> get comment; +} + +/// @nodoc +class __$$CommentsStateLoadedImplCopyWithImpl<$Res> + extends _$CommentsStateCopyWithImpl<$Res, _$CommentsStateLoadedImpl> + implements _$$CommentsStateLoadedImplCopyWith<$Res> { + __$$CommentsStateLoadedImplCopyWithImpl(_$CommentsStateLoadedImpl _value, + $Res Function(_$CommentsStateLoadedImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? comment = null, + }) { + return _then(_$CommentsStateLoadedImpl( + comment: null == comment + ? _value.comment + : comment // ignore: cast_nullable_to_non_nullable + as Comment, + )); + } + + @override + @pragma('vm:prefer-inline') + $CommentCopyWith<$Res> get comment { + return $CommentCopyWith<$Res>(_value.comment, (value) { + return _then(_value.copyWith(comment: value)); + }); + } +} + +/// @nodoc + +class _$CommentsStateLoadedImpl implements CommentsStateLoaded { + const _$CommentsStateLoadedImpl({required this.comment}); + + @override + final Comment comment; + + @override + String toString() { + return 'CommentsState.loaded(comment: $comment)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$CommentsStateLoadedImpl && + (identical(other.comment, comment) || other.comment == comment)); + } + + @override + int get hashCode => Object.hash(runtimeType, comment); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$CommentsStateLoadedImplCopyWith<_$CommentsStateLoadedImpl> get copyWith => + __$$CommentsStateLoadedImplCopyWithImpl<_$CommentsStateLoadedImpl>( + this, _$identity); + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(Comment comment) loaded, + required TResult Function(String errorMessage) error, + }) { + return loaded(comment); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(Comment comment)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return loaded?.call(comment); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(Comment comment)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (loaded != null) { + return loaded(comment); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_CommentsState value) $default, { + required TResult Function(CommentsStateLoading value) loading, + required TResult Function(CommentsStateLoaded value) loaded, + required TResult Function(CommentsStateError value) error, + }) { + return loaded(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_CommentsState value)? $default, { + TResult? Function(CommentsStateLoading value)? loading, + TResult? Function(CommentsStateLoaded value)? loaded, + TResult? Function(CommentsStateError value)? error, + }) { + return loaded?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_CommentsState value)? $default, { + TResult Function(CommentsStateLoading value)? loading, + TResult Function(CommentsStateLoaded value)? loaded, + TResult Function(CommentsStateError value)? error, + required TResult orElse(), + }) { + if (loaded != null) { + return loaded(this); + } + return orElse(); + } +} + +abstract class CommentsStateLoaded implements CommentsState { + const factory CommentsStateLoaded({required final Comment comment}) = + _$CommentsStateLoadedImpl; + + Comment get comment; + @JsonKey(ignore: true) + _$$CommentsStateLoadedImplCopyWith<_$CommentsStateLoadedImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$CommentsStateErrorImplCopyWith<$Res> { + factory _$$CommentsStateErrorImplCopyWith(_$CommentsStateErrorImpl value, + $Res Function(_$CommentsStateErrorImpl) then) = + __$$CommentsStateErrorImplCopyWithImpl<$Res>; + @useResult + $Res call({String errorMessage}); +} + +/// @nodoc +class __$$CommentsStateErrorImplCopyWithImpl<$Res> + extends _$CommentsStateCopyWithImpl<$Res, _$CommentsStateErrorImpl> + implements _$$CommentsStateErrorImplCopyWith<$Res> { + __$$CommentsStateErrorImplCopyWithImpl(_$CommentsStateErrorImpl _value, + $Res Function(_$CommentsStateErrorImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? errorMessage = null, + }) { + return _then(_$CommentsStateErrorImpl( + errorMessage: null == errorMessage + ? _value.errorMessage + : errorMessage // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc + +class _$CommentsStateErrorImpl implements CommentsStateError { + const _$CommentsStateErrorImpl({required this.errorMessage}); + + @override + final String errorMessage; + + @override + String toString() { + return 'CommentsState.error(errorMessage: $errorMessage)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$CommentsStateErrorImpl && + (identical(other.errorMessage, errorMessage) || + other.errorMessage == errorMessage)); + } + + @override + int get hashCode => Object.hash(runtimeType, errorMessage); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$CommentsStateErrorImplCopyWith<_$CommentsStateErrorImpl> get copyWith => + __$$CommentsStateErrorImplCopyWithImpl<_$CommentsStateErrorImpl>( + this, _$identity); + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(Comment comment) loaded, + required TResult Function(String errorMessage) error, + }) { + return error(errorMessage); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(Comment comment)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return error?.call(errorMessage); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(Comment comment)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(errorMessage); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_CommentsState value) $default, { + required TResult Function(CommentsStateLoading value) loading, + required TResult Function(CommentsStateLoaded value) loaded, + required TResult Function(CommentsStateError value) error, + }) { + return error(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_CommentsState value)? $default, { + TResult? Function(CommentsStateLoading value)? loading, + TResult? Function(CommentsStateLoaded value)? loaded, + TResult? Function(CommentsStateError value)? error, + }) { + return error?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_CommentsState value)? $default, { + TResult Function(CommentsStateLoading value)? loading, + TResult Function(CommentsStateLoaded value)? loaded, + TResult Function(CommentsStateError value)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(this); + } + return orElse(); + } +} + +abstract class CommentsStateError implements CommentsState { + const factory CommentsStateError({required final String errorMessage}) = + _$CommentsStateErrorImpl; + + String get errorMessage; + @JsonKey(ignore: true) + _$$CommentsStateErrorImplCopyWith<_$CommentsStateErrorImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart b/lib/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart index 904282c5..0de3af57 100644 --- a/lib/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart +++ b/lib/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart @@ -4,8 +4,8 @@ import 'package:eatvio_app/features/feed/repositories/feed_repository.dart'; class FeedCubit extends Cubit { final FeedRepository feedRepository; - int currentPage = 1; - final int lastPage = 7; + int _currentPage = 1; + final int _lastPage = 7; bool isLoading = false; FeedCubit({required this.feedRepository}) : super(const FeedState.loading()); @@ -27,9 +27,9 @@ class FeedCubit extends Cubit { loadNextPage() async { print('start'); try { - if (lastPage < currentPage) { - currentPage++; - final feedBlogPosts = await feedRepository.getFeedBlogPosts(page: currentPage); + if (_lastPage < _currentPage) { + _currentPage++; + final feedBlogPosts = await feedRepository.getFeedBlogPosts(page: _currentPage); emit( FeedState.loaded( feedBlogPostList: [ @@ -47,4 +47,8 @@ class FeedCubit extends Cubit { print('end'); } } + + likePost(int id) async => await feedRepository.likeBlogPost(id); + + unlikedPost(int id) async => await feedRepository.unlikedBlogPost(id); } diff --git a/lib/features/feed/presentation/widgets/blog_post_widget.dart b/lib/features/feed/presentation/widgets/blog_post_widget.dart index c75e6056..290560a6 100644 --- a/lib/features/feed/presentation/widgets/blog_post_widget.dart +++ b/lib/features/feed/presentation/widgets/blog_post_widget.dart @@ -3,6 +3,7 @@ import 'package:dismissible_page/dismissible_page.dart'; import 'package:eatvio_app/core/app_export.dart'; import 'package:eatvio_app/features/chat/presentation/pages/photo_view_screen.dart'; import 'package:eatvio_app/features/feed/models/feed_blog_post_model.dart'; +import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart'; import 'package:flutter/material.dart'; import 'package:flutter_html/flutter_html.dart'; import 'package:go_router/go_router.dart'; @@ -18,6 +19,16 @@ class BlogPostWidget extends StatefulWidget { } class _BlogPostWidgetState extends State { + late bool isLiked; + late int totalLikes; + + @override + void initState() { + isLiked = widget.feedBlogPostModel.wasLikedByMe; + totalLikes = widget.feedBlogPostModel.totalLikes; + super.initState(); + } + @override Widget build(BuildContext context) { return InkWell( @@ -106,7 +117,23 @@ class _BlogPostWidgetState extends State { padding: const EdgeInsets.symmetric(horizontal: 12), child: Row( children: [ - _iconButton(icon: Icons.favorite_border_rounded, text: widget.feedBlogPostModel.totalLikes.toString()), + _iconButton( + icon: Icons.favorite_border_rounded, + text: totalLikes.toString(), + iconColor: isLiked ? Colors.red.withOpacity(0.8) : null, + backgroundColor: isLiked ? Colors.red.withOpacity(0.1) : null, + textColor: isLiked ? Colors.red.withOpacity(0.8) : null, + onTap: () async { + setState(() { + isLiked = !isLiked; + isLiked ? totalLikes++ : totalLikes--; + }); + isLiked + ? await context.read().likePost(widget.feedBlogPostModel.id) + : await context.read().unlikedPost(widget.feedBlogPostModel.id); + await context.read().loadFeedBlogPostList(); + }, + ), SizedBox(width: 8), _iconButton( icon: Icons.mode_comment_outlined, @@ -150,14 +177,14 @@ class _BlogPostWidgetState extends State { ); } - _iconButton({required IconData icon, String? text, Function()? onTap}) { + _iconButton({required IconData icon, String? text, Function()? onTap, Color? iconColor, Color? backgroundColor, Color? textColor}) { return InkWell( onTap: onTap ?? () {}, borderRadius: BorderRadius.circular(16), child: Ink( padding: EdgeInsets.symmetric(horizontal: 12, vertical: 4), decoration: BoxDecoration( - color: appTheme.gray100, + color: backgroundColor ?? appTheme.gray100, borderRadius: BorderRadius.circular(16), ), height: 32, @@ -167,14 +194,14 @@ class _BlogPostWidgetState extends State { Icon( icon, size: 20, - color: appTheme.gray600, + color: iconColor ?? appTheme.gray600, ), if (text != null) SizedBox(width: 8), if (text != null) Text( text, style: TextStyle( - color: appTheme.gray600, + color: textColor ?? appTheme.gray600, fontWeight: FontWeight.w500, ), ), diff --git a/lib/features/feed/repositories/feed_repository.dart b/lib/features/feed/repositories/feed_repository.dart index b217759d..01d0dedb 100644 --- a/lib/features/feed/repositories/feed_repository.dart +++ b/lib/features/feed/repositories/feed_repository.dart @@ -1,3 +1,4 @@ +import 'package:eatvio_app/features/feed/models/comment_model.dart'; import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart'; import 'package:eatvio_app/features/feed/models/feed_blog_post_settings_model.dart'; import 'package:eatvio_app/features/feed/models/recipes_model.dart'; @@ -31,4 +32,44 @@ class FeedRepository { rethrow; } } + + Future getBlogPostComments(int id) async { + try { + return (await feedService.getBlogPostComments(id: id)); + } catch (e) { + rethrow; + } + } + + Future sendBlogPostComment({ + required int id, + required String commentText, + int? parentCommentId, + }) async { + try { + await feedService.sendBlogPostComment( + id: id, + body: commentText, + parentCommentId: parentCommentId, + ); + } catch (e) { + rethrow; + } + } + + Future likeBlogPost(int id) async { + try { + await feedService.likeBlogPost(id: id); + } catch (e) { + rethrow; + } + } + + Future unlikedBlogPost(int id) async { + try { + await feedService.unlikedBlogPost(id: id); + } catch (e) { + rethrow; + } + } } diff --git a/lib/features/feed/services/feed_service.dart b/lib/features/feed/services/feed_service.dart index 3fbb2dce..19d459cf 100644 --- a/lib/features/feed/services/feed_service.dart +++ b/lib/features/feed/services/feed_service.dart @@ -1,4 +1,5 @@ import 'package:dio/dio.dart'; +import 'package:eatvio_app/features/feed/models/comment_model.dart'; import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart'; import 'package:eatvio_app/features/feed/models/feed_blog_post_settings_model.dart'; import 'package:eatvio_app/features/feed/models/recipes_pagination_model.dart'; @@ -20,4 +21,26 @@ abstract class FeedService { @GET('/api/diets/index') Future getDiets(); + + @GET('/api/blogPosts/{id}/comments/show') + Future getBlogPostComments({ + @Path() required int id, + }); + + @POST('/api/blogPosts/{id}/comment/create') + Future sendBlogPostComment({ + @Path() required int id, + @Part() required String body, + @Part() int? parentCommentId, + }); + + @POST('/api/blogPosts/{id}/like') + Future likeBlogPost({ + @Path() required int id, + }); + + @POST('/api/blogPosts/{id}/unliked') + Future unlikedBlogPost({ + @Path() required int id, + }); } diff --git a/lib/features/feed/services/feed_service.g.dart b/lib/features/feed/services/feed_service.g.dart index a0b8a21e..39dec4e4 100644 --- a/lib/features/feed/services/feed_service.g.dart +++ b/lib/features/feed/services/feed_service.g.dart @@ -99,6 +99,129 @@ class _FeedService implements FeedService { return _value; } + @override + Future getBlogPostComments({required int id}) async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + const Map? _data = null; + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/blogPosts/${id}/comments/show', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); + final _result = await _dio.fetch>(_options); + late Comment _value; + try { + _value = Comment.fromJson(_result.data!); + } on Object catch (e, s) { + errorLogger?.logError(e, s, _options); + rethrow; + } + return _value; + } + + @override + Future sendBlogPostComment({ + required int id, + required String body, + int? parentCommentId, + }) async { + final _extra = {}; + final queryParameters = {}; + queryParameters.removeWhere((k, v) => v == null); + final _headers = {}; + final _data = FormData(); + _data.fields.add(MapEntry( + 'body', + body, + )); + if (parentCommentId != null) { + _data.fields.add(MapEntry( + 'parentCommentId', + parentCommentId.toString(), + )); + } + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/blogPosts/${id}/comment/create', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); + await _dio.fetch(_options); + } + + @override + Future likeBlogPost({required int id}) async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + const Map? _data = null; + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/blogPosts/${id}/like', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); + await _dio.fetch(_options); + } + + @override + Future unlikedBlogPost({required int id}) async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + const Map? _data = null; + final _options = _setStreamType(Options( + method: 'POST', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/blogPosts/${id}/unliked', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); + await _dio.fetch(_options); + } + RequestOptions _setStreamType(RequestOptions requestOptions) { if (T != dynamic && !(requestOptions.responseType == ResponseType.bytes || diff --git a/lib/locator_service.dart b/lib/locator_service.dart index 1e99c3c9..f0a28808 100644 --- a/lib/locator_service.dart +++ b/lib/locator_service.dart @@ -7,11 +7,13 @@ 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/repositories/chat_repository.dart'; import 'package:eatvio_app/features/chat/services/chat_service.dart'; import 'package:eatvio_app/features/diary/presentation/bloc/diary_bloc.dart'; import 'package:eatvio_app/features/diary/repositories/diary_repository.dart'; import 'package:eatvio_app/features/diary/services/diary_service.dart'; +import 'package:eatvio_app/features/feed/presentation/bloc/comments_cubit/comments_cubit.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/recipes_cubit/recipes_cubit.dart'; @@ -45,6 +47,8 @@ Future init() async { sl.registerFactory(() => ProfileCubit(profileRepository: sl())); sl.registerFactory(() => RecipeCreateCubit(recipeRepository: sl())); sl.registerFactory(() => DietsCubit(feedRepository: sl())); + sl.registerFactory(() => CommentsCubit(feedRepository: sl())); + sl.registerFactory(() => ChatSelectCubit(chatRepository: sl())); // Repository sl.registerLazySingleton(() => ChatRepository(chatService: sl())); diff --git a/lib/main.dart b/lib/main.dart index 8a9f334c..34f37ccf 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -4,8 +4,7 @@ import 'package:eatvio_app/core/initialization_cubit/initialization_state.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/calendar/presentation/bloc/calendar_cubit.dart'; -import 'package:eatvio_app/features/chat/presentation/pages/chat_select_screen/bloc/chat_select_bloc.dart'; -import 'package:eatvio_app/features/chat/presentation/pages/chat_select_screen/models/chat_select_model.dart'; +import 'package:eatvio_app/features/chat/presentation/bloc/chat_select_cubit/chat_select_cubit.dart'; import 'package:eatvio_app/features/diary/presentation/bloc/diary_bloc.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart'; @@ -56,9 +55,7 @@ class MyApp extends StatelessWidget { BlocProvider(create: (context) => sl()..loadDiets()), BlocProvider(create: (context) => MyProfileBloc(MyProfileState(myProfileModelObj: MyProfileModel()))..add(MyProfileInitialEvent())), BlocProvider(create: (context) => sl()..add(LoadDiary())), - BlocProvider( - create: (context) => ChatSelectBloc(ChatSelectState(chatSelectModelObj: ChatSelectModel()))..add(ChatSelectInitialEvent()), - ), + BlocProvider(create: (context) => sl()..getChatRooms()), BlocProvider(create: (context) => sl()..loadCalendarList()), BlocProvider(create: (context) => sl()..loadRecipeCreate()), ], diff --git a/pubspec.yaml b/pubspec.yaml index 02db5422..859b095d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,29 +14,29 @@ dependencies: sdk: flutter flutter_bloc: ^8.1.6 - shared_preferences: ^2.2.3 + shared_preferences: ^2.3.2 hive: ^2.2.3 hive_flutter: ^1.1.0 - cached_network_image: ^3.3.1 + cached_network_image: ^3.4.1 flutter_svg: ^2.0.10 equatable: ^2.0.5 - freezed_annotation: ^2.4.2 + freezed_annotation: ^2.4.4 json_annotation: ^4.9.0 validators: ^3.0.0 isar_flutter_libs: ^3.1.0 - path_provider: ^2.1.3 + path_provider: ^2.1.4 fl_chart: ^0.68.0 flutter_spinkit: ^5.2.1 carousel_slider_plus: ^7.0.0 flutter_form_builder: ^9.3.0 image_picker: ^1.1.2 flutter_typeahead: ^5.2.0 - go_router: ^14.2.0 + go_router: ^14.2.3 keyboard_dismisser: ^3.0.0 - retrofit: ^4.1.0 + retrofit: ^4.2.0 get_it: ^7.7.0 - dio: ^5.5.0 - dart_pusher_channels: ^1.2.2+1 + dio: ^5.6.0 + dart_pusher_channels: ^1.2.3 photo_view: ^0.15.0 dismissible_page: ^1.0.2 url_launcher: ^6.3.0 @@ -44,8 +44,8 @@ dependencies: lazy_load_scrollview: ^1.3.0 badges: ^3.1.2 google_fonts: ^6.2.1 - location: 6.0.2 - syncfusion_flutter_charts: ^26.2.8 + location: ^6.0.2 + syncfusion_flutter_charts: ^26.2.9 table_calendar: ^3.1.2 flutter_keyboard_visibility: ^6.0.0 share_plus: ^10.0.0 @@ -56,7 +56,7 @@ dev_dependencies: build_runner: ^2.4.11 freezed: ^2.5.2 json_serializable: ^6.8.0 - retrofit_generator: ^8.1.1 + retrofit_generator: ^8.2.0 flutter_test: sdk: flutter