diff --git a/lib/models/auth.dart b/lib/models/auth.dart index 0b0ce32..854e529 100644 --- a/lib/models/auth.dart +++ b/lib/models/auth.dart @@ -214,8 +214,8 @@ class AuthModel with ChangeNotifier { final info = json.decode(utf8.decode(res.bodyBytes)); return DataWithPage( data: info, - cursor: int.tryParse(res.headers["x-page"]) + 1, - hasMore: res.headers['x-hasmore'] != null, + cursor: int.tryParse(res.headers["x-page"] ?? ''), + hasMore: res.headers['x-hasmore'] == 'true', total: int.tryParse(res.headers['x-total'] ?? ''), ); } diff --git a/lib/models/gitea.dart b/lib/models/gitea.dart index e937c5d..92a3aad 100644 --- a/lib/models/gitea.dart +++ b/lib/models/gitea.dart @@ -85,3 +85,17 @@ class GiteaCommitAuthor { factory GiteaCommitAuthor.fromJson(Map json) => _$GiteaCommitAuthorFromJson(json); } + +@JsonSerializable(fieldRename: FieldRename.snake) +class GiteaIssue { + String title; + String body; + int number; + GiteaUser user; + int comments; + DateTime updatedAt; + String htmlUrl; + GiteaIssue(); + factory GiteaIssue.fromJson(Map json) => + _$GiteaIssueFromJson(json); +} diff --git a/lib/models/gitea.g.dart b/lib/models/gitea.g.dart index abbdc33..01777a0 100644 --- a/lib/models/gitea.g.dart +++ b/lib/models/gitea.g.dart @@ -153,3 +153,29 @@ Map _$GiteaCommitAuthorToJson(GiteaCommitAuthor instance) => 'email': instance.email, 'date': instance.date?.toIso8601String(), }; + +GiteaIssue _$GiteaIssueFromJson(Map json) { + return GiteaIssue() + ..title = json['title'] as String + ..body = json['body'] as String + ..number = json['number'] as int + ..user = json['user'] == null + ? null + : GiteaUser.fromJson(json['user'] as Map) + ..comments = json['comments'] as int + ..updatedAt = json['updated_at'] == null + ? null + : DateTime.parse(json['updated_at'] as String) + ..htmlUrl = json['html_url'] as String; +} + +Map _$GiteaIssueToJson(GiteaIssue instance) => + { + 'title': instance.title, + 'body': instance.body, + 'number': instance.number, + 'user': instance.user, + 'comments': instance.comments, + 'updated_at': instance.updatedAt?.toIso8601String(), + 'html_url': instance.htmlUrl, + }; diff --git a/lib/router.dart b/lib/router.dart index 49fa03a..9174f21 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -2,6 +2,7 @@ import 'package:fluro/fluro.dart'; import 'package:git_touch/screens/code_theme.dart'; import 'package:git_touch/screens/commits.dart'; import 'package:git_touch/screens/gitea_commits.dart'; +import 'package:git_touch/screens/gitea_issues.dart'; import 'package:git_touch/screens/gitea_object.dart'; import 'package:git_touch/screens/gitea_repo.dart'; import 'package:git_touch/screens/gitea_user.dart'; @@ -197,6 +198,8 @@ class GiteaRouter { GiteaRouter.repo, GiteaRouter.object, GiteaRouter.commits, + GiteaRouter.issues, + GiteaRouter.pulls, ]; static final user = RouterScreen( '/:login', @@ -217,4 +220,10 @@ class GiteaRouter { ); static final commits = RouterScreen('/:owner/:name/commits', (_, p) => GiteaCommitsScreen(p['owner'].first, p['name'].first)); + static final issues = RouterScreen('/:owner/:name/issues', + (_, p) => GiteaIssuesScreen(p['owner'].first, p['name'].first)); + static final pulls = RouterScreen( + '/:owner/:name/pulls', + (_, p) => + GiteaIssuesScreen(p['owner'].first, p['name'].first, isPr: true)); } diff --git a/lib/screens/gitea_issues.dart b/lib/screens/gitea_issues.dart new file mode 100644 index 0000000..fc870c4 --- /dev/null +++ b/lib/screens/gitea_issues.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; +import 'package:git_touch/models/auth.dart'; +import 'package:git_touch/models/gitea.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:provider/provider.dart'; + +class GiteaIssuesScreen extends StatelessWidget { + final String owner; + final String name; + final bool isPr; + GiteaIssuesScreen(this.owner, this.name, {this.isPr = false}); + + Future> _query(BuildContext context, + [int page = 1]) async { + final auth = Provider.of(context); + final type = isPr ? 'pulls' : 'issues'; + final res = await auth.fetchGiteaWithPage( + '/repos/$owner/$name/issues?state=open&page=$page&limit=20&type=$type'); + return ListPayload( + cursor: res.cursor, + hasMore: res.hasMore, + items: (res.data as List).map((v) => GiteaIssue.fromJson(v)).toList(), + ); + } + + @override + Widget build(BuildContext context) { + return ListStatefulScaffold( + title: AppBarTitle(isPr ? 'Pull Requests' : 'Issues'), + // TODO: create issue + onRefresh: () => _query(context), + onLoadMore: (cursor) => _query(context, cursor), + itemBuilder: (p) => IssueItem( + author: p.user.login, + avatarUrl: p.user.avatarUrl, + commentCount: p.comments, + number: p.number, + title: p.title, + updatedAt: p.updatedAt, + url: p.htmlUrl, + ), + ); + } +}