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 '../utils/utils.dart';
Future<List<NotificationPayload>> fetchNotifications([int page = 1]) async {
List items = await getWithCredentials('/notifications?page=$page&all=true');
return items.map((item) => NotificationPayload.fromJson(item)).toList();
String getRepoKey(NotificationGroup group) {
return '_' + group.owner + '_' + group.name;
}
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 {
String repo;
String owner;
String name;
get repo => owner + '/' + name;
List<NotificationPayload> items = [];
NotificationGroup(this.repo);
NotificationGroup(this.owner, this.name);
}
class NotificationScreen extends StatefulWidget {
@ -71,37 +139,16 @@ class NotificationScreenState extends State<NotificationScreen> {
// loading = true;
// });
var ns = await fetchNotifications();
var _groupMap = await fetchNotifications();
// 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(() {
groupMap = _groupMap;
// 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 {
print('onrefresh');
await _onSwitchTab(context, active);
@ -113,9 +160,18 @@ class NotificationScreenState extends State<NotificationScreen> {
title: Text('Notifications'),
onRefresh: _refresh,
bodyBuilder: () {
var children = groupMap.entries
.map((entry) => _buildGroupItem(entry.key, entry.value))
.toList();
List<Widget> children = [];
children.add(CupertinoSegmentedControl(
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);
},

View File

@ -86,12 +86,12 @@ class _PullRequestScreenState extends State<PullRequestScreen> {
Widget _buildBadge() {
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;
String text = merged ? 'Merged' : 'Open';
return Container(
decoration: BoxDecoration(
color: Color(bgColor),
color: bgColor,
borderRadius: BorderRadius.all(Radius.circular(4)),
),
padding: EdgeInsets.all(6),

View File

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

View File

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

View File

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

View File

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