1
0
mirror of https://github.com/git-touch/git-touch synced 2024-12-16 10:20:55 +01:00

feat: issue screen style

This commit is contained in:
Rongjian Zhang 2019-09-07 17:48:59 +08:00
parent 321ab0a60a
commit 1108346163
6 changed files with 156 additions and 145 deletions

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/widgets.dart';
import 'package:git_touch/models/theme.dart';
import 'package:git_touch/utils/utils.dart';
import 'package:provider/provider.dart';
import '../widgets/loading.dart';
import '../widgets/link.dart';
@ -102,11 +103,7 @@ class _LongListScaffoldState<T, K> extends State<LongListScaffold<T, K>> {
Widget _buildItem(BuildContext context, int index) {
if (index % 2 == 1) {
return Container(
decoration: BoxDecoration(
border: Border(bottom: BorderSide(color: Colors.black12)),
),
);
return BorderView();
}
int realIndex = index ~/ 2;

View File

@ -360,40 +360,41 @@ mutation {
);
},
headerBuilder: (payload) {
return Column(children: <Widget>[
Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
border: Border(bottom: BorderSide(color: Colors.black12)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Expanded(
child: Text(
payload['title'],
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
padding: EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Expanded(
child: Text(
payload['title'],
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
),
Padding(padding: EdgeInsets.only(right: 8)),
StateLabel(_getLabelStatus(payload))
],
),
Padding(padding: EdgeInsets.only(bottom: 16)),
CommentItem(
payload,
onReaction: _handleReaction(payload),
),
],
Padding(padding: EdgeInsets.only(right: 8)),
StateLabel(_getLabelStatus(payload))
],
),
Padding(padding: EdgeInsets.only(bottom: 16)),
CommentItem(
payload,
onReaction: _handleReaction(payload),
),
],
),
),
)
]);
BorderView(),
],
);
},
itemBuilder: (itemPayload) =>
TimelineItem(itemPayload, onReaction: _handleReaction(itemPayload)),

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/gestures.dart';
import 'package:git_touch/screens/user.dart';
import 'package:primer/primer.dart';
import '../providers/settings.dart';
import '../screens/repo.dart';
@ -41,6 +42,7 @@ TextSpan createLinkSpan(BuildContext context, String text, Function handle) {
recognizer: TapGestureRecognizer()
..onTap = () {
Navigator.of(context).push(
// FIXME: Material route
CupertinoPageRoute(
builder: (context) {
return handle();
@ -51,6 +53,10 @@ TextSpan createLinkSpan(BuildContext context, String text, Function handle) {
);
}
TextSpan createUserSpan(BuildContext context, String login) {
return createLinkSpan(context, login, () => UserScreen(login));
}
TextSpan createRepoLinkSpan(BuildContext context, String owner, String name) {
return createLinkSpan(context, '$owner/$name', () => RepoScreen(owner, name));
}

View File

@ -48,13 +48,13 @@ class CommentItem extends StatelessWidget {
size: 16,
login: payload['author']['login'],
),
Padding(padding: EdgeInsets.only(left: 6)),
SizedBox(width: 8),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
UserName(payload['author']['login']),
Padding(padding: EdgeInsets.only(bottom: 2)),
SizedBox(height: 2),
Text(
timeago.format(DateTime.parse(payload['createdAt'])),
style: TextStyle(color: Colors.black54, fontSize: 13),
@ -63,72 +63,72 @@ class CommentItem extends StatelessWidget {
),
),
]),
Padding(
padding: const EdgeInsets.only(top: 12),
child: MarkdownBody(
data: payload['body'],
// styleSheet: MarkdownStyleSheet(code: TextStyle(fontSize: 14)),
),
SizedBox(height: 12),
MarkdownBody(
data: payload['body'] as String,
// styleSheet: MarkdownStyleSheet(code: TextStyle(fontSize: 14)),
),
SizedBox(height: 12),
Wrap(
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;
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(6),
decoration: _getDecorationByKey(emojiKey),
child: RichText(
text: TextSpan(
style: TextStyle(fontSize: 16),
children: [
TextSpan(text: emoji),
TextSpan(text: ' '),
TextSpan(
text: count.toString(),
style: TextStyle(color: PrimerColors.blue500),
),
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(count.toString(),
style: TextStyle(
color: PrimerColors.blue500, fontSize: 14))
],
),
),
),
);
}).toList()
..add(
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(12),
child: Icon(
Octicons.smiley,
color: PrimerColors.blue500,
size: 16,
),
),
),
);
}),
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: PrimerColors.blue500)),
Icon(Octicons.smiley,
color: PrimerColors.blue500, size: 18),
],
),
),
),
],
),
],
);

