feat(gitee): branches, labels, contributors, refactor(RouterScreen) (#153)

* feat: labels, contributors, fix: bio in search

* feat: branch, cancel/confirm to showPicker

* refactor(router): RouterScreen fallback params
This commit is contained in:
Shreyas Thirumalai 2021-01-09 22:22:45 +05:30 committed by GitHub
parent 85a393dd2e
commit f723eef83a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 487 additions and 171 deletions

View File

@ -124,6 +124,15 @@ class GiteeBlob {
_$GiteeBlobFromJson(json); _$GiteeBlobFromJson(json);
} }
@JsonSerializable(fieldRename: FieldRename.snake)
class GiteeLabel {
String color;
String name;
GiteeLabel();
factory GiteeLabel.fromJson(Map<String, dynamic> json) =>
_$GiteeLabelFromJson(json);
}
@JsonSerializable(fieldRename: FieldRename.snake) @JsonSerializable(fieldRename: FieldRename.snake)
class GiteeIssue { class GiteeIssue {
int comments; int comments;
@ -138,6 +147,7 @@ class GiteeIssue {
GiteeRepo repository; GiteeRepo repository;
GiteeRepoOwner user; GiteeRepoOwner user;
String number; String number;
List<GiteeLabel> labels;
int id; int id;
GiteeIssue(); GiteeIssue();
factory GiteeIssue.fromJson(Map<String, dynamic> json) => factory GiteeIssue.fromJson(Map<String, dynamic> json) =>
@ -155,6 +165,7 @@ class GiteePull {
String title; String title;
String state; String state;
GiteeRepoOwner user; GiteeRepoOwner user;
List<GiteeLabel> labels;
int number; int number;
int id; int id;
GiteePull(); GiteePull();
@ -211,3 +222,20 @@ class GiteeCommitFile {
factory GiteeCommitFile.fromJson(Map<String, dynamic> json) => factory GiteeCommitFile.fromJson(Map<String, dynamic> json) =>
_$GiteeCommitFileFromJson(json); _$GiteeCommitFileFromJson(json);
} }
@JsonSerializable(fieldRename: FieldRename.snake)
class GiteeContributor {
String name;
int contributions;
GiteeContributor();
factory GiteeContributor.fromJson(Map<String, dynamic> json) =>
_$GiteeContributorFromJson(json);
}
@JsonSerializable(fieldRename: FieldRename.snake)
class GiteeBranch {
String name;
GiteeBranch();
factory GiteeBranch.fromJson(Map<String, dynamic> json) =>
_$GiteeBranchFromJson(json);
}

View File

@ -206,6 +206,18 @@ Map<String, dynamic> _$GiteeBlobToJson(GiteeBlob instance) => <String, dynamic>{
'content': instance.content, 'content': instance.content,
}; };
GiteeLabel _$GiteeLabelFromJson(Map<String, dynamic> json) {
return GiteeLabel()
..color = json['color'] as String
..name = json['name'] as String;
}
Map<String, dynamic> _$GiteeLabelToJson(GiteeLabel instance) =>
<String, dynamic>{
'color': instance.color,
'name': instance.name,
};
GiteeIssue _$GiteeIssueFromJson(Map<String, dynamic> json) { GiteeIssue _$GiteeIssueFromJson(Map<String, dynamic> json) {
return GiteeIssue() return GiteeIssue()
..comments = json['comments'] as int ..comments = json['comments'] as int
@ -224,6 +236,10 @@ GiteeIssue _$GiteeIssueFromJson(Map<String, dynamic> json) {
? null ? null
: GiteeRepoOwner.fromJson(json['user'] as Map<String, dynamic>) : GiteeRepoOwner.fromJson(json['user'] as Map<String, dynamic>)
..number = json['number'] as String ..number = json['number'] as String
..labels = (json['labels'] as List)
?.map((e) =>
e == null ? null : GiteeLabel.fromJson(e as Map<String, dynamic>))
?.toList()
..id = json['id'] as int; ..id = json['id'] as int;
} }
@ -241,6 +257,7 @@ Map<String, dynamic> _$GiteeIssueToJson(GiteeIssue instance) =>
'repository': instance.repository, 'repository': instance.repository,
'user': instance.user, 'user': instance.user,
'number': instance.number, 'number': instance.number,
'labels': instance.labels,
'id': instance.id, 'id': instance.id,
}; };
@ -257,6 +274,10 @@ GiteePull _$GiteePullFromJson(Map<String, dynamic> json) {
..user = json['user'] == null ..user = json['user'] == null
? null ? null
: GiteeRepoOwner.fromJson(json['user'] as Map<String, dynamic>) : GiteeRepoOwner.fromJson(json['user'] as Map<String, dynamic>)
..labels = (json['labels'] as List)
?.map((e) =>
e == null ? null : GiteeLabel.fromJson(e as Map<String, dynamic>))
?.toList()
..number = json['number'] as int ..number = json['number'] as int
..id = json['id'] as int; ..id = json['id'] as int;
} }
@ -271,6 +292,7 @@ Map<String, dynamic> _$GiteePullToJson(GiteePull instance) => <String, dynamic>{
'title': instance.title, 'title': instance.title,
'state': instance.state, 'state': instance.state,
'user': instance.user, 'user': instance.user,
'labels': instance.labels,
'number': instance.number, 'number': instance.number,
'id': instance.id, 'id': instance.id,
}; };
@ -349,3 +371,24 @@ Map<String, dynamic> _$GiteeCommitFileToJson(GiteeCommitFile instance) =>
'status': instance.status, 'status': instance.status,
'patch': instance.patch, 'patch': instance.patch,
}; };
GiteeContributor _$GiteeContributorFromJson(Map<String, dynamic> json) {
return GiteeContributor()
..name = json['name'] as String
..contributions = json['contributions'] as int;
}
Map<String, dynamic> _$GiteeContributorToJson(GiteeContributor instance) =>
<String, dynamic>{
'name': instance.name,
'contributions': instance.contributions,
};
GiteeBranch _$GiteeBranchFromJson(Map<String, dynamic> json) {
return GiteeBranch()..name = json['name'] as String;
}
Map<String, dynamic> _$GiteeBranchToJson(GiteeBranch instance) =>
<String, dynamic>{
'name': instance.name,
};

