diff --git a/lib/models/gitee.dart b/lib/models/gitee.dart index a016df87..51db8c9b 100644 --- a/lib/models/gitee.dart +++ b/lib/models/gitee.dart @@ -34,6 +34,7 @@ class GiteeListUser { @JsonSerializable(fieldRename: FieldRename.snake) class GiteeRepo { + GiteeRepoNamespace namespace; GiteeRepoOwner owner; String path; String description; @@ -45,6 +46,10 @@ class GiteeRepo { int stargazersCount; int watchersCount; DateTime updatedAt; + String license; + String homepage; + int openIssuesCount; + bool pullRequestsEnabled; GiteeRepo(); factory GiteeRepo.fromJson(Map json) => _$GiteeRepoFromJson(json); @@ -58,3 +63,11 @@ class GiteeRepoOwner { factory GiteeRepoOwner.fromJson(Map json) => _$GiteeRepoOwnerFromJson(json); } + +@JsonSerializable(fieldRename: FieldRename.snake) +class GiteeRepoNamespace { + String path; + GiteeRepoNamespace(); + factory GiteeRepoNamespace.fromJson(Map json) => + _$GiteeRepoNamespaceFromJson(json); +} diff --git a/lib/models/gitee.g.dart b/lib/models/gitee.g.dart index 5559ba4a..aec40c9a 100644 --- a/lib/models/gitee.g.dart +++ b/lib/models/gitee.g.dart @@ -57,6 +57,9 @@ Map _$GiteeListUserToJson(GiteeListUser instance) => GiteeRepo _$GiteeRepoFromJson(Map json) { return GiteeRepo() + ..namespace = json['namespace'] == null + ? null + : GiteeRepoNamespace.fromJson(json['namespace'] as Map) ..owner = json['owner'] == null ? null : GiteeRepoOwner.fromJson(json['owner'] as Map) @@ -71,10 +74,15 @@ GiteeRepo _$GiteeRepoFromJson(Map json) { ..watchersCount = json['watchers_count'] as int ..updatedAt = json['updated_at'] == null ? null - : DateTime.parse(json['updated_at'] as String); + : DateTime.parse(json['updated_at'] as String) + ..license = json['license'] as String + ..homepage = json['homepage'] as String + ..openIssuesCount = json['open_issues_count'] as int + ..pullRequestsEnabled = json['pull_requests_enabled'] as bool; } Map _$GiteeRepoToJson(GiteeRepo instance) => { + 'namespace': instance.namespace, 'owner': instance.owner, 'path': instance.path, 'description': instance.description, @@ -86,6 +94,10 @@ Map _$GiteeRepoToJson(GiteeRepo instance) => { 'stargazers_count': instance.stargazersCount, 'watchers_count': instance.watchersCount, 'updated_at': instance.updatedAt?.toIso8601String(), + 'license': instance.license, + 'homepage': instance.homepage, + 'open_issues_count': instance.openIssuesCount, + 'pull_requests_enabled': instance.pullRequestsEnabled, }; GiteeRepoOwner _$GiteeRepoOwnerFromJson(Map json) { @@ -99,3 +111,12 @@ Map _$GiteeRepoOwnerToJson(GiteeRepoOwner instance) => 'login': instance.login, 'avatar_url': instance.avatarUrl, }; + +GiteeRepoNamespace _$GiteeRepoNamespaceFromJson(Map json) { + return GiteeRepoNamespace()..path = json['path'] as String; +} + +Map _$GiteeRepoNamespaceToJson(GiteeRepoNamespace instance) => + { + 'path': instance.path, + }; diff --git a/lib/router.dart b/lib/router.dart index 62582611..48e2705b 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -6,6 +6,7 @@ import 'package:git_touch/screens/bb_issues.dart'; import 'package:git_touch/screens/bb_pulls.dart'; import 'package:git_touch/screens/bb_user.dart'; import 'package:git_touch/screens/code_theme.dart'; +import 'package:git_touch/screens/ge_repo.dart'; import 'package:git_touch/screens/ge_repos.dart'; import 'package:git_touch/screens/ge_user.dart'; import 'package:git_touch/screens/ge_users.dart'; @@ -379,6 +380,10 @@ class GiteeRouter { static const prefix = '/gitee'; static final routes = [ GiteeRouter.user, + GiteeRouter.repo, + GiteeRouter.stargazers, + GiteeRouter.watchers, + GiteeRouter.forks, ]; static final user = RouterScreen('/:login', (context, p) { final login = p['login'].first; @@ -397,4 +402,18 @@ class GiteeRouter { return GeUserScreen(login); } }); + static final repo = RouterScreen( + '/:owner/:name', + (context, params) => + GeRepoScreen(params['owner'].first, params['name'].first), + ); + static final stargazers = RouterScreen('/:owner/:name/stargazers', (_, p) { + return GeUsersScreen.stargazers(p['owner'].first, p['name'].first); + }); + static final watchers = RouterScreen('/:owner/:name/watchers', (_, p) { + return GeUsersScreen.watchers(p['owner'].first, p['name'].first); + }); + static final forks = RouterScreen('/:owner/:name/forks', (_, p) { + return GeReposScreen.forks(p['owner'].first, p['name'].first); + }); } diff --git a/lib/screens/ge_repo.dart b/lib/screens/ge_repo.dart new file mode 100644 index 00000000..aa36e986 --- /dev/null +++ b/lib/screens/ge_repo.dart @@ -0,0 +1,110 @@ +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'; +import 'package:git_touch/widgets/entry_item.dart'; +import 'package:git_touch/widgets/markdown_view.dart'; +import 'package:git_touch/widgets/repo_header.dart'; +import 'package:git_touch/widgets/table_view.dart'; +import 'package:provider/provider.dart'; +import 'package:tuple/tuple.dart'; + +class GeRepoScreen extends StatelessWidget { + final String owner; + final String name; + GeRepoScreen(this.owner, this.name); + + @override + Widget build(BuildContext context) { + return RefreshStatefulScaffold>( + title: AppBarTitle('Repository'), + fetch: () async { + final auth = context.read(); + final res = await Future.wait([ + auth.fetchGitee('/repos/$owner/$name'), + auth.fetchGitee('/repos/$owner/$name/readme'), + ]); + return Tuple2( + GiteeRepo.fromJson(res[0]), + (res[1]['content'] as String)?.base64ToUtf8, + ); + }, + bodyBuilder: (t, setState) { + final theme = Provider.of(context); + final p = t.item1; + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + RepoHeader( + avatarUrl: p.owner.avatarUrl, + avatarLink: '/gitee/${p.namespace.path}', + owner: p.namespace.path, + name: p.path, + description: p.description, + homepageUrl: p.homepage, + ), + CommonStyle.border, + Row( + children: [ + EntryItem( + text: 'Watchers', + url: '/gitee/$owner/$name/watchers', + ), + EntryItem( + count: p.stargazersCount, + text: 'Stars', + url: '/gitee/$owner/$name/stargazers', + ), + EntryItem( + count: p.forksCount, + text: 'Forks', + url: '/gitee/$owner/$name/forks', + ), + ], + ), + CommonStyle.border, + TableView( + hasIcon: true, + items: [ + TableViewItem( + leftIconData: Octicons.code, + text: Text('Code'), + rightWidget: Text(p.license ?? ''), + url: '/gitee/$owner/$name/blob', + ), + TableViewItem( + leftIconData: Octicons.issue_opened, + text: Text('Issues'), + rightWidget: Text(numberFormat.format(p.openIssuesCount)), + url: 'https://gitee.com/$owner/$name/issues', // TODO: + ), + if (p.pullRequestsEnabled) + TableViewItem( + leftIconData: Octicons.git_pull_request, + text: Text('Pull requests'), + url: 'https://gitee.com/$owner/$name/pulls', // TODO: + ), + TableViewItem( + leftIconData: Octicons.history, + text: Text('Commits'), + url: '/gitee/$owner/$name/commits', + ), + ], + ), + CommonStyle.verticalGap, + if (t.item2 != null) + Container( + padding: CommonStyle.padding, + color: theme.palette.background, + child: MarkdownView(t.item2), + ), + CommonStyle.verticalGap, + ], + ); + }, + ); + } +} diff --git a/lib/screens/ge_repos.dart b/lib/screens/ge_repos.dart index fc01eab1..21d2375f 100644 --- a/lib/screens/ge_repos.dart +++ b/lib/screens/ge_repos.dart @@ -17,6 +17,9 @@ class GeReposScreen extends StatelessWidget { GeReposScreen.star(String owner) : api = '/users/$owner/starred', title = 'Stars'; + GeReposScreen.forks(String owner, String name) + : api = '/repos/$owner/$name/forks', + title = 'Forks'; @override Widget build(BuildContext context) { diff --git a/lib/screens/ge_user.dart b/lib/screens/ge_user.dart index a5cf3d9c..0f57d812 100644 --- a/lib/screens/ge_user.dart +++ b/lib/screens/ge_user.dart @@ -92,7 +92,7 @@ class GeUserScreen extends StatelessWidget { // TableViewItem( // leftIconData: Octicons.home, // text: Text('Organizations'), - // url: '/gitea/$login?tab=organizations', + // url: '/gitee/$login?tab=organizations', // ), // ], // ), @@ -101,15 +101,15 @@ class GeUserScreen extends StatelessWidget { children: [ for (var v in repos) RepositoryItem( - owner: v.owner.login, + owner: v.namespace.path, avatarUrl: v.owner.avatarUrl, name: v.path, description: v.description, starCount: v.stargazersCount, forkCount: v.forksCount, note: 'Updated ${timeago.format(v.updatedAt)}', - url: '/gitea/${v.owner.login}/${v.path}', - avatarLink: '/gitea/${v.owner.login}', + url: '/gitee/${v.namespace.path}/${v.path}', + avatarLink: '/gitee/${v.namespace.path}', // iconData: , TODO: ) ],