mirror of
https://github.com/git-touch/git-touch
synced 2025-01-31 08:04:51 +01:00
refactor: refresh scaffold
This commit is contained in:
parent
0c315c354c
commit
79febd275b
@ -4,21 +4,12 @@ import 'package:git_touch/scaffolds/common.dart';
|
||||
import 'package:git_touch/scaffolds/utils.dart';
|
||||
import 'package:primer/primer.dart';
|
||||
|
||||
class RefreshStatefulScaffoldPayload<T> {
|
||||
bool loading;
|
||||
String error;
|
||||
T data;
|
||||
void Function() refresh;
|
||||
|
||||
RefreshStatefulScaffoldPayload(
|
||||
this.loading, this.error, this.data, this.refresh);
|
||||
}
|
||||
|
||||
class RefreshStatefulScaffold<T> extends StatefulWidget {
|
||||
final Widget title;
|
||||
final Widget Function(RefreshStatefulScaffoldPayload<T> payload) bodyBuilder;
|
||||
final Widget Function(T data, void Function(VoidCallback fn) setState)
|
||||
bodyBuilder;
|
||||
final Future<T> Function() fetchData;
|
||||
final Widget Function(RefreshStatefulScaffoldPayload<T> payload)
|
||||
final Widget Function(T data, void Function(VoidCallback fn) setState)
|
||||
actionBuilder;
|
||||
|
||||
RefreshStatefulScaffold({
|
||||
@ -39,13 +30,11 @@ class _RefreshStatefulScaffoldState<T>
|
||||
T _data;
|
||||
String _error = '';
|
||||
|
||||
RefreshStatefulScaffoldPayload get _payload =>
|
||||
RefreshStatefulScaffoldPayload(_loading, _error, _data, _refresh);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_refresh();
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
Future<void> _refresh() async {
|
||||
@ -69,7 +58,7 @@ class _RefreshStatefulScaffoldState<T>
|
||||
|
||||
Widget get _action {
|
||||
if (widget.actionBuilder == null) return null;
|
||||
return widget.actionBuilder(_payload);
|
||||
return widget.actionBuilder(_data, setState);
|
||||
}
|
||||
|
||||
@override
|
||||
@ -80,7 +69,7 @@ class _RefreshStatefulScaffoldState<T>
|
||||
body: RefreshWrapper(
|
||||
onRefresh: _refresh,
|
||||
body: ErrorLoadingWrapper(
|
||||
bodyBuilder: () => widget.bodyBuilder(_payload),
|
||||
bodyBuilder: () => widget.bodyBuilder(_data, setState),
|
||||
error: _error,
|
||||
loading: _data == null,
|
||||
reload: _refresh,
|
||||
|
@ -30,10 +30,10 @@ class GitlabIssueScreen extends StatelessWidget {
|
||||
]);
|
||||
return items;
|
||||
},
|
||||
bodyBuilder: (payload) {
|
||||
final data = payload.data[0];
|
||||
final notes = payload.data[1] as List;
|
||||
final emoji = payload.data[2];
|
||||
bodyBuilder: (data, _) {
|
||||
final issue = data[0];
|
||||
final notes = data[1] as List;
|
||||
final emoji = data[2];
|
||||
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
@ -41,16 +41,16 @@ class GitlabIssueScreen extends StatelessWidget {
|
||||
padding: CommonStyle.padding,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Text(data['title']),
|
||||
Text(issue['title']),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Avatar.medium(url: data['author']['avatar_url']),
|
||||
Avatar.medium(url: issue['author']['avatar_url']),
|
||||
Expanded(
|
||||
child: Text(data['description']),
|
||||
child: Text(issue['description']),
|
||||
),
|
||||
],
|
||||
),
|
||||
Text(timeago.format(DateTime.parse(data['created_at'])))
|
||||
Text(timeago.format(DateTime.parse(issue['created_at'])))
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -16,10 +16,10 @@ class GitlabTodosScreen extends StatelessWidget {
|
||||
fetchData: () {
|
||||
return Provider.of<AuthModel>(context).fetchGitlab('/todos');
|
||||
},
|
||||
bodyBuilder: (payload) {
|
||||
bodyBuilder: (data, _) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: (payload.data as List).map((item) {
|
||||
children: (data as List).map((item) {
|
||||
return Link(
|
||||
screenBuilder: (_) => GitlabIssueScreen(
|
||||
item['target']['project_id'], item['target']['iid'],
|
||||
|
@ -29,16 +29,16 @@ class GitlabUserScreen extends StatelessWidget {
|
||||
}
|
||||
return [user, projects];
|
||||
},
|
||||
bodyBuilder: (payload) {
|
||||
final data = payload.data[0];
|
||||
final projects = payload.data[1] as List;
|
||||
bodyBuilder: (data, _) {
|
||||
final user = data[0];
|
||||
final projects = data[1] as List;
|
||||
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
UserItem(
|
||||
login: data['username'],
|
||||
avatarUrl: data['avatar_url'],
|
||||
name: data['name'],
|
||||
login: user['username'],
|
||||
avatarUrl: user['avatar_url'],
|
||||
name: user['name'],
|
||||
),
|
||||
BorderView(height: 10),
|
||||
Column(
|
||||
|
@ -173,15 +173,15 @@ class ObjectScreen extends StatelessWidget {
|
||||
|
||||
return data['repository']['object'];
|
||||
},
|
||||
actionBuilder: (payload) {
|
||||
actionBuilder: (data, _) {
|
||||
switch (type) {
|
||||
case 'blob':
|
||||
return ActionEntry(
|
||||
iconData: Octicons.settings,
|
||||
onTap: () {
|
||||
if (payload.data != null) {
|
||||
Provider.of<ThemeModel>(context).pushRoute(context,
|
||||
(_) => CodeThemeScreen(payload.data['text'], _language));
|
||||
if (data != null) {
|
||||
Provider.of<ThemeModel>(context).pushRoute(
|
||||
context, (_) => CodeThemeScreen(data['text'], _language));
|
||||
}
|
||||
},
|
||||
);
|
||||
@ -189,12 +189,12 @@ class ObjectScreen extends StatelessWidget {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
bodyBuilder: (payload) {
|
||||
bodyBuilder: (data, _) {
|
||||
switch (type) {
|
||||
case 'tree':
|
||||
return _buildTree(payload.data);
|
||||
return _buildTree(data);
|
||||
case 'blob':
|
||||
return _buildBlob(context, payload.data);
|
||||
return _buildBlob(context, data);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
@ -124,8 +124,7 @@ class RepositoryScreen extends StatelessWidget {
|
||||
queryRepo(context),
|
||||
fetchReadme(context),
|
||||
]),
|
||||
actionBuilder: (payload) {
|
||||
var data = payload.data;
|
||||
actionBuilder: (data, setState) {
|
||||
return ActionButton(
|
||||
title: 'Repository Actions',
|
||||
items: [
|
||||
@ -142,7 +141,7 @@ class RepositoryScreen extends StatelessWidget {
|
||||
.putWithCredentials('/user/starred/$owner/$name');
|
||||
data[0]['viewerHasStarred'] = true;
|
||||
}
|
||||
payload.refresh();
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
ActionItem(
|
||||
@ -159,7 +158,7 @@ class RepositoryScreen extends StatelessWidget {
|
||||
.putWithCredentials('/repos/$owner/$name/subscription');
|
||||
data[0]['viewerSubscription'] = 'SUBSCRIBED';
|
||||
}
|
||||
payload.refresh();
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
],
|
||||
@ -170,35 +169,35 @@ class RepositoryScreen extends StatelessWidget {
|
||||
],
|
||||
);
|
||||
},
|
||||
bodyBuilder: (payload) {
|
||||
var data = payload.data[0];
|
||||
var readme = payload.data[1] as String;
|
||||
bodyBuilder: (data, _) {
|
||||
var repo = data[0];
|
||||
var readme = data[1] as String;
|
||||
|
||||
final langWidth = MediaQuery.of(context).size.width -
|
||||
CommonStyle.padding.left -
|
||||
CommonStyle.padding.right -
|
||||
(data['languages']['edges'] as List).length +
|
||||
(repo['languages']['edges'] as List).length +
|
||||
1;
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: <Widget>[
|
||||
RepositoryItem(data, inRepoScreen: true),
|
||||
RepositoryItem(repo, inRepoScreen: true),
|
||||
CommonStyle.border,
|
||||
Row(
|
||||
children: <Widget>[
|
||||
EntryItem(
|
||||
count: data['watchers']['totalCount'],
|
||||
count: repo['watchers']['totalCount'],
|
||||
text: 'Watchers',
|
||||
screenBuilder: (context) => UsersScreen.watchers(owner, name),
|
||||
),
|
||||
EntryItem(
|
||||
count: data['stargazers']['totalCount'],
|
||||
count: repo['stargazers']['totalCount'],
|
||||
text: 'Stars',
|
||||
screenBuilder: (context) => UsersScreen.stars(owner, name),
|
||||
),
|
||||
EntryItem(
|
||||
count: data['forks']['totalCount'],
|
||||
count: repo['forks']['totalCount'],
|
||||
text: 'Forks',
|
||||
screenBuilder: (context) =>
|
||||
RepositoriesScreen.forks(owner, name),
|
||||
@ -206,7 +205,7 @@ class RepositoryScreen extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
CommonStyle.verticalGap,
|
||||
if ((data['languages']['edges'] as List).isNotEmpty)
|
||||
if ((repo['languages']['edges'] as List).isNotEmpty)
|
||||
Container(
|
||||
color: Colors.white,
|
||||
padding: CommonStyle.padding.copyWith(top: 8, bottom: 8),
|
||||
@ -217,12 +216,12 @@ class RepositoryScreen extends StatelessWidget {
|
||||
child: Row(
|
||||
children: join(
|
||||
SizedBox(width: 1),
|
||||
(data['languages']['edges'] as List)
|
||||
(repo['languages']['edges'] as List)
|
||||
.map((lang) => Container(
|
||||
color: convertColor(lang['node']['color']),
|
||||
width: langWidth *
|
||||
lang['size'] /
|
||||
data['languages']['totalSize']))
|
||||
repo['languages']['totalSize']))
|
||||
.toList())),
|
||||
),
|
||||
),
|
||||
@ -230,24 +229,24 @@ class RepositoryScreen extends StatelessWidget {
|
||||
TableView(
|
||||
hasIcon: true,
|
||||
items: [
|
||||
if (data[branchInfoKey] != null)
|
||||
if (repo[branchInfoKey] != null)
|
||||
TableViewItem(
|
||||
leftIconData: Octicons.code,
|
||||
text: Text('Code'),
|
||||
rightWidget:
|
||||
Text(filesize((data['diskUsage'] as int) * 1000)),
|
||||
Text(filesize((repo['diskUsage'] as int) * 1000)),
|
||||
screenBuilder: (_) => ObjectScreen(
|
||||
owner: owner,
|
||||
name: name,
|
||||
branch: data[branchInfoKey]['name'],
|
||||
branch: repo[branchInfoKey]['name'],
|
||||
),
|
||||
),
|
||||
if (data['hasIssuesEnabled'] as bool)
|
||||
if (repo['hasIssuesEnabled'] as bool)
|
||||
TableViewItem(
|
||||
leftIconData: Octicons.issue_opened,
|
||||
text: Text('Issues'),
|
||||
rightWidget:
|
||||
Text(numberFormat.format(data['issues']['totalCount'])),
|
||||
Text(numberFormat.format(repo['issues']['totalCount'])),
|
||||
screenBuilder: (_) =>
|
||||
IssuesScreen(owner: owner, name: name),
|
||||
),
|
||||
@ -255,7 +254,7 @@ class RepositoryScreen extends StatelessWidget {
|
||||
leftIconData: Octicons.git_pull_request,
|
||||
text: Text('Pull requests'),
|
||||
rightWidget: Text(
|
||||
numberFormat.format(data['pullRequests']['totalCount'])),
|
||||
numberFormat.format(repo['pullRequests']['totalCount'])),
|
||||
screenBuilder: (_) => IssuesScreen(
|
||||
owner: owner, name: name, isPullRequest: true),
|
||||
),
|
||||
@ -263,8 +262,8 @@ class RepositoryScreen extends StatelessWidget {
|
||||
leftIconData: Octicons.project,
|
||||
text: Text('Projects'),
|
||||
rightWidget:
|
||||
Text(numberFormat.format(data['projects']['totalCount'])),
|
||||
url: 'https://github.com' + data['projectsResourcePath'],
|
||||
Text(numberFormat.format(repo['projects']['totalCount'])),
|
||||
url: 'https://github.com' + repo['projectsResourcePath'],
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -272,30 +271,30 @@ class RepositoryScreen extends StatelessWidget {
|
||||
TableView(
|
||||
hasIcon: true,
|
||||
items: [
|
||||
if (data[branchInfoKey] != null) ...[
|
||||
if (repo[branchInfoKey] != null) ...[
|
||||
TableViewItem(
|
||||
leftIconData: Octicons.history,
|
||||
text: Text('Commits'),
|
||||
rightWidget: Text(numberFormat.format(data[branchInfoKey]
|
||||
rightWidget: Text(numberFormat.format(repo[branchInfoKey]
|
||||
['target']['history']['totalCount'])),
|
||||
screenBuilder: (_) =>
|
||||
CommitsScreen(owner, name, branch: branch),
|
||||
),
|
||||
if (data['refs'] != null)
|
||||
if (repo['refs'] != null)
|
||||
TableViewItem(
|
||||
leftIconData: Octicons.git_branch,
|
||||
text: Text('Branches'),
|
||||
rightWidget: Text(data[branchInfoKey]['name'] +
|
||||
rightWidget: Text(repo[branchInfoKey]['name'] +
|
||||
' • ' +
|
||||
numberFormat.format(data['refs']['totalCount'])),
|
||||
numberFormat.format(repo['refs']['totalCount'])),
|
||||
onTap: () async {
|
||||
var refs = data['refs']['nodes'] as List;
|
||||
var refs = repo['refs']['nodes'] as List;
|
||||
if (refs.length < 2) return;
|
||||
|
||||
await Provider.of<ThemeModel>(context).showPicker(
|
||||
context,
|
||||
PickerGroupItem(
|
||||
value: data[branchInfoKey]['name'],
|
||||
value: repo[branchInfoKey]['name'],
|
||||
items: refs
|
||||
.map((b) => PickerItem(b['name'] as String,
|
||||
text: (b['name'] as String)))
|
||||
@ -319,16 +318,16 @@ class RepositoryScreen extends StatelessWidget {
|
||||
leftIconData: Octicons.tag,
|
||||
text: Text('Releases'),
|
||||
rightWidget:
|
||||
Text((data['releases']['totalCount'] as int).toString()),
|
||||
url: data['url'] + '/releases',
|
||||
Text((repo['releases']['totalCount'] as int).toString()),
|
||||
url: repo['url'] + '/releases',
|
||||
),
|
||||
TableViewItem(
|
||||
leftIconData: Octicons.law,
|
||||
text: Text('License'),
|
||||
rightWidget: Text(data['licenseInfo'] == null
|
||||
rightWidget: Text(repo['licenseInfo'] == null
|
||||
? 'Unknown'
|
||||
: (data['licenseInfo']['spdxId'] ??
|
||||
data['licenseInfo']['name'])),
|
||||
: (repo['licenseInfo']['spdxId'] ??
|
||||
repo['licenseInfo']['name'])),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -123,8 +123,7 @@ class UserScreen extends StatelessWidget {
|
||||
]);
|
||||
},
|
||||
title: AppBarTitle('User'), // TODO:
|
||||
actionBuilder: (payload) {
|
||||
var data = payload.data;
|
||||
actionBuilder: (data, _) {
|
||||
if (data == null)
|
||||
return ActionButton(
|
||||
title: "Actions",
|
||||
@ -175,8 +174,8 @@ class UserScreen extends StatelessWidget {
|
||||
title: 'Organization Actions',
|
||||
items: [
|
||||
if (data != null) ...[
|
||||
ActionItem.share(payload.data[0]['url']),
|
||||
ActionItem.launch(payload.data[0]['url']),
|
||||
ActionItem.share(data[0]['url']),
|
||||
ActionItem.launch(data[0]['url']),
|
||||
],
|
||||
],
|
||||
);
|
||||
@ -184,59 +183,59 @@ class UserScreen extends StatelessWidget {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
bodyBuilder: (payload) {
|
||||
var data = payload.data[0];
|
||||
var contributions = payload.data[1];
|
||||
final isOrganization = data['__typename'] == 'Organization';
|
||||
bodyBuilder: (data, _) {
|
||||
var user = data[0];
|
||||
var contributions = data[1];
|
||||
final isOrganization = user['__typename'] == 'Organization';
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: <Widget>[
|
||||
UserItem(
|
||||
login: data['login'],
|
||||
name: data['name'],
|
||||
avatarUrl: data['avatarUrl'],
|
||||
bio: isOrganization ? data['description'] : data['bio'],
|
||||
login: user['login'],
|
||||
name: user['name'],
|
||||
avatarUrl: user['avatarUrl'],
|
||||
bio: isOrganization ? user['description'] : user['bio'],
|
||||
inUserScreen: true,
|
||||
),
|
||||
CommonStyle.border,
|
||||
Row(children: [
|
||||
if (isOrganization) ...[
|
||||
EntryItem(
|
||||
count: data['pinnableItems']['totalCount'],
|
||||
count: user['pinnableItems']['totalCount'],
|
||||
text: 'Repositories',
|
||||
screenBuilder: (context) =>
|
||||
RepositoriesScreen.ofOrganization(data['login']),
|
||||
RepositoriesScreen.ofOrganization(user['login']),
|
||||
),
|
||||
EntryItem(
|
||||
count: data['membersWithRole']['totalCount'],
|
||||
count: user['membersWithRole']['totalCount'],
|
||||
text: 'Members',
|
||||
screenBuilder: (context) =>
|
||||
UsersScreen.members(data['login']),
|
||||
UsersScreen.members(user['login']),
|
||||
),
|
||||
] else ...[
|
||||
EntryItem(
|
||||
count: data['repositories']['totalCount'],
|
||||
count: user['repositories']['totalCount'],
|
||||
text: 'Repositories',
|
||||
screenBuilder: (context) => RepositoriesScreen(data['login']),
|
||||
screenBuilder: (context) => RepositoriesScreen(user['login']),
|
||||
),
|
||||
EntryItem(
|
||||
count: data['starredRepositories']['totalCount'],
|
||||
count: user['starredRepositories']['totalCount'],
|
||||
text: 'Stars',
|
||||
screenBuilder: (context) =>
|
||||
RepositoriesScreen.stars(data['login']),
|
||||
RepositoriesScreen.stars(user['login']),
|
||||
),
|
||||
EntryItem(
|
||||
count: data['followers']['totalCount'],
|
||||
count: user['followers']['totalCount'],
|
||||
text: 'Followers',
|
||||
screenBuilder: (context) =>
|
||||
UsersScreen.followers(data['login']),
|
||||
UsersScreen.followers(user['login']),
|
||||
),
|
||||
EntryItem(
|
||||
count: data['following']['totalCount'],
|
||||
count: user['following']['totalCount'],
|
||||
text: 'Following',
|
||||
screenBuilder: (context) =>
|
||||
UsersScreen.following(data['login']),
|
||||
UsersScreen.following(user['login']),
|
||||
),
|
||||
]
|
||||
]),
|
||||
@ -248,38 +247,38 @@ class UserScreen extends StatelessWidget {
|
||||
TableView(
|
||||
hasIcon: true,
|
||||
items: [
|
||||
if (!isOrganization && isNotNullOrEmpty(data['company']))
|
||||
if (!isOrganization && isNotNullOrEmpty(user['company']))
|
||||
TableViewItem(
|
||||
leftIconData: Octicons.organization,
|
||||
text: TextContainsOrganization(data['company'],
|
||||
text: TextContainsOrganization(user['company'],
|
||||
style: TextStyle(
|
||||
fontSize: 16, color: PrimerColors.gray900),
|
||||
overflow: TextOverflow.ellipsis),
|
||||
),
|
||||
if (isNotNullOrEmpty(data['location']))
|
||||
if (isNotNullOrEmpty(user['location']))
|
||||
TableViewItem(
|
||||
leftIconData: Octicons.location,
|
||||
text: Text(data['location']),
|
||||
text: Text(user['location']),
|
||||
onTap: () {
|
||||
launchUrl('https://www.google.com/maps/place/' +
|
||||
(data['location'] as String)
|
||||
(user['location'] as String)
|
||||
.replaceAll(RegExp(r'\s+'), ''));
|
||||
},
|
||||
),
|
||||
if (isNotNullOrEmpty(data['email']))
|
||||
if (isNotNullOrEmpty(user['email']))
|
||||
TableViewItem(
|
||||
leftIconData: Octicons.mail,
|
||||
text: Text(data['email']),
|
||||
text: Text(user['email']),
|
||||
onTap: () {
|
||||
launchUrl('mailto:' + data['email']);
|
||||
launchUrl('mailto:' + user['email']);
|
||||
},
|
||||
),
|
||||
if (isNotNullOrEmpty(data['websiteUrl']))
|
||||
if (isNotNullOrEmpty(user['websiteUrl']))
|
||||
TableViewItem(
|
||||
leftIconData: Octicons.link,
|
||||
text: Text(data['websiteUrl']),
|
||||
text: Text(user['websiteUrl']),
|
||||
onTap: () {
|
||||
var url = data['websiteUrl'] as String;
|
||||
var url = user['websiteUrl'] as String;
|
||||
if (!url.startsWith('http')) {
|
||||
url = 'http://$url';
|
||||
}
|
||||
@ -289,8 +288,8 @@ class UserScreen extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
...buildPinnedItems(
|
||||
data['pinnedItems']['nodes'],
|
||||
data[isOrganization ? 'pinnableItems' : 'repositories']
|
||||
user['pinnedItems']['nodes'],
|
||||
user[isOrganization ? 'pinnableItems' : 'repositories']
|
||||
['nodes']),
|
||||
CommonStyle.verticalGap,
|
||||
],
|
||||
|
Loading…
x
Reference in New Issue
Block a user