1
0
mirror of https://github.com/git-touch/git-touch synced 2025-02-22 06:17:40 +01:00

feat: add issue and pull request state

This commit is contained in:
Rongjian Zhang 2019-02-06 19:14:11 +08:00
parent c0629c5739
commit fb9fd4cb3a
6 changed files with 131 additions and 48 deletions

View File

@ -7,16 +7,84 @@ import '../widgets/list_group.dart';
import '../widgets/link.dart'; import '../widgets/link.dart';
import '../utils/utils.dart'; import '../utils/utils.dart';
Future<List<NotificationPayload>> fetchNotifications([int page = 1]) async { String getRepoKey(NotificationGroup group) {
List items = await getWithCredentials('/notifications?page=$page&all=true'); return '_' + group.owner + '_' + group.name;
return items.map((item) => NotificationPayload.fromJson(item)).toList(); }
String getItemKey(NotificationPayload item) {
return '_' + item.number.toString();
}
Future<Map<String, NotificationGroup>> fetchNotifications(
[int page = 1]) async {
List items = await getWithCredentials(
'/notifications?page=$page&all=true&per_page=100');
var ns = items.map((item) => NotificationPayload.fromJson(item)).toList();
Map<String, NotificationGroup> _groupMap = {};
ns.forEach((item) {
String repo = item.owner + '/' + item.name;
if (_groupMap[repo] == null) {
_groupMap[repo] = NotificationGroup(item.owner, item.name);
}
_groupMap[repo].items.add(item);
});
var schema = '{';
_groupMap.forEach((repo, group) {
var repoKey = getRepoKey(group);
schema +=
'$repoKey: repository(owner: "${group.owner}", name: "${group.name}") {';
group.items.forEach((item) {
var key = getItemKey(item);
switch (item.type) {
case 'Issue':
schema += '''
$key: issue(number: ${item.number}) {
state
}
''';
break;
case 'PullRequest':
schema += '''
$key: pullRequest(number: ${item.number}) {
state
}
''';
break;
}
});
schema += '}';
});
schema += '}';
// print(schema);
var data = await query(schema);
_groupMap.forEach((repo, group) {
group.items.forEach((item) {
var itemData = data[getRepoKey(group)][getItemKey(item)];
if (itemData != null) {
item.state = itemData['state'];
}
});
});
// print(data);
return _groupMap;
} }
class NotificationGroup { class NotificationGroup {
String repo; String owner;
String name;
get repo => owner + '/' + name;
List<NotificationPayload> items = []; List<NotificationPayload> items = [];
NotificationGroup(this.repo); NotificationGroup(this.owner, this.name);
} }
class NotificationScreen extends StatefulWidget { class NotificationScreen extends StatefulWidget {
@ -71,37 +139,16 @@ class NotificationScreenState extends State<NotificationScreen> {
// loading = true; // loading = true;
// }); // });
var ns = await fetchNotifications(); var _groupMap = await fetchNotifications();
// NotificationProvider.of(context).setCount(ns.length); // NotificationProvider.of(context).setCount(ns.length);
Map<String, NotificationGroup> _groupMap = {};
ns.forEach((item) {
String repo = item.owner + '/' + item.name;
if (_groupMap[repo] == null) {
_groupMap[repo] = NotificationGroup(repo);
}
_groupMap[repo].items.add(item);
});
setState(() { setState(() {
groupMap = _groupMap; groupMap = _groupMap;
// loading = false; // loading = false;
}); });
} }
// TODO: filter
// CupertinoSegmentedControl(
// groupValue: active,
// onValueChanged: (index) => _onSwitchTab(context, index),
// children: {
// 0: Text('Unread'),
// 1: Text('Paticipating'),
// 2: Text('All')
// },
// )
Future<void> _refresh() async { Future<void> _refresh() async {
print('onrefresh'); print('onrefresh');
await _onSwitchTab(context, active); await _onSwitchTab(context, active);
@ -113,9 +160,18 @@ class NotificationScreenState extends State<NotificationScreen> {
title: Text('Notifications'), title: Text('Notifications'),
onRefresh: _refresh, onRefresh: _refresh,
bodyBuilder: () { bodyBuilder: () {
var children = groupMap.entries List<Widget> children = [];
.map((entry) => _buildGroupItem(entry.key, entry.value)) children.add(CupertinoSegmentedControl(
.toList(); groupValue: active,
onValueChanged: (index) => _onSwitchTab(context, index),
children: {
0: Text('Unread'),
1: Text('Paticipating'),
2: Text('All')
},
));
children.addAll(groupMap.entries
.map((entry) => _buildGroupItem(entry.key, entry.value)));
return Column(children: children); return Column(children: children);
}, },

View File

@ -86,12 +86,12 @@ class _PullRequestScreenState extends State<PullRequestScreen> {
Widget _buildBadge() { Widget _buildBadge() {
bool merged = payload['merged']; bool merged = payload['merged'];
int bgColor = merged ? Palette.purple : Palette.green; Color bgColor = merged ? Palette.purple : Palette.green;
IconData iconData = merged ? Octicons.git_merge : Octicons.git_pull_request; IconData iconData = merged ? Octicons.git_merge : Octicons.git_pull_request;
String text = merged ? 'Merged' : 'Open'; String text = merged ? 'Merged' : 'Open';
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Color(bgColor), color: bgColor,
borderRadius: BorderRadius.all(Radius.circular(4)), borderRadius: BorderRadius.all(Radius.circular(4)),
), ),
padding: EdgeInsets.all(6), padding: EdgeInsets.all(6),

View File

@ -138,10 +138,10 @@ TextSpan createRepoLinkSpan(BuildContext context, String owner, String name) {
} }
class Palette { class Palette {
static const green = 0xff2cbe4e; static const green = Color(0xff2cbe4e);
static const purple = 0xff6f42c1; static const purple = Color(0xff6f42c1);
static const red = 0xffcb2431; static const red = Color(0xffcb2431);
static const gray = 0xff959da5; static const gray = Color(0xff959da5);
} }
final pageSize = 20; final pageSize = 20;

View File

@ -15,6 +15,8 @@ class NotificationPayload {
String updateAt; String updateAt;
bool unread; bool unread;
String state;
NotificationPayload.fromJson(input) { NotificationPayload.fromJson(input) {
id = input['id']; id = input['id'];
type = input['subject']['type']; type = input['subject']['type'];
@ -55,22 +57,47 @@ class _NotificationItemState extends State<NotificationItem> {
return IssueScreen(payload.number, payload.owner, payload.name); return IssueScreen(payload.number, payload.owner, payload.name);
case 'PullRequest': case 'PullRequest':
return PullRequestScreen(payload.number, payload.owner, payload.name); return PullRequestScreen(payload.number, payload.owner, payload.name);
case 'Release':
// return
default: default:
// throw new Exception('Unhandled notification type: $type'); // throw new Exception('Unhandled notification type: $type');
return Text('test'); return Text('test');
} }
} }
IconData _buildIconData() { Widget _buildIcon(IconData data, [Color color = Colors.black54]) {
return Icon(data, color: color, size: 20);
}
Widget _buildIconData() {
switch (payload.type) { switch (payload.type) {
case 'Issue': case 'Issue':
return Octicons.issue_opened; switch (payload.state) {
// color: Color.fromRGBO(0x28, 0xa7, 0x45, 1), case 'OPEN':
case 'PullRequest': return _buildIcon(Octicons.issue_opened, Palette.green);
return Octicons.git_pull_request; case 'CLOSED':
// color: Color.fromRGBO(0x6f, 0x42, 0xc1, 1), return _buildIcon(Octicons.issue_closed, Palette.red);
default: default:
return Octicons.person; return _buildIcon(Octicons.person);
}
break;
case 'PullRequest':
switch (payload.state) {
case 'OPEN':
return _buildIcon(Octicons.git_pull_request, Palette.green);
case 'CLOSED':
return _buildIcon(Octicons.git_pull_request, Palette.red);
case 'MERGED':
return _buildIcon(Octicons.git_merge, Palette.purple);
default:
return _buildIcon(Octicons.person);
}
break;
// color: Color.fromRGBO(0x6f, 0x42, 0xc1, 1),
case 'Release':
return _buildIcon(Octicons.tag);
default:
return _buildIcon(Octicons.person);
} }
} }
@ -98,7 +125,7 @@ class _NotificationItemState extends State<NotificationItem> {
children: <Widget>[ children: <Widget>[
Container( Container(
padding: EdgeInsets.only(right: 8), padding: EdgeInsets.only(right: 8),
child: Icon(_buildIconData(), color: Colors.black45, size: 20), child: _buildIconData(),
), ),
Expanded( Expanded(
child: Text( child: Text(

View File

@ -5,11 +5,11 @@ import '../providers/settings.dart';
import 'loading.dart'; import 'loading.dart';
typedef RefreshCallback = Future<void> Function(); typedef RefreshCallback = Future<void> Function();
typedef BodyBuilder = Widget Function(); typedef WidgetBuilder = Widget Function();
class RefreshScaffold extends StatefulWidget { class RefreshScaffold extends StatefulWidget {
final Widget title; final Widget title;
final BodyBuilder bodyBuilder; final WidgetBuilder bodyBuilder;
final RefreshCallback onRefresh; final RefreshCallback onRefresh;
RefreshScaffold({ RefreshScaffold({

View File

@ -24,13 +24,13 @@ class TimelineItem extends StatelessWidget {
Widget _buildItem({ Widget _buildItem({
String actor, String actor,
IconData iconData = Octicons.octoface, IconData iconData = Octicons.octoface,
int iconColor = Palette.gray, Color iconColor = Palette.gray,
TextSpan textSpan, TextSpan textSpan,
item, item,
}) { }) {
return Row( return Row(
children: <Widget>[ children: <Widget>[
Icon(iconData, color: Color(iconColor), size: 16), Icon(iconData, color: iconColor, size: 16),
Padding(padding: EdgeInsets.only(left: 4)), Padding(padding: EdgeInsets.only(left: 4)),
Expanded( Expanded(
child: RichText( child: RichText(
@ -198,7 +198,7 @@ class TimelineItem extends StatelessWidget {
case 'PullRequestReview': case 'PullRequestReview':
return _buildItem( return _buildItem(
actor: item['author']['login'], actor: item['author']['login'],
iconColor: 0xff28a745, iconColor: Color(0xff28a745),
iconData: Octicons.check, iconData: Octicons.check,
textSpan: _buildReviewText(context, item), textSpan: _buildReviewText(context, item),
item: item, item: item,
@ -207,7 +207,7 @@ class TimelineItem extends StatelessWidget {
return _buildItem( return _buildItem(
actor: item['actor']['login'], actor: item['actor']['login'],
iconData: Octicons.git_merge, iconData: Octicons.git_merge,
iconColor: 0xff6f42c1, iconColor: Color(0xff6f42c1),
textSpan: TextSpan(children: [ textSpan: TextSpan(children: [
TextSpan(text: ' merged commit '), TextSpan(text: ' merged commit '),
TextSpan(text: item['commit']['oid'].substring(0, 8)), TextSpan(text: item['commit']['oid'].substring(0, 8)),