Merge branch 'charlesmchen/imageEditorDesign12'
Before Width: | Height: | Size: 681 B After Width: | Height: | Size: 681 B |
Before Width: | Height: | Size: 409 B After Width: | Height: | Size: 402 B |
Before Width: | Height: | Size: 689 B After Width: | Height: | Size: 694 B |
Before Width: | Height: | Size: 989 B After Width: | Height: | Size: 979 B |
|
@ -7,7 +7,8 @@ import UIKit
|
||||||
|
|
||||||
protocol AttachmentApprovalInputAccessoryViewDelegate: class {
|
protocol AttachmentApprovalInputAccessoryViewDelegate: class {
|
||||||
func attachmentApprovalInputUpdateMediaRail()
|
func attachmentApprovalInputUpdateMediaRail()
|
||||||
func attachmentApprovalInputEditCaptions()
|
func attachmentApprovalInputStartEditingCaptions()
|
||||||
|
func attachmentApprovalInputStopEditingCaptions()
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: -
|
// MARK: -
|
||||||
|
@ -62,10 +63,7 @@ class AttachmentApprovalInputAccessoryView: UIView {
|
||||||
let backgroundView = UIView()
|
let backgroundView = UIView()
|
||||||
backgroundView.backgroundColor = UIColor.black.withAlphaComponent(0.6)
|
backgroundView.backgroundColor = UIColor.black.withAlphaComponent(0.6)
|
||||||
addSubview(backgroundView)
|
addSubview(backgroundView)
|
||||||
backgroundView.autoPinEdge(toSuperviewEdge: .top)
|
backgroundView.autoPinEdgesToSuperviewEdges()
|
||||||
backgroundView.autoPinEdge(toSuperviewEdge: .leading)
|
|
||||||
backgroundView.autoPinEdge(toSuperviewEdge: .trailing)
|
|
||||||
backgroundView.autoPinEdge(toSuperviewEdge: .bottom, withInset: -200)
|
|
||||||
|
|
||||||
currentCaptionLabel.textColor = UIColor(white: 1, alpha: 0.8)
|
currentCaptionLabel.textColor = UIColor(white: 1, alpha: 0.8)
|
||||||
currentCaptionLabel.font = UIFont.ows_dynamicTypeBody
|
currentCaptionLabel.font = UIFont.ows_dynamicTypeBody
|
||||||
|
@ -83,7 +81,13 @@ class AttachmentApprovalInputAccessoryView: UIView {
|
||||||
stackView.axis = .vertical
|
stackView.axis = .vertical
|
||||||
|
|
||||||
addSubview(stackView)
|
addSubview(stackView)
|
||||||
stackView.autoPinEdgesToSuperviewEdges()
|
stackView.autoPinEdge(toSuperviewEdge: .top)
|
||||||
|
stackView.autoPinEdge(toSuperviewEdge: .leading)
|
||||||
|
stackView.autoPinEdge(toSuperviewEdge: .trailing)
|
||||||
|
// We pin to the superview's _margin_. Otherwise the notch breaks
|
||||||
|
// the layout if you hide the keyboard in the simulator (or if the
|
||||||
|
// user uses an external keyboard).
|
||||||
|
stackView.autoPinEdge(toSuperviewMargin: .bottom)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Events
|
// MARK: - Events
|
||||||
|
@ -92,7 +96,7 @@ class AttachmentApprovalInputAccessoryView: UIView {
|
||||||
guard sender.state == .recognized else {
|
guard sender.state == .recognized else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
delegate?.attachmentApprovalInputEditCaptions()
|
delegate?.attachmentApprovalInputStartEditingCaptions()
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK:
|
// MARK:
|
||||||
|
@ -170,4 +174,8 @@ extension AttachmentApprovalInputAccessoryView: AttachmentCaptionToolbarDelegate
|
||||||
|
|
||||||
delegate?.attachmentApprovalInputUpdateMediaRail()
|
delegate?.attachmentApprovalInputUpdateMediaRail()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func attachmentCaptionToolbarDidComplete() {
|
||||||
|
delegate?.attachmentApprovalInputStopEditingCaptions()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,15 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
|
||||||
options: [UIPageViewControllerOptionInterPageSpacingKey: kSpacingBetweenItems])
|
options: [UIPageViewControllerOptionInterPageSpacingKey: kSpacingBetweenItems])
|
||||||
self.dataSource = self
|
self.dataSource = self
|
||||||
self.delegate = self
|
self.delegate = self
|
||||||
|
|
||||||
|
NotificationCenter.default.addObserver(self,
|
||||||
|
selector: #selector(didBecomeActive),
|
||||||
|
name: NSNotification.Name.OWSApplicationDidBecomeActive,
|
||||||
|
object: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
NotificationCenter.default.removeObserver(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc
|
@objc
|
||||||
|
@ -79,6 +88,14 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
|
||||||
return navController
|
return navController
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Notifications
|
||||||
|
|
||||||
|
@objc func didBecomeActive() {
|
||||||
|
AssertIsOnMainThread()
|
||||||
|
|
||||||
|
updateContents()
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Subviews
|
// MARK: - Subviews
|
||||||
|
|
||||||
var galleryRailView: GalleryRailView {
|
var galleryRailView: GalleryRailView {
|
||||||
|
@ -158,8 +175,8 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
|
||||||
|
|
||||||
private func updateContents() {
|
private func updateContents() {
|
||||||
updateNavigationBar()
|
updateNavigationBar()
|
||||||
updateControlVisibility()
|
|
||||||
updateInputAccessory()
|
updateInputAccessory()
|
||||||
|
updateControlVisibility()
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Input Accessory
|
// MARK: - Input Accessory
|
||||||
|
@ -714,7 +731,11 @@ extension AttachmentApprovalViewController: AttachmentApprovalInputAccessoryView
|
||||||
updateMediaRail()
|
updateMediaRail()
|
||||||
}
|
}
|
||||||
|
|
||||||
public func attachmentApprovalInputEditCaptions() {
|
public func attachmentApprovalInputStartEditingCaptions() {
|
||||||
isEditingCaptions = true
|
isEditingCaptions = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func attachmentApprovalInputStopEditingCaptions() {
|
||||||
|
isEditingCaptions = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import UIKit
|
||||||
|
|
||||||
protocol AttachmentCaptionToolbarDelegate: class {
|
protocol AttachmentCaptionToolbarDelegate: class {
|
||||||
func attachmentCaptionToolbarDidEdit(_ attachmentCaptionToolbar: AttachmentCaptionToolbar)
|
func attachmentCaptionToolbarDidEdit(_ attachmentCaptionToolbar: AttachmentCaptionToolbar)
|
||||||
|
func attachmentCaptionToolbarDidComplete()
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: -
|
// MARK: -
|
||||||
|
@ -193,7 +194,7 @@ class AttachmentCaptionToolbar: UIView, UITextViewDelegate {
|
||||||
// Though we can wrap the text, we don't want to encourage multline captions, plus a "done" button
|
// Though we can wrap the text, we don't want to encourage multline captions, plus a "done" button
|
||||||
// allows the user to get the keyboard out of the way while in the attachment approval view.
|
// allows the user to get the keyboard out of the way while in the attachment approval view.
|
||||||
if text == "\n" {
|
if text == "\n" {
|
||||||
textView.resignFirstResponder()
|
attachmentCaptionToolbarDelegate?.attachmentCaptionToolbarDidComplete()
|
||||||
return false
|
return false
|
||||||
} else {
|
} else {
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -458,6 +458,7 @@ extension AttachmentPrepViewController: ImageEditorViewDelegate {
|
||||||
navigationController.modalPresentationStyle = (isTransparent
|
navigationController.modalPresentationStyle = (isTransparent
|
||||||
? .overFullScreen
|
? .overFullScreen
|
||||||
: .fullScreen)
|
: .fullScreen)
|
||||||
|
navigationController.ows_prefersStatusBarHidden = true
|
||||||
|
|
||||||
if let navigationBar = navigationController.navigationBar as? OWSNavigationBar {
|
if let navigationBar = navigationController.navigationBar as? OWSNavigationBar {
|
||||||
navigationBar.overrideTheme(type: .clear)
|
navigationBar.overrideTheme(type: .clear)
|
||||||
|
|
|
@ -33,6 +33,8 @@ public class ImageEditorCanvasView: UIView {
|
||||||
private static let brushLayerZ: CGFloat = +1
|
private static let brushLayerZ: CGFloat = +1
|
||||||
// We want text to be rendered above the image and strokes.
|
// We want text to be rendered above the image and strokes.
|
||||||
private static let textLayerZ: CGFloat = +2
|
private static let textLayerZ: CGFloat = +2
|
||||||
|
// We leave space for 10k items/layers of each type.
|
||||||
|
private static let zPositionSpacing: CGFloat = 0.0001
|
||||||
|
|
||||||
@objc
|
@objc
|
||||||
public required init(model: ImageEditorModel,
|
public required init(model: ImageEditorModel,
|
||||||
|
@ -470,11 +472,22 @@ public class ImageEditorCanvasView: UIView {
|
||||||
shapeLayer.fillColor = nil
|
shapeLayer.fillColor = nil
|
||||||
shapeLayer.lineCap = kCALineCapRound
|
shapeLayer.lineCap = kCALineCapRound
|
||||||
shapeLayer.lineJoin = kCALineJoinRound
|
shapeLayer.lineJoin = kCALineJoinRound
|
||||||
shapeLayer.zPosition = brushLayerZ
|
shapeLayer.zPosition = zPositionForItem(item: item, model: model, zPositionBase: brushLayerZ)
|
||||||
|
|
||||||
return shapeLayer
|
return shapeLayer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class func zPositionForItem(item: ImageEditorItem,
|
||||||
|
model: ImageEditorModel,
|
||||||
|
zPositionBase: CGFloat) -> CGFloat {
|
||||||
|
let itemIds = model.itemIds()
|
||||||
|
guard let itemIndex = itemIds.firstIndex(of: item.itemId) else {
|
||||||
|
owsFailDebug("Couldn't find index of item.")
|
||||||
|
return zPositionBase
|
||||||
|
}
|
||||||
|
return zPositionBase + CGFloat(itemIndex) * zPositionSpacing
|
||||||
|
}
|
||||||
|
|
||||||
private class func textLayerForItem(item: ImageEditorTextItem,
|
private class func textLayerForItem(item: ImageEditorTextItem,
|
||||||
model: ImageEditorModel,
|
model: ImageEditorModel,
|
||||||
transform: ImageEditorTransform,
|
transform: ImageEditorTransform,
|
||||||
|
@ -532,7 +545,7 @@ public class ImageEditorCanvasView: UIView {
|
||||||
let transform = CGAffineTransform.identity.scaledBy(x: item.scaling, y: item.scaling).rotated(by: item.rotationRadians)
|
let transform = CGAffineTransform.identity.scaledBy(x: item.scaling, y: item.scaling).rotated(by: item.rotationRadians)
|
||||||
layer.setAffineTransform(transform)
|
layer.setAffineTransform(transform)
|
||||||
|
|
||||||
layer.zPosition = textLayerZ
|
layer.zPosition = zPositionForItem(item: item, model: model, zPositionBase: textLayerZ)
|
||||||
|
|
||||||
return layer
|
return layer
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,4 +74,9 @@ public class ImageEditorContents: NSObject {
|
||||||
public func items() -> [ImageEditorItem] {
|
public func items() -> [ImageEditorItem] {
|
||||||
return itemMap.orderedValues()
|
return itemMap.orderedValues()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc
|
||||||
|
public func itemIds() -> [String] {
|
||||||
|
return itemMap.orderedKeys
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,6 +114,11 @@ public class ImageEditorModel: NSObject {
|
||||||
return contents.items()
|
return contents.items()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc
|
||||||
|
public func itemIds() -> [String] {
|
||||||
|
return contents.itemIds()
|
||||||
|
}
|
||||||
|
|
||||||
@objc
|
@objc
|
||||||
public func has(itemForId itemId: String) -> Bool {
|
public func has(itemForId itemId: String) -> Bool {
|
||||||
return item(forId: itemId) != nil
|
return item(forId: itemId) != nil
|
||||||
|
|
|
@ -213,7 +213,6 @@ public class ImageEditorTextViewController: OWSViewController, VAlignTextViewDel
|
||||||
textView.isOpaque = false
|
textView.isOpaque = false
|
||||||
// We use a white cursor since we use a dark background.
|
// We use a white cursor since we use a dark background.
|
||||||
textView.tintColor = .white
|
textView.tintColor = .white
|
||||||
textView.returnKeyType = .done
|
|
||||||
// TODO: Limit the size of the text?
|
// TODO: Limit the size of the text?
|
||||||
// textView.delegate = self
|
// textView.delegate = self
|
||||||
textView.isScrollEnabled = true
|
textView.isScrollEnabled = true
|
||||||
|
|