Reputation: 509
So far I've tried watching the published value of the App events and updating the @State
property wrapper, but alas this has no runtime effect on the MenuBar commands.
struct MyCommands: Commands {
@State private var isShift = false
var body: some Commands {
CommandMenu("Things"){
Button("Thing A\(isShift ? " Shift" : "")"){
if isShift {
print("Thing A Shift")
} else {
print("Thing A")
}
}
.keyboardShortcut(.init(isShift ? "S" : "s"))
.onReceive(NSApplication.shared.publisher(for: \.currentEvent)) {
if let evt = $0 {
isShift = evt.modifierFlags.contains(.shift)
}
}
}
}
}
Upvotes: 1
Views: 436
Reputation: 509
I got it to work by actually taking the advice of ChrisR and moving the event detection to a StateObject and passing value into commands. For some reason the view diff won't change if updating commands from inside itself. Though not entirely sure if this is a bug or a feature.
Note: this is also visually jarring as you can see the menu flash for second when pressing shift, but in AppKit the menu would update instantly without flashing.
class EventWatch: ObservableObject {
@Published private(set) var modifiers: EventModifiers = []
private var watch: Set<AnyCancellable> = []
init(){
NSApplication.shared.publisher(for: \.currentEvent).sink{
if let event = $0 {
if event.type == .flagsChanged {
self.modifiers = EventModifiers(rawValue: Int(event.modifierFlags.rawValue))
}
}
}.store(in: &watch)
}
}
@main
struct MyApp: App {
@StateObject private var evt = EventWatch()
var body: some Scene {
WindowGroup("MyGroup") {
Text("My View").frame(minWidth: 1000, minHeight: 600)
}
.commands { MyCommands(isShift: evt.modifiers.contains(.shift)) }
}
}
Upvotes: 0
Reputation: 12165
This code just toggles the menu command by selecting it, and this works. So the question remains why the .onReceive
doesnt do it ...? Even if the @State change wouldn't trigger an immediate redraw in commands, it should still influence the next redraw on selecting the menu again.
struct MyCommands: Commands {
@State private var isShift = false
var body: some Commands {
CommandMenu("Things"){
Button("Thing A\(isShift ? " Shift" : "")"){
if isShift {
print("Thing A Shift")
} else {
print("Thing A")
}
isShift.toggle()
}
}
}
}
Upvotes: 1