refactor: contribution api

This commit is contained in:
Rongjian Zhang 2020-01-01 13:26:20 +08:00
parent 9f4df079a2
commit 35993942fe
10 changed files with 433 additions and 131 deletions

View File

@ -72,6 +72,8 @@ class GithubMeUser extends GithubMeAuditEntryActor
@override
GithubMeRepositoryConnection repositories;
GithubMeContributionsCollection contributionsCollection;
@override
@JsonKey(name: '__typename')
String resolveType;
@ -91,6 +93,7 @@ class GithubMeUser extends GithubMeAuditEntryActor
followers,
following,
repositories,
contributionsCollection,
resolveType
];
Map<String, dynamic> toJson() => _$GithubMeUserToJson(this);
@ -154,6 +157,66 @@ class GithubMeRepositoryConnection with EquatableMixin {
Map<String, dynamic> toJson() => _$GithubMeRepositoryConnectionToJson(this);
}
@JsonSerializable(explicitToJson: true)
class GithubMeContributionsCollection with EquatableMixin {
GithubMeContributionsCollection();
factory GithubMeContributionsCollection.fromJson(Map<String, dynamic> json) =>
_$GithubMeContributionsCollectionFromJson(json);
GithubMeContributionCalendar contributionCalendar;
@override
List<Object> get props => [contributionCalendar];
Map<String, dynamic> toJson() =>
_$GithubMeContributionsCollectionToJson(this);
}
@JsonSerializable(explicitToJson: true)
class GithubMeContributionCalendar with EquatableMixin {
GithubMeContributionCalendar();
factory GithubMeContributionCalendar.fromJson(Map<String, dynamic> json) =>
_$GithubMeContributionCalendarFromJson(json);
List<GithubMeContributionCalendarWeek> weeks;
@override
List<Object> get props => [weeks];
Map<String, dynamic> toJson() => _$GithubMeContributionCalendarToJson(this);
}
@JsonSerializable(explicitToJson: true)
class GithubMeContributionCalendarWeek with EquatableMixin {
GithubMeContributionCalendarWeek();
factory GithubMeContributionCalendarWeek.fromJson(
Map<String, dynamic> json) =>
_$GithubMeContributionCalendarWeekFromJson(json);
List<GithubMeContributionCalendarDay> contributionDays;
@override
List<Object> get props => [contributionDays];
Map<String, dynamic> toJson() =>
_$GithubMeContributionCalendarWeekToJson(this);
}
@JsonSerializable(explicitToJson: true)
class GithubMeContributionCalendarDay with EquatableMixin {
GithubMeContributionCalendarDay();
factory GithubMeContributionCalendarDay.fromJson(Map<String, dynamic> json) =>
_$GithubMeContributionCalendarDayFromJson(json);
String color;
@override
List<Object> get props => [color];
Map<String, dynamic> toJson() =>
_$GithubMeContributionCalendarDayToJson(this);
}
@JsonSerializable(explicitToJson: true)
class GithubMeAuditEntryActor with EquatableMixin {
GithubMeAuditEntryActor();
@ -452,6 +515,41 @@ class GithubMeQuery extends GraphQLQuery<GithubMe, JsonSerializable> {
arguments: [],
directives: [],
selectionSet: null)
])),
FieldNode(
name: NameNode(value: 'contributionsCollection'),
alias: null,
arguments: [],
directives: [],
selectionSet: SelectionSetNode(selections: [
FieldNode(
name: NameNode(value: 'contributionCalendar'),
alias: null,
arguments: [],
directives: [],
selectionSet: SelectionSetNode(selections: [
FieldNode(
name: NameNode(value: 'weeks'),
alias: null,
arguments: [],
directives: [],
selectionSet: SelectionSetNode(selections: [
FieldNode(
name: NameNode(value: 'contributionDays'),
alias: null,
arguments: [],
directives: [],
selectionSet:
SelectionSetNode(selections: [
FieldNode(
name: NameNode(value: 'color'),
alias: null,
arguments: [],
directives: [],
selectionSet: null)
]))
]))
]))
]))
]))
]))

