import 'package:didvan/config/design_config.dart'; import 'package:didvan/config/theme_data.dart'; import 'package:didvan/constants/app_icons.dart'; import 'package:didvan/models/comment/comment.dart'; import 'package:didvan/models/comment/reply.dart'; import 'package:didvan/models/view/action_sheet_data.dart'; import 'package:didvan/providers/user.dart'; import 'package:didvan/utils/action_sheet.dart'; import 'package:didvan/utils/date_time.dart'; import 'package:didvan/views/home/comments/comments_state.dart'; import 'package:didvan/views/home/widgets/menu_item.dart'; import 'package:didvan/views/widgets/animated_visibility.dart'; import 'package:didvan/views/widgets/didvan/icon_button.dart'; import 'package:didvan/views/widgets/didvan/text.dart'; import 'package:didvan/views/widgets/ink_wrapper.dart'; import 'package:didvan/views/widgets/skeleton_image.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; class Comment extends StatefulWidget { final FocusNode focusNode; final CommentData comment; const Comment({ Key? key, required this.focusNode, required this.comment, }) : super(key: key); @override State createState() => CommentState(); } class CommentState extends State { late final CommentsState state; bool _showSubComments = false; CommentData get _comment => widget.comment; @override void initState() { state = context.read(); super.initState(); } @override Widget build(BuildContext context) { return Column( children: [ _commentBuilder(comment: _comment), if (_comment.replies.isNotEmpty) const SizedBox(height: 16), for (var i = 0; i < _comment.replies.length; i++) AnimatedVisibility( duration: DesignConfig.lowAnimationDuration, isVisible: _showSubComments, child: _commentBuilder( isReply: true, comment: _comment.replies[i], ), ), ], ); } Widget _commentBuilder({required comment, bool isReply = false}) => Container( decoration: BoxDecoration( border: Border( right: isReply ? BorderSide(color: Theme.of(context).colorScheme.caption) : BorderSide.none, ), ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (isReply) const SizedBox(width: 12), if (comment.user.photo == null) const Icon(DidvanIcons.avatar_light), if (comment.user.photo != null) SkeletonImage( imageUrl: comment.user.photo, height: 24, width: 24, borderRadius: DesignConfig.highBorderRadius, ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ DidvanText( comment.user.fullName, style: Theme.of(context).textTheme.bodyText1, ), const Spacer(), DidvanText( DateTimeUtils.momentGenerator(comment.createdAt), style: Theme.of(context).textTheme.caption, color: Theme.of(context).colorScheme.caption, ), const SizedBox(width: 4), DidvanIconButton( size: 18, gestureSize: 24, icon: DidvanIcons.menu_light, onPressed: () => _showCommentActions(comment), ), ], ), const SizedBox(height: 8), if (isReply) DidvanText( 'پاسخ به ${comment.toUser.fullName}', style: Theme.of(context).textTheme.caption, color: Theme.of(context).colorScheme.caption, ), const SizedBox(height: 8), DidvanText(comment.text), const SizedBox(height: 8), Row( children: [ InkWrapper( onPressed: () { state.commentId = _comment.id; state.replyingTo = comment.user; state.showReplyBox = true; state.update(); widget.focusNode.requestFocus(); }, child: DidvanText( 'پاسخ', style: Theme.of(context).textTheme.bodyText1, color: Theme.of(context).colorScheme.primary, ), ), if (!isReply) const SizedBox(width: 20), if (!isReply && comment.replies.isNotEmpty) InkWrapper( onPressed: () => setState( () => _showSubComments = !_showSubComments, ), child: Row( children: [ DidvanText( 'پاسخ‌ها(${comment.replies.length})', style: Theme.of(context).textTheme.bodyText1, color: Theme.of(context).colorScheme.primary, ), AnimatedRotation( duration: DesignConfig.lowAnimationDuration, turns: _showSubComments ? 0.5 : 0, child: Icon( DidvanIcons.angle_down_regular, color: Theme.of(context).colorScheme.primary, ), ), ], ), ), const Spacer(), _FeedbackButtons( likeCount: comment.feedback.like, dislikeCount: comment.feedback.dislike, likeValue: comment.liked, dislikeValue: comment.disliked, onFeedback: (like, dislike, likeCount, dislikeCount) => state.feedback( id: _comment.id, like: like, dislike: dislike, likeCount: likeCount, dislikeCount: dislikeCount, replyId: isReply ? comment.id : null, ), ), ], ), ], ), ), ], ), ); Future _showCommentActions(comment) async { ActionSheetUtils.showBottomSheet( data: ActionSheetData( title: 'گزینه‌های نظر', content: Column( children: [ if (comment.user.id != context.read().user.id) MenuOption( title: 'گزارش محتوای نامناسب', onTap: () { state.reportComment(comment.id); ActionSheetUtils.pop(); }, icon: DidvanIcons.alert_regular, ), if (comment.user.id == context.read().user.id) MenuOption( title: 'حذف نظر', color: Theme.of(context).colorScheme.secondary, onTap: () { state.deleteComment( comment.id, comment.runtimeType == Reply ? _comment.id : null, ); ActionSheetUtils.pop(); }, icon: DidvanIcons.trash_solid, ), ], ), hasConfirmButton: false, hasDismissButton: false, ), ); } } class _FeedbackButtons extends StatefulWidget { final int likeCount; final int dislikeCount; final bool likeValue; final bool dislikeValue; final void Function(bool like, bool dislike, int likeCount, int dislikeCount) onFeedback; const _FeedbackButtons({ Key? key, required this.onFeedback, required this.likeCount, required this.dislikeCount, required this.likeValue, required this.dislikeValue, }) : super(key: key); @override State<_FeedbackButtons> createState() => _FeedbackButtonsState(); } class _FeedbackButtonsState extends State<_FeedbackButtons> { late bool _likeValue; late bool _dislikeValue; late int _likeCount; late int _dislikeCount; @override void initState() { _likeValue = widget.likeValue; _dislikeValue = widget.dislikeValue; _likeCount = widget.likeCount; _dislikeCount = widget.dislikeCount; super.initState(); } @override Widget build(BuildContext context) { return Row( children: [ DidvanText( _likeCount.toString(), style: Theme.of(context).textTheme.caption, color: Theme.of(context).colorScheme.caption, ), const SizedBox(width: 4), DidvanIconButton( icon: _likeValue ? DidvanIcons.like_solid : DidvanIcons.like_regular, color: _likeValue ? Theme.of(context).colorScheme.primary : null, gestureSize: 24, onPressed: () { setState(() { if (_likeValue) { _likeCount--; } else { _likeCount++; if (_dislikeValue) { _dislikeValue = false; _dislikeCount--; } } _likeValue = !_likeValue; }); widget.onFeedback( _likeValue, _dislikeValue, _likeCount, _dislikeCount); }, ), const SizedBox(width: 16), DidvanText( _dislikeCount.toString(), style: Theme.of(context).textTheme.caption, color: Theme.of(context).colorScheme.caption, ), const SizedBox(width: 4), DidvanIconButton( icon: _dislikeValue ? DidvanIcons.dislike_solid : DidvanIcons.dislike_regular, color: _dislikeValue ? Theme.of(context).colorScheme.secondary : null, gestureSize: 24, onPressed: () { setState(() { if (_dislikeValue) { _dislikeCount--; } else { _dislikeCount++; if (_likeValue) { _likeValue = false; _likeCount--; } } _dislikeValue = !_dislikeValue; }); widget.onFeedback( _likeValue, _dislikeValue, _likeCount, _dislikeCount); }, ), ], ); } }