Merge branch 'gil/SP1_space_creation' into gil/5231_SP3-1_Update_room_settings_for_Spaces

# Conflicts:
#	Podfile.lock
This commit is contained in:
Gil Eluard
2022-02-21 17:57:58 +01:00
687 changed files with 8777 additions and 3697 deletions
+62 -28
View File
@@ -241,30 +241,18 @@ NSString *const URLPreviewDidUpdateNotification = @"URLPreviewDidUpdateNotificat
- (NSAttributedString*)attributedTextMessage
{
@synchronized(bubbleComponents)
{
if (self.hasAttributedTextMessage && !attributedTextMessage.length)
{
// Attributed text message depends on the room read receipts which must be retrieved on the main thread to prevent us from race conditions.
// Check here the current thread, this is just a sanity check because the attributed text message
// is requested during the rendering step which takes place on the main thread.
if ([NSThread currentThread] != [NSThread mainThread])
{
MXLogDebug(@"[RoomBubbleCellData] attributedTextMessage called on wrong thread");
dispatch_sync(dispatch_get_main_queue(), ^{
self.attributedTextMessage = [self makeAttributedString];
});
}
else
{
self.attributedTextMessage = [self makeAttributedString];
}
}
}
[self buildAttributedStringIfNeeded];
return attributedTextMessage;
}
- (NSAttributedString*)attributedTextMessageWithoutPositioningSpace
{
[self buildAttributedStringIfNeeded];
return attributedTextMessageWithoutPositioningSpace;
}
- (BOOL)hasNoDisplay
{
if (self.tag == RoomBubbleCellDataTagKeyVerificationNoDisplay)
@@ -378,18 +366,25 @@ NSString *const URLPreviewDidUpdateNotification = @"URLPreviewDidUpdateNotificat
[self setNeedsUpdateAdditionalContentHeight];
}
- (NSAttributedString*)makeAttributedString
- (void)buildAttributedString
{
// CAUTION: This method must be called on the main thread.
// Return the collapsed string only for cells series header
if (self.collapsed && self.collapsedAttributedTextMessage && self.nextCollapsableCellData)
{
return super.collapsedAttributedTextMessage;
NSAttributedString *attributedString = super.collapsedAttributedTextMessage;
self.attributedTextMessage = attributedString;
self.attributedTextMessageWithoutPositioningSpace = attributedString;
return;
}
NSMutableAttributedString *currentAttributedTextMsg;
NSMutableAttributedString *currentAttributedTextMsgWithoutVertSpace = [NSMutableAttributedString new];
NSInteger selectedComponentIndex = self.selectedComponentIndex;
NSInteger lastMessageIndex = self.containsLastMessage ? self.mostRecentComponentIndex : NSNotFound;
@@ -416,11 +411,15 @@ NSString *const URLPreviewDidUpdateNotification = @"URLPreviewDidUpdateNotificat
{
currentAttributedTextMsg = [[NSMutableAttributedString alloc] initWithAttributedString:[RoomBubbleCellData timestampVerticalWhitespace]];
[currentAttributedTextMsg appendAttributedString:componentString];
[currentAttributedTextMsgWithoutVertSpace appendAttributedString:componentString];
}
else
{
// Init attributed string with the first text component
currentAttributedTextMsg = [[NSMutableAttributedString alloc] initWithAttributedString:componentString];
[currentAttributedTextMsgWithoutVertSpace appendAttributedString:componentString];
}
[self addVerticalWhitespaceToString:currentAttributedTextMsg forEvent:component.event.eventId];
@@ -456,10 +455,45 @@ NSString *const URLPreviewDidUpdateNotification = @"URLPreviewDidUpdateNotificat
[currentAttributedTextMsg appendAttributedString:componentString];
[self addVerticalWhitespaceToString:currentAttributedTextMsg forEvent:component.event.eventId];
[currentAttributedTextMsgWithoutVertSpace appendAttributedString:componentString];
}
}
return currentAttributedTextMsg;
// With bubbles the text is truncated with quote messages containing vertical border view
// Add horizontal space to fix the issue
if (self.displayFix & MXKRoomBubbleComponentDisplayFixHtmlBlockquote)
{
[currentAttributedTextMsgWithoutVertSpace appendString:@" "];
}
self.attributedTextMessage = currentAttributedTextMsg;
self.attributedTextMessageWithoutPositioningSpace = currentAttributedTextMsgWithoutVertSpace;
}
- (void)buildAttributedStringIfNeeded
{
@synchronized(bubbleComponents)
{
if (self.hasAttributedTextMessage && !attributedTextMessage.length)
{
// Attributed text message depends on the room read receipts which must be retrieved on the main thread to prevent us from race conditions.
// Check here the current thread, this is just a sanity check because the attributed text message
// is requested during the rendering step which takes place on the main thread.
if ([NSThread currentThread] != [NSThread mainThread])
{
MXLogDebug(@"[RoomBubbleCellData] attributedTextMessage called on wrong thread");
dispatch_sync(dispatch_get_main_queue(), ^{
[self buildAttributedString];
});
}
else
{
[self buildAttributedString];
}
}
}
}
- (NSInteger)firstVisibleComponentIndex
@@ -667,7 +701,7 @@ NSString *const URLPreviewDidUpdateNotification = @"URLPreviewDidUpdateNotificat
// component is not a thread root
return 0;
}
return RoomBubbleCellLayout.threadSummaryViewTopMargin +
return PlainRoomCellLayoutConstants.threadSummaryViewTopMargin +
[ThreadSummaryView contentViewHeightForThread:component.thread fitting:self.maxTextViewWidth];
}
@@ -694,7 +728,7 @@ NSString *const URLPreviewDidUpdateNotification = @"URLPreviewDidUpdateNotificat
// event is not in a thread
return 0;
}
return RoomBubbleCellLayout.fromAThreadViewTopMargin +
return PlainRoomCellLayoutConstants.fromAThreadViewTopMargin +
[FromAThreadView contentViewHeightForEvent:component.event fitting:self.maxTextViewWidth];
}
@@ -706,7 +740,7 @@ NSString *const URLPreviewDidUpdateNotification = @"URLPreviewDidUpdateNotificat
return 0;
}
return RoomBubbleCellLayout.urlPreviewViewTopMargin + [URLPreviewView contentViewHeightFor:component.urlPreviewData
return PlainRoomCellLayoutConstants.urlPreviewViewTopMargin + [URLPreviewView contentViewHeightFor:component.urlPreviewData
fitting:self.maxTextViewWidth];
}
@@ -731,7 +765,7 @@ NSString *const URLPreviewDidUpdateNotification = @"URLPreviewDidUpdateNotificat
BOOL showAllReactions = [self.eventsToShowAllReactions containsObject:eventId];
BubbleReactionsViewModel *viewModel = [[BubbleReactionsViewModel alloc] initWithAggregatedReactions:aggregatedReactions eventId:eventId showAll:showAllReactions];
height = [bubbleReactionsViewSizer heightForViewModel:viewModel fittingWidth:bubbleReactionsViewWidth] + RoomBubbleCellLayout.reactionsViewTopMargin;
height = [bubbleReactionsViewSizer heightForViewModel:viewModel fittingWidth:bubbleReactionsViewWidth] + PlainRoomCellLayoutConstants.reactionsViewTopMargin;
}
return height;
@@ -743,7 +777,7 @@ NSString *const URLPreviewDidUpdateNotification = @"URLPreviewDidUpdateNotificat
if (self.readReceipts[eventId].count)
{
height = RoomBubbleCellLayout.readReceiptsViewHeight + RoomBubbleCellLayout.readReceiptsViewTopMargin;
height = PlainRoomCellLayoutConstants.readReceiptsViewHeight + PlainRoomCellLayoutConstants.readReceiptsViewTopMargin;
}
return height;
@@ -130,6 +130,6 @@
@param roomDataSource room data source instance
*/
- (void)roomDataSource:(RoomDataSource * _Nonnull)roomDataSource
didTapThread:(MXThread * _Nonnull)thread;
didTapThread:(id<MXThreadProtocol> _Nonnull)thread;
@end
+24 -42
View File
@@ -466,7 +466,8 @@ const CGFloat kTypingCellHeight = 24;
// display thread summary view if the component has a thread in the room timeline
if (RiotSettings.shared.enableThreads && component.thread && !self.threadId)
{
threadSummaryView = [[ThreadSummaryView alloc] initWithThread:component.thread];
threadSummaryView = [[ThreadSummaryView alloc] initWithThread:component.thread
session:self.mxSession];
threadSummaryView.delegate = self;
threadSummaryView.tag = index;
@@ -512,7 +513,7 @@ const CGFloat kTypingCellHeight = 24;
if (roomMembers.count)
{
// Define the read receipts container, positioned on the right border of the bubble cell (Note the right margin 6 pts).
avatarsContainer = [[MXKReceiptSendersContainer alloc] initWithFrame:CGRectMake(bubbleCell.frame.size.width - RoomBubbleCellLayout.readReceiptsViewWidth + RoomBubbleCellLayout.readReceiptsViewRightMargin, bottomPositionY + RoomBubbleCellLayout.readReceiptsViewTopMargin, RoomBubbleCellLayout.readReceiptsViewWidth, RoomBubbleCellLayout.readReceiptsViewHeight) andMediaManager:self.mxSession.mediaManager];
avatarsContainer = [[MXKReceiptSendersContainer alloc] initWithFrame:CGRectMake(bubbleCell.frame.size.width - PlainRoomCellLayoutConstants.readReceiptsViewWidth + PlainRoomCellLayoutConstants.readReceiptsViewRightMargin, bottomPositionY + PlainRoomCellLayoutConstants.readReceiptsViewTopMargin, PlainRoomCellLayoutConstants.readReceiptsViewWidth, PlainRoomCellLayoutConstants.readReceiptsViewHeight) andMediaManager:self.mxSession.mediaManager];
// Custom avatar display
avatarsContainer.maxDisplayedAvatars = 5;
@@ -557,48 +558,17 @@ const CGFloat kTypingCellHeight = 24;
if ([componentEventId isEqualToString:self.room.accountData.readMarkerEventId])
{
bubbleCell.readMarkerView = [[UIView alloc] initWithFrame:CGRectMake(0, bottomPositionY - RoomBubbleCellLayout.readMarkerViewHeight, bubbleCell.bubbleOverlayContainer.frame.size.width, RoomBubbleCellLayout.readMarkerViewHeight)];
bubbleCell.readMarkerView.backgroundColor = ThemeService.shared.theme.tintColor;
UIView *readMarkerView = [[UIView alloc] initWithFrame:CGRectMake(0, bottomPositionY - PlainRoomCellLayoutConstants.readMarkerViewHeight, bubbleCell.bubbleOverlayContainer.frame.size.width, PlainRoomCellLayoutConstants.readMarkerViewHeight)];
readMarkerView.backgroundColor = ThemeService.shared.theme.tintColor;
// Hide by default the marker, it will be shown and animated when the cell will be rendered.
bubbleCell.readMarkerView.hidden = YES;
bubbleCell.readMarkerView.tag = index;
readMarkerView.hidden = YES;
readMarkerView.tag = index;
readMarkerView.accessibilityIdentifier = @"readMarker";
bubbleCell.readMarkerView.translatesAutoresizingMaskIntoConstraints = NO;
bubbleCell.readMarkerView.accessibilityIdentifier = @"readMarker";
[bubbleCell.bubbleOverlayContainer addSubview:bubbleCell.readMarkerView];
// Force read marker constraints
bubbleCell.readMarkerViewTopConstraint = [NSLayoutConstraint constraintWithItem:bubbleCell.readMarkerView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:bubbleCell.bubbleOverlayContainer
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:bottomPositionY - RoomBubbleCellLayout.readMarkerViewHeight];
bubbleCell.readMarkerViewLeadingConstraint = [NSLayoutConstraint constraintWithItem:bubbleCell.readMarkerView
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:bubbleCell.bubbleOverlayContainer
attribute:NSLayoutAttributeLeading
multiplier:1.0
constant:0];
bubbleCell.readMarkerViewTrailingConstraint = [NSLayoutConstraint constraintWithItem:bubbleCell.bubbleOverlayContainer
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:bubbleCell.readMarkerView
attribute:NSLayoutAttributeTrailing
multiplier:1.0
constant:0];
bubbleCell.readMarkerViewHeightConstraint = [NSLayoutConstraint constraintWithItem:bubbleCell.readMarkerView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:RoomBubbleCellLayout.readMarkerViewHeight];
[NSLayoutConstraint activateConstraints:@[bubbleCell.readMarkerViewTopConstraint, bubbleCell.readMarkerViewLeadingConstraint, bubbleCell.readMarkerViewTrailingConstraint, bubbleCell.readMarkerViewHeightConstraint]];
[cellDecorator addReadMarkerView:readMarkerView
toCell:bubbleCell
cellData:cellData
contentViewPositionY:bottomPositionY];
}
}
}
@@ -668,6 +638,13 @@ const CGFloat kTypingCellHeight = 24;
// Make extra cell layout updates if needed
[self updateCellLayoutIfNeeded:bubbleCell withCellData:cellData];
}
if ([cell conformsToProtocol:@protocol(Themable)])
{
id<Themable> cellThemable = (id<Themable>)cell;
[cellThemable updateWithTheme:ThemeService.shared.theme];
}
return cell;
}
@@ -1000,6 +977,11 @@ const CGFloat kTypingCellHeight = 24;
- (void)newThreadCreated:(NSNotification *)notification
{
if (self.threadId)
{
// no need to reload the thread screen
return;
}
NSUInteger count = 0;
@synchronized (bubbles)
{
@@ -58,7 +58,6 @@ final class EditHistoryCoordinatorBridgePresenter: NSObject {
func present(from viewController: UIViewController, animated: Bool) {
guard let formatter = self.createEventFormatter(session: self.session) else {
//s das
return
}
@@ -41,9 +41,13 @@ final class EmojiMartService: EmojiServiceType {
let emojiJSONData = try self.getEmojisJSONData()
let emojiJSONStore: EmojiMartStore = try self.serializationService.deserialize(emojiJSONData)
let emojiCategories = self.emojiCategories(from: emojiJSONStore)
completion(MXResponse.success(emojiCategories))
DispatchQueue.main.async {
completion(MXResponse.success(emojiCategories))
}
} catch {
completion(MXResponse.failure(error))
DispatchQueue.main.async {
completion(MXResponse.failure(error))
}
}
}
}
@@ -17,5 +17,7 @@
import Foundation
protocol EmojiServiceType {
/// Returns all available emoji categories. The completion will always be called on the main queue.
func getEmojiCategories(completion: @escaping (MXResponse<[EmojiCategory]>) -> Void)
}
@@ -164,7 +164,7 @@ final class EmojiPickerViewController: UIViewController {
private func setupSearchController() {
let searchController = UISearchController(searchResultsController: nil)
searchController.dimsBackgroundDuringPresentation = false
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchResultsUpdater = self
searchController.searchBar.placeholder = VectorL10n.searchDefaultPlaceholder
searchController.hidesNavigationBarDuringPresentation = false
@@ -88,13 +88,9 @@ final class EmojiPickerViewModel: EmojiPickerViewModelType {
self.emojiStore.set(emojiCategories)
let emojiCatagoryViewDataList = self.emojiCatagoryViewDataList(from: emojiCategories)
DispatchQueue.main.async {
self.update(viewState: .loaded(emojiCategories: emojiCatagoryViewDataList))
}
self.update(viewState: .loaded(emojiCategories: emojiCatagoryViewDataList))
case .failure(let error):
DispatchQueue.main.async {
self.update(viewState: .error(error))
}
self.update(viewState: .error(error))
}
}
}
@@ -35,6 +35,7 @@ class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegat
@IBOutlet private var descriptionContainerView: UIView!
@IBOutlet private var descriptionLabel: UILabel!
@IBOutlet private var descriptionIcon: UIImageView!
@IBOutlet private var attributionLabel: UILabel!
private var mapView: MGLMapView!
private var annotationView: LocationMarkerView?
@@ -101,6 +102,7 @@ class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegat
descriptionLabel.textColor = theme.colors.primaryContent
descriptionLabel.font = theme.fonts.footnote
descriptionIcon.tintColor = theme.colors.accent
attributionLabel.textColor = theme.colors.accent
layer.borderColor = theme.colors.quinaryContent.cgColor
}
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="19529" 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"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
@@ -15,48 +15,72 @@
<rect key="frame" x="0.0" y="0.0" width="395" height="250"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="oVd-gS-Rmb">
<rect key="frame" x="0.0" y="210" width="395" height="40"/>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="0D1-Km-vTu">
<rect key="frame" x="0.0" y="137.5" width="395" height="112.5"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="XHz-4S-fh4">
<rect key="frame" x="12" y="8" width="371" height="24"/>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="HzR-Av-TiG">
<rect key="frame" x="0.0" y="0.0" width="395" height="54.5"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="location_marker_icon" translatesAutoresizingMaskIntoConstraints="NO" id="GP2-dA-giJ">
<rect key="frame" x="0.0" y="0.0" width="24" height="24"/>
<constraints>
<constraint firstAttribute="width" constant="24" id="7nK-Kb-7Iq"/>
<constraint firstAttribute="height" constant="24" id="nBW-gN-0uW"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="c68-l7-McA">
<rect key="frame" x="32" y="2" width="339" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="©MapTiler ©OpenStreetMap contributors" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jWW-0w-1YM">
<rect key="frame" x="0.0" y="0.0" width="387" height="46.5"/>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="jWW-0w-1YM" firstAttribute="top" secondItem="HzR-Av-TiG" secondAttribute="top" id="1Hd-f0-Is6"/>
<constraint firstItem="jWW-0w-1YM" firstAttribute="leading" secondItem="HzR-Av-TiG" secondAttribute="leading" id="R9R-Za-1Li"/>
<constraint firstAttribute="trailing" secondItem="jWW-0w-1YM" secondAttribute="trailing" constant="8" id="Up7-yC-9tX"/>
<constraint firstAttribute="bottom" secondItem="jWW-0w-1YM" secondAttribute="bottom" constant="8" id="t8L-m8-q4c"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="oVd-gS-Rmb">
<rect key="frame" x="0.0" y="62.5" width="395" height="50"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="XHz-4S-fh4">
<rect key="frame" x="12" y="8" width="371" height="34"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="location_marker_icon" translatesAutoresizingMaskIntoConstraints="NO" id="GP2-dA-giJ">
<rect key="frame" x="0.0" y="5" width="24" height="24"/>
<constraints>
<constraint firstAttribute="width" constant="24" id="7nK-Kb-7Iq"/>
<constraint firstAttribute="height" constant="24" id="nBW-gN-0uW"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="c68-l7-McA">
<rect key="frame" x="32" y="7" width="339" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="XHz-4S-fh4" secondAttribute="trailing" constant="12" id="FI1-B7-bPV"/>
<constraint firstItem="XHz-4S-fh4" firstAttribute="top" secondItem="oVd-gS-Rmb" secondAttribute="top" constant="8" id="UJq-Yz-ikR"/>
<constraint firstAttribute="bottom" secondItem="XHz-4S-fh4" secondAttribute="bottom" constant="8" id="cvr-Gb-uLe"/>
<constraint firstItem="XHz-4S-fh4" firstAttribute="leading" secondItem="oVd-gS-Rmb" secondAttribute="leading" constant="12" id="wSE-NS-2h4"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="XHz-4S-fh4" secondAttribute="trailing" constant="12" id="FI1-B7-bPV"/>
<constraint firstItem="XHz-4S-fh4" firstAttribute="top" secondItem="oVd-gS-Rmb" secondAttribute="top" constant="8" id="UJq-Yz-ikR"/>
<constraint firstAttribute="bottom" secondItem="XHz-4S-fh4" secondAttribute="bottom" constant="8" id="cvr-Gb-uLe"/>
<constraint firstItem="XHz-4S-fh4" firstAttribute="leading" secondItem="oVd-gS-Rmb" secondAttribute="leading" constant="12" id="wSE-NS-2h4"/>
</constraints>
</view>
</stackView>
</subviews>
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="oVd-gS-Rmb" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="6Vw-QI-iN2"/>
<constraint firstItem="oVd-gS-Rmb" firstAttribute="bottom" secondItem="vUN-kp-3ea" secondAttribute="bottom" id="FVf-yb-Gxc"/>
<constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="oVd-gS-Rmb" secondAttribute="trailing" id="O3u-fm-TxC"/>
<constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="0D1-Km-vTu" secondAttribute="trailing" id="QHD-xv-nfX"/>
<constraint firstAttribute="bottom" secondItem="0D1-Km-vTu" secondAttribute="bottom" id="ea5-xx-V3s"/>
<constraint firstItem="0D1-Km-vTu" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="yJw-DU-ien"/>
</constraints>
<nil key="simulatedTopBarMetrics"/>
<nil key="simulatedBottomBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<connections>
<outlet property="attributionLabel" destination="jWW-0w-1YM" id="MtF-th-LJr"/>
<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"/>
+9 -2
View File
@@ -438,10 +438,17 @@ typedef NS_ENUM(NSUInteger, MXKRoomViewControllerJoinRoomResult) {
- (void)setBubbleTableViewContentOffset:(CGPoint)contentOffset animated:(BOOL)animated;
/**
Handle typing notification.
Sends a typing notification with the specified timeout.
@param typing Flag indicating whether the user is typing or not.
@param notificationTimeoutMS The length of time the typing notification is valid for
*/
- (void)handleTypingNotification:(BOOL)typing;
- (void)sendTypingNotification:(BOOL)typing timeout:(NSUInteger)notificationTimeoutMS;
/**
Share encryption keys in this room.
*/
- (void)shareEncryptionKeys;
@end
+22 -4
View File
@@ -228,6 +228,8 @@
[[[self class] nib] instantiateWithOwner:self options:nil];
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
// Adjust bottom constraint of the input toolbar container in order to take into account potential tabBar
_roomInputToolbarContainerBottomConstraint.active = NO;
_roomInputToolbarContainerBottomConstraint = [NSLayoutConstraint constraintWithItem:self.bottomLayoutGuide
@@ -237,6 +239,8 @@
attribute:NSLayoutAttributeBottom
multiplier:1.0f
constant:0.0f];
#pragma clang diagnostic pop
_roomInputToolbarContainerBottomConstraint.active = YES;
[self.view setNeedsUpdateConstraints];
@@ -419,6 +423,8 @@
});
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-implementations"
// The 2 following methods are deprecated since iOS 8
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
@@ -446,6 +452,7 @@
self->isSizeTransitionInProgress = NO;
});
}
#pragma clang diagnostic pop
- (void)viewDidLayoutSubviews
{
@@ -488,6 +495,8 @@
self.keyboardView = keyboardView;
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
- (void)setKeyboardHeight:(CGFloat)keyboardHeight
{
// Deduce the bottom constraint for the input toolbar view (Don't forget the potential tabBar)
@@ -531,6 +540,7 @@
super.keyboardHeight = keyboardHeight;
}
#pragma clang diagnostic pop
- (void)destroy
{
@@ -1046,7 +1056,7 @@
[titleView destroy];
}
titleView = self.navigationItem.titleView = [roomTitleViewClass roomTitleView];
self.navigationItem.titleView = titleView = [roomTitleViewClass roomTitleView];
titleView.delegate = self;
// Define directly the navigation titleView with the custom title view instance. Do not use anymore a container.
@@ -2116,6 +2126,8 @@
self->eventDetailsView = eventDetailsView;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:eventDetailsView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
@@ -2131,6 +2143,7 @@
attribute:NSLayoutAttributeTop
multiplier:1.0f
constant:-10.0f]];
#pragma clang diagnostic pop
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.view
attribute:NSLayoutAttributeLeading
@@ -3299,7 +3312,7 @@
roomDataSource.partialTextMessage = inputToolbarView.textMessage;
}
[self handleTypingNotification:typing];
[self handleTypingState:typing];
}
- (void)roomInputToolbarView:(MXKRoomInputToolbarView*)toolbarView heightDidChanged:(CGFloat)height completion:(void (^)(BOOL finished))completion
@@ -3420,7 +3433,7 @@
}
# pragma mark - Typing notification
- (void)handleTypingNotification:(BOOL)typing
- (void)handleTypingState:(BOOL)typing
{
NSUInteger notificationTimeoutMS = -1;
if (typing)
@@ -3482,6 +3495,11 @@
lastTypingDate = nil;
}
[self sendTypingNotification:typing timeout:notificationTimeoutMS];
}
- (void)sendTypingNotification:(BOOL)typing timeout:(NSUInteger)notificationTimeoutMS
{
MXWeakify(self);
// Send typing notification to server
@@ -3512,7 +3530,7 @@
// Check whether a new typing event has been observed
BOOL typing = (lastTypingDate != nil);
// Post a new typing notification
[self handleTypingNotification:typing];
[self handleTypingState:typing];
}
@@ -350,7 +350,7 @@
return [AvatarGenerator generateAvatarForMatrixItem:self.mxRoomMember.userId withDisplayName:self.mxRoomMember.displayname];
}
return [MXKTools paintImage:[UIImage imageNamed:@"placeholder"]
return [MXKTools paintImage:AssetImages.placeholder.image
withColor:ThemeService.shared.theme.tintColor];
}
@@ -984,7 +984,7 @@
}
else
{
roomCell.avatarImageView.image = [UIImage imageNamed:@"start_chat"];
roomCell.avatarImageView.image = AssetImages.startChat.image;
roomCell.avatarImageView.defaultBackgroundColor = [UIColor clearColor];
roomCell.avatarImageView.userInteractionEnabled = NO;
roomCell.titleLabel.text = [VectorL10n roomParticipantsActionStartNewChat];
@@ -104,6 +104,8 @@
// Adjust Top and Bottom constraints to take into account potential navBar and tabBar.
[NSLayoutConstraint deactivateConstraints:@[_searchBarTopConstraint]];
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
_searchBarTopConstraint = [NSLayoutConstraint constraintWithItem:self.topLayoutGuide
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
@@ -111,6 +113,7 @@
attribute:NSLayoutAttributeTop
multiplier:1.0f
constant:0.0f];
#pragma clang diagnostic pop
[NSLayoutConstraint activateConstraints:@[_searchBarTopConstraint]];
@@ -145,7 +148,7 @@
if (_showInviteUserFab)
{
// Add invite members button programmatically
[self vc_addFABWithImage:[UIImage imageNamed:@"add_member_floating_action"]
[self vc_addFABWithImage:AssetImages.addMemberFloatingAction.image
target:self
action:@selector(onAddParticipantButtonPressed)];
}
@@ -807,7 +810,7 @@
pendingMaskSpinnerView.alpha = 0;
[UIView animateWithDuration:0.3 delay:0.3 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
pendingMaskSpinnerView.alpha = 1;
self->pendingMaskSpinnerView.alpha = 1;
} completion:^(BOOL finished) {
}];
@@ -73,7 +73,8 @@ class RoomCoordinatorBridgePresenterParameters: NSObject {
/// RoomCoordinatorBridgePresenter enables to start RoomCoordinator from a view controller.
/// This bridge is used while waiting for global usage of coordinator pattern.
/// **WARNING**: This class breaks the Coordinator abstraction and it has been introduced for **Objective-C compatibility only** (mainly for integration in legacy view controllers). Each bridge should be removed once the underlying Coordinator has been integrated by another Coordinator.
/// **WARNING**: This class breaks the Coordinator abstraction and it has been introduced for **Objective-C compatibility only** (mainly for integration in legacy view controllers). Each bridge should be removed
/// once the underlying Coordinator has been integrated by another Coordinator.
@objcMembers
final class RoomCoordinatorBridgePresenter: NSObject {
+127 -63
View File
@@ -90,7 +90,7 @@ NSNotificationName const RoomCallTileTappedNotification = @"RoomCallTileTappedNo
NSNotificationName const RoomGroupCallTileTappedNotification = @"RoomGroupCallTileTappedNotification";
const NSTimeInterval kResizeComposerAnimationDuration = .05;
@interface RoomViewController () <UISearchBarDelegate, UIGestureRecognizerDelegate, UIScrollViewAccessibilityDelegate, RoomTitleViewTapGestureDelegate, RoomParticipantsViewControllerDelegate, MXKRoomMemberDetailsViewControllerDelegate, ContactsTableViewControllerDelegate, MXServerNoticesDelegate, RoomContextualMenuViewControllerDelegate,
@interface RoomViewController () <UISearchBarDelegate, UIGestureRecognizerDelegate, UIScrollViewAccessibilityDelegate, RoomTitleViewTapGestureDelegate, MXKRoomMemberDetailsViewControllerDelegate, ContactsTableViewControllerDelegate, MXServerNoticesDelegate, RoomContextualMenuViewControllerDelegate,
ReactionsMenuViewModelCoordinatorDelegate, EditHistoryCoordinatorBridgePresenterDelegate, MXKDocumentPickerPresenterDelegate, EmojiPickerCoordinatorBridgePresenterDelegate,
ReactionHistoryCoordinatorBridgePresenterDelegate, CameraPresenterDelegate, MediaPickerCoordinatorBridgePresenterDelegate,
RoomDataSourceDelegate, RoomCreationModalCoordinatorBridgePresenterDelegate, RoomInfoCoordinatorBridgePresenterDelegate, DialpadViewControllerDelegate, RemoveJitsiWidgetViewDelegate, VoiceMessageControllerDelegate, SpaceDetailPresenterDelegate, UserSuggestionCoordinatorBridgeDelegate, ThreadsCoordinatorBridgePresenterDelegate, MXThreadingServiceDelegate, RoomParticipantsInviteCoordinatorBridgePresenterDelegate>
@@ -443,7 +443,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
if (ThemeService.shared.isCurrentThemeDark)
{
[self.scrollToBottomButton setImage:[UIImage imageNamed:@"scrolldown_dark"] forState:UIControlStateNormal];
[self.scrollToBottomButton setImage:AssetImages.scrolldownDark.image forState:UIControlStateNormal];
self.jumpToLastUnreadBanner.backgroundColor = ThemeService.shared.theme.colors.navigation;
[self.jumpToLastUnreadBanner vc_removeShadow];
@@ -451,7 +451,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
}
else
{
[self.scrollToBottomButton setImage:[UIImage imageNamed:@"scrolldown"] forState:UIControlStateNormal];
[self.scrollToBottomButton setImage:AssetImages.scrolldown.image forState:UIControlStateNormal];
self.jumpToLastUnreadBanner.backgroundColor = ThemeService.shared.theme.colors.background;
[self.jumpToLastUnreadBanner vc_addShadowWithColor:ThemeService.shared.theme.shadowColor
@@ -1436,7 +1436,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
- (UIBarButtonItem *)videoCallBarButtonItem
{
UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"video_call"]
UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithImage:AssetImages.videoCall.image
style:UIBarButtonItemStylePlain
target:self
action:@selector(onVideoCallPressed:)];
@@ -1447,7 +1447,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
- (UIBarButtonItem *)threadMoreBarButtonItem
{
UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"room_context_menu_more"]
UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithImage:AssetImages.roomContextMenuMore.image
style:UIBarButtonItemStylePlain
target:self
action:@selector(onButtonPressed:)];
@@ -1459,7 +1459,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
- (BadgedBarButtonItem *)threadListBarButtonItem
{
UIButton *button = [UIButton new];
UIImage *icon = [[UIImage imageNamed:@"threads_icon"] vc_resizedWith:CGSizeMake(21, 21)];
UIImage *icon = [AssetImages.threadsIcon.image vc_resizedWith:CGSizeMake(21, 21)];
button.contentEdgeInsets = UIEdgeInsetsMake(4, 8, 4, 8);
[button setImage:icon
forState:UIControlStateNormal];
@@ -1616,7 +1616,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
if (self.roomDataSource.room.summary.membersCount.joined == 2 && self.roomDataSource.room.isDirect)
{
// voice call button for Matrix call
UIBarButtonItem *itemVoice = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"voice_call_hangon_icon"]
UIBarButtonItem *itemVoice = [[UIBarButtonItem alloc] initWithImage:AssetImages.voiceCallHangonIcon.image
style:UIBarButtonItemStylePlain
target:self
action:@selector(onVoiceCallPressed:)];
@@ -1645,7 +1645,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
{
// show Join button
CallTileActionButton *button = [CallTileActionButton new];
[button setImage:[UIImage imageNamed:@"call_video_icon"]
[button setImage:AssetImages.callVideoIcon.image
forState:UIControlStateNormal];
[button setTitle:[VectorL10n roomJoinGroupCall]
forState:UIControlStateNormal];
@@ -1667,7 +1667,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
UIBarButtonItem *item = [self videoCallBarButtonItem];
if (!self.canEditJitsiWidget)
{
item.image = [[UIImage imageNamed:@"video_call"] vc_withAlpha:0.3];
item.image = [AssetImages.videoCall.image vc_withAlpha:0.3];
}
[rightBarButtonItems addObject:item];
}
@@ -1676,7 +1676,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
if ([self widgetsCount:NO])
{
UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"integrations_icon"]
UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithImage:AssetImages.integrationsIcon.image
style:UIBarButtonItemStylePlain
target:self
action:@selector(onIntegrationsPressed:)];
@@ -1995,7 +1995,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
NSMutableArray *actionItems = [NSMutableArray new];
if (RiotSettings.shared.roomScreenAllowMediaLibraryAction)
{
[actionItems addObject:[[RoomActionItem alloc] initWithImage:[UIImage imageNamed:@"action_media_library"] andAction:^{
[actionItems addObject:[[RoomActionItem alloc] initWithImage:AssetImages.actionMediaLibrary.image andAction:^{
MXStrongifyAndReturnIfNil(self);
if ([self.inputToolbarView isKindOfClass:RoomInputToolbarView.class]) {
((RoomInputToolbarView *) self.inputToolbarView).actionMenuOpened = NO;
@@ -2005,7 +2005,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
}
if (RiotSettings.shared.roomScreenAllowStickerAction)
{
[actionItems addObject:[[RoomActionItem alloc] initWithImage:[UIImage imageNamed:@"action_sticker"] andAction:^{
[actionItems addObject:[[RoomActionItem alloc] initWithImage:AssetImages.actionSticker.image andAction:^{
MXStrongifyAndReturnIfNil(self);
if ([self.inputToolbarView isKindOfClass:RoomInputToolbarView.class]) {
((RoomInputToolbarView *) self.inputToolbarView).actionMenuOpened = NO;
@@ -2015,7 +2015,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
}
if (RiotSettings.shared.roomScreenAllowFilesAction)
{
[actionItems addObject:[[RoomActionItem alloc] initWithImage:[UIImage imageNamed:@"action_file"] andAction:^{
[actionItems addObject:[[RoomActionItem alloc] initWithImage:AssetImages.actionFile.image andAction:^{
MXStrongifyAndReturnIfNil(self);
if ([self.inputToolbarView isKindOfClass:RoomInputToolbarView.class]) {
((RoomInputToolbarView *) self.inputToolbarView).actionMenuOpened = NO;
@@ -2025,7 +2025,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
}
if (BuildSettings.pollsEnabled && self.displayConfiguration.sendingPollsEnabled)
{
[actionItems addObject:[[RoomActionItem alloc] initWithImage:[UIImage imageNamed:@"action_poll"] andAction:^{
[actionItems addObject:[[RoomActionItem alloc] initWithImage:AssetImages.actionPoll.image andAction:^{
MXStrongifyAndReturnIfNil(self);
if ([self.inputToolbarView isKindOfClass:RoomInputToolbarView.class]) {
((RoomInputToolbarView *) self.inputToolbarView).actionMenuOpened = NO;
@@ -2035,7 +2035,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
}
if (BuildSettings.locationSharingEnabled)
{
[actionItems addObject:[[RoomActionItem alloc] initWithImage:[UIImage imageNamed:@"action_location"] andAction:^{
[actionItems addObject:[[RoomActionItem alloc] initWithImage:AssetImages.actionLocation.image andAction:^{
MXStrongifyAndReturnIfNil(self);
if ([self.inputToolbarView isKindOfClass:RoomInputToolbarView.class]) {
((RoomInputToolbarView *) self.inputToolbarView).actionMenuOpened = NO;
@@ -2045,7 +2045,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
}
if (RiotSettings.shared.roomScreenAllowCameraAction)
{
[actionItems addObject:[[RoomActionItem alloc] initWithImage:[UIImage imageNamed:@"action_camera"] andAction:^{
[actionItems addObject:[[RoomActionItem alloc] initWithImage:AssetImages.actionCamera.image andAction:^{
MXStrongifyAndReturnIfNil(self);
if ([self.inputToolbarView isKindOfClass:RoomInputToolbarView.class]) {
((RoomInputToolbarView *) self.inputToolbarView).actionMenuOpened = NO;
@@ -2562,7 +2562,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
}
else
{
previewHeader.roomAvatarPlaceholder = [MXKTools paintImage:[UIImage imageNamed:@"placeholder"]
previewHeader.roomAvatarPlaceholder = [MXKTools paintImage:AssetImages.placeholder.image
withColor:ThemeService.shared.theme.tintColor];
}
}
@@ -2594,7 +2594,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
self.bubblesTableViewTopConstraint.constant = self.previewHeaderContainerHeightConstraint.constant - self.bubblesTableView.adjustedContentInset.top;
previewHeader.roomAvatar.alpha = 1;
self->previewHeader.roomAvatar.alpha = 1;
// Force to render the view
[self forceLayoutRefresh];
@@ -2758,17 +2758,35 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
}
else if (bubbleData.tag == RoomBubbleCellDataTagPoll)
{
if (bubbleData.isPaginationFirstBubble)
if (bubbleData.isIncoming)
{
cellIdentifier = RoomTimelineCellIdentifierPollWithPaginationTitle;
}
else if (bubbleData.shouldHideSenderInformation)
{
cellIdentifier = RoomTimelineCellIdentifierPollWithoutSenderInfo;
if (bubbleData.isPaginationFirstBubble)
{
cellIdentifier = RoomTimelineCellIdentifierIncomingPollWithPaginationTitle;
}
else if (bubbleData.shouldHideSenderInformation)
{
cellIdentifier = RoomTimelineCellIdentifierIncomingPollWithoutSenderInfo;
}
else
{
cellIdentifier = RoomTimelineCellIdentifierIncomingPoll;
}
}
else
{
cellIdentifier = RoomTimelineCellIdentifierPoll;
if (bubbleData.isPaginationFirstBubble)
{
cellIdentifier = RoomTimelineCellIdentifierOutgoingPollWithPaginationTitle;
}
else if (bubbleData.shouldHideSenderInformation)
{
cellIdentifier = RoomTimelineCellIdentifierOutgoingPollWithoutSenderInfo;
}
else
{
cellIdentifier = RoomTimelineCellIdentifierOutgoingPoll;
}
}
}
else if (bubbleData.tag == RoomBubbleCellDataTagLocation)
@@ -2804,6 +2822,61 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
}
}
}
else if (roomBubbleCellData.getFirstBubbleComponentWithDisplay.event.isEmote)
{
if (bubbleData.isIncoming)
{
if (bubbleData.isPaginationFirstBubble)
{
if (bubbleData.shouldHideSenderName)
{
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierIncomingEmoteEncryptedWithPaginationTitleWithoutSenderName : RoomTimelineCellIdentifierIncomingEmoteWithPaginationTitleWithoutSenderName;
}
else
{
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierIncomingEmoteEncryptedWithPaginationTitle : RoomTimelineCellIdentifierIncomingEmoteWithPaginationTitle;
}
}
else if (bubbleData.shouldHideSenderInformation)
{
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierIncomingEmoteEncryptedWithoutSenderInfo : RoomTimelineCellIdentifierIncomingEmoteWithoutSenderInfo;
}
else if (bubbleData.shouldHideSenderName)
{
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierIncomingEmoteEncryptedWithoutSenderName : RoomTimelineCellIdentifierIncomingEmoteWithoutSenderName;
}
else
{
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierIncomingEmoteEncrypted : RoomTimelineCellIdentifierIncomingEmote;
}
}
else
{
if (bubbleData.isPaginationFirstBubble)
{
if (bubbleData.shouldHideSenderName)
{
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierOutgoingEmoteEncryptedWithPaginationTitleWithoutSenderName : RoomTimelineCellIdentifierOutgoingEmoteWithPaginationTitleWithoutSenderName;
}
else
{
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierOutgoingEmoteEncryptedWithPaginationTitle : RoomTimelineCellIdentifierOutgoingEmoteWithPaginationTitle;
}
}
else if (bubbleData.shouldHideSenderInformation)
{
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierOutgoingEmoteEncryptedWithoutSenderInfo : RoomTimelineCellIdentifierOutgoingEmoteWithoutSenderInfo;
}
else if (bubbleData.shouldHideSenderName)
{
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierOutgoingEmoteEncryptedWithoutSenderName : RoomTimelineCellIdentifierOutgoingEmoteWithoutSenderName;
}
else
{
cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierOutgoingEmoteEncrypted : RoomTimelineCellIdentifierOutgoingEmote;
}
}
}
else if (bubbleData.isIncoming)
{
if (bubbleData.isAttachmentWithThumbnail)
@@ -3653,7 +3726,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
{
MXKPasteboardManager.shared.pasteboard.URL = url;
[self.view vc_toastWithMessage:VectorL10n.roomEventCopyLinkInfo
image:[UIImage imageNamed:@"link_icon"]
image:AssetImages.linkIcon.image
duration:2.0
position:ToastPositionBottom
additionalMargin:self.roomInputToolbarContainerHeightConstraint.constant];
@@ -4219,7 +4292,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
[self updateTitleViewEncryptionDecoration];
}
- (void)roomDataSource:(RoomDataSource *)roomDataSource didTapThread:(MXThread *)thread
- (void)roomDataSource:(RoomDataSource *)roomDataSource didTapThread:(id<MXThreadProtocol>)thread
{
[self openThreadWithId:thread.id];
}
@@ -4500,6 +4573,15 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
[self.userSuggestionCoordinator processTextMessage:toolbarView.textMessage];
}
- (void)roomInputToolbarViewDidOpenActionMenu:(MXKRoomInputToolbarView*)toolbarView
{
// Consider opening the action menu as beginning to type and share encryption keys if requested.
if ([MXKAppSettings standardAppSettings].outboundGroupSessionKeyPreSharingStrategy == MXKKeyPreSharingWhenTyping)
{
[self shareEncryptionKeys];
}
}
#pragma mark - MXKRoomMemberDetailsViewControllerDelegate
- (void)roomMemberDetailsViewController:(MXKRoomMemberDetailsViewController *)roomMemberDetailsViewController startChatWithMemberId:(NSString *)matrixId completion:(void (^)(void))completion
@@ -5671,6 +5753,8 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
self->encryptionInfoView = encryptionInfoView;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:encryptionInfoView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
@@ -5686,6 +5770,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
attribute:NSLayoutAttributeTop
multiplier:1.0f
constant:-10.0f]];
#pragma clang diagnostic pop
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.view
attribute:NSLayoutAttributeLeading
@@ -5745,44 +5830,23 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
- (void)animateReadMarkerView
{
// Check whether the cell with the read marker is known and if the marker is not animated yet.
if (readMarkerTableViewCell && readMarkerTableViewCell.readMarkerView.isHidden)
if (!readMarkerTableViewCell || readMarkerTableViewCell.readMarkerView.isHidden == NO)
{
RoomBubbleCellData *cellData = (RoomBubbleCellData*)readMarkerTableViewCell.bubbleData;
// Do not display the marker if this is the last message.
if (cellData.containsLastMessage && readMarkerTableViewCell.readMarkerView.tag == cellData.mostRecentComponentIndex)
{
readMarkerTableViewCell.readMarkerView.hidden = YES;
readMarkerTableViewCell = nil;
}
else
{
readMarkerTableViewCell.readMarkerView.hidden = NO;
// Animate the layout to hide the read marker
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[UIView animateWithDuration:1.5 delay:0 options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseIn
animations:^{
readMarkerTableViewCell.readMarkerViewLeadingConstraint.constant = readMarkerTableViewCell.readMarkerViewTrailingConstraint.constant = readMarkerTableViewCell.bubbleOverlayContainer.frame.size.width / 2;
readMarkerTableViewCell.readMarkerView.alpha = 0;
// Force to render the view
[readMarkerTableViewCell.bubbleOverlayContainer layoutIfNeeded];
}
completion:^(BOOL finished){
readMarkerTableViewCell.readMarkerView.hidden = YES;
readMarkerTableViewCell.readMarkerView.alpha = 1;
readMarkerTableViewCell = nil;
}];
});
}
return;
}
RoomBubbleCellData *cellData = (RoomBubbleCellData*)readMarkerTableViewCell.bubbleData;
id<RoomTimelineCellDecorator> cellDecorator = [RoomTimelineConfiguration shared].currentStyle.cellDecorator;
[cellDecorator dissmissReadMarkerViewForCell:readMarkerTableViewCell
cellData:cellData
animated:YES
completion:^{
self->readMarkerTableViewCell = nil;
}];
}
- (void)refreshRemoveJitsiWidgetView
@@ -96,6 +96,10 @@
{
continueBlock();
}
else if (result.result.unsignedData.relations.thread)
{
continueBlock();
}
else
{
[roomDataSource.room liveTimeline:^(id<MXEventTimeline> liveTimeline) {
@@ -143,14 +147,15 @@
{
if (cellData.hasThreadRoot)
{
MXThread *thread = cellData.bubbleComponents.firstObject.thread;
ThreadSummaryView *threadSummaryView = [[ThreadSummaryView alloc] initWithThread:thread];
id<MXThreadProtocol> thread = cellData.bubbleComponents.firstObject.thread;
ThreadSummaryView *threadSummaryView = [[ThreadSummaryView alloc] initWithThread:thread
session:self.mxSession];
[bubbleCell.tmpSubviews addObject:threadSummaryView];
threadSummaryView.translatesAutoresizingMaskIntoConstraints = NO;
[bubbleCell.contentView addSubview:threadSummaryView];
CGFloat leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin;
CGFloat leftMargin = PlainRoomCellLayoutConstants.reactionsViewLeftMargin;
CGFloat height = [ThreadSummaryView contentViewHeightForThread:thread fitting:cellData.maxTextViewWidth];
CGRect bubbleComponentFrame = [bubbleCell componentFrameInContentViewForIndex:0];
@@ -161,9 +166,9 @@
[threadSummaryView.leadingAnchor constraintEqualToAnchor:threadSummaryView.superview.leadingAnchor
constant:leftMargin],
[threadSummaryView.topAnchor constraintEqualToAnchor:threadSummaryView.superview.topAnchor
constant:bottomPositionY + RoomBubbleCellLayout.threadSummaryViewTopMargin],
constant:bottomPositionY + PlainRoomCellLayoutConstants.threadSummaryViewTopMargin],
[threadSummaryView.heightAnchor constraintEqualToConstant:height],
[threadSummaryView.trailingAnchor constraintLessThanOrEqualToAnchor:threadSummaryView.superview.trailingAnchor constant:-RoomBubbleCellLayout.reactionsViewRightMargin]
[threadSummaryView.trailingAnchor constraintLessThanOrEqualToAnchor:threadSummaryView.superview.trailingAnchor constant:-PlainRoomCellLayoutConstants.reactionsViewRightMargin]
]];
}
else if (event.isInThread)
@@ -174,7 +179,7 @@
fromAThreadView.translatesAutoresizingMaskIntoConstraints = NO;
[bubbleCell.contentView addSubview:fromAThreadView];
CGFloat leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin;
CGFloat leftMargin = PlainRoomCellLayoutConstants.reactionsViewLeftMargin;
CGFloat height = [FromAThreadView contentViewHeightForEvent:event fitting:cellData.maxTextViewWidth];
CGRect bubbleComponentFrame = [bubbleCell componentFrameInContentViewForIndex:0];
@@ -185,9 +190,9 @@
[fromAThreadView.leadingAnchor constraintEqualToAnchor:fromAThreadView.superview.leadingAnchor
constant:leftMargin],
[fromAThreadView.topAnchor constraintEqualToAnchor:fromAThreadView.superview.topAnchor
constant:bottomPositionY + RoomBubbleCellLayout.fromAThreadViewTopMargin],
constant:bottomPositionY + PlainRoomCellLayoutConstants.fromAThreadViewTopMargin],
[fromAThreadView.heightAnchor constraintEqualToConstant:height],
[fromAThreadView.trailingAnchor constraintLessThanOrEqualToAnchor:fromAThreadView.superview.trailingAnchor constant:-RoomBubbleCellLayout.reactionsViewRightMargin]
[fromAThreadView.trailingAnchor constraintLessThanOrEqualToAnchor:fromAThreadView.superview.trailingAnchor constant:-PlainRoomCellLayoutConstants.reactionsViewRightMargin]
]];
}
}
@@ -73,10 +73,7 @@
[self initWithTitles:titles viewControllers:viewControllers defaultSelected:0];
[super viewDidLoad];
// Add the Riot background image when search bar is empty
[self addBackgroundImageViewToView:self.view];
// Initialize here the data sources if a matrix session has been already set.
[self initializeDataSources];
@@ -87,13 +84,6 @@
{
[super userInterfaceThemeDidChange];
UIImageView *backgroundImageView = self.backgroundImageView;
if (backgroundImageView)
{
UIImage *image = [MXKTools paintImage:backgroundImageView.image withColor:ThemeService.shared.theme.matrixSearchBackgroundImageTintColor];
backgroundImageView.image = image;
}
// Match the search bar color to the navigation bar color as it extends slightly outside the frame.
self.searchBar.backgroundColor = ThemeService.shared.theme.baseColor;
}
@@ -165,7 +155,7 @@
threadParameters = [[ThreadParameters alloc] initWithThreadId:event.threadId
stackRoomScreen:NO];
}
else if ([self.mainSession.threadingService isEventThreadRoot:event])
else if (event.unsignedData.relations.thread || [self.mainSession.threadingService isEventThreadRoot:event])
{
threadParameters = [[ThreadParameters alloc] initWithThreadId:event.eventId
stackRoomScreen:NO];
@@ -227,15 +217,6 @@
#pragma mark - Override MXKViewController
- (void)setKeyboardHeight:(CGFloat)keyboardHeight
{
[self setKeyboardHeightForBackgroundImage:keyboardHeight];
[super setKeyboardHeight:keyboardHeight];
[self checkAndShowBackgroundImage];
}
- (void)startActivityIndicator
{
// Redirect the operation to the currently displayed VC
@@ -283,48 +264,6 @@
[self.navigationController popViewControllerAnimated:YES];
}
- (void)setKeyboardHeightForBackgroundImage:(CGFloat)keyboardHeight
{
[super setKeyboardHeightForBackgroundImage:keyboardHeight];
if (keyboardHeight > 0)
{
[self checkAndShowBackgroundImage];
}
}
// Check conditions before displaying the background
- (void)checkAndShowBackgroundImage
{
// Note: This background is hidden when keyboard is dismissed.
// The other conditions depend on the current selected view controller.
if (self.selectedViewController == messagesSearchViewController)
{
self.backgroundImageView.hidden = ((messagesSearchDataSource.serverCount != 0) || !messagesSearchViewController.noResultsLabel.isHidden || (self.keyboardHeight == 0));
}
else if (self.selectedViewController == filesSearchViewController)
{
self.backgroundImageView.hidden = ((filesSearchDataSource.serverCount != 0) || !filesSearchViewController.noResultsLabel.isHidden || (self.keyboardHeight == 0));
}
else
{
self.backgroundImageView.hidden = (self.keyboardHeight == 0);
}
if (!self.backgroundImageView.hidden)
{
[self.backgroundImageView layoutIfNeeded];
[self.selectedViewController.view layoutIfNeeded];
// Check whether there is enough space to display this background
// For example, in landscape with the iPhone 5 & 6 screen size, the backgroundImageView must be hidden.
if (self.backgroundImageView.frame.origin.y < 0 || (self.selectedViewController.view.frame.size.height - self.backgroundImageViewBottomConstraint.constant) < self.backgroundImageView.frame.size.height)
{
self.backgroundImageView.hidden = YES;
}
}
}
#pragma mark - Override SegmentedViewController
- (void)setSelectedIndex:(NSUInteger)selectedIndex
@@ -341,8 +280,6 @@
{
if (self.searchBar.text.length)
{
self.backgroundImageView.hidden = YES;
// Forward the search request to the data source
if (self.selectedViewController == messagesSearchViewController)
{
@@ -352,8 +289,8 @@
// Do it asynchronously to give time to messagesSearchViewController to be set up
// so that it can display its loading wheel
dispatch_async(dispatch_get_main_queue(), ^{
[messagesSearchDataSource searchMessages:self.searchBar.text force:NO];
messagesSearchViewController.shouldScrollToBottomOnRefresh = YES;
[self->messagesSearchDataSource searchMessages:self.searchBar.text force:NO];
self->messagesSearchViewController.shouldScrollToBottomOnRefresh = YES;
});
}
}
@@ -365,8 +302,8 @@
// Do it asynchronously to give time to filesSearchViewController to be set up
// so that it can display its loading wheel
dispatch_async(dispatch_get_main_queue(), ^{
[filesSearchDataSource searchMessages:self.searchBar.text force:NO];
filesSearchViewController.shouldScrollToBottomOnRefresh = YES;
[self->filesSearchDataSource searchMessages:self.searchBar.text force:NO];
self->filesSearchViewController.shouldScrollToBottomOnRefresh = YES;
});
}
}
@@ -383,8 +320,6 @@
[filesSearchDataSource searchMessages:nil force:NO];
}
}
[self checkAndShowBackgroundImage];
}
@end
@@ -172,9 +172,6 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
// The pending http operation
MXHTTPOperation* pendingOperation;
// the updating spinner
UIActivityIndicatorView* updatingSpinner;
UIAlertController *currentAlert;
// listen to more events than the mother class
@@ -1091,7 +1088,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
{
MXKPasteboardManager.shared.pasteboard.URL = url;
[self.view vc_toastWithMessage:VectorL10n.roomEventCopyLinkInfo
image:[UIImage imageNamed:@"link_icon"]
image:AssetImages.linkIcon.image
duration:2.0
position:ToastPositionBottom
additionalMargin:0.0];
@@ -2767,7 +2764,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
addAddressCell.mxkLabel.text = nil;
addAddressCell.accessoryType = UITableViewCellAccessoryNone;
addAddressCell.accessoryView = [[UIImageView alloc] initWithImage:[[UIImage imageNamed:@"plus_icon"] vc_tintedImageUsingColor:ThemeService.shared.theme.textPrimaryColor]];
addAddressCell.accessoryView = [[UIImageView alloc] initWithImage:[AssetImages.plusIcon.image vc_tintedImageUsingColor:ThemeService.shared.theme.textPrimaryColor]];
addAddressTextField = addAddressCell.mxkTextField;
addAddressTextField.placeholder = [VectorL10n roomDetailsNewAddressPlaceholder:self.mainSession.matrixRestClient.homeserverSuffix];
@@ -2844,7 +2841,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
{
if ([alias isEqualToString:canonicalAlias])
{
addressCell.accessoryView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"main_alias_icon"]];
addressCell.accessoryView = [[UIImageView alloc] initWithImage:AssetImages.mainAliasIcon.image];
}
}
}
@@ -2868,7 +2865,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
addCommunityCell.mxkLabel.text = nil;
addCommunityCell.accessoryType = UITableViewCellAccessoryNone;
addCommunityCell.accessoryView = [[UIImageView alloc] initWithImage:[[UIImage imageNamed:@"plus_icon"] vc_tintedImageUsingColor:ThemeService.shared.theme.textPrimaryColor]];
addCommunityCell.accessoryView = [[UIImageView alloc] initWithImage:[AssetImages.plusIcon.image vc_tintedImageUsingColor:ThemeService.shared.theme.textPrimaryColor]];
addGroupTextField = addCommunityCell.mxkTextField;
addGroupTextField.placeholder = [VectorL10n roomDetailsNewFlairPlaceholder:self.mainSession.matrixRestClient.homeserverSuffix];
@@ -3408,7 +3405,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
completionHandler(YES);
}];
removeAddressAction.backgroundColor = ThemeService.shared.theme.headerBackgroundColor;
removeAddressAction.image = [[UIImage imageNamed:@"remove_icon"] vc_notRenderedImage];
removeAddressAction.image = [AssetImages.removeIcon.image vc_notRenderedImage];
// Create swipe action configuration
@@ -3429,7 +3426,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
completionHandler(YES);
}];
removeAddressAction.backgroundColor = ThemeService.shared.theme.headerBackgroundColor;
removeAddressAction.image = [[UIImage imageNamed:@"remove_icon"] vc_notRenderedImage];
removeAddressAction.image = [AssetImages.removeIcon.image vc_notRenderedImage];
// Create swipe action configuration
@@ -34,11 +34,11 @@
{
if (enabled)
{
_checkBox.image = [UIImage imageNamed:@"selection_tick"];
_checkBox.image = AssetImages.selectionTick.image;
}
else
{
_checkBox.image = [UIImage imageNamed:@"selection_untick"];
_checkBox.image = AssetImages.selectionUntick.image;
}
_enabled = enabled;
@@ -131,7 +131,7 @@
[checkboxContainer addSubview:checkbox];
// Store the new check box unselected by default
checkbox.image = [UIImage imageNamed:@"selection_untick"];
checkbox.image = AssetImages.selectionUntick.image;
checkbox.tintColor = ThemeService.shared.theme.tintColor;
checkbox.tag = 0;
[checkBoxesArray addObject:checkbox];
@@ -263,7 +263,7 @@
if (isSelected && !checkBox.tag)
{
checkBox.image = [UIImage imageNamed:@"selection_tick"];
checkBox.image = AssetImages.selectionTick.image;
checkBox.tag = 1;
if (!self.allowsMultipleSelection)
@@ -276,7 +276,7 @@
checkBox = checkBoxesArray[k];
if (checkBox.tag)
{
checkBox.image = [UIImage imageNamed:@"selection_untick"];
checkBox.image = AssetImages.selectionUntick.image;
checkBox.tag = 0;
}
}
@@ -285,7 +285,7 @@
}
else if (!isSelected && checkBox.tag)
{
checkBox.image = [UIImage imageNamed:@"selection_untick"];
checkBox.image = AssetImages.selectionUntick.image;
checkBox.tag = 0;
}
}
@@ -0,0 +1,420 @@
/*
Copyright 2020 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import UIKit
@objc protocol BaseRoomCellProtocol: Themable {
var roomCellContentView: RoomCellContentView? { get }
}
/// `BaseRoomCell` allows a room cell that inherits from this class to embed and manage the default room message outer views and add an inner content view.
@objcMembers
class BaseRoomCell: MXKRoomBubbleTableViewCell, BaseRoomCellProtocol {
// MARK: - Constants
// MARK: - Properties
private var areViewsSetup: Bool = false
// MARK: Public
weak var roomCellContentView: RoomCellContentView?
private(set) var theme: Theme?
// Overrides
override var bubbleInfoContainer: UIView! {
get {
guard let infoContainer = self.roomCellContentView?.bubbleInfoContainer else {
fatalError("[BaseRoomCell] bubbleInfoContainer should not be used before set")
}
return infoContainer
}
set {
super.bubbleInfoContainer = newValue
}
}
override var bubbleOverlayContainer: UIView! {
get {
guard let overlayContainer = self.roomCellContentView?.bubbleOverlayContainer else {
fatalError("[BaseRoomCell] bubbleOverlayContainer should not be used before set")
}
return overlayContainer
}
set {
super.bubbleInfoContainer = newValue
}
}
override var bubbleInfoContainerTopConstraint: NSLayoutConstraint! {
get {
guard let infoContainerTopConstraint = self.roomCellContentView?.bubbleInfoContainerTopConstraint else {
fatalError("[BaseRoomCell] bubbleInfoContainerTopConstraint should not be used before set")
}
return infoContainerTopConstraint
}
set {
super.bubbleInfoContainerTopConstraint = newValue
}
}
override var pictureView: MXKImageView! {
get {
guard let roomCellContentView = self.roomCellContentView,
roomCellContentView.showSenderAvatar else {
return nil
}
guard let pictureView = self.roomCellContentView?.avatarImageView else {
fatalError("[BaseRoomCell] pictureView should not be used before set")
}
return pictureView
}
set {
super.pictureView = newValue
}
}
override var userNameLabel: UILabel! {
get {
guard let roomCellContentView = self.roomCellContentView, roomCellContentView.showSenderName else {
return nil
}
guard let userNameLabel = roomCellContentView.userNameLabel else {
fatalError("[BaseRoomCell] userNameLabel should not be used before set")
}
return userNameLabel
}
set {
super.userNameLabel = newValue
}
}
override var userNameTapGestureMaskView: UIView! {
get {
guard let roomCellContentView = self.roomCellContentView,
roomCellContentView.showSenderName else {
return nil
}
guard let userNameTapGestureMaskView = self.roomCellContentView?.userNameTouchMaskView else {
fatalError("[BaseRoomCell] userNameTapGestureMaskView should not be used before set")
}
return userNameTapGestureMaskView
}
set {
super.userNameTapGestureMaskView = newValue
}
}
override var readMarkerViewLeadingConstraint: NSLayoutConstraint! {
get {
if self is RoomCellReadMarkerDisplayable {
return self.roomCellContentView?.readMarkerViewLeadingConstraint
} else {
return super.readMarkerViewLeadingConstraint
}
}
set {
if self is RoomCellReadMarkerDisplayable {
self.roomCellContentView?.readMarkerViewLeadingConstraint = newValue
} else {
super.readMarkerViewLeadingConstraint = newValue
}
}
}
override var readMarkerViewTrailingConstraint: NSLayoutConstraint! {
get {
if self is RoomCellReadMarkerDisplayable {
return self.roomCellContentView?.readMarkerViewTrailingConstraint
} else {
return super.readMarkerViewTrailingConstraint
}
}
set {
if self is RoomCellReadMarkerDisplayable {
self.roomCellContentView?.readMarkerViewTrailingConstraint = newValue
} else {
super.readMarkerViewTrailingConstraint = newValue
}
}
}
// MARK: - Setup
required override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.commonInit()
}
private func commonInit() {
self.selectionStyle = .none
self.setupContentView()
self.update(theme: ThemeService.shared().theme)
}
// MARK: - Public
func removeDecorationViews() {
if let roomCellReadReceiptsDisplayable = self as? RoomCellReadReceiptsDisplayable {
roomCellReadReceiptsDisplayable.removeReadReceiptsView()
}
if let roomCellReactionsDisplayable = self as? RoomCellReactionsDisplayable {
roomCellReactionsDisplayable.removeReactionsView()
}
if let roomCellThreadSummaryDisplayable = self as? RoomCellThreadSummaryDisplayable {
roomCellThreadSummaryDisplayable.removeThreadSummaryView()
}
if let timestampDisplayable = self as? TimestampDisplayable {
timestampDisplayable.removeTimestampView()
}
if let urlPreviewDisplayable = self as? RoomCellURLPreviewDisplayable {
urlPreviewDisplayable.removeURLPreviewView()
}
}
// MARK: - Overrides
override var isTextViewNeedsPositioningVerticalSpace: Bool {
return false
}
override func setupViews() {
super.setupViews()
let showEncryptionStatus = roomCellContentView?.showEncryptionStatus ?? false
if showEncryptionStatus {
self.setupEncryptionStatusViewTapGestureRecognizer()
}
}
override func setupSenderNameLabel() {
guard let userNameTouchMaskView = self.roomCellContentView?.userNameTouchMaskView else {
return
}
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(onSenderNameTap(_:)))
tapGesture.numberOfTouchesRequired = 1
tapGesture.numberOfTapsRequired = 1
tapGesture.delegate = self
userNameTouchMaskView.addGestureRecognizer(tapGesture)
}
override func setupAvatarView() {
guard let avatarImageView = self.roomCellContentView?.avatarImageView else {
return
}
avatarImageView.mediaFolder = kMXMediaManagerAvatarThumbnailFolder
// Listen to avatar tap
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(onAvatarTap(_:)))
tapGesture.numberOfTouchesRequired = 1
tapGesture.numberOfTapsRequired = 1
tapGesture.delegate = self
avatarImageView.addGestureRecognizer(tapGesture)
avatarImageView.isUserInteractionEnabled = true
// Add a long gesture recognizer on avatar (in order to display for example the member details)
let longPress = UILongPressGestureRecognizer(target: self, action: #selector(onLongPressGesture(_:)))
avatarImageView.addGestureRecognizer(longPress)
}
override class func defaultReuseIdentifier() -> String! {
return String(describing: self)
}
override func prepareForReuse() {
super.prepareForReuse()
self.removeDecorationViews()
}
override func render(_ cellData: MXKCellData!) {
// In `MXKRoomBubbleTableViewCell` setupViews() is called in awakeFromNib() that is not called here, so call it only on first render() call
self.setupViewsIfNeeded()
super.render(cellData)
guard let roomCellContentView = self.roomCellContentView else {
return
}
if let bubbleData = self.bubbleData,
let paginationDate = bubbleData.date,
roomCellContentView.showPaginationTitle {
roomCellContentView.paginationLabel.text = bubbleData.eventFormatter.dateString(from: paginationDate, withTime: false)?.uppercased()
}
if roomCellContentView.showEncryptionStatus {
self.updateEncryptionStatusViewImage()
}
self.updateUserNameColor()
}
override func customizeRendering() {
super.customizeRendering()
self.updateUserNameColor()
}
// MARK: - Themable
func update(theme: Theme) {
self.theme = theme
self.roomCellContentView?.update(theme: theme)
}
// MARK: - Private
private func setupViewsIfNeeded() {
guard self.areViewsSetup == false else {
return
}
self.setupViews()
self.areViewsSetup = true
}
private func setupContentView() {
guard self.roomCellContentView == nil else {
return
}
let roomCellContentView = RoomCellContentView.instantiate()
self.contentView.vc_addSubViewMatchingParent(roomCellContentView)
self.roomCellContentView = roomCellContentView
}
// MARK: - RoomCellURLPreviewDisplayable
// Cannot use default implementation with ObjC protocol, if self conforms to RoomCellURLPreviewDisplayable method below will be used
func addURLPreviewView(_ urlPreviewView: UIView) {
self.roomCellContentView?.addURLPreviewView(urlPreviewView)
// tmpSubviews is used for touch detection in MXKRoomBubbleTableViewCell
self.addTemporarySubview(urlPreviewView)
}
func removeURLPreviewView() {
self.roomCellContentView?.removeURLPreviewView()
}
// MARK: - RoomCellReadReceiptsDisplayable
// Cannot use default implementation with ObjC protocol, if self conforms to RoomCellReadReceiptsDisplayable method below will be used
func addReadReceiptsView(_ readReceiptsView: UIView) {
self.roomCellContentView?.addReadReceiptsView(readReceiptsView)
// tmpSubviews is used for touch detection in MXKRoomBubbleTableViewCell
self.addTemporarySubview(readReceiptsView)
}
func removeReadReceiptsView() {
self.roomCellContentView?.removeReadReceiptsView()
}
// MARK: - RoomCellReactionsDisplayable
// Cannot use default implementation with ObjC protocol, if self conforms to RoomCellReactionsDisplayable method below will be used
func addReactionsView(_ reactionsView: UIView) {
self.roomCellContentView?.addReactionsView(reactionsView)
// tmpSubviews is used for touch detection in MXKRoomBubbleTableViewCell
self.addTemporarySubview(reactionsView)
}
func removeReactionsView() {
self.roomCellContentView?.removeReactionsView()
}
// MARK: - RoomCellThreadSummaryDisplayable
func addThreadSummaryView(_ threadSummaryView: ThreadSummaryView) {
self.roomCellContentView?.addThreadSummaryView(threadSummaryView)
// tmpSubviews is used for touch detection in MXKRoomBubbleTableViewCell
self.addTemporarySubview(threadSummaryView)
}
func removeThreadSummaryView() {
self.roomCellContentView?.removeThreadSummaryView()
}
// MARK: - RoomCellReadMarkerDisplayable
func addReadMarkerView(_ readMarkerView: UIView) {
self.roomCellContentView?.addReadMarkerView(readMarkerView)
self.readMarkerView = readMarkerView
}
override func removeReadMarkerView() {
self.roomCellContentView?.removeReadMarkerView()
super.removeReadMarkerView()
}
// Encryption status
private func updateEncryptionStatusViewImage() {
guard let component = self.bubbleData.getFirstBubbleComponentWithDisplay() else {
return
}
self.roomCellContentView?.encryptionImageView.image = RoomEncryptedDataBubbleCell.encryptionIcon(for: component)
}
private func setupEncryptionStatusViewTapGestureRecognizer() {
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleEncryptionStatusContainerViewTap(_:)))
tapGestureRecognizer.delegate = self
self.roomCellContentView?.encryptionImageView.isUserInteractionEnabled = true
}
@objc private func handleEncryptionStatusContainerViewTap(_ gestureRecognizer: UITapGestureRecognizer) {
guard let delegate = self.delegate else {
return
}
guard let component = self.bubbleData.getFirstBubbleComponentWithDisplay() else {
return
}
let userInfo: [AnyHashable: Any]?
if let tappedEvent = component.event {
userInfo = [kMXKRoomBubbleCellEventKey: tappedEvent]
} else {
userInfo = nil
}
delegate.cell(self, didRecognizeAction: kRoomEncryptedDataBubbleCellTapOnEncryptionIcon, userInfo: userInfo)
}
}
@@ -0,0 +1,368 @@
/*
Copyright 2019 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import UIKit
import Reusable
/// `RoomCellContentView` is a container view that display the default room message outer views and enables to manage them. Like pagination title, sender info, read receipts, reactions, encryption status.
@objcMembers
final class RoomCellContentView: UIView, NibLoadable {
// MARK: - Properties
// MARK: Outlets
@IBOutlet weak var paginationTitleContainerView: UIView!
@IBOutlet weak var paginationLabel: UILabel!
@IBOutlet weak var paginationSeparatorView: UIView!
@IBOutlet weak var userNameContainerView: UIView!
@IBOutlet weak var userNameLabel: UILabel!
@IBOutlet weak var userNameTouchMaskView: UIView!
@IBOutlet weak var userNameLabelTopConstraint: NSLayoutConstraint!
@IBOutlet weak var userNameLabelBottomConstraint: NSLayoutConstraint!
@IBOutlet weak var avatarContainerView: UIView!
@IBOutlet weak var avatarImageView: MXKImageView!
@IBOutlet weak var innerContentView: UIView!
@IBOutlet weak var innerContentViewTopConstraint: NSLayoutConstraint!
@IBOutlet weak var innerContentViewLeadingConstraint: NSLayoutConstraint!
@IBOutlet weak var innerContentViewTrailingConstraint: NSLayoutConstraint!
@IBOutlet weak var innerContentViewBottomContraint: NSLayoutConstraint!
@IBOutlet weak var encryptionStatusContainerView: UIView!
@IBOutlet weak var encryptionImageView: UIImageView!
@IBOutlet weak var bubbleInfoContainer: UIView!
@IBOutlet weak var bubbleInfoContainerTopConstraint: NSLayoutConstraint!
@IBOutlet weak var urlPreviewContainerView: UIView!
@IBOutlet weak var urlPreviewContentView: UIView!
@IBOutlet weak var urlPreviewContentViewLeadingConstraint: NSLayoutConstraint!
@IBOutlet weak var urlPreviewContentViewTrailingConstraint: NSLayoutConstraint!
@IBOutlet weak var readReceiptsContainerView: UIView!
@IBOutlet weak var readReceiptsContentView: UIView!
@IBOutlet weak var readMarkerContainerView: UIView!
@IBOutlet weak var readMarkerContentView: UIView!
var readMarkerViewLeadingConstraint: NSLayoutConstraint?
var readMarkerViewTrailingConstraint: NSLayoutConstraint?
@IBOutlet weak var reactionsContainerView: UIView!
@IBOutlet weak var reactionsContentView: UIView!
@IBOutlet weak var reactionsContentViewLeadingConstraint: NSLayoutConstraint!
@IBOutlet weak var reactionsContentViewTrailingConstraint: NSLayoutConstraint!
@IBOutlet weak var threadSummaryContainerView: UIView!
@IBOutlet weak var threadSummaryContentView: UIView!
@IBOutlet weak var threadSummaryContentViewLeadingConstraint: NSLayoutConstraint!
@IBOutlet weak var threadSummaryContentViewTrailingConstraint: NSLayoutConstraint!
@IBOutlet weak var threadSummaryContentViewBottomConstraint: NSLayoutConstraint!
@IBOutlet weak var bubbleOverlayContainer: UIView!
// MARK: Private
private var showURLPreview: Bool {
get {
return !self.urlPreviewContainerView.isHidden
}
set {
self.urlPreviewContainerView.isHidden = !newValue
}
}
private var showReadReceipts: Bool {
get {
return !self.readReceiptsContainerView.isHidden
}
set {
self.readReceiptsContainerView.isHidden = !newValue
}
}
private var showReactions: Bool {
get {
return !self.reactionsContainerView.isHidden
}
set {
self.reactionsContainerView.isHidden = !newValue
}
}
private var showThreadSummary: Bool {
get {
return !self.threadSummaryContainerView.isHidden
} set {
self.threadSummaryContainerView.isHidden = !newValue
}
}
// MARK: Public
var showPaginationTitle: Bool {
get {
return !self.paginationTitleContainerView.isHidden
}
set {
self.paginationTitleContainerView.isHidden = !newValue
}
}
var showSenderInfo: Bool {
get {
return self.showSenderAvatar && self.showSenderName
}
set {
self.showSenderAvatar = newValue
self.showSenderName = newValue
}
}
var showSenderAvatar: Bool {
get {
return !self.avatarContainerView.isHidden
}
set {
self.avatarContainerView.isHidden = !newValue
}
}
var showSenderName: Bool {
get {
return !self.userNameContainerView.isHidden
}
set {
self.userNameContainerView.isHidden = !newValue
}
}
var showEncryptionStatus: Bool {
get {
return !self.encryptionStatusContainerView.isHidden
}
set {
self.encryptionStatusContainerView.isHidden = !newValue
}
}
var showReadMarker: Bool {
get {
return !self.readMarkerContainerView.isHidden
}
set {
self.readMarkerContainerView.isHidden = !newValue
}
}
var decorationViewsAlignment: RoomCellDecorationAlignment = .left
// MARK: - Setup
class func instantiate() -> RoomCellContentView {
return RoomCellContentView.loadFromNib()
}
// MARK: - Public
func update(theme: Theme) {
self.backgroundColor = theme.backgroundColor
self.paginationLabel.textColor = theme.tintColor
self.paginationSeparatorView.backgroundColor = theme.tintColor
}
}
// MARK: - RoomCellReadReceiptsDisplayable
extension RoomCellContentView: RoomCellReadReceiptsDisplayable {
func addReadReceiptsView(_ readReceiptsView: UIView) {
self.readReceiptsContentView.vc_removeAllSubviews()
self.readReceiptsContentView.vc_addSubViewMatchingParent(readReceiptsView)
self.showReadReceipts = true
}
func removeReadReceiptsView() {
self.showReadReceipts = false
self.readReceiptsContentView.vc_removeAllSubviews()
}
}
// MARK: - RoomCellReactionsDisplayable
extension RoomCellContentView: RoomCellReactionsDisplayable {
func addReactionsView(_ reactionsView: UIView) {
self.reactionsContentView.vc_removeAllSubviews()
// Update reactions alignment according to current decoration alignment
if let bubbleReactionsView = reactionsView as? BubbleReactionsView {
let reactionsAlignment: BubbleReactionsViewAlignment
switch self.decorationViewsAlignment {
case .left:
reactionsAlignment = .left
case .right:
reactionsAlignment = .right
}
bubbleReactionsView.alignment = reactionsAlignment
}
self.reactionsContentView.vc_addSubViewMatchingParent(reactionsView)
self.showReactions = true
}
func removeReactionsView() {
self.showReactions = false
self.reactionsContentView.vc_removeAllSubviews()
}
}
// MARK: - RoomCellThreadSummaryDisplayable
extension RoomCellContentView: RoomCellThreadSummaryDisplayable {
func addThreadSummaryView(_ threadSummaryView: ThreadSummaryView) {
guard let containerView = self.threadSummaryContentView else {
return
}
containerView.vc_removeAllSubviews()
containerView.translatesAutoresizingMaskIntoConstraints = false
containerView.addSubview(threadSummaryView)
let leadingConstraint: NSLayoutConstraint
let trailingConstraint: NSLayoutConstraint
if self.decorationViewsAlignment == .right {
leadingConstraint = threadSummaryView.leadingAnchor.constraint(greaterThanOrEqualTo: containerView.leadingAnchor)
trailingConstraint = threadSummaryView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor)
} else {
leadingConstraint = threadSummaryView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor)
trailingConstraint = threadSummaryView.trailingAnchor.constraint(lessThanOrEqualTo: containerView.trailingAnchor)
}
NSLayoutConstraint.activate([
leadingConstraint,
threadSummaryView.topAnchor.constraint(equalTo: containerView.topAnchor),
threadSummaryView.heightAnchor.constraint(equalToConstant: PlainRoomCellLayoutConstants.threadSummaryViewHeight),
threadSummaryView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor),
trailingConstraint
])
self.showThreadSummary = true
}
func removeThreadSummaryView() {
self.showThreadSummary = false
self.threadSummaryContentView.vc_removeAllSubviews()
}
}
// MARK: - RoomCellURLPreviewDisplayable
extension RoomCellContentView: RoomCellURLPreviewDisplayable {
func addURLPreviewView(_ urlPreviewView: UIView) {
guard let containerView = self.urlPreviewContentView else {
return
}
containerView.vc_removeAllSubviews()
containerView.translatesAutoresizingMaskIntoConstraints = false
containerView.addSubview(urlPreviewView)
if let urlPreviewView = urlPreviewView as? URLPreviewView {
urlPreviewView.availableWidth = containerView.frame.width
}
let leadingConstraint: NSLayoutConstraint
let trailingConstraint: NSLayoutConstraint
if self.decorationViewsAlignment == .right {
leadingConstraint = urlPreviewView.leadingAnchor.constraint(greaterThanOrEqualTo: containerView.leadingAnchor)
trailingConstraint = urlPreviewView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor)
} else {
leadingConstraint = urlPreviewView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor)
trailingConstraint = urlPreviewView.trailingAnchor.constraint(lessThanOrEqualTo: containerView.trailingAnchor)
}
NSLayoutConstraint.activate([
leadingConstraint,
urlPreviewView.topAnchor.constraint(equalTo: containerView.topAnchor),
urlPreviewView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor),
trailingConstraint
])
self.showURLPreview = true
}
func removeURLPreviewView() {
self.showURLPreview = false
self.urlPreviewContentView.vc_removeAllSubviews()
}
}
// MARK: - RoomCellReadMarkerDisplayable
extension RoomCellContentView: RoomCellReadMarkerDisplayable {
func addReadMarkerView(_ readMarkerView: UIView) {
guard let containerView = self.readMarkerContainerView else {
return
}
self.readMarkerContentView.vc_removeAllSubviews()
readMarkerView.translatesAutoresizingMaskIntoConstraints = false
self.readMarkerContentView.addSubview(readMarkerView)
// Force read marker constraints
let topConstraint = readMarkerView.topAnchor.constraint(equalTo: containerView.topAnchor)
let leadingConstraint = readMarkerView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor)
let trailingConstraint = readMarkerView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor)
let heightConstraint = readMarkerView.heightAnchor.constraint(equalToConstant: PlainRoomCellLayoutConstants.readMarkerViewHeight)
let bottomContraint = readMarkerView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor)
NSLayoutConstraint.activate([topConstraint,
leadingConstraint,
trailingConstraint,
heightConstraint,
bottomContraint])
self.readMarkerViewLeadingConstraint = leadingConstraint
self.readMarkerViewTrailingConstraint = trailingConstraint
self.showReadMarker = true
}
func removeReadMarkerView() {
self.showReadMarker = false
self.readMarkerContentView.vc_removeAllSubviews()
}
}
@@ -9,7 +9,7 @@
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="zG5-YA-Ijy" customClass="BubbleCellContentView" customModule="Riot" customModuleProvider="target">
<view contentMode="scaleToFill" id="zG5-YA-Ijy" customClass="RoomCellContentView" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="595" height="97"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
@@ -17,7 +17,7 @@
<rect key="frame" x="0.0" y="0.0" width="595" height="97"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</view>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" translatesAutoresizingMaskIntoConstraints="NO" id="5GX-gn-bK1">
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="5GX-gn-bK1">
<rect key="frame" x="0.0" y="0.0" width="595" height="97"/>
<subviews>
<view hidden="YES" contentMode="scaleToFill" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="u1e-Q2-PhY">
@@ -58,24 +58,35 @@
<constraints>
<constraint firstItem="Ro1-vP-6Ha" firstAttribute="top" secondItem="u1e-Q2-PhY" secondAttribute="top" constant="10" id="5kZ-rt-pvq"/>
<constraint firstAttribute="trailing" secondItem="Ro1-vP-6Ha" secondAttribute="trailing" constant="10" id="8P7-ZL-7pg"/>
<constraint firstItem="Ro1-vP-6Ha" firstAttribute="leading" secondItem="u1e-Q2-PhY" secondAttribute="leading" constant="56" id="A4v-WV-EGn"/>
<constraint firstAttribute="bottom" secondItem="Ro1-vP-6Ha" secondAttribute="bottom" constant="10" id="UcW-P4-rQv"/>
</constraints>
</view>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="w0C-6a-f5M">
<rect key="frame" x="0.0" y="0.0" width="595" height="31"/>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="1cK-e6-Mg5">
<rect key="frame" x="0.0" y="0.0" width="595" height="0.0"/>
<subviews>
<view clipsSubviews="YES" contentMode="scaleAspectFill" translatesAutoresizingMaskIntoConstraints="NO" id="yXz-Za-4yR" customClass="MXKImageView">
<rect key="frame" x="13" y="10" width="30" height="30"/>
<color key="backgroundColor" red="0.66666666669999997" green="0.66666666669999997" blue="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<accessibility key="accessibilityConfiguration" identifier="PictureView"/>
<constraints>
<constraint firstAttribute="height" constant="30" id="FbD-UB-dqc"/>
<constraint firstAttribute="width" constant="30" id="y7F-jl-kEF"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="yXz-Za-4yR" firstAttribute="leading" secondItem="1cK-e6-Mg5" secondAttribute="leading" constant="13" id="UjU-eY-ARJ"/>
<constraint firstItem="yXz-Za-4yR" firstAttribute="top" secondItem="1cK-e6-Mg5" secondAttribute="top" constant="10" id="jlf-dg-fp0"/>
</constraints>
</view>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="w0C-6a-f5M">
<rect key="frame" x="0.0" y="0.0" width="595" height="31"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ohU-Sc-mgb">
<rect key="frame" x="46" y="4" width="534" height="30"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="User name:" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="8" translatesAutoresizingMaskIntoConstraints="NO" id="meG-P8-61b">
<rect key="frame" x="56" y="10" width="524" height="18"/>
@@ -93,9 +104,7 @@
<constraints>
<constraint firstAttribute="bottom" secondItem="meG-P8-61b" secondAttribute="bottom" constant="3" id="HDT-eS-UWo"/>
<constraint firstItem="ohU-Sc-mgb" firstAttribute="trailing" secondItem="meG-P8-61b" secondAttribute="trailing" id="Lbz-vD-hax"/>
<constraint firstItem="yXz-Za-4yR" firstAttribute="leading" secondItem="w0C-6a-f5M" secondAttribute="leading" constant="13" id="QlM-xG-bob"/>
<constraint firstItem="ohU-Sc-mgb" firstAttribute="bottom" secondItem="meG-P8-61b" secondAttribute="bottom" constant="6" id="U50-ZB-dRG"/>
<constraint firstItem="yXz-Za-4yR" firstAttribute="top" secondItem="w0C-6a-f5M" secondAttribute="top" constant="10" id="UMP-G3-iPN"/>
<constraint firstItem="meG-P8-61b" firstAttribute="top" secondItem="w0C-6a-f5M" secondAttribute="top" constant="10" id="baE-tR-0Ck"/>
<constraint firstItem="ohU-Sc-mgb" firstAttribute="leading" secondItem="meG-P8-61b" secondAttribute="leading" constant="-10" id="ktD-JC-hfG"/>
<constraint firstItem="ohU-Sc-mgb" firstAttribute="top" secondItem="meG-P8-61b" secondAttribute="top" constant="-6" id="s5V-Fj-iNL"/>
@@ -158,26 +167,25 @@
<constraint firstItem="oeI-eO-mFK" firstAttribute="leading" secondItem="vcq-cR-uBc" secondAttribute="leading" priority="750" id="vsh-pW-S46"/>
</constraints>
</view>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="4zo-V8-CNe">
<rect key="frame" x="0.0" y="0.0" width="595" height="12"/>
<view hidden="YES" clipsSubviews="YES" contentMode="scaleAspectFit" verticalHuggingPriority="254" translatesAutoresizingMaskIntoConstraints="NO" id="57V-Sl-EmD">
<rect key="frame" x="0.0" y="0.0" width="595" height="0.0"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="rQt-NH-Cb0">
<rect key="frame" x="439" y="0.0" width="150" height="12"/>
<view clipsSubviews="YES" contentMode="scaleAspectFit" translatesAutoresizingMaskIntoConstraints="NO" id="vpX-Nl-AEt">
<rect key="frame" x="56" y="0.0" width="524" height="0.0"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="width" constant="150" id="fsY-DK-hUg"/>
<constraint firstAttribute="height" priority="250" placeholder="YES" id="0Sv-R6-k3e"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="rQt-NH-Cb0" secondAttribute="bottom" id="6yV-vn-doj"/>
<constraint firstItem="rQt-NH-Cb0" firstAttribute="top" secondItem="4zo-V8-CNe" secondAttribute="top" id="DNc-jy-Urh"/>
<constraint firstAttribute="height" constant="12" id="TxZ-dJ-UI6"/>
<constraint firstAttribute="trailing" secondItem="rQt-NH-Cb0" secondAttribute="trailing" constant="6" id="lq2-AY-Lus"/>
<constraint firstAttribute="trailing" secondItem="vpX-Nl-AEt" secondAttribute="trailing" constant="15" id="ZmA-Ns-chh"/>
<constraint firstAttribute="bottom" secondItem="vpX-Nl-AEt" secondAttribute="bottom" id="blD-s1-b1N"/>
<constraint firstItem="vpX-Nl-AEt" firstAttribute="top" secondItem="57V-Sl-EmD" secondAttribute="top" id="sFV-XK-lE4"/>
</constraints>
</view>
<view hidden="YES" clipsSubviews="YES" contentMode="scaleAspectFit" translatesAutoresizingMaskIntoConstraints="NO" id="Dj1-m6-1Jw">
<view hidden="YES" clipsSubviews="YES" contentMode="scaleAspectFit" verticalHuggingPriority="252" translatesAutoresizingMaskIntoConstraints="NO" id="Dj1-m6-1Jw">
<rect key="frame" x="0.0" y="0.0" width="595" height="0.0"/>
<subviews>
<view clipsSubviews="YES" contentMode="scaleAspectFit" translatesAutoresizingMaskIntoConstraints="NO" id="SNw-aM-ILI">
@@ -195,18 +203,73 @@
<constraint firstAttribute="trailing" secondItem="SNw-aM-ILI" secondAttribute="trailing" constant="15" id="ynR-d4-6cf"/>
</constraints>
</view>
<view hidden="YES" contentMode="scaleToFill" verticalHuggingPriority="253" translatesAutoresizingMaskIntoConstraints="NO" id="4zo-V8-CNe">
<rect key="frame" x="0.0" y="0.0" width="595" height="16"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="rQt-NH-Cb0">
<rect key="frame" x="439" y="0.0" width="150" height="16"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="16" id="WZx-xk-gav"/>
<constraint firstAttribute="width" constant="150" id="fsY-DK-hUg"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="rQt-NH-Cb0" secondAttribute="bottom" id="6yV-vn-doj"/>
<constraint firstItem="rQt-NH-Cb0" firstAttribute="top" secondItem="4zo-V8-CNe" secondAttribute="top" id="DNc-jy-Urh"/>
<constraint firstAttribute="trailing" secondItem="rQt-NH-Cb0" secondAttribute="trailing" constant="6" id="lq2-AY-Lus"/>
</constraints>
</view>
<view hidden="YES" clipsSubviews="YES" contentMode="scaleToFill" verticalHuggingPriority="253" translatesAutoresizingMaskIntoConstraints="NO" id="2i0-Un-VXa">
<rect key="frame" x="0.0" y="0.0" width="595" height="0.0"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="3Cq-BI-po5">
<rect key="frame" x="0.0" y="0.0" width="595" height="0.0"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" priority="250" constant="2" id="3j7-Qe-vYL"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="3Cq-BI-po5" firstAttribute="top" secondItem="2i0-Un-VXa" secondAttribute="top" id="6YG-04-nSb"/>
<constraint firstItem="3Cq-BI-po5" firstAttribute="leading" secondItem="2i0-Un-VXa" secondAttribute="leading" id="CrN-xe-M6m"/>
<constraint firstAttribute="trailing" secondItem="3Cq-BI-po5" secondAttribute="trailing" id="SBL-F4-EJ8"/>
<constraint firstAttribute="bottom" secondItem="3Cq-BI-po5" secondAttribute="bottom" id="r3l-ZY-0kc"/>
</constraints>
</view>
<view hidden="YES" clipsSubviews="YES" contentMode="scaleAspectFit" translatesAutoresizingMaskIntoConstraints="NO" id="2eB-kB-m20">
<rect key="frame" x="0.0" y="0.0" width="595" height="0.0"/>
<subviews>
<view clipsSubviews="YES" contentMode="scaleAspectFit" translatesAutoresizingMaskIntoConstraints="NO" id="snf-Ea-To0">
<rect key="frame" x="56" y="0.0" width="524" height="0.0"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" priority="250" placeholder="YES" id="ymW-ys-P0T"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="snf-Ea-To0" secondAttribute="bottom" id="4tt-w0-4JE"/>
<constraint firstItem="snf-Ea-To0" firstAttribute="top" secondItem="2eB-kB-m20" secondAttribute="top" id="Im9-Z0-ieI"/>
<constraint firstAttribute="trailing" secondItem="snf-Ea-To0" secondAttribute="trailing" constant="15" id="Qwm-Of-Zgc"/>
</constraints>
</view>
</subviews>
<constraints>
<constraint firstItem="Dj1-m6-1Jw" firstAttribute="width" secondItem="5GX-gn-bK1" secondAttribute="width" id="0Px-jL-CMJ"/>
<constraint firstItem="1cK-e6-Mg5" firstAttribute="width" secondItem="5GX-gn-bK1" secondAttribute="width" id="2De-xT-k5e"/>
<constraint firstItem="meG-P8-61b" firstAttribute="trailing" secondItem="oeI-eO-mFK" secondAttribute="trailing" id="2Dy-o0-r33"/>
<constraint firstItem="snf-Ea-To0" firstAttribute="leading" secondItem="oeI-eO-mFK" secondAttribute="leading" id="2lm-T3-dEu"/>
<constraint firstItem="w0C-6a-f5M" firstAttribute="width" secondItem="5GX-gn-bK1" secondAttribute="width" id="5nl-Le-VDi"/>
<constraint firstItem="u1e-Q2-PhY" firstAttribute="width" secondItem="5GX-gn-bK1" secondAttribute="width" id="KrJ-dm-TaV"/>
<constraint firstItem="Ro1-vP-6Ha" firstAttribute="leading" secondItem="oeI-eO-mFK" secondAttribute="leading" id="S0v-mG-74W"/>
<constraint firstItem="57V-Sl-EmD" firstAttribute="width" secondItem="5GX-gn-bK1" secondAttribute="width" id="a2p-Bn-M5e"/>
<constraint firstItem="4zo-V8-CNe" firstAttribute="width" secondItem="5GX-gn-bK1" secondAttribute="width" id="bdq-sQ-NQy"/>
<constraint firstItem="vpX-Nl-AEt" firstAttribute="leading" secondItem="oeI-eO-mFK" secondAttribute="leading" id="lTt-Qx-fuQ"/>
<constraint firstItem="meG-P8-61b" firstAttribute="leading" secondItem="oeI-eO-mFK" secondAttribute="leading" id="lq1-xP-tea"/>
<constraint firstItem="SNw-aM-ILI" firstAttribute="leading" secondItem="oeI-eO-mFK" secondAttribute="leading" id="x1n-oT-dez"/>
</constraints>
@@ -227,6 +290,7 @@
<nil key="simulatedBottomBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<connections>
<outlet property="avatarContainerView" destination="1cK-e6-Mg5" id="8j5-Km-Jfj"/>
<outlet property="avatarImageView" destination="yXz-Za-4yR" id="f56-93-gxa"/>
<outlet property="bubbleInfoContainer" destination="7Y6-Py-paB" id="uLv-MM-HIL"/>
<outlet property="bubbleInfoContainerTopConstraint" destination="Wx9-0o-vzm" id="nLG-nC-lwV"/>
@@ -234,18 +298,34 @@
<outlet property="encryptionImageView" destination="Ujc-3c-e5B" id="7zc-Y7-1jT"/>
<outlet property="encryptionStatusContainerView" destination="uHE-o7-sCe" id="Dl7-QS-WKl"/>
<outlet property="innerContentView" destination="oeI-eO-mFK" id="ap1-He-C6g"/>
<outlet property="innerContentViewBottomContraint" destination="8M5-uW-82s" id="Vn0-6C-LSW"/>
<outlet property="innerContentViewLeadingConstraint" destination="0Fr-0L-9tU" id="ByY-oe-d8Y"/>
<outlet property="innerContentViewTopConstraint" destination="uZZ-I6-Xtq" id="HqY-G8-Od7"/>
<outlet property="innerContentViewTrailingConstraint" destination="Pbe-4d-q6Y" id="24b-AS-hX4"/>
<outlet property="paginationLabel" destination="r7y-FK-GWS" id="R9V-ix-mDu"/>
<outlet property="paginationSeparatorView" destination="ytv-tA-NmI" id="sgk-n1-KQi"/>
<outlet property="paginationTitleContainerView" destination="u1e-Q2-PhY" id="Osl-dF-fpA"/>
<outlet property="reactionsContainerView" destination="Dj1-m6-1Jw" id="p5e-n1-Wca"/>
<outlet property="reactionsContentView" destination="SNw-aM-ILI" id="wMe-f0-qhq"/>
<outlet property="reactionsContentViewLeadingConstraint" destination="x1n-oT-dez" id="LUh-3Q-SVr"/>
<outlet property="reactionsContentViewTrailingConstraint" destination="ynR-d4-6cf" id="Sy0-o9-vAC"/>
<outlet property="readMarkerContainerView" destination="2i0-Un-VXa" id="O4q-3S-R5o"/>
<outlet property="readMarkerContentView" destination="3Cq-BI-po5" id="Bwr-Sg-sOt"/>
<outlet property="readReceiptsContainerView" destination="4zo-V8-CNe" id="7ek-u4-CX8"/>
<outlet property="readReceiptsContentView" destination="rQt-NH-Cb0" id="tqw-je-kp9"/>
<outlet property="senderInfoContainerView" destination="w0C-6a-f5M" id="fZE-vY-0nR"/>
<outlet property="threadSummaryContainerView" destination="2eB-kB-m20" id="0Y4-4E-I9K"/>
<outlet property="threadSummaryContentView" destination="snf-Ea-To0" id="6Oo-Gj-e4Z"/>
<outlet property="threadSummaryContentViewBottomConstraint" destination="4tt-w0-4JE" id="6db-Jz-jys"/>
<outlet property="threadSummaryContentViewLeadingConstraint" destination="2lm-T3-dEu" id="jR6-sh-Nul"/>
<outlet property="threadSummaryContentViewTrailingConstraint" destination="Qwm-Of-Zgc" id="dfE-aR-MQQ"/>
<outlet property="urlPreviewContainerView" destination="57V-Sl-EmD" id="9c6-ai-BY8"/>
<outlet property="urlPreviewContentView" destination="vpX-Nl-AEt" id="P8S-Fg-VFQ"/>
<outlet property="urlPreviewContentViewLeadingConstraint" destination="lTt-Qx-fuQ" id="5Fc-zl-b1j"/>
<outlet property="urlPreviewContentViewTrailingConstraint" destination="ZmA-Ns-chh" id="EXg-Rr-cuJ"/>
<outlet property="userNameContainerView" destination="w0C-6a-f5M" id="fZE-vY-0nR"/>
<outlet property="userNameLabel" destination="meG-P8-61b" id="ETK-ag-WYR"/>
<outlet property="userNameLabelBottomConstraint" destination="HDT-eS-UWo" id="zTQ-5g-SAo"/>
<outlet property="userNameLabelTopConstraint" destination="baE-tR-0Ck" id="myA-Gm-17A"/>
<outlet property="userNameTouchMaskView" destination="ohU-Sc-mgb" id="FwW-aL-kc5"/>
</connections>
<point key="canvasLocation" x="-1092" y="-1332"/>
@@ -0,0 +1,23 @@
//
// 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
/// RoomCellContentView decoration view items alignment
enum RoomCellDecorationAlignment {
case left
case right
}
@@ -16,8 +16,8 @@
import Foundation
/// `BubbleCellReactionsDisplayable` is a protocol indicating that a cell support displaying reactions.
@objc protocol BubbleCellReactionsDisplayable {
/// `RoomCellReactionsDisplayable` is a protocol indicating that a cell support displaying reactions.
@objc protocol RoomCellReactionsDisplayable {
func addReactionsView(_ reactionsView: UIView)
func removeReactionsView()
}
@@ -0,0 +1,23 @@
//
// 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
/// `RoomCellReadMarkerDisplayable` is a protocol indicating that a cell support displaying read marker.
@objc protocol RoomCellReadMarkerDisplayable {
func addReadMarkerView(_ readMarkerView: UIView)
func removeReadMarkerView()
}
@@ -16,8 +16,8 @@
import Foundation
/// `BubbleCellReadReceiptsDisplayable` is a protocol indicating that a cell support displaying read receipts.
@objc protocol BubbleCellReadReceiptsDisplayable {
/// `RoomCellReadReceiptsDisplayable` is a protocol indicating that a cell support displaying read receipts.
@objc protocol RoomCellReadReceiptsDisplayable {
func addReadReceiptsView(_ readReceiptsView: UIView)
func removeReadReceiptsView()
}
@@ -16,8 +16,8 @@
import Foundation
/// `BubbleCellThreadSummaryDisplayable` is a protocol indicating that a cell support displaying a thread summary.
@objc protocol BubbleCellThreadSummaryDisplayable {
/// `RoomCellThreadSummaryDisplayable` is a protocol indicating that a cell support displaying a thread summary.
@objc protocol RoomCellThreadSummaryDisplayable {
func addThreadSummaryView(_ threadSummaryView: ThreadSummaryView)
func removeThreadSummaryView()
}
@@ -0,0 +1,23 @@
//
// 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
/// `RoomCellURLPreviewDisplayable` is a protocol indicating that a cell support displaying a URL preview.
@objc protocol RoomCellURLPreviewDisplayable {
func addURLPreviewView(_ urlPreviewView: UIView)
func removeURLPreviewView()
}
@@ -0,0 +1,23 @@
//
// 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
/// `TimestampDisplayable` is a protocol indicating that a view supports displaying a timestamp.
@objc protocol TimestampDisplayable {
func addTimestampView(_ timestampView: UIView)
func removeTimestampView()
}
@@ -112,9 +112,9 @@ extension CallBubbleCellBaseContentView: Themable {
}
// MARK: - BubbleCellReadReceiptsDisplayable
// MARK: - RoomCellReadReceiptsDisplayable
extension CallBubbleCellBaseContentView: BubbleCellReadReceiptsDisplayable {
extension CallBubbleCellBaseContentView: RoomCellReadReceiptsDisplayable {
func addReadReceiptsView(_ readReceiptsView: UIView) {
self.readReceiptsContentView.vc_removeAllSubviews()
@@ -144,7 +144,7 @@ class RoomBaseCallBubbleCell: MXKRoomBubbleTableViewCell {
}
extension RoomBaseCallBubbleCell: BubbleCellReadReceiptsDisplayable {
extension RoomBaseCallBubbleCell: RoomCellReadReceiptsDisplayable {
func addReadReceiptsView(_ readReceiptsView: UIView) {
innerContentView.addReadReceiptsView(readReceiptsView)
@@ -239,6 +239,16 @@ extern NSString *const kMXKRoomBubbleCellUrlItemInteraction;
*/
@property (nonatomic) WKWebView *attachmentWebView;
/**
Indicate true if the cell needs vertical space in the text to position UI components.
*/
@property (nonatomic, readonly) BOOL isTextViewNeedsPositioningVerticalSpace;
/**
Use bubbleData.attributedTextMessage or bubbleData.attributedTextMessageWithoutPositioningSpace according to isTextViewNeedsPositioningVerticalSpace value.
*/
@property (nonatomic, readonly) NSAttributedString *suitableAttributedTextMessage;
/**
Called during the designated initializer of the UITableViewCell class to set the default
properties values.
@@ -327,10 +337,34 @@ extern NSString *const kMXKRoomBubbleCellUrlItemInteraction;
*/
- (void)setupViews;
/// Setup sender name label if needed
- (void)setupSenderNameLabel;
/// Setup avatar view if needed
- (void)setupAvatarView;
/// Setup message text view if needed
- (void)setupMessageTextView;
/// Setup message text view long press gesture if needed
- (void)setupMessageTextViewLongPressGesture;
/// Add temporary subview to `tmpSubviews` property.
- (void)addTemporarySubview:(UIView*)subview;
/// Called when content view cell is tapped
- (IBAction)onContentViewTap:(UITapGestureRecognizer*)sender;
/// Called when sender name is tapped
- (IBAction)onSenderNameTap:(UITapGestureRecognizer*)sender;
/// Called when avatar view is tapped
- (IBAction)onAvatarTap:(UITapGestureRecognizer*)sender;
/// Called when a UI component is long pressed
- (IBAction)onLongPressGesture:(UILongPressGestureRecognizer*)longPressGestureRecognizer;
/// Remove marker view if present
- (void)removeReadMarkerView;
@end
@@ -30,6 +30,8 @@
#import "MXKMessageTextView.h"
#import "UITextView+MatrixKit.h"
#import "GeneratedInterface-Swift.h"
#pragma mark - Constant definitions
NSString *const kMXKRoomBubbleCellTapOnMessageTextView = @"kMXKRoomBubbleCellTapOnMessageTextView";
NSString *const kMXKRoomBubbleCellTapOnSenderNameLabel = @"kMXKRoomBubbleCellTapOnSenderNameLabel";
@@ -122,6 +124,7 @@ static BOOL _disableLongPressGestureOnEvent;
_allTextHighlighted = NO;
_isAutoAnimatedGif = NO;
_tmpSubviews = [NSMutableArray array];
_isTextViewNeedsPositioningVerticalSpace = YES;
}
- (void)awakeFromNib
@@ -133,86 +136,11 @@ static BOOL _disableLongPressGestureOnEvent;
- (void)setupViews
{
if (self.userNameLabel)
{
// Listen to name tap
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onSenderNameTap:)];
[tapGesture setNumberOfTouchesRequired:1];
[tapGesture setNumberOfTapsRequired:1];
[tapGesture setDelegate:self];
if (self.userNameTapGestureMaskView)
{
[self.userNameTapGestureMaskView addGestureRecognizer:tapGesture];
}
else
{
[self.userNameLabel addGestureRecognizer:tapGesture];
self.userNameLabel.userInteractionEnabled = YES;
}
}
[self setupSenderNameLabel];
if (self.pictureView)
{
self.pictureView.mediaFolder = kMXMediaManagerAvatarThumbnailFolder;
// Listen to avatar tap
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onAvatarTap:)];
[tapGesture setNumberOfTouchesRequired:1];
[tapGesture setNumberOfTapsRequired:1];
[tapGesture setDelegate:self];
[self.pictureView addGestureRecognizer:tapGesture];
self.pictureView.userInteractionEnabled = YES;
// Add a long gesture recognizer on avatar (in order to display for example the member details)
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(onLongPressGesture:)];
[self.pictureView addGestureRecognizer:longPress];
}
[self setupAvatarView];
if (self.messageTextView)
{
// Listen to textView tap
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onMessageTap:)];
[tapGesture setNumberOfTouchesRequired:1];
[tapGesture setNumberOfTapsRequired:1];
[tapGesture setDelegate:self];
[self.messageTextView addGestureRecognizer:tapGesture];
self.messageTextView.userInteractionEnabled = YES;
// Recognise and make tappable phone numbers, address, etc.
self.messageTextView.dataDetectorTypes = UIDataDetectorTypeAll;
// Listen to link click
self.messageTextView.delegate = self;
if (_disableLongPressGestureOnEvent == NO)
{
// Add a long gesture recognizer on text view (in order to display for example the event details)
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(onLongPressGesture:)];
longPress.delegate = self;
// MXKMessageTextView does not catch touches outside of links. Add a background view to handle long touch.
if ([self.messageTextView isKindOfClass:[MXKMessageTextView class]])
{
UIView *messageTextBackgroundView = [[UIView alloc] initWithFrame:self.messageTextView.frame];
messageTextBackgroundView.backgroundColor = [UIColor clearColor];
[self.contentView insertSubview:messageTextBackgroundView belowSubview:self.messageTextView];
messageTextBackgroundView.translatesAutoresizingMaskIntoConstraints = NO;
[messageTextBackgroundView.leftAnchor constraintEqualToAnchor:self.messageTextView.leftAnchor].active = YES;
[messageTextBackgroundView.rightAnchor constraintEqualToAnchor:self.messageTextView.rightAnchor].active = YES;
[messageTextBackgroundView.topAnchor constraintEqualToAnchor:self.messageTextView.topAnchor].active = YES;
[messageTextBackgroundView.bottomAnchor constraintEqualToAnchor:self.messageTextView.bottomAnchor].active = YES;
[messageTextBackgroundView addGestureRecognizer:longPress];
self.messageTextBackgroundView = messageTextBackgroundView;
}
else
{
[self.messageTextView addGestureRecognizer:longPress];
}
}
}
[self setupMessageTextView];
if (self.playIconView)
{
@@ -247,6 +175,109 @@ static BOOL _disableLongPressGestureOnEvent;
[self setupConstraintsConstantDefaultValues];
}
- (void)setupSenderNameLabel
{
if (!self.userNameLabel)
{
return;
}
// Listen to name tap
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onSenderNameTap:)];
[tapGesture setNumberOfTouchesRequired:1];
[tapGesture setNumberOfTapsRequired:1];
[tapGesture setDelegate:self];
if (self.userNameTapGestureMaskView)
{
[self.userNameTapGestureMaskView addGestureRecognizer:tapGesture];
}
else
{
[self.userNameLabel addGestureRecognizer:tapGesture];
self.userNameLabel.userInteractionEnabled = YES;
}
}
- (void)setupAvatarView
{
if (!self.pictureView)
{
return;
}
self.pictureView.mediaFolder = kMXMediaManagerAvatarThumbnailFolder;
// Listen to avatar tap
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onAvatarTap:)];
[tapGesture setNumberOfTouchesRequired:1];
[tapGesture setNumberOfTapsRequired:1];
[tapGesture setDelegate:self];
[self.pictureView addGestureRecognizer:tapGesture];
self.pictureView.userInteractionEnabled = YES;
// Add a long gesture recognizer on avatar (in order to display for example the member details)
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(onLongPressGesture:)];
[self.pictureView addGestureRecognizer:longPress];
}
- (void)setupMessageTextView
{
if (!self.messageTextView)
{
return;
}
// Listen to textView tap
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onMessageTap:)];
[tapGesture setNumberOfTouchesRequired:1];
[tapGesture setNumberOfTapsRequired:1];
[tapGesture setDelegate:self];
[self.messageTextView addGestureRecognizer:tapGesture];
self.messageTextView.userInteractionEnabled = YES;
// Recognise and make tappable phone numbers, address, etc.
self.messageTextView.dataDetectorTypes = UIDataDetectorTypeAll;
// Listen to link click
self.messageTextView.delegate = self;
[self setupMessageTextViewLongPressGesture];
}
- (void)setupMessageTextViewLongPressGesture
{
if (_disableLongPressGestureOnEvent)
{
return;
}
// Add a long gesture recognizer on text view (in order to display for example the event details)
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(onLongPressGesture:)];
longPress.delegate = self;
// MXKMessageTextView does not catch touches outside of links. Add a background view to handle long touch.
if ([self.messageTextView isKindOfClass:[MXKMessageTextView class]])
{
UIView *messageTextBackgroundView = [[UIView alloc] initWithFrame:self.messageTextView.frame];
messageTextBackgroundView.backgroundColor = [UIColor clearColor];
[self.contentView insertSubview:messageTextBackgroundView belowSubview:self.messageTextView];
messageTextBackgroundView.translatesAutoresizingMaskIntoConstraints = NO;
[messageTextBackgroundView.leftAnchor constraintEqualToAnchor:self.messageTextView.leftAnchor].active = YES;
[messageTextBackgroundView.rightAnchor constraintEqualToAnchor:self.messageTextView.rightAnchor].active = YES;
[messageTextBackgroundView.topAnchor constraintEqualToAnchor:self.messageTextView.topAnchor].active = YES;
[messageTextBackgroundView.bottomAnchor constraintEqualToAnchor:self.messageTextView.bottomAnchor].active = YES;
[messageTextBackgroundView addGestureRecognizer:longPress];
self.messageTextBackgroundView = messageTextBackgroundView;
}
else
{
[self.messageTextView addGestureRecognizer:longPress];
}
}
- (void)customizeTableViewCellRendering
{
[super customizeTableViewCellRendering];
@@ -366,18 +397,23 @@ static BOOL _disableLongPressGestureOnEvent;
{
if (_allTextHighlighted)
{
NSMutableAttributedString *highlightedString = [[NSMutableAttributedString alloc] initWithAttributedString:bubbleData.attributedTextMessage];
NSMutableAttributedString *highlightedString = [[NSMutableAttributedString alloc] initWithAttributedString:self.suitableAttributedTextMessage];
UIColor *color = self.tintColor ? self.tintColor : [UIColor lightGrayColor];
[highlightedString addAttribute:NSBackgroundColorAttributeName value:color range:NSMakeRange(0, highlightedString.length)];
self.messageTextView.attributedText = highlightedString;
}
else
{
self.messageTextView.attributedText = bubbleData.attributedTextMessage;
self.messageTextView.attributedText = self.suitableAttributedTextMessage;
}
}
}
- (NSAttributedString *)suitableAttributedTextMessage
{
return self.isTextViewNeedsPositioningVerticalSpace ? bubbleData.attributedTextMessage : bubbleData.attributedTextMessageWithoutPositioningSpace;
}
- (void)highlightTextMessageForEvent:(NSString*)eventId
{
if (self.messageTextView)
@@ -389,7 +425,7 @@ static BOOL _disableLongPressGestureOnEvent;
else
{
// Restore original string
self.messageTextView.attributedText = bubbleData.attributedTextMessage;
self.messageTextView.attributedText = self.suitableAttributedTextMessage;
}
}
}
@@ -559,14 +595,14 @@ static BOOL _disableLongPressGestureOnEvent;
// Underline attached file name
if (self.isBubbleDataContainsFileAttachment)
{
NSMutableAttributedString *updatedText = [[NSMutableAttributedString alloc] initWithAttributedString:bubbleData.attributedTextMessage];
NSMutableAttributedString *updatedText = [[NSMutableAttributedString alloc] initWithAttributedString:self.suitableAttributedTextMessage];
[updatedText addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInteger:NSUnderlineStyleSingle] range:NSMakeRange(0, updatedText.length)];
newText = updatedText;
}
else
{
newText = bubbleData.attributedTextMessage;
newText = self.suitableAttributedTextMessage;
}
// update the text only if it is required
@@ -927,8 +963,24 @@ static BOOL _disableLongPressGestureOnEvent;
}
else if (cell.messageTextView)
{
CGFloat maxTextViewWidth;
RoomTimelineConfiguration *timelineConfiguration = [RoomTimelineConfiguration shared];
id<RoomCellLayoutUpdating> cellLayoutUpdater = timelineConfiguration.currentStyle.cellLayoutUpdater;
// Handle updated text view layout if needed
if (cellLayoutUpdater)
{
maxTextViewWidth = [cellLayoutUpdater maximumTextViewWidthFor:cell cellData:cellData maximumCellWidth:maxWidth];
}
else
{
maxTextViewWidth = maxWidth - (cell.msgTextViewLeadingConstraint.constant + cell.msgTextViewTrailingConstraint.constant);
}
// Update maximum width available for the textview
bubbleData.maxTextViewWidth = maxWidth - (cell.msgTextViewLeadingConstraint.constant + cell.msgTextViewTrailingConstraint.constant);
bubbleData.maxTextViewWidth = maxTextViewWidth;
// Retrieve the suggested height of the message content
rowHeight = bubbleData.contentSize.height;
@@ -950,101 +1002,33 @@ static BOOL _disableLongPressGestureOnEvent;
{
[super prepareForReuse];
bubbleData = nil;
delegate = nil;
[[NSNotificationCenter defaultCenter] removeObserver:self];
self.readReceiptsAlignment = ReadReceiptAlignmentLeft;
_allTextHighlighted = NO;
_isAutoAnimatedGif = NO;
[self removeHTMLBlockquoteSideBorderViews];
[self removeTemporarySubviews];
[self cleanAttachmentView];
[self clearBubbleInfoContainer];
[self clearBubbleOverlayContainer];
[self resetConstraintsConstantToDefault];
[self clearAttachmentWebView];
[self didEndDisplay];
}
- (void)didEndDisplay
{
bubbleData = nil;
for (UIView *sideBorder in htmlBlockquoteSideBorderViews)
{
[sideBorder removeFromSuperview];
}
[htmlBlockquoteSideBorderViews removeAllObjects];
htmlBlockquoteSideBorderViews = nil;
if (_attachmentWebView)
{
[_attachmentWebView removeFromSuperview];
_attachmentWebView.navigationDelegate = nil;
_attachmentWebView = nil;
}
[self removeReadMarkerView];
[self cleanProgressView];
if (_readMarkerView)
{
[_readMarkerView removeFromSuperview];
_readMarkerView = nil;
_readMarkerViewTopConstraint = nil;
_readMarkerViewLeadingConstraint = nil;
_readMarkerViewTrailingConstraint = nil;
_readMarkerViewHeightConstraint = nil;
}
if (self.attachmentView)
{
// Remove all gesture recognizer
while (self.attachmentView.gestureRecognizers.count)
{
[self.attachmentView removeGestureRecognizer:self.attachmentView.gestureRecognizers[0]];
}
// Prevent the cell from displaying again the image in case of reuse.
self.attachmentView.image = nil;
}
// Remove potential dateTime (or unsent) label(s)
if (self.bubbleInfoContainer && self.bubbleInfoContainer.subviews.count > 0)
{
NSArray* subviews = self.bubbleInfoContainer.subviews;
for (UIView *view in subviews)
{
[view removeFromSuperview];
}
}
self.bubbleInfoContainer.hidden = YES;
// Remove temporary subviews
for (UIView *view in self.tmpSubviews)
{
[view removeFromSuperview];
}
[self.tmpSubviews removeAllObjects];
// Remove potential overlay subviews
if (self.bubbleOverlayContainer)
{
NSArray* subviews = self.bubbleOverlayContainer.subviews;
for (UIView *view in subviews)
{
[view removeFromSuperview];
}
self.bubbleOverlayContainer.hidden = YES;
}
if (self.progressView)
{
[self stopProgressUI];
// Remove long tap gesture on the progressView
while (self.progressView.gestureRecognizers.count)
{
[self.progressView removeGestureRecognizer:self.progressView.gestureRecognizers[0]];
}
}
[[NSNotificationCenter defaultCenter] removeObserver:self];
delegate = nil;
self.readReceiptsAlignment = ReadReceiptAlignmentLeft;
_allTextHighlighted = NO;
_isAutoAnimatedGif = NO;
[self resetConstraintsConstantToDefault];
// TODO: Stop gif animation
}
- (BOOL)shouldInteractWithURL:(NSURL *)URL urlItemInteraction:(UITextItemInteraction)urlItemInteraction associatedEvent:(MXEvent*)associatedEvent
@@ -1135,6 +1119,111 @@ static BOOL _disableLongPressGestureOnEvent;
[self.tmpSubviews addObject:subview];
}
#pragma mark - Cleaning
- (void)removeHTMLBlockquoteSideBorderViews
{
for (UIView *sideBorder in htmlBlockquoteSideBorderViews)
{
[sideBorder removeFromSuperview];
}
[htmlBlockquoteSideBorderViews removeAllObjects];
htmlBlockquoteSideBorderViews = nil;
}
- (void)removeReadMarkerView
{
if (_readMarkerView)
{
[_readMarkerView removeFromSuperview];
_readMarkerView = nil;
_readMarkerViewTopConstraint = nil;
_readMarkerViewLeadingConstraint = nil;
_readMarkerViewTrailingConstraint = nil;
_readMarkerViewHeightConstraint = nil;
}
}
- (void)removeTemporarySubviews
{
// Remove temporary subviews
for (UIView *view in self.tmpSubviews)
{
[view removeFromSuperview];
}
[self.tmpSubviews removeAllObjects];
}
- (void)cleanAttachmentView
{
if (self.attachmentView)
{
// Remove all gesture recognizer
while (self.attachmentView.gestureRecognizers.count)
{
[self.attachmentView removeGestureRecognizer:self.attachmentView.gestureRecognizers[0]];
}
// Prevent the cell from displaying again the image in case of reuse.
self.attachmentView.image = nil;
}
}
- (void)clearBubbleInfoContainer
{
// Remove potential dateTime (or unsent) label(s)
if (self.bubbleInfoContainer && self.bubbleInfoContainer.subviews.count > 0)
{
NSArray* subviews = self.bubbleInfoContainer.subviews;
for (UIView *view in subviews)
{
[view removeFromSuperview];
}
}
self.bubbleInfoContainer.hidden = YES;
}
- (void)clearBubbleOverlayContainer
{
// Remove potential overlay subviews
if (self.bubbleOverlayContainer)
{
NSArray* subviews = self.bubbleOverlayContainer.subviews;
for (UIView *view in subviews)
{
[view removeFromSuperview];
}
self.bubbleOverlayContainer.hidden = YES;
}
}
- (void)cleanProgressView
{
if (self.progressView)
{
[self stopProgressUI];
// Remove long tap gesture on the progressView
while (self.progressView.gestureRecognizers.count)
{
[self.progressView removeGestureRecognizer:self.progressView.gestureRecognizers[0]];
}
}
}
- (void)clearAttachmentWebView
{
if (_attachmentWebView)
{
[_attachmentWebView removeFromSuperview];
_attachmentWebView.navigationDelegate = nil;
_attachmentWebView = nil;
}
}
#pragma mark - Attachment progress handling
- (void)updateProgressUI:(NSDictionary*)statisticsDict
@@ -1488,6 +1577,8 @@ static NSMutableDictionary *childClasses;
return shouldInteractWithURL;
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-implementations"
// Delegate method only called on iOS 9. iOS 10+ use method above.
- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange
{
@@ -1510,6 +1601,7 @@ static NSMutableDictionary *childClasses;
return shouldInteractWithURL;
}
#pragma clang diagnostic pop
#pragma mark - WKNavigationDelegate
@@ -16,6 +16,7 @@
*/
#import "RoomEncryptedDataBubbleCell.h"
#import "GeneratedInterface-Swift.h"
NSString *const kRoomEncryptedDataBubbleCellTapOnEncryptionIcon = @"kRoomEncryptedDataBubbleCellTapOnEncryptionIcon";
@@ -28,7 +29,7 @@ NSString *const kRoomEncryptedDataBubbleCellTapOnEncryptionIcon = @"kRoomEncrypt
return nil;
}
return [UIImage imageNamed:@"encryption_warning"];
return AssetImages.encryptionWarning.image;
}
+ (void)addEncryptionStatusFromBubbleData:(MXKRoomBubbleCellData *)bubbleData inContainerView:(UIView *)containerView
@@ -31,11 +31,11 @@ class KeyVerificationBaseBubbleCell: MXKRoomBubbleTableViewCell {
weak var keyVerificationCellInnerContentView: KeyVerificationCellInnerContentView?
weak var bubbleCellContentView: BubbleCellContentView?
weak var roomCellContentView: RoomCellContentView?
override var bubbleInfoContainer: UIView! {
get {
guard let infoContainer = self.bubbleCellContentView?.bubbleInfoContainer else {
guard let infoContainer = self.roomCellContentView?.bubbleInfoContainer else {
fatalError("[KeyVerificationBaseBubbleCell] bubbleInfoContainer should not be used before set")
}
return infoContainer
@@ -47,7 +47,7 @@ class KeyVerificationBaseBubbleCell: MXKRoomBubbleTableViewCell {
override var bubbleOverlayContainer: UIView! {
get {
guard let overlayContainer = self.bubbleCellContentView?.bubbleOverlayContainer else {
guard let overlayContainer = self.roomCellContentView?.bubbleOverlayContainer else {
fatalError("[KeyVerificationBaseBubbleCell] bubbleOverlayContainer should not be used before set")
}
return overlayContainer
@@ -59,7 +59,7 @@ class KeyVerificationBaseBubbleCell: MXKRoomBubbleTableViewCell {
override var bubbleInfoContainerTopConstraint: NSLayoutConstraint! {
get {
guard let infoContainerTopConstraint = self.bubbleCellContentView?.bubbleInfoContainerTopConstraint else {
guard let infoContainerTopConstraint = self.roomCellContentView?.bubbleInfoContainerTopConstraint else {
fatalError("[KeyVerificationBaseBubbleCell] bubbleInfoContainerTopConstraint should not be used before set")
}
return infoContainerTopConstraint
@@ -92,7 +92,7 @@ class KeyVerificationBaseBubbleCell: MXKRoomBubbleTableViewCell {
// MARK: - Public
func update(theme: Theme) {
self.bubbleCellContentView?.update(theme: theme)
self.roomCellContentView?.update(theme: theme)
self.keyVerificationCellInnerContentView?.update(theme: theme)
}
@@ -190,27 +190,27 @@ class KeyVerificationBaseBubbleCell: MXKRoomBubbleTableViewCell {
super.render(cellData)
if let bubbleData = self.bubbleData,
let bubbleCellContentView = self.bubbleCellContentView,
let roomCellContentView = self.roomCellContentView,
let paginationDate = bubbleData.date,
bubbleCellContentView.showPaginationTitle {
bubbleCellContentView.paginationLabel.text = bubbleData.eventFormatter.dateString(from: paginationDate, withTime: false)?.uppercased()
roomCellContentView.showPaginationTitle {
roomCellContentView.paginationLabel.text = bubbleData.eventFormatter.dateString(from: paginationDate, withTime: false)?.uppercased()
}
}
// MARK: - Private
private func setupContentView() {
if self.bubbleCellContentView == nil {
if self.roomCellContentView == nil {
let bubbleCellContentView = BubbleCellContentView.instantiate()
let roomCellContentView = RoomCellContentView.instantiate()
let innerContentView = KeyVerificationCellInnerContentView.instantiate()
bubbleCellContentView.innerContentView.vc_addSubViewMatchingParent(innerContentView)
roomCellContentView.innerContentView.vc_addSubViewMatchingParent(innerContentView)
self.contentView.vc_addSubViewMatchingParent(bubbleCellContentView)
self.contentView.vc_addSubViewMatchingParent(roomCellContentView)
self.bubbleCellContentView = bubbleCellContentView
self.roomCellContentView = roomCellContentView
self.keyVerificationCellInnerContentView = innerContentView
}
}
@@ -241,21 +241,21 @@ class KeyVerificationBaseBubbleCell: MXKRoomBubbleTableViewCell {
var height = sizingView.systemLayoutSizeFitting(fittingSize).height
if let roomBubbleCellData = cellData as? RoomBubbleCellData, let readReceipts = roomBubbleCellData.readReceipts, readReceipts.count > 0 {
height+=RoomBubbleCellLayout.readReceiptsViewHeight
height+=PlainRoomCellLayoutConstants.readReceiptsViewHeight
}
return height
}
}
// MARK: - BubbleCellReadReceiptsDisplayable
extension KeyVerificationBaseBubbleCell: BubbleCellReadReceiptsDisplayable {
// MARK: - RoomCellReadReceiptsDisplayable
extension KeyVerificationBaseBubbleCell: RoomCellReadReceiptsDisplayable {
func addReadReceiptsView(_ readReceiptsView: UIView) {
self.bubbleCellContentView?.addReadReceiptsView(readReceiptsView)
self.roomCellContentView?.addReadReceiptsView(readReceiptsView)
}
func removeReadReceiptsView() {
self.bubbleCellContentView?.removeReadReceiptsView()
self.roomCellContentView?.removeReadReceiptsView()
}
}
@@ -37,11 +37,11 @@ final class KeyVerificationConclusionWithPaginationTitleBubbleCell: KeyVerificat
}
private func commonInit() {
guard let bubbleCellContentView = self.bubbleCellContentView else {
guard let roomCellContentView = self.roomCellContentView else {
fatalError("[KeyVerificationConclusionWithPaginationTitleBubbleCell] bubbleCellContentView should not be nil")
}
bubbleCellContentView.showPaginationTitle = true
roomCellContentView.showPaginationTitle = true
}
// MARK: - Overrides
@@ -37,11 +37,11 @@ final class KeyVerificationIncomingRequestApprovalWithPaginationTitleBubbleCell:
}
private func commonInit() {
guard let bubbleCellContentView = self.bubbleCellContentView else {
guard let roomCellContentView = self.roomCellContentView else {
fatalError("[KeyVerificationRequestStatusWithPaginationTitleBubbleCell] bubbleCellContentView should not be nil")
}
bubbleCellContentView.showPaginationTitle = true
roomCellContentView.showPaginationTitle = true
}
// MARK: - Overrides
@@ -37,11 +37,11 @@ final class KeyVerificationRequestStatusWithPaginationTitleBubbleCell: KeyVerifi
}
private func commonInit() {
guard let bubbleCellContentView = self.bubbleCellContentView else {
guard let roomCellContentView = self.roomCellContentView else {
fatalError("[KeyVerificationRequestStatusWithPaginationTitleBubbleCell] bubbleCellContentView should not be nil")
}
bubbleCellContentView.showPaginationTitle = true
roomCellContentView.showPaginationTitle = true
}
// MARK: - Overrides
@@ -32,7 +32,7 @@ class RoomCreationIntroCell: MXKRoomBubbleTableViewCell {
// MARK: - Properties
private weak var bubbleCellContentView: RoomCreationIntroCellContentView?
private weak var roomCellContentView: RoomCreationIntroCellContentView?
// MARK: - Setup
@@ -57,7 +57,7 @@ class RoomCreationIntroCell: MXKRoomBubbleTableViewCell {
// MARK: - Public
func update(theme: Theme) {
self.bubbleCellContentView?.update(theme: theme)
self.roomCellContentView?.update(theme: theme)
}
// MARK: - Overrides
@@ -92,7 +92,7 @@ class RoomCreationIntroCell: MXKRoomBubbleTableViewCell {
override func render(_ cellData: MXKCellData!) {
super.render(cellData)
guard let bubbleCellContentView = self.bubbleCellContentView else {
guard let roomCellContentView = self.roomCellContentView else {
MXLog.debug("[RoomCreationIntroCell] Fail to load content view")
return
}
@@ -103,7 +103,7 @@ class RoomCreationIntroCell: MXKRoomBubbleTableViewCell {
return
}
bubbleCellContentView.fill(with: viewData)
roomCellContentView.fill(with: viewData)
}
// MARK: - Private
@@ -140,23 +140,23 @@ class RoomCreationIntroCell: MXKRoomBubbleTableViewCell {
}
private func setupContentView() {
guard self.bubbleCellContentView == nil else {
guard self.roomCellContentView == nil else {
return
}
let bubbleCellContentView = RoomCreationIntroCellContentView.instantiate()
self.contentView.vc_addSubViewMatchingParent(bubbleCellContentView)
self.bubbleCellContentView = bubbleCellContentView
let roomCellContentView = RoomCreationIntroCellContentView.instantiate()
self.contentView.vc_addSubViewMatchingParent(roomCellContentView)
self.roomCellContentView = roomCellContentView
bubbleCellContentView.roomAvatarView?.action = { [weak self] in
roomCellContentView.roomAvatarView?.action = { [weak self] in
self?.notifyDelegate(with: RoomCreationIntroCell.tapOnAvatarView)
}
bubbleCellContentView.didTapTopic = { [weak self] in
roomCellContentView.didTapTopic = { [weak self] in
self?.notifyDelegate(with: RoomCreationIntroCell.tapOnAddTopic)
}
bubbleCellContentView.didTapAddParticipants = { [weak self] in
roomCellContentView.didTapAddParticipants = { [weak self] in
self?.notifyDelegate(with: RoomCreationIntroCell.tapOnAddParticipants)
}
}
@@ -70,18 +70,18 @@
// Handle user's picture by considering it is stored unencrypted on Matrix media repository
// Use the Riot style placeholder
if (!nextBubbleData.senderAvatarPlaceholder)
if (!nextBubbleData.targetAvatarPlaceholder)
{
nextBubbleData.senderAvatarPlaceholder = [AvatarGenerator generateAvatarForMatrixItem:nextBubbleData.senderId withDisplayName:nextBubbleData.senderDisplayName];
nextBubbleData.targetAvatarPlaceholder = [AvatarGenerator generateAvatarForMatrixItem:nextBubbleData.targetId withDisplayName:nextBubbleData.targetDisplayName];
}
avatarView.enableInMemoryCache = YES;
[avatarView setImageURI:nextBubbleData.senderAvatarUrl
[avatarView setImageURI:nextBubbleData.targetAvatarUrl
withType:nil
andImageOrientation:UIImageOrientationUp
toFitViewSize:avatarView.frame.size
withMethod:MXThumbnailingMethodCrop
previewImage:nextBubbleData.senderAvatarPlaceholder
previewImage:nextBubbleData.targetAvatarPlaceholder
mediaManager:nextBubbleData.mxSession.mediaManager];
// Clear the default background color of a MXKImageView instance

Some files were not shown because too many files have changed in this diff Show More