diff --git a/assets/icons/filter.svg b/assets/icons/filter.svg
new file mode 100644
index 00000000..7f5491ff
--- /dev/null
+++ b/assets/icons/filter.svg
@@ -0,0 +1,67 @@
+
+
+
+
diff --git a/assets/icons/like.svg b/assets/icons/like.svg
index 4fe0f919..11397221 100644
--- a/assets/icons/like.svg
+++ b/assets/icons/like.svg
@@ -1,22 +1,42 @@
-
-
+
-
diff --git a/assets/icons/like_filled.svg b/assets/icons/like_filled.svg
index 6233ab3a..e39670c3 100644
--- a/assets/icons/like_filled.svg
+++ b/assets/icons/like_filled.svg
@@ -1,22 +1,42 @@
-
-
+
-
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 bd4db44e..0c375699 100644
--- a/lib/features/blog_post/presentation/pages/blog_post_screen.dart
+++ b/lib/features/blog_post/presentation/pages/blog_post_screen.dart
@@ -2,11 +2,11 @@ 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/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/features/feed/presentation/widgets/comments_widget.dart';
import 'package:eatvio_app/locator_service.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
@@ -31,7 +31,6 @@ class _BlogPostScreenState extends State {
@override
void initState() {
- commentsCubit.getBlogPostComments(widget.blogPost.id);
isLiked = widget.blogPost.wasLikedByMe;
totalLikes = widget.blogPost.totalLikes;
super.initState();
@@ -40,8 +39,20 @@ class _BlogPostScreenState extends State {
@override
Widget build(BuildContext context) {
return BlocProvider(
- create: (BuildContext context) => commentsCubit,
- child: BlocBuilder(
+ create: (BuildContext context) => commentsCubit
+ ..getComments(
+ widget.blogPost.id.toString(),
+ CommentSourceType.blogPost,
+ true,
+ ),
+ child: BlocConsumer(
+ listener: (BuildContext context, CommentsState state) {
+ if (state is CommentsStateLoaded) {
+ setState(() {
+ replyId = state.replyId;
+ });
+ }
+ },
builder: (BuildContext context, CommentsState state) {
return Scaffold(
resizeToAvoidBottomInset: true,
@@ -61,6 +72,7 @@ class _BlogPostScreenState extends State {
if (replyId != null)
GestureDetector(
onTap: () {
+ context.read().setReplyId(null);
setState(() {
replyId = null;
textEditingController.clear();
@@ -83,7 +95,7 @@ class _BlogPostScreenState extends State {
),
if (replyId != null) SizedBox(width: 8),
SizedBox(
- width: mediaQueryData.size.width - (replyId == null ? 64 : 104),
+ width: MediaQuery.of(context).size.width - (replyId == null ? 64 : 104),
child: TextFormField(
onChanged: (_) {
setState(() {});
@@ -137,11 +149,13 @@ class _BlogPostScreenState extends State {
GestureDetector(
onTap: () {
if (textEditingController.text.length > 2) {
- commentsCubit.sendBlogPostComment(
- id: widget.blogPost.id,
+ commentsCubit.sendComment(
+ id: widget.blogPost.id.toString(),
commentText: textEditingController.text,
parentCommentId: replyId,
+ commentSourceType: CommentSourceType.blogPost,
);
+ context.read().setReplyId(null);
setState(() {
textEditingController.clear();
replyId = null;
@@ -310,7 +324,13 @@ class _BlogPostScreenState extends State {
padding: const EdgeInsets.all(32),
child: CupertinoActivityIndicator(),
),
- if (state is CommentsStateLoaded) _buildComments(state.comment),
+ if (state is CommentsStateLoaded)
+ CommentsWidget(
+ id: widget.blogPost.id.toString(),
+ commentSourceType: CommentSourceType.blogPost,
+ comment: state.comment,
+ replyId: replyId,
+ ),
],
),
),
@@ -320,102 +340,6 @@ class _BlogPostScreenState extends State {
);
}
- _buildComments(CommentModel comment) {
- return Column(
- children: [
- for (int i = 0; i < comment.data.length; i++) ...[
- _comment(comment.data[i]),
- if (comment.data[i].childrenComments.isNotEmpty) SizedBox(height: 8),
- 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(Comment comment, [double radius = 16]) {
- return Container(
- width: MediaQuery.of(context).size.width,
- decoration: BoxDecoration(
- color: replyId == comment.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: [
- CircleAvatar(
- foregroundImage: NetworkImage(comment.authorProfileIcon),
- radius: radius,
- ),
- SizedBox(width: 8),
- Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- mainAxisAlignment: MainAxisAlignment.start,
- children: [
- Text(
- comment.authorName,
- style: TextStyle(
- height: 1,
- color: Colors.grey.shade600,
- fontWeight: FontWeight.w500,
- ),
- ),
- SizedBox(width: 4),
- Text(
- comment.body,
- style: TextStyle(
- height: 1,
- color: Colors.black,
- ),
- ),
- SizedBox(height: 4),
- Row(
- children: [
- Text(
- comment.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 = comment.id;
- });
- },
- child: Text(
- 'Ответить',
- style: TextStyle(
- height: 1,
- fontSize: 12,
- color: Colors.grey.shade800,
- fontWeight: FontWeight.w500,
- ),
- ),
- ),
- ],
- ),
- ],
- ),
- ],
- ),
- ),
- );
- }
-
_iconButton({required IconData icon, String? text, Function()? onTap, Color? iconColor, Color? backgroundColor, Color? textColor}) {
return InkWell(
onTap: onTap ?? () {},
diff --git a/lib/features/chat/presentation/pages/chat_screen.dart b/lib/features/chat/presentation/pages/chat_screen.dart
index fac8c5eb..c11a4652 100644
--- a/lib/features/chat/presentation/pages/chat_screen.dart
+++ b/lib/features/chat/presentation/pages/chat_screen.dart
@@ -1,4 +1,5 @@
import 'dart:io';
+
import 'package:eatvio_app/core/app_export.dart';
import 'package:eatvio_app/features/chat/presentation/bloc/chat_room_cubit/chat_room_cubit.dart';
import 'package:eatvio_app/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.dart';
@@ -7,7 +8,6 @@ import 'package:eatvio_app/locator_service.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
-import 'package:lazy_load_scrollview/lazy_load_scrollview.dart';
class ChatScreen extends StatefulWidget {
final String chatId;
@@ -25,6 +25,24 @@ class _ChatScreenState extends State {
final scrollController = ScrollController();
final TextEditingController textEditingController = TextEditingController();
+ @override
+ void initState() {
+ scrollController.addListener(_onScroll);
+ super.initState();
+ }
+
+ _onScroll() {
+ if (scrollController.offset >= scrollController.position.maxScrollExtent && !scrollController.position.outOfRange) {
+ context.read().loadNextPage(widget.chatId);
+ }
+ }
+
+ @override
+ void dispose() {
+ scrollController.dispose();
+ super.dispose();
+ }
+
Widget build(BuildContext context) {
return BlocProvider(
create: (BuildContext context) => sl()..initChat(widget.chatId),
@@ -116,40 +134,35 @@ class _ChatScreenState extends State {
child: Container(
color: Color(0xFFF0F2F5),
width: double.maxFinite,
- child: LazyLoadScrollView(
- onEndOfPage: () => context.read().loadNextPage(widget.chatId),
- isLoading: state.isLoading,
- scrollOffset: MediaQuery.of(context).size.height.toInt(),
- child: CustomScrollView(
- physics: BouncingScrollPhysics(),
- controller: scrollController,
- reverse: true,
- slivers: [
- SliverPadding(
- padding: EdgeInsets.symmetric(vertical: 16),
- sliver: SliverList(
- delegate: SliverChildBuilderDelegate(
- (context, index) {
- if (index < state.chatMessages.length) {
- return ChatBubbleWidget(
- sendTime: state.chatMessages[index].updatedAt,
- text: state.chatMessages[index].data.trim(),
- isCurrentUser: state.chatRoom.users['to_chat_user']!.id != state.chatMessages[index].authorId,
- mediaData: state.chatMessages[index].mediaData ?? [],
- );
- } else {
- return Padding(
- padding: const EdgeInsets.all(8),
- child: Center(child: CupertinoActivityIndicator()),
- );
- }
- },
- childCount: state.chatMessages.length + (state.isLoading ? 1 : 0),
- ),
+ child: CustomScrollView(
+ physics: BouncingScrollPhysics(),
+ controller: scrollController,
+ reverse: true,
+ slivers: [
+ SliverPadding(
+ padding: EdgeInsets.symmetric(vertical: 16),
+ sliver: SliverList(
+ delegate: SliverChildBuilderDelegate(
+ (context, index) {
+ if (index < state.chatMessages.length) {
+ return ChatBubbleWidget(
+ sendTime: state.chatMessages[index].updatedAt,
+ text: state.chatMessages[index].data.trim(),
+ isCurrentUser: state.chatRoom.users['to_chat_user']!.id != state.chatMessages[index].authorId,
+ mediaData: state.chatMessages[index].mediaData ?? [],
+ );
+ } else {
+ return Padding(
+ padding: const EdgeInsets.all(8),
+ child: Center(child: CupertinoActivityIndicator()),
+ );
+ }
+ },
+ childCount: state.chatMessages.length + (state.isLoading ? 1 : 0),
),
),
- ],
- ),
+ ),
+ ],
),
),
),
diff --git a/lib/features/diets/presentation/pages/about_diet_screen.dart b/lib/features/diets/presentation/pages/about_diet_screen.dart
index ab1e69ff..627c7a68 100644
--- a/lib/features/diets/presentation/pages/about_diet_screen.dart
+++ b/lib/features/diets/presentation/pages/about_diet_screen.dart
@@ -1,11 +1,10 @@
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/diets_pagination_model.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/widgets/comments_widget.dart';
import 'package:eatvio_app/locator_service.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
@@ -28,17 +27,23 @@ class _AboutDietScreenState extends State {
int? replyId;
final textEditingController = TextEditingController();
- @override
- void initState() {
- super.initState();
- commentsCubit.getDietsComments(widget.diet.id);
- }
-
@override
Widget build(BuildContext context) {
return BlocProvider(
- create: (BuildContext context) => commentsCubit,
- child: BlocBuilder(
+ create: (BuildContext context) => commentsCubit
+ ..getComments(
+ widget.diet.id.toString(),
+ CommentSourceType.diet,
+ true,
+ ),
+ child: BlocConsumer(
+ listener: (BuildContext context, CommentsState state) {
+ if (state is CommentsStateLoaded) {
+ setState(() {
+ replyId = state.replyId;
+ });
+ }
+ },
builder: (BuildContext context, CommentsState state) {
return Scaffold(
resizeToAvoidBottomInset: true,
@@ -80,6 +85,7 @@ class _AboutDietScreenState extends State {
if (replyId != null)
GestureDetector(
onTap: () {
+ context.read().setReplyId(null);
setState(() {
replyId = null;
textEditingController.clear();
@@ -156,11 +162,13 @@ class _AboutDietScreenState extends State {
GestureDetector(
onTap: () {
if (textEditingController.text.length > 2) {
- commentsCubit.sendDietsComment(
- id: widget.diet.id,
+ commentsCubit.sendComment(
+ id: widget.diet.id.toString(),
commentText: textEditingController.text,
parentCommentId: replyId,
+ commentSourceType: CommentSourceType.diet,
);
+ context.read().setReplyId(null);
setState(() {
textEditingController.clear();
replyId = null;
@@ -187,25 +195,6 @@ class _AboutDietScreenState extends State {
],
),
),
- // floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
- // floatingActionButton: SizedBox(
- // width: MediaQuery.of(context).size.width - 32,
- // child: FloatingActionButton.extended(
- // heroTag: 'nextButtonRegistration',
- // highlightElevation: 0,
- // elevation: 0,
- // focusElevation: 0,
- // shape: RoundedRectangleBorder(
- // borderRadius: BorderRadius.circular(16),
- // ),
- // backgroundColor: appTheme.greenA700,
- // onPressed: () {},
- // label: Text(
- // 'Начать диету',
- // style: theme.textTheme.titleSmall,
- // ),
- // ),
- // ),
appBar: AppBar(
actions: [
InkWell(
@@ -340,7 +329,13 @@ class _AboutDietScreenState extends State {
padding: const EdgeInsets.all(32),
child: CupertinoActivityIndicator(),
),
- if (state is CommentsStateLoaded) _buildComments(state.comment),
+ if (state is CommentsStateLoaded)
+ CommentsWidget(
+ id: widget.diet.id.toString(),
+ commentSourceType: CommentSourceType.diet,
+ comment: state.comment,
+ replyId: replyId,
+ ),
],
),
),
@@ -446,100 +441,4 @@ class _AboutDietScreenState extends State {
],
);
}
-
- _buildComments(CommentModel 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(Comment diet, [double radius = 16]) {
- return Container(
- width: MediaQuery.of(context).size.width,
- decoration: BoxDecoration(
- color: replyId == diet.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: [
- CircleAvatar(
- foregroundImage: NetworkImage(diet.authorProfileIcon),
- radius: radius,
- ),
- SizedBox(width: 8),
- Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- mainAxisAlignment: MainAxisAlignment.start,
- children: [
- Text(
- diet.authorName,
- style: TextStyle(
- height: 1,
- color: Colors.grey.shade600,
- fontWeight: FontWeight.w500,
- ),
- ),
- SizedBox(width: 4),
- Text(
- diet.body,
- style: TextStyle(
- height: 1,
- color: Colors.black,
- ),
- ),
- SizedBox(height: 4),
- Row(
- children: [
- Text(
- diet.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 = diet.id;
- });
- },
- child: Text(
- 'Ответить',
- style: TextStyle(
- height: 1,
- fontSize: 12,
- color: Colors.grey.shade800,
- fontWeight: FontWeight.w500,
- ),
- ),
- ),
- ],
- ),
- ],
- ),
- ],
- ),
- ),
- );
- }
}
diff --git a/lib/features/feed/presentation/bloc/comments_cubit/comments_cubit.dart b/lib/features/feed/presentation/bloc/comments_cubit/comments_cubit.dart
index 3dc735fa..9c7b009d 100644
--- a/lib/features/feed/presentation/bloc/comments_cubit/comments_cubit.dart
+++ b/lib/features/feed/presentation/bloc/comments_cubit/comments_cubit.dart
@@ -1,5 +1,6 @@
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/presentation/widgets/comments_widget.dart';
import 'package:eatvio_app/features/feed/repositories/feed_repository.dart';
class CommentsCubit extends Cubit {
@@ -9,79 +10,60 @@ class CommentsCubit extends Cubit {
required this.feedRepository,
}) : super(CommentsState());
- getBlogPostComments(int id) async {
- emit(CommentsState.loading());
+ setReplyId(int? replyId) {
+ emit((state as CommentsStateLoaded).copyWith(replyId: replyId));
+ }
+
+ getComments(String id, CommentSourceType commentSourceType, [bool isFirstFetch = false]) async {
+ if (isFirstFetch) emit(CommentsState.loading());
try {
- emit(CommentsState.loaded(comment: await feedRepository.getBlogPostComments(id)));
+ switch (commentSourceType) {
+ case CommentSourceType.blogPost:
+ emit(CommentsState.loaded(comment: await feedRepository.getBlogPostComments(id)));
+ break;
+ case CommentSourceType.diet:
+ emit(CommentsState.loaded(comment: await feedRepository.getDietsComments(id)));
+ break;
+ case CommentSourceType.recipe:
+ emit(CommentsState.loaded(comment: await feedRepository.getRecipesComments(id)));
+ break;
+ }
} catch (e) {
emit(CommentsState.error(errorMessage: e.toString()));
}
}
- getRecipesComments(String id) async {
- emit(CommentsState.loading());
- try {
- emit(CommentsState.loaded(comment: await feedRepository.getRecipesComments(id)));
- } catch (e) {
- emit(CommentsState.error(errorMessage: e.toString()));
- }
- }
-
- getDietsComments(int id) async {
- emit(CommentsState.loading());
- try {
- emit(CommentsState.loaded(comment: await feedRepository.getDietsComments(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()));
- }
- }
-
- sendRecipesComment({
+ sendComment({
required String id,
required String commentText,
+ required CommentSourceType commentSourceType,
int? parentCommentId,
}) async {
try {
- await feedRepository.sendRecipesComment(
- id: id,
- commentText: commentText,
- parentCommentId: parentCommentId,
- );
- emit(CommentsState.loaded(comment: await feedRepository.getRecipesComments(id)));
- } catch (e) {
- emit(CommentsState.error(errorMessage: e.toString()));
- }
- }
-
- sendDietsComment({
- required int id,
- required String commentText,
- int? parentCommentId,
- }) async {
- try {
- await feedRepository.sendDietsComment(
- id: id,
- commentText: commentText,
- parentCommentId: parentCommentId,
- );
- emit(CommentsState.loaded(comment: await feedRepository.getDietsComments(id)));
+ switch (commentSourceType) {
+ case CommentSourceType.blogPost:
+ await feedRepository.sendBlogPostComment(
+ id: id,
+ commentText: commentText,
+ parentCommentId: parentCommentId,
+ );
+ break;
+ case CommentSourceType.diet:
+ await feedRepository.sendDietsComment(
+ id: id,
+ commentText: commentText,
+ parentCommentId: parentCommentId,
+ );
+ break;
+ case CommentSourceType.recipe:
+ await feedRepository.sendRecipesComment(
+ id: id,
+ commentText: commentText,
+ parentCommentId: parentCommentId,
+ );
+ break;
+ }
+ getComments(id, commentSourceType);
} 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
index 1be83081..0f9c49ea 100644
--- a/lib/features/feed/presentation/bloc/comments_cubit/comments_state.dart
+++ b/lib/features/feed/presentation/bloc/comments_cubit/comments_state.dart
@@ -11,6 +11,7 @@ abstract class CommentsState with _$CommentsState {
const factory CommentsState.loaded({
required CommentModel comment,
+ int? replyId,
}) = CommentsStateLoaded;
const factory CommentsState.error({
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
index d4993b5b..58463106 100644
--- a/lib/features/feed/presentation/bloc/comments_cubit/comments_state.freezed.dart
+++ b/lib/features/feed/presentation/bloc/comments_cubit/comments_state.freezed.dart
@@ -20,7 +20,7 @@ mixin _$CommentsState {
TResult when(
TResult Function() $default, {
required TResult Function() loading,
- required TResult Function(CommentModel comment) loaded,
+ required TResult Function(CommentModel comment, int? replyId) loaded,
required TResult Function(String errorMessage) error,
}) =>
throw _privateConstructorUsedError;
@@ -28,7 +28,7 @@ mixin _$CommentsState {
TResult? whenOrNull(
TResult? Function()? $default, {
TResult? Function()? loading,
- TResult? Function(CommentModel comment)? loaded,
+ TResult? Function(CommentModel comment, int? replyId)? loaded,
TResult? Function(String errorMessage)? error,
}) =>
throw _privateConstructorUsedError;
@@ -36,7 +36,7 @@ mixin _$CommentsState {
TResult maybeWhen(
TResult Function()? $default, {
TResult Function()? loading,
- TResult Function(CommentModel comment)? loaded,
+ TResult Function(CommentModel comment, int? replyId)? loaded,
TResult Function(String errorMessage)? error,
required TResult orElse(),
}) =>
@@ -126,7 +126,7 @@ class _$CommentsStateImpl implements _CommentsState {
TResult when(
TResult Function() $default, {
required TResult Function() loading,
- required TResult Function(CommentModel comment) loaded,
+ required TResult Function(CommentModel comment, int? replyId) loaded,
required TResult Function(String errorMessage) error,
}) {
return $default();
@@ -137,7 +137,7 @@ class _$CommentsStateImpl implements _CommentsState {
TResult? whenOrNull(
TResult? Function()? $default, {
TResult? Function()? loading,
- TResult? Function(CommentModel comment)? loaded,
+ TResult? Function(CommentModel comment, int? replyId)? loaded,
TResult? Function(String errorMessage)? error,
}) {
return $default?.call();
@@ -148,7 +148,7 @@ class _$CommentsStateImpl implements _CommentsState {
TResult maybeWhen(
TResult Function()? $default, {
TResult Function()? loading,
- TResult Function(CommentModel comment)? loaded,
+ TResult Function(CommentModel comment, int? replyId)? loaded,
TResult Function(String errorMessage)? error,
required TResult orElse(),
}) {
@@ -241,7 +241,7 @@ class _$CommentsStateLoadingImpl implements CommentsStateLoading {
TResult when(
TResult Function() $default, {
required TResult Function() loading,
- required TResult Function(CommentModel comment) loaded,
+ required TResult Function(CommentModel comment, int? replyId) loaded,
required TResult Function(String errorMessage) error,
}) {
return loading();
@@ -252,7 +252,7 @@ class _$CommentsStateLoadingImpl implements CommentsStateLoading {
TResult? whenOrNull(
TResult? Function()? $default, {
TResult? Function()? loading,
- TResult? Function(CommentModel comment)? loaded,
+ TResult? Function(CommentModel comment, int? replyId)? loaded,
TResult? Function(String errorMessage)? error,
}) {
return loading?.call();
@@ -263,7 +263,7 @@ class _$CommentsStateLoadingImpl implements CommentsStateLoading {
TResult maybeWhen(
TResult Function()? $default, {
TResult Function()? loading,
- TResult Function(CommentModel comment)? loaded,
+ TResult Function(CommentModel comment, int? replyId)? loaded,
TResult Function(String errorMessage)? error,
required TResult orElse(),
}) {
@@ -321,7 +321,7 @@ abstract class _$$CommentsStateLoadedImplCopyWith<$Res> {
$Res Function(_$CommentsStateLoadedImpl) then) =
__$$CommentsStateLoadedImplCopyWithImpl<$Res>;
@useResult
- $Res call({CommentModel comment});
+ $Res call({CommentModel comment, int? replyId});
$CommentModelCopyWith<$Res> get comment;
}
@@ -338,12 +338,17 @@ class __$$CommentsStateLoadedImplCopyWithImpl<$Res>
@override
$Res call({
Object? comment = null,
+ Object? replyId = freezed,
}) {
return _then(_$CommentsStateLoadedImpl(
comment: null == comment
? _value.comment
: comment // ignore: cast_nullable_to_non_nullable
as CommentModel,
+ replyId: freezed == replyId
+ ? _value.replyId
+ : replyId // ignore: cast_nullable_to_non_nullable
+ as int?,
));
}
@@ -359,14 +364,16 @@ class __$$CommentsStateLoadedImplCopyWithImpl<$Res>
/// @nodoc
class _$CommentsStateLoadedImpl implements CommentsStateLoaded {
- const _$CommentsStateLoadedImpl({required this.comment});
+ const _$CommentsStateLoadedImpl({required this.comment, this.replyId});
@override
final CommentModel comment;
+ @override
+ final int? replyId;
@override
String toString() {
- return 'CommentsState.loaded(comment: $comment)';
+ return 'CommentsState.loaded(comment: $comment, replyId: $replyId)';
}
@override
@@ -374,11 +381,12 @@ class _$CommentsStateLoadedImpl implements CommentsStateLoaded {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$CommentsStateLoadedImpl &&
- (identical(other.comment, comment) || other.comment == comment));
+ (identical(other.comment, comment) || other.comment == comment) &&
+ (identical(other.replyId, replyId) || other.replyId == replyId));
}
@override
- int get hashCode => Object.hash(runtimeType, comment);
+ int get hashCode => Object.hash(runtimeType, comment, replyId);
@JsonKey(ignore: true)
@override
@@ -392,10 +400,10 @@ class _$CommentsStateLoadedImpl implements CommentsStateLoaded {
TResult when(
TResult Function() $default, {
required TResult Function() loading,
- required TResult Function(CommentModel comment) loaded,
+ required TResult Function(CommentModel comment, int? replyId) loaded,
required TResult Function(String errorMessage) error,
}) {
- return loaded(comment);
+ return loaded(comment, replyId);
}
@override
@@ -403,10 +411,10 @@ class _$CommentsStateLoadedImpl implements CommentsStateLoaded {
TResult? whenOrNull(
TResult? Function()? $default, {
TResult? Function()? loading,
- TResult? Function(CommentModel comment)? loaded,
+ TResult? Function(CommentModel comment, int? replyId)? loaded,
TResult? Function(String errorMessage)? error,
}) {
- return loaded?.call(comment);
+ return loaded?.call(comment, replyId);
}
@override
@@ -414,12 +422,12 @@ class _$CommentsStateLoadedImpl implements CommentsStateLoaded {
TResult maybeWhen(
TResult Function()? $default, {
TResult Function()? loading,
- TResult Function(CommentModel comment)? loaded,
+ TResult Function(CommentModel comment, int? replyId)? loaded,
TResult Function(String errorMessage)? error,
required TResult orElse(),
}) {
if (loaded != null) {
- return loaded(comment);
+ return loaded(comment, replyId);
}
return orElse();
}
@@ -463,10 +471,12 @@ class _$CommentsStateLoadedImpl implements CommentsStateLoaded {
}
abstract class CommentsStateLoaded implements CommentsState {
- const factory CommentsStateLoaded({required final CommentModel comment}) =
- _$CommentsStateLoadedImpl;
+ const factory CommentsStateLoaded(
+ {required final CommentModel comment,
+ final int? replyId}) = _$CommentsStateLoadedImpl;
CommentModel get comment;
+ int? get replyId;
@JsonKey(ignore: true)
_$$CommentsStateLoadedImplCopyWith<_$CommentsStateLoadedImpl> get copyWith =>
throw _privateConstructorUsedError;
@@ -540,7 +550,7 @@ class _$CommentsStateErrorImpl implements CommentsStateError {
TResult when(
TResult Function() $default, {
required TResult Function() loading,
- required TResult Function(CommentModel comment) loaded,
+ required TResult Function(CommentModel comment, int? replyId) loaded,
required TResult Function(String errorMessage) error,
}) {
return error(errorMessage);
@@ -551,7 +561,7 @@ class _$CommentsStateErrorImpl implements CommentsStateError {
TResult? whenOrNull(
TResult? Function()? $default, {
TResult? Function()? loading,
- TResult? Function(CommentModel comment)? loaded,
+ TResult? Function(CommentModel comment, int? replyId)? loaded,
TResult? Function(String errorMessage)? error,
}) {
return error?.call(errorMessage);
@@ -562,7 +572,7 @@ class _$CommentsStateErrorImpl implements CommentsStateError {
TResult maybeWhen(
TResult Function()? $default, {
TResult Function()? loading,
- TResult Function(CommentModel comment)? loaded,
+ TResult Function(CommentModel comment, int? replyId)? loaded,
TResult Function(String errorMessage)? error,
required TResult orElse(),
}) {
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 0de3af57..3320c71c 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;
+ late int lastPage;
bool isLoading = false;
FeedCubit({required this.feedRepository}) : super(const FeedState.loading());
@@ -13,6 +13,7 @@ class FeedCubit extends Cubit {
loadFeedBlogPostList() async {
try {
final feedBlogPosts = await feedRepository.getFeedBlogPosts();
+ lastPage = feedBlogPosts.meta.lastPage;
emit(
FeedState.loaded(
feedBlogPostList: feedBlogPosts.feedBlogPostList,
@@ -25,26 +26,29 @@ class FeedCubit extends Cubit {
}
loadNextPage() async {
- print('start');
- try {
- if (_lastPage < _currentPage) {
- _currentPage++;
- final feedBlogPosts = await feedRepository.getFeedBlogPosts(page: _currentPage);
- emit(
- FeedState.loaded(
- feedBlogPostList: [
- ...(state as FeedStateLoaded).feedBlogPostList,
- ...feedBlogPosts.feedBlogPostList,
- ],
- isLoading: false,
- ),
- );
+ if (currentPage < lastPage && !isLoading) {
+ isLoading = true;
+
+ emit((state as FeedStateLoaded).copyWith(isLoading: isLoading));
+
+ try {
+ if (currentPage < lastPage) {
+ currentPage++;
+ final feedBlogPosts = await feedRepository.getFeedBlogPosts(page: currentPage);
+ isLoading = false;
+ emit(
+ FeedState.loaded(
+ feedBlogPostList: [
+ ...(state as FeedStateLoaded).feedBlogPostList,
+ ...feedBlogPosts.feedBlogPostList,
+ ],
+ isLoading: isLoading,
+ ),
+ );
+ }
+ } catch (e) {
+ emit(FeedState.error(errorMessage: e.toString()));
}
- } catch (e) {
- print('error bro');
- print(e.toString());
- } finally {
- print('end');
}
}
diff --git a/lib/features/feed/presentation/pages/feed_screen.dart b/lib/features/feed/presentation/pages/feed_screen.dart
index 824c5840..2200a6e6 100644
--- a/lib/features/feed/presentation/pages/feed_screen.dart
+++ b/lib/features/feed/presentation/pages/feed_screen.dart
@@ -26,6 +26,27 @@ class _FeedScreenState extends State {
final searchController = TextEditingController();
final List chipsLabelList = ['Все', 'Рецепты', 'Диеты', 'Планы питания', 'Консультанты'];
int _selectedChipIndex = 0;
+ final blogPostsScrollController = ScrollController();
+ final recipesScrollController = ScrollController();
+ final dietsScrollController = ScrollController();
+
+ @override
+ void initState() {
+ blogPostsScrollController.addListener(_onScroll);
+ super.initState();
+ }
+
+ _onScroll() {
+ if (blogPostsScrollController.offset >= blogPostsScrollController.position.maxScrollExtent && !blogPostsScrollController.position.outOfRange) {
+ context.read().loadNextPage();
+ }
+ }
+
+ @override
+ void dispose() {
+ blogPostsScrollController.dispose();
+ super.dispose();
+ }
@override
Widget build(BuildContext context) {
@@ -68,6 +89,7 @@ class _FeedScreenState extends State {
),
backgroundColor: Colors.grey.shade200,
body: NestedScrollView(
+ controller: blogPostsScrollController,
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return [
SliverAppBar(
@@ -108,47 +130,6 @@ class _FeedScreenState extends State {
);
}
- _buildDiets() {
- return RefreshIndicator(
- onRefresh: () => context.read().loadDiets(),
- child: BlocBuilder(
- builder: (BuildContext context, DietsState state) {
- if (state is DietsStateLoaded) {
- return ListView.separated(
- padding: EdgeInsets.symmetric(vertical: 8),
- shrinkWrap: true,
- physics: BouncingScrollPhysics(),
- itemBuilder: (context, index) {
- return DietsWidget(diet: state.diets.data[index]);
- },
- separatorBuilder: (context, index) {
- return SizedBox(height: 8);
- },
- itemCount: state.diets.data.length,
- );
- } else if (state is DietsStateError) {
- return Scaffold(
- backgroundColor: Colors.grey.shade200,
- body: Padding(
- padding: const EdgeInsets.all(16),
- child: Center(
- child: Text(state.errorMessage),
- ),
- ),
- );
- } else {
- return Scaffold(
- backgroundColor: Colors.grey.shade200,
- body: Center(
- child: CupertinoActivityIndicator(),
- ),
- );
- }
- },
- ),
- );
- }
-
_buildAllBlogPosts() {
return RefreshIndicator(
onRefresh: () => context.read().loadFeedBlogPostList(),
@@ -158,14 +139,17 @@ class _FeedScreenState extends State {
return ListView.separated(
padding: EdgeInsets.symmetric(vertical: 8),
shrinkWrap: true,
- physics: BouncingScrollPhysics(),
+ physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
+ if (index == state.feedBlogPostList.length) {
+ return CupertinoActivityIndicator();
+ }
return BlogPostWidget(feedBlogPostModel: state.feedBlogPostList[index]);
},
separatorBuilder: (context, index) {
return SizedBox(height: 8);
},
- itemCount: state.feedBlogPostList.length,
+ itemCount: state.isLoading ? state.feedBlogPostList.length + 1 : state.feedBlogPostList.length,
);
} else if (state is FeedStateError) {
return Scaffold(
@@ -231,6 +215,47 @@ class _FeedScreenState extends State {
);
}
+ _buildDiets() {
+ return RefreshIndicator(
+ onRefresh: () => context.read().loadDiets(),
+ child: BlocBuilder(
+ builder: (BuildContext context, DietsState state) {
+ if (state is DietsStateLoaded) {
+ return ListView.separated(
+ padding: EdgeInsets.symmetric(vertical: 8),
+ shrinkWrap: true,
+ physics: BouncingScrollPhysics(),
+ itemBuilder: (context, index) {
+ return DietsWidget(diet: state.diets.data[index]);
+ },
+ separatorBuilder: (context, index) {
+ return SizedBox(height: 8);
+ },
+ itemCount: state.diets.data.length,
+ );
+ } else if (state is DietsStateError) {
+ return Scaffold(
+ backgroundColor: Colors.grey.shade200,
+ body: Padding(
+ padding: const EdgeInsets.all(16),
+ child: Center(
+ child: Text(state.errorMessage),
+ ),
+ ),
+ );
+ } else {
+ return Scaffold(
+ backgroundColor: Colors.grey.shade200,
+ body: Center(
+ child: CupertinoActivityIndicator(),
+ ),
+ );
+ }
+ },
+ ),
+ );
+ }
+
_chipGroup() {
return PreferredSize(
preferredSize: Size(MediaQuery.of(context).size.width, 32),
diff --git a/lib/features/feed/presentation/widgets/blog_post_widget.dart b/lib/features/feed/presentation/widgets/blog_post_widget.dart
index e262e067..9d097936 100644
--- a/lib/features/feed/presentation/widgets/blog_post_widget.dart
+++ b/lib/features/feed/presentation/widgets/blog_post_widget.dart
@@ -124,6 +124,8 @@ class _BlogPostWidgetState extends State {
child: Hero(
tag: baseUrl + '/storage/' + widget.feedBlogPostModel.image,
child: CachedNetworkImage(
+ fit: BoxFit.fitWidth,
+ width: MediaQuery.of(context).size.width,
imageUrl: baseUrl + '/storage/' + widget.feedBlogPostModel.image,
errorWidget: (context, str, object) => SizedBox.shrink(),
),
diff --git a/lib/features/feed/presentation/widgets/comments_widget.dart b/lib/features/feed/presentation/widgets/comments_widget.dart
new file mode 100644
index 00000000..b530a7d8
--- /dev/null
+++ b/lib/features/feed/presentation/widgets/comments_widget.dart
@@ -0,0 +1,119 @@
+import 'package:eatvio_app/core/app_export.dart';
+import 'package:eatvio_app/features/feed/models/comment_model.dart';
+import 'package:eatvio_app/features/feed/presentation/bloc/comments_cubit/comments_cubit.dart';
+import 'package:flutter/material.dart';
+
+enum CommentSourceType { blogPost, recipe, diet }
+
+class CommentsWidget extends StatefulWidget {
+ final String id;
+ final CommentSourceType commentSourceType;
+ final CommentModel comment;
+ final int? replyId;
+
+ const CommentsWidget({
+ super.key,
+ required this.id,
+ required this.commentSourceType,
+ required this.comment,
+ this.replyId,
+ });
+
+ @override
+ State createState() => _CommentsWidgetState();
+}
+
+class _CommentsWidgetState extends State {
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ children: [
+ for (int i = 0; i < widget.comment.data.length; i++) ...[
+ _comment(widget.comment.data[i]),
+ if (widget.comment.data[i].childrenComments.isNotEmpty) SizedBox(height: 8),
+ for (int j = 0; j < widget.comment.data[i].childrenComments.length; j++)
+ Padding(
+ padding: EdgeInsets.only(left: 40),
+ child: _comment(widget.comment.data[i].childrenComments[j], 12, true),
+ ),
+ SizedBox(height: 8),
+ ],
+ ],
+ );
+ }
+
+ _comment(Comment comment, [double radius = 16, bool isChild = false]) {
+ return Container(
+ width: MediaQuery.of(context).size.width,
+ decoration: BoxDecoration(
+ color: widget.replyId == comment.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: [
+ CircleAvatar(
+ foregroundImage: NetworkImage(comment.authorProfileIcon),
+ radius: radius,
+ ),
+ SizedBox(width: 8),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisAlignment: MainAxisAlignment.start,
+ children: [
+ Text(
+ comment.authorName,
+ style: TextStyle(
+ height: 1,
+ color: Colors.grey.shade600,
+ fontWeight: FontWeight.w500,
+ ),
+ ),
+ SizedBox(width: 4),
+ Text(
+ comment.body,
+ style: TextStyle(
+ height: 1,
+ color: Colors.black,
+ ),
+ ),
+ SizedBox(height: 4),
+ Row(
+ children: [
+ Text(
+ comment.createdAt.format('dd MMMM', 'ru'),
+ style: TextStyle(
+ color: Colors.grey.shade600,
+ fontSize: 12,
+ fontWeight: FontWeight.w400,
+ height: 1,
+ ),
+ ),
+ SizedBox(width: 16),
+ if (!isChild)
+ GestureDetector(
+ onTap: () {
+ context.read().setReplyId(comment.id);
+ },
+ child: Text(
+ 'Ответить',
+ style: TextStyle(
+ height: 1,
+ fontSize: 12,
+ color: Colors.grey.shade800,
+ fontWeight: FontWeight.w500,
+ ),
+ ),
+ ),
+ ],
+ ),
+ ],
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/features/feed/presentation/widgets/diets_widget.dart b/lib/features/feed/presentation/widgets/diets_widget.dart
index bf94f9aa..7bc9054e 100644
--- a/lib/features/feed/presentation/widgets/diets_widget.dart
+++ b/lib/features/feed/presentation/widgets/diets_widget.dart
@@ -34,6 +34,8 @@ class _DietsWidgetState extends State {
borderRadius: BorderRadius.vertical(top: Radius.circular(12)),
child: CachedNetworkImage(
imageUrl: baseUrl + '/storage/' + widget.diet.image,
+ fit: BoxFit.fitWidth,
+ width: MediaQuery.of(context).size.width,
),
),
Positioned(
diff --git a/lib/features/feed/presentation/widgets/recipes_widget.dart b/lib/features/feed/presentation/widgets/recipes_widget.dart
index c341c5a4..54fb1b2d 100644
--- a/lib/features/feed/presentation/widgets/recipes_widget.dart
+++ b/lib/features/feed/presentation/widgets/recipes_widget.dart
@@ -34,6 +34,8 @@ class _RecipesWidgetState extends State {
borderRadius: BorderRadius.vertical(top: Radius.circular(12)),
child: CachedNetworkImage(
imageUrl: baseUrl + '/storage/' + widget.recipes.image,
+ fit: BoxFit.fitWidth,
+ width: MediaQuery.of(context).size.width,
),
),
Positioned(
diff --git a/lib/features/feed/repositories/feed_repository.dart b/lib/features/feed/repositories/feed_repository.dart
index 23089824..1696d948 100644
--- a/lib/features/feed/repositories/feed_repository.dart
+++ b/lib/features/feed/repositories/feed_repository.dart
@@ -40,7 +40,7 @@ class FeedRepository {
}
}
- Future getBlogPostComments(int id) async {
+ Future getBlogPostComments(String id) async {
try {
return (await feedService.getBlogPostComments(id: id));
} catch (e) {
@@ -49,7 +49,7 @@ class FeedRepository {
}
Future sendBlogPostComment({
- required int id,
+ required String id,
required String commentText,
int? parentCommentId,
}) async {
@@ -64,7 +64,7 @@ class FeedRepository {
}
}
- Future getDietsComments(int id) async {
+ Future getDietsComments(String id) async {
try {
return (await feedService.getDietsComments(id: id));
} catch (e) {
@@ -73,7 +73,7 @@ class FeedRepository {
}
Future sendDietsComment({
- required int id,
+ required String id,
required String commentText,
int? parentCommentId,
}) async {
diff --git a/lib/features/feed/services/feed_service.dart b/lib/features/feed/services/feed_service.dart
index f282547e..8a75d44f 100644
--- a/lib/features/feed/services/feed_service.dart
+++ b/lib/features/feed/services/feed_service.dart
@@ -27,24 +27,24 @@ abstract class FeedService {
@GET('/api/blogPosts/{id}/comments/show')
Future getBlogPostComments({
- @Path() required int id,
+ @Path() required String id,
});
@POST('/api/blogPosts/{id}/comment/create')
Future sendBlogPostComment({
- @Path() required int id,
+ @Path() required String id,
@Part() required String body,
@Part() int? parentCommentId,
});
@GET('/api/diets/{id}/comments/show')
Future getDietsComments({
- @Path() required int id,
+ @Path() required String id,
});
@POST('/api/diets/{id}/comment/create')
Future sendDietsComment({
- @Path() required int id,
+ @Path() required String 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 84016757..bc3f08f1 100644
--- a/lib/features/feed/services/feed_service.g.dart
+++ b/lib/features/feed/services/feed_service.g.dart
@@ -128,7 +128,7 @@ class _FeedService implements FeedService {
}
@override
- Future getBlogPostComments({required int id}) async {
+ Future getBlogPostComments({required String id}) async {
final _extra = {};
final queryParameters = {};
final _headers = {};
@@ -162,7 +162,7 @@ class _FeedService implements FeedService {
@override
Future sendBlogPostComment({
- required int id,
+ required String id,
required String body,
int? parentCommentId,
}) async {
@@ -201,7 +201,7 @@ class _FeedService implements FeedService {
}
@override
- Future getDietsComments({required int id}) async {
+ Future getDietsComments({required String id}) async {
final _extra = {};
final queryParameters = {};
final _headers = {};
@@ -235,7 +235,7 @@ class _FeedService implements FeedService {
@override
Future sendDietsComment({
- required int id,
+ required String id,
required String body,
int? parentCommentId,
}) async {
diff --git a/lib/features/profile/presentation/pages/profile_screen.dart b/lib/features/profile/presentation/pages/profile_screen.dart
index f044b17d..a1d0d15a 100644
--- a/lib/features/profile/presentation/pages/profile_screen.dart
+++ b/lib/features/profile/presentation/pages/profile_screen.dart
@@ -10,6 +10,8 @@ import 'package:eatvio_app/features/profile/presentation/widgets/weight_chart_wi
import 'package:eatvio_app/locator_service.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
+import 'package:go_router/go_router.dart';
+import 'package:share_plus/share_plus.dart';
class ProfileScreen extends StatefulWidget {
final Author? author;
@@ -118,13 +120,20 @@ class _ProfileScreenState extends State {
),
],
),
- Container(
- padding: EdgeInsets.only(left: 16),
- child: SvgPicture.asset(
- height: 24,
- width: 24,
- 'assets/icons/share.svg',
- colorFilter: ColorFilter.mode(appTheme.blueA400, BlendMode.srcIn),
+ GestureDetector(
+ onTap: () => Share.shareUri(
+ Uri.parse(
+ baseUrl + '/ru/profile/' + state.profile.user.slug,
+ ),
+ ),
+ child: Container(
+ padding: EdgeInsets.only(left: 16),
+ child: SvgPicture.asset(
+ height: 24,
+ width: 24,
+ 'assets/icons/share.svg',
+ colorFilter: ColorFilter.mode(appTheme.blueA400, BlendMode.srcIn),
+ ),
),
),
],
@@ -147,18 +156,21 @@ class _ProfileScreenState extends State {
Row(
children: [
SizedBox(width: 16),
- Container(
- alignment: Alignment.center,
- padding: EdgeInsets.all(8),
- width: (MediaQuery.of(context).size.width - 40) / 2,
- decoration: BoxDecoration(
- color: appTheme.blueA400.withOpacity(0.1),
- borderRadius: BorderRadius.circular(16),
- ),
- child: Text(
- 'Сообщение',
- style: TextStyle(
- color: appTheme.blueA400,
+ GestureDetector(
+ onTap: () => GoRouter.of(context).pushNamed('chatScreen', ),
+ child: Container(
+ alignment: Alignment.center,
+ padding: EdgeInsets.all(8),
+ width: (MediaQuery.of(context).size.width - 40) / 2,
+ decoration: BoxDecoration(
+ color: appTheme.blueA400.withOpacity(0.1),
+ borderRadius: BorderRadius.circular(16),
+ ),
+ child: Text(
+ 'Сообщение',
+ style: TextStyle(
+ color: appTheme.blueA400,
+ ),
),
),
),
diff --git a/lib/features/recipes/presentation/pages/about_recipes_screen.dart b/lib/features/recipes/presentation/pages/about_recipes_screen.dart
index 620580a0..b8e8fc9f 100644
--- a/lib/features/recipes/presentation/pages/about_recipes_screen.dart
+++ b/lib/features/recipes/presentation/pages/about_recipes_screen.dart
@@ -1,12 +1,11 @@
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/recipes_model.dart' as step;
import 'package:eatvio_app/features/feed/models/recipes_model.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/widgets/comments_widget.dart';
import 'package:eatvio_app/locator_service.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
@@ -26,21 +25,24 @@ class _AboutRecipesScreenState extends State {
final textEditingController = TextEditingController();
int? replyId;
- @override
- void initState() {
- super.initState();
- commentsCubit.getRecipesComments(widget.recipes.slug);
- }
-
@override
Widget build(BuildContext context) {
return BlocProvider(
- create: (BuildContext context) => commentsCubit,
- child: BlocBuilder(
- builder: (BuildContext context, CommentsState state) {
- if (state is CommentsStateError) {
- print(state.errorMessage);
+ create: (BuildContext context) => commentsCubit
+ ..getComments(
+ widget.recipes.slug,
+ CommentSourceType.recipe,
+ true,
+ ),
+ child: BlocConsumer(
+ listener: (BuildContext context, CommentsState state) {
+ if (state is CommentsStateLoaded) {
+ setState(() {
+ replyId = state.replyId;
+ });
}
+ },
+ builder: (BuildContext context, CommentsState state) {
return Scaffold(
resizeToAvoidBottomInset: true,
bottomSheet: Container(
@@ -59,6 +61,7 @@ class _AboutRecipesScreenState extends State {
if (replyId != null)
GestureDetector(
onTap: () {
+ context.read().setReplyId(null);
setState(() {
replyId = null;
textEditingController.clear();
@@ -81,7 +84,7 @@ class _AboutRecipesScreenState extends State {
),
if (replyId != null) SizedBox(width: 8),
SizedBox(
- width: mediaQueryData.size.width - (replyId == null ? 64 : 104),
+ width: MediaQuery.of(context).size.width - (replyId == null ? 64 : 104),
child: TextFormField(
onChanged: (_) {
setState(() {});
@@ -135,11 +138,13 @@ class _AboutRecipesScreenState extends State {
GestureDetector(
onTap: () {
if (textEditingController.text.length > 2) {
- commentsCubit.sendRecipesComment(
+ commentsCubit.sendComment(
id: widget.recipes.slug,
commentText: textEditingController.text,
parentCommentId: replyId,
+ commentSourceType: CommentSourceType.recipe,
);
+ context.read().setReplyId(null);
setState(() {
textEditingController.clear();
replyId = null;
@@ -300,17 +305,16 @@ class _AboutRecipesScreenState extends State {
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, index) => _step(widget.recipes.steps[index], index + 1),
- separatorBuilder: (context, index) =>
- Padding(
- padding: const EdgeInsets.all(16),
- child: Container(
- height: 0.4,
- decoration: BoxDecoration(
- color: Colors.grey,
- borderRadius: BorderRadius.circular(16),
- ),
- ),
+ separatorBuilder: (context, index) => Padding(
+ padding: const EdgeInsets.all(16),
+ child: Container(
+ height: 0.4,
+ decoration: BoxDecoration(
+ color: Colors.grey,
+ borderRadius: BorderRadius.circular(16),
),
+ ),
+ ),
itemCount: widget.recipes.steps.length,
),
SizedBox(height: 8),
@@ -343,7 +347,13 @@ class _AboutRecipesScreenState extends State {
padding: const EdgeInsets.all(32),
child: CupertinoActivityIndicator(),
),
- if (state is CommentsStateLoaded) _buildComments(state.comment),
+ if (state is CommentsStateLoaded)
+ CommentsWidget(
+ id: widget.recipes.slug,
+ commentSourceType: CommentSourceType.recipe,
+ comment: state.comment,
+ replyId: replyId,
+ ),
],
),
),
@@ -406,103 +416,4 @@ class _AboutRecipesScreenState extends State {
],
);
}
-
- _buildComments(CommentModel 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(Comment comment, [double radius = 16]) {
- return Container(
- width: MediaQuery
- .of(context)
- .size
- .width,
- decoration: BoxDecoration(
- color: replyId == comment.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: [
- CircleAvatar(
- foregroundImage: NetworkImage(comment.authorProfileIcon),
- radius: radius,
- ),
- SizedBox(width: 8),
- Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- mainAxisAlignment: MainAxisAlignment.start,
- children: [
- Text(
- comment.authorName,
- style: TextStyle(
- height: 1,
- color: Colors.grey.shade600,
- fontWeight: FontWeight.w500,
- ),
- ),
- SizedBox(width: 4),
- Text(
- comment.body,
- style: TextStyle(
- height: 1,
- color: Colors.black,
- ),
- ),
- SizedBox(height: 4),
- Row(
- children: [
- Text(
- comment.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 = comment.id;
- });
- },
- child: Text(
- 'Ответить',
- style: TextStyle(
- height: 1,
- fontSize: 12,
- color: Colors.grey.shade800,
- fontWeight: FontWeight.w500,
- ),
- ),
- ),
- ],
- ),
- ],
- ),
- ],
- ),
- ),
- );
- }
}
diff --git a/lib/old/diets/diet_create_screen/diet_create_screen.dart b/lib/old/diets/diet_create_screen/diet_create_screen.dart
index 2ade3f80..c5593dd4 100644
--- a/lib/old/diets/diet_create_screen/diet_create_screen.dart
+++ b/lib/old/diets/diet_create_screen/diet_create_screen.dart
@@ -38,7 +38,6 @@ class DietCreateScreen extends StatelessWidget {
}
_buildDietCreate(BuildContext context, DietCreateLoadedState state) {
- mediaQueryData = MediaQuery.of(context);
return SafeArea(
child: Scaffold(
resizeToAvoidBottomInset: false,
diff --git a/lib/old/diets/diet_edit_screen/diet_edit_screen.dart b/lib/old/diets/diet_edit_screen/diet_edit_screen.dart
index d76d79d7..5109bf12 100644
--- a/lib/old/diets/diet_edit_screen/diet_edit_screen.dart
+++ b/lib/old/diets/diet_edit_screen/diet_edit_screen.dart
@@ -39,7 +39,6 @@ class DietEditScreen extends StatelessWidget {
}
_buildDietEdit(BuildContext context, DietEditLoadedState state) {
- mediaQueryData = MediaQuery.of(context);
return SafeArea(
child: Scaffold(
resizeToAvoidBottomInset: false,
diff --git a/lib/old/diets/diet_show_screen/diet_show_screen.dart b/lib/old/diets/diet_show_screen/diet_show_screen.dart
index 9fae1efd..64a25e98 100644
--- a/lib/old/diets/diet_show_screen/diet_show_screen.dart
+++ b/lib/old/diets/diet_show_screen/diet_show_screen.dart
@@ -40,7 +40,6 @@ class DietScreen extends StatelessWidget {
}
_buildDiet(BuildContext context, DietLoadedState state) {
- mediaQueryData = MediaQuery.of(context);
return SafeArea(
child: Scaffold(
resizeToAvoidBottomInset: false,
diff --git a/lib/old/feed/blog_post_edit_screen/blog_post_edit_screen.dart b/lib/old/feed/blog_post_edit_screen/blog_post_edit_screen.dart
index ba691376..a88bf3e3 100644
--- a/lib/old/feed/blog_post_edit_screen/blog_post_edit_screen.dart
+++ b/lib/old/feed/blog_post_edit_screen/blog_post_edit_screen.dart
@@ -43,7 +43,6 @@ class BlogPostEditScreen extends StatelessWidget {
}
_buildBlogPostEdit(BuildContext context, BlogPostEditLoadedState state) {
- mediaQueryData = MediaQuery.of(context);
return Scaffold(
resizeToAvoidBottomInset: false,
body: Container(
diff --git a/lib/old/plans/plan_create_screen/plan_create_screen.dart b/lib/old/plans/plan_create_screen/plan_create_screen.dart
index 165be86b..c3ea8979 100644
--- a/lib/old/plans/plan_create_screen/plan_create_screen.dart
+++ b/lib/old/plans/plan_create_screen/plan_create_screen.dart
@@ -38,7 +38,6 @@ class PlanCreateScreen extends StatelessWidget {
}
_buildPlanCreate(BuildContext context, PlanCreateLoadedState state) {
- mediaQueryData = MediaQuery.of(context);
return SafeArea(
child: Scaffold(
resizeToAvoidBottomInset: false,
diff --git a/lib/old/plans/plan_edit_screen/plan_edit_screen.dart b/lib/old/plans/plan_edit_screen/plan_edit_screen.dart
index c7005746..905eb614 100644
--- a/lib/old/plans/plan_edit_screen/plan_edit_screen.dart
+++ b/lib/old/plans/plan_edit_screen/plan_edit_screen.dart
@@ -39,7 +39,6 @@ class PlanEditScreen extends StatelessWidget {
}
_buildPlanEdit(BuildContext context, PlanEditLoadedState state) {
- mediaQueryData = MediaQuery.of(context);
return SafeArea(
child: Scaffold(
resizeToAvoidBottomInset: false,
diff --git a/lib/old/plans/plan_show_screen/plan_show_screen.dart b/lib/old/plans/plan_show_screen/plan_show_screen.dart
index bf618680..24958189 100644
--- a/lib/old/plans/plan_show_screen/plan_show_screen.dart
+++ b/lib/old/plans/plan_show_screen/plan_show_screen.dart
@@ -40,7 +40,6 @@ class PlanScreen extends StatelessWidget {
}
_buildPlan(BuildContext context, PlanLoadedState state) {
- mediaQueryData = MediaQuery.of(context);
return SafeArea(
child: Scaffold(
resizeToAvoidBottomInset: false,
diff --git a/lib/old/profile/my_profile_screen/my_profile_screen.dart b/lib/old/profile/my_profile_screen/my_profile_screen.dart
index d10b70ab..ddf76455 100644
--- a/lib/old/profile/my_profile_screen/my_profile_screen.dart
+++ b/lib/old/profile/my_profile_screen/my_profile_screen.dart
@@ -58,7 +58,6 @@ class MyProfileScreen extends StatelessWidget {
}
_buildMyProfileScreen(BuildContext context, MyProfileLoadedState state) {
- mediaQueryData = MediaQuery.of(context);
return Scaffold(
appBar: AppBar(
toolbarHeight: 0,
diff --git a/lib/old/recipe/recipe_edit_screen/recipe_edit_screen.dart b/lib/old/recipe/recipe_edit_screen/recipe_edit_screen.dart
index e3dbcbe6..84350e27 100644
--- a/lib/old/recipe/recipe_edit_screen/recipe_edit_screen.dart
+++ b/lib/old/recipe/recipe_edit_screen/recipe_edit_screen.dart
@@ -45,7 +45,6 @@ class RecipeEditScreen extends StatelessWidget {
}
_buildRecipeEdit(BuildContext context, RecipeEditLoadedState state) {
- mediaQueryData = MediaQuery.of(context);
List steps = [];
if (state.steps != null) {
for (int i = 0; i < state.steps!.length; i++) {
diff --git a/lib/old/recipe/recipe_show_screen/recipe_show_screen.dart b/lib/old/recipe/recipe_show_screen/recipe_show_screen.dart
index 33f7cfc3..75e170ef 100644
--- a/lib/old/recipe/recipe_show_screen/recipe_show_screen.dart
+++ b/lib/old/recipe/recipe_show_screen/recipe_show_screen.dart
@@ -44,7 +44,6 @@ class RecipeScreen extends StatelessWidget {
}
_buildRecipe(BuildContext context, RecipeLoadedState state) {
- mediaQueryData = MediaQuery.of(context);
List steps = [];
if (state.steps != null) {
for (int i = 0; i < state.steps!.length; i++) {
diff --git a/pubspec.yaml b/pubspec.yaml
index a70e6c94..c746bd94 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -38,11 +38,10 @@ dependencies:
dismissible_page: ^1.0.2
url_launcher: ^6.3.0
easy_debounce: ^2.0.3
- lazy_load_scrollview: ^1.3.0
badges: ^3.1.2
google_fonts: ^6.2.1
location: ^6.0.2
- syncfusion_flutter_charts: ^26.2.12
+ syncfusion_flutter_charts: ^26.2.13
table_calendar: ^3.1.2
flutter_keyboard_visibility: ^6.0.0
share_plus: ^10.0.0