This is for MacOS. I am trying to send a message to a Model Object using a CommandMenu and then change the menu button title in response, with only partial success.
I am using @FocusedBinding and .focusedValue so that the model can be created in my view rather than at the App level. I want to do this so that I can switch to a document style app and have different model instances.
In the following example everything works as it should IF the model is a Struct. However I REQUIRE that the model be a Class so I can observe changes.
If the model is switched to a class by commenting out the struct Model and uncommenting the class Model in the example below there are two problems that I can't seem to fix:
First, the menu never switches from ‘Play’ to ‘Stop’
Second, I can’t change the Model var annotation to @StateObject - which is what a class really needs - without getting an error on the .focusedValue modifier.
Any help sorting this out would be greatly appreciated
import SwiftUI
@main
struct MessageApp : App {
var body: some Scene {
WindowGroup {
MessageView()
}
.commands {
AppCommands()
}
}
}
struct AppCommands : Commands {
struct PlayMenu : View {
@FocusedBinding(\.model) var model: Model?
var body: some View {
Button((model?.playing ?? false) ?
"Stop" : "Play", action: {
model?.send(command: .play)
}).keyboardShortcut(.space, modifiers: [])
}
}
var body: some Commands {
CommandMenu("Play") {
PlayMenu()
}
}
}
struct MessageView : View {
@State private var model = Model()
var body: some View {
Rectangle()
.focusedValue(\.model, $model)
.frame(idealWidth: 600, idealHeight: 400)
}
}
//class Model : ObservableObject{
// @Published var playing: Bool = false
//
// func send(command: ModelCommands) {
// playing.toggle()
// print(playing)
// }
//}
struct Model{
var playing: Bool = false
mutating func send(command: ModelCommands) {
playing.toggle()
print(playing)
}
}
struct FocusedModelBinding: FocusedValueKey {
typealias Value = Binding<Model>
}
extension FocusedValues {
var model: FocusedModelBinding.Value? {
get { self[FocusedModelBinding.self] }
set { self[FocusedModelBinding.self] = newValue }
}
}
enum ModelCommands: CaseIterable{
case play
}