From 60ba786162d677dad8dafec583d0c9637cd7c46e Mon Sep 17 00:00:00 2001 From: Ryan Nystrom Date: Sat, 12 Aug 2017 17:29:48 -0400 Subject: [PATCH] view PR file changes --- Classes/Issues/Files/Files.storyboard | 89 ++++++++++++++++ .../Files/GithubClient+PullRequestFiles.swift | 40 +++++++ .../Issues/Files/IssueFilesTableCell.swift | 39 +++++++ .../Files/IssueFilesViewController.swift | 100 ++++++++++++++++++ .../IssueViewFilesSectionController.swift | 10 +- Classes/Issues/IssuesViewController.swift | 2 +- Freetime.xcodeproj/project.pbxproj | 16 +++ Resources/Info.plist | 2 +- 8 files changed, 295 insertions(+), 3 deletions(-) create mode 100644 Classes/Issues/Files/Files.storyboard create mode 100644 Classes/Issues/Files/GithubClient+PullRequestFiles.swift create mode 100644 Classes/Issues/Files/IssueFilesTableCell.swift create mode 100644 Classes/Issues/Files/IssueFilesViewController.swift diff --git a/Classes/Issues/Files/Files.storyboard b/Classes/Issues/Files/Files.storyboard new file mode 100644 index 00000000..a726778c --- /dev/null +++ b/Classes/Issues/Files/Files.storyboard @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Classes/Issues/Files/GithubClient+PullRequestFiles.swift b/Classes/Issues/Files/GithubClient+PullRequestFiles.swift new file mode 100644 index 00000000..a7d85a58 --- /dev/null +++ b/Classes/Issues/Files/GithubClient+PullRequestFiles.swift @@ -0,0 +1,40 @@ +// +// GitHubClient+PullRequestFiles.swift +// Freetime +// +// Created by Ryan Nystrom on 8/12/17. +// Copyright © 2017 Ryan Nystrom. All rights reserved. +// + +import Foundation + +extension GithubClient { + + enum FileResult { + case success([File]) + case error + } + + func fetchFiles( + owner: String, + repo: String, + number: Int, + completion: @escaping (FileResult) -> ()) { + request(Request( + path: "repos/\(owner)/\(repo)/pulls/\(number)/files", + completion: { (response, _) in + if let arr = response.value as? [ [String: Any] ] { + var files = [File]() + for json in arr { + if let file = File(json: json) { + files.append(file) + } + } + completion(.success(files)) + } else { + completion(.error) + } + })) + } + +} diff --git a/Classes/Issues/Files/IssueFilesTableCell.swift b/Classes/Issues/Files/IssueFilesTableCell.swift new file mode 100644 index 00000000..7d7d8f52 --- /dev/null +++ b/Classes/Issues/Files/IssueFilesTableCell.swift @@ -0,0 +1,39 @@ +// +// IssueFilesTableCell.swift +// Freetime +// +// Created by Ryan Nystrom on 8/12/17. +// Copyright © 2017 Ryan Nystrom. All rights reserved. +// + +import UIKit + +final class IssueFilesTableCell: UITableViewCell { + + @IBOutlet weak var changeLabel: UILabel! + @IBOutlet weak var pathLabel: UILabel! + + // MARK: Public API + + func configure(path: String, additions: Int, deletions: Int) { + let changeString = NSMutableAttributedString() + var attributes: [String: Any] = [ + NSFontAttributeName: Styles.Fonts.secondaryBold, + ] + + if additions > 0 { + attributes[NSForegroundColorAttributeName] = Styles.Colors.Green.medium.color + changeString.append(NSAttributedString(string: "+\(additions) ", attributes: attributes)) + } + + if deletions > 0 { + attributes[NSForegroundColorAttributeName] = Styles.Colors.Red.medium.color + changeString.append(NSAttributedString(string: "-\(deletions)", attributes: attributes)) + } + + changeLabel.attributedText = changeString + + pathLabel.text = path + } + +} diff --git a/Classes/Issues/Files/IssueFilesViewController.swift b/Classes/Issues/Files/IssueFilesViewController.swift new file mode 100644 index 00000000..6adb6916 --- /dev/null +++ b/Classes/Issues/Files/IssueFilesViewController.swift @@ -0,0 +1,100 @@ +// +// IssueFilesViewController.swift +// Freetime +// +// Created by Ryan Nystrom on 8/12/17. +// Copyright © 2017 Ryan Nystrom. All rights reserved. +// + +import UIKit + +final class IssueFilesViewController: UITableViewController { + + private var model: IssueDetailsModel! + private var client: GithubClient! + private var result: GithubClient.FileResult? = nil + + override func viewDidLoad() { + super.viewDidLoad() + + let refreshControl = UIRefreshControl() + refreshControl.addTarget(self, action: #selector(IssueFilesViewController.onRefresh), for: .valueChanged) + tableView.refreshControl = refreshControl + + refreshControl.beginRefreshing() + fetch() + } + + // MARK: Public API + + func configure(model: IssueDetailsModel, client: GithubClient) { + self.model = model + self.client = client + } + + // MARK: Private API + + func onRefresh() { + fetch() + } + + func fetch() { + client.fetchFiles( + owner: model.owner, + repo: model.repo, + number: model.number) { [weak self] (result) in + self?.handle(result: result) + } + } + + func handle(result: GithubClient.FileResult) { + self.result = result + tableView.reloadData() + tableView.refreshControl?.endRefreshing() + + switch result { + case .success(let files): + let titleFormat = NSLocalizedString("Files (%zi)", comment: "") + title = String.localizedStringWithFormat(titleFormat, files.count) + default: break + } + } + + // MARK: UITableViewDataSource + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + guard let result = self.result else { return 0 } + switch result { + case .success(let files): return files.count + case .error: return 1 + } + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + guard let result = self.result else { fatalError("No cells when no data") } + + let identifier: String + var file: File? = nil + switch result { + case .success(let files): + identifier = "file" + file = files[indexPath.row] + case .error: + identifier = "error" + } + let cell = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath) + + if let cell = cell as? IssueFilesTableCell, let file = file { + cell.configure(path: file.filename, additions: file.additions.intValue, deletions: file.deletions.intValue) + } + + return cell + } + + // MARK: UITableViewDelegate + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableView.deselectRow(at: indexPath, animated: true) + } + +} diff --git a/Classes/Issues/Files/IssueViewFilesSectionController.swift b/Classes/Issues/Files/IssueViewFilesSectionController.swift index dadbd064..b971f11a 100644 --- a/Classes/Issues/Files/IssueViewFilesSectionController.swift +++ b/Classes/Issues/Files/IssueViewFilesSectionController.swift @@ -12,9 +12,11 @@ import IGListKit final class IssueViewFilesSectionController: ListSectionController { private let issueModel: IssueDetailsModel + private let client: GithubClient - init(issueModel: IssueDetailsModel) { + init(issueModel: IssueDetailsModel, client: GithubClient) { self.issueModel = issueModel + self.client = client super.init() } @@ -31,6 +33,12 @@ final class IssueViewFilesSectionController: ListSectionController { override func didSelectItem(at index: Int) { collectionContext?.deselectItem(at: index, sectionController: self, animated: true) + + guard let controller = UIStoryboard(name: "Files", bundle: Bundle.main) + .instantiateInitialViewController() as? IssueFilesViewController + else { return } + controller.configure(model: issueModel, client: client) + viewController?.showDetailViewController(controller, sender: nil) } } diff --git a/Classes/Issues/IssuesViewController.swift b/Classes/Issues/IssuesViewController.swift index 6e9a49fb..fcbc8679 100644 --- a/Classes/Issues/IssuesViewController.swift +++ b/Classes/Issues/IssuesViewController.swift @@ -288,7 +288,7 @@ IssueTextActionsViewDelegate { func listAdapter(_ listAdapter: ListAdapter, sectionControllerFor object: Any) -> ListSectionController { if let object = object as? ListDiffable, object === viewFilesModel { - return IssueViewFilesSectionController(issueModel: model) + return IssueViewFilesSectionController(issueModel: model, client: client) } switch object { diff --git a/Freetime.xcodeproj/project.pbxproj b/Freetime.xcodeproj/project.pbxproj index 67e7b598..171802e3 100644 --- a/Freetime.xcodeproj/project.pbxproj +++ b/Freetime.xcodeproj/project.pbxproj @@ -26,6 +26,10 @@ 291929471F3EAB250012067B /* IssueDetailsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291929461F3EAB250012067B /* IssueDetailsModel.swift */; }; 291929491F3EAD2E0012067B /* IssueViewFilesSectionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291929481F3EAD2E0012067B /* IssueViewFilesSectionController.swift */; }; 2919294B1F3EAD890012067B /* IssueViewFilesCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2919294A1F3EAD890012067B /* IssueViewFilesCell.swift */; }; + 2919294D1F3F746B0012067B /* GithubClient+PullRequestFiles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2919294C1F3F746B0012067B /* GithubClient+PullRequestFiles.swift */; }; + 2919294F1F3F76A20012067B /* Files.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2919294E1F3F76A20012067B /* Files.storyboard */; }; + 291929511F3F76B10012067B /* IssueFilesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291929501F3F76B10012067B /* IssueFilesViewController.swift */; }; + 291929531F3F9E490012067B /* IssueFilesTableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291929521F3F9E490012067B /* IssueFilesTableCell.swift */; }; 292484B81F01CB5C0054FE20 /* SwipeCellKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 292484B71F01CB5C0054FE20 /* SwipeCellKit.framework */; }; 292484B91F01CB5C0054FE20 /* SwipeCellKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 292484B71F01CB5C0054FE20 /* SwipeCellKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 2928C7881F15D7C50000D06D /* IssueRenamedModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2928C7871F15D7C50000D06D /* IssueRenamedModel.swift */; }; @@ -322,6 +326,10 @@ 291929461F3EAB250012067B /* IssueDetailsModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IssueDetailsModel.swift; sourceTree = ""; }; 291929481F3EAD2E0012067B /* IssueViewFilesSectionController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IssueViewFilesSectionController.swift; sourceTree = ""; }; 2919294A1F3EAD890012067B /* IssueViewFilesCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IssueViewFilesCell.swift; sourceTree = ""; }; + 2919294C1F3F746B0012067B /* GithubClient+PullRequestFiles.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "GithubClient+PullRequestFiles.swift"; sourceTree = ""; }; + 2919294E1F3F76A20012067B /* Files.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Files.storyboard; sourceTree = ""; }; + 291929501F3F76B10012067B /* IssueFilesViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IssueFilesViewController.swift; sourceTree = ""; }; + 291929521F3F9E490012067B /* IssueFilesTableCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IssueFilesTableCell.swift; sourceTree = ""; }; 292484B71F01CB5C0054FE20 /* SwipeCellKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = SwipeCellKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 2928C7871F15D7C50000D06D /* IssueRenamedModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IssueRenamedModel.swift; sourceTree = ""; }; 2928C7891F15D7E00000D06D /* IssueRenamedCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IssueRenamedCell.swift; sourceTree = ""; }; @@ -591,6 +599,10 @@ 291929431F3EAAAF0012067B /* Files */ = { isa = PBXGroup; children = ( + 2919294E1F3F76A20012067B /* Files.storyboard */, + 2919294C1F3F746B0012067B /* GithubClient+PullRequestFiles.swift */, + 291929521F3F9E490012067B /* IssueFilesTableCell.swift */, + 291929501F3F76B10012067B /* IssueFilesViewController.swift */, 2919294A1F3EAD890012067B /* IssueViewFilesCell.swift */, 291929481F3EAD2E0012067B /* IssueViewFilesSectionController.swift */, ); @@ -1342,6 +1354,7 @@ buildActionMask = 2147483647; files = ( 29416BF91F1138B700D03E1A /* OauthLogin.storyboard in Resources */, + 2919294F1F3F76A20012067B /* Files.storyboard in Resources */, 297AE8821EC0D5C200B44A1F /* LaunchScreen.storyboard in Resources */, 292FF8AC1F2FD3EC009E63F7 /* Settings.storyboard in Resources */, 29EE1C171F3A2E7A0046A54D /* Labels.storyboard in Resources */, @@ -1497,6 +1510,7 @@ 292FCB091EDFCC510026635E /* IssueCommentSummaryModel.swift in Sources */, 290EF5791F06BAF4006A2160 /* NoNewNotificationsSectionController.swift in Sources */, 292FCB151EDFCC510026635E /* IssueLabelsSectionController.swift in Sources */, + 291929531F3F9E490012067B /* IssueFilesTableCell.swift in Sources */, 297403D91F18545A00ABA95A /* IssueAssigneesSectionController.swift in Sources */, 292EB08D1F1FF58D0046865D /* IssueMilestoneEventModel.swift in Sources */, 292FCAFC1EDFCC510026635E /* IssueCommentImageModel.swift in Sources */, @@ -1577,6 +1591,7 @@ 29A476A01ED0E6C6005D0953 /* UIColor+Overlay.swift in Sources */, 29F7F05F1F2A839100F6075D /* IssueNeckLoadSectionController.swift in Sources */, 297403D11F184F8D00ABA95A /* IssueAssigneesModel.swift in Sources */, + 2919294D1F3F746B0012067B /* GithubClient+PullRequestFiles.swift in Sources */, 292FF8B51F303BD0009E63F7 /* IssuePreviewSectionController.swift in Sources */, 290D2A3D1F044CB20082E6CC /* UIViewController+SmartDeselection.swift in Sources */, 29A08FBD1F12EF7C00C5368E /* IssueReferencedCommitCell.swift in Sources */, @@ -1675,6 +1690,7 @@ 29C1677A1ECA14F700439D62 /* Feed.swift in Sources */, 292FCB171EDFCC510026635E /* IssueLabelSummaryModel.swift in Sources */, 291929491F3EAD2E0012067B /* IssueViewFilesSectionController.swift in Sources */, + 291929511F3F76B10012067B /* IssueFilesViewController.swift in Sources */, 98835BD41F1A17EE005BA24F /* Bundle+Version.swift in Sources */, 29FB94301EE752280016E6D4 /* IssueLabeledCell.swift in Sources */, 295C31C71F09E62600521CED /* NotificationNextPageCell.swift in Sources */, diff --git a/Resources/Info.plist b/Resources/Info.plist index ba4cea56..e300c4f4 100644 --- a/Resources/Info.plist +++ b/Resources/Info.plist @@ -32,7 +32,7 @@ CFBundleVersion - 1338 + 1347 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes