mirror of
https://github.com/git-touch/git-touch
synced 2024-12-18 11:19:28 +01:00
refactor: emoji reactions
This commit is contained in:
parent
e2e0f6ba25
commit
b032ab3d8a
@ -353,26 +353,6 @@ fragment ReactableParts on Reactable {
|
||||
return status;
|
||||
}
|
||||
|
||||
_handleReaction(payload) {
|
||||
return (String emojiKey, bool isRemove) async {
|
||||
if (emojiKey == null) return;
|
||||
|
||||
var id = payload['id'] as String;
|
||||
var operation = isRemove ? 'remove' : 'add';
|
||||
await Provider.of<AuthModel>(context).query('''
|
||||
mutation {
|
||||
${operation}Reaction(input: {subjectId: "$id", content: $emojiKey}) {
|
||||
clientMutationId
|
||||
}
|
||||
}
|
||||
''');
|
||||
setState(() {
|
||||
payload[emojiKey]['totalCount'] += isRemove ? -1 : 1;
|
||||
payload[emojiKey]['viewerHasReacted'] = !isRemove;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final auth = Provider.of<AuthModel>(context);
|
||||
@ -497,10 +477,7 @@ mutation {
|
||||
CommonStyle.border,
|
||||
],
|
||||
SizedBox(height: 8),
|
||||
CommentItem(
|
||||
p,
|
||||
onReaction: _handleReaction(p),
|
||||
),
|
||||
CommentItem.gh(p),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -508,8 +485,7 @@ mutation {
|
||||
],
|
||||
);
|
||||
},
|
||||
itemBuilder: (itemPayload) =>
|
||||
TimelineItem(itemPayload, onReaction: _handleReaction(itemPayload)),
|
||||
itemBuilder: (itemPayload) => TimelineItem(itemPayload),
|
||||
onRefresh: () async {
|
||||
var res = await _queryIssue();
|
||||
int totalCount = res['timelineItems']['totalCount'];
|
||||
|
@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:git_touch/models/auth.dart';
|
||||
import 'package:git_touch/models/theme.dart';
|
||||
import 'package:git_touch/widgets/markdown_view.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
@ -20,44 +21,153 @@ final emojiMap = {
|
||||
'EYES': '👀'
|
||||
};
|
||||
|
||||
class CommentItem extends StatelessWidget {
|
||||
class GhEmojiAction extends StatefulWidget {
|
||||
final Map<String, dynamic> payload;
|
||||
final Function(String emojiKey, bool isRemove) onReaction;
|
||||
GhEmojiAction(this.payload);
|
||||
@override
|
||||
_GhEmojiActionState createState() => _GhEmojiActionState();
|
||||
}
|
||||
|
||||
CommentItem(this.payload, {@required this.onReaction});
|
||||
class _GhEmojiActionState extends State<GhEmojiAction> {
|
||||
Decoration _getDecorationByKey(String emojiKey) {
|
||||
return BoxDecoration(
|
||||
color: _hasReacted(emojiKey) ? PrimerColors.blue000 : Colors.transparent,
|
||||
);
|
||||
}
|
||||
|
||||
get payload => widget.payload;
|
||||
|
||||
onReaction(String emojiKey, bool isRemove) async {
|
||||
if (emojiKey == null) return;
|
||||
|
||||
var id = payload['id'] as String;
|
||||
var operation = isRemove ? 'remove' : 'add';
|
||||
await Provider.of<AuthModel>(context).query('''
|
||||
mutation {
|
||||
${operation}Reaction(input: {subjectId: "$id", content: $emojiKey}) {
|
||||
clientMutationId
|
||||
}
|
||||
}
|
||||
''');
|
||||
setState(() {
|
||||
payload[emojiKey]['totalCount'] += isRemove ? -1 : 1;
|
||||
payload[emojiKey]['viewerHasReacted'] = !isRemove;
|
||||
});
|
||||
}
|
||||
|
||||
bool _hasReacted(String emojiKey) {
|
||||
if (payload[emojiKey] == null) return false;
|
||||
return payload[emojiKey]['viewerHasReacted'] as bool;
|
||||
}
|
||||
|
||||
Decoration _getDecorationByKey(String emojiKey) {
|
||||
return BoxDecoration(
|
||||
color:
|
||||
_hasReacted(emojiKey) ? PrimerColors.blue000 : Colors.transparent);
|
||||
@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: () {
|
||||
onReaction(emojiKey, _hasReacted(emojiKey));
|
||||
},
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(4),
|
||||
decoration: _getDecorationByKey(emojiKey),
|
||||
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 {
|
||||
final result = await theme.showDialogOptions(
|
||||
context,
|
||||
emojiMap.entries.map((entry) {
|
||||
var emojiKey = entry.key;
|
||||
return DialogOption(
|
||||
value: emojiKey,
|
||||
widget: Container(
|
||||
decoration: _getDecorationByKey(emojiKey),
|
||||
child: Text(emojiKey + ' ' + entry.value),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
);
|
||||
onReaction(result, _hasReacted(result));
|
||||
},
|
||||
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),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
final theme = Provider.of<ThemeModel>(context);
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Row(children: <Widget>[
|
||||
Avatar(
|
||||
url: payload['author']['avatarUrl'],
|
||||
linkUrl: '/' + payload['author']['login'],
|
||||
),
|
||||
avatar,
|
||||
SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
UserName(payload['author']['login']),
|
||||
UserName(login),
|
||||
SizedBox(height: 2),
|
||||
Text(
|
||||
timeago.format(DateTime.parse(payload['createdAt'])),
|
||||
timeago.format(createdAt),
|
||||
style: TextStyle(
|
||||
color: theme.palette.tertiaryText, fontSize: 13),
|
||||
),
|
||||
@ -66,69 +176,10 @@ class CommentItem extends StatelessWidget {
|
||||
),
|
||||
]),
|
||||
SizedBox(height: 12),
|
||||
MarkdownView(payload['body'] as String), // TODO: link
|
||||
MarkdownView(body), // TODO: link
|
||||
SizedBox(height: 12),
|
||||
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: () {
|
||||
onReaction(emojiKey, _hasReacted(emojiKey));
|
||||
},
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(4),
|
||||
decoration: _getDecorationByKey(emojiKey),
|
||||
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 {
|
||||
var result =
|
||||
await Provider.of<ThemeModel>(context).showDialogOptions(
|
||||
context,
|
||||
emojiMap.entries.map((entry) {
|
||||
var emojiKey = entry.key;
|
||||
return DialogOption(
|
||||
value: emojiKey,
|
||||
widget: Container(
|
||||
decoration: _getDecorationByKey(emojiKey),
|
||||
child: Text(emojiKey + ' ' + entry.value),
|
||||
),
|
||||
);
|
||||
}).toList());
|
||||
onReaction(result, _hasReacted(result));
|
||||
},
|
||||
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),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (widgets != null)
|
||||
...widgets
|
||||
],
|
||||
);
|
||||
}
|
||||
|
@ -51,9 +51,7 @@ class TimelineEventItem extends StatelessWidget {
|
||||
|
||||
class TimelineItem extends StatelessWidget {
|
||||
final Map<String, dynamic> p;
|
||||
final Function(String emojiKey, bool isRemove) onReaction;
|
||||
|
||||
TimelineItem(this.p, {@required this.onReaction});
|
||||
TimelineItem(this.p);
|
||||
|
||||
TextSpan _buildReviewText(BuildContext context, item) {
|
||||
switch (item['state']) {
|
||||
@ -102,7 +100,7 @@ class TimelineItem extends StatelessWidget {
|
||||
p: p,
|
||||
);
|
||||
case 'IssueComment':
|
||||
return CommentItem(p, onReaction: onReaction);
|
||||
return CommentItem.gh(p);
|
||||
case 'CrossReferencedEvent':
|
||||
return TimelineEventItem(
|
||||
actor: p['actor']['login'],
|
||||
@ -336,9 +334,10 @@ class TimelineItem extends StatelessWidget {
|
||||
Container(
|
||||
padding: CommonStyle.padding.copyWith(left: 50),
|
||||
child: Column(
|
||||
children: comments.map((v) {
|
||||
return CommentItem(v, onReaction: (_, __) {});
|
||||
}).toList()),
|
||||
children: <Widget>[
|
||||
for (var v in comments) CommentItem.gh(v),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user