View File

@ -317,39 +317,80 @@ class ThemeModel with ChangeNotifier {
await showCupertinoModalPopup( await showCupertinoModalPopup(
context: context, context: context,
builder: (context) { builder: (context) {
return Container( return Column(
height: 216, mainAxisAlignment: MainAxisAlignment.end,
child: CupertinoPicker( children: [
backgroundColor: palette.background, Container(
children: <Widget>[ alignment: Alignment.bottomCenter,
for (var v in groupItem.items) decoration: BoxDecoration(
Text(v.text, style: TextStyle(color: palette.text)), color: palette.background,
], border: Border(
itemExtent: 40, bottom: BorderSide(
scrollController: FixedExtentScrollController( color: palette.grayBackground,
initialItem: groupItem.items width: 0.0,
.toList() ),
.indexWhere((v) => v.value == groupItem.value)), ),
onSelectedItemChanged: (index) { ),
_selectedItem = groupItem.items[index].value; child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
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: <Widget>[
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 (groupItem.onChange != null) {
if (_debounce?.isActive ?? false) { if (_debounce?.isActive ?? false) {
_debounce.cancel(); _debounce.cancel();
} }
_debounce = Timer(const Duration(milliseconds: 500), () { _debounce = Timer(const Duration(milliseconds: 500), () {
groupItem.onChange(_selectedItem); groupItem.onChange(_selectedItem);
}); });
} }
}, },
), ),
)
],
); );
}, },
); );
if (groupItem.onClose != null) {
groupItem.onClose(_selectedItem);
}
} }
showActions(BuildContext context, List<ActionItem> actionItems) async { showActions(BuildContext context, List<ActionItem> actionItems) async {

View File

@ -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_blob.dart';
import 'package:git_touch/screens/ge_commit.dart'; import 'package:git_touch/screens/ge_commit.dart';
import 'package:git_touch/screens/ge_commits.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_files.dart';
import 'package:git_touch/screens/ge_issue.dart'; import 'package:git_touch/screens/ge_issue.dart';
import 'package:git_touch/screens/ge_issue_comment.dart'; import 'package:git_touch/screens/ge_issue_comment.dart';
@ -81,10 +82,12 @@ class CommonRouter {
CommonRouter.login, CommonRouter.login,
CommonRouter.settings CommonRouter.settings
]; ];
static final codeTheme = RouterScreen('/choose-code-theme', (context, p) { static final codeTheme =
RouterScreen('/choose-code-theme', (context, parameters) {
return CodeThemeScreen(); return CodeThemeScreen();
}); });
static final login = RouterScreen('/login', (context, p) => LoginScreen()); static final login =
RouterScreen('/login', (context, parameters) => LoginScreen());
static final settings = static final settings =
RouterScreen('/settings', (context, parameters) => SettingsScreen()); RouterScreen('/settings', (context, parameters) => SettingsScreen());
} }
@ -109,9 +112,9 @@ class GithubRouter {
GithubRouter.gistObject, GithubRouter.gistObject,
GithubRouter.compare, GithubRouter.compare,
]; ];
static final user = RouterScreen('/:login', (_, p) { static final user = RouterScreen('/:login', (context, parameters) {
final login = p['login'].first; final login = parameters['login'].first;
final tab = p['tab']?.first; final tab = parameters['tab']?.first;
switch (tab) { switch (tab) {
case 'followers': case 'followers':
return GhUsersScreen(login, UsersScreenType.follower); return GhUsersScreen(login, UsersScreenType.follower);
@ -135,75 +138,93 @@ class GithubRouter {
return GhUserScreen(login); return GhUserScreen(login);
} }
}); });
static final repo = RouterScreen('/:owner/:name', (_, p) { static final repo = RouterScreen('/:owner/:name', (context, parameters) {
if (p['ref'] == null) { if (parameters['ref'] == null) {
return GhRepoScreen(p['owner'].first, p['name'].first); return GhRepoScreen(parameters['owner'].first, parameters['name'].first);
} else { } else {
return GhRepoScreen(p['owner'].first, p['name'].first, return GhRepoScreen(parameters['owner'].first, parameters['name'].first,
branch: p['ref'].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( return GistObjectScreen(
p['login'].first, parameters['login'].first,
p['id'].first, parameters['id'].first,
p['file'].first, parameters['file'].first,
raw: p['raw']?.first, raw: parameters['raw']?.first,
content: p['content'].first, content: parameters['content'].first,
); );
}); });
static final gistFiles = RouterScreen('/:login/gists/:id', (_, p) { static final gistFiles =
return GhGistsFilesScreen(p['login'].first, p['id'].first); RouterScreen('/:login/gists/:id', (context, parameters) {
return GhGistsFilesScreen(
parameters['login'].first, parameters['id'].first);
}); });
static final issueAdd = RouterScreen('/:owner/:name/issues/new', (_, p) { static final issueAdd =
return GhIssueFormScreen(p['owner'].first, p['name'].first); RouterScreen('/:owner/:name/issues/new', (context, parameters) {
return GhIssueFormScreen(
parameters['owner'].first, parameters['name'].first);
}); });
static final issues = RouterScreen('/:owner/:name/issues', static final issues = RouterScreen(
(context, p) => GhIssuesScreen(p['owner'].first, p['name'].first)); '/:owner/:name/issues',
static final pulls = RouterScreen('/:owner/:name/pulls', (context, parameters) =>
(context, p) => GhPullsScreen(p['owner'].first, p['name'].first)); 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( static final issue = RouterScreen(
'/:owner/:name/issues/:number', '/:owner/:name/issues/:number',
(context, p) => GhIssueScreen( (context, parameters) => GhIssueScreen(parameters['owner'].first,
p['owner'].first, p['name'].first, int.parse(p['number'].first))); parameters['name'].first, int.parse(parameters['number'].first)));
static final pull = RouterScreen( static final pull = RouterScreen(
'/:owner/:name/pull/:number', '/:owner/:name/pull/:number',
(context, p) => GhIssueScreen( (context, parameters) => GhIssueScreen(parameters['owner'].first,
p['owner'].first, p['name'].first, int.parse(p['number'].first), parameters['name'].first, int.parse(parameters['number'].first),
isPullRequest: true)); isPullRequest: true));
static final files = RouterScreen( static final files = RouterScreen(
'/:owner/:name/pull/:number/files', '/:owner/:name/pull/:number/files',
(context, p) => GhFilesScreen( (context, parameters) => GhFilesScreen(
p['owner'].first, parameters['owner'].first,
p['name'].first, parameters['name'].first,
int.parse(p['number'].first), int.parse(parameters['number'].first),
)); ));
static final compare = RouterScreen( static final compare = RouterScreen(
'/:owner/:name/compare/:before/:head', '/:owner/:name/compare/:before/:head',
(context, p) => GhComparisonScreen(p['owner'].first, p['name'].first, (context, parameters) => GhComparisonScreen(
p['before'].first, p['head'].first)); parameters['owner'].first,
static final commits = RouterScreen('/:owner/:name/commits', parameters['name'].first,
(context, p) => GhCommitsScreen(p['owner'].first, p['name'].first)); parameters['before'].first,
static final object = RouterScreen('/:owner/:name/blob/:ref', (_, p) { 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( return GhObjectScreen(
p['owner'].first, parameters['owner'].first,
p['name'].first, parameters['name'].first,
p['ref'].first, parameters['ref'].first,
path: p['path']?.first, path: parameters['path']?.first,
raw: p['raw']?.first, raw: parameters['raw']?.first,
); );
}); });
static final stargazers = RouterScreen('/:owner/:name/stargazers', (_, p) { static final stargazers =
return GhUsersScreen(p['owner'].first, UsersScreenType.star, RouterScreen('/:owner/:name/stargazers', (context, parameters) {
repoName: p['name'].first); return GhUsersScreen(parameters['owner'].first, UsersScreenType.star,
repoName: parameters['name'].first);
}); });
static final watchers = RouterScreen('/:owner/:name/watchers', (_, p) { static final watchers =
return GhUsersScreen(p['owner'].first, UsersScreenType.watch, RouterScreen('/:owner/:name/watchers', (context, parameters) {
repoName: p['name'].first); return GhUsersScreen(parameters['owner'].first, UsersScreenType.watch,
repoName: parameters['name'].first);
}); });
static final contributors = static final contributors =
RouterScreen('/:owner/:name/contributors', (_, p) { RouterScreen('/:owner/:name/contributors', (context, parameters) {
return GhContributorsScreen(p['owner'].first, p['name'].first); return GhContributorsScreen(
parameters['owner'].first, parameters['name'].first);
}); });
} }
@ -224,44 +245,50 @@ class GitlabRouter {
GitlabRouter.groupMembers, GitlabRouter.groupMembers,
GitlabRouter.issue, GitlabRouter.issue,
]; ];
static final user = RouterScreen( static final user = RouterScreen('/user/:id',
'/user/:id', (context, p) => GlUserScreen(int.parse(p['id'].first))); (context, parameters) => GlUserScreen(int.parse(parameters['id'].first)));
static final group = RouterScreen( 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( static final blob = RouterScreen(
'/projects/:id/blob/:ref', '/projects/:id/blob/:ref',
(context, params) => GlBlobScreen( (context, parameters) => GlBlobScreen(
int.parse(params['id'].first), params['ref'].first, int.parse(parameters['id'].first), parameters['ref'].first,
path: params['path']?.first)); path: parameters['path']?.first));
static final tree = RouterScreen( static final tree = RouterScreen(
'/projects/:id/tree/:ref', '/projects/:id/tree/:ref',
(context, params) => GlTreeScreen( (context, parameters) => GlTreeScreen(
int.parse(params['id'].first), params['ref'].first, int.parse(parameters['id'].first), parameters['ref'].first,
path: params['path']?.first)); path: parameters['path']?.first));
static final project = RouterScreen('/projects/:id', static final project = RouterScreen(
(context, params) => GlProjectScreen(int.parse(params['id'].first))); '/projects/:id',
static final starrers = RouterScreen('/projects/:id/starrers', (context, parameters) =>
(context, params) => GlStarrersScreen(int.parse(params['id'].first))); 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( static final issues = RouterScreen(
'/projects/:id/issues', '/projects/:id/issues',
(context, params) => GlIssuesScreen( (context, parameters) => GlIssuesScreen(
params['id'].first, parameters['id'].first,
prefix: params['prefix'].first, prefix: parameters['prefix'].first,
)); ));
static final mergeRequests = RouterScreen( static final mergeRequests = RouterScreen(
'/projects/:id/merge_requests', '/projects/:id/merge_requests',
(context, params) => GlMergeRequestsScreen( (context, parameters) => GlMergeRequestsScreen(
params['id'].first, parameters['id'].first,
prefix: params['prefix'].first, prefix: parameters['prefix'].first,
)); ));
static final commits = RouterScreen( static final commits = RouterScreen(
'/projects/:id/commits', '/projects/:id/commits',
(context, params) => (context, parameters) => GlCommitsScreen(parameters['id'].first,
GlCommitsScreen(params['id'].first, prefix: params['prefix'].first)); prefix: parameters['prefix'].first));
static final commit = RouterScreen( static final commit = RouterScreen(
'/projects/:id/commit/:sha', '/projects/:id/commit/:sha',
(context, params) => (context, parameters) =>
GlCommitScreen(params['id'].first, sha: params['sha'].first)); GlCommitScreen(parameters['id'].first, sha: parameters['sha'].first));
static final projectMembers = RouterScreen( static final projectMembers = RouterScreen(
'/projects/:id/members', '/projects/:id/members',
(context, parameters) => (context, parameters) =>
@ -272,10 +299,10 @@ class GitlabRouter {
GlMembersScreen(int.parse(parameters['id'].first), 'groups')); GlMembersScreen(int.parse(parameters['id'].first), 'groups'));
static final issue = RouterScreen( static final issue = RouterScreen(
'/gitlab/projects/:id/issues/:iid', '/gitlab/projects/:id/issues/:iid',
(context, params) { (context, parameters) {
return GlIssueScreen( return GlIssueScreen(
int.parse(params['id'].first), int.parse(parameters['id'].first),
int.parse(params['iid'].first), int.parse(parameters['iid'].first),
); );
}, },
); );
@ -297,9 +324,9 @@ class GiteaRouter {
]; ];
static final status = static final status =
RouterScreen('/status', (context, parameters) => GtStatusScreen()); RouterScreen('/status', (context, parameters) => GtStatusScreen());
static final user = RouterScreen('/:login', (context, p) { static final user = RouterScreen('/:login', (context, parameters) {
final login = p['login'].first; final login = parameters['login'].first;
final tab = p['tab']?.first; final tab = parameters['tab']?.first;
switch (tab) { switch (tab) {
case 'followers': case 'followers':
return GtUsersScreen.followers(login); return GtUsersScreen.followers(login);
@ -321,32 +348,45 @@ class GiteaRouter {
}); });
static final repo = RouterScreen( static final repo = RouterScreen(
'/:owner/:name', '/:owner/:name',
(context, params) => (context, parameters) =>
GtRepoScreen(params['owner'].first, params['name'].first), GtRepoScreen(parameters['owner'].first, parameters['name'].first),
); );
static final object = RouterScreen( static final object = RouterScreen(
'/:owner/:name/blob', '/:owner/:name/blob',
(context, params) => GtObjectScreen( (context, parameters) => GtObjectScreen(
params['owner'].first, parameters['owner'].first,
params['name'].first, parameters['name'].first,
path: params['path']?.first, path: parameters['path']?.first,
), ),
); );
static final stargazers = RouterScreen('/:owner/:name/stargazers', (_, p) { static final stargazers =
return GtUsersScreen.stargazers(p['owner'].first, p['name'].first); RouterScreen('/:owner/:name/stargazers', (context, parameters) {
return GtUsersScreen.stargazers(
parameters['owner'].first, parameters['name'].first);
}); });
static final watchers = RouterScreen('/:owner/:name/watchers', (_, p) { static final watchers =
return GtUsersScreen.watchers(p['owner'].first, p['name'].first); RouterScreen('/:owner/:name/watchers', (context, parameters) {
return GtUsersScreen.watchers(
parameters['owner'].first, parameters['name'].first);
}); });
static final forks = RouterScreen('/:owner/:name/forks', (_, p) { static final forks =
return GtReposScreen.forks(p['owner'].first, p['name'].first); RouterScreen('/:owner/:name/forks', (context, parameters) {
return GtReposScreen.forks(
parameters['owner'].first, parameters['name'].first);
}); });
static final commits = RouterScreen('/:owner/:name/commits', static final commits = RouterScreen(
(_, p) => GtCommitsScreen(p['owner'].first, p['name'].first)); '/:owner/:name/commits',
static final issues = RouterScreen('/:owner/:name/issues', (context, parameters) =>
(_, p) => GtIssuesScreen(p['owner'].first, p['name'].first)); GtCommitsScreen(parameters['owner'].first, parameters['name'].first));
static final pulls = RouterScreen('/:owner/:name/pulls', static final issues = RouterScreen(
(_, p) => GtIssuesScreen(p['owner'].first, p['name'].first, isPr: true)); '/: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 { class BitbucketRouter {
@ -364,40 +404,46 @@ class BitbucketRouter {
]; ];
static final user = RouterScreen( static final user = RouterScreen(
'/:login', '/:login',
(context, params) => BbUserScreen(params['login'].first, (context, parameters) => BbUserScreen(parameters['login'].first,
isTeam: params['team'].first == '1')); isTeam: parameters['team'].first == '1'));
static final repo = RouterScreen( static final repo = RouterScreen(
'/:owner/:name', '/:owner/:name',
(context, params) => (context, parameters) =>
BbRepoScreen(params['owner'].first, params['name'].first), BbRepoScreen(parameters['owner'].first, parameters['name'].first),
); );
static final object = RouterScreen( static final object = RouterScreen(
'/:owner/:name/src/:ref', '/:owner/:name/src/:ref',
(context, params) => BbObjectScreen( (context, parameters) => BbObjectScreen(
params['owner'].first, parameters['owner'].first,
params['name'].first, parameters['name'].first,
params['ref'].first, parameters['ref'].first,
path: params['path']?.first, path: parameters['path']?.first,
), ),
); );
static final issues = RouterScreen('/:owner/:name/issues', static final issues = RouterScreen(
(_, p) => BbIssuesScreen(p['owner'].first, p['name'].first)); '/:owner/:name/issues',
(context, parameters) =>
BbIssuesScreen(parameters['owner'].first, parameters['name'].first));
static final commits = RouterScreen( static final commits = RouterScreen(
'/:owner/:name/commits/:ref', '/:owner/:name/commits/:ref',
(_, p) => (context, parameters) => BbCommitsScreen(parameters['owner'].first,
BbCommitsScreen(p['owner'].first, p['name'].first, p['ref'].first)); parameters['name'].first, parameters['ref'].first));
static final pulls = RouterScreen('/:owner/:name/pulls', static final pulls = RouterScreen(
(_, p) => BbPullsScreen(p['owner'].first, p['name'].first)); '/:owner/:name/pulls',
static final issueAdd = RouterScreen('/:owner/:name/issues/new', (context, parameters) =>
(_, p) => BbIssueFormScreen(p['owner'].first, p['name'].first)); 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( static final issue = RouterScreen(
'/:owner/:name/issues/:number', '/:owner/:name/issues/:number',
(_, p) => (context, parameters) => BbIssueScreen(parameters['owner'].first,
BbIssueScreen(p['owner'].first, p['name'].first, p['number'].first)); parameters['name'].first, parameters['number'].first));
static final issueComment = RouterScreen( static final issueComment = RouterScreen(
'/:owner/:name/issues/:number/comment', '/:owner/:name/issues/:number/comment',
(_, p) => BbIssueCommentScreen( (context, parameters) => BbIssueCommentScreen(parameters['owner'].first,
p['owner'].first, p['name'].first, p['number'].first)); parameters['name'].first, parameters['number'].first));
} }
class GiteeRouter { class GiteeRouter {
@ -421,13 +467,14 @@ class GiteeRouter {
GiteeRouter.pullComment, GiteeRouter.pullComment,
GiteeRouter.files, GiteeRouter.files,
GiteeRouter.commit, GiteeRouter.commit,
GiteeRouter.contributors,
]; ];
static final search = RouterScreen('/search', (context, parameters) { static final search = RouterScreen('/search', (context, parameters) {
return GeSearchScreen(); return GeSearchScreen();
}); });
static final user = RouterScreen('/:login', (context, p) { static final user = RouterScreen('/:login', (context, parameters) {
final login = p['login'].first; final login = parameters['login'].first;
final tab = p['tab']?.first; final tab = parameters['tab']?.first;
switch (tab) { switch (tab) {
case 'followers': case 'followers':
return GeUsersScreen.followers(login); return GeUsersScreen.followers(login);
@ -444,21 +491,37 @@ class GiteeRouter {
}); });
static final repo = RouterScreen( static final repo = RouterScreen(
'/:owner/:name', '/:owner/:name',
(context, params) => (context, parameters) {
GeRepoScreen(params['owner'].first, params['name'].first), 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) { static final stargazers =
return GeUsersScreen.stargazers(p['owner'].first, p['name'].first); RouterScreen('/:owner/:name/stargazers', (context, parameters) {
return GeUsersScreen.stargazers(
parameters['owner'].first, parameters['name'].first);
}); });
static final watchers = RouterScreen('/:owner/:name/watchers', (_, p) { static final watchers =
return GeUsersScreen.watchers(p['owner'].first, p['name'].first); RouterScreen('/:owner/:name/watchers', (context, parameters) {
return GeUsersScreen.watchers(
parameters['owner'].first, parameters['name'].first);
}); });
static final forks = RouterScreen('/:owner/:name/forks', (_, p) { static final forks =
return GeReposScreen.forks(p['owner'].first, p['name'].first); RouterScreen('/:owner/:name/forks', (context, parameters) {
return GeReposScreen.forks(
parameters['owner'].first, parameters['name'].first);
}); });
static final commits = RouterScreen( static final commits = RouterScreen(
'/:owner/:name/commits', '/: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( static final tree = RouterScreen(
'/:owner/:name/tree/:sha', '/:owner/:name/tree/:sha',
@ -543,4 +606,9 @@ class GiteeRouter {
(context, parameters) => GeCommitScreen(parameters['owner'].first, (context, parameters) => GeCommitScreen(parameters['owner'].first,
parameters['name'].first, parameters['sha'].first), parameters['name'].first, parameters['sha'].first),
); );
static final contributors = RouterScreen(
'/:owner/:name/contributors',
(context, parameters) => GeContributorsScreen(
parameters['owner'].first, parameters['name'].first),
);
} }

View File

@ -10,17 +10,17 @@ import '../generated/l10n.dart';
class GeCommitsScreen extends StatelessWidget { class GeCommitsScreen extends StatelessWidget {
final String owner; final String owner;
final String name; final String name;
// final String branch; // TODO: final String branch;
GeCommitsScreen(this.owner, this.name); GeCommitsScreen(this.owner, this.name, {this.branch});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ListStatefulScaffold<GiteeCommit, int>( return ListStatefulScaffold<GiteeCommit, int>(
title: AppBarTitle(S.of(context).commits), title: AppBarTitle(S.of(context).commits),
fetch: (page) async { fetch: (page) async {
final res = await context final res = await context.read<AuthModel>().fetchGiteeWithPage(
.read<AuthModel>() '/repos/$owner/$name/commits?sha=$branch',
.fetchGiteeWithPage('/repos/$owner/$name/commits', page: page); page: page);
return ListPayload( return ListPayload(
cursor: res.cursor, cursor: res.cursor,
hasMore: res.hasMore, hasMore: res.hasMore,

View File

@ -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<GiteeContributor, int>(
title: AppBarTitle(S.of(context).contributors),
fetch: (page) async {
page = page ?? 1;
final res = await context
.read<AuthModel>()
.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<ThemeModel>();
return Container(
padding: CommonStyle.padding,
child: Row(
children: <Widget>[
SizedBox(width: 10),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
children: <Widget>[
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()),
),
],
),
)
],
),
);
},
);
}
}

View File

@ -6,6 +6,7 @@ import 'package:git_touch/utils/utils.dart';
import 'package:git_touch/widgets/action_entry.dart'; import 'package:git_touch/widgets/action_entry.dart';
import 'package:git_touch/widgets/app_bar_title.dart'; import 'package:git_touch/widgets/app_bar_title.dart';
import 'package:git_touch/widgets/issue_item.dart'; import 'package:git_touch/widgets/issue_item.dart';
import 'package:git_touch/widgets/label.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class GeIssuesScreen extends StatelessWidget { class GeIssuesScreen extends StatelessWidget {
@ -40,6 +41,12 @@ class GeIssuesScreen extends StatelessWidget {
title: p.title, title: p.title,
updatedAt: DateTime.parse(p.updatedAt), updatedAt: DateTime.parse(p.updatedAt),
url: '/gitee/$owner/$name/issues/${p.number}', 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)
]),
), ),
); );
} }

View File

@ -4,6 +4,7 @@ import 'package:git_touch/models/gitee.dart';
import 'package:git_touch/scaffolds/list_stateful.dart'; import 'package:git_touch/scaffolds/list_stateful.dart';
import 'package:git_touch/widgets/app_bar_title.dart'; import 'package:git_touch/widgets/app_bar_title.dart';
import 'package:git_touch/widgets/issue_item.dart'; import 'package:git_touch/widgets/issue_item.dart';
import 'package:git_touch/widgets/label.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class GePullsScreen extends StatelessWidget { class GePullsScreen extends StatelessWidget {
@ -34,6 +35,12 @@ class GePullsScreen extends StatelessWidget {
title: p.title, title: p.title,
updatedAt: DateTime.parse(p.updatedAt), updatedAt: DateTime.parse(p.updatedAt),
url: '/gitee/$owner/$name/pulls/${p.number}', 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)
]),
), ),
); );
} }

