From 026a11a6ca6133875d2c6e961b254a22a74754c3 Mon Sep 17 00:00:00 2001 From: mso7nueh Date: Mon, 19 Aug 2024 16:15:18 +0300 Subject: [PATCH] feat(feed): comments + redesign blogPost --- .../presentation/pages/blog_post_screen.dart | 602 +++++---- .../chat/presentation/pages/chat_screen.dart | 39 +- .../chat/repositories/chat_repository.dart | 19 +- lib/features/chat/services/chat_service.dart | 4 +- .../chat/services/chat_service.g.dart | 9 +- lib/features/feed/models/comment_model.dart | 67 + .../feed/models/comment_model.freezed.dart | 1188 +++++++++++++++++ lib/features/feed/models/comment_model.g.dart | 95 ++ .../bloc/comments_cubit/comments_cubit.dart | 37 + .../bloc/comments_cubit/comments_state.dart | 19 + .../comments_state.freezed.dart | 621 +++++++++ .../feed/repositories/feed_repository.dart | 25 + lib/features/feed/services/feed_service.dart | 13 + .../feed/services/feed_service.g.dart | 73 + lib/locator_service.dart | 6 + pubspec.yaml | 6 +- 16 files changed, 2528 insertions(+), 295 deletions(-) create mode 100644 lib/features/feed/models/comment_model.dart create mode 100644 lib/features/feed/models/comment_model.freezed.dart create mode 100644 lib/features/feed/models/comment_model.g.dart create mode 100644 lib/features/feed/presentation/bloc/comments_cubit/comments_cubit.dart create mode 100644 lib/features/feed/presentation/bloc/comments_cubit/comments_state.dart create mode 100644 lib/features/feed/presentation/bloc/comments_cubit/comments_state.freezed.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..14281d47 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,363 @@ 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/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(); + + @override + void initState() { + commentsCubit.getBlogPostComments(widget.blogPost.id); + 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), + 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), + SizedBox( + width: mediaQueryData.size.width - 64, + child: TextFormField( + 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, + ); + setState(() { + textEditingController.clear(); + }); + } + }, + child: Container( + decoration: BoxDecoration( + color: appTheme.blueA400, + 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, + ), + ), + ], + ), + ], + ), + ), + ), + 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: widget.blogPost.totalLikes.toString()), + 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, + 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, + ), + ), + ], + ), ], ), ), ); } - _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}) { + return InkWell( + onTap: onTap ?? () {}, + borderRadius: BorderRadius.circular(16), + child: Ink( + padding: EdgeInsets.symmetric(horizontal: 12, vertical: 4), + decoration: BoxDecoration( + color: appTheme.gray100, + borderRadius: BorderRadius.circular(16), + ), + height: 32, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + icon, + size: 20, + color: 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: 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/presentation/pages/chat_screen.dart b/lib/features/chat/presentation/pages/chat_screen.dart index d724c3bd..eed575cb 100644 --- a/lib/features/chat/presentation/pages/chat_screen.dart +++ b/lib/features/chat/presentation/pages/chat_screen.dart @@ -163,14 +163,37 @@ 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 } @@ -239,9 +262,9 @@ class _ChatScreenState extends State { 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(); }); diff --git a/lib/features/chat/repositories/chat_repository.dart b/lib/features/chat/repositories/chat_repository.dart index f249f204..d5e67be1 100644 --- a/lib/features/chat/repositories/chat_repository.dart +++ b/lib/features/chat/repositories/chat_repository.dart @@ -1,5 +1,6 @@ import 'dart:io'; - +import 'package:dio/dio.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 +19,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); diff --git a/lib/features/chat/services/chat_service.dart b/lib/features/chat/services/chat_service.dart index 49a8f810..6061e7eb 100644 --- a/lib/features/chat/services/chat_service.dart +++ b/lib/features/chat/services/chat_service.dart @@ -1,5 +1,3 @@ -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'; @@ -22,7 +20,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 48a9b016..efa7d26b 100644 --- a/lib/features/chat/services/chat_service.g.dart +++ b/lib/features/chat/services/chat_service.g.dart @@ -59,7 +59,7 @@ class _ChatService implements ChatService { Future sendMessage({ required String id, String? data, - List? media_data, + List? media_data, }) async { final _extra = {}; final queryParameters = {}; @@ -73,12 +73,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))); } final _options = _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/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/repositories/feed_repository.dart b/lib/features/feed/repositories/feed_repository.dart index b217759d..3bbaeadd 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,28 @@ 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; + } + } } diff --git a/lib/features/feed/services/feed_service.dart b/lib/features/feed/services/feed_service.dart index 3fbb2dce..0e3248a5 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,16 @@ 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, + }); } diff --git a/lib/features/feed/services/feed_service.g.dart b/lib/features/feed/services/feed_service.g.dart index 36b29923..bb7171f5 100644 --- a/lib/features/feed/services/feed_service.g.dart +++ b/lib/features/feed/services/feed_service.g.dart @@ -120,6 +120,79 @@ 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); + } + RequestOptions _setStreamType(RequestOptions requestOptions) { if (T != dynamic && !(requestOptions.responseType == ResponseType.bytes || diff --git a/lib/locator_service.dart b/lib/locator_service.dart index e580c725..52d3f37f 100644 --- a/lib/locator_service.dart +++ b/lib/locator_service.dart @@ -12,6 +12,7 @@ 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 +46,7 @@ Future init() async { sl.registerFactory(() => ProfileCubit(profileRepository: sl())); sl.registerFactory(() => RecipeCreateCubit(recipeRepository: sl())); sl.registerFactory(() => DietsCubit(feedRepository: sl())); + sl.registerFactory(() => CommentsCubit(feedRepository: sl())); // Repository sl.registerLazySingleton(() => ChatRepository(chatService: sl())); @@ -69,6 +71,10 @@ Future init() async { () => Dio( BaseOptions( baseUrl: baseUrl, + headers: { + 'accept': 'application/json', + 'content-type': 'application/json', + }, ), ), ); diff --git a/pubspec.yaml b/pubspec.yaml index 02db5422..33058e55 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,7 +14,7 @@ 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 @@ -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