Fix compile errors: guard unwrap + ViewBuilder var mutation
Build iOS App / Build .ipa and publish source (push) Successful in 25s
Build iOS App / Build .ipa and publish source (push) Successful in 25s
- PRDetailView: guard let current = selectedTab ?? .overview fails because ?? already unwraps to non-optional. Use let current = selectedTab ?? .overview. - MarkdownText: var inCodeBlock inside ViewBuilder is not allowed. Precompute lines with their code-block state as a computed property on a private struct, then iterate via ForEach in the builder. Bump to 3.3.
This commit is contained in:
1 parent
dd0fc84238
commit
a9d408ee85
2 files changed
+58
-32
No files matched your search
@@ -195,8 +195,8 @@ struct PRDetailView: View {
|
||||
DragGesture(minimumDistance: 20)
|
||||
.onEnded { value in
|
||||
let tabs = DetailTab.allCases
|
||||
guard let current = selectedTab ?? .overview,
|
||||
let idx = tabs.firstIndex(of: current) else { return }
|
||||
let current = selectedTab ?? .overview
|
||||
guard let idx = tabs.firstIndex(of: current) else { return }
|
||||
if value.translation.width < -40, idx < tabs.count - 1 {
|
||||
withAnimation { selectedTab = tabs[idx + 1] }
|
||||
} else if value.translation.width > 40, idx > 0 {
|
||||
|
||||
+56
-30
@@ -179,49 +179,75 @@ struct MarkdownText: View {
|
||||
self.markdown = markdown
|
||||
}
|
||||
|
||||
/// One markdown source line with its render type resolved upfront, so the
|
||||
/// code-block state doesn't have to be mutated inside the ViewBuilder.
|
||||
private struct Line: Identifiable {
|
||||
enum Kind { case code, heading, bullet, text, blank }
|
||||
let id = UUID()
|
||||
let kind: Kind
|
||||
let text: String
|
||||
let level: Int // heading level
|
||||
}
|
||||
|
||||
private var lines: [Line] {
|
||||
let raw = markdown.components(separatedBy: "\n")
|
||||
var out: [Line] = []
|
||||
var inCodeBlock = false
|
||||
for line in raw {
|
||||
if line.hasPrefix("```") {
|
||||
inCodeBlock.toggle()
|
||||
continue
|
||||
}
|
||||
if inCodeBlock {
|
||||
out.append(Line(kind: .code, text: line, level: 0))
|
||||
} else if line.hasPrefix("# ") || line.hasPrefix("## ") || line.hasPrefix("### ") {
|
||||
let level = line.prefix(while: { $0 == "#" }).count
|
||||
out.append(Line(kind: .heading,
|
||||
text: String(line.dropFirst(level)).trimmingCharacters(in: .whitespaces),
|
||||
level: level))
|
||||
} else if line.hasPrefix("- ") || line.hasPrefix("* ") {
|
||||
out.append(Line(kind: .bullet,
|
||||
text: String(line.dropFirst(2)),
|
||||
level: 0))
|
||||
} else if line.trimmingCharacters(in: .whitespaces).isEmpty {
|
||||
out.append(Line(kind: .blank, text: "", level: 0))
|
||||
} else {
|
||||
out.append(Line(kind: .text, text: line, level: 0))
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
let lines = markdown.components(separatedBy: "\n")
|
||||
var inCodeBlock = false
|
||||
ForEach(Array(lines.enumerated()), id: \.offset) { _, line in
|
||||
if line.hasPrefix("```") {
|
||||
inCodeBlock.toggle()
|
||||
} else if inCodeBlock {
|
||||
Text(line)
|
||||
ForEach(lines) { line in
|
||||
switch line.kind {
|
||||
case .code:
|
||||
Text(line.text)
|
||||
.font(.caption.monospaced())
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding(4)
|
||||
.background(Color(.secondarySystemBackground))
|
||||
} else if line.hasPrefix("# ") || line.hasPrefix("## ") || line.hasPrefix("### ") {
|
||||
heading(line)
|
||||
} else if line.hasPrefix("- ") || line.hasPrefix("* ") {
|
||||
bullet(line)
|
||||
} else if line.trimmingCharacters(in: .whitespaces).isEmpty {
|
||||
case .heading:
|
||||
Text(line.text)
|
||||
.font(line.level == 1 ? .title2.bold() : line.level == 2 ? .title3.bold() : .headline)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
case .bullet:
|
||||
HStack(alignment: .top, spacing: 6) {
|
||||
Text("•")
|
||||
inline(line.text)
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
case .blank:
|
||||
Spacer(minLength: 4)
|
||||
} else {
|
||||
inline(line)
|
||||
case .text:
|
||||
inline(line.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
|
||||
private func heading(_ line: String) -> some View {
|
||||
let level = line.prefix(while: { $0 == "#" }).count
|
||||
let text = line.dropFirst(level).trimmingCharacters(in: .whitespaces)
|
||||
return Text(text)
|
||||
.font(level == 1 ? .title2.bold() : level == 2 ? .title3.bold() : .headline)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
|
||||
private func bullet(_ line: String) -> some View {
|
||||
HStack(alignment: .top, spacing: 6) {
|
||||
Text("•")
|
||||
inline(String(line.dropFirst(2)))
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
|
||||
private func inline(_ text: String) -> some View {
|
||||
if let attributed = try? AttributedString(markdown: text) {
|
||||
Text(attributed)
|
||||
|
||||
Reference in new issue
Block a user