refactor: list scaffold

This commit is contained in:
Rongjian Zhang 2020-10-04 22:10:05 +08:00
parent 2d9610170b
commit 1fe7e1fdc9
29 changed files with 411 additions and 502 deletions

View File

@ -26,13 +26,11 @@ class ListStatefulScaffold<T, K> extends StatefulWidget {
final Widget title;
final Widget Function() actionBuilder;
final Widget Function(T payload) itemBuilder;
final Future<ListPayload<T, K>> Function() onRefresh;
final Future<ListPayload<T, K>> Function(K cursor) onLoadMore;
ListStatefulScaffold({
@required this.title,
@required this.itemBuilder,
@required this.onRefresh,
@required this.onLoadMore,
this.actionBuilder,
});
@ -97,7 +95,7 @@ class _ListStatefulScaffoldState<T, K>
}
});
try {
var _payload = await widget.onRefresh();
var _payload = await widget.onLoadMore(null);
items = _payload.items;
cursor = _payload.cursor;
hasMore = _payload.hasMore;

View File

@ -12,27 +12,22 @@ class BbCommitsScreen extends StatelessWidget {
final String ref;
BbCommitsScreen(this.owner, this.name, this.ref);
Future<ListPayload<BbCommit, String>> _query(BuildContext context,
[String nextUrl]) async {
final res = await context
.read<AuthModel>()
.fetchBbWithPage(nextUrl ?? '/repositories/$owner/$name/commits/$ref');
return ListPayload(
cursor: res.cursor,
hasMore: res.hasMore,
items: <BbCommit>[
for (var v in res.data) BbCommit.fromJson(v),
],
);
}
@override
Widget build(BuildContext context) {
final auth = Provider.of<AuthModel>(context);
return ListStatefulScaffold<BbCommit, String>(
title: AppBarTitle('Commits'),
onRefresh: () => _query(context),
onLoadMore: (page) => _query(context, page),
onLoadMore: (nextUrl) async {
final res = await context.read<AuthModel>().fetchBbWithPage(
nextUrl ?? '/repositories/$owner/$name/commits/$ref');
return ListPayload(
cursor: res.cursor,
hasMore: res.hasMore,
items: <BbCommit>[
for (var v in res.data) BbCommit.fromJson(v),
],
);
},
itemBuilder: (v) {
return CommitItem(
url: '${auth.activeAccount.domain}/$owner/$name/commits/${v.hash}',

View File

@ -7,25 +7,21 @@ import 'package:git_touch/widgets/repository_item.dart';
import 'package:provider/provider.dart';
class BbExploreScreen extends StatelessWidget {
Future<ListPayload<BbRepo, String>> _query(BuildContext context,
[String nextUrl]) async {
final res = await context.read<AuthModel>().fetchBbWithPage(
nextUrl ?? '/repositories?role=member&sort=-updated_on');
return ListPayload(
cursor: res.cursor,
hasMore: res.hasMore,
items: <BbRepo>[
for (var v in res.data) BbRepo.fromJson(v),
],
);
}
@override
Widget build(BuildContext context) {
return ListStatefulScaffold<BbRepo, String>(
title: AppBarTitle('Explore'),
onRefresh: () => _query(context),
onLoadMore: (page) => _query(context, page),
onLoadMore: (nextUrl) async {
final res = await context.read<AuthModel>().fetchBbWithPage(
nextUrl ?? '/repositories?role=member&sort=-updated_on');
return ListPayload(
cursor: res.cursor,
hasMore: res.hasMore,
items: <BbRepo>[
for (var v in res.data) BbRepo.fromJson(v),
],
);
},
itemBuilder: (v) {
return RepositoryItem.bb(payload: v);
},

View File

@ -12,27 +12,23 @@ class BbIssuesScreen extends StatelessWidget {
final String ref;
BbIssuesScreen(this.owner, this.name, this.ref);
Future<ListPayload<BbIssues, String>> _query(BuildContext context,
[String nextUrl]) async {
final res = await context
.read<AuthModel>()
.fetchBbWithPage(nextUrl ?? '/repositories/$owner/$name/issues');
return ListPayload(
cursor: res.cursor,
hasMore: res.hasMore,
items: <BbIssues>[
for (var v in res.data) BbIssues.fromJson(v),
],
);
}
@override
Widget build(BuildContext context) {
final auth = Provider.of<AuthModel>(context);
return ListStatefulScaffold<BbIssues, String>(
title: AppBarTitle('Issues'),
onRefresh: () => _query(context),
onLoadMore: (page) => _query(context, page),
onLoadMore: (nextUrl) async {
final res = await context
.read<AuthModel>()
.fetchBbWithPage(nextUrl ?? '/repositories/$owner/$name/issues');
return ListPayload(
cursor: res.cursor,
hasMore: res.hasMore,
items: <BbIssues>[
for (var v in res.data) BbIssues.fromJson(v),
],
);
},
itemBuilder: (v) {
int issueNumber =
int.parse(v.issueLink.replaceFirst(RegExp(r'.*\/'), ''));

View File

@ -12,27 +12,22 @@ class BbPullsScreen extends StatelessWidget {
final String ref;
BbPullsScreen(this.owner, this.name, this.ref);
Future<ListPayload<BbPulls, String>> _query(BuildContext context,
[String nextUrl]) async {
final res = await context
.read<AuthModel>()
.fetchBbWithPage(nextUrl ?? '/repositories/$owner/$name/pullrequests');
return ListPayload(
cursor: res.cursor,
hasMore: res.hasMore,
items: <BbPulls>[
for (var v in res.data) BbPulls.fromJson(v),
],
);
}
@override
Widget build(BuildContext context) {
final auth = Provider.of<AuthModel>(context);
return ListStatefulScaffold<BbPulls, String>(
title: AppBarTitle('Pull requests'),
onRefresh: () => _query(context),
onLoadMore: (page) => _query(context, page),
onLoadMore: (nextUrl) async {
final res = await context.read<AuthModel>().fetchBbWithPage(
nextUrl ?? '/repositories/$owner/$name/pullrequests');
return ListPayload(
cursor: res.cursor,
hasMore: res.hasMore,
items: <BbPulls>[
for (var v in res.data) BbPulls.fromJson(v),
],
);
},
itemBuilder: (v) {
int pullNumber =
int.parse(v.pullRequestLink.replaceFirst(RegExp(r'.*\/'), ''));

View File

@ -8,26 +8,22 @@ import 'package:provider/provider.dart';
import 'package:timeago/timeago.dart' as timeago;
class BbTeamsScreen extends StatelessWidget {
Future<ListPayload<BbUser, String>> _query(BuildContext context,
[String nextUrl]) async {
final res = await context
.read<AuthModel>()
.fetchBbWithPage(nextUrl ?? '/teams?role=member');
return ListPayload(
cursor: res.cursor,
hasMore: res.hasMore,
items: <BbUser>[
for (var v in res.data) BbUser.fromJson(v),
],
);
}
@override
Widget build(BuildContext context) {
return ListStatefulScaffold<BbUser, String>(
title: AppBarTitle('Teams'),
onRefresh: () => _query(context),
onLoadMore: (page) => _query(context, page),
onLoadMore: (nextUrl) async {
final res = await context
.read<AuthModel>()
.fetchBbWithPage(nextUrl ?? '/teams?role=member');
return ListPayload(
cursor: res.cursor,
hasMore: res.hasMore,
items: <BbUser>[
for (var v in res.data) BbUser.fromJson(v),
],
);
},
itemBuilder: (v) {
return UserItem(
login: v.username,

View File

@ -13,25 +13,6 @@ class GhCommitsScreen extends StatelessWidget {
final String branch;
GhCommitsScreen(this.owner, this.name, {this.branch});
Future<ListPayload<GhCommitsCommit, String>> _query(BuildContext context,
[String cursor]) async {
final res = await context.read<AuthModel>().gqlClient.execute(
GhCommitsQuery(
variables: GhCommitsArguments(
owner: owner,
name: name,
hasRef: branch != null,
ref: branch ?? '',
after: cursor)));
final ref = res.data.repository.defaultBranchRef ?? res.data.repository.ref;
final history = (ref.target as GhCommitsCommit).history;
return ListPayload(
cursor: history.pageInfo.endCursor,
hasMore: history.pageInfo.hasNextPage,
items: history.nodes,
);
}
Widget _buildStatus(GhCommitsStatusState state) {
const size = 18.0;
switch (state) {
@ -48,8 +29,24 @@ class GhCommitsScreen extends StatelessWidget {
Widget build(BuildContext context) {
return ListStatefulScaffold<GhCommitsCommit, String>(
title: AppBarTitle('Commits'),
onRefresh: () => _query(context),
onLoadMore: (cursor) => _query(context, cursor),
onLoadMore: (cursor) async {
final res = await context.read<AuthModel>().gqlClient.execute(
GhCommitsQuery(
variables: GhCommitsArguments(
owner: owner,
name: name,
hasRef: branch != null,
ref: branch ?? '',
after: cursor)));
final ref =
res.data.repository.defaultBranchRef ?? res.data.repository.ref;
final history = (ref.target as GhCommitsCommit).history;
return ListPayload(
cursor: history.pageInfo.endCursor,
hasMore: history.pageInfo.hasNextPage,
items: history.nodes,
);
},
itemBuilder: (payload) {
final login = payload.author?.user?.login;
return CommitItem(

View File

@ -12,28 +12,25 @@ class GhContributorsScreen extends StatelessWidget {
final String name;
GhContributorsScreen(this.owner, this.name);
Future<ListPayload<GithubContributorItem, int>> _query(BuildContext context,
[int page = 1]) async {
final res = await context
.read<AuthModel>()
.ghClient
.getJSON<List, List<GithubContributorItem>>(
'/repos/$owner/$name/contributors?page=$page',
convert: (vs) =>
[for (var v in vs) GithubContributorItem.fromJson(v)],
);
return ListPayload(
cursor: page + 1,
items: res,
hasMore: res.isNotEmpty,
);
}
Widget build(BuildContext context) {
return ListStatefulScaffold<GithubContributorItem, int>(
title: AppBarTitle('Contributors'),
onRefresh: () => _query(context),
onLoadMore: (cursor) => _query(context, cursor),
onLoadMore: (page) async {
page = page ?? 1;
final res = await context
.read<AuthModel>()
.ghClient
.getJSON<List, List<GithubContributorItem>>(
'/repos/$owner/$name/contributors?page=$page',
convert: (vs) =>
[for (var v in vs) GithubContributorItem.fromJson(v)],
);
return ListPayload(
cursor: page + 1,
items: res,
hasMore: res.isNotEmpty,
);
},
itemBuilder: (v) {
final String login = v.login;
return ContributorItem(

View File

@ -12,25 +12,22 @@ class GhEventsScreen extends StatelessWidget {
final String login;
GhEventsScreen(this.login);
Future<ListPayload<GithubEvent, int>> fetchEvents(BuildContext context,
[int page = 1]) async {
final events = await context.read<AuthModel>().ghClient.getJSON(
'/users/$login/events?page=$page&per_page=$pageSize',
convert: (vs) => [for (var v in vs) GithubEvent.fromJson(v)]);
return ListPayload(
cursor: page + 1,
hasMore: events.length == pageSize,
items: events,
);
}
@override
Widget build(context) {
return ListStatefulScaffold<GithubEvent, int>(
title: AppBarTitle('Events'),
itemBuilder: (payload) => EventItem(payload),
onRefresh: () => fetchEvents(context),
onLoadMore: (page) => fetchEvents(context, page),
onLoadMore: (page) async {
page = page ?? 1;
final events = await context.read<AuthModel>().ghClient.getJSON(
'/users/$login/events?page=$page&per_page=$pageSize',
convert: (vs) => [for (var v in vs) GithubEvent.fromJson(v)]);
return ListPayload(
cursor: page + 1,
hasMore: events.length == pageSize,
items: events,
);
},
);
}
}

View File

@ -14,22 +14,6 @@ class GhFilesScreen extends StatelessWidget {
final int pullNumber;
GhFilesScreen(this.owner, this.name, this.pullNumber);
Future<ListPayload<GithubFilesItem, int>> _query(BuildContext context,
[int page = 1]) async {
final res = await context
.read<AuthModel>()
.ghClient
.getJSON<List, List<GithubFilesItem>>(
'/repos/$owner/$name/pulls/$pullNumber/files?page=$page',
convert: (vs) => [for (var v in vs) GithubFilesItem.fromJson(v)],
);
return ListPayload(
cursor: page + 1,
items: res,
hasMore: res.isNotEmpty,
);
}
Widget build(BuildContext context) {
return ListStatefulScaffold<GithubFilesItem, int>(
title: AppBarTitle('Files'),
@ -42,8 +26,21 @@ class GhFilesScreen extends StatelessWidget {
],
);
},
onRefresh: () => _query(context),
onLoadMore: (cursor) => _query(context, cursor),
onLoadMore: (page) async {
page = page ?? 1;
final res = await context
.read<AuthModel>()
.ghClient
.getJSON<List, List<GithubFilesItem>>(
'/repos/$owner/$name/pulls/$pullNumber/files?page=$page',
convert: (vs) => [for (var v in vs) GithubFilesItem.fromJson(v)],
);
return ListPayload(
cursor: page + 1,
items: res,
hasMore: res.isNotEmpty,
);
},
itemBuilder: (v) {
return FilesItem(
filename: v.filename,

View File

@ -11,28 +11,25 @@ class GhGistsScreen extends StatelessWidget {
final String login;
GhGistsScreen(this.login);
Future<ListPayload<GithubGistsItem, int>> _query(BuildContext context,
[int page = 1]) async {
final res = await context
.read<AuthModel>()
.ghClient
.getJSON<List, List<GithubGistsItem>>(
'/users/$login/gists?page=$page',
convert: (vs) => [for (var v in vs) GithubGistsItem.fromJson(v)],
);
return ListPayload(
cursor: page + 1,
items: res,
hasMore: res.isNotEmpty,
);
}
@override
Widget build(BuildContext context) {
return ListStatefulScaffold<GithubGistsItem, int>(
title: AppBarTitle('Gists'),
onRefresh: () => _query(context),
onLoadMore: (cursor) => _query(context, cursor),
onLoadMore: (page) async {
page = page ?? 1;
final res = await context
.read<AuthModel>()
.ghClient
.getJSON<List, List<GithubGistsItem>>(
'/users/$login/gists?page=$page',
convert: (vs) => [for (var v in vs) GithubGistsItem.fromJson(v)],
);
return ListPayload(
cursor: page + 1,
items: res,
hasMore: res.isNotEmpty,
);
},
itemBuilder: (v) {
return GistsItem(
description: v.description,

View File

@ -14,22 +14,6 @@ class GhIssuesScreen extends StatelessWidget {
final String name;
GhIssuesScreen(this.owner, this.name);
Future<ListPayload<GhIssuesIssue, String>> _query(BuildContext context,
[String cursor]) async {
final res = await context.read<AuthModel>().gqlClient.execute(GhIssuesQuery(
variables: GhIssuesArguments(
owner: owner,
name: name,
cursor: cursor,
)));
final issues = res.data.repository.issues;
return ListPayload(
cursor: issues.pageInfo.endCursor,
hasMore: issues.pageInfo.hasNextPage,
items: issues.nodes,
);
}
@override
Widget build(BuildContext context) {
return ListStatefulScaffold<GhIssuesIssue, String>(
@ -38,8 +22,21 @@ class GhIssuesScreen extends StatelessWidget {
iconData: Octicons.plus,
url: '/github/$owner/$name/issues/new',
),
onRefresh: () => _query(context),
onLoadMore: (cursor) => _query(context, cursor),
onLoadMore: (cursor) async {
final res =
await context.read<AuthModel>().gqlClient.execute(GhIssuesQuery(
variables: GhIssuesArguments(
owner: owner,
name: name,
cursor: cursor,
)));
final issues = res.data.repository.issues;
return ListPayload(
cursor: issues.pageInfo.endCursor,
hasMore: issues.pageInfo.hasNextPage,
items: issues.nodes,
);
},
itemBuilder: (p) => IssueItem(
author: p.author?.login,
avatarUrl: p.author?.avatarUrl,

View File

@ -32,28 +32,26 @@ class GhNewsScreenState extends State<GhNewsScreen> {
});
}
Future<ListPayload<GithubEvent, int>> fetchEvents([int page = 1]) async {
final auth = context.read<AuthModel>();
final login = auth.activeAccount.login;
final events = await auth.ghClient.getJSON(
'/users/$login/received_events?page=$page&per_page=$pageSize',
convert: (vs) => [for (var v in vs) GithubEvent.fromJson(v)],
);
return ListPayload(
cursor: page + 1,
hasMore: events.length == pageSize,
items: events,
);
}
@override
Widget build(context) {
return ListStatefulScaffold<GithubEvent, int>(
title: AppBarTitle('News'),
itemBuilder: (payload) => EventItem(payload),
onRefresh: fetchEvents,
onLoadMore: (page) => fetchEvents(page),
onLoadMore: (page) async {
page = page ?? 1;
final auth = context.read<AuthModel>();
final login = auth.activeAccount.login;
final events = await auth.ghClient.getJSON(
'/users/$login/received_events?page=$page&per_page=$pageSize',
convert: (vs) => [for (var v in vs) GithubEvent.fromJson(v)],
);
return ListPayload(
cursor: page + 1,
hasMore: events.length == pageSize,
items: events,
);
},
);
}
}

View File

@ -16,28 +16,25 @@ class GhOrgReposScreen extends StatelessWidget {
final String owner;
GhOrgReposScreen(this.owner);
Future<ListPayload<Repository, int>> _query(BuildContext context,
[int page = 1]) async {
final rs = await context
.read<AuthModel>()
.ghClient
.getJSON<List, List<Repository>>(
'/orgs/$owner/repos?sort=updated&page=$page',
convert: (vs) => [for (var v in vs) Repository.fromJson(v)],
);
return ListPayload(
cursor: page + 1,
items: rs,
hasMore: rs.isNotEmpty, // TODO:
);
}
@override
Widget build(BuildContext context) {
return ListStatefulScaffold<Repository, int>(
title: AppBarTitle('Repositories'),
onRefresh: () => _query(context),
onLoadMore: (cursor) => _query(context, cursor),
onLoadMore: (page) async {
page = page ?? 1;
final rs = await context
.read<AuthModel>()
.ghClient
.getJSON<List, List<Repository>>(
'/orgs/$owner/repos?sort=updated&page=$page',
convert: (vs) => [for (var v in vs) Repository.fromJson(v)],
);
return ListPayload(
cursor: page + 1,
items: rs,
hasMore: rs.isNotEmpty, // TODO:
);
},
itemBuilder: (v) {
return RepositoryItem.gh(
owner: v.owner.login,

View File

@ -11,29 +11,25 @@ class GhUserOrganizationScreen extends StatelessWidget {
final String login;
GhUserOrganizationScreen(this.login);
Future<ListPayload<GithubUserOrganizationItem, int>> _query(
BuildContext context,
[int page = 1]) async {
final res = await context
.read<AuthModel>()
.ghClient
.getJSON<List, List<GithubUserOrganizationItem>>(
'/users/$login/orgs?page=$page',
convert: (vs) =>
[for (var v in vs) GithubUserOrganizationItem.fromJson(v)],
);
return ListPayload(
cursor: page + 1,
items: res,
hasMore: res.isNotEmpty,
);
}
Widget build(BuildContext context) {
return ListStatefulScaffold<GithubUserOrganizationItem, int>(
title: AppBarTitle('Organizations'),
onRefresh: () => _query(context),
onLoadMore: (cursor) => _query(context, cursor),
onLoadMore: (page) async {
page = page ?? 1;
final res = await context
.read<AuthModel>()
.ghClient
.getJSON<List, List<GithubUserOrganizationItem>>(
'/users/$login/orgs?page=$page',
convert: (vs) =>
[for (var v in vs) GithubUserOrganizationItem.fromJson(v)],
);
return ListPayload(
cursor: page + 1,
items: res,
hasMore: res.isNotEmpty,
);
},
itemBuilder: (v) {
return UserItem.gh(
avatarUrl: v.avatarUrl,

View File

@ -12,28 +12,25 @@ class GhPullsScreen extends StatelessWidget {
final String name;
GhPullsScreen(this.owner, this.name);
Future<ListPayload<GhPullsPullRequest, String>> _query(BuildContext context,
[String cursor]) async {
final res = await context.read<AuthModel>().gqlClient.execute(GhPullsQuery(
variables: GhPullsArguments(
owner: owner,
name: name,
cursor: cursor,
)));
final pulls = res.data.repository.pullRequests;
return ListPayload(
cursor: pulls.pageInfo.endCursor,
hasMore: pulls.pageInfo.hasNextPage,
items: pulls.nodes,
);
}
@override
Widget build(BuildContext context) {
return ListStatefulScaffold<GhPullsPullRequest, String>(
title: AppBarTitle('Pull requests'),
onRefresh: () => _query(context),
onLoadMore: (cursor) => _query(context, cursor),
onLoadMore: (cursor) async {
final res =
await context.read<AuthModel>().gqlClient.execute(GhPullsQuery(
variables: GhPullsArguments(
owner: owner,
name: name,
cursor: cursor,
)));
final pulls = res.data.repository.pullRequests;
return ListPayload(
cursor: pulls.pageInfo.endCursor,
hasMore: pulls.pageInfo.hasNextPage,
items: pulls.nodes,
);
},
itemBuilder: (p) => IssueItem(
isPr: true,
author: p.author?.login,

View File

@ -19,34 +19,30 @@ class GhReposScreen extends StatelessWidget {
: title = 'Stars',
isStar = true;
Future<ListPayload<GhReposRepository, String>> _query(BuildContext context,
[String cursor]) async {
final auth = context.read<AuthModel>();
final res = await auth.gqlClient.execute(GhReposQuery(
variables:
GhReposArguments(owner: owner, isStar: isStar, after: cursor)));
final data = res.data.user;
if (isStar) {
return ListPayload(
cursor: data.starredRepositories.pageInfo.endCursor,
items: data.starredRepositories.nodes,
hasMore: data.starredRepositories.pageInfo.hasNextPage,
);
} else {
return ListPayload(
cursor: data.repositories.pageInfo.endCursor,
items: data.repositories.nodes,
hasMore: data.repositories.pageInfo.hasNextPage,
);
}
}
@override
Widget build(BuildContext context) {
return ListStatefulScaffold<GhReposRepository, String>(
title: AppBarTitle(title),
onRefresh: () => _query(context),
onLoadMore: (cursor) => _query(context, cursor),
onLoadMore: (cursor) async {
final auth = context.read<AuthModel>();
final res = await auth.gqlClient.execute(GhReposQuery(
variables:
GhReposArguments(owner: owner, isStar: isStar, after: cursor)));
final data = res.data.user;
if (isStar) {
return ListPayload(
cursor: data.starredRepositories.pageInfo.endCursor,
items: data.starredRepositories.nodes,
hasMore: data.starredRepositories.pageInfo.hasNextPage,
);
} else {
return ListPayload(
cursor: data.repositories.pageInfo.endCursor,
items: data.repositories.nodes,
hasMore: data.repositories.pageInfo.hasNextPage,
);
}
},
itemBuilder: (v) {
return RepositoryItem.gh(
owner: v.owner.login,

View File

@ -40,61 +40,6 @@ class GhUsersScreen extends StatelessWidget {
}
}
Future<ListPayload<GhUsersUser, String>> _queryUsers(BuildContext context,
[String cursor]) async {
final auth = context.read<AuthModel>();
final res = await auth.gqlClient.execute(GhUsersQuery(
variables: GhUsersArguments(
login: login,
repoName: repoName,
isFollowers: type == UsersScreenType.follower,
isFollowing: type == UsersScreenType.following,
isStar: type == UsersScreenType.star,
isWatch: type == UsersScreenType.watch,
isMember: type == UsersScreenType.member,
after: cursor)));
switch (type) {
case UsersScreenType.follower:
final payload = res.data.user.followers;
return ListPayload(
cursor: payload.pageInfo.endCursor,
hasMore: payload.pageInfo.hasNextPage,
items: payload.nodes,
);
case UsersScreenType.following:
final payload = res.data.user.following;
return ListPayload(
cursor: payload.pageInfo.endCursor,
hasMore: payload.pageInfo.hasNextPage,
items: payload.nodes,
);
case UsersScreenType.member:
final payload = res.data.organization.membersWithRole;
return ListPayload(
cursor: payload.pageInfo.endCursor,
hasMore: payload.pageInfo.hasNextPage,
items: payload.nodes,
);
case UsersScreenType.watch:
final payload = res.data.repository.watchers;
return ListPayload(
cursor: payload.pageInfo.endCursor,
hasMore: payload.pageInfo.hasNextPage,
items: payload.nodes,
);
case UsersScreenType.star:
final payload = res.data.repository.stargazers;
return ListPayload(
cursor: payload.pageInfo.endCursor,
hasMore: payload.pageInfo.hasNextPage,
items: payload.nodes,
);
default:
return null;
}
}
Widget _buildBio(BuildContext context, String company, String location,
DateTime createdAt) {
final theme = Provider.of<ThemeModel>(context);
@ -143,8 +88,59 @@ class GhUsersScreen extends StatelessWidget {
Widget build(BuildContext context) {
return ListStatefulScaffold<GhUsersUser, String>(
title: AppBarTitle(_title),
onRefresh: () => _queryUsers(context),
onLoadMore: (cursor) => _queryUsers(context, cursor),
onLoadMore: (cursor) async {
final auth = context.read<AuthModel>();
final res = await auth.gqlClient.execute(GhUsersQuery(
variables: GhUsersArguments(
login: login,
repoName: repoName,
isFollowers: type == UsersScreenType.follower,
isFollowing: type == UsersScreenType.following,
isStar: type == UsersScreenType.star,
isWatch: type == UsersScreenType.watch,
isMember: type == UsersScreenType.member,
after: cursor)));
switch (type) {
case UsersScreenType.follower:
final payload = res.data.user.followers;
return ListPayload(
cursor: payload.pageInfo.endCursor,
hasMore: payload.pageInfo.hasNextPage,
items: payload.nodes,
);
case UsersScreenType.following:
final payload = res.data.user.following;
return ListPayload(
cursor: payload.pageInfo.endCursor,
hasMore: payload.pageInfo.hasNextPage,
items: payload.nodes,
);
case UsersScreenType.member:
final payload = res.data.organization.membersWithRole;
return ListPayload(
cursor: payload.pageInfo.endCursor,
hasMore: payload.pageInfo.hasNextPage,
items: payload.nodes,
);
case UsersScreenType.watch:
final payload = res.data.repository.watchers;
return ListPayload(
cursor: payload.pageInfo.endCursor,
hasMore: payload.pageInfo.hasNextPage,
items: payload.nodes,
);
case UsersScreenType.star:
final payload = res.data.repository.stargazers;
return ListPayload(
cursor: payload.pageInfo.endCursor,
hasMore: payload.pageInfo.hasNextPage,
items: payload.nodes,
);
default:
return null;
}
},
itemBuilder: (payload) {
return UserItem.gh(
login: payload.login,

View File

@ -12,24 +12,22 @@ class GlCommitsScreen extends StatelessWidget {
// final String branch; // TODO:
GlCommitsScreen(this.id, {this.prefix});
Future<ListPayload<GitlabCommit, int>> _query(BuildContext context,
[int page = 1]) async {
final auth = context.read<AuthModel>();
final res = await auth
.fetchGitlabWithPage('/projects/$id/repository/commits?page=$page');
return ListPayload(
cursor: res.cursor,
hasMore: res.hasMore,
items: (res.data as List).map((v) => GitlabCommit.fromJson(v)).toList(),
);
}
@override
Widget build(BuildContext context) {
return ListStatefulScaffold<GitlabCommit, int>(
title: AppBarTitle('Commits'),
onRefresh: () => _query(context),
onLoadMore: (cursor) => _query(context, cursor),
onLoadMore: (page) async {
page = page ?? 1;
final auth = context.read<AuthModel>();
final res = await auth
.fetchGitlabWithPage('/projects/$id/repository/commits?page=$page');
return ListPayload(
cursor: res.cursor,
hasMore: res.hasMore,
items:
(res.data as List).map((v) => GitlabCommit.fromJson(v)).toList(),
);
},
itemBuilder: (c) {
return CommitItem(
author: c.authorName,

View File

@ -8,26 +8,23 @@ import 'package:provider/provider.dart';
import 'package:timeago/timeago.dart' as timeago;
class GlExploreScreen extends StatelessWidget {
Future<ListPayload<GitlabProject, int>> _query(BuildContext context,
[int page = 1]) async {
final auth = context.read<AuthModel>();
final res = await auth
.fetchGitlabWithPage('/projects?order_by=last_activity_at&page=$page');
return ListPayload(
cursor: res.cursor,
hasMore: res.hasMore,
items: <GitlabProject>[
for (var v in res.data) GitlabProject.fromJson(v),
],
);
}
@override
Widget build(BuildContext context) {
return ListStatefulScaffold<GitlabProject, int>(
title: AppBarTitle('Explore'),
onRefresh: () => _query(context),
onLoadMore: (page) => _query(context, page),
onLoadMore: (page) async {
page = page ?? 1;
final auth = context.read<AuthModel>();
final res = await auth.fetchGitlabWithPage(
'/projects?order_by=last_activity_at&page=$page');
return ListPayload(
cursor: res.cursor,
hasMore: res.hasMore,
items: <GitlabProject>[
for (var v in res.data) GitlabProject.fromJson(v),
],
);
},
itemBuilder: (v) {
return RepositoryItem.gl(
payload: v,

View File

@ -7,25 +7,22 @@ import 'package:git_touch/widgets/user_item.dart';
import 'package:provider/provider.dart';
class GlGroupsScreenn extends StatelessWidget {
Future<ListPayload<GitlabGroup, int>> _query(BuildContext context,
[int page = 1]) async {
final auth = context.read<AuthModel>();
final res = await auth.fetchGitlabWithPage('/groups?page=$page');
return ListPayload(
cursor: res.cursor,
hasMore: res.hasMore,
items: <GitlabGroup>[
for (var v in res.data) GitlabGroup.fromJson(v),
],
);
}
@override
Widget build(BuildContext context) {
return ListStatefulScaffold<GitlabGroup, int>(
title: AppBarTitle('Groups'),
onRefresh: () => _query(context),
onLoadMore: (page) => _query(context, page),
onLoadMore: (page) async {
page = page ?? 1;
final auth = context.read<AuthModel>();
final res = await auth.fetchGitlabWithPage('/groups?page=$page');
return ListPayload(
cursor: res.cursor,
hasMore: res.hasMore,
items: <GitlabGroup>[
for (var v in res.data) GitlabGroup.fromJson(v),
],
);
},
itemBuilder: (v) {
return UserItem(
avatarUrl: v.avatarUrl,

View File

@ -12,25 +12,23 @@ class GlIssuesScreen extends StatelessWidget {
final String prefix;
GlIssuesScreen(this.id, {this.prefix});
Future<ListPayload<GitlabIssue, int>> _query(BuildContext context,
[int page = 1]) async {
final auth = context.read<AuthModel>();
final res = await auth
.fetchGitlabWithPage('/projects/$id/issues?state=opened&page=$page');
return ListPayload(
cursor: res.cursor,
hasMore: res.hasMore,
items: (res.data as List).map((v) => GitlabIssue.fromJson(v)).toList(),
);
}
@override
Widget build(BuildContext context) {
return ListStatefulScaffold<GitlabIssue, int>(
title: AppBarTitle('Issues'),
// TODO: create issue
onRefresh: () => _query(context),
onLoadMore: (cursor) => _query(context, cursor),
onLoadMore: (page) async {
page = page ?? 1;
final auth = context.read<AuthModel>();
final res = await auth.fetchGitlabWithPage(
'/projects/$id/issues?state=opened&page=$page');
return ListPayload(
cursor: res.cursor,
hasMore: res.hasMore,
items:
(res.data as List).map((v) => GitlabIssue.fromJson(v)).toList(),
);
},
itemBuilder: (p) => IssueItem(
author: p.author.username,
avatarUrl: p.author.avatarUrl,

View File

@ -11,19 +11,6 @@ class GlMembersScreen extends StatelessWidget {
final String type;
GlMembersScreen(this.id, this.type);
Future<ListPayload<GitlabUser, int>> _query(BuildContext context,
[int page = 1]) async {
final auth = context.read<AuthModel>();
final res = await auth.fetchGitlabWithPage('/$type/$id/members?page=$page');
return ListPayload(
cursor: res.cursor,
hasMore: res.hasMore,
items: <GitlabUser>[
for (var v in res.data) GitlabUser.fromJson(v),
],
);
}
// https://docs.gitlab.com/ee/api/access_requests.html#valid-access-levels
static const accessLevelMap = {
10: 'Guest',
@ -37,8 +24,19 @@ class GlMembersScreen extends StatelessWidget {
Widget build(BuildContext context) {
return ListStatefulScaffold<GitlabUser, int>(
title: AppBarTitle('Members'),
onRefresh: () => _query(context),
onLoadMore: (page) => _query(context, page),
onLoadMore: (page) async {
page = page ?? 1;
final auth = context.read<AuthModel>();
final res =
await auth.fetchGitlabWithPage('/$type/$id/members?page=$page');
return ListPayload(
cursor: res.cursor,
hasMore: res.hasMore,
items: <GitlabUser>[
for (var v in res.data) GitlabUser.fromJson(v),
],
);
},
itemBuilder: (v) {
return UserItem(
avatarUrl: v.avatarUrl,

View File

@ -12,23 +12,21 @@ class GlMergeRequestsScreen extends StatelessWidget {
final String prefix;
GlMergeRequestsScreen(this.id, {this.prefix});
Future<ListPayload<GitlabIssue, int>> _query(BuildContext context,
[int page = 1]) async {
final res = await context.read<AuthModel>().fetchGitlabWithPage(
'/projects/$id/merge_requests?state=opened&page=$page');
return ListPayload(
cursor: res.cursor,
hasMore: res.hasMore,
items: (res.data as List).map((v) => GitlabIssue.fromJson(v)).toList(),
);
}
@override
Widget build(BuildContext context) {
return ListStatefulScaffold<GitlabIssue, int>(
title: AppBarTitle('Merge Requests'),
onRefresh: () => _query(context),
onLoadMore: (cursor) => _query(context, cursor),
onLoadMore: (page) async {
page = page ?? 1;
final res = await context.read<AuthModel>().fetchGitlabWithPage(
'/projects/$id/merge_requests?state=opened&page=$page');
return ListPayload(
cursor: res.cursor,
hasMore: res.hasMore,
items:
(res.data as List).map((v) => GitlabIssue.fromJson(v)).toList(),
);
},
itemBuilder: (p) => IssueItem(
isPr: true,
author: p.author.username,

View File

@ -11,24 +11,21 @@ import 'package:provider/provider.dart';
class GlProjectActivityScreen extends StatelessWidget {
final int id;
GlProjectActivityScreen(this.id);
Future<ListPayload<GitlabEvent, int>> _query(BuildContext context,
[int page]) async {
final auth = context.read<AuthModel>();
final vs = await auth.fetchGitlab('/projects/$id/events');
final events = (vs as List).map((v) => GitlabEvent.fromJson(v)).toList();
return ListPayload(cursor: page, items: events, hasMore: false);
}
@override
Widget build(BuildContext context) {
final theme = Provider.of<ThemeModel>(context);
return ListStatefulScaffold<GitlabEvent, int>(
title: AppBarTitle('Activity'),
onRefresh: () => _query(context),
onLoadMore: (int page) => _query(context, page),
onLoadMore: (page) async {
page = page ?? 1;
final auth = context.read<AuthModel>();
final vs = await auth.fetchGitlab('/projects/$id/events');
final events =
(vs as List).map((v) => GitlabEvent.fromJson(v)).toList();
return ListPayload(cursor: page, items: events, hasMore: false);
},
itemBuilder: (data) {
return Link(
url: '',

View File

@ -11,26 +11,23 @@ class GlStarrersScreen extends StatelessWidget {
final int id;
GlStarrersScreen(this.id);
Future<ListPayload<GitlabStarrer, int>> _query(BuildContext context,
[int page = 1]) async {
final res = await context
.read<AuthModel>()
.fetchGitlabWithPage('/projects/$id/starrers?page=$page');
return ListPayload(
cursor: res.cursor,
hasMore: res.hasMore,
items: <GitlabStarrer>[
for (var v in res.data) GitlabStarrer.fromJson(v),
],
);
}
@override
Widget build(BuildContext context) {
return ListStatefulScaffold<GitlabStarrer, int>(
title: AppBarTitle('Members'),
onRefresh: () => _query(context),
onLoadMore: (page) => _query(context, page),
onLoadMore: (page) async {
page = page ?? 1;
final res = await context
.read<AuthModel>()
.fetchGitlabWithPage('/projects/$id/starrers?page=$page');
return ListPayload(
cursor: res.cursor,
hasMore: res.hasMore,
items: <GitlabStarrer>[
for (var v in res.data) GitlabStarrer.fromJson(v),
],
);
},
itemBuilder: (v) {
return UserItem(
avatarUrl: v.user.avatarUrl,

View File

@ -12,24 +12,21 @@ class GtCommitsScreen extends StatelessWidget {
// final String branch; // TODO:
GtCommitsScreen(this.owner, this.name);
Future<ListPayload<GiteaCommit, int>> _query(BuildContext context,
[int page = 1]) async {
final res = await context
.read<AuthModel>()
.fetchGiteaWithPage('/repos/$owner/$name/commits?page=$page&limit=20');
return ListPayload(
cursor: res.cursor,
hasMore: res.hasMore,
items: (res.data as List).map((v) => GiteaCommit.fromJson(v)).toList(),
);
}
@override
Widget build(BuildContext context) {
return ListStatefulScaffold<GiteaCommit, int>(
title: AppBarTitle('Commits'),
onRefresh: () => _query(context),
onLoadMore: (cursor) => _query(context, cursor),
onLoadMore: (page) async {
page = page ?? 1;
final res = await context.read<AuthModel>().fetchGiteaWithPage(
'/repos/$owner/$name/commits?page=$page&limit=20');
return ListPayload(
cursor: res.cursor,
hasMore: res.hasMore,
items:
(res.data as List).map((v) => GiteaCommit.fromJson(v)).toList(),
);
},
itemBuilder: (c) {
return CommitItem(
author: c.author?.login ?? c.commit.author.name,

View File

@ -12,25 +12,22 @@ class GtIssuesScreen extends StatelessWidget {
final bool isPr;
GtIssuesScreen(this.owner, this.name, {this.isPr = false});
Future<ListPayload<GiteaIssue, int>> _query(BuildContext context,
[int page = 1]) async {
final type = isPr ? 'pulls' : 'issues';
final res = await context.read<AuthModel>().fetchGiteaWithPage(
'/repos/$owner/$name/issues?state=open&page=$page&limit=20&type=$type');
return ListPayload(
cursor: res.cursor,
hasMore: res.hasMore,
items: (res.data as List).map((v) => GiteaIssue.fromJson(v)).toList(),
);
}
@override
Widget build(BuildContext context) {
return ListStatefulScaffold<GiteaIssue, int>(
title: AppBarTitle(isPr ? 'Pull Requests' : 'Issues'),
// TODO: create issue
onRefresh: () => _query(context),
onLoadMore: (cursor) => _query(context, cursor),
onLoadMore: (page) async {
page = page ?? 1;
final type = isPr ? 'pulls' : 'issues';
final res = await context.read<AuthModel>().fetchGiteaWithPage(
'/repos/$owner/$name/issues?state=open&page=$page&limit=20&type=$type');
return ListPayload(
cursor: res.cursor,
hasMore: res.hasMore,
items: (res.data as List).map((v) => GiteaIssue.fromJson(v)).toList(),
);
},
itemBuilder: (p) => IssueItem(
author: p.user.login,
avatarUrl: p.user.avatarUrl,

View File

@ -7,26 +7,23 @@ import 'package:git_touch/widgets/user_item.dart';
import 'package:provider/provider.dart';
class GtOrgsScreen extends StatelessWidget {
// final String branch; // TODO:
Future<ListPayload<GiteaOrg, int>> _query(BuildContext context,
[int page = 1]) async {
final res = await context
.read<AuthModel>()
.fetchGiteaWithPage('/orgs?limit=20&page=$page');
// TODO: https://github.com/go-gitea/gitea/issues/10199
return ListPayload(
cursor: page + 1,
hasMore: (res.data as List).length == 20,
items: (res.data as List).map((v) => GiteaOrg.fromJson(v)).toList(),
);
}
@override
Widget build(BuildContext context) {
return ListStatefulScaffold<GiteaOrg, int>(
title: AppBarTitle('Organizations'),
onRefresh: () => _query(context),
onLoadMore: (cursor) => _query(context, cursor),
onLoadMore: (page) async {
// final String branch; // TODO:
page = page ?? 1;
final res = await context
.read<AuthModel>()
.fetchGiteaWithPage('/orgs?limit=20&page=$page');
// TODO: https://github.com/go-gitea/gitea/issues/10199
return ListPayload(
cursor: page + 1,
hasMore: (res.data as List).length == 20,
items: (res.data as List).map((v) => GiteaOrg.fromJson(v)).toList(),
);
},
itemBuilder: (v) {
return UserItem(
avatarUrl: v.avatarUrl,