1
0
mirror of https://github.com/git-touch/git-touch synced 2025-03-23 22:50:05 +01:00

refactor: user and organization screen

This commit is contained in:
Rongjian Zhang 2019-10-06 21:27:00 +08:00
parent 72649bb98e
commit 1f301ab3ef
6 changed files with 129 additions and 191 deletions

View File

@ -15,7 +15,6 @@ import 'screens/news.dart';
import 'screens/search.dart';
import 'screens/login.dart';
import 'screens/issue.dart';
import 'screens/organization.dart';
import 'screens/trending.dart';
import 'utils/utils.dart';
@ -106,7 +105,7 @@ class _HomeState extends State<Home> {
case 3:
return SearchScreen();
case 4:
return UserScreen.self();
return UserScreen(null);
}
}

View File

@ -1,140 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:git_touch/scaffolds/refresh_stateful.dart';
import 'package:git_touch/screens/repositories.dart';
import 'package:git_touch/screens/users.dart';
import 'package:git_touch/widgets/app_bar_title.dart';
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/user_item.dart';
import 'package:git_touch/models/auth.dart';
import 'package:provider/provider.dart';
import 'package:git_touch/widgets/action_button.dart';
import '../utils/utils.dart';
class OrganizationScreen extends StatelessWidget {
final String login;
OrganizationScreen(this.login);
@override
Widget build(BuildContext context) {
return RefreshStatefulScaffold(
fetchData: () async {
// Use pinnableItems instead of organization here due to token permission
var data = await Provider.of<AuthModel>(context).query('''
{
organization(login: "$login") {
name
avatarUrl
description
location
email
websiteUrl
url
pinnedItems(first: 6) {
nodes {
... on Repository {
$repoChunk
}
}
}
pinnableItems(first: 6, types: [REPOSITORY]) {
totalCount
nodes {
... on Repository {
$repoChunk
}
}
}
membersWithRole {
totalCount
}
}
}
''');
return data['organization'];
},
title: AppBarTitle('Organization'),
actionBuilder: (payload) {
return ActionButton(
title: 'Organization Actions',
items: [
if (payload.data != null) ...[
ActionItem.share(payload.data['url']),
ActionItem.launch(payload.data['url']),
],
],
);
},
bodyBuilder: (payload) {
var data = payload.data;
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
UserItem(
login: login,
name: data['name'],
avatarUrl: data['avatarUrl'],
bio: data['description'],
),
CommonStyle.border,
Row(children: <Widget>[
EntryItem(
count: data['pinnableItems']['totalCount'],
text: 'Repositories',
screenBuilder: (context) =>
RepositoriesScreen.ofOrganization(login),
),
EntryItem(
count: data['membersWithRole']['totalCount'],
text: 'Members',
screenBuilder: (context) => UsersScreen.members(login),
),
]),
CommonStyle.verticalGap,
TableView(
hasIcon: true,
items: [
if (isNotNullOrEmpty(data['location']))
TableViewItem(
leftIconData: Octicons.location,
text: Text(data['location']),
onTap: () {
launchUrl('https://www.google.com/maps/place/' +
(data['location'] as String)
.replaceAll(RegExp(r'\s+'), ''));
},
),
if (isNotNullOrEmpty(data['email']))
TableViewItem(
leftIconData: Octicons.mail,
text: Text(data['email']),
onTap: () {
launchUrl('mailto:' + data['email']);
},
),
if (isNotNullOrEmpty(data['websiteUrl']))
TableViewItem(
leftIconData: Octicons.link,
text: Text(data['websiteUrl']),
onTap: () {
var url = data['websiteUrl'] as String;
if (!url.startsWith('http')) {
url = 'http://$url';
}
launchUrl(url);
},
),
],
),
...buildPinnedItems(
data['pinnedItems']['nodes'], data['pinnableItems']['nodes']),
],
);
},
);
}
}

View File

