Merge pull request #1341 from aramsargsyan/read-receipts-details

Read receipts details
This commit is contained in:
giomfo
2017-06-30 10:33:06 +02:00
committed by GitHub
9 changed files with 356 additions and 13 deletions

View File

@@ -7,6 +7,8 @@
objects = {
/* Begin PBXBuildFile section */
24B5103E1EFA7083004C6AD2 /* ReadReceiptsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 24B5103D1EFA7083004C6AD2 /* ReadReceiptsViewController.m */; };
24B510401EFA88CC004C6AD2 /* ReadReceiptsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 24B5103F1EFA88CC004C6AD2 /* ReadReceiptsViewController.xib */; };
3205ED7D1E976C8A003D65FA /* DirectoryServerPickerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3205ED7C1E976C8A003D65FA /* DirectoryServerPickerViewController.m */; };
3205ED841E97725E003D65FA /* DirectoryServerTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 3205ED821E97725E003D65FA /* DirectoryServerTableViewCell.m */; };
3205ED851E97725E003D65FA /* DirectoryServerTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3205ED831E97725E003D65FA /* DirectoryServerTableViewCell.xib */; };
@@ -471,6 +473,9 @@
/* Begin PBXFileReference section */
1129C74A281B080432B1A1A1 /* Pods-Riot.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Riot.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Riot/Pods-Riot.debug.xcconfig"; sourceTree = "<group>"; };
24B5103C1EFA7083004C6AD2 /* ReadReceiptsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReadReceiptsViewController.h; sourceTree = "<group>"; };
24B5103D1EFA7083004C6AD2 /* ReadReceiptsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ReadReceiptsViewController.m; sourceTree = "<group>"; };
24B5103F1EFA88CC004C6AD2 /* ReadReceiptsViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ReadReceiptsViewController.xib; sourceTree = "<group>"; };
3205ED7B1E976C8A003D65FA /* DirectoryServerPickerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DirectoryServerPickerViewController.h; sourceTree = "<group>"; };
3205ED7C1E976C8A003D65FA /* DirectoryServerPickerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DirectoryServerPickerViewController.m; sourceTree = "<group>"; };
3205ED811E97725E003D65FA /* DirectoryServerTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DirectoryServerTableViewCell.h; sourceTree = "<group>"; };
@@ -1585,6 +1590,9 @@
F083BC541E7009EC00A9B29C /* StartChatViewController.xib */,
F083BC551E7009EC00A9B29C /* UsersDevicesViewController.h */,
F083BC561E7009EC00A9B29C /* UsersDevicesViewController.m */,
24B5103C1EFA7083004C6AD2 /* ReadReceiptsViewController.h */,
24B5103D1EFA7083004C6AD2 /* ReadReceiptsViewController.m */,
24B5103F1EFA88CC004C6AD2 /* ReadReceiptsViewController.xib */,
);
path = ViewController;
sourceTree = "<group>";
@@ -2041,6 +2049,7 @@
F083BD881E7009ED00A9B29C /* file_doc_icon@3x.png in Resources */,
F083BDAB1E7009ED00A9B29C /* placeholder@2x.png in Resources */,
F083BE4D1E7009ED00A9B29C /* RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.xib in Resources */,
24B510401EFA88CC004C6AD2 /* ReadReceiptsViewController.xib in Resources */,
F083BDC81E7009ED00A9B29C /* search_icon.png in Resources */,
F083BDE91E7009ED00A9B29C /* ring.mp3 in Resources */,
F083BE431E7009ED00A9B29C /* RoomIncomingEncryptedTextMsgWithoutSenderInfoBubbleCell.xib in Resources */,
@@ -2405,7 +2414,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
@@ -2457,6 +2466,7 @@
F083BE761E7009ED00A9B29C /* RoomOutgoingTextMsgWithPaginationTitleBubbleCell.m in Sources */,
F083BE5A1E7009ED00A9B29C /* RoomIncomingAttachmentBubbleCell.m in Sources */,
F083BE541E7009ED00A9B29C /* RoomOutgoingEncryptedTextMsgWithoutSenderNameBubbleCell.m in Sources */,
24B5103E1EFA7083004C6AD2 /* ReadReceiptsViewController.m in Sources */,
F083BE621E7009ED00A9B29C /* RoomIncomingTextMsgWithoutSenderInfoBubbleCell.m in Sources */,
F083BE881E7009ED00A9B29C /* RoomMemberTitleView.m in Sources */,
F083BE701E7009ED00A9B29C /* RoomOutgoingTextMsgBubbleCell.m in Sources */,

View File

