When it comes to canRedo
I tried multiple things, and what I ended up with is this - so observing viewModel
(or document
or any other undo-supporting data source) and updating canUndo
/canRedo
in reaction to it's change:
struct MyView: View {
@ObservedObject var viewModel: ViewModel
@Environment(\.undoManager) private var undoManger: UndoManager!
@State private var canUndo = false
@State private var canRedo = false
var body: some View {
RootView()
.onReceive(viewModel.objectWillChange) { _ in
canUndo = undoManger.canUndo
canRedo = undoManger.canRedo
}
if canUndo {
Button(
action: { undoManger?.undo() },
label: { Text("Undo") }
)
}
if canRedo {
Button(
action: { undoManger?.redo() },
label: { Text("Redo") }
)
}
...
I also wrapped it in a standalone button (without overgeneralizing the implementation above my own needs) that eliminates the boilerplate from my view and keeps complexity more private so it ends up like this for me:
struct MyView: View {
@ObservedObject var viewModel: ViewModel
var body: some View {
RootView()
UndoManagerActionButton(
.undo,
willChangePublisher: viewModel.objectWillChange
)
UndoManagerActionButton(
.redo,
willChangePublisher: viewModel.objectWillChange
)
...