mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
b6328f79b9
Shifted the initial HomeVC population to a background thread to avoid blocking launch processing Added some logging for database 'ABORT' errors to better identify cases of deadlocks Added a launch timeout modal to allow users to share their logs if the startup process happens to hang Updated the notification handling (and cancelling) so it could run on background threads (seemed to take up a decent chunk of main thread time) Fixed an issue where the IP2Country population was running sync which could cause a hang on startup Fixed an issue where the code checking if the UIPasteBoard contained an image was explicitly advised against by the documentation (caused some reported hangs) Fixed a hang which could be caused by a redundant function when the ImagePickerController appeared
124 lines
4.2 KiB
Swift
124 lines
4.2 KiB
Swift
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
|
|
|
import UIKit
|
|
import SessionUIKit
|
|
|
|
public final class InputTextView: UITextView, UITextViewDelegate {
|
|
private weak var snDelegate: InputTextViewDelegate?
|
|
private let maxWidth: CGFloat
|
|
private lazy var heightConstraint = self.set(.height, to: minHeight)
|
|
|
|
public override var text: String? { didSet { handleTextChanged() } }
|
|
|
|
// MARK: - UI Components
|
|
|
|
private lazy var placeholderLabel: UILabel = {
|
|
let result = UILabel()
|
|
result.font = .systemFont(ofSize: Values.mediumFontSize)
|
|
result.text = "vc_conversation_input_prompt".localized()
|
|
result.themeTextColor = .textSecondary
|
|
|
|
return result
|
|
}()
|
|
|
|
// MARK: - Settings
|
|
|
|
private let minHeight: CGFloat = 22
|
|
private let maxHeight: CGFloat = 80
|
|
|
|
// MARK: - Lifecycle
|
|
|
|
init(delegate: InputTextViewDelegate, maxWidth: CGFloat) {
|
|
snDelegate = delegate
|
|
self.maxWidth = maxWidth
|
|
|
|
super.init(frame: CGRect.zero, textContainer: nil)
|
|
|
|
setUpViewHierarchy()
|
|
self.delegate = self
|
|
self.isAccessibilityElement = true
|
|
self.accessibilityLabel = "vc_conversation_input_prompt".localized()
|
|
}
|
|
|
|
public override init(frame: CGRect, textContainer: NSTextContainer?) {
|
|
preconditionFailure("Use init(delegate:) instead.")
|
|
}
|
|
|
|
public required init?(coder: NSCoder) {
|
|
preconditionFailure("Use init(delegate:) instead.")
|
|
}
|
|
|
|
public override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
|
|
if action == #selector(paste(_:)) {
|
|
if UIPasteboard.general.hasImages {
|
|
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)
|
|
}
|
|
|
|
private func setUpViewHierarchy() {
|
|
showsHorizontalScrollIndicator = false
|
|
showsVerticalScrollIndicator = false
|
|
|
|
font = .systemFont(ofSize: Values.mediumFontSize)
|
|
themeBackgroundColor = .clear
|
|
themeTextColor = .textPrimary
|
|
themeTintColor = .primary
|
|
|
|
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
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Updating
|
|
|
|
public func textViewDidChange(_ textView: UITextView) {
|
|
handleTextChanged()
|
|
}
|
|
|
|
private func handleTextChanged() {
|
|
defer { snDelegate?.inputTextViewDidChangeContent(self) }
|
|
|
|
placeholderLabel.isHidden = !(text ?? "").isEmpty
|
|
|
|
let height = frame.height
|
|
let size = sizeThatFits(CGSize(width: maxWidth, height: .greatestFiniteMagnitude))
|
|
|
|
// `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)
|
|
|
|
guard newHeight != height else { return }
|
|
|
|
heightConstraint.constant = newHeight
|
|
snDelegate?.inputTextViewDidChangeSize(self)
|
|
}
|
|
}
|
|
|
|
// MARK: - InputTextViewDelegate
|
|
|
|
protocol InputTextViewDelegate: AnyObject {
|
|
func inputTextViewDidChangeSize(_ inputTextView: InputTextView)
|
|
func inputTextViewDidChangeContent(_ inputTextView: InputTextView)
|
|
func didPasteImageFromPasteboard(_ inputTextView: InputTextView, image: UIImage)
|
|
}
|