Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Undo/Redo Feature for Mantis #379

Merged
merged 42 commits into from
Mar 24, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
b89f15b
Undo/Redo Feature for Mantis
rickshane Mar 21, 2024
819f732
Addressing comments in PR
rickshane Mar 21, 2024
01533eb
Add MantisExampleTests target back to project - somehow got deleted.
rickshane Mar 21, 2024
8a5e2d6
Adressing Comments in Chante List:
rickshane Mar 21, 2024
f795269
added logic to validate the Catalyst menus (disable undo menus when "…
rickshane Mar 21, 2024
ee8c1d6
Address latest round of comments
rickshane Mar 21, 2024
6ae4859
Rename some delegate methods:
rickshane Mar 21, 2024
c3303c0
TransformStack private now
rickshane Mar 21, 2024
a5e9e9a
changed actionString declaration.
rickshane Mar 22, 2024
7009fa9
removed unwanted space
rickshane Mar 22, 2024
2af9429
Removed some old code, that was not needed anymore when the function …
rickshane Mar 22, 2024
dc4e47e
removed func cropViewControllerDidImageTransformed(_ cropViewControl…
rickshane Mar 22, 2024
735eafb
Remove spaces
rickshane Mar 22, 2024
65240e4
removed public from some data types:
rickshane Mar 22, 2024
be9e774
TransformDelegate methods no longer public
rickshane Mar 22, 2024
7e2206b
moved opening brackets up to end of function declarations
rickshane Mar 22, 2024
b8f83d8
removed public modifier in all variables and function signatures in T…
rickshane Mar 22, 2024
2495ff4
removed public modifier from all variables and function signatures in…
rickshane Mar 22, 2024
8d0c2b0
Placeholder localization strings for "Change Crop" and "Reset Changes"
rickshane Mar 22, 2024
8ddb1fc
Localized "Change Crop" and "Reset Changes" using Google Translate.
rickshane Mar 22, 2024
c9c53dc
updated the README.md file to describe Undo/Redo support.
rickshane Mar 22, 2024
55788f5
Changed Chinese language localization strings
rickshane Mar 22, 2024
ab5fb50
Refactoring work:
rickshane Mar 22, 2024
a137282
- Fixed a localization bug
rickshane Mar 22, 2024
6fd5e0d
cleaned up property list for TransformRecord
rickshane Mar 22, 2024
93ec1ce
made dictionary passed to TransformRecord have strong type in value f…
rickshane Mar 22, 2024
63a343f
changed transformDelegate to an optional
rickshane Mar 22, 2024
ea58166
made private some variables in TransformStack
rickshane Mar 22, 2024
f141294
Add new files to Mantis.xcodeproj:
rickshane Mar 22, 2024
b65f9a4
remove dead code
rickshane Mar 22, 2024
9f6497e
Rename delegate methods in CropViewControllerDelegate:
rickshane Mar 22, 2024
eaf77c7
Remove blanl line
rickshane Mar 22, 2024
787ba3f
Simplify an optional value boolean test
rickshane Mar 22, 2024
49b3c1c
Remove three unused variables from TransformStack
rickshane Mar 22, 2024
06d4b10
Address a SwiftLint warning in TransformRecord
rickshane Mar 22, 2024
c0a8d3f
Address a SwiftLint warning in TransformRecord
rickshane Mar 22, 2024
458a2fb
Fixed Unit Tests in Mantis.xcodeproj related to new API for undo/redo…
rickshane Mar 22, 2024
de6bf10
remove first call to transform() in applyCropState() and just set the…
rickshane Mar 23, 2024
837046d
moved function "pushTransformRecordOntoStack" out of CropViewControll…
rickshane Mar 23, 2024
27fbaa1
added bounds check in TransformStack.popTransformStack()
rickshane Mar 24, 2024
1348f80
added Unit Test for TransformStack
rickshane Mar 24, 2024
6756398
Updated TransformStack Unit Test.
rickshane Mar 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions Example/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,40 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}

extension AppDelegate {

override func buildMenu(with builder: UIMenuBuilder) {
super.buildMenu(with: builder)

// Ensure that the builder is modifying the menu bar system.
guard builder.system == UIMenuSystem.main else { return }

// remove items from Edit menu
builder.remove(menu: .undoRedo)

// Undo
let undoCommand = UIKeyCommand(title: "Undo",
action: #selector(EmbeddedCropViewController.undoButtonPressed(_:)),
input: "z",
modifierFlags: [.command])


// Redo
let redoCommand = UIKeyCommand(title: "Redo",
action: #selector(EmbeddedCropViewController.redoButtonPressed(_:)),
input: "z",
modifierFlags: [.shift, .command])

// Revert
let revertCommand = UIKeyCommand(title: "Revert to Original",
action: #selector(EmbeddedCropViewController.resetButtonPressed(_:)),
input: "r",
modifierFlags: [.alternate])

let undoMenu = UIMenu(title: "", identifier: .undoRedo, options: .displayInline, children: [undoCommand, redoCommand, revertCommand ])

builder.insertChild(undoMenu, atStartOfMenu: .edit)

}
}
29 changes: 26 additions & 3 deletions Example/Base.lproj/Main.storyboard
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="22505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22504"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
Expand Down Expand Up @@ -174,7 +174,7 @@
</constraints>
</stackView>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="sunflower" translatesAutoresizingMaskIntoConstraints="NO" id="pUS-Eo-0ui" userLabel="Cropped Image">
<rect key="frame" x="32" y="16" width="311" height="342"/>
<rect key="frame" x="32" y="36" width="311" height="322"/>
</imageView>
</subviews>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
Expand Down Expand Up @@ -247,6 +247,23 @@
<action selector="cancel:" destination="aIe-ND-Zfg" id="j3e-ai-8lv"/>
</connections>
</barButtonItem>
<barButtonItem title="Undo" id="HSP-G5-UOE">
<color key="tintColor" systemColor="systemYellowColor"/>
<connections>
<action selector="undoButtonPressed:" destination="aIe-ND-Zfg" id="8eI-4B-Rt7"/>
</connections>
</barButtonItem>
<barButtonItem title="Redo" id="l1v-fT-hP5">
<color key="tintColor" systemColor="systemYellowColor"/>
<connections>
<action selector="redoButtonPressed:" destination="aIe-ND-Zfg" id="pck-70-va2"/>
</connections>
</barButtonItem>
<barButtonItem title="Reset" id="eee-mM-zNC">
<connections>
<action selector="resetButtonPressed:" destination="aIe-ND-Zfg" id="S6Q-y0-GYz"/>
</connections>
</barButtonItem>
<barButtonItem style="plain" systemItem="flexibleSpace" id="DsY-rM-AWO"/>
<barButtonItem systemItem="bookmarks" id="sQZ-M0-ZLt">
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
Expand All @@ -270,7 +287,10 @@
<connections>
<outlet property="cancelButton" destination="5p4-Ob-R9b" id="kQq-ir-MSf"/>
<outlet property="doneButton" destination="kZP-3N-vXv" id="RPY-W3-vWu"/>
<outlet property="redoButton" destination="l1v-fT-hP5" id="jYe-4F-ear"/>
<outlet property="resetButton" destination="eee-mM-zNC" id="Jfu-qz-XAZ"/>
<outlet property="resolutionLabel" destination="NDR-Th-Zyy" id="rUQ-h6-q2i"/>
<outlet property="undoButton" destination="HSP-G5-UOE" id="BLL-45-Dfn"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="xP6-ML-BEH" userLabel="First Responder" sceneMemberID="firstResponder"/>
Expand Down Expand Up @@ -322,5 +342,8 @@
<systemColor name="systemGray6Color">
<color red="0.94901960784313721" green="0.94901960784313721" blue="0.96862745098039216" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
<systemColor name="systemYellowColor">
<color red="1" green="0.80000000000000004" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
</resources>
</document>
146 changes: 146 additions & 0 deletions Example/EmbeddedCropViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,54 @@ import Mantis

class EmbeddedCropViewController: UIViewController {

let _undoManager : UndoManager! = UndoManager()

var image: UIImage?
var cropViewController: CropViewController?

weak var toolbarDelegate: CropToolbarDelegate?


var didGetCroppedImage: ((UIImage) -> Void)?

@IBOutlet weak var cancelButton: UIBarButtonItem!
@IBOutlet weak var doneButton: UIBarButtonItem!
@IBOutlet weak var resolutionLabel: UILabel!

@IBOutlet weak var undoButton: UIBarButtonItem!
@IBOutlet weak var redoButton: UIBarButtonItem!
@IBOutlet weak var resetButton: UIBarButtonItem!

override func viewDidLoad() {
super.viewDidLoad()

TransformStack.shared.sharedTransformDelegate = self
undoButton.title = "Undo"
redoButton.title = "Redo"
cancelButton.title = "Cancel"
doneButton.title = "Done"
resetButton.title = "Revert"

resolutionLabel.text = "\(getResolution(image: image) ?? "unknown")"

view.backgroundColor = .black
navigationController?.toolbar.backgroundColor = .black

self.undoButton.isEnabled = false
self.redoButton.isEnabled = false
self.resetButton.isEnabled = false
}

@IBAction func undoButtonPressed(_ sender: Any) {
undo()
}

@IBAction func redoButtonPressed(_ sender: Any) {
redo()
}

@IBAction func resetButtonPressed(_ sender: Any) {
cropViewController?.didSelectReset()
}

@IBAction func cancel(_ sender: Any) {
Expand All @@ -48,9 +78,13 @@ class EmbeddedCropViewController: UIViewController {

var config = Mantis.Config()
config.cropToolbarConfig.mode = .embedded

config.cropToolbarConfig.toolbarButtonOptions = [.counterclockwiseRotate, .clockwiseRotate, .horizontallyFlip, .verticallyFlip]

Mantis.setupCropViewController(cropViewController, with: image, and: config)

self.cropViewController = cropViewController
self.toolbarDelegate = cropViewController
}

private func getResolution(image: UIImage?) -> String? {
Expand All @@ -59,9 +93,71 @@ class EmbeddedCropViewController: UIViewController {
}
return nil
}

override func validate(_ command: UICommand) {

if command.action == #selector(EmbeddedCropViewController.undoButtonPressed(_:)) {

let undoString = NSLocalizedString("Undo", comment: "Undo")

command.title = self._undoManager.canUndo ? "\(undoString) \(self._undoManager.undoActionName)" : undoString

if !self._undoManager.canUndo {
command.attributes = [.disabled]
}
}

if command.action == #selector(EmbeddedCropViewController.redoButtonPressed(_:)) {

let redoString = NSLocalizedString("Redo", comment: "Redo")

command.title = self._undoManager.canRedo ? "\(redoString) \(self._undoManager.redoActionName)" : redoString

if !self._undoManager.canRedo {
command.attributes = [.disabled]
}

}

if command.action == #selector(EmbeddedCropViewController.resetButtonPressed(_:)) {

command.title = NSLocalizedString("Revert to Original", comment: "Revert to Original")

if !self.resetButton.isEnabled {
command.attributes = [.disabled]
}
}
}
}

