diff --git a/Classes/Labels/GitHubClient+RepositoryLabels.swift b/Classes/Labels/GitHubClient+RepositoryLabels.swift new file mode 100644 index 000000000..3f8176a82 --- /dev/null +++ b/Classes/Labels/GitHubClient+RepositoryLabels.swift @@ -0,0 +1,62 @@ +// +// GitHubClient+Labels.swift +// Freetime +// +// Created by Quentin Dreyer on 05/03/2020. +// Copyright © 2020 Ryan Nystrom. All rights reserved. +// + +import GitHubAPI +import Apollo + +private extension FetchRepositoryLabelsQuery.Data { + + func labels() -> [String] { + var labels: [String] = [] + repository?.labels.map { nodes in + nodes.nodes.map { node in + labels += node.compactMap { + $0?.node?.name, + $0?.node?.color + } + } + } + return labels + } + + func nextPageToken() -> String? { + guard repository?.refs?.pageInfo.hasNextPage == true else { return nil } + return repository?.refs?.pageInfo.endCursor + } + +} + +extension GithubClient { + + struct RepositoryLabelsPayload { + let labels: [String] + let nextPage: String? + } + + func fetchRepositoryLabels(owner: String, + repo: String, + nextPage: String?, + completion: @escaping (Result) -> Void + ) { + let query = FetchRepositoryLabelsQuery(owner: owner, name: repo, after: nextPage) + client.query(query, result: { $0 }, completion: { result in + + switch result { + case .failure(let error): + completion(.error(error)) + + case .success(let data): + let payload = RepositoryLabelsPayload( + labels: data.labels(), + nextPage: data.nextPageToken() + ) + completion(.success(payload)) + } + }) + } +} diff --git a/Classes/Labels/LabelsViewController.swift b/Classes/Labels/LabelsViewController.swift index 502b75cba..d2b43c1bc 100644 --- a/Classes/Labels/LabelsViewController.swift +++ b/Classes/Labels/LabelsViewController.swift @@ -16,8 +16,9 @@ LabelSectionControllerDelegate { private let selectedLabels: Set private var labels = [RepositoryLabel]() + private let owner: String + private let repo: String private let client: GithubClient - private let request: RepositoryLabelsQuery init( selected: [RepositoryLabel], @@ -27,7 +28,8 @@ LabelSectionControllerDelegate { ) { self.selectedLabels = Set(selected) self.client = client - self.request = RepositoryLabelsQuery(owner: owner, repo: repo) + self.owner = owner + self.repo = repo super.init(emptyErrorMessage: NSLocalizedString("No labels found", comment: "")) preferredContentSize = Styles.Sizes.contextMenuSize title = Constants.Strings.labels @@ -87,20 +89,23 @@ LabelSectionControllerDelegate { // MARK: Overrides override func fetch(page: String?) { - client.client.query(request, result: { data in - data.repository?.labels?.nodes - }, completion: { [weak self] result in + client.fetchRepositoryLabels( + owner: owner, + repo: repo, + nextPage: page as String? + ) { [weak self] result in + guard let strongSelf = self else { return } switch result { - case .success(let nodes): - self?.labels = nodes.compactMap { + case .success(let payload): + self?.labels = payload.labels.compactMap { guard let node = $0 else { return nil } return RepositoryLabel(color: node.color, name: node.name) }.sorted { $0.name < $1.name } - self?.update(animated: true) - case .failure(let error): + strongSelf.update(animated: true) + case .error(let error): Squawk.show(error: error) } - }) + } } // MARK: BaseListViewControllerDataSource diff --git a/Freetime.xcodeproj/project.pbxproj b/Freetime.xcodeproj/project.pbxproj index 1f6f303db..0d0c23a4b 100644 --- a/Freetime.xcodeproj/project.pbxproj +++ b/Freetime.xcodeproj/project.pbxproj @@ -459,6 +459,7 @@ 29FE635F21AE2E2F00A07A86 /* RepositoryLoadingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29FE635E21AE2E2F00A07A86 /* RepositoryLoadingViewController.swift */; }; 29FE636121AE2E7900A07A86 /* RepositoryErrorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29FE636021AE2E7900A07A86 /* RepositoryErrorViewController.swift */; }; 29FF85A51EE1EA7A007B8762 /* ReactionContent+ReactionType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29FF85A41EE1EA7A007B8762 /* ReactionContent+ReactionType.swift */; }; + 2CDD97C22411B61C0016D5CF /* GitHubClient+RepositoryLabels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CDD97C12411B61C0016D5CF /* GitHubClient+RepositoryLabels.swift */; }; 3E79A2FF1F8A7DA700E1126B /* ShortcutHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E79A2FE1F8A7DA700E1126B /* ShortcutHandler.swift */; }; 4920F1A81F72E27200131E9D /* UIViewController+UserActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4920F1A71F72E27200131E9D /* UIViewController+UserActivity.swift */; }; 49AF91B1204B416500DFF325 /* MergeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49AF91B0204B416500DFF325 /* MergeTests.swift */; }; @@ -1060,6 +1061,7 @@ 29FE635E21AE2E2F00A07A86 /* RepositoryLoadingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepositoryLoadingViewController.swift; sourceTree = ""; }; 29FE636021AE2E7900A07A86 /* RepositoryErrorViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepositoryErrorViewController.swift; sourceTree = ""; }; 29FF85A41EE1EA7A007B8762 /* ReactionContent+ReactionType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ReactionContent+ReactionType.swift"; sourceTree = ""; }; + 2CDD97C12411B61C0016D5CF /* GitHubClient+RepositoryLabels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GitHubClient+RepositoryLabels.swift"; sourceTree = ""; }; 36115D494E8C3B4F39AC8CD9 /* Pods-Freetime.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Freetime.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Freetime/Pods-Freetime.debug.xcconfig"; sourceTree = ""; }; 3E106824819769E0A6665A79 /* Pods-FreetimeWatch.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FreetimeWatch.release.xcconfig"; path = "Pods/Target Support Files/Pods-FreetimeWatch/Pods-FreetimeWatch.release.xcconfig"; sourceTree = ""; }; 3E79A2FE1F8A7DA700E1126B /* ShortcutHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShortcutHandler.swift; sourceTree = ""; }; @@ -2154,6 +2156,7 @@ 2924C18A20D5B3A100FCFCFF /* LabelMenuCell.swift */, 29C8F9B4208C081D0075931C /* LabelSectionController.swift */, 2924C18C20D5B3DD00FCFCFF /* LabelsViewController.swift */, + 2CDD97C12411B61C0016D5CF /* GitHubClient+RepositoryLabels.swift */, ); path = Labels; sourceTree = ""; @@ -3263,6 +3266,7 @@ 031E0241220B433C00A329F1 /* UIImage+Color.swift in Sources */, 29999734203135E100995FFD /* IssueMergeContextCell.swift in Sources */, 29EDFE821F661562005BCCEB /* RepositoryReadmeModel.swift in Sources */, + 2CDD97C22411B61C0016D5CF /* GitHubClient+RepositoryLabels.swift in Sources */, 29EDFE841F661776005BCCEB /* RepositoryReadmeSectionController.swift in Sources */, 29136BDF200A7A75007317BE /* UIScrollView+LeftRightSafeInset.swift in Sources */, 298C7E2621D7F56600DD2A60 /* SettingsAccountCell.swift in Sources */, diff --git a/gql/RepositoryLabels.graphql b/gql/RepositoryLabels.graphql index 1ca72e7ef..947402a66 100644 --- a/gql/RepositoryLabels.graphql +++ b/gql/RepositoryLabels.graphql @@ -1,10 +1,14 @@ -query RepositoryLabels($owner: String!, $repo: String!) { +query RepositoryLabels($owner: String!, $repo: String!, $after: String) { repository(owner: $owner, name: $repo) { - labels(first:100) { + labels(first:100, after: $after) { nodes { name color } + pageInfo { + hasNextPage + endCursor + } } } }