1
0
mirror of https://github.com/git-touch/git-touch synced 2025-02-23 06:47:46 +01:00

feat(bitbucket): update (#147)

* feat: create issue

* feat: issue screen, comment on issue

* fix: remove refs from pullScreen uri
This commit is contained in:
Shreyas Thirumalai 2021-01-06 18:47:49 +05:30 committed by GitHub
parent 8415a677c0
commit 76f9999534
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 362 additions and 17 deletions

View File

@ -356,7 +356,11 @@ class AuthModel with ChangeNotifier {
}
}
Future<http.Response> fetchBb(String p) async {
Future<http.Response> fetchBb(
String p, {
isPost = false,
Map<String, dynamic> body = const {},
}) async {
if (p.startsWith('/') && !p.startsWith('/api')) p = '/api/2.0$p';
final input = Uri.parse(p);
final uri = Uri.parse(activeAccount.domain).replace(
@ -364,11 +368,26 @@ class AuthModel with ChangeNotifier {
path: input.path,
query: input.query,
);
if (isPost) {
return http.post(
uri,
headers: {HttpHeaders.contentTypeHeader: 'application/json'},
body: jsonEncode(body),
);
}
return http.get(uri);
}
Future fetchBbJson(String p) async {
final res = await fetchBb(p);
Future fetchBbJson(
String p, {
isPost = false,
Map<String, dynamic> body = const {},
}) async {
final res = await fetchBb(
p,
isPost: isPost,
body: body,
);
return json.decode(utf8.decode(res.bodyBytes));
}

View File

@ -123,3 +123,24 @@ class BbPulls {
factory BbPulls.fromJson(Map<String, dynamic> json) =>
_$BbPullsFromJson(json);
}
@JsonSerializable(fieldRename: FieldRename.snake)
class BbCommentContent {
String raw;
String markup;
String html;
BbCommentContent();
factory BbCommentContent.fromJson(Map<String, dynamic> json) =>
_$BbCommentContentFromJson(json);
}
@JsonSerializable(fieldRename: FieldRename.snake)
class BbComment {
String createdOn;
String updatedOn;
BbCommentContent content;
BbRepoOwner user;
BbComment();
factory BbComment.fromJson(Map<String, dynamic> json) =>
_$BbCommentFromJson(json);
}

View File

@ -214,3 +214,36 @@ Map<String, dynamic> _$BbPullsToJson(BbPulls instance) => <String, dynamic>{
'links': instance.links,
'created_on': instance.createdOn?.toIso8601String(),
};
BbCommentContent _$BbCommentContentFromJson(Map<String, dynamic> json) {
return BbCommentContent()
..raw = json['raw'] as String
..markup = json['markup'] as String
..html = json['html'] as String;
}
Map<String, dynamic> _$BbCommentContentToJson(BbCommentContent instance) =>
<String, dynamic>{
'raw': instance.raw,
'markup': instance.markup,
'html': instance.html,
};
BbComment _$BbCommentFromJson(Map<String, dynamic> json) {
return BbComment()
..createdOn = json['created_on'] as String
..updatedOn = json['updated_on'] as String
..content = json['content'] == null
? null
: BbCommentContent.fromJson(json['content'] as Map<String, dynamic>)
..user = json['user'] == null
? null
: BbRepoOwner.fromJson(json['user'] as Map<String, dynamic>);
}
Map<String, dynamic> _$BbCommentToJson(BbComment instance) => <String, dynamic>{
'created_on': instance.createdOn,
'updated_on': instance.updatedOn,
'content': instance.content,
'user': instance.user,
};

View File

@ -1,5 +1,8 @@
import 'package:fluro/fluro.dart';
import 'package:git_touch/screens/bb_commits.dart';
import 'package:git_touch/screens/bb_issue.dart';
import 'package:git_touch/screens/bb_issue_comment.dart';
import 'package:git_touch/screens/bb_issue_form.dart';
import 'package:git_touch/screens/bb_object.dart';
import 'package:git_touch/screens/bb_repo.dart';
import 'package:git_touch/screens/bb_issues.dart';
@ -350,6 +353,9 @@ class BitbucketRouter {
BitbucketRouter.repo,
BitbucketRouter.object,
BitbucketRouter.commits,
BitbucketRouter.issueAdd,
BitbucketRouter.issueComment,
BitbucketRouter.issue,
BitbucketRouter.issues,
BitbucketRouter.pulls,
];
@ -371,18 +377,24 @@ class BitbucketRouter {
path: params['path']?.first,
),
);
static final issues = RouterScreen(
'/:owner/:name/issues/:ref',
(_, p) =>
BbIssuesScreen(p['owner'].first, p['name'].first, p['ref'].first));
static final issues = RouterScreen('/:owner/:name/issues',
(_, p) => BbIssuesScreen(p['owner'].first, p['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/:ref',
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));
static final issue = RouterScreen(
'/:owner/:name/issues/:number',
(_, p) =>
BbPullsScreen(p['owner'].first, p['name'].first, p['ref'].first));
BbIssueScreen(p['owner'].first, p['name'].first, p['number'].first));
static final issueComment = RouterScreen(
'/:owner/:name/issues/:number/comment',
(_, p) => BbIssueCommentScreen(
p['owner'].first, p['name'].first, p['number'].first));
}
class GiteeRouter {

113
lib/screens/bb_issue.dart Normal file
View File

@ -0,0 +1,113 @@
import 'package:flutter/material.dart';
import 'package:git_touch/models/bitbucket.dart';
import 'package:git_touch/scaffolds/refresh_stateful.dart';
import 'package:git_touch/utils/utils.dart';
import 'package:git_touch/widgets/action_entry.dart';
import 'package:git_touch/widgets/avatar.dart';
import 'package:git_touch/widgets/link.dart';
import 'package:git_touch/widgets/comment_item.dart';
import 'package:primer/primer.dart';
import 'package:provider/provider.dart';
import 'package:git_touch/models/auth.dart';
import 'package:git_touch/models/theme.dart';
import 'package:tuple/tuple.dart';
class BbIssueScreen extends StatelessWidget {
final String owner;
final String name;
final String number;
final bool isPr;
BbIssueScreen(this.owner, this.name, this.number, {this.isPr: false});
@override
Widget build(BuildContext context) {
return RefreshStatefulScaffold<Tuple2<BbIssues, List<BbComment>>>(
title: Text("Issue: #$number"),
fetch: () async {
final auth = context.read<AuthModel>();
final items = await Future.wait([
auth.fetchBbJson('/repositories/$owner/$name/issues/$number'),
auth.fetchBbWithPage(
'/repositories/$owner/$name/issues/$number/comments')
]);
return Tuple2(BbIssues.fromJson(items[0]),
[for (var v in items[1].data) BbComment.fromJson(v)]);
},
actionBuilder: (data, _) => ActionEntry(
iconData: Octicons.plus,
url: '/bitbucket/$owner/$name/issues/$number/comment',
),
bodyBuilder: (data, _) {
final issue = data.item1;
final comments = data.item2;
final theme = context.read<ThemeModel>();
return Column(children: <Widget>[
Container(
padding: CommonStyle.padding,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Link(
url: '/bitbucket/$owner/$name',
child: Row(
children: <Widget>[
Avatar(
url: issue.reporter.avatarUrl,
size: AvatarSize.extraSmall,
),
SizedBox(width: 4),
Text(
'$owner / $name',
style: TextStyle(
fontSize: 17,
color: theme.palette.secondaryText,
),
),
SizedBox(width: 4),
Text(
'#$number',
style: TextStyle(
fontSize: 17,
color: theme.palette.tertiaryText,
),
),
],
),
),
SizedBox(height: 8),
Text(
issue.title,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
),
),
SizedBox(height: 8),
StateLabel(StateLabelStatus.issueOpened),
SizedBox(height: 16),
CommonStyle.border,
],
)),
Column(children: [
for (var comment in comments) ...[
Padding(
padding: EdgeInsets.only(left: 10),
child: CommentItem(
avatar: Avatar(
url: comment.user.avatarUrl,
linkUrl: '/bitbucket/${comment.user.displayName}',
),
createdAt: DateTime.parse(comment.createdOn),
body: comment.content.raw,
login: comment.user.displayName,
prefix: 'bitbucket')),
CommonStyle.border,
SizedBox(height: 16),
],
]),
]);
},
);
}
}

