Merge branch 'charlesmchen/imageEditorDesign5'

pull/2/head
Matthew Chen 6 years ago
commit 575de76a43

@ -2,17 +2,17 @@
"images" : [
{
"idiom" : "universal",
"filename" : "add-photo-24@1x.png",
"filename" : "create-album-outline-32@1x.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "add-photo-24@2x.png",
"filename" : "create-album-outline-32@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "add-photo-24@3x.png",
"filename" : "create-album-outline-32@3x.png",
"scale" : "3x"
}
],

Binary file not shown.

Before

Width:  |  Height:  |  Size: 262 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 392 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 549 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 477 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 813 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

@ -2,17 +2,17 @@
"images" : [
{
"idiom" : "universal",
"filename" : "add-caption-32@1x.png",
"filename" : "caption-24@1x.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "add-caption-32@2x.png",
"filename" : "caption-24@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "add-caption-32@3x.png",
"filename" : "caption-24@3x.png",
"scale" : "3x"
}
],

Binary file not shown.

Before

Width:  |  Height:  |  Size: 326 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 559 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 866 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 297 B

@ -2836,7 +2836,9 @@ typedef enum : NSUInteger {
OWSImagePickerGridController *picker = [OWSImagePickerGridController new];
picker.delegate = self;
pickerModal = [[OWSNavigationController alloc] initWithRootViewController:picker];
OWSNavigationController *modal = [[OWSNavigationController alloc] initWithRootViewController:picker];
modal.ows_prefersStatusBarHidden = @(YES);
pickerModal = modal;
} else {
UIImagePickerController *picker = [OWSImagePickerController new];
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;

@ -380,19 +380,32 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat
}
func complete(withAssets assets: [PHAsset]) {
let attachmentPromises: [Promise<SignalAttachment>] = assets.map({
return photoCollectionContents.outgoingAttachment(for: $0)
})
firstly {
when(fulfilled: attachmentPromises)
}.map { attachments in
Logger.debug("built all attachments")
self.didComplete(withAttachments: attachments)
}.catch { error in
Logger.error("failed to prepare attachments. error: \(error)")
OWSAlerts.showAlert(title: NSLocalizedString("IMAGE_PICKER_FAILED_TO_PROCESS_ATTACHMENTS", comment: "alert title"))
}.retainUntilComplete()
ModalActivityIndicatorViewController.present(fromViewController: self,
canCancel: false) { (modal) in
let attachmentPromises: [Promise<SignalAttachment>] = assets.map({
return self.photoCollectionContents.outgoingAttachment(for: $0)
})
firstly {
when(fulfilled: attachmentPromises)
}.map { attachments in
Logger.debug("built all attachments")
DispatchQueue.main.async {
modal.dismiss(completion: {
self.didComplete(withAttachments: attachments)
})
}
}.catch { error in
Logger.error("failed to prepare attachments. error: \(error)")
DispatchQueue.main.async {
modal.dismiss(completion: {
OWSAlerts.showAlert(title: NSLocalizedString("IMAGE_PICKER_FAILED_TO_PROCESS_ATTACHMENTS", comment: "alert title"))
})
}
}.retainUntilComplete()
}
}
private func didComplete(withAttachments attachments: [SignalAttachment]) {

@ -169,6 +169,7 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
let vc = AttachmentApprovalViewController(mode: .modal, attachments: attachments)
vc.approvalDelegate = approvalDelegate
let navController = OWSNavigationController(rootViewController: vc)
navController.ows_prefersStatusBarHidden = true
guard let navigationBar = navController.navigationBar as? OWSNavigationBar else {
owsFailDebug("navigationBar was nil or unexpected class")
@ -198,6 +199,10 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
// MARK: - View Lifecycle
public override var prefersStatusBarHidden: Bool {
return true
}
override public func viewDidLoad() {
super.viewDidLoad()
@ -229,8 +234,6 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
Logger.debug("")
super.viewWillAppear(animated)
CurrentAppContext().setStatusBarHidden(true, animated: animated)
guard let navigationBar = navigationController?.navigationBar as? OWSNavigationBar else {
owsFailDebug("navigationBar was nil or unexpected class")
return
@ -238,6 +241,7 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
navigationBar.overrideTheme(type: .clear)
updateNavigationBar()
updateControlVisibility()
}
override public func viewDidAppear(_ animated: Bool) {
@ -246,15 +250,12 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
super.viewDidAppear(animated)
updateNavigationBar()
updateControlVisibility()
}
override public func viewWillDisappear(_ animated: Bool) {
Logger.debug("")
super.viewWillDisappear(animated)
// Since this VC is being dismissed, the "show status bar" animation would feel like
// it's occuring on the presenting view controller - it's better not to animate at all.
CurrentAppContext().setStatusBarHidden(false, animated: false)
}
override public var inputAccessoryView: UIView? {
@ -263,12 +264,18 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
}
override public var canBecomeFirstResponder: Bool {
return true
return !shouldHideControls
}
// MARK: - Navigation Bar
public func updateNavigationBar() {
guard !shouldHideControls else {
self.navigationItem.leftBarButtonItem = nil
self.navigationItem.rightBarButtonItem = nil
return
}
var navigationBarItems = [UIView]()
var isShowingCaptionView = false
@ -295,7 +302,29 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
cancelButton.tintColor = .white
self.navigationItem.leftBarButtonItem = cancelButton
} else {
self.navigationItem.leftBarButtonItem = nil
// Note: using a custom leftBarButtonItem breaks the interactive pop gesture.
self.navigationItem.leftBarButtonItem = self.createOWSBackButton()
}
}
// MARK: - Control Visibility
public var shouldHideControls: Bool {
guard let pageViewController = pageViewControllers.first else {
return false
}
return pageViewController.shouldHideControls
}
private func updateControlVisibility() {
if shouldHideControls {
if isFirstResponder {
resignFirstResponder()
}
} else {
if !isFirstResponder {
becomeFirstResponder()
}
}
}
@ -376,6 +405,7 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
}
updateNavigationBar()
updateControlVisibility()
}
// MARK: - UIPageViewControllerDataSource
@ -622,7 +652,11 @@ extension AttachmentApprovalViewController: AttachmentPrepViewControllerDelegate
}
func prepViewControllerUpdateNavigationBar() {
self.updateNavigationBar()
updateNavigationBar()
}
func prepViewControllerUpdateControls() {
updateControlVisibility()
}
func prepViewControllerAttachmentCount() -> Int {
@ -682,6 +716,8 @@ protocol AttachmentPrepViewControllerDelegate: class {
func prepViewControllerUpdateNavigationBar()
func prepViewControllerUpdateControls()
func prepViewControllerAttachmentCount() -> Int
}
@ -712,7 +748,15 @@ public class AttachmentPrepViewController: OWSViewController, PlayerProgressBarD
fileprivate var isShowingCaptionView = false {
didSet {
prepDelegate?.prepViewControllerUpdateNavigationBar()
prepDelegate?.prepViewControllerUpdateControls()
}
}
public var shouldHideControls: Bool {
guard let imageEditorView = imageEditorView else {
return false
}
return imageEditorView.shouldHideControls
}
// MARK: - Initializers
@ -794,8 +838,7 @@ public class AttachmentPrepViewController: OWSViewController, PlayerProgressBarD
view.addSubview(imageEditorView)
imageEditorView.autoPinEdgesToSuperviewEdges()
imageEditorView.addControls(to: imageEditorView,
viewController: self)
imageEditorUpdateNavigationBar()
}
}
#endif
@ -872,6 +915,7 @@ public class AttachmentPrepViewController: OWSViewController, PlayerProgressBarD
super.viewWillAppear(animated)
prepDelegate?.prepViewControllerUpdateNavigationBar()
prepDelegate?.prepViewControllerUpdateControls()
}
override public func viewDidAppear(_ animated: Bool) {
@ -880,6 +924,7 @@ public class AttachmentPrepViewController: OWSViewController, PlayerProgressBarD
super.viewDidAppear(animated)
prepDelegate?.prepViewControllerUpdateNavigationBar()
prepDelegate?.prepViewControllerUpdateControls()
}
override public func viewWillLayoutSubviews() {
@ -1208,6 +1253,10 @@ extension AttachmentPrepViewController: ImageEditorViewDelegate {
public func imageEditorUpdateNavigationBar() {
prepDelegate?.prepViewControllerUpdateNavigationBar()
}
public func imageEditorUpdateControls() {
prepDelegate?.prepViewControllerUpdateControls()
}
}
// MARK: -
@ -1411,7 +1460,7 @@ class MediaMessageTextToolbar: UIView, UITextViewDelegate {
// Add shadow in case overlayed on white content
lengthLimitLabel.layer.shadowColor = UIColor.black.cgColor
lengthLimitLabel.layer.shadowOffset = CGSize(width: 0.0, height: 0.0)
lengthLimitLabel.layer.shadowOffset = .zero
lengthLimitLabel.layer.shadowOpacity = 0.8
lengthLimitLabel.isHidden = true
@ -1645,6 +1694,7 @@ public class ApprovalRailCellView: GalleryRailCellView {
imageView.layer.shadowColor = UIColor.black.cgColor
imageView.layer.shadowRadius = 2
imageView.layer.shadowOpacity = 0.66
imageView.layer.shadowOffset = .zero
return imageView
}()
@ -1676,8 +1726,8 @@ public class ApprovalRailCellView: GalleryRailCellView {
if hasCaption {
addSubview(captionIndicator)
captionIndicator.autoPinEdge(toSuperviewEdge: .top, withInset: 0)
captionIndicator.autoPinEdge(toSuperviewEdge: .leading, withInset: 4)
captionIndicator.autoPinEdge(toSuperviewEdge: .top, withInset: 2)
captionIndicator.autoPinEdge(toSuperviewEdge: .leading, withInset: 6)
} else {
captionIndicator.removeFromSuperview()
}

@ -75,11 +75,6 @@ class AttachmentCaptionViewController: OWSViewController {
configureTextView()
let cancelButton = UIBarButtonItem(barButtonSystemItem: .cancel,
target: self,
action: #selector(didTapCancel))
cancelButton.tintColor = .white
navigationItem.leftBarButtonItem = cancelButton
let doneIcon = UIImage(named: "image_editor_checkmark_full")?.withRenderingMode(.alwaysTemplate)
let doneButton = UIBarButtonItem(image: doneIcon, style: .plain,
target: self,
@ -96,7 +91,6 @@ class AttachmentCaptionViewController: OWSViewController {
stackView.axis = .vertical
stackView.spacing = 20
stackView.alignment = .fill
stackView.addBackgroundView(withBackgroundColor: UIColor(white: 0, alpha: 0.5))
stackView.layoutMargins = UIEdgeInsets(top: 16, left: 20, bottom: 16, right: 20)
stackView.isLayoutMarginsRelativeArrangement = true
self.view.addSubview(stackView)
@ -104,6 +98,15 @@ class AttachmentCaptionViewController: OWSViewController {
stackView.autoPinEdge(toSuperviewEdge: .trailing)
self.autoPinView(toBottomOfViewControllerOrKeyboard: stackView, avoidNotch: true)
let backgroundView = UIView()
backgroundView.backgroundColor = UIColor(white: 0, alpha: 0.5)
view.addSubview(backgroundView)
view.sendSubview(toBack: backgroundView)
backgroundView.autoPinEdge(toSuperviewEdge: .leading)
backgroundView.autoPinEdge(toSuperviewEdge: .trailing)
backgroundView.autoPinEdge(toSuperviewEdge: .bottom)
backgroundView.autoPinEdge(.top, to: .top, of: stackView)
let minTextHeight: CGFloat = textView.font?.lineHeight ?? 0
textViewHeightConstraint = textView.autoSetDimension(.height, toSize: minTextHeight)
@ -174,7 +177,7 @@ class AttachmentCaptionViewController: OWSViewController {
// Add shadow in case overlayed on white content
lengthLimitLabel.layer.shadowColor = UIColor.black.cgColor
lengthLimitLabel.layer.shadowOffset = CGSize(width: 0.0, height: 0.0)
lengthLimitLabel.layer.shadowOffset = .zero
lengthLimitLabel.layer.shadowOpacity = 0.8
lengthLimitLabel.isHidden = true

@ -1,5 +1,5 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
#import <UIKit/UIKit.h>
@ -23,6 +23,11 @@ NS_ASSUME_NONNULL_BEGIN
// unsaved changes.
@interface OWSNavigationController : UINavigationController
// If set, this property lets us override prefersStatusBarHidden behavior.
// This is useful for supressing the status bar while a modal is presented,
// regardless of which view is currently visible.
@property (nonatomic, nullable) NSNumber *ows_prefersStatusBarHidden;
@end
NS_ASSUME_NONNULL_END

@ -69,6 +69,14 @@ NS_ASSUME_NONNULL_BEGIN
self.interactivePopGestureRecognizer.delegate = self;
}
- (BOOL)prefersStatusBarHidden
{
if (self.ows_prefersStatusBarHidden) {
return self.ows_prefersStatusBarHidden.boolValue;
}
return [super prefersStatusBarHidden];
}
#pragma mark - UINavigationBarDelegate
- (void)setupNavbar

@ -64,14 +64,17 @@ public class GalleryRailCellView: UIView {
private(set) var isSelected: Bool = false
func setIsSelected(_ isSelected: Bool) {
let borderWidth: CGFloat = 2
self.isSelected = isSelected
// Reserve space for the selection border whether or not the cell is selected.
layoutMargins = UIEdgeInsets(top: 0, left: borderWidth, bottom: 0, right: borderWidth)
if isSelected {
layoutMargins = UIEdgeInsets(top: 0, left: 2, bottom: 0, right: 2)
imageView.layer.borderColor = Theme.galleryHighlightColor.cgColor
imageView.layer.borderWidth = 2
imageView.layer.cornerRadius = 2
imageView.layer.borderWidth = borderWidth
imageView.layer.cornerRadius = borderWidth
} else {
layoutMargins = .zero
imageView.layer.borderWidth = 0
imageView.layer.cornerRadius = 0
}

@ -84,11 +84,18 @@ public class ImageEditorBrushViewController: OWSViewController {
self.view.layoutSubviews()
}
public func updateNavigationBar() {
private func updateNavigationBar() {
// Hide controls during stroke.
let hasStroke = currentStroke != nil
guard !hasStroke else {
updateNavigationBar(navigationBarItems: [])
return
}
let undoButton = navigationBarButton(imageName: "image_editor_undo",
selector: #selector(didTapUndo(sender:)))
let doneButton = navigationBarButton(imageName: "image_editor_checkmark_full",
selector: #selector(didTapDone(sender:)))
selector: #selector(didTapDone(sender:)))
// Prevent users from undo any changes made before entering the view.
let canUndo = model.canUndo() && firstUndoOperationId != model.currentUndoOperationId()
@ -101,6 +108,12 @@ public class ImageEditorBrushViewController: OWSViewController {
updateNavigationBar(navigationBarItems: navigationBarItems)
}
private func updateControls() {
// Hide controls during stroke.
let hasStroke = currentStroke != nil
paletteView.isHidden = hasStroke
}
// MARK: - Actions
@objc func didTapUndo(sender: UIButton) {
@ -129,7 +142,12 @@ public class ImageEditorBrushViewController: OWSViewController {
// MARK: - Brush
// These properties are non-empty while drawing a stroke.
private var currentStroke: ImageEditorStrokeItem?
private var currentStroke: ImageEditorStrokeItem? {
didSet {
updateControls()
updateNavigationBar()
}
}
private var currentStrokeSamples = [ImageEditorStrokeItem.StrokeSample]()
@objc

@ -23,11 +23,13 @@ class ImageEditorCropViewController: OWSViewController {
private var transform: ImageEditorTransform
public let contentView = OWSLayerView()
public let clipView = OWSLayerView()
private var imageLayer = CALayer()
public let croppedContentView = OWSLayerView()
public let uncroppedContentView = UIView()
private var croppedImageLayer = CALayer()
private var uncroppedImageLayer = CALayer()
private enum CropRegion {
// The sides of the crop region.
@ -121,19 +123,32 @@ class ImageEditorCropViewController: OWSViewController {
}
wrapperView.addSubview(clipView)
imageLayer.contents = previewImage.cgImage
imageLayer.contentsScale = previewImage.scale
contentView.backgroundColor = .clear
contentView.isOpaque = false
contentView.layer.addSublayer(imageLayer)
contentView.layoutCallback = { [weak self] (_) in
croppedImageLayer.contents = previewImage.cgImage
croppedImageLayer.contentsScale = previewImage.scale
croppedContentView.backgroundColor = .clear
croppedContentView.isOpaque = false
croppedContentView.layer.addSublayer(croppedImageLayer)
croppedContentView.layoutCallback = { [weak self] (_) in
guard let strongSelf = self else {
return
}
strongSelf.updateContent()
}
clipView.addSubview(contentView)
contentView.autoPinEdgesToSuperviewEdges()
clipView.addSubview(croppedContentView)
croppedContentView.autoPinEdgesToSuperviewEdges()
uncroppedImageLayer.contents = previewImage.cgImage
uncroppedImageLayer.contentsScale = previewImage.scale
// The "uncropped" view/layer are used to display the
// content that has been cropped out. Its content
// should be semi-transparent to distinguish it from
// the content within the crop bounds.
uncroppedImageLayer.opacity = 0.5
uncroppedContentView.backgroundColor = .clear
uncroppedContentView.isOpaque = false
uncroppedContentView.layer.addSublayer(uncroppedImageLayer)
wrapperView.addSubview(uncroppedContentView)
uncroppedContentView.autoPin(toEdgesOf: croppedContentView)
// MARK: - Footer
@ -329,7 +344,7 @@ class ImageEditorCropViewController: OWSViewController {
Logger.verbose("")
let viewSize = contentView.bounds.size
let viewSize = croppedContentView.bounds.size
guard viewSize.width > 0,
viewSize.height > 0 else {
return
@ -354,13 +369,15 @@ class ImageEditorCropViewController: OWSViewController {
}
private func applyTransform() {
let viewSize = contentView.bounds.size
contentView.layer.setAffineTransform(transform.affineTransform(viewSize: viewSize))
let viewSize = croppedContentView.bounds.size
croppedContentView.layer.setAffineTransform(transform.affineTransform(viewSize: viewSize))
uncroppedContentView.layer.setAffineTransform(transform.affineTransform(viewSize: viewSize))
}
private func updateImageLayer() {
let viewSize = contentView.bounds.size
ImageEditorCanvasView.updateImageLayer(imageLayer: imageLayer, viewSize: viewSize, imageSize: model.srcImageSizePixels, transform: transform)
let viewSize = croppedContentView.bounds.size
ImageEditorCanvasView.updateImageLayer(imageLayer: croppedImageLayer, viewSize: viewSize, imageSize: model.srcImageSizePixels, transform: transform)
ImageEditorCanvasView.updateImageLayer(imageLayer: uncroppedImageLayer, viewSize: viewSize, imageSize: model.srcImageSizePixels, transform: transform)
}
private func configureGestures() {
@ -368,14 +385,22 @@ class ImageEditorCropViewController: OWSViewController {
let pinchGestureRecognizer = ImageEditorPinchGestureRecognizer(target: self, action: #selector(handlePinchGesture(_:)))
pinchGestureRecognizer.referenceView = self.clipView
// Use this VC as a delegate to ensure that pinches only
// receive touches that start inside of the cropped image bounds.
pinchGestureRecognizer.delegate = self
view.addGestureRecognizer(pinchGestureRecognizer)
let panGestureRecognizer = ImageEditorPanGestureRecognizer(target: self, action: #selector(handlePanGesture(_:)))
panGestureRecognizer.maximumNumberOfTouches = 1
panGestureRecognizer.referenceView = self.clipView
panGestureRecognizer.delegate = self
// _DO NOT_ use this VC as a delegate to filter touches;
// pan gestures can start outside the cropped image bounds.
// Otherwise the edges of the crop rect are difficult to
// "grab".
view.addGestureRecognizer(panGestureRecognizer)
// De-conflict the gestures; the pan gesture has priority.
panGestureRecognizer.shouldBeRequiredToFail(by: pinchGestureRecognizer)
}
override public var canBecomeFirstResponder: Bool {

@ -100,7 +100,12 @@ public class ImageEditorPaletteView: UIView {
// We use an invisible margin to expand the hot area of this control.
let margin: CGFloat = 20
imageView.autoPinEdgesToSuperviewEdges(with: UIEdgeInsets(top: margin, left: margin, bottom: margin, right: margin))
imageView.layer.borderColor = UIColor.white.cgColor
imageView.layer.borderWidth = CGHairlineWidth()
imageView.layer.shadowColor = UIColor.black.cgColor
imageView.layer.shadowRadius = 2.0
imageView.layer.shadowOpacity = 0.33
imageView.layer.shadowOffset = .zero
selectionWrapper.layoutCallback = { [weak self] (view) in
guard let strongSelf = self else {
return

@ -9,6 +9,7 @@ public protocol ImageEditorViewDelegate: class {
func imageEditor(presentFullScreenView viewController: UIViewController,
isTransparent: Bool)
func imageEditorUpdateNavigationBar()
func imageEditorUpdateControls()
}
// MARK: -
@ -81,16 +82,17 @@ public class ImageEditorView: UIView {
return true
}
// TODO: Should this method be private?
@objc
public func addControls(to containerView: UIView,
viewController: UIViewController) {
// MARK: - Navigation Bar
private func updateNavigationBar() {
delegate?.imageEditorUpdateNavigationBar()
}
// MARK: - Navigation Bar
public func navigationBarItems() -> [UIView] {
guard !shouldHideControls else {
return []
}
let undoButton = navigationBarButton(imageName: "image_editor_undo",
selector: #selector(didTapUndo(sender:)))
let brushButton = navigationBarButton(imageName: "image_editor_brush",
@ -110,6 +112,15 @@ public class ImageEditorView: UIView {
return buttons
}
private func updateControls() {
delegate?.imageEditorUpdateControls()
}
public var shouldHideControls: Bool {
// Hide controls during "text item move".
return movingTextItem != nil
}
// MARK: - Actions
@objc func didTapUndo(sender: UIButton) {
@ -138,6 +149,12 @@ public class ImageEditorView: UIView {
@objc func didTapNewText(sender: UIButton) {
Logger.verbose("")
createNewTextItem()
}
private func createNewTextItem() {
Logger.verbose("")
let viewSize = canvasView.gestureReferenceView.bounds.size
let imageSize = model.srcImageSizePixels
let imageFrame = ImageEditorCanvasView.imageFrame(forViewSize: viewSize, imageSize: imageSize,
@ -178,6 +195,8 @@ public class ImageEditorView: UIView {
let location = gestureRecognizer.location(in: canvasView.gestureReferenceView)
guard let textLayer = self.textLayer(forLocation: location) else {
// If there is no text item under the "tap", start a new one.
createNewTextItem()
return
}
@ -263,7 +282,12 @@ public class ImageEditorView: UIView {
// MARK: - Editor Gesture
// These properties are valid while moving a text item.
private var movingTextItem: ImageEditorTextItem?
private var movingTextItem: ImageEditorTextItem? {
didSet {
updateNavigationBar()
updateControls()
}
}
private var movingTextStartUnitCenter: CGPoint?
private var movingTextHasMoved = false
@ -479,11 +503,11 @@ extension ImageEditorView: ImageEditorModelObserver {
public func imageEditorModelDidChange(before: ImageEditorContents,
after: ImageEditorContents) {
delegate?.imageEditorUpdateNavigationBar()
updateNavigationBar()
}
public func imageEditorModelDidChange(changedItemIds: [String]) {
delegate?.imageEditorUpdateNavigationBar()
updateNavigationBar()
}
}

@ -15,6 +15,7 @@ public extension NSObject {
button.layer.shadowColor = UIColor.black.cgColor
button.layer.shadowRadius = 2
button.layer.shadowOpacity = 0.66
button.layer.shadowOffset = .zero
return button
}
}
@ -29,7 +30,7 @@ public extension UIViewController {
return
}
let spacing: CGFloat = 8
let spacing: CGFloat = 16
let stackView = UIStackView(arrangedSubviews: navigationBarItems)
stackView.axis = .horizontal
stackView.spacing = spacing

Loading…
Cancel
Save