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:
parent
8415a677c0
commit
76f9999534
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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
113
lib/screens/bb_issue.dart
Normal 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),
|
||||
],
|
||||
]),
|
||||
]);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
65
lib/screens/bb_issue_comment.dart
Normal file
65
lib/screens/bb_issue_comment.dart
Normal 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,
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
78
lib/screens/bb_issue_form.dart
Normal file
78
lib/screens/bb_issue_form.dart
Normal 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,
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -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',
|
||||
);
|
||||
},
|
||||
);
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user