View File

@ -44,6 +44,10 @@ GithubMeUser _$GithubMeUserFromJson(Map<String, dynamic> json) {
? null
: GithubMeRepositoryConnection.fromJson(
json['repositories'] as Map<String, dynamic>)
..contributionsCollection = json['contributionsCollection'] == null
? null
: GithubMeContributionsCollection.fromJson(
json['contributionsCollection'] as Map<String, dynamic>)
..resolveType = json['__typename'] as String;
}
@ -62,6 +66,7 @@ Map<String, dynamic> _$GithubMeUserToJson(GithubMeUser instance) =>
'followers': instance.followers?.toJson(),
'following': instance.following?.toJson(),
'repositories': instance.repositories?.toJson(),
'contributionsCollection': instance.contributionsCollection?.toJson(),
'__typename': instance.resolveType,
};
@ -110,6 +115,67 @@ Map<String, dynamic> _$GithubMeRepositoryConnectionToJson(
'totalCount': instance.totalCount,
};
GithubMeContributionsCollection _$GithubMeContributionsCollectionFromJson(
Map<String, dynamic> json) {
return GithubMeContributionsCollection()
..contributionCalendar = json['contributionCalendar'] == null
? null
: GithubMeContributionCalendar.fromJson(
json['contributionCalendar'] as Map<String, dynamic>);
}
Map<String, dynamic> _$GithubMeContributionsCollectionToJson(
GithubMeContributionsCollection instance) =>
<String, dynamic>{
'contributionCalendar': instance.contributionCalendar?.toJson(),
};
GithubMeContributionCalendar _$GithubMeContributionCalendarFromJson(
Map<String, dynamic> json) {
return GithubMeContributionCalendar()
..weeks = (json['weeks'] as List)
?.map((e) => e == null
? null
: GithubMeContributionCalendarWeek.fromJson(
e as Map<String, dynamic>))
?.toList();
}
Map<String, dynamic> _$GithubMeContributionCalendarToJson(
GithubMeContributionCalendar instance) =>
<String, dynamic>{
'weeks': instance.weeks?.map((e) => e?.toJson())?.toList(),
};
GithubMeContributionCalendarWeek _$GithubMeContributionCalendarWeekFromJson(
Map<String, dynamic> json) {
return GithubMeContributionCalendarWeek()
..contributionDays = (json['contributionDays'] as List)
?.map((e) => e == null
? null
: GithubMeContributionCalendarDay.fromJson(
e as Map<String, dynamic>))
?.toList();
}
Map<String, dynamic> _$GithubMeContributionCalendarWeekToJson(
GithubMeContributionCalendarWeek instance) =>
<String, dynamic>{
'contributionDays':
instance.contributionDays?.map((e) => e?.toJson())?.toList(),
};
GithubMeContributionCalendarDay _$GithubMeContributionCalendarDayFromJson(
Map<String, dynamic> json) {
return GithubMeContributionCalendarDay()..color = json['color'] as String;
}
Map<String, dynamic> _$GithubMeContributionCalendarDayToJson(
GithubMeContributionCalendarDay instance) =>
<String, dynamic>{
'color': instance.color,
};
GithubMeAuditEntryActor _$GithubMeAuditEntryActorFromJson(
Map<String, dynamic> json) {
return GithubMeAuditEntryActor();

View File

@ -21,5 +21,14 @@
repositories {
totalCount
}
contributionsCollection {
contributionCalendar {
weeks {
contributionDays {
color
}
}
}
}
}
}

View File

