feat: open and close issue

This commit is contained in:
Rongjian Zhang 2020-01-07 20:48:50 +08:00
parent 4551b6e9fd
commit 1b7bcdb7bb
5 changed files with 646 additions and 5 deletions

View File

@ -7959,3 +7959,398 @@ class GhRepoIdQuery extends GraphQLQuery<GhRepoId, GhRepoIdArguments> {
@override
GhRepoId parse(Map<String, dynamic> json) => GhRepoId.fromJson(json);
}
@JsonSerializable(explicitToJson: true)
class GhOpenIssue with EquatableMixin {
GhOpenIssue();
factory GhOpenIssue.fromJson(Map<String, dynamic> json) =>
_$GhOpenIssueFromJson(json);
GhOpenIssueReopenIssuePayload reopenIssue;
GhOpenIssueCloseIssuePayload closeIssue;
@override
List<Object> get props => [reopenIssue, closeIssue];
Map<String, dynamic> toJson() => _$GhOpenIssueToJson(this);
}
@JsonSerializable(explicitToJson: true)
class GhOpenIssueReopenIssuePayload with EquatableMixin {
GhOpenIssueReopenIssuePayload();
factory GhOpenIssueReopenIssuePayload.fromJson(Map<String, dynamic> json) =>
_$GhOpenIssueReopenIssuePayloadFromJson(json);
GhOpenIssueIssue issue;
@override
List<Object> get props => [issue];
Map<String, dynamic> toJson() => _$GhOpenIssueReopenIssuePayloadToJson(this);
}
@JsonSerializable(explicitToJson: true)
class GhOpenIssueIssue extends GhOpenIssueProjectCardItem
with EquatableMixin
implements
GhOpenIssueNode,
GhOpenIssueAssignable,
GhOpenIssueClosable,
GhOpenIssueComment,
GhOpenIssueUpdatable,
GhOpenIssueUpdatableComment,
GhOpenIssueLabelable,
GhOpenIssueLockable,
GhOpenIssueReactable,
GhOpenIssueRepositoryNode,
GhOpenIssueSubscribable,
GhOpenIssueUniformResourceLocatable {
GhOpenIssueIssue();
factory GhOpenIssueIssue.fromJson(Map<String, dynamic> json) =>
_$GhOpenIssueIssueFromJson(json);
@override
bool closed;
@override
@JsonKey(name: '__typename')
String resolveType;
@override
List<Object> get props => [closed, resolveType];
Map<String, dynamic> toJson() => _$GhOpenIssueIssueToJson(this);
}
@JsonSerializable(explicitToJson: true)
class GhOpenIssueProjectCardItem with EquatableMixin {
GhOpenIssueProjectCardItem();
factory GhOpenIssueProjectCardItem.fromJson(Map<String, dynamic> json) =>
_$GhOpenIssueProjectCardItemFromJson(json);
@override
List<Object> get props => [];
Map<String, dynamic> toJson() => _$GhOpenIssueProjectCardItemToJson(this);
}
@JsonSerializable(explicitToJson: true)
class GhOpenIssueNode with EquatableMixin {
GhOpenIssueNode();
factory GhOpenIssueNode.fromJson(Map<String, dynamic> json) =>
_$GhOpenIssueNodeFromJson(json);
@JsonKey(name: '__typename')
String resolveType;
@override
List<Object> get props => [resolveType];
Map<String, dynamic> toJson() => _$GhOpenIssueNodeToJson(this);
}
@JsonSerializable(explicitToJson: true)
class GhOpenIssueAssignable with EquatableMixin {
GhOpenIssueAssignable();
factory GhOpenIssueAssignable.fromJson(Map<String, dynamic> json) =>
_$GhOpenIssueAssignableFromJson(json);
@JsonKey(name: '__typename')
String resolveType;
@override
List<Object> get props => [resolveType];
Map<String, dynamic> toJson() => _$GhOpenIssueAssignableToJson(this);
}
@JsonSerializable(explicitToJson: true)
class GhOpenIssueClosable with EquatableMixin {
GhOpenIssueClosable();
factory GhOpenIssueClosable.fromJson(Map<String, dynamic> json) =>
_$GhOpenIssueClosableFromJson(json);
bool closed;
@JsonKey(name: '__typename')
String resolveType;
@override
List<Object> get props => [closed, resolveType];
Map<String, dynamic> toJson() => _$GhOpenIssueClosableToJson(this);
}
@JsonSerializable(explicitToJson: true)
class GhOpenIssueComment with EquatableMixin {
GhOpenIssueComment();
factory GhOpenIssueComment.fromJson(Map<String, dynamic> json) =>
_$GhOpenIssueCommentFromJson(json);
@JsonKey(name: '__typename')
String resolveType;
@override
List<Object> get props => [resolveType];
Map<String, dynamic> toJson() => _$GhOpenIssueCommentToJson(this);
}
@JsonSerializable(explicitToJson: true)
class GhOpenIssueUpdatable with EquatableMixin {
GhOpenIssueUpdatable();
factory GhOpenIssueUpdatable.fromJson(Map<String, dynamic> json) =>
_$GhOpenIssueUpdatableFromJson(json);
@JsonKey(name: '__typename')
String resolveType;
@override
List<Object> get props => [resolveType];
Map<String, dynamic> toJson() => _$GhOpenIssueUpdatableToJson(this);
}
@JsonSerializable(explicitToJson: true)
class GhOpenIssueUpdatableComment with EquatableMixin {
GhOpenIssueUpdatableComment();
factory GhOpenIssueUpdatableComment.fromJson(Map<String, dynamic> json) =>
_$GhOpenIssueUpdatableCommentFromJson(json);
@JsonKey(name: '__typename')
String resolveType;
@override
List<Object> get props => [resolveType];
Map<String, dynamic> toJson() => _$GhOpenIssueUpdatableCommentToJson(this);
}
@JsonSerializable(explicitToJson: true)
class GhOpenIssueLabelable with EquatableMixin {
GhOpenIssueLabelable();
factory GhOpenIssueLabelable.fromJson(Map<String, dynamic> json) =>
_$GhOpenIssueLabelableFromJson(json);
@JsonKey(name: '__typename')
String resolveType;
@override
List<Object> get props => [resolveType];
Map<String, dynamic> toJson() => _$GhOpenIssueLabelableToJson(this);
}
@JsonSerializable(explicitToJson: true)
class GhOpenIssueLockable with EquatableMixin {
GhOpenIssueLockable();
factory GhOpenIssueLockable.fromJson(Map<String, dynamic> json) =>
_$GhOpenIssueLockableFromJson(json);
@JsonKey(name: '__typename')
String resolveType;
@override
List<Object> get props => [resolveType];
Map<String, dynamic> toJson() => _$GhOpenIssueLockableToJson(this);
}
@JsonSerializable(explicitToJson: true)
class GhOpenIssueReactable with EquatableMixin {
GhOpenIssueReactable();
factory GhOpenIssueReactable.fromJson(Map<String, dynamic> json) =>
_$GhOpenIssueReactableFromJson(json);
@JsonKey(name: '__typename')
String resolveType;
@override
List<Object> get props => [resolveType];
Map<String, dynamic> toJson() => _$GhOpenIssueReactableToJson(this);
}
@JsonSerializable(explicitToJson: true)
class GhOpenIssueRepositoryNode with EquatableMixin {
GhOpenIssueRepositoryNode();
factory GhOpenIssueRepositoryNode.fromJson(Map<String, dynamic> json) =>
_$GhOpenIssueRepositoryNodeFromJson(json);
@JsonKey(name: '__typename')
String resolveType;
@override
List<Object> get props => [resolveType];
Map<String, dynamic> toJson() => _$GhOpenIssueRepositoryNodeToJson(this);
}
@JsonSerializable(explicitToJson: true)
class GhOpenIssueSubscribable with EquatableMixin {
GhOpenIssueSubscribable();
factory GhOpenIssueSubscribable.fromJson(Map<String, dynamic> json) =>
_$GhOpenIssueSubscribableFromJson(json);
@JsonKey(name: '__typename')
String resolveType;
@override
List<Object> get props => [resolveType];
Map<String, dynamic> toJson() => _$GhOpenIssueSubscribableToJson(this);
}
@JsonSerializable(explicitToJson: true)
class GhOpenIssueUniformResourceLocatable with EquatableMixin {
GhOpenIssueUniformResourceLocatable();
factory GhOpenIssueUniformResourceLocatable.fromJson(
Map<String, dynamic> json) =>
_$GhOpenIssueUniformResourceLocatableFromJson(json);
@JsonKey(name: '__typename')
String resolveType;
@override
List<Object> get props => [resolveType];
Map<String, dynamic> toJson() =>
_$GhOpenIssueUniformResourceLocatableToJson(this);
}
@JsonSerializable(explicitToJson: true)
class GhOpenIssueCloseIssuePayload with EquatableMixin {
GhOpenIssueCloseIssuePayload();
factory GhOpenIssueCloseIssuePayload.fromJson(Map<String, dynamic> json) =>
_$GhOpenIssueCloseIssuePayloadFromJson(json);
GhOpenIssueIssue issue;
@override
List<Object> get props => [issue];
Map<String, dynamic> toJson() => _$GhOpenIssueCloseIssuePayloadToJson(this);
}
@JsonSerializable(explicitToJson: true)
class GhOpenIssueArguments extends JsonSerializable with EquatableMixin {
GhOpenIssueArguments({this.id, this.open});
factory GhOpenIssueArguments.fromJson(Map<String, dynamic> json) =>
_$GhOpenIssueArgumentsFromJson(json);
final String id;
final bool open;
@override
List<Object> get props => [id, open];
Map<String, dynamic> toJson() => _$GhOpenIssueArgumentsToJson(this);
}
class GhOpenIssueQuery extends GraphQLQuery<GhOpenIssue, GhOpenIssueArguments> {
GhOpenIssueQuery({this.variables});
@override
final DocumentNode document = DocumentNode(definitions: [
OperationDefinitionNode(
type: OperationType.mutation,
name: NameNode(value: 'GhOpenIssue'),
variableDefinitions: [
VariableDefinitionNode(
variable: VariableNode(name: NameNode(value: 'id')),
type: NamedTypeNode(name: NameNode(value: 'ID'), isNonNull: true),
defaultValue: DefaultValueNode(value: null),
directives: []),
VariableDefinitionNode(
variable: VariableNode(name: NameNode(value: 'open')),
type: NamedTypeNode(
name: NameNode(value: 'Boolean'), isNonNull: true),
defaultValue: DefaultValueNode(value: null),
directives: [])
],
directives: [],
selectionSet: SelectionSetNode(selections: [
FieldNode(
name: NameNode(value: 'reopenIssue'),
alias: null,
arguments: [
ArgumentNode(
name: NameNode(value: 'input'),
value: ObjectValueNode(fields: [
ObjectFieldNode(
name: NameNode(value: 'issueId'),
value: VariableNode(name: NameNode(value: 'id')))
]))
],
directives: [
DirectiveNode(name: NameNode(value: 'include'), arguments: [
ArgumentNode(
name: NameNode(value: 'if'),
value: VariableNode(name: NameNode(value: 'open')))
])
],
selectionSet: SelectionSetNode(selections: [
FieldNode(
name: NameNode(value: 'issue'),
alias: null,
arguments: [],
directives: [],
selectionSet: SelectionSetNode(selections: [
FieldNode(
name: NameNode(value: 'closed'),
alias: null,
arguments: [],
directives: [],
selectionSet: null)
]))
])),
FieldNode(
name: NameNode(value: 'closeIssue'),
alias: null,
arguments: [
ArgumentNode(
name: NameNode(value: 'input'),
value: ObjectValueNode(fields: [
ObjectFieldNode(
name: NameNode(value: 'issueId'),
value: VariableNode(name: NameNode(value: 'id')))
]))
],
directives: [
DirectiveNode(name: NameNode(value: 'skip'), arguments: [
ArgumentNode(
name: NameNode(value: 'if'),
value: VariableNode(name: NameNode(value: 'open')))
])
],
selectionSet: SelectionSetNode(selections: [
FieldNode(
name: NameNode(value: 'issue'),
alias: null,
arguments: [],
directives: [],
selectionSet: SelectionSetNode(selections: [
FieldNode(
name: NameNode(value: 'closed'),
alias: null,
arguments: [],
directives: [],
selectionSet: null)
]))
]))
]))
]);
@override
final String operationName = 'GhOpenIssue';
@override
final GhOpenIssueArguments variables;
@override
List<Object> get props => [document, operationName, variables];
@override
GhOpenIssue parse(Map<String, dynamic> json) => GhOpenIssue.fromJson(json);
}

