Suppress undo during strokes.

pull/1/head
Matthew Chen 6 years ago
parent 9378ab2192
commit 3d67c6574d

@ -320,6 +320,13 @@ public class ImageEditorModel: NSObject {
private var undoStack = [ImageEditorOperation]() private var undoStack = [ImageEditorOperation]()
private var redoStack = [ImageEditorOperation]() private var redoStack = [ImageEditorOperation]()
// In some cases, we want to suppress changes to undo state.
// e.g. drawing a stroke will modify the model many times (once
// for each touch event/stroke sample), but we only want that
// to add a single undo operation.
private var isUndoSuppressed = false
private var suppressedUndoContents: ImageEditorContents?
// We don't want to allow editing of images if: // We don't want to allow editing of images if:
// //
// * They are invalid. // * They are invalid.
@ -365,6 +372,28 @@ public class ImageEditorModel: NSObject {
return !undoStack.isEmpty return !undoStack.isEmpty
} }
@objc
public func setIsUndoSuppressed(isUndoSuppressed: Bool) {
if isUndoSuppressed {
if self.isUndoSuppressed {
owsFailDebug("Undo already suppressed.")
}
if suppressedUndoContents != nil {
owsFailDebug("Unexpected suppressed undo contents.")
}
suppressedUndoContents = contents.clone()
} else {
if self.isUndoSuppressed {
if suppressedUndoContents == nil {
owsFailDebug("Missing suppressed undo contents.")
}
}
suppressedUndoContents = nil
}
self.isUndoSuppressed = isUndoSuppressed
}
@objc @objc
public func canRedo() -> Bool { public func canRedo() -> Bool {
return !redoStack.isEmpty return !redoStack.isEmpty
@ -402,29 +431,47 @@ public class ImageEditorModel: NSObject {
@objc @objc
public func append(item: ImageEditorItem) { public func append(item: ImageEditorItem) {
performAction { (newContents) in performAction({ (newContents) in
newContents.append(item: item) newContents.append(item: item)
} })
} }
@objc @objc
public func replace(item: ImageEditorItem) { public func replace(item: ImageEditorItem,
performAction { (newContents) in shouldRemoveUndoSuppression: Bool = false) {
performAction({ (newContents) in
newContents.replace(item: item) newContents.replace(item: item)
} }, shouldRemoveUndoSuppression: shouldRemoveUndoSuppression)
} }
@objc @objc
public func remove(item: ImageEditorItem) { public func remove(item: ImageEditorItem) {
performAction { (newContents) in performAction({ (newContents) in
newContents.remove(item: item) newContents.remove(item: item)
} })
} }
private func performAction(action: (ImageEditorContents) -> Void) { private func performAction(_ action: (ImageEditorContents) -> Void,
let undoOperation = ImageEditorOperation(contents: contents) shouldRemoveUndoSuppression: Bool = false) {
undoStack.append(undoOperation) if shouldRemoveUndoSuppression {
redoStack.removeAll() if !isUndoSuppressed {
owsFailDebug("Can't remove undo suppression, not suppressed.")
}
if let suppressedUndoContents = self.suppressedUndoContents {
let undoOperation = ImageEditorOperation(contents: suppressedUndoContents)
undoStack.append(undoOperation)
redoStack.removeAll()
} else {
owsFailDebug("Missing suppressed undo contents.")
}
self.isUndoSuppressed = false
setIsUndoSuppressed(isUndoSuppressed: false)
} else if !isUndoSuppressed {
let undoOperation = ImageEditorOperation(contents: contents)
undoStack.append(undoOperation)
redoStack.removeAll()
}
let newContents = contents.clone() let newContents = contents.clone()
action(newContents) action(newContents)

@ -107,6 +107,7 @@ public class ImageEditorView: UIView, ImageEditorModelDelegate {
if let stroke = self.currentStroke { if let stroke = self.currentStroke {
self.model.remove(item: stroke) self.model.remove(item: stroke)
} }
self.model.setIsUndoSuppressed(isUndoSuppressed: false)
self.currentStroke = nil self.currentStroke = nil
self.currentStrokeSamples.removeAll() self.currentStrokeSamples.removeAll()
} }
@ -131,9 +132,11 @@ public class ImageEditorView: UIView, ImageEditorModelDelegate {
currentStrokeSamples.append(unitSampleForGestureLocation()) currentStrokeSamples.append(unitSampleForGestureLocation())
let stroke = ImageEditorStrokeItem(color: strokeColor, unitSamples: self.currentStrokeSamples, unitStrokeWidth: unitStrokeWidth) model.setIsUndoSuppressed(isUndoSuppressed: true)
self.model.append(item: stroke)
self.currentStroke = stroke let stroke = ImageEditorStrokeItem(color: strokeColor, unitSamples: currentStrokeSamples, unitStrokeWidth: unitStrokeWidth)
model.append(item: stroke)
currentStroke = stroke
case .changed, .ended: case .changed, .ended:
currentStrokeSamples.append(unitSampleForGestureLocation()) currentStrokeSamples.append(unitSampleForGestureLocation())
@ -146,13 +149,15 @@ public class ImageEditorView: UIView, ImageEditorModelDelegate {
// Model items are immutable; we _replace_ the // Model items are immutable; we _replace_ the
// stroke item rather than modify it. // stroke item rather than modify it.
let stroke = ImageEditorStrokeItem(itemId: lastStroke.itemId, color: strokeColor, unitSamples: self.currentStrokeSamples, unitStrokeWidth: unitStrokeWidth) let stroke = ImageEditorStrokeItem(itemId: lastStroke.itemId, color: strokeColor, unitSamples: currentStrokeSamples, unitStrokeWidth: unitStrokeWidth)
self.model.replace(item: stroke)
self.currentStroke = stroke
if gestureRecognizer.state == .ended { if gestureRecognizer.state == .ended {
self.currentStroke = nil model.replace(item: stroke, shouldRemoveUndoSuppression: true)
self.currentStrokeSamples.removeAll() currentStroke = nil
currentStrokeSamples.removeAll()
} else {
model.replace(item: stroke)
currentStroke = stroke
} }
default: default:
removeCurrentStroke() removeCurrentStroke()

Loading…
Cancel
Save