Show commit details above changed files

This commit is contained in:
Georg Bauer
2026-08-01 14:27:28 +02:00
parent 5396a805b0
commit 3a69b70395
9 changed files with 461 additions and 57 deletions

View File

@@ -398,19 +398,96 @@ private final class FileListView: UITableView, UITableViewDataSource, UITableVie
}
}
@MainActor
private final class CommitHeaderView: UIView {
private let stack = UIStackView()
private let titleLabel = UILabel()
private let descriptionLabel = UILabel()
private let metadataStack = UIStackView()
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
descriptionLabel.font = .preferredFont(forTextStyle: .body)
descriptionLabel.adjustsFontForContentSizeCategory = true
descriptionLabel.numberOfLines = 0
metadataStack.axis = .vertical
metadataStack.spacing = 10
stack.axis = .vertical
stack.spacing = 12
stack.translatesAutoresizingMaskIntoConstraints = false
stack.addArrangedSubview(titleLabel)
stack.addArrangedSubview(descriptionLabel)
stack.addArrangedSubview(metadataStack)
addSubview(stack)
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),
])
}
@available(*, unavailable)
required init?(coder: NSCoder) { fatalError("init(coder:) is not supported") }
func configure(_ page: CommitDetailsPage) {
titleLabel.text = page.title
descriptionLabel.text = page.description
descriptionLabel.isHidden = page.description.isEmpty
metadataStack.arrangedSubviews.forEach { $0.removeFromSuperview() }
for metadata in page.metadata {
let isCommit = metadata.label == "Commit"
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 = isCommit
? UIFontMetrics(forTextStyle: .subheadline).scaledFont(
for: .monospacedSystemFont(ofSize: 15, weight: .regular)
)
: .preferredFont(forTextStyle: .subheadline)
value.adjustsFontForContentSizeCategory = true
value.numberOfLines = 0
value.lineBreakMode = isCommit ? .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 var rows: [FileRow] = []
private let branch: String?
private let commitHeader = CommitHeaderView()
private var page: CommitDetailsPage?
init(context: AppContext, owner: String, repository: String, sha: String) {
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"
}
@@ -423,18 +500,35 @@ final class FilesViewController: RefreshingTableViewController {
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 {
rows = try await context.core.commitFiles(
let page = try await context.core.commitDetails(
owner: owner,
repository: repository,
sha: sha
sha: sha,
branch: branch
)
self.page = page
commitHeader.configure(page)
tableView.tableHeaderView = commitHeader
tableView.reloadData()
tableView.backgroundView = rows.isEmpty
tableView.backgroundView = page.files.isEmpty
? EmptyBackgroundView(title: "No changed files", detail: "This commit does not contain file changes.")
: nil
} catch {
@@ -445,7 +539,7 @@ final class FilesViewController: RefreshingTableViewController {
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
rows.count
page?.files.count ?? 0
}
override func tableView(
@@ -454,7 +548,7 @@ final class FilesViewController: RefreshingTableViewController {
) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "file")
?? UITableViewCell(style: .subtitle, reuseIdentifier: "file")
let row = rows[indexPath.row]
let row = page!.files[indexPath.row]
configureTextCell(cell, title: row.path, detail: row.status)
cell.accessoryType = .disclosureIndicator
return cell
@@ -462,7 +556,7 @@ final class FilesViewController: RefreshingTableViewController {
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let row = rows[indexPath.row]
guard let row = page?.files[indexPath.row] else { return }
navigationController?.pushViewController(
DiffViewController(
context: context,
@@ -633,7 +727,8 @@ final class RepositoryDirectoryViewController: RefreshingTableViewController {
context: context,
owner: owner,
repository: repository,
sha: commit.sha
sha: commit.sha,
branch: commit.branchLabel
),
animated: true
)
@@ -780,7 +875,8 @@ final class RepositoryHistoryViewController: RefreshingTableViewController {
context: context,
owner: owner,
repository: repository,
sha: commit.sha
sha: commit.sha,
branch: commit.branchLabel
),
animated: true
)