Fix Mac crash when opening a book from search.

Defer NavigationStack path updates until after the practice tab is active so SwiftUI does not trap in boundPathChange.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
pepaskopec-blip 2026-09-22 12:42:04 +02:00
commit b6fa222659
3 changed files with 37 additions and 12 deletions

View file

@ -51,13 +51,7 @@ final class AppModel: ObservableObject {
tab = .practice
practicePath = []
default:
tab = .practice
if practicePath.last == r { return }
if practicePath.isEmpty {
practicePath = r.stack
} else {
practicePath.append(r)
}
applyPracticeRoute(r, replace: practicePath.isEmpty)
}
}
@ -75,8 +69,25 @@ final class AppModel: ObservableObject {
tab = .practice
practicePath = []
default:
tab = .practice
practicePath = r.stack
// Switching tabs and assigning a deep NavigationStack path in the
// same turn crashes SwiftUI on macOS (boundPathChange / unexpectedError).
applyPracticeRoute(r, replace: true)
}
}
/// Sets the practice tab path safely, especially when jumping from Search.
private func applyPracticeRoute(_ r: Route, replace: Bool) {
let stack = replace ? r.stack : (practicePath + [r])
if !replace, practicePath.last == r { return }
let switching = tab != .practice
tab = .practice
if switching || replace {
practicePath = []
DispatchQueue.main.async { [weak self] in
self?.practicePath = stack
}
} else {
practicePath = stack
}
}

View file

@ -54,8 +54,14 @@ enum Route: Hashable {
if id == "1984" { return "cetba1984" }
if id == "fuks" { return "cetbaFuks" }
return "cetba_" + id.replacingOccurrences(of: "-", with: "_")
case .bookQuiz(let id): return id == "1984" ? "cetba1984quiz" : "cetbaFuksQuiz"
case .bookPlot(let id): return id == "1984" ? "cetba1984dej" : "cetbaFuksDej"
case .bookQuiz(let id):
if id == "1984" { return "cetba1984quiz" }
if id == "fuks" { return "cetbaFuksQuiz" }
return "cetba_" + id.replacingOccurrences(of: "-", with: "_") + "_quiz"
case .bookPlot(let id):
if id == "1984" { return "cetba1984dej" }
if id == "fuks" { return "cetbaFuksDej" }
return "cetba_" + id.replacingOccurrences(of: "-", with: "_") + "_dej"
}
}
@ -123,6 +129,14 @@ func routeFromPage(_ page: String) -> Route? {
case "cetbaFuksQuiz": return .bookQuiz("fuks")
case "cetbaFuksDej": return .bookPlot("fuks")
default:
if page.hasPrefix("cetba_"), page.hasSuffix("_quiz") {
let slug = String(page.dropFirst(6).dropLast(5)).replacingOccurrences(of: "_", with: "-")
return .bookQuiz(slug)
}
if page.hasPrefix("cetba_"), page.hasSuffix("_dej") {
let slug = String(page.dropFirst(6).dropLast(4)).replacingOccurrences(of: "_", with: "-")
return .bookPlot(slug)
}
if page.hasPrefix("cetba_") {
let slug = String(page.dropFirst(6)).replacingOccurrences(of: "_", with: "-")
return .book(slug)

View file

@ -939,7 +939,7 @@ struct BookScreen: View {
}
ForEach(Array(b.arr("notes").enumerated()), id: \.offset) { _, note in
Section(note.str("title")) {
ForEach(note.strs("lines"), id: \.self) { line in
ForEach(Array(note.strs("lines").enumerated()), id: \.offset) { _, line in
Text(line)
}
}