mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-24 18:42:47 +02:00
Merge branch 'gil/SP1_space_creation' into gil/5231_SP3-1_Update_room_settings_for_Spaces
# Conflicts: # Podfile.lock
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
+100
-20
@@ -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
|
||||
}
|
||||
+2
-2
@@ -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()
|
||||
}
|
||||
+2
-2
@@ -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()
|
||||
}
|
||||
+2
-2
@@ -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()
|
||||
}
|
||||
+2
-2
@@ -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()
|
||||
+1
-1
@@ -144,7 +144,7 @@ class RoomBaseCallBubbleCell: MXKRoomBubbleTableViewCell {
|
||||
|
||||
}
|
||||
|
||||
extension RoomBaseCallBubbleCell: BubbleCellReadReceiptsDisplayable {
|
||||
extension RoomBaseCallBubbleCell: RoomCellReadReceiptsDisplayable {
|
||||
|
||||
func addReadReceiptsView(_ readReceiptsView: UIView) {
|
||||
innerContentView.addReadReceiptsView(readReceiptsView)
|
||||
+34
@@ -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
|
||||
+265
-173
@@ -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
|
||||
|
||||
+2
-1
@@ -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
|
||||
+18
-18
@@ -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()
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -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
|
||||
+2
-2
@@ -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
|
||||
+2
-2
@@ -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
|
||||
+11
-11
@@ -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)
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -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
Reference in New Issue
Block a user