diff --git a/lib/models/gitee.dart b/lib/models/gitee.dart index 4ac10dc..8073af8 100644 --- a/lib/models/gitee.dart +++ b/lib/models/gitee.dart @@ -124,6 +124,15 @@ class GiteeBlob { _$GiteeBlobFromJson(json); } +@JsonSerializable(fieldRename: FieldRename.snake) +class GiteeLabel { + String color; + String name; + GiteeLabel(); + factory GiteeLabel.fromJson(Map json) => + _$GiteeLabelFromJson(json); +} + @JsonSerializable(fieldRename: FieldRename.snake) class GiteeIssue { int comments; @@ -138,6 +147,7 @@ class GiteeIssue { GiteeRepo repository; GiteeRepoOwner user; String number; + List labels; int id; GiteeIssue(); factory GiteeIssue.fromJson(Map json) => @@ -155,6 +165,7 @@ class GiteePull { String title; String state; GiteeRepoOwner user; + List labels; int number; int id; GiteePull(); @@ -211,3 +222,20 @@ class GiteeCommitFile { factory GiteeCommitFile.fromJson(Map json) => _$GiteeCommitFileFromJson(json); } + +@JsonSerializable(fieldRename: FieldRename.snake) +class GiteeContributor { + String name; + int contributions; + GiteeContributor(); + factory GiteeContributor.fromJson(Map json) => + _$GiteeContributorFromJson(json); +} + +@JsonSerializable(fieldRename: FieldRename.snake) +class GiteeBranch { + String name; + GiteeBranch(); + factory GiteeBranch.fromJson(Map json) => + _$GiteeBranchFromJson(json); +} diff --git a/lib/models/gitee.g.dart b/lib/models/gitee.g.dart index 05870a4..df9af50 100644 --- a/lib/models/gitee.g.dart +++ b/lib/models/gitee.g.dart @@ -206,6 +206,18 @@ Map _$GiteeBlobToJson(GiteeBlob instance) => { 'content': instance.content, }; +GiteeLabel _$GiteeLabelFromJson(Map json) { + return GiteeLabel() + ..color = json['color'] as String + ..name = json['name'] as String; +} + +Map _$GiteeLabelToJson(GiteeLabel instance) => + { + 'color': instance.color, + 'name': instance.name, + }; + GiteeIssue _$GiteeIssueFromJson(Map json) { return GiteeIssue() ..comments = json['comments'] as int @@ -224,6 +236,10 @@ GiteeIssue _$GiteeIssueFromJson(Map json) { ? null : GiteeRepoOwner.fromJson(json['user'] as Map) ..number = json['number'] as String + ..labels = (json['labels'] as List) + ?.map((e) => + e == null ? null : GiteeLabel.fromJson(e as Map)) + ?.toList() ..id = json['id'] as int; } @@ -241,6 +257,7 @@ Map _$GiteeIssueToJson(GiteeIssue instance) => 'repository': instance.repository, 'user': instance.user, 'number': instance.number, + 'labels': instance.labels, 'id': instance.id, }; @@ -257,6 +274,10 @@ GiteePull _$GiteePullFromJson(Map json) { ..user = json['user'] == null ? null : GiteeRepoOwner.fromJson(json['user'] as Map) + ..labels = (json['labels'] as List) + ?.map((e) => + e == null ? null : GiteeLabel.fromJson(e as Map)) + ?.toList() ..number = json['number'] as int ..id = json['id'] as int; } @@ -271,6 +292,7 @@ Map _$GiteePullToJson(GiteePull instance) => { 'title': instance.title, 'state': instance.state, 'user': instance.user, + 'labels': instance.labels, 'number': instance.number, 'id': instance.id, }; @@ -349,3 +371,24 @@ Map _$GiteeCommitFileToJson(GiteeCommitFile instance) => 'status': instance.status, 'patch': instance.patch, }; + +GiteeContributor _$GiteeContributorFromJson(Map json) { + return GiteeContributor() + ..name = json['name'] as String + ..contributions = json['contributions'] as int; +} + +Map _$GiteeContributorToJson(GiteeContributor instance) => + { + 'name': instance.name, + 'contributions': instance.contributions, + }; + +GiteeBranch _$GiteeBranchFromJson(Map json) { + return GiteeBranch()..name = json['name'] as String; +} + +Map _$GiteeBranchToJson(GiteeBranch instance) => + { + 'name': instance.name, + }; diff --git a/lib/models/theme.dart b/lib/models/theme.dart index 3c25f10..eec9690 100644 --- a/lib/models/theme.dart +++ b/lib/models/theme.dart @@ -317,39 +317,80 @@ class ThemeModel with ChangeNotifier { await showCupertinoModalPopup( context: context, builder: (context) { - return Container( - height: 216, - child: CupertinoPicker( - backgroundColor: palette.background, - children: [ - for (var v in groupItem.items) - Text(v.text, style: TextStyle(color: palette.text)), - ], - itemExtent: 40, - scrollController: FixedExtentScrollController( - initialItem: groupItem.items - .toList() - .indexWhere((v) => v.value == groupItem.value)), - onSelectedItemChanged: (index) { - _selectedItem = groupItem.items[index].value; + return Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Container( + alignment: Alignment.bottomCenter, + decoration: BoxDecoration( + color: palette.background, + border: Border( + bottom: BorderSide( + color: palette.grayBackground, + width: 0.0, + ), + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + CupertinoButton( + child: Text('Cancel'), + onPressed: () { + Navigator.pop(context); + _selectedItem = groupItem.value; + }, + padding: const EdgeInsets.symmetric( + horizontal: 16.0, + vertical: 5.0, + ), + ), + CupertinoButton( + child: Text('Confirm'), + onPressed: () { + Navigator.pop(context); + groupItem.onClose(_selectedItem); + }, + padding: const EdgeInsets.symmetric( + horizontal: 16.0, + vertical: 5.0, + ), + ) + ], + ), + ), + Container( + height: 216, + child: CupertinoPicker( + backgroundColor: palette.background, + children: [ + for (var v in groupItem.items) + Text(v.text, style: TextStyle(color: palette.text)), + ], + itemExtent: 40, + scrollController: FixedExtentScrollController( + initialItem: groupItem.items + .toList() + .indexWhere((v) => v.value == groupItem.value)), + onSelectedItemChanged: (index) { + _selectedItem = groupItem.items[index].value; - if (groupItem.onChange != null) { - if (_debounce?.isActive ?? false) { - _debounce.cancel(); - } + if (groupItem.onChange != null) { + if (_debounce?.isActive ?? false) { + _debounce.cancel(); + } - _debounce = Timer(const Duration(milliseconds: 500), () { - groupItem.onChange(_selectedItem); - }); - } - }, - ), + _debounce = Timer(const Duration(milliseconds: 500), () { + groupItem.onChange(_selectedItem); + }); + } + }, + ), + ) + ], ); }, ); - if (groupItem.onClose != null) { - groupItem.onClose(_selectedItem); - } } showActions(BuildContext context, List actionItems) async { diff --git a/lib/router.dart b/lib/router.dart index fccc269..ef136f9 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -12,6 +12,7 @@ import 'package:git_touch/screens/code_theme.dart'; import 'package:git_touch/screens/ge_blob.dart'; import 'package:git_touch/screens/ge_commit.dart'; import 'package:git_touch/screens/ge_commits.dart'; +import 'package:git_touch/screens/ge_contributors.dart'; import 'package:git_touch/screens/ge_files.dart'; import 'package:git_touch/screens/ge_issue.dart'; import 'package:git_touch/screens/ge_issue_comment.dart'; @@ -81,10 +82,12 @@ class CommonRouter { CommonRouter.login, CommonRouter.settings ]; - static final codeTheme = RouterScreen('/choose-code-theme', (context, p) { + static final codeTheme = + RouterScreen('/choose-code-theme', (context, parameters) { return CodeThemeScreen(); }); - static final login = RouterScreen('/login', (context, p) => LoginScreen()); + static final login = + RouterScreen('/login', (context, parameters) => LoginScreen()); static final settings = RouterScreen('/settings', (context, parameters) => SettingsScreen()); } @@ -109,9 +112,9 @@ class GithubRouter { GithubRouter.gistObject, GithubRouter.compare, ]; - static final user = RouterScreen('/:login', (_, p) { - final login = p['login'].first; - final tab = p['tab']?.first; + static final user = RouterScreen('/:login', (context, parameters) { + final login = parameters['login'].first; + final tab = parameters['tab']?.first; switch (tab) { case 'followers': return GhUsersScreen(login, UsersScreenType.follower); @@ -135,75 +138,93 @@ class GithubRouter { return GhUserScreen(login); } }); - static final repo = RouterScreen('/:owner/:name', (_, p) { - if (p['ref'] == null) { - return GhRepoScreen(p['owner'].first, p['name'].first); + static final repo = RouterScreen('/:owner/:name', (context, parameters) { + if (parameters['ref'] == null) { + return GhRepoScreen(parameters['owner'].first, parameters['name'].first); } else { - return GhRepoScreen(p['owner'].first, p['name'].first, - branch: p['ref'].first); + return GhRepoScreen(parameters['owner'].first, parameters['name'].first, + branch: parameters['ref'].first); } }); - static final gistObject = RouterScreen('/:login/gists/:id/:file', (_, p) { + static final gistObject = + RouterScreen('/:login/gists/:id/:file', (context, parameters) { return GistObjectScreen( - p['login'].first, - p['id'].first, - p['file'].first, - raw: p['raw']?.first, - content: p['content'].first, + parameters['login'].first, + parameters['id'].first, + parameters['file'].first, + raw: parameters['raw']?.first, + content: parameters['content'].first, ); }); - static final gistFiles = RouterScreen('/:login/gists/:id', (_, p) { - return GhGistsFilesScreen(p['login'].first, p['id'].first); + static final gistFiles = + RouterScreen('/:login/gists/:id', (context, parameters) { + return GhGistsFilesScreen( + parameters['login'].first, parameters['id'].first); }); - static final issueAdd = RouterScreen('/:owner/:name/issues/new', (_, p) { - return GhIssueFormScreen(p['owner'].first, p['name'].first); + static final issueAdd = + RouterScreen('/:owner/:name/issues/new', (context, parameters) { + return GhIssueFormScreen( + parameters['owner'].first, parameters['name'].first); }); - static final issues = RouterScreen('/:owner/:name/issues', - (context, p) => GhIssuesScreen(p['owner'].first, p['name'].first)); - static final pulls = RouterScreen('/:owner/:name/pulls', - (context, p) => GhPullsScreen(p['owner'].first, p['name'].first)); + static final issues = RouterScreen( + '/:owner/:name/issues', + (context, parameters) => + GhIssuesScreen(parameters['owner'].first, parameters['name'].first)); + static final pulls = RouterScreen( + '/:owner/:name/pulls', + (context, parameters) => + GhPullsScreen(parameters['owner'].first, parameters['name'].first)); static final issue = RouterScreen( '/:owner/:name/issues/:number', - (context, p) => GhIssueScreen( - p['owner'].first, p['name'].first, int.parse(p['number'].first))); + (context, parameters) => GhIssueScreen(parameters['owner'].first, + parameters['name'].first, int.parse(parameters['number'].first))); static final pull = RouterScreen( '/:owner/:name/pull/:number', - (context, p) => GhIssueScreen( - p['owner'].first, p['name'].first, int.parse(p['number'].first), + (context, parameters) => GhIssueScreen(parameters['owner'].first, + parameters['name'].first, int.parse(parameters['number'].first), isPullRequest: true)); static final files = RouterScreen( '/:owner/:name/pull/:number/files', - (context, p) => GhFilesScreen( - p['owner'].first, - p['name'].first, - int.parse(p['number'].first), + (context, parameters) => GhFilesScreen( + parameters['owner'].first, + parameters['name'].first, + int.parse(parameters['number'].first), )); static final compare = RouterScreen( '/:owner/:name/compare/:before/:head', - (context, p) => GhComparisonScreen(p['owner'].first, p['name'].first, - p['before'].first, p['head'].first)); - static final commits = RouterScreen('/:owner/:name/commits', - (context, p) => GhCommitsScreen(p['owner'].first, p['name'].first)); - static final object = RouterScreen('/:owner/:name/blob/:ref', (_, p) { + (context, parameters) => GhComparisonScreen( + parameters['owner'].first, + parameters['name'].first, + parameters['before'].first, + parameters['head'].first)); + static final commits = RouterScreen( + '/:owner/:name/commits', + (context, parameters) => + GhCommitsScreen(parameters['owner'].first, parameters['name'].first)); + static final object = + RouterScreen('/:owner/:name/blob/:ref', (context, parameters) { return GhObjectScreen( - p['owner'].first, - p['name'].first, - p['ref'].first, - path: p['path']?.first, - raw: p['raw']?.first, + parameters['owner'].first, + parameters['name'].first, + parameters['ref'].first, + path: parameters['path']?.first, + raw: parameters['raw']?.first, ); }); - static final stargazers = RouterScreen('/:owner/:name/stargazers', (_, p) { - return GhUsersScreen(p['owner'].first, UsersScreenType.star, - repoName: p['name'].first); + static final stargazers = + RouterScreen('/:owner/:name/stargazers', (context, parameters) { + return GhUsersScreen(parameters['owner'].first, UsersScreenType.star, + repoName: parameters['name'].first); }); - static final watchers = RouterScreen('/:owner/:name/watchers', (_, p) { - return GhUsersScreen(p['owner'].first, UsersScreenType.watch, - repoName: p['name'].first); + static final watchers = + RouterScreen('/:owner/:name/watchers', (context, parameters) { + return GhUsersScreen(parameters['owner'].first, UsersScreenType.watch, + repoName: parameters['name'].first); }); static final contributors = - RouterScreen('/:owner/:name/contributors', (_, p) { - return GhContributorsScreen(p['owner'].first, p['name'].first); + RouterScreen('/:owner/:name/contributors', (context, parameters) { + return GhContributorsScreen( + parameters['owner'].first, parameters['name'].first); }); } @@ -224,44 +245,50 @@ class GitlabRouter { GitlabRouter.groupMembers, GitlabRouter.issue, ]; - static final user = RouterScreen( - '/user/:id', (context, p) => GlUserScreen(int.parse(p['id'].first))); + static final user = RouterScreen('/user/:id', + (context, parameters) => GlUserScreen(int.parse(parameters['id'].first))); static final group = RouterScreen( - '/group/:id', (context, p) => GlGroupScreen(int.parse(p['id'].first))); + '/group/:id', + (context, parameters) => + GlGroupScreen(int.parse(parameters['id'].first))); static final blob = RouterScreen( '/projects/:id/blob/:ref', - (context, params) => GlBlobScreen( - int.parse(params['id'].first), params['ref'].first, - path: params['path']?.first)); + (context, parameters) => GlBlobScreen( + int.parse(parameters['id'].first), parameters['ref'].first, + path: parameters['path']?.first)); static final tree = RouterScreen( '/projects/:id/tree/:ref', - (context, params) => GlTreeScreen( - int.parse(params['id'].first), params['ref'].first, - path: params['path']?.first)); - static final project = RouterScreen('/projects/:id', - (context, params) => GlProjectScreen(int.parse(params['id'].first))); - static final starrers = RouterScreen('/projects/:id/starrers', - (context, params) => GlStarrersScreen(int.parse(params['id'].first))); + (context, parameters) => GlTreeScreen( + int.parse(parameters['id'].first), parameters['ref'].first, + path: parameters['path']?.first)); + static final project = RouterScreen( + '/projects/:id', + (context, parameters) => + GlProjectScreen(int.parse(parameters['id'].first))); + static final starrers = RouterScreen( + '/projects/:id/starrers', + (context, parameters) => + GlStarrersScreen(int.parse(parameters['id'].first))); static final issues = RouterScreen( '/projects/:id/issues', - (context, params) => GlIssuesScreen( - params['id'].first, - prefix: params['prefix'].first, + (context, parameters) => GlIssuesScreen( + parameters['id'].first, + prefix: parameters['prefix'].first, )); static final mergeRequests = RouterScreen( '/projects/:id/merge_requests', - (context, params) => GlMergeRequestsScreen( - params['id'].first, - prefix: params['prefix'].first, + (context, parameters) => GlMergeRequestsScreen( + parameters['id'].first, + prefix: parameters['prefix'].first, )); static final commits = RouterScreen( '/projects/:id/commits', - (context, params) => - GlCommitsScreen(params['id'].first, prefix: params['prefix'].first)); + (context, parameters) => GlCommitsScreen(parameters['id'].first, + prefix: parameters['prefix'].first)); static final commit = RouterScreen( '/projects/:id/commit/:sha', - (context, params) => - GlCommitScreen(params['id'].first, sha: params['sha'].first)); + (context, parameters) => + GlCommitScreen(parameters['id'].first, sha: parameters['sha'].first)); static final projectMembers = RouterScreen( '/projects/:id/members', (context, parameters) => @@ -272,10 +299,10 @@ class GitlabRouter { GlMembersScreen(int.parse(parameters['id'].first), 'groups')); static final issue = RouterScreen( '/gitlab/projects/:id/issues/:iid', - (context, params) { + (context, parameters) { return GlIssueScreen( - int.parse(params['id'].first), - int.parse(params['iid'].first), + int.parse(parameters['id'].first), + int.parse(parameters['iid'].first), ); }, ); @@ -297,9 +324,9 @@ class GiteaRouter { ]; static final status = RouterScreen('/status', (context, parameters) => GtStatusScreen()); - static final user = RouterScreen('/:login', (context, p) { - final login = p['login'].first; - final tab = p['tab']?.first; + static final user = RouterScreen('/:login', (context, parameters) { + final login = parameters['login'].first; + final tab = parameters['tab']?.first; switch (tab) { case 'followers': return GtUsersScreen.followers(login); @@ -321,32 +348,45 @@ class GiteaRouter { }); static final repo = RouterScreen( '/:owner/:name', - (context, params) => - GtRepoScreen(params['owner'].first, params['name'].first), + (context, parameters) => + GtRepoScreen(parameters['owner'].first, parameters['name'].first), ); static final object = RouterScreen( '/:owner/:name/blob', - (context, params) => GtObjectScreen( - params['owner'].first, - params['name'].first, - path: params['path']?.first, + (context, parameters) => GtObjectScreen( + parameters['owner'].first, + parameters['name'].first, + path: parameters['path']?.first, ), ); - static final stargazers = RouterScreen('/:owner/:name/stargazers', (_, p) { - return GtUsersScreen.stargazers(p['owner'].first, p['name'].first); + static final stargazers = + RouterScreen('/:owner/:name/stargazers', (context, parameters) { + return GtUsersScreen.stargazers( + parameters['owner'].first, parameters['name'].first); }); - static final watchers = RouterScreen('/:owner/:name/watchers', (_, p) { - return GtUsersScreen.watchers(p['owner'].first, p['name'].first); + static final watchers = + RouterScreen('/:owner/:name/watchers', (context, parameters) { + return GtUsersScreen.watchers( + parameters['owner'].first, parameters['name'].first); }); - static final forks = RouterScreen('/:owner/:name/forks', (_, p) { - return GtReposScreen.forks(p['owner'].first, p['name'].first); + static final forks = + RouterScreen('/:owner/:name/forks', (context, parameters) { + return GtReposScreen.forks( + parameters['owner'].first, parameters['name'].first); }); - static final commits = RouterScreen('/:owner/:name/commits', - (_, p) => GtCommitsScreen(p['owner'].first, p['name'].first)); - static final issues = RouterScreen('/:owner/:name/issues', - (_, p) => GtIssuesScreen(p['owner'].first, p['name'].first)); - static final pulls = RouterScreen('/:owner/:name/pulls', - (_, p) => GtIssuesScreen(p['owner'].first, p['name'].first, isPr: true)); + static final commits = RouterScreen( + '/:owner/:name/commits', + (context, parameters) => + GtCommitsScreen(parameters['owner'].first, parameters['name'].first)); + static final issues = RouterScreen( + '/:owner/:name/issues', + (context, parameters) => + GtIssuesScreen(parameters['owner'].first, parameters['name'].first)); + static final pulls = RouterScreen( + '/:owner/:name/pulls', + (context, parameters) => GtIssuesScreen( + parameters['owner'].first, parameters['name'].first, + isPr: true)); } class BitbucketRouter { @@ -364,40 +404,46 @@ class BitbucketRouter { ]; static final user = RouterScreen( '/:login', - (context, params) => BbUserScreen(params['login'].first, - isTeam: params['team'].first == '1')); + (context, parameters) => BbUserScreen(parameters['login'].first, + isTeam: parameters['team'].first == '1')); static final repo = RouterScreen( '/:owner/:name', - (context, params) => - BbRepoScreen(params['owner'].first, params['name'].first), + (context, parameters) => + BbRepoScreen(parameters['owner'].first, parameters['name'].first), ); static final object = RouterScreen( '/:owner/:name/src/:ref', - (context, params) => BbObjectScreen( - params['owner'].first, - params['name'].first, - params['ref'].first, - path: params['path']?.first, + (context, parameters) => BbObjectScreen( + parameters['owner'].first, + parameters['name'].first, + parameters['ref'].first, + path: parameters['path']?.first, ), ); - static final issues = RouterScreen('/:owner/:name/issues', - (_, p) => BbIssuesScreen(p['owner'].first, p['name'].first)); + static final issues = RouterScreen( + '/:owner/:name/issues', + (context, parameters) => + BbIssuesScreen(parameters['owner'].first, parameters['name'].first)); static final commits = RouterScreen( '/:owner/:name/commits/:ref', - (_, p) => - BbCommitsScreen(p['owner'].first, p['name'].first, p['ref'].first)); - static final pulls = RouterScreen('/:owner/:name/pulls', - (_, p) => BbPullsScreen(p['owner'].first, p['name'].first)); - static final issueAdd = RouterScreen('/:owner/:name/issues/new', - (_, p) => BbIssueFormScreen(p['owner'].first, p['name'].first)); + (context, parameters) => BbCommitsScreen(parameters['owner'].first, + parameters['name'].first, parameters['ref'].first)); + static final pulls = RouterScreen( + '/:owner/:name/pulls', + (context, parameters) => + BbPullsScreen(parameters['owner'].first, parameters['name'].first)); + static final issueAdd = RouterScreen( + '/:owner/:name/issues/new', + (context, parameters) => BbIssueFormScreen( + parameters['owner'].first, parameters['name'].first)); static final issue = RouterScreen( '/:owner/:name/issues/:number', - (_, p) => - BbIssueScreen(p['owner'].first, p['name'].first, p['number'].first)); + (context, parameters) => BbIssueScreen(parameters['owner'].first, + parameters['name'].first, parameters['number'].first)); static final issueComment = RouterScreen( '/:owner/:name/issues/:number/comment', - (_, p) => BbIssueCommentScreen( - p['owner'].first, p['name'].first, p['number'].first)); + (context, parameters) => BbIssueCommentScreen(parameters['owner'].first, + parameters['name'].first, parameters['number'].first)); } class GiteeRouter { @@ -421,13 +467,14 @@ class GiteeRouter { GiteeRouter.pullComment, GiteeRouter.files, GiteeRouter.commit, + GiteeRouter.contributors, ]; static final search = RouterScreen('/search', (context, parameters) { return GeSearchScreen(); }); - static final user = RouterScreen('/:login', (context, p) { - final login = p['login'].first; - final tab = p['tab']?.first; + static final user = RouterScreen('/:login', (context, parameters) { + final login = parameters['login'].first; + final tab = parameters['tab']?.first; switch (tab) { case 'followers': return GeUsersScreen.followers(login); @@ -444,21 +491,37 @@ class GiteeRouter { }); static final repo = RouterScreen( '/:owner/:name', - (context, params) => - GeRepoScreen(params['owner'].first, params['name'].first), + (context, parameters) { + if (parameters['branch'] == null) { + return GeRepoScreen( + parameters['owner'].first, parameters['name'].first); + } else { + return GeRepoScreen(parameters['owner'].first, parameters['name'].first, + branch: parameters['branch'].first); + } + }, ); - static final stargazers = RouterScreen('/:owner/:name/stargazers', (_, p) { - return GeUsersScreen.stargazers(p['owner'].first, p['name'].first); + static final stargazers = + RouterScreen('/:owner/:name/stargazers', (context, parameters) { + return GeUsersScreen.stargazers( + parameters['owner'].first, parameters['name'].first); }); - static final watchers = RouterScreen('/:owner/:name/watchers', (_, p) { - return GeUsersScreen.watchers(p['owner'].first, p['name'].first); + static final watchers = + RouterScreen('/:owner/:name/watchers', (context, parameters) { + return GeUsersScreen.watchers( + parameters['owner'].first, parameters['name'].first); }); - static final forks = RouterScreen('/:owner/:name/forks', (_, p) { - return GeReposScreen.forks(p['owner'].first, p['name'].first); + static final forks = + RouterScreen('/:owner/:name/forks', (context, parameters) { + return GeReposScreen.forks( + parameters['owner'].first, parameters['name'].first); }); static final commits = RouterScreen( '/:owner/:name/commits', - (_, p) => GeCommitsScreen(p['owner'].first, p['name'].first), + (context, parameters) => GeCommitsScreen( + parameters['owner'].first, parameters['name'].first, + branch: + parameters['branch'] != null ? parameters['branch'].first : null), ); static final tree = RouterScreen( '/:owner/:name/tree/:sha', @@ -543,4 +606,9 @@ class GiteeRouter { (context, parameters) => GeCommitScreen(parameters['owner'].first, parameters['name'].first, parameters['sha'].first), ); + static final contributors = RouterScreen( + '/:owner/:name/contributors', + (context, parameters) => GeContributorsScreen( + parameters['owner'].first, parameters['name'].first), + ); } diff --git a/lib/screens/ge_commits.dart b/lib/screens/ge_commits.dart index 36189ad..501ad47 100644 --- a/lib/screens/ge_commits.dart +++ b/lib/screens/ge_commits.dart @@ -10,17 +10,17 @@ import '../generated/l10n.dart'; class GeCommitsScreen extends StatelessWidget { final String owner; final String name; - // final String branch; // TODO: - GeCommitsScreen(this.owner, this.name); + final String branch; + GeCommitsScreen(this.owner, this.name, {this.branch}); @override Widget build(BuildContext context) { return ListStatefulScaffold( title: AppBarTitle(S.of(context).commits), fetch: (page) async { - final res = await context - .read() - .fetchGiteeWithPage('/repos/$owner/$name/commits', page: page); + final res = await context.read().fetchGiteeWithPage( + '/repos/$owner/$name/commits?sha=$branch', + page: page); return ListPayload( cursor: res.cursor, hasMore: res.hasMore, diff --git a/lib/screens/ge_contributors.dart b/lib/screens/ge_contributors.dart new file mode 100644 index 0000000..98de455 --- /dev/null +++ b/lib/screens/ge_contributors.dart @@ -0,0 +1,80 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:git_touch/models/gitee.dart'; +import 'package:git_touch/models/theme.dart'; +import 'package:git_touch/scaffolds/list_stateful.dart'; +import 'package:git_touch/utils/utils.dart'; +import 'package:git_touch/widgets/app_bar_title.dart'; +import 'package:provider/provider.dart'; +import 'package:git_touch/models/auth.dart'; +import '../generated/l10n.dart'; + +class GeContributorsScreen extends StatelessWidget { + final String owner; + final String name; + GeContributorsScreen(this.owner, this.name); + + Widget build(BuildContext context) { + return ListStatefulScaffold( + title: AppBarTitle(S.of(context).contributors), + fetch: (page) async { + page = page ?? 1; + final res = await context + .read() + .fetchGiteeWithPage('/repos/$owner/$name/contributors') + .then((v) { + return [ + for (var contributor in v.data) + GiteeContributor.fromJson(contributor) + ]; + }); + return ListPayload( + cursor: page + 1, + items: res, + hasMore: res.isNotEmpty, + ); + }, + itemBuilder: (v) { + final theme = context.read(); + return Container( + padding: CommonStyle.padding, + child: Row( + children: [ + SizedBox(width: 10), + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text( + v.name, + style: TextStyle( + color: theme.palette.primary, + fontSize: 18, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + SizedBox(height: 6), + if (v.contributions != null) + DefaultTextStyle( + style: TextStyle( + color: theme.palette.secondaryText, + fontSize: 16, + ), + child: Text( + "Contributions: " + v.contributions.toString()), + ), + ], + ), + ) + ], + ), + ); + }, + ); + } +} diff --git a/lib/screens/ge_issues.dart b/lib/screens/ge_issues.dart index c3f9555..e5197ae 100644 --- a/lib/screens/ge_issues.dart +++ b/lib/screens/ge_issues.dart @@ -6,6 +6,7 @@ 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/widgets/issue_item.dart'; +import 'package:git_touch/widgets/label.dart'; import 'package:provider/provider.dart'; class GeIssuesScreen extends StatelessWidget { @@ -40,6 +41,12 @@ class GeIssuesScreen extends StatelessWidget { title: p.title, updatedAt: DateTime.parse(p.updatedAt), url: '/gitee/$owner/$name/issues/${p.number}', + labels: p.labels.isEmpty + ? null + : Wrap(spacing: 4, runSpacing: 4, children: [ + for (var label in p.labels) + MyLabel(name: label.name, cssColor: label.color) + ]), ), ); } diff --git a/lib/screens/ge_pulls.dart b/lib/screens/ge_pulls.dart index 0971bc4..8b91433 100644 --- a/lib/screens/ge_pulls.dart +++ b/lib/screens/ge_pulls.dart @@ -4,6 +4,7 @@ import 'package:git_touch/models/gitee.dart'; import 'package:git_touch/scaffolds/list_stateful.dart'; import 'package:git_touch/widgets/app_bar_title.dart'; import 'package:git_touch/widgets/issue_item.dart'; +import 'package:git_touch/widgets/label.dart'; import 'package:provider/provider.dart'; class GePullsScreen extends StatelessWidget { @@ -34,6 +35,12 @@ class GePullsScreen extends StatelessWidget { title: p.title, updatedAt: DateTime.parse(p.updatedAt), url: '/gitee/$owner/$name/pulls/${p.number}', + labels: p.labels.isEmpty + ? null + : Wrap(spacing: 4, runSpacing: 4, children: [ + for (var label in p.labels) + MyLabel(name: label.name, cssColor: label.color) + ]), ), ); } diff --git a/lib/screens/ge_repo.dart b/lib/screens/ge_repo.dart index 5172b55..0a6bfee 100644 --- a/lib/screens/ge_repo.dart +++ b/lib/screens/ge_repo.dart @@ -1,8 +1,8 @@ import 'dart:convert'; - import 'package:flutter/material.dart'; import 'package:git_touch/models/auth.dart'; import 'package:git_touch/models/gitee.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'; @@ -18,11 +18,13 @@ import '../generated/l10n.dart'; class GeRepoScreen extends StatelessWidget { final String owner; final String name; - GeRepoScreen(this.owner, this.name); + final String branch; + GeRepoScreen(this.owner, this.name, {this.branch}); @override Widget build(BuildContext context) { - return RefreshStatefulScaffold>( + return RefreshStatefulScaffold< + Tuple3>>( title: AppBarTitle(S.of(context).repository), fetch: () async { final auth = context.read(); @@ -43,11 +45,16 @@ class GeRepoScreen extends StatelessWidget { return utf8.decode(res.bodyBytes).normalizedHtml; }); final readmeData = MarkdownViewData(context, md: md, html: html); - - return Tuple2(repo, readmeData); + final branches = + await auth.fetchGitee('/repos/$owner/$name/branches').then((v) { + return [for (var branch in v) GiteeBranch.fromJson(branch)]; + }); + return Tuple3(repo, readmeData, branches); }, bodyBuilder: (t, setState) { final p = t.item1; + final branches = t.item3; + final theme = context.read(); return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ @@ -86,7 +93,8 @@ class GeRepoScreen extends StatelessWidget { leftIconData: Octicons.code, text: Text('Code'), rightWidget: Text(p.license ?? ''), - url: '/gitee/$owner/$name/tree/${p.defaultBranch}', + url: + '/gitee/$owner/$name/tree/${branch == null ? p.defaultBranch : branch}', ), TableViewItem( leftIconData: Octicons.issue_opened, @@ -103,8 +111,42 @@ class GeRepoScreen extends StatelessWidget { TableViewItem( leftIconData: Octicons.history, text: Text('Commits'), - url: '/gitee/$owner/$name/commits', + url: + '/gitee/$owner/$name/commits?branch=${branch == null ? p.defaultBranch : branch}', ), + if (branches != null) + TableViewItem( + leftIconData: Octicons.git_branch, + text: Text(S.of(context).branches), + rightWidget: Text( + (branch == null ? p.defaultBranch : branch) + + ' • ' + + branches.length.toString()), + onTap: () async { + if (branches.length < 2) return; + + await theme.showPicker( + context, + PickerGroupItem( + value: branch, + items: branches + .map((b) => PickerItem(b.name, text: b.name)) + .toList(), + onClose: (ref) { + if (ref != branch) { + theme.push( + context, '/gitee/$owner/$name?branch=$ref', + replace: true); + } + }, + ), + ); + }, + ), + TableViewItem( + leftIconData: Octicons.organization, + text: Text('Contributors'), + url: '/gitee/$owner/$name/contributors'), ], ), CommonStyle.verticalGap, diff --git a/lib/screens/ge_search.dart b/lib/screens/ge_search.dart index 957680f..4a5b438 100644 --- a/lib/screens/ge_search.dart +++ b/lib/screens/ge_search.dart @@ -131,7 +131,7 @@ class _GeSearchScreenState extends State { login: p.login, name: p.name, avatarUrl: p.avatarUrl, - bio: Text(p.htmlUrl), + bio: Text(p.bio != null ? p.bio : p.htmlUrl), ); default: return IssueItem(