Merge branch 'develop' into ismail/5096_thread_notifications

This commit is contained in:
ismailgulek
2022-02-02 12:46:00 +03:00
108 changed files with 1709 additions and 611 deletions
@@ -34,6 +34,8 @@ class BaseBubbleCell: MXKRoomBubbleTableViewCell, BaseBubbleCellType {
weak var bubbleCellContentView: BubbleCellContentView?
private(set) var theme: Theme?
// Overrides
override var bubbleInfoContainer: UIView! {
@@ -205,6 +207,7 @@ class BaseBubbleCell: MXKRoomBubbleTableViewCell, BaseBubbleCellType {
// MARK: - Themable
func update(theme: Theme) {
self.theme = theme
self.bubbleCellContentView?.update(theme: theme)
}
@@ -36,6 +36,9 @@ final class BubbleCellContentView: UIView, NibLoadable {
@IBOutlet weak var innerContentView: UIView!
@IBOutlet weak var innerContentViewLeadingConstraint: NSLayoutConstraint!
@IBOutlet weak var innerContentViewTrailingConstraint: NSLayoutConstraint!
@IBOutlet weak var encryptionStatusContainerView: UIView!
@IBOutlet weak var encryptionImageView: UIImageView!
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="19529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@@ -234,6 +234,8 @@
<outlet property="encryptionImageView" destination="Ujc-3c-e5B" id="7zc-Y7-1jT"/>
<outlet property="encryptionStatusContainerView" destination="uHE-o7-sCe" id="Dl7-QS-WKl"/>
<outlet property="innerContentView" destination="oeI-eO-mFK" id="ap1-He-C6g"/>
<outlet property="innerContentViewLeadingConstraint" destination="0Fr-0L-9tU" id="ByY-oe-d8Y"/>
<outlet property="innerContentViewTrailingConstraint" destination="Pbe-4d-q6Y" id="24b-AS-hX4"/>
<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"/>
@@ -246,7 +248,7 @@
<outlet property="userNameLabel" destination="meG-P8-61b" id="ETK-ag-WYR"/>
<outlet property="userNameTouchMaskView" destination="ohU-Sc-mgb" id="FwW-aL-kc5"/>
</connections>
<point key="canvasLocation" x="-976.08695652173924" y="-1318.1919642857142"/>
<point key="canvasLocation" x="-1092" y="-1332"/>
</view>
</objects>
<resources>
@@ -217,6 +217,7 @@ extern NSString *const kMXKRoomBubbleCellUrlItemInteraction;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *attachViewTopConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *attachViewBottomConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *attachViewLeadingConstraint;
@property (weak, nonatomic) NSLayoutConstraint *attachViewTrailingConstraint;
/**
The constraints which defines the relationship between bubbleInfoContainer and its superview
@@ -329,4 +330,7 @@ extern NSString *const kMXKRoomBubbleCellUrlItemInteraction;
/// Add temporary subview to `tmpSubviews` property.
- (void)addTemporarySubview:(UIView*)subview;
/// Called when content view cell is tapped
- (IBAction)onContentViewTap:(UITapGestureRecognizer*)sender;
@end
@@ -1069,10 +1069,7 @@ static BOOL _disableLongPressGestureOnEvent;
- (BOOL)isBubbleDataContainsFileAttachment
{
return bubbleData.attachment
&& (bubbleData.attachment.type == MXKAttachmentTypeFile || bubbleData.attachment.type == MXKAttachmentTypeAudio || bubbleData.attachment.type == MXKAttachmentTypeVoiceMessage)
&& bubbleData.attachment.contentURL
&& bubbleData.attachment.contentInfo;
return bubbleData.isAttachment;
}
- (MXKRoomBubbleComponent*)closestBubbleComponentForGestureRecognizer:(UIGestureRecognizer*)gestureRecognizer locationInView:(UIView*)view
@@ -49,7 +49,7 @@ class PollBubbleCell: SizableBaseBubbleCell, BubbleCellReactionsDisplayable {
}
// The normal flow for tapping on cell content views doesn't work for bubbles without attributed strings
func onContentViewTap(_ sender: UITapGestureRecognizer) {
override func onContentViewTap(_ sender: UITapGestureRecognizer) {
guard let event = self.event else {
return
}
@@ -67,6 +67,25 @@ typedef NS_ENUM(NSUInteger, RoomTimelineCellIdentifier) {
RoomTimelineCellIdentifierOutgoingAttachmentEncryptedWithoutSenderInfo,
RoomTimelineCellIdentifierOutgoingAttachmentEncryptedWithPaginationTitle,
// - Attachment without thumbnail
// --- Clear
RoomTimelineCellIdentifierIncomingAttachmentWithoutThumbnail,
RoomTimelineCellIdentifierIncomingAttachmentWithoutThumbnailWithoutSenderInfo,
RoomTimelineCellIdentifierIncomingAttachmentWithoutThumbnailWithPaginationTitle,
// --- Encrypted
RoomTimelineCellIdentifierIncomingAttachmentWithoutThumbnailEncrypted,
RoomTimelineCellIdentifierIncomingAttachmentWithoutThumbnailEncryptedWithoutSenderInfo,
RoomTimelineCellIdentifierIncomingAttachmentWithoutThumbnailEncryptedWithPaginationTitle,
// -- Outgoing
// --- Clear
RoomTimelineCellIdentifierOutgoingAttachmentWithoutThumbnail,
RoomTimelineCellIdentifierOutgoingAttachmentWithoutThumbnailWithoutSenderInfo,
RoomTimelineCellIdentifierOutgoingAttachmentWithoutThumbnailWithPaginationTitle,
// --- Encrypted
RoomTimelineCellIdentifierOutgoingAttachmentWithoutThumbnailEncrypted,
RoomTimelineCellIdentifierOutgoingAttachmentWithoutThumbnailEncryptedWithoutSenderInfo,
RoomTimelineCellIdentifierOutgoingAttachmentWithoutThumbnailEncryptedWithPaginationTitle,
// - Room membership
RoomTimelineCellIdentifierMembership,
RoomTimelineCellIdentifierMembershipWithPaginationTitle,
@@ -92,19 +111,29 @@ typedef NS_ENUM(NSUInteger, RoomTimelineCellIdentifier) {
RoomTimelineCellIdentifierGroupCallStatus,
// - Voice message
RoomTimelineCellIdentifierVoiceMessage,
RoomTimelineCellIdentifierVoiceMessageWithoutSenderInfo,
RoomTimelineCellIdentifierVoiceMessageWithPaginationTitle,
// -- Incoming
RoomTimelineCellIdentifierIncomingVoiceMessage,
RoomTimelineCellIdentifierIncomingVoiceMessageWithoutSenderInfo,
RoomTimelineCellIdentifierIncomingVoiceMessageWithPaginationTitle,
// -- Outgoing
RoomTimelineCellIdentifierOutgoingVoiceMessage,
RoomTimelineCellIdentifierOutgoingVoiceMessageWithoutSenderInfo,
RoomTimelineCellIdentifierOutgoingVoiceMessageWithPaginationTitle,
// - Poll
RoomTimelineCellIdentifierPoll,
RoomTimelineCellIdentifierPollWithoutSenderInfo,
RoomTimelineCellIdentifierPollWithPaginationTitle,
// - Location sharing
RoomTimelineCellIdentifierLocation,
RoomTimelineCellIdentifierLocationWithoutSenderInfo,
RoomTimelineCellIdentifierLocationWithPaginationTitle,
// -- Incoming
RoomTimelineCellIdentifierIncomingLocation,
RoomTimelineCellIdentifierIncomingLocationWithoutSenderInfo,
RoomTimelineCellIdentifierIncomingLocationWithPaginationTitle,
// -- Outgoing
RoomTimelineCellIdentifierOutgoingLocation,
RoomTimelineCellIdentifierOutgoingLocationWithoutSenderInfo,
RoomTimelineCellIdentifierOutgoingLocationWithPaginationTitle,
// - Others
RoomTimelineCellIdentifierEmpty,
@@ -121,6 +121,10 @@
}
}
RoomTimelineConfiguration *timelineConfiguration = [RoomTimelineConfiguration shared];
[timelineConfiguration.currentStyle.cellLayoutUpdater updateLayoutForSelectedStickerCell:self];
// Retrieve the suitable content size for the attachment thumbnail
CGSize contentSize = bubbleData.contentSize;
// Update image view frame in order to center loading wheel (if any)
@@ -24,11 +24,11 @@ class BubbleRoomCellLayoutUpdater: RoomCellLayoutUpdating {
private var theme: Theme
private var incomingColor: UIColor {
return self.theme.colors.system
return self.theme.roomCellIncomingBubbleBackgroundColor
}
private var outgoingColor: UIColor {
return self.theme.colors.accent.withAlphaComponent(0.10)
return self.theme.roomCellOutgoingBubbleBackgroundColor
}
// MARK: - Setup
@@ -41,10 +41,10 @@ class BubbleRoomCellLayoutUpdater: RoomCellLayoutUpdating {
func updateLayoutIfNeeded(for cell: MXKRoomBubbleTableViewCell, andCellData cellData: MXKRoomBubbleCellData) {
if cellData.isSenderCurrentUser {
self.updateLayout(forOutgoingTextMessageCell: cell, andCellData: cellData)
} else {
if cellData.isIncoming {
self.updateLayout(forIncomingTextMessageCell: cell, andCellData: cellData)
} else {
self.updateLayout(forOutgoingTextMessageCell: cell, andCellData: cellData)
}
}
@@ -107,6 +107,22 @@ class BubbleRoomCellLayoutUpdater: RoomCellLayoutUpdating {
self.setupOutgoingFileAttachViewMargins(for: cell)
}
func setupLayout(forIncomingFileAttachmentCell cell: MXKRoomBubbleTableViewCell) {
self.setupIncomingFileAttachViewMargins(for: cell)
}
func updateLayout(forSelectedStickerCell cell: RoomSelectedStickerBubbleCell) {
if cell.bubbleData.isIncoming {
self.setupLayout(forIncomingFileAttachmentCell: cell)
} else {
self.setupLayout(forOutgoingFileAttachmentCell: cell)
cell.userNameLabel?.isHidden = true
cell.pictureView?.isHidden = true
}
}
// MARK: Themable
func update(theme: Theme) {
@@ -160,13 +176,13 @@ class BubbleRoomCellLayoutUpdater: RoomCellLayoutUpdating {
switch firstEvent.eventType {
case .roomMessage:
if let messageTypeString = firstEvent.content["msgtype"] as? String {
let messageType = MXMessageType(identifier: messageTypeString)
if let messageType = firstEvent.messageType {
switch messageType {
case .text, .emote, .file:
case .text, .file:
return true
case .emote:
// Explicitely disable bubble for emotes
return false
default:
break
}
@@ -341,5 +357,33 @@ class BubbleRoomCellLayoutUpdater: RoomCellLayoutUpdating {
NSLayoutConstraint.activate([
rightConstraint
])
cell.attachViewTrailingConstraint = rightConstraint
}
private func setupIncomingFileAttachViewMargins(for cell: MXKRoomBubbleTableViewCell) {
guard let attachmentView = cell.attachmentView,
cell.attachViewLeadingConstraint == nil || cell.attachViewLeadingConstraint.isActive == false else {
return
}
if let attachViewTrailingConstraint = cell.attachViewTrailingConstraint {
attachViewTrailingConstraint.isActive = false
cell.attachViewTrailingConstraint = nil
}
let contentView = cell.contentView
// TODO: Use constants
let leftMargin: CGFloat = 67
let leftConstraint = attachmentView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: -leftMargin)
NSLayoutConstraint.activate([
leftConstraint
])
cell.attachViewLeadingConstraint = leftConstraint
}
}
@@ -28,39 +28,61 @@ class BubbleRoomTimelineCellDecorator: PlainRoomTimelineCellDecorator {
}
override func addTimestampLabel(toCell cell: MXKRoomBubbleTableViewCell, cellData: RoomBubbleCellData) {
// If cell contains a bubble background, add the timestamp inside of it
if let bubbleBackgroundView = cell.messageBubbleBackgroundView, bubbleBackgroundView.isHidden == false {
let componentIndex = cellData.mostRecentComponentIndex
guard let bubbleComponents = cellData.bubbleComponents,
componentIndex < bubbleComponents.count else {
return
}
let component = bubbleComponents[componentIndex]
let timestampLabel = self.createTimestampLabel(cellData: cellData,
bubbleComponent: component,
viewTag: componentIndex)
timestampLabel.translatesAutoresizingMaskIntoConstraints = false
cell.addTemporarySubview(timestampLabel)
bubbleBackgroundView.addSubview(timestampLabel)
let rightMargin: CGFloat = 8.0
let bottomMargin: CGFloat = 4.0
let trailingConstraint = timestampLabel.trailingAnchor.constraint(equalTo: bubbleBackgroundView.trailingAnchor, constant: -rightMargin)
let bottomConstraint = timestampLabel.bottomAnchor.constraint(equalTo: bubbleBackgroundView.bottomAnchor, constant: -bottomMargin)
NSLayoutConstraint.activate([
trailingConstraint,
bottomConstraint
])
if let bubbleBackgroundView = cell.messageBubbleBackgroundView, bubbleBackgroundView.isHidden == false, let timestampLabel = self.createTimestampLabel(for: cellData) {
self.addTimestampLabel(timestampLabel,
to: cell,
on: bubbleBackgroundView,
constrainingView: bubbleBackgroundView)
} else if cellData.isAttachmentWithThumbnail {
if cellData.attachment?.type == .sticker,
let attachmentView = cell.attachmentView,
let timestampLabel = self.createTimestampLabel(for: cellData) {
// Prevent overlap with send status icon
let bottomMargin: CGFloat = 20.0
let rightMargin: CGFloat = -27.0
self.addTimestampLabel(timestampLabel,
to: cell,
on: cell.contentView,
constrainingView: attachmentView,
rightMargin: rightMargin,
bottomMargin: bottomMargin)
} else if let attachmentView = cell.attachmentView, let timestampLabel = self.createTimestampLabel(for: cellData, textColor: self.theme.baseIconPrimaryColor) {
// For media with thumbnail cells, add timestamp inside thumbnail
self.addTimestampLabel(timestampLabel,
to: cell,
on: cell.contentView,
constrainingView: attachmentView)
} else {
super.addTimestampLabel(toCell: cell, cellData: cellData)
}
} else if let voiceMessageCell = cell as? VoiceMessageBubbleCell, let playbackView = voiceMessageCell.playbackController?.playbackView, let timestampLabel = self.createTimestampLabel(for: cellData) {
// Add timestamp on cell inherting from VoiceMessageBubbleCell
self.addTimestampLabel(timestampLabel,
to: cell,
on: cell.contentView,
constrainingView: playbackView)
} else if let fileWithoutThumbnailCell = cell as? FileWithoutThumbnailBaseBubbleCell, let fileAttachementView = fileWithoutThumbnailCell.fileAttachementView, let timestampLabel = self.createTimestampLabel(for: cellData) {
// Add timestamp on cell inherting from VoiceMessageBubbleCell
self.addTimestampLabel(timestampLabel,
to: cell,
on: fileAttachementView,
constrainingView: fileAttachementView)
} else {
super.addTimestampLabel(toCell: cell, cellData: cellData)
}
@@ -86,24 +108,9 @@ class BubbleRoomTimelineCellDecorator: PlainRoomTimelineCellDecorator {
let topMargin: CGFloat = 4.0
let leftMargin: CGFloat
let rightMargin: CGFloat
// Outgoing message
if cellData.isSenderCurrentUser {
reactionsView.alignment = .right
// TODO: Use constants
var outgointLeftMargin: CGFloat = 80.0
if cellData.containsBubbleComponentWithEncryptionBadge {
outgointLeftMargin += RoomBubbleCellLayout.encryptedContentLeftMargin
}
leftMargin = outgointLeftMargin
// TODO: Use constants
rightMargin = 33
} else {
// Incoming message
// Incoming message
if cellData.isIncoming {
var incomingLeftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin
@@ -117,6 +124,22 @@ class BubbleRoomTimelineCellDecorator: PlainRoomTimelineCellDecorator {
let messageViewMarginRight: CGFloat = 42.0
rightMargin = messageViewMarginRight
} else {
// Outgoing message
reactionsView.alignment = .right
// TODO: Use constants
var outgoingLeftMargin: CGFloat = 80.0
if cellData.containsBubbleComponentWithEncryptionBadge {
outgoingLeftMargin += RoomBubbleCellLayout.encryptedContentLeftMargin
}
leftMargin = outgoingLeftMargin
// TODO: Use constants
rightMargin = 33
}
let leadingConstraint = reactionsView.leadingAnchor.constraint(equalTo: cellContentView.leadingAnchor, constant: leftMargin)
@@ -152,16 +175,10 @@ class BubbleRoomTimelineCellDecorator: PlainRoomTimelineCellDecorator {
let leadingOrTrailingConstraint: NSLayoutConstraint
// Outgoing message
if cellData.isSenderCurrentUser {
// TODO: Use constants
let rightMargin: CGFloat = 34.0
leadingOrTrailingConstraint = urlPreviewView.trailingAnchor.constraint(equalTo: cellContentView.trailingAnchor, constant: -rightMargin)
} else {
// Incoming message
// Incoming message
if cellData.isIncoming {
var leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin
if cellData.containsBubbleComponentWithEncryptionBadge {
leftMargin += RoomBubbleCellLayout.encryptedContentLeftMargin
@@ -170,6 +187,13 @@ class BubbleRoomTimelineCellDecorator: PlainRoomTimelineCellDecorator {
leftMargin-=5.0
leadingOrTrailingConstraint = urlPreviewView.leadingAnchor.constraint(equalTo: cellContentView.leadingAnchor, constant: leftMargin)
} else {
// Outgoing message
// TODO: Use constants
let rightMargin: CGFloat = 34.0
leadingOrTrailingConstraint = urlPreviewView.trailingAnchor.constraint(equalTo: cellContentView.trailingAnchor, constant: -rightMargin)
}
let topMargin = contentViewPositionY + RoomBubbleCellLayout.urlPreviewViewTopMargin + RoomBubbleCellLayout.reactionsViewTopMargin
@@ -183,14 +207,16 @@ class BubbleRoomTimelineCellDecorator: PlainRoomTimelineCellDecorator {
// MARK: - Private
private func createTimestampLabel(cellData: MXKRoomBubbleCellData, bubbleComponent: MXKRoomBubbleComponent, viewTag: Int) -> UILabel {
// MARK: Timestamp management
private func createTimestampLabel(cellData: MXKRoomBubbleCellData, bubbleComponent: MXKRoomBubbleComponent, viewTag: Int, textColor: UIColor) -> UILabel {
let timeLabel = UILabel()
timeLabel.text = cellData.eventFormatter.timeString(from: bubbleComponent.date)
timeLabel.textAlignment = .right
timeLabel.textColor = ThemeService.shared().theme.textSecondaryColor
timeLabel.font = UIFont.systemFont(ofSize: 11, weight: .light)
timeLabel.textColor = textColor
timeLabel.font = self.theme.fonts.caption2
timeLabel.adjustsFontSizeToFitWidth = true
timeLabel.tag = viewTag
timeLabel.accessibilityIdentifier = "timestampLabel"
@@ -198,6 +224,23 @@ class BubbleRoomTimelineCellDecorator: PlainRoomTimelineCellDecorator {
return timeLabel
}
func createTimestampLabel(for cellData: RoomBubbleCellData) -> UILabel? {
return self.createTimestampLabel(for: cellData, textColor: self.theme.textSecondaryColor)
}
private func createTimestampLabel(for cellData: RoomBubbleCellData, textColor: UIColor) -> UILabel? {
let componentIndex = cellData.mostRecentComponentIndex
guard let bubbleComponents = cellData.bubbleComponents, componentIndex < bubbleComponents.count else {
return nil
}
let component = bubbleComponents[componentIndex]
return self.createTimestampLabel(cellData: cellData, bubbleComponent: component, viewTag: componentIndex, textColor: textColor)
}
private func canShowTimestamp(forCellData cellData: MXKRoomBubbleCellData) -> Bool {
guard cellData.isCollapsableAndCollapsed == false else {
@@ -208,12 +251,29 @@ class BubbleRoomTimelineCellDecorator: PlainRoomTimelineCellDecorator {
return false
}
switch cellData.cellDataTag {
case .location:
return true
default:
break
}
if let attachmentType = cellData.attachment?.type {
switch attachmentType {
case .voiceMessage, .audio:
return true
default:
break
}
}
if cellData.isAttachmentWithThumbnail {
return true
}
switch firstEvent.eventType {
case .roomMessage:
if let messageTypeString = firstEvent.content["msgtype"] as? String {
let messageType = MXMessageType(identifier: messageTypeString)
if let messageType = firstEvent.messageType {
switch messageType {
case .text, .emote, .file:
return true
@@ -227,4 +287,26 @@ class BubbleRoomTimelineCellDecorator: PlainRoomTimelineCellDecorator {
return false
}
private func addTimestampLabel(_ timestampLabel: UILabel,
to cell: MXKRoomBubbleTableViewCell,
on containerView: UIView,
constrainingView: UIView,
rightMargin: CGFloat = 8.0,
bottomMargin: CGFloat = 4.0) {
timestampLabel.translatesAutoresizingMaskIntoConstraints = false
cell.addTemporarySubview(timestampLabel)
containerView.addSubview(timestampLabel)
let trailingConstraint = timestampLabel.trailingAnchor.constraint(equalTo: constrainingView.trailingAnchor, constant: -rightMargin)
let bottomConstraint = timestampLabel.bottomAnchor.constraint(equalTo: constrainingView.bottomAnchor, constant: -bottomMargin)
NSLayoutConstraint.activate([
trailingConstraint,
bottomConstraint
])
}
}
@@ -51,8 +51,56 @@
#import "RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.h"
#import "RoomOutgoingEncryptedAttachmentWithPaginationTitleBubbleCell.h"
#import "GeneratedInterface-Swift.h"
@implementation BubbleRoomTimelineCellProvider
#pragma mark - Registration
- (void)registerCellsForTableView:(UITableView *)tableView
{
[super registerCellsForTableView:tableView];
[self registerFileWithoutThumbnailCellsForTableView:tableView];
}
- (void)registerVoiceMessageCellsForTableView:(UITableView*)tableView
{
// Incoming
[tableView registerClass:VoiceMessageIncomingBubbleCell.class forCellReuseIdentifier:VoiceMessageIncomingBubbleCell.defaultReuseIdentifier];
[tableView registerClass:VoiceMessageIncomingWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:VoiceMessageIncomingWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[tableView registerClass:VoiceMessageIncomingWithPaginationTitleBubbleCell.class forCellReuseIdentifier:VoiceMessageIncomingWithPaginationTitleBubbleCell.defaultReuseIdentifier];
// Outgoing
[tableView registerClass:VoiceMessageOutgoingWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:VoiceMessageOutgoingWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[tableView registerClass:VoiceMessageOutgoingWithPaginationTitleBubbleCell.class forCellReuseIdentifier:VoiceMessageOutgoingWithPaginationTitleBubbleCell.defaultReuseIdentifier];
}
- (void)registerLocationCellsForTableView:(UITableView*)tableView
{
// Incoming
[tableView registerClass:LocationIncomingBubbleCell.class forCellReuseIdentifier:LocationIncomingBubbleCell.defaultReuseIdentifier];
[tableView registerClass:LocationIncomingWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:LocationIncomingWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[tableView registerClass:LocationIncomingWithPaginationTitleBubbleCell.class forCellReuseIdentifier:LocationIncomingWithPaginationTitleBubbleCell.defaultReuseIdentifier];
// Outgoing
[tableView registerClass:LocationOutgoingWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:LocationOutgoingWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[tableView registerClass:LocationOutgoingWithPaginationTitleBubbleCell.class forCellReuseIdentifier:LocationOutgoingWithPaginationTitleBubbleCell.defaultReuseIdentifier];
}
- (void)registerFileWithoutThumbnailCellsForTableView:(UITableView*)tableView
{
// Incoming
[tableView registerClass:FileWithoutThumbnailIncomingBubbleCell.class forCellReuseIdentifier:FileWithoutThumbnailIncomingBubbleCell.defaultReuseIdentifier];
[tableView registerClass:FileWithoutThumbnailIncomingWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:FileWithoutThumbnailIncomingWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[tableView registerClass:FileWithoutThumbnailIncomingWithPaginationTitleBubbleCell.class forCellReuseIdentifier:FileWithoutThumbnailIncomingWithPaginationTitleBubbleCell.defaultReuseIdentifier];
// Outgoing
[tableView registerClass:FileWithoutThumbnailOutoingWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:FileWithoutThumbnailOutoingWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[tableView registerClass:FileWithoutThumbnailOutoingWithPaginationTitleBubbleCell.class forCellReuseIdentifier:FileWithoutThumbnailOutoingWithPaginationTitleBubbleCell.defaultReuseIdentifier];
}
#pragma mark - Mapping
- (NSDictionary<NSNumber*, Class>*)outgoingTextMessageCellsMapping
{
// Hide sender info and avatar for bubble outgoing messages
@@ -87,4 +135,60 @@
};
}
- (NSDictionary<NSNumber*, Class>*)incomingAttachmentWithoutThumbnailCellsMapping
{
return @{
// Clear
@(RoomTimelineCellIdentifierIncomingAttachmentWithoutThumbnail) : FileWithoutThumbnailIncomingBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingAttachmentWithoutThumbnailWithoutSenderInfo) : FileWithoutThumbnailIncomingWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingAttachmentWithoutThumbnailWithPaginationTitle) : FileWithoutThumbnailIncomingWithPaginationTitleBubbleCell.class,
// Encrypted
@(RoomTimelineCellIdentifierIncomingAttachmentWithoutThumbnailEncrypted) : FileWithoutThumbnailIncomingBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingAttachmentWithoutThumbnailEncryptedWithoutSenderInfo) : FileWithoutThumbnailIncomingWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingAttachmentWithoutThumbnailEncryptedWithPaginationTitle) : FileWithoutThumbnailIncomingWithPaginationTitleBubbleCell.class
};
}
- (NSDictionary<NSNumber*, Class>*)outgoingAttachmentWithoutThumbnailCellsMapping
{
return @{
// Clear
@(RoomTimelineCellIdentifierOutgoingAttachmentWithoutThumbnail) : FileWithoutThumbnailOutoingWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingAttachmentWithoutThumbnailWithoutSenderInfo) : FileWithoutThumbnailOutoingWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingAttachmentWithoutThumbnailWithPaginationTitle) : FileWithoutThumbnailOutoingWithPaginationTitleBubbleCell.class,
// Encrypted
@(RoomTimelineCellIdentifierOutgoingAttachmentWithoutThumbnailEncrypted) : FileWithoutThumbnailOutoingWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingAttachmentWithoutThumbnailEncryptedWithoutSenderInfo) : FileWithoutThumbnailOutoingWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingAttachmentWithoutThumbnailEncryptedWithPaginationTitle) : FileWithoutThumbnailOutoingWithPaginationTitleBubbleCell.class
};
}
- (NSDictionary<NSNumber*, Class>*)voiceMessageCellsMapping
{
return @{
// Incoming
@(RoomTimelineCellIdentifierIncomingVoiceMessage) : VoiceMessageIncomingBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingVoiceMessageWithoutSenderInfo) : VoiceMessageIncomingWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingVoiceMessageWithPaginationTitle) : VoiceMessageIncomingWithPaginationTitleBubbleCell.class,
// Outgoing
@(RoomTimelineCellIdentifierOutgoingVoiceMessage) : VoiceMessageOutgoingWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingVoiceMessageWithoutSenderInfo) : VoiceMessageOutgoingWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingVoiceMessageWithPaginationTitle) : VoiceMessageOutgoingWithPaginationTitleBubbleCell.class,
};
}
- (NSDictionary<NSNumber*, Class>*)locationCellsMapping
{
return @{
// Incoming
@(RoomTimelineCellIdentifierIncomingLocation) : LocationIncomingBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingLocationWithoutSenderInfo) : LocationIncomingWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingLocationWithPaginationTitle) : LocationIncomingWithPaginationTitleBubbleCell.class,
// Outgoing
@(RoomTimelineCellIdentifierOutgoingLocation) : LocationOutgoingWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingLocationWithoutSenderInfo) : LocationOutgoingWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingLocationWithPaginationTitle) : LocationOutgoingWithPaginationTitleBubbleCell.class
};
}
@end
@@ -0,0 +1,59 @@
//
// Copyright 2021 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
class FileWithoutThumbnailBaseBubbleCell: SizableBaseBubbleCell, BubbleCellReactionsDisplayable {
weak var fileAttachementView: FileWithoutThumbnailCellContentView?
override func render(_ cellData: MXKCellData!) {
super.render(cellData)
guard let data = cellData as? RoomBubbleCellData else {
return
}
self.fileAttachementView?.title = data.attributedTextMessage.string
self.update(theme: ThemeService.shared().theme)
}
override func setupViews() {
super.setupViews()
bubbleCellContentView?.backgroundColor = .clear
guard let contentView = bubbleCellContentView?.innerContentView else {
return
}
let fileAttachementView = FileWithoutThumbnailCellContentView.instantiate()
contentView.vc_addSubViewMatchingParent(fileAttachementView)
self.fileAttachementView = fileAttachementView
}
override func onContentViewTap(_ sender: UITapGestureRecognizer!) {
if let bubbleData = self.bubbleData, bubbleData.isAttachment {
self.delegate.cell(self, didRecognizeAction: kMXKRoomBubbleCellTapOnAttachmentView, userInfo: nil)
} else {
super.onContentViewTap(sender)
}
}
}
@@ -0,0 +1,82 @@
//
// Copyright 2021 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 FileWithoutThumbnailCellContentView: UIView, NibLoadable {
// MARK: - Constants
private enum Constants {
// TODO: Reuse constants, same as bubble bg
static let cornerRadius: CGFloat = 12.0
}
// MARK: - Properties
// MARK: Outlets
@IBOutlet private weak var iconImageView: UIImageView!
@IBOutlet private weak var titleLabel: UILabel!
// MARK: Public
var badgeImage: UIImage? {
get {
return self.iconImageView.image
}
set {
self.iconImageView.image = newValue
}
}
var title: String? {
get {
return self.titleLabel.text
}
set {
self.titleLabel.text = newValue
}
}
// MARK: - Setup
static func instantiate() -> FileWithoutThumbnailCellContentView {
return FileWithoutThumbnailCellContentView.loadFromNib()
}
// MARK: - Life cycle
override func awakeFromNib() {
super.awakeFromNib()
self.layer.masksToBounds = true
}
override func layoutSubviews() {
super.layoutSubviews()
self.layer.cornerRadius = Constants.cornerRadius
}
// MARK: - Public
func update(theme: Theme) {
self.titleLabel.textColor = theme.textPrimaryColor
}
}
@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="19529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<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="8T9-hj-ply" customClass="FileWithoutThumbnailCellContentView" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="313" height="42"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" spacing="16" translatesAutoresizingMaskIntoConstraints="NO" id="tvT-jE-0OH">
<rect key="frame" x="20" y="15" width="253" height="12"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" image="file_attachment" translatesAutoresizingMaskIntoConstraints="NO" id="Pse-Mu-Gle">
<rect key="frame" x="0.0" y="0.0" width="16" height="12"/>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" text="Filename.docx" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="eCx-a1-1CO">
<rect key="frame" x="32" y="0.0" width="221" height="12"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" systemColor="systemGray2Color"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
</subviews>
<color key="backgroundColor" red="0.95294117649999999" green="0.97254901959999995" blue="0.99215686270000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="tvT-jE-0OH" secondAttribute="trailing" constant="40" id="At8-ah-N7j"/>
<constraint firstItem="tvT-jE-0OH" firstAttribute="top" secondItem="8T9-hj-ply" secondAttribute="top" constant="15" id="C7r-6f-Bqf"/>
<constraint firstItem="tvT-jE-0OH" firstAttribute="leading" secondItem="8T9-hj-ply" secondAttribute="leading" constant="20" id="Yh6-91-Thq"/>
<constraint firstAttribute="bottom" secondItem="tvT-jE-0OH" secondAttribute="bottom" constant="15" id="yHE-fi-Paj"/>
</constraints>
<nil key="simulatedTopBarMetrics"/>
<nil key="simulatedBottomBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<connections>
<outlet property="iconImageView" destination="Pse-Mu-Gle" id="pAQ-jI-GDj"/>
<outlet property="titleLabel" destination="eCx-a1-1CO" id="Oj5-X3-Rop"/>
</connections>
<point key="canvasLocation" x="-1454.3478260869567" y="-405.80357142857139"/>
</view>
</objects>
<resources>
<image name="file_attachment" width="16" height="16"/>
<systemColor name="systemGray2Color">
<color red="0.68235294117647061" green="0.68235294117647061" blue="0.69803921568627447" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
</resources>
</document>
@@ -0,0 +1,39 @@
//
// Copyright 2021 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
class FileWithoutThumbnailIncomingBubbleCell: FileWithoutThumbnailBaseBubbleCell {
override func setupViews() {
super.setupViews()
bubbleCellContentView?.showSenderInfo = true
// TODO: Use constants
let messageViewMarginRight: CGFloat = 80
let messageLeftMargin: CGFloat = 48
bubbleCellContentView?.innerContentViewTrailingConstraint.constant = messageViewMarginRight
bubbleCellContentView?.innerContentViewLeadingConstraint.constant = messageLeftMargin
}
override func update(theme: Theme) {
super.update(theme: theme)
self.fileAttachementView?.backgroundColor = theme.roomCellIncomingBubbleBackgroundColor
}
}
@@ -0,0 +1,26 @@
//
// Copyright 2021 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
class FileWithoutThumbnailIncomingWithPaginationTitleBubbleCell: FileWithoutThumbnailIncomingBubbleCell {
override func setupViews() {
super.setupViews()
bubbleCellContentView?.showPaginationTitle = true
}
}
@@ -0,0 +1,26 @@
//
// Copyright 2021 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
class FileWithoutThumbnailIncomingWithoutSenderInfoBubbleCell: FileWithoutThumbnailIncomingBubbleCell {
override func setupViews() {
super.setupViews()
bubbleCellContentView?.showSenderInfo = false
}
}
@@ -0,0 +1,26 @@
//
// Copyright 2021 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
class FileWithoutThumbnailOutoingWithPaginationTitleBubbleCell: FileWithoutThumbnailOutoingWithoutSenderInfoBubbleCell {
override func setupViews() {
super.setupViews()
bubbleCellContentView?.showPaginationTitle = true
}
}
@@ -0,0 +1,40 @@
//
// Copyright 2021 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
class FileWithoutThumbnailOutoingWithoutSenderInfoBubbleCell: FileWithoutThumbnailBaseBubbleCell {
override func setupViews() {
super.setupViews()
bubbleCellContentView?.showSenderInfo = false
// TODO: Use constants
// Same as outgoing message
let rightMargin: CGFloat = 34.0
let leftMargin: CGFloat = 80.0
bubbleCellContentView?.innerContentViewTrailingConstraint.constant = rightMargin
bubbleCellContentView?.innerContentViewLeadingConstraint.constant = leftMargin
}
override func update(theme: Theme) {
super.update(theme: theme)
self.fileAttachementView?.backgroundColor = theme.roomCellOutgoingBubbleBackgroundColor
}
}
@@ -0,0 +1,31 @@
//
// Copyright 2021 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
class LocationIncomingBubbleCell: LocationBubbleCell {
override func setupViews() {
super.setupViews()
// TODO: Use constants
let messageViewMarginRight: CGFloat = 80
let messageLeftMargin: CGFloat = 48
bubbleCellContentView?.innerContentViewTrailingConstraint.constant = messageViewMarginRight
bubbleCellContentView?.innerContentViewLeadingConstraint.constant = messageLeftMargin
}
}
@@ -0,0 +1,25 @@
//
// Copyright 2021 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
class LocationIncomingWithPaginationTitleBubbleCell: LocationIncomingBubbleCell {
override func setupViews() {
super.setupViews()
bubbleCellContentView?.showPaginationTitle = true
}
}
@@ -0,0 +1,25 @@
//
// Copyright 2021 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
class LocationIncomingWithoutSenderInfoBubbleCell: LocationIncomingBubbleCell {
override func setupViews() {
super.setupViews()
bubbleCellContentView?.showSenderInfo = false
}
}
@@ -0,0 +1,25 @@
//
// Copyright 2021 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
class LocationOutgoingWithPaginationTitleBubbleCell: LocationOutgoingWithoutSenderInfoBubbleCell {
override func setupViews() {
super.setupViews()
bubbleCellContentView?.showPaginationTitle = true
}
}
@@ -0,0 +1,33 @@
//
// Copyright 2021 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
class LocationOutgoingWithoutSenderInfoBubbleCell: LocationBubbleCell {
override func setupViews() {
super.setupViews()
bubbleCellContentView?.showSenderInfo = false
// TODO: Use constants
// Same as outgoing message
let rightMargin: CGFloat = 34.0
let leftMargin: CGFloat = 80.0
bubbleCellContentView?.innerContentViewTrailingConstraint.constant = rightMargin
bubbleCellContentView?.innerContentViewLeadingConstraint.constant = leftMargin
}
}
@@ -0,0 +1,43 @@
//
// Copyright 2021 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
class VoiceMessageIncomingBubbleCell: VoiceMessageBubbleCell {
override func setupViews() {
super.setupViews()
// TODO: Use constants
let messageViewMarginRight: CGFloat = 80
let messageLeftMargin: CGFloat = 48
let playbackViewRightMargin: CGFloat = 40
bubbleCellContentView?.innerContentViewTrailingConstraint.constant = messageViewMarginRight
bubbleCellContentView?.innerContentViewLeadingConstraint.constant = messageLeftMargin
playbackController.playbackView.stackViewTrailingContraint.constant = playbackViewRightMargin
}
override func update(theme: Theme) {
guard let playbackController = playbackController else {
return
}
playbackController.playbackView.customBackgroundViewColor = theme.roomCellIncomingBubbleBackgroundColor
}
}
@@ -0,0 +1,25 @@
//
// Copyright 2021 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
class VoiceMessageIncomingWithPaginationTitleBubbleCell: VoiceMessageIncomingBubbleCell {
override func setupViews() {
super.setupViews()
bubbleCellContentView?.showPaginationTitle = true
}
}
@@ -0,0 +1,25 @@
//
// Copyright 2021 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
class VoiceMessageIncomingWithoutSenderInfoBubbleCell: VoiceMessageIncomingBubbleCell {
override func setupViews() {
super.setupViews()
bubbleCellContentView?.showSenderInfo = false
}
}
@@ -0,0 +1,26 @@
//
// Copyright 2021 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
class VoiceMessageOutgoingWithPaginationTitleBubbleCell: VoiceMessageOutgoingWithoutSenderInfoBubbleCell {
override func setupViews() {
super.setupViews()
bubbleCellContentView?.showPaginationTitle = true
}
}
@@ -0,0 +1,46 @@
//
// Copyright 2021 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
class VoiceMessageOutgoingWithoutSenderInfoBubbleCell: VoiceMessageBubbleCell {
override func setupViews() {
super.setupViews()
bubbleCellContentView?.showSenderInfo = false
// TODO: Use constants
// Same as outgoing message
let rightMargin: CGFloat = 34.0
let leftMargin: CGFloat = 80.0
let playbackViewRightMargin: CGFloat = 40
bubbleCellContentView?.innerContentViewTrailingConstraint.constant = rightMargin
bubbleCellContentView?.innerContentViewLeadingConstraint.constant = leftMargin
playbackController.playbackView.stackViewTrailingContraint.constant = playbackViewRightMargin
}
override func update(theme: Theme) {
guard let playbackController = playbackController else {
return
}
playbackController.playbackView.customBackgroundViewColor = theme.roomCellOutgoingBubbleBackgroundColor
}
}
@@ -19,6 +19,15 @@ import UIKit
@objcMembers
class PlainRoomTimelineCellDecorator: RoomTimelineCellDecorator {
// MARK: - Properties
// TODO: Conforms to Themable and don't use ThemeService
var theme: Theme {
return ThemeService.shared().theme
}
// MARK: - RoomTimelineCellDecorator
func addTimestampLabelIfNeeded(toCell cell: MXKRoomBubbleTableViewCell, cellData: RoomBubbleCellData) {
guard cellData.containsLastMessage && cellData.isCollapsableAndCollapsed == false else {
@@ -20,10 +20,26 @@ NS_ASSUME_NONNULL_BEGIN
@interface PlainRoomTimelineCellProvider: NSObject<RoomTimelineCellProvider>
#pragma mark - Registration
- (void)registerVoiceMessageCellsForTableView:(UITableView*)tableView;
- (void)registerLocationCellsForTableView:(UITableView*)tableView;
#pragma mark - Mapping
- (NSDictionary<NSNumber*, Class>*)outgoingTextMessageCellsMapping;
- (NSDictionary<NSNumber*, Class>*)outgoingAttachmentCellsMapping;
- (NSDictionary<NSNumber*, Class>*)incomingAttachmentWithoutThumbnailCellsMapping;
- (NSDictionary<NSNumber*, Class>*)outgoingAttachmentWithoutThumbnailCellsMapping;
- (NSDictionary<NSNumber*, Class>*)voiceMessageCellsMapping;
- (NSDictionary<NSNumber*, Class>*)locationCellsMapping;
@end
NS_ASSUME_NONNULL_END
@@ -283,6 +283,12 @@
NSDictionary *outgoingAttachmentCellsMapping = [self outgoingAttachmentCellsMapping];
[cellClasses addEntriesFromDictionary:outgoingAttachmentCellsMapping];
NSDictionary *outgoingAttachmentWithoutThumbnailCellsMapping = [self outgoingAttachmentWithoutThumbnailCellsMapping];
[cellClasses addEntriesFromDictionary:outgoingAttachmentWithoutThumbnailCellsMapping];
NSDictionary *incomingAttachmentWithoutThumbnailCellsMapping = [self incomingAttachmentWithoutThumbnailCellsMapping];
[cellClasses addEntriesFromDictionary:incomingAttachmentWithoutThumbnailCellsMapping];
// Other cells
NSDictionary *roomMembershipCellsMapping = [self membershipCellsMapping];
@@ -382,6 +388,34 @@
};
}
- (NSDictionary<NSNumber*, Class>*)incomingAttachmentWithoutThumbnailCellsMapping
{
return @{
// Clear
@(RoomTimelineCellIdentifierIncomingAttachmentWithoutThumbnail) : RoomIncomingTextMsgBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingAttachmentWithoutThumbnailWithoutSenderInfo) : RoomIncomingTextMsgWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingAttachmentWithoutThumbnailWithPaginationTitle) : RoomIncomingTextMsgWithPaginationTitleBubbleCell.class,
// Encrypted
@(RoomTimelineCellIdentifierIncomingAttachmentWithoutThumbnailEncrypted) : RoomIncomingEncryptedTextMsgBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingAttachmentWithoutThumbnailEncryptedWithoutSenderInfo) : RoomIncomingEncryptedTextMsgWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingAttachmentWithoutThumbnailEncryptedWithPaginationTitle) : RoomIncomingEncryptedTextMsgWithPaginationTitleBubbleCell.class
};
}
- (NSDictionary<NSNumber*, Class>*)outgoingAttachmentWithoutThumbnailCellsMapping
{
return @{
// Clear
@(RoomTimelineCellIdentifierOutgoingAttachmentWithoutThumbnail) : RoomOutgoingTextMsgBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingAttachmentWithoutThumbnailWithoutSenderInfo) : RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingAttachmentWithoutThumbnailWithPaginationTitle) : RoomOutgoingTextMsgWithPaginationTitleBubbleCell.class,
// Encrypted
@(RoomTimelineCellIdentifierOutgoingAttachmentWithoutThumbnailEncrypted) : RoomOutgoingEncryptedTextMsgBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingAttachmentWithoutThumbnailEncryptedWithoutSenderInfo) : RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingAttachmentWithoutThumbnailEncryptedWithPaginationTitle) : RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell.class
};
}
- (NSDictionary<NSNumber*, Class>*)membershipCellsMapping
{
return @{
@@ -425,9 +459,14 @@
- (NSDictionary<NSNumber*, Class>*)voiceMessageCellsMapping
{
return @{
@(RoomTimelineCellIdentifierVoiceMessage) : VoiceMessageBubbleCell.class,
@(RoomTimelineCellIdentifierVoiceMessageWithoutSenderInfo) : VoiceMessageWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierVoiceMessageWithPaginationTitle) : VoiceMessageWithPaginationTitleBubbleCell.class,
// Incoming
@(RoomTimelineCellIdentifierIncomingVoiceMessage) : VoiceMessageBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingVoiceMessageWithoutSenderInfo) : VoiceMessageWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingVoiceMessageWithPaginationTitle) : VoiceMessageWithPaginationTitleBubbleCell.class,
// Outoing
@(RoomTimelineCellIdentifierOutgoingVoiceMessage) : VoiceMessageBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingVoiceMessageWithoutSenderInfo) : VoiceMessageWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingVoiceMessageWithPaginationTitle) : VoiceMessageWithPaginationTitleBubbleCell.class
};
}
@@ -443,9 +482,14 @@
- (NSDictionary<NSNumber*, Class>*)locationCellsMapping
{
return @{
@(RoomTimelineCellIdentifierLocation) : LocationBubbleCell.class,
@(RoomTimelineCellIdentifierLocationWithoutSenderInfo) : LocationWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierLocationWithPaginationTitle) : LocationWithPaginationTitleBubbleCell.class
// Incoming
@(RoomTimelineCellIdentifierIncomingLocation) : LocationBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingLocationWithoutSenderInfo) : LocationWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingLocationWithPaginationTitle) : LocationWithPaginationTitleBubbleCell.class,
// Outgoing
@(RoomTimelineCellIdentifierOutgoingLocation) : LocationBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingLocationWithoutSenderInfo) : LocationWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingLocationWithPaginationTitle) : LocationWithPaginationTitleBubbleCell.class
};
}
@@ -27,4 +27,6 @@ protocol RoomCellLayoutUpdating: Themable {
func setupLayout(forOutgoingTextMessageCell cell: MXKRoomBubbleTableViewCell)
func setupLayout(forOutgoingFileAttachmentCell cell: MXKRoomBubbleTableViewCell)
func updateLayout(forSelectedStickerCell cell: RoomSelectedStickerBubbleCell)
}
@@ -18,7 +18,7 @@ import Foundation
class VoiceMessageBubbleCell: SizableBaseBubbleCell, BubbleCellReactionsDisplayable {
private var playbackController: VoiceMessagePlaybackController!
private(set) var playbackController: VoiceMessagePlaybackController!
override func render(_ cellData: MXKCellData!) {
super.render(cellData)
@@ -27,13 +27,15 @@ class VoiceMessageBubbleCell: SizableBaseBubbleCell, BubbleCellReactionsDisplaya
return
}
guard data.attachment.type == MXKAttachmentTypeVoiceMessage || data.attachment.type == MXKAttachmentTypeAudio else {
guard data.attachment.type == .voiceMessage || data.attachment.type == .audio else {
fatalError("Invalid attachment type passed to a voice message cell.")
}
if playbackController.attachment != data.attachment {
playbackController.attachment = data.attachment
}
self.update(theme: ThemeService.shared().theme)
}
override func setupViews() {
@@ -52,4 +54,15 @@ class VoiceMessageBubbleCell: SizableBaseBubbleCell, BubbleCellReactionsDisplaya
contentView.vc_addSubViewMatchingParent(playbackController.playbackView)
}
override func update(theme: Theme) {
super.update(theme: theme)
guard let playbackController = playbackController else {
return
}
playbackController.playbackView.update(theme: theme)
}
}