extension EmbeddedCropViewController: CropViewControllerDelegate {

func cropViewControllerDidReset(previous: CropState, current: CropState) {

let actionString = NSLocalizedString("Reset Changes", comment: "Reset Changes")

let previousValue : [String : Any?] = [.kCurrentTransformState : previous]
let currentValue : [String : Any?] = [.kCurrentTransformState : current]

let transformRecord = TransformRecord(transformType: .resetTransforms, actionName: actionString, previousValues: previousValue, currentValues: currentValue)

transformRecord.addAdjustmentToStack()
}

func cropViewControllerDidTransformImage(previous: Mantis.CropState, current: Mantis.CropState, userGenerated: Bool) {

if userGenerated {
let actionString = NSLocalizedString("Change Crop", comment: "Change Crop")

let previousValue : [String : Any?] = [.kCurrentTransformState : previous]
let currentValue : [String : Any?] = [.kCurrentTransformState : current]

let transformRecord = TransformRecord(transformType: .transform, actionName: actionString, previousValues: previousValue, currentValues: currentValue)

transformRecord.addAdjustmentToStack()
}
}

func cropViewControllerDidCrop(_ cropViewController: CropViewController,
cropped: UIImage,
transformation: Transformation,
Expand All @@ -84,3 +180,53 @@ extension EmbeddedCropViewController: CropViewControllerDelegate {
}

}

extension EmbeddedCropViewController : TransformDelegate {

func enableResetButton(_ enable: Bool) {
self.resetButton.isEnabled = enable
}

func undoManager() -> UndoManager {
return _undoManager
}

func isUndoing() -> Bool {
return true
}

func isRedoing() -> Bool {
return true
}

func undo() {

// Change State
if _undoManager.canUndo {

_undoManager.undo()
}
}

func redo() {

// Change State
if _undoManager.canRedo {

_undoManager.redo()
}
}

func isRedoEnabled() -> Bool {
return _undoManager.canRedo
}

func isUndoEnabled() -> Bool {
return _undoManager.canUndo
}

func updateCropState(_ cropState: Any) {
guard let cropState = cropState as? CropState else { return }
toolbarDelegate?.didSelectTransform(with: cropState)
}
}
Loading