View File

@ -0,0 +1,65 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:git_touch/models/auth.dart';
import 'package:git_touch/models/theme.dart';
import 'package:git_touch/scaffolds/common.dart';
import 'package:git_touch/utils/utils.dart';
import 'package:provider/provider.dart';
class BbIssueCommentScreen extends StatefulWidget {
final String owner;
final String name;
final String number;
BbIssueCommentScreen(this.owner, this.name, this.number);
@override
_BbIssueCommentScreenState createState() => _BbIssueCommentScreenState();
}
class _BbIssueCommentScreenState extends State<BbIssueCommentScreen> {
var _body = '';
@override
Widget build(BuildContext context) {
final theme = Provider.of<ThemeModel>(context);
final auth = Provider.of<AuthModel>(context);
return CommonScaffold(
title: Text('New Comment'),
body: Column(
children: <Widget>[
Padding(
padding: CommonStyle.padding,
child: CupertinoTextField(
style: TextStyle(color: theme.palette.text),
placeholder: 'Body',
onChanged: (v) {
setState(() {
_body = v;
});
},
maxLines: 10,
),
),
CupertinoButton.filled(
child: Text('Comment'),
onPressed: () async {
final res = await auth.fetchBb(
'/repositories/${widget.owner}/${widget.name}/issues/${widget.number}/comments',
isPost: true,
body: {
'content': {'raw': _body}
},
);
Navigator.pop(context, true);
await theme.push(
context,
'/bitbucket/${widget.owner}/${widget.name}/issues/${widget.number}',
replace: true,
);
},
),
],
),
);
}
}

