Files
Gotcha/ios/Sources/DiffScreen.swift
2026-08-03 17:54:07 +02:00

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
}
}