diff --git a/lib/models/comment/comment.dart b/lib/models/comment/comment.dart index c0f127b..1fbf8d3 100644 --- a/lib/models/comment/comment.dart +++ b/lib/models/comment/comment.dart @@ -6,12 +6,9 @@ class CommentData { int id; final String text; final String createdAt; - String? type; bool liked; bool disliked; - bool private; int status; - dynamic mention; final FeedbackData feedback; final UserOverview user; final List replies; @@ -22,21 +19,17 @@ class CommentData { required this.createdAt, required this.liked, required this.disliked, - required this.private, required this.feedback, required this.user, required this.replies, required this.status, - this.type, - required this.mention, }); - factory CommentData.fromJson(Map json, bool private) => CommentData( + factory CommentData.fromJson(Map json) => CommentData( id: json['id'], text: json['text'], createdAt: json['createdAt'], liked: json['liked'], - private: private, disliked: json['disliked'], feedback: FeedbackData.fromJson(json['feedback']), user: UserOverview.fromJson(json['user']), @@ -46,19 +39,14 @@ class CommentData { ), ), status: json['status'], - mention: json['mention'], ); - Map toJson() => { 'id': id, 'text': text, 'createdAt': createdAt, 'liked': liked, 'disliked': disliked, - 'private': private, - 'mention': mention, - 'type': type, 'feedback': feedback.toJson(), 'user': user.toJson(), 'replies': replies.map((e) => e.toJson()).toList(), diff --git a/lib/models/mention/mention.dart b/lib/models/mention/mention.dart index 963e55c..69419d0 100644 --- a/lib/models/mention/mention.dart +++ b/lib/models/mention/mention.dart @@ -1,9 +1,9 @@ class MentionData { - final int id; - final String fullName; - final String text; - final String createdAt; - final List mentions; + int id; + String fullName; + String text; + String createdAt; + List mentions; MentionData( {required this.id, @@ -12,8 +12,7 @@ class MentionData { required this.fullName, required this.mentions}); - factory MentionData.fromJson(Map json, bool private) => - MentionData( + factory MentionData.fromJson(Map json) => MentionData( id: json['id'], text: json['text'], createdAt: json['createdAt'], diff --git a/lib/models/users_mention.dart b/lib/models/users_mention.dart index 96da502..35c0923 100644 --- a/lib/models/users_mention.dart +++ b/lib/models/users_mention.dart @@ -1,17 +1,16 @@ class UsersMention { - int? id; - String? name; + int id; + String name; String? type; String? photo; - UsersMention({this.id, this.name, this.type, this.photo}); + UsersMention({required this.id, required this.name, this.type, this.photo}); - UsersMention.fromJson(Map json) { - id = json['id']; - name = json['name']; - type = json['type']; - photo = json['photo']; - } + factory UsersMention.fromJson(Map json) => UsersMention( + id: json['id'], + name: json['name'], + type: json['type'], + photo: json['photo']); Map toJson() { final Map data = {}; @@ -21,4 +20,4 @@ class UsersMention { data['photo'] = photo; return data; } -} \ No newline at end of file +} diff --git a/lib/views/comments/comments.dart b/lib/views/comments/comments.dart index f59c5fd..1488eff 100644 --- a/lib/views/comments/comments.dart +++ b/lib/views/comments/comments.dart @@ -1,15 +1,11 @@ -import 'dart:ui'; - import 'package:didvan/config/design_config.dart'; import 'package:didvan/config/theme_data.dart'; import 'package:didvan/constants/app_icons.dart'; import 'package:didvan/constants/assets.dart'; -import 'package:didvan/models/users_mention.dart'; import 'package:didvan/models/view/app_bar_data.dart'; import 'package:didvan/views/comments/comments_state.dart'; import 'package:didvan/views/comments/widgets/comment.dart'; import 'package:didvan/views/widgets/animated_visibility.dart'; -import 'package:didvan/views/widgets/didvan/checkbox.dart'; import 'package:didvan/views/widgets/didvan/icon_button.dart'; import 'package:didvan/views/widgets/didvan/scaffold.dart'; import 'package:didvan/views/widgets/didvan/text.dart'; @@ -19,12 +15,8 @@ import 'package:didvan/views/widgets/state_handlers/sliver_state_handler.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import '../widgets/didvan/didvan_title_divider.dart'; -import '../widgets/user_mention.dart'; - class Comments extends StatefulWidget { final Map pageData; - const Comments({ Key? key, required this.pageData, @@ -55,8 +47,6 @@ class _CommentsState extends State { @override Widget build(BuildContext context) { - final commentsState = context.watch(); - final bottomViewInset = MediaQuery.of(context).viewInsets.bottom; if (bottomViewInset == 0) { if (_bottomPadding != 0) { @@ -80,7 +70,6 @@ class _CommentsState extends State { ) : null, padding: const EdgeInsets.only(left: 16, right: 16, bottom: 92), - showSliversFirst: false, slivers: [ Consumer( builder: (context, state, child) => @@ -91,8 +80,7 @@ class _CommentsState extends State { childCount: state.comments.length, placeholder: const _CommentPlaceholder(), centerEmptyState: _isPage, - enableEmptyState: - state.comments.isEmpty && state.privateComments.isEmpty, + enableEmptyState: state.comments.isEmpty, emptyState: EmptyState( asset: Assets.emptyChat, title: 'اولین نظر را بنویسید...', @@ -108,84 +96,6 @@ class _CommentsState extends State { ), ), ], - children: commentsState.privateComments.isNotEmpty - ? [ - const SizedBox( - height: 6, - ), - DidvanTitleDivider( - title: "نظرات پنهان شده", - color: Theme.of(context).colorScheme.primary, - icon: Icon( - commentsState.showPrivates - ? DidvanIcons.angle_up_regular - : DidvanIcons.angle_down_regular, - color: Theme.of(context).colorScheme.primary, - ), - onClick: () { - commentsState.showPrivates = - !commentsState.showPrivates; - commentsState.update(); - }, - ), - const SizedBox( - height: 16, - ), - AnimatedVisibility( - duration: DesignConfig.lowAnimationDuration, - isVisible: commentsState.showPrivates, - child: _buildPrivateComments(commentsState), - ), - const SizedBox( - height: 16, - ), - const DidvanTitleDivider( - title: "سایر نظرات", - ), - ] - : null, - ), - AnimatedVisibility( - duration: DesignConfig.lowAnimationDuration, - isVisible: commentsState.showUsersForMentionsLayout, - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 8.0, sigmaY: 8.0), - child: Container( - decoration: BoxDecoration( - color: - Theme.of(context).colorScheme.focused.withOpacity(0.5)), - child: DidvanScaffold( - appBarData: null, - padding: const EdgeInsets.only( - left: 16, right: 16, top: 16, bottom: 92), - backgroundColor: Colors.white.withOpacity(0.0), - slivers: [ - Consumer( - builder: (context, state, child) => - SliverStateHandler( - onRetry: state.getUsersMention, - state: state, - itemPadding: const EdgeInsets.symmetric(vertical: 8), - childCount: state.usersMention.length, - placeholder: const _UsersPlaceholder(), - centerEmptyState: _isPage, - enableEmptyState: state.usersMention.isEmpty, - emptyState: EmptyState( - asset: Assets.emptyBookmark, - title: 'لیست خالی است', - ), - builder: (context, state, index) { - return UserMention( - user: state.usersMention[index], - index: index, - ); - }, - ), - ), - ], - ), - ), - ), ), Positioned( left: 0, @@ -197,28 +107,10 @@ class _CommentsState extends State { ), ); } - - ListView _buildPrivateComments(CommentsState commentsState) { - return ListView.builder( - physics: const BouncingScrollPhysics(), - itemCount: commentsState.privateComments.length, - shrinkWrap: true, - itemBuilder: (context, index) { - return Comment( - key: ValueKey( - commentsState.privateComments[index].id.toString() + - commentsState.privateComments[index].text, - ), - focusNode: _focusNode, - comment: commentsState.privateComments[index], - ); - }); - } } class _MessageBox extends StatefulWidget { final FocusNode focusNode; - const _MessageBox({Key? key, required this.focusNode}) : super(key: key); @override @@ -226,179 +118,59 @@ class _MessageBox extends StatefulWidget { } class _MessageBoxState extends State<_MessageBox> { + final _controller = TextEditingController(); + @override Widget build(BuildContext context) { final state = context.watch(); - - void onCheckBoxChange(bool b) { - state.hideMentionedUser = b; - state.update(); - } - return Column( children: [ AnimatedVisibility( duration: DesignConfig.lowAnimationDuration, isVisible: state.showReplyBox, - child: Column( - children: [ - Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.secondCTA, - borderRadius: const BorderRadius.only( - topRight: Radius.circular(16), - topLeft: Radius.circular(16)), - boxShadow: [ - BoxShadow( - color: Theme.of(context) - .colorScheme - .title - .withOpacity(0.2), - offset: const Offset( - 5.0, - 5.0, - ), - blurRadius: 10.0, - spreadRadius: 2.0, - ) - ] - - // border: Border( - // top: BorderSide( - // color: Theme.of(context).colorScheme.border, - // ), - // ), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - if (state.replyingTo != null) - DidvanText( - 'پاسخ به ${state.replyingTo!.fullName}:', - color: Theme.of(context).colorScheme.primary, - style: Theme.of(context).textTheme.bodySmall, - ), - const Spacer(), - DidvanIconButton( - gestureSize: 24, - color: Theme.of(context).colorScheme.primary, - icon: DidvanIcons.close_regular, - onPressed: () { - state.commentId = null; - state.replyingTo = null; - state.showReplyBox = false; - state.update(); - }, - ), - ], - ), - ), - Container( - color: Theme.of(context).colorScheme.secondCTA, - padding: const EdgeInsets.fromLTRB(16, 8, 16, 8), - child: Divider( - height: 2, + child: Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, + border: Border( + top: BorderSide( color: Theme.of(context).colorScheme.border, ), - ) - ], - ), - ), - AnimatedVisibility( - duration: DesignConfig.lowAnimationDuration, - isVisible: state.usersMentioned.name != null, - child: Column( - children: [ - Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.secondCTA, - borderRadius: !state.showReplyBox - ? const BorderRadius.only( - topLeft: Radius.circular(16), - topRight: Radius.circular(16)) - : null), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Container( - color: Theme.of(context).colorScheme.primary, - width: 2, - height: 40, - ), - const SizedBox( - width: 8, - ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - DidvanText( - "اشاره به", - color: Theme.of(context).colorScheme.text, - style: Theme.of(context).textTheme.labelSmall, - ), - DidvanText( - state.usersMentioned.name.toString(), - color: Theme.of(context).colorScheme.text, - style: Theme.of(context).textTheme.bodySmall, - ), - ], - ) - ], - ), - Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - DidvanIconButton( - gestureSize: 24, - color: Theme.of(context).colorScheme.primary, - icon: DidvanIcons.close_regular, - onPressed: () { - state.usersMentioned = UsersMention(); - state.update(); - }, - ), - !state.showReplyBox - ? DidvanCheckbox( - title: "پنهان کردن فراخوانی", - value: state.hideMentionedUser, - color: Theme.of(context).colorScheme.primary, - onChanged: onCheckBoxChange, - size: 12, - ) - : const SizedBox(), - ], - ) - ], - ), ), - ], + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + if (state.replyingTo != null) + DidvanText( + 'پاسخ به ${state.replyingTo!.fullName}:', + color: Theme.of(context).colorScheme.caption, + style: Theme.of(context).textTheme.bodySmall, + ), + const Spacer(), + DidvanIconButton( + gestureSize: 24, + color: Theme.of(context).colorScheme.caption, + icon: DidvanIcons.close_regular, + onPressed: () { + state.commentId = null; + state.replyingTo = null; + state.showReplyBox = false; + state.update(); + }, + ), + ], + ), ), ), Container( decoration: BoxDecoration( - boxShadow: state.showReplyBox && state.usersMentioned.name == null - ? null - : [ - BoxShadow( - color: - Theme.of(context).colorScheme.title.withOpacity(0.2), - offset: const Offset( - 5.0, - 5.0, - ), - blurRadius: 10.0, - spreadRadius: 2.0, - ) - ], - color: state.showReplyBox && state.usersMentioned.name == null - ? Theme.of(context).colorScheme.secondCTA - : Theme.of(context).colorScheme.surface, + color: Theme.of(context).colorScheme.surface, + border: Border( + top: BorderSide( + color: Theme.of(context).colorScheme.border, + ), + ), ), child: Row( children: [ @@ -411,7 +183,7 @@ class _MessageBoxState extends State<_MessageBox> { Expanded( child: TextField( focusNode: widget.focusNode, - controller: state.commentTextFieldController, + controller: _controller, keyboardType: TextInputType.multiline, textInputAction: TextInputAction.send, style: Theme.of(context).textTheme.bodyMedium, @@ -423,7 +195,7 @@ class _MessageBoxState extends State<_MessageBox> { hintStyle: Theme.of(context).textTheme.bodySmall!.copyWith( color: Theme.of(context).colorScheme.disabledText), ), - onChanged: (value) => _onChange(state, value), + onChanged: (value) => state.text = value, ), ), ], @@ -434,33 +206,9 @@ class _MessageBoxState extends State<_MessageBox> { } void _onSend(CommentsState state) { - if (state.commentTextFieldController.text.replaceAll(' ', '').isNotEmpty) { + if (state.text.replaceAll(' ', '').isNotEmpty) { state.addComment(); - state.commentTextFieldController.text = ''; - } - } - - void _onChange(CommentsState state, value) { - state.commentTextFieldController.text = value; - if (state.usersMentioned.name == null) { - if (state.commentTextFieldController.text.contains("@")) { - int index = state.commentTextFieldController.text.indexOf("@"); - if (state.commentTextFieldController.text.length > index + 1) { - if (state.commentTextFieldController.text - .substring(index) - .contains(" ")) { - state.showUsersForMentionsLayout = false; - } else { - state.mentionedText = - state.commentTextFieldController.text.substring(index); - state.getUsersMention(); - state.showUsersForMentionsLayout = true; - } - } - } else { - state.showUsersForMentionsLayout = false; - } - state.update(); + _controller.text = ''; } } } @@ -528,28 +276,3 @@ class _CommentPlaceholder extends StatelessWidget { ); } } - -class _UsersPlaceholder extends StatelessWidget { - const _UsersPlaceholder({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return const Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ShimmerPlaceholder( - height: 40, - width: 40, - borderRadius: DesignConfig.highBorderRadius, - ), - SizedBox(width: 16), - Expanded( - child: ShimmerPlaceholder( - borderRadius: DesignConfig.highBorderRadius, - height: 40, - ), - ), - ], - ); - } -} diff --git a/lib/views/comments/comments_state.dart b/lib/views/comments/comments_state.dart index d47c2a3..4a0594c 100644 --- a/lib/views/comments/comments_state.dart +++ b/lib/views/comments/comments_state.dart @@ -4,33 +4,24 @@ import 'package:didvan/models/comment/feedback.dart'; import 'package:didvan/models/comment/reply.dart'; import 'package:didvan/models/comment/user.dart'; import 'package:didvan/models/enums.dart'; -import 'package:didvan/models/users_mention.dart'; import 'package:didvan/models/view/alert_data.dart'; import 'package:didvan/providers/core.dart'; import 'package:didvan/providers/user.dart'; import 'package:didvan/services/network/request.dart'; import 'package:didvan/services/network/request_helper.dart'; import 'package:didvan/utils/action_sheet.dart'; -import 'package:flutter/cupertino.dart'; import 'package:provider/provider.dart'; class CommentsState extends CoreProvier { - TextEditingController commentTextFieldController = TextEditingController(); - UsersMention usersMentioned = UsersMention(); - String mentionedText = ''; + String text = ''; int? commentId; UserOverview? replyingTo; bool showReplyBox = false; - bool showUsersForMentionsLayout = false; - bool showPrivates = false; - bool hideMentionedUser = false; late void Function(int count) onCommentsChanged; int _count = 0; late String type; final List comments = []; - final List privateComments = []; - final List usersMention = []; final Map> _feedbackQueue = {}; int itemId = 0; @@ -42,40 +33,14 @@ class CommentsState extends CoreProvier { await service.httpGet(); if (service.isSuccess) { comments.clear(); - final messagesPublic = service.result['comments']['public']; - for (var i = 0; i < messagesPublic.length; i++) { - comments.add(CommentData.fromJson(messagesPublic[i], false)); + final messages = service.result['comments']; + for (var i = 0; i < messages.length; i++) { + comments.add(CommentData.fromJson(messages[i])); _count++; - for (var j = 0; j < messagesPublic[i]['replies'].length; j++) { + for (var j = 0; j < messages[i]['replies'].length; j++) { _count++; } } - - final messagesPrivate = service.result['comments']['private']; - for (var i = 0; i < messagesPrivate.length; i++) { - privateComments.add(CommentData.fromJson(messagesPrivate[i], true)); - _count++; - for (var j = 0; j < messagesPrivate[i]['replies'].length; j++) { - _count++; - } - } - appState = AppState.idle; - return; - } - appState = AppState.failed; - } - - Future getUsersMention() async { - final service = RequestService( - RequestHelper.usersMentions(mentionedText.replaceAll("@", "")), - ); - await service.httpGet(); - if (service.isSuccess) { - usersMention.clear(); - final List users = service.data('users'); - usersMention - .addAll(users.map((users) => UsersMention.fromJson(users)).toList()); - appState = AppState.idle; return; } @@ -122,14 +87,12 @@ class CommentsState extends CoreProvier { } Future addComment() async { - late List cList = - hideMentionedUser ? privateComments : comments; final user = DesignConfig.context!.read().user; if (replyingTo != null) { comments.firstWhere((comment) => comment.id == commentId).replies.add( Reply( id: 0, - text: commentTextFieldController.text, + text: text, createdAt: DateTime.now().toString(), liked: false, disliked: false, @@ -141,15 +104,14 @@ class CommentsState extends CoreProvier { photo: user.photo, ), status: 2, - mention: usersMentioned.name, ), ); } else { - cList.insert( + comments.insert( 0, CommentData( id: 0, - text: commentTextFieldController.text, + text: text, createdAt: DateTime.now().toString(), liked: false, disliked: false, @@ -161,8 +123,6 @@ class CommentsState extends CoreProvier { ), replies: [], status: 2, - private: hideMentionedUser, - mention: usersMentioned.name, ), ); } @@ -178,12 +138,8 @@ class CommentsState extends CoreProvier { body.addAll({'status': 2}); showReplyBox = false; - // update(); - body.addAll({ - 'text': commentTextFieldController.text, - "mention": usersMentioned.id, - "private": hideMentionedUser - }); + update(); + body.addAll({'text': text}); final service = RequestService( RequestHelper.addComment(itemId, type), body: body, @@ -192,20 +148,17 @@ class CommentsState extends CoreProvier { await service.post(); if (service.isSuccess) { if (replyingTo != null) { - cList + comments .firstWhere((comment) => comment.id == commentId) .replies .firstWhere((reply) => reply.id == 0) .id = service.result['comment']['id']; } else { - cList.firstWhere((comment) => comment.id == 0).id = + comments.firstWhere((comment) => comment.id == 0).id = service.result['comment']['id']; } commentId = null; replyingTo = null; - usersMentioned = UsersMention(); - mentionedText = ''; - update(); } } diff --git a/lib/views/comments/widgets/comment.dart b/lib/views/comments/widgets/comment.dart index 785d99e..124d8bc 100644 --- a/lib/views/comments/widgets/comment.dart +++ b/lib/views/comments/widgets/comment.dart @@ -20,7 +20,6 @@ import 'package:provider/provider.dart'; class Comment extends StatefulWidget { final FocusNode focusNode; final CommentData comment; - const Comment({ Key? key, required this.focusNode, @@ -110,13 +109,6 @@ class CommentState extends State { ), ], ), - comment.mention != null - ? DidvanText( - comment.mention.toString(), - color: Theme.of(context).colorScheme.primary, - style: Theme.of(context).textTheme.titleSmall, - ) - : const SizedBox(), const SizedBox(height: 8), if (isReply) DidvanText( @@ -132,22 +124,19 @@ class CommentState extends State { children: [ Icon( Icons.circle, - color: - Theme.of(context).colorScheme.secondaryDisabled, + color: Theme.of(context) + .colorScheme + .secondary + .withOpacity(0.3), size: 18, ), const SizedBox(width: 4), DidvanText( 'در انتظار تایید', - style: Theme.of(context) - .textTheme - .titleSmall! - .copyWith( - color: Theme.of(context) - .colorScheme - .secondaryDisabled), - color: - Theme.of(context).colorScheme.secondaryDisabled, + color: Theme.of(context) + .colorScheme + .secondary + .withOpacity(0.3), ), ], ), @@ -265,7 +254,6 @@ class _FeedbackButtons extends StatefulWidget { final bool dislikeValue; final void Function(bool like, bool dislike, int likeCount, int dislikeCount) onFeedback; - const _FeedbackButtons({ Key? key, required this.onFeedback, diff --git a/lib/views/mentions/mentions.dart b/lib/views/mentions/mentions.dart index aac0615..511d604 100644 --- a/lib/views/mentions/mentions.dart +++ b/lib/views/mentions/mentions.dart @@ -4,10 +4,9 @@ import 'package:didvan/config/design_config.dart'; import 'package:didvan/config/theme_data.dart'; import 'package:didvan/constants/app_icons.dart'; import 'package:didvan/constants/assets.dart'; -import 'package:didvan/models/users_mention.dart'; import 'package:didvan/models/view/app_bar_data.dart'; -import 'package:didvan/views/comments/widgets/comment.dart'; import 'package:didvan/views/mentions/mentions_state.dart'; +import 'package:didvan/views/mentions/widgets/mention.dart'; import 'package:didvan/views/widgets/animated_visibility.dart'; import 'package:didvan/views/widgets/didvan/checkbox.dart'; import 'package:didvan/views/widgets/didvan/icon_button.dart'; @@ -18,8 +17,7 @@ import 'package:didvan/views/widgets/state_handlers/empty_state.dart'; import 'package:didvan/views/widgets/state_handlers/sliver_state_handler.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; - -import '../widgets/didvan/didvan_title_divider.dart'; +import '../comments/comments_state.dart'; import '../widgets/user_mention.dart'; class Mentions extends StatefulWidget { @@ -54,6 +52,12 @@ class _MentionsState extends State { bool get _isPage => widget.pageData['isPage'] != false; + void _onChange(MentionsState state, value) { + state.searchUsers = value; + state.getUsersMention(); + state.update(); + } + @override Widget build(BuildContext context) { final commentsState = context.watch(); @@ -92,12 +96,11 @@ class _MentionsState extends State { childCount: state.comments.length, placeholder: const _CommentPlaceholder(), centerEmptyState: _isPage, - enableEmptyState: - state.comments.isEmpty && state.privateComments.isEmpty, + enableEmptyState: state.comments.isEmpty, emptyState: EmptyState( asset: Assets.emptyChat, title: 'دوستان خود را فراخوانی کنید'), - builder: (context, state, index) => Comment( + builder: (context, state, index) => Mention( key: ValueKey( state.comments[index].id.toString() + state.comments[index].text, @@ -108,42 +111,6 @@ class _MentionsState extends State { ), ), ], - children: commentsState.privateComments.isNotEmpty - ? [ - const SizedBox( - height: 6, - ), - DidvanTitleDivider( - title: "نظرات پنهان شده", - color: Theme.of(context).colorScheme.primary, - icon: Icon( - commentsState.showPrivates - ? DidvanIcons.angle_up_regular - : DidvanIcons.angle_down_regular, - color: Theme.of(context).colorScheme.primary, - ), - onClick: () { - commentsState.showPrivates = - !commentsState.showPrivates; - commentsState.update(); - }, - ), - const SizedBox( - height: 16, - ), - AnimatedVisibility( - duration: DesignConfig.lowAnimationDuration, - isVisible: commentsState.showPrivates, - child: _buildPrivateComments(commentsState), - ), - const SizedBox( - height: 16, - ), - const DidvanTitleDivider( - title: "سایر نظرات", - ), - ] - : null, ), AnimatedVisibility( duration: DesignConfig.lowAnimationDuration, @@ -159,30 +126,73 @@ class _MentionsState extends State { padding: const EdgeInsets.only( left: 16, right: 16, top: 16, bottom: 92), backgroundColor: Colors.white.withOpacity(0.0), + showSliversFirst: false, slivers: [ Consumer( builder: (context, state, child) => SliverStateHandler( onRetry: state.getUsersMention, state: state, - itemPadding: const EdgeInsets.symmetric(vertical: 8), - childCount: state.usersMention.length, + childCount: state.users.length, placeholder: const _UsersPlaceholder(), centerEmptyState: _isPage, - enableEmptyState: state.usersMention.isEmpty, + enableEmptyState: state.users.isEmpty, emptyState: EmptyState( asset: Assets.emptyBookmark, title: 'لیست خالی است', ), builder: (context, state, index) { return UserMention( - user: state.usersMention[index], + user: state.users[index], index: index, ); }, ), ), ], + children: [ + Row( + children: [ + Expanded( + child: TextField( + keyboardType: TextInputType.multiline, + textInputAction: TextInputAction.send, + style: Theme.of(context).textTheme.bodyMedium, + onEditingComplete: () {}, + onChanged: (val) => _onChange(commentsState, val), + decoration: InputDecoration( + icon: const Icon(DidvanIcons.search_regular), + border: InputBorder.none, + hintText: 'جستجو کنید...', + hintStyle: Theme.of(context) + .textTheme + .bodySmall! + .copyWith( + color: Theme.of(context) + .colorScheme + .disabledText), + ), + ), + ), + DidvanIconButton( + icon: DidvanIcons.close_regular, + onPressed: () { + commentsState.showUsersForMentionsLayout = false; + commentsState.update(); + }), + ], + ), + const SizedBox( + height: 4, + ), + Divider( + height: 1, + color: Theme.of(context).colorScheme.splash, + ), + const SizedBox( + height: 12, + ) + ], ), ), ), @@ -197,23 +207,6 @@ class _MentionsState extends State { ), ); } - - ListView _buildPrivateComments(MentionsState commentsState) { - return ListView.builder( - physics: const BouncingScrollPhysics(), - itemCount: commentsState.privateComments.length, - shrinkWrap: true, - itemBuilder: (context, index) { - return Comment( - key: ValueKey( - commentsState.privateComments[index].id.toString() + - commentsState.privateComments[index].text, - ), - focusNode: _focusNode, - comment: commentsState.privateComments[index], - ); - }); - } } class _MessageBox extends StatefulWidget { @@ -245,31 +238,23 @@ class _MessageBoxState extends State<_MessageBox> { Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( - color: Theme.of(context).colorScheme.secondCTA, - borderRadius: const BorderRadius.only( - topRight: Radius.circular(16), - topLeft: Radius.circular(16)), - boxShadow: [ - BoxShadow( - color: Theme.of(context) - .colorScheme - .title - .withOpacity(0.2), - offset: const Offset( - 5.0, - 5.0, - ), - blurRadius: 10.0, - spreadRadius: 2.0, - ) - ] - - // border: Border( - // top: BorderSide( - // color: Theme.of(context).colorScheme.border, - // ), - // ), + color: Theme.of(context).colorScheme.secondCTA, + borderRadius: const BorderRadius.only( + topRight: Radius.circular(16), + topLeft: Radius.circular(16)), + boxShadow: [ + BoxShadow( + color: + Theme.of(context).colorScheme.title.withOpacity(0.2), + offset: const Offset( + 5.0, + 5.0, + ), + blurRadius: 10.0, + spreadRadius: 2.0, ), + ], + ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -307,7 +292,7 @@ class _MessageBoxState extends State<_MessageBox> { ), AnimatedVisibility( duration: DesignConfig.lowAnimationDuration, - isVisible: state.usersMentioned.name != null, + isVisible: state.mentionedUsers.isNotEmpty, child: Column( children: [ Container( @@ -343,7 +328,9 @@ class _MessageBoxState extends State<_MessageBox> { style: Theme.of(context).textTheme.labelSmall, ), DidvanText( - state.usersMentioned.name.toString(), + state.mentionedUsers + .map((user) => user.name) + .join("، "), color: Theme.of(context).colorScheme.text, style: Theme.of(context).textTheme.bodySmall, ), @@ -359,19 +346,10 @@ class _MessageBoxState extends State<_MessageBox> { color: Theme.of(context).colorScheme.primary, icon: DidvanIcons.close_regular, onPressed: () { - state.usersMentioned = UsersMention(); + state.mentionedUsers = []; state.update(); }, ), - !state.showReplyBox - ? DidvanCheckbox( - title: "پنهان کردن فراخوانی", - value: state.hideMentionedUser, - color: Theme.of(context).colorScheme.primary, - onChanged: onCheckBoxChange, - size: 12, - ) - : const SizedBox(), ], ) ], @@ -382,23 +360,12 @@ class _MessageBoxState extends State<_MessageBox> { ), Container( decoration: BoxDecoration( - boxShadow: state.showReplyBox && state.usersMentioned.name == null - ? null - : [ - BoxShadow( - color: - Theme.of(context).colorScheme.title.withOpacity(0.2), - offset: const Offset( - 5.0, - 5.0, - ), - blurRadius: 10.0, - spreadRadius: 2.0, - ) - ], - color: state.showReplyBox && state.usersMentioned.name == null - ? Theme.of(context).colorScheme.secondCTA - : Theme.of(context).colorScheme.surface, + color: Theme.of(context).colorScheme.surface, + border: Border( + top: BorderSide( + color: Theme.of(context).colorScheme.border, + ), + ), ), child: Row( children: [ @@ -423,9 +390,19 @@ class _MessageBoxState extends State<_MessageBox> { hintStyle: Theme.of(context).textTheme.bodySmall!.copyWith( color: Theme.of(context).colorScheme.disabledText), ), - onChanged: (value) => _onChange(state, value), ), ), + const Spacer(), + if (!state.showUsersForMentionsLayout) + DidvanIconButton( + onPressed: () { + state.showUsersForMentionsLayout = true; + state.update(); + }, + icon: DidvanIcons.user_shield_regular, + size: 24, + color: Theme.of(context).colorScheme.focusedBorder, + ), ], ), ), @@ -437,30 +414,8 @@ class _MessageBoxState extends State<_MessageBox> { if (state.commentTextFieldController.text.replaceAll(' ', '').isNotEmpty) { state.addComment(); state.commentTextFieldController.text = ''; - } - } - - void _onChange(MentionsState state, value) { - state.commentTextFieldController.text = value; - if (state.usersMentioned.name == null) { - if (state.commentTextFieldController.text.contains("@")) { - int index = state.commentTextFieldController.text.indexOf("@"); - if (state.commentTextFieldController.text.length > index + 1) { - if (state.commentTextFieldController.text - .substring(index) - .contains(" ")) { - state.showUsersForMentionsLayout = false; - } else { - state.mentionedText = - state.commentTextFieldController.text.substring(index); - state.getUsersMention(); - state.showUsersForMentionsLayout = true; - } - } - } else { - state.showUsersForMentionsLayout = false; - } - state.update(); + state.searchUsers = ''; + state.mentionedUsers.clear(); } } } diff --git a/lib/views/mentions/mentions_state.dart b/lib/views/mentions/mentions_state.dart index 01fbf57..4440559 100644 --- a/lib/views/mentions/mentions_state.dart +++ b/lib/views/mentions/mentions_state.dart @@ -1,23 +1,19 @@ import 'package:didvan/config/design_config.dart'; -import 'package:didvan/models/comment/comment.dart'; -import 'package:didvan/models/comment/feedback.dart'; -import 'package:didvan/models/comment/reply.dart'; +import 'package:didvan/models/mention/mention.dart'; import 'package:didvan/models/comment/user.dart'; import 'package:didvan/models/enums.dart'; import 'package:didvan/models/users_mention.dart'; -import 'package:didvan/models/view/alert_data.dart'; import 'package:didvan/providers/core.dart'; import 'package:didvan/providers/user.dart'; import 'package:didvan/services/network/request.dart'; import 'package:didvan/services/network/request_helper.dart'; -import 'package:didvan/utils/action_sheet.dart'; import 'package:flutter/cupertino.dart'; import 'package:provider/provider.dart'; class MentionsState extends CoreProvier { TextEditingController commentTextFieldController = TextEditingController(); - UsersMention usersMentioned = UsersMention(); - String mentionedText = ''; + List mentionedUsers = []; + String searchUsers = ''; int? commentId; UserOverview? replyingTo; bool showReplyBox = false; @@ -27,38 +23,27 @@ class MentionsState extends CoreProvier { int _count = 0; late String type; - final List comments = []; - final List privateComments = []; - final List usersMention = []; - final Map> _feedbackQueue = {}; + final List comments = []; + final List users = []; int itemId = 0; Future getComments() async { final service = RequestService( - RequestHelper.comments(itemId, type), + RequestHelper.mention(itemId, type), ); await service.httpGet(); if (service.isSuccess) { comments.clear(); - final messagesPublic = service.result['comments']['public']; - for (var i = 0; i < messagesPublic.length; i++) { - comments.add(CommentData.fromJson(messagesPublic[i], false)); + final messages = service.result['comments']; + + for (var i = 0; i < messages.length; i++) { + comments.add(MentionData.fromJson(messages[i])); _count++; - for (var j = 0; j < messagesPublic[i]['replies'].length; j++) { - _count++; - } } - final messagesPrivate = service.result['comments']['private']; - for (var i = 0; i < messagesPrivate.length; i++) { - privateComments.add(CommentData.fromJson(messagesPrivate[i], true)); - _count++; - for (var j = 0; j < messagesPrivate[i]['replies'].length; j++) { - _count++; - } - } appState = AppState.idle; + return; } appState = AppState.failed; @@ -66,14 +51,17 @@ class MentionsState extends CoreProvier { Future getUsersMention() async { final service = RequestService( - RequestHelper.usersMentions(mentionedText.replaceAll("@", "")), + RequestHelper.usersMentions(searchUsers), ); + await service.httpGet(); + if (service.isSuccess) { - usersMention.clear(); - final List users = service.data('users'); - usersMention - .addAll(users.map((users) => UsersMention.fromJson(users)).toList()); + users.clear(); + final List resUsers = service.data('users'); + + users + .addAll(resUsers.map((user) => UsersMention.fromJson(user)).toList()); appState = AppState.idle; return; @@ -81,169 +69,49 @@ class MentionsState extends CoreProvier { appState = AppState.failed; } - Future feedback({ - required int id, - required bool like, - required bool dislike, - required int likeCount, - required int dislikeCount, - int? replyId, - }) async { - _feedbackQueue.addAll({id: MapEntry(like, dislike)}); - dynamic comment; - if (replyId == null) { - comment = comments.firstWhere((comment) => comment.id == id); - } else { - comment = comments - .firstWhere((comment) => comment.id == id) - .replies - .firstWhere((element) => element.id == replyId); - } - - if (comment != null) { - comment.feedback.like = likeCount; - comment.feedback.dislike = dislikeCount; - comment.disliked = dislike; - comment.liked = like; - } - Future.delayed(const Duration(milliseconds: 500), () async { - if (!_feedbackQueue.containsKey(id)) return; - final service = RequestService( - RequestHelper.feedback(itemId, id, type), - body: { - 'like': _feedbackQueue[id]!.key, - 'dislike': _feedbackQueue[id]!.value, - }, - ); - await service.put(); - _feedbackQueue.remove(id); - }); - } - Future addComment() async { - late List cList = - hideMentionedUser ? privateComments : comments; + late List cList = comments; final user = DesignConfig.context!.read().user; - if (replyingTo != null) { - comments.firstWhere((comment) => comment.id == commentId).replies.add( - Reply( - id: 0, - text: commentTextFieldController.text, - createdAt: DateTime.now().toString(), - liked: false, - disliked: false, - feedback: FeedbackData(like: 0, dislike: 0), - toUser: replyingTo!, - user: UserOverview( - id: user.id, - fullName: user.fullName, - photo: user.photo, - ), - status: 2, - mention: usersMentioned.name, - ), - ); - } else { - cList.insert( - 0, - CommentData( - id: 0, - text: commentTextFieldController.text, - createdAt: DateTime.now().toString(), - liked: false, - disliked: false, - feedback: FeedbackData(like: 0, dislike: 0), - user: UserOverview( - id: user.id, - fullName: user.fullName, - photo: user.photo, - ), - replies: [], - status: 2, - private: hideMentionedUser, - mention: usersMentioned.name, - ), - ); - } + + cList.insert( + 0, + MentionData( + id: 0, + fullName: user.fullName, + text: commentTextFieldController.text, + createdAt: DateTime.now().toString(), + mentions: mentionedUsers.map((user) => user.name).toList(), + ), + ); final body = {}; - if (commentId != null) { - body.addAll({'commentId': commentId}); - } - if (replyingTo != null) { - body.addAll({'replyUserId': replyingTo!.id}); - } - body.addAll({'status': 2}); - - showReplyBox = false; - // update(); body.addAll({ 'text': commentTextFieldController.text, - "mention": usersMentioned.id, - "private": hideMentionedUser + "mentions": mentionedUsers.map((user) => user.id.toString()).toList(), }); + final service = RequestService( - RequestHelper.addComment(itemId, type), + RequestHelper.mention(itemId, type), body: body, ); await service.post(); if (service.isSuccess) { - if (replyingTo != null) { - cList - .firstWhere((comment) => comment.id == commentId) - .replies - .firstWhere((reply) => reply.id == 0) - .id = service.result['comment']['id']; - } else { - cList.firstWhere((comment) => comment.id == 0).id = - service.result['comment']['id']; - } - commentId = null; - replyingTo = null; - usersMentioned = UsersMention(); - mentionedText = ''; + cList.firstWhere((comment) => comment.id == 0).id = + service.result['comment']['id']; + + mentionedUsers = []; + searchUsers = ''; update(); } } - void reportComment(int id) { - final service = RequestService(RequestHelper.reportComment(id)); - service.post(); - ActionSheetUtils.showAlert( - AlertData( - message: 'گزارش شما با موفقیت ثبت شد و به زودی بررسی میگردد.', - aLertType: ALertType.success, - ), - ); - } - void deleteComment(int id, int status, int? rootId) async { final service = RequestService(RequestHelper.deleteComment(id)); - service.delete(); - if (rootId == null) { - final comment = comments.firstWhere((element) => element.id == id); - if (comment.replies.isNotEmpty) { - _count = 0; - await getComments(); - } else { - comments.remove(comment); + await service.delete(); - if (status != 2) { - _count--; - } - } - } else { - comments - .firstWhere((element) => element.id == rootId) - .replies - .removeWhere((element) => element.id == id); - - if (status != 2) { - _count--; - } - } + if (service.isSuccess) await getComments(); notifyListeners(); } diff --git a/lib/views/mentions/widgets/mention.dart b/lib/views/mentions/widgets/mention.dart index 7217093..ef3ef03 100644 --- a/lib/views/mentions/widgets/mention.dart +++ b/lib/views/mentions/widgets/mention.dart @@ -1,17 +1,14 @@ 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/mention/mention.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/mentions/mentions_state.dart'; import 'package:didvan/views/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/skeleton_image.dart'; diff --git a/lib/views/widgets/user_mention.dart b/lib/views/widgets/user_mention.dart index e4febab..fc084d5 100644 --- a/lib/views/widgets/user_mention.dart +++ b/lib/views/widgets/user_mention.dart @@ -1,4 +1,7 @@ +import 'package:didvan/config/design_config.dart'; import 'package:didvan/config/theme_data.dart'; +import 'package:didvan/views/mentions/mentions_state.dart'; +import 'package:didvan/views/widgets/animated_visibility.dart'; import 'package:didvan/views/widgets/ink_wrapper.dart'; import 'package:didvan/views/widgets/skeleton_image.dart'; import 'package:flutter/material.dart'; @@ -6,7 +9,6 @@ import 'package:provider/provider.dart'; import '../../constants/app_icons.dart'; import '../../models/users_mention.dart'; -import '../comments/comments_state.dart'; import 'didvan/text.dart'; class UserMention extends StatefulWidget { @@ -26,28 +28,62 @@ class UserMention extends StatefulWidget { class _UserMentionState extends State { @override Widget build(BuildContext context) { - final state = context.watch(); + final state = context.watch(); + final userFound = state.mentionedUsers.contains(widget.user); return InkWrapper( onPressed: () { - state.usersMentioned = widget.user; - state.commentTextFieldController.text = state - .commentTextFieldController.text - .replaceAll(state.mentionedText.toString(), "") - .replaceAll("@", ""); - state.showUsersForMentionsLayout = false; + if (userFound) { + state.mentionedUsers.remove(widget.user); + } else { + state.mentionedUsers.add(widget.user); + } + state.update(); }, child: Column( children: [ + const SizedBox( + height: 8, + ), Row( children: [ + Container( + width: 18, + height: 18, + decoration: BoxDecoration( + color: Colors.transparent, + borderRadius: BorderRadius.circular(6), + border: Border.all( + width: 1.0, + color: userFound + ? Theme.of(context).colorScheme.checkFav + : Theme.of(context).colorScheme.text), + ), + margin: const EdgeInsets.all(8), + child: AnimatedVisibility( + isVisible: userFound, + duration: DesignConfig.mediumAnimationDuration, + child: Center( + child: Icon( + Icons.check, + size: 12, + color: userFound + ? Theme.of(context).colorScheme.checkFav + : Theme.of(context).colorScheme.text, + ), + ), + ), + ), widget.user.photo == null - ? const Icon(DidvanIcons.avatar_light,size: 40,) + ? const Icon( + DidvanIcons.avatar_light, + size: 40, + ) : SkeletonImage( imageUrl: widget.user.photo.toString(), - height: 40, - width: 40, + height: 36, + width: 36, borderRadius: BorderRadius.circular(360), ), const SizedBox( @@ -62,7 +98,7 @@ class _UserMentionState extends State { const SizedBox( height: 8, ), - widget.index == state.usersMention.length - 1 + widget.index == state.users.length - 1 ? const SizedBox() : Divider( height: 2,