@ -2,31 +2,31 @@ import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:git_touch/models/theme.dart';
import 'package:git_touch/scaffolds/refresh_stateful.dart';
import 'package:git_touch/screens/repositories.dart';
import 'package:git_touch/screens/settings.dart';
import 'package:git_touch/screens/users.dart';
import 'package:git_touch/utils/utils.dart';
import 'package:git_touch/widgets/action_entry.dart';
import 'package:git_touch/widgets/app_bar_title.dart';
import 'package:git_touch/screens/repositories.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:primer/primer.dart';
import 'package:github_contributions/github_contributions.dart';
import 'package:git_touch/models/auth.dart';
import 'package:provider/provider.dart';
import '../widgets/entry_item.dart';
import 'package:git_touch/widgets/repository_item.dart';
import 'package:git_touch/widgets/action_button.dart';
import '../screens/users.dart';
import '../screens/settings.dart';
import '../utils/utils.dart';
import 'package:primer/primer.dart';
class UserScreen extends StatelessWidget {
final String login;
final bool isOrganization;
UserScreen(this.login);
UserScreen.self() : login = null;
UserScreen(this.login, {this.isOrganization = false});
Future query(BuildContext context) async {
Future queryUser(BuildContext context) async {
var _login = login ?? Provider.of<AuthModel>(context).activeAccount.login;
var data = await Provider.of<AuthModel>(context).query('''
{
@ -67,6 +67,43 @@ class UserScreen extends StatelessWidget {
return data['user'];
}
Future queryOrganization(BuildContext context) async {
// Use pinnableItems instead of organization here due to token permission
var data = await Provider.of<AuthModel>(context).query('''
{
organization(login: "$login") {
login
name
avatarUrl
description
location
email
websiteUrl
url
pinnedItems(first: 6) {
nodes {
... on Repository {
$repoChunk
}
}
}
pinnableItems(first: 6, types: [REPOSITORY]) {
totalCount
nodes {
... on Repository {
$repoChunk
}
}
}
membersWithRole {
totalCount
}
}
}
''');
return data['organization'];
}
Future<List<ContributionsInfo>> fetchContributions(
BuildContext context) async {
var _login = login ?? Provider.of<AuthModel>(context).activeAccount.login;
@ -87,12 +124,33 @@ class UserScreen extends StatelessWidget {
return RefreshStatefulScaffold(
fetchData: () {
return Future.wait(
[query(context), fetchContributions(context)],
isOrganization
? [
queryOrganization(context),
Future.value([].cast<ContributionsInfo>())
]
: [
queryUser(context),
fetchContributions(context),
],
);
},
title: AppBarTitle('User'),
title: AppBarTitle(isOrganization ? 'Organization' : 'User'),
actionBuilder: (payload) {
var data = payload.data;
if (isOrganization) {
return ActionButton(
title: 'Organization Actions',
items: [
if (data != null) ...[
ActionItem.share(payload.data[0]['url']),
ActionItem.launch(payload.data[0]['url']),
],
],
);
}
if (login == null) {
return ActionEntry(
iconData: Icons.settings,
@ -131,36 +189,57 @@ class UserScreen extends StatelessWidget {
},
bodyBuilder: (payload) {
var data = payload.data[0];
var contributions = payload.data[1] as List<ContributionsInfo>;
var _login =
login ?? Provider.of<AuthModel>(context).activeAccount.login;
var contributions = payload.data[1];
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
UserItem.fromData(data, inUserScreen: true),
UserItem(
login: data['login'],
name: data['name'],
avatarUrl: data['avatarUrl'],
bio: isOrganization ? data['description'] : data['bio'],
inUserScreen: true,
),
CommonStyle.border,
Row(children: <Widget>[
EntryItem(
count: data['repositories']['totalCount'],
text: 'Repositories',
screenBuilder: (context) => RepositoriesScreen(_login),
),
EntryItem(
count: data['starredRepositories']['totalCount'],
text: 'Stars',
screenBuilder: (context) => RepositoriesScreen.stars(_login),
),
EntryItem(
count: data['followers']['totalCount'],
text: 'Followers',
screenBuilder: (context) => UsersScreen.followers(_login),
),
EntryItem(
count: data['following']['totalCount'],
text: 'Following',
screenBuilder: (context) => UsersScreen.following(_login),
),
Row(children: [
if (isOrganization) ...[
EntryItem(
count: data['pinnableItems']['totalCount'],
text: 'Repositories',
screenBuilder: (context) =>
RepositoriesScreen.ofOrganization(data['login']),
),
EntryItem(
count: data['membersWithRole']['totalCount'],
text: 'Members',
screenBuilder: (context) =>
UsersScreen.members(data['login']),
),
] else ...[
EntryItem(
count: data['repositories']['totalCount'],
text: 'Repositories',
screenBuilder: (context) => RepositoriesScreen(data['login']),
),
EntryItem(
count: data['starredRepositories']['totalCount'],
text: 'Stars',
screenBuilder: (context) =>
RepositoriesScreen.stars(data['login']),
),
EntryItem(
count: data['followers']['totalCount'],
text: 'Followers',
screenBuilder: (context) =>
UsersScreen.followers(data['login']),
),
EntryItem(
count: data['following']['totalCount'],
text: 'Following',
screenBuilder: (context) =>
UsersScreen.following(data['login']),
),
]
]),
CommonStyle.verticalGap,
if (contributions.isNotEmpty) ...[
@ -170,7 +249,7 @@ class UserScreen extends StatelessWidget {
TableView(
hasIcon: true,
items: [
if (isNotNullOrEmpty(data['company']))
if (!isOrganization && isNotNullOrEmpty(data['company']))
TableViewItem(
leftIconData: Octicons.organization,
text: TextContainsOrganization(data['company'],
@ -211,7 +290,9 @@ class UserScreen extends StatelessWidget {
],
),
...buildPinnedItems(
data['pinnedItems']['nodes'], data['repositories']['nodes']),
data['pinnedItems']['nodes'],
data[isOrganization ? 'pinnableItems' : 'repositories']
['nodes']),
CommonStyle.verticalGap,
],
);

View File

@ -1,6 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:git_touch/screens/organization.dart';
import 'package:git_touch/screens/repository.dart';
import 'package:git_touch/screens/user.dart';
import 'package:git_touch/widgets/avatar.dart';
@ -135,10 +134,11 @@ class RepositoryItem extends StatelessWidget {
children: <Widget>[
Link(
child: Avatar.small(url: payload['owner']['avatarUrl']),
screenBuilder: (_) =>
payload['owner']['__typename'] == 'Organization'
? OrganizationScreen(payload['owner']['login'])
: UserScreen(payload['owner']['login']),
screenBuilder: (_) => UserScreen(
payload['owner']['login'],
isOrganization:
payload['owner']['__typename'] == 'Organization',
),
),
SizedBox(width: 8),
Expanded(

View File

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:git_touch/screens/organization.dart';
import 'package:git_touch/screens/user.dart';
import 'package:git_touch/utils/utils.dart';
class TextContainsOrganization extends StatelessWidget {
@ -23,7 +23,7 @@ class TextContainsOrganization extends StatelessWidget {
spans.add(TextSpan(text: chunks[index]));
}
spans.add(createLinkSpan(context, orgs[index],
(_) => OrganizationScreen(orgs[index].substring(1))));
(_) => UserScreen(orgs[index].substring(1), isOrganization: true)));
}
if (chunks.last.isNotEmpty) {
spans.add(TextSpan(text: chunks.last));

View File

@ -1,5 +1,4 @@
import 'package:flutter/material.dart';
import 'package:git_touch/screens/organization.dart';
import 'package:git_touch/screens/user.dart';
import 'package:git_touch/utils/utils.dart';
import 'package:git_touch/widgets/avatar.dart';
@ -44,8 +43,7 @@ class UserItem extends StatelessWidget {
return Link(
screenBuilder: inUserScreen
? null
: (_) =>
isOrganization ? OrganizationScreen(login) : UserScreen(login),
: (_) => UserScreen(login, isOrganization: isOrganization),
child: Container(
padding: CommonStyle.padding,
child: Row(