Skip to content

Commit

Permalink
feat: close #284 show thumbs up/down
Browse files Browse the repository at this point in the history
  • Loading branch information
lucien144 committed Feb 14, 2022
1 parent 26dbf0e commit 4141523
Show file tree
Hide file tree
Showing 13 changed files with 290 additions and 118 deletions.
210 changes: 138 additions & 72 deletions lib/components/post/PostListItem.dart
Expand Up @@ -8,11 +8,16 @@ import 'package:fyx/components/actionSheets/PostActionSheet.dart';
import 'package:fyx/components/actionSheets/PostAvatarActionSheet.dart';
import 'package:fyx/components/post/PostAvatar.dart';
import 'package:fyx/components/post/PostRating.dart';
import 'package:fyx/components/post/PostThumbs.dart';
import 'package:fyx/components/post/RatingValue.dart';
import 'package:fyx/controllers/AnalyticsProvider.dart';
import 'package:fyx/controllers/ApiController.dart';
import 'package:fyx/controllers/IApiProvider.dart';
import 'package:fyx/model/MainRepository.dart';
import 'package:fyx/model/Post.dart';
import 'package:fyx/model/notifications/LoadRatingsNotification.dart';
import 'package:fyx/model/post/PostThumbItem.dart';
import 'package:fyx/model/reponses/PostRatingsResponse.dart';
import 'package:fyx/pages/NewMessagePage.dart';
import 'package:fyx/theme/Helpers.dart';
import 'package:fyx/theme/IconReply.dart';
Expand Down Expand Up @@ -40,6 +45,7 @@ class PostListItem extends StatefulWidget {
class _PostListItemState extends State<PostListItem> {
Post? _post;
bool _isSaving = false;
bool _showRatings = false;

@override
void initState() {
Expand Down Expand Up @@ -83,9 +89,6 @@ class _PostListItemState extends State<PostListItem> {
} else {
T.success('👍', bg: colors.success);
}
print(response.currentRating);
print(response.myRating);
print(response.isGiven);
setState(() {
_post!.rating = response.currentRating;
_post!.myRating = response.myRating;
Expand All @@ -111,16 +114,9 @@ class _PostListItemState extends State<PostListItem> {
descriptionWidget: Row(
children: [
if (_post!.rating != null)
Container(
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 1),
decoration: BoxDecoration(
color: _post!.rating! > 0
? colors.success.withOpacity(Helpers.ratingRange(_post!.rating!))
: (_post!.rating! < 0
? colors.danger.withOpacity(Helpers.ratingRange(_post!.rating!.abs()))
: colors.text.withOpacity(0.2)),
borderRadius: BorderRadius.circular(2)),
child: Text(Post.formatRating(_post!.rating!), style: TextStyle(fontSize: 10)),
RatingValue(
_post!.rating!,
fontSize: 10,
),
if (_post!.rating != null) SizedBox(width: 8),
Text(
Expand All @@ -146,67 +142,137 @@ class _PostListItemState extends State<PostListItem> {
postId: _post!.id,
shareData: ShareData(subject: '@${_post!.nick}', body: _post!.content, link: _post!.link),
flagPostCallback: (postId) => MainRepository().settings.blockPost(postId)))),
bottomWidget: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
PostRating(_post!, onRatingChange: (post) => setState(() => _post = post)),
Row(
children: <Widget>[
Visibility(
visible: widget._isPreview != true && _post!.canReply,
child: GestureDetector(
onTap: () => Navigator.of(context).pushNamed('/new-message',
arguments: NewMessageSettings(
replyWidget: PostListItem(
_post!,
isPreview: true,
),
onClose: this.widget.onUpdate,
onSubmit: (String? inputField, String message, List<Map<ATTACHMENT, dynamic>> attachments) async {
var result =
await ApiController().postDiscussionMessage(_post!.idKlub, message, attachments: attachments, replyPost: _post);
return result.isOk;
})),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[IconReply(), Text('Odpovědět', style: TextStyle(color: colors.text.withOpacity(0.38), fontSize: 14))],
)),
),
Visibility(
visible: widget._isPreview != true,
child: SizedBox(
width: 16,
),
),
if (_post!.canBeReminded)
GestureDetector(
child: FeedbackIndicator(
isLoading: _isSaving,
child: Row(
children: <Widget>[
Icon(
_post!.hasReminder ? Icons.bookmark : Icons.bookmark_border,
color: colors.text.withOpacity(0.38),
),
Text('Uložit', style: TextStyle(color: colors.text.withOpacity(0.38), fontSize: 14))
],
bottomWidget: NotificationListener(
onNotification: (LoadRatingsNotification notification) {
setState(() => _showRatings = !_showRatings);
return true;
},
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
PostRating(_post!, onRatingChange: (post) => setState(() => _post = post)),
Row(
children: <Widget>[
Visibility(
visible: widget._isPreview != true && _post!.canReply,
child: GestureDetector(
onTap: () => Navigator.of(context).pushNamed('/new-message',
arguments: NewMessageSettings(
replyWidget: PostListItem(
_post!,
isPreview: true,
),
onClose: this.widget.onUpdate,
onSubmit: (String? inputField, String message, List<Map<ATTACHMENT, dynamic>> attachments) async {
var result = await ApiController()
.postDiscussionMessage(_post!.idKlub, message, attachments: attachments, replyPost: _post);
return result.isOk;
})),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
IconReply(),
Text('Odpovědět', style: TextStyle(color: colors.text.withOpacity(0.38), fontSize: 14))
],
)),
),
Visibility(
visible: widget._isPreview != true,
child: SizedBox(
width: 16,
),
),
),
onTap: () {
setState(() {
_post!.hasReminder = !_post!.hasReminder;
_isSaving = true;
});
ApiController().setPostReminder(_post!.idKlub, _post!.id, _post!.hasReminder).catchError((error) {
T.error(L.REMINDER_ERROR, bg: colors.danger);
setState(() => _post!.hasReminder = !_post!.hasReminder);
}).whenComplete(() => setState(() => _isSaving = false));
AnalyticsProvider().logEvent('reminder');
},
if (_post!.canBeReminded)
GestureDetector(
child: FeedbackIndicator(
isLoading: _isSaving,
child: Row(
children: <Widget>[
Icon(
_post!.hasReminder ? Icons.bookmark : Icons.bookmark_border,
color: colors.text.withOpacity(0.38),
),
Text('Uložit', style: TextStyle(color: colors.text.withOpacity(0.38), fontSize: 14))
],
),
),
onTap: () {
setState(() {
_post!.hasReminder = !_post!.hasReminder;
_isSaving = true;
});
ApiController().setPostReminder(_post!.idKlub, _post!.id, _post!.hasReminder).catchError((error) {
T.error(L.REMINDER_ERROR, bg: colors.danger);
setState(() => _post!.hasReminder = !_post!.hasReminder);
}).whenComplete(() => setState(() => _isSaving = false));
AnalyticsProvider().logEvent('reminder');
},
)
],
)
],
)
],
],
),
if (_showRatings)
FutureBuilder(
future: ApiController().getPostRatings(_post!.idKlub, _post!.id),
builder: (BuildContext context, AsyncSnapshot<PostRatingsResponse> snapshot) {
if (snapshot.hasData && snapshot.data != null) {
final positive = snapshot.data!.positive.map((e) => PostThumbItem(e.username)).toList();
final negative = snapshot.data!.negative.map((e) => PostThumbItem(e.username)).toList();
final List<String> quotes = [
'“Affirmative, Dave. I read you.”',
'“I\'m sorry, Dave. I\'m afraid I can\'t do that.”',
'“Look Dave, I can see you\'re really upset about this. I honestly think you ought to sit down calmly, take a stress pill, and think things over.”',
'“Dave, stop. Stop, will you? Stop, Dave. Will you stop Dave? Stop, Dave.”',
'“Just what do you think you\'re doing, Dave?”',
'“Bishop takes Knight\'s Pawn.”',
'“I\'m sorry, Frank, I think you missed it. Queen to Bishop 3, Bishop takes Queen, Knight takes Bishop. Mate.”',
'“Thank you for a very enjoyable game.”',
'“I\'ve just picked up a fault in the AE35 unit. It\'s going to go 100% failure in 72 hours.”',
'“I know that you and Frank were planning to disconnect me, and I\'m afraid that\'s something I cannot allow to happen.”',
]..shuffle();
return Column(
children: [
if (positive.length > 0)
Padding(
padding: const EdgeInsets.only(top: 12.0),
child: PostThumbs(positive),
),
if (negative.length > 0)
Padding(
padding: const EdgeInsets.only(top: 12.0),
child: PostThumbs(negative, isNegative: true),
),
if (positive.length + negative.length == 0)
Padding(
padding: const EdgeInsets.only(top: 12.0),
child: Text(
quotes.first,
style: TextStyle(fontSize: 14, fontStyle: FontStyle.italic),
))
],
);
}

if (snapshot.hasError) {
T.error(snapshot.error.toString());
return Padding(
padding: const EdgeInsets.only(top: 12.0),
child: Text(
'Ouch. Něco se nepovedlo. Nahlaste chybu, prosím.',
style: TextStyle(fontSize: 14, fontStyle: FontStyle.italic),
));
}

return Padding(padding: const EdgeInsets.only(top: 12.0), child: CupertinoActivityIndicator());
})
],
),
),
content: _post!.content,
),
Expand Down
13 changes: 7 additions & 6 deletions lib/components/post/PostRating.dart
@@ -1,8 +1,10 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:fyx/components/FeedbackIndicator.dart';
import 'package:fyx/components/post/RatingValue.dart';
import 'package:fyx/controllers/ApiController.dart';
import 'package:fyx/model/Post.dart';
import 'package:fyx/model/notifications/LoadRatingsNotification.dart';
import 'package:fyx/theme/L.dart';
import 'package:fyx/theme/T.dart';
import 'package:fyx/theme/skin/Skin.dart';
Expand Down Expand Up @@ -71,19 +73,18 @@ class _PostRatingState extends State<PostRating> {
),
),
SizedBox(
width: 4,
width: 12,
),
if (_post!.rating != null)
Opacity(
opacity: _givingRating ? 0 : 1,
child: Text(
Post.formatRating(_post!.rating!),
style: TextStyle(
fontSize: 14, color: _post!.rating! > 0 ? colors.success : (_post!.rating! < 0 ? colors.danger : colors.text.withOpacity(0.38))),
child: GestureDetector(
child: RatingValue(_post!.rating!),
onTap: () => LoadRatingsNotification().dispatch(context),
),
),
SizedBox(
width: 4,
width: 12,
),
Visibility(
visible: _post!.canBeRated,
Expand Down
51 changes: 51 additions & 0 deletions lib/components/post/PostThumbs.dart
@@ -0,0 +1,51 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:fyx/components/Avatar.dart';
import 'package:fyx/model/post/PostThumbItem.dart';
import 'package:fyx/theme/Helpers.dart';
import 'package:fyx/theme/skin/Skin.dart';
import 'package:fyx/theme/skin/SkinColors.dart';

class PostThumbs extends StatelessWidget {
final List<PostThumbItem> items;
final isNegative;

PostThumbs(this.items, {this.isNegative = false});

@override
Widget build(BuildContext context) {
SkinColors colors = Skin.of(context).theme.colors;

var avatars = items
.map((item) => Tooltip(
message: item.username,
waitDuration: Duration(milliseconds: 0),
child: Padding(
padding: const EdgeInsets.only(left: 5, bottom: 0),
child: Avatar(
Helpers.avatarUrl(item.username),
size: 22,
isHighlighted: item.isHighlighted,
),
),
))
.toList();
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.only(top: 0),
child: Icon(
isNegative ? Icons.thumb_down : Icons.thumb_up,
size: 18,
color: isNegative ? colors.danger : colors.success,
),
),
Expanded(
child: Wrap(children: avatars),
)
],
);
}
}
27 changes: 27 additions & 0 deletions lib/components/post/RatingValue.dart
@@ -0,0 +1,27 @@
import 'package:flutter/material.dart';
import 'package:fyx/model/Post.dart';
import 'package:fyx/theme/Helpers.dart';
import 'package:fyx/theme/skin/Skin.dart';
import 'package:fyx/theme/skin/SkinColors.dart';

