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

251 lines
7.5 KiB
Dart
Raw Normal View History

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
2021-01-17 15:08:32 +01:00
import 'package:git_touch/graphql/github.data.gql.dart';
2021-01-31 12:27:45 +01:00
import 'package:git_touch/graphql/schema.schema.gql.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';
2021-01-31 12:27:45 +01:00
class EmojiPayload {
GReactionContent key;
String text;
int count;
bool reacted;
EmojiPayload({
2021-05-16 09:16:35 +02:00
required this.key,
required this.text,
required this.count,
required this.reacted,
2021-01-31 12:27:45 +01:00
});
}
typedef EmojiUpdateCallaback = void Function(GReactionContent data);
2020-01-30 10:20:36 +01:00
class GhEmojiAction extends StatefulWidget {
2021-05-16 09:16:35 +02:00
final String? id;
2021-01-31 12:27:45 +01:00
final Iterable<EmojiPayload> items;
final EmojiUpdateCallaback onReaction;
GhEmojiAction(this.id, GReactableParts r, this.onReaction)
: items = [
EmojiPayload(
key: GReactionContent.THUMBS_UP,
text: '👍',
count: r.THUMBS_UP.totalCount,
reacted: r.THUMBS_UP.viewerHasReacted,
),
EmojiPayload(
key: GReactionContent.THUMBS_DOWN,
text: '👎',
count: r.THUMBS_DOWN.totalCount,
reacted: r.THUMBS_DOWN.viewerHasReacted,
),
EmojiPayload(
key: GReactionContent.LAUGH,
text: '😄',
count: r.LAUGH.totalCount,
reacted: r.LAUGH.viewerHasReacted,
),
EmojiPayload(
key: GReactionContent.HOORAY,
text: '🎉',
count: r.HOORAY.totalCount,
reacted: r.HOORAY.viewerHasReacted,
),
EmojiPayload(
key: GReactionContent.CONFUSED,
text: '😕',
count: r.CONFUSED.totalCount,
reacted: r.CONFUSED.viewerHasReacted,
),
EmojiPayload(
key: GReactionContent.HEART,
text: '❤️',
count: r.HEART.totalCount,
reacted: r.HEART.viewerHasReacted,
),
EmojiPayload(
key: GReactionContent.ROCKET,
text: '🚀',
count: r.ROCKET.totalCount,
reacted: r.ROCKET.viewerHasReacted,
),
EmojiPayload(
key: GReactionContent.EYES,
text: '👀',
count: r.EYES.totalCount,
reacted: r.EYES.viewerHasReacted,
),
];
2020-01-30 10:20:36 +01:00
@override
_GhEmojiActionState createState() => _GhEmojiActionState();
}
2020-01-30 10:20:36 +01:00
class _GhEmojiActionState extends State<GhEmojiAction> {
2021-01-31 12:27:45 +01:00
_onReaction(EmojiPayload item) async {
final op = item.reacted ? 'remove' : 'add';
2021-01-31 12:27:45 +01:00
await context.read<AuthModel>().query('''
2020-01-30 10:20:36 +01:00
mutation {
2021-01-31 12:27:45 +01:00
${op}Reaction(input: {subjectId: "${widget.id}", content: ${item.key.name}}) {
2020-01-30 10:20:36 +01:00
clientMutationId
}
}
''');
2021-01-31 12:27:45 +01:00
setState(() {
item.reacted = !item.reacted;
if (item.reacted) {
item.count++;
} else {
item.count--;
}
});
// TODO: should set state from parent widgets
// widget.onReaction(item.key);
2019-04-05 15:19:00 +02:00
}
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: [
2021-01-31 12:27:45 +01:00
for (final item in widget.items)
if (item.count > 0)
2021-05-16 09:16:35 +02:00
LinkWidget(
2021-01-31 12:27:45 +01:00
onTap: () {
_onReaction(item);
},
child: Container(
padding: EdgeInsets.all(4),
decoration: BoxDecoration(
color: item.reacted
? (theme.brightness == Brightness.dark
? PrimerColors.blue900
: PrimerColors.blue000)
: Colors.transparent,
),
child: Wrap(
crossAxisAlignment: WrapCrossAlignment.center,
children: <Widget>[
Text(item.text, style: TextStyle(fontSize: 18)),
SizedBox(width: 4),
Text(numberFormat.format(item.count),
style: TextStyle(
color: theme.palette.primary, fontSize: 14))
],
),
2020-01-30 10:20:36 +01:00
),
),
2021-05-16 09:16:35 +02:00
LinkWidget(
2020-01-30 10:20:36 +01:00
onTap: () async {
2021-01-31 12:27:45 +01:00
await theme.showActions(context, [
for (final item in widget.items)
ActionItem(
text: item.text,
2020-02-08 06:02:12 +01:00
onTap: (_) {
2021-01-31 12:27:45 +01:00
_onReaction(item);
2020-02-08 06:02:12 +01:00
},
2021-01-31 12:27:45 +01:00
)
]);
2020-01-30 10:20:36 +01:00
},
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;
2021-05-16 09:16:35 +02:00
final String? login;
final DateTime? createdAt;
final String? body;
final String prefix;
2021-05-16 09:16:35 +02:00
final List<Widget>? widgets;
final List<ActionItem>? commentActionItemList;
2020-01-30 10:20:36 +01:00
// p.author could be null (deleted user)
2021-01-31 12:27:45 +01:00
CommentItem.gql(
GCommentParts p, GReactableParts r, EmojiUpdateCallaback onReaction)
2021-01-17 15:08:32 +01:00
: avatar = Avatar(
url: p.author?.avatarUrl ??
'https://avatars.githubusercontent.com/u/10137?s=460&u=b1951d34a583cf12ec0d3b0781ba19be97726318&v=4',
linkUrl: '/github/' + (p.author?.login ?? 'ghost'),
2021-01-17 15:08:32 +01:00
),
login = p.author?.login ?? 'ghost',
2021-01-17 15:08:32 +01:00
createdAt = p.createdAt,
body = p.body,
2021-01-31 12:27:45 +01:00
widgets = [GhEmojiAction(p.id, r, onReaction)],
2021-01-17 15:08:32 +01:00
prefix = 'github',
commentActionItemList = []; // TODO
2020-01-30 10:20:36 +01:00
CommentItem({
2021-05-16 09:16:35 +02:00
required this.avatar,
required this.login,
required this.createdAt,
required this.body,
required this.prefix,
2020-01-30 10:20:36 +01:00
this.widgets,
this.commentActionItemList,
2020-01-30 10:20:36 +01:00
});
@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>[
UserName(login, prefix),
2019-09-07 11:48:59 +02:00
SizedBox(height: 2),
Text(
2021-05-16 09:16:35 +02: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),
),
],
),
),
Align(
alignment: Alignment.centerRight,
child: ActionButton(
iconData: Octicons.kebab_horizontal,
title: 'Comment Actions',
items: [
2021-05-16 09:16:35 +02:00
if (commentActionItemList != null) ...commentActionItemList!
],
)),
]),
2019-09-07 11:48:59 +02:00
SizedBox(height: 12),
2020-11-08 08:00:13 +01:00
MarkdownFlutterView(body, padding: EdgeInsets.zero), // TODO: link
2019-09-07 11:48:59 +02:00
SizedBox(height: 12),
2021-05-16 09:16:35 +02:00
if (widgets != null) ...widgets!
],
);
}
}