session-ios/Session/Shared/CaptionView.swift

189 lines
5.2 KiB
Swift

// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
import UIKit
import SessionUIKit
import SessionUtilitiesKit
public protocol CaptionContainerViewDelegate: AnyObject {
func captionContainerViewDidUpdateText(_ captionContainerView: CaptionContainerView)
}
public class CaptionContainerView: UIView {
weak var delegate: CaptionContainerViewDelegate?
var currentText: String? {
get { return currentCaptionView.text }
set {
currentCaptionView.text = newValue
delegate?.captionContainerViewDidUpdateText(self)
}
}
var pendingText: String? {
get { return pendingCaptionView.text }
set {
pendingCaptionView.text = newValue
delegate?.captionContainerViewDidUpdateText(self)
}
}
func updatePagerTransition(ratioComplete: CGFloat) {
if let currentText = self.currentText, currentText.count > 0 {
currentCaptionView.alpha = 1 - ratioComplete
} else {
currentCaptionView.alpha = 0
}
if let pendingText = self.pendingText, pendingText.count > 0 {
pendingCaptionView.alpha = ratioComplete
} else {
pendingCaptionView.alpha = 0
}
}
func completePagerTransition() {
updatePagerTransition(ratioComplete: 1)
// promote "pending" to "current" caption view.
let oldCaptionView = self.currentCaptionView
self.currentCaptionView = self.pendingCaptionView
self.pendingCaptionView = oldCaptionView
self.pendingText = nil
self.currentCaptionView.alpha = 1
self.pendingCaptionView.alpha = 0
}
// MARK: Initializers
override init(frame: CGRect) {
super.init(frame: frame)
setContentHuggingHigh()
setCompressionResistanceHigh()
addSubview(currentCaptionView)
currentCaptionView.autoPinEdgesToSuperviewEdges(with: .zero, excludingEdge: .top)
currentCaptionView.autoPinEdge(toSuperviewEdge: .top, withInset: 0, relation: .greaterThanOrEqual)
pendingCaptionView.alpha = 0
addSubview(pendingCaptionView)
pendingCaptionView.autoPinEdgesToSuperviewEdges(with: .zero, excludingEdge: .top)
pendingCaptionView.autoPinEdge(toSuperviewEdge: .top, withInset: 0, relation: .greaterThanOrEqual)
}
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: Subviews
private var pendingCaptionView: CaptionView = CaptionView()
private var currentCaptionView: CaptionView = CaptionView()
}
private class CaptionView: UIView {
var text: String? {
get { return textView.text }
set {
if let captionText = newValue, captionText.count > 0 {
textView.text = captionText
} else {
textView.text = nil
}
}
}
// MARK: Subviews
let textView: CaptionTextView = {
let textView = CaptionTextView()
textView.font = UIFont.preferredFont(forTextStyle: .body)
textView.themeTextColor = .textPrimary
textView.themeBackgroundColor = .clear
textView.isEditable = false
textView.isSelectable = false
return textView
}()
let scrollFadeView: GradientView = {
let result: GradientView = GradientView()
result.themeBackgroundGradient = [
.clear,
.black
]
return result
}()
// MARK: Initializers
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(textView)
textView.autoPinEdgesToSuperviewMargins()
addSubview(scrollFadeView)
scrollFadeView.autoPinEdgesToSuperviewEdges(with: .zero, excludingEdge: .top)
scrollFadeView.autoSetDimension(.height, toSize: 20)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: UIView overrides
override func layoutSubviews() {
super.layoutSubviews()
scrollFadeView.isHidden = !textView.doesContentNeedScroll
}
// MARK: -
class CaptionTextView: UITextView {
var kMaxHeight: CGFloat = ScaleFromIPhone5(200)
override var text: String! {
didSet {
invalidateIntrinsicContentSize()
}
}
override var font: UIFont? {
didSet {
invalidateIntrinsicContentSize()
}
}
var doesContentNeedScroll: Bool {
return self.bounds.height == kMaxHeight
}
override func layoutSubviews() {
super.layoutSubviews()
// Enable/disable scrolling depending on wether we've clipped
// content in `intrinsicContentSize`
isScrollEnabled = doesContentNeedScroll
}
override var intrinsicContentSize: CGSize {
var size = super.intrinsicContentSize
if size.height == UIView.noIntrinsicMetric {
size.height = layoutManager.usedRect(for: textContainer).height + textContainerInset.top + textContainerInset.bottom
}
size.height = min(kMaxHeight, size.height)
return size
}
}
}