From 47affb81c02edb6ba2a637731cf99e70442bb208 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Mon, 19 Nov 2018 15:31:31 -0600 Subject: [PATCH 1/6] Move gallery rail into input accessory view TODO -[] caption field per photo, separate from album message -[] caption field sticks to keyboard on becoming first responder -[] swipe updates caption field (not album message) -[] limit caption length to 240 chars -[] add more asset TODO picker -[] Done becomes "next" -[] shared navbar, album picker doesn't cover entire screen -[] new selected checkmark asset --- .../AttachmentApprovalViewController.swift | 128 ++++++++++-------- 1 file changed, 69 insertions(+), 59 deletions(-) diff --git a/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift b/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift index b748ebeb8..c2b971b9a 100644 --- a/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift +++ b/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift @@ -108,8 +108,6 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC public weak var approvalDelegate: AttachmentApprovalViewControllerDelegate? - private(set) var captioningToolbar: CaptioningToolbar! - // MARK: - Initializers @available(*, unavailable, message:"use attachment: constructor instead.") @@ -148,45 +146,35 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC return navController } - // MARK: - View Lifecycle + // MARK: - Subviews - let galleryRailView = GalleryRailView() - let railContainerView = UIView() + var galleryRailView: GalleryRailView { + return bottomToolView.galleryRailView + } - override public func viewDidLoad() { - super.viewDidLoad() + var captioningToolbar: CaptioningToolbar { + return bottomToolView.captioningToolbar + } - self.view.backgroundColor = .black + lazy var bottomToolView: BottomToolView = { + let isAddMoreVisible = mode == .sharedNavigation + let bottomToolView = BottomToolView(isAddMoreVisible: isAddMoreVisible) - disablePagingIfNecessary() + return bottomToolView + }() - railContainerView.backgroundColor = UIColor.black.withAlphaComponent(0.6) - view.addSubview(railContainerView) - railContainerView.preservesSuperviewLayoutMargins = true - railContainerView.layoutMargins.bottom = 50 - railContainerView.autoPinEdgesToSuperviewEdges(with: .zero, excludingEdge: .top) + // MARK: - View Lifecycle - let footerGradientView = GradientView(from: .clear, to: .black) - railContainerView.addSubview(footerGradientView) - footerGradientView.autoPinEdgesToSuperviewEdges(with: .zero, excludingEdge: .top) - footerGradientView.autoSetDimension(.height, toSize: ScaleFromIPhone5(100)) + override public func viewDidLoad() { + super.viewDidLoad() - railContainerView.addSubview(galleryRailView) - galleryRailView.delegate = self - galleryRailView.scrollFocusMode = .keepWithinBounds + self.view.backgroundColor = .black - galleryRailView.autoPinEdge(toSuperviewEdge: .leading) - galleryRailView.autoPinEdge(toSuperviewEdge: .trailing) - galleryRailView.autoPinEdge(toSuperviewMargin: .top) - galleryRailView.autoPinEdge(toSuperviewMargin: .bottom) - galleryRailView.autoSetDimension(.height, toSize: 72) + disablePagingIfNecessary() // Bottom Toolbar - - let isAddMoreVisible = mode == .sharedNavigation - let captioningToolbar = CaptioningToolbar(isAddMoreVisible: isAddMoreVisible) + galleryRailView.delegate = self captioningToolbar.captioningToolbarDelegate = self - self.captioningToolbar = captioningToolbar // Navigation @@ -232,8 +220,8 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC } override public var inputAccessoryView: UIView? { - self.captioningToolbar.layoutIfNeeded() - return self.captioningToolbar + bottomToolView.layoutIfNeeded() + return bottomToolView } override public var canBecomeFirstResponder: Bool { @@ -447,8 +435,7 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC galleryRailView.configureCellViews(itemProvider: attachmentItemCollection, focusedItem: currentItem) addDeleteIcon(cellViews: galleryRailView.cellViews) - railContainerView.isHidden = attachmentItemCollection.attachmentItems.count < 2 - captioningToolbar.alwaysShowGradient = railContainerView.isHidden + galleryRailView.isHidden = attachmentItemCollection.attachmentItems.count < 2 } let attachmentItemCollection: AttachmentItemCollection @@ -944,6 +931,54 @@ extension AttachmentPrepViewController: UIScrollViewDelegate { } } +class BottomToolView: UIView { + let captioningToolbar: CaptioningToolbar + let galleryRailView: GalleryRailView + + let kGalleryRailViewHeight: CGFloat = 72 + + required init(isAddMoreVisible: Bool) { + captioningToolbar = CaptioningToolbar(isAddMoreVisible: isAddMoreVisible) + + galleryRailView = GalleryRailView() + galleryRailView.scrollFocusMode = .keepWithinBounds + galleryRailView.autoSetDimension(.height, toSize: kGalleryRailViewHeight) + + super.init(frame: .zero) + + // Specifying autorsizing mask and an intrinsic content size allows proper + // sizing when used as an input accessory view. + self.autoresizingMask = .flexibleHeight + self.translatesAutoresizingMaskIntoConstraints = false + + backgroundColor = UIColor.black.withAlphaComponent(0.6) + preservesSuperviewLayoutMargins = true + + let stackView = UIStackView(arrangedSubviews: [self.galleryRailView, self.captioningToolbar]) + stackView.axis = .vertical + + addSubview(stackView) + stackView.autoPinEdge(toSuperviewEdge: .leading) + stackView.autoPinEdge(toSuperviewEdge: .trailing) + stackView.autoPinEdge(toSuperviewEdge: .top) + stackView.autoPinEdge(toSuperviewMargin: .bottom) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: + + override var intrinsicContentSize: CGSize { + get { + // Since we have `self.autoresizingMask = UIViewAutoresizingFlexibleHeight`, we must specify + // an intrinsicContentSize. Specifying CGSize.zero causes the height to be determined by autolayout. + return CGSize.zero + } + } +} + protocol CaptioningToolbarDelegate: class { func captioningToolbarDidTapSend(_ captioningToolbar: CaptioningToolbar) func captioningToolbarDidBeginEditing(_ captioningToolbar: CaptioningToolbar) @@ -964,7 +999,6 @@ class CaptioningToolbar: UIView, UITextViewDelegate { set { self.textView.text = newValue } } - private let bottomGradient: GradientView = GradientView(from: .clear, to: .black) private let lengthLimitLabel: UILabel = UILabel() // Layout Constants @@ -1051,7 +1085,6 @@ class CaptioningToolbar: UIView, UITextViewDelegate { self.lengthLimitLabel.isHidden = true let contentView = UIView() - contentView.addSubview(bottomGradient) contentView.addSubview(sendButton) contentView.addSubview(textView) contentView.addSubview(lengthLimitLabel) @@ -1103,11 +1136,6 @@ class CaptioningToolbar: UIView, UITextViewDelegate { lengthLimitLabel.autoPinEdge(.bottom, to: .top, of: textView, withOffset: -6) lengthLimitLabel.setContentHuggingHigh() lengthLimitLabel.setCompressionResistanceHigh() - - bottomGradient.isHidden = true - let bottomGradientHeight = ScaleFromIPhone5(100) - bottomGradient.autoSetDimension(.height, toSize: bottomGradientHeight) - bottomGradient.autoPinEdgesToSuperviewEdges(with: .zero, excludingEdge: .top) } required init?(coder aDecoder: NSCoder) { @@ -1166,30 +1194,12 @@ class CaptioningToolbar: UIView, UITextViewDelegate { } } - var alwaysShowGradient: Bool = false { - didSet { - if alwaysShowGradient { - bottomGradient.isHidden = false - } - } - } - public func textViewDidBeginEditing(_ textView: UITextView) { self.captioningToolbarDelegate?.captioningToolbarDidBeginEditing(self) - if !alwaysShowGradient { - UIView.animate(withDuration: 0.2) { - self.bottomGradient.isHidden = false - } - } } public func textViewDidEndEditing(_ textView: UITextView) { self.captioningToolbarDelegate?.captioningToolbarDidEndEditing(self) - if !alwaysShowGradient { - UIView.animate(withDuration: 0.2) { - self.bottomGradient.isHidden = true - } - } } // MARK: - Helpers From 79995cc52c346bb87ab7a0f0ea0a4531fe79b7d9 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Mon, 19 Nov 2018 15:48:43 -0600 Subject: [PATCH 2/6] rename captioning -> messageText TODO -[] caption field per photo, separate from album message -[] caption field sticks to keyboard on becoming first responder -[] swipe updates caption field (not album message) -[] limit caption length to 240 chars -[] add more asset TODO picker -[] Done becomes "next" -[] shared navbar, album picker doesn't cover entire screen -[] new selected checkmark asset --- .../AttachmentApprovalViewController.swift | 64 +++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift b/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift index c2b971b9a..bd477b8f5 100644 --- a/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift +++ b/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift @@ -100,7 +100,7 @@ public enum AttachmentApprovalViewControllerMode: UInt { } @objc -public class AttachmentApprovalViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate, CaptioningToolbarDelegate { +public class AttachmentApprovalViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate, MediaMessageTextToolbarDelegate { // MARK: - Properties @@ -152,8 +152,8 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC return bottomToolView.galleryRailView } - var captioningToolbar: CaptioningToolbar { - return bottomToolView.captioningToolbar + var mediaMessageTextToolbar: MediaMessageTextToolbar { + return bottomToolView.mediaMessageTextToolbar } lazy var bottomToolView: BottomToolView = { @@ -174,7 +174,7 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC // Bottom Toolbar galleryRailView.delegate = self - captioningToolbar.captioningToolbarDelegate = self + mediaMessageTextToolbar.mediaMessageTextToolbarDelegate = self // Navigation @@ -194,7 +194,7 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC self.setCurrentItem(firstItem, direction: .forward, animated: false) - captioningToolbar.captionText = currentViewController.attachment.captionText + mediaMessageTextToolbar.messageText = currentViewController.attachment.captionText } override public func viewWillAppear(_ animated: Bool) { @@ -335,11 +335,11 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC } if transitionCompleted { - UIView.transition(with: self.captioningToolbar, + UIView.transition(with: self.mediaMessageTextToolbar, duration: 0.1, options: .transitionCrossDissolve, animations: { - self.captioningToolbar.captionText = self.currentViewController.attachment.captionText + self.mediaMessageTextToolbar.messageText = self.currentViewController.attachment.captionText }, completion: nil) previousPage.zoomOut(animated: false) @@ -484,38 +484,38 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC self.approvalDelegate?.attachmentApproval(self, didCancelAttachments: attachments) } - // MARK: - CaptioningToolbarDelegate + // MARK: - MediaMessageTextToolbarDelegate var currentPageController: AttachmentPrepViewController { return viewControllers!.first as! AttachmentPrepViewController } - func captioningToolbarDidBeginEditing(_ captioningToolbar: CaptioningToolbar) { + func mediaMessageTextToolbarDidBeginEditing(_ mediaMessageTextToolbar: MediaMessageTextToolbar) { currentPageController.setAttachmentViewScale(.compact, animated: true) } - func captioningToolbarDidEndEditing(_ captioningToolbar: CaptioningToolbar) { + func mediaMessageTextToolbarDidEndEditing(_ mediaMessageTextToolbar: MediaMessageTextToolbar) { currentPageController.setAttachmentViewScale(.fullsize, animated: true) } - func captioningToolbarDidTapSend(_ captioningToolbar: CaptioningToolbar) { + func mediaMessageTextToolbarDidTapSend(_ mediaMessageTextToolbar: MediaMessageTextToolbar) { // Toolbar flickers in and out if there are errors // and remains visible momentarily after share extension is dismissed. // It's easiest to just hide it at this point since we're done with it. currentViewController.shouldAllowAttachmentViewResizing = false - captioningToolbar.isUserInteractionEnabled = false - captioningToolbar.isHidden = true + mediaMessageTextToolbar.isUserInteractionEnabled = false + mediaMessageTextToolbar.isHidden = true approvalDelegate?.attachmentApproval(self, didApproveAttachments: attachments) } - func captioningToolbar(_ captioningToolbar: CaptioningToolbar, textViewDidChange textView: UITextView) { + func mediaMessageTextToolbar(_ mediaMessageTextToolbar: MediaMessageTextToolbar, textViewDidChange textView: UITextView) { currentItem.attachment.captionText = textView.text self.approvalDelegate?.attachmentApproval?(self, changedCaptionOfAttachment: currentItem.attachment) } - func captioningToolbarDidAddMore(_ captioningToolbar: CaptioningToolbar) { + func mediaMessageTextToolbarDidAddMore(_ mediaMessageTextToolbar: MediaMessageTextToolbar) { self.approvalDelegate?.attachmentApproval?(self, addMoreToAttachments: attachments) } } @@ -932,13 +932,13 @@ extension AttachmentPrepViewController: UIScrollViewDelegate { } class BottomToolView: UIView { - let captioningToolbar: CaptioningToolbar + let mediaMessageTextToolbar: MediaMessageTextToolbar let galleryRailView: GalleryRailView let kGalleryRailViewHeight: CGFloat = 72 required init(isAddMoreVisible: Bool) { - captioningToolbar = CaptioningToolbar(isAddMoreVisible: isAddMoreVisible) + mediaMessageTextToolbar = MediaMessageTextToolbar(isAddMoreVisible: isAddMoreVisible) galleryRailView = GalleryRailView() galleryRailView.scrollFocusMode = .keepWithinBounds @@ -954,7 +954,7 @@ class BottomToolView: UIView { backgroundColor = UIColor.black.withAlphaComponent(0.6) preservesSuperviewLayoutMargins = true - let stackView = UIStackView(arrangedSubviews: [self.galleryRailView, self.captioningToolbar]) + let stackView = UIStackView(arrangedSubviews: [self.galleryRailView, self.mediaMessageTextToolbar]) stackView.axis = .vertical addSubview(stackView) @@ -979,22 +979,22 @@ class BottomToolView: UIView { } } -protocol CaptioningToolbarDelegate: class { - func captioningToolbarDidTapSend(_ captioningToolbar: CaptioningToolbar) - func captioningToolbarDidBeginEditing(_ captioningToolbar: CaptioningToolbar) - func captioningToolbarDidEndEditing(_ captioningToolbar: CaptioningToolbar) - func captioningToolbar(_ captioningToolbar: CaptioningToolbar, textViewDidChange: UITextView) - func captioningToolbarDidAddMore(_ captioningToolbar: CaptioningToolbar) +protocol MediaMessageTextToolbarDelegate: class { + func mediaMessageTextToolbarDidTapSend(_ mediaMessageTextToolbar: MediaMessageTextToolbar) + func mediaMessageTextToolbarDidBeginEditing(_ mediaMessageTextToolbar: MediaMessageTextToolbar) + func mediaMessageTextToolbarDidEndEditing(_ mediaMessageTextToolbar: MediaMessageTextToolbar) + func mediaMessageTextToolbar(_ mediaMessageTextToolbar: MediaMessageTextToolbar, textViewDidChange: UITextView) + func mediaMessageTextToolbarDidAddMore(_ mediaMessageTextToolbar: MediaMessageTextToolbar) } -class CaptioningToolbar: UIView, UITextViewDelegate { +class MediaMessageTextToolbar: UIView, UITextViewDelegate { - weak var captioningToolbarDelegate: CaptioningToolbarDelegate? + weak var mediaMessageTextToolbarDelegate: MediaMessageTextToolbarDelegate? private let addMoreButton: UIButton private let sendButton: UIButton private let textView: UITextView - var captionText: String? { + var messageText: String? { get { return self.textView.text } set { self.textView.text = newValue } } @@ -1145,18 +1145,18 @@ class CaptioningToolbar: UIView, UITextViewDelegate { // MARK: - @objc func didTapSend() { - self.captioningToolbarDelegate?.captioningToolbarDidTapSend(self) + self.mediaMessageTextToolbarDelegate?.mediaMessageTextToolbarDidTapSend(self) } @objc func didTapAddMore() { - self.captioningToolbarDelegate?.captioningToolbarDidAddMore(self) + self.mediaMessageTextToolbarDelegate?.mediaMessageTextToolbarDidAddMore(self) } // MARK: - UITextViewDelegate public func textViewDidChange(_ textView: UITextView) { updateHeight(textView: textView) - self.captioningToolbarDelegate?.captioningToolbar(self, textViewDidChange: textView) + self.mediaMessageTextToolbarDelegate?.mediaMessageTextToolbar(self, textViewDidChange: textView) } public func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { @@ -1195,11 +1195,11 @@ class CaptioningToolbar: UIView, UITextViewDelegate { } public func textViewDidBeginEditing(_ textView: UITextView) { - self.captioningToolbarDelegate?.captioningToolbarDidBeginEditing(self) + self.mediaMessageTextToolbarDelegate?.mediaMessageTextToolbarDidBeginEditing(self) } public func textViewDidEndEditing(_ textView: UITextView) { - self.captioningToolbarDelegate?.captioningToolbarDidEndEditing(self) + self.mediaMessageTextToolbarDelegate?.mediaMessageTextToolbarDidEndEditing(self) } // MARK: - Helpers From cd88ef2bec6ae6ce8ac11c4879891b53e1256c53 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Tue, 20 Nov 2018 13:57:15 -0600 Subject: [PATCH 3/6] CaptionView text field per page --- .../translations/en.lproj/Localizable.strings | 3 + .../AttachmentApprovalViewController.swift | 186 ++++++++++++++++++ 2 files changed, 189 insertions(+) diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index ad3d5bd83..69677fcf4 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -101,6 +101,9 @@ /* One-line label indicating the user can add no more text to the attachment caption. */ "ATTACHMENT_APPROVAL_CAPTION_LENGTH_LIMIT_REACHED" = "Message limit reached."; +/* placeholder text for an empty captioning field */ +"ATTACHMENT_APPROVAL_CAPTION_PLACEHOLDER" = "Add a caption…"; + /* Format string for file extension label in call interstitial view */ "ATTACHMENT_APPROVAL_FILE_EXTENSION_FORMAT" = "File type: %@"; diff --git a/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift b/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift index bd477b8f5..c00777dad 100644 --- a/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift +++ b/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift @@ -598,6 +598,8 @@ public class AttachmentPrepViewController: OWSViewController, PlayerProgressBarD // MARK: - View Lifecycle + let captionView = CaptionView() + override public func loadView() { self.view = UIView() @@ -698,8 +700,23 @@ public class AttachmentPrepViewController: OWSViewController, PlayerProgressBarD playButton.addTarget(self, action: #selector(playButtonTapped), for: .touchUpInside) playButton.autoCenterInSuperview() } + + // Caption + + captionView.captionText = attachment.captionText + + view.addSubview(captionView) + captionView.autoPinWidthToSuperview() + + // MJK TODO ideal CaptionView placement + // 1. when no keyboard is popped (e.g. initially) to be *just* above the rail + // 2. when the CaptionTextView is first responder, to be *just* above the keyboard + // 3. when the MessageTextView is first responder, to be behind the keyboard + captionView.autoPinEdge(toSuperviewMargin: .bottom, withInset: 136) } + var captionViewBottomConstraint: NSLayoutConstraint! + override public func viewWillLayoutSubviews() { Logger.debug("") super.viewWillLayoutSubviews() @@ -979,6 +996,175 @@ class BottomToolView: UIView { } } +protocol CaptionViewDelegate: class { + func captionViewDidChange(_ captionView: CaptionView) +} + +class CaptionView: UIView { + + var captionText: String? { + get { return textView.text } + set { + textView.text = newValue + updatePlaceholderTextViewVisibility() + } + } + + weak var delegate: CaptionViewDelegate? + + private let kMinTextViewHeight: CGFloat = 38 + private var textViewHeightConstraint: NSLayoutConstraint! + + // TODO show length limit label + private let lengthLimitLabel: UILabel = UILabel() + + // MARK: Initializers + + override init(frame: CGRect) { + super.init(frame: frame) + + addSubview(placeholderTextView) + placeholderTextView.autoPinEdgesToSuperviewMargins() + + backgroundColor = UIColor.black.withAlphaComponent(0.6) + addSubview(textView) + textView.autoPinEdgesToSuperviewMargins() + textView.delegate = self + + self.textViewHeightConstraint = textView.autoSetDimension(.height, toSize: kMinTextViewHeight) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: + + override var inputAccessoryView: UIView? { + return nil + } + + // MARK: Subviews + + func updatePlaceholderTextViewVisibility() { + let isHidden: Bool = { + guard !self.textView.isFirstResponder else { + return true + } + + guard let captionText = self.textView.text else { + return false + } + + guard captionText.count > 0 else { + return false + } + + return true + }() + + placeholderTextView.isHidden = isHidden + } + + private lazy var placeholderTextView: UITextView = { + let placeholderTextView = UITextView() + placeholderTextView.text = NSLocalizedString("ATTACHMENT_APPROVAL_CAPTION_PLACEHOLDER", comment: "placeholder text for an empty captioning field") + placeholderTextView.isEditable = false + + placeholderTextView.backgroundColor = .clear + placeholderTextView.keyboardAppearance = Theme.keyboardAppearance + placeholderTextView.font = UIFont.ows_dynamicTypeBody + // MJK FIXME always dark theme + placeholderTextView.textColor = Theme.placeholderColor + placeholderTextView.returnKeyType = .done + + return placeholderTextView + }() + + private lazy var textView: UITextView = { + let textView = UITextView() + textView.backgroundColor = .clear + textView.keyboardAppearance = Theme.keyboardAppearance + textView.font = UIFont.ows_dynamicTypeBody + textView.textColor = Theme.darkThemePrimaryColor + textView.returnKeyType = .done + + return textView + }() +} + +extension CaptionView: UITextViewDelegate { +// @available(iOS 2.0, *) +// optional public func textViewShouldBeginEditing(_ textView: UITextView) -> Bool +// +// @available(iOS 2.0, *) +// optional public func textViewShouldEndEditing(_ textView: UITextView) -> Bool +// + public func textViewDidBeginEditing(_ textView: UITextView) { + updatePlaceholderTextViewVisibility() + } + + public func textViewDidEndEditing(_ textView: UITextView) { + updatePlaceholderTextViewVisibility() + } + + public func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { + let existingText: String = textView.text ?? "" + let proposedText: String = (existingText as NSString).replacingCharacters(in: range, with: text) + + guard proposedText.utf8.count <= kOversizeTextMessageSizeThreshold else { + Logger.debug("long text was truncated") + self.lengthLimitLabel.isHidden = false + + // `range` represents the section of the existing text we will replace. We can re-use that space. + // Range is in units of NSStrings's standard UTF-16 characters. Since some of those chars could be + // represented as single bytes in utf-8, while others may be 8 or more, the only way to be sure is + // to just measure the utf8 encoded bytes of the replaced substring. + let bytesAfterDelete: Int = (existingText as NSString).replacingCharacters(in: range, with: "").utf8.count + + // Accept as much of the input as we can + let byteBudget: Int = Int(kOversizeTextMessageSizeThreshold) - bytesAfterDelete + if byteBudget >= 0, let acceptableNewText = text.truncated(toByteCount: UInt(byteBudget)) { + textView.text = (existingText as NSString).replacingCharacters(in: range, with: acceptableNewText) + } + + return false + } + self.lengthLimitLabel.isHidden = true + + // 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. + if text == "\n" { + textView.resignFirstResponder() + return false + } else { + return true + } + } + + public func textViewDidChange(_ textView: UITextView) { + self.delegate?.captionViewDidChange(self) + } +// +// +// @available(iOS 2.0, *) +// optional public func textViewDidChangeSelection(_ textView: UITextView) +// +// +// @available(iOS 10.0, *) +// optional public func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool +// +// @available(iOS 10.0, *) +// optional public func textView(_ textView: UITextView, shouldInteractWith textAttachment: NSTextAttachment, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool +// +// +// @available(iOS, introduced: 7.0, deprecated: 10.0, message: "Use textView:shouldInteractWithURL:inRange:forInteractionType: instead") +// optional public func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool +// +// @available(iOS, introduced: 7.0, deprecated: 10.0, message: "Use textView:shouldInteractWithTextAttachment:inRange:forInteractionType: instead") +// optional public func textView(_ textView: UITextView, shouldInteractWith textAttachment: NSTextAttachment, in characterRange: NSRange) -> Bool +} + protocol MediaMessageTextToolbarDelegate: class { func mediaMessageTextToolbarDidTapSend(_ mediaMessageTextToolbar: MediaMessageTextToolbar) func mediaMessageTextToolbarDidBeginEditing(_ mediaMessageTextToolbar: MediaMessageTextToolbar) From 4f0092615aa35d823c44a84d8d0baafd30bc698d Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Tue, 20 Nov 2018 17:08:55 -0600 Subject: [PATCH 4/6] Support captions *and* independent message body --- .../ConversationViewController.m | 105 +++++++----------- .../PhotoLibrary/ImagePickerController.swift | 6 +- .../AttachmentApprovalViewController.swift | 101 ++++++++--------- 3 files changed, 92 insertions(+), 120 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index 93bec0d0a..b36e089e4 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -2481,7 +2481,7 @@ typedef enum : NSUInteger { { OWSAssertDebug(attachment); - [self tryToSendAttachmentIfApproved:attachment]; + [self showApprovalDialogForAttachment:attachment]; [ThreadUtil addThreadToProfileWhitelistIfEmptyContactThread:self.thread]; [self.conversationViewModel ensureDynamicInteractions]; @@ -2580,14 +2580,14 @@ typedef enum : NSUInteger { // Although we want to be able to send higher quality attachments through the document picker // it's more imporant that we ensure the sent format is one all clients can accept (e.g. *not* quicktime .mov) if ([SignalAttachment isInvalidVideoWithDataSource:dataSource dataUTI:type]) { - [self sendQualityAdjustedAttachmentForVideo:url filename:filename skipApprovalDialog:NO]; + [self showApprovalDialogAfterProcessingVideoURL:url filename:filename]; return; } // "Document picker" attachments _SHOULD NOT_ be resized, if possible. SignalAttachment *attachment = [SignalAttachment attachmentWithDataSource:dataSource dataUTI:type imageQuality:TSImageQualityOriginal]; - [self tryToSendAttachmentIfApproved:attachment]; + [self showApprovalDialogForAttachment:attachment]; } #pragma mark - UIImagePickerController @@ -2673,12 +2673,17 @@ typedef enum : NSUInteger { self.view.frame = frame; } +#pragma mark - OWSImagePickerControllerDelegate + - (void)imagePicker:(OWSImagePickerGridController *)imagePicker didPickImageAttachments:(NSArray *)attachments + messageText:(NSString *_Nullable)messageText { - [self tryToSendAttachmentsIfApproved:attachments skipApprovalDialog:YES]; + [self tryToSendAttachments:attachments messageText:messageText]; } +#pragma mark - UIImagePickerControllerDelegate + /* * Fetching data from UIImagePickerController */ @@ -2725,9 +2730,7 @@ typedef enum : NSUInteger { NSURL *videoURL = info[UIImagePickerControllerMediaURL]; [self dismissViewControllerAnimated:YES completion:^{ - [self sendQualityAdjustedAttachmentForVideo:videoURL - filename:filename - skipApprovalDialog:NO]; + [self showApprovalDialogAfterProcessingVideoURL:videoURL filename:filename]; }]; } else if (picker.sourceType == UIImagePickerControllerSourceTypeCamera) { // Static Image captured from camera @@ -2751,7 +2754,7 @@ typedef enum : NSUInteger { [self showErrorAlertForAttachment:attachment]; failedToPickAttachment(nil); } else { - [self tryToSendAttachmentIfApproved:attachment skipApprovalDialog:NO]; + [self showApprovalDialogForAttachment:attachment]; } } else { failedToPickAttachment(nil); @@ -2808,34 +2811,13 @@ typedef enum : NSUInteger { [self showErrorAlertForAttachment:attachment]; failedToPickAttachment(nil); } else { - [self tryToSendAttachmentIfApproved:attachment]; + [self showApprovalDialogForAttachment:attachment]; } }]; }]; } } -- (void)sendMessageAttachments:(NSArray *)attachments -{ - OWSAssertIsOnMainThread(); - for (SignalAttachment *attachment in attachments) { - OWSAssertDebug(![attachment hasError]); - OWSAssertDebug([attachment mimeType].length > 0); - } - - BOOL didAddToProfileWhitelist = [ThreadUtil addThreadToProfileWhitelistIfEmptyContactThread:self.thread]; - TSOutgoingMessage *message = [ThreadUtil enqueueMessageWithAttachments:attachments - messageBody:nil - inThread:self.thread - quotedReplyModel:self.inputToolbar.quotedReply]; - - [self messageWasSent:message]; - - if (didAddToProfileWhitelist) { - [self.conversationViewModel ensureDynamicInteractions]; - } -} - - (void)sendContactShare:(ContactShareViewModel *)contactShare { OWSAssertIsOnMainThread(); @@ -2864,9 +2846,7 @@ typedef enum : NSUInteger { }]; } -- (void)sendQualityAdjustedAttachmentForVideo:(NSURL *)movieURL - filename:(nullable NSString *)filename - skipApprovalDialog:(BOOL)skipApprovalDialog +- (void)showApprovalDialogAfterProcessingVideoURL:(NSURL *)movieURL filename:(nullable NSString *)filename { OWSAssertIsOnMainThread(); @@ -2895,7 +2875,7 @@ typedef enum : NSUInteger { attachment ? [attachment errorName] : @"Missing data"); [self showErrorAlertForAttachment:attachment]; } else { - [self tryToSendAttachmentIfApproved:attachment skipApprovalDialog:skipApprovalDialog]; + [self showApprovalDialogForAttachment:attachment]; } }]; }) retainUntilComplete]; @@ -3086,7 +3066,7 @@ typedef enum : NSUInteger { OWSLogWarn(@"Invalid attachment: %@.", attachment ? [attachment errorName] : @"Missing data"); [self showErrorAlertForAttachment:attachment]; } else { - [self tryToSendAttachmentIfApproved:attachment skipApprovalDialog:YES]; + [self tryToSendAttachments:@[ attachment ] messageText:nil]; } } @@ -3480,37 +3460,28 @@ typedef enum : NSUInteger { { OWSLogError(@""); - [self tryToSendAttachmentIfApproved:attachment]; + [self showApprovalDialogForAttachment:attachment]; } -- (void)tryToSendAttachmentIfApproved:(SignalAttachment *_Nullable)attachment +- (void)showApprovalDialogForAttachment:(SignalAttachment *_Nullable)attachment { if (attachment == nil) { - OWSLogWarn(@"Missing attachment"); + OWSFailDebug(@"attachment was unexpetedly nil"); [self showErrorAlertForAttachment:nil]; return; } - [self tryToSendAttachmentsIfApproved:@[ attachment ]]; + [self showApprovalDialogForAttachments:@[ attachment ]]; } -- (void)tryToSendAttachmentIfApproved:(SignalAttachment *_Nullable)attachment - skipApprovalDialog:(BOOL)skipApprovalDialog +- (void)showApprovalDialogForAttachments:(NSArray *)attachments { - if (attachment == nil) { - OWSLogWarn(@"Missing attachment"); - [self showErrorAlertForAttachment:nil]; - return; - } - [self tryToSendAttachmentsIfApproved:@[ attachment ] skipApprovalDialog:skipApprovalDialog]; -} + OWSNavigationController *modal = + [AttachmentApprovalViewController wrappedInNavControllerWithAttachments:attachments approvalDelegate:self]; -- (void)tryToSendAttachmentsIfApproved:(NSArray *)attachments -{ - [self tryToSendAttachmentsIfApproved:attachments skipApprovalDialog:NO]; + [self presentViewController:modal animated:YES completion:nil]; } -- (void)tryToSendAttachmentsIfApproved:(NSArray *)attachments - skipApprovalDialog:(BOOL)skipApprovalDialog +- (void)tryToSendAttachments:(NSArray *)attachments messageText:(NSString *_Nullable)messageText { OWSLogError(@""); @@ -3519,7 +3490,7 @@ typedef enum : NSUInteger { if ([self isBlockedConversation]) { [self showUnblockConversationUI:^(BOOL isBlocked) { if (!isBlocked) { - [weakSelf tryToSendAttachmentsIfApproved:attachments]; + [weakSelf tryToSendAttachments:attachments messageText:messageText]; } }]; return; @@ -3529,8 +3500,8 @@ typedef enum : NSUInteger { showSafetyNumberConfirmationIfNecessaryWithConfirmationText:[SafetyNumberStrings confirmSendButton] completion:^(BOOL didConfirmIdentity) { if (didConfirmIdentity) { - [weakSelf - tryToSendAttachmentsIfApproved:attachments]; + [weakSelf tryToSendAttachments:attachments + messageText:messageText]; } }]; if (didShowSNAlert) { @@ -3545,13 +3516,16 @@ typedef enum : NSUInteger { } } - if (skipApprovalDialog) { - [self sendMessageAttachments:attachments]; - } else { - OWSNavigationController *modal = - [AttachmentApprovalViewController wrappedInNavControllerWithAttachments:attachments - approvalDelegate:self]; - [self presentViewController:modal animated:YES completion:nil]; + BOOL didAddToProfileWhitelist = [ThreadUtil addThreadToProfileWhitelistIfEmptyContactThread:self.thread]; + TSOutgoingMessage *message = [ThreadUtil enqueueMessageWithAttachments:attachments + messageBody:messageText + inThread:self.thread + quotedReplyModel:self.inputToolbar.quotedReply]; + + [self messageWasSent:message]; + + if (didAddToProfileWhitelist) { + [self.conversationViewModel ensureDynamicInteractions]; } }); } @@ -3660,10 +3634,13 @@ typedef enum : NSUInteger { [self updateNavigationBarSubtitleLabel]; } +#pragma mark - AttachmentApprovalViewControllerDelegate + - (void)attachmentApproval:(AttachmentApprovalViewController *)attachmentApproval didApproveAttachments:(NSArray *)attachments + messageText:(NSString *_Nullable)messageText { - [self sendMessageAttachments:attachments]; + [self tryToSendAttachments:attachments messageText:messageText]; [self dismissViewControllerAnimated:YES completion:nil]; // We always want to scroll to the bottom of the conversation after the local user // sends a message. Normally, this is taken care of in yapDatabaseModified:, but diff --git a/Signal/src/ViewControllers/PhotoLibrary/ImagePickerController.swift b/Signal/src/ViewControllers/PhotoLibrary/ImagePickerController.swift index f48ea7c4a..f999fb84b 100644 --- a/Signal/src/ViewControllers/PhotoLibrary/ImagePickerController.swift +++ b/Signal/src/ViewControllers/PhotoLibrary/ImagePickerController.swift @@ -8,7 +8,7 @@ import PromiseKit @objc(OWSImagePickerControllerDelegate) protocol ImagePickerControllerDelegate { - func imagePicker(_ imagePicker: ImagePickerGridController, didPickImageAttachments attachments: [SignalAttachment]) + func imagePicker(_ imagePicker: ImagePickerGridController, didPickImageAttachments attachments: [SignalAttachment], messageText: String?) } @objc(OWSImagePickerGridController) @@ -386,9 +386,9 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat // MARK: - AttachmentApprovalViewControllerDelegate - func attachmentApproval(_ attachmentApproval: AttachmentApprovalViewController, didApproveAttachments attachments: [SignalAttachment]) { + func attachmentApproval(_ attachmentApproval: AttachmentApprovalViewController, didApproveAttachments attachments: [SignalAttachment], messageText: String?) { self.dismiss(animated: true) { - self.delegate?.imagePicker(self, didPickImageAttachments: attachments) + self.delegate?.imagePicker(self, didPickImageAttachments: attachments, messageText: messageText) } } diff --git a/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift b/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift index c00777dad..040c54e6c 100644 --- a/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift +++ b/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift @@ -9,7 +9,7 @@ import PromiseKit @objc public protocol AttachmentApprovalViewControllerDelegate: class { - func attachmentApproval(_ attachmentApproval: AttachmentApprovalViewController, didApproveAttachments attachments: [SignalAttachment]) + func attachmentApproval(_ attachmentApproval: AttachmentApprovalViewController, didApproveAttachments attachments: [SignalAttachment], messageText: String?) func attachmentApproval(_ attachmentApproval: AttachmentApprovalViewController, didCancelAttachments attachments: [SignalAttachment]) @objc optional func attachmentApproval(_ attachmentApproval: AttachmentApprovalViewController, addMoreToAttachments attachments: [SignalAttachment]) @objc optional func attachmentApproval(_ attachmentApproval: AttachmentApprovalViewController, changedCaptionOfAttachment attachment: SignalAttachment) @@ -62,6 +62,10 @@ class SignalAttachmentItem: Hashable { // MARK: + var captionText: String? { + return attachment.captionText + } + var imageSize: CGSize = .zero func getThumbnailImage() -> Promise { @@ -100,7 +104,7 @@ public enum AttachmentApprovalViewControllerMode: UInt { } @objc -public class AttachmentApprovalViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate, MediaMessageTextToolbarDelegate { +public class AttachmentApprovalViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate { // MARK: - Properties @@ -193,8 +197,6 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC } self.setCurrentItem(firstItem, direction: .forward, animated: false) - - mediaMessageTextToolbar.messageText = currentViewController.attachment.captionText } override public func viewWillAppear(_ animated: Bool) { @@ -335,13 +337,6 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC } if transitionCompleted { - UIView.transition(with: self.mediaMessageTextToolbar, - duration: 0.1, - options: .transitionCrossDissolve, - animations: { - self.mediaMessageTextToolbar.messageText = self.currentViewController.attachment.captionText - }, - completion: nil) previousPage.zoomOut(animated: false) updateMediaRail() } @@ -411,6 +406,7 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC Logger.debug("cache miss.") let viewController = AttachmentPrepViewController(attachmentItem: item) + viewController.prepDelegate = self cachedPages[item] = viewController return viewController @@ -483,9 +479,9 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC @objc func cancelPressed(sender: UIButton) { self.approvalDelegate?.attachmentApproval(self, didCancelAttachments: attachments) } +} - // MARK: - MediaMessageTextToolbarDelegate - +extension AttachmentApprovalViewController: MediaMessageTextToolbarDelegate { var currentPageController: AttachmentPrepViewController { return viewControllers!.first as! AttachmentPrepViewController } @@ -506,13 +502,7 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC mediaMessageTextToolbar.isUserInteractionEnabled = false mediaMessageTextToolbar.isHidden = true - approvalDelegate?.attachmentApproval(self, didApproveAttachments: attachments) - } - - func mediaMessageTextToolbar(_ mediaMessageTextToolbar: MediaMessageTextToolbar, textViewDidChange textView: UITextView) { - currentItem.attachment.captionText = textView.text - - self.approvalDelegate?.attachmentApproval?(self, changedCaptionOfAttachment: currentItem.attachment) + approvalDelegate?.attachmentApproval(self, didApproveAttachments: attachments, messageText: mediaMessageTextToolbar.messageText) } func mediaMessageTextToolbarDidAddMore(_ mediaMessageTextToolbar: MediaMessageTextToolbar) { @@ -520,6 +510,12 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC } } +extension AttachmentApprovalViewController: AttachmentPrepViewControllerDelegate { + func prepViewController(_ prepViewController: AttachmentPrepViewController, didUpdateCaptionForAttachmentItem attachmentItem: SignalAttachmentItem) { + self.approvalDelegate?.attachmentApproval?(self, changedCaptionOfAttachment: attachmentItem.attachment) + } +} + // MARK: GalleryRail extension SignalAttachmentItem: GalleryRailItem { @@ -563,6 +559,10 @@ extension AttachmentApprovalViewController: GalleryRailViewDelegate { // MARK: - Individual Page +protocol AttachmentPrepViewControllerDelegate: class { + func prepViewController(_ prepViewController: AttachmentPrepViewController, didUpdateCaptionForAttachmentItem attachmentItem: SignalAttachmentItem) +} + public class AttachmentPrepViewController: OWSViewController, PlayerProgressBarDelegate, OWSVideoPlayerDelegate { // We sometimes shrink the attachment view so that it remains somewhat visible // when the keyboard is presented. @@ -572,6 +572,8 @@ public class AttachmentPrepViewController: OWSViewController, PlayerProgressBarD // MARK: - Properties + weak var prepDelegate: AttachmentPrepViewControllerDelegate? + let attachmentItem: SignalAttachmentItem var attachment: SignalAttachment { return attachmentItem.attachment @@ -598,7 +600,9 @@ public class AttachmentPrepViewController: OWSViewController, PlayerProgressBarD // MARK: - View Lifecycle - let captionView = CaptionView() + lazy var captionView: CaptionView = { + return CaptionView(attachmentItem: attachmentItem) + }() override public func loadView() { self.view = UIView() @@ -703,9 +707,9 @@ public class AttachmentPrepViewController: OWSViewController, PlayerProgressBarD // Caption - captionView.captionText = attachment.captionText - view.addSubview(captionView) + captionView.delegate = self + captionView.autoPinWidthToSuperview() // MJK TODO ideal CaptionView placement @@ -880,6 +884,14 @@ public class AttachmentPrepViewController: OWSViewController, PlayerProgressBarD } } +extension AttachmentPrepViewController: CaptionViewDelegate { + func captionView(_ captionView: CaptionView, didChangeCaptionText captionText: String?, attachmentItem: SignalAttachmentItem) { + let attachment = attachmentItem.attachment + attachment.captionText = captionText + prepDelegate?.prepViewController(self, didUpdateCaptionForAttachmentItem: attachmentItem) + } +} + extension AttachmentPrepViewController: UIScrollViewDelegate { public func viewForZooming(in scrollView: UIScrollView) -> UIView? { @@ -997,7 +1009,7 @@ class BottomToolView: UIView { } protocol CaptionViewDelegate: class { - func captionViewDidChange(_ captionView: CaptionView) + func captionView(_ captionView: CaptionView, didChangeCaptionText captionText: String?, attachmentItem: SignalAttachmentItem) } class CaptionView: UIView { @@ -1010,6 +1022,11 @@ class CaptionView: UIView { } } + let attachmentItem: SignalAttachmentItem + var attachment: SignalAttachment { + return attachmentItem.attachment + } + weak var delegate: CaptionViewDelegate? private let kMinTextViewHeight: CGFloat = 38 @@ -1020,8 +1037,12 @@ class CaptionView: UIView { // MARK: Initializers - override init(frame: CGRect) { - super.init(frame: frame) + init(attachmentItem: SignalAttachmentItem) { + self.attachmentItem = attachmentItem + + super.init(frame: .zero) + + self.captionText = attachmentItem.captionText addSubview(placeholderTextView) placeholderTextView.autoPinEdgesToSuperviewMargins() @@ -1094,12 +1115,6 @@ class CaptionView: UIView { } extension CaptionView: UITextViewDelegate { -// @available(iOS 2.0, *) -// optional public func textViewShouldBeginEditing(_ textView: UITextView) -> Bool -// -// @available(iOS 2.0, *) -// optional public func textViewShouldEndEditing(_ textView: UITextView) -> Bool -// public func textViewDidBeginEditing(_ textView: UITextView) { updatePlaceholderTextViewVisibility() } @@ -1143,33 +1158,14 @@ extension CaptionView: UITextViewDelegate { } public func textViewDidChange(_ textView: UITextView) { - self.delegate?.captionViewDidChange(self) + self.delegate?.captionView(self, didChangeCaptionText: textView.text, attachmentItem: attachmentItem) } -// -// -// @available(iOS 2.0, *) -// optional public func textViewDidChangeSelection(_ textView: UITextView) -// -// -// @available(iOS 10.0, *) -// optional public func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool -// -// @available(iOS 10.0, *) -// optional public func textView(_ textView: UITextView, shouldInteractWith textAttachment: NSTextAttachment, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool -// -// -// @available(iOS, introduced: 7.0, deprecated: 10.0, message: "Use textView:shouldInteractWithURL:inRange:forInteractionType: instead") -// optional public func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool -// -// @available(iOS, introduced: 7.0, deprecated: 10.0, message: "Use textView:shouldInteractWithTextAttachment:inRange:forInteractionType: instead") -// optional public func textView(_ textView: UITextView, shouldInteractWith textAttachment: NSTextAttachment, in characterRange: NSRange) -> Bool } protocol MediaMessageTextToolbarDelegate: class { func mediaMessageTextToolbarDidTapSend(_ mediaMessageTextToolbar: MediaMessageTextToolbar) func mediaMessageTextToolbarDidBeginEditing(_ mediaMessageTextToolbar: MediaMessageTextToolbar) func mediaMessageTextToolbarDidEndEditing(_ mediaMessageTextToolbar: MediaMessageTextToolbar) - func mediaMessageTextToolbar(_ mediaMessageTextToolbar: MediaMessageTextToolbar, textViewDidChange: UITextView) func mediaMessageTextToolbarDidAddMore(_ mediaMessageTextToolbar: MediaMessageTextToolbar) } @@ -1342,7 +1338,6 @@ class MediaMessageTextToolbar: UIView, UITextViewDelegate { public func textViewDidChange(_ textView: UITextView) { updateHeight(textView: textView) - self.mediaMessageTextToolbarDelegate?.mediaMessageTextToolbar(self, textViewDidChange: textView) } public func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { From fcc4b516a5b5333c7c1378d113fc8b8e4b22a634 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Mon, 26 Nov 2018 12:31:03 -0700 Subject: [PATCH 5/6] fix typo in logging --- .../ConversationView/ConversationViewController.m | 2 +- Signal/src/ViewControllers/MediaPageViewController.swift | 4 ++-- Signal/src/ViewControllers/MediaTileViewController.swift | 2 +- .../ViewControllers/AttachmentApprovalViewController.swift | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index b36e089e4..7e6aefde9 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -3466,7 +3466,7 @@ typedef enum : NSUInteger { - (void)showApprovalDialogForAttachment:(SignalAttachment *_Nullable)attachment { if (attachment == nil) { - OWSFailDebug(@"attachment was unexpetedly nil"); + OWSFailDebug(@"attachment was unexpectedly nil"); [self showErrorAlertForAttachment:nil]; return; } diff --git a/Signal/src/ViewControllers/MediaPageViewController.swift b/Signal/src/ViewControllers/MediaPageViewController.swift index d238a5a4d..02ac04b05 100644 --- a/Signal/src/ViewControllers/MediaPageViewController.swift +++ b/Signal/src/ViewControllers/MediaPageViewController.swift @@ -50,7 +50,7 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou public func setCurrentItem(_ item: MediaGalleryItem, direction: UIPageViewControllerNavigationDirection, animated isAnimated: Bool) { guard let galleryPage = self.buildGalleryPage(galleryItem: item) else { - owsFailDebug("unexpetedly unable to build new gallery page") + owsFailDebug("unexpectedly unable to build new gallery page") return } @@ -83,7 +83,7 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou self.delegate = self guard let initialPage = self.buildGalleryPage(galleryItem: initialItem) else { - owsFailDebug("unexpetedly unable to build initial gallery item") + owsFailDebug("unexpectedly unable to build initial gallery item") return } self.initialPage = initialPage diff --git a/Signal/src/ViewControllers/MediaTileViewController.swift b/Signal/src/ViewControllers/MediaTileViewController.swift index 2f9acb261..76db73209 100644 --- a/Signal/src/ViewControllers/MediaTileViewController.swift +++ b/Signal/src/ViewControllers/MediaTileViewController.swift @@ -616,7 +616,7 @@ public class MediaTileViewController: UICollectionViewController, MediaGalleryDa Logger.debug("with deletedSections: \(deletedSections) deletedItems: \(deletedItems)") guard let collectionView = self.collectionView else { - owsFailDebug("collectionView was unexpetedly nil") + owsFailDebug("collectionView was unexpectedly nil") return } diff --git a/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift b/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift index 040c54e6c..20506e570 100644 --- a/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift +++ b/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift @@ -414,7 +414,7 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC private func setCurrentItem(_ item: SignalAttachmentItem, direction: UIPageViewControllerNavigationDirection, animated isAnimated: Bool) { guard let page = self.buildPage(item: item) else { - owsFailDebug("unexpetedly unable to build new page") + owsFailDebug("unexpectedly unable to build new page") return } From 28f8fc5911f57029582ac727a62624f64a507e9f Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Mon, 26 Nov 2018 12:34:54 -0700 Subject: [PATCH 6/6] per cr, avoid unnecessary --- .../AttachmentApprovalViewController.swift | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift b/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift index 20506e570..daf4bba9b 100644 --- a/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift +++ b/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift @@ -1327,11 +1327,11 @@ class MediaMessageTextToolbar: UIView, UITextViewDelegate { // MARK: - @objc func didTapSend() { - self.mediaMessageTextToolbarDelegate?.mediaMessageTextToolbarDidTapSend(self) + mediaMessageTextToolbarDelegate?.mediaMessageTextToolbarDidTapSend(self) } @objc func didTapAddMore() { - self.mediaMessageTextToolbarDelegate?.mediaMessageTextToolbarDidAddMore(self) + mediaMessageTextToolbarDelegate?.mediaMessageTextToolbarDidAddMore(self) } // MARK: - UITextViewDelegate @@ -1376,11 +1376,11 @@ class MediaMessageTextToolbar: UIView, UITextViewDelegate { } public func textViewDidBeginEditing(_ textView: UITextView) { - self.mediaMessageTextToolbarDelegate?.mediaMessageTextToolbarDidBeginEditing(self) + mediaMessageTextToolbarDelegate?.mediaMessageTextToolbarDidBeginEditing(self) } public func textViewDidEndEditing(_ textView: UITextView) { - self.mediaMessageTextToolbarDelegate?.mediaMessageTextToolbarDidEndEditing(self) + mediaMessageTextToolbarDelegate?.mediaMessageTextToolbarDidEndEditing(self) } // MARK: - Helpers @@ -1390,11 +1390,11 @@ class MediaMessageTextToolbar: UIView, UITextViewDelegate { let currentSize = textView.frame.size let newHeight = clampedTextViewHeight(fixedWidth: currentSize.width) - if newHeight != self.textViewHeight { - Logger.debug("TextView height changed: \(self.textViewHeight) -> \(newHeight)") - self.textViewHeight = newHeight - self.textViewHeightConstraint?.constant = textViewHeight - self.invalidateIntrinsicContentSize() + if newHeight != textViewHeight { + Logger.debug("TextView height changed: \(textViewHeight) -> \(newHeight)") + textViewHeight = newHeight + textViewHeightConstraint?.constant = textViewHeight + invalidateIntrinsicContentSize() } }