Add trivial test interaction to image editor.

pull/1/head
Matthew Chen 6 years ago
parent 0d81139be5
commit e2afe27f5e

@ -894,6 +894,7 @@ public class AttachmentPrepViewController: OWSViewController, PlayerProgressBarD
let imageMediaView = self.mediaMessageView.contentView {
let imageEditorView = ImageEditorView(model: imageEditorModel)
imageEditorView.addRedBorder()
imageMediaView.isUserInteractionEnabled = true
imageMediaView.addSubview(imageEditorView)
imageEditorView.autoPinEdgesToSuperviewEdges()
self.imageEditorView = imageEditorView

@ -73,7 +73,7 @@ public class ImageEditorStrokeItem: ImageEditorItem {
public let unitSamples: [StrokeSample]
// Expressed as a "Unit" value as a fraction of
// max(width, height) of the source image.
// min(width, height) of the destination viewport.
@objc
public let unitStrokeWidth: CGFloat
@ -87,6 +87,17 @@ public class ImageEditorStrokeItem: ImageEditorItem {
super.init(itemType: .stroke)
}
@objc
public class func defaultUnitStrokeWidth() -> CGFloat {
return 0.05
}
@objc
public class func strokeWidth(forUnitStrokeWidth unitStrokeWidth: CGFloat,
dstSize: CGSize) -> CGFloat {
return CGFloatClamp01(unitStrokeWidth) * min(dstSize.width, dstSize.height)
}
}
// MARK: -
@ -219,8 +230,18 @@ private class ImageEditorOperation: NSObject {
// MARK: -
@objc
public protocol ImageEditorModelDelegate: class {
func imageEditorModelDidChange()
}
// MARK: -
@objc
public class ImageEditorModel: NSObject {
@objc
public weak var delegate: ImageEditorModelDelegate?
@objc
public let srcImagePath: String
@ -293,6 +314,8 @@ public class ImageEditorModel: NSObject {
redoStack.append(redoOperation)
self.contents = undoOperation.contents
delegate?.imageEditorModelDidChange()
}
@objc
@ -306,6 +329,8 @@ public class ImageEditorModel: NSObject {
undoStack.append(undoOperation)
self.contents = redoOperation.contents
delegate?.imageEditorModelDidChange()
}
@objc
@ -337,5 +362,7 @@ public class ImageEditorModel: NSObject {
let newContents = contents.clone()
action(newContents)
contents = newContents
delegate?.imageEditorModelDidChange()
}
}

@ -5,7 +5,7 @@
import UIKit
@objc
public class ImageEditorView: UIView {
public class ImageEditorView: UIView, ImageEditorModelDelegate {
private let model: ImageEditorModel
@objc
@ -13,10 +13,155 @@ public class ImageEditorView: UIView {
self.model = model
super.init(frame: .zero)
model.delegate = self
self.isUserInteractionEnabled = true
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTap))
self.addGestureRecognizer(tapGesture)
}
@available(*, unavailable, message: "use other init() instead.")
required public init?(coder aDecoder: NSCoder) {
notImplemented()
}
// MARK: - Actions
@objc
func didTap() {
Logger.verbose("")
addRandomStroke()
}
private func addRandomStroke() {
let randomUnitValue = { () -> CGFloat in
let scale: UInt32 = 32
let value = CGFloat(arc4random_uniform(scale)) / CGFloat(scale)
return value
}
let randomSample = {
return CGPoint(x: randomUnitValue(), y: randomUnitValue())
}
let item = ImageEditorStrokeItem(color: UIColor.red,
unitSamples: [randomSample(), randomSample(), randomSample() ],
unitStrokeWidth: ImageEditorStrokeItem.defaultUnitStrokeWidth())
model.append(item: item)
}
// MARK: - ImageEditorModelDelegate
public func imageEditorModelDidChange() {
// TODO: We eventually want to narrow our change events
// to reflect the specific item(s) which changed.
updateAllContent()
}
// MARK: - Accessor Overrides
@objc public override var bounds: CGRect {
didSet {
if oldValue != bounds {
updateAllContent()
}
}
}
@objc public override var frame: CGRect {
didSet {
if oldValue != frame {
updateAllContent()
}
}
}
// MARK: - Content
var contentLayers = [CALayer]()
internal func updateAllContent() {
AssertIsOnMainThread()
for layer in contentLayers {
layer.removeFromSuperlayer()
}
contentLayers.removeAll()
guard bounds.width > 0,
bounds.height > 0 else {
return
}
// Don't animate changes.
CATransaction.begin()
CATransaction.setDisableActions(true)
for item in model.items() {
guard let layer = layerForItem(item: item) else {
Logger.error("Couldn't create layer for item.")
continue
}
self.layer.addSublayer(layer)
}
CATransaction.commit()
}
private func layerForItem(item: ImageEditorItem) -> CALayer? {
AssertIsOnMainThread()
switch item.itemType {
case .test:
owsFailDebug("Unexpected test item.")
return nil
case .stroke:
guard let strokeItem = item as? ImageEditorStrokeItem else {
owsFailDebug("Item has unexpected type: \(type(of: item)).")
return nil
}
return strokeLayerForItem(item: strokeItem)
}
}
private func strokeLayerForItem(item: ImageEditorStrokeItem) -> CALayer? {
AssertIsOnMainThread()
let viewSize = bounds.size
let strokeWidth = ImageEditorStrokeItem.strokeWidth(forUnitStrokeWidth: item.unitStrokeWidth,
dstSize: viewSize)
let unitSamples = item.unitSamples
guard unitSamples.count > 1 else {
return nil
}
let shapeLayer = CAShapeLayer()
shapeLayer.lineWidth = strokeWidth
shapeLayer.strokeColor = item.color.cgColor
shapeLayer.frame = self.bounds
let transformSampleToPoint = { (unitSample: CGPoint) -> CGPoint in
return CGPoint(x: viewSize.width * unitSample.x,
y: viewSize.height * unitSample.y)
}
// TODO: Use bezier curves to smooth stroke.
let bezierPath = UIBezierPath()
var hasSample = false
for unitSample in unitSamples {
let point = transformSampleToPoint(unitSample)
if hasSample {
bezierPath.addLine(to: point)
} else {
bezierPath.move(to: point)
hasSample = true
}
}
shapeLayer.path = bezierPath.cgPath
shapeLayer.fillColor = nil
return shapeLayer
}
}

Loading…
Cancel
Save