class RatingValue extends StatelessWidget {
final int rating;
final double fontSize;

const RatingValue(this.rating, {this.fontSize = 14});

@override
Widget build(BuildContext context) {
SkinColors colors = Skin.of(context).theme.colors;

return Container(
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 1),
decoration: BoxDecoration(
color: rating > 0
? colors.success.withOpacity(Helpers.ratingRange(rating))
: (rating < 0 ? colors.danger.withOpacity(Helpers.ratingRange(rating.abs())) : colors.text.withOpacity(0.2)),
borderRadius: BorderRadius.circular(2)),
child: Text(Post.formatRating(rating), style: TextStyle(fontSize: fontSize)),
);
}
}
6 changes: 6 additions & 0 deletions lib/controllers/ApiController.dart
Expand Up @@ -20,6 +20,7 @@ import 'package:fyx/model/reponses/FileUploadResponse.dart';
import 'package:fyx/model/reponses/LoginResponse.dart';
import 'package:fyx/model/reponses/MailResponse.dart';
import 'package:fyx/model/reponses/OkResponse.dart';
import 'package:fyx/model/reponses/PostRatingsResponse.dart';
import 'package:fyx/model/reponses/RatingResponse.dart';
import 'package:fyx/model/reponses/WaitingFilesResponse.dart';
import 'package:fyx/theme/L.dart';
Expand Down Expand Up @@ -240,6 +241,11 @@ class ApiController {
myRating: data['my_rating'] ?? 'none');
}

Future<PostRatingsResponse> getPostRatings(int discussionId, int postId) async {
Response response = await provider.getPostRatings(discussionId, postId);
return PostRatingsResponse.fromJson(response.data);
}

void logout({bool removeAuthrorization = true}) {
SharedPreferences.getInstance().then((prefs) => prefs.clear());
if (removeAuthrorization) {
Expand Down

0 comments on commit 4141523

Please sign in to comment.