mirror of
https://github.com/git-touch/git-touch
synced 2025-03-22 22:20:09 +01:00
refactor: use hash code as key
This commit is contained in:
parent
785c4368b6
commit
4099baaadb
@ -127,6 +127,73 @@ class GithubEventRelease {
|
||||
_$GithubEventReleaseFromJson(json);
|
||||
}
|
||||
|
||||
// Notification
|
||||
@JsonSerializable(fieldRename: FieldRename.snake)
|
||||
class GithubNotificationItem {
|
||||
String id;
|
||||
String htmlUrl;
|
||||
GithubNotificationItemSubject subject;
|
||||
DateTime updatedAt;
|
||||
GithubNotificationItemRepo repository;
|
||||
bool unread;
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
String state;
|
||||
|
||||
String get key => '_$hashCode';
|
||||
|
||||
GithubNotificationItem();
|
||||
|
||||
factory GithubNotificationItem.fromJson(Map<String, dynamic> json) =>
|
||||
_$GithubNotificationItemFromJson(json);
|
||||
}
|
||||
|
||||
@JsonSerializable(fieldRename: FieldRename.snake)
|
||||
class GithubNotificationItemSubject {
|
||||
String title;
|
||||
String type;
|
||||
String url;
|
||||
|
||||
int _number;
|
||||
int get number {
|
||||
if (_number == null) {
|
||||
_number = int.parse(url?.split('/')?.last ?? '0');
|
||||
}
|
||||
return _number;
|
||||
}
|
||||
|
||||
GithubNotificationItemSubject();
|
||||
|
||||
factory GithubNotificationItemSubject.fromJson(Map<String, dynamic> json) =>
|
||||
_$GithubNotificationItemSubjectFromJson(json);
|
||||
}
|
||||
|
||||
@JsonSerializable(fieldRename: FieldRename.snake)
|
||||
class GithubNotificationItemRepo {
|
||||
String fullName;
|
||||
|
||||
Tuple2<String, String> _repo;
|
||||
String get owner {
|
||||
if (_repo == null) {
|
||||
_repo = parseRepositoryFullName(fullName);
|
||||
}
|
||||
return _repo.item1;
|
||||
}
|
||||
|
||||
String get name {
|
||||
if (_repo == null) {
|
||||
_repo = parseRepositoryFullName(fullName);
|
||||
}
|
||||
return _repo.item2;
|
||||
}
|
||||
|
||||
GithubNotificationItemRepo();
|
||||
|
||||
factory GithubNotificationItemRepo.fromJson(Map<String, dynamic> json) =>
|
||||
_$GithubNotificationItemRepoFromJson(json);
|
||||
}
|
||||
|
||||
// Trending
|
||||
@JsonSerializable()
|
||||
class GithubTrendingItem {
|
||||
String author;
|
||||
|
@ -164,6 +164,63 @@ Map<String, dynamic> _$GithubEventReleaseToJson(GithubEventRelease instance) =>
|
||||
'tag_name': instance.tagName,
|
||||
};
|
||||
|
||||
GithubNotificationItem _$GithubNotificationItemFromJson(
|
||||
Map<String, dynamic> json) {
|
||||
return GithubNotificationItem()
|
||||
..id = json['id'] as String
|
||||
..htmlUrl = json['html_url'] as String
|
||||
..subject = json['subject'] == null
|
||||
? null
|
||||
: GithubNotificationItemSubject.fromJson(
|
||||
json['subject'] as Map<String, dynamic>)
|
||||
..updatedAt = json['updated_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['updated_at'] as String)
|
||||
..repository = json['repository'] == null
|
||||
? null
|
||||
: GithubNotificationItemRepo.fromJson(
|
||||
json['repository'] as Map<String, dynamic>)
|
||||
..unread = json['unread'] as bool;
|
||||
}
|
||||
|
||||
Map<String, dynamic> _$GithubNotificationItemToJson(
|
||||
GithubNotificationItem instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'html_url': instance.htmlUrl,
|
||||
'subject': instance.subject,
|
||||
'updated_at': instance.updatedAt?.toIso8601String(),
|
||||
'repository': instance.repository,
|
||||
'unread': instance.unread,
|
||||
};
|
||||
|
||||
GithubNotificationItemSubject _$GithubNotificationItemSubjectFromJson(
|
||||
Map<String, dynamic> json) {
|
||||
return GithubNotificationItemSubject()
|
||||
..title = json['title'] as String
|
||||
..type = json['type'] as String
|
||||
..url = json['url'] as String;
|
||||
}
|
||||
|
||||
Map<String, dynamic> _$GithubNotificationItemSubjectToJson(
|
||||
GithubNotificationItemSubject instance) =>
|
||||
<String, dynamic>{
|
||||
'title': instance.title,
|
||||
'type': instance.type,
|
||||
'url': instance.url,
|
||||
};
|
||||
|
||||
GithubNotificationItemRepo _$GithubNotificationItemRepoFromJson(
|
||||
Map<String, dynamic> json) {
|
||||
return GithubNotificationItemRepo()..fullName = json['full_name'] as String;
|
||||
}
|
||||
|
||||
Map<String, dynamic> _$GithubNotificationItemRepoToJson(
|
||||
GithubNotificationItemRepo instance) =>
|
||||
<String, dynamic>{
|
||||
'full_name': instance.fullName,
|
||||
};
|
||||
|
||||
GithubTrendingItem _$GithubTrendingItemFromJson(Map<String, dynamic> json) {
|
||||
return GithubTrendingItem()
|
||||
..author = json['author'] as String
|
||||
|
@ -1,54 +1,31 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:timeago/timeago.dart' as timeago;
|
||||
import 'package:git_touch/models/github.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
|
||||
class NotificationPayload {
|
||||
String id;
|
||||
String type;
|
||||
String owner;
|
||||
String name;
|
||||
int number;
|
||||
String title;
|
||||
String updateAt;
|
||||
bool unread;
|
||||
|
||||
String state;
|
||||
|
||||
String get key => '_' + number.toString();
|
||||
|
||||
NotificationPayload.fromJson(input) {
|
||||
id = input['id'];
|
||||
type = input['subject']['type'];
|
||||
name = input['repository']['name'];
|
||||
owner = input['repository']['owner']['login'];
|
||||
|
||||
String url = input['subject']['url'];
|
||||
|
||||
if (type == 'Issue' || type == 'PullRequest') {
|
||||
String numberStr = url.split('/').lastWhere((_) => true);
|
||||
number = int.parse(numberStr);
|
||||
} else {
|
||||
// Fimber.d(input);
|
||||
}
|
||||
|
||||
title = input['subject']['title'];
|
||||
updateAt = timeago.format(DateTime.parse(input['updated_at']));
|
||||
unread = input['unread'];
|
||||
}
|
||||
}
|
||||
import '../utils/utils.dart';
|
||||
|
||||
class NotificationGroup {
|
||||
String owner;
|
||||
String name;
|
||||
get repo => owner + '/' + name;
|
||||
List<NotificationPayload> items = [];
|
||||
String fullName;
|
||||
List<GithubNotificationItem> items = [];
|
||||
|
||||
// Add heading _ to fix number case
|
||||
// - => __
|
||||
// . => ___
|
||||
String get key =>
|
||||
('_' + owner + '_' + name).replaceAll('-', '__').replaceAll('.', '___');
|
||||
Tuple2<String, String> _repo;
|
||||
String get owner {
|
||||
if (_repo == null) {
|
||||
_repo = parseRepositoryFullName(fullName);
|
||||
}
|
||||
return _repo.item1;
|
||||
}
|
||||
|
||||
NotificationGroup(this.owner, this.name);
|
||||
String get name {
|
||||
if (_repo == null) {
|
||||
_repo = parseRepositoryFullName(fullName);
|
||||
}
|
||||
return _repo.item2;
|
||||
}
|
||||
|
||||
String get key => '_$hashCode';
|
||||
|
||||
NotificationGroup(this.fullName);
|
||||
}
|
||||
|
||||
class NotificationModel with ChangeNotifier {
|
||||
|
@ -7,6 +7,7 @@ import 'package:git_touch/widgets/app_bar_title.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:git_touch/models/notification.dart';
|
||||
import 'package:git_touch/models/auth.dart';
|
||||
import 'package:git_touch/models/github.dart';
|
||||
import '../widgets/notification_item.dart';
|
||||
import '../widgets/list_group.dart';
|
||||
import '../widgets/empty.dart';
|
||||
@ -21,7 +22,8 @@ class NotificationScreenState extends State<NotificationScreen> {
|
||||
Future<Map<String, NotificationGroup>> fetchNotifications(int index) async {
|
||||
List items = await Provider.of<AuthModel>(context).getWithCredentials(
|
||||
'/notifications?all=${index == 2}&participating=${index == 1}');
|
||||
var ns = items.map((item) => NotificationPayload.fromJson(item)).toList();
|
||||
final ns =
|
||||
items.map((item) => GithubNotificationItem.fromJson(item)).toList();
|
||||
|
||||
if (index == 0) {
|
||||
Provider.of<NotificationModel>(context).setCount(ns.length);
|
||||
@ -30,9 +32,9 @@ class NotificationScreenState extends State<NotificationScreen> {
|
||||
Map<String, NotificationGroup> _groupMap = {};
|
||||
|
||||
ns.forEach((item) {
|
||||
String repo = item.owner + '/' + item.name;
|
||||
final repo = item.repository.fullName;
|
||||
if (_groupMap[repo] == null) {
|
||||
_groupMap[repo] = NotificationGroup(item.owner, item.name);
|
||||
_groupMap[repo] = NotificationGroup(repo);
|
||||
}
|
||||
|
||||
_groupMap[repo].items.add(item);
|
||||
@ -44,7 +46,8 @@ class NotificationScreenState extends State<NotificationScreen> {
|
||||
_groupMap.forEach((repo, group) {
|
||||
// Check if issue and pull request exist
|
||||
if (group.items.where((item) {
|
||||
return item.type == 'Issue' || item.type == 'PullRequest';
|
||||
return item.subject.type == 'Issue' ||
|
||||
item.subject.type == 'PullRequest';
|
||||
}).isEmpty) {
|
||||
return;
|
||||
}
|
||||
@ -53,19 +56,17 @@ class NotificationScreenState extends State<NotificationScreen> {
|
||||
'${group.key}: repository(owner: "${group.owner}", name: "${group.name}") {';
|
||||
|
||||
group.items.forEach((item) {
|
||||
var key = item.key;
|
||||
|
||||
switch (item.type) {
|
||||
switch (item.subject.type) {
|
||||
case 'Issue':
|
||||
schema += '''
|
||||
$key: issue(number: ${item.number}) {
|
||||
${item.key}: issue(number: ${item.subject.number}) {
|
||||
state
|
||||
}
|
||||
''';
|
||||
break;
|
||||
case 'PullRequest':
|
||||
schema += '''
|
||||
$key: pullRequest(number: ${item.number}) {
|
||||
${item.key}: pullRequest(number: ${item.subject.number}) {
|
||||
state
|
||||
}
|
||||
''';
|
||||
@ -102,20 +103,19 @@ $key: pullRequest(number: ${item.number}) {
|
||||
BuildContext context,
|
||||
MapEntry<String, NotificationGroup> entry,
|
||||
Map<String, NotificationGroup> groupMap) {
|
||||
var group = entry.value;
|
||||
var repo = group.repo;
|
||||
final group = entry.value;
|
||||
return ListGroup(
|
||||
title: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
repo,
|
||||
group.fullName,
|
||||
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
await Provider.of<AuthModel>(context)
|
||||
.putWithCredentials('/repos/$repo/notifications');
|
||||
.putWithCredentials('/repos/${group.fullName}/notifications');
|
||||
// await _onSwitchTab(); // TODO:
|
||||
},
|
||||
child: Icon(
|
||||
|
@ -1,15 +1,15 @@
|
||||
import 'package:fimber/fimber.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:git_touch/models/notification.dart';
|
||||
import 'package:git_touch/widgets/issue_icon.dart';
|
||||
import '../utils/utils.dart';
|
||||
import 'package:git_touch/models/github.dart';
|
||||
import 'package:git_touch/utils/utils.dart';
|
||||
import 'package:git_touch/models/auth.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'link.dart';
|
||||
import 'package:git_touch/widgets/link.dart';
|
||||
|
||||
class NotificationItem extends StatefulWidget {
|
||||
final NotificationPayload payload;
|
||||
final GithubNotificationItem payload;
|
||||
final Function markAsRead;
|
||||
|
||||
NotificationItem({
|
||||
@ -23,7 +23,7 @@ class NotificationItem extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _NotificationItemState extends State<NotificationItem> {
|
||||
NotificationPayload get payload => widget.payload;
|
||||
GithubNotificationItem get payload => widget.payload;
|
||||
bool loading = false;
|
||||
|
||||
Widget _buildIcon(IconData data, [Color color = Colors.black54]) {
|
||||
@ -31,7 +31,7 @@ class _NotificationItemState extends State<NotificationItem> {
|
||||
}
|
||||
|
||||
Widget _buildIconData() {
|
||||
switch (payload.type) {
|
||||
switch (payload.subject.type) {
|
||||
case 'Issue':
|
||||
switch (payload.state) {
|
||||
case 'OPEN':
|
||||
@ -60,7 +60,7 @@ class _NotificationItemState extends State<NotificationItem> {
|
||||
case 'Commit':
|
||||
return _buildIcon(Octicons.git_commit);
|
||||
default:
|
||||
Fimber.d('Unhandled notification type: ${payload.type}');
|
||||
Fimber.d('Unhandled notification type: ${payload.subject.type}');
|
||||
return _buildIcon(Octicons.octoface);
|
||||
}
|
||||
}
|
||||
@ -80,7 +80,7 @@ class _NotificationItemState extends State<NotificationItem> {
|
||||
});
|
||||
try {
|
||||
await Provider.of<AuthModel>(context)
|
||||
.patchWithCredentials('/notifications/threads/' + payload.id);
|
||||
.patchWithCredentials('/notifications/threads/${payload.id}');
|
||||
widget.markAsRead();
|
||||
} finally {
|
||||
if (mounted) {
|
||||
@ -93,13 +93,14 @@ class _NotificationItemState extends State<NotificationItem> {
|
||||
}
|
||||
|
||||
String get _url {
|
||||
switch (payload.type) {
|
||||
switch (payload.subject.type) {
|
||||
case 'Issue':
|
||||
return '/${payload.repository.owner}/${payload.repository.name}/issues/${payload.subject.number}';
|
||||
case 'PullRequest':
|
||||
final resource = payload.type == 'PullRequest' ? 'pulls' : 'issues';
|
||||
return '/${payload.owner}/${payload.name}/$resource/${payload.number}';
|
||||
return '/${payload.repository.owner}/${payload.repository.name}/pulls/${payload.subject.number}';
|
||||
case 'Release':
|
||||
return 'https://github.com/${payload.owner}/${payload.name}/releases/tag/${payload.title}';
|
||||
// TODO: title
|
||||
// return 'https://github.com/${payload.repository.owner}/${payload.repository.name}/releases/tag/${payload.title}';
|
||||
case 'Commit':
|
||||
return '';
|
||||
default:
|
||||
@ -124,7 +125,7 @@ class _NotificationItemState extends State<NotificationItem> {
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
payload.title,
|
||||
payload.subject.title,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(fontSize: 15),
|
||||
),
|
||||
|
Loading…
x
Reference in New Issue
Block a user