I'm making a Document App and I have a bunch of @State variables for passing around information about what things are selected in different parts of the app. For example:
@main
struct ClaraApp: App {
@State var activeTab: TabType = .vocab
@State var selectedVocab: Vocab.ID?
@State var selectedLearner: Learner.ID?
@State var selectedLesson: Lesson.ID?
@State var selectedAttendance: Attendance.ID?
…
Which are then used as Binding variables in the relevant views.
struct VocabView: View{
@Binding var selectedVocab: Vocab.ID?
…
With this, I can refer to the currently selected vocabulary item in a TableView from a function running in the Menu Commands.
This was working fine, until I started playing around with having multiple documents open. I've realised that using State variables in this results in some rather undesirable behaviour where controlling one document ends up controlling any others open.
I also have some auxiliary windows to show data (the idea is that these will be on a projected screen). Ideally, changing from one document to another should change the data displayed on them, but it works very inconsistently with my current method. One of the windows wouldn't update at all, it got so confused.
None of this behaviour is especially surprising. The variables are declared at the App level, so of course they will apply across all open documents. I also need them at that level because I need to pass them to menu commands and across different views.
It occurred to me that one way around this (or at least the first part of this issue) would be to store all these State variables (active tab, selected learner etc.) in the document itself. This would have the added advantage of bringing the user straight back to what they were last doing when they open a document. However, something about making a change to a document every single time you click on an item in a list seems a bit off to me.
Would that be the best practice here? Is there a better way of having a different set of State variables for each open document, which are still accessible at the App level? Is there a way to detect which document currently has focus?
EDIT: Here's a bit more of the code from the app struct, for a little more context.
@main
struct ClaraApp: App {
@State var activeTab: TabType = .vocab
@State var selectedVocab: Vocab.ID?
@State var selectedLearner: Learner.ID?
@State var selectedLesson: Lesson.ID?
@State var selectedAttendance: Attendance.ID?
@State var attendeeList: [String]?
@State var vocabReader: [Vocab]?
var body: some Scene {
DocumentGroup(newDocument: ClaraDocument(claraDoc:GroupVocab())) { file in
MainContentView(data: file.$document, activeTab: $activeTab, selectedVocab: $selectedVocab, selectedLearner: $selectedLearner, selectedAttendance: $selectedAttendance, selectedLesson: $selectedLesson, attendeeList: $attendeeList, vocabReader: $vocabReader)
.focusedSceneValue(\.document, file.$document)
.commands{
MenuCommands(activeTab: $activeTab, selectedVocab: $selectedVocab, selectedLearner: $selectedLearner, selectedLesson: $selectedLesson, selectedAttendance: $selectedAttendance, attendeeList: $attendeeList)
}
WindowGroup("Name Picker"){
NamePickerView(names: attendeeList ?? [""], selectedLesson: selectedLesson)
}.handlesExternalEvents(matching: Set(arrayLiteral: "NamePickerWindow"))
WindowGroup("Vocabulary Display"){
VocabDisplayView(vocabs: vocabReader ?? [Vocab()])
}.handlesExternalEvents(matching: Set(arrayLiteral: "VocabDisplayWindow"))
}
}
EDIT: Following this solution, I'm making some changes https://stackoverflow.com/a/68334001/2682035 However, currently stuck on some menu command buttons not recognising changes immediately. Will post full solution when I've worked it out.