diff --git a/lib/scaffolds/refresh_stateful.dart b/lib/scaffolds/refresh_stateful.dart index 5fec2f7..0b956d3 100644 --- a/lib/scaffolds/refresh_stateful.dart +++ b/lib/scaffolds/refresh_stateful.dart @@ -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 { - bool loading; - String error; - T data; - void Function() refresh; - - RefreshStatefulScaffoldPayload( - this.loading, this.error, this.data, this.refresh); -} - class RefreshStatefulScaffold extends StatefulWidget { final Widget title; - final Widget Function(RefreshStatefulScaffoldPayload payload) bodyBuilder; + final Widget Function(T data, void Function(VoidCallback fn) setState) + bodyBuilder; final Future Function() fetchData; - final Widget Function(RefreshStatefulScaffoldPayload payload) + final Widget Function(T data, void Function(VoidCallback fn) setState) actionBuilder; RefreshStatefulScaffold({ @@ -39,13 +30,11 @@ class _RefreshStatefulScaffoldState T _data; String _error = ''; - RefreshStatefulScaffoldPayload get _payload => - RefreshStatefulScaffoldPayload(_loading, _error, _data, _refresh); - @override void initState() { super.initState(); _refresh(); + setState(() {}); } Future _refresh() async { @@ -69,7 +58,7 @@ class _RefreshStatefulScaffoldState 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 body: RefreshWrapper( onRefresh: _refresh, body: ErrorLoadingWrapper( - bodyBuilder: () => widget.bodyBuilder(_payload), + bodyBuilder: () => widget.bodyBuilder(_data, setState), error: _error, loading: _data == null, reload: _refresh, diff --git a/lib/screens/gitlab/issue.dart b/lib/screens/gitlab/issue.dart index aa24370..41905b6 100644 --- a/lib/screens/gitlab/issue.dart +++ b/lib/screens/gitlab/issue.dart @@ -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: [ @@ -41,16 +41,16 @@ class GitlabIssueScreen extends StatelessWidget { padding: CommonStyle.padding, child: Column( children: [ - Text(data['title']), + Text(issue['title']), Row( children: [ - 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']))) ], ), ), diff --git a/lib/screens/gitlab/todos.dart b/lib/screens/gitlab/todos.dart index 95417af..772145e 100644 --- a/lib/screens/gitlab/todos.dart +++ b/lib/screens/gitlab/todos.dart @@ -16,10 +16,10 @@ class GitlabTodosScreen extends StatelessWidget { fetchData: () { return Provider.of(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'], diff --git a/lib/screens/gitlab/user.dart b/lib/screens/gitlab/user.dart index 4f512cb..d9e2f6a 100644 --- a/lib/screens/gitlab/user.dart +++ b/lib/screens/gitlab/user.dart @@ -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: [ 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( diff --git a/lib/screens/object.dart b/lib/screens/object.dart index f36cb3b..5d70d9b 100644 --- a/lib/screens/object.dart +++ b/lib/screens/object.dart @@ -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(context).pushRoute(context, - (_) => CodeThemeScreen(payload.data['text'], _language)); + if (data != null) { + Provider.of(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; } diff --git a/lib/screens/repository.dart b/lib/screens/repository.dart index 5728b5e..b0de367 100644 --- a/lib/screens/repository.dart +++ b/lib/screens/repository.dart @@ -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: [ - RepositoryItem(data, inRepoScreen: true), + RepositoryItem(repo, inRepoScreen: true), CommonStyle.border, Row( children: [ 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(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'])), ), ], ), diff --git a/lib/screens/user.dart b/lib/screens/user.dart index 4abf0c1..9173612 100644 --- a/lib/screens/user.dart +++ b/lib/screens/user.dart @@ -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: [ 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, ],