1
0
mirror of https://gitlab.com/comunic/comunicmobile synced 2024-10-23 06:53:23 +00:00
comunicmobile/lib/ui/tiles/post_tile.dart

373 lines
10 KiB
Dart
Raw Normal View History

2019-05-18 07:45:15 +00:00
import 'dart:io';
import 'package:comunic/enums/likes_type.dart';
2019-05-11 07:48:01 +00:00
import 'package:comunic/enums/post_kind.dart';
2019-05-18 12:58:35 +00:00
import 'package:comunic/helpers/comments_helper.dart';
import 'package:comunic/helpers/likes_helper.dart';
2019-05-10 17:15:11 +00:00
import 'package:comunic/lists/users_list.dart';
2019-05-18 13:54:10 +00:00
import 'package:comunic/models/comment.dart';
2019-05-18 12:58:35 +00:00
import 'package:comunic/models/new_comment.dart';
2019-05-10 17:15:11 +00:00
import 'package:comunic/models/post.dart';
2019-05-11 07:48:01 +00:00
import 'package:comunic/models/user.dart';
2019-05-16 12:52:22 +00:00
import 'package:comunic/ui/tiles/comment_tile.dart';
2019-05-11 07:48:01 +00:00
import 'package:comunic/ui/widgets/account_image_widget.dart';
import 'package:comunic/ui/widgets/network_image_widget.dart';
import 'package:comunic/utils/date_utils.dart';
2019-05-18 07:45:15 +00:00
import 'package:comunic/utils/files_utils.dart';
2019-05-11 13:35:07 +00:00
import 'package:comunic/utils/intl_utils.dart';
2019-05-18 07:45:15 +00:00
import 'package:comunic/utils/ui_utils.dart';
2019-05-10 17:15:11 +00:00
import 'package:flutter/material.dart';
/// Single posts tile
///
/// @author Pierre HUBERT
2019-05-11 07:48:01 +00:00
/// User style
const TextStyle _userNameStyle = TextStyle(
color: Color.fromRGBO(0x72, 0xaf, 0xd2, 1.0), //#72afd2
fontWeight: FontWeight.w600,
fontSize: 16.0);
2019-05-18 07:45:15 +00:00
class PostTile extends StatefulWidget {
2019-05-10 17:15:11 +00:00
final Post post;
final UsersList usersInfo;
const PostTile({
Key key,
@required this.post,
@required this.usersInfo,
}) : assert(post != null),
2019-05-10 17:15:11 +00:00
assert(usersInfo != null),
super(key: key);
2019-05-18 07:45:15 +00:00
@override
State<StatefulWidget> createState() => _PostTileState();
}
class _PostTileState extends State<PostTile> {
2019-05-18 13:05:26 +00:00
// Helpers
final _likesHelper = LikesHelper();
2019-05-18 13:05:26 +00:00
final _commentsHelper = CommentsHelper();
2019-05-18 07:45:15 +00:00
// Class members
2019-05-18 12:58:35 +00:00
TextEditingController _commentController = TextEditingController();
2019-05-18 07:45:15 +00:00
File _commentImage;
2019-05-18 12:58:35 +00:00
bool _submitting = false;
2019-05-18 07:45:15 +00:00
User get _user => widget.usersInfo.getUser(widget.post.userID);
2019-05-18 12:58:35 +00:00
bool get _commentValid => _commentController.text.toString().length > 3;
2019-05-18 07:45:15 +00:00
bool get _hasImage => _commentImage != null;
2019-05-11 07:48:01 +00:00
2019-05-18 12:58:35 +00:00
bool get _canSubmitComment => !_submitting && (_commentValid || _hasImage);
set _sendingComment(bool sending) => setState(() => _submitting = sending);
2019-05-11 07:48:01 +00:00
Widget _buildHeaderRow() {
// Header row
return Row(
children: <Widget>[
// User account image
Padding(
padding: const EdgeInsets.only(right: 8.0, left: 8.0),
child: AccountImageWidget(user: _user),
),
// Column with user name + post target
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
_user.displayName,
style: _userNameStyle,
),
2019-05-18 07:45:15 +00:00
Text(diffTimeFromNowToStr(widget.post.timeSent)),
2019-05-11 07:48:01 +00:00
],
),
),
PopupMenuButton(
itemBuilder: (c) => [],
)
],
);
}
Widget _buildContentRow() {
Widget postContent;
2019-05-18 07:45:15 +00:00
switch (widget.post.kind) {
2019-05-11 07:48:01 +00:00
case PostKind.IMAGE:
postContent = _buildPostImage();
break;
default:
}
return Column(
children: <Widget>[
// Post "rich" content
Container(child: postContent),
// Post text
2019-05-18 07:45:15 +00:00
Container(
child: widget.post.hasContent ? Text(widget.post.content) : null),
2019-05-11 07:48:01 +00:00
],
);
}
2019-05-11 13:35:07 +00:00
Widget _buildButtonsArea() {
return Padding(
padding:
const EdgeInsets.only(top: 16.0, left: 8.0, right: 8.0, bottom: 16.0),
child: Column(
children: <Widget>[
// Like button
Center(
child: InkWell(
onTap: () => _updateLike(),
2019-05-11 13:35:07 +00:00
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(left: 8.0, right: 8.0),
child: Icon(
Icons.thumb_up,
2019-05-18 07:45:15 +00:00
color: widget.post.userLikes ? Colors.blue : null,
2019-05-11 13:35:07 +00:00
),
),
2019-05-18 07:45:15 +00:00
Text(widget.post.likes < 2
? tr("%num% like",
args: {"num": widget.post.likes.toString()})
: tr("%num% likes",
args: {"num": widget.post.likes.toString()}))
2019-05-11 13:35:07 +00:00
],
),
),
),
],
),
);
}
2019-05-10 17:15:11 +00:00
@override
Widget build(BuildContext context) {
2019-05-11 07:48:01 +00:00
return Card(
elevation: 1.0,
2019-05-16 12:52:22 +00:00
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
_buildHeaderRow(),
_buildContentRow(),
_buildButtonsArea(),
],
),
),
Container(
2019-05-18 07:45:15 +00:00
child: widget.post.hasComments ? _buildComments() : null,
2019-05-16 12:52:22 +00:00
),
],
2019-05-11 07:48:01 +00:00
),
);
}
Widget _buildPostImage() {
return NetworkImageWidget(
2019-05-18 07:45:15 +00:00
url: widget.post.fileURL,
2019-05-11 07:48:01 +00:00
allowFullScreen: true,
roundedEdges: false,
2019-05-10 17:15:11 +00:00
);
}
2019-05-16 12:52:22 +00:00
/// Build the list of comments
Widget _buildComments() {
2019-05-18 07:45:15 +00:00
assert(widget.post.hasComments);
2019-05-16 12:52:22 +00:00
2019-05-18 07:45:15 +00:00
final comments = List<Widget>.generate(
widget.post.comments.length,
2019-05-16 12:52:22 +00:00
(num) => CommentTile(
2019-05-18 07:45:15 +00:00
comment: widget.post.comments[num],
user: widget.usersInfo.getUser(widget.post.comments[num].userID),
2019-05-18 13:54:10 +00:00
onUpdateLike: _updateCommentLike,
2019-05-16 12:52:22 +00:00
),
);
2019-05-18 07:45:15 +00:00
// Add comments form
comments.add(_buildCommentsForm());
2019-05-16 12:52:22 +00:00
return Container(
color: Colors.grey[300],
child: Padding(
padding: const EdgeInsets.only(top: 8.0, bottom: 8.0),
child: Column(
children: comments,
),
),
);
}
2019-05-18 07:45:15 +00:00
/// Build comments form
Widget _buildCommentsForm() {
return Padding(
padding: EdgeInsets.only(
left: 8.0,
right: 8.0,
top: (widget.post.comments.length > 0 ? 8.0 : 0)),
child: Row(
children: <Widget>[
// Comment input
Expanded(
child: TextField(
2019-05-18 12:58:35 +00:00
controller: _commentController,
2019-05-18 07:45:15 +00:00
onChanged: (s) => setState(() {}),
2019-05-18 12:58:35 +00:00
onSubmitted: _canSubmitComment ? (s) => _submitComment() : null,
2019-05-18 07:45:15 +00:00
decoration: InputDecoration(
hintText: tr("New comment..."),
hintStyle: TextStyle(color: Colors.grey, fontSize: 12),
fillColor: Colors.white,
filled: true,
border: OutlineInputBorder(
borderSide: BorderSide(width: 0.5, color: Colors.grey),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(3),
bottomLeft: Radius.circular(3),
),
gapPadding: 1),
contentPadding: EdgeInsets.only(
left: 10,
right: 10,
bottom: 5,
top: 5,
)),
),
),
// Image button
Container(
width: 30,
child: FlatButton(
padding: EdgeInsets.only(),
onPressed: _pickImageForComment,
2019-05-18 07:45:15 +00:00
child: Icon(
Icons.image,
color: _hasImage ? Colors.blue : Colors.grey,
),
),
),
// Submit button
Container(
width: 40,
child: FlatButton(
padding: EdgeInsets.only(),
2019-05-18 12:58:35 +00:00
onPressed: _canSubmitComment ? () => _submitComment() : null,
2019-05-18 07:45:15 +00:00
child: Icon(
Icons.send,
2019-05-18 12:58:35 +00:00
color: _canSubmitComment ? Colors.blue : Colors.grey,
2019-05-18 07:45:15 +00:00
),
),
),
],
),
);
}
2019-05-18 12:58:35 +00:00
/// Clear comments submitting form
void clearCommentForm() {
setState(() {
_commentController.text = "";
_commentImage = null;
});
}
2019-05-18 07:45:15 +00:00
/// Pick an image
Future<void> _pickImageForComment() async {
2019-05-18 07:45:15 +00:00
// Ask the user to confirm image removal if there is already one selected
if (_hasImage) {
if (await askUserConfirmation(
context: context,
title: tr("Remove selected image"),
message: tr("Do you want to unselected currently selected image ?"),
)) {
setState(() {
_commentImage = null;
});
}
return;
}
// Pick a new image
final newImage = await pickImage(context);
setState(() {
_commentImage = newImage;
});
}
/// Submit comment entered by the user
2019-05-18 12:58:35 +00:00
Future<void> _submitComment() async {
_sendingComment = true;
2019-05-18 13:05:26 +00:00
final commentID = await _commentsHelper.createComment(NewComment(
2019-05-18 12:58:35 +00:00
postID: widget.post.id,
content: _commentController.text,
image: _commentImage,
));
_sendingComment = false;
if (commentID < 1)
return showSimpleSnack(context, tr("Could not create comment!"));
clearCommentForm();
// Get and show new comment
2019-05-18 13:05:26 +00:00
final newComment = await _commentsHelper.getSingle(commentID);
if (newComment == null)
return showSimpleSnack(
context, tr("Could not retrieve created comment!"));
setState(() {
widget.post.comments.add(newComment);
});
2019-05-18 12:58:35 +00:00
}
/// Update like status
Future<void> _updateLike() async {
// Update liking status
_likesHelper.setLiking(
type: LikesType.POST,
like: !widget.post.userLikes,
id: widget.post.id,
);
// Save new like status
setState(() {
widget.post.userLikes = !widget.post.userLikes;
widget.post.userLikes ? widget.post.likes++ : widget.post.likes--;
});
}
2019-05-18 13:54:10 +00:00
/// Invert comment like status
Future<void> _updateCommentLike(Comment comment) async {
// Update liking status
_likesHelper.setLiking(
type: LikesType.COMMENT,
like: !comment.userLike,
id: comment.id,
);
// Save new like status
setState(() {
comment.userLike = !comment.userLike;
comment.userLike ? comment.likes++ : comment.likes--;
});
}
2019-05-10 17:15:11 +00:00
}