diff --git a/GiteaPR.xcodeproj/project.pbxproj b/GiteaPR.xcodeproj/project.pbxproj index 5efb1e1..508aa4b 100644 --- a/GiteaPR.xcodeproj/project.pbxproj +++ b/GiteaPR.xcodeproj/project.pbxproj @@ -187,7 +187,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 6; + CURRENT_PROJECT_VERSION = 7; DEVELOPMENT_TEAM = ""; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_CFBundleDisplayName = "GiteaPR"; @@ -197,7 +197,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.5; + MARKETING_VERSION = 1.6; PRODUCT_BUNDLE_IDENTIFIER = com.bueso.giteapr; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; @@ -211,7 +211,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 6; + CURRENT_PROJECT_VERSION = 7; DEVELOPMENT_TEAM = ""; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_CFBundleDisplayName = "GiteaPR"; @@ -221,7 +221,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.5; + MARKETING_VERSION = 1.6; PRODUCT_BUNDLE_IDENTIFIER = com.bueso.giteapr; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; diff --git a/GiteaPR/Detail/DiffView.swift b/GiteaPR/Detail/DiffView.swift index e31af1d..ee9cab2 100644 --- a/GiteaPR/Detail/DiffView.swift +++ b/GiteaPR/Detail/DiffView.swift @@ -6,6 +6,12 @@ import SwiftUI /// `/pulls/{n}/files` (the field is absent), so the diff is fetched from the /// PR's `.diff` endpoint and the hunks belonging to this file are extracted. /// Added/deleted lines are colour-coded. +/// +/// Rendering: a plain VStack inside nested vertical→horizontal ScrollViews. +/// A LazyVStack inside a dual-axis `ScrollView([.horizontal, .vertical])` is a +/// known-bad combination (rows collapse to ~zero width, so the background tint +/// renders but the text disappears); VStack + nested scroll is the stable +/// pattern for monospaced diff text. struct DiffView: View { let repo: Repository let prNumber: Int @@ -24,13 +30,14 @@ struct DiffView: View { systemImage: "doc.text", description: Text(errorMessage)) } else { - ScrollView([.horizontal, .vertical]) { - LazyVStack(alignment: .leading, spacing: 0) { - ForEach(lines) { line in - diffLine(line) + ScrollView(.vertical) { + ScrollView(.horizontal) { + VStack(alignment: .leading, spacing: 0) { + ForEach(lines) { line in + diffLine(line) + } } } - .font(.caption.monospaced()) } } } @@ -62,28 +69,30 @@ struct DiffView: View { } /// Extract the unified-diff block for `filename` from a multi-file diff. - /// Falls back to the whole diff if the header can't be matched. private func extractSection(named filename: String, from diff: String) -> String { let marker = "+++ b/\(filename)" guard let idx = diff.range(of: marker)?.upperBound else { return "" } let tail = String(diff[idx...]) - // Find the next "diff --git " after this file's header to delimit it. - let rest = tail.dropFirst(marker.count) - if let next = rest.range(of: "\ndiff --git ") { + if let next = tail.range(of: "\ndiff --git ") { return String(tail[.. some View { - Text(line.text) - .frame(maxWidth: .infinity, alignment: .leading) - .padding(.horizontal, 8) - .padding(.vertical, 1) - .background(background(for: line.type)) - .foregroundColor(foreground(for: line.type)) + HStack(spacing: 0) { + Text(line.text) + .font(.caption.monospaced()) + .foregroundColor(foreground(for: line.type)) + .fixedSize(horizontal: true, vertical: false) + .frame(minWidth: 0, maxWidth: .infinity, alignment: .leading) + } + .padding(.horizontal, 8) + .padding(.vertical, 1) + .background(background(for: line.type)) + .frame(maxWidth: .infinity, alignment: .leading) } private func background(for type: DiffLineType) -> Color { @@ -120,9 +129,8 @@ struct DiffView: View { private enum DiffLineType { case context, addition, deletion, hunk, meta } private struct DiffLine: Identifiable { - // Stable id: a fresh UUID() on EVERY access (computed property) makes - // SwiftUI's ForEach re-identify on every render, churning the main thread - // and eventually crashing. Store it once. + // Stable id: generate once, not on every access (a fresh UUID each read + // churns SwiftUI's ForEach on the main thread and can crash). let id: UUID = UUID() let text: String let type: DiffLineType