Add placeholder text to message input field

This commit is contained in:
Michael Kirk 2018-12-08 19:05:56 -05:00
parent 800994f106
commit 2f92995cd6
2 changed files with 131 additions and 62 deletions

View File

@ -1314,6 +1314,9 @@
/* status message while attachment is uploading */
"MESSAGE_STATUS_UPLOADING" = "Uploading…";
/* placeholder text for the editable message field */
"MESSAGE_TEXT_FIELD_PLACEHOLDER" = "New Message";
/* Indicates that one member of this group conversation is no longer verified. Embeds {{user's name or phone number}}. */
"MESSAGES_VIEW_1_MEMBER_NO_LONGER_VERIFIED_FORMAT" = "%@ is no longer marked as verified. Tap for options.";

View File

@ -1529,32 +1529,16 @@ protocol MediaMessageTextToolbarDelegate: class {
class MediaMessageTextToolbar: UIView, UITextViewDelegate {
weak var mediaMessageTextToolbarDelegate: MediaMessageTextToolbarDelegate?
private let addMoreButton: UIButton
private let sendButton: UIButton
let textView: UITextView
var messageText: String? {
get { return self.textView.text }
set { self.textView.text = newValue }
get { return textView.text }
set {
textView.text = newValue
updatePlaceholderTextViewVisibility()
}
}
private lazy var lengthLimitLabel: UILabel = {
let lengthLimitLabel = UILabel()
// Length Limit Label shown when the user inputs too long of a message
lengthLimitLabel.textColor = .white
lengthLimitLabel.text = NSLocalizedString("ATTACHMENT_APPROVAL_MESSAGE_LENGTH_LIMIT_REACHED", comment: "One-line label indicating the user can add no more text to the media message field.")
lengthLimitLabel.textAlignment = .center
// 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.shadowOpacity = 0.8
lengthLimitLabel.isHidden = true
return lengthLimitLabel
}()
// Layout Constants
let kMinTextViewHeight: CGFloat = 38
@ -1566,30 +1550,11 @@ class MediaMessageTextToolbar: UIView, UITextViewDelegate {
var textViewHeightConstraint: NSLayoutConstraint!
var textViewHeight: CGFloat
class MessageTextView: UITextView {
// When creating new lines, contentOffset is animated, but because because
// we are simultaneously resizing the text view, this can cause the
// text in the textview to be "too high" in the text view.
// Solution is to disable animation for setting content offset.
override func setContentOffset(_ contentOffset: CGPoint, animated: Bool) {
super.setContentOffset(contentOffset, animated: false)
}
}
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
}
}
// MARK: - Initializers
init(isAddMoreVisible: Bool) {
self.addMoreButton = UIButton(type: .custom)
self.sendButton = UIButton(type: .system)
self.textView = MessageTextView()
self.textViewHeight = kMinTextViewHeight
super.init(frame: CGRect.zero)
@ -1601,18 +1566,6 @@ class MediaMessageTextToolbar: UIView, UITextViewDelegate {
self.backgroundColor = UIColor.clear
textView.delegate = self
textView.keyboardAppearance = Theme.keyboardAppearance
textView.backgroundColor = Theme.darkThemeBackgroundColor
textView.tintColor = Theme.darkThemePrimaryColor
textView.layer.borderColor = Theme.darkThemePrimaryColor.cgColor
textView.layer.borderWidth = 0.5
textView.layer.cornerRadius = kMinTextViewHeight / 2
textView.font = UIFont.ows_dynamicTypeBody
textView.textColor = Theme.darkThemePrimaryColor
textView.returnKeyType = .done
textView.textContainerInset = UIEdgeInsets(top: 7, left: 7, bottom: 7, right: 7)
textView.scrollIndicatorInsets = UIEdgeInsets(top: 5, left: 0, bottom: 5, right: 3)
let addMoreIcon = #imageLiteral(resourceName: "album_add_more").withRenderingMode(.alwaysTemplate)
addMoreButton.setImage(addMoreIcon, for: .normal)
@ -1632,7 +1585,7 @@ class MediaMessageTextToolbar: UIView, UITextViewDelegate {
let contentView = UIView()
contentView.addSubview(sendButton)
contentView.addSubview(textView)
contentView.addSubview(textContainer)
contentView.addSubview(lengthLimitLabel)
if isAddMoreVisible {
contentView.addSubview(addMoreButton)
@ -1658,20 +1611,20 @@ class MediaMessageTextToolbar: UIView, UITextViewDelegate {
// So it doesn't work as expected with RTL layouts when we explicitly want something
// to be on the right side for both RTL and LTR layouts, like with the send button.
// I believe this is a bug in PureLayout. Filed here: https://github.com/PureLayout/PureLayout/issues/209
textView.autoPinEdge(toSuperviewMargin: .top)
textView.autoPinEdge(toSuperviewMargin: .bottom)
textContainer.autoPinEdge(toSuperviewMargin: .top)
textContainer.autoPinEdge(toSuperviewMargin: .bottom)
if isAddMoreVisible {
addMoreButton.autoPinEdge(toSuperviewMargin: .left)
textView.autoPinEdge(.left, to: .right, of: addMoreButton, withOffset: kToolbarMargin)
textContainer.autoPinEdge(.left, to: .right, of: addMoreButton, withOffset: kToolbarMargin)
addMoreButton.autoAlignAxis(.horizontal, toSameAxisOf: sendButton)
addMoreButton.setContentHuggingHigh()
addMoreButton.setCompressionResistanceHigh()
} else {
textView.autoPinEdge(toSuperviewMargin: .left)
textContainer.autoPinEdge(toSuperviewMargin: .left)
}
sendButton.autoPinEdge(.left, to: .right, of: textView, withOffset: kToolbarMargin)
sendButton.autoPinEdge(.bottom, to: .bottom, of: textView, withOffset: -3)
sendButton.autoPinEdge(.left, to: .right, of: textContainer, withOffset: kToolbarMargin)
sendButton.autoPinEdge(.bottom, to: .bottom, of: textContainer, withOffset: -3)
sendButton.autoPinEdge(toSuperviewMargin: .right)
sendButton.setContentHuggingHigh()
@ -1679,7 +1632,7 @@ class MediaMessageTextToolbar: UIView, UITextViewDelegate {
lengthLimitLabel.autoPinEdge(toSuperviewMargin: .left)
lengthLimitLabel.autoPinEdge(toSuperviewMargin: .right)
lengthLimitLabel.autoPinEdge(.bottom, to: .top, of: textView, withOffset: -6)
lengthLimitLabel.autoPinEdge(.bottom, to: .top, of: textContainer, withOffset: -6)
lengthLimitLabel.setContentHuggingHigh()
lengthLimitLabel.setCompressionResistanceHigh()
}
@ -1688,7 +1641,98 @@ class MediaMessageTextToolbar: UIView, UITextViewDelegate {
notImplemented()
}
// MARK: -
// MARK: - UIView Overrides
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
}
}
// MARK: - Subviews
private let addMoreButton: UIButton
private let sendButton: UIButton
private lazy var lengthLimitLabel: UILabel = {
let lengthLimitLabel = UILabel()
// Length Limit Label shown when the user inputs too long of a message
lengthLimitLabel.textColor = .white
lengthLimitLabel.text = NSLocalizedString("ATTACHMENT_APPROVAL_MESSAGE_LENGTH_LIMIT_REACHED", comment: "One-line label indicating the user can add no more text to the media message field.")
lengthLimitLabel.textAlignment = .center
// 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.shadowOpacity = 0.8
lengthLimitLabel.isHidden = true
return lengthLimitLabel
}()
lazy var textView: UITextView = {
let textView = buildTextView()
textView.returnKeyType = .done
textView.scrollIndicatorInsets = UIEdgeInsets(top: 5, left: 0, bottom: 5, right: 3)
return textView
}()
private lazy var placeholderTextView: UITextView = {
let placeholderTextView = buildTextView()
placeholderTextView.text = NSLocalizedString("MESSAGE_TEXT_FIELD_PLACEHOLDER", comment: "placeholder text for the editable message field")
placeholderTextView.isEditable = false
return placeholderTextView
}()
private lazy var textContainer: UIView = {
let textContainer = UIView()
textContainer.layer.borderColor = Theme.darkThemePrimaryColor.cgColor
textContainer.layer.borderWidth = 0.5
textContainer.layer.cornerRadius = kMinTextViewHeight / 2
textContainer.clipsToBounds = true
textContainer.addSubview(placeholderTextView)
placeholderTextView.autoPinEdgesToSuperviewEdges()
textContainer.addSubview(textView)
textView.autoPinEdgesToSuperviewEdges()
return textContainer
}()
private func buildTextView() -> UITextView {
let textView = MessageTextView()
textView.keyboardAppearance = Theme.keyboardAppearance
textView.backgroundColor = .clear
textView.tintColor = Theme.darkThemePrimaryColor
textView.font = UIFont.ows_dynamicTypeBody
textView.textColor = Theme.darkThemePrimaryColor
textView.textContainerInset = UIEdgeInsets(top: 7, left: 7, bottom: 7, right: 7)
return textView
}
class MessageTextView: UITextView {
// When creating new lines, contentOffset is animated, but because
// we are simultaneously resizing the text view, this can cause the
// text in the textview to be "too high" in the text view.
// Solution is to disable animation for setting content offset.
override func setContentOffset(_ contentOffset: CGPoint, animated: Bool) {
super.setContentOffset(contentOffset, animated: false)
}
}
// MARK: - Actions
@objc func didTapSend() {
mediaMessageTextToolbarDelegate?.mediaMessageTextToolbarDidTapSend(self)
@ -1741,14 +1785,36 @@ class MediaMessageTextToolbar: UIView, UITextViewDelegate {
public func textViewDidBeginEditing(_ textView: UITextView) {
mediaMessageTextToolbarDelegate?.mediaMessageTextToolbarDidBeginEditing(self)
updatePlaceholderTextViewVisibility()
}
public func textViewDidEndEditing(_ textView: UITextView) {
mediaMessageTextToolbarDelegate?.mediaMessageTextToolbarDidEndEditing(self)
updatePlaceholderTextViewVisibility()
}
// MARK: - Helpers
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 func updateHeight(textView: UITextView) {
// compute new height assuming width is unchanged
let currentSize = textView.frame.size