session-ios/Session/Conversations/Input View/InputTextView.swift

125 lines
4.2 KiB
Swift
Raw Normal View History

// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
2021-01-29 01:46:32 +01:00
import UIKit
import SessionUIKit
public final class InputTextView: UITextView, UITextViewDelegate {
2021-04-01 05:24:10 +02:00
private weak var snDelegate: InputTextViewDelegate?
2021-03-01 23:33:31 +01:00
private let maxWidth: CGFloat
2021-01-29 01:46:32 +01:00
private lazy var heightConstraint = self.set(.height, to: minHeight)
public override var text: String? { didSet { handleTextChanged() } }
2021-02-22 04:29:14 +01:00
// MARK: - UI Components
2021-01-29 01:46:32 +01:00
private lazy var placeholderLabel: UILabel = {
let result = UILabel()
result.font = .systemFont(ofSize: Values.mediumFontSize)
result.text = "vc_conversation_input_prompt".localized()
result.themeTextColor = .textSecondary
2021-01-29 01:46:32 +01:00
return result
}()
// MARK: - Settings
2021-01-29 01:46:32 +01:00
private let minHeight: CGFloat = 22
2021-02-10 05:33:39 +01:00
private let maxHeight: CGFloat = 80
2021-01-29 01:46:32 +01:00
// MARK: - Lifecycle
2021-03-01 23:33:31 +01:00
init(delegate: InputTextViewDelegate, maxWidth: CGFloat) {
2021-01-29 01:46:32 +01:00
snDelegate = delegate
2021-03-01 23:33:31 +01:00
self.maxWidth = maxWidth
2021-01-29 01:46:32 +01:00
super.init(frame: CGRect.zero, textContainer: nil)
2021-01-29 01:46:32 +01:00
setUpViewHierarchy()
self.delegate = self
2021-08-25 06:12:47 +02:00
self.isAccessibilityElement = true
self.accessibilityLabel = "vc_conversation_input_prompt".localized()
2021-01-29 01:46:32 +01:00
}
public override init(frame: CGRect, textContainer: NSTextContainer?) {
preconditionFailure("Use init(delegate:) instead.")
}
public required init?(coder: NSCoder) {
preconditionFailure("Use init(delegate:) instead.")
}
2021-12-13 05:51:42 +01:00
public override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if action == #selector(paste(_:)) {
if UIPasteboard.general.hasImages {
2021-12-13 05:51:42 +01:00
return true
}
}
return super.canPerformAction(action, withSender: sender)
}
public override func paste(_ sender: Any?) {
if let image = UIPasteboard.general.image {
snDelegate?.didPasteImageFromPasteboard(self, image: image)
}
super.paste(sender)
}
2021-01-29 01:46:32 +01:00
private func setUpViewHierarchy() {
showsHorizontalScrollIndicator = false
showsVerticalScrollIndicator = false
2021-01-29 01:46:32 +01:00
font = .systemFont(ofSize: Values.mediumFontSize)
themeBackgroundColor = .clear
themeTextColor = .textPrimary
themeTintColor = .primary
2021-01-29 01:46:32 +01:00
heightConstraint.isActive = true
let horizontalInset: CGFloat = 2
textContainerInset = UIEdgeInsets(top: 0, left: horizontalInset, bottom: 0, right: horizontalInset)
addSubview(placeholderLabel)
placeholderLabel.pin(.leading, to: .leading, of: self, withInset: horizontalInset + 3) // Slight visual adjustment
placeholderLabel.pin(.top, to: .top, of: self)
pin(.trailing, to: .trailing, of: placeholderLabel, withInset: horizontalInset)
pin(.bottom, to: .bottom, of: placeholderLabel)
ThemeManager.onThemeChange(observer: self) { [weak self] theme, _ in
switch theme.interfaceStyle {
case .light: self?.keyboardAppearance = .light
default: self?.keyboardAppearance = .dark
}
}
2021-01-29 01:46:32 +01:00
}
// MARK: - Updating
2021-01-29 01:46:32 +01:00
public func textViewDidChange(_ textView: UITextView) {
2021-02-22 04:29:14 +01:00
handleTextChanged()
}
private func handleTextChanged() {
2021-04-01 05:24:10 +02:00
defer { snDelegate?.inputTextViewDidChangeContent(self) }
placeholderLabel.isHidden = !(text ?? "").isEmpty
2021-01-29 01:46:32 +01:00
let height = frame.height
2021-03-01 23:33:31 +01:00
let size = sizeThatFits(CGSize(width: maxWidth, height: .greatestFiniteMagnitude))
2021-01-29 01:46:32 +01:00
// `textView.contentSize` isn't accurate when restoring a multiline draft, so we set it here manually
self.contentSize = size
let newHeight = size.height.clamp(minHeight, maxHeight)
2021-01-29 01:46:32 +01:00
guard newHeight != height else { return }
2021-01-29 01:46:32 +01:00
heightConstraint.constant = newHeight
2021-04-01 05:24:10 +02:00
snDelegate?.inputTextViewDidChangeSize(self)
2021-01-29 01:46:32 +01:00
}
}
// MARK: - InputTextViewDelegate
protocol InputTextViewDelegate: AnyObject {
2021-01-29 01:46:32 +01:00
func inputTextViewDidChangeSize(_ inputTextView: InputTextView)
func inputTextViewDidChangeContent(_ inputTextView: InputTextView)
2021-12-13 05:51:42 +01:00
func didPasteImageFromPasteboard(_ inputTextView: InputTextView, image: UIImage)
2021-01-29 01:46:32 +01:00
}