From be26c135e1c33111d4a43dd4dd9540e5d5d58d5c Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Wed, 27 Feb 2019 15:32:09 -0500 Subject: [PATCH] Rework image editor buttons, modes, etc. --- .../AttachmentApprovalViewController.swift | 3 +- .../ImageEditor/ImageEditorPaletteView.swift | 1 + .../Views/ImageEditor/ImageEditorView.swift | 121 +++++++++++------- 3 files changed, 78 insertions(+), 47 deletions(-) diff --git a/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift b/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift index 398c3e2c3..53b149cc9 100644 --- a/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift +++ b/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift @@ -953,7 +953,8 @@ public class AttachmentPrepViewController: OWSViewController, PlayerProgressBarD autoPinView(toBottomOfViewControllerOrKeyboard: imageEditorView, avoidNotch: true) imageEditorView.autoPinWidthToSuperview() - imageEditorView.addControls(to: imageEditorView) + imageEditorView.addControls(to: imageEditorView, + viewController: self) } } #endif diff --git a/SignalMessaging/Views/ImageEditor/ImageEditorPaletteView.swift b/SignalMessaging/Views/ImageEditor/ImageEditorPaletteView.swift index 1d4889198..1f35fe06d 100644 --- a/SignalMessaging/Views/ImageEditor/ImageEditorPaletteView.swift +++ b/SignalMessaging/Views/ImageEditor/ImageEditorPaletteView.swift @@ -140,6 +140,7 @@ public class ImageEditorPaletteView: UIView { let gradientLayer = CAGradientLayer() gradientView.layer.addSublayer(gradientLayer) gradientLayer.frame = gradientBounds + // See: https://github.com/signalapp/Signal-Android/blob/master/res/values/arrays.xml#L267 gradientLayer.colors = [ UIColor(rgbHex: 0xffffff).cgColor, UIColor(rgbHex: 0xff0000).cgColor, diff --git a/SignalMessaging/Views/ImageEditor/ImageEditorView.swift b/SignalMessaging/Views/ImageEditor/ImageEditorView.swift index b026f5540..4f6234503 100644 --- a/SignalMessaging/Views/ImageEditor/ImageEditorView.swift +++ b/SignalMessaging/Views/ImageEditor/ImageEditorView.swift @@ -29,12 +29,14 @@ public class ImageEditorView: UIView { // This is the default mode. It is used for interacting with text items. case none case brush + case text } private var editorMode = EditorMode.none { didSet { AssertIsOnMainThread() + updateButtons() updateGestureState() } } @@ -130,15 +132,18 @@ public class ImageEditorView: UIView { } // The model supports redo if we ever want to add it. - private let undoButton = UIButton(type: .custom) - private let brushButton = UIButton(type: .custom) - private let cropButton = UIButton(type: .custom) - private let newTextButton = UIButton(type: .custom) - private var allButtons = [UIButton]() + private let undoButton = OWSButton() + private let brushButton = OWSButton() + private let cropButton = OWSButton() + private let newTextButton = OWSButton() + private let captionButton = OWSButton() + private let doneButton = OWSButton() + private let buttonStackView = UIStackView() // TODO: Should this method be private? @objc - public func addControls(to containerView: UIView) { + public func addControls(to containerView: UIView, + viewController: UIViewController) { configure(button: undoButton, imageName: "image_editor_undo", selector: #selector(didTapUndo(sender:))) @@ -155,16 +160,21 @@ public class ImageEditorView: UIView { imageName: "image_editor_text", selector: #selector(didTapNewText(sender:))) - allButtons = [brushButton, cropButton, undoButton, newTextButton] + configure(button: captionButton, + imageName: "image_editor_caption", + selector: #selector(didTapCaption(sender:))) + + configure(button: doneButton, + imageName: "image_editor_checkmark_full", + selector: #selector(didTapDone(sender:))) - let stackView = UIStackView(arrangedSubviews: allButtons) - stackView.axis = .vertical - stackView.alignment = .center - stackView.spacing = 10 + buttonStackView.axis = .horizontal + buttonStackView.alignment = .center + buttonStackView.spacing = 20 - containerView.addSubview(stackView) - stackView.autoAlignAxis(toSuperviewAxis: .horizontal) - stackView.autoPinTrailingToSuperviewMargin(withInset: 10) + containerView.addSubview(buttonStackView) + buttonStackView.autoPin(toTopLayoutGuideOf: viewController, withInset: 0) + buttonStackView.autoPinTrailingToSuperviewMargin(withInset: 18) containerView.addSubview(paletteView) paletteView.autoVCenterInSuperview() @@ -182,10 +192,6 @@ public class ImageEditorView: UIView { owsFailDebug("Missing asset: \(imageName)") } button.tintColor = .white - button.setTitleColor(.white, for: .normal) - button.setTitleColor(.gray, for: .disabled) - button.setTitleColor(UIColor.ows_materialBlue, for: .selected) - button.titleLabel?.font = UIFont.ows_dynamicTypeBody.ows_mediumWeight() button.addTarget(self, action: selector, for: .touchUpInside) button.layer.shadowColor = UIColor.black.cgColor button.layer.shadowRadius = 4 @@ -193,14 +199,39 @@ public class ImageEditorView: UIView { } private func updateButtons() { - undoButton.isEnabled = model.canUndo() - brushButton.isSelected = editorMode == .brush - cropButton.isSelected = false - newTextButton.isSelected = false + var buttons = [OWSButton]() + + var hasPalette = false + switch editorMode { + case .text: + // TODO: + hasPalette = true + break + case .brush: + hasPalette = true + + if model.canUndo() { + buttons = [undoButton, doneButton] + } else { + buttons = [doneButton] + } + case .none: + if model.canUndo() { + buttons = [undoButton, newTextButton, brushButton, cropButton, captionButton] + } else { + buttons = [newTextButton, brushButton, cropButton, captionButton] + } + } - for button in allButtons { - button.isHidden = isEditingTextItem + for subview in buttonStackView.subviews { + subview.removeFromSuperview() } + buttonStackView.addArrangedSubview(UIView.hStretchingSpacer()) + for button in buttons { + buttonStackView.addArrangedSubview(button) + } + + paletteView.isHidden = !hasPalette } // MARK: - Actions @@ -217,7 +248,7 @@ public class ImageEditorView: UIView { @objc func didTapBrush(sender: UIButton) { Logger.verbose("") - toggle(editorMode: .brush) + self.editorMode = .brush } @objc func didTapCrop(sender: UIButton) { @@ -244,13 +275,16 @@ public class ImageEditorView: UIView { edit(textItem: textItem) } - func toggle(editorMode: EditorMode) { - if self.editorMode == editorMode { - self.editorMode = .none - } else { - self.editorMode = editorMode - } - updateButtons() + @objc func didTapCaption(sender: UIButton) { + Logger.verbose("") + + // TODO: + } + + @objc func didTapDone(sender: UIButton) { + Logger.verbose("") + + self.editorMode = .none } // MARK: - Gestures @@ -270,6 +304,11 @@ public class ImageEditorView: UIView { brushGestureRecognizer?.isEnabled = true tapGestureRecognizer?.isEnabled = false pinchGestureRecognizer?.isEnabled = false + case .text: + moveTextGestureRecognizer?.isEnabled = false + brushGestureRecognizer?.isEnabled = false + tapGestureRecognizer?.isEnabled = false + pinchGestureRecognizer?.isEnabled = false } } @@ -537,20 +576,10 @@ public class ImageEditorView: UIView { // MARK: - Edit Text Tool - private var isEditingTextItem = false { - didSet { - AssertIsOnMainThread() - - updateButtons() - } - } - private func edit(textItem: ImageEditorTextItem) { Logger.verbose("") - toggle(editorMode: .none) - - isEditingTextItem = true + self.editorMode = .text // TODO: let maxTextWidthPoints = model.srcImageSizePixels.width * ImageEditorTextItem.kDefaultUnitWidth @@ -566,7 +595,7 @@ public class ImageEditorView: UIView { private func presentCropTool() { Logger.verbose("") - toggle(editorMode: .none) + self.editorMode = .none guard let srcImage = canvasView.loadSrcImage() else { owsFailDebug("Couldn't load src image.") @@ -628,7 +657,7 @@ extension ImageEditorView: ImageEditorTextViewControllerDelegate { public func textEditDidComplete(textItem: ImageEditorTextItem, text: String?) { AssertIsOnMainThread() - isEditingTextItem = false + self.editorMode = .none guard let text = text?.ows_stripped(), text.count > 0 else { @@ -648,7 +677,7 @@ extension ImageEditorView: ImageEditorTextViewControllerDelegate { } public func textEditDidCancel() { - isEditingTextItem = false + self.editorMode = .none } }