1
0
mirror of https://github.com/git-touch/git-touch synced 2024-12-22 13:25:13 +01:00
git-touch-android-ios-app/lib/widgets/timeline_item.dart
2019-12-01 00:22:19 +08:00

360 lines
11 KiB
Dart

import 'dart:core';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:git_touch/models/theme.dart';
import 'package:primer/primer.dart';
import 'package:provider/provider.dart';
import '../utils/utils.dart';
import 'comment_item.dart';
class TimelineEventItem extends StatelessWidget {
final String actor;
final IconData iconData;
final Color iconColor;
final TextSpan textSpan;
final item;
TimelineEventItem({
this.actor,
this.iconData = Octicons.octoface,
this.iconColor = PrimerColors.gray400,
this.textSpan,
this.item,
});
@override
Widget build(BuildContext context) {
final theme = Provider.of<ThemeModel>(context);
return Row(
children: <Widget>[
SizedBox(width: 6),
Icon(iconData, color: iconColor, size: 20),
SizedBox(width: 12),
Expanded(
child: RichText(
text: TextSpan(
style: TextStyle(color: theme.palette.text),
children: [
// TODO: actor is null
createUserSpan(context, actor),
textSpan,
// TextSpan(text: ' ' + TimeAgo.formatFromString(item['createdAt']))
],
),
),
),
],
);
}
}
class TimelineItem extends StatelessWidget {
final Map<String, dynamic> payload;
final Function(String emojiKey, bool isRemove) onReaction;
TimelineItem(this.payload, {@required this.onReaction});
TextSpan _buildReviewText(BuildContext context, item) {
switch (item['state']) {
case 'APPROVED':
return TextSpan(text: ' approved these changes');
case 'COMMENTED':
return TextSpan(text: ' reviewed ');
default:
return warningSpan;
}
}
TextSpan _buildLabel(item) {
// FIXME:
var color = convertColor(item['label']['color']);
return TextSpan(
text: item['label']['name'],
style: TextStyle(
color: getFontColorByBrightness(color),
backgroundColor: color,
// https://stackoverflow.com/a/52592679
// ..strokeWidth = 16.5
// ..style = PaintingStyle.stroke
),
);
}
Widget _buildByType(BuildContext context, String type) {
final theme = Provider.of<ThemeModel>(context);
var defaultItem = TimelineEventItem(
actor: '',
iconData: Octicons.octoface,
textSpan: TextSpan(children: [
TextSpan(text: 'Woops, $type type not implemented yet'),
]),
item: payload,
);
switch (type) {
// common types
case 'Commit':
return TimelineEventItem(
actor: payload['author']['user'] == null
? null
: payload['author']['user']['login'],
iconData: Octicons.git_commit,
textSpan: TextSpan(children: [
TextSpan(text: ' added commit '),
TextSpan(text: payload['oid'].substring(0, 8))
]),
item: payload,
);
case 'IssueComment':
return CommentItem(payload, onReaction: onReaction);
case 'CrossReferencedEvent':
return TimelineEventItem(
actor: payload['actor']['login'],
iconData: Octicons.primitive_dot,
iconColor: GithubPalette.open,
textSpan: TextSpan(
text: ' referenced this on #' +
payload['source']['number'].toString()),
item: payload,
);
case 'ClosedEvent':
return TimelineEventItem(
actor: payload['actor']['login'],
iconData: Octicons.circle_slash,
iconColor: GithubPalette.closed,
textSpan: TextSpan(text: ' closed this '),
item: payload,
);
case 'ReopenedEvent':
return TimelineEventItem(
actor: payload['actor']['login'],
iconData: Octicons.primitive_dot,
iconColor: GithubPalette.open,
textSpan: TextSpan(text: ' reopened this '),
item: payload,
);
case 'SubscribedEvent':
case 'UnsubscribedEvent':
return defaultItem; // TODO:
case 'ReferencedEvent':
// TODO: isCrossRepository
if (payload['commit'] == null) {
return Container();
}
return TimelineEventItem(
actor: payload['actor']['login'],
iconData: Octicons.bookmark,
textSpan: TextSpan(children: [
TextSpan(text: ' referenced this pull request from commit '),
TextSpan(text: payload['commit']['oid'].substring(0, 8)),
]),
item: payload,
);
case 'AssignedEvent':
return TimelineEventItem(
actor: payload['actor']['login'],
iconData: Octicons.key,
textSpan: TextSpan(children: [
TextSpan(text: ' assigned this to '),
TextSpan(text: payload['user']['login'])
]),
item: payload,
);
case 'UnassignedEvent':
return defaultItem; // TODO:
case 'LabeledEvent':
return TimelineEventItem(
actor: payload['actor']['login'],
iconData: Octicons.tag,
textSpan: TextSpan(children: [
TextSpan(text: ' added '),
_buildLabel(payload),
TextSpan(text: ' label'),
]),
item: payload,
);
case 'UnlabeledEvent':
return TimelineEventItem(
actor: payload['actor']['login'],
iconData: Octicons.tag,
textSpan: TextSpan(children: [
TextSpan(text: ' removed '),
_buildLabel(payload),
TextSpan(text: ' label'),
]),
item: payload,
);
case 'MilestonedEvent':
return TimelineEventItem(
actor: payload['actor']['login'],
iconData: Octicons.milestone,
textSpan: TextSpan(children: [
TextSpan(text: ' added this to '),
TextSpan(text: payload['milestoneTitle']),
TextSpan(text: ' milestone'),
]),
item: payload,
);
case 'DemilestonedEvent':
return defaultItem; // TODO:
case 'RenamedTitleEvent':
return TimelineEventItem(
actor: payload['actor']['login'],
iconData: Octicons.pencil,
textSpan: TextSpan(children: [
TextSpan(text: ' changed the title '),
TextSpan(
text: payload['previousTitle'],
style: TextStyle(decoration: TextDecoration.lineThrough),
),
TextSpan(text: ' to '),
TextSpan(text: payload['currentTitle'])
]),
item: payload,
);
case 'LockedEvent':
return TimelineEventItem(
actor: payload['actor']['login'],
iconData: Octicons.lock,
textSpan: TextSpan(children: [
TextSpan(text: ' locked this conversation '),
]),
item: payload,
);
case 'UnlockedEvent':
return TimelineEventItem(
actor: payload['actor']['login'],
iconData: Octicons.key,
textSpan: TextSpan(children: [
TextSpan(text: ' unlocked this conversation '),
]),
item: payload,
);
// issue only types
case 'TransferredEvent':
return defaultItem; // TODO:
// pull request only types
case 'CommitCommentThread':
return defaultItem; // TODO:
case 'PullRequestReview':
return TimelineEventItem(
actor: payload['author']['login'],
iconColor: GithubPalette.open,
iconData: Octicons.check,
textSpan: _buildReviewText(context, payload),
item: payload,
);
case 'PullRequestReviewThread':
case 'PullRequestReviewComment':
return defaultItem; // TODO:
case 'MergedEvent':
return TimelineEventItem(
actor: payload['actor']['login'],
iconData: Octicons.git_merge,
iconColor: GithubPalette.merged,
textSpan: TextSpan(children: [
TextSpan(text: ' merged commit '),
TextSpan(text: payload['commit']['oid'].substring(0, 8)),
TextSpan(text: ' into '),
TextSpan(text: payload['mergeRefName']),
]),
item: payload,
);
case 'DeployedEvent':
case 'DeploymentEnvironmentChangedEvent':
return defaultItem; // TODO:
case 'HeadRefDeletedEvent':
return TimelineEventItem(
actor: payload['actor']['login'],
iconData: Octicons.git_branch,
textSpan: TextSpan(children: [
TextSpan(text: ' deleted the '),
TextSpan(text: payload['headRefName']),
TextSpan(text: ' branch'),
]),
item: payload,
);
case 'HeadRefRestoredEvent':
case 'HeadRefForcePushedEvent':
return TimelineEventItem(
iconData: Octicons.repo_force_push,
actor: payload['actor']['login'],
textSpan: TextSpan(
children: [
TextSpan(text: ' force-pushed the '),
WidgetSpan(
child: PrimerBranchName(
payload['pullRequest']['headRef']['name'])),
TextSpan(text: ' branch from '),
TextSpan(
text:
(payload['beforeCommit']['oid'] as String).substring(0, 7),
style: TextStyle(color: theme.palette.primary),
),
TextSpan(text: ' to '),
TextSpan(
text: (payload['afterCommit']['oid'] as String).substring(0, 7),
style: TextStyle(color: theme.palette.primary),
),
],
),
item: payload,
);
case 'BaseRefForcePushedEvent':
return defaultItem; // TODO:
case 'ReviewRequestedEvent':
return TimelineEventItem(
iconData: Octicons.eye,
actor: payload['actor']['login'],
textSpan: TextSpan(children: [
TextSpan(text: ' requested a review from '),
createUserSpan(context, payload['requestedReviewer']['login']),
]),
item: payload,
);
case 'ReviewRequestRemovedEvent':
case 'ReviewDismissedEvent':
return defaultItem; // TODO:
default:
return defaultItem;
}
}
@override
Widget build(BuildContext context) {
final type = payload['__typename'] as String;
Widget widget = Container(
padding: CommonStyle.padding,
child: _buildByType(context, type),
);
if (type == 'PullRequestReview') {
final comments = payload['comments']['nodes'] as List;
if (comments.isNotEmpty) {
widget = Column(
children: <Widget>[
widget,
Container(
padding: CommonStyle.padding.copyWith(left: 50),
child: Column(
children: comments.map((v) {
return CommentItem(v, onReaction: (_, __) {});
}).toList()),
),
],
);
}
}
return widget;
}
}