CaptionView text field per page

pull/1/head
Michael Kirk 7 years ago
parent 79995cc52c
commit cd88ef2bec

@ -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: %@";

@ -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)

Loading…
Cancel
Save