When I run this code, and click on one of both 'currentZin' in the first screen that comes up with the view WordView, I see the content of the .preview value I used to initialize currentVerse (Verse= .preview) and not the values of the currentVerse that is in the Button action.
When I leave the WordView-sheet and click again the WordView shows the good result. I looks that on the first click the currentVerse = verse in the Button is not executed. If Ido not initialize it, it has a nil value. Can Anyone explain what happens and how to solve it.
struct HymnVerses: View {
var hymn:Hymn
@State private var currentZin: Int = 2
@State private var isLatin: Bool = true
@State private var isMasked: Bool = false
@State private var isTranslation: Bool = true
@State private var currentSentence: String = ""
@State private var showWordView: Bool = false
@State private var currentVerse: Verse = .preview
// Deze calculated property wordt op voorhand berekend.
// Hierdoor blijft de referentie naar het origineel bestaan
// wanneer ik currentVerse bereken. Daarvoor geraakte ik ze altijd kwijt.
private var filteredVerses: [Verse] {
hymn.verses.filter { $0.zin <= currentZin }
}
var body: some View {
List {
ForEach(filteredVerses) { verse in
VStack(alignment: .leading) {
Button {
currentVerse = verse
showWordView = true
} label: {
Text("\(verse.zin). \(currentSentence(for: verse))")
.font(.headline)
}
}
} .onAppear {
currentVerse = filteredVerses.first!
}
}.sheet(isPresented: $showWordView, content: {
WordView(vers: currentVerse, showWordView: $showWordView)
})
.toolbar {
ToolbarItem(placement: .bottomBar) {
Button(isLatin ? "Dutch" : "Latin") {
isLatin.toggle()
}
}
ToolbarItem(placement: .bottomBar) {
Button(isMasked ? "Unmask" : "Mask") {
isMasked.toggle()
}
}
ToolbarItem(placement: .bottomBar) {
Button("Restart") {
currentZin = 1
}
}
ToolbarItem(placement: .bottomBar) {
Button("Next") {
if currentZin < hymn.verses.count {
currentZin += 1
}
}
}
}
}
func maskLetters(in sentence: String, with mask: Character = "*") -> String {
return sentence.map { char in
if char.isLetter {
return String(mask)
} else {
return String(char)
}
}.joined()
}
private func currentSentence(for verse: Verse) -> String {
var temp: String {
return isLatin ? verse.latijn : verse.nederlands
}
if isMasked {
return maskLetters(in: temp)
}
else {
return temp
}
}
}
#Preview {
/// the navigationStack is nodig omdat anders de toolbar niet zichtbaar is met #Preview
NavigationStack {
let allTexts = AllTexts()
HymnVerses(hymn: .preview).environment(allTexts)
}
}