View File

@ -3317,3 +3317,213 @@ Map<String, dynamic> _$GhRepoIdArgumentsToJson(GhRepoIdArguments instance) =>
'owner': instance.owner,
'name': instance.name,
};
GhOpenIssue _$GhOpenIssueFromJson(Map<String, dynamic> json) {
return GhOpenIssue()
..reopenIssue = json['reopenIssue'] == null
? null
: GhOpenIssueReopenIssuePayload.fromJson(
json['reopenIssue'] as Map<String, dynamic>)
..closeIssue = json['closeIssue'] == null
? null
: GhOpenIssueCloseIssuePayload.fromJson(
json['closeIssue'] as Map<String, dynamic>);
}
Map<String, dynamic> _$GhOpenIssueToJson(GhOpenIssue instance) =>
<String, dynamic>{
'reopenIssue': instance.reopenIssue?.toJson(),
'closeIssue': instance.closeIssue?.toJson(),
};
GhOpenIssueReopenIssuePayload _$GhOpenIssueReopenIssuePayloadFromJson(
Map<String, dynamic> json) {
return GhOpenIssueReopenIssuePayload()
..issue = json['issue'] == null
? null
: GhOpenIssueIssue.fromJson(json['issue'] as Map<String, dynamic>);
}
Map<String, dynamic> _$GhOpenIssueReopenIssuePayloadToJson(
GhOpenIssueReopenIssuePayload instance) =>
<String, dynamic>{
'issue': instance.issue?.toJson(),
};
GhOpenIssueIssue _$GhOpenIssueIssueFromJson(Map<String, dynamic> json) {
return GhOpenIssueIssue()
..closed = json['closed'] as bool
..resolveType = json['__typename'] as String;
}
Map<String, dynamic> _$GhOpenIssueIssueToJson(GhOpenIssueIssue instance) =>
<String, dynamic>{
'closed': instance.closed,
'__typename': instance.resolveType,
};
GhOpenIssueProjectCardItem _$GhOpenIssueProjectCardItemFromJson(
Map<String, dynamic> json) {
return GhOpenIssueProjectCardItem();
}
Map<String, dynamic> _$GhOpenIssueProjectCardItemToJson(
GhOpenIssueProjectCardItem instance) =>
<String, dynamic>{};
GhOpenIssueNode _$GhOpenIssueNodeFromJson(Map<String, dynamic> json) {
return GhOpenIssueNode()..resolveType = json['__typename'] as String;
}
Map<String, dynamic> _$GhOpenIssueNodeToJson(GhOpenIssueNode instance) =>
<String, dynamic>{
'__typename': instance.resolveType,
};
GhOpenIssueAssignable _$GhOpenIssueAssignableFromJson(
Map<String, dynamic> json) {
return GhOpenIssueAssignable()..resolveType = json['__typename'] as String;
}
Map<String, dynamic> _$GhOpenIssueAssignableToJson(
GhOpenIssueAssignable instance) =>
<String, dynamic>{
'__typename': instance.resolveType,
};
GhOpenIssueClosable _$GhOpenIssueClosableFromJson(Map<String, dynamic> json) {
return GhOpenIssueClosable()
..closed = json['closed'] as bool
..resolveType = json['__typename'] as String;
}
Map<String, dynamic> _$GhOpenIssueClosableToJson(
GhOpenIssueClosable instance) =>
<String, dynamic>{
'closed': instance.closed,
'__typename': instance.resolveType,
};
GhOpenIssueComment _$GhOpenIssueCommentFromJson(Map<String, dynamic> json) {
return GhOpenIssueComment()..resolveType = json['__typename'] as String;
}
Map<String, dynamic> _$GhOpenIssueCommentToJson(GhOpenIssueComment instance) =>
<String, dynamic>{
'__typename': instance.resolveType,
};
GhOpenIssueUpdatable _$GhOpenIssueUpdatableFromJson(Map<String, dynamic> json) {
return GhOpenIssueUpdatable()..resolveType = json['__typename'] as String;
}
Map<String, dynamic> _$GhOpenIssueUpdatableToJson(
GhOpenIssueUpdatable instance) =>
<String, dynamic>{
'__typename': instance.resolveType,
};
GhOpenIssueUpdatableComment _$GhOpenIssueUpdatableCommentFromJson(
Map<String, dynamic> json) {
return GhOpenIssueUpdatableComment()
..resolveType = json['__typename'] as String;
}
Map<String, dynamic> _$GhOpenIssueUpdatableCommentToJson(
GhOpenIssueUpdatableComment instance) =>
<String, dynamic>{
'__typename': instance.resolveType,
};
GhOpenIssueLabelable _$GhOpenIssueLabelableFromJson(Map<String, dynamic> json) {
return GhOpenIssueLabelable()..resolveType = json['__typename'] as String;
}
Map<String, dynamic> _$GhOpenIssueLabelableToJson(
GhOpenIssueLabelable instance) =>
<String, dynamic>{
'__typename': instance.resolveType,
};
GhOpenIssueLockable _$GhOpenIssueLockableFromJson(Map<String, dynamic> json) {
return GhOpenIssueLockable()..resolveType = json['__typename'] as String;
}
Map<String, dynamic> _$GhOpenIssueLockableToJson(
GhOpenIssueLockable instance) =>
<String, dynamic>{
'__typename': instance.resolveType,
};
GhOpenIssueReactable _$GhOpenIssueReactableFromJson(Map<String, dynamic> json) {
return GhOpenIssueReactable()..resolveType = json['__typename'] as String;
}
Map<String, dynamic> _$GhOpenIssueReactableToJson(
GhOpenIssueReactable instance) =>
<String, dynamic>{
'__typename': instance.resolveType,
};
GhOpenIssueRepositoryNode _$GhOpenIssueRepositoryNodeFromJson(
Map<String, dynamic> json) {
return GhOpenIssueRepositoryNode()
..resolveType = json['__typename'] as String;
}
Map<String, dynamic> _$GhOpenIssueRepositoryNodeToJson(
GhOpenIssueRepositoryNode instance) =>
<String, dynamic>{
'__typename': instance.resolveType,
};
GhOpenIssueSubscribable _$GhOpenIssueSubscribableFromJson(
Map<String, dynamic> json) {
return GhOpenIssueSubscribable()..resolveType = json['__typename'] as String;
}
Map<String, dynamic> _$GhOpenIssueSubscribableToJson(
GhOpenIssueSubscribable instance) =>
<String, dynamic>{
'__typename': instance.resolveType,
};
GhOpenIssueUniformResourceLocatable
_$GhOpenIssueUniformResourceLocatableFromJson(Map<String, dynamic> json) {
return GhOpenIssueUniformResourceLocatable()
..resolveType = json['__typename'] as String;
}
Map<String, dynamic> _$GhOpenIssueUniformResourceLocatableToJson(
GhOpenIssueUniformResourceLocatable instance) =>
<String, dynamic>{
'__typename': instance.resolveType,
};
GhOpenIssueCloseIssuePayload _$GhOpenIssueCloseIssuePayloadFromJson(
Map<String, dynamic> json) {
return GhOpenIssueCloseIssuePayload()
..issue = json['issue'] == null
? null
: GhOpenIssueIssue.fromJson(json['issue'] as Map<String, dynamic>);
}
Map<String, dynamic> _$GhOpenIssueCloseIssuePayloadToJson(
GhOpenIssueCloseIssuePayload instance) =>
<String, dynamic>{
'issue': instance.issue?.toJson(),
};
GhOpenIssueArguments _$GhOpenIssueArgumentsFromJson(Map<String, dynamic> json) {
return GhOpenIssueArguments(
id: json['id'] as String,
open: json['open'] as bool,
);
}
Map<String, dynamic> _$GhOpenIssueArgumentsToJson(
GhOpenIssueArguments instance) =>
<String, dynamic>{
'id': instance.id,
'open': instance.open,
};

