Merge branch 'develop' into riot_2890

This commit is contained in:
manuroe
2020-01-16 09:33:57 +01:00
committed by GitHub
55 changed files with 2515 additions and 99 deletions
@@ -0,0 +1,91 @@
/*
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 UIKit
import Reusable
@objcMembers
final class BubbleCellContentView: UIView, NibLoadable {
// MARK: - Properties
// MARK: Outlets
@IBOutlet weak var bubbleInfoContainer: UIView!
@IBOutlet weak var bubbleInfoContainerTopConstraint: NSLayoutConstraint!
@IBOutlet weak var innerContentView: UIView!
@IBOutlet weak var readReceiptsContainerView: UIView!
@IBOutlet weak var readReceiptsContentView: UIView!
@IBOutlet weak var bubbleOverlayContainer: UIView!
@IBOutlet weak var paginationTitleContainerView: UIView!
@IBOutlet weak var paginationLabel: UILabel!
@IBOutlet weak var paginationSeparatorView: UIView!
// MARK: Private
private var showReadReceipts: Bool {
get {
return !self.readReceiptsContainerView.isHidden
}
set {
self.readReceiptsContainerView.isHidden = !newValue
}
}
// MARK: Public
var showPaginationTitle: Bool {
get {
return !self.paginationTitleContainerView.isHidden
}
set {
self.paginationTitleContainerView.isHidden = !newValue
}
}
// MARK: - Setup
class func instantiate() -> BubbleCellContentView {
return BubbleCellContentView.loadFromNib()
}
// MARK: - Public
func update(theme: Theme) {
self.backgroundColor = theme.backgroundColor
self.paginationLabel.textColor = theme.tintColor
self.paginationSeparatorView.backgroundColor = theme.tintColor
}
}
// MARK: - BubbleCellReadReceiptsDisplayable
extension BubbleCellContentView: BubbleCellReadReceiptsDisplayable {
func addReadReceiptsView(_ readReceiptsView: UIView) {
self.readReceiptsContentView.vc_removeAllSubviews()
self.readReceiptsContentView.vc_addSubViewMatchingParent(readReceiptsView)
self.showReadReceipts = true
}
func removeReadReceiptsView() {
self.showReadReceipts = false
self.readReceiptsContentView.vc_removeAllSubviews()
}
}
@@ -0,0 +1,148 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="zG5-YA-Ijy" customClass="BubbleCellContentView" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="595" height="97"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="XQw-Mj-NZY">
<rect key="frame" x="0.0" y="0.0" width="595" height="97"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</view>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="5GX-gn-bK1">
<rect key="frame" x="0.0" y="0.0" width="595" height="97"/>
<subviews>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="u1e-Q2-PhY">
<rect key="frame" x="0.0" y="0.0" width="595" height="54"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Ro1-vP-6Ha" userLabel="Pagination Title View">
<rect key="frame" x="67" y="10" width="518" height="24"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="r7y-FK-GWS" userLabel="Pagination Label">
<rect key="frame" x="0.0" y="0.0" width="508" height="18"/>
<constraints>
<constraint firstAttribute="height" constant="18" id="uCj-An-Yc2"/>
</constraints>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<color key="textColor" red="0.66666666669999997" green="0.66666666669999997" blue="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ytv-tA-NmI" userLabel="Pagination Separator View">
<rect key="frame" x="0.0" y="23" width="518" height="1"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<accessibility key="accessibilityConfiguration" identifier="PaginationTitleView"/>
<constraints>
<constraint firstAttribute="height" constant="24" id="5bk-I2-Cw6"/>
<constraint firstAttribute="bottom" secondItem="ytv-tA-NmI" secondAttribute="bottom" id="5oD-hl-YNI"/>
<constraint firstAttribute="trailing" secondItem="ytv-tA-NmI" secondAttribute="trailing" id="Cfu-Jn-urV"/>
<constraint firstItem="r7y-FK-GWS" firstAttribute="leading" secondItem="Ro1-vP-6Ha" secondAttribute="leading" id="Fpo-9J-9Ci"/>
<constraint firstItem="r7y-FK-GWS" firstAttribute="top" secondItem="Ro1-vP-6Ha" secondAttribute="top" id="Rpc-oi-muy"/>
<constraint firstItem="ytv-tA-NmI" firstAttribute="top" secondItem="r7y-FK-GWS" secondAttribute="bottom" constant="5" id="lam-eF-rEV"/>
<constraint firstItem="ytv-tA-NmI" firstAttribute="leading" secondItem="Ro1-vP-6Ha" secondAttribute="leading" id="oBH-4x-jgt"/>
<constraint firstAttribute="trailing" secondItem="r7y-FK-GWS" secondAttribute="trailing" constant="10" id="r4y-XW-aAD"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="Ro1-vP-6Ha" firstAttribute="top" secondItem="u1e-Q2-PhY" secondAttribute="top" constant="10" id="5kZ-rt-pvq"/>
<constraint firstAttribute="trailing" secondItem="Ro1-vP-6Ha" secondAttribute="trailing" constant="10" id="8P7-ZL-7pg"/>
<constraint firstItem="Ro1-vP-6Ha" firstAttribute="leading" secondItem="u1e-Q2-PhY" secondAttribute="leading" constant="67" id="NCS-nK-fLb"/>
<constraint firstAttribute="bottom" secondItem="Ro1-vP-6Ha" secondAttribute="bottom" constant="20" id="UcW-P4-rQv"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="vcq-cR-uBc">
<rect key="frame" x="0.0" y="0.0" width="595" height="97"/>
<subviews>
<view clipsSubviews="YES" contentMode="scaleAspectFit" translatesAutoresizingMaskIntoConstraints="NO" id="oeI-eO-mFK">
<rect key="frame" x="56" y="3" width="474" height="91"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</view>
<view hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="7Y6-Py-paB">
<rect key="frame" x="530" y="3" width="50" height="91"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<accessibility key="accessibilityConfiguration" identifier="BubbleInfoContainer"/>
<constraints>
<constraint firstAttribute="width" constant="50" id="LtA-zk-OCc"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="oeI-eO-mFK" firstAttribute="leading" secondItem="vcq-cR-uBc" secondAttribute="leading" constant="56" id="0Fr-0L-9tU"/>
<constraint firstItem="7Y6-Py-paB" firstAttribute="top" secondItem="vcq-cR-uBc" secondAttribute="top" constant="3" id="16j-F9-tL8"/>
<constraint firstAttribute="bottom" secondItem="oeI-eO-mFK" secondAttribute="bottom" constant="3" id="8M5-uW-82s"/>
<constraint firstItem="7Y6-Py-paB" firstAttribute="leading" secondItem="oeI-eO-mFK" secondAttribute="trailing" id="9V6-A8-9i0"/>
<constraint firstAttribute="bottom" secondItem="7Y6-Py-paB" secondAttribute="bottom" constant="3" id="lee-yN-381"/>
<constraint firstAttribute="trailing" secondItem="7Y6-Py-paB" secondAttribute="trailing" constant="15" id="rG0-0L-I4O"/>
<constraint firstItem="oeI-eO-mFK" firstAttribute="top" secondItem="vcq-cR-uBc" secondAttribute="top" constant="3" id="uZZ-I6-Xtq"/>
</constraints>
</view>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="4zo-V8-CNe">
<rect key="frame" x="0.0" y="0.0" width="595" height="12"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="rQt-NH-Cb0">
<rect key="frame" x="439" y="0.0" width="150" height="12"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="width" constant="150" id="fsY-DK-hUg"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="rQt-NH-Cb0" secondAttribute="bottom" id="6yV-vn-doj"/>
<constraint firstItem="rQt-NH-Cb0" firstAttribute="top" secondItem="4zo-V8-CNe" secondAttribute="top" id="DNc-jy-Urh"/>
<constraint firstAttribute="height" constant="12" id="TxZ-dJ-UI6"/>
<constraint firstAttribute="trailing" secondItem="rQt-NH-Cb0" secondAttribute="trailing" constant="6" id="lq2-AY-Lus"/>
</constraints>
</view>
</subviews>
<constraints>
<constraint firstItem="u1e-Q2-PhY" firstAttribute="width" secondItem="5GX-gn-bK1" secondAttribute="width" id="KrJ-dm-TaV"/>
<constraint firstItem="4zo-V8-CNe" firstAttribute="width" secondItem="5GX-gn-bK1" secondAttribute="width" id="bdq-sQ-NQy"/>
</constraints>
</stackView>
</subviews>
<color key="backgroundColor" red="0.95294117649999999" green="0.97254901959999995" blue="0.99215686270000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="5GX-gn-bK1" firstAttribute="leading" secondItem="zG5-YA-Ijy" secondAttribute="leading" id="36u-ut-l3G"/>
<constraint firstItem="5GX-gn-bK1" firstAttribute="top" secondItem="zG5-YA-Ijy" secondAttribute="top" id="As1-dI-9ba"/>
<constraint firstItem="XQw-Mj-NZY" firstAttribute="top" secondItem="zG5-YA-Ijy" secondAttribute="top" id="BuL-ri-8kT"/>
<constraint firstAttribute="bottom" secondItem="5GX-gn-bK1" secondAttribute="bottom" id="cNV-Or-YPg"/>
<constraint firstAttribute="trailing" secondItem="5GX-gn-bK1" secondAttribute="trailing" id="deR-Cu-Brh"/>
<constraint firstAttribute="trailing" secondItem="XQw-Mj-NZY" secondAttribute="trailing" id="eJl-Fg-neU"/>
<constraint firstAttribute="bottom" secondItem="XQw-Mj-NZY" secondAttribute="bottom" id="kPs-G8-HdC"/>
<constraint firstItem="XQw-Mj-NZY" firstAttribute="leading" secondItem="zG5-YA-Ijy" secondAttribute="leading" id="w8M-8g-ZQD"/>
</constraints>
<nil key="simulatedTopBarMetrics"/>
<nil key="simulatedBottomBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<connections>
<outlet property="bubbleInfoContainer" destination="7Y6-Py-paB" id="uLv-MM-HIL"/>
<outlet property="bubbleInfoContainerTopConstraint" destination="16j-F9-tL8" id="zxd-pd-SSx"/>
<outlet property="bubbleOverlayContainer" destination="XQw-Mj-NZY" id="6d1-EN-LPY"/>
<outlet property="innerContentView" destination="oeI-eO-mFK" id="ap1-He-C6g"/>
<outlet property="paginationLabel" destination="r7y-FK-GWS" id="R9V-ix-mDu"/>
<outlet property="paginationSeparatorView" destination="ytv-tA-NmI" id="sgk-n1-KQi"/>
<outlet property="paginationTitleContainerView" destination="u1e-Q2-PhY" id="Osl-dF-fpA"/>
<outlet property="readReceiptsContainerView" destination="4zo-V8-CNe" id="7ek-u4-CX8"/>
<outlet property="readReceiptsContentView" destination="rQt-NH-Cb0" id="tqw-je-kp9"/>
</connections>
<point key="canvasLocation" x="-975" y="-1318"/>
</view>
</objects>
</document>
@@ -0,0 +1,22 @@
/*
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
@objc protocol BubbleCellReadReceiptsDisplayable {
func addReadReceiptsView(_ readReceiptsView: UIView)
func removeReadReceiptsView()
}
@@ -0,0 +1,261 @@
/*
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?
override var bubbleInfoContainer: UIView! {
get {
guard let infoContainer = self.bubbleCellContentView?.bubbleInfoContainer else {
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 {
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 {
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)
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")
}
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()
}
// 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()
}
}
// MARK: - Private
private func setupContentView() {
if self.bubbleCellContentView == nil {
let bubbleCellContentView = BubbleCellContentView.instantiate()
let innerContentView = KeyVerificationCellInnerContentView.instantiate()
bubbleCellContentView.innerContentView.vc_addSubViewMatchingParent(innerContentView)
self.contentView.vc_addSubViewMatchingParent(bubbleCellContentView)
self.bubbleCellContentView = bubbleCellContentView
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
}
return height
}
}
// MARK: - BubbleCellReadReceiptsDisplayable
extension KeyVerificationBaseBubbleCell: BubbleCellReadReceiptsDisplayable {
func addReadReceiptsView(_ readReceiptsView: UIView) {
self.bubbleCellContentView?.addReadReceiptsView(readReceiptsView)
}
func removeReadReceiptsView() {
self.bubbleCellContentView?.removeReadReceiptsView()
}
}
@@ -0,0 +1,180 @@
/*
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 UIKit
import Reusable
final class KeyVerificationCellInnerContentView: UIView, NibLoadable {
// MARK: - Constants
private enum Constants {
static let cornerRadius: CGFloat = 8.0
static let buttonBackgroundColorAlpha: CGFloat = 0.2
static let buttonCornerRadius: CGFloat = 6.0
}
// MARK: - Properties
// MARK: Outlets
@IBOutlet private weak var badgeImageView: UIImageView!
@IBOutlet private weak var titleLabel: UILabel!
@IBOutlet private weak var otherUserInformationLabel: UILabel!
@IBOutlet private weak var requestStatusLabel: UILabel!
@IBOutlet private weak var buttonsContainerView: UIView!
@IBOutlet private weak var acceptButton: UIButton!
@IBOutlet private weak var declineButton: UIButton!
// MARK: Public
var isButtonsHidden: Bool {
get {
return self.acceptButton.isHidden && self.declineButton.isHidden
}
set {
self.buttonsContainerView.isHidden = newValue
}
}
var isRequestStatusHidden: Bool {
get {
return self.requestStatusLabel.isHidden
}
set {
self.requestStatusLabel.isHidden = newValue
}
}
var badgeImage: UIImage? {
get {
return self.badgeImageView.image
}
set {
self.badgeImageView.image = newValue
}
}
var title: String? {
get {
return self.titleLabel.text
}
set {
self.titleLabel.text = newValue
}
}
var otherUserInfo: String? {
return self.otherUserInformationLabel.text
}
var requestStatusText: String? {
get {
return self.requestStatusLabel.text
}
set {
self.requestStatusLabel.text = newValue
}
}
var acceptActionHandler: (() -> Void)?
var declineActionHandler: (() -> Void)?
// MARK: - Setup
static func instantiate() -> KeyVerificationCellInnerContentView {
let view = KeyVerificationCellInnerContentView.loadFromNib()
return view
}
// MARK: - Life cycle
override func awakeFromNib() {
super.awakeFromNib()
self.layer.masksToBounds = true
self.acceptButton.layer.masksToBounds = true
self.acceptButton.titleLabel?.adjustsFontSizeToFitWidth = true
self.acceptButton.titleLabel?.minimumScaleFactor = 0.5
self.acceptButton.titleLabel?.baselineAdjustment = .alignCenters
self.acceptButton.setTitle(VectorL10n.keyVerificationTileRequestIncomingApprovalAccept, for: .normal)
self.declineButton.layer.masksToBounds = true
self.declineButton.titleLabel?.adjustsFontSizeToFitWidth = true
self.declineButton.titleLabel?.minimumScaleFactor = 0.5
self.declineButton.titleLabel?.baselineAdjustment = .alignCenters
self.declineButton.setTitle(VectorL10n.keyVerificationTileRequestIncomingApprovalDecline, for: .normal)
}
override func layoutSubviews() {
super.layoutSubviews()
self.layer.cornerRadius = Constants.cornerRadius
if self.isButtonsHidden == false {
self.acceptButton.layer.cornerRadius = Constants.buttonCornerRadius
self.declineButton.layer.cornerRadius = Constants.buttonCornerRadius
}
}
// MARK: - Public
func update(theme: Theme) {
self.backgroundColor = theme.headerBackgroundColor
self.titleLabel.textColor = theme.textPrimaryColor
self.otherUserInformationLabel.textColor = theme.textSecondaryColor
self.acceptButton.vc_setBackgroundColor(theme.tintColor.withAlphaComponent(Constants.buttonBackgroundColorAlpha), for: .normal)
self.declineButton.vc_setBackgroundColor(theme.noticeColor.withAlphaComponent(Constants.buttonBackgroundColorAlpha), for: .normal)
}
func updateSenderInfo(with userId: String, userDisplayName: String?) {
self.otherUserInformationLabel.text = self.buildUserInfoText(with: userId, userDisplayName: userDisplayName)
}
// MARK: - Private
private func buildUserInfoText(with userId: String, userDisplayName: String?) -> String {
let userInfoText: String
if let userDisplayName = userDisplayName {
userInfoText = "\(userId) (\(userDisplayName))"
} else {
userInfoText = userId
}
return userInfoText
}
// MARK: - Action
@IBAction private func declineButtonAction(_ sender: Any) {
self.declineActionHandler?()
}
@IBAction private func acceptButtonAction(_ sender: Any) {
self.acceptActionHandler?()
}
}
@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="KeyVerificationCellInnerContentView" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="313" height="133"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="center" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="2Sr-GM-aAU">
<rect key="frame" x="10" y="10" width="293" height="113"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" spacing="4" translatesAutoresizingMaskIntoConstraints="NO" id="5gD-pX-GFz">
<rect key="frame" x="70" y="0.0" width="153.5" height="16"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" image="encryption_normal" translatesAutoresizingMaskIntoConstraints="NO" id="EHJ-3L-OPJ">
<rect key="frame" x="0.0" y="0.0" width="16" height="16"/>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" text="Verification request" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="BOd-4B-LQX">
<rect key="frame" x="20" y="0.0" width="133.5" height="16"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalCompressionResistancePriority="751" text="User (@user:matrix.org)" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="e1n-WP-GTb">
<rect key="frame" x="83.5" y="26" width="126" height="13.5"/>
<fontDescription key="fontDescription" type="system" pointSize="11"/>
<color key="textColor" red="0.1803921568627451" green="0.18431372549019609" blue="0.19607843137254902" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" text="Waiting..." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="e6I-aZ-RRO">
<rect key="frame" x="118" y="49.5" width="57" height="13.5"/>
<fontDescription key="fontDescription" type="system" pointSize="13"/>
<color key="textColor" red="0.38039215686274508" green="0.4392156862745098" blue="0.54509803921568623" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="5Tr-gP-gPB">
<rect key="frame" x="0.0" y="73" width="293" height="40"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" distribution="equalSpacing" alignment="center" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="WxG-vh-Bn0">
<rect key="frame" x="71" y="0.0" width="151" height="40"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="atD-LF-sGH">
<rect key="frame" x="0.0" y="0.0" width="72" height="40"/>
<inset key="contentEdgeInsets" minX="10" minY="0.0" maxX="10" maxY="0.0"/>
<state key="normal" title="Decline">
<color key="titleColor" red="1" green="0.29411764705882354" blue="0.33333333333333331" alpha="1" colorSpace="calibratedRGB"/>
</state>
<connections>
<action selector="declineButtonAction:" destination="iN0-l3-epB" eventType="touchUpInside" id="dS6-Xr-6jZ"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="irs-8W-qcs">
<rect key="frame" x="82" y="0.0" width="69" height="40"/>
<inset key="contentEdgeInsets" minX="10" minY="0.0" maxX="10" maxY="0.0"/>
<state key="normal" title="Accept">
<color key="titleColor" red="0.011764705882352941" green="0.70196078431372544" blue="0.50588235294117645" alpha="1" colorSpace="calibratedRGB"/>
</state>
<connections>
<action selector="acceptButtonAction:" destination="iN0-l3-epB" eventType="touchUpInside" id="IQ6-be-vJt"/>
</connections>
</button>
</subviews>
<constraints>
<constraint firstItem="atD-LF-sGH" firstAttribute="height" secondItem="WxG-vh-Bn0" secondAttribute="height" priority="999" id="3sT-HV-Os0"/>
<constraint firstItem="irs-8W-qcs" firstAttribute="height" secondItem="WxG-vh-Bn0" secondAttribute="height" priority="999" id="CfM-Vc-MQ2"/>
</constraints>
</stackView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="WxG-vh-Bn0" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="5Tr-gP-gPB" secondAttribute="leading" id="4al-oB-NpF"/>
<constraint firstAttribute="bottom" secondItem="WxG-vh-Bn0" secondAttribute="bottom" id="rCo-gP-UF5"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="WxG-vh-Bn0" secondAttribute="trailing" id="u47-KK-aKk"/>
<constraint firstAttribute="height" priority="999" constant="40" id="ujN-jh-fde"/>
<constraint firstItem="WxG-vh-Bn0" firstAttribute="top" secondItem="5Tr-gP-gPB" secondAttribute="top" id="wNH-CW-iLB"/>
<constraint firstItem="WxG-vh-Bn0" firstAttribute="centerX" secondItem="5Tr-gP-gPB" secondAttribute="centerX" id="yWq-qo-MY7"/>
</constraints>
</view>
</subviews>
<constraints>
<constraint firstItem="5Tr-gP-gPB" firstAttribute="width" secondItem="2Sr-GM-aAU" secondAttribute="width" id="VJx-xp-NZE"/>
</constraints>
</stackView>
</subviews>
<color key="backgroundColor" red="0.95294117647058818" green="0.97254901960784312" blue="0.99215686274509807" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="2Sr-GM-aAU" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="10" id="M7S-MY-Jxk"/>
<constraint firstItem="2Sr-GM-aAU" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="10" id="SfH-5W-p30"/>
<constraint firstAttribute="trailing" secondItem="2Sr-GM-aAU" secondAttribute="trailing" constant="10" id="rVw-1F-ch3"/>
<constraint firstAttribute="bottom" secondItem="2Sr-GM-aAU" secondAttribute="bottom" constant="10" id="vL2-dm-qbe"/>
</constraints>
<nil key="simulatedTopBarMetrics"/>
<nil key="simulatedBottomBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<connections>
<outlet property="acceptButton" destination="irs-8W-qcs" id="LKq-qE-bbg"/>
<outlet property="badgeImageView" destination="EHJ-3L-OPJ" id="eNW-bg-eYy"/>
<outlet property="buttonsContainerView" destination="5Tr-gP-gPB" id="aqy-vT-mu3"/>
<outlet property="declineButton" destination="atD-LF-sGH" id="CfI-FW-ySy"/>
<outlet property="otherUserInformationLabel" destination="e1n-WP-GTb" id="jhY-gH-QnO"/>
<outlet property="requestStatusLabel" destination="e6I-aZ-RRO" id="zQf-qy-3Rq"/>
<outlet property="titleLabel" destination="BOd-4B-LQX" id="4sw-3J-faF"/>
</connections>
<point key="canvasLocation" x="-828.26086956521749" y="-386.04910714285711"/>
</view>
</objects>
<resources>
<image name="encryption_normal" width="16" height="16"/>
</resources>
</document>
@@ -0,0 +1,102 @@
/*
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 UIKit
@objcMembers
class KeyVerificationConclusionBubbleCell: KeyVerificationBaseBubbleCell {
// MARK: - Constants
private enum Sizing {
static let view = KeyVerificationConclusionBubbleCell(style: .default, reuseIdentifier: nil)
}
// 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.keyVerificationCellInnerContentView?.isButtonsHidden = true
self.keyVerificationCellInnerContentView?.isRequestStatusHidden = true
}
// MARK: - Overrides
override func render(_ cellData: MXKCellData!) {
super.render(cellData)
guard let keyVerificationCellInnerContentView = self.keyVerificationCellInnerContentView,
let bubbleData = self.bubbleData as? RoomBubbleCellData,
let viewData = self.viewData(from: bubbleData) else {
NSLog("[KeyVerificationConclusionBubbleCell] Fail to render \(String(describing: cellData))")
return
}
keyVerificationCellInnerContentView.badgeImage = viewData.badgeImage
keyVerificationCellInnerContentView.title = viewData.title
keyVerificationCellInnerContentView.updateSenderInfo(with: viewData.senderId, userDisplayName: viewData.senderDisplayName)
}
override class func sizingView() -> KeyVerificationBaseBubbleCell {
return self.Sizing.view
}
// MARK: - Private
private func viewData(from roomBubbleData: RoomBubbleCellData) -> KeyVerificationConclusionViewData? {
guard let event = roomBubbleData.bubbleComponents.first?.event else {
return nil
}
let viewData: KeyVerificationConclusionViewData?
let senderId = self.senderId(from: bubbleData)
let senderDisplayName = self.senderDisplayName(from: bubbleData)
let title: String?
let badgeImage: UIImage?
switch event.eventType {
case .keyVerificationDone:
badgeImage = Asset.Images.encryptionTrusted.image
title = VectorL10n.keyVerificationTileConclusionDoneTitle
case .keyVerificationCancel:
badgeImage = Asset.Images.encryptionWarning.image
title = VectorL10n.keyVerificationTileConclusionWarningTitle
default:
badgeImage = nil
title = nil
}
if let title = title, let badgeImage = badgeImage {
viewData = KeyVerificationConclusionViewData(badgeImage: badgeImage,
title: title,
senderId: senderId,
senderDisplayName: senderDisplayName)
} else {
viewData = nil
}
return viewData
}
}
@@ -0,0 +1,24 @@
/*
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
struct KeyVerificationConclusionViewData {
let badgeImage: UIImage
let title: String
let senderId: String
let senderDisplayName: String?
}
@@ -0,0 +1,52 @@
/*
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 UIKit
@objcMembers
final class KeyVerificationConclusionWithPaginationTitleBubbleCell: KeyVerificationConclusionBubbleCell {
// MARK: - Constants
private enum Sizing {
static let view = KeyVerificationConclusionWithPaginationTitleBubbleCell(style: .default, reuseIdentifier: nil)
}
// 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() {
guard let bubbleCellContentView = self.bubbleCellContentView else {
fatalError("[KeyVerificationConclusionWithPaginationTitleBubbleCell] bubbleCellContentView should not be nil")
}
bubbleCellContentView.showPaginationTitle = true
}
// MARK: - Overrides
override class func sizingView() -> KeyVerificationBaseBubbleCell {
return self.Sizing.view
}
}
@@ -0,0 +1,104 @@
/*
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 UIKit
@objcMembers
class KeyVerificationIncomingRequestApprovalBubbleCell: KeyVerificationBaseBubbleCell {
// MARK: - Constants
private enum Sizing {
static let view = KeyVerificationIncomingRequestApprovalBubbleCell(style: .default, reuseIdentifier: nil)
}
// 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() {
guard let keyVerificationCellInnerContentView = self.keyVerificationCellInnerContentView else {
fatalError("[KeyVerificationIncomingRequestApprovalBubbleCell] keyVerificationCellInnerContentView should not be nil")
}
keyVerificationCellInnerContentView.isButtonsHidden = false
keyVerificationCellInnerContentView.isRequestStatusHidden = true
keyVerificationCellInnerContentView.badgeImage = Asset.Images.encryptionNormal.image
}
// MARK: - Overrides
override func prepareForReuse() {
super.prepareForReuse()
self.keyVerificationCellInnerContentView?.acceptActionHandler = nil
self.keyVerificationCellInnerContentView?.declineActionHandler = nil
}
override func render(_ cellData: MXKCellData!) {
super.render(cellData)
guard let keyVerificationCellInnerContentView = self.keyVerificationCellInnerContentView,
let bubbleData = self.bubbleData,
let viewData = self.viewData(from: bubbleData) else {
NSLog("[KeyVerificationIncomingRequestApprovalBubbleCell] Fail to render \(String(describing: cellData))")
return
}
keyVerificationCellInnerContentView.title = viewData.title
keyVerificationCellInnerContentView.updateSenderInfo(with: viewData.senderId, userDisplayName: viewData.senderDisplayName)
let actionUserInfo: [AnyHashable: Any]?
if let eventId = bubbleData.getFirstBubbleComponentWithDisplay()?.event.eventId {
actionUserInfo = [kMXKRoomBubbleCellEventIdKey: eventId]
} else {
actionUserInfo = nil
}
keyVerificationCellInnerContentView.acceptActionHandler = { [weak self] in
self?.delegate?.cell(self, didRecognizeAction: kMXKRoomBubbleCellKeyVerificationIncomingRequestAcceptPressed, userInfo: actionUserInfo)
}
keyVerificationCellInnerContentView.declineActionHandler = { [weak self] in
self?.delegate?.cell(self, didRecognizeAction: kMXKRoomBubbleCellKeyVerificationIncomingRequestDeclinePressed, userInfo: actionUserInfo)
}
}
override class func sizingView() -> KeyVerificationBaseBubbleCell {
return self.Sizing.view
}
// MARK: - Private
private func viewData(from bubbleData: MXKRoomBubbleCellData) -> KeyVerificationIncomingRequestApprovalViewData? {
let senderId = self.senderId(from: bubbleData)
let senderDisplayName = self.senderDisplayName(from: bubbleData)
let title = VectorL10n.keyVerificationTileRequestIncomingTitle
return KeyVerificationIncomingRequestApprovalViewData(title: title,
senderId: senderId,
senderDisplayName: senderDisplayName)
}
}
@@ -0,0 +1,23 @@
/*
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
struct KeyVerificationIncomingRequestApprovalViewData {
let title: String
let senderId: String
let senderDisplayName: String?
}
@@ -0,0 +1,52 @@
/*
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 UIKit
@objcMembers
final class KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell: KeyVerificationIncomingRequestApprovalBubbleCell {
// MARK: - Constants
private enum Sizing {
static let view = KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell(style: .default, reuseIdentifier: nil)
}
// 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() {
guard let bubbleCellContentView = self.bubbleCellContentView else {
fatalError("[KeyVerificationRequestStatusWithPaginationTitleBubbleCell] bubbleCellContentView should not be nil")
}
bubbleCellContentView.showPaginationTitle = true
}
// MARK: - Overrides
override class func sizingView() -> KeyVerificationBaseBubbleCell {
return self.Sizing.view
}
}
@@ -0,0 +1,125 @@
/*
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 UIKit
@objcMembers
class KeyVerificationRequestStatusBubbleCell: KeyVerificationBaseBubbleCell {
// MARK: - Constants
private enum Sizing {
static let view = KeyVerificationRequestStatusBubbleCell(style: .default, reuseIdentifier: nil)
}
// 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() {
guard let keyVerificationCellInnerContentView = self.keyVerificationCellInnerContentView else {
fatalError("[KeyVerificationRequestStatusBubbleCell] keyVerificationCellInnerContentView should not be nil")
}
keyVerificationCellInnerContentView.isButtonsHidden = true
keyVerificationCellInnerContentView.isRequestStatusHidden = false
keyVerificationCellInnerContentView.badgeImage = Asset.Images.encryptionNormal.image
}
// MARK: - Overrides
override func render(_ cellData: MXKCellData!) {
super.render(cellData)
guard let keyVerificationCellInnerContentView = self.keyVerificationCellInnerContentView,
let roomBubbleCellData = self.bubbleData as? RoomBubbleCellData,
let viewData = self.viewData(from: roomBubbleCellData) else {
NSLog("[KeyVerificationRequestStatusBubbleCell] Fail to render \(String(describing: cellData))")
return
}
keyVerificationCellInnerContentView.title = viewData.title
keyVerificationCellInnerContentView.updateSenderInfo(with: viewData.senderId, userDisplayName: viewData.senderDisplayName)
keyVerificationCellInnerContentView.requestStatusText = viewData.statusText
}
override class func sizingView() -> KeyVerificationBaseBubbleCell {
return self.Sizing.view
}
// MARK: - Private
private func viewData(from roomBubbleCellData: RoomBubbleCellData) -> KeyVerificationRequestStatusViewData? {
let senderId = self.senderId(from: bubbleData)
let senderDisplayName = self.senderDisplayName(from: bubbleData)
let title: String
let statusText: String?
if roomBubbleCellData.isIncoming {
title = VectorL10n.keyVerificationTileRequestIncomingTitle
} else {
title = VectorL10n.keyVerificationTileRequestOutgoingTitle
}
if let keyVerification = roomBubbleCellData.keyVerification {
switch keyVerification.state {
case .requestPending:
if !roomBubbleCellData.isIncoming {
statusText = VectorL10n.keyVerificationTileRequestStatusWaiting
} else {
if roomBubbleCellData.isKeyVerificationOperationPending {
statusText = VectorL10n.keyVerificationTileRequestStatusDataLoading
} else {
// Should not happen, KeyVerificationIncomingRequestApprovalBubbleCell should be displayed in this case.
statusText = nil
}
}
case .requestExpired:
statusText = VectorL10n.keyVerificationTileRequestStatusExpired
case .requestCancelled, .transactionCancelled:
let userName = senderDisplayName ?? senderId
statusText = VectorL10n.keyVerificationTileRequestStatusCancelled(userName)
case .requestCancelledByMe, .transactionCancelledByMe:
statusText = VectorL10n.keyVerificationTileRequestStatusCancelledByMe
default:
statusText = VectorL10n.keyVerificationTileRequestStatusAccepted
}
} else {
statusText = VectorL10n.keyVerificationTileRequestStatusDataLoading
}
let viewData: KeyVerificationRequestStatusViewData?
if let statusText = statusText {
viewData = KeyVerificationRequestStatusViewData(title: title,
senderId: senderId,
senderDisplayName: senderDisplayName,
statusText: statusText)
} else {
viewData = nil
}
return viewData
}
}
@@ -0,0 +1,24 @@
/*
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
struct KeyVerificationRequestStatusViewData {
let title: String
let senderId: String
let senderDisplayName: String?
let statusText: String
}
@@ -0,0 +1,52 @@
/*
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 UIKit
@objcMembers
final class KeyVerificationRequestStatusWithPaginationTitleBubbleCell: KeyVerificationRequestStatusBubbleCell {
// MARK: - Constants
private enum Sizing {
static let view = KeyVerificationRequestStatusWithPaginationTitleBubbleCell(style: .default, reuseIdentifier: nil)
}
// 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() {
guard let bubbleCellContentView = self.bubbleCellContentView else {
fatalError("[KeyVerificationRequestStatusWithPaginationTitleBubbleCell] bubbleCellContentView should not be nil")
}
bubbleCellContentView.showPaginationTitle = true
}
// MARK: - Overrides
override class func sizingView() -> KeyVerificationBaseBubbleCell {
return self.Sizing.view
}
}
@@ -0,0 +1,43 @@
/*
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
final class SizingViewHeight: Hashable, Equatable {
// MARK: - Properties
let uniqueIdentifier: Int
var heights: [CGFloat /* width */: CGFloat /* height */] = [:]
// MARK: - Setup
init(uniqueIdentifier: Int) {
self.uniqueIdentifier = uniqueIdentifier
}
// MARK: - Hashable
func hash(into hasher: inout Hasher) {
hasher.combine(self.uniqueIdentifier)
}
// MARK: - Equatable
static func == (lhs: SizingViewHeight, rhs: SizingViewHeight) -> Bool {
return lhs.uniqueIdentifier == rhs.uniqueIdentifier
}
}