@ -94,6 +94,8 @@ class GithubUserUser extends GithubUserAuditEntryActor
GithubUserFollowingConnection following;
GithubUserContributionsCollection contributionsCollection;
GithubUserRepositoryConnection repositories;
GithubUserPinnableItemConnection pinnedItems;
@ -126,6 +128,7 @@ class GithubUserUser extends GithubUserAuditEntryActor
starredRepositories,
followers,
following,
contributionsCollection,
repositories,
pinnedItems,
viewerCanFollow,
@ -182,6 +185,68 @@ class GithubUserFollowingConnection with EquatableMixin {
Map<String, dynamic> toJson() => _$GithubUserFollowingConnectionToJson(this);
}
@JsonSerializable(explicitToJson: true)
class GithubUserContributionsCollection with EquatableMixin {
GithubUserContributionsCollection();
factory GithubUserContributionsCollection.fromJson(
Map<String, dynamic> json) =>
_$GithubUserContributionsCollectionFromJson(json);
GithubUserContributionCalendar contributionCalendar;
@override
List<Object> get props => [contributionCalendar];
Map<String, dynamic> toJson() =>
_$GithubUserContributionsCollectionToJson(this);
}
@JsonSerializable(explicitToJson: true)
class GithubUserContributionCalendar with EquatableMixin {
GithubUserContributionCalendar();
factory GithubUserContributionCalendar.fromJson(Map<String, dynamic> json) =>
_$GithubUserContributionCalendarFromJson(json);
List<GithubUserContributionCalendarWeek> weeks;
@override
List<Object> get props => [weeks];
Map<String, dynamic> toJson() => _$GithubUserContributionCalendarToJson(this);
}
@JsonSerializable(explicitToJson: true)
class GithubUserContributionCalendarWeek with EquatableMixin {
GithubUserContributionCalendarWeek();
factory GithubUserContributionCalendarWeek.fromJson(
Map<String, dynamic> json) =>
_$GithubUserContributionCalendarWeekFromJson(json);
List<GithubUserContributionCalendarDay> contributionDays;
@override
List<Object> get props => [contributionDays];
Map<String, dynamic> toJson() =>
_$GithubUserContributionCalendarWeekToJson(this);
}
@JsonSerializable(explicitToJson: true)
class GithubUserContributionCalendarDay with EquatableMixin {
GithubUserContributionCalendarDay();
factory GithubUserContributionCalendarDay.fromJson(
Map<String, dynamic> json) =>
_$GithubUserContributionCalendarDayFromJson(json);
String color;
@override
List<Object> get props => [color];
Map<String, dynamic> toJson() =>
_$GithubUserContributionCalendarDayToJson(this);
}
@JsonSerializable(explicitToJson: true)
class GithubUserRepositoryConnection with EquatableMixin {
GithubUserRepositoryConnection();
@ -768,6 +833,44 @@ class GithubUserQuery extends GraphQLQuery<GithubUser, GithubUserArguments> {
directives: [],
selectionSet: null)
])),
FieldNode(
name: NameNode(value: 'contributionsCollection'),
alias: null,
arguments: [],
directives: [],
selectionSet: SelectionSetNode(selections: [
FieldNode(
name: NameNode(value: 'contributionCalendar'),
alias: null,
arguments: [],
directives: [],
selectionSet: SelectionSetNode(selections: [
FieldNode(
name: NameNode(value: 'weeks'),
alias: null,
arguments: [],
directives: [],
selectionSet:
SelectionSetNode(selections: [
FieldNode(
name: NameNode(
value: 'contributionDays'),
alias: null,
arguments: [],
directives: [],
selectionSet:
SelectionSetNode(selections: [
FieldNode(
name:
NameNode(value: 'color'),
alias: null,
arguments: [],
directives: [],
selectionSet: null)
]))
]))
]))
])),
FieldNode(
name: NameNode(value: 'repositories'),
alias: null,

View File

@ -57,6 +57,10 @@ GithubUserUser _$GithubUserUserFromJson(Map<String, dynamic> json) {
? null
: GithubUserFollowingConnection.fromJson(
json['following'] as Map<String, dynamic>)
..contributionsCollection = json['contributionsCollection'] == null
? null
: GithubUserContributionsCollection.fromJson(
json['contributionsCollection'] as Map<String, dynamic>)
..repositories = json['repositories'] == null
? null
: GithubUserRepositoryConnection.fromJson(
@ -84,6 +88,7 @@ Map<String, dynamic> _$GithubUserUserToJson(GithubUserUser instance) =>
'starredRepositories': instance.starredRepositories?.toJson(),
'followers': instance.followers?.toJson(),
'following': instance.following?.toJson(),
'contributionsCollection': instance.contributionsCollection?.toJson(),
'repositories': instance.repositories?.toJson(),
'pinnedItems': instance.pinnedItems?.toJson(),
'viewerCanFollow': instance.viewerCanFollow,
@ -129,6 +134,67 @@ Map<String, dynamic> _$GithubUserFollowingConnectionToJson(
'totalCount': instance.totalCount,
};
GithubUserContributionsCollection _$GithubUserContributionsCollectionFromJson(
Map<String, dynamic> json) {
return GithubUserContributionsCollection()
..contributionCalendar = json['contributionCalendar'] == null
? null
: GithubUserContributionCalendar.fromJson(
json['contributionCalendar'] as Map<String, dynamic>);
}
Map<String, dynamic> _$GithubUserContributionsCollectionToJson(
GithubUserContributionsCollection instance) =>
<String, dynamic>{
'contributionCalendar': instance.contributionCalendar?.toJson(),
};
GithubUserContributionCalendar _$GithubUserContributionCalendarFromJson(
Map<String, dynamic> json) {
return GithubUserContributionCalendar()
..weeks = (json['weeks'] as List)
?.map((e) => e == null
? null
: GithubUserContributionCalendarWeek.fromJson(
e as Map<String, dynamic>))
?.toList();
}
Map<String, dynamic> _$GithubUserContributionCalendarToJson(
GithubUserContributionCalendar instance) =>
<String, dynamic>{
'weeks': instance.weeks?.map((e) => e?.toJson())?.toList(),
};
GithubUserContributionCalendarWeek _$GithubUserContributionCalendarWeekFromJson(
Map<String, dynamic> json) {
return GithubUserContributionCalendarWeek()
..contributionDays = (json['contributionDays'] as List)
?.map((e) => e == null
? null
: GithubUserContributionCalendarDay.fromJson(
e as Map<String, dynamic>))
?.toList();
}
Map<String, dynamic> _$GithubUserContributionCalendarWeekToJson(
GithubUserContributionCalendarWeek instance) =>
<String, dynamic>{
'contributionDays':
instance.contributionDays?.map((e) => e?.toJson())?.toList(),
};
GithubUserContributionCalendarDay _$GithubUserContributionCalendarDayFromJson(
Map<String, dynamic> json) {
return GithubUserContributionCalendarDay()..color = json['color'] as String;
}
Map<String, dynamic> _$GithubUserContributionCalendarDayToJson(
GithubUserContributionCalendarDay instance) =>
<String, dynamic>{
'color': instance.color,
};
GithubUserRepositoryConnection _$GithubUserRepositoryConnectionFromJson(
Map<String, dynamic> json) {
return GithubUserRepositoryConnection()

View File

@ -20,6 +20,15 @@ query($login: String!) {
following {
totalCount
}
contributionsCollection {
contributionCalendar {
weeks {
contributionDays {
color
}
}
}
}
repositories(
first: 6
ownerAffiliations: OWNER

View File

@ -8,45 +8,22 @@ import 'package:git_touch/widgets/app_bar_title.dart';
import 'package:git_touch/widgets/entry_item.dart';
import 'package:git_touch/widgets/table_view.dart';
import 'package:git_touch/widgets/text_contains_organization.dart';
import 'package:git_touch/widgets/user_contributions.dart';
import 'package:git_touch/widgets/user_item.dart';
import 'package:github_contributions/github_contributions.dart';
import 'package:git_touch/models/auth.dart';
import 'package:provider/provider.dart';
import 'package:tuple/tuple.dart';
class MeScreen extends StatelessWidget {
MeScreen();
Future<GithubMeUser> _query(BuildContext context) async {
final data = await Provider.of<AuthModel>(context)
.gqlClient
.execute(GithubMeQuery());
return data.data.viewer;
}
Future<List<ContributionsInfo>> _fetchContributions(
BuildContext context) async {
final login = Provider.of<AuthModel>(context).activeAccount.login;
return getContributions(login);
}
@override
Widget build(BuildContext context) {
return RefreshStatefulScaffold<
Tuple2<GithubMeUser, List<ContributionsInfo>>>(
return RefreshStatefulScaffold<GithubMeUser>(
fetchData: () async {
final vs = await Future.wait([
_query(context),
_fetchContributions(context),
]);
return Tuple2(vs[0] as GithubMeUser, vs[1] as List<ContributionsInfo>);
final data = await Provider.of<AuthModel>(context)
.gqlClient
.execute(GithubMeQuery());
return data.data.viewer;
},
title: AppBarTitle('Me'),
bodyBuilder: (data, _) {
final user = data.item1;
final contributions = data.item2;
bodyBuilder: (user, _) {
final theme = Provider.of<ThemeModel>(context);
final login = user.login;
@ -84,7 +61,39 @@ class MeScreen extends StatelessWidget {
),
]),
CommonStyle.verticalGap,
UserContributions(contributions),
Container(
color: theme.palette.background,
padding: CommonStyle.padding,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
reverse: true,
child: Wrap(
spacing: 3,
children: user
.contributionsCollection.contributionCalendar.weeks
.map((week) {
return Wrap(
direction: Axis.vertical,
spacing: 3,
children: week.contributionDays.map((day) {
var color = convertColor(day.color);
if (theme.brightness == Brightness.dark) {
color = Color.fromRGBO(0xff - color.red,
0xff - color.green, 0xff - color.blue, 1);
}
return SizedBox(
width: 10,
height: 10,
child: DecoratedBox(
decoration: BoxDecoration(color: color),
),
);
}).toList(),
);
}).toList(),
),
),
),
CommonStyle.verticalGap,
TableView(
hasIcon: true,

View File

@ -11,13 +11,10 @@ import 'package:git_touch/widgets/entry_item.dart';
import 'package:git_touch/widgets/repository_item.dart';
import 'package:git_touch/widgets/table_view.dart';
import 'package:git_touch/widgets/text_contains_organization.dart';
import 'package:git_touch/widgets/user_contributions.dart';
import 'package:git_touch/widgets/user_item.dart';
import 'package:github_contributions/github_contributions.dart';
import 'package:git_touch/models/auth.dart';
import 'package:provider/provider.dart';
import 'package:git_touch/widgets/action_button.dart';
import 'package:tuple/tuple.dart';
final userRouter = RouterScreen(
'/:login',
@ -46,28 +43,6 @@ class UserScreen extends StatelessWidget {
UserScreen(this.login);
Future<GithubUserRepositoryOwner> _query(BuildContext context) async {
final data = await Provider.of<AuthModel>(context)
.gqlClient
.execute(GithubUserQuery(variables: GithubUserArguments(login: login)));
return data.data.repositoryOwner;
}
Future<List<ContributionsInfo>> _fetchContributions(
BuildContext context) async {
var _login = login ?? Provider.of<AuthModel>(context).activeAccount.login;
switch (Provider.of<AuthModel>(context).activeAccount.platform) {
case PlatformType.gitlab:
return [];
default:
try {
return await getContributions(_login);
} catch (err) {
return [];
}
}
}
Iterable<Widget> _buildPinnedItems(Iterable<GithubUserRepository> pinnedItems,
Iterable<GithubUserRepository> repositories) {
String title;
@ -94,8 +69,7 @@ class UserScreen extends StatelessWidget {
];
}
Widget _buildUser(BuildContext context, GithubUserUser user,
List<ContributionsInfo> contributions) {
Widget _buildUser(BuildContext context, GithubUserUser user) {
final theme = Provider.of<ThemeModel>(context);
final login = user.login;
return Column(
@ -132,7 +106,38 @@ class UserScreen extends StatelessWidget {
),
]),
CommonStyle.verticalGap,
UserContributions(contributions),
Container(
color: theme.palette.background,
padding: CommonStyle.padding,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
reverse: true,
child: Wrap(
spacing: 3,
children: user.contributionsCollection.contributionCalendar.weeks
.map((week) {
return Wrap(
direction: Axis.vertical,
spacing: 3,
children: week.contributionDays.map((day) {
var color = convertColor(day.color);
if (theme.brightness == Brightness.dark) {
color = Color.fromRGBO(0xff - color.red,
0xff - color.green, 0xff - color.blue, 1);
}
return SizedBox(
width: 10,
height: 10,
child: DecoratedBox(
decoration: BoxDecoration(color: color),
),
);
}).toList(),
);
}).toList(),
),
),
),
CommonStyle.verticalGap,
TableView(
hasIcon: true,
@ -262,25 +267,20 @@ class UserScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return RefreshStatefulScaffold<
Tuple2<GithubUserRepositoryOwner, List<ContributionsInfo>>>(
return RefreshStatefulScaffold<GithubUserRepositoryOwner>(
fetchData: () async {
final vs = await Future.wait([
_query(context),
_fetchContributions(context),
]);
return Tuple2(vs[0] as GithubUserRepositoryOwner,
vs[1] as List<ContributionsInfo>);
final data = await Provider.of<AuthModel>(context).gqlClient.execute(
GithubUserQuery(variables: GithubUserArguments(login: login)));
return data.data.repositoryOwner;
},
title: AppBarTitle('User'), // TODO:
actionBuilder: (data, _) {
if (data == null)
actionBuilder: (payload, _) {
if (payload == null)
return ActionButton(
title: "Actions",
items: [],
);
final payload = data.item1;
switch (payload.resolveType) {
case 'User':
final user = payload as GithubUserUser;
@ -302,7 +302,7 @@ class UserScreen extends StatelessWidget {
}
},
),
if (data != null) ...[
if (payload != null) ...[
ActionItem.share(user.url),
ActionItem.launch(user.url),
],
@ -313,7 +313,7 @@ class UserScreen extends StatelessWidget {
return ActionButton(
title: 'Organization Actions',
items: [
if (data != null) ...[
if (payload != null) ...[
ActionItem.share(organization.url),
ActionItem.launch(organization.url),
],
@ -323,11 +323,10 @@ class UserScreen extends StatelessWidget {
return null;
}
},
bodyBuilder: (data, _) {
final payload = data.item1;
bodyBuilder: (payload, _) {
switch (payload.resolveType) {
case 'User':
return _buildUser(context, payload as GithubUserUser, data.item2);
return _buildUser(context, payload as GithubUserUser);
case 'Organization':
return _buildOrganization(
context, payload as GithubUserOrganization);

View File

@ -1,56 +0,0 @@
import 'package:flutter/material.dart';
import 'package:git_touch/models/theme.dart';
import 'package:git_touch/utils/utils.dart';
import 'package:github_contributions/github_contributions.dart';
import 'package:provider/provider.dart';
class UserContributions extends StatelessWidget {
final List<ContributionsInfo> contributions;
UserContributions(this.contributions);
@override
Widget build(BuildContext context) {
final theme = Provider.of<ThemeModel>(context);
final row = Row(
children: <Widget>[],
crossAxisAlignment: CrossAxisAlignment.start,
);
Column column;
contributions.asMap().forEach((i, v) {
var color = convertColor(v.color);
if (theme.brightness == Brightness.dark) {
color = Color.fromRGBO(
0xff - color.red, 0xff - color.green, 0xff - color.blue, 1);
}
final rect = SizedBox(
width: 10,
height: 10,
child: DecoratedBox(
decoration: BoxDecoration(color: color),
),
);
if (i % 7 == 0) {
column = Column(children: <Widget>[rect]);
row.children.add(column);
row.children.add(SizedBox(width: 3));
} else {
column.children.add(SizedBox(height: 3));
column.children.add(rect);
}
});
return Container(
color: theme.palette.background,
padding: CommonStyle.padding,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
reverse: true,
child: row,
),
);
}
}

View File

@ -19,7 +19,6 @@ dependencies:
flutter_highlight: ^0.5.0
primer: ^0.0.2
nanoid: ^0.0.6
github_contributions: ^0.2.0
seti: ^0.2.0
http: ^0.12.0
intl: ^0.16.0