Files
GitHawk/Classes/Repository/RepositoryCodeDirectoryViewController.swift
Ashley Ng 5c94d98cf6 Adds more share actions when browsing a repository (#2161) (#2237)
* add additional share actions

* fix share URLs
2018-10-07 16:00:14 -04:00

234 lines
7.5 KiB
Swift

//
// RepositoryCodeDirectoryViewController.swift
// Freetime
//
// Created by Ryan Nystrom on 10/8/17.
// Copyright © 2017 Ryan Nystrom. All rights reserved.
//
import UIKit
import IGListKit
import TUSafariActivity
final class RepositoryCodeDirectoryViewController: BaseListViewController<NSNumber>,
BaseListViewControllerDataSource,
ListSingleSectionControllerDelegate,
RepositoryBranchUpdatable
{
private let client: GithubClient
private var branch: String
private let path: FilePath
private let repo: RepositoryDetails
private var files = [RepositoryFile]()
private var repoUrl: URL {
return URL(string: "https://github.com/\(repo.owner)/\(repo.name)/tree/\(branch)/\(path.path)")!
}
private lazy var moreOptionsItem: UIBarButtonItem = {
let barButtonItem = UIBarButtonItem(
image: UIImage(named: "bullets-hollow"),
target: self,
action: #selector(RepositoryCodeDirectoryViewController.onShare(sender:)))
barButtonItem.isEnabled = false
return barButtonItem
}()
init(
client: GithubClient,
repo: RepositoryDetails,
branch: String,
path: FilePath
) {
self.client = client
self.repo = repo
self.branch = branch
self.path = path
super.init(
emptyErrorMessage: NSLocalizedString("Cannot load directory.", comment: "")
)
self.dataSource = self
// set on init in case used by Tabman
self.title = NSLocalizedString("Code", comment: "")
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
configureTitle(filePath: path, target: self, action: #selector(onFileNavigationTitle(sender:)))
makeBackBarItemEmpty()
navigationItem.rightBarButtonItem = moreOptionsItem
}
// MARK: Public API
static func createRoot(
client: GithubClient,
repo: RepositoryDetails,
branch: String
) -> RepositoryCodeDirectoryViewController {
return RepositoryCodeDirectoryViewController(
client: client,
repo: repo,
branch: branch,
path: FilePath(components: [])
)
}
// MARK: Private API
@objc func onFileNavigationTitle(sender: UIView) {
showAlert(filePath: path, sender: sender)
}
@objc func onShare(sender: UIButton) {
let alertTitle = "\(repo.owner)/\(repo.name):\(branch)"
let alert = UIAlertController.configured(title: alertTitle, preferredStyle: .actionSheet)
weak var weakSelf = self
let alertBuilder = AlertActionBuilder { $0.rootViewController = weakSelf }
var actions = [
AlertAction(alertBuilder).share([path.path], activities: nil, type: .shareFilePath) {
$0.popoverPresentationController?.setSourceView(sender)
},
AlertAction(alertBuilder).share([repoUrl], activities: [TUSafariActivity()], type: .shareUrl) {
$0.popoverPresentationController?.setSourceView(sender)
},
AlertAction.cancel()
]
if let name = self.path.components.last {
actions.insert(AlertAction(alertBuilder).share([name], activities: nil, type: .shareFileName) {
$0.popoverPresentationController?.setSourceView(sender)
}, at: 1)
}
alert.addActions(actions)
alert.popoverPresentationController?.setSourceView(sender)
present(alert, animated: trueUnlessReduceMotionEnabled)
}
// MARK: Overrides
override func fetch(page: NSNumber?) {
client.fetchFiles(
owner: repo.owner,
repo: repo.name,
branch: branch,
path: path.path
) { [weak self] (result) in
switch result {
case .error:
self?.error(animated: trueUnlessReduceMotionEnabled)
case .success(let files):
self?.files = files
self?.update(animated: trueUnlessReduceMotionEnabled)
self?.moreOptionsItem.isEnabled = true
}
}
}
// MARK: BaseListViewControllerDataSource
func headModels(listAdapter: ListAdapter) -> [ListDiffable] {
return []
}
func models(listAdapter: ListAdapter) -> [ListDiffable] {
return files
}
func sectionController(model: Any, listAdapter: ListAdapter) -> ListSectionController {
let controller = ListSingleSectionController(cellClass: RepositoryFileCell.self, configureBlock: { (file, cell: UICollectionViewCell) in
guard let cell = cell as? RepositoryFileCell, let file = file as? RepositoryFile else { return }
cell.configure(path: file.name, isDirectory: file.isDirectory)
}, sizeBlock: { (_, context: ListCollectionContext?) -> CGSize in
guard let width = context?.containerSize.width else { return .zero }
return CGSize(width: width, height: Styles.Sizes.tableCellHeight)
})
controller.selectionDelegate = self
return controller
}
func emptySectionController(listAdapter: ListAdapter) -> ListSectionController {
return ListSingleSectionController(cellClass: LabelCell.self, configureBlock: { (_, cell: UICollectionViewCell) in
guard let cell = cell as? LabelCell else { return }
cell.label.text = NSLocalizedString("No files found.", comment: "")
}, sizeBlock: { [weak self] (_, context: ListCollectionContext?) -> CGSize in
guard let context = context,
let strongSelf = self
else { return .zero }
return CGSize(
width: context.containerSize.width,
height: context.containerSize.height - strongSelf.view.safeAreaInsets.top - strongSelf.view.safeAreaInsets.bottom
)
})
}
// MARK: ListSingleSectionControllerDelegate
func didSelect(_ sectionController: ListSingleSectionController, with object: Any) {
guard let file = object as? RepositoryFile else { return }
let nextPath = path.appending(file.name)
if file.isDirectory {
showDirectory(at: nextPath)
} else {
showFile(at: nextPath)
}
}
}
// MARK: - RepositoryCodeDirectoryViewController (Navigation) -
extension RepositoryCodeDirectoryViewController {
private func showDirectory(at path: FilePath) {
let controller = RepositoryCodeDirectoryViewController(
client: client,
repo: repo,
branch: branch,
path: path
)
navigationController?.pushViewController(controller, animated: trueUnlessReduceMotionEnabled)
}
private func showFile(at path: FilePath) {
let controller: UIViewController
if path.hasBinarySuffix {
controller = RepositoryWebViewController(
repo: repo,
branch: branch,
path: path
)
} else {
controller = RepositoryCodeBlobViewController(
client: client,
repo: repo,
branch: branch,
path: path
)
}
navigationController?.pushViewController(controller, animated: trueUnlessReduceMotionEnabled)
}
//Mark: RepositoryBranchUpdatable
func updateBranch(to newBranch: String) {
guard self.branch != newBranch else { return }
self.branch = newBranch
fetch(page: nil)
}
}