D1APP-61 comments
This commit is contained in:
parent
33dabd7ab5
commit
4f4a709562
|
|
@ -1,6 +1,15 @@
|
||||||
|
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/view/app_bar_data.dart';
|
import 'package:didvan/models/view/app_bar_data.dart';
|
||||||
import 'package:didvan/pages/home/comments/comments_state.dart';
|
import 'package:didvan/pages/home/comments/comments_state.dart';
|
||||||
|
import 'package:didvan/pages/home/comments/widgets/comment_item.dart';
|
||||||
|
import 'package:didvan/widgets/animated_visibility.dart';
|
||||||
|
import 'package:didvan/widgets/didvan/icon_button.dart';
|
||||||
import 'package:didvan/widgets/didvan/scaffold.dart';
|
import 'package:didvan/widgets/didvan/scaffold.dart';
|
||||||
|
import 'package:didvan/widgets/didvan/text.dart';
|
||||||
|
import 'package:didvan/widgets/shimmer_placeholder.dart';
|
||||||
|
import 'package:didvan/widgets/state_handlers/sliver_state_handler.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
|
@ -19,8 +28,9 @@ class _CommentsState extends State<Comments> {
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
final state = context.read<CommentsState>();
|
final state = context.read<CommentsState>();
|
||||||
state.id = widget.pageData['id'];
|
state.itemId = widget.pageData['id'];
|
||||||
state.isRadar = widget.pageData['isRadar'];
|
state.isRadar = widget.pageData['isRadar'];
|
||||||
|
state.onCommentAdded = widget.pageData['onCommentAdded'];
|
||||||
Future.delayed(
|
Future.delayed(
|
||||||
Duration.zero,
|
Duration.zero,
|
||||||
() => state.getComments(),
|
() => state.getComments(),
|
||||||
|
|
@ -30,8 +40,205 @@ class _CommentsState extends State<Comments> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return DidvanScaffold(
|
return Material(
|
||||||
appBarData: AppBarData(),
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
DidvanScaffold(
|
||||||
|
backgroundColor: Theme.of(context).colorScheme.surface,
|
||||||
|
appBarData: AppBarData(
|
||||||
|
hasBack: true,
|
||||||
|
title: 'نظرات',
|
||||||
|
subtitle: widget.pageData['title'],
|
||||||
|
),
|
||||||
|
padding: const EdgeInsets.only(left: 16, right: 16, bottom: 92),
|
||||||
|
slivers: [
|
||||||
|
Consumer<CommentsState>(
|
||||||
|
builder: (context, state, child) =>
|
||||||
|
SliverStateHandler<CommentsState>(
|
||||||
|
onRetry: state.getComments,
|
||||||
|
state: state,
|
||||||
|
itemPadding: const EdgeInsets.symmetric(vertical: 16),
|
||||||
|
childCount: state.comments.length,
|
||||||
|
placeholder: const _CommentPlaceholder(),
|
||||||
|
builder: (context, state, index) => Comment(
|
||||||
|
comment: state.comments[index],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
bottom: MediaQuery.of(context).viewInsets.bottom,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
child: const _MessageBox(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MessageBox extends StatefulWidget {
|
||||||
|
const _MessageBox({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<_MessageBox> createState() => _MessageBoxState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MessageBoxState extends State<_MessageBox> {
|
||||||
|
final _controller = TextEditingController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final state = context.watch<CommentsState>();
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
AnimatedVisibility(
|
||||||
|
duration: DesignConfig.lowAnimationDuration,
|
||||||
|
isVisible: state.replyingTo != null,
|
||||||
|
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,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
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.caption,
|
||||||
|
),
|
||||||
|
const Spacer(),
|
||||||
|
DidvanIconButton(
|
||||||
|
gestureSize: 24,
|
||||||
|
color: Theme.of(context).colorScheme.caption,
|
||||||
|
icon: DidvanIcons.close_regular,
|
||||||
|
onPressed: () {
|
||||||
|
state.commentId = null;
|
||||||
|
state.replyingTo = null;
|
||||||
|
state.update();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(context).colorScheme.surface,
|
||||||
|
border: Border(
|
||||||
|
top: BorderSide(
|
||||||
|
color: Theme.of(context).colorScheme.border,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
DidvanIconButton(
|
||||||
|
onPressed: () => _onSend(state),
|
||||||
|
icon: DidvanIcons.send_solid,
|
||||||
|
size: 24,
|
||||||
|
color: Theme.of(context).colorScheme.focusedBorder,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: TextField(
|
||||||
|
controller: _controller,
|
||||||
|
textInputAction: TextInputAction.send,
|
||||||
|
style: Theme.of(context).textTheme.bodyText2,
|
||||||
|
onEditingComplete: () {},
|
||||||
|
onSubmitted: (value) => _onSend(state),
|
||||||
|
decoration: InputDecoration(
|
||||||
|
border: InputBorder.none,
|
||||||
|
hintText: 'پیام خود را ارسال کنید',
|
||||||
|
hintStyle: Theme.of(context).textTheme.caption!.copyWith(
|
||||||
|
color: Theme.of(context).colorScheme.disabledText),
|
||||||
|
),
|
||||||
|
onChanged: (value) => state.text = value,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onSend(CommentsState state) {
|
||||||
|
if (state.text.replaceAll(' ', '').isNotEmpty) {
|
||||||
|
state.addComment();
|
||||||
|
_controller.text = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CommentPlaceholder extends StatelessWidget {
|
||||||
|
const _CommentPlaceholder({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
const ShimmerPlaceholder(
|
||||||
|
height: 24,
|
||||||
|
width: 24,
|
||||||
|
borderRadius: DesignConfig.highBorderRadius,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: const [
|
||||||
|
ShimmerPlaceholder(
|
||||||
|
height: 20,
|
||||||
|
width: 100,
|
||||||
|
),
|
||||||
|
ShimmerPlaceholder(
|
||||||
|
height: 14,
|
||||||
|
width: 100,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
const ShimmerPlaceholder(
|
||||||
|
height: 16,
|
||||||
|
width: double.infinity,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
const ShimmerPlaceholder(
|
||||||
|
height: 16,
|
||||||
|
width: 200,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: const [
|
||||||
|
ShimmerPlaceholder(
|
||||||
|
height: 24,
|
||||||
|
width: 48,
|
||||||
|
),
|
||||||
|
SizedBox(width: 8),
|
||||||
|
ShimmerPlaceholder(
|
||||||
|
height: 24,
|
||||||
|
width: 48,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,126 @@
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:didvan/config/design_config.dart';
|
||||||
import 'package:didvan/models/comment/comment.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/comment/user.dart';
|
||||||
import 'package:didvan/models/enums.dart';
|
import 'package:didvan/models/enums.dart';
|
||||||
import 'package:didvan/providers/core_provider.dart';
|
import 'package:didvan/providers/core_provider.dart';
|
||||||
|
import 'package:didvan/providers/user_provider.dart';
|
||||||
import 'package:didvan/services/network/request.dart';
|
import 'package:didvan/services/network/request.dart';
|
||||||
import 'package:didvan/services/network/request_helper.dart';
|
import 'package:didvan/services/network/request_helper.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class CommentsState extends CoreProvier {
|
class CommentsState extends CoreProvier {
|
||||||
final List<Comment> comments = [];
|
String text = '';
|
||||||
|
int? commentId;
|
||||||
|
UserOverview? replyingTo;
|
||||||
|
late VoidCallback onCommentAdded;
|
||||||
|
|
||||||
|
final List<CommentData> comments = [];
|
||||||
|
final Map<int, MapEntry<bool, bool>> _feedbackQueue = {};
|
||||||
|
|
||||||
bool isRadar = true;
|
bool isRadar = true;
|
||||||
int id = 0;
|
int itemId = 0;
|
||||||
|
|
||||||
Future<void> getComments() async {
|
Future<void> getComments() async {
|
||||||
appState = AppState.busy;
|
appState = AppState.busy;
|
||||||
final service = RequestService(
|
final service = RequestService(
|
||||||
isRadar
|
isRadar
|
||||||
? RequestHelper.radarComments(id)
|
? RequestHelper.radarComments(itemId)
|
||||||
: RequestHelper.newsComments(id),
|
: RequestHelper.newsComments(itemId),
|
||||||
);
|
);
|
||||||
await service.httpGet();
|
await service.httpGet();
|
||||||
if (service.isSuccess) {
|
if (service.isSuccess) {
|
||||||
final messages = service.result['messages'];
|
final messages = service.result['comments'];
|
||||||
for (var i = 0; i < messages.length; i++) {
|
for (var i = 0; i < messages.length; i++) {
|
||||||
comments.add(Comment.fromJson(messages[i]));
|
comments.add(CommentData.fromJson(messages[i]));
|
||||||
}
|
}
|
||||||
appState = AppState.idle;
|
appState = AppState.idle;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
appState = AppState.failed;
|
appState = AppState.failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> feedback(int id, bool like, bool dislike) async {
|
||||||
|
_feedbackQueue.addAll({id: MapEntry(like, dislike)});
|
||||||
|
Future.delayed(const Duration(milliseconds: 500), () async {
|
||||||
|
if (!_feedbackQueue.containsKey(id)) return;
|
||||||
|
final service = RequestService(
|
||||||
|
isRadar
|
||||||
|
? RequestHelper.feedbackRadarComment(itemId, id)
|
||||||
|
: RequestHelper.feedbackNewsComment(itemId, id),
|
||||||
|
body: {
|
||||||
|
'like': _feedbackQueue[id]!.key,
|
||||||
|
'dislike': _feedbackQueue[id]!.value,
|
||||||
|
});
|
||||||
|
await service.put();
|
||||||
|
_feedbackQueue.remove(id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> addComment() async {
|
||||||
|
final user = DesignConfig.context.read<UserProvider>().user;
|
||||||
|
if (replyingTo != null) {
|
||||||
|
final coment = comments.firstWhere((comment) => comment.id == commentId);
|
||||||
|
coment.replies.add(
|
||||||
|
Reply(
|
||||||
|
id: Random().nextInt(1000),
|
||||||
|
text: text,
|
||||||
|
createdAt: DateTime.now().toString(),
|
||||||
|
liked: false,
|
||||||
|
disliked: false,
|
||||||
|
feedback: const FeedbackData(like: 0, dislike: 0),
|
||||||
|
toUser: replyingTo!,
|
||||||
|
user: UserOverview(
|
||||||
|
id: user.id,
|
||||||
|
fullName: user.fullName,
|
||||||
|
photo: user.photo,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
comments.insert(
|
||||||
|
0,
|
||||||
|
CommentData(
|
||||||
|
id: Random().nextInt(1000),
|
||||||
|
text: text,
|
||||||
|
createdAt: DateTime.now().toString(),
|
||||||
|
liked: false,
|
||||||
|
disliked: false,
|
||||||
|
feedback: const FeedbackData(like: 0, dislike: 0),
|
||||||
|
user: UserOverview(
|
||||||
|
id: user.id,
|
||||||
|
fullName: user.fullName,
|
||||||
|
photo: user.photo,
|
||||||
|
),
|
||||||
|
replies: [],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onCommentAdded();
|
||||||
|
|
||||||
|
final body = {};
|
||||||
|
|
||||||
|
if (commentId != null) {
|
||||||
|
body.addAll({'commentId': commentId});
|
||||||
|
}
|
||||||
|
if (replyingTo != null) {
|
||||||
|
body.addAll({'replyUserId': replyingTo!.id});
|
||||||
|
}
|
||||||
|
body.addAll({'text': text});
|
||||||
|
final service = RequestService(
|
||||||
|
isRadar
|
||||||
|
? RequestHelper.addRadarComment(itemId)
|
||||||
|
: RequestHelper.addNewsComment(itemId),
|
||||||
|
body: body);
|
||||||
|
commentId = null;
|
||||||
|
replyingTo = null;
|
||||||
|
update();
|
||||||
|
await service.post();
|
||||||
|
update();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,262 @@
|
||||||
|
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/pages/home/comments/comments_state.dart';
|
||||||
|
import 'package:didvan/utils/date_time.dart';
|
||||||
|
import 'package:didvan/widgets/animated_visibility.dart';
|
||||||
|
import 'package:didvan/widgets/didvan/icon_button.dart';
|
||||||
|
import 'package:didvan/widgets/didvan/text.dart';
|
||||||
|
import 'package:didvan/widgets/ink_wrapper.dart';
|
||||||
|
import 'package:didvan/widgets/skeleton_image.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class Comment extends StatefulWidget {
|
||||||
|
final CommentData comment;
|
||||||
|
const Comment({
|
||||||
|
Key? key,
|
||||||
|
required this.comment,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<Comment> createState() => CommentState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class CommentState extends State<Comment> {
|
||||||
|
late final CommentsState state;
|
||||||
|
|
||||||
|
bool _showSubComments = false;
|
||||||
|
|
||||||
|
CommentData get _comment => widget.comment;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
state = context.read<CommentsState>();
|
||||||
|
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(
|
||||||
|
isSubComment: true,
|
||||||
|
comment: _comment.replies[i],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _commentBuilder({required comment, bool isSubComment = false}) =>
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border(
|
||||||
|
right: isSubComment
|
||||||
|
? BorderSide(color: Theme.of(context).colorScheme.caption)
|
||||||
|
: BorderSide.none,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
if (isSubComment) 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(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
DidvanText(
|
||||||
|
comment.user.fullName,
|
||||||
|
style: Theme.of(context).textTheme.bodyText1,
|
||||||
|
),
|
||||||
|
DidvanText(
|
||||||
|
DateTimeUtils.momentGenerator(comment.createdAt),
|
||||||
|
style: Theme.of(context).textTheme.caption,
|
||||||
|
color: Theme.of(context).colorScheme.caption,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
if (isSubComment)
|
||||||
|
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.update();
|
||||||
|
},
|
||||||
|
child: DidvanText(
|
||||||
|
'پاسخ',
|
||||||
|
style: Theme.of(context).textTheme.bodyText1,
|
||||||
|
color: Theme.of(context).colorScheme.primary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (!isSubComment) const SizedBox(width: 20),
|
||||||
|
if (!isSubComment && 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) =>
|
||||||
|
state.feedback(comment.id, like, dislike),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class _FeedbackButtons extends StatefulWidget {
|
||||||
|
final int likeCount;
|
||||||
|
final int dislikeCount;
|
||||||
|
final bool likeValue;
|
||||||
|
final bool dislikeValue;
|
||||||
|
final void Function(bool like, bool dislike) 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);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
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);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue