diff --git a/lib/graphql/github_me.dart b/lib/graphql/github_me.dart index 0972541..a4ab480 100644 --- a/lib/graphql/github_me.dart +++ b/lib/graphql/github_me.dart @@ -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 toJson() => _$GithubMeUserToJson(this); @@ -154,6 +157,66 @@ class GithubMeRepositoryConnection with EquatableMixin { Map toJson() => _$GithubMeRepositoryConnectionToJson(this); } +@JsonSerializable(explicitToJson: true) +class GithubMeContributionsCollection with EquatableMixin { + GithubMeContributionsCollection(); + + factory GithubMeContributionsCollection.fromJson(Map json) => + _$GithubMeContributionsCollectionFromJson(json); + + GithubMeContributionCalendar contributionCalendar; + + @override + List get props => [contributionCalendar]; + Map toJson() => + _$GithubMeContributionsCollectionToJson(this); +} + +@JsonSerializable(explicitToJson: true) +class GithubMeContributionCalendar with EquatableMixin { + GithubMeContributionCalendar(); + + factory GithubMeContributionCalendar.fromJson(Map json) => + _$GithubMeContributionCalendarFromJson(json); + + List weeks; + + @override + List get props => [weeks]; + Map toJson() => _$GithubMeContributionCalendarToJson(this); +} + +@JsonSerializable(explicitToJson: true) +class GithubMeContributionCalendarWeek with EquatableMixin { + GithubMeContributionCalendarWeek(); + + factory GithubMeContributionCalendarWeek.fromJson( + Map json) => + _$GithubMeContributionCalendarWeekFromJson(json); + + List contributionDays; + + @override + List get props => [contributionDays]; + Map toJson() => + _$GithubMeContributionCalendarWeekToJson(this); +} + +@JsonSerializable(explicitToJson: true) +class GithubMeContributionCalendarDay with EquatableMixin { + GithubMeContributionCalendarDay(); + + factory GithubMeContributionCalendarDay.fromJson(Map json) => + _$GithubMeContributionCalendarDayFromJson(json); + + String color; + + @override + List get props => [color]; + Map toJson() => + _$GithubMeContributionCalendarDayToJson(this); +} + @JsonSerializable(explicitToJson: true) class GithubMeAuditEntryActor with EquatableMixin { GithubMeAuditEntryActor(); @@ -452,6 +515,41 @@ class GithubMeQuery extends GraphQLQuery { 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) + ])) + ])) + ])) ])) ])) ])) diff --git a/lib/graphql/github_me.g.dart b/lib/graphql/github_me.g.dart index 27ab182..0517159 100644 --- a/lib/graphql/github_me.g.dart +++ b/lib/graphql/github_me.g.dart @@ -44,6 +44,10 @@ GithubMeUser _$GithubMeUserFromJson(Map json) { ? null : GithubMeRepositoryConnection.fromJson( json['repositories'] as Map) + ..contributionsCollection = json['contributionsCollection'] == null + ? null + : GithubMeContributionsCollection.fromJson( + json['contributionsCollection'] as Map) ..resolveType = json['__typename'] as String; } @@ -62,6 +66,7 @@ Map _$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 _$GithubMeRepositoryConnectionToJson( 'totalCount': instance.totalCount, }; +GithubMeContributionsCollection _$GithubMeContributionsCollectionFromJson( + Map json) { + return GithubMeContributionsCollection() + ..contributionCalendar = json['contributionCalendar'] == null + ? null + : GithubMeContributionCalendar.fromJson( + json['contributionCalendar'] as Map); +} + +Map _$GithubMeContributionsCollectionToJson( + GithubMeContributionsCollection instance) => + { + 'contributionCalendar': instance.contributionCalendar?.toJson(), + }; + +GithubMeContributionCalendar _$GithubMeContributionCalendarFromJson( + Map json) { + return GithubMeContributionCalendar() + ..weeks = (json['weeks'] as List) + ?.map((e) => e == null + ? null + : GithubMeContributionCalendarWeek.fromJson( + e as Map)) + ?.toList(); +} + +Map _$GithubMeContributionCalendarToJson( + GithubMeContributionCalendar instance) => + { + 'weeks': instance.weeks?.map((e) => e?.toJson())?.toList(), + }; + +GithubMeContributionCalendarWeek _$GithubMeContributionCalendarWeekFromJson( + Map json) { + return GithubMeContributionCalendarWeek() + ..contributionDays = (json['contributionDays'] as List) + ?.map((e) => e == null + ? null + : GithubMeContributionCalendarDay.fromJson( + e as Map)) + ?.toList(); +} + +Map _$GithubMeContributionCalendarWeekToJson( + GithubMeContributionCalendarWeek instance) => + { + 'contributionDays': + instance.contributionDays?.map((e) => e?.toJson())?.toList(), + }; + +GithubMeContributionCalendarDay _$GithubMeContributionCalendarDayFromJson( + Map json) { + return GithubMeContributionCalendarDay()..color = json['color'] as String; +} + +Map _$GithubMeContributionCalendarDayToJson( + GithubMeContributionCalendarDay instance) => + { + 'color': instance.color, + }; + GithubMeAuditEntryActor _$GithubMeAuditEntryActorFromJson( Map json) { return GithubMeAuditEntryActor(); diff --git a/lib/graphql/github_me.graphql b/lib/graphql/github_me.graphql index 7f5827e..3f2724f 100644 --- a/lib/graphql/github_me.graphql +++ b/lib/graphql/github_me.graphql @@ -21,5 +21,14 @@ repositories { totalCount } + contributionsCollection { + contributionCalendar { + weeks { + contributionDays { + color + } + } + } + } } } diff --git a/lib/graphql/github_user.dart b/lib/graphql/github_user.dart index cad01a5..aa29e98 100644 --- a/lib/graphql/github_user.dart +++ b/lib/graphql/github_user.dart @@ -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 toJson() => _$GithubUserFollowingConnectionToJson(this); } +@JsonSerializable(explicitToJson: true) +class GithubUserContributionsCollection with EquatableMixin { + GithubUserContributionsCollection(); + + factory GithubUserContributionsCollection.fromJson( + Map json) => + _$GithubUserContributionsCollectionFromJson(json); + + GithubUserContributionCalendar contributionCalendar; + + @override + List get props => [contributionCalendar]; + Map toJson() => + _$GithubUserContributionsCollectionToJson(this); +} + +@JsonSerializable(explicitToJson: true) +class GithubUserContributionCalendar with EquatableMixin { + GithubUserContributionCalendar(); + + factory GithubUserContributionCalendar.fromJson(Map json) => + _$GithubUserContributionCalendarFromJson(json); + + List weeks; + + @override + List get props => [weeks]; + Map toJson() => _$GithubUserContributionCalendarToJson(this); +} + +@JsonSerializable(explicitToJson: true) +class GithubUserContributionCalendarWeek with EquatableMixin { + GithubUserContributionCalendarWeek(); + + factory GithubUserContributionCalendarWeek.fromJson( + Map json) => + _$GithubUserContributionCalendarWeekFromJson(json); + + List contributionDays; + + @override + List get props => [contributionDays]; + Map toJson() => + _$GithubUserContributionCalendarWeekToJson(this); +} + +@JsonSerializable(explicitToJson: true) +class GithubUserContributionCalendarDay with EquatableMixin { + GithubUserContributionCalendarDay(); + + factory GithubUserContributionCalendarDay.fromJson( + Map json) => + _$GithubUserContributionCalendarDayFromJson(json); + + String color; + + @override + List get props => [color]; + Map toJson() => + _$GithubUserContributionCalendarDayToJson(this); +} + @JsonSerializable(explicitToJson: true) class GithubUserRepositoryConnection with EquatableMixin { GithubUserRepositoryConnection(); @@ -768,6 +833,44 @@ class GithubUserQuery extends GraphQLQuery { 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, diff --git a/lib/graphql/github_user.g.dart b/lib/graphql/github_user.g.dart index c37f538..f32d835 100644 --- a/lib/graphql/github_user.g.dart +++ b/lib/graphql/github_user.g.dart @@ -57,6 +57,10 @@ GithubUserUser _$GithubUserUserFromJson(Map json) { ? null : GithubUserFollowingConnection.fromJson( json['following'] as Map) + ..contributionsCollection = json['contributionsCollection'] == null + ? null + : GithubUserContributionsCollection.fromJson( + json['contributionsCollection'] as Map) ..repositories = json['repositories'] == null ? null : GithubUserRepositoryConnection.fromJson( @@ -84,6 +88,7 @@ Map _$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 _$GithubUserFollowingConnectionToJson( 'totalCount': instance.totalCount, }; +GithubUserContributionsCollection _$GithubUserContributionsCollectionFromJson( + Map json) { + return GithubUserContributionsCollection() + ..contributionCalendar = json['contributionCalendar'] == null + ? null + : GithubUserContributionCalendar.fromJson( + json['contributionCalendar'] as Map); +} + +Map _$GithubUserContributionsCollectionToJson( + GithubUserContributionsCollection instance) => + { + 'contributionCalendar': instance.contributionCalendar?.toJson(), + }; + +GithubUserContributionCalendar _$GithubUserContributionCalendarFromJson( + Map json) { + return GithubUserContributionCalendar() + ..weeks = (json['weeks'] as List) + ?.map((e) => e == null + ? null + : GithubUserContributionCalendarWeek.fromJson( + e as Map)) + ?.toList(); +} + +Map _$GithubUserContributionCalendarToJson( + GithubUserContributionCalendar instance) => + { + 'weeks': instance.weeks?.map((e) => e?.toJson())?.toList(), + }; + +GithubUserContributionCalendarWeek _$GithubUserContributionCalendarWeekFromJson( + Map json) { + return GithubUserContributionCalendarWeek() + ..contributionDays = (json['contributionDays'] as List) + ?.map((e) => e == null + ? null + : GithubUserContributionCalendarDay.fromJson( + e as Map)) + ?.toList(); +} + +Map _$GithubUserContributionCalendarWeekToJson( + GithubUserContributionCalendarWeek instance) => + { + 'contributionDays': + instance.contributionDays?.map((e) => e?.toJson())?.toList(), + }; + +GithubUserContributionCalendarDay _$GithubUserContributionCalendarDayFromJson( + Map json) { + return GithubUserContributionCalendarDay()..color = json['color'] as String; +} + +Map _$GithubUserContributionCalendarDayToJson( + GithubUserContributionCalendarDay instance) => + { + 'color': instance.color, + }; + GithubUserRepositoryConnection _$GithubUserRepositoryConnectionFromJson( Map json) { return GithubUserRepositoryConnection() diff --git a/lib/graphql/github_user.graphql b/lib/graphql/github_user.graphql index ac94877..b095e68 100644 --- a/lib/graphql/github_user.graphql +++ b/lib/graphql/github_user.graphql @@ -20,6 +20,15 @@ query($login: String!) { following { totalCount } + contributionsCollection { + contributionCalendar { + weeks { + contributionDays { + color + } + } + } + } repositories( first: 6 ownerAffiliations: OWNER diff --git a/lib/screens/me.dart b/lib/screens/me.dart index aaaa58d..d68d062 100644 --- a/lib/screens/me.dart +++ b/lib/screens/me.dart @@ -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 _query(BuildContext context) async { - final data = await Provider.of(context) - .gqlClient - .execute(GithubMeQuery()); - return data.data.viewer; - } - - Future> _fetchContributions( - BuildContext context) async { - final login = Provider.of(context).activeAccount.login; - return getContributions(login); - } - @override Widget build(BuildContext context) { - return RefreshStatefulScaffold< - Tuple2>>( + return RefreshStatefulScaffold( fetchData: () async { - final vs = await Future.wait([ - _query(context), - _fetchContributions(context), - ]); - return Tuple2(vs[0] as GithubMeUser, vs[1] as List); + final data = await Provider.of(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(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, diff --git a/lib/screens/user.dart b/lib/screens/user.dart index 418ae1e..744ad24 100644 --- a/lib/screens/user.dart +++ b/lib/screens/user.dart @@ -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 _query(BuildContext context) async { - final data = await Provider.of(context) - .gqlClient - .execute(GithubUserQuery(variables: GithubUserArguments(login: login))); - return data.data.repositoryOwner; - } - - Future> _fetchContributions( - BuildContext context) async { - var _login = login ?? Provider.of(context).activeAccount.login; - switch (Provider.of(context).activeAccount.platform) { - case PlatformType.gitlab: - return []; - default: - try { - return await getContributions(_login); - } catch (err) { - return []; - } - } - } - Iterable _buildPinnedItems(Iterable pinnedItems, Iterable repositories) { String title; @@ -94,8 +69,7 @@ class UserScreen extends StatelessWidget { ]; } - Widget _buildUser(BuildContext context, GithubUserUser user, - List contributions) { + Widget _buildUser(BuildContext context, GithubUserUser user) { final theme = Provider.of(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>>( + return RefreshStatefulScaffold( fetchData: () async { - final vs = await Future.wait([ - _query(context), - _fetchContributions(context), - ]); - return Tuple2(vs[0] as GithubUserRepositoryOwner, - vs[1] as List); + final data = await Provider.of(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); diff --git a/lib/widgets/user_contributions.dart b/lib/widgets/user_contributions.dart deleted file mode 100644 index 51d8a11..0000000 --- a/lib/widgets/user_contributions.dart +++ /dev/null @@ -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 contributions; - - UserContributions(this.contributions); - - @override - Widget build(BuildContext context) { - final theme = Provider.of(context); - - final row = Row( - children: [], - 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: [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, - ), - ); - } -} diff --git a/pubspec.yaml b/pubspec.yaml index 268cadc..49eb555 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -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