@@ -414,6 +414,10 @@
"room_details_copy_room_address" = "Copy Room Address";
"room_details_copy_room_url" = "Copy Room URL";
// Read Receipts
"read_receipts_list" = "Read Receipts List";
"receipt_status_read" = "Read: ";
// Media picker
"media_picker_library" = "Library";
"media_picker_select" = "Select";

View File

@@ -23,6 +23,13 @@
*/
extern NSString *const kMXKRoomBubbleCellRiotEditButtonPressed;
/**
Action identifier used when the user tapped on receipts area.
The 'userInfo' disctionary contains an 'MXKReceiptSendersContainer' object under the 'kMXKRoomBubbleCellReceiptsContainerKey' key, representing the receipts container which was tapped on.
*/
extern NSString *const kMXKRoomBubbleCellTapOnReceiptsContainer;
/**
Define a `MXKRoomBubbleTableViewCell` category at Riot level to handle bubble customisation.
*/
@@ -56,6 +63,11 @@ extern NSString *const kMXKRoomBubbleCellRiotEditButtonPressed;
*/
- (void)addDateLabel;
/**
Called when the user taps on the Receipt Container.
*/
- (IBAction)onReceiptContainerTap:(UITapGestureRecognizer *)sender;
/**
Blur the view by adding a transparent overlay. Default is NO.
*/

View File

@@ -29,6 +29,7 @@
#define VECTOR_ROOMBUBBLETABLEVIEWCELL_MARK_WIDTH 4
NSString *const kMXKRoomBubbleCellRiotEditButtonPressed = @"kMXKRoomBubbleCellRiotEditButtonPressed";
NSString *const kMXKRoomBubbleCellTapOnReceiptsContainer = @"kMXKRoomBubbleCellTapOnReceiptsContainer";
@implementation MXKRoomBubbleTableViewCell (Riot)
@@ -153,7 +154,7 @@ NSString *const kMXKRoomBubbleCellRiotEditButtonPressed = @"kMXKRoomBubbleCellRi
// Retrieve the read receipts container related to the selected component (if any)
// Blur the others
for (UIView* view in self.bubbleOverlayContainer.subviews)
for (UIView* view in self.tmpSubviews)
{
// Note read receipt container tag is equal to the index of the related component.
if (view.tag != componentIndex)
@@ -323,11 +324,14 @@ NSString *const kMXKRoomBubbleCellRiotEditButtonPressed = @"kMXKRoomBubbleCellRi
self.bubbleOverlayContainer.alpha = 0.8;
self.bubbleOverlayContainer.userInteractionEnabled = YES;
// Blur read receipts if any
// Blur subviews if any
for (UIView* view in self.bubbleOverlayContainer.subviews)
{
view.alpha = 0.2;
}
// Move this view in front
[self.contentView bringSubviewToFront:self.bubbleOverlayContainer];
}
else
{
@@ -338,7 +342,7 @@ NSString *const kMXKRoomBubbleCellRiotEditButtonPressed = @"kMXKRoomBubbleCellRi
self.bubbleOverlayContainer.alpha = 1;
self.bubbleOverlayContainer.userInteractionEnabled = NO;
// Restore read receipts display
// Restore subviews display
for (UIView* view in self.bubbleOverlayContainer.subviews)
{
view.alpha = 1;
@@ -406,6 +410,14 @@ NSString *const kMXKRoomBubbleCellRiotEditButtonPressed = @"kMXKRoomBubbleCellRi
}
}
- (IBAction)onReceiptContainerTap:(UITapGestureRecognizer *)sender
{
if (self.delegate)
{
[self.delegate cell:self didRecognizeAction:kMXKRoomBubbleCellTapOnReceiptsContainer userInfo:@{kMXKRoomBubbleCellReceiptsContainerKey : sender.view}];
}
}
#pragma mark - Internals
- (void)addEditButtonForComponent:(NSUInteger)componentIndex completion:(void (^ __nullable)(BOOL finished))completion

View File

