element-ios/Riot/Modules/Room/Views/BubbleCells/RoomCreationIntro/RoomCreationIntroCell.swift
2021-02-23 08:48:17 +01:00

199 lines
6.8 KiB
Swift

//
// Copyright 2020 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 UIKit
@objcMembers
class RoomCreationIntroCell: MXKRoomBubbleTableViewCell {
// MARK: - Constants
private enum Sizing {
static var sizes = Set<SizingViewHeight>()
static let view: RoomCreationIntroCell = RoomCreationIntroCell(style: .default, reuseIdentifier: nil)
}
static let tapOnAvatarView = "RoomCreationIntroCellTapOnAvatarView"
static let tapOnAddTopic = "RoomCreationIntroCellTapOnAddTopic"
static let tapOnAddParticipants = "RoomCreationIntroCellTapOnAddParticipants"
// MARK: - Properties
private weak var bubbleCellContentView: RoomCreationIntroCellContentView?
// 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)
}
// MARK: - Overrides
override class func defaultReuseIdentifier() -> String! {
return String(describing: self)
}
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)
guard let bubbleCellContentView = self.bubbleCellContentView else {
NSLog("[RoomCreationIntroCell] Fail to load content view")
return
}
guard let bubbleData = self.bubbleData,
let viewData = self.viewData(from: bubbleData) else {
NSLog("[RoomCreationIntroCell] Fail to render \(String(describing: cellData))")
return
}
bubbleCellContentView.fill(with: viewData)
}
// MARK: - Private
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 class func sizingView() -> RoomCreationIntroCell {
return self.Sizing.view
}
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)
return sizingView.systemLayoutSizeFitting(fittingSize).height
}
private func setupContentView() {
guard self.bubbleCellContentView == nil else {
return
}
let bubbleCellContentView = RoomCreationIntroCellContentView.instantiate()
self.contentView.vc_addSubViewMatchingParent(bubbleCellContentView)
self.bubbleCellContentView = bubbleCellContentView
bubbleCellContentView.roomAvatarView?.action = { [weak self] in
self?.notifyDelegate(with: RoomCreationIntroCell.tapOnAvatarView)
}
bubbleCellContentView.didTapTopic = { [weak self] in
self?.notifyDelegate(with: RoomCreationIntroCell.tapOnAddTopic)
}
bubbleCellContentView.didTapAddParticipants = { [weak self] in
self?.notifyDelegate(with: RoomCreationIntroCell.tapOnAddParticipants)
}
}
private func viewData(from bubbleData: MXKRoomBubbleCellData) -> RoomCreationIntroViewData? {
guard let session = bubbleData.mxSession, let roomId = bubbleData.roomId, let room = session.room(withRoomId: roomId) else {
return nil
}
guard let roomSummary = room.summary else {
return nil
}
let discussionType: DiscussionType
if roomSummary.isDirect {
if roomSummary.membersCount.members > 2 {
discussionType = .directMessage
} else {
discussionType = .multipleDirectMessage
}
} else {
discussionType = .room(topic: roomSummary.topic)
}
let displayName = roomSummary.displayname ?? ""
let roomAvatarViewData = RoomAvatarViewData(roomId: roomId,
roomDisplayName: displayName,
avatarUrl: room.summary.avatar, mediaManager: session.mediaManager)
return RoomCreationIntroViewData(dicussionType: discussionType, roomDisplayName: displayName, avatarViewData: roomAvatarViewData)
}
private func notifyDelegate(with actionIdentifier: String) {
self.delegate.cell(self, didRecognizeAction: actionIdentifier, userInfo: nil)
}
}