View File

@ -6,6 +6,43 @@ import '../utils/utils.dart';
import 'comment_item.dart';
import 'user_name.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) {
return Row(
children: <Widget>[
SizedBox(width: 6),
Icon(iconData, color: iconColor, size: 20),
SizedBox(width: 12),
Expanded(
child: RichText(
text: TextSpan(style: TextStyle(color: Colors.black), 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;
@ -23,32 +60,6 @@ class TimelineItem extends StatelessWidget {
}
}
Widget _buildItem({
String actor,
IconData iconData = Octicons.octoface,
Color iconColor = PrimerColors.gray400,
TextSpan textSpan,
item,
}) {
return Row(
children: <Widget>[
Padding(padding: EdgeInsets.only(left: 6)),
Icon(iconData, color: iconColor, size: 20),
Padding(padding: EdgeInsets.only(left: 12)),
Expanded(
child: RichText(
text: TextSpan(style: TextStyle(color: Colors.black), children: [
// TODO: actor is null
createUserSpan(actor),
textSpan,
// TextSpan(text: ' ' + TimeAgo.formatFromString(item['createdAt']))
]),
),
),
],
);
}
TextSpan _buildLabel(item) {
var color = convertColor(item['label']['color']);
var grayscale = color.red * 0.3 + color.green * 0.59 + color.blue * 0.11;
@ -73,7 +84,7 @@ class TimelineItem extends StatelessWidget {
Widget _buildByType(BuildContext context) {
String type = payload['__typename'];
var defaultItem = _buildItem(
var defaultItem = TimelineEventItem(
actor: '',
iconData: Octicons.octoface,
textSpan: TextSpan(children: [
@ -85,7 +96,7 @@ class TimelineItem extends StatelessWidget {
switch (type) {
// common types
case 'Commit':
return _buildItem(
return TimelineEventItem(
actor: payload['author']['user'] == null
? null
: payload['author']['user']['login'],
@ -99,7 +110,7 @@ class TimelineItem extends StatelessWidget {
case 'IssueComment':
return CommentItem(payload, onReaction: onReaction);
case 'CrossReferencedEvent':
return _buildItem(
return TimelineEventItem(
actor: payload['actor']['login'],
iconData: Octicons.primitive_dot,
iconColor: Palette.green,
@ -109,7 +120,7 @@ class TimelineItem extends StatelessWidget {
item: payload,
);
case 'ClosedEvent':
return _buildItem(
return TimelineEventItem(
actor: payload['actor']['login'],
iconData: Octicons.circle_slash,
iconColor: PrimerColors.red600,
@ -118,7 +129,7 @@ class TimelineItem extends StatelessWidget {
);
case 'ReopenedEvent':
return _buildItem(
return TimelineEventItem(
actor: payload['actor']['login'],
iconData: Octicons.primitive_dot,
iconColor: Palette.green,
@ -134,7 +145,7 @@ class TimelineItem extends StatelessWidget {
return Container();
}
return _buildItem(
return TimelineEventItem(
actor: payload['actor']['login'],
iconData: Octicons.bookmark,
textSpan: TextSpan(children: [
@ -144,7 +155,7 @@ class TimelineItem extends StatelessWidget {
item: payload,
);
case 'AssignedEvent':
return _buildItem(
return TimelineEventItem(
actor: payload['actor']['login'],
iconData: Octicons.key,
textSpan: TextSpan(children: [
@ -156,7 +167,7 @@ class TimelineItem extends StatelessWidget {
case 'UnassignedEvent':
return defaultItem; // TODO:
case 'LabeledEvent':
return _buildItem(
return TimelineEventItem(
actor: payload['actor']['login'],
iconData: Octicons.tag,
textSpan: TextSpan(children: [
@ -167,7 +178,7 @@ class TimelineItem extends StatelessWidget {
item: payload,
);
case 'UnlabeledEvent':
return _buildItem(
return TimelineEventItem(
actor: payload['actor']['login'],
iconData: Octicons.tag,
textSpan: TextSpan(children: [
@ -179,7 +190,7 @@ class TimelineItem extends StatelessWidget {
);
case 'MilestonedEvent':
return _buildItem(
return TimelineEventItem(
actor: payload['actor']['login'],
iconData: Octicons.milestone,
textSpan: TextSpan(children: [
@ -192,7 +203,7 @@ class TimelineItem extends StatelessWidget {
case 'DemilestonedEvent':
return defaultItem; // TODO:
case 'RenamedTitleEvent':
return _buildItem(
return TimelineEventItem(
actor: payload['actor']['login'],
iconData: Octicons.pencil,
textSpan: TextSpan(children: [
@ -207,7 +218,7 @@ class TimelineItem extends StatelessWidget {
item: payload,
);
case 'LockedEvent':
return _buildItem(
return TimelineEventItem(
actor: payload['actor']['login'],
iconData: Octicons.lock,
textSpan: TextSpan(children: [
@ -216,7 +227,7 @@ class TimelineItem extends StatelessWidget {
item: payload,
);
case 'UnlockedEvent':
return _buildItem(
return TimelineEventItem(
actor: payload['actor']['login'],
iconData: Octicons.key,
textSpan: TextSpan(children: [
@ -233,7 +244,7 @@ class TimelineItem extends StatelessWidget {
case 'CommitCommentThread':
return defaultItem; // TODO:
case 'PullRequestReview':
return _buildItem(
return TimelineEventItem(
actor: payload['author']['login'],
iconColor: Color(0xff28a745),
iconData: Octicons.check,
@ -244,7 +255,7 @@ class TimelineItem extends StatelessWidget {
case 'PullRequestReviewComment':
return defaultItem; // TODO:
case 'MergedEvent':
return _buildItem(
return TimelineEventItem(
actor: payload['actor']['login'],
iconData: Octicons.git_merge,
iconColor: Color(0xff6f42c1),
@ -260,7 +271,7 @@ class TimelineItem extends StatelessWidget {
case 'DeploymentEnvironmentChangedEvent':
return defaultItem; // TODO:
case 'HeadRefDeletedEvent':
return _buildItem(
return TimelineEventItem(
actor: payload['actor']['login'],
iconData: Octicons.git_branch,
textSpan: TextSpan(children: [
@ -275,14 +286,14 @@ class TimelineItem extends StatelessWidget {
case 'BaseRefForcePushedEvent':
return defaultItem; // TODO:
case 'ReviewRequestedEvent':
return _buildItem(
return TimelineEventItem(
iconData: Octicons.eye,
// actor: payload['author']['login'],
// TODO:
actor: 'test',
textSpan: TextSpan(children: [
TextSpan(text: ' requested a review from '),
createUserSpan(payload['requestedReviewer']['login']),
createUserSpan(context, payload['requestedReviewer']['login']),
]),
item: payload,
);

View File

@ -5,10 +5,6 @@ import 'link.dart';
final style = TextStyle(fontWeight: FontWeight.w600);
TextSpan createUserSpan(String login) {
return TextSpan(text: login, style: style);
}
class UserName extends StatelessWidget {
final String login;