96 lines
3.6 KiB
Swift
96 lines
3.6 KiB
Swift
import UIKit
|
|
|
|
enum DiffSource {
|
|
case commit(owner: String, repository: String, sha: String, path: String)
|
|
case pull(owner: String, repository: String, number: Int64, path: String)
|
|
}
|
|
|
|
@MainActor
|
|
final class DiffViewController: UIViewController {
|
|
private let context: AppContext
|
|
private let source: DiffSource
|
|
private let codeView = CodeScrollView()
|
|
private let spinner = UIActivityIndicatorView(style: .medium)
|
|
private var loadingTask: Task<Void, Never>?
|
|
|
|
init(context: AppContext, source: DiffSource) {
|
|
self.context = context
|
|
self.source = source
|
|
super.init(nibName: nil, bundle: nil)
|
|
}
|
|
|
|
@available(*, unavailable)
|
|
required init?(coder: NSCoder) { fatalError("init(coder:) is not supported") }
|
|
|
|
override func viewDidLoad() {
|
|
super.viewDidLoad()
|
|
view.backgroundColor = .systemBackground
|
|
codeView.refreshControl = UIRefreshControl()
|
|
codeView.refreshControl?.addTarget(self, action: #selector(reload), for: .valueChanged)
|
|
view.addSubview(codeView)
|
|
NSLayoutConstraint.activate([
|
|
codeView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
|
|
codeView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
|
|
codeView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
|
|
codeView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
|
|
])
|
|
beginNavigationLoading(spinner)
|
|
reload()
|
|
}
|
|
|
|
deinit { loadingTask?.cancel() }
|
|
|
|
@objc private func reload() {
|
|
loadingTask?.cancel()
|
|
loadingTask = Task {
|
|
do {
|
|
let page: DiffPage
|
|
switch source {
|
|
case let .commit(owner, repository, sha, path):
|
|
page = try await context.core.commitDiff(
|
|
owner: owner,
|
|
repository: repository,
|
|
sha: sha,
|
|
path: path
|
|
)
|
|
case let .pull(owner, repository, number, path):
|
|
page = try await context.core.pullDiff(
|
|
owner: owner,
|
|
repository: repository,
|
|
number: number,
|
|
path: path
|
|
)
|
|
}
|
|
title = page.title
|
|
codeView.display(diffText(page))
|
|
} catch {
|
|
if !Task.isCancelled { show(error: error) }
|
|
}
|
|
endNavigationLoading(spinner)
|
|
codeView.refreshControl?.endRefreshing()
|
|
}
|
|
}
|
|
|
|
private func diffText(_ page: DiffPage) -> NSAttributedString {
|
|
let output = NSMutableAttributedString()
|
|
let font = UIFont.monospacedSystemFont(ofSize: 12, weight: .regular)
|
|
for line in page.lines {
|
|
let text = String(format: "%4@ %4@ %@\n", line.oldNumber, line.newNumber, line.text)
|
|
let color: UIColor
|
|
switch line.kind {
|
|
case .addition: color = UIColor.systemGreen.withAlphaComponent(0.16)
|
|
case .removal: color = UIColor.systemRed.withAlphaComponent(0.16)
|
|
case .hunk: color = UIColor.systemBlue.withAlphaComponent(0.14)
|
|
case .header: color = UIColor.systemGray.withAlphaComponent(0.14)
|
|
case .context: color = .clear
|
|
}
|
|
output.append(NSAttributedString(string: text, attributes: [
|
|
.font: font,
|
|
.foregroundColor: UIColor.label,
|
|
.backgroundColor: color,
|
|
]))
|
|
}
|
|
return output
|
|
}
|
|
}
|