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/comments/comments_state.dart'; import 'package:didvan/views/widgets/menu_item.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:flutter_svg/flutter_svg.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; 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++) _commentBuilder( isReply: true, comment: _comment.replies[i], ), ], ); } Widget _commentBuilder({required comment, bool isReply = false}) => Container( margin: EdgeInsets.only(right: isReply ? 24.0 : 0.0), decoration: BoxDecoration( border: Border( right: isReply ? BorderSide( color: Theme.of(context).colorScheme.caption, width: 3.0, ) : BorderSide.none, ), ), child: Padding( padding: EdgeInsets.only(right: isReply ? 16.0 : 0.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ if (comment.user.photo == null) const Icon( DidvanIcons.avatar_light, size: 50, ), if (comment.user.photo != null) SkeletonImage( imageUrl: comment.user.photo, height: 50, width: 50, borderRadius: DesignConfig.highBorderRadius, ), const SizedBox(width: 6), Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ DidvanText( comment.user.fullName, style: const TextStyle( fontSize: 16, fontWeight: FontWeight.normal, color: Color.fromARGB(255, 102, 102, 102)), ), const SizedBox(height: 4), DidvanText( DateTimeUtils.momentGenerator(comment.createdAt), style: const TextStyle( fontSize: 12, fontWeight: FontWeight.bold, ), color: const Color.fromARGB(255, 0, 126, 167), ), ], ), const Spacer(), DidvanIconButton( size: 18, gestureSize: 24, icon: DidvanIcons.menu_light, onPressed: () => _showCommentActions(comment), ), ], ), const SizedBox(height: 8), DidvanText( comment.text, color: const Color.fromARGB(255, 102, 102, 102), ), const SizedBox(height: 8), if (comment.status == 2) Row( children: [ Icon( Icons.circle, color: Theme.of(context) .colorScheme .secondary .withValues(alpha: 0.3), size: 18, ), const SizedBox(width: 4), DidvanText( 'در انتظار تایید', color: Theme.of(context) .colorScheme .secondary .withValues(alpha: 0.3), ), ], ), const SizedBox(height: 8), if (_comment.status != 2) Row( children: [ _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, ), ), const SizedBox( width: 20, ), 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.bodySmall, color: const Color.fromARGB(255, 102, 102, 102), ), ), ], ), ], ), ), ); Future _showCommentActions(comment) async { ActionSheetUtils(context).showBottomSheet( data: ActionSheetData( title: 'گزینه‌های نظر', content: Column( children: [ if (comment.user.id != context.read().user.id) MenuOption( title: 'گزارش محتوای نامناسب', onTap: () { state.reportComment(comment.id); ActionSheetUtils(context).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.status, comment.runtimeType == Reply ? _comment.id : null, ); ActionSheetUtils(context).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( mainAxisAlignment: MainAxisAlignment.start, children: [ GestureDetector( onTap: () { setState(() { if (_likeValue) { _likeCount--; } else { _likeCount++; if (_dislikeValue) { _dislikeValue = false; _dislikeCount--; } } _likeValue = !_likeValue; }); widget.onFeedback( _likeValue, _dislikeValue, _likeCount, _dislikeCount); }, child: AnimatedContainer( duration: const Duration(milliseconds: 200), transform: _likeValue ? (Matrix4.identity()..scale(1.2)) : Matrix4.identity(), child: AnimatedSwitcher( duration: const Duration(milliseconds: 300), transitionBuilder: (Widget child, Animation animation) { return ScaleTransition( scale: animation, child: RotationTransition( turns: Tween(begin: 0.8, end: 1.0).animate(animation), child: child, ), ); }, child: SvgPicture.asset( _likeValue ? 'lib/assets/icons/likefill.svg' : 'lib/assets/icons/like.svg', key: ValueKey(_likeValue), color: _likeValue ? const Color.fromARGB(255, 43, 178, 74) : null, width: 16, height: 16, ), ), ), ), const SizedBox(width: 4), AnimatedDefaultTextStyle( duration: const Duration(milliseconds: 200), style: Theme.of(context).textTheme.bodySmall!.copyWith( color: _likeValue ? const Color.fromARGB(255, 43, 178, 74) : null, fontWeight: _likeValue ? FontWeight.bold : FontWeight.normal, ), child: DidvanText( 'پسندیدم', color: _likeValue ? const Color.fromARGB(255, 43, 178, 74) : null, style: const TextStyle(fontSize: 11), ), ), const SizedBox( width: 5, ), AnimatedSwitcher( duration: const Duration(milliseconds: 250), transitionBuilder: (Widget child, Animation animation) { return SlideTransition( position: Tween( begin: const Offset(0, 0.5), end: const Offset(0, 0), ).animate(animation), child: FadeTransition(opacity: animation, child: child), ); }, child: DidvanText('(${_likeCount.toString()})', key: ValueKey(_likeCount), style: Theme.of(context).textTheme.bodySmall!.copyWith( fontSize: 11, color: _likeValue ? const Color.fromARGB(255, 43, 178, 74) : null, )), ), const SizedBox(width: 12), GestureDetector( onTap: () { setState(() { if (_dislikeValue) { _dislikeCount--; } else { _dislikeCount++; if (_likeValue) { _likeValue = false; _likeCount--; } } _dislikeValue = !_dislikeValue; }); widget.onFeedback( _likeValue, _dislikeValue, _likeCount, _dislikeCount); }, child: AnimatedContainer( duration: const Duration(milliseconds: 200), transform: _dislikeValue ? (Matrix4.identity()..scale(1.2)) : Matrix4.identity(), child: AnimatedSwitcher( duration: const Duration(milliseconds: 300), transitionBuilder: (Widget child, Animation animation) { return ScaleTransition( scale: animation, child: RotationTransition( turns: Tween(begin: 0.8, end: 1.0).animate(animation), child: child, ), ); }, child: SvgPicture.asset( _dislikeValue ? 'lib/assets/icons/dislike_fill.svg' : 'lib/assets/icons/dislike.svg', key: ValueKey(_dislikeValue), color: _dislikeValue ? const Color.fromARGB(255, 196, 18, 18) : null, width: 16, height: 16, ), ), ), ), const SizedBox(width: 4), AnimatedDefaultTextStyle( duration: const Duration(milliseconds: 200), style: Theme.of(context).textTheme.bodySmall!.copyWith( color: _dislikeValue ? const Color.fromARGB(255, 196, 18, 18) : null, fontWeight: _dislikeValue ? FontWeight.bold : FontWeight.normal, ), child: DidvanText( 'نپسندیدم', color: _dislikeValue ? const Color.fromARGB(255, 196, 18, 18) : null, fontSize: 11, ), ), const SizedBox( width: 5, ), AnimatedSwitcher( duration: const Duration(milliseconds: 250), transitionBuilder: (Widget child, Animation animation) { return SlideTransition( position: Tween( begin: const Offset(0, 0.5), end: const Offset(0, 0), ).animate(animation), child: FadeTransition(opacity: animation, child: child), ); }, child: DidvanText( '(${_dislikeCount.toString()})', key: ValueKey(_dislikeCount), style: Theme.of(context).textTheme.bodySmall!.copyWith( fontSize: 11, ), color: _dislikeValue ? const Color.fromARGB(255, 196, 18, 18) : null, ), ), const SizedBox(width: 4), ], ); } }