mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-25 19:10:49 +02:00
b298dedc22
Merge commit 'f823ab9aae70e8d15ed7cc079210dd9bbbb6c8e1' into feature/foss_update_1_11_19 * commit 'f823ab9aae70e8d15ed7cc079210dd9bbbb6c8e1': finish version++ version++ comments update submodule remove obsolete tests removed unused code update submodule fix Libolm removal update license macro update license Prepare for new sprint # Conflicts: # Config/AppVersion.xcconfig # IDETemplateMacros.plist # LICENSE # README.md # Riot/Categories/MXSession+Riot.m # Riot/Managers/EncryptionKeyManager/EncryptionKeyManager.swift # Riot/Managers/KeyValueStorage/Extensions/Keychain.swift # Riot/Managers/KeyValueStorage/KeyValueStore.swift # Riot/Managers/KeyValueStorage/KeychainStore.swift # Riot/Managers/KeyValueStorage/MemoryStore.swift # Riot/Managers/PushNotification/PushNotificationService.m # Riot/Managers/Settings/RiotSettings.swift # Riot/Managers/Settings/Shared/RiotSharedSettings.swift # Riot/Modules/Analytics/AnalyticsUIElement.swift # Riot/Modules/Application/AppCoordinator.swift # Riot/Modules/Application/LegacyAppDelegate.h # Riot/Modules/Application/LegacyAppDelegate.m # Riot/Modules/Authentication/Legacy/AuthenticationViewController.h # Riot/Modules/Authentication/Legacy/AuthenticationViewController.m # Riot/Modules/Authentication/Legacy/Views/AuthInputsView.h # Riot/Modules/Authentication/Legacy/Views/AuthInputsView.m # Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m # Riot/Modules/Common/Recents/RecentsViewController.m # Riot/Modules/Common/WebViewController/WebViewViewController.m # Riot/Modules/Contacts/Details/ContactDetailsViewController.m # Riot/Modules/Contacts/Views/ContactTableViewCell.m # Riot/Modules/Favorites/FavouritesViewController.h # Riot/Modules/Favorites/FavouritesViewController.m # Riot/Modules/GlobalSearch/UnifiedSearchViewController.m # Riot/Modules/People/PeopleViewController.h # Riot/Modules/People/PeopleViewController.m # Riot/Modules/Room/ContextualMenu/ReactionsMenu/ReactionsMenuViewModel.swift # Riot/Modules/Room/DataSources/RoomDataSource.m # Riot/Modules/Room/Files/RoomFilesViewController.m # Riot/Modules/Room/Members/Detail/RoomMemberDetailsViewController.m # Riot/Modules/Room/Members/RoomParticipantsViewController.m # Riot/Modules/Room/RoomViewController.m # Riot/Modules/Room/Settings/RoomSettingsViewController.m # Riot/Modules/Room/TimelineCells/RoomCreationIntro/RoomCreationIntroCell.swift # Riot/Modules/Room/TimelineCells/RoomCreationIntro/RoomCreationIntroCellContentView.swift # Riot/Modules/Room/TimelineCells/RoomCreationIntro/RoomCreationIntroViewData.swift # Riot/Modules/Room/TimelineCells/RoomTimelineCellIdentifier.h # Riot/Modules/Rooms/RoomsViewController.h # Riot/Modules/Rooms/ShowDirectory/Cells/Network/DirectoryNetworkTableHeaderFooterView.swift # Riot/Modules/Rooms/ShowDirectory/Cells/Room/DirectoryRoomTableViewCell.swift # Riot/Modules/Rooms/ShowDirectory/PublicRoomsDirectoryViewModel.swift # Riot/Modules/Secrets/Recover/RecoverWithKey/SecretsRecoveryWithKeyCoordinator.swift # Riot/Modules/Secrets/Recover/RecoverWithKey/SecretsRecoveryWithKeyViewController.swift # Riot/Modules/Secrets/Recover/RecoverWithPassphrase/SecretsRecoveryWithPassphraseCoordinator.swift # Riot/Modules/Secrets/Recover/RecoverWithPassphrase/SecretsRecoveryWithPassphraseViewController.swift # Riot/Modules/Secrets/Recover/SecretsRecoveryCoordinator.swift # Riot/Modules/SecureBackup/Setup/Intro/SecureBackupSetupIntroViewController.swift # Riot/Modules/SecureBackup/Setup/Intro/SecureBackupSetupIntroViewModel.swift # Riot/Modules/SecureBackup/Setup/Intro/SecureBackupSetupIntroViewModelType.swift # Riot/Modules/SetPinCode/PinCodePreferences.swift # Riot/Modules/SetPinCode/SetupBiometrics/BiometricsAuthenticationPresenter.swift # Riot/Modules/Settings/Security/ManageSession/ManageSessionViewController.m # Riot/Modules/Settings/Security/SecurityViewController.m # Riot/Modules/Settings/SettingsViewController.m # Riot/Modules/SplitView/SplitViewCoordinator.swift # Riot/Modules/SplitView/SplitViewCoordinatorType.swift # Riot/Modules/StartChat/StartChatViewController.m # Riot/Modules/TabBar/MasterTabBarController.h # Riot/Modules/TabBar/MasterTabBarController.m # Riot/Utils/EventFormatter.m # Riot/Utils/HTMLFormatter.swift # Riot/Utils/Tools.m # RiotNSE/NotificationService.swift
403 lines
14 KiB
Swift
403 lines
14 KiB
Swift
/*
|
|
Copyright 2019-2024 New Vector Ltd.
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only
|
|
Please see LICENSE in the repository root for full details.
|
|
*/
|
|
|
|
import UIKit
|
|
import Reusable
|
|
|
|
/// `RoomCellContentView` is a container view that display the default room message outer views and enables to manage them. Like pagination title, sender info, read receipts, reactions, encryption status.
|
|
@objcMembers
|
|
final class RoomCellContentView: UIView, NibLoadable {
|
|
|
|
// MARK: - Properties
|
|
|
|
// MARK: Outlets
|
|
|
|
@IBOutlet weak var paginationTitleContainerView: UIView!
|
|
@IBOutlet weak var paginationLabel: UILabel!
|
|
@IBOutlet weak var paginationSeparatorView: UIView!
|
|
|
|
@IBOutlet weak var userNameContainerView: UIView!
|
|
@IBOutlet weak var userNameLabel: UILabel!
|
|
@IBOutlet weak var userNameTouchMaskView: UIView!
|
|
|
|
@IBOutlet weak var userNameLabelTopConstraint: NSLayoutConstraint!
|
|
@IBOutlet weak var userNameLabelBottomConstraint: NSLayoutConstraint!
|
|
|
|
@IBOutlet weak var avatarContainerView: UIView!
|
|
@IBOutlet weak var avatarImageView: MXKImageView!
|
|
private var pillImageView: UIImageView? // BWI: #5223 add federation icon in timeline
|
|
|
|
@IBOutlet weak var innerContentView: UIView!
|
|
|
|
@IBOutlet weak var innerContentViewTopConstraint: NSLayoutConstraint!
|
|
@IBOutlet weak var innerContentViewLeadingConstraint: NSLayoutConstraint!
|
|
@IBOutlet weak var innerContentViewTrailingConstraint: NSLayoutConstraint!
|
|
@IBOutlet weak var innerContentViewBottomContraint: NSLayoutConstraint!
|
|
|
|
@IBOutlet weak var encryptionStatusContainerView: UIView!
|
|
@IBOutlet weak var encryptionImageView: UIImageView!
|
|
|
|
@IBOutlet weak var bubbleInfoContainer: UIView!
|
|
@IBOutlet weak var bubbleInfoContainerTopConstraint: NSLayoutConstraint!
|
|
|
|
@IBOutlet weak var urlPreviewContainerView: UIView!
|
|
@IBOutlet weak var urlPreviewContentView: UIView!
|
|
@IBOutlet weak var urlPreviewContentViewLeadingConstraint: NSLayoutConstraint!
|
|
@IBOutlet weak var urlPreviewContentViewTrailingConstraint: NSLayoutConstraint!
|
|
|
|
@IBOutlet weak var readReceiptsContainerView: UIView!
|
|
@IBOutlet weak var readReceiptsContentView: UIView!
|
|
|
|
@IBOutlet weak var readMarkerContainerView: UIView!
|
|
@IBOutlet weak var readMarkerContentView: UIView!
|
|
|
|
var readMarkerViewLeadingConstraint: NSLayoutConstraint?
|
|
var readMarkerViewTrailingConstraint: NSLayoutConstraint?
|
|
|
|
@IBOutlet weak var reactionsContainerView: UIView!
|
|
@IBOutlet weak var reactionsContentView: UIView!
|
|
@IBOutlet weak var reactionsContentViewLeadingConstraint: NSLayoutConstraint!
|
|
@IBOutlet weak var reactionsContentViewTrailingConstraint: NSLayoutConstraint!
|
|
|
|
@IBOutlet weak var threadSummaryContainerView: UIView!
|
|
@IBOutlet weak var threadSummaryContentView: UIView!
|
|
@IBOutlet weak var threadSummaryContentViewLeadingConstraint: NSLayoutConstraint!
|
|
@IBOutlet weak var threadSummaryContentViewTrailingConstraint: NSLayoutConstraint!
|
|
@IBOutlet weak var threadSummaryContentViewBottomConstraint: NSLayoutConstraint!
|
|
|
|
@IBOutlet weak var bubbleOverlayContainer: UIView!
|
|
|
|
// MARK: Private
|
|
|
|
private var showURLPreview: Bool {
|
|
get {
|
|
return !self.urlPreviewContainerView.isHidden
|
|
}
|
|
set {
|
|
self.urlPreviewContainerView.isHidden = !newValue
|
|
}
|
|
}
|
|
|
|
private var showReadReceipts: Bool {
|
|
get {
|
|
return !self.readReceiptsContainerView.isHidden
|
|
}
|
|
set {
|
|
self.readReceiptsContainerView.isHidden = !newValue
|
|
}
|
|
}
|
|
|
|
private var showReactions: Bool {
|
|
get {
|
|
return !self.reactionsContainerView.isHidden
|
|
}
|
|
set {
|
|
self.reactionsContainerView.isHidden = !newValue
|
|
}
|
|
}
|
|
|
|
private var showThreadSummary: Bool {
|
|
get {
|
|
return !self.threadSummaryContainerView.isHidden
|
|
} set {
|
|
self.threadSummaryContainerView.isHidden = !newValue
|
|
}
|
|
}
|
|
|
|
// MARK: Public
|
|
|
|
var showPaginationTitle: Bool {
|
|
get {
|
|
return !self.paginationTitleContainerView.isHidden
|
|
}
|
|
set {
|
|
self.paginationTitleContainerView.isHidden = !newValue
|
|
}
|
|
}
|
|
|
|
var showSenderInfo: Bool {
|
|
get {
|
|
return self.showSenderAvatar && self.showSenderName
|
|
}
|
|
set {
|
|
self.showSenderAvatar = newValue
|
|
self.showSenderName = newValue
|
|
}
|
|
}
|
|
|
|
var showSenderAvatar: Bool {
|
|
get {
|
|
return !self.avatarContainerView.isHidden
|
|
}
|
|
set {
|
|
self.avatarContainerView.isHidden = !newValue
|
|
}
|
|
}
|
|
|
|
var showSenderName: Bool {
|
|
get {
|
|
return !self.userNameContainerView.isHidden
|
|
}
|
|
set {
|
|
self.userNameContainerView.isHidden = !newValue
|
|
}
|
|
}
|
|
|
|
var showEncryptionStatus: Bool {
|
|
get {
|
|
return !self.encryptionStatusContainerView.isHidden
|
|
}
|
|
set {
|
|
self.encryptionStatusContainerView.isHidden = !newValue
|
|
}
|
|
}
|
|
|
|
var showReadMarker: Bool {
|
|
get {
|
|
return !self.readMarkerContainerView.isHidden
|
|
}
|
|
set {
|
|
self.readMarkerContainerView.isHidden = !newValue
|
|
}
|
|
}
|
|
|
|
// BWI: #5223 add federation icon in timeline
|
|
var showFederationPill: Bool {
|
|
get {
|
|
if let pillImageView = self.pillImageView {
|
|
return !pillImageView.isHidden
|
|
} else {
|
|
return false
|
|
}
|
|
}
|
|
set {
|
|
self.pillImageView?.isHidden = !newValue
|
|
}
|
|
}
|
|
|
|
var decorationViewsAlignment: RoomCellDecorationAlignment = .left
|
|
|
|
// MARK: - Setup
|
|
|
|
class func instantiate() -> RoomCellContentView {
|
|
let roomCell = RoomCellContentView.loadFromNib()
|
|
// BWI: #5223 add federation icon in timeline
|
|
roomCell.addFederationPill()
|
|
return roomCell
|
|
}
|
|
|
|
// BWI: #5223 add federation icon in timeline
|
|
func addFederationPill() {
|
|
// bwi: 5216 - federation
|
|
if BWIBuildSettings.shared.isFederationEnabled {
|
|
// add imageview for the pill if it doesn't exist
|
|
if pillImageView == nil {
|
|
let imageView = FederationIconHelper.shared.getFederatedIconImageView(avatarFrame: avatarImageView.frame)
|
|
pillImageView = imageView
|
|
pillImageView?.contentMode = .scaleAspectFit
|
|
avatarContainerView.addSubview(imageView)
|
|
}
|
|
|
|
pillImageView?.image = FederationIconHelper.shared.federationBadgeImage()
|
|
} else {
|
|
pillImageView?.image = nil
|
|
}
|
|
}
|
|
|
|
// MARK: - Public
|
|
|
|
func update(theme: Theme) {
|
|
self.backgroundColor = theme.backgroundColor
|
|
self.paginationLabel.textColor = theme.tintColor
|
|
self.paginationSeparatorView.backgroundColor = theme.tintColor
|
|
|
|
// BWI: #5223 add federation icon in timeline
|
|
if BWIBuildSettings.shared.isFederationEnabled {
|
|
pillImageView?.image = FederationIconHelper.shared.federationBadgeImage()
|
|
} else {
|
|
pillImageView?.image = nil
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - RoomCellReadReceiptsDisplayable
|
|
extension RoomCellContentView: RoomCellReadReceiptsDisplayable {
|
|
|
|
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()
|
|
}
|
|
}
|
|
|
|
// MARK: - RoomCellReactionsDisplayable
|
|
extension RoomCellContentView: RoomCellReactionsDisplayable {
|
|
|
|
func addReactionsView(_ reactionsView: UIView) {
|
|
self.reactionsContentView.vc_removeAllSubviews()
|
|
|
|
// Update reactions alignment according to current decoration alignment
|
|
if let reactionsView = reactionsView as? RoomReactionsView {
|
|
|
|
let reactionsAlignment: RoomReactionsViewAlignment
|
|
|
|
switch self.decorationViewsAlignment {
|
|
case .left:
|
|
reactionsAlignment = .left
|
|
case .right:
|
|
reactionsAlignment = .right
|
|
}
|
|
|
|
reactionsView.alignment = reactionsAlignment
|
|
}
|
|
|
|
self.reactionsContentView.vc_addSubViewMatchingParent(reactionsView)
|
|
|
|
self.showReactions = true
|
|
}
|
|
|
|
func removeReactionsView() {
|
|
self.showReactions = false
|
|
self.reactionsContentView.vc_removeAllSubviews()
|
|
}
|
|
}
|
|
|
|
// MARK: - RoomCellThreadSummaryDisplayable
|
|
extension RoomCellContentView: RoomCellThreadSummaryDisplayable {
|
|
|
|
func addThreadSummaryView(_ threadSummaryView: ThreadSummaryView) {
|
|
|
|
guard let containerView = self.threadSummaryContentView else {
|
|
return
|
|
}
|
|
|
|
containerView.vc_removeAllSubviews()
|
|
|
|
containerView.translatesAutoresizingMaskIntoConstraints = false
|
|
containerView.addSubview(threadSummaryView)
|
|
|
|
let leadingConstraint: NSLayoutConstraint
|
|
let trailingConstraint: NSLayoutConstraint
|
|
|
|
if self.decorationViewsAlignment == .right {
|
|
leadingConstraint = threadSummaryView.leadingAnchor.constraint(greaterThanOrEqualTo: containerView.leadingAnchor)
|
|
trailingConstraint = threadSummaryView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor)
|
|
} else {
|
|
leadingConstraint = threadSummaryView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor)
|
|
trailingConstraint = threadSummaryView.trailingAnchor.constraint(lessThanOrEqualTo: containerView.trailingAnchor)
|
|
}
|
|
|
|
NSLayoutConstraint.activate([
|
|
leadingConstraint,
|
|
threadSummaryView.topAnchor.constraint(equalTo: containerView.topAnchor),
|
|
threadSummaryView.heightAnchor.constraint(equalToConstant: PlainRoomCellLayoutConstants.threadSummaryViewHeight),
|
|
threadSummaryView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor),
|
|
trailingConstraint
|
|
])
|
|
|
|
self.showThreadSummary = true
|
|
}
|
|
|
|
func removeThreadSummaryView() {
|
|
self.showThreadSummary = false
|
|
self.threadSummaryContentView.vc_removeAllSubviews()
|
|
}
|
|
}
|
|
|
|
// MARK: - RoomCellURLPreviewDisplayable
|
|
extension RoomCellContentView: RoomCellURLPreviewDisplayable {
|
|
|
|
func addURLPreviewView(_ urlPreviewView: UIView) {
|
|
|
|
guard let containerView = self.urlPreviewContentView else {
|
|
return
|
|
}
|
|
|
|
containerView.vc_removeAllSubviews()
|
|
|
|
containerView.translatesAutoresizingMaskIntoConstraints = false
|
|
containerView.addSubview(urlPreviewView)
|
|
|
|
if let urlPreviewView = urlPreviewView as? URLPreviewView {
|
|
urlPreviewView.availableWidth = containerView.frame.width
|
|
}
|
|
|
|
let leadingConstraint: NSLayoutConstraint
|
|
let trailingConstraint: NSLayoutConstraint
|
|
|
|
if self.decorationViewsAlignment == .right {
|
|
leadingConstraint = urlPreviewView.leadingAnchor.constraint(greaterThanOrEqualTo: containerView.leadingAnchor)
|
|
trailingConstraint = urlPreviewView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor)
|
|
} else {
|
|
leadingConstraint = urlPreviewView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor)
|
|
trailingConstraint = urlPreviewView.trailingAnchor.constraint(lessThanOrEqualTo: containerView.trailingAnchor)
|
|
}
|
|
|
|
NSLayoutConstraint.activate([
|
|
leadingConstraint,
|
|
urlPreviewView.topAnchor.constraint(equalTo: containerView.topAnchor),
|
|
urlPreviewView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor),
|
|
trailingConstraint
|
|
])
|
|
|
|
self.showURLPreview = true
|
|
}
|
|
|
|
func removeURLPreviewView() {
|
|
self.showURLPreview = false
|
|
self.urlPreviewContentView.vc_removeAllSubviews()
|
|
}
|
|
}
|
|
|
|
// MARK: - RoomCellReadMarkerDisplayable
|
|
extension RoomCellContentView: RoomCellReadMarkerDisplayable {
|
|
|
|
func addReadMarkerView(_ readMarkerView: UIView) {
|
|
guard let containerView = self.readMarkerContainerView else {
|
|
return
|
|
}
|
|
|
|
self.readMarkerContentView.vc_removeAllSubviews()
|
|
|
|
readMarkerView.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
self.readMarkerContentView.addSubview(readMarkerView)
|
|
|
|
// Force read marker constraints
|
|
let topConstraint = readMarkerView.topAnchor.constraint(equalTo: containerView.topAnchor)
|
|
|
|
let leadingConstraint = readMarkerView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor)
|
|
|
|
let trailingConstraint = readMarkerView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor)
|
|
|
|
let heightConstraint = readMarkerView.heightAnchor.constraint(equalToConstant: PlainRoomCellLayoutConstants.readMarkerViewHeight)
|
|
|
|
let bottomContraint = readMarkerView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor)
|
|
|
|
NSLayoutConstraint.activate([topConstraint,
|
|
leadingConstraint,
|
|
trailingConstraint,
|
|
heightConstraint,
|
|
bottomContraint])
|
|
|
|
self.readMarkerViewLeadingConstraint = leadingConstraint
|
|
self.readMarkerViewTrailingConstraint = trailingConstraint
|
|
|
|
self.showReadMarker = true
|
|
}
|
|
|
|
func removeReadMarkerView() {
|
|
self.showReadMarker = false
|
|
self.readMarkerContentView.vc_removeAllSubviews()
|
|
}
|
|
}
|