element-ios/Riot/Modules/Room/Views/BubbleCells/KeyVerification/KeyVerificationBaseBubbleCell.swift

262 lines
8.7 KiB
Swift
Raw Normal View History

2019-12-20 09:42:28 +00:00
/*
Copyright 2019 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import Foundation
@objcMembers
class KeyVerificationBaseBubbleCell: MXKRoomBubbleTableViewCell {
// MARK: - Constants
private enum Sizing {
static var sizes = Set<SizingViewHeight>()
}
// MARK: - Properties
// MARK: Public
weak var keyVerificationCellInnerContentView: KeyVerificationCellInnerContentView?
weak var bubbleCellContentView: BubbleCellContentView?
2019-12-20 09:42:28 +00:00
override var bubbleInfoContainer: UIView! {
get {
guard let infoContainer = self.bubbleCellContentView?.bubbleInfoContainer else {
2019-12-20 09:42:28 +00:00
fatalError("[KeyVerificationBaseBubbleCell] bubbleInfoContainer should not be used before set")
}
return infoContainer
}
set {
super.bubbleInfoContainer = newValue
}
}
override var bubbleOverlayContainer: UIView! {
get {
guard let overlayContainer = self.bubbleCellContentView?.bubbleOverlayContainer else {
2019-12-20 09:42:28 +00:00
fatalError("[KeyVerificationBaseBubbleCell] bubbleOverlayContainer should not be used before set")
}
return overlayContainer
}
set {
super.bubbleInfoContainer = newValue
}
}
override var bubbleInfoContainerTopConstraint: NSLayoutConstraint! {
get {
guard let infoContainerTopConstraint = self.bubbleCellContentView?.bubbleInfoContainerTopConstraint else {
2019-12-20 09:42:28 +00:00
fatalError("[KeyVerificationBaseBubbleCell] bubbleInfoContainerTopConstraint should not be used before set")
}
return infoContainerTopConstraint
}
set {
super.bubbleInfoContainerTopConstraint = newValue
}
}
// MARK: - Setup
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.commonInit()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func commonInit() {
self.selectionStyle = .none
self.setupContentView()
self.update(theme: ThemeService.shared().theme)
super.setupViews()
}
// MARK: - Public
func update(theme: Theme) {
self.bubbleCellContentView?.update(theme: theme)
2019-12-20 09:42:28 +00:00
self.keyVerificationCellInnerContentView?.update(theme: theme)
}
func buildUserInfoText(with userId: String, userDisplayName: String?) -> String {
let userInfoText: String
if let userDisplayName = userDisplayName {
userInfoText = "\(userId) (\(userDisplayName))"
} else {
userInfoText = userId
}
return userInfoText
}
func senderId(from bubbleCellData: MXKRoomBubbleCellData) -> String {
return bubbleCellData.senderId ?? ""
}
func senderDisplayName(from bubbleCellData: MXKRoomBubbleCellData) -> String? {
let senderId = self.senderId(from: bubbleCellData)
guard let senderDisplayName = bubbleCellData.senderDisplayName, senderId != senderDisplayName else {
return nil
}
return senderDisplayName
}
class func sizingView() -> KeyVerificationBaseBubbleCell {
fatalError("[KeyVerificationBaseBubbleCell] Subclass should implement this method")
2019-12-20 09:42:28 +00:00
}
class func sizingViewHeightHashValue(from bubbleCellData: MXKRoomBubbleCellData) -> Int {
var hasher = Hasher()
let sizingView = self.sizingView()
sizingView.render(bubbleCellData)
// Add cell class name
hasher.combine(self.defaultReuseIdentifier())
if let keyVerificationCellInnerContentView = sizingView.keyVerificationCellInnerContentView {
// Add other user info
if let otherUserInfo = keyVerificationCellInnerContentView.otherUserInfo {
hasher.combine(otherUserInfo)
}
// Add request status text
if keyVerificationCellInnerContentView.isRequestStatusHidden == false,
let requestStatusText = sizingView.keyVerificationCellInnerContentView?.requestStatusText {
hasher.combine(requestStatusText)
}
}
return hasher.finalize()
2019-12-20 09:42:28 +00:00
}
// MARK: - Overrides
override class func defaultReuseIdentifier() -> String! {
return String(describing: self)
}
override func didEndDisplay() {
super.didEndDisplay()
self.removeReadReceiptsView()
}
override class func height(for cellData: MXKCellData!, withMaximumWidth maxWidth: CGFloat) -> CGFloat {
guard let cellData = cellData else {
return 0
}
guard let roomBubbleCellData = cellData as? MXKRoomBubbleCellData else {
return 0
}
let height: CGFloat
let sizingViewHeight = self.findOrCreateSizingViewHeight(from: roomBubbleCellData)
if let cachedHeight = sizingViewHeight.heights[maxWidth] {
height = cachedHeight
} else {
height = self.contentViewHeight(for: roomBubbleCellData, fitting: maxWidth)
sizingViewHeight.heights[maxWidth] = height
}
return height
}
override func render(_ cellData: MXKCellData!) {
super.render(cellData)
if let bubbleData = self.bubbleData,
let bubbleCellContentView = self.bubbleCellContentView,
let paginationDate = bubbleData.date,
bubbleCellContentView.showPaginationTitle {
bubbleCellContentView.paginationLabel.text = bubbleData.eventFormatter.dateString(from: paginationDate, withTime: false)?.uppercased()
}
}
2019-12-20 09:42:28 +00:00
// MARK: - Private
private func setupContentView() {
if self.bubbleCellContentView == nil {
2019-12-20 09:42:28 +00:00
let bubbleCellContentView = BubbleCellContentView.instantiate()
2019-12-20 09:42:28 +00:00
let innerContentView = KeyVerificationCellInnerContentView.instantiate()
bubbleCellContentView.innerContentView.vc_addSubViewMatchingParent(innerContentView)
2019-12-20 09:42:28 +00:00
self.contentView.vc_addSubViewMatchingParent(bubbleCellContentView)
2019-12-20 09:42:28 +00:00
self.bubbleCellContentView = bubbleCellContentView
2019-12-20 09:42:28 +00:00
self.keyVerificationCellInnerContentView = innerContentView
}
}
private static func findOrCreateSizingViewHeight(from bubbleData: MXKRoomBubbleCellData) -> SizingViewHeight {
let sizingViewHeight: SizingViewHeight
let bubbleDataHashValue = bubbleData.hashValue
if let foundSizingViewHeight = self.Sizing.sizes.first(where: { (sizingViewHeight) -> Bool in
return sizingViewHeight.uniqueIdentifier == bubbleDataHashValue
}) {
sizingViewHeight = foundSizingViewHeight
} else {
sizingViewHeight = SizingViewHeight(uniqueIdentifier: bubbleDataHashValue)
}
return sizingViewHeight
}
private static func contentViewHeight(for cellData: MXKCellData, fitting width: CGFloat) -> CGFloat {
let sizingView = self.sizingView()
sizingView.render(cellData)
sizingView.layoutIfNeeded()
let fittingSize = CGSize(width: width, height: UIView.layoutFittingCompressedSize.height)
var height = sizingView.systemLayoutSizeFitting(fittingSize).height
if let roomBubbleCellData = cellData as? RoomBubbleCellData, let readReceipts = roomBubbleCellData.readReceipts, readReceipts.count > 0 {
height+=RoomBubbleCellLayout.readReceiptsViewHeight
}
2019-12-20 09:42:28 +00:00
return height
}
}
// MARK: - BubbleCellReadReceiptsDisplayable
extension KeyVerificationBaseBubbleCell: BubbleCellReadReceiptsDisplayable {
func addReadReceiptsView(_ readReceiptsView: UIView) {
self.bubbleCellContentView?.addReadReceiptsView(readReceiptsView)
2019-12-20 09:42:28 +00:00
}
func removeReadReceiptsView() {
self.bubbleCellContentView?.removeReadReceiptsView()
2019-12-20 09:42:28 +00:00
}
}