From 55356315c437143ab2c3f06d254539fa6e1e2ebb Mon Sep 17 00:00:00 2001 From: Rongjian Zhang Date: Sun, 10 Feb 2019 12:42:21 +0800 Subject: [PATCH] feat: add repo's issues and pull requests screen --- lib/screens/inbox.dart | 193 --------------------------------- lib/screens/issues.dart | 145 ++++++++++++++++++++++++- lib/screens/notifications.dart | 2 + lib/screens/pull_requests.dart | 13 --- lib/screens/repo.dart | 12 +- 5 files changed, 153 insertions(+), 212 deletions(-) delete mode 100644 lib/screens/inbox.dart delete mode 100644 lib/screens/pull_requests.dart diff --git a/lib/screens/inbox.dart b/lib/screens/inbox.dart deleted file mode 100644 index 2581e22..0000000 --- a/lib/screens/inbox.dart +++ /dev/null @@ -1,193 +0,0 @@ -// import 'package:flutter/material.dart'; -// import 'package:flutter/cupertino.dart'; -// import '../widgets/list_scaffold.dart'; -// import '../utils/utils.dart'; -// import '../screens/issue.dart'; -// import '../screens/pull_request.dart'; -// import '../widgets/link.dart'; - -// class NotificationPayload { -// String type; -// String owner; -// String name; -// int number; -// String title; -// String updateAt; -// bool unread; - -// NotificationPayload.fromJson(input) { -// type = input['subject']['type']; -// name = input['repository']['name']; -// owner = input['repository']['owner']['login']; - -// String url = input['subject']['url']; -// String numberStr = url.split('/').lastWhere((_) => true); -// number = int.parse(numberStr); - -// title = input['subject']['title']; -// updateAt = TimeAgo.formatFromString(input['updated_at']); -// unread = input['unread']; -// } -// } - -// class NotificationItem extends StatelessWidget { -// const NotificationItem({ -// Key key, -// @required this.payload, -// }) : super(key: key); - -// final NotificationPayload payload; - -// Widget _buildRoute() { -// switch (payload.type) { -// case 'Issue': -// return IssueScreen(payload.number, payload.owner, payload.name); -// case 'PullRequest': -// return PullRequestScreen(payload.number, payload.owner, payload.name); -// default: -// // throw new Exception('Unhandled notification type: $type'); -// return Text('test'); -// } -// } - -// IconData _buildIconData() { -// switch (payload.type) { -// case 'Issue': -// return Octicons.issue_opened; -// // color: Color.fromRGBO(0x28, 0xa7, 0x45, 1), -// case 'PullRequest': -// return Octicons.git_pull_request; -// // color: Color.fromRGBO(0x6f, 0x42, 0xc1, 1), -// default: -// return Octicons.person; -// } -// } - -// @override -// Widget build(BuildContext context) { -// return Link( -// onTap: () { -// Navigator.of(context).push( -// CupertinoPageRoute(builder: (context) => _buildRoute()), -// ); -// }, -// child: Container( -// padding: EdgeInsets.all(8), -// // color: payload.unread ? Colors.white : Colors.black12, -// child: Column( -// crossAxisAlignment: CrossAxisAlignment.start, -// children: [ -// Row( -// crossAxisAlignment: CrossAxisAlignment.start, -// children: [ -// Container( -// padding: EdgeInsets.only(right: 8, top: 20), -// child: Icon(_buildIconData(), color: Colors.black45), -// ), -// Expanded( -// child: Container( -// child: Column( -// crossAxisAlignment: CrossAxisAlignment.start, -// children: [ -// Text( -// payload.owner + -// '/' + -// payload.name + -// ' #' + -// payload.number.toString(), -// style: TextStyle(fontSize: 13, color: Colors.black54), -// ), -// Padding(padding: EdgeInsets.only(top: 4)), -// Text( -// payload.title, -// style: TextStyle(fontSize: 15), -// maxLines: 3, -// overflow: TextOverflow.ellipsis, -// ), -// Padding(padding: EdgeInsets.only(top: 6)), -// Text( -// payload.updateAt, -// style: TextStyle( -// fontSize: 12, -// // fontWeight: FontWeight.w300, -// color: Colors.black54, -// ), -// ) -// ], -// ), -// ), -// ), -// Column( -// children: [ -// Icon(Octicons.check, color: Colors.black45), -// Icon(Octicons.unmute, color: Colors.black45) -// ], -// ), -// ], -// ), -// ], -// ), -// ), -// ); -// } -// } - -// Future> fetchNotifications(int page) async { -// List items = -// await getWithCredentials('/notifications?page=$page&per_page=20'); -// return items.map((item) => NotificationPayload.fromJson(item)).toList(); -// } - -// /// [@deprecated] -// class InboxScreen extends StatefulWidget { -// @override -// _InboxScreenState createState() => _InboxScreenState(); -// } - -// class _InboxScreenState extends State { -// // int active = 0; -// int page = 0; -// var payload; -// List _items = []; - -// final titleMap = { -// 0: 'Unread', -// 1: 'Participating', -// 2: 'All', -// }; - -// Future _refresh() async { -// page = 1; -// var items = await fetchNotifications(page); -// setState(() { -// _items = items; -// }); -// } - -// @override -// Widget build(BuildContext context) { -// return ListScaffold( -// title: Text('Inbox'), -// trailingIconData: Octicons.check, -// trailingOnTap: () async { -// bool answer = await showConfim(context, 'Mark all as read?'); -// if (answer == true) { -// await putWithCredentials('/notifications'); -// _refresh(); -// } -// }, -// onRefresh: _refresh, -// onLoadMore: () async { -// page = page + 1; -// var items = await fetchNotifications(page); -// setState(() { -// _items.addAll(items); -// }); -// }, -// itemCount: _items.length, -// itemBuilder: (context, index) { -// return NotificationItem(payload: _items[index]); -// }, -// ); -// } -// } diff --git a/lib/screens/issues.dart b/lib/screens/issues.dart index b41a258..218d564 100644 --- a/lib/screens/issues.dart +++ b/lib/screens/issues.dart @@ -1,13 +1,152 @@ import 'package:flutter/material.dart'; +import '../scaffolds/list.dart'; +import '../providers/settings.dart'; +import '../utils/utils.dart'; +import '../widgets/link.dart'; +import '../screens/pull_request.dart'; +import '../screens/issue.dart'; class IssuesScreen extends StatefulWidget { + final String owner; + final String name; + final bool isPullRequest; + + IssuesScreen({ + @required this.owner, + @required this.name, + this.isPullRequest = false, + }); + @override _IssuesScreenState createState() => _IssuesScreenState(); } class _IssuesScreenState extends State { - @override - Widget build(BuildContext context) { - return Container(); + get owner => widget.owner; + get name => widget.name; + get isPullRequest => widget.isPullRequest; + + Future _query([String cursor]) async { + var cursorChunk = cursor == null ? '' : ', after: "$cursor"'; + var resource = isPullRequest ? 'pullRequests' : 'issues'; + + var data = await SettingsProvider.of(context).query(''' +{ + repository(owner: "$owner", name: "$name") { + $resource(states: OPEN, first: $pageSize$cursorChunk) { + pageInfo { + hasNextPage + endCursor + } + nodes { + number + title + updatedAt + } + } + } +} + '''); + + var repo = data["repository"][resource]; + + return ListPayload( + cursor: repo["pageInfo"]["endCursor"], + hasMore: repo['pageInfo']['hasNextPage'], + items: repo["nodes"], + ); + } + + IconData _buildIconData() { + return widget.isPullRequest + ? Octicons.git_pull_request + : Octicons.issue_opened; + } + + Widget _buildItem(payload) { + return Link( + screenBuilder: (context) { + if (widget.isPullRequest) { + return PullRequestScreen( + number: payload['number'], + owner: owner, + name: name, + ); + } else { + return IssueScreen( + number: payload['number'], + owner: owner, + name: name, + ); + } + }, + child: Container( + padding: EdgeInsets.all(8), + // color: payload.unread ? Colors.white : Colors.black12, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + padding: EdgeInsets.only(right: 8, top: 4), + child: Icon(_buildIconData(), color: Palette.green), + ), + Expanded( + child: Container( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Text( + // owner + + // '/' + + // name + + // ' #' + + // payload['number'].toString(), + // style: TextStyle(fontSize: 13, color: Colors.black54), + // ), + // Padding(padding: EdgeInsets.only(top: 4)), + Text( + payload['title'], + style: TextStyle(fontSize: 15), + maxLines: 3, + overflow: TextOverflow.ellipsis, + ), + Padding(padding: EdgeInsets.only(top: 6)), + Text( + payload['updatedAt'], + style: TextStyle( + fontSize: 12, + // fontWeight: FontWeight.w300, + color: Colors.black54, + ), + ) + ], + ), + ), + ), + // Column( + // children: [ + // Icon(Octicons.check, color: Colors.black45), + // Icon(Octicons.unmute, color: Colors.black45) + // ], + // ), + ], + ), + ], + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return ListScaffold( + title: Text('Issues of $owner/$name'), + onRefresh: () => _query(), + onLoadMore: (cursor) => _query(cursor), + itemBuilder: _buildItem, + ); } } diff --git a/lib/screens/notifications.dart b/lib/screens/notifications.dart index ce37089..68b8731 100644 --- a/lib/screens/notifications.dart +++ b/lib/screens/notifications.dart @@ -157,6 +157,8 @@ $key: pullRequest(number: ${item.number}) { } Future _onSwitchTab([int index]) async { + if (loading) return; + setState(() { error = ''; if (index != null) { diff --git a/lib/screens/pull_requests.dart b/lib/screens/pull_requests.dart deleted file mode 100644 index 195568a..0000000 --- a/lib/screens/pull_requests.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'package:flutter/material.dart'; - -class PullRequestsScreen extends StatefulWidget { - @override - _PullRequestsScreenState createState() => _PullRequestsScreenState(); -} - -class _PullRequestsScreenState extends State { - @override - Widget build(BuildContext context) { - return Container(); - } -} diff --git a/lib/screens/repo.dart b/lib/screens/repo.dart index b46cac5..f01a7d5 100644 --- a/lib/screens/repo.dart +++ b/lib/screens/repo.dart @@ -7,7 +7,6 @@ import '../scaffolds/refresh.dart'; import '../widgets/repo_item.dart'; import '../widgets/entry_item.dart'; import '../screens/issues.dart'; -import '../screens/pull_requests.dart'; class RepoScreen extends StatefulWidget { final String owner; @@ -93,12 +92,19 @@ class _RepoScreenState extends State { EntryItem( count: payload['issues']['totalCount'], text: 'Issues', - screenBuilder: (context) => IssuesScreen(), + screenBuilder: (context) => IssuesScreen( + owner: widget.owner, + name: widget.name, + ), ), EntryItem( count: payload['pullRequests']['totalCount'], text: 'Pull Requests', - screenBuilder: (context) => PullRequestsScreen(), + screenBuilder: (context) => IssuesScreen( + owner: widget.owner, + name: widget.name, + isPullRequest: true, + ), ), ], ),