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:
parent
c0629c5739
commit
fb9fd4cb3a
@ -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);
|
||||||
},
|
},
|
||||||
|
@ -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),
|
||||||
|
@ -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;
|
||||||
|
@ -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(
|
||||||
|
@ -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({
|
||||||
|
@ -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)),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user