View File

@ -1,8 +1,8 @@
import 'dart:convert'; import 'dart:convert';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:git_touch/models/auth.dart'; import 'package:git_touch/models/auth.dart';
import 'package:git_touch/models/gitee.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/scaffolds/refresh_stateful.dart';
import 'package:git_touch/utils/utils.dart'; import 'package:git_touch/utils/utils.dart';
import 'package:git_touch/widgets/app_bar_title.dart'; import 'package:git_touch/widgets/app_bar_title.dart';
@ -18,11 +18,13 @@ import '../generated/l10n.dart';
class GeRepoScreen extends StatelessWidget { class GeRepoScreen extends StatelessWidget {
final String owner; final String owner;
final String name; final String name;
GeRepoScreen(this.owner, this.name); final String branch;
GeRepoScreen(this.owner, this.name, {this.branch});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return RefreshStatefulScaffold<Tuple2<GiteeRepo, MarkdownViewData>>( return RefreshStatefulScaffold<
Tuple3<GiteeRepo, MarkdownViewData, List<GiteeBranch>>>(
title: AppBarTitle(S.of(context).repository), title: AppBarTitle(S.of(context).repository),
fetch: () async { fetch: () async {
final auth = context.read<AuthModel>(); final auth = context.read<AuthModel>();
@ -43,11 +45,16 @@ class GeRepoScreen extends StatelessWidget {
return utf8.decode(res.bodyBytes).normalizedHtml; return utf8.decode(res.bodyBytes).normalizedHtml;
}); });
final readmeData = MarkdownViewData(context, md: md, html: html); final readmeData = MarkdownViewData(context, md: md, html: html);
final branches =
return Tuple2(repo, readmeData); 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) { bodyBuilder: (t, setState) {
final p = t.item1; final p = t.item1;
final branches = t.item3;
final theme = context.read<ThemeModel>();
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[ children: <Widget>[
@ -86,7 +93,8 @@ class GeRepoScreen extends StatelessWidget {
leftIconData: Octicons.code, leftIconData: Octicons.code,
text: Text('Code'), text: Text('Code'),
rightWidget: Text(p.license ?? ''), rightWidget: Text(p.license ?? ''),
url: '/gitee/$owner/$name/tree/${p.defaultBranch}', url:
'/gitee/$owner/$name/tree/${branch == null ? p.defaultBranch : branch}',
), ),
TableViewItem( TableViewItem(
leftIconData: Octicons.issue_opened, leftIconData: Octicons.issue_opened,
@ -103,8 +111,42 @@ class GeRepoScreen extends StatelessWidget {
TableViewItem( TableViewItem(
leftIconData: Octicons.history, leftIconData: Octicons.history,
text: Text('Commits'), 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, CommonStyle.verticalGap,

View File

@ -131,7 +131,7 @@ class _GeSearchScreenState extends State<GeSearchScreen> {
login: p.login, login: p.login,
name: p.name, name: p.name,
avatarUrl: p.avatarUrl, avatarUrl: p.avatarUrl,
bio: Text(p.htmlUrl), bio: Text(p.bio != null ? p.bio : p.htmlUrl),
); );
default: default:
return IssueItem( return IssueItem(