@@ -144,13 +144,8 @@
// Ignore the read receipts on the bubble without actual display.
if ((self.showBubbleReceipts && cellData.hasReadReceipts) || self.showReadMarker)
{
// Read receipts container are inserted here on the right side into the overlay container.
// Read receipts container are inserted here on the right side into the content view.
// Some vertical whitespaces are added in message text view (see RoomBubbleCellData class) to insert correctly multiple receipts.
bubbleCell.bubbleOverlayContainer.backgroundColor = [UIColor clearColor];
bubbleCell.bubbleOverlayContainer.alpha = 1;
bubbleCell.bubbleOverlayContainer.userInteractionEnabled = NO;
bubbleCell.bubbleOverlayContainer.hidden = NO;
NSInteger index = bubbleComponents.count;
CGFloat bottomPositionY = bubbleCell.frame.size.height;
while (index--)
@@ -199,10 +194,26 @@
avatarsContainer.tag = index;
[avatarsContainer refreshReceiptSenders:roomMembers withPlaceHolders:placeholders andAlignment:ReadReceiptAlignmentRight];
avatarsContainer.readReceipts = receipts;
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:cell action:@selector(onReceiptContainerTap:)];
[tapRecognizer setNumberOfTapsRequired:1];
[tapRecognizer setNumberOfTouchesRequired:1];
[avatarsContainer addGestureRecognizer:tapRecognizer];
avatarsContainer.userInteractionEnabled = YES;
avatarsContainer.translatesAutoresizingMaskIntoConstraints = NO;
avatarsContainer.accessibilityIdentifier = @"readReceiptsContainer";
[bubbleCell.bubbleOverlayContainer addSubview:avatarsContainer];
// Add this read receipts container in the content view
if (!bubbleCell.tmpSubviews)
{
bubbleCell.tmpSubviews = [NSMutableArray arrayWithArray:@[avatarsContainer]];
}
else
{
[bubbleCell.tmpSubviews addObject:avatarsContainer];
}
[bubbleCell.contentView addSubview:avatarsContainer];
// Force receipts container size
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:avatarsContainer
@@ -224,14 +235,14 @@
NSLayoutConstraint *trailingConstraint = [NSLayoutConstraint constraintWithItem:avatarsContainer
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:bubbleCell.bubbleOverlayContainer
toItem:avatarsContainer.superview
attribute:NSLayoutAttributeTrailing
multiplier:1.0
constant:-6];
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:avatarsContainer
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:bubbleCell.bubbleOverlayContainer
toItem:avatarsContainer.superview
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:bottomPositionY - 13];
@@ -244,6 +255,13 @@
// Check whether the read marker must be displayed here.
if (self.showReadMarker)
{
// The read marker is added into the overlay container.
// CAUTION: Keep disabled the user interaction on this container to not disturb tap gesture handling.
bubbleCell.bubbleOverlayContainer.backgroundColor = [UIColor clearColor];
bubbleCell.bubbleOverlayContainer.alpha = 1;
bubbleCell.bubbleOverlayContainer.userInteractionEnabled = NO;
bubbleCell.bubbleOverlayContainer.hidden = NO;
if ([component.event.eventId isEqualToString:self.room.accountData.readMarkerEventId])
{
bubbleCell.readMarkerView = [[UIView alloc] initWithFrame:CGRectMake(0, bottomPositionY - 2, bubbleCell.bubbleOverlayContainer.frame.size.width, 2)];

View File

@@ -0,0 +1,24 @@
/*
Copyright 2017 Aram Sargsyan
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import <UIKit/UIKit.h>
#import <MatrixKit/MatrixKit.h>
@interface ReadReceiptsViewController : MXKViewController
+ (void)openInViewController:(UIViewController *)viewController fromContainer:(MXKReceiptSendersContainer *)receiptSendersContainer withSession:(MXSession *)session;
@end

View File

@@ -0,0 +1,168 @@
/*
Copyright 2017 Aram Sargsyan
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 "ReadReceiptsViewController.h"
#import <MatrixKit/MatrixKit.h>
#import "RiotDesignValues.h"
@interface ReadReceiptsViewController () <UITableViewDataSource, UITableViewDelegate>
@property (nonatomic) MXRestClient* restClient;
@property (nonatomic) MXSession *session;
@property (nonatomic) NSArray <MXRoomMember *> *roomMembers;
@property (nonatomic) NSArray <UIImage *> *placeholders;
@property (nonatomic) NSArray <MXReceiptData *> *receipts;
@property (weak, nonatomic) IBOutlet UIView *overlayView;
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
@property (weak, nonatomic) IBOutlet UIView *containerView;
@property (weak, nonatomic) IBOutlet UITableView *receiptsTableView;
@end
@implementation ReadReceiptsViewController
#pragma mark - Public
+ (void)openInViewController:(UIViewController *)viewController fromContainer:(MXKReceiptSendersContainer *)receiptSendersContainer withSession:(MXSession *)session
{
ReadReceiptsViewController *receiptsController = [[[self class] alloc] initWithNibName:NSStringFromClass([self class]) bundle:nil];
receiptsController.restClient = receiptSendersContainer.restClient;
receiptsController.session = session;
receiptsController.roomMembers = receiptSendersContainer.roomMembers;
receiptsController.placeholders = receiptSendersContainer.placeholders;
receiptsController.receipts = receiptSendersContainer.readReceipts;
receiptsController.providesPresentationContextTransitionStyle = YES;
receiptsController.definesPresentationContext = YES;
receiptsController.modalPresentationStyle = UIModalPresentationOverFullScreen;
receiptsController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[viewController presentViewController:receiptsController animated:YES completion:nil];
}
#pragma mark - Lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
[self configureViews];
[self configureReceiptsTableView];
[self addOverlayViewGesture];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Views
- (void)configureViews
{
self.containerView.layer.cornerRadius = 20;
self.titleLabel.text = NSLocalizedStringFromTable(@"read_receipts_list", @"Vector", nil);
}
- (void)configureReceiptsTableView
{
self.receiptsTableView.dataSource = self;
self.receiptsTableView.delegate = self;
self.receiptsTableView.showsVerticalScrollIndicator = NO;
self.receiptsTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
[self.receiptsTableView registerNib:[MXKReadReceiptTableViewCell nib] forCellReuseIdentifier:[MXKReadReceiptTableViewCell defaultReuseIdentifier]];
}
- (void)addOverlayViewGesture
{
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(overlayTap)];
[tapRecognizer setNumberOfTapsRequired:1];
[tapRecognizer setNumberOfTouchesRequired:1];
[self.overlayView addGestureRecognizer:tapRecognizer];
}
#pragma mark - Actions
- (void)overlayTap
{
[self dismissViewControllerAnimated:YES completion:nil];
}
#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.roomMembers.count;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
MXKReadReceiptTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:[MXKReadReceiptTableViewCell defaultReuseIdentifier] forIndexPath:indexPath];
if (indexPath.row < self.roomMembers.count)
{
NSString *name = self.roomMembers[indexPath.row].displayname;
if (name.length == 0) {
name = self.roomMembers[indexPath.row].userId;
}
cell.displayNameLabel.text = name;
}
if (indexPath.row < self.placeholders.count)
{
NSString *avatarUrl = self.roomMembers[indexPath.row].avatarUrl;
if (self.restClient && avatarUrl)
{
CGFloat side = CGRectGetWidth(cell.avatarImageView.frame);
avatarUrl = [self.restClient urlOfContentThumbnail:avatarUrl toFitViewSize:CGSizeMake(side, side) withMethod:MXThumbnailingMethodCrop];
}
[cell.avatarImageView setImageURL:avatarUrl withType:nil andImageOrientation:UIImageOrientationUp previewImage:self.placeholders[indexPath.row]];
}
if (indexPath.row < self.receipts.count)
{
NSString *receiptReadText = NSLocalizedStringFromTable(@"receipt_status_read", @"Vector", nil);
NSString *receiptTimeText = [(MXKEventFormatter*)self.session.roomSummaryUpdateDelegate dateStringFromTimestamp:self.receipts[indexPath.row].ts withTime:YES];
NSMutableAttributedString *receiptDescription = [[NSMutableAttributedString alloc] initWithString:receiptReadText attributes:@{NSForegroundColorAttributeName : kRiotTextColorGray, NSFontAttributeName : [UIFont boldSystemFontOfSize:15]}];
[receiptDescription appendAttributedString:[[NSAttributedString alloc] initWithString:receiptTimeText attributes:@{NSForegroundColorAttributeName : kRiotTextColorGray, NSFontAttributeName : [UIFont systemFontOfSize:15]}]];
cell.receiptDescriptionLabel.attributedText = receiptDescription;
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
#pragma mark - UITableViewDelegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 70;
}
@end

View File

@@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12120" systemVersion="16E195" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12088"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="ReadReceiptsViewController">
<connections>
<outlet property="containerView" destination="kg4-Yk-K6b" id="DNS-mH-6HR"/>
<outlet property="overlayView" destination="41Z-5b-umc" id="gpj-Ux-mhK"/>
<outlet property="receiptsTableView" destination="9qg-nd-kFU" id="ZWb-Hn-hIe"/>
<outlet property="titleLabel" destination="jsl-CT-BFF" id="7co-HF-mWI"/>
<outlet property="view" destination="iN0-l3-epB" id="bVY-jN-77v"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view alpha="0.5" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="41Z-5b-umc" userLabel="Overlay View">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
</view>
<view clipsSubviews="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="kg4-Yk-K6b" userLabel="Master Container View">
<rect key="frame" x="10" y="58.5" width="355" height="550"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="YD2-h3-4xX" userLabel="Title Container View">
<rect key="frame" x="0.0" y="0.0" width="355" height="40"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jsl-CT-BFF" userLabel="Title Label">
<rect key="frame" x="156.5" y="10" width="41.5" height="19.5"/>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="16"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="jsl-CT-BFF" firstAttribute="centerY" secondItem="YD2-h3-4xX" secondAttribute="centerY" id="3nq-G3-rhK"/>
<constraint firstItem="jsl-CT-BFF" firstAttribute="centerX" secondItem="YD2-h3-4xX" secondAttribute="centerX" id="YfA-8b-6PG"/>
<constraint firstAttribute="height" constant="40" id="vYa-wu-b0l"/>
</constraints>
</view>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="9qg-nd-kFU">
<rect key="frame" x="0.0" y="40" width="355" height="510"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</tableView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="9qg-nd-kFU" secondAttribute="bottom" id="9tH-uU-nTl"/>
<constraint firstAttribute="trailing" secondItem="9qg-nd-kFU" secondAttribute="trailing" id="MLa-NR-q4z"/>
<constraint firstItem="YD2-h3-4xX" firstAttribute="leading" secondItem="kg4-Yk-K6b" secondAttribute="leading" id="X5O-8F-CyO"/>
<constraint firstAttribute="trailing" secondItem="YD2-h3-4xX" secondAttribute="trailing" id="aUL-jB-exK"/>
<constraint firstItem="YD2-h3-4xX" firstAttribute="top" secondItem="kg4-Yk-K6b" secondAttribute="top" id="aUc-NR-Suw"/>
<constraint firstAttribute="width" relation="lessThanOrEqual" constant="550" id="j5U-sf-HMF"/>
<constraint firstItem="9qg-nd-kFU" firstAttribute="leading" secondItem="kg4-Yk-K6b" secondAttribute="leading" id="p5C-BH-56n"/>
<constraint firstItem="9qg-nd-kFU" firstAttribute="top" secondItem="YD2-h3-4xX" secondAttribute="bottom" id="thD-Si-NzK"/>
<constraint firstAttribute="height" relation="lessThanOrEqual" constant="550" id="wln-eD-ner"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="41Z-5b-umc" secondAttribute="bottom" id="2qB-lj-z6b"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="kg4-Yk-K6b" secondAttribute="trailing" constant="10" id="96x-1M-6KX"/>
<constraint firstItem="41Z-5b-umc" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="CoG-Nf-HX8"/>
<constraint firstItem="kg4-Yk-K6b" firstAttribute="top" relation="greaterThanOrEqual" secondItem="iN0-l3-epB" secondAttribute="top" constant="10" id="ERj-JN-Ljg"/>
<constraint firstItem="kg4-Yk-K6b" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" id="M3i-yJ-w5M"/>
<constraint firstAttribute="trailing" secondItem="41Z-5b-umc" secondAttribute="trailing" id="USj-F9-gZi"/>
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="kg4-Yk-K6b" secondAttribute="bottom" constant="10" id="Xl6-6H-Rb6"/>
<constraint firstItem="kg4-Yk-K6b" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" priority="750" constant="10" id="Zmw-aZ-NHG"/>
<constraint firstAttribute="bottom" secondItem="kg4-Yk-K6b" secondAttribute="bottom" priority="750" constant="10" id="hTL-dj-W5I"/>
<constraint firstItem="kg4-Yk-K6b" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="centerY" id="hgX-JU-Hm1"/>
<constraint firstAttribute="trailing" secondItem="kg4-Yk-K6b" secondAttribute="trailing" priority="750" constant="10" id="lJU-iL-6th"/>
<constraint firstItem="kg4-Yk-K6b" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="iN0-l3-epB" secondAttribute="leading" constant="10" id="qYN-Lz-Uvz"/>
<constraint firstItem="kg4-Yk-K6b" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" priority="750" constant="10" id="xg1-8A-kJZ"/>
<constraint firstItem="41Z-5b-umc" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="z6e-1g-MG7"/>
</constraints>
</view>
</objects>
</document>

View File

@@ -45,6 +45,8 @@
#import "UsersDevicesViewController.h"
#import "ReadReceiptsViewController.h"
#import "RoomEmptyBubbleCell.h"
#import "RoomIncomingTextMsgBubbleCell.h"
@@ -1709,6 +1711,11 @@
[self showEncryptionInformation:tappedEvent];
}
}
else if ([actionIdentifier isEqualToString:kMXKRoomBubbleCellTapOnReceiptsContainer])
{
MXKReceiptSendersContainer *container = userInfo[kMXKRoomBubbleCellReceiptsContainerKey];
[ReadReceiptsViewController openInViewController:self fromContainer:container withSession:self.mainSession];
}
else
{
// Keep default implementation for other actions