View File

@ -0,0 +1,12 @@
mutation GhOpenIssue($id: ID!, $open: Boolean!) {
reopenIssue(input: { issueId: $id }) @include(if: $open) {
issue {
closed
}
}
closeIssue(input: { issueId: $id }) @skip(if: $open) {
issue {
closed
}
}
}

View File

@ -30,7 +30,8 @@ class LongListPayload<T, K> {
// e.g. https://github.com/reactjs/rfcs/pull/68
class LongListStatefulScaffold<T, K> extends StatefulWidget {
final Widget title;
final Widget Function(T headerPayload) trailingBuilder;
final Widget Function(
T headerPayload, void Function(VoidCallback fn) setState) trailingBuilder;
final Widget Function(T headerPayload) headerBuilder;
final Widget Function(K itemPayload) itemBuilder;
final Future<LongListPayload<T, K>> Function() onRefresh;
@ -200,8 +201,9 @@ class _LongListStatefulScaffoldState<T, K>
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: widget.title,
trailing:
payload == null ? null : widget.trailingBuilder(payload.header),
trailing: payload == null
? null
: widget.trailingBuilder(payload.header, setState),
),
child: SafeArea(
child: CupertinoScrollbar(
@ -215,7 +217,7 @@ class _LongListStatefulScaffoldState<T, K>
title: widget.title,
actions: payload == null
? null
: [widget.trailingBuilder(payload.header)],
: [widget.trailingBuilder(payload.header, setState)],
),
body: RefreshIndicator(
onRefresh: _refresh,

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:git_touch/graphql/gh.dart';
import 'package:git_touch/models/auth.dart';
import 'package:git_touch/utils/utils.dart';
import 'package:git_touch/widgets/action_button.dart';
@ -55,6 +56,8 @@ class _IssueScreenState extends State<IssueScreen> {
title
closed
url
viewerCanReact
viewerCanUpdate
...CommentParts
...ReactableParts
''';
@ -361,13 +364,32 @@ mutation {
@override
Widget build(BuildContext context) {
final auth = Provider.of<AuthModel>(context);
return LongListStatefulScaffold(
title: Text('Issue #$number'),
trailingBuilder: (payload) {
trailingBuilder: (payload, setState) {
return ActionButton(
title: (isPullRequest ? 'Pull Request' : 'Issue') + ' Actions',
items: [
if (payload != null) ...[
if (!isPullRequest && payload['viewerCanUpdate'])
ActionItem(
text: payload['closed'] ? 'Reopen issue' : 'Close issue',
onTap: (_) async {
final res = await auth.gqlClient.execute(
GhOpenIssueQuery(
variables: GhOpenIssueArguments(
id: payload['id'],
open: payload['closed'],
),
),
);
setState(() {
payload['closed'] = res.data.reopenIssue?.issue?.closed ??
res.data.closeIssue.issue.closed;
});
},
),
ActionItem.share(payload['url']),
ActionItem.launch(payload['url']),
],