From ab5e53119c99a87d22776df49a413f1eec9cb9ce Mon Sep 17 00:00:00 2001 From: Ehud Adler Date: Sat, 24 Nov 2018 21:56:27 -0500 Subject: [PATCH 1/6] Subscribe/Unsubscribe --- Classes/Issues/GithubClient+Issues.swift | 20 ++++ Classes/Issues/Issue+IssueType.swift | 4 + .../IssueManagingContextController.swift | 27 ++++- Classes/Issues/IssueResult.swift | 5 + Classes/Issues/IssueType.swift | 1 + Classes/Issues/PullRequest+IssueType.swift | 4 + Classes/Views/Constants.swift | 2 + gql/API.swift | 101 ++++++++++++++---- gql/IssueOrPullRequest.graphql | 2 + 9 files changed, 146 insertions(+), 20 deletions(-) diff --git a/Classes/Issues/GithubClient+Issues.swift b/Classes/Issues/GithubClient+Issues.swift index 48d0c260a..2d138d5df 100644 --- a/Classes/Issues/GithubClient+Issues.swift +++ b/Classes/Issues/GithubClient+Issues.swift @@ -163,6 +163,7 @@ extension GithubClient { milestone: milestoneModel, targetBranch: targetBranchModel, timelinePages: [newPage] + (prependResult?.timelinePages ?? []), + viewerIsSubscribed: issueType.viewerSubscribed, viewerCanUpdate: issueType.viewerCanUpdate, hasIssuesEnabled: repository.hasIssuesEnabled, viewerCanAdminister: canAdmin, @@ -297,6 +298,25 @@ extension GithubClient { } } + + func setSubscription( + previous: IssueResult, + subscribed: Bool, + completion: ((Result) -> Void)? = nil + ) { + + let cache = self.cache + + client.send(V3SubscribeThreadRequest(id: previous.id, ignore: subscribed)) { result in + switch result { + case .success: + completion?(.success(true)) + case .failure(let error): + cache.set(value: previous) + } + } + } + enum CollaboratorPermission: String { case admin case write diff --git a/Classes/Issues/Issue+IssueType.swift b/Classes/Issues/Issue+IssueType.swift index f8c2b6c39..9502a014a 100644 --- a/Classes/Issues/Issue+IssueType.swift +++ b/Classes/Issues/Issue+IssueType.swift @@ -11,6 +11,10 @@ import IGListKit extension IssueOrPullRequestQuery.Data.Repository.IssueOrPullRequest.AsIssue: IssueType { + var viewerSubscribed: Bool { + return viewerSubscription?.rawValue != "IGNORED" + } + var pullRequest: Bool { return false } diff --git a/Classes/Issues/IssueManagingContextController.swift b/Classes/Issues/IssueManagingContextController.swift index cf42cbaf6..1a2fb4708 100644 --- a/Classes/Issues/IssueManagingContextController.swift +++ b/Classes/Issues/IssueManagingContextController.swift @@ -84,6 +84,8 @@ final class IssueManagingContextController: NSObject, ContextMenuDelegate { case lock case reopen case close + case subscribe + case unsubscribe } var actions: [Action] { @@ -97,6 +99,15 @@ final class IssueManagingContextController: NSObject, ContextMenuDelegate { if result.pullRequest { actions.append(.reviewers) } + } + + if result.viewerIsSubscribed { + actions.append(.unsubscribe) + } else { + actions.append(.subscribe) + } + + if case .collaborator = permissions { if result.labels.locked { actions.append(.unlock) } else { @@ -144,13 +155,19 @@ final class IssueManagingContextController: NSObject, ContextMenuDelegate { case .close: title = Constants.Strings.close iconName = "x" + case .subscribe: + title = Constants.Strings.subscribe + iconName = "unmute" + case .unsubscribe: + title = Constants.Strings.unsubscribe + iconName = "mute" } // Lock always has the divider above it assuming you're a collaborator. // If you aren't a collaborator (Lock does not show), close has the divider above it. let separator: Bool switch action { - case .lock, .unlock: separator = true + case .subscribe, .unsubscribe: separator = true case .reopen, .close: separator = permissions != .collaborator default: separator = false } @@ -186,6 +203,8 @@ final class IssueManagingContextController: NSObject, ContextMenuDelegate { case .lock: strongSelf.lock(true) case .reopen: strongSelf.close(false) case .close: strongSelf.close(true) + case .subscribe: strongSelf.subscribe(true) + case .unsubscribe: strongSelf.subscribe(false) } } } @@ -271,6 +290,12 @@ final class IssueManagingContextController: NSObject, ContextMenuDelegate { ) } + func subscribe(_ doSubscribe: Bool) { + guard let previous = result else { return } + delegate?.willMutateModel(from: self) + client.setSubscription(previous: previous, subscribed: doSubscribe) + Haptic.triggerNotification(.success) + } func close(_ doClose: Bool) { guard let previous = result else { return } delegate?.willMutateModel(from: self) diff --git a/Classes/Issues/IssueResult.swift b/Classes/Issues/IssueResult.swift index 08ff5e32e..ff161dc0a 100644 --- a/Classes/Issues/IssueResult.swift +++ b/Classes/Issues/IssueResult.swift @@ -25,6 +25,7 @@ struct IssueResult: Cachable { let targetBranch: IssueTargetBranchModel? // end optionals let timelinePages: [IssueTimelinePage] + let viewerIsSubscribed: Bool let viewerCanUpdate: Bool let hasIssuesEnabled: Bool let viewerCanAdminister: Bool @@ -73,6 +74,7 @@ struct IssueResult: Cachable { labels: IssueLabelsModel? = nil, assignee: IssueAssigneesModel? = nil, timelinePages: [IssueTimelinePage]? = nil, + viewerIsSubscribed: Bool? = nil, viewerCanUpdate: Bool? = nil, hasIssuesEnabled: Bool? = nil, viewerCanAdminister: Bool? = nil, @@ -90,6 +92,7 @@ struct IssueResult: Cachable { milestone: self.milestone, targetBranch: self.targetBranch, timelinePages: timelinePages ?? self.timelinePages, + viewerIsSubscribed: viewerIsSubscribed ?? self.viewerIsSubscribed, viewerCanUpdate: viewerCanUpdate ?? self.viewerCanUpdate, hasIssuesEnabled: hasIssuesEnabled ?? self.hasIssuesEnabled, viewerCanAdminister: viewerCanAdminister ?? self.viewerCanAdminister, @@ -114,6 +117,7 @@ struct IssueResult: Cachable { milestone: milestone, targetBranch: self.targetBranch, timelinePages: timelinePages ?? self.timelinePages, + viewerIsSubscribed: self.viewerIsSubscribed, viewerCanUpdate: self.viewerCanUpdate, hasIssuesEnabled: self.hasIssuesEnabled, viewerCanAdminister: self.viewerCanAdminister, @@ -138,6 +142,7 @@ struct IssueResult: Cachable { milestone: self.milestone, targetBranch: self.targetBranch, timelinePages: timelinePages ?? self.timelinePages, + viewerIsSubscribed: self.viewerIsSubscribed, viewerCanUpdate: self.viewerCanUpdate, hasIssuesEnabled: self.hasIssuesEnabled, viewerCanAdminister: self.viewerCanAdminister, diff --git a/Classes/Issues/IssueType.swift b/Classes/Issues/IssueType.swift index d3c4e8b6b..d43c29d55 100644 --- a/Classes/Issues/IssueType.swift +++ b/Classes/Issues/IssueType.swift @@ -32,6 +32,7 @@ protocol IssueType { var targetBranch: String? { get } var locked: Bool { get } var headPaging: HeadPaging { get } + var viewerSubscribed: Bool { get } var viewerCanUpdate: Bool { get } var fileChanges: FileChanges? { get } diff --git a/Classes/Issues/PullRequest+IssueType.swift b/Classes/Issues/PullRequest+IssueType.swift index b320bb597..0be2eb20d 100644 --- a/Classes/Issues/PullRequest+IssueType.swift +++ b/Classes/Issues/PullRequest+IssueType.swift @@ -12,6 +12,10 @@ import StyledTextKit extension IssueOrPullRequestQuery.Data.Repository.IssueOrPullRequest.AsPullRequest: IssueType { + var viewerSubscribed: Bool { + return viewerSubscription?.rawValue != "IGNORED" + } + var pullRequest: Bool { return true } diff --git a/Classes/Views/Constants.swift b/Classes/Views/Constants.swift index 2f4270a9c..cc85db2d2 100644 --- a/Classes/Views/Constants.swift +++ b/Classes/Views/Constants.swift @@ -52,5 +52,7 @@ enum Constants { static let reviewers = NSLocalizedString("Reviewers", comment: "") static let clear = NSLocalizedString("Clear", comment: "") static let preview = NSLocalizedString("Preview", comment: "") + static let subscribe = NSLocalizedString("Subscribe", comment: "") + static let unsubscribe = NSLocalizedString("Unsubscribe", comment: "") } } diff --git a/gql/API.swift b/gql/API.swift index 76a36a998..d901524dd 100644 --- a/gql/API.swift +++ b/gql/API.swift @@ -109,6 +109,47 @@ public enum StatusState: RawRepresentable, Equatable, Apollo.JSONDecodable, Apol } } +/// The possible states of a subscription. +public enum SubscriptionState: RawRepresentable, Equatable, Apollo.JSONDecodable, Apollo.JSONEncodable { + public typealias RawValue = String + /// The User is only notified when particpating or @mentioned. + case unsubscribed + /// The User is notified of all conversations. + case subscribed + /// The User is never notified. + case ignored + /// Auto generated constant for unknown enum values + case __unknown(RawValue) + + public init?(rawValue: RawValue) { + switch rawValue { + case "UNSUBSCRIBED": self = .unsubscribed + case "SUBSCRIBED": self = .subscribed + case "IGNORED": self = .ignored + default: self = .__unknown(rawValue) + } + } + + public var rawValue: RawValue { + switch self { + case .unsubscribed: return "UNSUBSCRIBED" + case .subscribed: return "SUBSCRIBED" + case .ignored: return "IGNORED" + case .__unknown(let value): return value + } + } + + public static func == (lhs: SubscriptionState, rhs: SubscriptionState) -> Bool { + switch (lhs, rhs) { + case (.unsubscribed, .unsubscribed): return true + case (.subscribed, .subscribed): return true + case (.ignored, .ignored): return true + case (.__unknown(let lhsValue), .__unknown(let rhsValue)): return lhsValue == rhsValue + default: return false + } + } +} + /// The possible states of a pull request review. public enum PullRequestReviewState: RawRepresentable, Equatable, Apollo.JSONDecodable, Apollo.JSONEncodable { public typealias RawValue = String @@ -1500,7 +1541,7 @@ public final class IssueAutocompleteQuery: GraphQLQuery { public final class IssueOrPullRequestQuery: GraphQLQuery { public static let operationString = - "query IssueOrPullRequest($owner: String!, $repo: String!, $number: Int!, $page_size: Int!, $before: String) {\n repository(owner: $owner, name: $repo) {\n __typename\n name\n hasIssuesEnabled\n viewerCanAdminister\n mergeCommitAllowed\n rebaseMergeAllowed\n squashMergeAllowed\n mentionableUsers(first: 50) {\n __typename\n nodes {\n __typename\n avatarUrl\n login\n }\n }\n defaultBranchRef {\n __typename\n name\n }\n issueOrPullRequest(number: $number) {\n __typename\n ... on Issue {\n timeline(last: $page_size, before: $before) {\n __typename\n pageInfo {\n __typename\n ...headPaging\n }\n nodes {\n __typename\n ... on Commit {\n ...nodeFields\n author {\n __typename\n user {\n __typename\n login\n avatarUrl\n }\n }\n oid\n messageHeadline\n }\n ... on IssueComment {\n ...nodeFields\n ...reactionFields\n ...commentFields\n ...updatableFields\n ...deletableFields\n }\n ... on LabeledEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n label {\n __typename\n color\n name\n }\n createdAt\n }\n ... on UnlabeledEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n label {\n __typename\n color\n name\n }\n createdAt\n }\n ... on ClosedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n closer {\n __typename\n ... on Commit {\n oid\n }\n ... on PullRequest {\n mergeCommit {\n __typename\n oid\n }\n }\n }\n }\n ... on ReopenedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n }\n ... on RenamedTitleEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n currentTitle\n }\n ... on LockedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n }\n ... on UnlockedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n }\n ... on CrossReferencedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n source {\n __typename\n ... on Issue {\n title\n number\n closed\n repository {\n __typename\n name\n owner {\n __typename\n login\n }\n }\n }\n ... on PullRequest {\n title\n number\n closed\n merged\n repository {\n __typename\n name\n owner {\n __typename\n login\n }\n }\n }\n }\n }\n ... on ReferencedEvent {\n createdAt\n ...nodeFields\n refCommit: commit {\n __typename\n oid\n }\n actor {\n __typename\n login\n }\n commitRepository {\n __typename\n ...referencedRepositoryFields\n }\n subject {\n __typename\n ... on Issue {\n title\n number\n closed\n }\n ... on PullRequest {\n title\n number\n closed\n merged\n }\n }\n }\n ... on RenamedTitleEvent {\n ...nodeFields\n createdAt\n currentTitle\n previousTitle\n actor {\n __typename\n login\n }\n }\n ... on AssignedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n user {\n __typename\n login\n }\n }\n ... on UnassignedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n user {\n __typename\n login\n }\n }\n ... on MilestonedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n milestoneTitle\n }\n ... on DemilestonedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n milestoneTitle\n }\n }\n }\n milestone {\n __typename\n ...milestoneFields\n }\n ...reactionFields\n ...commentFields\n ...lockableFields\n ...closableFields\n ...labelableFields\n ...updatableFields\n ...nodeFields\n ...assigneeFields\n number\n title\n }\n ... on PullRequest {\n timeline(last: $page_size, before: $before) {\n __typename\n pageInfo {\n __typename\n ...headPaging\n }\n nodes {\n __typename\n ... on Commit {\n ...nodeFields\n author {\n __typename\n user {\n __typename\n login\n avatarUrl\n }\n }\n oid\n messageHeadline\n }\n ... on IssueComment {\n ...nodeFields\n ...reactionFields\n ...commentFields\n ...updatableFields\n ...deletableFields\n }\n ... on LabeledEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n label {\n __typename\n color\n name\n }\n createdAt\n }\n ... on UnlabeledEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n label {\n __typename\n color\n name\n }\n createdAt\n }\n ... on ClosedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n closer {\n __typename\n ... on Commit {\n oid\n }\n ... on PullRequest {\n mergeCommit {\n __typename\n oid\n }\n }\n }\n }\n ... on ReopenedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n }\n ... on RenamedTitleEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n currentTitle\n }\n ... on LockedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n }\n ... on UnlockedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n }\n ... on MergedEvent {\n ...nodeFields\n mergedCommit: commit {\n __typename\n oid\n }\n actor {\n __typename\n login\n }\n createdAt\n }\n ... on PullRequestReviewThread {\n comments(first: $page_size) {\n __typename\n nodes {\n __typename\n ...reactionFields\n ...nodeFields\n ...commentFields\n path\n diffHunk\n }\n }\n }\n ... on PullRequestReview {\n ...nodeFields\n ...commentFields\n state\n submittedAt\n author {\n __typename\n login\n }\n comments {\n __typename\n totalCount\n }\n }\n ... on CrossReferencedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n source {\n __typename\n ... on Issue {\n title\n number\n closed\n repository {\n __typename\n name\n owner {\n __typename\n login\n }\n }\n }\n ... on PullRequest {\n title\n number\n closed\n merged\n repository {\n __typename\n name\n owner {\n __typename\n login\n }\n }\n }\n }\n }\n ... on ReferencedEvent {\n createdAt\n ...nodeFields\n actor {\n __typename\n login\n }\n commitRepository {\n __typename\n ...referencedRepositoryFields\n }\n subject {\n __typename\n ... on Issue {\n title\n number\n closed\n }\n ... on PullRequest {\n title\n number\n closed\n merged\n }\n }\n }\n ... on RenamedTitleEvent {\n ...nodeFields\n createdAt\n currentTitle\n previousTitle\n actor {\n __typename\n login\n }\n }\n ... on AssignedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n user {\n __typename\n login\n }\n }\n ... on UnassignedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n user {\n __typename\n login\n }\n }\n ... on ReviewRequestedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n requestedReviewer {\n __typename\n ... on Actor {\n login\n }\n }\n }\n ... on ReviewRequestRemovedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n requestedReviewer {\n __typename\n ... on Actor {\n login\n }\n }\n }\n ... on MilestonedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n milestoneTitle\n }\n ... on DemilestonedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n milestoneTitle\n }\n }\n }\n reviewRequests(first: $page_size) {\n __typename\n nodes {\n __typename\n requestedReviewer {\n __typename\n ... on Actor {\n login\n avatarUrl\n }\n }\n }\n }\n commits(last: 1) {\n __typename\n nodes {\n __typename\n commit {\n __typename\n ...commitContext\n }\n }\n }\n milestone {\n __typename\n ...milestoneFields\n }\n ...reactionFields\n ...commentFields\n ...lockableFields\n ...closableFields\n ...labelableFields\n ...updatableFields\n ...nodeFields\n ...assigneeFields\n number\n title\n merged\n baseRefName\n changedFiles\n additions\n deletions\n mergeable\n mergeStateStatus\n }\n }\n }\n}" + "query IssueOrPullRequest($owner: String!, $repo: String!, $number: Int!, $page_size: Int!, $before: String) {\n repository(owner: $owner, name: $repo) {\n __typename\n name\n hasIssuesEnabled\n viewerCanAdminister\n mergeCommitAllowed\n rebaseMergeAllowed\n squashMergeAllowed\n mentionableUsers(first: 50) {\n __typename\n nodes {\n __typename\n avatarUrl\n login\n }\n }\n defaultBranchRef {\n __typename\n name\n }\n issueOrPullRequest(number: $number) {\n __typename\n ... on Issue {\n id\n viewerSubscription\n timeline(last: $page_size, before: $before) {\n __typename\n pageInfo {\n __typename\n ...headPaging\n }\n nodes {\n __typename\n ... on Commit {\n ...nodeFields\n author {\n __typename\n user {\n __typename\n login\n avatarUrl\n }\n }\n oid\n messageHeadline\n }\n ... on IssueComment {\n ...nodeFields\n ...reactionFields\n ...commentFields\n ...updatableFields\n ...deletableFields\n }\n ... on LabeledEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n label {\n __typename\n color\n name\n }\n createdAt\n }\n ... on UnlabeledEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n label {\n __typename\n color\n name\n }\n createdAt\n }\n ... on ClosedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n closer {\n __typename\n ... on Commit {\n oid\n }\n ... on PullRequest {\n mergeCommit {\n __typename\n oid\n }\n }\n }\n }\n ... on ReopenedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n }\n ... on RenamedTitleEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n currentTitle\n }\n ... on LockedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n }\n ... on UnlockedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n }\n ... on CrossReferencedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n source {\n __typename\n ... on Issue {\n title\n number\n closed\n repository {\n __typename\n name\n owner {\n __typename\n login\n }\n }\n }\n ... on PullRequest {\n title\n number\n closed\n merged\n repository {\n __typename\n name\n owner {\n __typename\n login\n }\n }\n }\n }\n }\n ... on ReferencedEvent {\n createdAt\n ...nodeFields\n refCommit: commit {\n __typename\n oid\n }\n actor {\n __typename\n login\n }\n commitRepository {\n __typename\n ...referencedRepositoryFields\n }\n subject {\n __typename\n ... on Issue {\n title\n number\n closed\n }\n ... on PullRequest {\n title\n number\n closed\n merged\n }\n }\n }\n ... on RenamedTitleEvent {\n ...nodeFields\n createdAt\n currentTitle\n previousTitle\n actor {\n __typename\n login\n }\n }\n ... on AssignedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n user {\n __typename\n login\n }\n }\n ... on UnassignedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n user {\n __typename\n login\n }\n }\n ... on MilestonedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n milestoneTitle\n }\n ... on DemilestonedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n milestoneTitle\n }\n }\n }\n milestone {\n __typename\n ...milestoneFields\n }\n ...reactionFields\n ...commentFields\n ...lockableFields\n ...closableFields\n ...labelableFields\n ...updatableFields\n ...nodeFields\n ...assigneeFields\n number\n title\n }\n ... on PullRequest {\n viewerSubscription\n timeline(last: $page_size, before: $before) {\n __typename\n pageInfo {\n __typename\n ...headPaging\n }\n nodes {\n __typename\n ... on Commit {\n ...nodeFields\n author {\n __typename\n user {\n __typename\n login\n avatarUrl\n }\n }\n oid\n messageHeadline\n }\n ... on IssueComment {\n ...nodeFields\n ...reactionFields\n ...commentFields\n ...updatableFields\n ...deletableFields\n }\n ... on LabeledEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n label {\n __typename\n color\n name\n }\n createdAt\n }\n ... on UnlabeledEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n label {\n __typename\n color\n name\n }\n createdAt\n }\n ... on ClosedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n closer {\n __typename\n ... on Commit {\n oid\n }\n ... on PullRequest {\n mergeCommit {\n __typename\n oid\n }\n }\n }\n }\n ... on ReopenedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n }\n ... on RenamedTitleEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n currentTitle\n }\n ... on LockedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n }\n ... on UnlockedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n }\n ... on MergedEvent {\n ...nodeFields\n mergedCommit: commit {\n __typename\n oid\n }\n actor {\n __typename\n login\n }\n createdAt\n }\n ... on PullRequestReviewThread {\n comments(first: $page_size) {\n __typename\n nodes {\n __typename\n ...reactionFields\n ...nodeFields\n ...commentFields\n path\n diffHunk\n }\n }\n }\n ... on PullRequestReview {\n ...nodeFields\n ...commentFields\n state\n submittedAt\n author {\n __typename\n login\n }\n comments {\n __typename\n totalCount\n }\n }\n ... on CrossReferencedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n source {\n __typename\n ... on Issue {\n title\n number\n closed\n repository {\n __typename\n name\n owner {\n __typename\n login\n }\n }\n }\n ... on PullRequest {\n title\n number\n closed\n merged\n repository {\n __typename\n name\n owner {\n __typename\n login\n }\n }\n }\n }\n }\n ... on ReferencedEvent {\n createdAt\n ...nodeFields\n actor {\n __typename\n login\n }\n commitRepository {\n __typename\n ...referencedRepositoryFields\n }\n subject {\n __typename\n ... on Issue {\n title\n number\n closed\n }\n ... on PullRequest {\n title\n number\n closed\n merged\n }\n }\n }\n ... on RenamedTitleEvent {\n ...nodeFields\n createdAt\n currentTitle\n previousTitle\n actor {\n __typename\n login\n }\n }\n ... on AssignedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n user {\n __typename\n login\n }\n }\n ... on UnassignedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n user {\n __typename\n login\n }\n }\n ... on ReviewRequestedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n requestedReviewer {\n __typename\n ... on Actor {\n login\n }\n }\n }\n ... on ReviewRequestRemovedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n requestedReviewer {\n __typename\n ... on Actor {\n login\n }\n }\n }\n ... on MilestonedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n milestoneTitle\n }\n ... on DemilestonedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n milestoneTitle\n }\n }\n }\n reviewRequests(first: $page_size) {\n __typename\n nodes {\n __typename\n requestedReviewer {\n __typename\n ... on Actor {\n login\n avatarUrl\n }\n }\n }\n }\n commits(last: 1) {\n __typename\n nodes {\n __typename\n commit {\n __typename\n ...commitContext\n }\n }\n }\n milestone {\n __typename\n ...milestoneFields\n }\n ...reactionFields\n ...commentFields\n ...lockableFields\n ...closableFields\n ...labelableFields\n ...updatableFields\n ...nodeFields\n ...assigneeFields\n number\n title\n merged\n baseRefName\n changedFiles\n additions\n deletions\n mergeable\n mergeStateStatus\n }\n }\n }\n}" public static var requestString: String { return operationString.appending(HeadPaging.fragmentString).appending(NodeFields.fragmentString).appending(ReactionFields.fragmentString).appending(CommentFields.fragmentString).appending(UpdatableFields.fragmentString).appending(DeletableFields.fragmentString).appending(ReferencedRepositoryFields.fragmentString).appending(MilestoneFields.fragmentString).appending(LockableFields.fragmentString).appending(ClosableFields.fragmentString).appending(LabelableFields.fragmentString).appending(AssigneeFields.fragmentString).appending(CommitContext.fragmentString) } @@ -1817,12 +1858,12 @@ public final class IssueOrPullRequestQuery: GraphQLQuery { self.snapshot = snapshot } - public static func makeIssue(timeline: AsIssue.Timeline, milestone: AsIssue.Milestone? = nil, viewerCanReact: Bool, reactionGroups: [AsIssue.ReactionGroup]? = nil, author: AsIssue.Author? = nil, editor: AsIssue.Editor? = nil, lastEditedAt: String? = nil, body: String, createdAt: String, viewerDidAuthor: Bool, locked: Bool, closed: Bool, labels: AsIssue.Label? = nil, viewerCanUpdate: Bool, id: GraphQLID, assignees: AsIssue.Assignee, number: Int, title: String) -> IssueOrPullRequest { - return IssueOrPullRequest(snapshot: ["__typename": "Issue", "timeline": timeline.snapshot, "milestone": milestone.flatMap { (value: AsIssue.Milestone) -> Snapshot in value.snapshot }, "viewerCanReact": viewerCanReact, "reactionGroups": reactionGroups.flatMap { (value: [AsIssue.ReactionGroup]) -> [Snapshot] in value.map { (value: AsIssue.ReactionGroup) -> Snapshot in value.snapshot } }, "author": author.flatMap { (value: AsIssue.Author) -> Snapshot in value.snapshot }, "editor": editor.flatMap { (value: AsIssue.Editor) -> Snapshot in value.snapshot }, "lastEditedAt": lastEditedAt, "body": body, "createdAt": createdAt, "viewerDidAuthor": viewerDidAuthor, "locked": locked, "closed": closed, "labels": labels.flatMap { (value: AsIssue.Label) -> Snapshot in value.snapshot }, "viewerCanUpdate": viewerCanUpdate, "id": id, "assignees": assignees.snapshot, "number": number, "title": title]) + public static func makeIssue(id: GraphQLID, viewerSubscription: SubscriptionState? = nil, timeline: AsIssue.Timeline, milestone: AsIssue.Milestone? = nil, viewerCanReact: Bool, reactionGroups: [AsIssue.ReactionGroup]? = nil, author: AsIssue.Author? = nil, editor: AsIssue.Editor? = nil, lastEditedAt: String? = nil, body: String, createdAt: String, viewerDidAuthor: Bool, locked: Bool, closed: Bool, labels: AsIssue.Label? = nil, viewerCanUpdate: Bool, assignees: AsIssue.Assignee, number: Int, title: String) -> IssueOrPullRequest { + return IssueOrPullRequest(snapshot: ["__typename": "Issue", "id": id, "viewerSubscription": viewerSubscription, "timeline": timeline.snapshot, "milestone": milestone.flatMap { (value: AsIssue.Milestone) -> Snapshot in value.snapshot }, "viewerCanReact": viewerCanReact, "reactionGroups": reactionGroups.flatMap { (value: [AsIssue.ReactionGroup]) -> [Snapshot] in value.map { (value: AsIssue.ReactionGroup) -> Snapshot in value.snapshot } }, "author": author.flatMap { (value: AsIssue.Author) -> Snapshot in value.snapshot }, "editor": editor.flatMap { (value: AsIssue.Editor) -> Snapshot in value.snapshot }, "lastEditedAt": lastEditedAt, "body": body, "createdAt": createdAt, "viewerDidAuthor": viewerDidAuthor, "locked": locked, "closed": closed, "labels": labels.flatMap { (value: AsIssue.Label) -> Snapshot in value.snapshot }, "viewerCanUpdate": viewerCanUpdate, "assignees": assignees.snapshot, "number": number, "title": title]) } - public static func makePullRequest(timeline: AsPullRequest.Timeline, reviewRequests: AsPullRequest.ReviewRequest? = nil, commits: AsPullRequest.Commit, milestone: AsPullRequest.Milestone? = nil, viewerCanReact: Bool, reactionGroups: [AsPullRequest.ReactionGroup]? = nil, author: AsPullRequest.Author? = nil, editor: AsPullRequest.Editor? = nil, lastEditedAt: String? = nil, body: String, createdAt: String, viewerDidAuthor: Bool, locked: Bool, closed: Bool, labels: AsPullRequest.Label? = nil, viewerCanUpdate: Bool, id: GraphQLID, assignees: AsPullRequest.Assignee, number: Int, title: String, merged: Bool, baseRefName: String, changedFiles: Int, additions: Int, deletions: Int, mergeable: MergeableState, mergeStateStatus: MergeStateStatus) -> IssueOrPullRequest { - return IssueOrPullRequest(snapshot: ["__typename": "PullRequest", "timeline": timeline.snapshot, "reviewRequests": reviewRequests.flatMap { (value: AsPullRequest.ReviewRequest) -> Snapshot in value.snapshot }, "commits": commits.snapshot, "milestone": milestone.flatMap { (value: AsPullRequest.Milestone) -> Snapshot in value.snapshot }, "viewerCanReact": viewerCanReact, "reactionGroups": reactionGroups.flatMap { (value: [AsPullRequest.ReactionGroup]) -> [Snapshot] in value.map { (value: AsPullRequest.ReactionGroup) -> Snapshot in value.snapshot } }, "author": author.flatMap { (value: AsPullRequest.Author) -> Snapshot in value.snapshot }, "editor": editor.flatMap { (value: AsPullRequest.Editor) -> Snapshot in value.snapshot }, "lastEditedAt": lastEditedAt, "body": body, "createdAt": createdAt, "viewerDidAuthor": viewerDidAuthor, "locked": locked, "closed": closed, "labels": labels.flatMap { (value: AsPullRequest.Label) -> Snapshot in value.snapshot }, "viewerCanUpdate": viewerCanUpdate, "id": id, "assignees": assignees.snapshot, "number": number, "title": title, "merged": merged, "baseRefName": baseRefName, "changedFiles": changedFiles, "additions": additions, "deletions": deletions, "mergeable": mergeable, "mergeStateStatus": mergeStateStatus]) + public static func makePullRequest(viewerSubscription: SubscriptionState? = nil, timeline: AsPullRequest.Timeline, reviewRequests: AsPullRequest.ReviewRequest? = nil, commits: AsPullRequest.Commit, milestone: AsPullRequest.Milestone? = nil, viewerCanReact: Bool, reactionGroups: [AsPullRequest.ReactionGroup]? = nil, author: AsPullRequest.Author? = nil, editor: AsPullRequest.Editor? = nil, lastEditedAt: String? = nil, body: String, createdAt: String, viewerDidAuthor: Bool, locked: Bool, closed: Bool, labels: AsPullRequest.Label? = nil, viewerCanUpdate: Bool, id: GraphQLID, assignees: AsPullRequest.Assignee, number: Int, title: String, merged: Bool, baseRefName: String, changedFiles: Int, additions: Int, deletions: Int, mergeable: MergeableState, mergeStateStatus: MergeStateStatus) -> IssueOrPullRequest { + return IssueOrPullRequest(snapshot: ["__typename": "PullRequest", "viewerSubscription": viewerSubscription, "timeline": timeline.snapshot, "reviewRequests": reviewRequests.flatMap { (value: AsPullRequest.ReviewRequest) -> Snapshot in value.snapshot }, "commits": commits.snapshot, "milestone": milestone.flatMap { (value: AsPullRequest.Milestone) -> Snapshot in value.snapshot }, "viewerCanReact": viewerCanReact, "reactionGroups": reactionGroups.flatMap { (value: [AsPullRequest.ReactionGroup]) -> [Snapshot] in value.map { (value: AsPullRequest.ReactionGroup) -> Snapshot in value.snapshot } }, "author": author.flatMap { (value: AsPullRequest.Author) -> Snapshot in value.snapshot }, "editor": editor.flatMap { (value: AsPullRequest.Editor) -> Snapshot in value.snapshot }, "lastEditedAt": lastEditedAt, "body": body, "createdAt": createdAt, "viewerDidAuthor": viewerDidAuthor, "locked": locked, "closed": closed, "labels": labels.flatMap { (value: AsPullRequest.Label) -> Snapshot in value.snapshot }, "viewerCanUpdate": viewerCanUpdate, "id": id, "assignees": assignees.snapshot, "number": number, "title": title, "merged": merged, "baseRefName": baseRefName, "changedFiles": changedFiles, "additions": additions, "deletions": deletions, "mergeable": mergeable, "mergeStateStatus": mergeStateStatus]) } public var __typename: String { @@ -1850,6 +1891,8 @@ public final class IssueOrPullRequestQuery: GraphQLQuery { public static let selections: [GraphQLSelection] = [ GraphQLField("__typename", type: .nonNull(.scalar(String.self))), + GraphQLField("id", type: .nonNull(.scalar(GraphQLID.self))), + GraphQLField("viewerSubscription", type: .scalar(SubscriptionState.self)), GraphQLField("timeline", arguments: ["last": GraphQLVariable("page_size"), "before": GraphQLVariable("before")], type: .nonNull(.object(Timeline.selections))), GraphQLField("milestone", type: .object(Milestone.selections)), GraphQLField("__typename", type: .nonNull(.scalar(String.self))), @@ -1884,8 +1927,8 @@ public final class IssueOrPullRequestQuery: GraphQLQuery { self.snapshot = snapshot } - public init(timeline: Timeline, milestone: Milestone? = nil, viewerCanReact: Bool, reactionGroups: [ReactionGroup]? = nil, author: Author? = nil, editor: Editor? = nil, lastEditedAt: String? = nil, body: String, createdAt: String, viewerDidAuthor: Bool, locked: Bool, closed: Bool, labels: Label? = nil, viewerCanUpdate: Bool, id: GraphQLID, assignees: Assignee, number: Int, title: String) { - self.init(snapshot: ["__typename": "Issue", "timeline": timeline.snapshot, "milestone": milestone.flatMap { (value: Milestone) -> Snapshot in value.snapshot }, "viewerCanReact": viewerCanReact, "reactionGroups": reactionGroups.flatMap { (value: [ReactionGroup]) -> [Snapshot] in value.map { (value: ReactionGroup) -> Snapshot in value.snapshot } }, "author": author.flatMap { (value: Author) -> Snapshot in value.snapshot }, "editor": editor.flatMap { (value: Editor) -> Snapshot in value.snapshot }, "lastEditedAt": lastEditedAt, "body": body, "createdAt": createdAt, "viewerDidAuthor": viewerDidAuthor, "locked": locked, "closed": closed, "labels": labels.flatMap { (value: Label) -> Snapshot in value.snapshot }, "viewerCanUpdate": viewerCanUpdate, "id": id, "assignees": assignees.snapshot, "number": number, "title": title]) + public init(id: GraphQLID, viewerSubscription: SubscriptionState? = nil, timeline: Timeline, milestone: Milestone? = nil, viewerCanReact: Bool, reactionGroups: [ReactionGroup]? = nil, author: Author? = nil, editor: Editor? = nil, lastEditedAt: String? = nil, body: String, createdAt: String, viewerDidAuthor: Bool, locked: Bool, closed: Bool, labels: Label? = nil, viewerCanUpdate: Bool, assignees: Assignee, number: Int, title: String) { + self.init(snapshot: ["__typename": "Issue", "id": id, "viewerSubscription": viewerSubscription, "timeline": timeline.snapshot, "milestone": milestone.flatMap { (value: Milestone) -> Snapshot in value.snapshot }, "viewerCanReact": viewerCanReact, "reactionGroups": reactionGroups.flatMap { (value: [ReactionGroup]) -> [Snapshot] in value.map { (value: ReactionGroup) -> Snapshot in value.snapshot } }, "author": author.flatMap { (value: Author) -> Snapshot in value.snapshot }, "editor": editor.flatMap { (value: Editor) -> Snapshot in value.snapshot }, "lastEditedAt": lastEditedAt, "body": body, "createdAt": createdAt, "viewerDidAuthor": viewerDidAuthor, "locked": locked, "closed": closed, "labels": labels.flatMap { (value: Label) -> Snapshot in value.snapshot }, "viewerCanUpdate": viewerCanUpdate, "assignees": assignees.snapshot, "number": number, "title": title]) } public var __typename: String { @@ -1897,6 +1940,25 @@ public final class IssueOrPullRequestQuery: GraphQLQuery { } } + public var id: GraphQLID { + get { + return snapshot["id"]! as! GraphQLID + } + set { + snapshot.updateValue(newValue, forKey: "id") + } + } + + /// Identifies if the viewer is watching, not watching, or ignoring the subscribable entity. + public var viewerSubscription: SubscriptionState? { + get { + return snapshot["viewerSubscription"] as? SubscriptionState + } + set { + snapshot.updateValue(newValue, forKey: "viewerSubscription") + } + } + /// A list of events, comments, commits, etc. associated with the issue. public var timeline: Timeline { get { @@ -2037,16 +2099,6 @@ public final class IssueOrPullRequestQuery: GraphQLQuery { } } - /// ID of the object. - public var id: GraphQLID { - get { - return snapshot["id"]! as! GraphQLID - } - set { - snapshot.updateValue(newValue, forKey: "id") - } - } - /// A list of Users assigned to this object. public var assignees: Assignee { get { @@ -6726,6 +6778,7 @@ public final class IssueOrPullRequestQuery: GraphQLQuery { public static let selections: [GraphQLSelection] = [ GraphQLField("__typename", type: .nonNull(.scalar(String.self))), + GraphQLField("viewerSubscription", type: .scalar(SubscriptionState.self)), GraphQLField("timeline", arguments: ["last": GraphQLVariable("page_size"), "before": GraphQLVariable("before")], type: .nonNull(.object(Timeline.selections))), GraphQLField("reviewRequests", arguments: ["first": GraphQLVariable("page_size")], type: .object(ReviewRequest.selections)), GraphQLField("commits", arguments: ["last": 1], type: .nonNull(.object(Commit.selections))), @@ -6769,8 +6822,8 @@ public final class IssueOrPullRequestQuery: GraphQLQuery { self.snapshot = snapshot } - public init(timeline: Timeline, reviewRequests: ReviewRequest? = nil, commits: Commit, milestone: Milestone? = nil, viewerCanReact: Bool, reactionGroups: [ReactionGroup]? = nil, author: Author? = nil, editor: Editor? = nil, lastEditedAt: String? = nil, body: String, createdAt: String, viewerDidAuthor: Bool, locked: Bool, closed: Bool, labels: Label? = nil, viewerCanUpdate: Bool, id: GraphQLID, assignees: Assignee, number: Int, title: String, merged: Bool, baseRefName: String, changedFiles: Int, additions: Int, deletions: Int, mergeable: MergeableState, mergeStateStatus: MergeStateStatus) { - self.init(snapshot: ["__typename": "PullRequest", "timeline": timeline.snapshot, "reviewRequests": reviewRequests.flatMap { (value: ReviewRequest) -> Snapshot in value.snapshot }, "commits": commits.snapshot, "milestone": milestone.flatMap { (value: Milestone) -> Snapshot in value.snapshot }, "viewerCanReact": viewerCanReact, "reactionGroups": reactionGroups.flatMap { (value: [ReactionGroup]) -> [Snapshot] in value.map { (value: ReactionGroup) -> Snapshot in value.snapshot } }, "author": author.flatMap { (value: Author) -> Snapshot in value.snapshot }, "editor": editor.flatMap { (value: Editor) -> Snapshot in value.snapshot }, "lastEditedAt": lastEditedAt, "body": body, "createdAt": createdAt, "viewerDidAuthor": viewerDidAuthor, "locked": locked, "closed": closed, "labels": labels.flatMap { (value: Label) -> Snapshot in value.snapshot }, "viewerCanUpdate": viewerCanUpdate, "id": id, "assignees": assignees.snapshot, "number": number, "title": title, "merged": merged, "baseRefName": baseRefName, "changedFiles": changedFiles, "additions": additions, "deletions": deletions, "mergeable": mergeable, "mergeStateStatus": mergeStateStatus]) + public init(viewerSubscription: SubscriptionState? = nil, timeline: Timeline, reviewRequests: ReviewRequest? = nil, commits: Commit, milestone: Milestone? = nil, viewerCanReact: Bool, reactionGroups: [ReactionGroup]? = nil, author: Author? = nil, editor: Editor? = nil, lastEditedAt: String? = nil, body: String, createdAt: String, viewerDidAuthor: Bool, locked: Bool, closed: Bool, labels: Label? = nil, viewerCanUpdate: Bool, id: GraphQLID, assignees: Assignee, number: Int, title: String, merged: Bool, baseRefName: String, changedFiles: Int, additions: Int, deletions: Int, mergeable: MergeableState, mergeStateStatus: MergeStateStatus) { + self.init(snapshot: ["__typename": "PullRequest", "viewerSubscription": viewerSubscription, "timeline": timeline.snapshot, "reviewRequests": reviewRequests.flatMap { (value: ReviewRequest) -> Snapshot in value.snapshot }, "commits": commits.snapshot, "milestone": milestone.flatMap { (value: Milestone) -> Snapshot in value.snapshot }, "viewerCanReact": viewerCanReact, "reactionGroups": reactionGroups.flatMap { (value: [ReactionGroup]) -> [Snapshot] in value.map { (value: ReactionGroup) -> Snapshot in value.snapshot } }, "author": author.flatMap { (value: Author) -> Snapshot in value.snapshot }, "editor": editor.flatMap { (value: Editor) -> Snapshot in value.snapshot }, "lastEditedAt": lastEditedAt, "body": body, "createdAt": createdAt, "viewerDidAuthor": viewerDidAuthor, "locked": locked, "closed": closed, "labels": labels.flatMap { (value: Label) -> Snapshot in value.snapshot }, "viewerCanUpdate": viewerCanUpdate, "id": id, "assignees": assignees.snapshot, "number": number, "title": title, "merged": merged, "baseRefName": baseRefName, "changedFiles": changedFiles, "additions": additions, "deletions": deletions, "mergeable": mergeable, "mergeStateStatus": mergeStateStatus]) } public var __typename: String { @@ -6782,6 +6835,16 @@ public final class IssueOrPullRequestQuery: GraphQLQuery { } } + /// Identifies if the viewer is watching, not watching, or ignoring the subscribable entity. + public var viewerSubscription: SubscriptionState? { + get { + return snapshot["viewerSubscription"] as? SubscriptionState + } + set { + snapshot.updateValue(newValue, forKey: "viewerSubscription") + } + } + /// A list of events, comments, commits, etc. associated with the pull request. public var timeline: Timeline { get { diff --git a/gql/IssueOrPullRequest.graphql b/gql/IssueOrPullRequest.graphql index c5fe1c742..1aca51503 100644 --- a/gql/IssueOrPullRequest.graphql +++ b/gql/IssueOrPullRequest.graphql @@ -17,6 +17,7 @@ query IssueOrPullRequest($owner: String!, $repo: String!, $number: Int!, $page_s } issueOrPullRequest(number: $number) { ... on Issue { + viewerSubscription timeline(last: $page_size, before: $before) { pageInfo{...headPaging} nodes { @@ -182,6 +183,7 @@ query IssueOrPullRequest($owner: String!, $repo: String!, $number: Int!, $page_s title } ... on PullRequest { + viewerSubscription timeline(last: $page_size, before: $before) { pageInfo{...headPaging} nodes { From aa61bca6aa58d146644c4d7dd3818befc0959872 Mon Sep 17 00:00:00 2001 From: Ehud Adler Date: Wed, 28 Nov 2018 20:06:51 -0500 Subject: [PATCH 2/6] Working on mutation --- Classes/Issues/GithubClient+Issues.swift | 26 +- .../IssueManagingContextController.swift | 22 +- gql/API.swift | 373 +++++++++++++++--- gql/Fragments.graphql | 6 + gql/UpdateSubscription.graphql | 7 + 5 files changed, 358 insertions(+), 76 deletions(-) create mode 100644 gql/UpdateSubscription.graphql diff --git a/Classes/Issues/GithubClient+Issues.swift b/Classes/Issues/GithubClient+Issues.swift index 2d138d5df..e3383fa11 100644 --- a/Classes/Issues/GithubClient+Issues.swift +++ b/Classes/Issues/GithubClient+Issues.swift @@ -298,23 +298,29 @@ extension GithubClient { } } - func setSubscription( - previous: IssueResult, + subscriptionId: String, subscribed: Bool, - completion: ((Result) -> Void)? = nil - ) { + completion: @escaping (Bool) -> Void + ) { - let cache = self.cache + let state: SubscriptionState = subscribed + ? .subscribed + : .unsubscribed + + let mutation = UpdateSubscriptionMutation(subscribable_Id: subscriptionId, subscription_state: state) - client.send(V3SubscribeThreadRequest(id: previous.id, ignore: subscribed)) { result in + client.mutate(mutation, result: { data in + print(data.updateSubscription?.subscribable) // Returns nil + }, completion: { result in switch result { - case .success: - completion?(.success(true)) + case .success(_): + completion(true) case .failure(let error): - cache.set(value: previous) + completion(false) + Squawk.show(error: error) } - } + }) } enum CollaboratorPermission: String { diff --git a/Classes/Issues/IssueManagingContextController.swift b/Classes/Issues/IssueManagingContextController.swift index 1a2fb4708..f1c805270 100644 --- a/Classes/Issues/IssueManagingContextController.swift +++ b/Classes/Issues/IssueManagingContextController.swift @@ -89,7 +89,7 @@ final class IssueManagingContextController: NSObject, ContextMenuDelegate { } var actions: [Action] { - if case .none = permissions { return [] } + guard let result = self.result else { return [] } var actions = [Action]() @@ -114,15 +114,15 @@ final class IssueManagingContextController: NSObject, ContextMenuDelegate { actions.append(.lock) } } - - switch result.labels.status.status { - case .closed: - actions.append(.reopen) - case .open: - actions.append(.close) - case .merged: break + if permissions == .collaborator || permissions == .author { + switch result.labels.status.status { + case .closed: + actions.append(.reopen) + case .open: + actions.append(.close) + case .merged: break + } } - return actions } @@ -293,7 +293,9 @@ final class IssueManagingContextController: NSObject, ContextMenuDelegate { func subscribe(_ doSubscribe: Bool) { guard let previous = result else { return } delegate?.willMutateModel(from: self) - client.setSubscription(previous: previous, subscribed: doSubscribe) + client.setSubscription(subscriptionId: previous.id, subscribed: doSubscribe) { (result) in + print(result) + } Haptic.triggerNotification(.success) } func close(_ doClose: Bool) { diff --git a/gql/API.swift b/gql/API.swift index d901524dd..e52b1f07d 100644 --- a/gql/API.swift +++ b/gql/API.swift @@ -58,6 +58,47 @@ public enum ReactionContent: RawRepresentable, Equatable, Apollo.JSONDecodable, } } +/// The possible states of a subscription. +public enum SubscriptionState: RawRepresentable, Equatable, Apollo.JSONDecodable, Apollo.JSONEncodable { + public typealias RawValue = String + /// The User is only notified when particpating or @mentioned. + case unsubscribed + /// The User is notified of all conversations. + case subscribed + /// The User is never notified. + case ignored + /// Auto generated constant for unknown enum values + case __unknown(RawValue) + + public init?(rawValue: RawValue) { + switch rawValue { + case "UNSUBSCRIBED": self = .unsubscribed + case "SUBSCRIBED": self = .subscribed + case "IGNORED": self = .ignored + default: self = .__unknown(rawValue) + } + } + + public var rawValue: RawValue { + switch self { + case .unsubscribed: return "UNSUBSCRIBED" + case .subscribed: return "SUBSCRIBED" + case .ignored: return "IGNORED" + case .__unknown(let value): return value + } + } + + public static func == (lhs: SubscriptionState, rhs: SubscriptionState) -> Bool { + switch (lhs, rhs) { + case (.unsubscribed, .unsubscribed): return true + case (.subscribed, .subscribed): return true + case (.ignored, .ignored): return true + case (.__unknown(let lhsValue), .__unknown(let rhsValue)): return lhsValue == rhsValue + default: return false + } + } +} + /// The possible commit status states. public enum StatusState: RawRepresentable, Equatable, Apollo.JSONDecodable, Apollo.JSONEncodable { public typealias RawValue = String @@ -109,47 +150,6 @@ public enum StatusState: RawRepresentable, Equatable, Apollo.JSONDecodable, Apol } } -/// The possible states of a subscription. -public enum SubscriptionState: RawRepresentable, Equatable, Apollo.JSONDecodable, Apollo.JSONEncodable { - public typealias RawValue = String - /// The User is only notified when particpating or @mentioned. - case unsubscribed - /// The User is notified of all conversations. - case subscribed - /// The User is never notified. - case ignored - /// Auto generated constant for unknown enum values - case __unknown(RawValue) - - public init?(rawValue: RawValue) { - switch rawValue { - case "UNSUBSCRIBED": self = .unsubscribed - case "SUBSCRIBED": self = .subscribed - case "IGNORED": self = .ignored - default: self = .__unknown(rawValue) - } - } - - public var rawValue: RawValue { - switch self { - case .unsubscribed: return "UNSUBSCRIBED" - case .subscribed: return "SUBSCRIBED" - case .ignored: return "IGNORED" - case .__unknown(let value): return value - } - } - - public static func == (lhs: SubscriptionState, rhs: SubscriptionState) -> Bool { - switch (lhs, rhs) { - case (.unsubscribed, .unsubscribed): return true - case (.subscribed, .subscribed): return true - case (.ignored, .ignored): return true - case (.__unknown(let lhsValue), .__unknown(let rhsValue)): return lhsValue == rhsValue - default: return false - } - } -} - /// The possible states of a pull request review. public enum PullRequestReviewState: RawRepresentable, Equatable, Apollo.JSONDecodable, Apollo.JSONEncodable { public typealias RawValue = String @@ -1541,7 +1541,7 @@ public final class IssueAutocompleteQuery: GraphQLQuery { public final class IssueOrPullRequestQuery: GraphQLQuery { public static let operationString = - "query IssueOrPullRequest($owner: String!, $repo: String!, $number: Int!, $page_size: Int!, $before: String) {\n repository(owner: $owner, name: $repo) {\n __typename\n name\n hasIssuesEnabled\n viewerCanAdminister\n mergeCommitAllowed\n rebaseMergeAllowed\n squashMergeAllowed\n mentionableUsers(first: 50) {\n __typename\n nodes {\n __typename\n avatarUrl\n login\n }\n }\n defaultBranchRef {\n __typename\n name\n }\n issueOrPullRequest(number: $number) {\n __typename\n ... on Issue {\n id\n viewerSubscription\n timeline(last: $page_size, before: $before) {\n __typename\n pageInfo {\n __typename\n ...headPaging\n }\n nodes {\n __typename\n ... on Commit {\n ...nodeFields\n author {\n __typename\n user {\n __typename\n login\n avatarUrl\n }\n }\n oid\n messageHeadline\n }\n ... on IssueComment {\n ...nodeFields\n ...reactionFields\n ...commentFields\n ...updatableFields\n ...deletableFields\n }\n ... on LabeledEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n label {\n __typename\n color\n name\n }\n createdAt\n }\n ... on UnlabeledEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n label {\n __typename\n color\n name\n }\n createdAt\n }\n ... on ClosedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n closer {\n __typename\n ... on Commit {\n oid\n }\n ... on PullRequest {\n mergeCommit {\n __typename\n oid\n }\n }\n }\n }\n ... on ReopenedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n }\n ... on RenamedTitleEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n currentTitle\n }\n ... on LockedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n }\n ... on UnlockedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n }\n ... on CrossReferencedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n source {\n __typename\n ... on Issue {\n title\n number\n closed\n repository {\n __typename\n name\n owner {\n __typename\n login\n }\n }\n }\n ... on PullRequest {\n title\n number\n closed\n merged\n repository {\n __typename\n name\n owner {\n __typename\n login\n }\n }\n }\n }\n }\n ... on ReferencedEvent {\n createdAt\n ...nodeFields\n refCommit: commit {\n __typename\n oid\n }\n actor {\n __typename\n login\n }\n commitRepository {\n __typename\n ...referencedRepositoryFields\n }\n subject {\n __typename\n ... on Issue {\n title\n number\n closed\n }\n ... on PullRequest {\n title\n number\n closed\n merged\n }\n }\n }\n ... on RenamedTitleEvent {\n ...nodeFields\n createdAt\n currentTitle\n previousTitle\n actor {\n __typename\n login\n }\n }\n ... on AssignedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n user {\n __typename\n login\n }\n }\n ... on UnassignedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n user {\n __typename\n login\n }\n }\n ... on MilestonedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n milestoneTitle\n }\n ... on DemilestonedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n milestoneTitle\n }\n }\n }\n milestone {\n __typename\n ...milestoneFields\n }\n ...reactionFields\n ...commentFields\n ...lockableFields\n ...closableFields\n ...labelableFields\n ...updatableFields\n ...nodeFields\n ...assigneeFields\n number\n title\n }\n ... on PullRequest {\n viewerSubscription\n timeline(last: $page_size, before: $before) {\n __typename\n pageInfo {\n __typename\n ...headPaging\n }\n nodes {\n __typename\n ... on Commit {\n ...nodeFields\n author {\n __typename\n user {\n __typename\n login\n avatarUrl\n }\n }\n oid\n messageHeadline\n }\n ... on IssueComment {\n ...nodeFields\n ...reactionFields\n ...commentFields\n ...updatableFields\n ...deletableFields\n }\n ... on LabeledEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n label {\n __typename\n color\n name\n }\n createdAt\n }\n ... on UnlabeledEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n label {\n __typename\n color\n name\n }\n createdAt\n }\n ... on ClosedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n closer {\n __typename\n ... on Commit {\n oid\n }\n ... on PullRequest {\n mergeCommit {\n __typename\n oid\n }\n }\n }\n }\n ... on ReopenedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n }\n ... on RenamedTitleEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n currentTitle\n }\n ... on LockedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n }\n ... on UnlockedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n }\n ... on MergedEvent {\n ...nodeFields\n mergedCommit: commit {\n __typename\n oid\n }\n actor {\n __typename\n login\n }\n createdAt\n }\n ... on PullRequestReviewThread {\n comments(first: $page_size) {\n __typename\n nodes {\n __typename\n ...reactionFields\n ...nodeFields\n ...commentFields\n path\n diffHunk\n }\n }\n }\n ... on PullRequestReview {\n ...nodeFields\n ...commentFields\n state\n submittedAt\n author {\n __typename\n login\n }\n comments {\n __typename\n totalCount\n }\n }\n ... on CrossReferencedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n source {\n __typename\n ... on Issue {\n title\n number\n closed\n repository {\n __typename\n name\n owner {\n __typename\n login\n }\n }\n }\n ... on PullRequest {\n title\n number\n closed\n merged\n repository {\n __typename\n name\n owner {\n __typename\n login\n }\n }\n }\n }\n }\n ... on ReferencedEvent {\n createdAt\n ...nodeFields\n actor {\n __typename\n login\n }\n commitRepository {\n __typename\n ...referencedRepositoryFields\n }\n subject {\n __typename\n ... on Issue {\n title\n number\n closed\n }\n ... on PullRequest {\n title\n number\n closed\n merged\n }\n }\n }\n ... on RenamedTitleEvent {\n ...nodeFields\n createdAt\n currentTitle\n previousTitle\n actor {\n __typename\n login\n }\n }\n ... on AssignedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n user {\n __typename\n login\n }\n }\n ... on UnassignedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n user {\n __typename\n login\n }\n }\n ... on ReviewRequestedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n requestedReviewer {\n __typename\n ... on Actor {\n login\n }\n }\n }\n ... on ReviewRequestRemovedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n requestedReviewer {\n __typename\n ... on Actor {\n login\n }\n }\n }\n ... on MilestonedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n milestoneTitle\n }\n ... on DemilestonedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n milestoneTitle\n }\n }\n }\n reviewRequests(first: $page_size) {\n __typename\n nodes {\n __typename\n requestedReviewer {\n __typename\n ... on Actor {\n login\n avatarUrl\n }\n }\n }\n }\n commits(last: 1) {\n __typename\n nodes {\n __typename\n commit {\n __typename\n ...commitContext\n }\n }\n }\n milestone {\n __typename\n ...milestoneFields\n }\n ...reactionFields\n ...commentFields\n ...lockableFields\n ...closableFields\n ...labelableFields\n ...updatableFields\n ...nodeFields\n ...assigneeFields\n number\n title\n merged\n baseRefName\n changedFiles\n additions\n deletions\n mergeable\n mergeStateStatus\n }\n }\n }\n}" + "query IssueOrPullRequest($owner: String!, $repo: String!, $number: Int!, $page_size: Int!, $before: String) {\n repository(owner: $owner, name: $repo) {\n __typename\n name\n hasIssuesEnabled\n viewerCanAdminister\n mergeCommitAllowed\n rebaseMergeAllowed\n squashMergeAllowed\n mentionableUsers(first: 50) {\n __typename\n nodes {\n __typename\n avatarUrl\n login\n }\n }\n defaultBranchRef {\n __typename\n name\n }\n issueOrPullRequest(number: $number) {\n __typename\n ... on Issue {\n viewerSubscription\n timeline(last: $page_size, before: $before) {\n __typename\n pageInfo {\n __typename\n ...headPaging\n }\n nodes {\n __typename\n ... on Commit {\n ...nodeFields\n author {\n __typename\n user {\n __typename\n login\n avatarUrl\n }\n }\n oid\n messageHeadline\n }\n ... on IssueComment {\n ...nodeFields\n ...reactionFields\n ...commentFields\n ...updatableFields\n ...deletableFields\n }\n ... on LabeledEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n label {\n __typename\n color\n name\n }\n createdAt\n }\n ... on UnlabeledEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n label {\n __typename\n color\n name\n }\n createdAt\n }\n ... on ClosedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n closer {\n __typename\n ... on Commit {\n oid\n }\n ... on PullRequest {\n mergeCommit {\n __typename\n oid\n }\n }\n }\n }\n ... on ReopenedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n }\n ... on RenamedTitleEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n currentTitle\n }\n ... on LockedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n }\n ... on UnlockedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n }\n ... on CrossReferencedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n source {\n __typename\n ... on Issue {\n title\n number\n closed\n repository {\n __typename\n name\n owner {\n __typename\n login\n }\n }\n }\n ... on PullRequest {\n title\n number\n closed\n merged\n repository {\n __typename\n name\n owner {\n __typename\n login\n }\n }\n }\n }\n }\n ... on ReferencedEvent {\n createdAt\n ...nodeFields\n refCommit: commit {\n __typename\n oid\n }\n actor {\n __typename\n login\n }\n commitRepository {\n __typename\n ...referencedRepositoryFields\n }\n subject {\n __typename\n ... on Issue {\n title\n number\n closed\n }\n ... on PullRequest {\n title\n number\n closed\n merged\n }\n }\n }\n ... on RenamedTitleEvent {\n ...nodeFields\n createdAt\n currentTitle\n previousTitle\n actor {\n __typename\n login\n }\n }\n ... on AssignedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n user {\n __typename\n login\n }\n }\n ... on UnassignedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n user {\n __typename\n login\n }\n }\n ... on MilestonedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n milestoneTitle\n }\n ... on DemilestonedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n milestoneTitle\n }\n }\n }\n milestone {\n __typename\n ...milestoneFields\n }\n ...reactionFields\n ...commentFields\n ...lockableFields\n ...closableFields\n ...labelableFields\n ...updatableFields\n ...nodeFields\n ...assigneeFields\n number\n title\n }\n ... on PullRequest {\n viewerSubscription\n timeline(last: $page_size, before: $before) {\n __typename\n pageInfo {\n __typename\n ...headPaging\n }\n nodes {\n __typename\n ... on Commit {\n ...nodeFields\n author {\n __typename\n user {\n __typename\n login\n avatarUrl\n }\n }\n oid\n messageHeadline\n }\n ... on IssueComment {\n ...nodeFields\n ...reactionFields\n ...commentFields\n ...updatableFields\n ...deletableFields\n }\n ... on LabeledEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n label {\n __typename\n color\n name\n }\n createdAt\n }\n ... on UnlabeledEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n label {\n __typename\n color\n name\n }\n createdAt\n }\n ... on ClosedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n closer {\n __typename\n ... on Commit {\n oid\n }\n ... on PullRequest {\n mergeCommit {\n __typename\n oid\n }\n }\n }\n }\n ... on ReopenedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n }\n ... on RenamedTitleEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n currentTitle\n }\n ... on LockedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n }\n ... on UnlockedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n }\n ... on MergedEvent {\n ...nodeFields\n mergedCommit: commit {\n __typename\n oid\n }\n actor {\n __typename\n login\n }\n createdAt\n }\n ... on PullRequestReviewThread {\n comments(first: $page_size) {\n __typename\n nodes {\n __typename\n ...reactionFields\n ...nodeFields\n ...commentFields\n path\n diffHunk\n }\n }\n }\n ... on PullRequestReview {\n ...nodeFields\n ...commentFields\n state\n submittedAt\n author {\n __typename\n login\n }\n comments {\n __typename\n totalCount\n }\n }\n ... on CrossReferencedEvent {\n ...nodeFields\n actor {\n __typename\n login\n }\n createdAt\n source {\n __typename\n ... on Issue {\n title\n number\n closed\n repository {\n __typename\n name\n owner {\n __typename\n login\n }\n }\n }\n ... on PullRequest {\n title\n number\n closed\n merged\n repository {\n __typename\n name\n owner {\n __typename\n login\n }\n }\n }\n }\n }\n ... on ReferencedEvent {\n createdAt\n ...nodeFields\n actor {\n __typename\n login\n }\n commitRepository {\n __typename\n ...referencedRepositoryFields\n }\n subject {\n __typename\n ... on Issue {\n title\n number\n closed\n }\n ... on PullRequest {\n title\n number\n closed\n merged\n }\n }\n }\n ... on RenamedTitleEvent {\n ...nodeFields\n createdAt\n currentTitle\n previousTitle\n actor {\n __typename\n login\n }\n }\n ... on AssignedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n user {\n __typename\n login\n }\n }\n ... on UnassignedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n user {\n __typename\n login\n }\n }\n ... on ReviewRequestedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n requestedReviewer {\n __typename\n ... on Actor {\n login\n }\n }\n }\n ... on ReviewRequestRemovedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n requestedReviewer {\n __typename\n ... on Actor {\n login\n }\n }\n }\n ... on MilestonedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n milestoneTitle\n }\n ... on DemilestonedEvent {\n ...nodeFields\n createdAt\n actor {\n __typename\n login\n }\n milestoneTitle\n }\n }\n }\n reviewRequests(first: $page_size) {\n __typename\n nodes {\n __typename\n requestedReviewer {\n __typename\n ... on Actor {\n login\n avatarUrl\n }\n }\n }\n }\n commits(last: 1) {\n __typename\n nodes {\n __typename\n commit {\n __typename\n ...commitContext\n }\n }\n }\n milestone {\n __typename\n ...milestoneFields\n }\n ...reactionFields\n ...commentFields\n ...lockableFields\n ...closableFields\n ...labelableFields\n ...updatableFields\n ...nodeFields\n ...assigneeFields\n number\n title\n merged\n baseRefName\n changedFiles\n additions\n deletions\n mergeable\n mergeStateStatus\n }\n }\n }\n}" public static var requestString: String { return operationString.appending(HeadPaging.fragmentString).appending(NodeFields.fragmentString).appending(ReactionFields.fragmentString).appending(CommentFields.fragmentString).appending(UpdatableFields.fragmentString).appending(DeletableFields.fragmentString).appending(ReferencedRepositoryFields.fragmentString).appending(MilestoneFields.fragmentString).appending(LockableFields.fragmentString).appending(ClosableFields.fragmentString).appending(LabelableFields.fragmentString).appending(AssigneeFields.fragmentString).appending(CommitContext.fragmentString) } @@ -1858,8 +1858,8 @@ public final class IssueOrPullRequestQuery: GraphQLQuery { self.snapshot = snapshot } - public static func makeIssue(id: GraphQLID, viewerSubscription: SubscriptionState? = nil, timeline: AsIssue.Timeline, milestone: AsIssue.Milestone? = nil, viewerCanReact: Bool, reactionGroups: [AsIssue.ReactionGroup]? = nil, author: AsIssue.Author? = nil, editor: AsIssue.Editor? = nil, lastEditedAt: String? = nil, body: String, createdAt: String, viewerDidAuthor: Bool, locked: Bool, closed: Bool, labels: AsIssue.Label? = nil, viewerCanUpdate: Bool, assignees: AsIssue.Assignee, number: Int, title: String) -> IssueOrPullRequest { - return IssueOrPullRequest(snapshot: ["__typename": "Issue", "id": id, "viewerSubscription": viewerSubscription, "timeline": timeline.snapshot, "milestone": milestone.flatMap { (value: AsIssue.Milestone) -> Snapshot in value.snapshot }, "viewerCanReact": viewerCanReact, "reactionGroups": reactionGroups.flatMap { (value: [AsIssue.ReactionGroup]) -> [Snapshot] in value.map { (value: AsIssue.ReactionGroup) -> Snapshot in value.snapshot } }, "author": author.flatMap { (value: AsIssue.Author) -> Snapshot in value.snapshot }, "editor": editor.flatMap { (value: AsIssue.Editor) -> Snapshot in value.snapshot }, "lastEditedAt": lastEditedAt, "body": body, "createdAt": createdAt, "viewerDidAuthor": viewerDidAuthor, "locked": locked, "closed": closed, "labels": labels.flatMap { (value: AsIssue.Label) -> Snapshot in value.snapshot }, "viewerCanUpdate": viewerCanUpdate, "assignees": assignees.snapshot, "number": number, "title": title]) + public static func makeIssue(viewerSubscription: SubscriptionState? = nil, timeline: AsIssue.Timeline, milestone: AsIssue.Milestone? = nil, viewerCanReact: Bool, reactionGroups: [AsIssue.ReactionGroup]? = nil, author: AsIssue.Author? = nil, editor: AsIssue.Editor? = nil, lastEditedAt: String? = nil, body: String, createdAt: String, viewerDidAuthor: Bool, locked: Bool, closed: Bool, labels: AsIssue.Label? = nil, viewerCanUpdate: Bool, id: GraphQLID, assignees: AsIssue.Assignee, number: Int, title: String) -> IssueOrPullRequest { + return IssueOrPullRequest(snapshot: ["__typename": "Issue", "viewerSubscription": viewerSubscription, "timeline": timeline.snapshot, "milestone": milestone.flatMap { (value: AsIssue.Milestone) -> Snapshot in value.snapshot }, "viewerCanReact": viewerCanReact, "reactionGroups": reactionGroups.flatMap { (value: [AsIssue.ReactionGroup]) -> [Snapshot] in value.map { (value: AsIssue.ReactionGroup) -> Snapshot in value.snapshot } }, "author": author.flatMap { (value: AsIssue.Author) -> Snapshot in value.snapshot }, "editor": editor.flatMap { (value: AsIssue.Editor) -> Snapshot in value.snapshot }, "lastEditedAt": lastEditedAt, "body": body, "createdAt": createdAt, "viewerDidAuthor": viewerDidAuthor, "locked": locked, "closed": closed, "labels": labels.flatMap { (value: AsIssue.Label) -> Snapshot in value.snapshot }, "viewerCanUpdate": viewerCanUpdate, "id": id, "assignees": assignees.snapshot, "number": number, "title": title]) } public static func makePullRequest(viewerSubscription: SubscriptionState? = nil, timeline: AsPullRequest.Timeline, reviewRequests: AsPullRequest.ReviewRequest? = nil, commits: AsPullRequest.Commit, milestone: AsPullRequest.Milestone? = nil, viewerCanReact: Bool, reactionGroups: [AsPullRequest.ReactionGroup]? = nil, author: AsPullRequest.Author? = nil, editor: AsPullRequest.Editor? = nil, lastEditedAt: String? = nil, body: String, createdAt: String, viewerDidAuthor: Bool, locked: Bool, closed: Bool, labels: AsPullRequest.Label? = nil, viewerCanUpdate: Bool, id: GraphQLID, assignees: AsPullRequest.Assignee, number: Int, title: String, merged: Bool, baseRefName: String, changedFiles: Int, additions: Int, deletions: Int, mergeable: MergeableState, mergeStateStatus: MergeStateStatus) -> IssueOrPullRequest { @@ -1891,7 +1891,6 @@ public final class IssueOrPullRequestQuery: GraphQLQuery { public static let selections: [GraphQLSelection] = [ GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("id", type: .nonNull(.scalar(GraphQLID.self))), GraphQLField("viewerSubscription", type: .scalar(SubscriptionState.self)), GraphQLField("timeline", arguments: ["last": GraphQLVariable("page_size"), "before": GraphQLVariable("before")], type: .nonNull(.object(Timeline.selections))), GraphQLField("milestone", type: .object(Milestone.selections)), @@ -1927,8 +1926,8 @@ public final class IssueOrPullRequestQuery: GraphQLQuery { self.snapshot = snapshot } - public init(id: GraphQLID, viewerSubscription: SubscriptionState? = nil, timeline: Timeline, milestone: Milestone? = nil, viewerCanReact: Bool, reactionGroups: [ReactionGroup]? = nil, author: Author? = nil, editor: Editor? = nil, lastEditedAt: String? = nil, body: String, createdAt: String, viewerDidAuthor: Bool, locked: Bool, closed: Bool, labels: Label? = nil, viewerCanUpdate: Bool, assignees: Assignee, number: Int, title: String) { - self.init(snapshot: ["__typename": "Issue", "id": id, "viewerSubscription": viewerSubscription, "timeline": timeline.snapshot, "milestone": milestone.flatMap { (value: Milestone) -> Snapshot in value.snapshot }, "viewerCanReact": viewerCanReact, "reactionGroups": reactionGroups.flatMap { (value: [ReactionGroup]) -> [Snapshot] in value.map { (value: ReactionGroup) -> Snapshot in value.snapshot } }, "author": author.flatMap { (value: Author) -> Snapshot in value.snapshot }, "editor": editor.flatMap { (value: Editor) -> Snapshot in value.snapshot }, "lastEditedAt": lastEditedAt, "body": body, "createdAt": createdAt, "viewerDidAuthor": viewerDidAuthor, "locked": locked, "closed": closed, "labels": labels.flatMap { (value: Label) -> Snapshot in value.snapshot }, "viewerCanUpdate": viewerCanUpdate, "assignees": assignees.snapshot, "number": number, "title": title]) + public init(viewerSubscription: SubscriptionState? = nil, timeline: Timeline, milestone: Milestone? = nil, viewerCanReact: Bool, reactionGroups: [ReactionGroup]? = nil, author: Author? = nil, editor: Editor? = nil, lastEditedAt: String? = nil, body: String, createdAt: String, viewerDidAuthor: Bool, locked: Bool, closed: Bool, labels: Label? = nil, viewerCanUpdate: Bool, id: GraphQLID, assignees: Assignee, number: Int, title: String) { + self.init(snapshot: ["__typename": "Issue", "viewerSubscription": viewerSubscription, "timeline": timeline.snapshot, "milestone": milestone.flatMap { (value: Milestone) -> Snapshot in value.snapshot }, "viewerCanReact": viewerCanReact, "reactionGroups": reactionGroups.flatMap { (value: [ReactionGroup]) -> [Snapshot] in value.map { (value: ReactionGroup) -> Snapshot in value.snapshot } }, "author": author.flatMap { (value: Author) -> Snapshot in value.snapshot }, "editor": editor.flatMap { (value: Editor) -> Snapshot in value.snapshot }, "lastEditedAt": lastEditedAt, "body": body, "createdAt": createdAt, "viewerDidAuthor": viewerDidAuthor, "locked": locked, "closed": closed, "labels": labels.flatMap { (value: Label) -> Snapshot in value.snapshot }, "viewerCanUpdate": viewerCanUpdate, "id": id, "assignees": assignees.snapshot, "number": number, "title": title]) } public var __typename: String { @@ -1940,15 +1939,6 @@ public final class IssueOrPullRequestQuery: GraphQLQuery { } } - public var id: GraphQLID { - get { - return snapshot["id"]! as! GraphQLID - } - set { - snapshot.updateValue(newValue, forKey: "id") - } - } - /// Identifies if the viewer is watching, not watching, or ignoring the subscribable entity. public var viewerSubscription: SubscriptionState? { get { @@ -2099,6 +2089,16 @@ public final class IssueOrPullRequestQuery: GraphQLQuery { } } + /// ID of the object. + public var id: GraphQLID { + get { + return snapshot["id"]! as! GraphQLID + } + set { + snapshot.updateValue(newValue, forKey: "id") + } + } + /// A list of Users assigned to this object. public var assignees: Assignee { get { @@ -16858,6 +16858,267 @@ public final class SearchReposQuery: GraphQLQuery { } } +public final class UpdateSubscriptionMutation: GraphQLMutation { + public static let operationString = + "mutation UpdateSubscription($subscribable_Id: ID!, $subscription_state: SubscriptionState!) {\n updateSubscription(input: {subscribableId: $subscribable_Id, state: $subscription_state}) {\n __typename\n subscribable {\n __typename\n ...subscribableFields\n }\n }\n}" + + public static var requestString: String { return operationString.appending(SubscribableFields.fragmentString) } + + public var subscribable_Id: GraphQLID + public var subscription_state: SubscriptionState + + public init(subscribable_Id: GraphQLID, subscription_state: SubscriptionState) { + self.subscribable_Id = subscribable_Id + self.subscription_state = subscription_state + } + + public var variables: GraphQLMap? { + return ["subscribable_Id": subscribable_Id, "subscription_state": subscription_state] + } + + public struct Data: GraphQLSelectionSet { + public static let possibleTypes = ["Mutation"] + + public static let selections: [GraphQLSelection] = [ + GraphQLField("updateSubscription", arguments: ["input": ["subscribableId": GraphQLVariable("subscribable_Id"), "state": GraphQLVariable("subscription_state")]], type: .object(UpdateSubscription.selections)), + ] + + public var snapshot: Snapshot + + public init(snapshot: Snapshot) { + self.snapshot = snapshot + } + + public init(updateSubscription: UpdateSubscription? = nil) { + self.init(snapshot: ["__typename": "Mutation", "updateSubscription": updateSubscription.flatMap { (value: UpdateSubscription) -> Snapshot in value.snapshot }]) + } + + /// Updates the state for subscribable subjects. + public var updateSubscription: UpdateSubscription? { + get { + return (snapshot["updateSubscription"] as? Snapshot).flatMap { UpdateSubscription(snapshot: $0) } + } + set { + snapshot.updateValue(newValue?.snapshot, forKey: "updateSubscription") + } + } + + public struct UpdateSubscription: GraphQLSelectionSet { + public static let possibleTypes = ["UpdateSubscriptionPayload"] + + public static let selections: [GraphQLSelection] = [ + GraphQLField("__typename", type: .nonNull(.scalar(String.self))), + GraphQLField("subscribable", type: .nonNull(.object(Subscribable.selections))), + ] + + public var snapshot: Snapshot + + public init(snapshot: Snapshot) { + self.snapshot = snapshot + } + + public init(subscribable: Subscribable) { + self.init(snapshot: ["__typename": "UpdateSubscriptionPayload", "subscribable": subscribable.snapshot]) + } + + public var __typename: String { + get { + return snapshot["__typename"]! as! String + } + set { + snapshot.updateValue(newValue, forKey: "__typename") + } + } + + /// The input subscribable entity. + public var subscribable: Subscribable { + get { + return Subscribable(snapshot: snapshot["subscribable"]! as! Snapshot) + } + set { + snapshot.updateValue(newValue.snapshot, forKey: "subscribable") + } + } + + public struct Subscribable: GraphQLSelectionSet { + public static let possibleTypes = ["Issue", "Repository", "Commit", "PullRequest", "Team"] + + public static let selections: [GraphQLSelection] = [ + GraphQLField("__typename", type: .nonNull(.scalar(String.self))), + GraphQLField("__typename", type: .nonNull(.scalar(String.self))), + GraphQLField("id", type: .nonNull(.scalar(GraphQLID.self))), + GraphQLField("viewerCanSubscribe", type: .nonNull(.scalar(Bool.self))), + GraphQLField("viewerSubscription", type: .scalar(SubscriptionState.self)), + ] + + public var snapshot: Snapshot + + public init(snapshot: Snapshot) { + self.snapshot = snapshot + } + + public static func makeIssue(id: GraphQLID, viewerCanSubscribe: Bool, viewerSubscription: SubscriptionState? = nil) -> Subscribable { + return Subscribable(snapshot: ["__typename": "Issue", "id": id, "viewerCanSubscribe": viewerCanSubscribe, "viewerSubscription": viewerSubscription]) + } + + public static func makeRepository(id: GraphQLID, viewerCanSubscribe: Bool, viewerSubscription: SubscriptionState? = nil) -> Subscribable { + return Subscribable(snapshot: ["__typename": "Repository", "id": id, "viewerCanSubscribe": viewerCanSubscribe, "viewerSubscription": viewerSubscription]) + } + + public static func makeCommit(id: GraphQLID, viewerCanSubscribe: Bool, viewerSubscription: SubscriptionState? = nil) -> Subscribable { + return Subscribable(snapshot: ["__typename": "Commit", "id": id, "viewerCanSubscribe": viewerCanSubscribe, "viewerSubscription": viewerSubscription]) + } + + public static func makePullRequest(id: GraphQLID, viewerCanSubscribe: Bool, viewerSubscription: SubscriptionState? = nil) -> Subscribable { + return Subscribable(snapshot: ["__typename": "PullRequest", "id": id, "viewerCanSubscribe": viewerCanSubscribe, "viewerSubscription": viewerSubscription]) + } + + public static func makeTeam(id: GraphQLID, viewerCanSubscribe: Bool, viewerSubscription: SubscriptionState? = nil) -> Subscribable { + return Subscribable(snapshot: ["__typename": "Team", "id": id, "viewerCanSubscribe": viewerCanSubscribe, "viewerSubscription": viewerSubscription]) + } + + public var __typename: String { + get { + return snapshot["__typename"]! as! String + } + set { + snapshot.updateValue(newValue, forKey: "__typename") + } + } + + public var id: GraphQLID { + get { + return snapshot["id"]! as! GraphQLID + } + set { + snapshot.updateValue(newValue, forKey: "id") + } + } + + /// Check if the viewer is able to change their subscription status for the repository. + public var viewerCanSubscribe: Bool { + get { + return snapshot["viewerCanSubscribe"]! as! Bool + } + set { + snapshot.updateValue(newValue, forKey: "viewerCanSubscribe") + } + } + + /// Identifies if the viewer is watching, not watching, or ignoring the subscribable entity. + public var viewerSubscription: SubscriptionState? { + get { + return snapshot["viewerSubscription"] as? SubscriptionState + } + set { + snapshot.updateValue(newValue, forKey: "viewerSubscription") + } + } + + public var fragments: Fragments { + get { + return Fragments(snapshot: snapshot) + } + set { + snapshot += newValue.snapshot + } + } + + public struct Fragments { + public var snapshot: Snapshot + + public var subscribableFields: SubscribableFields { + get { + return SubscribableFields(snapshot: snapshot) + } + set { + snapshot += newValue.snapshot + } + } + } + } + } + } +} + +public struct SubscribableFields: GraphQLFragment { + public static let fragmentString = + "fragment subscribableFields on Subscribable {\n __typename\n id\n viewerCanSubscribe\n viewerSubscription\n}" + + public static let possibleTypes = ["Issue", "Repository", "Commit", "PullRequest", "Team"] + + public static let selections: [GraphQLSelection] = [ + GraphQLField("__typename", type: .nonNull(.scalar(String.self))), + GraphQLField("id", type: .nonNull(.scalar(GraphQLID.self))), + GraphQLField("viewerCanSubscribe", type: .nonNull(.scalar(Bool.self))), + GraphQLField("viewerSubscription", type: .scalar(SubscriptionState.self)), + ] + + public var snapshot: Snapshot + + public init(snapshot: Snapshot) { + self.snapshot = snapshot + } + + public static func makeIssue(id: GraphQLID, viewerCanSubscribe: Bool, viewerSubscription: SubscriptionState? = nil) -> SubscribableFields { + return SubscribableFields(snapshot: ["__typename": "Issue", "id": id, "viewerCanSubscribe": viewerCanSubscribe, "viewerSubscription": viewerSubscription]) + } + + public static func makeRepository(id: GraphQLID, viewerCanSubscribe: Bool, viewerSubscription: SubscriptionState? = nil) -> SubscribableFields { + return SubscribableFields(snapshot: ["__typename": "Repository", "id": id, "viewerCanSubscribe": viewerCanSubscribe, "viewerSubscription": viewerSubscription]) + } + + public static func makeCommit(id: GraphQLID, viewerCanSubscribe: Bool, viewerSubscription: SubscriptionState? = nil) -> SubscribableFields { + return SubscribableFields(snapshot: ["__typename": "Commit", "id": id, "viewerCanSubscribe": viewerCanSubscribe, "viewerSubscription": viewerSubscription]) + } + + public static func makePullRequest(id: GraphQLID, viewerCanSubscribe: Bool, viewerSubscription: SubscriptionState? = nil) -> SubscribableFields { + return SubscribableFields(snapshot: ["__typename": "PullRequest", "id": id, "viewerCanSubscribe": viewerCanSubscribe, "viewerSubscription": viewerSubscription]) + } + + public static func makeTeam(id: GraphQLID, viewerCanSubscribe: Bool, viewerSubscription: SubscriptionState? = nil) -> SubscribableFields { + return SubscribableFields(snapshot: ["__typename": "Team", "id": id, "viewerCanSubscribe": viewerCanSubscribe, "viewerSubscription": viewerSubscription]) + } + + public var __typename: String { + get { + return snapshot["__typename"]! as! String + } + set { + snapshot.updateValue(newValue, forKey: "__typename") + } + } + + public var id: GraphQLID { + get { + return snapshot["id"]! as! GraphQLID + } + set { + snapshot.updateValue(newValue, forKey: "id") + } + } + + /// Check if the viewer is able to change their subscription status for the repository. + public var viewerCanSubscribe: Bool { + get { + return snapshot["viewerCanSubscribe"]! as! Bool + } + set { + snapshot.updateValue(newValue, forKey: "viewerCanSubscribe") + } + } + + /// Identifies if the viewer is watching, not watching, or ignoring the subscribable entity. + public var viewerSubscription: SubscriptionState? { + get { + return snapshot["viewerSubscription"] as? SubscriptionState + } + set { + snapshot.updateValue(newValue, forKey: "viewerSubscription") + } + } +} + public struct ReactionFields: GraphQLFragment { public static let fragmentString = "fragment reactionFields on Reactable {\n __typename\n viewerCanReact\n reactionGroups {\n __typename\n viewerHasReacted\n users(first: 3) {\n __typename\n nodes {\n __typename\n login\n }\n totalCount\n }\n content\n }\n}" diff --git a/gql/Fragments.graphql b/gql/Fragments.graphql index 5e90f9b67..bd67a8168 100644 --- a/gql/Fragments.graphql +++ b/gql/Fragments.graphql @@ -1,3 +1,9 @@ +fragment subscribableFields on Subscribable { + id + viewerCanSubscribe + viewerSubscription +} + fragment reactionFields on Reactable { viewerCanReact reactionGroups { diff --git a/gql/UpdateSubscription.graphql b/gql/UpdateSubscription.graphql new file mode 100644 index 000000000..aaa45a139 --- /dev/null +++ b/gql/UpdateSubscription.graphql @@ -0,0 +1,7 @@ +mutation UpdateSubscription($subscribable_Id: ID!, $subscription_state: SubscriptionState!) { + updateSubscription(input:{subscribableId: $subscribable_Id, state: $subscription_state}) { + subscribable{ + ...subscribableFields + } + } +} From bbda2d3f57749b2365d1c2700cfc78bfa384d13d Mon Sep 17 00:00:00 2001 From: Ehud Adler Date: Thu, 29 Nov 2018 23:58:45 -0500 Subject: [PATCH 3/6] Fixed mutation --- Classes/Issues/GithubClient+Issues.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/Issues/GithubClient+Issues.swift b/Classes/Issues/GithubClient+Issues.swift index e3383fa11..a9e2a4413 100644 --- a/Classes/Issues/GithubClient+Issues.swift +++ b/Classes/Issues/GithubClient+Issues.swift @@ -311,7 +311,7 @@ extension GithubClient { let mutation = UpdateSubscriptionMutation(subscribable_Id: subscriptionId, subscription_state: state) client.mutate(mutation, result: { data in - print(data.updateSubscription?.subscribable) // Returns nil + data.updateSubscription?.subscribable }, completion: { result in switch result { case .success(_): From 5f1f3790dff3255bb4dada1fdccfe05b22b9b338 Mon Sep 17 00:00:00 2001 From: Ehud Adler Date: Fri, 30 Nov 2018 00:52:12 -0500 Subject: [PATCH 4/6] Fixed code logic --- Classes/Issues/GithubClient+Issues.swift | 28 +++++++++++-------- Classes/Issues/Issue+IssueType.swift | 4 +-- .../IssueManagingContextController.swift | 6 ++-- Classes/Issues/IssueResult.swift | 18 ++++++------ Classes/Issues/IssueType.swift | 3 +- Classes/Issues/PullRequest+IssueType.swift | 4 +-- 6 files changed, 34 insertions(+), 29 deletions(-) diff --git a/Classes/Issues/GithubClient+Issues.swift b/Classes/Issues/GithubClient+Issues.swift index a9e2a4413..54c4a0d66 100644 --- a/Classes/Issues/GithubClient+Issues.swift +++ b/Classes/Issues/GithubClient+Issues.swift @@ -163,13 +163,13 @@ extension GithubClient { milestone: milestoneModel, targetBranch: targetBranchModel, timelinePages: [newPage] + (prependResult?.timelinePages ?? []), - viewerIsSubscribed: issueType.viewerSubscribed, viewerCanUpdate: issueType.viewerCanUpdate, hasIssuesEnabled: repository.hasIssuesEnabled, viewerCanAdminister: canAdmin, defaultBranch: repository.defaultBranchRef?.name ?? "master", fileChanges: issueType.fileChanges, - mergeModel: issueType.mergeModel(availableTypes: availableMergeTypes) + mergeModel: issueType.mergeModel(availableTypes: availableMergeTypes), + subscriptionState: issueType.subscriptionState ) DispatchQueue.main.async { @@ -299,25 +299,31 @@ extension GithubClient { } func setSubscription( - subscriptionId: String, - subscribed: Bool, - completion: @escaping (Bool) -> Void + previous: IssueResult, + subscribe: Bool, + completion: ((Result) -> Void)? = nil ) { - let state: SubscriptionState = subscribed + let state: SubscriptionState = subscribe ? .subscribed - : .unsubscribed + : .ignored + + let optimisticResult = previous.updated(subscriptionState: state) - let mutation = UpdateSubscriptionMutation(subscribable_Id: subscriptionId, subscription_state: state) + let cache = self.cache + cache.set(value: optimisticResult) + + let mutation = UpdateSubscriptionMutation(subscribable_Id: previous.id, subscription_state: state) client.mutate(mutation, result: { data in data.updateSubscription?.subscribable }, completion: { result in switch result { - case .success(_): - completion(true) + case .success(let subscribable): + completion?(.success(subscribable.viewerSubscription)) case .failure(let error): - completion(false) + cache.set(value: previous) + completion?(.error(error)) Squawk.show(error: error) } }) diff --git a/Classes/Issues/Issue+IssueType.swift b/Classes/Issues/Issue+IssueType.swift index 9502a014a..3e3cc90bd 100644 --- a/Classes/Issues/Issue+IssueType.swift +++ b/Classes/Issues/Issue+IssueType.swift @@ -11,8 +11,8 @@ import IGListKit extension IssueOrPullRequestQuery.Data.Repository.IssueOrPullRequest.AsIssue: IssueType { - var viewerSubscribed: Bool { - return viewerSubscription?.rawValue != "IGNORED" + var subscriptionState: SubscriptionState { + return viewerSubscription ?? .ignored } var pullRequest: Bool { diff --git a/Classes/Issues/IssueManagingContextController.swift b/Classes/Issues/IssueManagingContextController.swift index f1c805270..73a2d1122 100644 --- a/Classes/Issues/IssueManagingContextController.swift +++ b/Classes/Issues/IssueManagingContextController.swift @@ -101,7 +101,7 @@ final class IssueManagingContextController: NSObject, ContextMenuDelegate { } } - if result.viewerIsSubscribed { + if result.subscriptionState == .subscribed { actions.append(.unsubscribe) } else { actions.append(.subscribe) @@ -293,9 +293,7 @@ final class IssueManagingContextController: NSObject, ContextMenuDelegate { func subscribe(_ doSubscribe: Bool) { guard let previous = result else { return } delegate?.willMutateModel(from: self) - client.setSubscription(subscriptionId: previous.id, subscribed: doSubscribe) { (result) in - print(result) - } + client.setSubscription(previous: previous, subscribe: doSubscribe) Haptic.triggerNotification(.success) } func close(_ doClose: Bool) { diff --git a/Classes/Issues/IssueResult.swift b/Classes/Issues/IssueResult.swift index ff161dc0a..dbf5c469a 100644 --- a/Classes/Issues/IssueResult.swift +++ b/Classes/Issues/IssueResult.swift @@ -25,13 +25,13 @@ struct IssueResult: Cachable { let targetBranch: IssueTargetBranchModel? // end optionals let timelinePages: [IssueTimelinePage] - let viewerIsSubscribed: Bool let viewerCanUpdate: Bool let hasIssuesEnabled: Bool let viewerCanAdminister: Bool let defaultBranch: String let fileChanges: FileChanges? let mergeModel: IssueMergeModel? + let subscriptionState: SubscriptionState var timelineViewModels: [ListDiffable] { return timelinePages.reduce([], { $0 + $1.viewModels }) @@ -74,12 +74,12 @@ struct IssueResult: Cachable { labels: IssueLabelsModel? = nil, assignee: IssueAssigneesModel? = nil, timelinePages: [IssueTimelinePage]? = nil, - viewerIsSubscribed: Bool? = nil, viewerCanUpdate: Bool? = nil, hasIssuesEnabled: Bool? = nil, viewerCanAdminister: Bool? = nil, defaultBranch: String? = nil, - mergeModel: IssueMergeModel? = nil + mergeModel: IssueMergeModel? = nil, + subscriptionState: SubscriptionState? = nil ) -> IssueResult { return IssueResult( id: id ?? self.id, @@ -92,13 +92,13 @@ struct IssueResult: Cachable { milestone: self.milestone, targetBranch: self.targetBranch, timelinePages: timelinePages ?? self.timelinePages, - viewerIsSubscribed: viewerIsSubscribed ?? self.viewerIsSubscribed, viewerCanUpdate: viewerCanUpdate ?? self.viewerCanUpdate, hasIssuesEnabled: hasIssuesEnabled ?? self.hasIssuesEnabled, viewerCanAdminister: viewerCanAdminister ?? self.viewerCanAdminister, defaultBranch: defaultBranch ?? self.defaultBranch, fileChanges: fileChanges, - mergeModel: mergeModel ?? self.mergeModel + mergeModel: mergeModel ?? self.mergeModel, + subscriptionState: subscriptionState ?? self.subscriptionState ) } @@ -117,13 +117,13 @@ struct IssueResult: Cachable { milestone: milestone, targetBranch: self.targetBranch, timelinePages: timelinePages ?? self.timelinePages, - viewerIsSubscribed: self.viewerIsSubscribed, viewerCanUpdate: self.viewerCanUpdate, hasIssuesEnabled: self.hasIssuesEnabled, viewerCanAdminister: self.viewerCanAdminister, defaultBranch: self.defaultBranch, fileChanges: self.fileChanges, - mergeModel: self.mergeModel + mergeModel: self.mergeModel, + subscriptionState: self.subscriptionState ) } @@ -142,13 +142,13 @@ struct IssueResult: Cachable { milestone: self.milestone, targetBranch: self.targetBranch, timelinePages: timelinePages ?? self.timelinePages, - viewerIsSubscribed: self.viewerIsSubscribed, viewerCanUpdate: self.viewerCanUpdate, hasIssuesEnabled: self.hasIssuesEnabled, viewerCanAdminister: self.viewerCanAdminister, defaultBranch: self.defaultBranch, fileChanges: self.fileChanges, - mergeModel: self.mergeModel + mergeModel: self.mergeModel, + subscriptionState: self.subscriptionState ) } diff --git a/Classes/Issues/IssueType.swift b/Classes/Issues/IssueType.swift index d43c29d55..1265ff639 100644 --- a/Classes/Issues/IssueType.swift +++ b/Classes/Issues/IssueType.swift @@ -32,9 +32,10 @@ protocol IssueType { var targetBranch: String? { get } var locked: Bool { get } var headPaging: HeadPaging { get } - var viewerSubscribed: Bool { get } var viewerCanUpdate: Bool { get } var fileChanges: FileChanges? { get } + var subscriptionState: SubscriptionState { get } + var reviewRequestModel: IssueAssigneesModel? { get } func mergeModel(availableTypes: [IssueMergeType]) -> IssueMergeModel? diff --git a/Classes/Issues/PullRequest+IssueType.swift b/Classes/Issues/PullRequest+IssueType.swift index 0be2eb20d..6b8e6c0b6 100644 --- a/Classes/Issues/PullRequest+IssueType.swift +++ b/Classes/Issues/PullRequest+IssueType.swift @@ -12,8 +12,8 @@ import StyledTextKit extension IssueOrPullRequestQuery.Data.Repository.IssueOrPullRequest.AsPullRequest: IssueType { - var viewerSubscribed: Bool { - return viewerSubscription?.rawValue != "IGNORED" + var subscriptionState: SubscriptionState { + return viewerSubscription ?? .ignored } var pullRequest: Bool { From 9124e6d76a768f67611433b183f39750028cc691 Mon Sep 17 00:00:00 2001 From: Ehud Adler Date: Fri, 30 Nov 2018 14:25:02 -0500 Subject: [PATCH 5/6] Fixed test --- FreetimeTests/SplitViewTests.swift | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/FreetimeTests/SplitViewTests.swift b/FreetimeTests/SplitViewTests.swift index dcc9e697b..4b2dfda51 100644 --- a/FreetimeTests/SplitViewTests.swift +++ b/FreetimeTests/SplitViewTests.swift @@ -114,9 +114,7 @@ class SplitViewTests: XCTestCase { client: GithubClient(userSession: nil), repo: RepositoryDetails( owner: "Foo", - name: "Bar", - defaultBranch: "Baz", - hasIssuesEnabled: false + name: "Bar" )) let detail2 = IssuesViewController( From 7cbe77a05cf735a71b9a1574645b36f4857cfcd6 Mon Sep 17 00:00:00 2001 From: Ehud Adler Date: Fri, 30 Nov 2018 14:25:22 -0500 Subject: [PATCH 6/6] Switched ignored to unsubscribed --- Classes/Issues/GithubClient+Issues.swift | 2 +- Classes/Issues/Issue+IssueType.swift | 2 +- Classes/Issues/PullRequest+IssueType.swift | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Classes/Issues/GithubClient+Issues.swift b/Classes/Issues/GithubClient+Issues.swift index 54c4a0d66..b06f89e7d 100644 --- a/Classes/Issues/GithubClient+Issues.swift +++ b/Classes/Issues/GithubClient+Issues.swift @@ -306,7 +306,7 @@ extension GithubClient { let state: SubscriptionState = subscribe ? .subscribed - : .ignored + : .unsubscribed let optimisticResult = previous.updated(subscriptionState: state) diff --git a/Classes/Issues/Issue+IssueType.swift b/Classes/Issues/Issue+IssueType.swift index 3e3cc90bd..3fe3f4ce6 100644 --- a/Classes/Issues/Issue+IssueType.swift +++ b/Classes/Issues/Issue+IssueType.swift @@ -12,7 +12,7 @@ import IGListKit extension IssueOrPullRequestQuery.Data.Repository.IssueOrPullRequest.AsIssue: IssueType { var subscriptionState: SubscriptionState { - return viewerSubscription ?? .ignored + return viewerSubscription ?? .unsubscribed } var pullRequest: Bool { diff --git a/Classes/Issues/PullRequest+IssueType.swift b/Classes/Issues/PullRequest+IssueType.swift index 6b8e6c0b6..319310ed6 100644 --- a/Classes/Issues/PullRequest+IssueType.swift +++ b/Classes/Issues/PullRequest+IssueType.swift @@ -13,7 +13,7 @@ import StyledTextKit extension IssueOrPullRequestQuery.Data.Repository.IssueOrPullRequest.AsPullRequest: IssueType { var subscriptionState: SubscriptionState { - return viewerSubscription ?? .ignored + return viewerSubscription ?? .unsubscribed } var pullRequest: Bool {