Prepare Gotcha 1.0 for release
This commit is contained in:
178
ios/Sources/CommitDetailScreen.swift
Normal file
178
ios/Sources/CommitDetailScreen.swift
Normal file
@@ -0,0 +1,178 @@
|
||||
import UIKit
|
||||
|
||||
private final class CommitHeaderView: UIView {
|
||||
private let stack = UIStackView()
|
||||
private let titleLabel = UILabel()
|
||||
private var descriptionView: UIView?
|
||||
private let metadataStack = UIStackView()
|
||||
private let bottomSeparator = separator()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
backgroundColor = .systemBackground
|
||||
directionalLayoutMargins = .init(top: 20, leading: 20, bottom: 20, trailing: 20)
|
||||
|
||||
titleLabel.font = .preferredFont(forTextStyle: .title2)
|
||||
titleLabel.adjustsFontForContentSizeCategory = true
|
||||
titleLabel.numberOfLines = 0
|
||||
titleLabel.accessibilityTraits = .header
|
||||
|
||||
metadataStack.axis = .vertical
|
||||
metadataStack.spacing = 10
|
||||
stack.axis = .vertical
|
||||
stack.spacing = 12
|
||||
stack.translatesAutoresizingMaskIntoConstraints = false
|
||||
stack.addArrangedSubview(titleLabel)
|
||||
stack.addArrangedSubview(metadataStack)
|
||||
addSubview(stack)
|
||||
bottomSeparator.translatesAutoresizingMaskIntoConstraints = false
|
||||
addSubview(bottomSeparator)
|
||||
NSLayoutConstraint.activate([
|
||||
stack.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor),
|
||||
stack.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor),
|
||||
stack.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor),
|
||||
stack.bottomAnchor.constraint(equalTo: layoutMarginsGuide.bottomAnchor),
|
||||
bottomSeparator.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||
bottomSeparator.trailingAnchor.constraint(equalTo: trailingAnchor),
|
||||
bottomSeparator.bottomAnchor.constraint(equalTo: bottomAnchor),
|
||||
])
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder: NSCoder) { fatalError("init(coder:) is not supported") }
|
||||
|
||||
func configure(_ page: CommitDetailsPage) {
|
||||
titleLabel.text = page.title
|
||||
descriptionView?.removeFromSuperview()
|
||||
if !page.description.isEmpty {
|
||||
let view = markdownView(page.description)
|
||||
stack.insertArrangedSubview(view, at: 1)
|
||||
descriptionView = view
|
||||
}
|
||||
metadataStack.arrangedSubviews.forEach { $0.removeFromSuperview() }
|
||||
for metadata in page.metadata {
|
||||
let label = UILabel()
|
||||
label.text = metadata.label.uppercased()
|
||||
label.font = .preferredFont(forTextStyle: .caption2)
|
||||
label.adjustsFontForContentSizeCategory = true
|
||||
label.textColor = .secondaryLabel
|
||||
|
||||
let value = UILabel()
|
||||
value.text = metadata.value
|
||||
value.font = metadata.monospaced
|
||||
? UIFontMetrics(forTextStyle: .subheadline).scaledFont(
|
||||
for: .monospacedSystemFont(ofSize: 15, weight: .regular)
|
||||
)
|
||||
: .preferredFont(forTextStyle: .subheadline)
|
||||
value.adjustsFontForContentSizeCategory = true
|
||||
value.numberOfLines = 0
|
||||
value.lineBreakMode = metadata.monospaced ? .byCharWrapping : .byWordWrapping
|
||||
|
||||
let row = UIStackView(arrangedSubviews: [label, value])
|
||||
row.axis = .vertical
|
||||
row.spacing = 2
|
||||
row.isAccessibilityElement = true
|
||||
row.accessibilityLabel = "\(metadata.label): \(metadata.value)"
|
||||
metadataStack.addArrangedSubview(row)
|
||||
}
|
||||
}
|
||||
}
|
||||
@MainActor
|
||||
final class FilesViewController: RefreshingTableViewController {
|
||||
private let context: AppContext
|
||||
private let owner: String
|
||||
private let repository: String
|
||||
private let sha: String
|
||||
private let branch: String?
|
||||
private let commitHeader = CommitHeaderView()
|
||||
private var page: CommitDetailsPage?
|
||||
|
||||
init(context: AppContext, owner: String, repository: String, sha: String, branch: String? = nil) {
|
||||
self.context = context
|
||||
self.owner = owner
|
||||
self.repository = repository
|
||||
self.sha = sha
|
||||
self.branch = branch
|
||||
super.init()
|
||||
title = "Changed Files"
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder: NSCoder) { fatalError("init(coder:) is not supported") }
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
loadContent(refreshing: false)
|
||||
}
|
||||
|
||||
override func viewDidLayoutSubviews() {
|
||||
super.viewDidLayoutSubviews()
|
||||
guard let header = tableView.tableHeaderView else { return }
|
||||
let size = header.systemLayoutSizeFitting(
|
||||
CGSize(width: tableView.bounds.width, height: 0),
|
||||
withHorizontalFittingPriority: .required,
|
||||
verticalFittingPriority: .fittingSizeLevel
|
||||
)
|
||||
guard header.frame.height != size.height else { return }
|
||||
header.frame.size.height = size.height
|
||||
tableView.tableHeaderView = header
|
||||
}
|
||||
|
||||
override func loadContent(refreshing: Bool) {
|
||||
beginLoading(refreshing: refreshing)
|
||||
loadingTask?.cancel()
|
||||
loadingTask = Task {
|
||||
do {
|
||||
let page = try await context.core.commitDetails(
|
||||
owner: owner,
|
||||
repository: repository,
|
||||
sha: sha,
|
||||
branch: branch
|
||||
)
|
||||
self.page = page
|
||||
commitHeader.configure(page)
|
||||
tableView.tableHeaderView = commitHeader
|
||||
tableView.reloadData()
|
||||
tableView.backgroundView = page.files.isEmpty
|
||||
? EmptyBackgroundView(title: "No changed files", detail: "This commit does not contain file changes.")
|
||||
: nil
|
||||
} catch {
|
||||
if !Task.isCancelled { show(error: error) }
|
||||
}
|
||||
endLoading()
|
||||
}
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
page?.files.count ?? 0
|
||||
}
|
||||
|
||||
override func tableView(
|
||||
_ tableView: UITableView,
|
||||
cellForRowAt indexPath: IndexPath
|
||||
) -> UITableViewCell {
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "file")
|
||||
?? UITableViewCell(style: .subtitle, reuseIdentifier: "file")
|
||||
let row = page!.files[indexPath.row]
|
||||
configureTextCell(cell, title: row.path, detail: row.status)
|
||||
cell.accessoryType = .disclosureIndicator
|
||||
return cell
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
guard let row = page?.files[indexPath.row] else { return }
|
||||
navigationController?.pushViewController(
|
||||
DiffViewController(
|
||||
context: context,
|
||||
source: .commit(
|
||||
owner: owner,
|
||||
repository: repository,
|
||||
sha: sha,
|
||||
path: row.path
|
||||
)
|
||||
),
|
||||
animated: true
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user