Merge branch 'develop' into ismail/5096_thread_notifications

This commit is contained in:
ismailgulek
2022-01-27 03:20:25 +03:00
210 changed files with 3878 additions and 1073 deletions
@@ -18,6 +18,13 @@ import Foundation
import MatrixSDK
import Reusable
import DGCollectionViewLeftAlignFlowLayout
import UIKit
/// BubbleReactionsView items alignment
enum BubbleReactionsViewAlignment {
case left
case right
}
@objcMembers
final class BubbleReactionsView: UIView, NibOwnerLoadable {
@@ -51,6 +58,12 @@ final class BubbleReactionsView: UIView, NibOwnerLoadable {
}
}
var alignment: BubbleReactionsViewAlignment = .left {
didSet {
self.updateCollectionViewLayout(for: alignment)
}
}
// MARK: - Setup
private func commonInit() {
@@ -87,7 +100,18 @@ final class BubbleReactionsView: UIView, NibOwnerLoadable {
self.collectionView.isScrollEnabled = false
self.collectionView.delegate = self
self.collectionView.dataSource = self
self.collectionView.collectionViewLayout = DGCollectionViewLeftAlignFlowLayout()
self.alignment = .left
self.collectionView.register(cellType: BubbleReactionViewCell.self)
self.collectionView.register(cellType: BubbleReactionActionViewCell.self)
self.collectionView.reloadData()
}
private func updateCollectionViewLayout(for alignment: BubbleReactionsViewAlignment) {
let collectionViewLayout = self.collectionViewLayout(for: alignment)
self.collectionView.collectionViewLayout = collectionViewLayout
if let collectionViewFlowLayout = self.collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
collectionViewFlowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
@@ -95,9 +119,22 @@ final class BubbleReactionsView: UIView, NibOwnerLoadable {
collectionViewFlowLayout.minimumLineSpacing = Constants.minimumLineSpacing
}
self.collectionView.register(cellType: BubbleReactionViewCell.self)
self.collectionView.register(cellType: BubbleReactionActionViewCell.self)
self.collectionView.reloadData()
self.collectionView.collectionViewLayout.invalidateLayout()
}
private func collectionViewLayout(for alignment: BubbleReactionsViewAlignment) -> UICollectionViewLayout {
let collectionViewLayout: UICollectionViewLayout
switch alignment {
case .left:
collectionViewLayout = DGCollectionViewLeftAlignFlowLayout()
case .right:
collectionViewLayout = CollectionViewRightAlignFlowLayout()
}
return collectionViewLayout
}
private func setupLongPressGestureRecognizer() {
@@ -584,7 +584,7 @@ NSString *const URLPreviewDidUpdateNotification = @"URLPreviewDidUpdateNotificat
// Add vertical whitespace in case of a thread root
additionalVerticalHeight+= [self threadSummaryViewHeightForEventId:eventId];
// Add vertical whitespace in case of from a thread
additionalVerticalHeight+= [self fromThreadViewHeightForEventId:eventId];
additionalVerticalHeight+= [self fromAThreadViewHeightForEventId:eventId];
// Add vertical whitespace in case of read receipts.
additionalVerticalHeight+= [self readReceiptHeightForEventId:eventId];
@@ -605,7 +605,7 @@ NSString *const URLPreviewDidUpdateNotification = @"URLPreviewDidUpdateNotificat
height+= [self urlPreviewHeightForEventId:eventId];
height+= [self reactionHeightForEventId:eventId];
height+= [self threadSummaryViewHeightForEventId:eventId];
height+= [self fromThreadViewHeightForEventId:eventId];
height+= [self fromAThreadViewHeightForEventId:eventId];
height+= [self readReceiptHeightForEventId:eventId];
}
@@ -671,16 +671,16 @@ NSString *const URLPreviewDidUpdateNotification = @"URLPreviewDidUpdateNotificat
[ThreadSummaryView contentViewHeightForThread:component.thread fitting:self.maxTextViewWidth];
}
- (CGFloat)fromThreadViewHeightForEventId:(NSString*)eventId
- (CGFloat)fromAThreadViewHeightForEventId:(NSString*)eventId
{
if (!RiotSettings.shared.enableThreads)
{
// do not show from thread view if threads not enabled
// do not show from a thread view if threads not enabled
return 0;
}
if (roomDataSource.threadId)
{
// do not show from thread view on threads
// do not show from a thread view on threads
return 0;
}
NSInteger index = [self bubbleComponentIndexForEventId:eventId];
@@ -694,8 +694,8 @@ NSString *const URLPreviewDidUpdateNotification = @"URLPreviewDidUpdateNotificat
// event is not in a thread
return 0;
}
return RoomBubbleCellLayout.fromThreadViewTopMargin +
[FromThreadView contentViewHeightForEvent:component.event fitting:self.maxTextViewWidth];
return RoomBubbleCellLayout.fromAThreadViewTopMargin +
[FromAThreadView contentViewHeightForEvent:component.event fitting:self.maxTextViewWidth];
}
- (CGFloat)urlPreviewHeightForEventId:(NSString*)eventId
@@ -907,6 +907,12 @@ NSString *const URLPreviewDidUpdateNotification = @"URLPreviewDidUpdateNotificat
- (BOOL)addEvent:(MXEvent*)event andRoomState:(MXRoomState*)roomState
{
RoomTimelineConfiguration *timelineConfiguration = [RoomTimelineConfiguration shared];
if (NO == [timelineConfiguration.currentStyle canAddEvent:event and:roomState to:self]) {
return NO;
}
BOOL shouldAddEvent = YES;
switch (self.tag)
@@ -118,14 +118,14 @@
@protocol RoomDataSourceDelegate <MXKDataSourceDelegate>
/**
Called when the room's encryption trust level did updated.
Called when the room's encryption trust level did update.
@param roomDataSource room data source instance
*/
- (void)roomDataSourceDidUpdateEncryptionTrustLevel:(RoomDataSource * _Nonnull)roomDataSource;
/**
Called when a thread summary view
Called when a thread summary view is tapped.
@param roomDataSource room data source instance
*/
+35 -178
View File
@@ -383,6 +383,8 @@ const CGFloat kTypingCellHeight = 24;
UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
id<RoomTimelineCellDecorator> cellDecorator = [RoomTimelineConfiguration shared].currentStyle.cellDecorator;
// Finalize cell view customization here
if ([cell isKindOfClass:MXKRoomBubbleTableViewCell.class])
{
@@ -394,11 +396,8 @@ const CGFloat kTypingCellHeight = 24;
BOOL isCollapsableCellCollapsed = cellData.collapsable && cellData.collapsed;
// Display timestamp of the last message
if (cellData.containsLastMessage && !isCollapsableCellCollapsed)
{
[bubbleCell addTimestampLabelForComponent:cellData.mostRecentComponentIndex];
}
// Display timestamp of the message if needed
[cellDecorator addTimestampLabelIfNeededToCell:bubbleCell cellData:cellData];
NSMutableArray *temporaryViews = [NSMutableArray new];
@@ -442,23 +441,8 @@ const CGFloat kTypingCellHeight = 24;
urlPreviewView.tag = index;
[temporaryViews addObject:urlPreviewView];
[bubbleCell.tmpSubviews addObject:urlPreviewView];
urlPreviewView.translatesAutoresizingMaskIntoConstraints = NO;
urlPreviewView.availableWidth = cellData.maxTextViewWidth;
[bubbleCell.contentView addSubview:urlPreviewView];
CGFloat leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin;
if (roomBubbleCellData.containsBubbleComponentWithEncryptionBadge)
{
leftMargin+= RoomBubbleCellLayout.encryptedContentLeftMargin;
}
// Set the preview view's origin
[NSLayoutConstraint activateConstraints: @[
[urlPreviewView.leadingAnchor constraintEqualToAnchor:urlPreviewView.superview.leadingAnchor constant:leftMargin],
[urlPreviewView.topAnchor constraintEqualToAnchor:urlPreviewView.superview.topAnchor constant:bottomPositionY + RoomBubbleCellLayout.urlPreviewViewTopMargin + RoomBubbleCellLayout.reactionsViewTopMargin],
]];
[cellDecorator addURLPreviewView:urlPreviewView
toCell:bubbleCell cellData:cellData contentViewPositionY:bottomPositionY];
}
MXAggregatedReactions* reactions = cellData.reactions[componentEventId].aggregatedReactionsWithNonZeroCount;
@@ -480,44 +464,8 @@ const CGFloat kTypingCellHeight = 24;
bubbleReactionsViewModel.viewModelDelegate = self;
[temporaryViews addObject:reactionsView];
[bubbleCell.tmpSubviews addObject:reactionsView];
if ([[bubbleCell class] conformsToProtocol:@protocol(BubbleCellReactionsDisplayable)])
{
id<BubbleCellReactionsDisplayable> reactionsDisplayable = (id<BubbleCellReactionsDisplayable>)bubbleCell;
[reactionsDisplayable addReactionsView:reactionsView];
}
else
{
reactionsView.translatesAutoresizingMaskIntoConstraints = NO;
[bubbleCell.contentView addSubview:reactionsView];
CGFloat leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin;
if (roomBubbleCellData.containsBubbleComponentWithEncryptionBadge)
{
leftMargin+= RoomBubbleCellLayout.encryptedContentLeftMargin;
}
// The top constraint may need to include the URL preview view
NSLayoutConstraint *topConstraint;
if (urlPreviewView)
{
topConstraint = [reactionsView.topAnchor constraintEqualToAnchor:urlPreviewView.bottomAnchor constant:RoomBubbleCellLayout.reactionsViewTopMargin];
}
else
{
topConstraint = [reactionsView.topAnchor constraintEqualToAnchor:reactionsView.superview.topAnchor constant:bottomPositionY + RoomBubbleCellLayout.reactionsViewTopMargin];
}
// Force receipts container size
[NSLayoutConstraint activateConstraints:
@[
[reactionsView.leadingAnchor constraintEqualToAnchor:reactionsView.superview.leadingAnchor constant:leftMargin],
[reactionsView.trailingAnchor constraintEqualToAnchor:reactionsView.superview.trailingAnchor constant:-RoomBubbleCellLayout.reactionsViewRightMargin],
topConstraint
]];
}
[cellDecorator addReactionView:reactionsView toCell:bubbleCell
cellData:cellData contentViewPositionY:bottomPositionY upperDecorationView:urlPreviewView];
}
ThreadSummaryView *threadSummaryView;
@@ -527,55 +475,16 @@ const CGFloat kTypingCellHeight = 24;
{
threadSummaryView = [[ThreadSummaryView alloc] initWithThread:component.thread];
threadSummaryView.delegate = self;
threadSummaryView.tag = index;
[temporaryViews addObject:threadSummaryView];
[bubbleCell.tmpSubviews addObject:threadSummaryView];
UIView *upperDecorationView = reactionsView ?: urlPreviewView;
threadSummaryView.translatesAutoresizingMaskIntoConstraints = NO;
if ([[bubbleCell class] conformsToProtocol:@protocol(BubbleCellThreadSummaryDisplayable)])
{
id<BubbleCellThreadSummaryDisplayable> threadSummaryDisplayable = (id<BubbleCellThreadSummaryDisplayable>)bubbleCell;
[threadSummaryDisplayable addThreadSummaryView:threadSummaryView];
}
else
{
[bubbleCell.contentView addSubview:threadSummaryView];
CGFloat leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin;
if (roomBubbleCellData.containsBubbleComponentWithEncryptionBadge)
{
leftMargin+= RoomBubbleCellLayout.encryptedContentLeftMargin;
}
// The top constraint may need to include the URL preview view or reactions view
NSLayoutConstraint *topConstraint;
if (reactionsView)
{
topConstraint = [threadSummaryView.topAnchor constraintEqualToAnchor:reactionsView.bottomAnchor
constant:RoomBubbleCellLayout.threadSummaryViewTopMargin];
}
else if (urlPreviewView)
{
topConstraint = [threadSummaryView.topAnchor constraintEqualToAnchor:urlPreviewView.bottomAnchor
constant:RoomBubbleCellLayout.threadSummaryViewTopMargin];
}
else
{
topConstraint = [threadSummaryView.topAnchor constraintEqualToAnchor:threadSummaryView.superview.topAnchor
constant:bottomPositionY + RoomBubbleCellLayout.threadSummaryViewTopMargin];
}
// Set constraints for the summary view
[NSLayoutConstraint activateConstraints: @[
[threadSummaryView.leadingAnchor constraintEqualToAnchor:threadSummaryView.superview.leadingAnchor
constant:leftMargin],
topConstraint,
[threadSummaryView.heightAnchor constraintEqualToConstant:[ThreadSummaryView contentViewHeightForThread:component.thread fitting:cellData.maxTextViewWidth]],
[threadSummaryView.trailingAnchor constraintLessThanOrEqualToAnchor:threadSummaryView.superview.trailingAnchor constant:-RoomBubbleCellLayout.reactionsViewRightMargin]
]];
}
[cellDecorator addThreadSummaryView:threadSummaryView
toCell:bubbleCell
cellData:cellData
contentViewPositionY:bottomPositionY
upperDecorationView:upperDecorationView];
}
MXKReceiptSendersContainer* avatarsContainer;
@@ -633,67 +542,13 @@ const CGFloat kTypingCellHeight = 24;
avatarsContainer.accessibilityIdentifier = @"readReceiptsContainer";
[temporaryViews addObject:avatarsContainer];
// Add this read receipts container in the content view
[bubbleCell.tmpSubviews addObject:avatarsContainer];
UIView *upperDecorationView = threadSummaryView ?: (reactionsView ?: urlPreviewView);
if ([[bubbleCell class] conformsToProtocol:@protocol(BubbleCellReadReceiptsDisplayable)])
{
id<BubbleCellReadReceiptsDisplayable> readReceiptsDisplayable = (id<BubbleCellReadReceiptsDisplayable>)bubbleCell;
[readReceiptsDisplayable addReadReceiptsView:avatarsContainer];
}
else
{
[bubbleCell.contentView addSubview:avatarsContainer];
// Force receipts container size
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:avatarsContainer
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:RoomBubbleCellLayout.readReceiptsViewWidth];
NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:avatarsContainer
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:RoomBubbleCellLayout.readReceiptsViewHeight];
// Force receipts container position
NSLayoutConstraint *trailingConstraint = [NSLayoutConstraint constraintWithItem:avatarsContainer
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:avatarsContainer.superview
attribute:NSLayoutAttributeTrailing
multiplier:1.0
constant:-RoomBubbleCellLayout.readReceiptsViewRightMargin];
// At the bottom, we either have a thread summary, a reactions, a URL preview or nothing
NSLayoutConstraint *topConstraint;
if (threadSummaryView)
{
topConstraint = [avatarsContainer.topAnchor constraintEqualToAnchor:threadSummaryView.bottomAnchor constant:RoomBubbleCellLayout.readReceiptsViewTopMargin];
}
else if (reactionsView)
{
topConstraint = [avatarsContainer.topAnchor constraintEqualToAnchor:reactionsView.bottomAnchor constant:RoomBubbleCellLayout.readReceiptsViewTopMargin];
}
else if (urlPreviewView)
{
topConstraint = [avatarsContainer.topAnchor constraintEqualToAnchor:urlPreviewView.bottomAnchor constant:RoomBubbleCellLayout.readReceiptsViewTopMargin];
}
else
{
topConstraint = [avatarsContainer.topAnchor constraintEqualToAnchor:avatarsContainer.superview.topAnchor constant:bottomPositionY + RoomBubbleCellLayout.readReceiptsViewTopMargin];
}
// Available on iOS 8 and later
[NSLayoutConstraint activateConstraints:@[widthConstraint, heightConstraint, topConstraint, trailingConstraint]];
}
[cellDecorator addReadReceiptsView:avatarsContainer
toCell:bubbleCell
cellData:cellData
contentViewPositionY:bottomPositionY
upperDecorationView:upperDecorationView];
}
}
@@ -776,16 +631,7 @@ const CGFloat kTypingCellHeight = 24;
// Check whether an event is currently selected: the other messages are then blurred
if (_selectedEventId)
{
// Check whether the selected event belongs to this bubble
NSInteger selectedComponentIndex = cellData.selectedComponentIndex;
if (selectedComponentIndex != NSNotFound)
{
[bubbleCell selectComponent:cellData.selectedComponentIndex showEditButton:NO showTimestamp:cellData.showTimestampForSelectedComponent];
}
else
{
bubbleCell.blurred = YES;
}
[[RoomTimelineConfiguration shared].currentStyle applySelectedStyleIfNeededToCell:bubbleCell cellData:cellData];
}
// Reset the marker if any
@@ -822,13 +668,24 @@ const CGFloat kTypingCellHeight = 24;
// We are interested only by outgoing messages
if ([cellData.senderId isEqualToString: self.mxSession.credentials.userId])
{
[bubbleCell updateTickViewWithFailedEventIds:self.failedEventIds];
[cellDecorator addSendStatusViewToCell:bubbleCell
withFailedEventIds:self.failedEventIds];
}
// Make extra cell layout updates if needed
[self updateCellLayoutIfNeeded:bubbleCell withCellData:cellData];
}
return cell;
}
- (void)updateCellLayoutIfNeeded:(MXKRoomBubbleTableViewCell*)cell withCellData:(MXKRoomBubbleCellData*)cellData {
RoomTimelineConfiguration *timelineConfiguration = [RoomTimelineConfiguration shared];
[timelineConfiguration.currentStyle.cellLayoutUpdater updateLayoutIfNeededFor:cell andCellData:cellData];
}
- (RoomBubbleCellData*)roomBubbleCellDataForEventId:(NSString*)eventId
{
id<MXKRoomBubbleCellDataStoring> cellData = [self cellDataOfEventWithEventId:eventId];
@@ -18,7 +18,7 @@ import UIKit
import Reusable
import Mapbox
class LocationUserMarkerView: MGLAnnotationView, NibLoadable {
class LocationMarkerView: MGLAnnotationView, NibLoadable {
@IBOutlet private var avatarView: UserAvatarView!
@@ -0,0 +1,76 @@
<?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" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
<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" insetsLayoutMarginsFromSafeArea="NO" id="iN0-l3-epB" customClass="LocationMarkerView" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="50" height="108"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="GS1-Cw-Ezx">
<rect key="frame" x="0.0" y="0.0" width="50" height="54"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="location_user_marker" translatesAutoresizingMaskIntoConstraints="NO" id="ldO-kc-R5W">
<rect key="frame" x="0.0" y="0.0" width="50" height="54"/>
<constraints>
<constraint firstAttribute="width" constant="50" id="41S-fj-tn4"/>
<constraint firstAttribute="height" constant="54" id="MAX-5E-xvS"/>
</constraints>
</imageView>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="location_marker_icon" translatesAutoresizingMaskIntoConstraints="NO" id="gQe-Hv-22e">
<rect key="frame" x="13" y="15" width="24" height="24"/>
<color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="width" constant="24" id="XuF-VU-qG2"/>
<constraint firstAttribute="height" constant="24" id="ejE-pC-umv"/>
</constraints>
</imageView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="qut-wn-BX3" customClass="UserAvatarView" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="2" y="2" width="46" height="46"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="46" id="BjG-I5-n8f"/>
<constraint firstAttribute="width" constant="46" id="W3F-Aw-FO3"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="ldO-kc-R5W" firstAttribute="top" secondItem="GS1-Cw-Ezx" secondAttribute="top" id="1cb-YG-bcI"/>
<constraint firstItem="ldO-kc-R5W" firstAttribute="leading" secondItem="GS1-Cw-Ezx" secondAttribute="leading" id="8I8-Zn-R5S"/>
<constraint firstItem="gQe-Hv-22e" firstAttribute="centerY" secondItem="GS1-Cw-Ezx" secondAttribute="centerY" id="EE9-rM-y0V"/>
<constraint firstItem="qut-wn-BX3" firstAttribute="centerY" secondItem="GS1-Cw-Ezx" secondAttribute="centerY" constant="-2" id="EQM-Hr-37h"/>
<constraint firstAttribute="trailing" secondItem="ldO-kc-R5W" secondAttribute="trailing" id="QUB-rY-t4j"/>
<constraint firstItem="qut-wn-BX3" firstAttribute="centerX" secondItem="GS1-Cw-Ezx" secondAttribute="centerX" id="XLg-Qs-yTR"/>
<constraint firstAttribute="bottom" secondItem="ldO-kc-R5W" secondAttribute="bottom" id="l4H-nN-44g"/>
<constraint firstItem="gQe-Hv-22e" firstAttribute="centerX" secondItem="GS1-Cw-Ezx" secondAttribute="centerX" id="syG-Kp-4F9"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="GS1-Cw-Ezx" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="61F-Ve-exC"/>
<constraint firstAttribute="trailing" secondItem="GS1-Cw-Ezx" secondAttribute="trailing" id="H8I-4T-A0M"/>
<constraint firstItem="GS1-Cw-Ezx" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="hhI-gR-E5z"/>
<constraint firstAttribute="bottom" secondItem="GS1-Cw-Ezx" secondAttribute="bottom" constant="54" id="mvD-6W-gMh"/>
</constraints>
<nil key="simulatedTopBarMetrics"/>
<nil key="simulatedBottomBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<connections>
<outlet property="avatarView" destination="qut-wn-BX3" id="wHA-bz-A2y"/>
</connections>
<point key="canvasLocation" x="58.695652173913047" y="4.6875"/>
</view>
</objects>
<resources>
<image name="location_marker_icon" width="24" height="24"/>
<image name="location_user_marker" width="51" height="54.5"/>
</resources>
</document>
@@ -1,46 +0,0 @@
<?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" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
<capability name="Safe area layout guides" minToolsVersion="9.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="iN0-l3-epB" customClass="LocationUserMarkerView" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="50" height="54"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="location_user_marker" translatesAutoresizingMaskIntoConstraints="NO" id="ldO-kc-R5W">
<rect key="frame" x="0.0" y="0.0" width="50" height="54"/>
</imageView>
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="qut-wn-BX3" customClass="UserAvatarView" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="2" y="2" width="46" height="46"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</view>
</subviews>
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="ldO-kc-R5W" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="VF5-CP-8eH"/>
<constraint firstItem="ldO-kc-R5W" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="Voc-LH-fTw"/>
<constraint firstAttribute="trailing" secondItem="ldO-kc-R5W" secondAttribute="trailing" id="Vt0-UN-s20"/>
<constraint firstAttribute="bottom" secondItem="ldO-kc-R5W" secondAttribute="bottom" id="Ybf-8x-UaG"/>
</constraints>
<nil key="simulatedTopBarMetrics"/>
<nil key="simulatedBottomBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<connections>
<outlet property="avatarView" destination="qut-wn-BX3" id="wHA-bz-A2y"/>
</connections>
<point key="canvasLocation" x="-84.057971014492765" y="-80.357142857142847"/>
</view>
</objects>
<resources>
<image name="location_user_marker" width="51" height="54.5"/>
</resources>
</document>
@@ -17,7 +17,6 @@
import UIKit
import Reusable
import Mapbox
import Keys
class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegate {
@@ -25,7 +24,6 @@ class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegat
private struct Constants {
static let mapHeight: CGFloat = 300.0
static let mapTilerKey = RiotKeys().mapTilerAPIKey
static let mapZoomLevel = 15.0
static let cellBorderRadius: CGFloat = 1.0
static let cellCornerRadius: CGFloat = 8.0
@@ -36,9 +34,10 @@ class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegat
@IBOutlet private var descriptionContainerView: UIView!
@IBOutlet private var descriptionLabel: UILabel!
@IBOutlet private var descriptionIcon: UIImageView!
private var mapView: MGLMapView!
private var annotationView: LocationUserMarkerView?
private var annotationView: LocationMarkerView?
// MARK: Public
@@ -73,19 +72,13 @@ class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegat
// MARK: - Public
public func displayLocation(_ location: CLLocationCoordinate2D,
userIdentifier: String,
userDisplayName: String,
userAvatarURLString: String?,
mediaManager: MXMediaManager) {
annotationView = LocationUserMarkerView.loadFromNib()
public func displayLocation(_ location: CLLocationCoordinate2D, userAvatarData: AvatarViewData? = nil) {
annotationView?.setAvatarData(AvatarViewData(matrixItemId: userIdentifier,
displayName: userDisplayName,
avatarUrl: userAvatarURLString,
mediaManager: mediaManager,
fallbackImage: .matrixItem(userIdentifier, userDisplayName)))
annotationView = LocationMarkerView.loadFromNib()
if let userAvatarData = userAvatarData {
annotationView?.setAvatarData(userAvatarData)
}
if let annotations = mapView.annotations {
mapView.removeAnnotations(annotations)
@@ -103,6 +96,7 @@ class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegat
func update(theme: Theme) {
descriptionLabel.textColor = theme.colors.primaryContent
descriptionLabel.font = theme.fonts.footnote
descriptionIcon.tintColor = theme.colors.accent
layer.borderColor = theme.colors.quinaryContent.cgColor
}
@@ -58,6 +58,7 @@
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<connections>
<outlet property="descriptionContainerView" destination="oVd-gS-Rmb" id="Npu-jp-oYo"/>
<outlet property="descriptionIcon" destination="GP2-dA-giJ" id="7YL-UU-ClT"/>
<outlet property="descriptionLabel" destination="c68-l7-McA" id="HiH-8Q-yTp"/>
</connections>
<point key="canvasLocation" x="165.94202898550725" y="-100.78125"/>
+447
View File
@@ -0,0 +1,447 @@
/*
Copyright 2015 OpenMarket Ltd
Copyright 2019 The Matrix.org Foundation C.I.C
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 <MatrixSDK/MatrixSDK.h>
#import "MXKViewController.h"
#import "MXKRoomDataSource.h"
#import "MXKRoomTitleView.h"
#import "MXKRoomInputToolbarView.h"
#import "MXKRoomActivitiesView.h"
#import "MXKEventDetailsView.h"
#import "MXKAttachmentsViewController.h"
#import "MXKAttachmentAnimator.h"
typedef NS_ENUM(NSUInteger, MXKRoomViewControllerJoinRoomResult) {
MXKRoomViewControllerJoinRoomResultSuccess,
MXKRoomViewControllerJoinRoomResultFailureRoomEmpty,
MXKRoomViewControllerJoinRoomResultFailureJoinInProgress,
MXKRoomViewControllerJoinRoomResultFailureGeneric
};
/**
This view controller displays messages of a room. Only one matrix session is handled by this view controller.
*/
@interface MXKRoomViewController : MXKViewController <MXKDataSourceDelegate, MXKRoomTitleViewDelegate, MXKRoomInputToolbarViewDelegate, UITableViewDelegate, UIDocumentInteractionControllerDelegate, MXKAttachmentsViewControllerDelegate, MXKRoomActivitiesViewDelegate, MXKSourceAttachmentAnimatorDelegate>
{
@protected
/**
The identifier of the current event displayed at the bottom of the table (just above the toolbar).
Use to anchor the message displayed at the bottom during table refresh.
*/
NSString *currentEventIdAtTableBottom;
/**
Boolean value used to scroll to bottom the bubble history after refresh.
*/
BOOL shouldScrollToBottomOnTableRefresh;
/**
Potential event details view.
*/
__weak MXKEventDetailsView *eventDetailsView;
/**
Current alert (if any).
*/
__weak UIAlertController *currentAlert;
/**
The document interaction Controller used to share attachment
*/
UIDocumentInteractionController *documentInteractionController;
/**
The current shared attachment.
*/
MXKAttachment *currentSharedAttachment;
/**
The potential text input placeholder is saved when it is replaced temporarily
*/
NSString *savedInputToolbarPlaceholder;
/**
Tell whether the input toolbar required to run an animation indicator.
*/
BOOL isInputToolbarProcessing;
/**
Tell whether a device rotation is in progress
*/
BOOL isSizeTransitionInProgress;
/**
The current visibility of the status bar in this view controller.
*/
BOOL isStatusBarHidden;
/**
YES to prevent `bubblesTableView` scrolling when calling -[setBubbleTableViewContentOffset:animated:]
*/
BOOL preventBubblesTableViewScroll;
}
/**
The current data source associated to the view controller.
*/
@property (nonatomic, readonly) MXKRoomDataSource *roomDataSource;
/**
Flag indicating if this instance has the memory ownership of its `roomDataSource`.
If YES, it will release it on [self destroy] call;
Default is NO.
*/
@property (nonatomic) BOOL hasRoomDataSourceOwnership;
/**
Tell whether the bubbles table view display is in transition. Its display is not warranty during the transition.
*/
@property (nonatomic, getter=isBubbleTableViewDisplayInTransition) BOOL bubbleTableViewDisplayInTransition;
/**
Tell whether the automatic events acknowledgement (based on read receipt) is enabled.
Default is YES.
*/
@property (nonatomic, getter=isEventsAcknowledgementEnabled) BOOL eventsAcknowledgementEnabled;
/**
Tell whether the room read marker must be updated when an event is acknowledged with a read receipt.
Default is NO.
*/
@property (nonatomic) BOOL updateRoomReadMarker;
/**
When the room view controller displays a room data source based on a timeline with an initial event,
the bubble table view content is scrolled by default to display the top of this event at the center of the screen
the first time it appears.
Use this property to force the table view to center its content on the bottom part of the event.
Default is NO.
*/
@property (nonatomic) BOOL centerBubblesTableViewContentOnTheInitialEventBottom;
/**
The current title view defined into the view controller.
*/
@property (nonatomic, weak, readonly) MXKRoomTitleView* titleView;
/**
The current input toolbar view defined into the view controller.
*/
@property (nonatomic, weak, readonly) MXKRoomInputToolbarView* inputToolbarView;
/**
The current extra info view defined into the view controller.
*/
@property (nonatomic, readonly) MXKRoomActivitiesView* activitiesView;
/**
The threshold used to trigger inconspicuous back pagination, or forwards pagination
for non live timeline. A pagination is triggered when the vertical content offset
is lower this threshold.
Default is 300.
*/
@property (nonatomic) NSUInteger paginationThreshold;
/**
The maximum number of messages to retrieve during a pagination. Default is 30.
*/
@property (nonatomic) NSUInteger paginationLimit;
/**
Enable/disable saving of the current typed text in message composer when view disappears.
The message composer is prefilled with this text when the room is opened again.
This property value is YES by default.
*/
@property BOOL saveProgressTextInput;
/**
The invited rooms can be automatically joined when the data source is ready.
This property enable/disable this option. Its value is YES by default.
*/
@property BOOL autoJoinInvitedRoom;
/**
Tell whether the room history is automatically scrolled to the most recent messages
when a keyboard is presented. YES by default.
This option is ignored when an alert is presented.
*/
@property BOOL scrollHistoryToTheBottomOnKeyboardPresentation;
/**
YES (default) to show actions button in document preview. NO otherwise.
*/
@property BOOL allowActionsInDocumentPreview;
/**
Duration of the animation in case of the composer needs to be resized (default 0.3s)
*/
@property NSTimeInterval resizeComposerAnimationDuration;
/**
This object is defined when the displayed room is left. It is added into the bubbles table header.
This label is used to display the reason why the room has been left.
*/
@property (nonatomic, weak, readonly) UILabel *leftRoomReasonLabel;
@property (weak, nonatomic) IBOutlet UITableView *bubblesTableView;
@property (weak, nonatomic) IBOutlet UIView *roomTitleViewContainer;
@property (weak, nonatomic) IBOutlet UIView *roomInputToolbarContainer;
@property (weak, nonatomic) IBOutlet UIView *roomActivitiesContainer;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *bubblesTableViewTopConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *bubblesTableViewBottomConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *roomActivitiesContainerHeightConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *roomInputToolbarContainerHeightConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *roomInputToolbarContainerBottomConstraint;
#pragma mark - Class methods
/**
Returns the `UINib` object initialized for a `MXKRoomViewController`.
@return The initialized `UINib` object or `nil` if there were errors during initialization
or the nib file could not be located.
@discussion You may override this method to provide a customized nib. If you do,
you should also override `roomViewController` to return your
view controller loaded from your custom nib.
*/
+ (UINib *)nib;
/**
Creates and returns a new `MXKRoomViewController` object.
@discussion This is the designated initializer for programmatic instantiation.
@return An initialized `MXKRoomViewController` object if successful, `nil` otherwise.
*/
+ (instancetype)roomViewController;
/**
Display a room.
@param dataSource the data source .
*/
- (void)displayRoom:(MXKRoomDataSource*)dataSource;
/**
This method is called when the associated data source is ready.
By default this operation triggers the initial back pagination when the user is an actual
member of the room (membership = join).
The invited rooms are automatically joined during this operation if 'autoJoinInvitedRoom' is YES.
When the room is successfully joined, an initial back pagination is triggered too.
Else nothing is done for the invited rooms.
Override it to customize the view controller behavior when the data source is ready.
*/
- (void)onRoomDataSourceReady;
/**
Update view controller appearance according to the state of its associated data source.
This method is called in the following use cases:
- on data source change (see `[MXKRoomViewController displayRoom:]`).
- on data source state change (see `[MXKDataSourceDelegate dataSource:didStateChange:]`)
- when view did appear.
The default implementation:
- show input toolbar view if the dataSource is defined and ready (`MXKDataSourceStateReady`), hide toolbar in others use cases.
- stop activity indicator if the dataSource is defined and ready (`MXKDataSourceStateReady`).
- update view controller title with room information.
Override it to customize view appearance according to data source state.
*/
- (void)updateViewControllerAppearanceOnRoomDataSourceState;
/**
This method is called when the associated data source has encountered an error on the timeline.
Override it to customize the view controller behavior.
@param notif the notification data sent with kMXKRoomDataSourceTimelineError notif.
*/
- (void)onTimelineError:(NSNotification *)notif;
/**
Join the current displayed room.
This operation fails if the user has already joined the room, or if the data source is not ready.
It fails if a join request is already running too.
@param completion the block to execute at the end of the operation.
You may specify nil for this parameter.
*/
- (void)joinRoom:(void(^)(MXKRoomViewControllerJoinRoomResult result))completion;
/**
Join a room with a room id or an alias.
This operation fails if the user has already joined the room, or if the data source is not ready,
or if the access to the room is forbidden to the user.
It fails if a join request is already running too.
@param roomIdOrAlias the id or the alias of the room to join.
@param viaServers The server names to try and join through in addition to those that are automatically chosen. It is optional and can be nil.
@param signUrl the signurl paramater passed with a 3PID invitation. It is optional and can be nil.
@param completion the block to execute at the end of the operation.
You may specify nil for this parameter.
*/
- (void)joinRoomWithRoomIdOrAlias:(NSString*)roomIdOrAlias
viaServers:(NSArray<NSString*>*)viaServers
andSignUrl:(NSString*)signUrl
completion:(void(^)(MXKRoomViewControllerJoinRoomResult result))completion;
/**
Update view controller appearance when the user is about to leave the displayed room.
This method is called when the user will leave the current room (see `kMXSessionWillLeaveRoomNotification`).
The default implementation:
- discard `roomDataSource`
- hide input toolbar view
- freeze the room title display
- add a label (`leftRoomReasonLabel`) in bubbles table header to display the reason why the room has been left.
Override it to customize view appearance, or to withdraw the view controller.
@param event the MXEvent responsible for the leaving.
*/
- (void)leaveRoomOnEvent:(MXEvent*)event;
/**
Register the class used to instantiate the title view which will handle the room name display.
The resulting view is added into 'roomTitleViewContainer' view, which must be defined before calling this method.
Note: By default the room name is displayed by using 'navigationItem.title' field of the view controller.
@param roomTitleViewClass a MXKRoomTitleView-inherited class.
*/
- (void)setRoomTitleViewClass:(Class)roomTitleViewClass;
/**
Register the class used to instantiate the input toolbar view which will handle message composer
and attachments selection for the room.
The resulting view is added into 'roomInputToolbarContainer' view, which must be defined before calling this method.
@param roomInputToolbarViewClass a MXKRoomInputToolbarView-inherited class, or nil to remove the current view.
*/
- (void)setRoomInputToolbarViewClass:(Class)roomInputToolbarViewClass;
/**
Register the class used to instantiate the extra info view.
The resulting view is added into 'roomActivitiesContainer' view, which must be defined before calling this method.
@param roomActivitiesViewClass a MXKRoomActivitiesViewClass-inherited class, or nil to remove the current view.
*/
- (void)setRoomActivitiesViewClass:(Class)roomActivitiesViewClass;
/**
Register the class used to instantiate the viewer dedicated to the attachments with thumbnail.
By default 'MXKAttachmentsViewController' class is used.
@param attachmentsViewerClass a MXKAttachmentsViewController-inherited class, or nil to restore the default class.
*/
- (void)setAttachmentsViewerClass:(Class)attachmentsViewerClass;
/**
Register the view class used to display the details of an event.
MXKEventDetailsView is used by default.
@param eventDetailsViewClass a MXKEventDetailsView-inherited class.
*/
- (void)setEventDetailsViewClass:(Class)eventDetailsViewClass;
/**
Detect and process potential IRC command in provided string.
@param string to analyse
@return YES if IRC style command has been detected and interpreted.
*/
- (BOOL)isIRCStyleCommand:(NSString*)string;
/**
Mention the member display name in the current text of the message composer.
The message composer becomes then the first responder.
*/
- (void)mention:(MXRoomMember*)roomMember;
/**
Force to dismiss keyboard if any
*/
- (void)dismissKeyboard;
/**
Tell whether the most recent message of the room history is visible.
*/
- (BOOL)isBubblesTableScrollViewAtTheBottom;
/**
Scroll the room history until the most recent message.
*/
- (void)scrollBubblesTableViewToBottomAnimated:(BOOL)animated;
/**
Dismiss the keyboard and all the potential subviews.
*/
- (void)dismissTemporarySubViews;
/**
Display a popup with the event detais.
@param event the event to inspect.
*/
- (void)showEventDetails:(MXEvent *)event;
/**
Present the attachments viewer by displaying the attachment of the provided cell.
@param cell the table view cell with attachment
*/
- (void)showAttachmentInCell:(UITableViewCell*)cell;
/**
Force a refresh of the room history display.
You should not call this method directly.
You may override it in inherited 'MXKRoomViewController' class.
@param useBottomAnchor tells whether the updated history must keep display the same event at the bottom.
@return a boolean value which tells whether the table has been scrolled to the bottom.
*/
- (BOOL)reloadBubblesTable:(BOOL)useBottomAnchor;
/**
Sets the offset from the content `bubblesTableView`'s origin. Take into account `preventBubblesTableViewScroll` value.
@param contentOffset Offset from the content `bubblesTableView`s origin.
@param animated YES to animate the transition.
*/
- (void)setBubbleTableViewContentOffset:(CGPoint)contentOffset animated:(BOOL)animated;
/**
Handle typing notification.
@param typing Flag indicating whether the user is typing or not.
*/
- (void)handleTypingNotification:(BOOL)typing;
@end
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11762" systemVersion="16C67" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="MXKRoomViewController">
<connections>
<outlet property="bubblesTableView" destination="BGD-sd-SQR" id="OG4-Tw-Ovt"/>
<outlet property="bubblesTableViewBottomConstraint" destination="Ksk-39-kfi" id="CTo-Ux-4NP"/>
<outlet property="bubblesTableViewTopConstraint" destination="X14-4s-uGM" id="Hic-6h-N05"/>
<outlet property="roomActivitiesContainer" destination="XX4-n6-hCm" id="uD0-ab-8s8"/>
<outlet property="roomActivitiesContainerHeightConstraint" destination="E8v-l2-8eV" id="ebD-oV-ttx"/>
<outlet property="roomInputToolbarContainer" destination="nLd-BP-JAE" id="1dp-P1-0js"/>
<outlet property="roomInputToolbarContainerBottomConstraint" destination="kQ6-Cg-FMi" id="nHr-fR-XnV"/>
<outlet property="roomInputToolbarContainerHeightConstraint" destination="5eD-Fm-RDb" id="6ny-5w-1UA"/>
<outlet property="view" destination="iN0-l3-epB" id="ieV-u7-rXU"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" keyboardDismissMode="interactive" style="plain" separatorStyle="none" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" translatesAutoresizingMaskIntoConstraints="NO" id="BGD-sd-SQR">
<rect key="frame" x="0.0" y="0.0" width="375" height="626"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</tableView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="XX4-n6-hCm" userLabel="Activities Container">
<rect key="frame" x="0.0" y="606" width="375" height="20"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="20" id="E8v-l2-8eV"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="nLd-BP-JAE" userLabel="Room Input Toolbar Container">
<rect key="frame" x="0.0" y="626" width="375" height="41"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="41" id="5eD-Fm-RDb"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="BGD-sd-SQR" secondAttribute="trailing" id="0la-ok-MBr"/>
<constraint firstItem="nLd-BP-JAE" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="4Q7-hr-rqi"/>
<constraint firstAttribute="bottom" secondItem="BGD-sd-SQR" secondAttribute="bottom" constant="41" id="Ksk-39-kfi"/>
<constraint firstItem="XX4-n6-hCm" firstAttribute="bottom" secondItem="nLd-BP-JAE" secondAttribute="top" id="QO8-nF-xys"/>
<constraint firstItem="XX4-n6-hCm" firstAttribute="width" secondItem="iN0-l3-epB" secondAttribute="width" id="WhE-lH-ZtR"/>
<constraint firstItem="BGD-sd-SQR" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="X14-4s-uGM"/>
<constraint firstAttribute="trailing" secondItem="nLd-BP-JAE" secondAttribute="trailing" id="YAu-gd-ItG"/>
<constraint firstItem="XX4-n6-hCm" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="csl-KT-4s9"/>
<constraint firstItem="BGD-sd-SQR" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="haP-Kv-OLI"/>
<constraint firstAttribute="bottom" secondItem="nLd-BP-JAE" secondAttribute="bottom" id="kQ6-Cg-FMi"/>
</constraints>
<nil key="simulatedStatusBarMetrics"/>
</view>
</objects>
</document>
+1 -1
View File
@@ -134,7 +134,7 @@ final class RoomCoordinator: NSObject, RoomCoordinatorProtocol {
self.selectedEventId = eventId
if self.hasStartedOnce {
self.roomViewController.highlightEvent(eventId, completion: completion)
self.roomViewController.highlightAndDisplayEvent(eventId, completion: completion)
} else {
self.start(withCompletion: completion)
}
+1 -1
View File
@@ -106,7 +106,7 @@ extern NSNotificationName const RoomGroupCallTileTappedNotification;
@param eventId Identifier of the event to be highlighted.
@param completion Completion block to be called at the end of process. Optional.
*/
- (void)highlightEvent:(NSString *)eventId completion:(nullable void (^)(void))completion;
- (void)highlightAndDisplayEvent:(NSString *)eventId completion:(nullable void (^)(void))completion;
/**
Creates and returns a new `RoomViewController` object.
+92 -238
View File
@@ -54,55 +54,7 @@
#import "JitsiViewController.h"
#import "RoomEmptyBubbleCell.h"
#import "RoomIncomingTextMsgBubbleCell.h"
#import "RoomIncomingTextMsgWithoutSenderInfoBubbleCell.h"
#import "RoomIncomingTextMsgWithPaginationTitleBubbleCell.h"
#import "RoomIncomingTextMsgWithoutSenderNameBubbleCell.h"
#import "RoomIncomingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.h"
#import "RoomIncomingAttachmentBubbleCell.h"
#import "RoomIncomingAttachmentWithoutSenderInfoBubbleCell.h"
#import "RoomIncomingAttachmentWithPaginationTitleBubbleCell.h"
#import "RoomIncomingEncryptedTextMsgBubbleCell.h"
#import "RoomIncomingEncryptedTextMsgWithoutSenderInfoBubbleCell.h"
#import "RoomIncomingEncryptedTextMsgWithPaginationTitleBubbleCell.h"
#import "RoomIncomingEncryptedTextMsgWithoutSenderNameBubbleCell.h"
#import "RoomIncomingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.h"
#import "RoomIncomingEncryptedAttachmentBubbleCell.h"
#import "RoomIncomingEncryptedAttachmentWithoutSenderInfoBubbleCell.h"
#import "RoomIncomingEncryptedAttachmentWithPaginationTitleBubbleCell.h"
#import "RoomOutgoingTextMsgBubbleCell.h"
#import "RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.h"
#import "RoomOutgoingTextMsgWithPaginationTitleBubbleCell.h"
#import "RoomOutgoingTextMsgWithoutSenderNameBubbleCell.h"
#import "RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.h"
#import "RoomOutgoingAttachmentBubbleCell.h"
#import "RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.h"
#import "RoomOutgoingAttachmentWithPaginationTitleBubbleCell.h"
#import "RoomOutgoingEncryptedTextMsgBubbleCell.h"
#import "RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.h"
#import "RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell.h"
#import "RoomOutgoingEncryptedTextMsgWithoutSenderNameBubbleCell.h"
#import "RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.h"
#import "RoomOutgoingEncryptedAttachmentBubbleCell.h"
#import "RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.h"
#import "RoomOutgoingEncryptedAttachmentWithPaginationTitleBubbleCell.h"
#import "RoomMembershipBubbleCell.h"
#import "RoomMembershipWithPaginationTitleBubbleCell.h"
#import "RoomMembershipCollapsedBubbleCell.h"
#import "RoomMembershipCollapsedWithPaginationTitleBubbleCell.h"
#import "RoomMembershipExpandedBubbleCell.h"
#import "RoomMembershipExpandedWithPaginationTitleBubbleCell.h"
#import "RoomCreationWithPaginationCollapsedBubbleCell.h"
#import "RoomCreationCollapsedBubbleCell.h"
#import "RoomSelectedStickerBubbleCell.h"
#import "RoomPredecessorBubbleCell.h"
#import "MXKRoomBubbleTableViewCell+Riot.h"
#import "AvatarGenerator.h"
@@ -130,6 +82,8 @@
#import "MXSDKOptions.h"
#import "RoomTimelineCellProvider.h"
#import "GeneratedInterface-Swift.h"
NSNotificationName const RoomCallTileTappedNotification = @"RoomCallTileTappedNotification";
@@ -139,7 +93,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
@interface RoomViewController () <UISearchBarDelegate, UIGestureRecognizerDelegate, UIScrollViewAccessibilityDelegate, RoomTitleViewTapGestureDelegate, RoomParticipantsViewControllerDelegate, MXKRoomMemberDetailsViewControllerDelegate, ContactsTableViewControllerDelegate, MXServerNoticesDelegate, RoomContextualMenuViewControllerDelegate,
ReactionsMenuViewModelCoordinatorDelegate, EditHistoryCoordinatorBridgePresenterDelegate, MXKDocumentPickerPresenterDelegate, EmojiPickerCoordinatorBridgePresenterDelegate,
ReactionHistoryCoordinatorBridgePresenterDelegate, CameraPresenterDelegate, MediaPickerCoordinatorBridgePresenterDelegate,
RoomDataSourceDelegate, RoomCreationModalCoordinatorBridgePresenterDelegate, RoomInfoCoordinatorBridgePresenterDelegate, DialpadViewControllerDelegate, RemoveJitsiWidgetViewDelegate, VoiceMessageControllerDelegate, SpaceDetailPresenterDelegate, UserSuggestionCoordinatorBridgeDelegate, RoomCoordinatorBridgePresenterDelegate, ThreadsCoordinatorBridgePresenterDelegate, MXThreadingServiceDelegate>
RoomDataSourceDelegate, RoomCreationModalCoordinatorBridgePresenterDelegate, RoomInfoCoordinatorBridgePresenterDelegate, DialpadViewControllerDelegate, RemoveJitsiWidgetViewDelegate, VoiceMessageControllerDelegate, SpaceDetailPresenterDelegate, UserSuggestionCoordinatorBridgeDelegate, ThreadsCoordinatorBridgePresenterDelegate, MXThreadingServiceDelegate>
{
// The preview header
@@ -246,9 +200,8 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
@property (nonatomic, strong) RoomMessageURLParser *roomMessageURLParser;
@property (nonatomic, strong) RoomCreationModalCoordinatorBridgePresenter *roomCreationModalCoordinatorBridgePresenter;
@property (nonatomic, strong) RoomInfoCoordinatorBridgePresenter *roomInfoCoordinatorBridgePresenter;
@property (nonatomic, strong) RoomCoordinatorBridgePresenter *threadBridgePresenter;
@property (nonatomic, strong) CustomSizedPresentationController *customSizedPresentationController;
@property (nonatomic, strong) ThreadsCoordinatorBridgePresenter *threadsCoordinatorBridgePresenter;
@property (nonatomic, strong) ThreadsCoordinatorBridgePresenter *threadsBridgePresenter;
@property (nonatomic, getter=isActivitiesViewExpanded) BOOL activitiesViewExpanded;
@property (nonatomic, getter=isScrollToBottomHidden) BOOL scrollToBottomHidden;
@property (nonatomic, getter=isMissedDiscussionsBadgeHidden) BOOL missedDiscussionsBadgeHidden;
@@ -372,83 +325,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
[super viewDidLoad];
// Register first customized cell view classes used to render bubbles
[self.bubblesTableView registerClass:RoomIncomingTextMsgBubbleCell.class forCellReuseIdentifier:RoomIncomingTextMsgBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomIncomingTextMsgWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomIncomingTextMsgWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomIncomingTextMsgWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomIncomingTextMsgWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomIncomingAttachmentBubbleCell.class forCellReuseIdentifier:RoomIncomingAttachmentBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomIncomingAttachmentWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomIncomingAttachmentWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomIncomingAttachmentWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomIncomingAttachmentWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomIncomingTextMsgWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomIncomingTextMsgWithoutSenderNameBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomIncomingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomIncomingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomIncomingEncryptedTextMsgBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedTextMsgBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomIncomingEncryptedTextMsgWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedTextMsgWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomIncomingEncryptedTextMsgWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedTextMsgWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomIncomingEncryptedAttachmentBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedAttachmentBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomIncomingEncryptedAttachmentWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedAttachmentWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomIncomingEncryptedAttachmentWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedAttachmentWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomIncomingEncryptedTextMsgWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedTextMsgWithoutSenderNameBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomIncomingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomOutgoingAttachmentBubbleCell.class forCellReuseIdentifier:RoomOutgoingAttachmentBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomOutgoingAttachmentWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomOutgoingAttachmentWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomOutgoingTextMsgBubbleCell.class forCellReuseIdentifier:RoomOutgoingTextMsgBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomOutgoingTextMsgWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomOutgoingTextMsgWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomOutgoingTextMsgWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomOutgoingTextMsgWithoutSenderNameBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomOutgoingEncryptedAttachmentBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedAttachmentBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomOutgoingEncryptedAttachmentWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedAttachmentWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomOutgoingEncryptedTextMsgBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedTextMsgBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomOutgoingEncryptedTextMsgWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedTextMsgWithoutSenderNameBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomEmptyBubbleCell.class forCellReuseIdentifier:RoomEmptyBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomMembershipBubbleCell.class forCellReuseIdentifier:RoomMembershipBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomMembershipWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomMembershipWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomMembershipCollapsedBubbleCell.class forCellReuseIdentifier:RoomMembershipCollapsedBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomMembershipCollapsedWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomMembershipCollapsedWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomMembershipExpandedBubbleCell.class forCellReuseIdentifier:RoomMembershipExpandedBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomMembershipExpandedWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomMembershipExpandedWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomSelectedStickerBubbleCell.class forCellReuseIdentifier:RoomSelectedStickerBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomPredecessorBubbleCell.class forCellReuseIdentifier:RoomPredecessorBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:KeyVerificationIncomingRequestApprovalBubbleCell.class forCellReuseIdentifier:KeyVerificationIncomingRequestApprovalBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell.class forCellReuseIdentifier:KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:KeyVerificationRequestStatusBubbleCell.class forCellReuseIdentifier:KeyVerificationRequestStatusBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:KeyVerificationRequestStatusWithPaginationTitleBubbleCell.class forCellReuseIdentifier:KeyVerificationRequestStatusWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:KeyVerificationConclusionBubbleCell.class forCellReuseIdentifier:KeyVerificationConclusionBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:KeyVerificationConclusionWithPaginationTitleBubbleCell.class forCellReuseIdentifier:KeyVerificationConclusionWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomCreationCollapsedBubbleCell.class forCellReuseIdentifier:RoomCreationCollapsedBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomCreationWithPaginationCollapsedBubbleCell.class forCellReuseIdentifier:RoomCreationWithPaginationCollapsedBubbleCell.defaultReuseIdentifier];
// call cells
[self.bubblesTableView registerClass:RoomDirectCallStatusBubbleCell.class forCellReuseIdentifier:RoomDirectCallStatusBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomGroupCallStatusBubbleCell.class forCellReuseIdentifier:RoomGroupCallStatusBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:RoomCreationIntroCell.class forCellReuseIdentifier:RoomCreationIntroCell.defaultReuseIdentifier];
[self.bubblesTableView registerNib:RoomTypingBubbleCell.nib forCellReuseIdentifier:RoomTypingBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:VoiceMessageBubbleCell.class forCellReuseIdentifier:VoiceMessageBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:VoiceMessageWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:VoiceMessageWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:VoiceMessageWithPaginationTitleBubbleCell.class forCellReuseIdentifier:VoiceMessageWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:PollBubbleCell.class forCellReuseIdentifier:PollBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:PollWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:PollWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:PollWithPaginationTitleBubbleCell.class forCellReuseIdentifier:PollWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:LocationBubbleCell.class forCellReuseIdentifier:LocationBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:LocationWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:LocationWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[self.bubblesTableView registerClass:LocationWithPaginationTitleBubbleCell.class forCellReuseIdentifier:LocationWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[[RoomTimelineConfiguration shared].currentStyle.cellProvider registerCellsForTableView:self.bubblesTableView];
[self vc_removeBackTitle];
@@ -2271,6 +2148,8 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
[MXSDKOptions sharedInstance].videoConversionPresetName = presetName;
[roomInputToolbarView sendSelectedVideoAsset:videoAsset isPhotoLibraryAsset:isPhotoLibraryAsset];
}];
compressionPrompt.popoverPresentationController.sourceView = roomInputToolbarView.attachMediaButton;
compressionPrompt.popoverPresentationController.sourceRect = roomInputToolbarView.attachMediaButton.bounds;
[self presentViewController:compressionPrompt animated:YES completion:nil];
}
@@ -2733,14 +2612,23 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
- (Class<MXKCellRendering>)cellViewClassForCellData:(MXKCellData*)cellData
{
Class cellViewClass = nil;
BOOL showEncryptionBadge = NO;
RoomTimelineCellIdentifier cellIdentifier = [self cellIdentifierForCellData:cellData andRoomDataSource:customizedRoomDataSource];
RoomTimelineConfiguration *timelineConfiguration = [RoomTimelineConfiguration shared];
return [timelineConfiguration.currentStyle.cellProvider cellViewClassForCellIdentifier:cellIdentifier];;
}
- (RoomTimelineCellIdentifier)cellIdentifierForCellData:(MXKCellData*)cellData andRoomDataSource:(RoomDataSource *)customizedRoomDataSource;
{
// Sanity check
if (![cellData conformsToProtocol:@protocol(MXKRoomBubbleCellDataStoring)])
{
return nil;
return RoomTimelineCellIdentifierUnknown;
}
BOOL showEncryptionBadge = NO;
RoomTimelineCellIdentifier cellIdentifier;
id<MXKRoomBubbleCellDataStoring> bubbleData = (id<MXKRoomBubbleCellDataStoring>)cellData;
@@ -2755,27 +2643,27 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
// Select the suitable table view cell class, by considering first the empty bubble cell.
if (bubbleData.hasNoDisplay)
{
cellViewClass = RoomEmptyBubbleCell.class;
cellIdentifier = RoomTimelineCellIdentifierEmpty;
}
else if (bubbleData.tag == RoomBubbleCellDataTagRoomCreationIntro)
{
cellViewClass = RoomCreationIntroCell.class;
cellIdentifier = RoomTimelineCellIdentifierRoomCreationIntro;
}
else if (bubbleData.tag == RoomBubbleCellDataTagRoomCreateWithPredecessor)
{
cellViewClass = RoomPredecessorBubbleCell.class;
cellIdentifier = RoomTimelineCellIdentifierRoomPredecessor;
}
else if (bubbleData.tag == RoomBubbleCellDataTagKeyVerificationRequestIncomingApproval)
{
cellViewClass = bubbleData.isPaginationFirstBubble ? KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell.class : KeyVerificationIncomingRequestApprovalBubbleCell.class;
cellIdentifier = bubbleData.isPaginationFirstBubble ? RoomTimelineCellIdentifierKeyVerificationIncomingRequestApprovalWithPaginationTitle : RoomTimelineCellIdentifierKeyVerificationIncomingRequestApproval;
}
else if (bubbleData.tag == RoomBubbleCellDataTagKeyVerificationRequest)
{
cellViewClass = bubbleData.isPaginationFirstBubble ? KeyVerificationRequestStatusWithPaginationTitleBubbleCell.class : KeyVerificationRequestStatusBubbleCell.class;
cellIdentifier = bubbleData.isPaginationFirstBubble ? RoomTimelineCellIdentifierKeyVerificationRequestStatusWithPaginationTitle : RoomTimelineCellIdentifierKeyVerificationRequestStatus;
}
else if (bubbleData.tag == RoomBubbleCellDataTagKeyVerificationConclusion)
{
cellViewClass = bubbleData.isPaginationFirstBubble ? KeyVerificationConclusionWithPaginationTitleBubbleCell.class : KeyVerificationConclusionBubbleCell.class;
cellIdentifier = bubbleData.isPaginationFirstBubble ? RoomTimelineCellIdentifierKeyVerificationConclusionWithPaginationTitle : RoomTimelineCellIdentifierKeyVerificationConclusion;
}
else if (bubbleData.tag == RoomBubbleCellDataTagMembership)
{
@@ -2783,80 +2671,80 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
{
if (bubbleData.nextCollapsableCellData)
{
cellViewClass = bubbleData.isPaginationFirstBubble ? RoomMembershipCollapsedWithPaginationTitleBubbleCell.class : RoomMembershipCollapsedBubbleCell.class;
cellIdentifier = bubbleData.isPaginationFirstBubble ? RoomTimelineCellIdentifierMembershipCollapsedWithPaginationTitle : RoomTimelineCellIdentifierMembershipCollapsed;
}
else
{
// Use a normal membership cell for a single membership event
cellViewClass = bubbleData.isPaginationFirstBubble ? RoomMembershipWithPaginationTitleBubbleCell.class : RoomMembershipBubbleCell.class;
cellIdentifier = bubbleData.isPaginationFirstBubble ? RoomTimelineCellIdentifierMembershipWithPaginationTitle : RoomTimelineCellIdentifierMembership;
}
}
else if (bubbleData.collapsedAttributedTextMessage)
{
// The cell (and its series) is not collapsed but this cell is the first
// of the series. So, use the cell with the "collapse" button.
cellViewClass = bubbleData.isPaginationFirstBubble ? RoomMembershipExpandedWithPaginationTitleBubbleCell.class : RoomMembershipExpandedBubbleCell.class;
cellIdentifier = bubbleData.isPaginationFirstBubble ? RoomTimelineCellIdentifierMembershipExpandedWithPaginationTitle : RoomTimelineCellIdentifierMembershipExpanded;
}
else
{
cellViewClass = bubbleData.isPaginationFirstBubble ? RoomMembershipWithPaginationTitleBubbleCell.class : RoomMembershipBubbleCell.class;
cellIdentifier = bubbleData.isPaginationFirstBubble ? RoomTimelineCellIdentifierMembershipWithPaginationTitle : RoomTimelineCellIdentifierMembership;
}
}
else if (bubbleData.tag == RoomBubbleCellDataTagRoomCreateConfiguration)
{
cellViewClass = bubbleData.isPaginationFirstBubble ? RoomCreationWithPaginationCollapsedBubbleCell.class : RoomCreationCollapsedBubbleCell.class;
cellIdentifier = bubbleData.isPaginationFirstBubble ? RoomTimelineCellIdentifierRoomCreationCollapsedWithPaginationTitle : RoomTimelineCellIdentifierRoomCreationCollapsed;
}
else if (bubbleData.tag == RoomBubbleCellDataTagCall)
{
cellViewClass = RoomDirectCallStatusBubbleCell.class;
cellIdentifier = RoomTimelineCellIdentifierDirectCallStatus;
}
else if (bubbleData.tag == RoomBubbleCellDataTagGroupCall)
{
cellViewClass = RoomGroupCallStatusBubbleCell.class;
cellIdentifier = RoomTimelineCellIdentifierGroupCallStatus;
}
else if (bubbleData.attachment.type == MXKAttachmentTypeVoiceMessage || bubbleData.attachment.type == MXKAttachmentTypeAudio)
{
if (bubbleData.isPaginationFirstBubble)
{
cellViewClass = VoiceMessageWithPaginationTitleBubbleCell.class;
cellIdentifier = RoomTimelineCellIdentifierVoiceMessageWithPaginationTitle;
}
else if (bubbleData.shouldHideSenderInformation)
{
cellViewClass = VoiceMessageWithoutSenderInfoBubbleCell.class;
cellIdentifier = RoomTimelineCellIdentifierVoiceMessageWithoutSenderInfo;
}
else
{
cellViewClass = VoiceMessageBubbleCell.class;
cellIdentifier = RoomTimelineCellIdentifierVoiceMessage;
}
}
else if (bubbleData.tag == RoomBubbleCellDataTagPoll)
{
if (bubbleData.isPaginationFirstBubble)
{
cellViewClass = PollWithPaginationTitleBubbleCell.class;
cellIdentifier = RoomTimelineCellIdentifierPollWithPaginationTitle;
}
else if (bubbleData.shouldHideSenderInformation)
{
cellViewClass = PollWithoutSenderInfoBubbleCell.class;
cellIdentifier = RoomTimelineCellIdentifierPollWithoutSenderInfo;
}
else
{
cellViewClass = PollBubbleCell.class;
cellIdentifier = RoomTimelineCellIdentifierPoll;
}
}
else if (bubbleData.tag == RoomBubbleCellDataTagLocation)
{
if (bubbleData.isPaginationFirstBubble)
{
cellViewClass = LocationWithPaginationTitleBubbleCell.class;
cellIdentifier = RoomTimelineCellIdentifierLocationWithPaginationTitle;
}
else if (bubbleData.shouldHideSenderInformation)
{
cellViewClass = LocationWithoutSenderInfoBubbleCell.class;
cellIdentifier = RoomTimelineCellIdentifierLocationWithoutSenderInfo;
}
else
{
cellViewClass = LocationBubbleCell.class;
cellIdentifier = RoomTimelineCellIdentifierLocation;
}
}
else if (bubbleData.isIncoming)
@@ -2866,19 +2754,19 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
// Check whether the provided celldata corresponds to a selected sticker
if (customizedRoomDataSource.selectedEventId && (bubbleData.attachment.type == MXKAttachmentTypeSticker) && [bubbleData.attachment.eventId isEqualToString:customizedRoomDataSource.selectedEventId])
{
cellViewClass = RoomSelectedStickerBubbleCell.class;
cellIdentifier = RoomTimelineCellIdentifierSelectedSticker;
}
else if (bubbleData.isPaginationFirstBubble)
{
cellViewClass = showEncryptionBadge ? RoomIncomingEncryptedAttachmentWithPaginationTitleBubbleCell.class : RoomIncomingAttachmentWithPaginationTitleBubbleCell.class;
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierIncomingAttachmentEncryptedWithPaginationTitle : RoomTimelineCellIdentifierIncomingAttachmentWithPaginationTitle;
}
else if (bubbleData.shouldHideSenderInformation)
{
cellViewClass = showEncryptionBadge ? RoomIncomingEncryptedAttachmentWithoutSenderInfoBubbleCell.class : RoomIncomingAttachmentWithoutSenderInfoBubbleCell.class;
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierIncomingAttachmentEncryptedWithoutSenderInfo : RoomTimelineCellIdentifierIncomingAttachmentWithoutSenderInfo;
}
else
{
cellViewClass = showEncryptionBadge ? RoomIncomingEncryptedAttachmentBubbleCell.class : RoomIncomingAttachmentBubbleCell.class;
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierIncomingAttachmentEncrypted : RoomTimelineCellIdentifierIncomingAttachment;
}
}
else
@@ -2887,24 +2775,24 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
{
if (bubbleData.shouldHideSenderName)
{
cellViewClass = showEncryptionBadge ? RoomIncomingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class : RoomIncomingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class;
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithPaginationTitleWithoutSenderName : RoomTimelineCellIdentifierIncomingTextMessageWithPaginationTitleWithoutSenderName;
}
else
{
cellViewClass = showEncryptionBadge ? RoomIncomingEncryptedTextMsgWithPaginationTitleBubbleCell.class : RoomIncomingTextMsgWithPaginationTitleBubbleCell.class;
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithPaginationTitle : RoomTimelineCellIdentifierIncomingTextMessageWithPaginationTitle;
}
}
else if (bubbleData.shouldHideSenderInformation)
{
cellViewClass = showEncryptionBadge ? RoomIncomingEncryptedTextMsgWithoutSenderInfoBubbleCell.class : RoomIncomingTextMsgWithoutSenderInfoBubbleCell.class;
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithoutSenderInfo : RoomTimelineCellIdentifierIncomingTextMessageWithoutSenderInfo;
}
else if (bubbleData.shouldHideSenderName)
{
cellViewClass = showEncryptionBadge ? RoomIncomingEncryptedTextMsgWithoutSenderNameBubbleCell.class : RoomIncomingTextMsgWithoutSenderNameBubbleCell.class;
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithoutSenderName : RoomTimelineCellIdentifierIncomingTextMessageWithoutSenderName;
}
else
{
cellViewClass = showEncryptionBadge ? RoomIncomingEncryptedTextMsgBubbleCell.class : RoomIncomingTextMsgBubbleCell.class;
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierIncomingTextMessageEncrypted : RoomTimelineCellIdentifierIncomingTextMessage;
}
}
}
@@ -2916,19 +2804,19 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
// Check whether the provided celldata corresponds to a selected sticker
if (customizedRoomDataSource.selectedEventId && (bubbleData.attachment.type == MXKAttachmentTypeSticker) && [bubbleData.attachment.eventId isEqualToString:customizedRoomDataSource.selectedEventId])
{
cellViewClass = RoomSelectedStickerBubbleCell.class;
cellIdentifier = RoomTimelineCellIdentifierSelectedSticker;
}
else if (bubbleData.isPaginationFirstBubble)
{
cellViewClass = showEncryptionBadge ? RoomOutgoingEncryptedAttachmentWithPaginationTitleBubbleCell.class :RoomOutgoingAttachmentWithPaginationTitleBubbleCell.class;
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierOutgoingAttachmentEncryptedWithPaginationTitle : RoomTimelineCellIdentifierOutgoingAttachmentWithPaginationTitle;
}
else if (bubbleData.shouldHideSenderInformation)
{
cellViewClass = showEncryptionBadge ? RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.class : RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.class;
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierOutgoingAttachmentEncryptedWithoutSenderInfo : RoomTimelineCellIdentifierOutgoingAttachmentWithoutSenderInfo;
}
else
{
cellViewClass = showEncryptionBadge ? RoomOutgoingEncryptedAttachmentBubbleCell.class : RoomOutgoingAttachmentBubbleCell.class;
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierOutgoingAttachmentEncrypted : RoomTimelineCellIdentifierOutgoingAttachment;
}
}
else
@@ -2937,29 +2825,29 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
{
if (bubbleData.shouldHideSenderName)
{
cellViewClass = showEncryptionBadge ? RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class : RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class;
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithPaginationTitleWithoutSenderName : RoomTimelineCellIdentifierOutgoingTextMessageWithPaginationTitleWithoutSenderName;
}
else
{
cellViewClass = showEncryptionBadge ? RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell.class : RoomOutgoingTextMsgWithPaginationTitleBubbleCell.class;
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithPaginationTitle : RoomTimelineCellIdentifierOutgoingTextMessageWithPaginationTitle;
}
}
else if (bubbleData.shouldHideSenderInformation)
{
cellViewClass = showEncryptionBadge ? RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.class :RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.class;
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithoutSenderInfo : RoomTimelineCellIdentifierOutgoingTextMessageWithoutSenderInfo;
}
else if (bubbleData.shouldHideSenderName)
{
cellViewClass = showEncryptionBadge ? RoomOutgoingEncryptedTextMsgWithoutSenderNameBubbleCell.class : RoomOutgoingTextMsgWithoutSenderNameBubbleCell.class;
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithoutSenderName : RoomTimelineCellIdentifierOutgoingTextMessageWithoutSenderName;
}
else
{
cellViewClass = showEncryptionBadge ? RoomOutgoingEncryptedTextMsgBubbleCell.class : RoomOutgoingTextMsgBubbleCell.class;
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierOutgoingTextMessageEncrypted : RoomTimelineCellIdentifierOutgoingTextMessage;
}
}
}
return cellViewClass;
return cellIdentifier;
}
#pragma mark - MXKDataSource delegate
@@ -3426,6 +3314,9 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
MXStrongifyAndReturnIfNil(self);
[self cancelEventSelection];
[self presentEventForwardingDialogForSelectedEvent:selectedEvent];
}]];
}
@@ -3455,6 +3346,9 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
MXStrongifyAndReturnIfNil(self);
[self cancelEventSelection];
[self presentEventForwardingDialogForSelectedEvent:selectedEvent];
}]];
}
@@ -3496,6 +3390,9 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
MXStrongifyAndReturnIfNil(self);
[self cancelEventSelection];
[self presentEventForwardingDialogForSelectedEvent:selectedEvent];
}]];
}
@@ -3657,10 +3554,11 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
// Create a matrix.to permalink that is common to all matrix clients
NSString *permalink = [MXTools permalinkToEvent:selectedEvent.eventId inRoom:selectedEvent.roomId];
NSURL *url = [NSURL URLWithString:permalink];
if (permalink)
if (url)
{
MXKPasteboardManager.shared.pasteboard.string = permalink;
MXKPasteboardManager.shared.pasteboard.URL = url;
[self.view vc_toastWithMessage:VectorL10n.roomEventCopyLinkInfo
image:[UIImage imageNamed:@"link_icon"]
duration:2.0
@@ -3711,24 +3609,21 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
if (selectedEvent.eventType != MXEventTypeRoomEncryption)
{
NSString *title;
UIAlertActionStyle style;
EventMenuItemType itemType;
if (selectedEvent.eventType == MXEventTypePollStart)
{
title = [VectorL10n roomEventActionRemovePoll];
style = UIAlertActionStyleDefault;
itemType = EventMenuItemTypeRemovePoll;
}
else
{
title = [VectorL10n roomEventActionRedact];
style = UIAlertActionStyleDestructive;
itemType = EventMenuItemTypeRemove;
}
[self.eventMenuBuilder addItemWithType:itemType
action:[UIAlertAction actionWithTitle:title
style:style
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction * action) {
MXStrongifyAndReturnIfNil(self);
@@ -4545,10 +4440,11 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
- (IBAction)onThreadListTapped:(id)sender
{
self.threadsCoordinatorBridgePresenter = [[ThreadsCoordinatorBridgePresenter alloc] initWithSession:self.mainSession
roomId:self.roomDataSource.roomId];
self.threadsCoordinatorBridgePresenter.delegate = self;
[self.threadsCoordinatorBridgePresenter pushFrom:self.navigationController animated:YES];
self.threadsBridgePresenter = [[ThreadsCoordinatorBridgePresenter alloc] initWithSession:self.mainSession
roomId:self.roomDataSource.roomId
threadId:nil];
self.threadsBridgePresenter.delegate = self;
[self.threadsBridgePresenter pushFrom:self.navigationController animated:YES];
}
- (IBAction)onIntegrationsPressed:(id)sender
@@ -6571,25 +6467,20 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
- (void)openThreadWithId:(NSString *)threadId
{
if (self.threadBridgePresenter)
if (self.threadsBridgePresenter)
{
[self.threadBridgePresenter dismissWithAnimated:YES completion:nil];
self.threadBridgePresenter = nil;
[self.threadsBridgePresenter dismissWithAnimated:YES completion:nil];
self.threadsBridgePresenter = nil;
}
RoomDisplayConfiguration *configuration = RoomDisplayConfiguration.forThreads;
RoomCoordinatorBridgePresenterParameters *parameters = [[RoomCoordinatorBridgePresenterParameters alloc] initWithSession:self.mainSession
roomId:self.roomDataSource.roomId
eventId:nil
threadId:threadId
displayConfiguration:configuration
previewData:nil];
self.threadBridgePresenter = [[RoomCoordinatorBridgePresenter alloc] initWithParameters:parameters];
self.threadBridgePresenter.delegate = self;
[self.threadBridgePresenter pushFrom:self.navigationController animated:YES];
self.threadsBridgePresenter = [[ThreadsCoordinatorBridgePresenter alloc] initWithSession:self.mainSession
roomId:self.roomDataSource.roomId
threadId:threadId];
self.threadsBridgePresenter.delegate = self;
[self.threadsBridgePresenter pushFrom:self.navigationController animated:YES];
}
- (void)highlightEvent:(NSString *)eventId completion:(void (^)(void))completion
- (void)highlightAndDisplayEvent:(NSString *)eventId completion:(void (^)(void))completion
{
NSInteger row = [self.roomDataSource indexOfCellDataWithEventId:eventId];
if (row == NSNotFound)
@@ -7100,66 +6991,29 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
[self mention:member];
}
#pragma mark - RoomCoordinatorBridgePresenterDelegate
- (void)roomCoordinatorBridgePresenterDidLeaveRoom:(RoomCoordinatorBridgePresenter *)bridgePresenter
{
}
- (void)roomCoordinatorBridgePresenterDidCancelRoomPreview:(RoomCoordinatorBridgePresenter *)bridgePresenter
{
}
- (void)roomCoordinatorBridgePresenter:(RoomCoordinatorBridgePresenter *)bridgePresenter
didSelectRoomWithId:(NSString *)roomId
eventId:(NSString*)eventId
{
if (bridgePresenter == self.threadBridgePresenter && [roomId isEqualToString:self.roomDataSource.roomId] && eventId)
{
// thread view wants to highlight an event in the timeline
// dismiss thread view first
MXWeakify(self);
[self.threadBridgePresenter dismissWithAnimated:YES completion:^{
MXStrongifyAndReturnIfNil(self);
[self highlightEvent:eventId completion:nil];
}];
}
}
- (void)roomCoordinatorBridgePresenterDidDismissInteractively:(RoomCoordinatorBridgePresenter *)bridgePresenter
{
if (bridgePresenter == self.threadBridgePresenter)
{
self.threadBridgePresenter = nil;
}
}
#pragma mark - ThreadsCoordinatorBridgePresenterDelegate
- (void)threadsCoordinatorBridgePresenterDelegateDidComplete:(ThreadsCoordinatorBridgePresenter *)coordinatorBridgePresenter
{
self.threadsCoordinatorBridgePresenter = nil;
self.threadsBridgePresenter = nil;
}
- (void)threadsCoordinatorBridgePresenterDelegateDidSelect:(ThreadsCoordinatorBridgePresenter *)coordinatorBridgePresenter roomId:(NSString *)roomId eventId:(NSString *)eventId
{
MXWeakify(self);
[self.threadsCoordinatorBridgePresenter dismissWithAnimated:YES completion:^{
[self.threadsBridgePresenter dismissWithAnimated:YES completion:^{
MXStrongifyAndReturnIfNil(self);
if (eventId)
{
[self highlightEvent:eventId completion:nil];
[self highlightAndDisplayEvent:eventId completion:nil];
}
}];
}
- (void)threadsCoordinatorBridgePresenterDidDismissInteractively:(ThreadsCoordinatorBridgePresenter *)coordinatorBridgePresenter
{
self.threadsCoordinatorBridgePresenter = nil;
self.threadsBridgePresenter = nil;
}
#pragma mark - MXThreadingServiceDelegate
@@ -127,57 +127,62 @@
// Display date for each message
[bubbleCell addDateLabel];
RoomBubbleCellData *cellData = (RoomBubbleCellData*)[self cellDataAtIndex:indexPath.row];
MXEvent *event = cellData.events.firstObject;
if (event)
if (RiotSettings.shared.enableThreads)
{
if (cellData.hasThreadRoot)
RoomBubbleCellData *cellData = (RoomBubbleCellData*)[self cellDataAtIndex:indexPath.row];
MXEvent *event = cellData.events.firstObject;
if (event)
{
MXThread *thread = cellData.bubbleComponents.firstObject.thread;
ThreadSummaryView *threadSummaryView = [[ThreadSummaryView alloc] initWithThread:thread];
[bubbleCell.tmpSubviews addObject:threadSummaryView];
if (cellData.hasThreadRoot)
{
MXThread *thread = cellData.bubbleComponents.firstObject.thread;
ThreadSummaryView *threadSummaryView = [[ThreadSummaryView alloc] initWithThread:thread];
[bubbleCell.tmpSubviews addObject:threadSummaryView];
threadSummaryView.translatesAutoresizingMaskIntoConstraints = NO;
[bubbleCell.contentView addSubview:threadSummaryView];
threadSummaryView.translatesAutoresizingMaskIntoConstraints = NO;
[bubbleCell.contentView addSubview:threadSummaryView];
CGFloat leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin;
CGFloat leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin;
CGFloat height = [ThreadSummaryView contentViewHeightForThread:thread fitting:cellData.maxTextViewWidth];
CGRect bubbleComponentFrame = [bubbleCell componentFrameInContentViewForIndex:0];
CGFloat bottomPositionY = bubbleComponentFrame.origin.y + bubbleComponentFrame.size.height;
CGRect bubbleComponentFrame = [bubbleCell componentFrameInContentViewForIndex:0];
CGFloat bottomPositionY = bubbleComponentFrame.origin.y + bubbleComponentFrame.size.height;
// Set constraints for the summary view
[NSLayoutConstraint activateConstraints: @[
[threadSummaryView.leadingAnchor constraintEqualToAnchor:threadSummaryView.superview.leadingAnchor
constant:leftMargin],
[threadSummaryView.topAnchor constraintEqualToAnchor:threadSummaryView.superview.topAnchor
// Set constraints for the summary view
[NSLayoutConstraint activateConstraints: @[
[threadSummaryView.leadingAnchor constraintEqualToAnchor:threadSummaryView.superview.leadingAnchor
constant:leftMargin],
[threadSummaryView.topAnchor constraintEqualToAnchor:threadSummaryView.superview.topAnchor
constant:bottomPositionY + RoomBubbleCellLayout.threadSummaryViewTopMargin],
[threadSummaryView.heightAnchor constraintEqualToConstant:[ThreadSummaryView contentViewHeightForThread:thread fitting:cellData.maxTextViewWidth]],
[threadSummaryView.trailingAnchor constraintLessThanOrEqualToAnchor:threadSummaryView.superview.trailingAnchor constant:-RoomBubbleCellLayout.reactionsViewRightMargin]
]];
}
else if (event.isInThread)
{
FromThreadView *fromThreadView = [FromThreadView instantiate];
[bubbleCell.tmpSubviews addObject:fromThreadView];
[threadSummaryView.heightAnchor constraintEqualToConstant:height],
[threadSummaryView.trailingAnchor constraintLessThanOrEqualToAnchor:threadSummaryView.superview.trailingAnchor constant:-RoomBubbleCellLayout.reactionsViewRightMargin]
]];
}
else if (event.isInThread)
{
FromAThreadView *fromAThreadView = [FromAThreadView instantiate];
[bubbleCell.tmpSubviews addObject:fromAThreadView];
fromAThreadView.translatesAutoresizingMaskIntoConstraints = NO;
[bubbleCell.contentView addSubview:fromAThreadView];
fromThreadView.translatesAutoresizingMaskIntoConstraints = NO;
[bubbleCell.contentView addSubview:fromThreadView];
CGFloat leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin;
CGFloat height = [FromAThreadView contentViewHeightForEvent:event fitting:cellData.maxTextViewWidth];
CGFloat leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin;
CGRect bubbleComponentFrame = [bubbleCell componentFrameInContentViewForIndex:0];
CGFloat bottomPositionY = bubbleComponentFrame.origin.y + bubbleComponentFrame.size.height;
CGRect bubbleComponentFrame = [bubbleCell componentFrameInContentViewForIndex:0];
CGFloat bottomPositionY = bubbleComponentFrame.origin.y + bubbleComponentFrame.size.height;
// Set constraints for the summary view
[NSLayoutConstraint activateConstraints: @[
[fromThreadView.leadingAnchor constraintEqualToAnchor:fromThreadView.superview.leadingAnchor
constant:leftMargin],
[fromThreadView.topAnchor constraintEqualToAnchor:fromThreadView.superview.topAnchor
constant:bottomPositionY + RoomBubbleCellLayout.fromThreadViewTopMargin],
[fromThreadView.heightAnchor constraintEqualToConstant:[FromThreadView contentViewHeightForEvent:event fitting:cellData.maxTextViewWidth]],
[fromThreadView.trailingAnchor constraintLessThanOrEqualToAnchor:fromThreadView.superview.trailingAnchor constant:-RoomBubbleCellLayout.reactionsViewRightMargin]
]];
// Set constraints for the summary view
[NSLayoutConstraint activateConstraints: @[
[fromAThreadView.leadingAnchor constraintEqualToAnchor:fromAThreadView.superview.leadingAnchor
constant:leftMargin],
[fromAThreadView.topAnchor constraintEqualToAnchor:fromAThreadView.superview.topAnchor
constant:bottomPositionY + RoomBubbleCellLayout.fromAThreadViewTopMargin],
[fromAThreadView.heightAnchor constraintEqualToConstant:height],
[fromAThreadView.trailingAnchor constraintLessThanOrEqualToAnchor:fromAThreadView.superview.trailingAnchor constant:-RoomBubbleCellLayout.reactionsViewRightMargin]
]];
}
}
}
}
@@ -1041,10 +1041,11 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
// Create a matrix.to permalink to the room
NSString *permalink = [MXTools permalinkToRoom:roomAliasLabel.text];
if (permalink)
NSURL *url = [NSURL URLWithString:permalink];
if (url)
{
MXKPasteboardManager.shared.pasteboard.string = permalink;
MXKPasteboardManager.shared.pasteboard.URL = url;
[self.view vc_toastWithMessage:VectorL10n.roomEventCopyLinkInfo
image:[UIImage imageNamed:@"link_icon"]
duration:2.0
@@ -0,0 +1,332 @@
/*
Copyright 2015 OpenMarket Ltd
Copyright 2018 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 "MXKTableViewCell.h"
#import "MXKCellRendering.h"
#import "MXKReceiptSendersContainer.h"
#import <WebKit/WebKit.h>
@class MXKImageView;
@class MXKPieChartView;
@class MXKRoomBubbleCellData;
#pragma mark - MXKCellRenderingDelegate cell tap locations
/**
Action identifier used when the user tapped on message text view.
The `userInfo` dictionary contains an `MXEvent` object under the `kMXKRoomBubbleCellEventKey` key, representing the tapped event.
*/
extern NSString *const kMXKRoomBubbleCellTapOnMessageTextView;
/**
Action identifier used when the user tapped on user name label.
The `userInfo` dictionary contains an `NSString` object under the `kMXKRoomBubbleCellUserIdKey` key, representing the user id of the tapped name label.
*/
extern NSString *const kMXKRoomBubbleCellTapOnSenderNameLabel;
/**
Action identifier used when the user tapped on avatar view.
The `userInfo` dictionary contains an `NSString` object under the `kMXKRoomBubbleCellUserIdKey` key, representing the user id of the tapped avatar.
*/
extern NSString *const kMXKRoomBubbleCellTapOnAvatarView;
/**
Action identifier used when the user tapped on date/time container.
The `userInfo` is nil.
*/
extern NSString *const kMXKRoomBubbleCellTapOnDateTimeContainer;
/**
Action identifier used when the user tapped on attachment view.
The `userInfo` is nil. The attachment can be retrieved via MXKRoomBubbleTableViewCell.attachmentView.
*/
extern NSString *const kMXKRoomBubbleCellTapOnAttachmentView;
/**
Action identifier used when the user tapped on overlay container.
The `userInfo` is nil
*/
extern NSString *const kMXKRoomBubbleCellTapOnOverlayContainer;
/**
Action identifier used when the user tapped on content view.
The `userInfo` dictionary may contain an `MXEvent` object under the `kMXKRoomBubbleCellEventKey` key, representing the event displayed at the level of the tapped line. This dictionary is empty if no event correspond to the tapped position.
*/
extern NSString *const kMXKRoomBubbleCellTapOnContentView;
/**
Action identifier used when the user pressed unsent button displayed in front of an unsent event.
The `userInfo` dictionary contains an `MXEvent` object under the `kMXKRoomBubbleCellEventKey` key, representing the unsent event.
*/
extern NSString *const kMXKRoomBubbleCellUnsentButtonPressed;
/**
Action identifier used when the user long pressed on a displayed event.
The `userInfo` dictionary contains an `MXEvent` object under the `kMXKRoomBubbleCellEventKey` key, representing the selected event.
*/
extern NSString *const kMXKRoomBubbleCellLongPressOnEvent;
/**
Action identifier used when the user long pressed on progress view.
The `userInfo` is nil. The progress view can be retrieved via MXKRoomBubbleTableViewCell.progressView.
*/
extern NSString *const kMXKRoomBubbleCellLongPressOnProgressView;
/**
Action identifier used when the user long pressed on avatar view.
The `userInfo` dictionary contains an `NSString` object under the `kMXKRoomBubbleCellUserIdKey` key, representing the user id of the concerned avatar.
*/
extern NSString *const kMXKRoomBubbleCellLongPressOnAvatarView;
/**
Action identifier used when the user clicked on a link.
This action is sent via the MXKCellRenderingDelegate `shouldDoAction` operation.
The `userInfo` dictionary contains a `NSURL` object under the `kMXKRoomBubbleCellUrl` key, representing the url the user wants to open. And a NSNumber wrapping `UITextItemInteraction` raw value, representing the type of interaction expected with the URL, under the `kMXKRoomBubbleCellUrlItemInteraction` key.
The shouldDoAction implementation must return NO to prevent the system (safari) from opening the link.
@discussion: If the link refers to a room alias/id, a user id or an event id, the non-ASCII characters (like '#' in room alias) has been
escaped to be able to convert it into a legal URL string.
*/
extern NSString *const kMXKRoomBubbleCellShouldInteractWithURL;
/**
Notifications `userInfo` keys
*/
extern NSString *const kMXKRoomBubbleCellUserIdKey;
extern NSString *const kMXKRoomBubbleCellEventKey;
extern NSString *const kMXKRoomBubbleCellEventIdKey;
extern NSString *const kMXKRoomBubbleCellReceiptsContainerKey;
extern NSString *const kMXKRoomBubbleCellUrl;
extern NSString *const kMXKRoomBubbleCellUrlItemInteraction;
#pragma mark - MXKRoomBubbleTableViewCell
/**
`MXKRoomBubbleTableViewCell` is a base class for displaying a room bubble.
This class is used to handle a maximum of items which may be present in bubbles display (like the user's picture view, the message text view...).
To optimize bubbles rendering, we advise to define a .xib for each kind of bubble layout (with or without sender's information, with or without attachment...).
Each inherited class should define only the actual displayed items.
*/
@interface MXKRoomBubbleTableViewCell : MXKTableViewCell <MXKCellRendering, UITextViewDelegate, WKNavigationDelegate>
{
@protected
/**
The current bubble data displayed by the table view cell
*/
MXKRoomBubbleCellData *bubbleData;
}
/**
The current bubble data displayed by the table view cell
*/
@property (strong, nonatomic, readonly) MXKRoomBubbleCellData *bubbleData;
/**
Option to highlight or not the content of message text view (May be used in case of text selection).
NO by default.
*/
@property (nonatomic) BOOL allTextHighlighted;
/**
Tell whether the animation should start automatically in case of animated gif (NO by default).
*/
@property (nonatomic) BOOL isAutoAnimatedGif;
/**
The default picture displayed when no picture is available.
*/
@property (nonatomic) UIImage *picturePlaceholder;
/**
The list of the temporary subviews that should be removed before reusing the cell (empty array by default).
*/
@property (nonatomic) NSMutableArray<UIView*> *tmpSubviews;
/**
The read receipts alignment.
By default, they are left aligned.
*/
@property (nonatomic) ReadReceiptsAlignment readReceiptsAlignment;
@property (weak, nonatomic) IBOutlet UILabel *userNameLabel;
@property (weak, nonatomic) IBOutlet UIView *userNameTapGestureMaskView;
@property (strong, nonatomic) IBOutlet MXKImageView *pictureView;
@property (weak, nonatomic) IBOutlet UITextView *messageTextView;
@property (strong, nonatomic) IBOutlet MXKImageView *attachmentView;
@property (strong, nonatomic) IBOutlet UIImageView *playIconView;
@property (strong, nonatomic) IBOutlet UIImageView *fileTypeIconView;
@property (weak, nonatomic) IBOutlet UIView *bubbleInfoContainer;
@property (weak, nonatomic) IBOutlet UIView *bubbleOverlayContainer;
/**
The container view in which the encryption information may be displayed
*/
@property (weak, nonatomic) IBOutlet UIView *encryptionStatusContainerView;
@property (weak, nonatomic) IBOutlet UIView *progressView;
@property (weak, nonatomic) IBOutlet UILabel *statsLabel;
@property (weak, nonatomic) IBOutlet MXKPieChartView *progressChartView;
/**
The constraints which defines the relationship between messageTextView and its superview.
The defined constant are supposed >= 0.
*/
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *msgTextViewTopConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *msgTextViewBottomConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *msgTextViewLeadingConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *msgTextViewTrailingConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *msgTextViewWidthConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *msgTextViewMinHeightConstraint;
/**
The constraints which defines the relationship between attachmentView and its superview
The defined constant are supposed >= 0.
*/
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *attachViewWidthConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *attachViewMinHeightConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *attachViewTopConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *attachViewBottomConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *attachViewLeadingConstraint;
/**
The constraints which defines the relationship between bubbleInfoContainer and its superview
The defined constant are supposed >= 0.
*/
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *bubbleInfoContainerTopConstraint;
/**
The read marker view and its layout constraints (nil by default).
*/
@property (nonatomic) UIView *readMarkerView;
@property (nonatomic) NSLayoutConstraint *readMarkerViewTopConstraint;
@property (nonatomic) NSLayoutConstraint *readMarkerViewLeadingConstraint;
@property (nonatomic) NSLayoutConstraint *readMarkerViewTrailingConstraint;
@property (nonatomic) NSLayoutConstraint *readMarkerViewHeightConstraint;
/**
The potential webview used to render an attachment (for example an animated gif).
*/
@property (nonatomic) WKWebView *attachmentWebView;
/**
Called during the designated initializer of the UITableViewCell class to set the default
properties values.
You should not call this method directly.
Subclasses can override this method as needed to customize the initialization.
*/
- (void)finalizeInit;
/**
Handle progressView display.
*/
- (void)startProgressUI;
- (void)updateProgressUI:(NSDictionary*)statisticsDict;
#pragma mark - Original Xib values
/**
Get an original instance of the `MXKRoomBubbleTableViewCell` child class.
@return an instance of the child class caller which has the original Xib values.
*/
+ (MXKRoomBubbleTableViewCell*)cellWithOriginalXib;
/**
Disable the handling of the long press on event (see kMXKRoomBubbleCellLongPressOnEvent). NO by default.
CAUTION: Changing this flag only impact the new created cells (existing 'MXKRoomBubbleTableViewCell' instances are unchanged).
*/
+ (void)disableLongPressGestureOnEvent:(BOOL)disable;
/**
Method used during [MXKCellRendering render:] to check the provided `cellData`
and prepare the protected `bubbleData`.
Do not override it.
@param cellData the data object to render.
*/
- (void)prepareRender:(MXKCellData*)cellData;
/**
Refresh the flair information added to the sender display name.
*/
- (void)renderSenderFlair;
/**
Highlight text message related to a specific event in the displayed message.
@param eventId the id of the event to highlight (use nil to cancel highlighting).
*/
- (void)highlightTextMessageForEvent:(NSString*)eventId;
/**
The top position of an event in the cell.
A cell can display several events. The method returns the vertical position of a given
event in the cell.
@return the y position (in pixel) of the event in the cell.
*/
- (CGFloat)topPositionOfEvent:(NSString*)eventId;
/**
The bottom position of an event in the cell.
A cell can display several events. The method returns the vertical position of the bottom part
of a given event in the cell.
@return the y position (in pixel) of the bottom part of the event in the cell.
*/
- (CGFloat)bottomPositionOfEvent:(NSString*)eventId;
/**
Restore `attachViewBottomConstraint` constant to default value.
*/
- (void)resetAttachmentViewBottomConstraintConstant;
/**
Redeclare heightForCellData:withMaximumWidth: method from MXKCellRendering to use it as a class method in Swift and not a static method.
*/
+ (CGFloat)heightForCellData:(MXKCellData*)cellData withMaximumWidth:(CGFloat)maxWidth;
/**
Setup outlets views. Useful to call when cell subclass does not use a xib otherwise this method is called automatically in `awakeFromNib`.
*/
- (void)setupViews;
/// Add temporary subview to `tmpSubviews` property.
- (void)addTemporarySubview:(UIView*)subview;
@end
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,26 @@
/*
Copyright 2015 OpenMarket 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 "MXKTableViewCell.h"
#import "MXKCellRendering.h"
/**
`MXKRoomIOSBubbleTableViewCell` instances mimic bubbles in the stock iOS messages application.
*/
@interface MXKRoomIOSBubbleTableViewCell : MXKTableViewCell <MXKCellRendering>
@end
@@ -0,0 +1,45 @@
/*
Copyright 2015 OpenMarket 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 "MXKRoomIOSBubbleTableViewCell.h"
#import "MXKRoomBubbleCellDataStoring.h"
@implementation MXKRoomIOSBubbleTableViewCell
- (void)render:(MXKCellData *)cellData
{
id<MXKRoomBubbleCellDataStoring> bubbleData = (id<MXKRoomBubbleCellDataStoring>)cellData;
if (bubbleData)
{
self.textLabel.attributedText = bubbleData.attributedTextMessage;
}
else
{
self.textLabel.text = @"";
}
// Light custo for now... @TODO
self.layer.cornerRadius = 20;
self.backgroundColor = [UIColor blueColor];
}
+ (CGFloat)heightForCellData:(MXKCellData *)cellData withMaximumWidth:(CGFloat)maxWidth
{
return 44;
}
@end
@@ -0,0 +1,36 @@
/*
Copyright 2015 OpenMarket 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 "MXKRoomOutgoingBubbleTableViewCell.h"
/**
`MXKRoomIOSBubbleTableViewCell` instances mimic bubbles in the stock iOS messages application.
It is dedicated to outgoing messages.
It subclasses `MXKRoomOutgoingBubbleTableViewCell` to take benefit of the available mechanic.
*/
@interface MXKRoomIOSOutgoingBubbleTableViewCell : MXKRoomOutgoingBubbleTableViewCell
/**
The green bubble displayed in background.
*/
@property (weak, nonatomic) IBOutlet UIImageView *bubbleImageView;
/**
The width constraint on this backgroung green bubble.
*/
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *bubbleImageViewWidthConstraint;
@end
@@ -0,0 +1,130 @@
/*
Copyright 2015 OpenMarket 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 "MXKRoomIOSOutgoingBubbleTableViewCell.h"
#import "MXKRoomBubbleCellData.h"
#import "MXEvent+MatrixKit.h"
#import "MXKTools.h"
#import "NSBundle+MatrixKit.h"
#import "MXKImageView.h"
#define OUTGOING_BUBBLE_COLOR 0x00e34d
@implementation MXKRoomIOSOutgoingBubbleTableViewCell
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self)
{
// Create the strechable background bubble
self.bubbleImageView.image = self.class.bubbleImage;
}
return self;
}
- (void)layoutSubviews
{
[super layoutSubviews];
}
- (void)render:(MXKCellData *)cellData
{
[super render:cellData];
// Reset values
self.bubbleImageView.hidden = NO;
// Customise the data precomputed by the legacy classes
// Replace black color in texts by the white color expected for outgoing messages.
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithAttributedString:self.messageTextView.attributedText];
// Change all attributes one by one
[attributedString enumerateAttributesInRange:NSMakeRange(0, attributedString.length) options:0 usingBlock:^(NSDictionary *attrs, NSRange range, BOOL *stop)
{
// Replace only black colored texts
if (attrs[NSForegroundColorAttributeName] == self->bubbleData.eventFormatter.defaultTextColor)
{
// By white
NSMutableDictionary *newAttrs = [NSMutableDictionary dictionaryWithDictionary:attrs];
newAttrs[NSForegroundColorAttributeName] = [UIColor whiteColor];
[attributedString setAttributes:newAttrs range:range];
}
}];
self.messageTextView.attributedText = attributedString;
// Update the bubble width to include the text view
self.bubbleImageViewWidthConstraint.constant = bubbleData.contentSize.width + 17;
// Limit bubble width
if (self.bubbleImageViewWidthConstraint.constant < 46)
{
self.bubbleImageViewWidthConstraint.constant = 46;
}
// Mask the image with the bubble
if (bubbleData.attachment && bubbleData.attachment.type != MXKAttachmentTypeFile && bubbleData.attachment.type != MXKAttachmentTypeAudio)
{
self.bubbleImageView.hidden = YES;
UIImageView *rightBubbleImageView = [[UIImageView alloc] initWithImage:self.class.bubbleImage];
rightBubbleImageView.frame = CGRectMake(0, 0, self.bubbleImageViewWidthConstraint.constant, bubbleData.contentSize.height + self.attachViewTopConstraint.constant - 4);
self.attachmentView.layer.mask = rightBubbleImageView.layer;
}
}
+ (CGFloat)heightForCellData:(MXKCellData *)cellData withMaximumWidth:(CGFloat)maxWidth
{
CGFloat rowHeight = [super heightForCellData:cellData withMaximumWidth:maxWidth];
CGFloat height = self.cellWithOriginalXib.frame.size.height;
// Use the xib height as the minimal height
if (rowHeight < height)
{
rowHeight = height;
}
return rowHeight;
}
/**
Create the strechable background bubble.
@return the bubble image.
*/
+ (UIImage *)bubbleImage
{
UIImage *rightBubbleImage = [NSBundle mxk_imageFromMXKAssetsBundleWithName:@"bubble_ios_messages_right"];
rightBubbleImage = [MXKTools paintImage:rightBubbleImage
withColor:[MXKTools colorWithRGBValue:OUTGOING_BUBBLE_COLOR]];
UIEdgeInsets edgeInsets = UIEdgeInsetsMake(17, 22, 17, 27);
return [rightBubbleImage resizableImageWithCapInsets:edgeInsets];
}
@end
@@ -0,0 +1,161 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11762" systemVersion="16C67" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
<capability name="Constraints to layout margins" minToolsVersion="6.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"/>
<tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="pad-g3-2YJ" customClass="MXKRoomIOSOutgoingBubbleTableViewCell">
<rect key="frame" x="0.0" y="0.0" width="600" height="40"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="pad-g3-2YJ" id="fCg-ju-gnG">
<rect key="frame" x="0.0" y="0.0" width="600" height="39"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Ktd-ms-tAu" userLabel="Bubble Image View">
<rect key="frame" x="160" y="2" width="422" height="35"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" constant="422" id="ptG-QV-Cix"/>
</constraints>
</imageView>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" scrollEnabled="NO" editable="NO" text="text message" translatesAutoresizingMaskIntoConstraints="NO" id="tgO-Rv-C7R">
<rect key="frame" x="74" y="3" width="495" height="36"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
<dataDetectorType key="dataDetectorTypes" link="YES"/>
</textView>
<view contentMode="scaleAspectFit" translatesAutoresizingMaskIntoConstraints="NO" id="SIW-l4-PfI" userLabel="Attachment View" customClass="MXKImageView">
<rect key="frame" x="160" y="2" width="422" height="35"/>
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
<constraints>
<constraint firstAttribute="width" constant="192" id="iGr-e7-bde"/>
</constraints>
<variation key="default">
<mask key="constraints">
<exclude reference="iGr-e7-bde"/>
</mask>
</variation>
</view>
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="ZC1-hT-7fs">
<rect key="frame" x="355" y="4" width="32" height="32"/>
<constraints>
<constraint firstAttribute="width" constant="32" id="MOQ-Xi-18w"/>
<constraint firstAttribute="height" constant="32" id="pGM-pf-SiP"/>
</constraints>
</imageView>
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="Mqf-7a-bsm">
<rect key="frame" x="361" y="10" width="20" height="20"/>
</activityIndicatorView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="LVJ-Av-zVs" userLabel="showHideDateTime">
<rect key="frame" x="0.0" y="0.0" width="74" height="39"/>
<state key="normal">
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="showHideDateTime:" destination="pad-g3-2YJ" eventType="touchUpInside" id="Ztw-z5-zlU"/>
</connections>
</button>
<view hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="a51-cR-7FE" userLabel="bubbleInfoContainer">
<rect key="frame" x="8" y="10" width="66" height="29"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
</view>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="apW-hM-veR" userLabel="ProgressView">
<rect key="frame" x="18" y="-16" width="100" height="71"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="text" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="3" baselineAdjustment="alignBaselines" minimumFontSize="4" preferredMaxLayoutWidth="100" translatesAutoresizingMaskIntoConstraints="NO" id="DYj-Mb-me4" userLabel="Progress stats">
<rect key="frame" x="0.0" y="61" width="100" height="10"/>
<fontDescription key="fontDescription" type="system" pointSize="8"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<view userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Oec-kb-Tsz" customClass="MXKPieChartView">
<rect key="frame" x="30" y="0.0" width="40" height="41"/>
<constraints>
<constraint firstAttribute="height" constant="40" id="6tZ-ag-7TT"/>
<constraint firstAttribute="width" constant="40" id="duC-38-cLC"/>
</constraints>
</view>
</subviews>
<gestureRecognizers/>
<constraints>
<constraint firstItem="Oec-kb-Tsz" firstAttribute="top" secondItem="apW-hM-veR" secondAttribute="top" id="49H-ch-qkC"/>
<constraint firstAttribute="height" constant="70" id="GhG-zB-k3A"/>
<constraint firstAttribute="centerX" secondItem="Oec-kb-Tsz" secondAttribute="centerX" id="KZy-2p-KaW"/>
<constraint firstItem="DYj-Mb-me4" firstAttribute="leading" secondItem="apW-hM-veR" secondAttribute="leading" id="UxL-bV-5Ca"/>
<constraint firstAttribute="bottom" secondItem="DYj-Mb-me4" secondAttribute="bottom" id="YFp-gQ-NFz"/>
<constraint firstAttribute="width" constant="100" id="Zr4-5T-h9g"/>
<constraint firstAttribute="trailing" secondItem="DYj-Mb-me4" secondAttribute="trailing" id="ehN-ME-1U1"/>
<constraint firstAttribute="centerX" secondItem="DYj-Mb-me4" secondAttribute="centerX" id="nuq-lO-8pT"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="SIW-l4-PfI" firstAttribute="centerX" secondItem="Mqf-7a-bsm" secondAttribute="centerX" id="1b6-1l-hg0"/>
<constraint firstItem="tgO-Rv-C7R" firstAttribute="leading" secondItem="LVJ-Av-zVs" secondAttribute="trailing" id="45B-ph-Sc3"/>
<constraint firstAttribute="bottom" secondItem="tgO-Rv-C7R" secondAttribute="bottom" id="7C3-Tl-mMq"/>
<constraint firstItem="tgO-Rv-C7R" firstAttribute="top" secondItem="fCg-ju-gnG" secondAttribute="top" constant="3" id="8Sy-eu-tYs"/>
<constraint firstItem="SIW-l4-PfI" firstAttribute="width" secondItem="Ktd-ms-tAu" secondAttribute="width" id="AjE-jd-r7q"/>
<constraint firstAttribute="trailing" secondItem="SIW-l4-PfI" secondAttribute="trailing" constant="8" id="D8p-mV-ytb"/>
<constraint firstItem="a51-cR-7FE" firstAttribute="leading" secondItem="fCg-ju-gnG" secondAttribute="leading" constant="8" id="E3x-h8-GPF"/>
<constraint firstItem="SIW-l4-PfI" firstAttribute="bottom" secondItem="Ktd-ms-tAu" secondAttribute="bottom" id="ET2-rD-uVQ"/>
<constraint firstItem="LVJ-Av-zVs" firstAttribute="leading" secondItem="fCg-ju-gnG" secondAttribute="leading" id="Hve-E3-z5N"/>
<constraint firstAttribute="bottom" secondItem="LVJ-Av-zVs" secondAttribute="bottom" id="IKr-Dc-HKz"/>
<constraint firstAttribute="trailingMargin" secondItem="Ktd-ms-tAu" secondAttribute="trailing" constant="10" id="LEJ-mA-aF4"/>
<constraint firstItem="apW-hM-veR" firstAttribute="leading" secondItem="fCg-ju-gnG" secondAttribute="leading" constant="18" id="LFn-vp-m0v"/>
<constraint firstItem="tgO-Rv-C7R" firstAttribute="leading" secondItem="a51-cR-7FE" secondAttribute="trailing" id="PJ9-Px-DPH"/>
<constraint firstItem="SIW-l4-PfI" firstAttribute="top" secondItem="fCg-ju-gnG" secondAttribute="top" constant="18" id="QDm-tP-KWa"/>
<constraint firstItem="SIW-l4-PfI" firstAttribute="top" secondItem="Ktd-ms-tAu" secondAttribute="top" id="W0E-eV-LGg"/>
<constraint firstAttribute="bottom" secondItem="SIW-l4-PfI" secondAttribute="bottom" id="fMN-Th-SOT"/>
<constraint firstItem="a51-cR-7FE" firstAttribute="top" secondItem="fCg-ju-gnG" secondAttribute="top" constant="10" id="fQv-07-Pgx"/>
<constraint firstItem="SIW-l4-PfI" firstAttribute="centerY" secondItem="ZC1-hT-7fs" secondAttribute="centerY" id="ffI-vh-SW3"/>
<constraint firstAttribute="bottom" secondItem="Ktd-ms-tAu" secondAttribute="bottom" constant="2" id="haQ-G8-eZD"/>
<constraint firstItem="tgO-Rv-C7R" firstAttribute="leading" secondItem="fCg-ju-gnG" secondAttribute="leading" constant="74" id="hwr-aa-TB4"/>
<constraint firstItem="SIW-l4-PfI" firstAttribute="centerX" secondItem="ZC1-hT-7fs" secondAttribute="centerX" id="jah-TA-P0P"/>
<constraint firstItem="Ktd-ms-tAu" firstAttribute="top" secondItem="fCg-ju-gnG" secondAttribute="top" constant="2" id="ltB-ic-svk"/>
<constraint firstItem="LVJ-Av-zVs" firstAttribute="top" secondItem="fCg-ju-gnG" secondAttribute="top" id="pYO-hi-P72"/>
<constraint firstItem="SIW-l4-PfI" firstAttribute="centerY" secondItem="Mqf-7a-bsm" secondAttribute="centerY" id="sKJ-ny-LjM"/>
<constraint firstAttribute="bottom" secondItem="a51-cR-7FE" secondAttribute="bottom" id="viZ-Sx-3RW"/>
<constraint firstItem="apW-hM-veR" firstAttribute="centerY" secondItem="SIW-l4-PfI" secondAttribute="centerY" id="wmh-x1-U32"/>
<constraint firstAttribute="trailing" secondItem="tgO-Rv-C7R" secondAttribute="trailing" constant="31" id="xYz-lp-c7K"/>
<constraint firstItem="SIW-l4-PfI" firstAttribute="leading" secondItem="Ktd-ms-tAu" secondAttribute="leading" id="zvi-c3-uqP"/>
</constraints>
<variation key="default">
<mask key="constraints">
<exclude reference="D8p-mV-ytb"/>
<exclude reference="QDm-tP-KWa"/>
<exclude reference="fMN-Th-SOT"/>
</mask>
</variation>
</tableViewCellContentView>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<outlet property="activityIndicator" destination="Mqf-7a-bsm" id="toi-nL-eJa"/>
<outlet property="attachViewTopConstraint" destination="QDm-tP-KWa" id="Ku6-FC-jqo"/>
<outlet property="attachViewWidthConstraint" destination="iGr-e7-bde" id="uD4-aU-1Ru"/>
<outlet property="attachmentView" destination="SIW-l4-PfI" id="L4H-ub-pPI"/>
<outlet property="bubbleImageView" destination="Ktd-ms-tAu" id="I0r-5F-rhe"/>
<outlet property="bubbleImageViewWidthConstraint" destination="ptG-QV-Cix" id="TUH-dw-uqF"/>
<outlet property="bubbleInfoContainer" destination="a51-cR-7FE" id="wrR-cU-DVm"/>
<outlet property="bubbleInfoContainerTopConstraint" destination="fQv-07-Pgx" id="82c-KH-Wop"/>
<outlet property="messageTextView" destination="tgO-Rv-C7R" id="LZ5-hQ-AbQ"/>
<outlet property="msgTextViewBottomConstraint" destination="7C3-Tl-mMq" id="5Ff-xL-G1i"/>
<outlet property="msgTextViewLeadingConstraint" destination="hwr-aa-TB4" id="A1E-ap-Ug6"/>
<outlet property="msgTextViewTopConstraint" destination="8Sy-eu-tYs" id="7yx-oJ-KBP"/>
<outlet property="msgTextViewTrailingConstraint" destination="xYz-lp-c7K" id="hc2-Cg-is4"/>
<outlet property="playIconView" destination="ZC1-hT-7fs" id="zeH-8B-gxw"/>
<outlet property="progressChartView" destination="Oec-kb-Tsz" id="uoq-6v-6Tm"/>
<outlet property="progressView" destination="apW-hM-veR" id="Iy8-ca-hMi"/>
<outlet property="statsLabel" destination="DYj-Mb-me4" id="CbG-5V-unO"/>
</connections>
</tableViewCell>
</objects>
</document>
@@ -0,0 +1,29 @@
/*
Copyright 2015 OpenMarket 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 "MXKRoomBubbleTableViewCell.h"
/**
`MXKRoomIncomingBubbleTableViewCell` inherits from 'MXKRoomBubbleTableViewCell' class in order to handle specific
options related to incoming messages (like typing badge).
In order to optimize bubbles rendering, we advise to define a .xib for each layout.
*/
@interface MXKRoomIncomingBubbleTableViewCell : MXKRoomBubbleTableViewCell
@property (weak, nonatomic) IBOutlet UIImageView *typingBadge;
@end
@@ -0,0 +1,65 @@
/*
Copyright 2015 OpenMarket 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 "MXKRoomIncomingBubbleTableViewCell.h"
#import "MXKRoomBubbleCellData.h"
#import "NSBundle+MatrixKit.h"
@implementation MXKRoomIncomingBubbleTableViewCell
- (void)finalizeInit
{
[super finalizeInit];
self.readReceiptsAlignment = ReadReceiptAlignmentRight;
}
- (void)awakeFromNib
{
[super awakeFromNib];
self.typingBadge.image = [NSBundle mxk_imageFromMXKAssetsBundleWithName:@"icon_keyboard"];
}
- (void)render:(MXKCellData *)cellData
{
[super render:cellData];
if (bubbleData)
{
// Handle here typing badge (if any)
if (self.typingBadge)
{
if (bubbleData.isTyping)
{
self.typingBadge.hidden = NO;
[self.typingBadge.superview bringSubviewToFront:self.typingBadge];
}
else
{
self.typingBadge.hidden = YES;
}
}
}
}
- (void)didEndDisplay
{
[super didEndDisplay];
self.readReceiptsAlignment = ReadReceiptAlignmentRight;
}
@end
@@ -0,0 +1,27 @@
/*
Copyright 2015 OpenMarket 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 "MXKRoomBubbleTableViewCell.h"
/**
`MXKRoomOutgoingBubbleTableViewCell` inherits from 'MXKRoomBubbleTableViewCell' class in order to handle specific
options related to outgoing messages (like unsent labels, upload progress in case of attachment).
In order to optimize bubbles rendering, we advise to define a .xib for each layout.
*/
@interface MXKRoomOutgoingBubbleTableViewCell : MXKRoomBubbleTableViewCell
@end
@@ -0,0 +1,117 @@
/*
Copyright 2015 OpenMarket 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 "MXKRoomOutgoingBubbleTableViewCell.h"
#import "MXEvent+MatrixKit.h"
#import "NSBundle+Matrixkit.h"
#import "MXKRoomBubbleCellData.h"
#import "MXKSwiftHeader.h"
@implementation MXKRoomOutgoingBubbleTableViewCell
- (void)render:(MXKCellData *)cellData
{
[super render:cellData];
if (bubbleData)
{
// Add unsent label for failed components (except if the app customizes it)
if (self.bubbleInfoContainer && (bubbleData.useCustomUnsentButton == NO))
{
for (MXKRoomBubbleComponent *component in bubbleData.bubbleComponents)
{
if (component.event.sentState == MXEventSentStateFailed)
{
UIButton *unsentButton = [[UIButton alloc] initWithFrame:CGRectMake(0, component.position.y, 58 , 20)];
[unsentButton setTitle:[MatrixKitL10n unsent] forState:UIControlStateNormal];
[unsentButton setTitle:[MatrixKitL10n unsent] forState:UIControlStateSelected];
[unsentButton setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[unsentButton setTitleColor:[UIColor redColor] forState:UIControlStateSelected];
unsentButton.backgroundColor = [UIColor whiteColor];
unsentButton.titleLabel.font = [UIFont systemFontOfSize:14];
[unsentButton addTarget:self action:@selector(onResendToggle:) forControlEvents:UIControlEventTouchUpInside];
[self.bubbleInfoContainer addSubview:unsentButton];
self.bubbleInfoContainer.hidden = NO;
self.bubbleInfoContainer.userInteractionEnabled = YES;
// ensure that bubbleInfoContainer is at front to catch the tap event
[self.bubbleInfoContainer.superview bringSubviewToFront:self.bubbleInfoContainer];
}
}
}
}
}
- (void)didEndDisplay
{
[super didEndDisplay];
self.bubbleInfoContainer.userInteractionEnabled = NO;
}
#pragma mark - User actions
- (IBAction)onResendToggle:(id)sender
{
if ([sender isKindOfClass:[UIButton class]] && self.delegate)
{
MXEvent *selectedEvent = nil;
NSArray *bubbleComponents = bubbleData.bubbleComponents;
if (bubbleComponents.count == 1)
{
MXKRoomBubbleComponent *component = [bubbleComponents firstObject];
selectedEvent = component.event;
}
else if (bubbleComponents.count)
{
// Here the selected view is a textView (attachment has no more than one component)
// Look for the selected component
UIButton *unsentButton = (UIButton *)sender;
for (MXKRoomBubbleComponent *component in bubbleComponents)
{
// Ignore components without display.
if (!component.attributedTextMessage)
{
continue;
}
if (unsentButton.frame.origin.y == component.position.y)
{
selectedEvent = component.event;
break;
}
}
}
if (selectedEvent)
{
[self.delegate cell:self didRecognizeAction:kMXKRoomBubbleCellUnsentButtonPressed userInfo:@{kMXKRoomBubbleCellEventKey:selectedEvent}];
}
}
}
@end
@@ -0,0 +1,25 @@
/*
Copyright 2017 Vector Creations 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 "MXKRoomBubbleTableViewCell.h"
/**
`MXKRoomEmptyBubbleTableViewCell` displays an empty bubbles without user's information.
This kind of bubble may be used to localize an event without display in the room history.
*/
@interface MXKRoomEmptyBubbleTableViewCell : MXKRoomBubbleTableViewCell
@end
@@ -0,0 +1,21 @@
/*
Copyright 2017 Vector Creations 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 "MXKRoomEmptyBubbleTableViewCell.h"
@implementation MXKRoomEmptyBubbleTableViewCell
@end
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12120" systemVersion="16F73" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12088"/>
<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"/>
<tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="pad-g3-2YJ" customClass="MXKRoomEmptyBubbleTableViewCell">
<rect key="frame" x="0.0" y="0.0" width="600" height="8"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="pad-g3-2YJ" id="fCg-ju-gnG">
<rect key="frame" x="0.0" y="0.0" width="600" height="7"/>
<autoresizingMask key="autoresizingMask"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
</tableViewCellContentView>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
</tableViewCell>
</objects>
</document>
@@ -0,0 +1,24 @@
/*
Copyright 2015 OpenMarket 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 "MXKRoomIncomingBubbleTableViewCell.h"
/**
`MXKRoomIncomingAttachmentBubbleCell` displays incoming attachment bubbles with sender's information.
*/
@interface MXKRoomIncomingAttachmentBubbleCell : MXKRoomIncomingBubbleTableViewCell
@end
@@ -0,0 +1,21 @@
/*
Copyright 2015 OpenMarket 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 "MXKRoomIncomingAttachmentBubbleCell.h"
@implementation MXKRoomIncomingAttachmentBubbleCell
@end
@@ -0,0 +1,171 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11762" systemVersion="16C67" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
<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"/>
<tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="WmY-Jw-mqv" customClass="MXKRoomIncomingAttachmentBubbleCell">
<rect key="frame" x="0.0" y="0.0" width="600" height="50"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="WmY-Jw-mqv" id="ef1-Tq-U3Z">
<rect key="frame" x="0.0" y="0.0" width="600" height="49"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<view clipsSubviews="YES" contentMode="scaleAspectFill" translatesAutoresizingMaskIntoConstraints="NO" id="hgp-Z5-rAj" userLabel="Picture View" customClass="MXKImageView">
<rect key="frame" x="8" y="5" width="40" height="40"/>
<color key="backgroundColor" red="0.66666666666666663" green="0.66666666666666663" blue="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" constant="40" id="NQk-ck-Lo8"/>
<constraint firstAttribute="height" constant="40" id="dNT-QU-CUG"/>
</constraints>
</view>
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="zwq-eh-8Fb" userLabel="typingBadge">
<rect key="frame" x="5" y="0.0" width="20" height="20"/>
<constraints>
<constraint firstAttribute="width" constant="20" id="7ni-rb-ovL"/>
<constraint firstAttribute="height" constant="20" id="mcu-rQ-hnj"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="User name:" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="8" translatesAutoresizingMaskIntoConstraints="NO" id="q9c-0p-QyP">
<rect key="frame" x="51" y="3" width="480" height="20"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="20" placeholder="YES" id="5ZO-W1-tS2"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="13"/>
<color key="textColor" red="0.33333333333333331" green="0.33333333333333331" blue="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<view contentMode="scaleAspectFit" translatesAutoresizingMaskIntoConstraints="NO" id="5IE-JS-uf3" userLabel="Attachment View" customClass="MXKImageView">
<rect key="frame" x="51" y="18" width="192" height="23"/>
<color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803926" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" constant="192" id="9zO-jU-qTb"/>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="23" id="C5F-6D-LZx"/>
</constraints>
</view>
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="K9X-gn-noF" userLabel="File Type Image View">
<rect key="frame" x="51" y="18" width="32" height="32"/>
<constraints>
<constraint firstAttribute="width" constant="32" id="OE8-oh-B7Q"/>
<constraint firstAttribute="height" constant="32" id="jJB-zj-fbT"/>
</constraints>
</imageView>
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Cot-3X-2cU" userLabel="Play Icon Image View">
<rect key="frame" x="131" y="14" width="32" height="32"/>
<constraints>
<constraint firstAttribute="height" constant="32" id="8io-Wk-GzF"/>
<constraint firstAttribute="width" constant="32" id="aeJ-j3-rfX"/>
</constraints>
</imageView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="kwd-hP-feC" userLabel="showHideDateTime">
<rect key="frame" x="531" y="0.0" width="69" height="49"/>
<constraints>
<constraint firstAttribute="width" constant="69" id="9vA-4g-EE5"/>
</constraints>
<state key="normal">
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="showHideDateTime:" destination="WmY-Jw-mqv" eventType="touchUpInside" id="jYV-nj-p60"/>
</connections>
</button>
<view hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="IOg-Kt-8vW" userLabel="bubbleInfoContainer">
<rect key="frame" x="531" y="18" width="61" height="31"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" constant="61" id="tLr-6k-ArA"/>
</constraints>
</view>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fdx-qs-8en" userLabel="ProgressView">
<rect key="frame" x="487" y="-5" width="100" height="70"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="rate" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="3" baselineAdjustment="alignBaselines" minimumFontSize="4" preferredMaxLayoutWidth="100" translatesAutoresizingMaskIntoConstraints="NO" id="eU5-iK-u8i" userLabel="Progress stats">
<rect key="frame" x="0.0" y="60" width="100" height="10"/>
<fontDescription key="fontDescription" type="system" pointSize="8"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<view userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="hJj-TC-pxK" customClass="MXKPieChartView">
<rect key="frame" x="30" y="0.0" width="40" height="40"/>
<constraints>
<constraint firstAttribute="width" constant="40" id="Cpt-s4-tlK"/>
<constraint firstAttribute="height" constant="40" id="Jb4-9E-tG0"/>
</constraints>
</view>
</subviews>
<gestureRecognizers/>
<constraints>
<constraint firstAttribute="height" constant="70" id="5w2-Hm-hZx"/>
<constraint firstAttribute="centerX" secondItem="eU5-iK-u8i" secondAttribute="centerX" id="APi-aE-mLc"/>
<constraint firstItem="eU5-iK-u8i" firstAttribute="leading" secondItem="fdx-qs-8en" secondAttribute="leading" id="Njw-3a-E9Y"/>
<constraint firstAttribute="bottom" secondItem="eU5-iK-u8i" secondAttribute="bottom" id="QMO-g9-QVE"/>
<constraint firstAttribute="centerX" secondItem="hJj-TC-pxK" secondAttribute="centerX" id="laR-Vg-ol3"/>
<constraint firstItem="hJj-TC-pxK" firstAttribute="top" secondItem="fdx-qs-8en" secondAttribute="top" id="ovD-8p-4dP"/>
<constraint firstAttribute="width" constant="100" id="ryE-fW-SgG"/>
<constraint firstAttribute="trailing" secondItem="eU5-iK-u8i" secondAttribute="trailing" id="teG-8q-BOX"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="GGt-zb-6zg">
<rect key="frame" x="48" y="0.0" width="486" height="26"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
</view>
</subviews>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="hgp-Z5-rAj" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" constant="5" id="2Ih-ga-N9s"/>
<constraint firstItem="kwd-hP-feC" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" id="5bB-HV-WAA"/>
<constraint firstItem="5IE-JS-uf3" firstAttribute="leading" secondItem="hgp-Z5-rAj" secondAttribute="trailing" constant="3" id="6mM-Ag-m0K"/>
<constraint firstItem="5IE-JS-uf3" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" constant="18" id="96U-67-5TP"/>
<constraint firstAttribute="trailing" secondItem="q9c-0p-QyP" secondAttribute="trailing" constant="69" id="Bkh-h2-JOQ"/>
<constraint firstItem="GGt-zb-6zg" firstAttribute="leading" secondItem="q9c-0p-QyP" secondAttribute="leading" constant="-3" id="CsE-Bf-Wq7"/>
<constraint firstItem="5IE-JS-uf3" firstAttribute="centerY" secondItem="Cot-3X-2cU" secondAttribute="centerY" id="H5t-l6-fL1"/>
<constraint firstItem="q9c-0p-QyP" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" constant="3" id="Ixr-7h-f8j"/>
<constraint firstItem="GGt-zb-6zg" firstAttribute="trailing" secondItem="q9c-0p-QyP" secondAttribute="trailing" constant="3" id="Ku9-ad-hb4"/>
<constraint firstAttribute="bottom" secondItem="kwd-hP-feC" secondAttribute="bottom" id="LQg-cI-Nkn"/>
<constraint firstAttribute="bottom" secondItem="5IE-JS-uf3" secondAttribute="bottom" constant="8" id="SHN-tC-zsJ"/>
<constraint firstAttribute="bottom" secondItem="IOg-Kt-8vW" secondAttribute="bottom" id="TPw-iE-nii"/>
<constraint firstItem="IOg-Kt-8vW" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" constant="18" id="XSL-TG-m62"/>
<constraint firstItem="q9c-0p-QyP" firstAttribute="leading" secondItem="hgp-Z5-rAj" secondAttribute="trailing" constant="3" id="YWK-C2-15w"/>
<constraint firstItem="GGt-zb-6zg" firstAttribute="top" secondItem="q9c-0p-QyP" secondAttribute="top" constant="-3" id="cqf-j2-9vP"/>
<constraint firstItem="zwq-eh-8Fb" firstAttribute="leading" secondItem="ef1-Tq-U3Z" secondAttribute="leading" constant="5" id="dgK-4e-UuE"/>
<constraint firstAttribute="trailing" secondItem="kwd-hP-feC" secondAttribute="trailing" id="f2V-Ka-kU3"/>
<constraint firstAttribute="trailing" secondItem="IOg-Kt-8vW" secondAttribute="trailing" constant="8" id="hQV-lO-7aQ"/>
<constraint firstItem="GGt-zb-6zg" firstAttribute="bottom" secondItem="q9c-0p-QyP" secondAttribute="bottom" constant="3" id="kYd-0y-Rcu"/>
<constraint firstItem="5IE-JS-uf3" firstAttribute="leading" secondItem="K9X-gn-noF" secondAttribute="leading" id="p93-5h-lvW"/>
<constraint firstItem="5IE-JS-uf3" firstAttribute="centerX" secondItem="Cot-3X-2cU" secondAttribute="centerX" id="sF7-QL-vdj"/>
<constraint firstItem="zwq-eh-8Fb" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" id="tUd-UR-lzA"/>
<constraint firstItem="hgp-Z5-rAj" firstAttribute="leading" secondItem="ef1-Tq-U3Z" secondAttribute="leading" constant="8" id="tuw-aU-ncu"/>
<constraint firstItem="5IE-JS-uf3" firstAttribute="centerY" secondItem="fdx-qs-8en" secondAttribute="centerY" id="v0F-Ts-14P"/>
<constraint firstItem="5IE-JS-uf3" firstAttribute="top" secondItem="K9X-gn-noF" secondAttribute="top" id="wkX-zQ-iQS"/>
<constraint firstAttribute="trailing" secondItem="fdx-qs-8en" secondAttribute="trailing" constant="13" id="xKk-Gz-moE"/>
</constraints>
</tableViewCellContentView>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<outlet property="attachViewBottomConstraint" destination="SHN-tC-zsJ" id="cG0-a7-eHa"/>
<outlet property="attachViewMinHeightConstraint" destination="C5F-6D-LZx" id="frk-Ox-WbA"/>
<outlet property="attachViewTopConstraint" destination="96U-67-5TP" id="Ugm-cH-32E"/>
<outlet property="attachViewWidthConstraint" destination="9zO-jU-qTb" id="fOO-VW-fe1"/>
<outlet property="attachmentView" destination="5IE-JS-uf3" id="imT-1z-hR1"/>
<outlet property="bubbleInfoContainer" destination="IOg-Kt-8vW" id="TAw-QY-Y9e"/>
<outlet property="bubbleInfoContainerTopConstraint" destination="XSL-TG-m62" id="qVf-vJ-4aP"/>
<outlet property="fileTypeIconView" destination="K9X-gn-noF" id="4Pj-bc-3gk"/>
<outlet property="pictureView" destination="hgp-Z5-rAj" id="rKM-QG-RJN"/>
<outlet property="playIconView" destination="Cot-3X-2cU" id="KEF-KK-Og1"/>
<outlet property="progressChartView" destination="hJj-TC-pxK" id="Zz3-s5-Qqr"/>
<outlet property="progressView" destination="fdx-qs-8en" id="V7E-pn-Xze"/>
<outlet property="statsLabel" destination="eU5-iK-u8i" id="MSm-kU-RSY"/>
<outlet property="typingBadge" destination="zwq-eh-8Fb" id="4vs-Dk-vWt"/>
<outlet property="userNameLabel" destination="q9c-0p-QyP" id="JId-R7-LoM"/>
<outlet property="userNameTapGestureMaskView" destination="GGt-zb-6zg" id="uV1-Jm-vLT"/>
</connections>
</tableViewCell>
</objects>
</document>
@@ -0,0 +1,24 @@
/*
Copyright 2015 OpenMarket 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 "MXKRoomIncomingAttachmentBubbleCell.h"
/**
`MXKRoomIncomingAttachmentWithoutSenderInfoBubbleCell` displays incoming message bubbles without sender's information.
*/
@interface MXKRoomIncomingAttachmentWithoutSenderInfoBubbleCell : MXKRoomIncomingAttachmentBubbleCell
@end
@@ -0,0 +1,21 @@
/*
Copyright 2015 OpenMarket 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 "MXKRoomIncomingAttachmentWithoutSenderInfoBubbleCell.h"
@implementation MXKRoomIncomingAttachmentWithoutSenderInfoBubbleCell
@end
@@ -0,0 +1,127 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11762" systemVersion="16C67" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
<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"/>
<tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="WmY-Jw-mqv" customClass="MXKRoomIncomingAttachmentWithoutSenderInfoBubbleCell">
<rect key="frame" x="0.0" y="0.0" width="600" height="50"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="WmY-Jw-mqv" id="ef1-Tq-U3Z">
<rect key="frame" x="0.0" y="0.0" width="600" height="49"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<view contentMode="scaleAspectFit" translatesAutoresizingMaskIntoConstraints="NO" id="5IE-JS-uf3" userLabel="Attachment View" customClass="MXKImageView">
<rect key="frame" x="51" y="8" width="192" height="33"/>
<color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803926" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" constant="192" id="9zO-jU-qTb"/>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="33" id="Uqr-7d-0dv"/>
</constraints>
</view>
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="K9X-gn-noF" userLabel="File Type Image View">
<rect key="frame" x="51" y="8" width="32" height="32"/>
<constraints>
<constraint firstAttribute="width" constant="32" id="OE8-oh-B7Q"/>
<constraint firstAttribute="height" constant="32" id="jJB-zj-fbT"/>
</constraints>
</imageView>
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Cot-3X-2cU" userLabel="Play Icon Image View">
<rect key="frame" x="131" y="9" width="32" height="32"/>
<constraints>
<constraint firstAttribute="height" constant="32" id="8io-Wk-GzF"/>
<constraint firstAttribute="width" constant="32" id="aeJ-j3-rfX"/>
</constraints>
</imageView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="kwd-hP-feC" userLabel="showHideDateTime">
<rect key="frame" x="531" y="0.0" width="69" height="49"/>
<constraints>
<constraint firstAttribute="width" constant="69" id="9vA-4g-EE5"/>
</constraints>
<state key="normal">
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="showHideDateTime:" destination="WmY-Jw-mqv" eventType="touchUpInside" id="jYV-nj-p60"/>
</connections>
</button>
<view hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="IOg-Kt-8vW" userLabel="bubbleInfoContainer">
<rect key="frame" x="531" y="8" width="61" height="41"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" constant="61" id="tLr-6k-ArA"/>
</constraints>
</view>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fdx-qs-8en" userLabel="ProgressView">
<rect key="frame" x="487" y="-10" width="100" height="70"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="rate" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="3" baselineAdjustment="alignBaselines" minimumFontSize="4" preferredMaxLayoutWidth="100" translatesAutoresizingMaskIntoConstraints="NO" id="eU5-iK-u8i" userLabel="Progress stats">
<rect key="frame" x="0.0" y="60" width="100" height="10"/>
<fontDescription key="fontDescription" type="system" pointSize="8"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<view userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="hJj-TC-pxK" customClass="MXKPieChartView">
<rect key="frame" x="30" y="0.0" width="40" height="40"/>
<constraints>
<constraint firstAttribute="width" constant="40" id="Cpt-s4-tlK"/>
<constraint firstAttribute="height" constant="40" id="Jb4-9E-tG0"/>
</constraints>
</view>
</subviews>
<gestureRecognizers/>
<constraints>
<constraint firstAttribute="height" constant="70" id="5w2-Hm-hZx"/>
<constraint firstAttribute="centerX" secondItem="eU5-iK-u8i" secondAttribute="centerX" id="APi-aE-mLc"/>
<constraint firstItem="eU5-iK-u8i" firstAttribute="leading" secondItem="fdx-qs-8en" secondAttribute="leading" id="Njw-3a-E9Y"/>
<constraint firstAttribute="bottom" secondItem="eU5-iK-u8i" secondAttribute="bottom" id="QMO-g9-QVE"/>
<constraint firstAttribute="centerX" secondItem="hJj-TC-pxK" secondAttribute="centerX" id="laR-Vg-ol3"/>
<constraint firstItem="hJj-TC-pxK" firstAttribute="top" secondItem="fdx-qs-8en" secondAttribute="top" id="ovD-8p-4dP"/>
<constraint firstAttribute="width" constant="100" id="ryE-fW-SgG"/>
<constraint firstAttribute="trailing" secondItem="eU5-iK-u8i" secondAttribute="trailing" id="teG-8q-BOX"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="kwd-hP-feC" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" id="5bB-HV-WAA"/>
<constraint firstItem="5IE-JS-uf3" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" constant="8" id="96U-67-5TP"/>
<constraint firstItem="5IE-JS-uf3" firstAttribute="centerY" secondItem="Cot-3X-2cU" secondAttribute="centerY" id="H5t-l6-fL1"/>
<constraint firstAttribute="bottom" secondItem="kwd-hP-feC" secondAttribute="bottom" id="LQg-cI-Nkn"/>
<constraint firstAttribute="bottom" secondItem="5IE-JS-uf3" secondAttribute="bottom" constant="8" id="SHN-tC-zsJ"/>
<constraint firstAttribute="bottom" secondItem="IOg-Kt-8vW" secondAttribute="bottom" id="TPw-iE-nii"/>
<constraint firstItem="IOg-Kt-8vW" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" constant="8" id="XSL-TG-m62"/>
<constraint firstItem="5IE-JS-uf3" firstAttribute="leading" secondItem="ef1-Tq-U3Z" secondAttribute="leading" constant="51" id="bSL-lG-ued"/>
<constraint firstAttribute="trailing" secondItem="kwd-hP-feC" secondAttribute="trailing" id="f2V-Ka-kU3"/>
<constraint firstAttribute="trailing" secondItem="IOg-Kt-8vW" secondAttribute="trailing" constant="8" id="hQV-lO-7aQ"/>
<constraint firstItem="5IE-JS-uf3" firstAttribute="leading" secondItem="K9X-gn-noF" secondAttribute="leading" id="p93-5h-lvW"/>
<constraint firstItem="5IE-JS-uf3" firstAttribute="centerX" secondItem="Cot-3X-2cU" secondAttribute="centerX" id="sF7-QL-vdj"/>
<constraint firstItem="5IE-JS-uf3" firstAttribute="centerY" secondItem="fdx-qs-8en" secondAttribute="centerY" id="v0F-Ts-14P"/>
<constraint firstItem="5IE-JS-uf3" firstAttribute="top" secondItem="K9X-gn-noF" secondAttribute="top" id="wkX-zQ-iQS"/>
<constraint firstAttribute="trailing" secondItem="fdx-qs-8en" secondAttribute="trailing" constant="13" id="xKk-Gz-moE"/>
</constraints>
</tableViewCellContentView>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<outlet property="attachViewBottomConstraint" destination="SHN-tC-zsJ" id="cG0-a7-eHa"/>
<outlet property="attachViewMinHeightConstraint" destination="Uqr-7d-0dv" id="UIs-4K-np5"/>
<outlet property="attachViewTopConstraint" destination="96U-67-5TP" id="Ugm-cH-32E"/>
<outlet property="attachViewWidthConstraint" destination="9zO-jU-qTb" id="fOO-VW-fe1"/>
<outlet property="attachmentView" destination="5IE-JS-uf3" id="imT-1z-hR1"/>
<outlet property="bubbleInfoContainer" destination="IOg-Kt-8vW" id="TAw-QY-Y9e"/>
<outlet property="bubbleInfoContainerTopConstraint" destination="XSL-TG-m62" id="qVf-vJ-4aP"/>
<outlet property="fileTypeIconView" destination="K9X-gn-noF" id="4Pj-bc-3gk"/>
<outlet property="playIconView" destination="Cot-3X-2cU" id="KEF-KK-Og1"/>
<outlet property="progressChartView" destination="hJj-TC-pxK" id="Zz3-s5-Qqr"/>
<outlet property="progressView" destination="fdx-qs-8en" id="V7E-pn-Xze"/>
<outlet property="statsLabel" destination="eU5-iK-u8i" id="MSm-kU-RSY"/>
</connections>
</tableViewCell>
</objects>
</document>
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="17701" 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="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@@ -128,6 +128,7 @@
<connections>
<outlet property="activityIndicator" destination="OrM-nA-kyg" id="Frc-ED-PlH"/>
<outlet property="attachViewBottomConstraint" destination="SHN-tC-zsJ" id="cG0-a7-eHa"/>
<outlet property="attachViewLeadingConstraint" destination="p93-5h-lvW" id="WRx-S5-r3M"/>
<outlet property="attachViewMinHeightConstraint" destination="C5F-6D-LZx" id="frk-Ox-WbA"/>
<outlet property="attachViewTopConstraint" destination="96U-67-5TP" id="Ugm-cH-32E"/>
<outlet property="attachViewWidthConstraint" destination="9zO-jU-qTb" id="fOO-VW-fe1"/>
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="17701" 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="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@@ -161,6 +161,7 @@
<connections>
<outlet property="activityIndicator" destination="jmK-pe-WZd" id="F7y-hE-pcg"/>
<outlet property="attachViewBottomConstraint" destination="SHN-tC-zsJ" id="cG0-a7-eHa"/>
<outlet property="attachViewLeadingConstraint" destination="6mM-Ag-m0K" id="lG4-bl-Kio"/>
<outlet property="attachViewMinHeightConstraint" destination="C5F-6D-LZx" id="frk-Ox-WbA"/>
<outlet property="attachViewTopConstraint" destination="96U-67-5TP" id="Ugm-cH-32E"/>
<outlet property="attachViewWidthConstraint" destination="9zO-jU-qTb" id="fOO-VW-fe1"/>
@@ -0,0 +1,24 @@
/*
Copyright 2015 OpenMarket 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 "RoomOutgoingAttachmentWithPaginationTitleBubbleCell.h"
/**
`RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell` displays outgoing attachment bubbles and pagination title but no sender name.
*/
@interface RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell : RoomOutgoingAttachmentWithPaginationTitleBubbleCell
@end
@@ -0,0 +1,32 @@
/*
Copyright 2015 OpenMarket Ltd
Copyright 2017 Vector Creations 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 "RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell.h"
#import "ThemeService.h"
#import "GeneratedInterface-Swift.h"
@implementation RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell
- (void)customizeTableViewCellRendering
{
[super customizeTableViewCellRendering];
self.messageTextView.tintColor = ThemeService.shared.theme.tintColor;
}
@end
@@ -0,0 +1,161 @@
<?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="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
<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"/>
<tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="WmY-Jw-mqv" customClass="RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell">
<rect key="frame" x="0.0" y="0.0" width="600" height="120"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="WmY-Jw-mqv" id="ef1-Tq-U3Z">
<rect key="frame" x="0.0" y="0.0" width="600" height="120"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="SFg-55-RF4" userLabel="Pagination Title View">
<rect key="frame" x="56" y="10" width="534" height="24"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="wkY-7Y-sGw" userLabel="Pagination Label">
<rect key="frame" x="0.0" y="0.0" width="524" height="18"/>
<constraints>
<constraint firstAttribute="height" constant="18" id="PiZ-Ag-oxc"/>
</constraints>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<color key="textColor" red="0.66666666666666663" green="0.66666666666666663" blue="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="0kR-4b-Wav" userLabel="Pagination Separator View">
<rect key="frame" x="0.0" y="23" width="534" 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="trailing" secondItem="wkY-7Y-sGw" secondAttribute="trailing" constant="10" id="4DU-xA-diS"/>
<constraint firstItem="wkY-7Y-sGw" firstAttribute="top" secondItem="SFg-55-RF4" secondAttribute="top" id="6Cz-bj-kUg"/>
<constraint firstItem="0kR-4b-Wav" firstAttribute="top" secondItem="wkY-7Y-sGw" secondAttribute="bottom" constant="5" id="K4B-zf-5x2"/>
<constraint firstAttribute="height" constant="24" id="Qo9-cw-LCa"/>
<constraint firstAttribute="trailing" secondItem="0kR-4b-Wav" secondAttribute="trailing" id="fnd-bR-QmB"/>
<constraint firstAttribute="bottom" secondItem="0kR-4b-Wav" secondAttribute="bottom" id="pBK-pC-oCA"/>
<constraint firstItem="0kR-4b-Wav" firstAttribute="leading" secondItem="SFg-55-RF4" secondAttribute="leading" id="rhH-Hz-w9J"/>
<constraint firstItem="wkY-7Y-sGw" firstAttribute="leading" secondItem="SFg-55-RF4" secondAttribute="leading" id="uq9-MP-Dmm"/>
</constraints>
</view>
<view clipsSubviews="YES" contentMode="scaleAspectFill" translatesAutoresizingMaskIntoConstraints="NO" id="hgp-Z5-rAj" userLabel="Picture View" customClass="MXKImageView">
<rect key="frame" x="13" y="54" width="30" height="30"/>
<color key="backgroundColor" red="0.66666666666666663" green="0.66666666666666663" blue="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<accessibility key="accessibilityConfiguration" identifier="PictureView"/>
<constraints>
<constraint firstAttribute="width" constant="30" id="NQk-ck-Lo8"/>
<constraint firstAttribute="height" constant="30" id="dNT-QU-CUG"/>
</constraints>
</view>
<view contentMode="scaleAspectFit" translatesAutoresizingMaskIntoConstraints="NO" id="5IE-JS-uf3" userLabel="Attachment View" customClass="MXKImageView">
<rect key="frame" x="56" y="45" width="192" height="65"/>
<color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803926" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<accessibility key="accessibilityConfiguration" identifier="AttachmentView"/>
<constraints>
<constraint firstAttribute="width" constant="192" id="9zO-jU-qTb"/>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="34" id="C5F-6D-LZx"/>
</constraints>
</view>
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="K9X-gn-noF" userLabel="File Type Image View">
<rect key="frame" x="56" y="45" width="32" height="32"/>
<accessibility key="accessibilityConfiguration" identifier="FileTypeImageView"/>
<constraints>
<constraint firstAttribute="width" constant="32" id="OE8-oh-B7Q"/>
<constraint firstAttribute="height" constant="32" id="jJB-zj-fbT"/>
</constraints>
</imageView>
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Cot-3X-2cU" userLabel="Play Icon Image View">
<rect key="frame" x="136" y="61.5" width="32" height="32"/>
<accessibility key="accessibilityConfiguration" identifier="PlayIconImageView"/>
<constraints>
<constraint firstAttribute="height" constant="32" id="8io-Wk-GzF"/>
<constraint firstAttribute="width" constant="32" id="aeJ-j3-rfX"/>
</constraints>
</imageView>
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="jmK-pe-WZd">
<rect key="frame" x="142" y="67.5" width="20" height="20"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="accessibilityIdentifier" value="ActivityIndicator"/>
</userDefinedRuntimeAttributes>
</activityIndicatorView>
<view hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="IOg-Kt-8vW">
<rect key="frame" x="515" y="54" width="70" height="66"/>
<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="70" id="tLr-6k-ArA"/>
</constraints>
</view>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fdx-qs-8en" userLabel="ProgressView">
<rect key="frame" x="487" y="50" width="100" height="70"/>
<gestureRecognizers/>
<constraints>
<constraint firstAttribute="height" constant="70" id="5w2-Hm-hZx"/>
<constraint firstAttribute="width" constant="100" id="ryE-fW-SgG"/>
</constraints>
</view>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="3b7-4a-YL0">
<rect key="frame" x="8" y="3" width="584" height="114"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</view>
</subviews>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="3b7-4a-YL0" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="topMargin" constant="-8" id="10i-70-PDz"/>
<constraint firstItem="hgp-Z5-rAj" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" constant="54" id="2Ih-ga-N9s"/>
<constraint firstItem="5IE-JS-uf3" firstAttribute="leading" secondItem="hgp-Z5-rAj" secondAttribute="trailing" constant="13" id="6mM-Ag-m0K"/>
<constraint firstItem="5IE-JS-uf3" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" constant="45" id="96U-67-5TP"/>
<constraint firstAttribute="bottom" secondItem="fdx-qs-8en" secondAttribute="bottom" id="AeT-4F-mKp"/>
<constraint firstItem="5IE-JS-uf3" firstAttribute="centerY" secondItem="Cot-3X-2cU" secondAttribute="centerY" id="H5t-l6-fL1"/>
<constraint firstItem="SFg-55-RF4" firstAttribute="leading" secondItem="ef1-Tq-U3Z" secondAttribute="leading" constant="56" id="I4N-5Q-LFe"/>
<constraint firstItem="jmK-pe-WZd" firstAttribute="centerX" secondItem="5IE-JS-uf3" secondAttribute="centerX" id="IoK-NR-EyQ"/>
<constraint firstAttribute="bottom" secondItem="5IE-JS-uf3" secondAttribute="bottom" constant="10" id="SHN-tC-zsJ"/>
<constraint firstAttribute="bottom" secondItem="IOg-Kt-8vW" secondAttribute="bottom" id="TPw-iE-nii"/>
<constraint firstItem="IOg-Kt-8vW" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" constant="54" id="XSL-TG-m62"/>
<constraint firstItem="3b7-4a-YL0" firstAttribute="leading" secondItem="ef1-Tq-U3Z" secondAttribute="leadingMargin" constant="-8" id="aGh-ad-trR"/>
<constraint firstAttribute="trailingMargin" secondItem="3b7-4a-YL0" secondAttribute="trailing" constant="-8" id="abE-n9-N8T"/>
<constraint firstAttribute="trailing" secondItem="IOg-Kt-8vW" secondAttribute="trailing" constant="15" id="hQV-lO-7aQ"/>
<constraint firstAttribute="trailing" secondItem="SFg-55-RF4" secondAttribute="trailing" constant="10" id="jvR-oT-EQF"/>
<constraint firstItem="5IE-JS-uf3" firstAttribute="leading" secondItem="K9X-gn-noF" secondAttribute="leading" id="p93-5h-lvW"/>
<constraint firstItem="jmK-pe-WZd" firstAttribute="centerY" secondItem="5IE-JS-uf3" secondAttribute="centerY" id="qqJ-jh-rGK"/>
<constraint firstItem="5IE-JS-uf3" firstAttribute="centerX" secondItem="Cot-3X-2cU" secondAttribute="centerX" id="sF7-QL-vdj"/>
<constraint firstItem="hgp-Z5-rAj" firstAttribute="leading" secondItem="ef1-Tq-U3Z" secondAttribute="leading" constant="13" id="tuw-aU-ncu"/>
<constraint firstItem="SFg-55-RF4" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" constant="10" id="wJX-7V-bJB"/>
<constraint firstItem="5IE-JS-uf3" firstAttribute="top" secondItem="K9X-gn-noF" secondAttribute="top" id="wkX-zQ-iQS"/>
<constraint firstAttribute="bottomMargin" secondItem="3b7-4a-YL0" secondAttribute="bottom" constant="-8" id="wpa-8Z-Gy3"/>
<constraint firstAttribute="trailing" secondItem="fdx-qs-8en" secondAttribute="trailing" constant="13" id="xKk-Gz-moE"/>
</constraints>
</tableViewCellContentView>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<accessibility key="accessibilityConfiguration" identifier="RoomBubbleCell"/>
<connections>
<outlet property="activityIndicator" destination="jmK-pe-WZd" id="F7y-hE-pcg"/>
<outlet property="attachViewBottomConstraint" destination="SHN-tC-zsJ" id="cG0-a7-eHa"/>
<outlet property="attachViewLeadingConstraint" destination="6mM-Ag-m0K" id="lG4-bl-Kio"/>
<outlet property="attachViewMinHeightConstraint" destination="C5F-6D-LZx" id="frk-Ox-WbA"/>
<outlet property="attachViewTopConstraint" destination="96U-67-5TP" id="Ugm-cH-32E"/>
<outlet property="attachViewWidthConstraint" destination="9zO-jU-qTb" id="fOO-VW-fe1"/>
<outlet property="attachmentView" destination="5IE-JS-uf3" id="imT-1z-hR1"/>
<outlet property="bubbleInfoContainer" destination="IOg-Kt-8vW" id="TAw-QY-Y9e"/>
<outlet property="bubbleInfoContainerTopConstraint" destination="XSL-TG-m62" id="qVf-vJ-4aP"/>
<outlet property="bubbleOverlayContainer" destination="3b7-4a-YL0" id="KNb-h4-YHD"/>
<outlet property="fileTypeIconView" destination="K9X-gn-noF" id="4Pj-bc-3gk"/>
<outlet property="paginationLabel" destination="wkY-7Y-sGw" id="9Uh-tX-t0I"/>
<outlet property="paginationSeparatorView" destination="0kR-4b-Wav" id="c7x-Sh-aj6"/>
<outlet property="paginationTitleView" destination="SFg-55-RF4" id="mbP-6I-gOn"/>
<outlet property="pictureView" destination="hgp-Z5-rAj" id="rKM-QG-RJN"/>
<outlet property="playIconView" destination="Cot-3X-2cU" id="KEF-KK-Og1"/>
<outlet property="progressView" destination="fdx-qs-8en" id="V7E-pn-Xze"/>
</connections>
<point key="canvasLocation" x="-26" y="113"/>
</tableViewCell>
</objects>
</document>
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="17701" 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="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@@ -95,6 +95,7 @@
<connections>
<outlet property="activityIndicator" destination="8Bq-Mk-bN8" id="cbT-lK-yjP"/>
<outlet property="attachViewBottomConstraint" destination="SHN-tC-zsJ" id="cG0-a7-eHa"/>
<outlet property="attachViewLeadingConstraint" destination="bSL-lG-ued" id="M5E-Ot-73d"/>
<outlet property="attachViewMinHeightConstraint" destination="Uqr-7d-0dv" id="UIs-4K-np5"/>
<outlet property="attachViewTopConstraint" destination="96U-67-5TP" id="Ugm-cH-32E"/>
<outlet property="attachViewWidthConstraint" destination="9zO-jU-qTb" id="fOO-VW-fe1"/>
@@ -0,0 +1,26 @@
/*
Copyright 2015 OpenMarket 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 "MXKRoomOutgoingBubbleTableViewCell.h"
/**
`MXKRoomOutgoingAttachmentBubbleCell` displays outgoing attachment bubbles.
*/
@interface MXKRoomOutgoingAttachmentBubbleCell : MXKRoomOutgoingBubbleTableViewCell
@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicator;
@end
@@ -0,0 +1,155 @@
/*
Copyright 2015 OpenMarket Ltd
Copyright 2018 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 "MXKRoomOutgoingAttachmentBubbleCell.h"
#import "MXEvent+MatrixKit.h"
#import "MXKRoomBubbleCellData.h"
#import "MXKImageView.h"
#import "MXKPieChartView.h"
#import "GeneratedInterface-Swift.h"
@implementation MXKRoomOutgoingAttachmentBubbleCell
- (void)dealloc
{
[self stopAnimating];
}
- (void)setupViews
{
[super setupViews];
RoomTimelineConfiguration *timelineConfiguration = [RoomTimelineConfiguration shared];
[timelineConfiguration.currentStyle.cellLayoutUpdater setupLayoutForOutgoingFileAttachmentCell:self];
}
- (void)render:(MXKCellData *)cellData
{
[super render:cellData];
if (bubbleData)
{
// Do not display activity indicator on outgoing attachments (These attachments are supposed to be stored locally)
// Some download may append to retrieve the actual thumbnail after posting an image.
self.attachmentView.hideActivityIndicator = YES;
// Check if the attachment is uploading
MXKRoomBubbleComponent *component = bubbleData.bubbleComponents.firstObject;
if (component.event.sentState == MXEventSentStatePreparing || component.event.sentState == MXEventSentStateEncrypting || component.event.sentState == MXEventSentStateUploading)
{
// Retrieve the uploadId embedded in the fake url
bubbleData.uploadId = component.event.content[@"url"];
self.attachmentView.alpha = 0.5;
// Start showing upload progress
[self startUploadAnimating];
}
else if (component.event.sentState == MXEventSentStateSending)
{
self.attachmentView.alpha = 0.5;
[self.activityIndicator startAnimating];
}
else if (component.event.sentState == MXEventSentStateFailed)
{
self.attachmentView.alpha = 0.5;
[self.activityIndicator stopAnimating];
}
else
{
self.attachmentView.alpha = 1;
[self.activityIndicator stopAnimating];
}
}
}
- (void)didEndDisplay
{
[super didEndDisplay];
// Hide potential loading wheel
[self stopAnimating];
}
-(void)startUploadAnimating
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMXMediaLoaderStateDidChangeNotification object:nil];
[self.activityIndicator startAnimating];
MXMediaLoader *uploader = [MXMediaManager existingUploaderWithId:bubbleData.uploadId];
if (uploader)
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onMediaLoaderStateDidChange:) name:kMXMediaLoaderStateDidChangeNotification object:uploader];
if (uploader.statisticsDict)
{
[self.activityIndicator stopAnimating];
[self updateProgressUI:uploader.statisticsDict];
// Check whether the upload is ended
if (self.progressChartView.progress == 1.0)
{
[self stopAnimating];
}
}
}
else
{
self.progressView.hidden = YES;
}
}
-(void)stopAnimating
{
self.progressView.hidden = YES;
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMXMediaLoaderStateDidChangeNotification object:nil];
[self.activityIndicator stopAnimating];
}
- (void)onMediaLoaderStateDidChange:(NSNotification *)notif
{
MXMediaLoader *loader = (MXMediaLoader*)notif.object;
// Consider only the progress of the current upload.
if ([loader.uploadId isEqualToString:bubbleData.uploadId])
{
switch (loader.state) {
case MXMediaLoaderStateUploadInProgress:
{
[self.activityIndicator stopAnimating];
[self updateProgressUI:loader.statisticsDict];
// the upload is ended
if (self.progressChartView.progress == 1.0)
{
[self stopAnimating];
}
break;
}
default:
break;
}
}
}
@end
@@ -0,0 +1,144 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11762" systemVersion="16C67" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
<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"/>
<tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="pad-g3-2YJ" customClass="MXKRoomOutgoingAttachmentBubbleCell">
<rect key="frame" x="0.0" y="0.0" width="600" height="50"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="pad-g3-2YJ" id="fCg-ju-gnG">
<rect key="frame" x="0.0" y="0.0" width="600" height="49"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<view clipsSubviews="YES" contentMode="scaleAspectFill" translatesAutoresizingMaskIntoConstraints="NO" id="ezT-Dl-ESR" userLabel="Picture View" customClass="MXKImageView">
<rect key="frame" x="552" y="5" width="40" height="40"/>
<color key="backgroundColor" red="0.66666666666666663" green="0.66666666666666663" blue="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" constant="40" id="JHc-dD-geb"/>
<constraint firstAttribute="height" constant="40" id="lFb-Jo-C7R"/>
</constraints>
</view>
<view contentMode="scaleAspectFit" translatesAutoresizingMaskIntoConstraints="NO" id="SIW-l4-PfI" userLabel="Attachment View" customClass="MXKImageView">
<rect key="frame" x="357" y="18" width="192" height="23"/>
<color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803926" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" constant="192" id="iGr-e7-bde"/>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="23" id="kGW-IH-XnB"/>
</constraints>
</view>
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="KGx-6M-GER" userLabel="File Type Image View">
<rect key="frame" x="357" y="18" width="32" height="32"/>
<constraints>
<constraint firstAttribute="height" constant="32" id="QGB-Md-MLn"/>
<constraint firstAttribute="width" constant="32" id="h7Q-f3-gtz"/>
</constraints>
</imageView>
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="ZC1-hT-7fs" userLabel="Play Icon Image View">
<rect key="frame" x="437" y="14" width="32" height="32"/>
<constraints>
<constraint firstAttribute="width" constant="32" id="MOQ-Xi-18w"/>
<constraint firstAttribute="height" constant="32" id="pGM-pf-SiP"/>
</constraints>
</imageView>
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="Mqf-7a-bsm">
<rect key="frame" x="443" y="20" width="20" height="20"/>
</activityIndicatorView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="LVJ-Av-zVs" userLabel="showHideDateTime">
<rect key="frame" x="0.0" y="0.0" width="69" height="49"/>
<constraints>
<constraint firstAttribute="width" constant="69" id="ghQ-Qb-BBg"/>
</constraints>
<state key="normal">
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="showHideDateTime:" destination="pad-g3-2YJ" eventType="touchUpInside" id="Ztw-z5-zlU"/>
</connections>
</button>
<view hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="a51-cR-7FE" userLabel="bubbleInfoContainer">
<rect key="frame" x="8" y="18" width="61" height="31"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" constant="61" id="fDy-iL-hrD"/>
</constraints>
</view>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="apW-hM-veR" userLabel="ProgressView">
<rect key="frame" x="18" y="-5" width="100" height="70"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="text" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="3" baselineAdjustment="alignBaselines" minimumFontSize="4" preferredMaxLayoutWidth="100" translatesAutoresizingMaskIntoConstraints="NO" id="DYj-Mb-me4" userLabel="Progress stats">
<rect key="frame" x="0.0" y="60" width="100" height="10"/>
<fontDescription key="fontDescription" type="system" pointSize="8"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<view userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Oec-kb-Tsz" customClass="MXKPieChartView">
<rect key="frame" x="30" y="0.0" width="40" height="40"/>
<constraints>
<constraint firstAttribute="height" constant="40" id="6tZ-ag-7TT"/>
<constraint firstAttribute="width" constant="40" id="duC-38-cLC"/>
</constraints>
</view>
</subviews>
<gestureRecognizers/>
<constraints>
<constraint firstItem="Oec-kb-Tsz" firstAttribute="top" secondItem="apW-hM-veR" secondAttribute="top" id="49H-ch-qkC"/>
<constraint firstAttribute="height" constant="70" id="GhG-zB-k3A"/>
<constraint firstAttribute="centerX" secondItem="Oec-kb-Tsz" secondAttribute="centerX" id="KZy-2p-KaW"/>
<constraint firstItem="DYj-Mb-me4" firstAttribute="leading" secondItem="apW-hM-veR" secondAttribute="leading" id="UxL-bV-5Ca"/>
<constraint firstAttribute="bottom" secondItem="DYj-Mb-me4" secondAttribute="bottom" id="YFp-gQ-NFz"/>
<constraint firstAttribute="width" constant="100" id="Zr4-5T-h9g"/>
<constraint firstAttribute="trailing" secondItem="DYj-Mb-me4" secondAttribute="trailing" id="ehN-ME-1U1"/>
<constraint firstAttribute="centerX" secondItem="DYj-Mb-me4" secondAttribute="centerX" id="nuq-lO-8pT"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="SIW-l4-PfI" firstAttribute="centerX" secondItem="Mqf-7a-bsm" secondAttribute="centerX" id="1b6-1l-hg0"/>
<constraint firstAttribute="trailing" secondItem="ezT-Dl-ESR" secondAttribute="trailing" constant="8" id="3Pd-Qy-Xva"/>
<constraint firstItem="ezT-Dl-ESR" firstAttribute="leading" secondItem="SIW-l4-PfI" secondAttribute="trailing" constant="3" id="9z3-D2-2SS"/>
<constraint firstItem="a51-cR-7FE" firstAttribute="leading" secondItem="fCg-ju-gnG" secondAttribute="leading" constant="8" id="E3x-h8-GPF"/>
<constraint firstItem="LVJ-Av-zVs" firstAttribute="leading" secondItem="fCg-ju-gnG" secondAttribute="leading" id="Hve-E3-z5N"/>
<constraint firstAttribute="bottom" secondItem="LVJ-Av-zVs" secondAttribute="bottom" id="IKr-Dc-HKz"/>
<constraint firstItem="apW-hM-veR" firstAttribute="leading" secondItem="fCg-ju-gnG" secondAttribute="leading" constant="18" id="LFn-vp-m0v"/>
<constraint firstItem="SIW-l4-PfI" firstAttribute="top" secondItem="fCg-ju-gnG" secondAttribute="top" constant="18" id="QDm-tP-KWa"/>
<constraint firstItem="ezT-Dl-ESR" firstAttribute="top" secondItem="fCg-ju-gnG" secondAttribute="top" constant="5" id="aHl-KA-68x"/>
<constraint firstAttribute="bottom" secondItem="SIW-l4-PfI" secondAttribute="bottom" constant="8" id="fMN-Th-SOT"/>
<constraint firstItem="a51-cR-7FE" firstAttribute="top" secondItem="fCg-ju-gnG" secondAttribute="top" constant="18" id="fQv-07-Pgx"/>
<constraint firstItem="SIW-l4-PfI" firstAttribute="centerY" secondItem="ZC1-hT-7fs" secondAttribute="centerY" id="ffI-vh-SW3"/>
<constraint firstItem="SIW-l4-PfI" firstAttribute="leading" secondItem="KGx-6M-GER" secondAttribute="leading" id="j1U-XX-IZW"/>
<constraint firstItem="SIW-l4-PfI" firstAttribute="centerX" secondItem="ZC1-hT-7fs" secondAttribute="centerX" id="jah-TA-P0P"/>
<constraint firstItem="SIW-l4-PfI" firstAttribute="top" secondItem="KGx-6M-GER" secondAttribute="top" id="loA-GI-HkT"/>
<constraint firstItem="LVJ-Av-zVs" firstAttribute="top" secondItem="fCg-ju-gnG" secondAttribute="top" id="pYO-hi-P72"/>
<constraint firstItem="SIW-l4-PfI" firstAttribute="centerY" secondItem="Mqf-7a-bsm" secondAttribute="centerY" id="sKJ-ny-LjM"/>
<constraint firstAttribute="bottom" secondItem="a51-cR-7FE" secondAttribute="bottom" id="viZ-Sx-3RW"/>
<constraint firstItem="apW-hM-veR" firstAttribute="centerY" secondItem="SIW-l4-PfI" secondAttribute="centerY" id="wmh-x1-U32"/>
</constraints>
</tableViewCellContentView>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<outlet property="activityIndicator" destination="Mqf-7a-bsm" id="toi-nL-eJa"/>
<outlet property="attachViewBottomConstraint" destination="fMN-Th-SOT" id="WVk-1p-S0P"/>
<outlet property="attachViewMinHeightConstraint" destination="kGW-IH-XnB" id="97f-NR-EDv"/>
<outlet property="attachViewTopConstraint" destination="QDm-tP-KWa" id="Ku6-FC-jqo"/>
<outlet property="attachViewWidthConstraint" destination="iGr-e7-bde" id="uD4-aU-1Ru"/>
<outlet property="attachmentView" destination="SIW-l4-PfI" id="L4H-ub-pPI"/>
<outlet property="bubbleInfoContainer" destination="a51-cR-7FE" id="wrR-cU-DVm"/>
<outlet property="bubbleInfoContainerTopConstraint" destination="fQv-07-Pgx" id="82c-KH-Wop"/>
<outlet property="fileTypeIconView" destination="KGx-6M-GER" id="MXF-4w-mY7"/>
<outlet property="pictureView" destination="ezT-Dl-ESR" id="YsO-Kp-xaD"/>
<outlet property="playIconView" destination="ZC1-hT-7fs" id="zeH-8B-gxw"/>
<outlet property="progressChartView" destination="Oec-kb-Tsz" id="uoq-6v-6Tm"/>
<outlet property="progressView" destination="apW-hM-veR" id="Iy8-ca-hMi"/>
<outlet property="statsLabel" destination="DYj-Mb-me4" id="CbG-5V-unO"/>
</connections>
</tableViewCell>
</objects>
</document>
@@ -0,0 +1,24 @@
/*
Copyright 2015 OpenMarket 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 "MXKRoomOutgoingAttachmentBubbleCell.h"
/**
`MXKRoomOutgoingAttachmentWithoutSenderInfoBubbleCell` displays outgoing attachment with thumbnail, without user's name.
*/
@interface MXKRoomOutgoingAttachmentWithoutSenderInfoBubbleCell : MXKRoomOutgoingAttachmentBubbleCell
@end
@@ -0,0 +1,21 @@
/*
Copyright 2015 OpenMarket 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 "MXKRoomOutgoingAttachmentWithoutSenderInfoBubbleCell.h"
@implementation MXKRoomOutgoingAttachmentWithoutSenderInfoBubbleCell
@end
@@ -0,0 +1,132 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11762" systemVersion="16C67" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
<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"/>
<tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="pad-g3-2YJ" customClass="MXKRoomOutgoingAttachmentWithoutSenderInfoBubbleCell">
<rect key="frame" x="0.0" y="0.0" width="600" height="50"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="pad-g3-2YJ" id="fCg-ju-gnG">
<rect key="frame" x="0.0" y="0.0" width="600" height="49"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<view contentMode="scaleAspectFit" translatesAutoresizingMaskIntoConstraints="NO" id="SIW-l4-PfI" userLabel="Attachment View" customClass="MXKImageView">
<rect key="frame" x="357" y="8" width="192" height="33"/>
<color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803926" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" constant="192" id="iGr-e7-bde"/>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="33" id="nSK-Ug-3Q4"/>
</constraints>
</view>
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="KGx-6M-GER" userLabel="File Type Image View">
<rect key="frame" x="357" y="8" width="32" height="32"/>
<constraints>
<constraint firstAttribute="height" constant="32" id="QGB-Md-MLn"/>
<constraint firstAttribute="width" constant="32" id="h7Q-f3-gtz"/>
</constraints>
</imageView>
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="ZC1-hT-7fs" userLabel="Play Icon Image View">
<rect key="frame" x="437" y="9" width="32" height="32"/>
<constraints>
<constraint firstAttribute="width" constant="32" id="MOQ-Xi-18w"/>
<constraint firstAttribute="height" constant="32" id="pGM-pf-SiP"/>
</constraints>
</imageView>
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="Mqf-7a-bsm">
<rect key="frame" x="443" y="15" width="20" height="20"/>
</activityIndicatorView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="LVJ-Av-zVs" userLabel="showHideDateTime">
<rect key="frame" x="0.0" y="0.0" width="69" height="49"/>
<constraints>
<constraint firstAttribute="width" constant="69" id="ghQ-Qb-BBg"/>
</constraints>
<state key="normal">
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="showHideDateTime:" destination="pad-g3-2YJ" eventType="touchUpInside" id="Ztw-z5-zlU"/>
</connections>
</button>
<view hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="a51-cR-7FE" userLabel="bubbleInfoContainer">
<rect key="frame" x="8" y="8" width="61" height="41"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" constant="61" id="fDy-iL-hrD"/>
</constraints>
</view>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="apW-hM-veR" userLabel="ProgressView">
<rect key="frame" x="18" y="-10" width="100" height="70"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="text" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="3" baselineAdjustment="alignBaselines" minimumFontSize="4" preferredMaxLayoutWidth="100" translatesAutoresizingMaskIntoConstraints="NO" id="DYj-Mb-me4" userLabel="Progress stats">
<rect key="frame" x="0.0" y="60" width="100" height="10"/>
<fontDescription key="fontDescription" type="system" pointSize="8"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<view userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Oec-kb-Tsz" customClass="MXKPieChartView">
<rect key="frame" x="30" y="0.0" width="40" height="40"/>
<constraints>
<constraint firstAttribute="height" constant="40" id="6tZ-ag-7TT"/>
<constraint firstAttribute="width" constant="40" id="duC-38-cLC"/>
</constraints>
</view>
</subviews>
<gestureRecognizers/>
<constraints>
<constraint firstItem="Oec-kb-Tsz" firstAttribute="top" secondItem="apW-hM-veR" secondAttribute="top" id="49H-ch-qkC"/>
<constraint firstAttribute="height" constant="70" id="GhG-zB-k3A"/>
<constraint firstAttribute="centerX" secondItem="Oec-kb-Tsz" secondAttribute="centerX" id="KZy-2p-KaW"/>
<constraint firstItem="DYj-Mb-me4" firstAttribute="leading" secondItem="apW-hM-veR" secondAttribute="leading" id="UxL-bV-5Ca"/>
<constraint firstAttribute="bottom" secondItem="DYj-Mb-me4" secondAttribute="bottom" id="YFp-gQ-NFz"/>
<constraint firstAttribute="width" constant="100" id="Zr4-5T-h9g"/>
<constraint firstAttribute="trailing" secondItem="DYj-Mb-me4" secondAttribute="trailing" id="ehN-ME-1U1"/>
<constraint firstAttribute="centerX" secondItem="DYj-Mb-me4" secondAttribute="centerX" id="nuq-lO-8pT"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="SIW-l4-PfI" firstAttribute="centerX" secondItem="Mqf-7a-bsm" secondAttribute="centerX" id="1b6-1l-hg0"/>
<constraint firstItem="a51-cR-7FE" firstAttribute="leading" secondItem="fCg-ju-gnG" secondAttribute="leading" constant="8" id="E3x-h8-GPF"/>
<constraint firstItem="LVJ-Av-zVs" firstAttribute="leading" secondItem="fCg-ju-gnG" secondAttribute="leading" id="Hve-E3-z5N"/>
<constraint firstAttribute="bottom" secondItem="LVJ-Av-zVs" secondAttribute="bottom" id="IKr-Dc-HKz"/>
<constraint firstItem="apW-hM-veR" firstAttribute="leading" secondItem="fCg-ju-gnG" secondAttribute="leading" constant="18" id="LFn-vp-m0v"/>
<constraint firstItem="SIW-l4-PfI" firstAttribute="top" secondItem="fCg-ju-gnG" secondAttribute="top" constant="8" id="QDm-tP-KWa"/>
<constraint firstAttribute="bottom" secondItem="SIW-l4-PfI" secondAttribute="bottom" constant="8" id="fMN-Th-SOT"/>
<constraint firstItem="SIW-l4-PfI" firstAttribute="centerY" secondItem="ZC1-hT-7fs" secondAttribute="centerY" id="ffI-vh-SW3"/>
<constraint firstItem="SIW-l4-PfI" firstAttribute="leading" secondItem="KGx-6M-GER" secondAttribute="leading" id="j1U-XX-IZW"/>
<constraint firstItem="SIW-l4-PfI" firstAttribute="centerX" secondItem="ZC1-hT-7fs" secondAttribute="centerX" id="jah-TA-P0P"/>
<constraint firstItem="SIW-l4-PfI" firstAttribute="top" secondItem="KGx-6M-GER" secondAttribute="top" id="loA-GI-HkT"/>
<constraint firstItem="LVJ-Av-zVs" firstAttribute="top" secondItem="fCg-ju-gnG" secondAttribute="top" id="pYO-hi-P72"/>
<constraint firstItem="SIW-l4-PfI" firstAttribute="centerY" secondItem="Mqf-7a-bsm" secondAttribute="centerY" id="sKJ-ny-LjM"/>
<constraint firstAttribute="bottom" secondItem="a51-cR-7FE" secondAttribute="bottom" id="viZ-Sx-3RW"/>
<constraint firstAttribute="trailing" secondItem="SIW-l4-PfI" secondAttribute="trailing" constant="51" id="wgx-Zr-5R6"/>
<constraint firstItem="apW-hM-veR" firstAttribute="centerY" secondItem="SIW-l4-PfI" secondAttribute="centerY" id="wmh-x1-U32"/>
<constraint firstItem="a51-cR-7FE" firstAttribute="top" secondItem="fCg-ju-gnG" secondAttribute="top" constant="8" id="xop-v3-Xh2"/>
</constraints>
</tableViewCellContentView>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<outlet property="activityIndicator" destination="Mqf-7a-bsm" id="toi-nL-eJa"/>
<outlet property="attachViewBottomConstraint" destination="fMN-Th-SOT" id="fw0-N9-RUj"/>
<outlet property="attachViewMinHeightConstraint" destination="nSK-Ug-3Q4" id="rfM-Ha-vVp"/>
<outlet property="attachViewTopConstraint" destination="QDm-tP-KWa" id="Ku6-FC-jqo"/>
<outlet property="attachViewWidthConstraint" destination="iGr-e7-bde" id="uD4-aU-1Ru"/>
<outlet property="attachmentView" destination="SIW-l4-PfI" id="L4H-ub-pPI"/>
<outlet property="bubbleInfoContainer" destination="a51-cR-7FE" id="wrR-cU-DVm"/>
<outlet property="fileTypeIconView" destination="KGx-6M-GER" id="MXF-4w-mY7"/>
<outlet property="playIconView" destination="ZC1-hT-7fs" id="zeH-8B-gxw"/>
<outlet property="progressChartView" destination="Oec-kb-Tsz" id="uoq-6v-6Tm"/>
<outlet property="progressView" destination="apW-hM-veR" id="Iy8-ca-hMi"/>
<outlet property="statsLabel" destination="DYj-Mb-me4" id="CbG-5V-unO"/>
</connections>
</tableViewCell>
</objects>
</document>
@@ -37,11 +37,17 @@ class LocationBubbleCell: SizableBaseBubbleCell, BubbleCellReactionsDisplayable
let location = CLLocationCoordinate2D(latitude: locationContent.latitude, longitude: locationContent.longitude)
locationView.displayLocation(location,
userIdentifier: bubbleData.senderId,
userDisplayName: bubbleData.senderDisplayName,
userAvatarURLString: bubbleData.senderAvatarUrl,
mediaManager: bubbleData.mxSession.mediaManager)
if locationContent.assetType == .user {
let avatarViewData = AvatarViewData(matrixItemId: bubbleData.senderId,
displayName: bubbleData.senderDisplayName,
avatarUrl: bubbleData.senderAvatarUrl,
mediaManager: bubbleData.mxSession.mediaManager,
fallbackImage: .matrixItem(bubbleData.senderId, bubbleData.senderDisplayName))
locationView.displayLocation(location, userAvatarData: avatarViewData)
} else {
locationView.displayLocation(location)
}
}
override func setupViews() {
@@ -51,5 +51,5 @@ final class RoomBubbleCellLayout: NSObject {
static let threadSummaryViewTopMargin: CGFloat = 8.0
static let threadSummaryViewHeight: CGFloat = 40.0
static let fromThreadViewTopMargin: CGFloat = 8.0
static let fromAThreadViewTopMargin: CGFloat = 8.0
}
@@ -0,0 +1,115 @@
//
// 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.
//
/// RoomTimelineCellIdentifier represents room timeline cell identifiers.
typedef NS_ENUM(NSUInteger, RoomTimelineCellIdentifier) {
RoomTimelineCellIdentifierUnknown,
// - Text message
// -- Incoming
// --- Clear
RoomTimelineCellIdentifierIncomingTextMessage,
RoomTimelineCellIdentifierIncomingTextMessageWithoutSenderInfo,
RoomTimelineCellIdentifierIncomingTextMessageWithPaginationTitle,
RoomTimelineCellIdentifierIncomingTextMessageWithoutSenderName,
RoomTimelineCellIdentifierIncomingTextMessageWithPaginationTitleWithoutSenderName,
// --- Encrypted
RoomTimelineCellIdentifierIncomingTextMessageEncrypted,
RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithoutSenderInfo,
RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithPaginationTitle,
RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithoutSenderName,
RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithPaginationTitleWithoutSenderName,
// -- Outgoing
// --- Clear
RoomTimelineCellIdentifierOutgoingTextMessage,
RoomTimelineCellIdentifierOutgoingTextMessageWithoutSenderInfo,
RoomTimelineCellIdentifierOutgoingTextMessageWithPaginationTitle,
RoomTimelineCellIdentifierOutgoingTextMessageWithoutSenderName,
RoomTimelineCellIdentifierOutgoingTextMessageWithPaginationTitleWithoutSenderName,
// --- Encrypted
RoomTimelineCellIdentifierOutgoingTextMessageEncrypted,
RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithoutSenderInfo,
RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithPaginationTitle,
RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithoutSenderName,
RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithPaginationTitleWithoutSenderName,
// - Attachment
// -- Incoming
// --- Clear
RoomTimelineCellIdentifierIncomingAttachment,
RoomTimelineCellIdentifierIncomingAttachmentWithoutSenderInfo,
RoomTimelineCellIdentifierIncomingAttachmentWithPaginationTitle,
// --- Encrypted
RoomTimelineCellIdentifierIncomingAttachmentEncrypted,
RoomTimelineCellIdentifierIncomingAttachmentEncryptedWithoutSenderInfo,
RoomTimelineCellIdentifierIncomingAttachmentEncryptedWithPaginationTitle,
// -- Outgoing
// --- Clear
RoomTimelineCellIdentifierOutgoingAttachment,
RoomTimelineCellIdentifierOutgoingAttachmentWithoutSenderInfo,
RoomTimelineCellIdentifierOutgoingAttachmentWithPaginationTitle,
// --- Encrypted
RoomTimelineCellIdentifierOutgoingAttachmentEncrypted,
RoomTimelineCellIdentifierOutgoingAttachmentEncryptedWithoutSenderInfo,
RoomTimelineCellIdentifierOutgoingAttachmentEncryptedWithPaginationTitle,
// - Room membership
RoomTimelineCellIdentifierMembership,
RoomTimelineCellIdentifierMembershipWithPaginationTitle,
RoomTimelineCellIdentifierMembershipCollapsed,
RoomTimelineCellIdentifierMembershipCollapsedWithPaginationTitle,
RoomTimelineCellIdentifierMembershipExpanded,
RoomTimelineCellIdentifierMembershipExpandedWithPaginationTitle,
// - Key verification
RoomTimelineCellIdentifierKeyVerificationIncomingRequestApproval,
RoomTimelineCellIdentifierKeyVerificationIncomingRequestApprovalWithPaginationTitle,
RoomTimelineCellIdentifierKeyVerificationRequestStatus,
RoomTimelineCellIdentifierKeyVerificationRequestStatusWithPaginationTitle,
RoomTimelineCellIdentifierKeyVerificationConclusion,
RoomTimelineCellIdentifierKeyVerificationConclusionWithPaginationTitle,
// - Room creation
RoomTimelineCellIdentifierRoomCreationCollapsed,
RoomTimelineCellIdentifierRoomCreationCollapsedWithPaginationTitle,
// - Call
RoomTimelineCellIdentifierDirectCallStatus,
RoomTimelineCellIdentifierGroupCallStatus,
// - Voice message
RoomTimelineCellIdentifierVoiceMessage,
RoomTimelineCellIdentifierVoiceMessageWithoutSenderInfo,
RoomTimelineCellIdentifierVoiceMessageWithPaginationTitle,
// - Poll
RoomTimelineCellIdentifierPoll,
RoomTimelineCellIdentifierPollWithoutSenderInfo,
RoomTimelineCellIdentifierPollWithPaginationTitle,
// - Location sharing
RoomTimelineCellIdentifierLocation,
RoomTimelineCellIdentifierLocationWithoutSenderInfo,
RoomTimelineCellIdentifierLocationWithPaginationTitle,
// - Others
RoomTimelineCellIdentifierEmpty,
RoomTimelineCellIdentifierSelectedSticker,
RoomTimelineCellIdentifierRoomPredecessor,
RoomTimelineCellIdentifierRoomCreationIntro,
RoomTimelineCellIdentifierTyping
};
@@ -0,0 +1,96 @@
//
// 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
/// RoomTimelineConfiguration enables to manage room timeline appearance configuration
@objcMembers
class RoomTimelineConfiguration: NSObject {
// MARK: - Constants
static let shared = RoomTimelineConfiguration()
// MARK: - Properties
private(set) var currentStyle: RoomTimelineStyle
// MARK: - Setup
init(style: RoomTimelineStyle) {
self.currentStyle = style
super.init()
self.registerThemeDidChange()
}
convenience init(styleIdentifier: RoomTimelineStyleIdentifier) {
let style = type(of: self).style(for: styleIdentifier)
self.init(style: style)
}
convenience override init() {
let styleIdentifier = RiotSettings.shared.roomTimelineStyleIdentifier
self.init(styleIdentifier: styleIdentifier)
}
// MARK: - Public
func updateStyle(_ roomTimelineStyle: RoomTimelineStyle) {
self.currentStyle = roomTimelineStyle
}
func updateStyle(withIdentifier identifier: RoomTimelineStyleIdentifier) {
let style = type(of: self).style(for: identifier)
self.updateStyle(style)
}
// MARK: - Private
private func registerThemeDidChange() {
NotificationCenter.default.addObserver(self, selector: #selector(themeDidChange(notification:)), name: .themeServiceDidChangeTheme, object: nil)
}
@objc private func themeDidChange(notification: Notification) {
guard let themeService = notification.object as? ThemeService else {
return
}
self.currentStyle.update(theme: themeService.theme)
}
private class func style(for identifier: RoomTimelineStyleIdentifier) -> RoomTimelineStyle {
let roomTimelineStyle: RoomTimelineStyle
let theme = ThemeService.shared().theme
switch identifier {
case .plain:
roomTimelineStyle = PlainRoomTimelineStyle(theme: theme)
case .bubble:
roomTimelineStyle = BubbleRoomTimelineStyle(theme: theme)
}
return roomTimelineStyle
}
}
@@ -27,7 +27,6 @@
@property (weak, nonatomic) IBOutlet UILabel *descriptionLabel;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *userNameLabelTopConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *attachViewLeadingConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *descriptionContainerViewBottomConstraint;
@end
@@ -0,0 +1,345 @@
//
// 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
@objcMembers
class BubbleRoomCellLayoutUpdater: RoomCellLayoutUpdating {
// MARK: - Properties
private var theme: Theme
private var incomingColor: UIColor {
return self.theme.colors.system
}
private var outgoingColor: UIColor {
return self.theme.colors.accent.withAlphaComponent(0.10)
}
// MARK: - Setup
init(theme: Theme) {
self.theme = theme
}
// MARK: - Public
func updateLayoutIfNeeded(for cell: MXKRoomBubbleTableViewCell, andCellData cellData: MXKRoomBubbleCellData) {
if cellData.isSenderCurrentUser {
self.updateLayout(forOutgoingTextMessageCell: cell, andCellData: cellData)
} else {
self.updateLayout(forIncomingTextMessageCell: cell, andCellData: cellData)
}
}
func updateLayout(forIncomingTextMessageCell cell: MXKRoomBubbleTableViewCell, andCellData cellData: MXKRoomBubbleCellData) {
if let messageBubbleBackgroundView = cell.messageBubbleBackgroundView {
if self.canUseBubbleBackground(forCell: cell, withCellData: cellData) {
messageBubbleBackgroundView.isHidden = false
self.updateMessageBubbleBackgroundView(messageBubbleBackgroundView, withCell: cell, andCellData: cellData)
} else {
messageBubbleBackgroundView.isHidden = true
}
}
}
func updateLayout(forOutgoingTextMessageCell cell: MXKRoomBubbleTableViewCell, andCellData cellData: MXKRoomBubbleCellData) {
if let messageBubbleBackgroundView = cell.messageBubbleBackgroundView {
if self.canUseBubbleBackground(forCell: cell, withCellData: cellData) {
messageBubbleBackgroundView.isHidden = false
self.updateMessageBubbleBackgroundView(messageBubbleBackgroundView, withCell: cell, andCellData: cellData)
} else {
messageBubbleBackgroundView.isHidden = true
}
}
}
func setupLayout(forIncomingTextMessageCell cell: MXKRoomBubbleTableViewCell) {
self.setupIncomingMessageTextViewMargins(for: cell)
self.addBubbleBackgroundViewToCell(cell, backgroundColor: self.incomingColor)
cell.setNeedsUpdateConstraints()
}
func setupLayout(forOutgoingTextMessageCell cell: MXKRoomBubbleTableViewCell) {
self.setupOutgoingMessageTextViewMargins(for: cell)
// Hide avatar view
cell.pictureView?.isHidden = true
self.addBubbleBackgroundViewToCell(cell, backgroundColor: self.outgoingColor)
cell.setNeedsUpdateConstraints()
}
func setupLayout(forOutgoingFileAttachmentCell cell: MXKRoomBubbleTableViewCell) {
// Hide avatar view
cell.pictureView?.isHidden = true
self.setupOutgoingFileAttachViewMargins(for: cell)
}
// MARK: Themable
func update(theme: Theme) {
self.theme = theme
}
// MARK: - Private
// MARK: Bubble background view
private func createBubbleBackgroundView(with backgroundColor: UIColor) -> RoomMessageBubbleBackgroundView {
let bubbleBackgroundView = RoomMessageBubbleBackgroundView()
bubbleBackgroundView.backgroundColor = backgroundColor
return bubbleBackgroundView
}
private func addBubbleBackgroundViewToCell(_ bubbleCell: MXKRoomBubbleTableViewCell, backgroundColor: UIColor) {
guard let messageTextView = bubbleCell.messageTextView else {
return
}
let topMargin: CGFloat = 0.0
let leftMargin: CGFloat = 5.0
let rightMargin: CGFloat = 45.0 // Add extra space for timestamp
let bubbleBackgroundView = self.createBubbleBackgroundView(with: backgroundColor)
bubbleCell.contentView.insertSubview(bubbleBackgroundView, at: 0)
let topAnchor = messageTextView.topAnchor
let leadingAnchor = messageTextView.leadingAnchor
let trailingAnchor = messageTextView.trailingAnchor
bubbleBackgroundView.updateHeight(messageTextView.frame.height)
NSLayoutConstraint.activate([
bubbleBackgroundView.topAnchor.constraint(equalTo: topAnchor, constant: topMargin),
bubbleBackgroundView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: -leftMargin),
bubbleBackgroundView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: rightMargin)
])
}
private func canUseBubbleBackground(forCell cell: MXKRoomBubbleTableViewCell, withCellData cellData: MXKRoomBubbleCellData) -> Bool {
guard let firstComponent = cellData.getFirstBubbleComponentWithDisplay(), let firstEvent = firstComponent.event else {
return false
}
switch firstEvent.eventType {
case .roomMessage:
if let messageTypeString = firstEvent.content["msgtype"] as? String {
let messageType = MXMessageType(identifier: messageTypeString)
switch messageType {
case .text, .emote, .file:
return true
default:
break
}
}
default:
break
}
return false
}
private func getTextMessageHeight(for cell: MXKRoomBubbleTableViewCell, andCellData cellData: MXKRoomBubbleCellData) -> CGFloat? {
guard let roomBubbleCellData = cellData as? RoomBubbleCellData,
let lastBubbleComponent = cellData.getLastBubbleComponentWithDisplay(),
let firstComponent = roomBubbleCellData.getFirstBubbleComponentWithDisplay() else {
return nil
}
let bubbleHeight: CGFloat
let lastEventId = lastBubbleComponent.event.eventId
let lastMessageBottomPosition = cell.bottomPosition(ofEvent: lastEventId)
let firstEventId = firstComponent.event.eventId
let firstMessageTopPosition = cell.topPosition(ofEvent: firstEventId)
let additionalContentHeight = roomBubbleCellData.additionalContentHeight
bubbleHeight = lastMessageBottomPosition - firstMessageTopPosition - additionalContentHeight
guard bubbleHeight >= 0 else {
return nil
}
return bubbleHeight
}
// TODO: Improve text message height calculation
// This method is closer to final result but lack of stability because of extra vertical space not handled here.
// private func getTextMessageHeight(for cell: MXKRoomBubbleTableViewCell, andCellData cellData: MXKRoomBubbleCellData) -> CGFloat? {
//
// guard let roomBubbleCellData = cellData as? RoomBubbleCellData,
// let firstComponent = roomBubbleCellData.getFirstBubbleComponentWithDisplay() else {
// return nil
// }
//
// let bubbleHeight: CGFloat
//
// let componentIndex = cellData.bubbleComponentIndex(forEventId: firstComponent.event.eventId)
//
// let componentFrame = cell.componentFrameInContentView(for: componentIndex)
//
// bubbleHeight = componentFrame.height
//
// guard bubbleHeight >= 0 else {
// return nil
// }
//
// return bubbleHeight
// }
private func getMessageBubbleBackgroundHeight(for cell: MXKRoomBubbleTableViewCell, andCellData cellData: MXKRoomBubbleCellData) -> CGFloat? {
var finalBubbleHeight: CGFloat?
let extraMargin: CGFloat = 4.0
if let bubbleHeight = self.getTextMessageHeight(for: cell, andCellData: cellData) {
finalBubbleHeight = bubbleHeight + extraMargin
} else if let messageTextViewHeight = cell.messageTextView?.frame.height {
finalBubbleHeight = messageTextViewHeight + extraMargin
}
return finalBubbleHeight
}
@discardableResult
private func updateMessageBubbleBackgroundView(_ roomMessageBubbleBackgroundView: RoomMessageBubbleBackgroundView, withCell cell: MXKRoomBubbleTableViewCell, andCellData cellData: MXKRoomBubbleCellData) -> Bool {
if let bubbleHeight = self.getMessageBubbleBackgroundHeight(for: cell, andCellData: cellData) {
return roomMessageBubbleBackgroundView.updateHeight(bubbleHeight)
} else {
return false
}
}
private func getIncomingMessageTextViewInsets(from bubbleCell: MXKRoomBubbleTableViewCell) -> UIEdgeInsets {
let messageViewMarginTop: CGFloat
let messageViewMarginBottom: CGFloat = -2.0
let messageViewMarginLeft: CGFloat = 3.0
let messageViewMarginRight: CGFloat = 80
if bubbleCell.userNameLabel != nil {
messageViewMarginTop = 10.0
} else {
messageViewMarginTop = 0.0
}
let messageViewInsets = UIEdgeInsets(top: messageViewMarginTop, left: messageViewMarginLeft, bottom: messageViewMarginBottom, right: messageViewMarginRight)
return messageViewInsets
}
// MARK: Text message
private func setupIncomingMessageTextViewMargins(for cell: MXKRoomBubbleTableViewCell) {
guard cell.messageTextView != nil else {
return
}
let messageViewInsets = self.getIncomingMessageTextViewInsets(from: cell)
cell.msgTextViewBottomConstraint.constant += messageViewInsets.bottom
cell.msgTextViewTopConstraint.constant += messageViewInsets.top
cell.msgTextViewLeadingConstraint.constant += messageViewInsets.left
cell.msgTextViewTrailingConstraint.constant += messageViewInsets.right
}
private func setupOutgoingMessageTextViewMargins(for cell: MXKRoomBubbleTableViewCell) {
guard let messageTextView = cell.messageTextView else {
return
}
let contentView = cell.contentView
let leftMargin: CGFloat = 80.0
let rightMargin: CGFloat = 78.0
let bottomMargin: CGFloat = -2.0
cell.msgTextViewLeadingConstraint.isActive = false
cell.msgTextViewTrailingConstraint.isActive = false
let leftConstraint = messageTextView.leadingAnchor.constraint(greaterThanOrEqualTo: contentView.leadingAnchor, constant: leftMargin)
let rightConstraint = messageTextView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -rightMargin)
NSLayoutConstraint.activate([
leftConstraint,
rightConstraint
])
cell.msgTextViewLeadingConstraint = leftConstraint
cell.msgTextViewTrailingConstraint = rightConstraint
cell.msgTextViewBottomConstraint.constant += bottomMargin
}
private func setupOutgoingFileAttachViewMargins(for cell: MXKRoomBubbleTableViewCell) {
guard let attachmentView = cell.attachmentView else {
return
}
let contentView = cell.contentView
// TODO: Use constants
// Same as URL preview
let rightMargin: CGFloat = 34.0
if let attachViewLeadingConstraint = cell.attachViewLeadingConstraint {
attachViewLeadingConstraint.isActive = false
cell.attachViewLeadingConstraint = nil
}
let rightConstraint = attachmentView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -rightMargin)
NSLayoutConstraint.activate([
rightConstraint
])
}
}
@@ -0,0 +1,230 @@
//
// 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 BubbleRoomTimelineCellDecorator: PlainRoomTimelineCellDecorator {
override func addTimestampLabelIfNeeded(toCell cell: MXKRoomBubbleTableViewCell, cellData: RoomBubbleCellData) {
guard self.canShowTimestamp(forCellData: cellData) else {
return
}
self.addTimestampLabel(toCell: cell, cellData: cellData)
}
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
])
} else {
super.addTimestampLabel(toCell: cell, cellData: cellData)
}
}
override func addReactionView(_ reactionsView: BubbleReactionsView,
toCell cell: MXKRoomBubbleTableViewCell, cellData: RoomBubbleCellData, contentViewPositionY: CGFloat, upperDecorationView: UIView?) {
cell.addTemporarySubview(reactionsView)
if let reactionsDisplayable = cell as? BubbleCellReactionsDisplayable {
reactionsDisplayable.addReactionsView(reactionsView)
return
}
reactionsView.translatesAutoresizingMaskIntoConstraints = false
let cellContentView = cell.contentView
cellContentView.addSubview(reactionsView)
// TODO: Use constants
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
var incomingLeftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin
if cellData.containsBubbleComponentWithEncryptionBadge {
incomingLeftMargin += RoomBubbleCellLayout.encryptedContentLeftMargin
}
leftMargin = incomingLeftMargin - 6.0
// TODO: Use constants
let messageViewMarginRight: CGFloat = 42.0
rightMargin = messageViewMarginRight
}
let leadingConstraint = reactionsView.leadingAnchor.constraint(equalTo: cellContentView.leadingAnchor, constant: leftMargin)
let trailingConstraint = reactionsView.trailingAnchor.constraint(equalTo: cellContentView.trailingAnchor, constant: -rightMargin)
let topConstraint: NSLayoutConstraint
if let upperDecorationView = upperDecorationView {
topConstraint = reactionsView.topAnchor.constraint(equalTo: upperDecorationView.bottomAnchor, constant: topMargin)
} else {
topConstraint = reactionsView.topAnchor.constraint(equalTo: cellContentView.topAnchor, constant: contentViewPositionY + topMargin)
}
NSLayoutConstraint.activate([
leadingConstraint,
trailingConstraint,
topConstraint
])
}
override func addURLPreviewView(_ urlPreviewView: URLPreviewView,
toCell cell: MXKRoomBubbleTableViewCell,
cellData: RoomBubbleCellData,
contentViewPositionY: CGFloat) {
cell.addTemporarySubview(urlPreviewView)
let cellContentView = cell.contentView
urlPreviewView.translatesAutoresizingMaskIntoConstraints = false
urlPreviewView.availableWidth = cellData.maxTextViewWidth
cellContentView.addSubview(urlPreviewView)
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
var leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin
if cellData.containsBubbleComponentWithEncryptionBadge {
leftMargin += RoomBubbleCellLayout.encryptedContentLeftMargin
}
leftMargin-=5.0
leadingOrTrailingConstraint = urlPreviewView.leadingAnchor.constraint(equalTo: cellContentView.leadingAnchor, constant: leftMargin)
}
let topMargin = contentViewPositionY + RoomBubbleCellLayout.urlPreviewViewTopMargin + RoomBubbleCellLayout.reactionsViewTopMargin
// Set the preview view's origin
NSLayoutConstraint.activate([
leadingOrTrailingConstraint,
urlPreviewView.topAnchor.constraint(equalTo: cellContentView.topAnchor, constant: topMargin)
])
}
// MARK: - Private
private func createTimestampLabel(cellData: MXKRoomBubbleCellData, bubbleComponent: MXKRoomBubbleComponent, viewTag: Int) -> 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.adjustsFontSizeToFitWidth = true
timeLabel.tag = viewTag
timeLabel.accessibilityIdentifier = "timestampLabel"
return timeLabel
}
private func canShowTimestamp(forCellData cellData: MXKRoomBubbleCellData) -> Bool {
guard cellData.isCollapsableAndCollapsed == false else {
return false
}
guard let firstComponent = cellData.getFirstBubbleComponentWithDisplay(), let firstEvent = firstComponent.event else {
return false
}
switch firstEvent.eventType {
case .roomMessage:
if let messageTypeString = firstEvent.content["msgtype"] as? String {
let messageType = MXMessageType(identifier: messageTypeString)
switch messageType {
case .text, .emote, .file:
return true
default:
break
}
}
default:
break
}
return 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 "PlainRoomTimelineCellProvider.h"
NS_ASSUME_NONNULL_BEGIN
@interface BubbleRoomTimelineCellProvider : PlainRoomTimelineCellProvider
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,90 @@
//
// 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 "BubbleRoomTimelineCellProvider.h"
#pragma mark - Imports
#pragma mark Text message
// Outgoing
// Clear
#import "RoomOutgoingTextMsgBubbleCell.h"
#import "RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.h"
#import "RoomOutgoingTextMsgWithPaginationTitleBubbleCell.h"
#import "RoomOutgoingTextMsgWithoutSenderNameBubbleCell.h"
#import "RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.h"
#import "RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell.h"
// Encrypted
#import "RoomOutgoingEncryptedTextMsgBubbleCell.h"
#import "RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.h"
#import "RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell.h"
#import "RoomOutgoingEncryptedTextMsgWithoutSenderNameBubbleCell.h"
#import "RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.h"
#pragma mark Attachment
// Outgoing
// Clear
#import "RoomOutgoingAttachmentBubbleCell.h"
#import "RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.h"
#import "RoomOutgoingAttachmentWithPaginationTitleBubbleCell.h"
// Encrypted
#import "RoomOutgoingEncryptedAttachmentBubbleCell.h"
#import "RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.h"
#import "RoomOutgoingEncryptedAttachmentWithPaginationTitleBubbleCell.h"
@implementation BubbleRoomTimelineCellProvider
- (NSDictionary<NSNumber*, Class>*)outgoingTextMessageCellsMapping
{
// Hide sender info and avatar for bubble outgoing messages
return @{
// Clear
@(RoomTimelineCellIdentifierOutgoingTextMessage) : RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingTextMessageWithoutSenderInfo) : RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingTextMessageWithPaginationTitle) : RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingTextMessageWithoutSenderName) : RoomOutgoingTextMsgWithoutSenderNameBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingTextMessageWithPaginationTitleWithoutSenderName) : RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class,
// Encrypted
@(RoomTimelineCellIdentifierOutgoingTextMessageEncrypted) : RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithoutSenderInfo) : RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithPaginationTitle) : RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithoutSenderName) : RoomOutgoingEncryptedTextMsgWithoutSenderNameBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithPaginationTitleWithoutSenderName) : RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class,
};
}
- (NSDictionary<NSNumber*, Class>*)outgoingAttachmentCellsMapping
{
// Hide sender info and avatar for bubble outgoing file attachment
return @{
// Clear
@(RoomTimelineCellIdentifierOutgoingAttachment) : RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingAttachmentWithoutSenderInfo) : RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingAttachmentWithPaginationTitle) : RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell.class,
// Encrypted
@(RoomTimelineCellIdentifierOutgoingAttachmentEncrypted) : RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingAttachmentEncryptedWithoutSenderInfo) : RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingAttachmentEncryptedWithPaginationTitle) : RoomOutgoingEncryptedAttachmentWithPaginationTitleBubbleCell.class
};
}
@end
@@ -0,0 +1,76 @@
//
// 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 BubbleRoomTimelineStyle: RoomTimelineStyle {
// MARK: - Properties
// MARK: Private
private var theme: Theme
// MARK: Public
let identifier: RoomTimelineStyleIdentifier
let cellLayoutUpdater: RoomCellLayoutUpdating?
let cellProvider: RoomTimelineCellProvider
let cellDecorator: RoomTimelineCellDecorator
// MARK: - Setup
init(theme: Theme) {
self.theme = theme
self.identifier = .bubble
self.cellLayoutUpdater = BubbleRoomCellLayoutUpdater(theme: theme)
self.cellProvider = BubbleRoomTimelineCellProvider()
self.cellDecorator = BubbleRoomTimelineCellDecorator()
}
// MARK: - Public
func canAddEvent(_ event: MXEvent, and roomState: MXRoomState, to cellData: MXKRoomBubbleCellData) -> Bool {
return false
}
func applySelectedStyleIfNeeded(toCell cell: MXKRoomBubbleTableViewCell, cellData: RoomBubbleCellData) {
// Check whether the selected event belongs to this bubble
let selectedComponentIndex = cellData.selectedComponentIndex
if selectedComponentIndex != NSNotFound {
cell.selectComponent(UInt(selectedComponentIndex),
showEditButton: false,
showTimestamp: false)
self.cellDecorator.addTimestampLabel(toCell: cell, cellData: cellData)
} else {
cell.blurred = true
}
}
// MARK: Themable
func update(theme: Theme) {
self.theme = theme
self.cellLayoutUpdater?.update(theme: theme)
}
}
@@ -0,0 +1,30 @@
//
// 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
extension MXKRoomBubbleTableViewCell {
// Enables to get existing bubble background view
// This used while there is no dedicated cell classes for bubble style
var messageBubbleBackgroundView: RoomMessageBubbleBackgroundView? {
let foundView = self.contentView.subviews.first { view in
return view is RoomMessageBubbleBackgroundView
}
return foundView as? RoomMessageBubbleBackgroundView
}
}
@@ -0,0 +1,74 @@
//
// 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 RoomMessageBubbleBackgroundView: UIView {
// MARK: - Constant
private enum Constants {
static let cornerRadius: CGFloat = 12.0
}
// MARK: - Properties
private var heightConstraint: NSLayoutConstraint?
// MARK: - Setup
convenience init() {
self.init(frame: CGRect.zero)
}
override init(frame: CGRect) {
super.init(frame: frame)
self.commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
self.commonInit()
}
private func commonInit() {
self.translatesAutoresizingMaskIntoConstraints = false
self.layer.masksToBounds = true
self.layer.cornerRadius = Constants.cornerRadius
}
// MARK: - Public
@discardableResult
func updateHeight(_ height: CGFloat) -> Bool {
if let heightConstraint = self.heightConstraint {
guard heightConstraint.constant != height else {
return false
}
heightConstraint.constant = height
return true
} else {
let heightConstraint = self.heightAnchor.constraint(equalToConstant: height)
heightConstraint.isActive = true
self.heightConstraint = heightConstraint
return true
}
}
}
@@ -0,0 +1,197 @@
//
// 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
@objcMembers
class PlainRoomTimelineCellDecorator: RoomTimelineCellDecorator {
func addTimestampLabelIfNeeded(toCell cell: MXKRoomBubbleTableViewCell, cellData: RoomBubbleCellData) {
guard cellData.containsLastMessage && cellData.isCollapsableAndCollapsed == false else {
return
}
// Display timestamp of the last message
self.addTimestampLabel(toCell: cell, cellData: cellData)
}
func addTimestampLabel(toCell cell: MXKRoomBubbleTableViewCell, cellData: RoomBubbleCellData) {
cell.addTimestampLabel(forComponent: UInt(cellData.mostRecentComponentIndex))
}
func addURLPreviewView(_ urlPreviewView: URLPreviewView,
toCell cell: MXKRoomBubbleTableViewCell,
cellData: RoomBubbleCellData,
contentViewPositionY: CGFloat) {
cell.addTemporarySubview(urlPreviewView)
let cellContentView = cell.contentView
urlPreviewView.translatesAutoresizingMaskIntoConstraints = false
urlPreviewView.availableWidth = cellData.maxTextViewWidth
cellContentView.addSubview(urlPreviewView)
var leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin
if cellData.containsBubbleComponentWithEncryptionBadge {
leftMargin += RoomBubbleCellLayout.encryptedContentLeftMargin
}
let topMargin = contentViewPositionY + RoomBubbleCellLayout.urlPreviewViewTopMargin + RoomBubbleCellLayout.reactionsViewTopMargin
// Set the preview view's origin
NSLayoutConstraint.activate([
urlPreviewView.leadingAnchor.constraint(equalTo: cellContentView.leadingAnchor, constant: leftMargin),
urlPreviewView.topAnchor.constraint(equalTo: cellContentView.topAnchor, constant: topMargin)
])
}
func addReactionView(_ reactionsView: BubbleReactionsView,
toCell cell: MXKRoomBubbleTableViewCell,
cellData: RoomBubbleCellData,
contentViewPositionY: CGFloat,
upperDecorationView: UIView?) {
cell.addTemporarySubview(reactionsView)
if let reactionsDisplayable = cell as? BubbleCellReactionsDisplayable {
reactionsDisplayable.addReactionsView(reactionsView)
} else {
reactionsView.translatesAutoresizingMaskIntoConstraints = false
let cellContentView = cell.contentView
cellContentView.addSubview(reactionsView)
var leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin
if cellData.containsBubbleComponentWithEncryptionBadge {
leftMargin += RoomBubbleCellLayout.encryptedContentLeftMargin
}
let rightMargin = RoomBubbleCellLayout.reactionsViewRightMargin
let topMargin = RoomBubbleCellLayout.reactionsViewTopMargin
// The top constraint may need to include the URL preview view
let topConstraint: NSLayoutConstraint
if let upperDecorationView = upperDecorationView {
topConstraint = reactionsView.topAnchor.constraint(equalTo: upperDecorationView.bottomAnchor, constant: topMargin)
} else {
topConstraint = reactionsView.topAnchor.constraint(equalTo: cellContentView.topAnchor, constant: contentViewPositionY + topMargin)
}
NSLayoutConstraint.activate([
reactionsView.leadingAnchor.constraint(equalTo: cellContentView.leadingAnchor, constant: leftMargin),
reactionsView.trailingAnchor.constraint(equalTo: cellContentView.trailingAnchor, constant: -rightMargin),
topConstraint
])
}
}
func addReadReceiptsView(_ readReceiptsView: MXKReceiptSendersContainer,
toCell cell: MXKRoomBubbleTableViewCell,
cellData: RoomBubbleCellData,
contentViewPositionY: CGFloat,
upperDecorationView: UIView?) {
cell.addTemporarySubview(readReceiptsView)
if let readReceiptsDisplayable = cell as? BubbleCellReadReceiptsDisplayable {
readReceiptsDisplayable.addReadReceiptsView(readReceiptsView)
} else {
let cellContentView = cell.contentView
cellContentView.addSubview(readReceiptsView)
// Force receipts container size
let widthConstraint = readReceiptsView.widthAnchor.constraint(equalToConstant: RoomBubbleCellLayout.readReceiptsViewWidth)
let heightConstraint = readReceiptsView.heightAnchor.constraint(equalToConstant: RoomBubbleCellLayout.readReceiptsViewHeight)
// Force receipts container position
let trailingConstraint = readReceiptsView.trailingAnchor.constraint(equalTo: cellContentView.trailingAnchor, constant: -RoomBubbleCellLayout.readReceiptsViewRightMargin)
let topMargin = RoomBubbleCellLayout.readReceiptsViewTopMargin
let topConstraint: NSLayoutConstraint
if let upperDecorationView = upperDecorationView {
topConstraint = readReceiptsView.topAnchor.constraint(equalTo: upperDecorationView.bottomAnchor, constant: topMargin)
} else {
topConstraint = readReceiptsView.topAnchor.constraint(equalTo: cellContentView.topAnchor, constant: contentViewPositionY + topMargin)
}
NSLayoutConstraint.activate([
widthConstraint,
heightConstraint,
trailingConstraint,
topConstraint
])
}
}
func addThreadSummaryView(_ threadSummaryView: ThreadSummaryView,
toCell cell: MXKRoomBubbleTableViewCell,
cellData: RoomBubbleCellData,
contentViewPositionY: CGFloat,
upperDecorationView: UIView?) {
cell.addTemporarySubview(threadSummaryView)
if let threadSummaryDisplayable = cell as? BubbleCellThreadSummaryDisplayable {
threadSummaryDisplayable.addThreadSummaryView(threadSummaryView)
} else {
threadSummaryView.translatesAutoresizingMaskIntoConstraints = false
let cellContentView = cell.contentView
cellContentView.addSubview(threadSummaryView)
var leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin
if cellData.containsBubbleComponentWithEncryptionBadge {
leftMargin += RoomBubbleCellLayout.encryptedContentLeftMargin
}
let rightMargin = RoomBubbleCellLayout.reactionsViewRightMargin
let topMargin = RoomBubbleCellLayout.threadSummaryViewTopMargin
let height = ThreadSummaryView.contentViewHeight(forThread: threadSummaryView.thread,
fitting: cellData.maxTextViewWidth)
// The top constraint may need to include the URL preview view
let topConstraint: NSLayoutConstraint
if let upperDecorationView = upperDecorationView {
topConstraint = threadSummaryView.topAnchor.constraint(equalTo: upperDecorationView.bottomAnchor,
constant: topMargin)
} else {
topConstraint = threadSummaryView.topAnchor.constraint(equalTo: cellContentView.topAnchor,
constant: contentViewPositionY + topMargin)
}
NSLayoutConstraint.activate([
threadSummaryView.leadingAnchor.constraint(equalTo: cellContentView.leadingAnchor,
constant: leftMargin),
threadSummaryView.trailingAnchor.constraint(lessThanOrEqualTo: cellContentView.trailingAnchor,
constant: -rightMargin),
threadSummaryView.heightAnchor.constraint(equalToConstant: height),
topConstraint
])
}
}
func addSendStatusView(toCell cell: MXKRoomBubbleTableViewCell, withFailedEventIds failedEventIds: Set<AnyHashable>) {
cell.updateTickView(withFailedEventIds: failedEventIds)
}
}
@@ -0,0 +1,29 @@
//
// 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 "RoomTimelineCellProvider.h"
NS_ASSUME_NONNULL_BEGIN
@interface PlainRoomTimelineCellProvider: NSObject<RoomTimelineCellProvider>
- (NSDictionary<NSNumber*, Class>*)outgoingTextMessageCellsMapping;
- (NSDictionary<NSNumber*, Class>*)outgoingAttachmentCellsMapping;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,453 @@
//
// 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 "PlainRoomTimelineCellProvider.h"
#import "MXKRoomBubbleTableViewCell+Riot.h"
#import "RoomEmptyBubbleCell.h"
#import "RoomIncomingTextMsgBubbleCell.h"
#import "RoomIncomingTextMsgWithoutSenderInfoBubbleCell.h"
#import "RoomIncomingTextMsgWithPaginationTitleBubbleCell.h"
#import "RoomIncomingTextMsgWithoutSenderNameBubbleCell.h"
#import "RoomIncomingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.h"
#import "RoomIncomingAttachmentBubbleCell.h"
#import "RoomIncomingAttachmentWithoutSenderInfoBubbleCell.h"
#import "RoomIncomingAttachmentWithPaginationTitleBubbleCell.h"
#import "RoomIncomingEncryptedTextMsgBubbleCell.h"
#import "RoomIncomingEncryptedTextMsgWithoutSenderInfoBubbleCell.h"
#import "RoomIncomingEncryptedTextMsgWithPaginationTitleBubbleCell.h"
#import "RoomIncomingEncryptedTextMsgWithoutSenderNameBubbleCell.h"
#import "RoomIncomingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.h"
#import "RoomIncomingEncryptedAttachmentBubbleCell.h"
#import "RoomIncomingEncryptedAttachmentWithoutSenderInfoBubbleCell.h"
#import "RoomIncomingEncryptedAttachmentWithPaginationTitleBubbleCell.h"
#import "RoomOutgoingTextMsgBubbleCell.h"
#import "RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.h"
#import "RoomOutgoingTextMsgWithPaginationTitleBubbleCell.h"
#import "RoomOutgoingTextMsgWithoutSenderNameBubbleCell.h"
#import "RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.h"
#import "RoomOutgoingAttachmentBubbleCell.h"
#import "RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.h"
#import "RoomOutgoingAttachmentWithPaginationTitleBubbleCell.h"
#import "RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell.h"
#import "RoomOutgoingEncryptedTextMsgBubbleCell.h"
#import "RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.h"
#import "RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell.h"
#import "RoomOutgoingEncryptedTextMsgWithoutSenderNameBubbleCell.h"
#import "RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.h"
#import "RoomOutgoingEncryptedAttachmentBubbleCell.h"
#import "RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.h"
#import "RoomOutgoingEncryptedAttachmentWithPaginationTitleBubbleCell.h"
#import "RoomMembershipBubbleCell.h"
#import "RoomMembershipWithPaginationTitleBubbleCell.h"
#import "RoomMembershipCollapsedBubbleCell.h"
#import "RoomMembershipCollapsedWithPaginationTitleBubbleCell.h"
#import "RoomMembershipExpandedBubbleCell.h"
#import "RoomMembershipExpandedWithPaginationTitleBubbleCell.h"
#import "RoomCreationWithPaginationCollapsedBubbleCell.h"
#import "RoomCreationCollapsedBubbleCell.h"
#import "RoomSelectedStickerBubbleCell.h"
#import "RoomPredecessorBubbleCell.h"
#import "GeneratedInterface-Swift.h"
@interface PlainRoomTimelineCellProvider()
@property (nonatomic, strong) NSDictionary<NSNumber*, Class>* cellClasses;
@end
@implementation PlainRoomTimelineCellProvider
#pragma mark - Public
- (void)registerCellsForTableView:(UITableView*)tableView
{
// Text message
[self registerIncomingTextMessageCellsForTableView:tableView];
[self registerOutgoingTextMessageCellsForTableView:tableView];
// Attachment cells
[self registerIncomingAttachmentCellsForTableView:tableView];
[self registerOutgoingAttachmentCellsForTableView:tableView];
// Other cells
[self registerMembershipCellsForTableView:tableView];
[self registerKeyVerificationCellsForTableView:tableView];
[self registerRoomCreationCellsForTableView:tableView];
[self registerCallCellsForTableView:tableView];
[self registerVoiceMessageCellsForTableView:tableView];
[self registerPollCellsForTableView:tableView];
[self registerLocationCellsForTableView:tableView];
[tableView registerClass:RoomEmptyBubbleCell.class forCellReuseIdentifier:RoomEmptyBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomSelectedStickerBubbleCell.class forCellReuseIdentifier:RoomSelectedStickerBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomPredecessorBubbleCell.class forCellReuseIdentifier:RoomPredecessorBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomCreationIntroCell.class forCellReuseIdentifier:RoomCreationIntroCell.defaultReuseIdentifier];
[tableView registerNib:RoomTypingBubbleCell.nib forCellReuseIdentifier:RoomTypingBubbleCell.defaultReuseIdentifier];
}
- (Class<MXKCellRendering>)cellViewClassForCellIdentifier:(RoomTimelineCellIdentifier)identifier
{
if (self.cellClasses == nil)
{
self.cellClasses = [self buildCellClasses];
}
Class cellViewClass = self.cellClasses[@(identifier)];
return cellViewClass;
}
#pragma mark - Private
#pragma mark Cell registration
- (void)registerIncomingTextMessageCellsForTableView:(UITableView*)tableView
{
// Clear
[tableView registerClass:RoomIncomingTextMsgBubbleCell.class forCellReuseIdentifier:RoomIncomingTextMsgBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomIncomingTextMsgWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomIncomingTextMsgWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomIncomingTextMsgWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomIncomingTextMsgWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomIncomingTextMsgWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomIncomingTextMsgWithoutSenderNameBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomIncomingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomIncomingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.defaultReuseIdentifier];
// Encrypted
[tableView registerClass:RoomIncomingEncryptedTextMsgBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedTextMsgBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomIncomingEncryptedTextMsgWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedTextMsgWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomIncomingEncryptedTextMsgWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedTextMsgWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomIncomingEncryptedTextMsgWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedTextMsgWithoutSenderNameBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomIncomingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.defaultReuseIdentifier];
}
- (void)registerOutgoingTextMessageCellsForTableView:(UITableView*)tableView
{
// Clear
[tableView registerClass:RoomOutgoingTextMsgBubbleCell.class forCellReuseIdentifier:RoomOutgoingTextMsgBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomOutgoingTextMsgWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomOutgoingTextMsgWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomOutgoingTextMsgWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomOutgoingTextMsgWithoutSenderNameBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.defaultReuseIdentifier];
// Encrypted
[tableView registerClass:RoomOutgoingEncryptedAttachmentWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedAttachmentWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomOutgoingEncryptedTextMsgBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedTextMsgBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomOutgoingEncryptedTextMsgWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedTextMsgWithoutSenderNameBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.defaultReuseIdentifier];
}
- (void)registerIncomingAttachmentCellsForTableView:(UITableView*)tableView
{
// Clear
[tableView registerClass:RoomIncomingAttachmentBubbleCell.class forCellReuseIdentifier:RoomIncomingAttachmentBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomIncomingAttachmentWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomIncomingAttachmentWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomIncomingAttachmentWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomIncomingAttachmentWithPaginationTitleBubbleCell.defaultReuseIdentifier];
// Encrypted
[tableView registerClass:RoomIncomingEncryptedAttachmentBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedAttachmentBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomIncomingEncryptedAttachmentWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedAttachmentWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomIncomingEncryptedAttachmentWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomIncomingEncryptedAttachmentWithPaginationTitleBubbleCell.defaultReuseIdentifier];
}
- (void)registerOutgoingAttachmentCellsForTableView:(UITableView*)tableView
{
// Clear
[tableView registerClass:RoomOutgoingAttachmentBubbleCell.class forCellReuseIdentifier:RoomOutgoingAttachmentBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomOutgoingAttachmentWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomOutgoingAttachmentWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell.class forCellReuseIdentifier:RoomOutgoingAttachmentWithPaginationTitleWithoutSenderNameBubbleCell.defaultReuseIdentifier];
// Encrypted
[tableView registerClass:RoomOutgoingEncryptedAttachmentBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedAttachmentBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
}
- (void)registerMembershipCellsForTableView:(UITableView*)tableView
{
[tableView registerClass:RoomMembershipBubbleCell.class forCellReuseIdentifier:RoomMembershipBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomMembershipWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomMembershipWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomMembershipCollapsedBubbleCell.class forCellReuseIdentifier:RoomMembershipCollapsedBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomMembershipCollapsedWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomMembershipCollapsedWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomMembershipExpandedBubbleCell.class forCellReuseIdentifier:RoomMembershipExpandedBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomMembershipExpandedWithPaginationTitleBubbleCell.class forCellReuseIdentifier:RoomMembershipExpandedWithPaginationTitleBubbleCell.defaultReuseIdentifier];
}
- (void)registerKeyVerificationCellsForTableView:(UITableView*)tableView
{
[tableView registerClass:KeyVerificationIncomingRequestApprovalBubbleCell.class forCellReuseIdentifier:KeyVerificationIncomingRequestApprovalBubbleCell.defaultReuseIdentifier];
[tableView registerClass:KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell.class forCellReuseIdentifier:KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[tableView registerClass:KeyVerificationRequestStatusBubbleCell.class forCellReuseIdentifier:KeyVerificationRequestStatusBubbleCell.defaultReuseIdentifier];
[tableView registerClass:KeyVerificationRequestStatusWithPaginationTitleBubbleCell.class forCellReuseIdentifier:KeyVerificationRequestStatusWithPaginationTitleBubbleCell.defaultReuseIdentifier];
[tableView registerClass:KeyVerificationConclusionBubbleCell.class forCellReuseIdentifier:KeyVerificationConclusionBubbleCell.defaultReuseIdentifier];
[tableView registerClass:KeyVerificationConclusionWithPaginationTitleBubbleCell.class forCellReuseIdentifier:KeyVerificationConclusionWithPaginationTitleBubbleCell.defaultReuseIdentifier];
}
- (void)registerRoomCreationCellsForTableView:(UITableView*)tableView
{
[tableView registerClass:RoomCreationCollapsedBubbleCell.class forCellReuseIdentifier:RoomCreationCollapsedBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomCreationWithPaginationCollapsedBubbleCell.class forCellReuseIdentifier:RoomCreationWithPaginationCollapsedBubbleCell.defaultReuseIdentifier];
}
- (void)registerCallCellsForTableView:(UITableView*)tableView
{
[tableView registerClass:RoomDirectCallStatusBubbleCell.class forCellReuseIdentifier:RoomDirectCallStatusBubbleCell.defaultReuseIdentifier];
[tableView registerClass:RoomGroupCallStatusBubbleCell.class forCellReuseIdentifier:RoomGroupCallStatusBubbleCell.defaultReuseIdentifier];
}
- (void)registerVoiceMessageCellsForTableView:(UITableView*)tableView
{
[tableView registerClass:VoiceMessageBubbleCell.class forCellReuseIdentifier:VoiceMessageBubbleCell.defaultReuseIdentifier];
[tableView registerClass:VoiceMessageWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:VoiceMessageWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[tableView registerClass:VoiceMessageWithPaginationTitleBubbleCell.class forCellReuseIdentifier:VoiceMessageWithPaginationTitleBubbleCell.defaultReuseIdentifier];
}
- (void)registerPollCellsForTableView:(UITableView*)tableView
{
[tableView registerClass:PollBubbleCell.class forCellReuseIdentifier:PollBubbleCell.defaultReuseIdentifier];
[tableView registerClass:PollWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:PollWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[tableView registerClass:PollWithPaginationTitleBubbleCell.class forCellReuseIdentifier:PollWithPaginationTitleBubbleCell.defaultReuseIdentifier];
}
- (void)registerLocationCellsForTableView:(UITableView*)tableView
{
[tableView registerClass:LocationBubbleCell.class forCellReuseIdentifier:LocationBubbleCell.defaultReuseIdentifier];
[tableView registerClass:LocationWithoutSenderInfoBubbleCell.class forCellReuseIdentifier:LocationWithoutSenderInfoBubbleCell.defaultReuseIdentifier];
[tableView registerClass:LocationWithPaginationTitleBubbleCell.class forCellReuseIdentifier:LocationWithPaginationTitleBubbleCell.defaultReuseIdentifier];
}
#pragma mark Cell class association
- (NSDictionary<NSNumber*, Class>*)buildCellClasses
{
NSMutableDictionary<NSNumber*, Class>* cellClasses = [NSMutableDictionary dictionary];
// Text message
NSDictionary *incomingTextMessageCellsMapping = [self incomingTextMessageCellsMapping];
[cellClasses addEntriesFromDictionary:incomingTextMessageCellsMapping];
NSDictionary *outgoingTextMessageCellsMapping = [self outgoingTextMessageCellsMapping];
[cellClasses addEntriesFromDictionary:outgoingTextMessageCellsMapping];
// Attachment
NSDictionary *incomingAttachmentCellsMapping = [self incomingAttachmentCellsMapping];
[cellClasses addEntriesFromDictionary:incomingAttachmentCellsMapping];
NSDictionary *outgoingAttachmentCellsMapping = [self outgoingAttachmentCellsMapping];
[cellClasses addEntriesFromDictionary:outgoingAttachmentCellsMapping];
// Other cells
NSDictionary *roomMembershipCellsMapping = [self membershipCellsMapping];
[cellClasses addEntriesFromDictionary:roomMembershipCellsMapping];
NSDictionary *keyVerificationCellsMapping = [self keyVerificationCellsMapping];
[cellClasses addEntriesFromDictionary:keyVerificationCellsMapping];
NSDictionary *roomCreationCellsMapping = [self roomCreationCellsMapping];
[cellClasses addEntriesFromDictionary:roomCreationCellsMapping];
NSDictionary *callCellsMapping = [self callCellsMapping];
[cellClasses addEntriesFromDictionary:callCellsMapping];
NSDictionary *voiceMessageCellsMapping = [self voiceMessageCellsMapping];
[cellClasses addEntriesFromDictionary:voiceMessageCellsMapping];
NSDictionary *pollCellsMapping = [self pollCellsMapping];
[cellClasses addEntriesFromDictionary:pollCellsMapping];
NSDictionary *locationCellsMapping = [self locationCellsMapping];
[cellClasses addEntriesFromDictionary:locationCellsMapping];
NSDictionary *othersCells = @{
@(RoomTimelineCellIdentifierEmpty) : RoomEmptyBubbleCell.class,
@(RoomTimelineCellIdentifierSelectedSticker) : RoomSelectedStickerBubbleCell.class,
@(RoomTimelineCellIdentifierRoomPredecessor) : RoomPredecessorBubbleCell.class,
@(RoomTimelineCellIdentifierRoomCreationIntro) : RoomCreationIntroCell.class,
@(RoomTimelineCellIdentifierTyping) : RoomTypingBubbleCell.class,
};
[cellClasses addEntriesFromDictionary:othersCells];
return [cellClasses copy];
}
- (NSDictionary<NSNumber*, Class>*)incomingTextMessageCellsMapping
{
return @{
// Clear
@(RoomTimelineCellIdentifierIncomingTextMessage) : RoomIncomingTextMsgBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingTextMessageWithoutSenderInfo) : RoomIncomingTextMsgWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingTextMessageWithPaginationTitle) : RoomIncomingTextMsgWithPaginationTitleBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingTextMessageWithoutSenderName) : RoomIncomingTextMsgWithoutSenderNameBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingTextMessageWithPaginationTitleWithoutSenderName) : RoomIncomingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class,
// Encrypted
@(RoomTimelineCellIdentifierIncomingTextMessageEncrypted) : RoomIncomingEncryptedTextMsgBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithoutSenderInfo) : RoomIncomingEncryptedTextMsgWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithPaginationTitle) : RoomIncomingEncryptedTextMsgWithPaginationTitleBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithoutSenderName) : RoomIncomingEncryptedTextMsgWithoutSenderNameBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingTextMessageEncryptedWithPaginationTitleWithoutSenderName) : RoomIncomingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class,
};
}
- (NSDictionary<NSNumber*, Class>*)outgoingTextMessageCellsMapping
{
return @{
// Clear
@(RoomTimelineCellIdentifierOutgoingTextMessage) : RoomOutgoingTextMsgBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingTextMessageWithoutSenderInfo) : RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingTextMessageWithPaginationTitle) : RoomOutgoingTextMsgWithPaginationTitleBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingTextMessageWithoutSenderName) : RoomOutgoingTextMsgWithoutSenderNameBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingTextMessageWithPaginationTitleWithoutSenderName) : RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class,
// Encrypted
@(RoomTimelineCellIdentifierOutgoingTextMessageEncrypted) : RoomOutgoingEncryptedTextMsgBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithoutSenderInfo) : RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithPaginationTitle) : RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithoutSenderName) : RoomOutgoingEncryptedTextMsgWithoutSenderNameBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingTextMessageEncryptedWithPaginationTitleWithoutSenderName) : RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.class,
};
}
- (NSDictionary<NSNumber*, Class>*)incomingAttachmentCellsMapping
{
return @{
// Clear
@(RoomTimelineCellIdentifierIncomingAttachment) : RoomIncomingAttachmentBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingAttachmentWithoutSenderInfo) : RoomIncomingAttachmentWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingAttachmentWithPaginationTitle) : RoomIncomingAttachmentWithPaginationTitleBubbleCell.class,
// Encrypted
@(RoomTimelineCellIdentifierIncomingAttachmentEncrypted) : RoomIncomingEncryptedAttachmentBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingAttachmentEncryptedWithoutSenderInfo) : RoomIncomingEncryptedAttachmentWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierIncomingAttachmentEncryptedWithPaginationTitle) : RoomIncomingEncryptedAttachmentWithPaginationTitleBubbleCell.class
};
}
- (NSDictionary<NSNumber*, Class>*)outgoingAttachmentCellsMapping
{
return @{
// Clear
@(RoomTimelineCellIdentifierOutgoingAttachment) : RoomOutgoingAttachmentBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingAttachmentWithoutSenderInfo) : RoomOutgoingAttachmentWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingAttachmentWithPaginationTitle) : RoomOutgoingAttachmentWithPaginationTitleBubbleCell.class,
// Encrypted
@(RoomTimelineCellIdentifierOutgoingAttachmentEncrypted) : RoomOutgoingEncryptedAttachmentBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingAttachmentEncryptedWithoutSenderInfo) : RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierOutgoingAttachmentEncryptedWithPaginationTitle) : RoomOutgoingEncryptedAttachmentWithPaginationTitleBubbleCell.class
};
}
- (NSDictionary<NSNumber*, Class>*)membershipCellsMapping
{
return @{
@(RoomTimelineCellIdentifierMembership) : RoomMembershipBubbleCell.class,
@(RoomTimelineCellIdentifierMembershipWithPaginationTitle) : RoomMembershipWithPaginationTitleBubbleCell.class,
@(RoomTimelineCellIdentifierMembershipCollapsed) : RoomMembershipCollapsedBubbleCell.class,
@(RoomTimelineCellIdentifierMembershipCollapsedWithPaginationTitle) : RoomMembershipCollapsedWithPaginationTitleBubbleCell.class,
@(RoomTimelineCellIdentifierMembershipExpanded) : RoomMembershipExpandedBubbleCell.class,
@(RoomTimelineCellIdentifierMembershipExpandedWithPaginationTitle) : RoomMembershipExpandedWithPaginationTitleBubbleCell.class,
};
}
- (NSDictionary<NSNumber*, Class>*)keyVerificationCellsMapping
{
return @{
@(RoomTimelineCellIdentifierKeyVerificationIncomingRequestApproval) : KeyVerificationIncomingRequestApprovalBubbleCell.class,
@(RoomTimelineCellIdentifierKeyVerificationIncomingRequestApprovalWithPaginationTitle) : KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell.class,
@(RoomTimelineCellIdentifierKeyVerificationRequestStatus) : KeyVerificationRequestStatusBubbleCell.class,
@(RoomTimelineCellIdentifierKeyVerificationRequestStatusWithPaginationTitle) : KeyVerificationRequestStatusWithPaginationTitleBubbleCell.class,
@(RoomTimelineCellIdentifierKeyVerificationConclusion) : KeyVerificationConclusionBubbleCell.class,
@(RoomTimelineCellIdentifierKeyVerificationConclusionWithPaginationTitle) : KeyVerificationConclusionWithPaginationTitleBubbleCell.class,
};
}
- (NSDictionary<NSNumber*, Class>*)roomCreationCellsMapping
{
return @{
@(RoomTimelineCellIdentifierRoomCreationCollapsed) : RoomCreationCollapsedBubbleCell.class,
@(RoomTimelineCellIdentifierRoomCreationCollapsedWithPaginationTitle) : RoomCreationWithPaginationCollapsedBubbleCell.class,
};
}
- (NSDictionary<NSNumber*, Class>*)callCellsMapping
{
return @{
@(RoomTimelineCellIdentifierDirectCallStatus) : RoomDirectCallStatusBubbleCell.class,
@(RoomTimelineCellIdentifierGroupCallStatus) : RoomGroupCallStatusBubbleCell.class,
};
}
- (NSDictionary<NSNumber*, Class>*)voiceMessageCellsMapping
{
return @{
@(RoomTimelineCellIdentifierVoiceMessage) : VoiceMessageBubbleCell.class,
@(RoomTimelineCellIdentifierVoiceMessageWithoutSenderInfo) : VoiceMessageWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierVoiceMessageWithPaginationTitle) : VoiceMessageWithPaginationTitleBubbleCell.class,
};
}
- (NSDictionary<NSNumber*, Class>*)pollCellsMapping
{
return @{
@(RoomTimelineCellIdentifierPoll) : PollBubbleCell.class,
@(RoomTimelineCellIdentifierPollWithoutSenderInfo) : PollWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierPollWithPaginationTitle) : PollWithPaginationTitleBubbleCell.class,
};
}
- (NSDictionary<NSNumber*, Class>*)locationCellsMapping
{
return @{
@(RoomTimelineCellIdentifierLocation) : LocationBubbleCell.class,
@(RoomTimelineCellIdentifierLocationWithoutSenderInfo) : LocationWithoutSenderInfoBubbleCell.class,
@(RoomTimelineCellIdentifierLocationWithPaginationTitle) : LocationWithPaginationTitleBubbleCell.class
};
}
@end
@@ -0,0 +1,74 @@
//
// 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 PlainRoomTimelineStyle: RoomTimelineStyle {
// MARK: - Properties
// MARK: Private
private var theme: Theme
// MARK: Public
let identifier: RoomTimelineStyleIdentifier
let cellLayoutUpdater: RoomCellLayoutUpdating?
let cellProvider: RoomTimelineCellProvider
let cellDecorator: RoomTimelineCellDecorator
// MARK: - Setup
init(theme: Theme) {
self.theme = theme
self.identifier = .plain
self.cellLayoutUpdater = nil
self.cellProvider = PlainRoomTimelineCellProvider()
self.cellDecorator = PlainRoomTimelineCellDecorator()
}
// MARK: - Methods
func canAddEvent(_ event: MXEvent, and roomState: MXRoomState, to cellData: MXKRoomBubbleCellData) -> Bool {
return true
}
func applySelectedStyleIfNeeded(toCell cell: MXKRoomBubbleTableViewCell, cellData: RoomBubbleCellData) {
// Check whether the selected event belongs to this bubble
let selectedComponentIndex = cellData.selectedComponentIndex
if selectedComponentIndex != NSNotFound {
let showTimestamp = cellData.showTimestampForSelectedComponent
cell.selectComponent(UInt(selectedComponentIndex),
showEditButton: false,
showTimestamp: showTimestamp)
} else {
cell.blurred = true
}
}
// MARK: Themable
func update(theme: Theme) {
self.theme = theme
}
}
@@ -0,0 +1,30 @@
//
// 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
/// Enables to setup or update a room timeline cell view
@objc
protocol RoomCellLayoutUpdating: Themable {
func updateLayoutIfNeeded(for cell: MXKRoomBubbleTableViewCell, andCellData cellData: MXKRoomBubbleCellData)
func setupLayout(forIncomingTextMessageCell cell: MXKRoomBubbleTableViewCell)
func setupLayout(forOutgoingTextMessageCell cell: MXKRoomBubbleTableViewCell)
func setupLayout(forOutgoingFileAttachmentCell cell: MXKRoomBubbleTableViewCell)
}
@@ -0,0 +1,53 @@
//
// 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
/// RoomTimelineCellDecorator enables to add decoration on a cell (reactions, read receipts, timestamp, URL preview).
@objc
protocol RoomTimelineCellDecorator {
func addTimestampLabelIfNeeded(toCell cell: MXKRoomBubbleTableViewCell,
cellData: RoomBubbleCellData)
func addTimestampLabel(toCell cell: MXKRoomBubbleTableViewCell, cellData: RoomBubbleCellData)
func addURLPreviewView(_ urlPreviewView: URLPreviewView,
toCell cell: MXKRoomBubbleTableViewCell,
cellData: RoomBubbleCellData,
contentViewPositionY: CGFloat)
func addReactionView(_ reactionsView: BubbleReactionsView,
toCell cell: MXKRoomBubbleTableViewCell,
cellData: RoomBubbleCellData,
contentViewPositionY: CGFloat,
upperDecorationView: UIView?)
func addReadReceiptsView(_ readReceiptsView: MXKReceiptSendersContainer,
toCell cell: MXKRoomBubbleTableViewCell,
cellData: RoomBubbleCellData,
contentViewPositionY: CGFloat,
upperDecorationView: UIView?)
func addThreadSummaryView(_ threadSummaryView: ThreadSummaryView,
toCell cell: MXKRoomBubbleTableViewCell,
cellData: RoomBubbleCellData,
contentViewPositionY: CGFloat,
upperDecorationView: UIView?)
func addSendStatusView(toCell cell: MXKRoomBubbleTableViewCell,
withFailedEventIds failedEventIds: Set<AnyHashable>)
}
@@ -0,0 +1,36 @@
//
// 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/UIKit.h>
#import "RoomTimelineCellIdentifier.h"
#import "MXKCellRendering.h"
NS_ASSUME_NONNULL_BEGIN
/// Enables to register and provide room timeline cells
@protocol RoomTimelineCellProvider <NSObject>
/// Register timeline cells for the given table view
- (void)registerCellsForTableView:(UITableView*)tableView;
/// Get timeline cell class from cell identifier
- (Class<MXKCellRendering>)cellViewClassForCellIdentifier:(RoomTimelineCellIdentifier)identifier;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,45 @@
//
// 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
import MatrixSDK
/// RoomTimelineStyle describes a room timeline style used to customize timeline appearance
@objc
protocol RoomTimelineStyle: Themable {
// MARK: - Properties
/// Style identifier
var identifier: RoomTimelineStyleIdentifier { get }
/// Update layout if needed for cells provided by the cell provider
var cellLayoutUpdater: RoomCellLayoutUpdating? { get }
/// Register and provide timeline cells
var cellProvider: RoomTimelineCellProvider { get }
/// Handle cell decorations (reactions, read receipts, URL preview, )
var cellDecorator: RoomTimelineCellDecorator { get }
// MARK: - Methods
/// Indicate to merge or not event in timeline
func canAddEvent(_ event: MXEvent, and roomState: MXRoomState, to cellData: MXKRoomBubbleCellData) -> Bool
/// Apply selected or blurred style on cell
func applySelectedStyleIfNeeded(toCell cell: MXKRoomBubbleTableViewCell, cellData: RoomBubbleCellData)
}
@@ -17,7 +17,8 @@
import Foundation
/// Represents the room timeline style identifiers available
enum RoomTimelineStyleIdentifier {
@objc
enum RoomTimelineStyleIdentifier: Int {
case plain
case bubble
}
@@ -0,0 +1,24 @@
/*
Copyright 2015 OpenMarket 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 "MXKRoomIncomingBubbleTableViewCell.h"
/**
`MXKRoomIncomingTextMsgBubbleCell` displays incoming message bubbles with sender's information.
*/
@interface MXKRoomIncomingTextMsgBubbleCell : MXKRoomIncomingBubbleTableViewCell
@end
@@ -0,0 +1,32 @@
/*
Copyright 2015 OpenMarket 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 "MXKRoomIncomingTextMsgBubbleCell.h"
#import "GeneratedInterface-Swift.h"
@implementation MXKRoomIncomingTextMsgBubbleCell
- (void)setupViews
{
[super setupViews];
RoomTimelineConfiguration *timelineConfiguration = [RoomTimelineConfiguration shared];
[timelineConfiguration.currentStyle.cellLayoutUpdater setupLayoutForIncomingTextMessageCell:self];
}
@end
@@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
<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"/>
<tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="WmY-Jw-mqv" customClass="MXKRoomIncomingTextMsgBubbleCell">
<rect key="frame" x="0.0" y="0.0" width="600" height="50"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="WmY-Jw-mqv" id="ef1-Tq-U3Z">
<rect key="frame" x="0.0" y="0.0" width="600" height="49.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<view clipsSubviews="YES" contentMode="scaleAspectFill" translatesAutoresizingMaskIntoConstraints="NO" id="hgp-Z5-rAj" userLabel="Picture View" customClass="MXKImageView">
<rect key="frame" x="8" y="5" width="40" height="40"/>
<color key="backgroundColor" red="0.66666666666666663" green="0.66666666666666663" blue="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" constant="40" id="NQk-ck-Lo8"/>
<constraint firstAttribute="height" constant="40" id="dNT-QU-CUG"/>
</constraints>
</view>
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="zwq-eh-8Fb" userLabel="typingBadge">
<rect key="frame" x="5" y="0.0" width="20" height="20"/>
<constraints>
<constraint firstAttribute="width" constant="20" id="7ni-rb-ovL"/>
<constraint firstAttribute="height" constant="20" id="mcu-rQ-hnj"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="User name:" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="8" translatesAutoresizingMaskIntoConstraints="NO" id="q9c-0p-QyP">
<rect key="frame" x="51" y="3" width="480" height="20"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="20" placeholder="YES" id="5ZO-W1-tS2"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="13"/>
<color key="textColor" red="0.33333333333333331" green="0.33333333333333331" blue="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" scrollEnabled="NO" editable="NO" text="text message" translatesAutoresizingMaskIntoConstraints="NO" id="HTH-5n-MSU" customClass="MXKMessageTextView">
<rect key="frame" x="51" y="10" width="97" height="39.5"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" constant="97" id="9EQ-AP-La0"/>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="39" id="ZZt-rc-tVJ"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
<dataDetectorType key="dataDetectorTypes" link="YES"/>
</textView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="kwd-hP-feC" userLabel="showHideDateTime">
<rect key="frame" x="531" y="0.0" width="69" height="49.5"/>
<constraints>
<constraint firstAttribute="width" constant="69" id="9vA-4g-EE5"/>
</constraints>
<state key="normal">
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="showHideDateTime:" destination="WmY-Jw-mqv" eventType="touchUpInside" id="jYV-nj-p60"/>
</connections>
</button>
<view hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="IOg-Kt-8vW" userLabel="bubbleInfoContainer">
<rect key="frame" x="531" y="10" width="61" height="39.5"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" constant="61" id="tLr-6k-ArA"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="L3N-gy-H1n">
<rect key="frame" x="48" y="0.0" width="486" height="26"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
</view>
</subviews>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="hgp-Z5-rAj" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" constant="5" id="2Ih-ga-N9s"/>
<constraint firstItem="kwd-hP-feC" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" id="5bB-HV-WAA"/>
<constraint firstItem="L3N-gy-H1n" firstAttribute="leading" secondItem="q9c-0p-QyP" secondAttribute="leading" constant="-3" id="7gc-A2-DNj"/>
<constraint firstAttribute="trailing" secondItem="q9c-0p-QyP" secondAttribute="trailing" constant="69" id="Bkh-h2-JOQ"/>
<constraint firstItem="L3N-gy-H1n" firstAttribute="trailing" secondItem="q9c-0p-QyP" secondAttribute="trailing" constant="3" id="FLX-Dd-CqO"/>
<constraint firstItem="L3N-gy-H1n" firstAttribute="bottom" secondItem="q9c-0p-QyP" secondAttribute="bottom" constant="3" id="IpR-cp-Yod"/>
<constraint firstItem="q9c-0p-QyP" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" constant="3" id="Ixr-7h-f8j"/>
<constraint firstAttribute="bottom" secondItem="kwd-hP-feC" secondAttribute="bottom" id="LQg-cI-Nkn"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="HTH-5n-MSU" secondAttribute="trailing" constant="69" id="Shz-6S-kGd"/>
<constraint firstAttribute="bottom" secondItem="IOg-Kt-8vW" secondAttribute="bottom" id="TPw-iE-nii"/>
<constraint firstItem="IOg-Kt-8vW" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" constant="10" id="XSL-TG-m62"/>
<constraint firstItem="q9c-0p-QyP" firstAttribute="leading" secondItem="hgp-Z5-rAj" secondAttribute="trailing" constant="3" id="YWK-C2-15w"/>
<constraint firstItem="zwq-eh-8Fb" firstAttribute="leading" secondItem="ef1-Tq-U3Z" secondAttribute="leading" constant="5" id="dgK-4e-UuE"/>
<constraint firstAttribute="trailing" secondItem="kwd-hP-feC" secondAttribute="trailing" id="f2V-Ka-kU3"/>
<constraint firstAttribute="trailing" secondItem="IOg-Kt-8vW" secondAttribute="trailing" constant="8" id="hQV-lO-7aQ"/>
<constraint firstItem="HTH-5n-MSU" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" constant="10" id="mkw-3s-H8B"/>
<constraint firstAttribute="bottom" secondItem="HTH-5n-MSU" secondAttribute="bottom" id="oTk-3F-SEC"/>
<constraint firstItem="zwq-eh-8Fb" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" id="tUd-UR-lzA"/>
<constraint firstItem="L3N-gy-H1n" firstAttribute="top" secondItem="q9c-0p-QyP" secondAttribute="top" constant="-3" id="tXi-p0-wft"/>
<constraint firstItem="hgp-Z5-rAj" firstAttribute="leading" secondItem="ef1-Tq-U3Z" secondAttribute="leading" constant="8" id="tuw-aU-ncu"/>
<constraint firstItem="HTH-5n-MSU" firstAttribute="leading" secondItem="ef1-Tq-U3Z" secondAttribute="leading" constant="51" id="uig-Xh-7m6"/>
</constraints>
</tableViewCellContentView>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<outlet property="bubbleInfoContainer" destination="IOg-Kt-8vW" id="TAw-QY-Y9e"/>
<outlet property="bubbleInfoContainerTopConstraint" destination="XSL-TG-m62" id="qVf-vJ-4aP"/>
<outlet property="messageTextView" destination="HTH-5n-MSU" id="YN4-iK-gNc"/>
<outlet property="msgTextViewBottomConstraint" destination="oTk-3F-SEC" id="o0p-3S-hM4"/>
<outlet property="msgTextViewLeadingConstraint" destination="uig-Xh-7m6" id="kgj-3v-ECW"/>
<outlet property="msgTextViewMinHeightConstraint" destination="ZZt-rc-tVJ" id="hDD-TL-PFM"/>
<outlet property="msgTextViewTopConstraint" destination="mkw-3s-H8B" id="lON-oG-Xx9"/>
<outlet property="msgTextViewTrailingConstraint" destination="Shz-6S-kGd" id="5ib-m6-Lna"/>
<outlet property="msgTextViewWidthConstraint" destination="9EQ-AP-La0" id="wgi-Yc-sTT"/>
<outlet property="pictureView" destination="hgp-Z5-rAj" id="rKM-QG-RJN"/>
<outlet property="typingBadge" destination="zwq-eh-8Fb" id="4vs-Dk-vWt"/>
<outlet property="userNameLabel" destination="q9c-0p-QyP" id="JId-R7-LoM"/>
<outlet property="userNameTapGestureMaskView" destination="L3N-gy-H1n" id="1Eb-Vn-fSP"/>
</connections>
</tableViewCell>
</objects>
</document>
@@ -0,0 +1,24 @@
/*
Copyright 2015 OpenMarket 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 "MXKRoomIncomingTextMsgBubbleCell.h"
/**
`MXKRoomIncomingTextMsgWithoutSenderInfoBubbleCell` displays incoming message bubbles without sender's information.
*/
@interface MXKRoomIncomingTextMsgWithoutSenderInfoBubbleCell : MXKRoomIncomingTextMsgBubbleCell
@end
@@ -0,0 +1,21 @@
/*
Copyright 2015 OpenMarket 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 "MXKRoomIncomingTextMsgWithoutSenderInfoBubbleCell.h"
@implementation MXKRoomIncomingTextMsgWithoutSenderInfoBubbleCell
@end
@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
<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"/>
<tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="WmY-Jw-mqv" customClass="MXKRoomIncomingTextMsgWithoutSenderInfoBubbleCell">
<rect key="frame" x="0.0" y="0.0" width="600" height="35"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="WmY-Jw-mqv" id="ef1-Tq-U3Z">
<rect key="frame" x="0.0" y="0.0" width="600" height="34.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" scrollEnabled="NO" editable="NO" text="text message" translatesAutoresizingMaskIntoConstraints="NO" id="HTH-5n-MSU" customClass="MXKMessageTextView">
<rect key="frame" x="51" y="0.0" width="97" height="34.5"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="29" id="SHB-dF-A5J"/>
<constraint firstAttribute="width" constant="97" id="aQ3-Pg-LVD"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
<dataDetectorType key="dataDetectorTypes" link="YES"/>
</textView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="kwd-hP-feC" userLabel="showHideDateTime">
<rect key="frame" x="531" y="0.0" width="69" height="34.5"/>
<constraints>
<constraint firstAttribute="width" constant="69" id="9vA-4g-EE5"/>
</constraints>
<state key="normal">
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="showHideDateTime:" destination="WmY-Jw-mqv" eventType="touchUpInside" id="jYV-nj-p60"/>
</connections>
</button>
<view hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="IOg-Kt-8vW" userLabel="bubbleInfoContainer">
<rect key="frame" x="531" y="0.0" width="61" height="34.5"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" constant="61" id="tLr-6k-ArA"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="kwd-hP-feC" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" id="5bB-HV-WAA"/>
<constraint firstAttribute="bottom" secondItem="kwd-hP-feC" secondAttribute="bottom" id="LQg-cI-Nkn"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="HTH-5n-MSU" secondAttribute="trailing" constant="69" id="Shz-6S-kGd"/>
<constraint firstAttribute="bottom" secondItem="IOg-Kt-8vW" secondAttribute="bottom" id="TPw-iE-nii"/>
<constraint firstItem="IOg-Kt-8vW" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" id="XSL-TG-m62"/>
<constraint firstAttribute="trailing" secondItem="kwd-hP-feC" secondAttribute="trailing" id="f2V-Ka-kU3"/>
<constraint firstAttribute="trailing" secondItem="IOg-Kt-8vW" secondAttribute="trailing" constant="8" id="hQV-lO-7aQ"/>
<constraint firstItem="HTH-5n-MSU" firstAttribute="top" secondItem="ef1-Tq-U3Z" secondAttribute="top" id="mkw-3s-H8B"/>
<constraint firstAttribute="bottom" secondItem="HTH-5n-MSU" secondAttribute="bottom" id="oTk-3F-SEC"/>
<constraint firstItem="HTH-5n-MSU" firstAttribute="leading" secondItem="ef1-Tq-U3Z" secondAttribute="leading" constant="51" id="uig-Xh-7m6"/>
</constraints>
</tableViewCellContentView>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<outlet property="bubbleInfoContainer" destination="IOg-Kt-8vW" id="TAw-QY-Y9e"/>
<outlet property="bubbleInfoContainerTopConstraint" destination="XSL-TG-m62" id="qVf-vJ-4aP"/>
<outlet property="messageTextView" destination="HTH-5n-MSU" id="YN4-iK-gNc"/>
<outlet property="msgTextViewBottomConstraint" destination="oTk-3F-SEC" id="86P-vn-8mz"/>
<outlet property="msgTextViewLeadingConstraint" destination="uig-Xh-7m6" id="kgj-3v-ECW"/>
<outlet property="msgTextViewMinHeightConstraint" destination="SHB-dF-A5J" id="RjV-W7-QaK"/>
<outlet property="msgTextViewTopConstraint" destination="mkw-3s-H8B" id="lON-oG-Xx9"/>
<outlet property="msgTextViewTrailingConstraint" destination="Shz-6S-kGd" id="5ib-m6-Lna"/>
<outlet property="msgTextViewWidthConstraint" destination="aQ3-Pg-LVD" id="JPV-up-dzy"/>
</connections>
</tableViewCell>
</objects>
</document>
@@ -0,0 +1,24 @@
/*
Copyright 2015 OpenMarket 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 "MXKRoomOutgoingBubbleTableViewCell.h"
/**
`MXKRoomOutgoingTextMsgBubbleCell` displays outgoing message bubbles with user's picture.
*/
@interface MXKRoomOutgoingTextMsgBubbleCell : MXKRoomOutgoingBubbleTableViewCell
@end
@@ -0,0 +1,33 @@
/*
Copyright 2015 OpenMarket 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 "MXKRoomOutgoingTextMsgBubbleCell.h"
#import "GeneratedInterface-Swift.h"
@implementation MXKRoomOutgoingTextMsgBubbleCell
- (void)setupViews
{
[super setupViews];
RoomTimelineConfiguration *timelineConfiguration = [RoomTimelineConfiguration shared];
[timelineConfiguration.currentStyle.cellLayoutUpdater setupLayoutForOutgoingTextMessageCell:self];
}
@end
@@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
<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"/>
<tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="pad-g3-2YJ" customClass="MXKRoomOutgoingTextMsgBubbleCell">
<rect key="frame" x="0.0" y="0.0" width="600" height="50"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="pad-g3-2YJ" id="fCg-ju-gnG">
<rect key="frame" x="0.0" y="0.0" width="600" height="49.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<view clipsSubviews="YES" contentMode="scaleAspectFill" translatesAutoresizingMaskIntoConstraints="NO" id="ezT-Dl-ESR" userLabel="Picture View" customClass="MXKImageView">
<rect key="frame" x="552" y="5" width="40" height="40"/>
<color key="backgroundColor" red="0.66666666666666663" green="0.66666666666666663" blue="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" constant="40" id="JHc-dD-geb"/>
<constraint firstAttribute="height" constant="40" id="lFb-Jo-C7R"/>
</constraints>
</view>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" scrollEnabled="NO" editable="NO" text="text message" translatesAutoresizingMaskIntoConstraints="NO" id="tgO-Rv-C7R" customClass="MXKMessageTextView">
<rect key="frame" x="452" y="10" width="97" height="39.5"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="39" id="2xF-Uv-zZv"/>
<constraint firstAttribute="width" constant="97" id="ghN-E7-j4d"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
<dataDetectorType key="dataDetectorTypes" link="YES"/>
</textView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="LVJ-Av-zVs" userLabel="showHideDateTime">
<rect key="frame" x="0.0" y="0.0" width="69" height="49.5"/>
<constraints>
<constraint firstAttribute="width" constant="69" id="ghQ-Qb-BBg"/>
</constraints>
<state key="normal">
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="showHideDateTime:" destination="pad-g3-2YJ" eventType="touchUpInside" id="Ztw-z5-zlU"/>
</connections>
</button>
<view hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="a51-cR-7FE" userLabel="bubbleInfoContainer">
<rect key="frame" x="8" y="10" width="61" height="39.5"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" constant="61" id="fDy-iL-hrD"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="ezT-Dl-ESR" secondAttribute="trailing" constant="8" id="3Pd-Qy-Xva"/>
<constraint firstAttribute="bottom" secondItem="tgO-Rv-C7R" secondAttribute="bottom" id="7C3-Tl-mMq"/>
<constraint firstItem="tgO-Rv-C7R" firstAttribute="top" secondItem="fCg-ju-gnG" secondAttribute="top" constant="10" id="8Sy-eu-tYs"/>
<constraint firstItem="a51-cR-7FE" firstAttribute="leading" secondItem="fCg-ju-gnG" secondAttribute="leading" constant="8" id="E3x-h8-GPF"/>
<constraint firstItem="LVJ-Av-zVs" firstAttribute="leading" secondItem="fCg-ju-gnG" secondAttribute="leading" id="Hve-E3-z5N"/>
<constraint firstAttribute="bottom" secondItem="LVJ-Av-zVs" secondAttribute="bottom" id="IKr-Dc-HKz"/>
<constraint firstItem="ezT-Dl-ESR" firstAttribute="top" secondItem="fCg-ju-gnG" secondAttribute="top" constant="5" id="aHl-KA-68x"/>
<constraint firstItem="a51-cR-7FE" firstAttribute="top" secondItem="fCg-ju-gnG" secondAttribute="top" constant="10" id="fQv-07-Pgx"/>
<constraint firstItem="tgO-Rv-C7R" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="fCg-ju-gnG" secondAttribute="leading" constant="69" id="hwr-aa-TB4"/>
<constraint firstItem="LVJ-Av-zVs" firstAttribute="top" secondItem="fCg-ju-gnG" secondAttribute="top" id="pYO-hi-P72"/>
<constraint firstAttribute="bottom" secondItem="a51-cR-7FE" secondAttribute="bottom" id="viZ-Sx-3RW"/>
<constraint firstAttribute="trailing" secondItem="tgO-Rv-C7R" secondAttribute="trailing" constant="51" id="xYz-lp-c7K"/>
</constraints>
</tableViewCellContentView>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<outlet property="bubbleInfoContainer" destination="a51-cR-7FE" id="wrR-cU-DVm"/>
<outlet property="bubbleInfoContainerTopConstraint" destination="fQv-07-Pgx" id="82c-KH-Wop"/>
<outlet property="messageTextView" destination="tgO-Rv-C7R" id="LZ5-hQ-AbQ"/>
<outlet property="msgTextViewBottomConstraint" destination="7C3-Tl-mMq" id="wCR-UC-iq8"/>
<outlet property="msgTextViewLeadingConstraint" destination="hwr-aa-TB4" id="c9j-8p-cpx"/>
<outlet property="msgTextViewMinHeightConstraint" destination="2xF-Uv-zZv" id="t2t-18-GqU"/>
<outlet property="msgTextViewTopConstraint" destination="8Sy-eu-tYs" id="7yx-oJ-KBP"/>
<outlet property="msgTextViewTrailingConstraint" destination="xYz-lp-c7K" id="ubt-P4-J2o"/>
<outlet property="msgTextViewWidthConstraint" destination="ghN-E7-j4d" id="Dic-6M-yCy"/>
<outlet property="pictureView" destination="ezT-Dl-ESR" id="YsO-Kp-xaD"/>
</connections>
</tableViewCell>
</objects>
</document>
@@ -0,0 +1,24 @@
/*
Copyright 2015 OpenMarket 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 "MXKRoomOutgoingTextMsgBubbleCell.h"
/**
`MXKRoomOutgoingTextMsgWithoutSenderInfoBubbleCell` displays outgoing message bubbles without user's name.
*/
@interface MXKRoomOutgoingTextMsgWithoutSenderInfoBubbleCell : MXKRoomOutgoingTextMsgBubbleCell
@end
@@ -0,0 +1,21 @@
/*
Copyright 2015 OpenMarket 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 "MXKRoomOutgoingTextMsgWithoutSenderInfoBubbleCell.h"
@implementation MXKRoomOutgoingTextMsgWithoutSenderInfoBubbleCell
@end
@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
<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"/>
<tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="pad-g3-2YJ" customClass="MXKRoomOutgoingTextMsgWithoutSenderInfoBubbleCell">
<rect key="frame" x="0.0" y="0.0" width="600" height="35"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="pad-g3-2YJ" id="fCg-ju-gnG">
<rect key="frame" x="0.0" y="0.0" width="600" height="34.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" scrollEnabled="NO" editable="NO" text="text message" translatesAutoresizingMaskIntoConstraints="NO" id="tgO-Rv-C7R" customClass="MXKMessageTextView">
<rect key="frame" x="452" y="0.0" width="97" height="34.5"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" constant="97" id="QpI-TQ-x5C"/>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="34" id="ur4-ZU-uyL"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
<dataDetectorType key="dataDetectorTypes" link="YES"/>
</textView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="LVJ-Av-zVs" userLabel="showHideDateTime">
<rect key="frame" x="0.0" y="0.0" width="69" height="34.5"/>
<constraints>
<constraint firstAttribute="width" constant="69" id="ghQ-Qb-BBg"/>
</constraints>
<state key="normal">
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="showHideDateTime:" destination="pad-g3-2YJ" eventType="touchUpInside" id="Ztw-z5-zlU"/>
</connections>
</button>
<view hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="a51-cR-7FE" userLabel="bubbleInfoContainer">
<rect key="frame" x="8" y="0.0" width="61" height="34.5"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" constant="61" id="fDy-iL-hrD"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="tgO-Rv-C7R" secondAttribute="bottom" id="7C3-Tl-mMq"/>
<constraint firstItem="tgO-Rv-C7R" firstAttribute="top" secondItem="fCg-ju-gnG" secondAttribute="top" id="8Sy-eu-tYs"/>
<constraint firstItem="a51-cR-7FE" firstAttribute="leading" secondItem="fCg-ju-gnG" secondAttribute="leading" constant="8" id="E3x-h8-GPF"/>
<constraint firstItem="LVJ-Av-zVs" firstAttribute="leading" secondItem="fCg-ju-gnG" secondAttribute="leading" id="Hve-E3-z5N"/>
<constraint firstAttribute="bottom" secondItem="LVJ-Av-zVs" secondAttribute="bottom" id="IKr-Dc-HKz"/>
<constraint firstItem="a51-cR-7FE" firstAttribute="top" secondItem="fCg-ju-gnG" secondAttribute="top" id="fQv-07-Pgx"/>
<constraint firstItem="tgO-Rv-C7R" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="fCg-ju-gnG" secondAttribute="leading" constant="69" id="hwr-aa-TB4"/>
<constraint firstItem="LVJ-Av-zVs" firstAttribute="top" secondItem="fCg-ju-gnG" secondAttribute="top" id="pYO-hi-P72"/>
<constraint firstAttribute="bottom" secondItem="a51-cR-7FE" secondAttribute="bottom" id="viZ-Sx-3RW"/>
<constraint firstAttribute="trailing" secondItem="tgO-Rv-C7R" secondAttribute="trailing" constant="51" id="xYz-lp-c7K"/>
</constraints>
</tableViewCellContentView>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<outlet property="bubbleInfoContainer" destination="a51-cR-7FE" id="wrR-cU-DVm"/>
<outlet property="bubbleInfoContainerTopConstraint" destination="fQv-07-Pgx" id="82c-KH-Wop"/>
<outlet property="messageTextView" destination="tgO-Rv-C7R" id="LZ5-hQ-AbQ"/>
<outlet property="msgTextViewBottomConstraint" destination="7C3-Tl-mMq" id="ReW-nS-1Jc"/>
<outlet property="msgTextViewLeadingConstraint" destination="hwr-aa-TB4" id="c9j-8p-cpx"/>
<outlet property="msgTextViewMinHeightConstraint" destination="ur4-ZU-uyL" id="gIe-dR-6cb"/>
<outlet property="msgTextViewTopConstraint" destination="8Sy-eu-tYs" id="7yx-oJ-KBP"/>
<outlet property="msgTextViewTrailingConstraint" destination="xYz-lp-c7K" id="ubt-P4-J2o"/>
<outlet property="msgTextViewWidthConstraint" destination="QpI-TQ-x5C" id="6JK-pz-IWm"/>
</connections>
</tableViewCell>
</objects>
</document>
@@ -18,7 +18,7 @@ import Foundation
import Reusable
@objcMembers
class FromThreadView: UIView {
class FromAThreadView: UIView {
private enum Constants {
static let viewHeight: CGFloat = 18
@@ -32,8 +32,8 @@ class FromThreadView: UIView {
return Constants.viewHeight
}
static func instantiate() -> FromThreadView {
let view = FromThreadView.loadFromNib()
static func instantiate() -> FromAThreadView {
let view = FromAThreadView.loadFromNib()
view.update(theme: ThemeService.shared().theme)
view.titleLabel.text = VectorL10n.messageFromAThread
return view
@@ -41,9 +41,9 @@ class FromThreadView: UIView {
}
extension FromThreadView: NibLoadable {}
extension FromAThreadView: NibLoadable {}
extension FromThreadView: Themable {
extension FromAThreadView: Themable {
func update(theme: Theme) {
backgroundColor = .clear
@@ -11,22 +11,22 @@
<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="FromThreadView" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="139" height="44"/>
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="FromAThreadView" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="139" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" spacing="4" translatesAutoresizingMaskIntoConstraints="NO" id="gZf-Nh-De6">
<rect key="frame" x="0.0" y="0.0" width="139" height="44"/>
<rect key="frame" x="0.0" y="0.0" width="139" height="18"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="threads_icon" translatesAutoresizingMaskIntoConstraints="NO" id="cdy-fz-kjn">
<rect key="frame" x="0.0" y="0.0" width="18" height="44"/>
<rect key="frame" x="0.0" y="0.0" width="18" height="18"/>
<constraints>
<constraint firstAttribute="height" constant="18" id="3mH-It-De7"/>
<constraint firstAttribute="width" constant="18" id="Jzw-cL-zxG"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="From a thread" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fX6-Xz-I4e">
<rect key="frame" x="22" y="0.0" width="117" height="44"/>
<rect key="frame" x="22" y="0.0" width="117" height="18"/>
<fontDescription key="fontDescription" type="system" pointSize="13"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
@@ -38,16 +38,16 @@
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="gZf-Nh-De6" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="0Hy-t1-GHo"/>
<constraint firstAttribute="trailing" secondItem="gZf-Nh-De6" secondAttribute="trailing" id="ELX-qi-dTm"/>
<constraint firstAttribute="bottom" secondItem="gZf-Nh-De6" secondAttribute="bottom" id="Pye-fH-Zny"/>
<constraint firstItem="gZf-Nh-De6" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="b2i-tg-f7D"/>
<constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="gZf-Nh-De6" secondAttribute="trailing" id="w9I-0I-lD2"/>
<constraint firstItem="gZf-Nh-De6" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="dWk-cp-fYS"/>
</constraints>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<connections>
<outlet property="iconView" destination="cdy-fz-kjn" id="Kev-ko-oTu"/>
<outlet property="titleLabel" destination="fX6-Xz-I4e" id="65X-PJ-RpF"/>
</connections>
<point key="canvasLocation" x="-119.56521739130436" y="-252.45535714285714"/>
<point key="canvasLocation" x="-119.56521739130436" y="-257.47767857142856"/>
</view>
</objects>
<resources>
@@ -16,8 +16,8 @@
import Foundation
struct ThreadSummaryViewModel {
var numberOfReplies: Int
var lastMessageSenderAvatar: AvatarViewDataProtocol?
var lastMessageText: NSAttributedString?
struct ThreadSummaryModel {
let numberOfReplies: Int
let lastMessageSenderAvatar: AvatarViewDataProtocol?
let lastMessageText: NSAttributedString?
}
@@ -38,7 +38,7 @@ class ThreadSummaryView: UIView {
@IBOutlet private weak var lastMessageContentLabel: UILabel!
private var theme: Theme = ThemeService.shared().theme
private(set) var thread: MXThread!
private(set) var thread: MXThread?
private lazy var tapGestureRecognizer: UITapGestureRecognizer = {
return UITapGestureRecognizer(target: self, action: #selector(tapped(_:)))
@@ -56,9 +56,10 @@ class ThreadSummaryView: UIView {
loadNibContent()
update(theme: ThemeService.shared().theme)
configure()
translatesAutoresizingMaskIntoConstraints = false
}
static func contentViewHeight(forThread thread: MXThread, fitting maxWidth: CGFloat) -> CGFloat {
static func contentViewHeight(forThread thread: MXThread?, fitting maxWidth: CGFloat) -> CGFloat {
return RoomBubbleCellLayout.threadSummaryViewHeight
}
@@ -67,14 +68,14 @@ class ThreadSummaryView: UIView {
loadNibContent()
}
@nonobjc func configure(withViewModel viewModel: ThreadSummaryViewModel) {
numberOfRepliesLabel.text = String(viewModel.numberOfReplies)
if let avatar = viewModel.lastMessageSenderAvatar {
@nonobjc func configure(withModel model: ThreadSummaryModel) {
numberOfRepliesLabel.text = String(model.numberOfReplies)
if let avatar = model.lastMessageSenderAvatar {
lastMessageAvatarView.fill(with: avatar)
} else {
lastMessageAvatarView.avatarImageView.image = nil
}
if let lastMessage = viewModel.lastMessageText {
if let lastMessage = model.lastMessageText {
let mutable = NSMutableAttributedString(attributedString: lastMessage)
mutable.setAttributes([
.font: Constants.lastMessageFont
@@ -116,10 +117,10 @@ class ThreadSummaryView: UIView {
with: roomState,
error: formatterError)
let viewModel = ThreadSummaryViewModel(numberOfReplies: thread.numberOfReplies,
lastMessageSenderAvatar: avatarViewData,
lastMessageText: lastMessageText)
self.configure(withViewModel: viewModel)
let model = ThreadSummaryModel(numberOfReplies: thread.numberOfReplies,
lastMessageSenderAvatar: avatarViewData,
lastMessageText: lastMessageText)
self.configure(withModel: model)
}
}
@@ -132,8 +133,6 @@ class ThreadSummaryView: UIView {
}
}
// extension ThreadSummaryView: NibLoadable {}
extension ThreadSummaryView: NibOwnerLoadable {}
extension ThreadSummaryView: Themable {
@@ -16,12 +16,12 @@
import Foundation
struct ThreadRoomTitleViewModel {
var roomAvatar: AvatarViewDataProtocol?
var roomEncryptionBadge: UIImage?
var roomDisplayName: String?
struct ThreadRoomTitleModel {
let roomAvatar: AvatarViewDataProtocol?
let roomEncryptionBadge: UIImage?
let roomDisplayName: String?
static let empty = ThreadRoomTitleViewModel(roomAvatar: nil,
roomEncryptionBadge: nil,
roomDisplayName: nil)
static let empty = ThreadRoomTitleModel(roomAvatar: nil,
roomEncryptionBadge: nil,
roomDisplayName: nil)
}
@@ -38,15 +38,15 @@ class ThreadRoomTitleView: RoomTitleView {
// MARK: - Methods
func configure(withViewModel viewModel: ThreadRoomTitleViewModel) {
if let avatarViewData = viewModel.roomAvatar {
func configure(withModel model: ThreadRoomTitleModel) {
if let avatarViewData = model.roomAvatar {
roomAvatarView.fill(with: avatarViewData)
} else {
roomAvatarView.avatarImageView.image = nil
}
roomEncryptionBadgeView.image = viewModel.roomEncryptionBadge
roomEncryptionBadgeView.isHidden = viewModel.roomEncryptionBadge == nil
roomNameLabel.text = viewModel.roomDisplayName
roomEncryptionBadgeView.image = model.roomEncryptionBadge
roomEncryptionBadgeView.isHidden = model.roomEncryptionBadge == nil
roomNameLabel.text = model.roomDisplayName
}
// MARK: - Overrides
@@ -81,10 +81,10 @@ class ThreadRoomTitleView: RoomTitleView {
encrpytionBadge = nil
}
let viewModel = ThreadRoomTitleViewModel(roomAvatar: avatarViewData,
roomEncryptionBadge: encrpytionBadge,
roomDisplayName: room.displayName)
configure(withViewModel: viewModel)
let model = ThreadRoomTitleModel(roomAvatar: avatarViewData,
roomEncryptionBadge: encrpytionBadge,
roomDisplayName: room.displayName)
configure(withModel: model)
}
override func awakeFromNib() {