1
0
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:
Rongjian Zhang 2019-12-26 18:00:36 +08:00
parent 785c4368b6
commit 4099baaadb
5 changed files with 173 additions and 71 deletions

View File

@ -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;

View File

@ -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

View File

@ -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 {

View File

@ -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(

View File

@ -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),
),