Merge branch 'master' into patch-1

This commit is contained in:
manuroe
2017-07-05 15:21:44 +02:00
committed by GitHub
54 changed files with 1230 additions and 346 deletions

View File

@@ -22,7 +22,10 @@ Denis Morozov <dmorozkn at gmail.com>
* Fix default room avatar for an empty room #1044
* PR #1090, PR #1113, PR #1123: UX improvements
* PR #1132: Check email validity during reset password operation
* VoIP improvements
Aram Sargsyan <aram.sargsyan.1997 at gmail.com>
* PR #1341: Read receipts details
Nathan van Beelen <nathan at vanbeelen.org>
* PR #1317: Dutch translation of the strings

View File

@@ -1,3 +1,49 @@
Changes in 0.4.3 (2017-07-05)
===============================================
Improvement:
* Update the application title with "Riot.im".
Changes in 0.4.2 (2017-06-30)
===============================================
Improvements:
* Upgrade MatrixKit version (v0.5.2).
* Chat: Expand read receipts when user taps on it #59, thanks to @aramsargsyan (#1341).
* GA: Disable GA in debug as it pollutes stats and crashes.
* Home: Display room name on 2 lines.
Bug fixes:
* Fix: Crash when scrolling in the public rooms from Unified Search (#1355).
* Chat screen: the message overlaps its timestamp.
* Chat screen: several encryption icons are displayed on the same event.
* Blank pages with random "unread msgs" bars whilst they load.
* Fix a crash when rotating + debackgrounding the app (#1362).
* Bug report: Remove the old requirement for an existing email account.
* Crash report: Do not loose what the user typed when debackgrounding the app.
Changes in 0.4.1 (2017-06-23)
===============================================
Improvements:
* Upgrade MatrixKit version (v0.5.1).
Bug fixes:
* Room Chat: Scrolling manually to the bottom of the no live timeline doesn't flip it to read/write view (#1312).
* Enhancement - UX Rework: Update the buttons of the room expanded header (vector-im/riot-meta#76).
* Contact search: Unexpected empty search result.
* tap-on-tab should include the top-of-page location in its cycle of options (#1316).
* Fix crash on decline button, thanks to @morozkin (#1330).
* Room directory: stuck after the 20 first items (#1329).
* Room directory: "No public rooms available" is displayed while loading (#1336).
* Room directory: Clicking on "No public rooms available" make the app crash.
* Crash when hitting a room header after some special steps (#1340).
* Chat screen: the search icon is missing after switching in live from a non live timeline (#1344).
* Crash when hitting room from unified search/browse directory (#1342).
* tapping on an unread room on home page takes you to the wrong room (#1304).
* Read marker: when being kicked, the "Jump to first unread message" shouldn't be displayed (#1338).
Changes in 0.4.0 (2017-06-16)
===============================================

View File

@@ -8,7 +8,7 @@ target "Riot" do
# Different flavours of pods to MatrixKit
# The tagged version on which this version of Riot has been built
pod 'MatrixKit', '0.5.0'
pod 'MatrixKit', '0.5.2'
# The lastest release available on the CocoaPods repository
#pod 'MatrixKit'

View File

@@ -39,13 +39,13 @@ PODS:
- GZIP (1.1.1)
- HPGrowingTextView (1.1)
- libPhoneNumber-iOS (0.9.10)
- MatrixKit (0.5.0):
- MatrixKit (0.5.2):
- cmark (~> 0.24.1)
- DTCoreText (~> 1.6.17)
- HPGrowingTextView (~> 1.1)
- libPhoneNumber-iOS (~> 0.9.10)
- MatrixSDK (= 0.8.0)
- MatrixSDK (0.8.0):
- MatrixSDK (= 0.8.2)
- MatrixSDK (0.8.2):
- AFNetworking (~> 3.1.0)
- GZIP (~> 1.1.1)
- OLMKit (2.2.2):
@@ -53,9 +53,9 @@ PODS:
- OLMKit/olmcpp (= 2.2.2)
- OLMKit/olmc (2.2.2)
- OLMKit/olmcpp (2.2.2)
- Realm (2.8.1):
- Realm/Headers (= 2.8.1)
- Realm/Headers (2.8.1)
- Realm (2.8.3):
- Realm/Headers (= 2.8.3)
- Realm/Headers (2.8.3)
- WebRTC (58.17.16937)
DEPENDENCIES:
@@ -63,7 +63,7 @@ DEPENDENCIES:
- DTCoreText
- GBDeviceInfo (~> 4.3.0)
- GoogleAnalytics
- MatrixKit (= 0.5.0)
- MatrixKit (= 0.5.2)
- OLMKit
- Realm (~> 2.8.1)
- WebRTC (= 58.17.16937)
@@ -78,12 +78,12 @@ SPEC CHECKSUMS:
GZIP: f8beb59597f651e6970a45b816508a9c6d700b77
HPGrowingTextView: 88a716d97fb853bcb08a4a08e4727da17efc9b19
libPhoneNumber-iOS: f721ae4d5854bce60934f9fb9b0b28e8e68913cb
MatrixKit: 3783ee9b8b049a05a5856c66f749319ec1592161
MatrixSDK: 6d1bf7ffc4792622da5441b4ddc6d5c02a0675b3
MatrixKit: daad23e5724d8f26a44a322f4d259a26b614ddc6
MatrixSDK: 1f9b5fa6334485c431884d2d2ea9ac5f65557528
OLMKit: b9d8c0ffee9ea8c45bc0aaa9afb47f93fba7efbd
Realm: 2627602ad6818451f0cb8c2a6e072f7f10a5f360
Realm: 3601ef091c8c499a31101d8563b991e75546cdce
WebRTC: 1e9a85bf75509eec44be6478c64e9de65ac82332
PODFILE CHECKSUM: 24c0a0406f24e3ba56478f5e9322cda986a7c199
PODFILE CHECKSUM: ba9311a74b4af32f75db5053d87c9f7181a42d17
COCOAPODS: 1.2.1

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 */; };
@@ -422,6 +424,9 @@
F083BEA21E7009ED00A9B29C /* TableViewCellWithPhoneNumberTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = F083BD1B1E7009ED00A9B29C /* TableViewCellWithPhoneNumberTextField.m */; };
F083BEA31E7009ED00A9B29C /* TableViewCellWithPhoneNumberTextField.xib in Resources */ = {isa = PBXBuildFile; fileRef = F083BD1C1E7009ED00A9B29C /* TableViewCellWithPhoneNumberTextField.xib */; };
F083BEA51E70356E00A9B29C /* RiotTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F083BB041E7005FD00A9B29C /* RiotTests.m */; };
F0A4A1671EF7CB66003630DB /* members_list_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = F0A4A1641EF7CB66003630DB /* members_list_icon.png */; };
F0A4A1681EF7CB66003630DB /* members_list_icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F0A4A1651EF7CB66003630DB /* members_list_icon@2x.png */; };
F0A4A1691EF7CB66003630DB /* members_list_icon@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = F0A4A1661EF7CB66003630DB /* members_list_icon@3x.png */; };
F0D869EB1EC455A100BB0A2B /* create_direct_chat.png in Resources */ = {isa = PBXBuildFile; fileRef = F0D869E81EC455A100BB0A2B /* create_direct_chat.png */; };
F0D869EC1EC455A100BB0A2B /* create_direct_chat@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F0D869E91EC455A100BB0A2B /* create_direct_chat@2x.png */; };
F0D869ED1EC455A100BB0A2B /* create_direct_chat@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = F0D869EA1EC455A100BB0A2B /* create_direct_chat@3x.png */; };
@@ -468,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>"; };
@@ -1006,6 +1014,9 @@
F083BD1C1E7009ED00A9B29C /* TableViewCellWithPhoneNumberTextField.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = TableViewCellWithPhoneNumberTextField.xib; sourceTree = "<group>"; };
F094A9A21B78D8F000B1FBBF /* Riot.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Riot.app; sourceTree = BUILT_PRODUCTS_DIR; };
F094A9BE1B78D8F000B1FBBF /* RiotTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RiotTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
F0A4A1641EF7CB66003630DB /* members_list_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = members_list_icon.png; sourceTree = "<group>"; };
F0A4A1651EF7CB66003630DB /* members_list_icon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "members_list_icon@2x.png"; sourceTree = "<group>"; };
F0A4A1661EF7CB66003630DB /* members_list_icon@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "members_list_icon@3x.png"; sourceTree = "<group>"; };
F0D869E81EC455A100BB0A2B /* create_direct_chat.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = create_direct_chat.png; sourceTree = "<group>"; };
F0D869E91EC455A100BB0A2B /* create_direct_chat@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "create_direct_chat@2x.png"; sourceTree = "<group>"; };
F0D869EA1EC455A100BB0A2B /* create_direct_chat@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "create_direct_chat@3x.png"; sourceTree = "<group>"; };
@@ -1156,6 +1167,9 @@
F083BB151E7009EC00A9B29C /* Images */ = {
isa = PBXGroup;
children = (
F0A4A1641EF7CB66003630DB /* members_list_icon.png */,
F0A4A1651EF7CB66003630DB /* members_list_icon@2x.png */,
F0A4A1661EF7CB66003630DB /* members_list_icon@3x.png */,
F0614A101EDEE65000F5DC9A /* cancel.png */,
F0614A111EDEE65000F5DC9A /* cancel@2x.png */,
F0614A121EDEE65000F5DC9A /* cancel@3x.png */,
@@ -1576,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>";
@@ -2032,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 */,
@@ -2130,6 +2148,7 @@
F083BD891E7009ED00A9B29C /* file_music_icon.png in Resources */,
F083BDD11E7009ED00A9B29C /* settings_icon.png in Resources */,
F083BD811E7009ED00A9B29C /* favourite@2x.png in Resources */,
F0A4A1681EF7CB66003630DB /* members_list_icon@2x.png in Resources */,
F083BD9F1E7009ED00A9B29C /* mod_icon@2x.png in Resources */,
F083BD801E7009ED00A9B29C /* favourite.png in Resources */,
F083BD4B1E7009ED00A9B29C /* camera_capture.png in Resources */,
@@ -2266,6 +2285,7 @@
F083BD631E7009ED00A9B29C /* direct_icon@2x.png in Resources */,
F083BE991E7009ED00A9B29C /* MessagesSearchResultTextMsgBubbleCell.xib in Resources */,
F083BD711E7009ED00A9B29C /* e2e_unencrypted.png in Resources */,
F0A4A1671EF7CB66003630DB /* members_list_icon.png in Resources */,
F083BE731E7009ED00A9B29C /* RoomOutgoingTextMsgWithoutSenderInfoBubbleCell.xib in Resources */,
F083BD251E7009ED00A9B29C /* admin_icon.png in Resources */,
F083BDBE1E7009ED00A9B29C /* riot_icon@3x.png in Resources */,
@@ -2328,6 +2348,7 @@
F083BDE01E7009ED00A9B29C /* video_icon.png in Resources */,
F083BD601E7009ED00A9B29C /* details_icon@2x.png in Resources */,
F083BE5F1E7009ED00A9B29C /* RoomIncomingAttachmentWithPaginationTitleBubbleCell.xib in Resources */,
F0A4A1691EF7CB66003630DB /* members_list_icon@3x.png in Resources */,
F083BE8D1E7009ED00A9B29C /* PreviewRoomTitleView.xib in Resources */,
F083BD561E7009ED00A9B29C /* camera_video_capture.png in Resources */,
F083BD651E7009ED00A9B29C /* directChatOff.png in Resources */,
@@ -2445,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

@@ -1,5 +1,6 @@
/*
Copyright 2015 OpenMarket Ltd
Copyright 2017 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -61,9 +62,10 @@ static RageShakeManager* sharedInstance = nil;
return self;
}
- (void)promptCrashReportInViewController:(UIViewController*)viewController {
if ([MXLogger crashLog] && [MFMailComposeViewController canSendMail]) {
- (void)promptCrashReportInViewController:(UIViewController*)viewController
{
if ([MXLogger crashLog])
{
confirmationAlert = [[MXKAlert alloc] initWithTitle:NSLocalizedStringFromTable(@"bug_report_prompt", @"Vector", nil) message:nil style:MXKAlertStyleAlert];
__weak typeof(self) weakSelf = self;
@@ -101,14 +103,15 @@ static RageShakeManager* sharedInstance = nil;
}
}
- (void)stopShaking:(UIResponder*)responder {
- (void)stopShaking:(UIResponder*)responder
{
NSLog(@"[RageShakeManager] Stop shaking with [%@]", [responder class]);
if (isShaking && [AppDelegate theDelegate].isAppForeground && !confirmationAlert
&& (([[NSDate date] timeIntervalSince1970] - startShakingTimeStamp) > RAGESHAKEMANAGER_MINIMUM_SHAKING_DURATION)) {
if ([responder isKindOfClass:[UIViewController class]] && [MFMailComposeViewController canSendMail]) {
&& (([[NSDate date] timeIntervalSince1970] - startShakingTimeStamp) > RAGESHAKEMANAGER_MINIMUM_SHAKING_DURATION))
{
if ([responder isKindOfClass:[UIViewController class]])
{
confirmationAlert = [[MXKAlert alloc] initWithTitle:NSLocalizedStringFromTable(@"rage_shake_prompt", @"Vector", nil) message:nil style:MXKAlertStyleAlert];
__weak typeof(self) weakSelf = self;

View File

@@ -28,6 +28,8 @@
#import "SettingsViewController.h"
#import "ContactDetailsViewController.h"
#import "BugReportViewController.h"
#import "NSBundle+MatrixKit.h"
#import "MatrixSDK/MatrixSDK.h"
@@ -790,6 +792,11 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
// Set Google Analytics dispatch interval to e.g. 20 seconds.
gai.dispatchInterval = 20;
#ifdef DEBUG
// Disable GAI in debug as it pollutes stats and crashes in GA
gai.dryRun = YES;
#endif
}
else
{
@@ -824,6 +831,13 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
NSString *filePath = [MXLogger crashLog];
if (filePath)
{
// Do not show the crash report dialog if it is already displayed
if ([self.window.rootViewController.childViewControllers[0] isKindOfClass:[UINavigationController class]]
&& [((UINavigationController*)self.window.rootViewController.childViewControllers[0]).visibleViewController isKindOfClass:[BugReportViewController class]])
{
return;
}
NSString *description = [[NSString alloc] initWithContentsOfFile:filePath
usedEncoding:nil
error:nil];
@@ -2314,7 +2328,6 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
// Release properly
[currentCallViewController destroy];
currentCallViewController = nil;
if (completion)
{

BIN
Riot/Assets/Images/logo.png Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

BIN
Riot/Assets/Images/logo@2x.png Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 24 KiB

BIN
Riot/Assets/Images/logo@3x.png Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

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";
@@ -470,3 +474,5 @@
"bug_report_send_screenshot" = "Send screenshot";
"bug_report_progress_zipping" = "Collecting logs";
"bug_report_progress_uploading" = "Uploading report";
"bug_report_send" = "Send";

View File

@@ -45,6 +45,7 @@
<segue destination="nDS-pp-sWM" kind="show" identifier="showMemberDetails" id="cUw-vU-gJq"/>
<segue destination="gkO-rP-nGK" kind="show" identifier="showContactDetails" action="showDetailViewController:sender:" id="f5u-Y1-7nt"/>
<segue destination="ZZb-IS-a1F" kind="presentation" identifier="showUnknownDevices" id="wUx-4y-ybn"/>
<segue destination="udm-55-AMb" kind="show" identifier="showContactPicker" id="Q6y-9M-Ugl"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="94y-cU-qQD" userLabel="First Responder" sceneMemberID="firstResponder"/>
@@ -80,12 +81,12 @@
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
</view>
<barButtonItem key="rightBarButtonItem" image="search_icon.png" id="Koy-mU-PTG" userLabel="Menu Bar Button Item"/>
</navigationItem>
<connections>
<outlet property="roomTitleViewContainer" destination="djN-zB-Vni" id="VQG-Mp-hSa"/>
<segue destination="nDS-pp-sWM" kind="show" identifier="showMemberDetails" id="fNQ-S3-DbZ"/>
<segue destination="gkO-rP-nGK" kind="show" identifier="showContactDetails" id="ziz-Xl-QVg"/>
<segue destination="e7G-NU-7ck" kind="show" identifier="showRoomDetails" id="mFs-HA-7Oo"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Yjg-uP-Hcy" userLabel="First Responder" sceneMemberID="firstResponder"/>
@@ -153,7 +154,7 @@
<tableViewController id="e7G-NU-7ck" customClass="SegmentedViewController" sceneMemberID="viewController"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="fXh-hO-Zgf" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2558" y="-546"/>
<point key="canvasLocation" x="3326" y="-442"/>
</scene>
<!--People View Controller-->
<scene sceneID="Qba-PP-lco">
@@ -396,7 +397,7 @@
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="01q-h6-40E" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="3326" y="-420"/>
<point key="canvasLocation" x="5046" y="-711"/>
</scene>
<!--RoomNav-->
<scene sceneID="r7l-gg-dq7">
@@ -524,6 +525,24 @@
</objects>
<point key="canvasLocation" x="1385" y="180"/>
</scene>
<!--Contacts Table View Controller-->
<scene sceneID="2zi-xJ-RQo">
<objects>
<viewController id="udm-55-AMb" customClass="ContactsTableViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Jch-ZS-1Mm"/>
<viewControllerLayoutGuide type="bottom" id="7q1-ig-sPp"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="6G9-nj-ktC">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="uv3-zI-b3q" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="374" y="449"/>
</scene>
<!--Directory Server Picker View Controller-->
<scene sceneID="t8d-GX-ntZ">
<objects>
@@ -558,9 +577,10 @@
<image name="tab_rooms_selected.png" width="25" height="25"/>
</resources>
<inferredMetricsTieBreakers>
<segue reference="0ws-cL-0tk"/>
<segue reference="tk8-vF-K4T"/>
<segue reference="Tfl-tq-LQp"/>
<segue reference="ziz-Xl-QVg"/>
<segue reference="mFs-HA-7Oo"/>
<segue reference="fNQ-S3-DbZ"/>
</inferredMetricsTieBreakers>
</document>

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)
@@ -47,8 +48,15 @@ NSString *const kMXKRoomBubbleCellRiotEditButtonPressed = @"kMXKRoomBubbleCellRi
if (component && component.date)
{
// Check whether this is the first displayed component.
BOOL isFirstDisplayedComponent = (componentIndex == 0);
if ([bubbleData isKindOfClass:RoomBubbleCellData.class])
{
isFirstDisplayedComponent = (componentIndex == ((RoomBubbleCellData*)bubbleData).oldestComponentIndex);
}
CGFloat timeLabelPosX = self.bubbleInfoContainer.frame.size.width - VECTOR_ROOMBUBBLETABLEVIEWCELL_TIMELABEL_WIDTH;
CGFloat timeLabelPosY = componentIndex ? component.position.y + self.msgTextViewTopConstraint.constant - self.bubbleInfoContainerTopConstraint.constant: 0;
CGFloat timeLabelPosY = isFirstDisplayedComponent ? 0 : component.position.y + self.msgTextViewTopConstraint.constant - self.bubbleInfoContainerTopConstraint.constant;
UILabel *timeLabel = [[UILabel alloc] initWithFrame:CGRectMake(timeLabelPosX, timeLabelPosY, VECTOR_ROOMBUBBLETABLEVIEWCELL_TIMELABEL_WIDTH , 18)];
timeLabel.text = [bubbleData.eventFormatter timeStringFromDate:component.date];
@@ -104,7 +112,7 @@ NSString *const kMXKRoomBubbleCellRiotEditButtonPressed = @"kMXKRoomBubbleCellRi
[NSLayoutConstraint activateConstraints:@[rightConstraint, topConstraint, widthConstraint, heightConstraint]];
// Check whether a vertical whitespace was applied to display correctly the timestamp.
if (componentIndex || bubbleData.shouldHideSenderInformation || bubbleData.shouldHideSenderName)
if (!isFirstDisplayedComponent || bubbleData.shouldHideSenderInformation || bubbleData.shouldHideSenderName)
{
// Adjust the position of the potential encryption icon in this case.
if (self.encryptionStatusContainerView)
@@ -146,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)
@@ -171,18 +179,29 @@ NSString *const kMXKRoomBubbleCellRiotEditButtonPressed = @"kMXKRoomBubbleCellRi
// Define the marker frame
CGFloat markPosY = component.position.y + self.msgTextViewTopConstraint.constant;
CGFloat markHeight;
if (componentIndex == bubbleComponents.count - 1)
NSInteger mostRecentComponentIndex = bubbleComponents.count - 1;
if ([bubbleData isKindOfClass:RoomBubbleCellData.class])
{
// There is no component after this component in the cell,
// use the rest of the cell height
markHeight = self.contentView.frame.size.height - markPosY;
mostRecentComponentIndex = ((RoomBubbleCellData*)bubbleData).mostRecentComponentIndex;
}
else
// Compute the mark height.
// Use the rest of the cell height by default.
CGFloat markHeight = self.contentView.frame.size.height - markPosY;
if (componentIndex != mostRecentComponentIndex)
{
// There is another component (with display) after this component in the cell.
// Stop the marker height to the top of this component.
for (NSInteger index = componentIndex + 1; index < bubbleComponents.count; index ++)
{
MXKRoomBubbleComponent *nextComponent = bubbleComponents[index];
if (nextComponent.attributedTextMessage)
{
// Stop the marker height to the top of the next component in the cell
MXKRoomBubbleComponent *nextComponent = bubbleComponents[componentIndex + 1];
markHeight = nextComponent.position.y - component.position.y;
break;
}
}
}
UIView *markerView = [[UIView alloc] initWithFrame:CGRectMake(VECTOR_ROOMBUBBLETABLEVIEWCELL_MARK_X,
@@ -305,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
{
@@ -320,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;
@@ -388,16 +410,31 @@ 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
{
MXKRoomBubbleComponent *component = bubbleData.bubbleComponents[componentIndex];
// Check whether this is the first displayed component.
BOOL isFirstDisplayedComponent = (componentIndex == 0);
if ([bubbleData isKindOfClass:RoomBubbleCellData.class])
{
isFirstDisplayedComponent = (componentIndex == ((RoomBubbleCellData*)bubbleData).oldestComponentIndex);
}
// Define 'Edit' button frame
UIImage *editIcon = [UIImage imageNamed:@"edit_icon"];
CGFloat editBtnPosX = self.bubbleInfoContainer.frame.size.width - VECTOR_ROOMBUBBLETABLEVIEWCELL_TIMELABEL_WIDTH - 22 - editIcon.size.width / 2;
CGFloat editBtnPosY = componentIndex ? component.position.y + self.msgTextViewTopConstraint.constant - self.bubbleInfoContainerTopConstraint.constant - 13 : -13;
CGFloat editBtnPosY = isFirstDisplayedComponent ? -13 : component.position.y + self.msgTextViewTopConstraint.constant - self.bubbleInfoContainerTopConstraint.constant - 13;
UIButton *editButton = [[UIButton alloc] initWithFrame:CGRectMake(editBtnPosX, editBtnPosY, 44, 44)];
[editButton setImage:editIcon forState:UIControlStateNormal];

View File

@@ -5,7 +5,7 @@
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>Riot</string>
<string>Riot.im</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
@@ -17,11 +17,11 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.4.0</string>
<string>0.4.3</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>0.4.0</string>
<string>0.4.3</string>
<key>ITSAppUsesNonExemptEncryption</key>
<true/>
<key>ITSEncryptionExportComplianceCode</key>

View File

@@ -148,14 +148,13 @@
{
// Update search results.
searchText = [searchText stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSMutableArray<MXKContact*> *unfilteredLocalContacts;
NSMutableArray<MXKContact*> *unfilteredMatrixContacts;
searchProcessingCount++;
if (!searchText.length)
{
searchProcessingLocalContacts = nil;
searchProcessingMatrixContacts = nil;
// Disclose by default the sections if a search was in progress.
if (searchProcessingText.length)
{
@@ -164,11 +163,9 @@
}
else if (forceRefresh || !searchProcessingText.length || [searchText hasPrefix:searchProcessingText] == NO)
{
// Retrieve all the local contacts
searchProcessingLocalContacts = [self unfilteredLocalContactsArray];
// Retrieve all known matrix users
searchProcessingMatrixContacts = [self unfilteredMatrixContactsArray];
// Prepare on the main thread the arrays used to initialize the search on the processing queue.
unfilteredLocalContacts = [self unfilteredLocalContactsArray];
unfilteredMatrixContacts = [self unfilteredMatrixContactsArray];
// Disclose the sections
shrinkedSectionsBitMask = 0;
@@ -176,6 +173,18 @@
dispatch_async(searchProcessingQueue, ^{
// Reset the current arrays if it is required
if (!searchText.length)
{
searchProcessingLocalContacts = nil;
searchProcessingMatrixContacts = nil;
}
else if (unfilteredLocalContacts)
{
searchProcessingLocalContacts = unfilteredLocalContacts;
searchProcessingMatrixContacts = unfilteredMatrixContacts;
}
for (NSUInteger index = 0; index < searchProcessingLocalContacts.count;)
{
MXKContact* contact = searchProcessingLocalContacts[index];

View File

@@ -37,6 +37,11 @@
*/
@property(nonatomic) NSString *selectedEventId;
/**
The index of the oldest component (component with a timestamp, and an actual display). NSNotFound by default.
*/
@property(nonatomic, readonly) NSInteger oldestComponentIndex;
/**
The index of the most recent component (component with a timestamp, and an actual display). NSNotFound by default.
*/

View File

@@ -348,6 +348,27 @@ static NSAttributedString *readReceiptVerticalWhitespace = nil;
}
}
- (NSInteger)oldestComponentIndex
{
// Update the related component index
NSInteger oldestComponentIndex = NSNotFound;
NSArray *components = self.bubbleComponents;
NSInteger index = 0;
while (index < components.count)
{
MXKRoomBubbleComponent *component = components[index];
if (component.attributedTextMessage && component.date)
{
oldestComponentIndex = index;
break;
}
index++;
}
return oldestComponentIndex;
}
- (NSInteger)mostRecentComponentIndex
{
// Update the related component index

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

@@ -214,6 +214,10 @@ double const kPublicRoomsDirectoryDataExpiration = 10;
{
if (_hasReachedPaginationEnd)
{
if (complete)
{
complete(0);
}
return nil;
}
@@ -339,6 +343,8 @@ double const kPublicRoomsDirectoryDataExpiration = 10;
tableViewCell.selectionStyle = UITableViewCellSelectionStyleNone;
}
if (state == MXKDataSourceStateReady)
{
if (_searchPattern.length)
{
tableViewCell.textLabel.text = NSLocalizedStringFromTable(@"search_no_result", @"Vector", nil);
@@ -347,6 +353,12 @@ double const kPublicRoomsDirectoryDataExpiration = 10;
{
tableViewCell.textLabel.text = NSLocalizedStringFromTable(@"room_directory_no_public_room", @"Vector", nil);
}
}
else
{
// Show nothing while loading and in other cases
tableViewCell.textLabel.text = @"";
}
return tableViewCell;
}

View File

@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12121" systemVersion="16F73" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina5_5" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@@ -48,11 +48,11 @@
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="5rn-KE-plm">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<navigationBar contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="k7D-Gy-yBR">
<rect key="frame" x="0.0" y="20" width="375" height="44"/>
<rect key="frame" x="0.0" y="20" width="414" height="44"/>
<constraints>
<constraint firstAttribute="height" constant="44" id="GiL-7R-Wm2"/>
</constraints>
@@ -71,31 +71,31 @@
</userDefinedRuntimeAttributes>
</navigationBar>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="izX-ya-hXh">
<rect key="frame" x="0.0" y="63" width="375" height="1"/>
<rect key="frame" x="0.0" y="63" width="414" height="1"/>
<color key="backgroundColor" red="0.66666666666666663" green="0.66666666666666663" blue="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="1" id="ZiW-uP-cgo"/>
</constraints>
</view>
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" keyboardDismissMode="onDrag" translatesAutoresizingMaskIntoConstraints="NO" id="OHV-KQ-Ww0">
<rect key="frame" x="0.0" y="64" width="375" height="603"/>
<rect key="frame" x="0.0" y="64" width="414" height="672"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="rhx-dD-4EJ" userLabel="Content View">
<rect key="frame" x="0.0" y="0.0" width="375" height="485"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="logo.png" translatesAutoresizingMaskIntoConstraints="NO" id="d8r-TX-pwX" userLabel="Welcome Image View">
<rect key="frame" x="127.5" y="25" width="120" height="99"/>
<rect key="frame" x="127.66666666666666" y="25" width="120" height="101"/>
<accessibility key="accessibilityConfiguration" identifier="AuthenticationVCWelcomeImageView"/>
<constraints>
<constraint firstAttribute="width" constant="120" id="ZFx-Mn-Kzq"/>
<constraint firstAttribute="height" constant="99" id="zA1-WN-LdU"/>
<constraint firstAttribute="height" constant="101" id="zA1-WN-LdU"/>
</constraints>
</imageView>
<view clipsSubviews="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="xWb-IJ-v7F" userLabel="AuthInputsContainerView">
<rect key="frame" x="0.0" y="160" width="375" height="200"/>
<subviews>
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="30E-gm-z6O">
<rect key="frame" x="177.5" y="90" width="20" height="20"/>
<rect key="frame" x="177.66666666666666" y="90" width="20" height="20"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="accessibilityIdentifier" value="AuthenticationVCActivityIndicator"/>
</userDefinedRuntimeAttributes>
@@ -107,7 +107,7 @@
<nil key="highlightedColor"/>
</label>
<button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="wIH-Kd-r7q" userLabel="retryButton">
<rect key="frame" x="165.5" y="30" width="45" height="30"/>
<rect key="frame" x="165.66666666666666" y="30" width="45" height="30"/>
<accessibility key="accessibilityConfiguration" identifier="AuthenticationVCRetryButton"/>
<constraints>
<constraint firstAttribute="height" constant="30" id="WtO-NT-ei8"/>
@@ -391,10 +391,10 @@
</userDefinedRuntimeAttributes>
</scrollView>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="q1e-Wg-6t7" userLabel="Authentication Fallback ContentView">
<rect key="frame" x="0.0" y="20" width="375" height="647"/>
<rect key="frame" x="0.0" y="20" width="414" height="716"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="9qj-5c-Sfb">
<rect key="frame" x="317" y="5" width="50" height="35"/>
<rect key="frame" x="356" y="5" width="50" height="35"/>
<accessibility key="accessibilityConfiguration" identifier="AuthenticationVCCancelAuthFallbackButton"/>
<constraints>
<constraint firstAttribute="width" constant="50" id="GMq-PF-fBv"/>
@@ -408,7 +408,7 @@
</connections>
</button>
<webView contentMode="scaleToFill" scalesPageToFit="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Vhh-m0-nXN" userLabel="fallback WebView" customClass="MXKAuthenticationFallbackWebView">
<rect key="frame" x="0.0" y="40" width="375" height="607"/>
<rect key="frame" x="0.0" y="40" width="414" height="676"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="accessibilityIdentifier" value="AuthenticationVCFallbackWebView"/>
@@ -448,7 +448,7 @@
</view>
</objects>
<resources>
<image name="logo.png" width="120" height="99"/>
<image name="logo.png" width="120" height="101"/>
<image name="selection_untick.png" width="22" height="22"/>
</resources>
</document>

View File

@@ -90,6 +90,11 @@
_sendButton.enabled = NO;
}
[_cancelButton setTitle:[NSBundle mxk_localizedStringForKey:@"cancel"] forState:UIControlStateNormal];
[_cancelButton setTitle:[NSBundle mxk_localizedStringForKey:@"cancel"] forState:UIControlStateHighlighted];
[_sendButton setTitle:NSLocalizedStringFromTable(@"bug_report_send", @"Vector", nil) forState:UIControlStateNormal];
[_sendButton setTitle:NSLocalizedStringFromTable(@"bug_report_send", @"Vector", nil) forState:UIControlStateHighlighted];
_sendingContainer.hidden = YES;
self.sendLogs = YES;
@@ -127,6 +132,8 @@
{
[super viewWillDisappear:animated];
[self dismissKeyboard];
if (screenShotFile)
{
[[NSFileManager defaultManager] removeItemAtURL:screenShotFile error:nil];
@@ -161,6 +168,12 @@
}
#pragma mark - MXKViewController
- (void)dismissKeyboard
{
// Hide the keyboard
[_bugReportDescriptionTextView resignFirstResponder];
}
- (void)onKeyboardShowAnimationComplete
{
self.keyboardView = _bugReportDescriptionTextView.inputAccessoryView.superview;

View File

@@ -1,11 +1,11 @@
<?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">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12121" systemVersion="16F73" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina5_5" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12088"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@@ -102,7 +102,7 @@
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="252" verticalHuggingPriority="251" image="imageView:hcc-ve-8OC:image" translatesAutoresizingMaskIntoConstraints="NO" id="hcc-ve-8OC">
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="252" verticalHuggingPriority="251" image="selection_tick.png" translatesAutoresizingMaskIntoConstraints="NO" id="hcc-ve-8OC">
<rect key="frame" x="20" y="1" width="22" height="22"/>
</imageView>
</subviews>
@@ -125,7 +125,7 @@
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="252" verticalHuggingPriority="251" image="imageView:hcc-ve-8OC:image" translatesAutoresizingMaskIntoConstraints="NO" id="wmW-9T-6xp">
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="252" verticalHuggingPriority="251" image="selection_tick.png" translatesAutoresizingMaskIntoConstraints="NO" id="wmW-9T-6xp">
<rect key="frame" x="20" y="1" width="22" height="21.999999999999943"/>
</imageView>
</subviews>
@@ -243,88 +243,6 @@
</view>
</objects>
<resources>
<image name="imageView:hcc-ve-8OC:image" width="22" height="22">
<mutableData key="keyedArchiveRepresentation">
YnBsaXN0MDDUAQIDBAUGPT5YJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoK4HCBMU
GR4fIyQrLjE3OlUkbnVsbNUJCgsMDQ4PEBESVk5TU2l6ZVYkY2xhc3NcTlNJbWFnZUZsYWdzVk5TUmVw
c1dOU0NvbG9ygAKADRIgwAAAgAOAC1h7MjIsIDIyfdIVChYYWk5TLm9iamVjdHOhF4AEgArSFQoaHaIb
HIAFgAaACRAA0iAKISJfEBROU1RJRkZSZXByZXNlbnRhdGlvboAHgAhPERAuTU0AKgAAB5gAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAADiEXLCliRX8/mGnGTbh97E22fuw/mGnGKWJFfw4hFywAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASLR87OIlfr1C+hPJWzY//VcmM
/1TIi/9UyIv/VcmM/1bNj/9QvoTyOIlfrxItHzsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAEEAgYoYkR/UcKH9ljPkP9VyYv/VMaK/1TGiv9Uxor/VMaK/1TGiv9Uxor/VcmL/1jPkP9Rwof2KGJE
fwEEAgYAAAAAAAAAAAAAAAAAAAAAAAAAAAEEAgYyeFOcV8+Q/1XJjP9Uxor/VMaK/1TGiv9Uxor/VMaK
/1TGiv9Uxor/VMaK/1TGiv9Uxor/VcmM/1fPkP8yeFOcAQQCBgAAAAAAAAAAAAAAAAAAAAAoYkR/V8+Q
/1TIi/9Uxor/VMaK/1TGiv9Uxor/VMaK/1TGiv9Uxor/VMaK/1TGiv9Uxor/VMaK/1TGiv9UyIv/V8+Q
/yhiRH8AAAAAAAAAAAAAAAASLR46UsOH91XJjP9Uxor/VMaK/1TGiv9Uxor/VMaK/1TGiv9Uxor/VMaK
/1TGiv9Uxor/VMaK/1TGiv9Uxor/VMaK/1XJjP9Sw4f3Ei0eOgAAAAABAgIEOYlfslfPkP9Uxor/VMaK
/1TGiv9Uxor/VMaK/1TGiv9Uxor/VMaK/1TGiv9Uxor/VMaK/1PGif9Uxor/UsWJ/1TGiv9Uxor/V8+Q
/zmJX7IBAgIEDSAWK1C/hfRVyYv/VMaK/1TGiv9Uxor/VMaK/1TGiv9Uxor/VMaK/1TGiv9Uxor/VMaK
/1LFif9XyIz/uenQ/5XfuP9Txon/VMaK/1XJi/9Qv4X0DSAWKyhiRX9WzY//VMaK/1TGiv9Uxor/VMaK
/1TGiv9Uxor/VMaK/1TGiv9Uxor/VMaK/1LFif9Xxoz/vOrT///////i9uz/X8uS/1PGif9Uxor/Vs2P
/yhiRX8/mGnGVcmM/1TGiv9Uxor/VMaK/1TGiv9Uxor/U8aJ/1TGiv9Uxor/VMaK/1LFif9XyIz/vOrT
///////p+PH/ctKg/1HFiP9Uxor/VMaK/1XJjP8/mGnGTrd+7VTIiv9Uxor/VMaK/1TGiv9Uxor/U8aK
/1nJj/9RxYn/VMaK/1LFif9XyIz/vOrT///////p+PD/cdGf/0/Eh/9Uxor/VMaK/1TGiv9UyIr/Trd+
7U22fuxUyIr/VMaK/1TGiv9Uxor/U8aJ/57hv//X8+X/Zs2X/07Ehv9XyIz/wOvV///////n+O//b8+e
/0/Eh/9Uxor/VMaK/1TGiv9Uxor/VMiK/022fuw/mmnGVcmM/1TGiv9Uxor/U8aK/1fIjP/K79z/////
/9nz5v9s0Jz/uurR///////m9+//b9Ge/0/Eh/9Uxor/VMaK/1TGiv9Uxor/VMaK/1XJjP8/mmnGKGJF
f1bNj/9Uxor/VMaK/1TGiv9SxYn/X8qT/8zw3///////9fv3///////n+O//b9Ge/0/Eh/9Uxor/VMaK
/1TGiv9Uxor/VMaK/1TGiv9WzY//KGJFfw0gFitQv4X0VcmL/1TGiv9Uxor/VMaK/1HFiP9eypL/zPDf
///////o+PD/b9Ge/0/Eh/9Uxor/VMaK/1TGiv9Uxor/VMaK/1TGiv9VyYv/UL+F9A0gFisBAgIEOohf
sVfPkP9Uxor/VMaK/1TGiv9Uxor/UcWI/2DLk/+76tH/ddOj/0/Fh/9Uxor/VMaK/1TGiv9Uxor/VMaK
/1TGiv9Uxor/V8+Q/zqIX7EBAgIEAAAAABItHjpSw4f3VcmM/1TGiv9Uxor/VMaK/1TGiv9SxYn/UsWI
/1LFiP9Uxor/VMaK/1TGiv9Uxor/VMaK/1TGiv9Uxor/VcmM/1LDh/cSLR46AAAAAAAAAAAAAAAAKGJE
f1fPkP9UyIv/VMaK/1TGiv9Uxor/VMaK/1TGiv9Uxor/VMaK/1TGiv9Uxor/VMaK/1TGiv9Uxor/VMiL
/1fPkP8oYkR/AAAAAAAAAAAAAAAAAAAAAAEEAgYyeFOcV8+Q/1XJjP9Uxor/VMaK/1TGiv9Uxor/VMaK
/1TGiv9Uxor/VMaK/1TGiv9Uxor/VcmM/1fPkP8yeFOcAQQCBgAAAAAAAAAAAAAAAAAAAAAAAAAAAQQC
BihiRH9Rwof2WM+Q/1XJi/9Uxor/VMaK/1TGiv9Uxor/VMaK/1TGiv9VyYv/WM+Q/1HCh/YoYkR/AQQC
BgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEi0fOzqJX69Qv4TzVs2P/1XJjP9UyIv/VMiL
/1XJjP9WzY//UL+E8zqJX68SLR87AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAADiEXLCliRX8/mGnGTbh97E24few/mGnGKWJFfw4hFywAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAA4BAAADAAAAAQAWAAABAQADAAAAAQAWAAABAgADAAAABAAACEYBAwADAAAAAQABAAAB
BgADAAAAAQACAAABEQAEAAAAAQAAAAgBEgADAAAAAQABAAABFQADAAAAAQAEAAABFgADAAAAAQAWAAAB
FwAEAAAAAQAAB5ABHAADAAAAAQABAAABUgADAAAAAQABAAABUwADAAAABAAACE6HcwAHAAAH2AAACFYA
AAAAAAgACAAIAAgAAQABAAEAAQAAB9hhcHBsAiAAAG1udHJSR0IgWFlaIAfZAAIAGQALABoAC2Fjc3BB
UFBMAAAAAGFwcGwAAAAAAAAAAAAAAAAAAAAAAAD21gABAAAAANMtYXBwbAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC2Rlc2MAAAEIAAAAb2RzY20AAAF4AAAFnGNwcnQA
AAcUAAAAOHd0cHQAAAdMAAAAFHJYWVoAAAdgAAAAFGdYWVoAAAd0AAAAFGJYWVoAAAeIAAAAFHJUUkMA
AAecAAAADmNoYWQAAAesAAAALGJUUkMAAAecAAAADmdUUkMAAAecAAAADmRlc2MAAAAAAAAAFEdlbmVy
aWMgUkdCIFByb2ZpbGUAAAAAAAAAAAAAABRHZW5lcmljIFJHQiBQcm9maWxlAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABtbHVjAAAAAAAAAB8AAAAMc2tTSwAAACgA
AAGEZGFESwAAAC4AAAGsY2FFUwAAACQAAAHadmlWTgAAACQAAAH+cHRCUgAAACYAAAIidWtVQQAAACoA
AAJIZnJGVQAAACgAAAJyaHVIVQAAACgAAAKaemhUVwAAABYAAALCbmJOTwAAACYAAALYY3NDWgAAACIA
AAL+aGVJTAAAAB4AAAMgaXRJVAAAACgAAAM+cm9STwAAACQAAANmZGVERQAAACwAAAOKa29LUgAAABYA
AAO2c3ZTRQAAACYAAALYemhDTgAAABYAAAPMamFKUAAAABoAAAPiZWxHUgAAACIAAAP8cHRQTwAAACYA
AAQebmxOTAAAACgAAAREZXNFUwAAACYAAAQedGhUSAAAACQAAARsdHJUUgAAACIAAASQZmlGSQAAACgA
AASyaHJIUgAAACgAAATacGxQTAAAACwAAAUCcnVSVQAAACIAAAUuYXJFRwAAACYAAAVQZW5VUwAAACYA
AAV2AFYBYQBlAG8AYgBlAGMAbgD9ACAAUgBHAEIAIABwAHIAbwBmAGkAbABHAGUAbgBlAHIAZQBsACAA
UgBHAEIALQBiAGUAcwBrAHIAaQB2AGUAbABzAGUAUABlAHIAZgBpAGwAIABSAEcAQgAgAGcAZQBuAOgA
cgBpAGMAQx6lAHUAIABoAOwAbgBoACAAUgBHAEIAIABDAGgAdQBuAGcAUABlAHIAZgBpAGwAIABSAEcA
QgAgAEcAZQBuAOkAcgBpAGMAbwQXBDAEMwQwBDsETAQ9BDgEOQAgBD8EQAQ+BEQEMAQ5BDsAIABSAEcA
QgBQAHIAbwBmAGkAbAAgAGcA6QBuAOkAcgBpAHEAdQBlACAAUgBWAEIAwQBsAHQAYQBsAOEAbgBvAHMA
IABSAEcAQgAgAHAAcgBvAGYAaQBskBp1KAAgAFIARwBCACCCcl9pY8+P8ABHAGUAbgBlAHIAaQBzAGsA
IABSAEcAQgAtAHAAcgBvAGYAaQBsAE8AYgBlAGMAbgD9ACAAUgBHAEIAIABwAHIAbwBmAGkAbAXkBegF
1QXkBdkF3AAgAFIARwBCACAF2wXcBdwF2QBQAHIAbwBmAGkAbABvACAAUgBHAEIAIABnAGUAbgBlAHIA
aQBjAG8AUAByAG8AZgBpAGwAIABSAEcAQgAgAGcAZQBuAGUAcgBpAGMAQQBsAGwAZwBlAG0AZQBpAG4A
ZQBzACAAUgBHAEIALQBQAHIAbwBmAGkAbMd8vBgAIABSAEcAQgAg1QS4XNMMx3xmbpAaACAAUgBHAEIA
IGPPj/Blh072TgCCLAAgAFIARwBCACAw1zDtMNUwoTCkMOsDkwO1A70DuQO6A8wAIAPAA8EDvwPGA68D
uwAgAFIARwBCAFAAZQByAGYAaQBsACAAUgBHAEIAIABnAGUAbgDpAHIAaQBjAG8AQQBsAGcAZQBtAGUA
ZQBuACAAUgBHAEIALQBwAHIAbwBmAGkAZQBsDkIOGw4jDkQOHw4lDkwAIABSAEcAQgAgDhcOMQ5IDicO
RA4bAEcAZQBuAGUAbAAgAFIARwBCACAAUAByAG8AZgBpAGwAaQBZAGwAZQBpAG4AZQBuACAAUgBHAEIA
LQBwAHIAbwBmAGkAaQBsAGkARwBlAG4AZQByAGkBDQBrAGkAIABSAEcAQgAgAHAAcgBvAGYAaQBsAFUA
bgBpAHcAZQByAHMAYQBsAG4AeQAgAHAAcgBvAGYAaQBsACAAUgBHAEIEHgQxBEkEOAQ5ACAEPwRABD4E
RAQ4BDsETAAgAFIARwBCBkUGRAZBACAGKgY5BjEGSgZBACAAUgBHAEIAIAYnBkQGOQYnBkUARwBlAG4A
ZQByAGkAYwAgAFIARwBCACAAUAByAG8AZgBpAGwAZXRleHQAAAAAQ29weXJpZ2h0IDIwMDcgQXBwbGUg
SW5jLiwgYWxsIHJpZ2h0cyByZXNlcnZlZC4AWFlaIAAAAAAAAPNSAAEAAAABFs9YWVogAAAAAAAAdE0A
AD3uAAAD0FhZWiAAAAAAAABadQAArHMAABc0WFlaIAAAAAAAACgaAAAVnwAAuDZjdXJ2AAAAAAAAAAEB
zQAAc2YzMgAAAAAAAQxCAAAF3v//8yYAAAeSAAD9kf//+6L///2jAAAD3AAAwGzSJSYnKFokY2xhc3Nu
YW1lWCRjbGFzc2VzXxAQTlNCaXRtYXBJbWFnZVJlcKMnKSpaTlNJbWFnZVJlcFhOU09iamVjdNIlJiwt
V05TQXJyYXmiLCrSJSYvMF5OU011dGFibGVBcnJheaMvLCrTMjMKNDU2V05TV2hpdGVcTlNDb2xvclNw
YWNlRDAgMAAQA4AM0iUmODlXTlNDb2xvcqI4KtIlJjs8V05TSW1hZ2WiOypfEA9OU0tleWVkQXJjaGl2
ZXLRP0BUcm9vdIABAAgAEQAaACMALQAyADcARgBMAFcAXgBlAHIAeQCBAIMAhQCKAIwAjgCXAJwApwCp
AKsArQCyALUAtwC5ALsAvQDCANkA2wDdEQ8RFBEfESgROxE/EUoRUxFYEWARYxFoEXcRexGCEYoRlxGc
EZ4RoBGlEa0RsBG1Eb0RwBHSEdUR2gAAAAAAAAIBAAAAAAAAAEEAAAAAAAAAAAAAAAAAABHcA
</mutableData>
</image>
<image name="selection_tick.png" width="22" height="22"/>
</resources>
</document>

View File

@@ -40,37 +40,6 @@
@implementation CallViewController
#pragma mark - Class methods
+ (UINib *)nib
{
return [UINib nibWithNibName:NSStringFromClass(self.class)
bundle:[NSBundle bundleForClass:self.class]];
}
+ (instancetype)callViewController:(MXCall*)call
{
CallViewController* instance = [[[self class] alloc] initWithNibName:NSStringFromClass(self.class)
bundle:[NSBundle bundleForClass:self.class]];
// Load the view controller's view now (buttons and views will then be available).
if ([instance respondsToSelector:@selector(loadViewIfNeeded)])
{
// iOS 9 and later
[instance loadViewIfNeeded];
}
else if (instance.view)
{
// Patch: on iOS < 9.0, we load the view by calling its getter.
}
instance.mxCall = call;
return instance;
}
#pragma mark -
- (void)finalizeInit
{
[super finalizeInit];

View File

@@ -230,19 +230,7 @@
if (roomsAdded)
{
// Notify the table view there are new items at its tail
NSMutableArray<NSIndexPath *> *indexPaths = [NSMutableArray arrayWithCapacity:roomsAdded];
NSUInteger numberOfRowsBefore = [self->dataSource tableView:self.tableView numberOfRowsInSection:0];
numberOfRowsBefore -= roomsAdded;
for (NSUInteger i = 0; i < roomsAdded; i++)
{
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:(numberOfRowsBefore + i) inSection:0];
[indexPaths addObject:indexPath];
}
[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView reloadData];
}
[self removeSpinnerFooterView];

View File

@@ -240,9 +240,11 @@
{
if (self.delegate)
{
id<MXKRecentCellDataStoring> cellData = [recentsDataSource cellDataAtIndexPath:[NSIndexPath indexPathForRow:indexPath.item inSection:collectionView.tag]];
RoomCollectionViewCell *roomCollectionViewCell = (RoomCollectionViewCell*)[collectionView cellForItemAtIndexPath:indexPath];
[self.delegate recentListViewController:self didSelectRoom:cellData.roomSummary.roomId inMatrixSession:cellData.roomSummary.room.mxSession];
id<MXKRecentCellDataStoring> renderedCellData = (id<MXKRecentCellDataStoring>)roomCollectionViewCell.renderedCellData;
[self.delegate recentListViewController:self didSelectRoom:renderedCellData.roomSummary.roomId inMatrixSession:renderedCellData.roomSummary.room.mxSession];
}
// Hide the keyboard when user select a room

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,177 @@
/*
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;
@property (weak, nonatomic) IBOutlet UIButton *closeButton;
@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);
[_closeButton setTitle:[NSBundle mxk_localizedStringForKey:@"close"] forState:UIControlStateNormal];
[_closeButton setTitle:[NSBundle mxk_localizedStringForKey:@"close"] forState:UIControlStateHighlighted];
}
- (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];
}
- (IBAction)onCloseButtonPress:(id)sender
{
[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,98 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12121" systemVersion="16F73" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
<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="closeButton" destination="np9-sm-bvz" id="6Na-H8-nmE"/>
<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="460"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</tableView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="np9-sm-bvz">
<rect key="frame" x="296" y="510" width="39" height="30"/>
<state key="normal" title="Close"/>
<connections>
<action selector="onCloseButtonPress:" destination="-1" eventType="touchUpInside" id="3LU-e2-3qZ"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="9qg-nd-kFU" secondAttribute="bottom" constant="50" 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="bottom" secondItem="np9-sm-bvz" secondAttribute="bottom" constant="10" id="fYr-Lb-UtL"/>
<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 firstAttribute="trailing" secondItem="np9-sm-bvz" secondAttribute="trailing" constant="20" symbolic="YES" id="pEK-YF-c4b"/>
<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="40" 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="40" 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

@@ -327,10 +327,10 @@
[self prepareStickyHeaders];
// In case of split view controller where the primary and secondary view controllers are displayed side-by-side on screen,
// the selected room (if any) is updated and kept visible.
// the selected room (if any) is updated.
if (!self.splitViewController.isCollapsed)
{
[self refreshCurrentSelectedCell:YES];
[self refreshCurrentSelectedCell:NO];
}
}
@@ -1662,10 +1662,27 @@
- (void)scrollToTheTopTheNextRoomWithMissedNotificationsInSection:(NSInteger)section
{
UITableViewCell *firstVisibleCell = self.recentsTableView.visibleCells.firstObject;
UITableViewCell *firstVisibleCell;
NSIndexPath *firstVisibleCellIndexPath;
UIView *firstSectionHeader = displayedSectionHeaders.firstObject;
if (firstSectionHeader && firstSectionHeader.frame.origin.y <= self.recentsTableView.contentOffset.y)
{
// Compute the height of the hidden part of the section header.
CGFloat hiddenPart = self.recentsTableView.contentOffset.y - firstSectionHeader.frame.origin.y;
CGFloat firstVisibleCellPosY = self.recentsTableView.contentOffset.y + (firstSectionHeader.frame.size.height - hiddenPart);
firstVisibleCellIndexPath = [self.recentsTableView indexPathForRowAtPoint:CGPointMake(0, firstVisibleCellPosY)];
firstVisibleCell = [self.recentsTableView cellForRowAtIndexPath:firstVisibleCellIndexPath];
}
else
{
firstVisibleCell = self.recentsTableView.visibleCells.firstObject;
firstVisibleCellIndexPath = [self.recentsTableView indexPathForCell:firstVisibleCell];
}
if (firstVisibleCell)
{
NSIndexPath *firstVisibleCellIndexPath = [self.recentsTableView indexPathForCell:firstVisibleCell];
NSInteger nextCellRow = (firstVisibleCellIndexPath.section == section) ? firstVisibleCellIndexPath.row + 1 : 0;
// Look for the next room with missed notifications.

View File

@@ -601,7 +601,7 @@
// Add a plus icon to the contact cell in the contacts picker, in order to make it more understandable for the end user.
contactsDataSource.contactCellAccessoryImage = [UIImage imageNamed:@"plus_icon"];
// List all the participants by their matrix user id, or a room 3pid invite token to ignore them during the contacts search.
// List all the participants matrix user id to ignore them during the contacts search.
for (Contact *contact in actualParticipants)
{
[contactsDataSource.ignoredContactsByMatrixId setObject:contact forKey:contact.mxMember.userId];
@@ -612,10 +612,6 @@
{
[contactsDataSource.ignoredContactsByMatrixId setObject:contact forKey:contact.mxMember.userId];
}
else if (contact.mxThirdPartyInvite)
{
[contactsDataSource.ignoredContactsByMatrixId setObject:contact forKey:contact.mxThirdPartyInvite.token];
}
}
if (userParticipant)
{
@@ -905,7 +901,7 @@
- (void)pushViewController:(UIViewController*)viewController
{
// Check whether the view controller is displayed inside a segmented one.
if (self.parentViewController)
if (self.parentViewController.navigationController)
{
// Hide back button title
self.parentViewController.navigationItem.backBarButtonItem =[[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil];

View File

@@ -23,9 +23,11 @@
#import "RoomParticipantsViewController.h"
#import "ContactsTableViewController.h"
#import "UIViewController+RiotSearch.h"
@interface RoomViewController : MXKRoomViewController <UISearchBarDelegate, UIGestureRecognizerDelegate, RoomTitleViewTapGestureDelegate, RoomParticipantsViewControllerDelegate, MXKRoomMemberDetailsViewControllerDelegate>
@interface RoomViewController : MXKRoomViewController <UISearchBarDelegate, UIGestureRecognizerDelegate, RoomTitleViewTapGestureDelegate, RoomParticipantsViewControllerDelegate, MXKRoomMemberDetailsViewControllerDelegate, ContactsTableViewControllerDelegate>
// The expanded header
@property (weak, nonatomic) IBOutlet UIView *expandedHeaderContainer;

View File

@@ -45,6 +45,8 @@
#import "UsersDevicesViewController.h"
#import "ReadReceiptsViewController.h"
#import "RoomEmptyBubbleCell.h"
#import "RoomIncomingTextMsgBubbleCell.h"
@@ -162,6 +164,9 @@
// Tell whether the view controller is appeared or not.
BOOL isAppeared;
// The search bar buttom item back up.
UIBarButtonItem *searchBarButtonItem;
}
@end
@@ -853,6 +858,14 @@
{
[self showExpandedHeader:NO];
// Force a simple title view initialised with the current room before leaving actually the room.
[self setRoomTitleViewClass:SimpleRoomTitleView.class];
self.titleView.editable = NO;
self.titleView.mxRoom = self.roomDataSource.room;
// Hide the potential read marker banner.
self.jumpToLastUnreadBannerContainer.hidden = YES;
[super leaveRoomOnEvent:event];
}
@@ -906,7 +919,7 @@
} failure:^(NSError *error) {
NSLog(@"[Vector RoomVC] Join roomAlias (%@) failed", roomAlias);
NSLog(@"[RoomVC] Join roomAlias (%@) failed", roomAlias);
//Alert user
[[AppDelegate theDelegate] showErrorAsAlert:error];
@@ -961,15 +974,20 @@
{
[super setBubbleTableViewDisplayInTransition:bubbleTableViewDisplayInTransition];
// Refresh additional displays when the table is ready.
if (!bubbleTableViewDisplayInTransition && !self.bubblesTableView.isHidden)
{
[self refreshActivitiesViewDisplay];
[self checkReadMarkerVisibility];
[self refreshJumpToLastUnreadBannerDisplay];
}
}
}
- (void)destroy
{
searchBarButtonItem = nil;
self.navigationItem.rightBarButtonItem.enabled = NO;
if (currentAlert)
@@ -1007,7 +1025,7 @@
if (previewHeader || (self.expandedHeaderContainer.isHidden == NO))
{
// Here [destroy] is called before [viewWillDisappear:]
NSLog(@"[Vector RoomVC] destroyed whereas it is still visible");
NSLog(@"[RoomVC] destroyed whereas it is still visible");
[previewHeader removeFromSuperview];
previewHeader = nil;
@@ -1067,6 +1085,12 @@
- (void)refreshRoomTitle
{
if (searchBarButtonItem && !self.navigationItem.rightBarButtonItem)
{
// Restore by default the search bar button.
self.navigationItem.rightBarButtonItem = searchBarButtonItem;
}
// Set the right room title view
if (self.isRoomPreview)
{
@@ -1101,7 +1125,8 @@
}
else
{
// Hide the search button
// Remove the search button temporarily
searchBarButtonItem = self.navigationItem.rightBarButtonItem;
self.navigationItem.rightBarButtonItem = nil;
[self setRoomTitleViewClass:SimpleRoomTitleView.class];
@@ -1198,7 +1223,7 @@
// - if the event details view is displayed
if (isVisible && (isSizeTransitionInProgress == YES || !self.roomDataSource || !self.roomDataSource.isLive || (self.roomDataSource.room.state.membership != MXMembershipJoin) || !self.splitViewController || encryptionInfoView.superview || eventDetailsView.superview))
{
NSLog(@"[Vector RoomVC] Show expanded header ignored");
NSLog(@"[RoomVC] Show expanded header ignored");
return;
}
@@ -1279,7 +1304,7 @@
// or if the view controller is not embedded inside a split view controller yet.
if (isVisible && (isSizeTransitionInProgress == YES || !self.splitViewController))
{
NSLog(@"[Vector RoomVC] Show preview header ignored");
NSLog(@"[RoomVC] Show preview header ignored");
return;
}
@@ -1686,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
@@ -1984,7 +2014,7 @@
__strong __typeof(weakSelf)strongSelf = weakSelf;
[strongSelf stopActivityIndicator];
NSLog(@"[Vector RoomVC] Redact event (%@) failed", selectedEvent.eventId);
NSLog(@"[RoomVC] Redact event (%@) failed", selectedEvent.eventId);
//Alert user
[[AppDelegate theDelegate] showErrorAsAlert:error];
@@ -2071,7 +2101,7 @@
__strong __typeof(weakSelf)strongSelf = weakSelf;
[strongSelf stopActivityIndicator];
NSLog(@"[Vector RoomVC] Ignore user (%@) failed", selectedEvent.sender);
NSLog(@"[RoomVC] Ignore user (%@) failed", selectedEvent.sender);
//Alert user
[[AppDelegate theDelegate] showErrorAsAlert:error];
@@ -2093,7 +2123,7 @@
__strong __typeof(weakSelf)strongSelf = weakSelf;
[strongSelf stopActivityIndicator];
NSLog(@"[Vector RoomVC] Report event (%@) failed", selectedEvent.eventId);
NSLog(@"[RoomVC] Report event (%@) failed", selectedEvent.eventId);
//Alert user
[[AppDelegate theDelegate] showErrorAsAlert:error];
@@ -2351,6 +2381,46 @@
unknownDevices = nil;
}
}
else if ([[segue identifier] isEqualToString:@"showContactPicker"])
{
ContactsTableViewController *contactsPickerViewController = (ContactsTableViewController*)pushedViewController;
// Set delegate to handle selected contact
contactsPickerViewController.contactsTableViewControllerDelegate = self;
// Prepare its data source
ContactsDataSource *contactsDataSource = [[ContactsDataSource alloc] init];
contactsDataSource.areSectionsShrinkable = YES;
contactsDataSource.displaySearchInputInContactsList = YES;
contactsDataSource.forceMatrixIdInDisplayName = YES;
// Add a plus icon to the contact cell in the contacts picker, in order to make it more understandable for the end user.
contactsDataSource.contactCellAccessoryImage = [UIImage imageNamed:@"plus_icon"];
// List all the participants matrix user id to ignore them during the contacts search.
MXSession* session = self.roomDataSource.mxSession;
NSString* roomId = self.roomDataSource.roomId;
MXRoom *room = [session roomWithRoomId:roomId];
if (room)
{
NSArray *members = [room.state membersWithoutConferenceUser];
for (MXRoomMember *mxMember in members)
{
// Check his status
if (mxMember.membership == MXMembershipJoin || mxMember.membership == MXMembershipInvite)
{
// Create the contact related to this member
MXKContact *contact = [[MXKContact alloc] initMatrixContactWithDisplayName:mxMember.displayname andMatrixID:mxMember.userId];
[contactsDataSource.ignoredContactsByMatrixId setObject:contact forKey:mxMember.userId];
}
}
}
[contactsPickerViewController showSearch:YES];
contactsPickerViewController.searchBar.placeholder = NSLocalizedStringFromTable(@"room_participants_invite_another_user", @"Vector", nil);
[contactsPickerViewController displayList:contactsDataSource];
}
// Hide back button title
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil];
@@ -2560,6 +2630,16 @@
[super scrollViewDidScroll:scrollView];
[self checkReadMarkerVisibility];
// Switch back to the live mode when the user scrolls to the bottom of the non live timeline.
if (!self.roomDataSource.isLive && ![self isRoomPreview])
{
CGFloat contentBottomPosY = self.bubblesTableView.contentOffset.y + self.bubblesTableView.frame.size.height - self.bubblesTableView.contentInset.bottom;
if (contentBottomPosY >= self.bubblesTableView.contentSize.height && ![self.roomDataSource.timeline canPaginate:MXTimelineDirectionForwards])
{
[self goBackToLive];
}
}
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
@@ -2722,6 +2802,11 @@
selectedRoomDetailsIndex = 0;
[self performSegueWithIdentifier:@"showRoomDetails" sender:self];
}
else if (tappedView == titleView.addParticipantMask)
{
// Open contact picker
[self performSegueWithIdentifier:@"showContactPicker" sender:self];
}
else if (tappedView == previewHeader.rightButton)
{
// 'Join' button has been pressed
@@ -2810,7 +2895,7 @@
} failure:^(NSError *error) {
[self stopActivityIndicator];
NSLog(@"[Vector RoomVC] Failed to reject an invited room (%@) failed", self.roomDataSource.room.state.roomId);
NSLog(@"[RoomVC] Failed to reject an invited room (%@) failed", self.roomDataSource.room.state.roomId);
}];
}
@@ -3011,7 +3096,7 @@
{
[roomActivitiesView displayOngoingConferenceCall:^(BOOL video) {
NSLog(@"[Vector RoomVC] onOngoingConferenceCallPressed");
NSLog(@"[RoomVC] onOngoingConferenceCallPressed");
// Make sure there is not yet a call
if (![customizedRoomDataSource.mxSession.callManager callInRoom:customizedRoomDataSource.roomId])
@@ -3025,7 +3110,8 @@
{
// Show "scroll to bottom" icon when the most recent message is not visible,
// or when the timelime is not live (this icon is used to go back to live).
if (!self.roomDataSource.isLive || (!self.bubblesTableView.isHidden && [self isBubblesTableScrollViewAtTheBottom] == NO))
// Note: we check if `currentEventIdAtTableBottom` is set to know whether the table has been rendered at least once.
if (!self.roomDataSource.isLive || (currentEventIdAtTableBottom && [self isBubblesTableScrollViewAtTheBottom] == NO))
{
// Retrieve the unread messages count
NSUInteger unreadCount = self.roomDataSource.room.summary.localUnreadEventCount;
@@ -3039,6 +3125,26 @@
[roomActivitiesView displayScrollToBottomIcon:unreadCount onIconTapGesture:^{
[self goBackToLive];
}];
}
else
{
[self refreshTypingNotification];
}
}
// Recognize swipe downward to dismiss keyboard if any
UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(onSwipeGesture:)];
[swipe setNumberOfTouchesRequired:1];
[swipe setDirection:UISwipeGestureRecognizerDirectionDown];
[roomActivitiesView addGestureRecognizer:swipe];
}
}
- (void)goBackToLive
{
if (self.roomDataSource.isLive)
{
// Enable the read marker display, and disable its update (in order to not mark as read all the new messages by default).
@@ -3070,21 +3176,6 @@
self.inputToolbarView.textMessage = roomDataSource.partialTextMessage;
}
}
}];
}
else
{
[self refreshTypingNotification];
}
}
// Recognize swipe downward to dismiss keyboard if any
UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(onSwipeGesture:)];
[swipe setNumberOfTouchesRequired:1];
[swipe setDirection:UISwipeGestureRecognizerDirectionDown];
[roomActivitiesView addGestureRecognizer:swipe];
}
}
#pragma mark - Missed discussions handling
@@ -3606,5 +3697,127 @@
}
}
#pragma mark - ContactsTableViewControllerDelegate
- (void)contactsTableViewController:(ContactsTableViewController *)contactsTableViewController didSelectContact:(MXKContact*)contact
{
__weak typeof(self) weakSelf = self;
if (currentAlert)
{
[currentAlert dismiss:NO];
currentAlert = nil;
}
// Invite ?
NSString *promptMsg = [NSString stringWithFormat:NSLocalizedStringFromTable(@"room_participants_invite_prompt_msg", @"Vector", nil), contact.displayName];
currentAlert = [[MXKAlert alloc] initWithTitle:NSLocalizedStringFromTable(@"room_participants_invite_prompt_title", @"Vector", nil)
message:promptMsg
style:MXKAlertStyleAlert];
currentAlert.cancelButtonIndex = [currentAlert addActionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"]
style:MXKAlertActionStyleCancel
handler:^(MXKAlert *alert) {
if (weakSelf)
{
__strong __typeof(weakSelf)strongSelf = weakSelf;
strongSelf->currentAlert = nil;
}
}];
[currentAlert addActionWithTitle:NSLocalizedStringFromTable(@"invite", @"Vector", nil)
style:MXKAlertActionStyleDefault
handler:^(MXKAlert *alert) {
// Sanity check
if (!weakSelf)
{
return;
}
__strong __typeof(weakSelf)strongSelf = weakSelf;
strongSelf->currentAlert = nil;
MXSession* session = strongSelf.roomDataSource.mxSession;
NSString* roomId = strongSelf.roomDataSource.roomId;
MXRoom *room = [session roomWithRoomId:roomId];
NSArray *identifiers = contact.matrixIdentifiers;
NSString *participantId;
if (identifiers.count)
{
participantId = identifiers.firstObject;
// Invite this user if a room is defined
[room inviteUser:participantId success:^{
// Refresh display by removing the contacts picker
[contactsTableViewController withdrawViewControllerAnimated:YES completion:nil];
} failure:^(NSError *error) {
NSLog(@"[RoomVC] Invite %@ failed", participantId);
// Alert user
[[AppDelegate theDelegate] showErrorAsAlert:error];
}];
}
else
{
if (contact.emailAddresses.count)
{
// This is a local contact, consider the first email by default.
// TODO: Prompt the user to select the right email.
MXKEmail *email = contact.emailAddresses.firstObject;
participantId = email.emailAddress;
}
else
{
// This is the text filled by the user.
participantId = contact.displayName;
}
// Is it an email or a Matrix user ID?
if ([MXTools isEmailAddress:participantId])
{
[room inviteUserByEmail:participantId success:^{
// Refresh display by removing the contacts picker
[contactsTableViewController withdrawViewControllerAnimated:YES completion:nil];
} failure:^(NSError *error) {
NSLog(@"[RoomVC] Invite be email %@ failed", participantId);
// Alert user
[[AppDelegate theDelegate] showErrorAsAlert:error];
}];
}
else //if ([MXTools isMatrixUserIdentifier:participantId])
{
[room inviteUser:participantId success:^{
// Refresh display by removing the contacts picker
[contactsTableViewController withdrawViewControllerAnimated:YES completion:nil];
} failure:^(NSError *error) {
NSLog(@"[RoomVC] Invite %@ failed", participantId);
// Alert user
[[AppDelegate theDelegate] showErrorAsAlert:error];
}];
}
}
}];
currentAlert.mxkAccessibilityIdentifier = @"RoomVCInviteAlert";
[currentAlert showInViewController:self];
}
@end

View File

@@ -209,9 +209,14 @@
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == recentsDataSource.directorySection)
{
// Sanity check
MXPublicRoom *publicRoom = [recentsDataSource.publicRoomsDirectoryDataSource roomAtIndexPath:indexPath];
if (publicRoom)
{
[self openPublicRoomAtIndexPath:indexPath];
}
}
else
{
[super tableView:tableView didSelectRowAtIndexPath:indexPath];
@@ -268,9 +273,12 @@
- (void)triggerDirectoryPagination
{
if (recentsDataSource.publicRoomsDirectoryDataSource.hasReachedPaginationEnd || footerSpinnerView)
if (!recentsDataSource
|| recentsDataSource.state == MXKDataSourceStateUnknown
|| recentsDataSource.publicRoomsDirectoryDataSource.hasReachedPaginationEnd
|| footerSpinnerView)
{
// We got all public rooms or we are already paginating
// We are not yet ready or being killed or we got all public rooms or we are already paginating
// Do nothing
return;
}

View File

@@ -96,6 +96,12 @@ NSString *const kRoomEncryptedDataBubbleCellTapOnEncryptionIcon = @"kRoomEncrypt
{
component = bubbleComponents[componentIndex];
// Ignore components without display.
if (!component.attributedTextMessage)
{
continue;
}
UIImage *icon = [RoomEncryptedDataBubbleCell encryptionIconForEvent:component.event andSession:bubbleData.mxSession];
UIImageView *encryptStatusImageView = [[UIImageView alloc] initWithImage:icon];

View File

@@ -18,6 +18,8 @@
#import "RoomEncryptedDataBubbleCell.h"
#import "RoomBubbleCellData.h"
@implementation RoomIncomingEncryptedTextMsgBubbleCell
- (void)awakeFromNib
@@ -64,15 +66,27 @@
// Check which bubble component is displayed in front of the tapped line.
NSArray *bubbleComponents = bubbleData.bubbleComponents;
// Consider by default the first component
MXKRoomBubbleComponent *tappedComponent = bubbleComponents.firstObject;
// Consider by default the first display component
NSInteger firstComponentIndex = 0;
if ([bubbleData isKindOfClass:RoomBubbleCellData.class])
{
firstComponentIndex = ((RoomBubbleCellData*)bubbleData).oldestComponentIndex;
}
MXKRoomBubbleComponent *tappedComponent = bubbleComponents[firstComponentIndex++];
CGPoint tapPoint = [sender locationInView:self.messageTextView];
for (NSInteger index = 1; index < bubbleComponents.count; index++)
for (NSInteger index = firstComponentIndex; index < bubbleComponents.count; index++)
{
// Here the bubble is composed by multiple text messages
MXKRoomBubbleComponent *component = bubbleComponents[index];
// Ignore components without display.
if (!component.attributedTextMessage)
{
continue;
}
if (tapPoint.y < component.position.y)
{
break;

View File

@@ -18,6 +18,8 @@
#import "RoomEncryptedDataBubbleCell.h"
#import "RoomBubbleCellData.h"
@implementation RoomIncomingEncryptedTextMsgWithPaginationTitleBubbleCell
- (void)awakeFromNib
@@ -64,15 +66,27 @@
// Check which bubble component is displayed in front of the tapped line.
NSArray *bubbleComponents = bubbleData.bubbleComponents;
// Consider by default the first component
MXKRoomBubbleComponent *tappedComponent = bubbleComponents.firstObject;
// Consider by default the first display component
NSInteger firstComponentIndex = 0;
if ([bubbleData isKindOfClass:RoomBubbleCellData.class])
{
firstComponentIndex = ((RoomBubbleCellData*)bubbleData).oldestComponentIndex;
}
MXKRoomBubbleComponent *tappedComponent = bubbleComponents[firstComponentIndex++];
CGPoint tapPoint = [sender locationInView:self.messageTextView];
for (NSInteger index = 1; index < bubbleComponents.count; index++)
for (NSInteger index = firstComponentIndex; index < bubbleComponents.count; index++)
{
// Here the bubble is composed by multiple text messages
MXKRoomBubbleComponent *component = bubbleComponents[index];
// Ignore components without display.
if (!component.attributedTextMessage)
{
continue;
}
if (tapPoint.y < component.position.y)
{
break;

View File

@@ -18,6 +18,8 @@
#import "RoomEncryptedDataBubbleCell.h"
#import "RoomBubbleCellData.h"
@implementation RoomIncomingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell
- (void)awakeFromNib
@@ -64,15 +66,27 @@
// Check which bubble component is displayed in front of the tapped line.
NSArray *bubbleComponents = bubbleData.bubbleComponents;
// Consider by default the first component
MXKRoomBubbleComponent *tappedComponent = bubbleComponents.firstObject;
// Consider by default the first display component
NSInteger firstComponentIndex = 0;
if ([bubbleData isKindOfClass:RoomBubbleCellData.class])
{
firstComponentIndex = ((RoomBubbleCellData*)bubbleData).oldestComponentIndex;
}
MXKRoomBubbleComponent *tappedComponent = bubbleComponents[firstComponentIndex++];
CGPoint tapPoint = [sender locationInView:self.messageTextView];
for (NSInteger index = 1; index < bubbleComponents.count; index++)
for (NSInteger index = firstComponentIndex; index < bubbleComponents.count; index++)
{
// Here the bubble is composed by multiple text messages
MXKRoomBubbleComponent *component = bubbleComponents[index];
// Ignore components without display.
if (!component.attributedTextMessage)
{
continue;
}
if (tapPoint.y < component.position.y)
{
break;

View File

@@ -18,6 +18,8 @@
#import "RoomEncryptedDataBubbleCell.h"
#import "RoomBubbleCellData.h"
@implementation RoomIncomingEncryptedTextMsgWithoutSenderInfoBubbleCell
- (void)awakeFromNib
@@ -64,15 +66,27 @@
// Check which bubble component is displayed in front of the tapped line.
NSArray *bubbleComponents = bubbleData.bubbleComponents;
// Consider by default the first component
MXKRoomBubbleComponent *tappedComponent = bubbleComponents.firstObject;
// Consider by default the first display component
NSInteger firstComponentIndex = 0;
if ([bubbleData isKindOfClass:RoomBubbleCellData.class])
{
firstComponentIndex = ((RoomBubbleCellData*)bubbleData).oldestComponentIndex;
}
MXKRoomBubbleComponent *tappedComponent = bubbleComponents[firstComponentIndex++];
CGPoint tapPoint = [sender locationInView:self.messageTextView];
for (NSInteger index = 1; index < bubbleComponents.count; index++)
for (NSInteger index = firstComponentIndex; index < bubbleComponents.count; index++)
{
// Here the bubble is composed by multiple text messages
MXKRoomBubbleComponent *component = bubbleComponents[index];
// Ignore components without display.
if (!component.attributedTextMessage)
{
continue;
}
if (tapPoint.y < component.position.y)
{
break;

View File

@@ -18,6 +18,8 @@
#import "RoomEncryptedDataBubbleCell.h"
#import "RoomBubbleCellData.h"
@implementation RoomIncomingEncryptedTextMsgWithoutSenderNameBubbleCell
- (void)awakeFromNib
@@ -64,15 +66,27 @@
// Check which bubble component is displayed in front of the tapped line.
NSArray *bubbleComponents = bubbleData.bubbleComponents;
// Consider by default the first component
MXKRoomBubbleComponent *tappedComponent = bubbleComponents.firstObject;
// Consider by default the first display component
NSInteger firstComponentIndex = 0;
if ([bubbleData isKindOfClass:RoomBubbleCellData.class])
{
firstComponentIndex = ((RoomBubbleCellData*)bubbleData).oldestComponentIndex;
}
MXKRoomBubbleComponent *tappedComponent = bubbleComponents[firstComponentIndex++];
CGPoint tapPoint = [sender locationInView:self.messageTextView];
for (NSInteger index = 1; index < bubbleComponents.count; index++)
for (NSInteger index = firstComponentIndex; index < bubbleComponents.count; index++)
{
// Here the bubble is composed by multiple text messages
MXKRoomBubbleComponent *component = bubbleComponents[index];
// Ignore components without display.
if (!component.attributedTextMessage)
{
continue;
}
if (tapPoint.y < component.position.y)
{
break;

View File

@@ -18,6 +18,8 @@
#import "RoomEncryptedDataBubbleCell.h"
#import "RoomBubbleCellData.h"
@implementation RoomOutgoingEncryptedTextMsgBubbleCell
- (void)awakeFromNib
@@ -64,15 +66,27 @@
// Check which bubble component is displayed in front of the tapped line.
NSArray *bubbleComponents = bubbleData.bubbleComponents;
// Consider by default the first component
MXKRoomBubbleComponent *tappedComponent = bubbleComponents.firstObject;
// Consider by default the first display component
NSInteger firstComponentIndex = 0;
if ([bubbleData isKindOfClass:RoomBubbleCellData.class])
{
firstComponentIndex = ((RoomBubbleCellData*)bubbleData).oldestComponentIndex;
}
MXKRoomBubbleComponent *tappedComponent = bubbleComponents[firstComponentIndex++];
CGPoint tapPoint = [sender locationInView:self.messageTextView];
for (NSInteger index = 1; index < bubbleComponents.count; index++)
for (NSInteger index = firstComponentIndex; index < bubbleComponents.count; index++)
{
// Here the bubble is composed by multiple text messages
MXKRoomBubbleComponent *component = bubbleComponents[index];
// Ignore components without display.
if (!component.attributedTextMessage)
{
continue;
}
if (tapPoint.y < component.position.y)
{
break;

View File

@@ -18,6 +18,8 @@
#import "RoomEncryptedDataBubbleCell.h"
#import "RoomBubbleCellData.h"
@implementation RoomOutgoingEncryptedTextMsgWithPaginationTitleBubbleCell
- (void)awakeFromNib
@@ -64,15 +66,27 @@
// Check which bubble component is displayed in front of the tapped line.
NSArray *bubbleComponents = bubbleData.bubbleComponents;
// Consider by default the first component
MXKRoomBubbleComponent *tappedComponent = bubbleComponents.firstObject;
// Consider by default the first display component
NSInteger firstComponentIndex = 0;
if ([bubbleData isKindOfClass:RoomBubbleCellData.class])
{
firstComponentIndex = ((RoomBubbleCellData*)bubbleData).oldestComponentIndex;
}
MXKRoomBubbleComponent *tappedComponent = bubbleComponents[firstComponentIndex++];
CGPoint tapPoint = [sender locationInView:self.messageTextView];
for (NSInteger index = 1; index < bubbleComponents.count; index++)
for (NSInteger index = firstComponentIndex; index < bubbleComponents.count; index++)
{
// Here the bubble is composed by multiple text messages
MXKRoomBubbleComponent *component = bubbleComponents[index];
// Ignore components without display.
if (!component.attributedTextMessage)
{
continue;
}
if (tapPoint.y < component.position.y)
{
break;

View File

@@ -18,6 +18,8 @@
#import "RoomEncryptedDataBubbleCell.h"
#import "RoomBubbleCellData.h"
@implementation RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell
- (void)awakeFromNib
@@ -64,15 +66,27 @@
// Check which bubble component is displayed in front of the tapped line.
NSArray *bubbleComponents = bubbleData.bubbleComponents;
// Consider by default the first component
MXKRoomBubbleComponent *tappedComponent = bubbleComponents.firstObject;
// Consider by default the first display component
NSInteger firstComponentIndex = 0;
if ([bubbleData isKindOfClass:RoomBubbleCellData.class])
{
firstComponentIndex = ((RoomBubbleCellData*)bubbleData).oldestComponentIndex;
}
MXKRoomBubbleComponent *tappedComponent = bubbleComponents[firstComponentIndex++];
CGPoint tapPoint = [sender locationInView:self.messageTextView];
for (NSInteger index = 1; index < bubbleComponents.count; index++)
for (NSInteger index = firstComponentIndex; index < bubbleComponents.count; index++)
{
// Here the bubble is composed by multiple text messages
MXKRoomBubbleComponent *component = bubbleComponents[index];
// Ignore components without display.
if (!component.attributedTextMessage)
{
continue;
}
if (tapPoint.y < component.position.y)
{
break;

View File

@@ -18,6 +18,8 @@
#import "RoomEncryptedDataBubbleCell.h"
#import "RoomBubbleCellData.h"
@implementation RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell
- (void)awakeFromNib
@@ -64,15 +66,27 @@
// Check which bubble component is displayed in front of the tapped line.
NSArray *bubbleComponents = bubbleData.bubbleComponents;
// Consider by default the first component
MXKRoomBubbleComponent *tappedComponent = bubbleComponents.firstObject;
// Consider by default the first display component
NSInteger firstComponentIndex = 0;
if ([bubbleData isKindOfClass:RoomBubbleCellData.class])
{
firstComponentIndex = ((RoomBubbleCellData*)bubbleData).oldestComponentIndex;
}
MXKRoomBubbleComponent *tappedComponent = bubbleComponents[firstComponentIndex++];
CGPoint tapPoint = [sender locationInView:self.messageTextView];
for (NSInteger index = 1; index < bubbleComponents.count; index++)
for (NSInteger index = firstComponentIndex; index < bubbleComponents.count; index++)
{
// Here the bubble is composed by multiple text messages
MXKRoomBubbleComponent *component = bubbleComponents[index];
// Ignore components without display.
if (!component.attributedTextMessage)
{
continue;
}
if (tapPoint.y < component.position.y)
{
break;

View File

@@ -18,6 +18,8 @@
#import "RoomEncryptedDataBubbleCell.h"
#import "RoomBubbleCellData.h"
@implementation RoomOutgoingEncryptedTextMsgWithoutSenderNameBubbleCell
- (void)awakeFromNib
@@ -64,15 +66,27 @@
// Check which bubble component is displayed in front of the tapped line.
NSArray *bubbleComponents = bubbleData.bubbleComponents;
// Consider by default the first component
MXKRoomBubbleComponent *tappedComponent = bubbleComponents.firstObject;
// Consider by default the first display component
NSInteger firstComponentIndex = 0;
if ([bubbleData isKindOfClass:RoomBubbleCellData.class])
{
firstComponentIndex = ((RoomBubbleCellData*)bubbleData).oldestComponentIndex;
}
MXKRoomBubbleComponent *tappedComponent = bubbleComponents[firstComponentIndex++];
CGPoint tapPoint = [sender locationInView:self.messageTextView];
for (NSInteger index = 1; index < bubbleComponents.count; index++)
for (NSInteger index = firstComponentIndex; index < bubbleComponents.count; index++)
{
// Here the bubble is composed by multiple text messages
MXKRoomBubbleComponent *component = bubbleComponents[index];
// Ignore components without display.
if (!component.attributedTextMessage)
{
continue;
}
if (tapPoint.y < component.position.y)
{
break;

View File

@@ -29,6 +29,8 @@
}
@property (weak, nonatomic) IBOutlet UILabel *roomTitle;
@property (weak, nonatomic) IBOutlet UILabel *roomTitle1;
@property (weak, nonatomic) IBOutlet UILabel *roomTitle2;
@property (weak, nonatomic) IBOutlet UIView *directRoomBorderView;
@property (weak, nonatomic) IBOutlet MXKImageView *roomAvatar;

View File

@@ -22,6 +22,8 @@
#import "MXRoom+Riot.h"
#import "MXTools.h"
@implementation RoomCollectionViewCell
#pragma mark - Class methods
@@ -39,6 +41,8 @@
_missedNotifAndUnreadBadgeBgViewWidthConstraint.constant = 0;
self.roomTitle.textColor = kRiotTextColorBlack;
self.roomTitle1.textColor = kRiotTextColorBlack;
self.roomTitle2.textColor = kRiotTextColorBlack;
self.missedNotifAndUnreadBadgeLabel.textColor = [UIColor whiteColor];
// Prepare direct room border
@@ -54,8 +58,6 @@
- (void)layoutSubviews
{
[super layoutSubviews];
}
- (void)render:(MXKCellData *)cellData
@@ -68,7 +70,24 @@
if (roomCellData)
{
// Report computed values as is
self.roomTitle.hidden = NO;
self.roomTitle.text = roomCellData.roomDisplayname;
self.roomTitle1.hidden = YES;
self.roomTitle2.hidden = YES;
// Check whether the room display name is an alias to keep visible the HS.
if ([MXTools isMatrixRoomAlias:roomCellData.roomDisplayname])
{
NSRange range = [roomCellData.roomDisplayname rangeOfString:@":" options:NSBackwardsSearch];
if (range.location != NSNotFound)
{
self.roomTitle.hidden = YES;
self.roomTitle1.hidden = NO;
self.roomTitle1.text = [roomCellData.roomDisplayname substringToIndex:range.location + 1];
self.roomTitle2.hidden = NO;
self.roomTitle2.text = [roomCellData.roomDisplayname substringFromIndex:range.location + 1];
}
}
// Notify unreads and bing
if (roomCellData.hasUnread)
@@ -87,11 +106,11 @@
// Use bold font for the room title
if ([UIFont respondsToSelector:@selector(systemFontOfSize:weight:)])
{
self.roomTitle.font = [UIFont systemFontOfSize:15 weight:UIFontWeightBold];
self.roomTitle.font = self.roomTitle1.font = self.roomTitle2.font = [UIFont systemFontOfSize:13 weight:UIFontWeightBold];
}
else
{
self.roomTitle.font = [UIFont boldSystemFontOfSize:15];
self.roomTitle.font = self.roomTitle1.font = self.roomTitle2.font = [UIFont boldSystemFontOfSize:13];
}
}
else if (roomCellData.roomSummary.room.state.membership == MXMembershipInvite)
@@ -107,11 +126,11 @@
// Use bold font for the room title
if ([UIFont respondsToSelector:@selector(systemFontOfSize:weight:)])
{
self.roomTitle.font = [UIFont systemFontOfSize:15 weight:UIFontWeightBold];
self.roomTitle.font = self.roomTitle1.font = self.roomTitle2.font = [UIFont systemFontOfSize:13 weight:UIFontWeightBold];
}
else
{
self.roomTitle.font = [UIFont boldSystemFontOfSize:15];
self.roomTitle.font = self.roomTitle1.font = self.roomTitle2.font = [UIFont boldSystemFontOfSize:13];
}
}
else
@@ -119,11 +138,11 @@
// The room title is not bold anymore
if ([UIFont respondsToSelector:@selector(systemFontOfSize:weight:)])
{
self.roomTitle.font = [UIFont systemFontOfSize:15 weight:UIFontWeightMedium];
self.roomTitle.font = self.roomTitle1.font = self.roomTitle2.font = [UIFont systemFontOfSize:13 weight:UIFontWeightMedium];
}
else
{
self.roomTitle.font = [UIFont systemFontOfSize:15];
self.roomTitle.font = self.roomTitle1.font = self.roomTitle2.font = [UIFont systemFontOfSize:13];
}
}
@@ -137,15 +156,20 @@
}
}
- (MXKCellData*)renderedCellData
{
return roomCellData;
}
+ (CGFloat)heightForCellData:(MXKCellData *)cellData withMaximumWidth:(CGFloat)maxWidth
{
// The height is fixed
return 100;
return 115;
}
+ (CGSize)defaultCellSize
{
return CGSizeMake(80, 100);
return CGSizeMake(80, 115);
}
- (void)prepareForReuse
@@ -158,6 +182,8 @@
[self removeGestureRecognizer:self.gestureRecognizers[0]];
}
self.tag = -1;
roomCellData = nil;
}
@end

View File

@@ -1,11 +1,11 @@
<?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">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12121" systemVersion="16F73" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12088"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
@@ -13,10 +13,10 @@
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" id="eCk-zY-LXq" customClass="RoomCollectionViewCell">
<rect key="frame" x="0.0" y="0.0" width="80" height="100"/>
<rect key="frame" x="0.0" y="0.0" width="80" height="115"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="80" height="100"/>
<rect key="frame" x="0.0" y="0.0" width="80" height="115"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<view contentMode="scaleAspectFit" translatesAutoresizingMaskIntoConstraints="NO" id="T1Q-RS-8o6" customClass="MXKImageView">
@@ -61,13 +61,24 @@
<constraint firstAttribute="width" constant="15" id="bbS-D2-SZi"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="RoomTitle" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="oxX-IL-dG4">
<rect key="frame" x="4" y="74" width="72" height="21"/>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="RoomTitle" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="oxX-IL-dG4">
<rect key="frame" x="4" y="74" width="72" height="16"/>
<accessibility key="accessibilityConfiguration" identifier="TitleLabel"/>
<constraints>
<constraint firstAttribute="height" constant="21" id="WA1-mL-sFU"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="14"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="13"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="RoomTitle" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="X8H-1U-wc3">
<rect key="frame" x="7" y="74" width="66" height="16"/>
<accessibility key="accessibilityConfiguration" identifier="TitleLabel"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="13"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="RoomTitle" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Jkz-Zp-aaG">
<rect key="frame" x="7" y="90" width="66" height="16"/>
<accessibility key="accessibilityConfiguration" identifier="TitleLabel"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="13"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
@@ -75,16 +86,25 @@
</view>
<constraints>
<constraint firstAttribute="trailing" secondItem="5Yd-df-HbB" secondAttribute="trailing" constant="12" id="0gr-xn-dfD"/>
<constraint firstAttribute="bottom" secondItem="oxX-IL-dG4" secondAttribute="bottom" constant="5" id="1JB-d1-zb9"/>
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="oxX-IL-dG4" secondAttribute="bottom" constant="5" id="1JB-d1-zb9"/>
<constraint firstItem="oxX-IL-dG4" firstAttribute="top" secondItem="T1Q-RS-8o6" secondAttribute="bottom" constant="4" id="2DB-H2-E2v"/>
<constraint firstItem="oxX-IL-dG4" firstAttribute="leading" secondItem="eCk-zY-LXq" secondAttribute="leading" constant="4" id="6gu-JD-Gb1"/>
<constraint firstItem="X8H-1U-wc3" firstAttribute="centerX" secondItem="oxX-IL-dG4" secondAttribute="centerX" id="K9T-eO-WNb"/>
<constraint firstItem="xws-BR-H47" firstAttribute="centerX" secondItem="T1Q-RS-8o6" secondAttribute="centerX" id="Lo3-Ov-Bw8"/>
<constraint firstAttribute="trailing" secondItem="Q6g-b0-3sZ" secondAttribute="trailing" id="Mf1-H6-oH4"/>
<constraint firstItem="Jkz-Zp-aaG" firstAttribute="centerX" secondItem="oxX-IL-dG4" secondAttribute="centerX" id="OQy-tF-e3Z"/>
<constraint firstItem="Jkz-Zp-aaG" firstAttribute="top" secondItem="X8H-1U-wc3" secondAttribute="bottom" id="XDO-yX-Zs5"/>
<constraint firstItem="X8H-1U-wc3" firstAttribute="leading" secondItem="eCk-zY-LXq" secondAttribute="leading" constant="7" id="XU5-Lv-9Xn"/>
<constraint firstItem="T1Q-RS-8o6" firstAttribute="top" secondItem="eCk-zY-LXq" secondAttribute="top" constant="10" id="cc7-bg-15Z"/>
<constraint firstItem="Jkz-Zp-aaG" firstAttribute="leading" secondItem="eCk-zY-LXq" secondAttribute="leading" constant="7" id="fPh-Lb-Bv9"/>
<constraint firstItem="xws-BR-H47" firstAttribute="centerY" secondItem="T1Q-RS-8o6" secondAttribute="centerY" id="faX-hg-WfP"/>
<constraint firstItem="5Yd-df-HbB" firstAttribute="top" secondItem="eCk-zY-LXq" secondAttribute="top" constant="55" id="h4R-2d-Xxn"/>
<constraint firstAttribute="trailing" secondItem="oxX-IL-dG4" secondAttribute="trailing" constant="4" id="hDl-X9-M4n"/>
<constraint firstItem="T1Q-RS-8o6" firstAttribute="centerX" secondItem="eCk-zY-LXq" secondAttribute="centerX" id="hmB-fl-oN2"/>
<constraint firstItem="Q6g-b0-3sZ" firstAttribute="top" secondItem="eCk-zY-LXq" secondAttribute="top" constant="5" id="jST-Ic-lsn"/>
<constraint firstAttribute="trailing" secondItem="X8H-1U-wc3" secondAttribute="trailing" constant="7" id="o5i-7H-n0G"/>
<constraint firstAttribute="trailing" secondItem="Jkz-Zp-aaG" secondAttribute="trailing" constant="7" id="uQe-FG-3lb"/>
<constraint firstItem="X8H-1U-wc3" firstAttribute="top" secondItem="oxX-IL-dG4" secondAttribute="top" id="uTm-3W-QoM"/>
</constraints>
<connections>
<outlet property="directRoomBorderView" destination="xws-BR-H47" id="34A-hu-DXq"/>
@@ -94,6 +114,8 @@
<outlet property="missedNotifAndUnreadBadgeLabel" destination="ZUZ-tv-dVV" id="6IV-rz-s4I"/>
<outlet property="roomAvatar" destination="T1Q-RS-8o6" id="4sR-Wm-jwz"/>
<outlet property="roomTitle" destination="oxX-IL-dG4" id="vff-Fw-AOf"/>
<outlet property="roomTitle1" destination="X8H-1U-wc3" id="nnS-Hp-1qV"/>
<outlet property="roomTitle2" destination="Jkz-Zp-aaG" id="xO1-Av-NID"/>
</connections>
</collectionViewCell>
</objects>

View File

@@ -1,11 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11762" systemVersion="15G1108" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12120" systemVersion="16F73" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12088"/>
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@@ -47,12 +48,12 @@
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="details_icon" translatesAutoresizingMaskIntoConstraints="NO" id="S3Y-wJ-HOe">
<rect key="frame" x="325" y="187" width="6" height="12"/>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="members_list_icon.png" translatesAutoresizingMaskIntoConstraints="NO" id="S3Y-wJ-HOe">
<rect key="frame" x="260" y="185.5" width="15" height="15"/>
<accessibility key="accessibilityConfiguration" identifier="RoomMembersDetailsIcon"/>
<constraints>
<constraint firstAttribute="width" constant="6" id="XTx-6p-2wB"/>
<constraint firstAttribute="height" constant="12" id="tXh-eB-ave"/>
<constraint firstAttribute="width" constant="15" id="XTx-6p-2wB"/>
<constraint firstAttribute="height" constant="15" id="tXh-eB-ave"/>
</constraints>
</imageView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Ckb-7c-sTg">
@@ -67,9 +68,28 @@
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="MFb-0F-eO8">
<rect key="frame" x="0.0" y="177" width="600" height="38"/>
<rect key="frame" x="0.0" y="177" width="322" height="38"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="tsg-nl-P3k">
<rect key="frame" x="322" y="173.5" width="38" height="38"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="add_participant.png" translatesAutoresizingMaskIntoConstraints="NO" id="i40-fd-AlH">
<rect key="frame" x="10" y="10" width="18" height="18"/>
<constraints>
<constraint firstAttribute="width" constant="18" id="Jxs-fk-U04"/>
<constraint firstAttribute="width" secondItem="i40-fd-AlH" secondAttribute="height" multiplier="1:1" id="cuB-Hn-Dl3"/>
</constraints>
</imageView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="width" constant="38" id="E23-7d-llG"/>
<constraint firstItem="i40-fd-AlH" firstAttribute="centerX" secondItem="tsg-nl-P3k" secondAttribute="centerX" id="gK0-hw-x7R"/>
<constraint firstItem="i40-fd-AlH" firstAttribute="centerY" secondItem="tsg-nl-P3k" secondAttribute="centerY" id="tyV-XH-iOk"/>
<constraint firstAttribute="width" secondItem="tsg-nl-P3k" secondAttribute="height" multiplier="1:1" id="xH6-0P-TLQ"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<accessibility key="accessibilityConfiguration" identifier="RoomTitle"/>
@@ -77,15 +97,18 @@
<constraint firstAttribute="trailing" secondItem="uSp-YH-L18" secondAttribute="trailing" id="0UG-aH-hVB"/>
<constraint firstItem="qD3-kA-DSI" firstAttribute="centerX" secondItem="BkF-x3-7fX" secondAttribute="centerX" id="1MA-VE-nEM"/>
<constraint firstAttribute="bottom" secondItem="MFb-0F-eO8" secondAttribute="bottom" id="1W0-oZ-AQb"/>
<constraint firstItem="tsg-nl-P3k" firstAttribute="centerY" secondItem="ou0-3Z-weL" secondAttribute="centerY" id="3Pa-cx-AsC"/>
<constraint firstItem="6uH-I3-RQg" firstAttribute="centerX" secondItem="BkF-x3-7fX" secondAttribute="centerX" id="3uN-6W-rVZ"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="S3Y-wJ-HOe" secondAttribute="trailing" id="3z3-Ye-wh3"/>
<constraint firstItem="8HH-9b-1yH" firstAttribute="leading" secondItem="BkF-x3-7fX" secondAttribute="leading" id="49B-Gu-i1k"/>
<constraint firstItem="8HH-9b-1yH" firstAttribute="top" secondItem="BkF-x3-7fX" secondAttribute="top" id="4IU-hf-3R1"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="tsg-nl-P3k" secondAttribute="trailing" id="4Y7-tV-Spc"/>
<constraint firstItem="ou0-3Z-weL" firstAttribute="centerX" secondItem="BkF-x3-7fX" secondAttribute="centerX" id="9kY-pQ-khO"/>
<constraint firstItem="S3Y-wJ-HOe" firstAttribute="centerY" secondItem="ou0-3Z-weL" secondAttribute="centerY" id="C0N-Rf-ncJ"/>
<constraint firstItem="S3Y-wJ-HOe" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="BkF-x3-7fX" secondAttribute="leading" id="Dib-vF-l0D"/>
<constraint firstItem="qD3-kA-DSI" firstAttribute="top" secondItem="6uH-I3-RQg" secondAttribute="bottom" constant="5" id="IRZ-hl-lUU"/>
<constraint firstItem="S3Y-wJ-HOe" firstAttribute="leading" secondItem="ou0-3Z-weL" secondAttribute="trailing" constant="7" id="JrS-kW-PJv"/>
<constraint firstItem="MFb-0F-eO8" firstAttribute="leading" secondItem="BkF-x3-7fX" secondAttribute="leading" id="LTB-3D-soR"/>
<constraint firstItem="tsg-nl-P3k" firstAttribute="leading" secondItem="MFb-0F-eO8" secondAttribute="trailing" id="QOq-Cv-1pw"/>
<constraint firstItem="tsg-nl-P3k" firstAttribute="leading" secondItem="ou0-3Z-weL" secondAttribute="trailing" constant="4" id="RNc-DE-a8O"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="qD3-kA-DSI" secondAttribute="trailing" constant="31" id="RSk-Fd-oq0"/>
<constraint firstAttribute="trailing" secondItem="8HH-9b-1yH" secondAttribute="trailing" id="SrK-30-YET"/>
<constraint firstItem="MFb-0F-eO8" firstAttribute="top" secondItem="8HH-9b-1yH" secondAttribute="bottom" id="ULI-RY-Ase"/>
@@ -97,16 +120,17 @@
<constraint firstItem="uSp-YH-L18" firstAttribute="top" secondItem="BkF-x3-7fX" secondAttribute="top" id="dn3-Hv-OyX"/>
<constraint firstAttribute="trailing" secondItem="Ckb-7c-sTg" secondAttribute="trailing" id="erV-R4-LXD"/>
<constraint firstItem="6uH-I3-RQg" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="BkF-x3-7fX" secondAttribute="leading" constant="31" id="gnq-cO-l4Y"/>
<constraint firstItem="ou0-3Z-weL" firstAttribute="leading" secondItem="S3Y-wJ-HOe" secondAttribute="trailing" constant="7" id="iAL-UV-5nu"/>
<constraint firstItem="qD3-kA-DSI" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="BkF-x3-7fX" secondAttribute="leading" constant="31" id="jjG-gN-eIv"/>
<constraint firstItem="6uH-I3-RQg" firstAttribute="top" secondItem="uSp-YH-L18" secondAttribute="bottom" constant="8" id="rAh-mV-nb5"/>
<constraint firstItem="ou0-3Z-weL" firstAttribute="top" secondItem="qD3-kA-DSI" secondAttribute="bottom" constant="14" id="sJB-Wr-gFl"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="ou0-3Z-weL" secondAttribute="trailing" constant="31" id="sPZ-Hp-JeH"/>
<constraint firstAttribute="trailing" secondItem="MFb-0F-eO8" secondAttribute="trailing" id="vjK-vS-uzY"/>
<constraint firstItem="8HH-9b-1yH" firstAttribute="bottom" secondItem="qD3-kA-DSI" secondAttribute="bottom" constant="7" id="wzH-3D-S6C"/>
<constraint firstAttribute="bottom" secondItem="ou0-3Z-weL" secondAttribute="bottom" constant="14" id="yXn-jl-DeG"/>
</constraints>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<connections>
<outlet property="addParticipantMask" destination="tsg-nl-P3k" id="ADj-t1-9wf"/>
<outlet property="bottomBorderView" destination="Ckb-7c-sTg" id="2Ky-GN-bO0"/>
<outlet property="displayNameTextField" destination="6uH-I3-RQg" id="MfX-LQ-C2K"/>
<outlet property="roomAvatarHeaderBackground" destination="uSp-YH-L18" id="sfW-ED-5bD"/>
@@ -119,6 +143,7 @@
</view>
</objects>
<resources>
<image name="details_icon" width="31" height="31"/>
<image name="add_participant.png" width="58" height="58"/>
<image name="members_list_icon.png" width="12" height="12"/>
</resources>
</document>

View File

@@ -36,6 +36,7 @@
@property (weak, nonatomic) IBOutlet UIView *titleMask;
@property (weak, nonatomic) IBOutlet UIView *roomDetailsMask;
@property (weak, nonatomic) IBOutlet UIView *addParticipantMask;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *displayNameCenterXConstraint;
@property (weak, nonatomic) IBOutlet UIImageView *roomDetailsIconImageView;

View File

@@ -59,6 +59,16 @@
[self.roomDetailsMask addGestureRecognizer:tap];
self.roomDetailsMask.userInteractionEnabled = YES;
}
if (_addParticipantMask)
{
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(reportTapGesture:)];
[tap setNumberOfTouchesRequired:1];
[tap setNumberOfTapsRequired:1];
[tap setDelegate:self];
[self.addParticipantMask addGestureRecognizer:tap];
self.addParticipantMask.userInteractionEnabled = YES;
}
}
- (void)layoutSubviews