forked from eatvio/eatvio_app
Merge branch 'main' into personalDiets
This commit is contained in:
@@ -1,20 +1,25 @@
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/comments_cubit/comments_state.dart';
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:eatvio_app/core/comments/comments_cubit/comments_state.dart';
|
||||
import 'package:eatvio_app/core/comments/repositories/comments_repository.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/widgets/comments_widget.dart';
|
||||
import 'package:eatvio_app/features/feed/repositories/feed_repository.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class CommentsCubit extends Cubit<CommentsState> {
|
||||
final FeedRepository feedRepository;
|
||||
final CommentsRepository commentsRepository;
|
||||
|
||||
CommentsCubit({
|
||||
required this.feedRepository,
|
||||
required this.commentsRepository,
|
||||
}) : super(const CommentsState());
|
||||
|
||||
void setReplyId(int? replyId) {
|
||||
emit((state as CommentsStateLoaded).copyWith(replyId: replyId));
|
||||
}
|
||||
|
||||
Future<void> getComments(String id, CommentSourceType commentSourceType, [bool isFirstFetch = false]) async {
|
||||
Future<void> getComments(String id, CommentSourceType commentSourceType, [bool isFirstFetch = false]) async {
|
||||
if (isFirstFetch) emit(const CommentsState.loading());
|
||||
try {
|
||||
switch (commentSourceType) {
|
||||
@@ -27,7 +32,7 @@ class CommentsCubit extends Cubit<CommentsState> {
|
||||
case CommentSourceType.recipe:
|
||||
emit(CommentsState.loaded(comment: await feedRepository.getRecipesComments(id: id)));
|
||||
break;
|
||||
case CommentSourceType.plan:
|
||||
case CommentSourceType.plan:
|
||||
emit(CommentsState.loaded(comment: await feedRepository.getPlansComments(slug: id)));
|
||||
break;
|
||||
}
|
||||
@@ -78,4 +83,34 @@ class CommentsCubit extends Cubit<CommentsState> {
|
||||
emit(CommentsState.error(errorMessage: e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> deleteComment({required int id}) async {
|
||||
if (state is! CommentsStateLoaded) return false;
|
||||
final commentModel = (state as CommentsStateLoaded).comment;
|
||||
final updatedCommentModel = commentModel.copyWith(data: commentModel.data.where((comment) => comment.id != id).toList());
|
||||
try {
|
||||
await commentsRepository.deleteComment(id: id);
|
||||
emit(CommentsState.loaded(comment: updatedCommentModel));
|
||||
return true;
|
||||
} catch (e, st) {
|
||||
emit(CommentsState.loaded(comment: commentModel));
|
||||
log(e.toString(), stackTrace: st);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Future<bool> updateComment({required int id, required String body}) async {
|
||||
final commentModel = (state as CommentsStateLoaded).comment;
|
||||
final updatedCommentModel =
|
||||
commentModel.copyWith(data: commentModel.data.map((comment) => comment.id == id ? comment.copyWith(body: body) : comment).toList());
|
||||
try {
|
||||
await commentsRepository.updateComment(id: id, body: body);
|
||||
emit(CommentsState.loaded(comment: updatedCommentModel));
|
||||
return true;
|
||||
} catch (e, st) {
|
||||
emit(CommentsState.loaded(comment: commentModel));
|
||||
log(e.toString(), stackTrace: st);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ abstract class CommentsState with _$CommentsState {
|
||||
const factory CommentsState.loaded({
|
||||
required CommentModel comment,
|
||||
int? replyId,
|
||||
int? editedCommentId,
|
||||
}) = CommentsStateLoaded;
|
||||
|
||||
const factory CommentsState.error({
|
||||
12
lib/core/comments/models/comment_update_model.dart
Normal file
12
lib/core/comments/models/comment_update_model.dart
Normal file
@@ -0,0 +1,12 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'comment_update_model.freezed.dart';
|
||||
part 'comment_update_model.g.dart';
|
||||
|
||||
@freezed
|
||||
abstract class CommentUpdateModel with _$CommentUpdateModel {
|
||||
|
||||
factory CommentUpdateModel({required String body}) = _CommentUpdateModel;
|
||||
|
||||
factory CommentUpdateModel.fromJson(Map<String, dynamic> json) => _$CommentUpdateModelFromJson(json);
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
import 'package:eatvio_app/core/theme/custom_text_style.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/widgets/bottom_sheet_handler_bar.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_divider.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_text_form_field.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
void showCommentsActionsBottomSheet(
|
||||
BuildContext context, {
|
||||
required void Function()? reply,
|
||||
required void Function() copy,
|
||||
required void Function(String text) edit,
|
||||
required void Function() delete,
|
||||
required void Function() complain,
|
||||
required String commentText,
|
||||
required bool isMyComment,
|
||||
}) {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
backgroundColor: Colors.transparent,
|
||||
builder: (context) => Container(
|
||||
margin: EdgeInsets.only(left: 8, right: 8, bottom: MediaQuery.of(context).padding.bottom),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
color: appTheme.whiteA700,
|
||||
),
|
||||
child: CommentsActionsBottomSheet(
|
||||
isMyComment: isMyComment,
|
||||
reply: reply,
|
||||
copy: copy,
|
||||
edit: edit,
|
||||
delete: delete,
|
||||
complain: complain,
|
||||
commentText: commentText,
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
class CommentsActionsBottomSheet extends StatefulWidget {
|
||||
const CommentsActionsBottomSheet({
|
||||
super.key,
|
||||
required this.isMyComment,
|
||||
required this.reply,
|
||||
required this.copy,
|
||||
required this.edit,
|
||||
required this.delete,
|
||||
required this.complain,
|
||||
required this.commentText,
|
||||
});
|
||||
final bool isMyComment;
|
||||
final void Function()? reply;
|
||||
final void Function() copy;
|
||||
final void Function(String text) edit;
|
||||
final void Function() delete;
|
||||
final void Function() complain;
|
||||
final String commentText;
|
||||
|
||||
@override
|
||||
State<CommentsActionsBottomSheet> createState() => _CommentsActionsBottomSheetState();
|
||||
}
|
||||
|
||||
class _CommentsActionsBottomSheetState extends State<CommentsActionsBottomSheet> {
|
||||
bool isUserEditingComment = false;
|
||||
final controller = TextEditingController();
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
controller.text = widget.commentText;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final s = S.of(context);
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: isUserEditingComment
|
||||
? Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Row(children: [
|
||||
Expanded(
|
||||
child: CustomTextFormField(
|
||||
autofocus: true,
|
||||
controller: controller,
|
||||
onChanged: (value) => setState(() {}),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
widget.edit(controller.text);
|
||||
GoRouter.of(context).pop();
|
||||
},
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: controller.text.length > 2 ? appTheme.blueA400 : appTheme.gray50,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
height: 32,
|
||||
width: 32,
|
||||
child: Icon(
|
||||
Icons.send_rounded,
|
||||
size: 18,
|
||||
color: controller.text.length > 2 ? appTheme.whiteA700 : appTheme.black,
|
||||
),
|
||||
),
|
||||
)
|
||||
])
|
||||
],
|
||||
),
|
||||
)
|
||||
: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 7,
|
||||
),
|
||||
const BottomSheetHandlerBar(),
|
||||
if (widget.isMyComment)
|
||||
_ActionWidget(
|
||||
text: s.edit,
|
||||
iconPath: 'assets/icons/edit_paint.svg',
|
||||
needToPop: false,
|
||||
onTap: () => setState(() {
|
||||
isUserEditingComment = true;
|
||||
}),
|
||||
)
|
||||
else if (widget.reply != null)
|
||||
_ActionWidget(
|
||||
text: s.reply,
|
||||
iconPath: 'assets/icons/reply.svg',
|
||||
onTap: widget.reply!,
|
||||
),
|
||||
if (widget.reply != null) const CustomDivider(),
|
||||
_ActionWidget(
|
||||
text: s.copy,
|
||||
iconPath: 'assets/icons/copy2.svg',
|
||||
onTap: widget.copy,
|
||||
),
|
||||
if (widget.isMyComment) ...[
|
||||
if (widget.reply != null) ...[
|
||||
const CustomDivider(),
|
||||
_ActionWidget(
|
||||
text: s.reply,
|
||||
iconPath: 'assets/icons/reply.svg',
|
||||
onTap: widget.reply!,
|
||||
),
|
||||
],
|
||||
const CustomDivider(),
|
||||
_ActionWidget(
|
||||
text: s.deleteComment,
|
||||
iconPath: 'assets/icons/red_trash.svg',
|
||||
onTap: widget.delete,
|
||||
),
|
||||
] else ...[
|
||||
const CustomDivider(),
|
||||
_ActionWidget(
|
||||
text: s.complain,
|
||||
iconPath: 'assets/icons/complain.svg',
|
||||
onTap: widget.complain,
|
||||
),
|
||||
]
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ActionWidget extends StatelessWidget {
|
||||
const _ActionWidget({required this.text, required this.iconPath, required this.onTap, this.needToPop = true});
|
||||
final String text;
|
||||
final String iconPath;
|
||||
final void Function() onTap;
|
||||
final bool needToPop;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
if (needToPop) Navigator.pop(context);
|
||||
onTap();
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
text,
|
||||
style: TextStyles.textLMedium.copyWith(color: appTheme.black),
|
||||
),
|
||||
const Spacer(),
|
||||
SvgPicture.asset(iconPath)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
24
lib/core/comments/repositories/comments_repository.dart
Normal file
24
lib/core/comments/repositories/comments_repository.dart
Normal file
@@ -0,0 +1,24 @@
|
||||
import 'package:eatvio_app/core/comments/models/comment_update_model.dart';
|
||||
import 'package:eatvio_app/core/comments/services/comments_service.dart';
|
||||
|
||||
class CommentsRepository {
|
||||
final CommentsService service;
|
||||
|
||||
CommentsRepository({required this.service});
|
||||
|
||||
Future<void> deleteComment({required int id}) async {
|
||||
try {
|
||||
return service.deleteComment(id);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> updateComment({required int id, required String body}) async {
|
||||
try {
|
||||
return service.updateComment(id, CommentUpdateModel(body: body));
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
16
lib/core/comments/services/comments_service.dart
Normal file
16
lib/core/comments/services/comments_service.dart
Normal file
@@ -0,0 +1,16 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:eatvio_app/core/comments/models/comment_update_model.dart';
|
||||
import 'package:retrofit/retrofit.dart';
|
||||
|
||||
part 'comments_service.g.dart';
|
||||
|
||||
@RestApi()
|
||||
abstract class CommentsService {
|
||||
factory CommentsService(Dio dio, {String baseUrl}) = _CommentsService;
|
||||
|
||||
@DELETE('/api/comments/{id}')
|
||||
Future<void> deleteComment(@Path('id') int id);
|
||||
|
||||
@PATCH('/api/comments/{id}')
|
||||
Future<void> updateComment(@Path('id') int id, @Body() CommentUpdateModel body);
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
String baseUrl = 'https://eatvio.ru';
|
||||
// String baseUrl = 'https://dev2.eatvio.com';
|
||||
|
||||
|
||||
const List<int> durationValues = [7, 14, 21];
|
||||
|
||||
const List<String> dietTypeValues = ['veg', 'light', 'carb', 'meat'];
|
||||
|
||||
@@ -1,7 +1 @@
|
||||
enum ComplainedContent {
|
||||
diet,
|
||||
plan,
|
||||
recipe,
|
||||
profile,
|
||||
posts
|
||||
}
|
||||
enum ComplainedContent { diet, plan, recipe, profile, posts, comment }
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:eatvio_app/core/comments/repositories/comments_repository.dart';
|
||||
import 'package:eatvio_app/core/comments/services/comments_service.dart';
|
||||
import 'package:eatvio_app/core/const.dart';
|
||||
import 'package:eatvio_app/core/dio/phone_verify_error_interceptor.dart';
|
||||
import 'package:eatvio_app/core/firebase_api.dart';
|
||||
@@ -56,7 +58,7 @@ import 'package:eatvio_app/features/diary/presentation/bloc/diary_cubit.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/diets/presentation/cubit/about_diet_cubit.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/comments_cubit/comments_cubit.dart';
|
||||
import 'package:eatvio_app/core/comments/comments_cubit/comments_cubit.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/consultants_cubit/consultants_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';
|
||||
@@ -128,7 +130,7 @@ Future<void> init() async {
|
||||
sl.registerFactory<ProfileCubit>(() => ProfileCubit(profileRepository: sl(), chatRepository: sl(), consultantRepository: sl()));
|
||||
sl.registerFactory<profile_plans.PlansCubit>(() => profile_plans.PlansCubit(plansRepository: sl()));
|
||||
sl.registerFactory<DietsCubit>(() => DietsCubit(feedRepository: sl(), dietsRepository: sl()));
|
||||
sl.registerFactory<CommentsCubit>(() => CommentsCubit(feedRepository: sl()));
|
||||
sl.registerFactory<CommentsCubit>(() => CommentsCubit(feedRepository: sl(), commentsRepository: sl()));
|
||||
sl.registerFactory<PlansCubit>(() => PlansCubit(feedRepository: sl(), planRepository: sl()));
|
||||
sl.registerFactory<SettingsCubit>(() => SettingsCubit(profileRepository: sl(), settingsRepository: sl(), consultantRepository: sl()));
|
||||
sl.registerFactory<RegisterConsultantCubit>(() => RegisterConsultantCubit(consultantRepository: sl()));
|
||||
@@ -198,6 +200,7 @@ Future<void> init() async {
|
||||
sl.registerFactory<MyRecipesRepository>(() => MyRecipesRepository(myRecipesService: sl()));
|
||||
sl.registerFactory<ResetPasswordRepository>(() => ResetPasswordRepository(resetPasswordService: sl()));
|
||||
sl.registerLazySingleton<BlockedUsersRepository>(() => BlockedUsersRepository(blockedUserService: sl()));
|
||||
sl.registerLazySingleton<CommentsRepository>(() => CommentsRepository(service: sl()));
|
||||
|
||||
// Services
|
||||
sl.registerLazySingleton<ChatService>(() => ChatService(sl()));
|
||||
@@ -230,6 +233,7 @@ Future<void> init() async {
|
||||
sl.registerLazySingleton<FirebaseApi>(() => FirebaseApi());
|
||||
sl.registerLazySingleton<ResetPasswordService>(() => ResetPasswordService(sl()));
|
||||
sl.registerLazySingleton<BlockedUserService>(() => BlockedUserService(sl()));
|
||||
sl.registerLazySingleton<CommentsService>(() => CommentsService(sl()));
|
||||
|
||||
// External
|
||||
sl.registerLazySingleton(
|
||||
|
||||
@@ -7,8 +7,8 @@ import 'package:eatvio_app/core/widgets/custom_popup.dart';
|
||||
import 'package:eatvio_app/core/widgets/loader.dart';
|
||||
import 'package:eatvio_app/features/blog_post/presentation/cubit/blog_post_cubit.dart';
|
||||
import 'package:eatvio_app/features/blog_post/presentation/cubit/blog_post_state.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/core/comments/comments_cubit/comments_cubit.dart';
|
||||
import 'package:eatvio_app/core/comments/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/core/locator_service.dart';
|
||||
|
||||
@@ -72,6 +72,12 @@ class ComplainingCubit extends Cubit<ComplainingState> {
|
||||
emit(state.copyWith(wasSentSuccessfully: true));
|
||||
return;
|
||||
}
|
||||
case ComplainedContent.comment:
|
||||
if (id != null) {
|
||||
await repository.sendCommentComplain(id: id, category: category.getValue(), body: state.complainInfo);
|
||||
emit(state.copyWith(wasSentSuccessfully: true));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e, st) {
|
||||
|
||||
@@ -64,4 +64,16 @@ class ComplainingRepository {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> sendCommentComplain({
|
||||
required int id,
|
||||
required String category,
|
||||
required ComplainModel body,
|
||||
}) async {
|
||||
try {
|
||||
await service.sendCommentComplain(id: id, category: category, body: body);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,5 +42,12 @@ abstract class ComplainingService {
|
||||
@Path() required String category,
|
||||
@Body() required ComplainModel body,
|
||||
});
|
||||
|
||||
@POST('/api/comments/{id}/complain/{category}')
|
||||
Future<void> sendCommentComplain({
|
||||
@Path() required int id,
|
||||
@Path() required String category,
|
||||
@Body() required ComplainModel body,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@ import 'package:eatvio_app/features/diets/presentation/widgets/info_bouble.dart'
|
||||
import 'package:eatvio_app/core/widgets/main_background_bouble.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/start_diet_bottom_sheet.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/core/comments/comments_cubit/comments_cubit.dart';
|
||||
import 'package:eatvio_app/core/comments/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/generated/l10n.dart';
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
import 'package:eatvio_app/core/comments/presentation/comments_actions_bottom_sheet.dart';
|
||||
import 'package:eatvio_app/core/const.dart';
|
||||
import 'package:eatvio_app/core/enums/complained_content.dart';
|
||||
import 'package:eatvio_app/core/locator_service.dart';
|
||||
import 'package:eatvio_app/core/utils/date_time_utils.dart';
|
||||
import 'package:eatvio_app/core/utils/toasts.dart';
|
||||
import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_cubit.dart';
|
||||
import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_state.dart';
|
||||
import 'package:eatvio_app/features/complaining/presentation/complaining_bottom_sheet.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/core/comments/comments_cubit/comments_cubit.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
@@ -53,98 +58,133 @@ class _CommentsWidgetState extends State<CommentsWidget> {
|
||||
);
|
||||
}
|
||||
|
||||
Container _comment(S s, Comment comment, [double radius = 18, bool isChild = false]) {
|
||||
return Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
decoration: BoxDecoration(
|
||||
color: widget.replyId == comment.id ? appTheme.blueA400.withValues(alpha: 0.1) : Colors.white,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
GoRouter.of(context).pushNamed(
|
||||
'profileScreen',
|
||||
extra: Author(
|
||||
authorSlug: comment.authorSlug,
|
||||
authorName: comment.authorName,
|
||||
authorProfileIcon: comment.authorProfileIcon.contains('https') ? comment.authorProfileIcon : baseUrl + comment.authorProfileIcon,
|
||||
authorIsMe: (sl<ProfileAvatarCubit>().state as ProfileAvatarStateLoaded).profile.slug == comment.authorSlug ? true : false,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: CircleAvatar(
|
||||
foregroundImage: NetworkImage(
|
||||
comment.authorProfileIcon.contains('https') ? comment.authorProfileIcon : baseUrl + comment.authorProfileIcon,
|
||||
),
|
||||
backgroundImage: const AssetImage('assets/images/no_avatar.png'),
|
||||
radius: radius,
|
||||
Widget _comment(S s, Comment comment, [double radius = 18, bool isChild = false]) {
|
||||
final isMe = (sl<ProfileAvatarCubit>().state as ProfileAvatarStateLoaded).profile.slug == comment.authorSlug;
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
showCommentsActionsBottomSheet(
|
||||
context,
|
||||
commentText: comment.body,
|
||||
reply: !isChild
|
||||
? () {
|
||||
context.read<CommentsCubit>().setReplyId(comment.id);
|
||||
}
|
||||
: null,
|
||||
copy: () {
|
||||
Clipboard.setData(ClipboardData(text: comment.body));
|
||||
showInfoToast(s.link_was_copied);
|
||||
},
|
||||
edit: (String text) {
|
||||
context.read<CommentsCubit>().updateComment(id: comment.id, body: text);
|
||||
},
|
||||
delete: () {
|
||||
context.read<CommentsCubit>().deleteComment(id: comment.id);
|
||||
},
|
||||
complain: () {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
builder: (context) => ComplainingBottomSheet(
|
||||
complainedContentType: ComplainedContent.comment,
|
||||
id: comment.id,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
comment.authorName,
|
||||
style: TextStyle(
|
||||
height: 1,
|
||||
color: appTheme.gray,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
);
|
||||
},
|
||||
isMyComment: isMe,
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
decoration: BoxDecoration(
|
||||
color: widget.replyId == comment.id ? appTheme.blueA400.withValues(alpha: 0.1) : Colors.white,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
GoRouter.of(context).pushNamed(
|
||||
'profileScreen',
|
||||
extra: Author(
|
||||
authorSlug: comment.authorSlug,
|
||||
authorName: comment.authorName,
|
||||
authorProfileIcon: comment.authorProfileIcon.contains('https') ? comment.authorProfileIcon : baseUrl + comment.authorProfileIcon,
|
||||
authorIsMe: isMe,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: CircleAvatar(
|
||||
foregroundImage: NetworkImage(
|
||||
comment.authorProfileIcon.contains('https') ? comment.authorProfileIcon : baseUrl + comment.authorProfileIcon,
|
||||
),
|
||||
backgroundImage: const AssetImage('assets/images/no_avatar.png'),
|
||||
radius: radius,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
SizedBox(
|
||||
width: isChild ? MediaQuery.of(context).size.width * 0.72 : MediaQuery.of(context).size.width * 0.8,
|
||||
child: Text(
|
||||
comment.body,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
comment.authorName,
|
||||
style: TextStyle(
|
||||
height: 1,
|
||||
color: appTheme.black,
|
||||
fontSize: 16,
|
||||
color: appTheme.gray,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
comment.createdAt.format('dd MMMM', 'ru'),
|
||||
const SizedBox(height: 4),
|
||||
SizedBox(
|
||||
width: isChild ? MediaQuery.of(context).size.width * 0.72 : MediaQuery.of(context).size.width * 0.8,
|
||||
child: Text(
|
||||
comment.body,
|
||||
style: TextStyle(
|
||||
height: 1,
|
||||
color: appTheme.gray,
|
||||
fontSize: 14,
|
||||
color: appTheme.black,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
if (!isChild)
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
context.read<CommentsCubit>().setReplyId(comment.id);
|
||||
},
|
||||
child: Text(
|
||||
s.answer,
|
||||
style: TextStyle(
|
||||
height: 1,
|
||||
color: appTheme.gray,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
comment.createdAt.format('dd MMMM', 'ru'),
|
||||
style: TextStyle(
|
||||
height: 1,
|
||||
color: appTheme.gray,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
const SizedBox(width: 16),
|
||||
if (!isChild)
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
context.read<CommentsCubit>().setReplyId(comment.id);
|
||||
},
|
||||
child: Text(
|
||||
s.answer,
|
||||
style: TextStyle(
|
||||
height: 1,
|
||||
color: appTheme.gray,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -66,7 +66,7 @@ class NotificationsCubit extends Cubit<NotificationsState> {
|
||||
|
||||
Future<void> getNotifications() async {
|
||||
try {
|
||||
final notifications = await notificationsRepository.getNotifications(page: 2);
|
||||
final notifications = await notificationsRepository.getNotifications(page: 1);
|
||||
_notifications.clear();
|
||||
_notifications.addAll(notifications ?? []);
|
||||
emit(
|
||||
|
||||
@@ -67,7 +67,7 @@ class _PlanSubscriptionStartedToAuthorWidget extends StatelessWidget {
|
||||
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: s.fillYasterday,
|
||||
notificationsText: s.userSubscribedToPlan(notification.customerName, notification.planName),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -81,7 +81,7 @@ class _PlanSubscriptionCanceledToAuthorWidget extends StatelessWidget {
|
||||
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: s.fillYasterday,
|
||||
notificationsText: s.userCanceldThePlanSubscription(notification.customerName, notification.planName),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -95,7 +95,7 @@ class _ChosenPlanStartedToClientWidget extends StatelessWidget {
|
||||
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: s.fillYasterday,
|
||||
notificationsText: s.planStarted(notification.planName),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -109,7 +109,7 @@ class _ChosenPlanTomorrowReminderToClientWidget extends StatelessWidget {
|
||||
|
||||
return _BaseNotificationWidget(
|
||||
isRead: notification.isRead,
|
||||
notificationsText: s.fillYasterday,
|
||||
notificationsText: s.tomorrowYourPlanWillStart(notification.planName),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,8 +15,8 @@ import 'package:eatvio_app/features/diets/presentation/widgets/author_card.dart'
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/expandable_text.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/info_bouble.dart';
|
||||
import 'package:eatvio_app/core/widgets/main_background_bouble.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/core/comments/comments_cubit/comments_cubit.dart';
|
||||
import 'package:eatvio_app/core/comments/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/features/plans/presentation/cubit/about_plan_cubit.dart';
|
||||
|
||||
@@ -16,8 +16,8 @@ import 'package:eatvio_app/features/diets/presentation/widgets/author_card.dart'
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/expandable_text.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/info_bouble.dart';
|
||||
import 'package:eatvio_app/core/widgets/main_background_bouble.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/core/comments/comments_cubit/comments_cubit.dart';
|
||||
import 'package:eatvio_app/core/comments/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/features/recipe/presentation/cubit/about_recipe_cubit.dart';
|
||||
|
||||
@@ -200,6 +200,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"continueButton": MessageLookupByLibrary.simpleMessage("Продолжить"),
|
||||
"continue_": MessageLookupByLibrary.simpleMessage("Продолжить"),
|
||||
"copied": MessageLookupByLibrary.simpleMessage("cкопирован"),
|
||||
"copy": MessageLookupByLibrary.simpleMessage("Скопировать"),
|
||||
"copy_link": MessageLookupByLibrary.simpleMessage("Скопировать ссылку"),
|
||||
"copy_referral_link": MessageLookupByLibrary.simpleMessage(
|
||||
"Скопировать пригласительную ссылку",
|
||||
@@ -255,6 +256,9 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
),
|
||||
"days": MessageLookupByLibrary.simpleMessage("дней"),
|
||||
"deception": MessageLookupByLibrary.simpleMessage("Обман"),
|
||||
"deleteComment": MessageLookupByLibrary.simpleMessage(
|
||||
"Удалить комментарий",
|
||||
),
|
||||
"deleted": MessageLookupByLibrary.simpleMessage("Удалена"),
|
||||
"diary": MessageLookupByLibrary.simpleMessage("Дневник"),
|
||||
"diet": MessageLookupByLibrary.simpleMessage("Диета"),
|
||||
@@ -622,6 +626,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"removeFromActive": MessageLookupByLibrary.simpleMessage(
|
||||
"Снять с публикации",
|
||||
),
|
||||
"reply": MessageLookupByLibrary.simpleMessage("Ответить"),
|
||||
"save": MessageLookupByLibrary.simpleMessage("Сохранить"),
|
||||
"send": MessageLookupByLibrary.simpleMessage("Отправить"),
|
||||
"send_complain": MessageLookupByLibrary.simpleMessage("Отправить жалобу"),
|
||||
|
||||
@@ -3404,6 +3404,26 @@ class S {
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Скопировать`
|
||||
String get copy {
|
||||
return Intl.message('Скопировать', name: 'copy', desc: '', args: []);
|
||||
}
|
||||
|
||||
/// `Ответить`
|
||||
String get reply {
|
||||
return Intl.message('Ответить', name: 'reply', desc: '', args: []);
|
||||
}
|
||||
|
||||
/// `Удалить комментарий`
|
||||
String get deleteComment {
|
||||
return Intl.message(
|
||||
'Удалить комментарий',
|
||||
name: 'deleteComment',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AppLocalizationDelegate extends LocalizationsDelegate<S> {
|
||||
|
||||
@@ -402,7 +402,11 @@
|
||||
"allowAcessToGaleryDescription": "Предоставление доступа позволит вам добавлять фото к записям",
|
||||
"allowAccessToCamera": "Разрешите доступ к камере",
|
||||
"allowAccessToCameraDescription": "Предоставление доступа позволит вам делать фотографии и добавлять к записям",
|
||||
"allowAccess": "Разрешить доступ",
|
||||
"allowAccess": "Разрешить доступ" ,
|
||||
"copy": "Скопировать",
|
||||
"reply": "Ответить",
|
||||
"deleteComment": "Удалить комментарий"
|
||||
,
|
||||
"personalDietCreating": "Составление индивидуальной диеты"
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user