git-touch-android-ios-app/lib/widgets/comment_item.dart

194 lines
5.5 KiB
Dart
Raw Normal View History

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
2020-01-30 10:20:36 +01:00
import 'package:git_touch/models/auth.dart';
import 'package:git_touch/models/theme.dart';
2020-02-08 06:02:12 +01:00
import 'package:git_touch/widgets/action_button.dart';
import 'package:git_touch/widgets/markdown_view.dart';
import 'package:provider/provider.dart';
2019-08-31 14:44:59 +02:00
import 'package:timeago/timeago.dart' as timeago;
2019-05-12 09:14:28 +02:00
import 'package:primer/primer.dart';
2019-01-31 07:37:25 +01:00
import '../utils/utils.dart';
2019-02-07 07:35:19 +01:00
import 'avatar.dart';
2019-04-05 15:19:00 +02:00
import 'link.dart';
2019-02-07 07:35:19 +01:00
import 'user_name.dart';
final emojiMap = {
'THUMBS_UP': '👍',
'THUMBS_DOWN': '👎',
'LAUGH': '😄',
'HOORAY': '🎉',
'CONFUSED': '😕',
'HEART': '❤️',
'ROCKET': '🚀',
'EYES': '👀'
};
2020-01-30 10:20:36 +01:00
class GhEmojiAction extends StatefulWidget {
final Map<String, dynamic> payload;
2020-01-30 10:20:36 +01:00
GhEmojiAction(this.payload);
@override
_GhEmojiActionState createState() => _GhEmojiActionState();
}
2020-01-30 10:20:36 +01:00
class _GhEmojiActionState extends State<GhEmojiAction> {
get payload => widget.payload;
2020-02-08 06:02:12 +01:00
onReaction(String emojiKey) async {
2020-01-30 10:20:36 +01:00
if (emojiKey == null) return;
2020-02-08 06:02:12 +01:00
final isRemove = _hasReacted(emojiKey);
2020-01-30 10:20:36 +01:00
var id = payload['id'] as String;
var operation = isRemove ? 'remove' : 'add';
try {
await Provider.of<AuthModel>(context).query('''
2020-01-30 10:20:36 +01:00
mutation {
${operation}Reaction(input: {subjectId: "$id", content: $emojiKey}) {
clientMutationId
}
}
''');
setState(() {
payload[emojiKey]['totalCount'] += isRemove ? -1 : 1;
payload[emojiKey]['viewerHasReacted'] = !isRemove;
});
} catch (e) {
final theme = Provider.of<ThemeModel>(context);
theme.showWarning(context, e);
}
2020-01-30 10:20:36 +01:00
}
2019-04-05 15:19:00 +02:00
bool _hasReacted(String emojiKey) {
if (payload[emojiKey] == null) return false;
return payload[emojiKey]['viewerHasReacted'] as bool;
}
2020-01-30 10:20:36 +01:00
@override
Widget build(BuildContext context) {
final theme = Provider.of<ThemeModel>(context);
return Wrap(
crossAxisAlignment: WrapCrossAlignment.center,
children: [
...emojiMap.entries
.where((entry) => payload[entry.key]['totalCount'] as int != 0)
.map<Widget>((entry) {
var emojiKey = entry.key;
var emoji = entry.value;
var count = payload[entry.key]['totalCount'] as int;
return Link(
onTap: () {
2020-02-08 06:02:12 +01:00
onReaction(emojiKey);
2020-01-30 10:20:36 +01:00
},
child: Container(
padding: EdgeInsets.all(4),
2020-02-08 06:09:53 +01:00
decoration: BoxDecoration(
color: _hasReacted(emojiKey)
? (theme.brightness == Brightness.dark
? PrimerColors.blue900
: PrimerColors.blue000)
: Colors.transparent,
),
2020-01-30 10:20:36 +01:00
child: Wrap(
crossAxisAlignment: WrapCrossAlignment.center,
children: <Widget>[
Text(emoji, style: TextStyle(fontSize: 18)),
SizedBox(width: 4),
Text(numberFormat.format(count),
style:
TextStyle(color: theme.palette.primary, fontSize: 14))
],
),
),
);
}),
Link(
onTap: () async {
2020-02-08 06:02:12 +01:00
await theme.showActions(
2020-01-30 10:20:36 +01:00
context,
emojiMap.entries.map((entry) {
2020-02-08 06:02:12 +01:00
final emojiKey = entry.key;
return ActionItem(
text: emojiKey + ' ' + entry.value,
onTap: (_) {
onReaction(emojiKey);
},
2020-01-30 10:20:36 +01:00
);
}).toList(),
);
},
child: Container(
padding: EdgeInsets.all(4),
child: Wrap(
crossAxisAlignment: WrapCrossAlignment.center,
children: <Widget>[
Text('+', style: TextStyle(color: theme.palette.primary)),
Icon(Octicons.smiley, color: theme.palette.primary, size: 18),
],
),
),
),
],
);
2019-04-05 15:19:00 +02:00
}
2020-01-30 10:20:36 +01:00
}
class CommentItem extends StatelessWidget {
final Avatar avatar;
final String login;
final DateTime createdAt;
final String body;
final List<Widget> widgets;
CommentItem.gh(Map<String, dynamic> payload)
: avatar = Avatar(
url: payload['author']['avatarUrl'], // TODO: deleted user
linkUrl: '/' + payload['author']['login'],
),
login = payload['author']['login'],
createdAt = DateTime.parse(payload['createdAt']),
body = payload['body'],
widgets = [GhEmojiAction(payload)];
CommentItem({
@required this.avatar,
@required this.login,
@required this.createdAt,
@required this.body,
this.widgets,
});
@override
Widget build(BuildContext context) {
2019-11-08 11:29:08 +01:00
final theme = Provider.of<ThemeModel>(context);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(children: <Widget>[
2020-01-30 10:20:36 +01:00
avatar,
2019-09-07 11:48:59 +02:00
SizedBox(width: 8),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
2020-01-30 10:20:36 +01:00
UserName(login),
2019-09-07 11:48:59 +02:00
SizedBox(height: 2),
Text(
2020-01-30 10:20:36 +01:00
timeago.format(createdAt),
2019-11-08 11:29:08 +01:00
style: TextStyle(
2020-01-27 08:11:51 +01:00
color: theme.palette.tertiaryText, fontSize: 13),
),
],
),
),
]),
2019-09-07 11:48:59 +02:00
SizedBox(height: 12),
2020-01-30 10:20:36 +01:00
MarkdownView(body), // TODO: link
2019-09-07 11:48:59 +02:00
SizedBox(height: 12),
2020-01-30 10:20:36 +01:00
if (widgets != null)
...widgets
],
);
}
}