mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
Clean up image editor.
This commit is contained in:
parent
97660e0a11
commit
b64be3aa73
6 changed files with 172 additions and 229 deletions
|
@ -4,16 +4,6 @@
|
|||
|
||||
import UIKit
|
||||
|
||||
//@objc
|
||||
//public protocol ImageEditorViewDelegate: class {
|
||||
// func imageEditor(presentFullScreenOverlay viewController: UIViewController,
|
||||
// withNavigation: Bool)
|
||||
// func imageEditorPresentCaptionView()
|
||||
// func imageEditorUpdateNavigationBar()
|
||||
//}
|
||||
|
||||
// MARK: -
|
||||
|
||||
@objc
|
||||
public protocol ImageEditorBrushViewControllerDelegate: class {
|
||||
func brushDidComplete()
|
||||
|
@ -30,15 +20,17 @@ public class ImageEditorBrushViewController: OWSViewController {
|
|||
|
||||
private let canvasView: ImageEditorCanvasView
|
||||
|
||||
private let paletteView = ImageEditorPaletteView()
|
||||
private let paletteView: ImageEditorPaletteView
|
||||
|
||||
private var brushGestureRecognizer: ImageEditorPanGestureRecognizer?
|
||||
|
||||
init(delegate: ImageEditorBrushViewControllerDelegate,
|
||||
model: ImageEditorModel) {
|
||||
model: ImageEditorModel,
|
||||
currentColor: ImageEditorColor) {
|
||||
self.delegate = delegate
|
||||
self.model = model
|
||||
self.canvasView = ImageEditorCanvasView(model: model)
|
||||
self.paletteView = ImageEditorPaletteView(currentColor: currentColor)
|
||||
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
|
||||
|
@ -55,6 +47,7 @@ public class ImageEditorBrushViewController: OWSViewController {
|
|||
public override func loadView() {
|
||||
self.view = UIView()
|
||||
self.view.backgroundColor = .black
|
||||
self.view.isOpaque = true
|
||||
|
||||
canvasView.configureSubviews()
|
||||
self.view.addSubview(canvasView)
|
||||
|
@ -63,7 +56,7 @@ public class ImageEditorBrushViewController: OWSViewController {
|
|||
paletteView.delegate = self
|
||||
self.view.addSubview(paletteView)
|
||||
paletteView.autoVCenterInSuperview()
|
||||
paletteView.autoPinEdge(toSuperviewEdge: .leading, withInset: 20)
|
||||
paletteView.autoPinEdge(toSuperviewEdge: .trailing, withInset: 20)
|
||||
|
||||
self.view.isUserInteractionEnabled = true
|
||||
|
||||
|
@ -103,12 +96,6 @@ public class ImageEditorBrushViewController: OWSViewController {
|
|||
updateNavigationBar(navigationBarItems: navigationBarItems)
|
||||
}
|
||||
|
||||
private var currentColor: UIColor {
|
||||
get {
|
||||
return paletteView.selectedColor
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Actions
|
||||
|
||||
@objc func didTapUndo(sender: UIButton) {
|
||||
|
@ -168,7 +155,7 @@ public class ImageEditorBrushViewController: OWSViewController {
|
|||
self.currentStrokeSamples.append(newSample)
|
||||
}
|
||||
|
||||
let strokeColor = currentColor
|
||||
let strokeColor = paletteView.selectedValue.color
|
||||
// TODO: Tune stroke width.
|
||||
let unitStrokeWidth = ImageEditorStrokeItem.defaultUnitStrokeWidth()
|
||||
|
||||
|
|
|
@ -10,11 +10,60 @@ public protocol ImageEditorPaletteViewDelegate: class {
|
|||
|
||||
// MARK: -
|
||||
|
||||
@objc
|
||||
public class ImageEditorColor: NSObject {
|
||||
public let color: UIColor
|
||||
|
||||
// Colors are chosen from a spectrum of colors.
|
||||
// This unit value represents the location of the
|
||||
// color within that spectrum.
|
||||
public let palettePhase: CGFloat
|
||||
|
||||
public var cgColor: CGColor {
|
||||
return color.cgColor
|
||||
}
|
||||
|
||||
public required init(color: UIColor, palettePhase: CGFloat) {
|
||||
self.color = color
|
||||
self.palettePhase = palettePhase
|
||||
}
|
||||
|
||||
public class func defaultColor() -> ImageEditorColor {
|
||||
return ImageEditorColor(color: UIColor(rgbHex: 0xffffff), palettePhase: 0)
|
||||
}
|
||||
|
||||
public static var gradientUIColors: [UIColor] {
|
||||
return [
|
||||
UIColor(rgbHex: 0xffffff),
|
||||
UIColor(rgbHex: 0xff0000),
|
||||
UIColor(rgbHex: 0xff00ff),
|
||||
UIColor(rgbHex: 0x0000ff),
|
||||
UIColor(rgbHex: 0x00ffff),
|
||||
UIColor(rgbHex: 0x00ff00),
|
||||
UIColor(rgbHex: 0xffff00),
|
||||
UIColor(rgbHex: 0xff5500),
|
||||
UIColor(rgbHex: 0x000000)
|
||||
]
|
||||
}
|
||||
|
||||
public static var gradientCGColors: [CGColor] {
|
||||
return gradientUIColors.map({ (color) in
|
||||
return color.cgColor
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
public class ImageEditorPaletteView: UIView {
|
||||
|
||||
public weak var delegate: ImageEditorPaletteViewDelegate?
|
||||
|
||||
public required init() {
|
||||
public var selectedValue: ImageEditorColor
|
||||
|
||||
public required init(currentColor: ImageEditorColor) {
|
||||
self.selectedValue = currentColor
|
||||
|
||||
super.init(frame: .zero)
|
||||
|
||||
createContents()
|
||||
|
@ -27,9 +76,6 @@ public class ImageEditorPaletteView: UIView {
|
|||
|
||||
// MARK: - Views
|
||||
|
||||
// The actual default is selected later.
|
||||
public var selectedColor = UIColor.white
|
||||
|
||||
private let imageView = UIImageView()
|
||||
private let selectionView = UIView()
|
||||
private let selectionWrapper = OWSLayerView()
|
||||
|
@ -84,36 +130,36 @@ public class ImageEditorPaletteView: UIView {
|
|||
// 0 = the color at the top of the image is selected.
|
||||
// 1 = the color at the bottom of the image is selected.
|
||||
private let selectionSize: CGFloat = 20
|
||||
private var selectionAlpha: CGFloat = 0
|
||||
|
||||
private func selectColor(atLocationY y: CGFloat) {
|
||||
selectionAlpha = y.inverseLerp(0, imageView.height(), shouldClamp: true)
|
||||
let palettePhase = y.inverseLerp(0, imageView.height(), shouldClamp: true)
|
||||
self.selectedValue = value(for: palettePhase)
|
||||
|
||||
updateState()
|
||||
|
||||
delegate?.selectedColorDidChange()
|
||||
}
|
||||
|
||||
private func updateState() {
|
||||
var selectedColor = UIColor.white
|
||||
if let image = imageView.image {
|
||||
if let imageColor = image.color(atLocation: CGPoint(x: CGFloat(image.size.width) * 0.5, y: CGFloat(image.size.height) * selectionAlpha)) {
|
||||
selectedColor = imageColor
|
||||
} else {
|
||||
owsFailDebug("Couldn't determine image color.")
|
||||
}
|
||||
} else {
|
||||
private func value(for palettePhase: CGFloat) -> ImageEditorColor {
|
||||
guard let image = imageView.image else {
|
||||
owsFailDebug("Missing image.")
|
||||
return ImageEditorColor.defaultColor()
|
||||
}
|
||||
self.selectedColor = selectedColor
|
||||
guard let color = image.color(atLocation: CGPoint(x: CGFloat(image.size.width) * 0.5, y: CGFloat(image.size.height) * palettePhase)) else {
|
||||
owsFailDebug("Missing color.")
|
||||
return ImageEditorColor.defaultColor()
|
||||
}
|
||||
return ImageEditorColor(color: color, palettePhase: palettePhase)
|
||||
}
|
||||
|
||||
selectionView.backgroundColor = selectedColor
|
||||
private func updateState() {
|
||||
selectionView.backgroundColor = selectedValue.color
|
||||
|
||||
guard let selectionConstraint = selectionConstraint else {
|
||||
owsFailDebug("Missing selectionConstraint.")
|
||||
return
|
||||
}
|
||||
let selectionY = selectionWrapper.height() * selectionAlpha
|
||||
let selectionY = selectionWrapper.height() * selectedValue.palettePhase
|
||||
selectionConstraint.constant = selectionY
|
||||
}
|
||||
|
||||
|
@ -142,17 +188,7 @@ public class ImageEditorPaletteView: UIView {
|
|||
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,
|
||||
UIColor(rgbHex: 0xff00ff).cgColor,
|
||||
UIColor(rgbHex: 0x0000ff).cgColor,
|
||||
UIColor(rgbHex: 0x00ffff).cgColor,
|
||||
UIColor(rgbHex: 0x00ff00).cgColor,
|
||||
UIColor(rgbHex: 0xffff00).cgColor,
|
||||
UIColor(rgbHex: 0xff5500).cgColor,
|
||||
UIColor(rgbHex: 0x000000).cgColor
|
||||
]
|
||||
gradientLayer.colors = ImageEditorColor.gradientCGColors
|
||||
gradientLayer.startPoint = CGPoint.zero
|
||||
gradientLayer.endPoint = CGPoint(x: 0, y: gradientSize.height)
|
||||
gradientLayer.endPoint = CGPoint(x: 0, y: 1.0)
|
||||
|
|
|
@ -11,7 +11,7 @@ public class ImageEditorTextItem: ImageEditorItem {
|
|||
public let text: String
|
||||
|
||||
@objc
|
||||
public let color: UIColor
|
||||
public let color: ImageEditorColor
|
||||
|
||||
@objc
|
||||
public let font: UIFont
|
||||
|
@ -60,7 +60,7 @@ public class ImageEditorTextItem: ImageEditorItem {
|
|||
|
||||
@objc
|
||||
public init(text: String,
|
||||
color: UIColor,
|
||||
color: ImageEditorColor,
|
||||
font: UIFont,
|
||||
fontReferenceImageWidth: CGFloat,
|
||||
unitCenter: ImageEditorSample = ImageEditorSample(x: 0.5, y: 0.5),
|
||||
|
@ -81,7 +81,7 @@ public class ImageEditorTextItem: ImageEditorItem {
|
|||
|
||||
private init(itemId: String,
|
||||
text: String,
|
||||
color: UIColor,
|
||||
color: ImageEditorColor,
|
||||
font: UIFont,
|
||||
fontReferenceImageWidth: CGFloat,
|
||||
unitCenter: ImageEditorSample,
|
||||
|
@ -101,17 +101,17 @@ public class ImageEditorTextItem: ImageEditorItem {
|
|||
}
|
||||
|
||||
@objc
|
||||
public class func empty(withColor color: UIColor, unitWidth: CGFloat, fontReferenceImageWidth: CGFloat) -> ImageEditorTextItem {
|
||||
public class func empty(withColor color: ImageEditorColor, unitWidth: CGFloat, fontReferenceImageWidth: CGFloat) -> ImageEditorTextItem {
|
||||
// TODO: Tune the default font size.
|
||||
let font = UIFont.boldSystemFont(ofSize: 30.0)
|
||||
return ImageEditorTextItem(text: "", color: color, font: font, fontReferenceImageWidth: fontReferenceImageWidth, unitWidth: unitWidth)
|
||||
}
|
||||
|
||||
@objc
|
||||
public func copy(withText newText: String) -> ImageEditorTextItem {
|
||||
public func copy(withText newText: String, color newColor: ImageEditorColor) -> ImageEditorTextItem {
|
||||
return ImageEditorTextItem(itemId: itemId,
|
||||
text: newText,
|
||||
color: color,
|
||||
color: newColor,
|
||||
font: font,
|
||||
fontReferenceImageWidth: fontReferenceImageWidth,
|
||||
unitCenter: unitCenter,
|
||||
|
|
|
@ -92,7 +92,7 @@ private class VAlignTextView: UITextView {
|
|||
|
||||
@objc
|
||||
public protocol ImageEditorTextViewControllerDelegate: class {
|
||||
func textEditDidComplete(textItem: ImageEditorTextItem, text: String?)
|
||||
func textEditDidComplete(textItem: ImageEditorTextItem, text: String?, color: ImageEditorColor)
|
||||
func textEditDidCancel()
|
||||
}
|
||||
|
||||
|
@ -106,14 +106,24 @@ public class ImageEditorTextViewController: OWSViewController, VAlignTextViewDel
|
|||
|
||||
private let maxTextWidthPoints: CGFloat
|
||||
|
||||
private let textView = VAlignTextView(alignment: .bottom)
|
||||
private let textView = VAlignTextView(alignment: .center)
|
||||
|
||||
private let model: ImageEditorModel
|
||||
|
||||
private let canvasView: ImageEditorCanvasView
|
||||
|
||||
private let paletteView: ImageEditorPaletteView
|
||||
|
||||
init(delegate: ImageEditorTextViewControllerDelegate,
|
||||
model: ImageEditorModel,
|
||||
textItem: ImageEditorTextItem,
|
||||
maxTextWidthPoints: CGFloat) {
|
||||
self.delegate = delegate
|
||||
self.model = model
|
||||
self.textItem = textItem
|
||||
self.maxTextWidthPoints = maxTextWidthPoints
|
||||
self.canvasView = ImageEditorCanvasView(model: model)
|
||||
self.paletteView = ImageEditorPaletteView(currentColor: textItem.color)
|
||||
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
|
||||
|
@ -131,43 +141,63 @@ public class ImageEditorTextViewController: OWSViewController, VAlignTextViewDel
|
|||
super.viewWillAppear(animated)
|
||||
|
||||
textView.becomeFirstResponder()
|
||||
|
||||
self.view.layoutSubviews()
|
||||
}
|
||||
|
||||
public override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
textView.becomeFirstResponder()
|
||||
|
||||
self.view.layoutSubviews()
|
||||
}
|
||||
|
||||
public override func loadView() {
|
||||
self.view = UIView()
|
||||
self.view.backgroundColor = UIColor(white: 0.5, alpha: 0.5)
|
||||
self.view.backgroundColor = .black
|
||||
self.view.isOpaque = true
|
||||
|
||||
canvasView.configureSubviews()
|
||||
self.view.addSubview(canvasView)
|
||||
canvasView.autoPinEdgesToSuperviewEdges()
|
||||
|
||||
let tintView = UIView()
|
||||
tintView.backgroundColor = UIColor(white: 0, alpha: 0.33)
|
||||
tintView.isOpaque = false
|
||||
self.view.addSubview(tintView)
|
||||
tintView.autoPinEdgesToSuperviewEdges()
|
||||
tintView.layer.opacity = 0
|
||||
UIView.animate(withDuration: 0.25, animations: {
|
||||
tintView.layer.opacity = 1
|
||||
}, completion: { (_) in
|
||||
tintView.layer.opacity = 1
|
||||
})
|
||||
|
||||
configureTextView()
|
||||
|
||||
navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .stop,
|
||||
target: self,
|
||||
action: #selector(didTapBackButton))
|
||||
|
||||
self.view.layoutMargins = UIEdgeInsets(top: 16, left: 20, bottom: 16, right: 20)
|
||||
|
||||
self.view.addSubview(textView)
|
||||
textView.autoPinTopToSuperviewMargin()
|
||||
textView.autoHCenterInSuperview()
|
||||
// In order to have text wrapping be as WYSIWYG as possible, we limit the text view
|
||||
// to the max text width on the image.
|
||||
// let maxTextWidthPoints = max(textItem.widthPoints, 200)
|
||||
// textView.autoSetDimension(.width, toSize: maxTextWidthPoints, relation: .lessThanOrEqual)
|
||||
// textView.autoPinEdge(toSuperviewMargin: .leading, relation: .greaterThanOrEqual)
|
||||
// textView.autoPinEdge(toSuperviewMargin: .trailing, relation: .greaterThanOrEqual)
|
||||
textView.autoPinEdge(toSuperviewMargin: .leading)
|
||||
textView.autoPinEdge(toSuperviewMargin: .trailing)
|
||||
self.autoPinView(toBottomOfViewControllerOrKeyboard: textView, avoidNotch: true)
|
||||
|
||||
// TODO: Honor old color state.
|
||||
paletteView.delegate = self
|
||||
self.view.addSubview(paletteView)
|
||||
paletteView.autoVCenterInSuperview()
|
||||
paletteView.autoPinEdge(toSuperviewEdge: .trailing, withInset: 20)
|
||||
// This will determine the text view's size.
|
||||
paletteView.autoPinEdge(.leading, to: .trailing, of: textView, withOffset: 8)
|
||||
|
||||
updateNavigationBar()
|
||||
}
|
||||
|
||||
private func configureTextView() {
|
||||
textView.text = textItem.text
|
||||
textView.font = textItem.font
|
||||
textView.textColor = textItem.color
|
||||
textView.textColor = textItem.color.color
|
||||
|
||||
textView.isEditable = true
|
||||
textView.backgroundColor = .clear
|
||||
|
@ -186,23 +216,37 @@ public class ImageEditorTextViewController: OWSViewController, VAlignTextViewDel
|
|||
textView.contentInset = .zero
|
||||
}
|
||||
|
||||
private func updateNavigationBar() {
|
||||
let undoButton = navigationBarButton(imageName: "image_editor_undo",
|
||||
selector: #selector(didTapUndo(sender:)))
|
||||
let doneButton = navigationBarButton(imageName: "image_editor_checkmark_full",
|
||||
selector: #selector(didTapDone(sender:)))
|
||||
|
||||
let navigationBarItems = [undoButton, doneButton]
|
||||
updateNavigationBar(navigationBarItems: navigationBarItems)
|
||||
}
|
||||
|
||||
// MARK: - Events
|
||||
|
||||
@objc public func didTapBackButton() {
|
||||
@objc func didTapUndo(sender: UIButton) {
|
||||
Logger.verbose("")
|
||||
|
||||
// TODO: Honor color state.
|
||||
self.delegate?.textEditDidCancel()
|
||||
|
||||
self.dismiss(animated: false) {
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
||||
|
||||
@objc func didTapDone(sender: UIButton) {
|
||||
Logger.verbose("")
|
||||
|
||||
completeAndDismiss()
|
||||
}
|
||||
|
||||
private func completeAndDismiss() {
|
||||
|
||||
// Before we take a screenshot, make sure selection state
|
||||
// auto-complete suggestions, cursor don't affect screenshot.
|
||||
textView.resignFirstResponder()
|
||||
if textView.isFirstResponder {
|
||||
owsFailDebug("Text view is still first responder.")
|
||||
}
|
||||
textView.selectedTextRange = nil
|
||||
|
||||
self.delegate?.textEditDidComplete(textItem: textItem, text: textView.text)
|
||||
self.delegate?.textEditDidComplete(textItem: textItem, text: textView.text, color: paletteView.selectedValue)
|
||||
|
||||
self.dismiss(animated: false) {
|
||||
// Do nothing.
|
||||
|
@ -215,3 +259,11 @@ public class ImageEditorTextViewController: OWSViewController, VAlignTextViewDel
|
|||
completeAndDismiss()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
extension ImageEditorTextViewController: ImageEditorPaletteViewDelegate {
|
||||
public func selectedColorDidChange() {
|
||||
self.textView.textColor = self.paletteView.selectedValue.color
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,30 +25,8 @@ public class ImageEditorView: UIView {
|
|||
|
||||
private let canvasView: ImageEditorCanvasView
|
||||
|
||||
private let paletteView = ImageEditorPaletteView()
|
||||
|
||||
enum EditorMode: String {
|
||||
// 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()
|
||||
delegate?.imageEditorUpdateNavigationBar()
|
||||
}
|
||||
}
|
||||
|
||||
private var currentColor: UIColor {
|
||||
get {
|
||||
return paletteView.selectedColor
|
||||
}
|
||||
}
|
||||
// TODO: We could hang this on the model or make this static.
|
||||
private var currentColor = ImageEditorColor.defaultColor()
|
||||
|
||||
@objc
|
||||
public required init(model: ImageEditorModel, delegate: ImageEditorViewDelegate) {
|
||||
|
@ -78,8 +56,6 @@ public class ImageEditorView: UIView {
|
|||
self.addSubview(canvasView)
|
||||
canvasView.autoPinEdgesToSuperviewEdges()
|
||||
|
||||
paletteView.delegate = self
|
||||
|
||||
self.isUserInteractionEnabled = true
|
||||
|
||||
let moveTextGestureRecognizer = ImageEditorPanGestureRecognizer(target: self, action: #selector(handleMoveTextGesture(_:)))
|
||||
|
@ -102,60 +78,16 @@ public class ImageEditorView: UIView {
|
|||
// editorGestureRecognizer.require(toFail: tapGestureRecognizer)
|
||||
// editorGestureRecognizer.require(toFail: pinchGestureRecognizer)
|
||||
|
||||
updateGestureState()
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private func commitTextEditingChanges(textItem: ImageEditorTextItem, textView: UITextView) {
|
||||
AssertIsOnMainThread()
|
||||
|
||||
guard let text = textView.text?.ows_stripped(),
|
||||
text.count > 0 else {
|
||||
model.remove(item: textItem)
|
||||
return
|
||||
}
|
||||
|
||||
// Model items are immutable; we _replace_ the item rather than modify it.
|
||||
let newItem = textItem.copy(withText: text)
|
||||
if model.has(itemForId: textItem.itemId) {
|
||||
model.replace(item: newItem, suppressUndo: false)
|
||||
} else {
|
||||
model.append(item: newItem)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Should this method be private?
|
||||
@objc
|
||||
public func addControls(to containerView: UIView,
|
||||
viewController: UIViewController) {
|
||||
|
||||
containerView.addSubview(paletteView)
|
||||
paletteView.autoVCenterInSuperview()
|
||||
paletteView.autoPinLeadingToSuperviewMargin(withInset: 10)
|
||||
|
||||
updateButtons()
|
||||
|
||||
delegate?.imageEditorUpdateNavigationBar()
|
||||
}
|
||||
|
||||
private func updateButtons() {
|
||||
var hasPalette = false
|
||||
switch editorMode {
|
||||
case .text:
|
||||
// TODO:
|
||||
hasPalette = true
|
||||
break
|
||||
case .brush:
|
||||
hasPalette = true
|
||||
case .none:
|
||||
hasPalette = false
|
||||
break
|
||||
}
|
||||
|
||||
paletteView.isHidden = !hasPalette
|
||||
}
|
||||
|
||||
// MARK: - Navigation Bar
|
||||
|
||||
public func navigationBarItems() -> [UIView] {
|
||||
|
@ -170,17 +102,10 @@ public class ImageEditorView: UIView {
|
|||
let captionButton = navigationBarButton(imageName: "image_editor_caption",
|
||||
selector: #selector(didTapCaption(sender:)))
|
||||
|
||||
switch editorMode {
|
||||
case .text:
|
||||
return []
|
||||
case .brush:
|
||||
return []
|
||||
case .none:
|
||||
if model.canUndo() {
|
||||
return [undoButton, newTextButton, brushButton, cropButton, captionButton]
|
||||
} else {
|
||||
return [newTextButton, brushButton, cropButton, captionButton]
|
||||
}
|
||||
if model.canUndo() {
|
||||
return [undoButton, newTextButton, brushButton, cropButton, captionButton]
|
||||
} else {
|
||||
return [newTextButton, brushButton, cropButton, captionButton]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -198,9 +123,7 @@ public class ImageEditorView: UIView {
|
|||
@objc func didTapBrush(sender: UIButton) {
|
||||
Logger.verbose("")
|
||||
|
||||
self.editorMode = .brush
|
||||
|
||||
let brushView = ImageEditorBrushViewController(delegate: self, model: model)
|
||||
let brushView = ImageEditorBrushViewController(delegate: self, model: model, currentColor: currentColor)
|
||||
self.delegate?.imageEditor(presentFullScreenOverlay: brushView,
|
||||
withNavigation: true)
|
||||
}
|
||||
|
@ -233,44 +156,10 @@ public class ImageEditorView: UIView {
|
|||
Logger.verbose("")
|
||||
|
||||
delegate?.imageEditorPresentCaptionView()
|
||||
|
||||
// // TODO:
|
||||
// let maxTextWidthPoints = model.srcImageSizePixels.width * ImageEditorTextItem.kDefaultUnitWidth
|
||||
// // let maxTextWidthPoints = canvasView.imageView.width() * ImageEditorTextItem.kDefaultUnitWidth
|
||||
//
|
||||
// let textEditor = ImageEditorTextViewController(delegate: self, textItem: textItem, maxTextWidthPoints: maxTextWidthPoints)
|
||||
// self.delegate?.imageEditor(presentFullScreenOverlay: textEditor,
|
||||
// withNavigation: true)
|
||||
|
||||
// TODO:
|
||||
}
|
||||
|
||||
@objc func didTapDone(sender: UIButton) {
|
||||
Logger.verbose("")
|
||||
|
||||
self.editorMode = .none
|
||||
}
|
||||
|
||||
// MARK: - Gestures
|
||||
|
||||
private func updateGestureState() {
|
||||
AssertIsOnMainThread()
|
||||
|
||||
switch editorMode {
|
||||
case .none:
|
||||
moveTextGestureRecognizer?.isEnabled = true
|
||||
tapGestureRecognizer?.isEnabled = true
|
||||
pinchGestureRecognizer?.isEnabled = true
|
||||
case .brush:
|
||||
// Brush strokes can start and end (and return from) outside the view.
|
||||
moveTextGestureRecognizer?.isEnabled = false
|
||||
tapGestureRecognizer?.isEnabled = false
|
||||
pinchGestureRecognizer?.isEnabled = false
|
||||
case .text:
|
||||
moveTextGestureRecognizer?.isEnabled = false
|
||||
tapGestureRecognizer?.isEnabled = false
|
||||
pinchGestureRecognizer?.isEnabled = false
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Tap Gesture
|
||||
|
@ -483,7 +372,7 @@ public class ImageEditorView: UIView {
|
|||
self.currentStrokeSamples.append(newSample)
|
||||
}
|
||||
|
||||
let strokeColor = currentColor
|
||||
let strokeColor = currentColor.color
|
||||
// TODO: Tune stroke width.
|
||||
let unitStrokeWidth = ImageEditorStrokeItem.defaultUnitStrokeWidth()
|
||||
|
||||
|
@ -527,13 +416,14 @@ public class ImageEditorView: UIView {
|
|||
private func edit(textItem: ImageEditorTextItem) {
|
||||
Logger.verbose("")
|
||||
|
||||
self.editorMode = .text
|
||||
|
||||
// TODO:
|
||||
let maxTextWidthPoints = model.srcImageSizePixels.width * ImageEditorTextItem.kDefaultUnitWidth
|
||||
// let maxTextWidthPoints = canvasView.imageView.width() * ImageEditorTextItem.kDefaultUnitWidth
|
||||
|
||||
let textEditor = ImageEditorTextViewController(delegate: self, textItem: textItem, maxTextWidthPoints: maxTextWidthPoints)
|
||||
let textEditor = ImageEditorTextViewController(delegate: self,
|
||||
model: model,
|
||||
textItem: textItem,
|
||||
maxTextWidthPoints: maxTextWidthPoints)
|
||||
self.delegate?.imageEditor(presentFullScreenOverlay: textEditor,
|
||||
withNavigation: true)
|
||||
}
|
||||
|
@ -543,8 +433,6 @@ public class ImageEditorView: UIView {
|
|||
private func presentCropTool() {
|
||||
Logger.verbose("")
|
||||
|
||||
self.editorMode = .none
|
||||
|
||||
guard let srcImage = canvasView.loadSrcImage() else {
|
||||
owsFailDebug("Couldn't load src image.")
|
||||
return
|
||||
|
@ -573,10 +461,6 @@ extension ImageEditorView: UIGestureRecognizerDelegate {
|
|||
owsFailDebug("Unexpected gesture.")
|
||||
return false
|
||||
}
|
||||
guard editorMode == .none else {
|
||||
// We only filter touches when in default mode.
|
||||
return true
|
||||
}
|
||||
|
||||
let location = touch.location(in: canvasView.gestureReferenceView)
|
||||
let isInTextArea = self.textLayer(forLocation: location) != nil
|
||||
|
@ -590,14 +474,10 @@ extension ImageEditorView: ImageEditorModelObserver {
|
|||
|
||||
public func imageEditorModelDidChange(before: ImageEditorContents,
|
||||
after: ImageEditorContents) {
|
||||
updateButtons()
|
||||
|
||||
delegate?.imageEditorUpdateNavigationBar()
|
||||
}
|
||||
|
||||
public func imageEditorModelDidChange(changedItemIds: [String]) {
|
||||
updateButtons()
|
||||
|
||||
delegate?.imageEditorUpdateNavigationBar()
|
||||
}
|
||||
}
|
||||
|
@ -606,11 +486,9 @@ extension ImageEditorView: ImageEditorModelObserver {
|
|||
|
||||
extension ImageEditorView: ImageEditorTextViewControllerDelegate {
|
||||
|
||||
public func textEditDidComplete(textItem: ImageEditorTextItem, text: String?) {
|
||||
public func textEditDidComplete(textItem: ImageEditorTextItem, text: String?, color: ImageEditorColor) {
|
||||
AssertIsOnMainThread()
|
||||
|
||||
self.editorMode = .none
|
||||
|
||||
guard let text = text?.ows_stripped(),
|
||||
text.count > 0 else {
|
||||
if model.has(itemForId: textItem.itemId) {
|
||||
|
@ -620,7 +498,7 @@ extension ImageEditorView: ImageEditorTextViewControllerDelegate {
|
|||
}
|
||||
|
||||
// Model items are immutable; we _replace_ the item rather than modify it.
|
||||
let newItem = textItem.copy(withText: text)
|
||||
let newItem = textItem.copy(withText: text, color: color)
|
||||
if model.has(itemForId: textItem.itemId) {
|
||||
model.replace(item: newItem, suppressUndo: false)
|
||||
} else {
|
||||
|
@ -629,7 +507,6 @@ extension ImageEditorView: ImageEditorTextViewControllerDelegate {
|
|||
}
|
||||
|
||||
public func textEditDidCancel() {
|
||||
self.editorMode = .none
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -648,16 +525,7 @@ extension ImageEditorView: ImageEditorCropViewControllerDelegate {
|
|||
|
||||
// MARK: -
|
||||
|
||||
extension ImageEditorView: ImageEditorPaletteViewDelegate {
|
||||
public func selectedColorDidChange() {
|
||||
// TODO:
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
extension ImageEditorView: ImageEditorBrushViewControllerDelegate {
|
||||
public func brushDidComplete() {
|
||||
self.editorMode = .none
|
||||
}
|
||||
}
|
||||
|
|
|
@ -129,7 +129,7 @@ public extension CGFloat {
|
|||
return CGFloatClamp(self, minValue, maxValue)
|
||||
}
|
||||
|
||||
public func clamp01(_ minValue: CGFloat, _ maxValue: CGFloat) -> CGFloat {
|
||||
public func clamp01() -> CGFloat {
|
||||
return CGFloatClamp01(self)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue