From 7496129973914ec810c7d0cbb906cd951d396cf0 Mon Sep 17 00:00:00 2001 From: Rongjian Zhang Date: Wed, 1 Jan 2020 16:35:50 +0800 Subject: [PATCH] refactor: me screen --- lib/graphql/github_user.dart | 184 +++++++++++++++++++++++++++++++- lib/graphql/github_user.g.dart | 8 +- lib/graphql/github_user.graphql | 37 ++++++- lib/main.dart | 3 +- lib/screens/me.dart | 158 --------------------------- lib/screens/user.dart | 57 ++++++---- 6 files changed, 262 insertions(+), 185 deletions(-) delete mode 100644 lib/screens/me.dart diff --git a/lib/graphql/github_user.dart b/lib/graphql/github_user.dart index d68db15..01793e8 100644 --- a/lib/graphql/github_user.dart +++ b/lib/graphql/github_user.dart @@ -15,8 +15,10 @@ class GithubUser with EquatableMixin { GithubUserRepositoryOwner repositoryOwner; + GithubUserUser viewer; + @override - List get props => [repositoryOwner]; + List get props => [repositoryOwner, viewer]; Map toJson() => _$GithubUserToJson(this); } @@ -694,15 +696,17 @@ class GithubUserMemberStatusable with EquatableMixin { @JsonSerializable(explicitToJson: true) class GithubUserArguments extends JsonSerializable with EquatableMixin { - GithubUserArguments({this.login}); + GithubUserArguments({this.login, this.isViewer}); factory GithubUserArguments.fromJson(Map json) => _$GithubUserArgumentsFromJson(json); final String login; + final bool isViewer; + @override - List get props => [login]; + List get props => [login, isViewer]; Map toJson() => _$GithubUserArgumentsToJson(this); } @@ -720,6 +724,12 @@ class GithubUserQuery extends GraphQLQuery { type: NamedTypeNode( name: NameNode(value: 'String'), isNonNull: true), defaultValue: DefaultValueNode(value: null), + directives: []), + VariableDefinitionNode( + variable: VariableNode(name: NameNode(value: 'isViewer')), + type: NamedTypeNode( + name: NameNode(value: 'Boolean'), isNonNull: true), + defaultValue: DefaultValueNode(value: null), directives: []) ], directives: [], @@ -732,7 +742,13 @@ class GithubUserQuery extends GraphQLQuery { name: NameNode(value: 'login'), value: VariableNode(name: NameNode(value: 'login'))) ], - directives: [], + directives: [ + DirectiveNode(name: NameNode(value: 'skip'), arguments: [ + ArgumentNode( + name: NameNode(value: 'if'), + value: VariableNode(name: NameNode(value: 'isViewer'))) + ]) + ], selectionSet: SelectionSetNode(selections: [ FieldNode( name: NameNode(value: '__typename'), @@ -1502,6 +1518,166 @@ class GithubUserQuery extends GraphQLQuery { selectionSet: null) ])) ])) + ])), + FieldNode( + name: NameNode(value: 'viewer'), + alias: null, + arguments: [], + directives: [ + DirectiveNode(name: NameNode(value: 'include'), arguments: [ + ArgumentNode( + name: NameNode(value: 'if'), + value: VariableNode(name: NameNode(value: 'isViewer'))) + ]) + ], + selectionSet: SelectionSetNode(selections: [ + FieldNode( + name: NameNode(value: 'login'), + alias: null, + arguments: [], + directives: [], + selectionSet: null), + FieldNode( + name: NameNode(value: 'avatarUrl'), + alias: null, + arguments: [], + directives: [], + selectionSet: null), + FieldNode( + name: NameNode(value: 'url'), + alias: null, + arguments: [], + directives: [], + selectionSet: null), + FieldNode( + name: NameNode(value: 'name'), + alias: null, + arguments: [], + directives: [], + selectionSet: null), + FieldNode( + name: NameNode(value: 'bio'), + alias: null, + arguments: [], + directives: [], + selectionSet: null), + FieldNode( + name: NameNode(value: 'company'), + alias: null, + arguments: [], + directives: [], + selectionSet: null), + FieldNode( + name: NameNode(value: 'location'), + alias: null, + arguments: [], + directives: [], + selectionSet: null), + FieldNode( + name: NameNode(value: 'email'), + alias: null, + arguments: [], + directives: [], + selectionSet: null), + FieldNode( + name: NameNode(value: 'websiteUrl'), + alias: null, + arguments: [], + directives: [], + selectionSet: null), + FieldNode( + name: NameNode(value: 'createdAt'), + alias: null, + arguments: [], + directives: [], + selectionSet: null), + FieldNode( + name: NameNode(value: 'starredRepositories'), + alias: null, + arguments: [], + directives: [], + selectionSet: SelectionSetNode(selections: [ + FieldNode( + name: NameNode(value: 'totalCount'), + alias: null, + arguments: [], + directives: [], + selectionSet: null) + ])), + FieldNode( + name: NameNode(value: 'followers'), + alias: null, + arguments: [], + directives: [], + selectionSet: SelectionSetNode(selections: [ + FieldNode( + name: NameNode(value: 'totalCount'), + alias: null, + arguments: [], + directives: [], + selectionSet: null) + ])), + FieldNode( + name: NameNode(value: 'following'), + alias: null, + arguments: [], + directives: [], + selectionSet: SelectionSetNode(selections: [ + FieldNode( + name: NameNode(value: 'totalCount'), + alias: null, + arguments: [], + directives: [], + selectionSet: null) + ])), + FieldNode( + name: NameNode(value: 'repositories'), + alias: null, + arguments: [], + directives: [], + selectionSet: SelectionSetNode(selections: [ + FieldNode( + name: NameNode(value: 'totalCount'), + alias: null, + 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_user.g.dart b/lib/graphql/github_user.g.dart index a9f46d0..53aeebf 100644 --- a/lib/graphql/github_user.g.dart +++ b/lib/graphql/github_user.g.dart @@ -11,12 +11,16 @@ GithubUser _$GithubUserFromJson(Map json) { ..repositoryOwner = json['repositoryOwner'] == null ? null : GithubUserRepositoryOwner.fromJson( - json['repositoryOwner'] as Map); + json['repositoryOwner'] as Map) + ..viewer = json['viewer'] == null + ? null + : GithubUserUser.fromJson(json['viewer'] as Map); } Map _$GithubUserToJson(GithubUser instance) => { 'repositoryOwner': instance.repositoryOwner?.toJson(), + 'viewer': instance.viewer?.toJson(), }; GithubUserRepositoryOwner _$GithubUserRepositoryOwnerFromJson( @@ -546,6 +550,7 @@ Map _$GithubUserMemberStatusableToJson( GithubUserArguments _$GithubUserArgumentsFromJson(Map json) { return GithubUserArguments( login: json['login'] as String, + isViewer: json['isViewer'] as bool, ); } @@ -553,4 +558,5 @@ Map _$GithubUserArgumentsToJson( GithubUserArguments instance) => { 'login': instance.login, + 'isViewer': instance.isViewer, }; diff --git a/lib/graphql/github_user.graphql b/lib/graphql/github_user.graphql index a5c5219..b1a83f8 100644 --- a/lib/graphql/github_user.graphql +++ b/lib/graphql/github_user.graphql @@ -1,5 +1,5 @@ -query($login: String!) { - repositoryOwner(login: $login) { +query($login: String!, $isViewer: Boolean!) { + repositoryOwner(login: $login) @skip(if: $isViewer) { __typename login avatarUrl @@ -149,4 +149,37 @@ query($login: String!) { } } } + viewer @include(if: $isViewer) { + login + avatarUrl + url + name + bio + company + location + email + websiteUrl + createdAt + starredRepositories { + totalCount + } + followers { + totalCount + } + following { + totalCount + } + repositories { + totalCount + } + contributionsCollection { + contributionCalendar { + weeks { + contributionDays { + color + } + } + } + } + } } diff --git a/lib/main.dart b/lib/main.dart index 0a3f768..0c693f3 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -13,7 +13,6 @@ import 'package:git_touch/screens/gitlab_tree.dart'; import 'package:git_touch/screens/gitlab_user.dart'; import 'package:git_touch/screens/issue_form.dart'; import 'package:git_touch/screens/issues.dart'; -import 'package:git_touch/screens/me.dart'; import 'package:git_touch/screens/notification.dart'; import 'package:git_touch/screens/object.dart'; import 'package:git_touch/screens/repository.dart'; @@ -129,7 +128,7 @@ class _HomeState extends State { case 3: return SearchScreen(); case 4: - return MeScreen(); + return UserScreen(''); } break; case PlatformType.gitlab: diff --git a/lib/screens/me.dart b/lib/screens/me.dart deleted file mode 100644 index 6820191..0000000 --- a/lib/screens/me.dart +++ /dev/null @@ -1,158 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:git_touch/graphql/github_me.dart'; -import 'package:git_touch/models/theme.dart'; -import 'package:git_touch/scaffolds/refresh_stateful.dart'; -import 'package:git_touch/utils/utils.dart'; -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_item.dart'; -import 'package:git_touch/models/auth.dart'; -import 'package:provider/provider.dart'; - -class MeScreen extends StatelessWidget { - @override - Widget build(BuildContext context) { - return RefreshStatefulScaffold( - fetchData: () async { - final data = await Provider.of(context) - .gqlClient - .execute(GithubMeQuery()); - return data.data.viewer; - }, - title: AppBarTitle('Me'), - bodyBuilder: (user, _) { - final theme = Provider.of(context); - final login = user.login; - - return Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - UserItem( - login: user.login, - name: user.name, - avatarUrl: user.avatarUrl, - bio: Text(user.bio ?? ''), - inUserScreen: true, - ), - CommonStyle.border, - Row(children: [ - EntryItem( - count: user.repositories.totalCount, - text: 'Repositories', - url: '/$login?tab=repositories', - ), - EntryItem( - count: user.starredRepositories.totalCount, - text: 'Stars', - url: '/$login?tab=stars', - ), - EntryItem( - count: user.followers.totalCount, - text: 'Followers', - url: '/$login?tab=followers', - ), - EntryItem( - count: user.following.totalCount, - text: 'Following', - url: '/$login?tab=following', - ), - ]), - CommonStyle.verticalGap, - 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, - items: [ - if (isNotNullOrEmpty(user.company)) - TableViewItem( - leftIconData: Octicons.organization, - text: TextContainsOrganization( - user.company, - style: TextStyle(fontSize: 16, color: theme.palette.text), - oneLine: true, - ), - ), - if (isNotNullOrEmpty(user.location)) - TableViewItem( - leftIconData: Octicons.location, - text: Text(user.location), - onTap: () { - launchUrl('https://www.google.com/maps/place/' + - user.location.replaceAll(RegExp(r'\s+'), '')); - }, - ), - if (isNotNullOrEmpty(user.email)) - TableViewItem( - leftIconData: Octicons.mail, - text: Text(user.email), - onTap: () { - launchUrl('mailto:' + user.email); - }, - ), - if (isNotNullOrEmpty(user.websiteUrl)) - TableViewItem( - leftIconData: Octicons.link, - text: Text(user.websiteUrl), - onTap: () { - var url = user.websiteUrl; - if (!url.startsWith('http')) { - url = 'http://$url'; - } - launchUrl(url); - }, - ), - ], - ), - CommonStyle.verticalGap, - TableView( - hasIcon: true, - items: [ - TableViewItem( - leftIconData: Octicons.settings, - text: Text('Settings'), - url: '/settings', - ), - ], - ), - CommonStyle.verticalGap, - ], - ); - }, - ); - } -} diff --git a/lib/screens/user.dart b/lib/screens/user.dart index 94d5f9a..b294836 100644 --- a/lib/screens/user.dart +++ b/lib/screens/user.dart @@ -43,6 +43,8 @@ class UserScreen extends StatelessWidget { UserScreen(this.login); + bool get isViewer => login.isEmpty; + Iterable _buildPinnedItems(Iterable pinnedItems, Iterable repositories) { String title; @@ -58,7 +60,6 @@ class UserScreen extends StatelessWidget { if (items.isEmpty) return []; return [ - CommonStyle.verticalGap, if (title != null) TableViewHeader(title), ...join( CommonStyle.border, @@ -70,7 +71,7 @@ class UserScreen extends StatelessWidget { } Widget _buildHeader(BuildContext context, String avatarUrl, String name, - DateTime createdAt, String bio) { + String login, DateTime createdAt, String bio) { final theme = Provider.of(context); return Container( @@ -153,8 +154,8 @@ class UserScreen extends StatelessWidget { return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - _buildHeader( - context, user.avatarUrl, user.name, user.createdAt, user.bio), + _buildHeader(context, user.avatarUrl, user.name, user.login, + user.createdAt, user.bio), CommonStyle.border, Row(children: [ EntryItem( @@ -255,11 +256,24 @@ class UserScreen extends StatelessWidget { ), ], ), - ..._buildPinnedItems( - user.pinnedItems.nodes - .where((n) => n is GithubUserRepository) - .cast(), - user.repositories.nodes), + CommonStyle.verticalGap, + if (isViewer) + TableView( + hasIcon: true, + items: [ + TableViewItem( + leftIconData: Octicons.settings, + text: Text('Settings'), + url: '/settings', + ), + ], + ) + else + ..._buildPinnedItems( + user.pinnedItems.nodes + .where((n) => n is GithubUserRepository) + .cast(), + user.repositories.nodes), CommonStyle.verticalGap, ], ); @@ -270,19 +284,19 @@ class UserScreen extends StatelessWidget { return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - _buildHeader(context, payload.avatarUrl, payload.name, + _buildHeader(context, payload.avatarUrl, payload.name, payload.login, payload.createdAt, payload.description), CommonStyle.border, Row(children: [ EntryItem( count: payload.pinnableItems.totalCount, text: 'Repositories', - url: '/$login?tab=repositories', + url: '/${payload.login}?tab=repositories', ), EntryItem( count: payload.membersWithRole.totalCount, text: 'Members', - url: '/$login?tab=people', + url: '/${payload.login}?tab=people', ), ]), CommonStyle.verticalGap, @@ -320,6 +334,7 @@ class UserScreen extends StatelessWidget { ), ], ), + CommonStyle.verticalGap, ..._buildPinnedItems( payload.pinnedItems.nodes .where((n) => n is GithubUserRepository) @@ -338,10 +353,12 @@ class UserScreen extends StatelessWidget { return RefreshStatefulScaffold( fetchData: () async { final data = await Provider.of(context).gqlClient.execute( - GithubUserQuery(variables: GithubUserArguments(login: login))); - return data.data.repositoryOwner; + GithubUserQuery( + variables: + GithubUserArguments(login: login, isViewer: isViewer))); + return isViewer ? data.data.viewer : data.data.repositoryOwner; }, - title: AppBarTitle('User'), // TODO: + title: AppBarTitle(isViewer ? 'Me' : 'User'), // TODO: actionBuilder: (payload, _) { if (payload == null) return ActionButton( @@ -361,11 +378,12 @@ class UserScreen extends StatelessWidget { onPress: (_) async { if (user.viewerIsFollowing) { await Provider.of(context) - .deleteWithCredentials('/user/following/$login'); + .deleteWithCredentials( + '/user/following/${user.login}'); user.viewerIsFollowing = false; } else { - Provider.of(context) - .putWithCredentials('/user/following/$login'); + Provider.of(context).putWithCredentials( + '/user/following/${user.login}'); user.viewerIsFollowing = true; } }, @@ -392,6 +410,9 @@ class UserScreen extends StatelessWidget { } }, bodyBuilder: (payload, _) { + if (isViewer) { + return _buildUser(context, payload as GithubUserUser); + } switch (payload.resolveType) { case 'User': return _buildUser(context, payload as GithubUserUser);