View File

@ -0,0 +1,78 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:git_touch/models/auth.dart';
import 'package:git_touch/models/bitbucket.dart';
import 'package:git_touch/models/theme.dart';
import 'package:git_touch/scaffolds/common.dart';
import 'package:git_touch/utils/utils.dart';
import 'package:provider/provider.dart';
class BbIssueFormScreen extends StatefulWidget {
final String owner;
final String name;
BbIssueFormScreen(this.owner, this.name);
@override
_BbIssueFormScreenState createState() => _BbIssueFormScreenState();
}
class _BbIssueFormScreenState extends State<BbIssueFormScreen> {
var _title = '';
var _body = '';
@override
Widget build(BuildContext context) {
final theme = Provider.of<ThemeModel>(context);
final auth = Provider.of<AuthModel>(context);
return CommonScaffold(
title: Text('Submit an issue'),
body: Column(
children: <Widget>[
Padding(
padding: CommonStyle.padding,
child: CupertinoTextField(
style: TextStyle(color: theme.palette.text),
placeholder: 'Title',
onChanged: (v) {
setState(() {
_title = v;
});
},
),
),
Padding(
padding: CommonStyle.padding,
child: CupertinoTextField(
style: TextStyle(color: theme.palette.text),
placeholder: 'Body',
onChanged: (v) {
setState(() {
_body = v;
});
},
maxLines: 10,
),
),
CupertinoButton.filled(
child: Text('Submit'),
onPressed: () async {
final res = await auth.fetchBbJson(
'/repositories/${widget.owner}/${widget.name}/issues',
isPost: true,
body: {'body': _body, 'title': _title},
).then((v) {
return BbIssues.fromJson(v);
});
Navigator.pop(context, true);
await theme.push(
context,
'/bitbucket/${widget.owner}/${widget.name}/issues',
replace: true,
);
},
),
],
),
);
}
}

View File

@ -2,6 +2,8 @@ import 'package:flutter/material.dart';
import 'package:git_touch/models/auth.dart';
import 'package:git_touch/models/bitbucket.dart';
import 'package:git_touch/scaffolds/list_stateful.dart';
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:provider/provider.dart';
@ -10,14 +12,17 @@ import '../generated/l10n.dart';
class BbIssuesScreen extends StatelessWidget {
final String owner;
final String name;
final String ref;
BbIssuesScreen(this.owner, this.name, this.ref);
BbIssuesScreen(this.owner, this.name);
@override
Widget build(BuildContext context) {
final auth = Provider.of<AuthModel>(context);
return ListStatefulScaffold<BbIssues, String>(
title: AppBarTitle(S.of(context).issues),
actionBuilder: () {
return ActionEntry(
iconData: Octicons.plus, url: '/bitbucket/$owner/$name/issues/new');
},
fetch: (nextUrl) async {
final res = await context
.read<AuthModel>()
@ -40,7 +45,7 @@ class BbIssuesScreen extends StatelessWidget {
subtitle: '#' + issueNumber.toString(),
commentCount: 0,
updatedAt: v.createdOn,
url: '${auth.activeAccount.domain}/$owner/$name/issues/$issueNumber',
url: '/bitbucket/$owner/$name/issues/$issueNumber',
);
},
);

View File

@ -10,8 +10,7 @@ import '../generated/l10n.dart';
class BbPullsScreen extends StatelessWidget {
final String owner;
final String name;
final String ref;
BbPullsScreen(this.owner, this.name, this.ref);
BbPullsScreen(this.owner, this.name);
@override
Widget build(BuildContext context) {

View File

@ -61,12 +61,12 @@ class BbRepoScreen extends StatelessWidget {
TableViewItem(
leftIconData: Octicons.issue_opened,
text: Text('Issues'),
url: '/bitbucket/$owner/$name/issues/${p.mainbranch.name}',
url: '/bitbucket/$owner/$name/issues',
),
TableViewItem(
leftIconData: Octicons.git_pull_request,
text: Text('Pull requests'),
url: '/bitbucket/$owner/$name/pulls/${p.mainbranch.name}',
url: '/bitbucket/$owner/$name/pulls',
),
TableViewItem(
leftIconData: Octicons.history,