diff --git a/lib/screens/notifications.dart b/lib/screens/notifications.dart index 00c04cc..6f03f1f 100644 --- a/lib/screens/notifications.dart +++ b/lib/screens/notifications.dart @@ -7,16 +7,84 @@ import '../widgets/list_group.dart'; import '../widgets/link.dart'; import '../utils/utils.dart'; -Future> 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> 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 _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 items = []; - NotificationGroup(this.repo); + NotificationGroup(this.owner, this.name); } class NotificationScreen extends StatefulWidget { @@ -71,37 +139,16 @@ class NotificationScreenState extends State { // loading = true; // }); - var ns = await fetchNotifications(); + var _groupMap = await fetchNotifications(); // NotificationProvider.of(context).setCount(ns.length); - Map _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 _refresh() async { print('onrefresh'); await _onSwitchTab(context, active); @@ -113,9 +160,18 @@ class NotificationScreenState extends State { title: Text('Notifications'), onRefresh: _refresh, bodyBuilder: () { - var children = groupMap.entries - .map((entry) => _buildGroupItem(entry.key, entry.value)) - .toList(); + List 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); }, diff --git a/lib/screens/pull_request.dart b/lib/screens/pull_request.dart index 0a2dccb..b3af3af 100644 --- a/lib/screens/pull_request.dart +++ b/lib/screens/pull_request.dart @@ -86,12 +86,12 @@ class _PullRequestScreenState extends State { 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), diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index d860b89..20d3df8 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -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; diff --git a/lib/widgets/notification_item.dart b/lib/widgets/notification_item.dart index 12fa160..c259d1d 100644 --- a/lib/widgets/notification_item.dart +++ b/lib/widgets/notification_item.dart @@ -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 { 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 { children: [ Container( padding: EdgeInsets.only(right: 8), - child: Icon(_buildIconData(), color: Colors.black45, size: 20), + child: _buildIconData(), ), Expanded( child: Text( diff --git a/lib/widgets/refresh_scaffold.dart b/lib/widgets/refresh_scaffold.dart index ff19e52..ad06227 100644 --- a/lib/widgets/refresh_scaffold.dart +++ b/lib/widgets/refresh_scaffold.dart @@ -5,11 +5,11 @@ import '../providers/settings.dart'; import 'loading.dart'; typedef RefreshCallback = Future 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({ diff --git a/lib/widgets/timeline_item.dart b/lib/widgets/timeline_item.dart index c768f52..b0af7e5 100644 --- a/lib/widgets/timeline_item.dart +++ b/lib/widgets/timeline_item.dart @@ -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: [ - 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)),