Console: Implement Recents List based on MatrixKit.

This commit is contained in:
giomfo 2015-04-03 15:02:16 +02:00
parent 2c7a2ac80a
commit 77c755e55d
9 changed files with 216 additions and 727 deletions

View file

@ -66,10 +66,10 @@
F0CEA5B119E6898800E47915 /* tab_home.ico in Resources */ = {isa = PBXBuildFile; fileRef = F0CEA5B019E6898800E47915 /* tab_home.ico */; };
F0D3C30C1A011EF10000D49E /* AppSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = F0D3C30B1A011EF10000D49E /* AppSettings.m */; };
F0D3C30F1A01330F0000D49E /* SettingsTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = F0D3C30E1A01330F0000D49E /* SettingsTableViewCell.m */; };
F0D942F61A31F3A300826CC1 /* RecentRoom.m in Sources */ = {isa = PBXBuildFile; fileRef = F0D942F51A31F3A300826CC1 /* RecentRoom.m */; };
F0E84D401A1F9AEC005F2E42 /* RecentsTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = F0E84D3F1A1F9AEC005F2E42 /* RecentsTableViewCell.m */; };
F0F148A81AB1BF01005F5D4A /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F0F148A71AB1BF01005F5D4A /* AudioToolbox.framework */; };
F0F535BB1ACD6C4F00B603F8 /* RageShakeManager.m in Sources */ = {isa = PBXBuildFile; fileRef = F0F535BA1ACD6C4F00B603F8 /* RageShakeManager.m */; };
F0F535BF1ACDE46200B603F8 /* RecentListDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = F0F535BE1ACDE46200B603F8 /* RecentListDataSource.m */; };
F0F90C691A32596700455977 /* icon_search.png in Resources */ = {isa = PBXBuildFile; fileRef = F0F90C681A32596700455977 /* icon_search.png */; };
F0F90C6B1A325ABF00455977 /* icon_search@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F0F90C6A1A325ABF00455977 /* icon_search@2x.png */; };
/* End PBXBuildFile section */
@ -183,13 +183,13 @@
F0D3C30B1A011EF10000D49E /* AppSettings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppSettings.m; sourceTree = "<group>"; };
F0D3C30D1A01330F0000D49E /* SettingsTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsTableViewCell.h; sourceTree = "<group>"; };
F0D3C30E1A01330F0000D49E /* SettingsTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsTableViewCell.m; sourceTree = "<group>"; };
F0D942F41A31F3A300826CC1 /* RecentRoom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecentRoom.h; sourceTree = "<group>"; };
F0D942F51A31F3A300826CC1 /* RecentRoom.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RecentRoom.m; sourceTree = "<group>"; };
F0E84D3E1A1F9AEC005F2E42 /* RecentsTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecentsTableViewCell.h; sourceTree = "<group>"; };
F0E84D3F1A1F9AEC005F2E42 /* RecentsTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RecentsTableViewCell.m; sourceTree = "<group>"; };
F0F148A71AB1BF01005F5D4A /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
F0F535B91ACD6C4F00B603F8 /* RageShakeManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RageShakeManager.h; sourceTree = "<group>"; };
F0F535BA1ACD6C4F00B603F8 /* RageShakeManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RageShakeManager.m; sourceTree = "<group>"; };
F0F535BD1ACDE46200B603F8 /* RecentListDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecentListDataSource.h; sourceTree = "<group>"; };
F0F535BE1ACDE46200B603F8 /* RecentListDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RecentListDataSource.m; sourceTree = "<group>"; };
F0F90C681A32596700455977 /* icon_search.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon_search.png; sourceTree = "<group>"; };
F0F90C6A1A325ABF00455977 /* icon_search@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon_search@2x.png"; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -357,8 +357,8 @@
71193D351A6E49F000E59A9E /* MXCPhoneNumber.m */,
710CA4C01A7FBFED00EEFB96 /* RageShakableUIResponder.h */,
710CA4C11A7FBFED00EEFB96 /* RageShakableUIResponder.m */,
F0D942F41A31F3A300826CC1 /* RecentRoom.h */,
F0D942F51A31F3A300826CC1 /* RecentRoom.m */,
F0F535BD1ACDE46200B603F8 /* RecentListDataSource.h */,
F0F535BE1ACDE46200B603F8 /* RecentListDataSource.m */,
71193D3C1A6E61AD00E59A9E /* SectionedContacts.h */,
71193D3D1A6E61AD00E59A9E /* SectionedContacts.m */,
);
@ -597,6 +597,7 @@
F052377C1A7289F00079F3E0 /* APNSHandler.m in Sources */,
F07A80D819DD9DE700B621A1 /* main.m in Sources */,
71193D371A6E49F000E59A9E /* MXCEmail.m in Sources */,
F0F535BF1ACDE46200B603F8 /* RecentListDataSource.m in Sources */,
F077E6491A72966F008D5AD5 /* MatrixSDKHandler.m in Sources */,
71193D3E1A6E61AD00E59A9E /* SectionedContacts.m in Sources */,
F03EF5FB19F171EB00A0EE52 /* SettingsViewController.m in Sources */,
@ -609,7 +610,6 @@
710CA4C51A7FC27100EEFB96 /* MXCTableViewController.m in Sources */,
F03EF5F619F171EB00A0EE52 /* HomeViewController.m in Sources */,
71DB9DC11A495B6400504A09 /* MemberViewController.m in Sources */,
F0D942F61A31F3A300826CC1 /* RecentRoom.m in Sources */,
F03EF5F919F171EB00A0EE52 /* RecentsViewController.m in Sources */,
F08E67961A77965A00AABD4C /* MXC3PID.m in Sources */,
71193D291A6E3DC000E59A9E /* ContactsViewController.m in Sources */,

View file

@ -16,7 +16,7 @@
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<connections>
<segue destination="7bK-jq-Zjz" kind="relationship" relationship="rootViewController" id="tsl-Nk-0bq"/>
<segue destination="q3d-uQ-djS" kind="relationship" relationship="rootViewController" id="bg4-7B-0ft"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="8fS-aE-onr" sceneMemberID="firstResponder"/>
@ -36,10 +36,10 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="OWi-J8-sFZ" userLabel="MembersView">
<rect key="frame" x="0.0" y="64" width="600" height="487"/>
<rect key="frame" x="0.0" y="64" width="600" height="536"/>
<subviews>
<tableView clipsSubviews="YES" contentMode="scaleToFill" bounces="NO" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="50" sectionHeaderHeight="22" sectionFooterHeight="22" translatesAutoresizingMaskIntoConstraints="NO" id="pLY-I9-ghF" userLabel="MembersTableView">
<rect key="frame" x="0.0" y="0.0" width="600" height="487"/>
<rect key="frame" x="0.0" y="0.0" width="600" height="536"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<view key="tableFooterView" contentMode="scaleToFill" id="fdb-ra-p9Z" userLabel="fakeTableFooterView">
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
@ -1549,78 +1549,26 @@
<point key="canvasLocation" x="60" y="-266"/>
</scene>
<!--Recents-->
<scene sceneID="smW-Zh-WAh">
<scene sceneID="PCl-Pf-mIl">
<objects>
<tableViewController title="Recents" clearsSelectionOnViewWillAppear="NO" id="7bK-jq-Zjz" customClass="RecentsViewController" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" keyboardDismissMode="interactive" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="70" sectionHeaderHeight="22" sectionFooterHeight="22" id="r7i-6Z-zg0">
<viewController id="q3d-uQ-djS" customClass="RecentsViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="2f0-dG-TSc"/>
<viewControllerLayoutGuide type="bottom" id="sQB-zl-eM7"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Qys-kQ-1ab">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<prototypes>
<tableViewCell contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="RecentsCell" id="WCw-Qf-5nD" customClass="RecentsTableViewCell">
<rect key="frame" x="0.0" y="86" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="WCw-Qf-5nD" id="37f-cq-3Eg">
<rect key="frame" x="0.0" y="0.0" width="320" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="RoomTitle" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="YTM-8H-EpC">
<rect key="frame" x="8" y="8" width="504" height="23"/>
<fontDescription key="fontDescription" type="system" pointSize="19"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="LastEventDescription" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5g8-vg-2EB">
<rect key="frame" x="8" y="42" width="584" height="18"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Oct 12 18:15" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="eKl-0r-wFc">
<rect key="frame" x="520" y="8" width="72" height="15"/>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstItem="YTM-8H-EpC" firstAttribute="leading" secondItem="37f-cq-3Eg" secondAttribute="leading" constant="8" id="0FC-Ly-dRv"/>
<constraint firstAttribute="trailing" secondItem="YTM-8H-EpC" secondAttribute="trailing" constant="88" id="56p-nx-gML"/>
<constraint firstAttribute="trailing" secondItem="5g8-vg-2EB" secondAttribute="trailing" constant="8" id="Avl-RN-f0J"/>
<constraint firstItem="5g8-vg-2EB" firstAttribute="leading" secondItem="37f-cq-3Eg" secondAttribute="leading" constant="8" id="YEf-Sg-fK1"/>
<constraint firstItem="eKl-0r-wFc" firstAttribute="top" secondItem="37f-cq-3Eg" secondAttribute="top" constant="8" id="m8Q-2Z-v8h"/>
<constraint firstAttribute="bottom" secondItem="5g8-vg-2EB" secondAttribute="bottom" constant="9" id="oqT-mf-B3Y"/>
<constraint firstItem="YTM-8H-EpC" firstAttribute="top" secondItem="37f-cq-3Eg" secondAttribute="top" constant="8" id="s5s-Hs-1tF"/>
<constraint firstAttribute="trailing" secondItem="eKl-0r-wFc" secondAttribute="trailing" constant="8" id="zkS-cE-swl"/>
</constraints>
</tableViewCellContentView>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<connections>
<outlet property="lastEventDescription" destination="5g8-vg-2EB" id="Usm-IJ-hlX"/>
<outlet property="recentDate" destination="eKl-0r-wFc" id="W7l-rp-OVX"/>
<outlet property="roomTitle" destination="YTM-8H-EpC" id="eZ8-OJ-Lpy"/>
<segue destination="vC3-pB-5Vb" kind="showDetail" identifier="showDetail" id="6S0-TO-JiA"/>
</connections>
</tableViewCell>
</prototypes>
<sections/>
<connections>
<outlet property="dataSource" destination="7bK-jq-Zjz" id="Gho-Na-rnu"/>
<outlet property="delegate" destination="7bK-jq-Zjz" id="RA6-mI-bju"/>
</connections>
</tableView>
<navigationItem key="navigationItem" title="Recents" id="Zdf-7t-Un8"/>
</view>
<navigationItem key="navigationItem" title="Recents" id="L1h-TL-97X"/>
<connections>
<outlet property="activityIndicator" destination="4dn-O0-IJ0" id="1dd-MZ-4V4"/>
<segue destination="vC3-pB-5Vb" kind="showDetail" identifier="showDetails" id="Waw-2O-9El"/>
</connections>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Rux-fX-hf1" sceneMemberID="firstResponder"/>
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="white" id="4dn-O0-IJ0">
<rect key="frame" x="0.0" y="0.0" width="20" height="20"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
</activityIndicatorView>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="mmH-l4-2US" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1665" y="-687"/>
<point key="canvasLocation" x="1649" y="-678"/>
</scene>
<!--RoomNav-->
<scene sceneID="r7l-gg-dq7">
@ -1806,6 +1754,6 @@
<image name="tab_settings.png" width="25" height="25"/>
</resources>
<inferredMetricsTieBreakers>
<segue reference="0ws-cL-0tk"/>
<segue reference="Waw-2O-9El"/>
</inferredMetricsTieBreakers>
</document>

View file

@ -0,0 +1,24 @@
/*
Copyright 2015 OpenMarket Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import <MatrixKit/MatrixKit.h>
/**
The data source for Console `RecentsViewController`.
*/
@interface RecentListDataSource : MXKRecentListDataSource
@end

View file

@ -0,0 +1,51 @@
/*
Copyright 2015 OpenMarket Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "RecentListDataSource.h"
#import "AppDelegate.h"
@implementation RecentListDataSource
#pragma mark - UITableViewDataSource
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
// Return NO if you do not want the specified item to be editable.
return YES;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Leave the selected room
id<MXKRecentCellDataStoring> recentCellData = [self cellDataAtIndex:indexPath.row];
// cancel pending uploads/downloads
// they are useless by now
[MXKMediaManager cancelDownloadsInCacheFolder:recentCellData.room.state.roomId];
// TODO GFO cancel pending uploads related to this room
[recentCellData.room leave:^{
// Refresh table display
[self didCellDataChange:recentCellData];
} failure:^(NSError *error) {
NSLog(@"[Console RecentListDataSource] Failed to leave room (%@) failed: %@", recentCellData.room.state.roomId, error);
//Alert user
[[AppDelegate theDelegate] showErrorAsAlert:error];
}];
}
}
@end

View file

@ -1,37 +0,0 @@
/*
Copyright 2014 OpenMarket Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import <MatrixSDK/MatrixSDK.h>
// When a recent is initialized with a blank last event description (unexpected/unsupported event),
// a back pagination is triggered to find a non empty description.
// The following notification is posted when this operation succeeds
extern NSString *const kRecentRoomUpdatedByBackPagination;
@interface RecentRoom : NSObject
@property (nonatomic, readonly) NSString *roomId;
@property (nonatomic, readonly) NSString *lastEventDescription;
@property (nonatomic, readonly) uint64_t lastEventOriginServerTs;
@property (nonatomic, readonly) NSUInteger unreadCount;
@property (nonatomic, readonly) BOOL containsBingUnread;
- (id)initWithLastEvent:(MXEvent*)event andRoomState:(MXRoomState*)roomState markAsUnread:(BOOL)isUnread;
// Update the current last event description with the provided event, except if this description is empty (see unsupported/unexpected events).
// Return true when the provided event is considered as new last event
- (BOOL)updateWithLastEvent:(MXEvent*)event andRoomState:(MXRoomState*)roomState markAsUnread:(BOOL)isUnread;
- (void)resetUnreadCount;
@end

View file

@ -1,166 +0,0 @@
/*
Copyright 2014 OpenMarket Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "RecentRoom.h"
#import "MatrixSDKHandler.h"
NSString *const kRecentRoomUpdatedByBackPagination = @"kRecentRoomUpdatedByBackPagination";
@interface RecentRoom() {
MXRoom *mxRoom;
id backPaginationListener;
MXHTTPOperation *backPaginationOperation;
// Keep reference on last event (used in case of redaction)
MXEvent *lastEvent;
}
@end
@implementation RecentRoom
- (id)initWithLastEvent:(MXEvent*)event andRoomState:(MXRoomState*)roomState markAsUnread:(BOOL)isUnread {
if (self = [super init]) {
MatrixSDKHandler *mxHandler = [MatrixSDKHandler sharedHandler];
_roomId = event.roomId;
_lastEventDescription = [mxHandler displayTextForEvent:event withRoomState:roomState inSubtitleMode:YES];
_lastEventOriginServerTs = event.originServerTs;
_unreadCount = isUnread ? 1 : 0;
// In case of unread, check whether the last event description contains bing words
_containsBingUnread = (isUnread && !event.isState && !event.redactedBecause && [mxHandler containsBingWord:_lastEventDescription]);
// Keep ref on event
lastEvent = event;
if (!_lastEventDescription.length) {
// Trigger back pagination to get an event with a non empty description
[self triggerBackPagination];
}
}
return self;
}
- (BOOL)updateWithLastEvent:(MXEvent*)event andRoomState:(MXRoomState*)roomState markAsUnread:(BOOL)isUnread {
MatrixSDKHandler *mxHandler = [MatrixSDKHandler sharedHandler];
// Check whether the description of the provided event is not empty
NSString *description = [mxHandler displayTextForEvent:event withRoomState:roomState inSubtitleMode:YES];
if (description.length) {
[self cancelBackPagination];
// Update current last event
lastEvent = event;
_lastEventDescription = description;
_lastEventOriginServerTs = event.originServerTs;
if (isUnread) {
_unreadCount ++;
_containsBingUnread = (_containsBingUnread || (!event.isState && !event.redactedBecause && [mxHandler containsBingWord:_lastEventDescription]));
}
return YES;
} else if (_lastEventDescription.length) {
// Here we tried to update the last event with a new live one, but the description of this new one is empty.
// Consider the specific case of redaction event
if (event.eventType == MXEventTypeRoomRedaction) {
// Check whether the redacted event is the current last event
if ([event.redacts isEqualToString:lastEvent.eventId]) {
// Update last event description
MXEvent *redactedEvent = [lastEvent prune];
redactedEvent.redactedBecause = event.originalDictionary;
_lastEventDescription = [mxHandler displayTextForEvent:redactedEvent withRoomState:nil inSubtitleMode:YES];
if (!_lastEventDescription.length) {
// The current last event must be removed, decrement the unread count (if not null)
if (_unreadCount) {
_unreadCount--;
if (_unreadCount == 0) {
_containsBingUnread = NO;
} // else _containsBingUnread may be false, we should perhaps reset this flag here
}
// Trigger back pagination to get an event with a non empty description
[self triggerBackPagination];
}
return YES;
}
}
}
return NO;
}
- (void)resetUnreadCount {
_unreadCount = 0;
_containsBingUnread = NO;
}
- (void)dealloc {
[self cancelBackPagination];
lastEvent = nil;
_lastEventDescription = nil;
}
- (void)triggerBackPagination {
// Add listener if it is not already done
if (!backPaginationListener) {
MatrixSDKHandler *mxHandler = [MatrixSDKHandler sharedHandler];
mxRoom = [mxHandler.mxSession roomWithRoomId:_roomId];
if (mxRoom) {
backPaginationListener = [mxRoom listenToEventsOfTypes:mxHandler.eventsFilterForMessages onEvent:^(MXEvent *event, MXEventDirection direction, MXRoomState *roomState) {
// Handle only backward events (Sanity check: be sure that the description has not been set by an other way)
if (direction == MXEventDirectionBackwards && !_lastEventDescription.length) {
if ([self updateWithLastEvent:event andRoomState:roomState markAsUnread:NO]) {
// Force recents refresh
[[NSNotificationCenter defaultCenter] postNotificationName:kRecentRoomUpdatedByBackPagination object:_roomId];
}
}
}];
// Trigger a back pagination by reseting first backState to get room history from live
[mxRoom resetBackState];
} else {
return;
}
}
if (mxRoom.canPaginate) {
backPaginationOperation = [mxRoom paginateBackMessages:10 complete:^{
backPaginationOperation = nil;
// Check whether another back pagination is required
if (!_lastEventDescription.length) {
[self triggerBackPagination];
}
} failure:^(NSError *error) {
backPaginationOperation = nil;
NSLog(@"[RecentRoom] Failed to paginate back: %@", error);
[self cancelBackPagination];
}];
} else {
// Force recents refresh
[[NSNotificationCenter defaultCenter] postNotificationName:kRecentRoomUpdatedByBackPagination object:_roomId];
[self cancelBackPagination];
}
}
- (void)cancelBackPagination {
if (backPaginationListener && mxRoom) {
[mxRoom removeListener:backPaginationListener];
backPaginationListener = nil;
mxRoom = nil;
}
if (backPaginationOperation) {
[backPaginationOperation cancel];
backPaginationOperation = nil;
}
}
@end

View file

@ -111,7 +111,7 @@
// Select room to display its details (dispatch this action in order to let TabBarController end its refresh)
dispatch_async(dispatch_get_main_queue(), ^{
recentsViewController.preSelectedRoomId = roomId;
recentsViewController.selectedRoomId = roomId;
});
}
@ -120,7 +120,7 @@
if (recentsViewController) {
[recentsNavigationController popToViewController:recentsViewController animated:animated];
// Release the current selected room
recentsViewController.preSelectedRoomId = nil;
recentsViewController.selectedRoomId = nil;
}
}

View file

@ -1,5 +1,5 @@
/*
Copyright 2014 OpenMarket Ltd
Copyright 2015 OpenMarket Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -14,13 +14,11 @@
limitations under the License.
*/
#import "MXCTableViewController.h"
#import <MatrixKit/MatrixKit.h>
@class RoomViewController;
@interface RecentsViewController : MXKRecentListViewController <MXKRecentListViewControllerDelegate, UISearchBarDelegate>
@interface RecentsViewController : MXCTableViewController <UISearchBarDelegate>
@property (strong, nonatomic) NSString *preSelectedRoomId; // set a non-nil value to this property will open room details
@property (strong, nonatomic) NSString *selectedRoomId; // set a non-nil value to this property will open room details
@end

View file

@ -1,5 +1,5 @@
/*
Copyright 2014 OpenMarket Ltd
Copyright 2015 OpenMarket Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -17,37 +17,27 @@
#import "RecentsViewController.h"
#import "RoomViewController.h"
#import "RecentRoom.h"
#import "RecentsTableViewCell.h"
#import "AppDelegate.h"
#import "MatrixSDKHandler.h"
#import "RecentListDataSource.h"
#import "RageShakeManager.h"
@interface RecentsViewController () {
// Array of RecentRooms
NSMutableArray *recents;
id recentsListener;
NSUInteger unreadCount;
// Search
UISearchBar *recentsSearchBar;
NSMutableArray *filteredRecents;
BOOL searchBarShouldEndEditing;
// Date formatter
NSDateFormatter *dateFormatter;
//
BOOL shouldScrollToTopOnRefresh;
// Keep reference on the current room view controller to release it correctly
RoomViewController *currentRoomViewController;
// Keep the selected cell index to handle correctly split view controller display in landscape mode
NSInteger currentSelectedCellIndexPathRow;
// The activity indicator is displayed on main screen in order to ignore potential table scrolling
// In some case this activity indicator shoud be hidden (For example when the recents view controller is not visible).
BOOL shouldHideActivityIndicator;
}
@property (strong, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicator;
@end
@ -69,28 +59,18 @@
UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(createNewRoom:)];
self.navigationItem.rightBarButtonItems = @[searchButton, addButton];
// Add background to activity indicator
CGRect frame = _activityIndicator.frame;
frame.size.width += 30;
frame.size.height += 30;
_activityIndicator.bounds = frame;
_activityIndicator.backgroundColor = [UIColor darkGrayColor];
[_activityIndicator.layer setCornerRadius:5];
// Initialisation
recents = nil;
filteredRecents = nil;
unreadCount = 0;
currentSelectedCellIndexPathRow = -1;
NSString *dateFormat = @"MMM dd HH:mm";
dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:[[[NSBundle mainBundle] preferredLocalizations] objectAtIndex:0]]];
[dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
[dateFormatter setTimeStyle:NSDateFormatterNoStyle];
[dateFormatter setDateFormat:dateFormat];
// Setup `MXKRecentListViewController` properties
self.rageShakeManager = [RageShakeManager sharedManager];
[[MatrixSDKHandler sharedHandler] addObserver:self forKeyPath:@"status" options:0 context:nil];
// The view controller handles itself the selected recent
self.delegate = self;
// List all the recents for the logged user
MXKRecentListDataSource *listDataSource = [[RecentListDataSource alloc] initWithMatrixSession:[MatrixSDKHandler sharedHandler].mxSession];
[self displayList:listDataSource];
}
- (void)dealloc {
@ -98,19 +78,14 @@
[currentRoomViewController destroy];
currentRoomViewController = nil;
}
if (recentsListener) {
[[MatrixSDKHandler sharedHandler].mxSession removeListener:recentsListener];
recentsListener = nil;
}
recents = nil;
_preSelectedRoomId = nil;
_selectedRoomId = nil;
recentsSearchBar = nil;
filteredRecents = nil;
}
- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
[super setEditing:editing animated:animated];
if (dateFormatter) {
dateFormatter = nil;
}
[[MatrixSDKHandler sharedHandler] removeObserver:self forKeyPath:@"status"];
self.tableView.editing = editing;
}
- (void)didReceiveMemoryWarning {
@ -121,17 +96,10 @@
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
MatrixSDKHandler *mxHandler = [MatrixSDKHandler sharedHandler];
[mxHandler addObserver:self forKeyPath:@"isActivityInProgress" options:0 context:nil];
[self updateTitleView];
// Refresh display
shouldHideActivityIndicator = NO;
if (mxHandler.isActivityInProgress) {
[self startActivityIndicator];
}
[self configureView];
if (self.splitViewController) {
// if (self.splitViewController)
{
// Deselect the current selected row, it will be restored on viewDidAppear (if any)
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
if (indexPath) {
@ -143,19 +111,14 @@
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[MatrixSDKHandler sharedHandler] removeObserver:self forKeyPath:@"isActivityInProgress"];
// Leave potential editing mode
[self setEditing:NO];
// Leave potential search session
if (recentsSearchBar) {
[self searchBarCancelButtonClicked:recentsSearchBar];
}
// Hide activity indicator
[self stopActivityIndicator];
shouldHideActivityIndicator = YES;
_preSelectedRoomId = nil;
_selectedRoomId = nil;
}
- (void)viewDidAppear:(BOOL)animated {
@ -178,39 +141,40 @@
#pragma mark -
- (void)setPreSelectedRoomId:(NSString *)roomId {
_preSelectedRoomId = nil;
- (void)setSelectedRoomId:(NSString *)roomId {
if (_selectedRoomId && [_selectedRoomId isEqualToString:roomId]) {
// Nothing to do
return;
}
_selectedRoomId = roomId;
if (roomId) {
// Check whether recents update is in progress
if ([_activityIndicator isAnimating]) {
// Postpone room details display
_preSelectedRoomId = roomId;
return;
}
// Open details view
// NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
// if (indexPath) {
// id<MXKRecentCellDataStoring> recentCellData = [self.dataSource cellDataAtIndex:indexPath.row];
// if (![recentCellData.room.state.roomId isEqualToString:roomId]) {
// [self.tableView deselectRowAtIndexPath:indexPath animated:NO];
// indexPath = nil;
// }
// }
//
// if (!indexPath) {
// NSInteger cellCount = [self.dataSource tableView:self.tableView numberOfRowsInSection:0];
// for (NSInteger index = 0; index < cellCount; index ++) {
// id<MXKRecentCellDataStoring> recentCellData = [self.dataSource cellDataAtIndex:index];
// if ([_selectedRoomId isEqualToString:recentCellData.room.state.roomId]) {
// indexPath = [NSIndexPath indexPathForRow:index inSection:0];
// break;
// }
// }
//
// if (indexPath) {
// [self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionMiddle];
// }
// }
// Look for the room index in recents list
NSIndexPath *indexPath = nil;
for (NSUInteger index = 0; index < recents.count; index++) {
RecentRoom *recentRoom = [recents objectAtIndex:index];
if ([roomId isEqualToString:recentRoom.roomId]) {
indexPath = [NSIndexPath indexPathForRow:index inSection:0];
break;
}
}
if (indexPath) {
// Open details view
[self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionMiddle];
UITableViewCell *recentCell = [self.tableView cellForRowAtIndexPath:indexPath];
[self performSegueWithIdentifier:@"showDetail" sender:recentCell];
} else {
NSLog(@"[RecentsVC] We are not able to open room (%@) because it does not appear in recents yet", roomId);
// Postpone room details display. We run activity indicator until recents are updated (thanks to recents listener)
_preSelectedRoomId = roomId;
// Start activity indicator
[self startActivityIndicator];
}
[self performSegueWithIdentifier:@"showDetails" sender:self];
} else if (currentRoomViewController) {
// Release the current selected room
[currentRoomViewController destroy];
@ -236,6 +200,11 @@
[self.tableView reloadData];
if (shouldScrollToTopOnRefresh) {
[self scrollToTop];
shouldScrollToTopOnRefresh = NO;
}
// In case of split view controller where the primary and secondary view controllers are displayed side-by-side onscreen,
// the selected room (if any) is updated and kept visible.
if (self.splitViewController && !self.splitViewController.isCollapsed) {
@ -243,190 +212,28 @@
}
}
- (void)configureView {
MatrixSDKHandler *mxHandler = [MatrixSDKHandler sharedHandler];
[[NSNotificationCenter defaultCenter] removeObserver:self name:kRecentRoomUpdatedByBackPagination object:nil];
if (mxHandler.mxSession) {
// Check matrix handler status
if (mxHandler.status == MatrixSDKHandlerStatusStoreDataReady || mxHandler.status == MatrixSDKHandlerStatusInitialServerSyncInProgress) {
// Server sync is not complete yet
if (!recents) {
// Retrieve recents from local storage (some data may not be up-to-date)
NSArray *recentEvents = [NSMutableArray arrayWithArray:[mxHandler.mxSession recentsWithTypeIn:mxHandler.eventsFilterForMessages]];
recents = [NSMutableArray arrayWithCapacity:recentEvents.count];
for (MXEvent *mxEvent in recentEvents) {
MXRoom *mxRoom = [mxHandler.mxSession roomWithRoomId:mxEvent.roomId];
RecentRoom *recentRoom = [[RecentRoom alloc] initWithLastEvent:mxEvent andRoomState:mxRoom.state markAsUnread:NO];
if (recentRoom) {
[recents addObject:recentRoom];
}
}
unreadCount = 0;
}
} else if (mxHandler.status == MatrixSDKHandlerStatusServerSyncDone) {
// Force recents refresh and add listener to update them (if it is not already done)
if (!recentsListener) {
NSArray *recentEvents = [NSMutableArray arrayWithArray:[mxHandler.mxSession recentsWithTypeIn:mxHandler.eventsFilterForMessages]];
recents = [NSMutableArray arrayWithCapacity:recentEvents.count];
for (MXEvent *mxEvent in recentEvents) {
MXRoom *mxRoom = [mxHandler.mxSession roomWithRoomId:mxEvent.roomId];
RecentRoom *recentRoom = [[RecentRoom alloc] initWithLastEvent:mxEvent andRoomState:mxRoom.state markAsUnread:NO];
if (recentRoom) {
[recents addObject:recentRoom];
}
}
unreadCount = 0;
// Check whether redaction event belongs to the listened events list
NSArray *listenedEventTypes = mxHandler.eventsFilterForMessages;
BOOL hideRedactionEvent = ([listenedEventTypes indexOfObject:kMXEventTypeStringRoomRedaction] == NSNotFound);
if (hideRedactionEvent) {
// Add redaction event to the listened events list in order to take into account redaction of the last event in recents.
// (See [RecentRoom updateWithLastEvent:...] for more details)
listenedEventTypes = [listenedEventTypes arrayByAddingObject:kMXEventTypeStringRoomRedaction];
}
// Register recent listener
recentsListener = [mxHandler.mxSession listenToEventsOfTypes:listenedEventTypes onEvent:^(MXEvent *event, MXEventDirection direction, MXRoomState *roomState) {
// Consider first live event
if (direction == MXEventDirectionForwards) {
// Check user's membership in live room state (We will remove left rooms from recents)
MXRoom *mxRoom = [mxHandler.mxSession roomWithRoomId:event.roomId];
BOOL isLeft = (mxRoom == nil || mxRoom.state.membership == MXMembershipLeave || mxRoom.state.membership == MXMembershipBan);
// Consider this new event as unread only if the sender is not the user and if the room is not visible
BOOL isUnread = (![event.userId isEqualToString:mxHandler.userId]
&& ![[AppDelegate theDelegate].masterTabBarController.visibleRoomId isEqualToString:event.roomId]);
// Look for the room
BOOL isFound = NO;
for (NSUInteger index = 0; index < recents.count; index++) {
RecentRoom *recentRoom = [recents objectAtIndex:index];
if ([event.roomId isEqualToString:recentRoom.roomId]) {
isFound = YES;
// Decrement here unreads count for this recent (we will add later the refreshed count)
unreadCount -= recentRoom.unreadCount;
if (isLeft) {
// Remove left room
[recents removeObjectAtIndex:index];
if (filteredRecents) {
NSUInteger filteredIndex = [filteredRecents indexOfObject:recentRoom];
if (filteredIndex != NSNotFound) {
[filteredRecents removeObjectAtIndex:filteredIndex];
}
}
} else {
if ([recentRoom updateWithLastEvent:event andRoomState:roomState markAsUnread:isUnread]) {
if (index) {
// Move this room at first position
[recents removeObjectAtIndex:index];
[recents insertObject:recentRoom atIndex:0];
}
// Update filtered recents (if any)
if (filteredRecents) {
NSUInteger filteredIndex = [filteredRecents indexOfObject:recentRoom];
if (filteredIndex && filteredIndex != NSNotFound) {
[filteredRecents removeObjectAtIndex:filteredIndex];
[filteredRecents insertObject:recentRoom atIndex:0];
}
}
}
// Refresh global unreads count
unreadCount += recentRoom.unreadCount;
}
// Refresh title
[self updateTitleView];
break;
}
}
if (!isFound && !isLeft) {
// Insert in first position this new room
RecentRoom *recentRoom = [[RecentRoom alloc] initWithLastEvent:event andRoomState:roomState markAsUnread:isUnread];
if (recentRoom) {
[recents insertObject:recentRoom atIndex:0];
if (isUnread) {
unreadCount++;
[self updateTitleView];
}
// Check whether we were waiting for this room
if (_preSelectedRoomId) {
if ([recentRoom.roomId isEqualToString:_preSelectedRoomId]) {
[self stopActivityIndicator];
self.preSelectedRoomId = _preSelectedRoomId;
}
}
}
}
// Reload table
[self refreshRecentsDisplay];
}
}];
}
// else nothing to do
} else if (mxHandler.status != MatrixSDKHandlerStatusPaused) {
// Here status is MatrixSDKHandlerStatusLoggedOut or MatrixSDKHandlerStatusLogged - Reset recents
recents = nil;
}
// Reload table
[self refreshRecentsDisplay];
// Check whether a room is preselected
if (_preSelectedRoomId) {
self.preSelectedRoomId = _preSelectedRoomId;
}
} else {
if (mxHandler.status == MatrixSDKHandlerStatusLoggedOut) {
// Update title
unreadCount = 0;
[self updateTitleView];
}
recents = nil;
[self refreshRecentsDisplay];
}
if (recents) {
// Add observer to force refresh when a recent last description is updated thanks to back pagination
// (This happens when the current last event description is blank, a back pagination is triggered to display non empty description)
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onRecentRoomUpdatedByBackPagination:) name:kRecentRoomUpdatedByBackPagination object:nil];
} else {
// Remove potential listener
if (recentsListener && mxHandler.mxSession) {
[mxHandler.mxSession removeListener:recentsListener];
recentsListener = nil;
}
}
[self updateTitleView];
}
- (void)onRecentRoomUpdatedByBackPagination:(NSNotification *)notif{
[self refreshRecentsDisplay];
[self updateTitleView];
if ([notif.object isKindOfClass:[NSString class]]) {
NSString* roomId = notif.object;
// Check whether this room is currently displayed in RoomViewController
if ([[AppDelegate theDelegate].masterTabBarController.visibleRoomId isEqualToString:roomId]) {
// For sanity reason, we have to force a full refresh in order to restore back state of the room
dispatch_async(dispatch_get_main_queue(), ^{
MXKRoomDataSource *roomDataSrc = currentRoomViewController.dataSource;
[currentRoomViewController displayRoom:roomDataSrc];
});
}
}
}
//- (void)onRecentRoomUpdatedByBackPagination:(NSNotification *)notif{
// [self refreshRecentsDisplay];
// [self updateTitleView];
//
// if ([notif.object isKindOfClass:[NSString class]]) {
// NSString* roomId = notif.object;
// // Check whether this room is currently displayed in RoomViewController
// if ([[AppDelegate theDelegate].masterTabBarController.visibleRoomId isEqualToString:roomId]) {
// // For sanity reason, we have to force a full refresh in order to restore back state of the room
// dispatch_async(dispatch_get_main_queue(), ^{
// MXKRoomDataSource *roomDataSrc = currentRoomViewController.dataSource;
// [currentRoomViewController displayRoom:roomDataSrc];
// });
// }
// }
//}
- (void)updateTitleView {
NSString *title = @"Recents";
if (unreadCount) {
title = [NSString stringWithFormat:@"Recents (%tu)", unreadCount];
if (self.dataSource.unreadCount) {
title = [NSString stringWithFormat:@"Recents (%tu)", self.dataSource.unreadCount];
}
self.navigationItem.title = title;
}
@ -438,7 +245,7 @@
- (void)search:(id)sender {
if (!recentsSearchBar) {
// Check whether there are data in which search
if (recents.count) {
if ([self.dataSource tableView:self.tableView numberOfRowsInSection:0]) {
// Create search bar
recentsSearchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 44)];
recentsSearchBar.showsCancelButton = YES;
@ -463,18 +270,6 @@
}
}
- (void)startActivityIndicator {
// Add the spinner on main screen in order to ignore potential table scrolling
_activityIndicator.center = CGPointMake(self.view.center.x, self.view.center.x);
[[AppDelegate theDelegate].window addSubview:_activityIndicator];
[_activityIndicator startAnimating];
}
- (void)stopActivityIndicator {
[_activityIndicator stopAnimating];
[_activityIndicator removeFromSuperview];
}
- (void)scrollToTop {
// stop any scrolling effect
[UIView setAnimationsEnabled:NO];
@ -487,11 +282,16 @@
// Update here the index of the current selected cell (if any) - Useful in landscape mode with split view controller.
currentSelectedCellIndexPathRow = -1;
if (currentRoomViewController) {
// Restore the current selected room id, it is erased when view controller disappeared (see viewWillDisappear).
if (!_selectedRoomId) {
_selectedRoomId = currentRoomViewController.dataSource.room.state.roomId;
}
// Look for the rank of this selected room in displayed recents
NSArray *displayedRecents = filteredRecents ? filteredRecents : recents;
for (NSInteger index = 0; index < displayedRecents.count; index ++) {
RecentRoom *recentRoom = [displayedRecents objectAtIndex:index];
if ([currentRoomViewController.dataSource.roomId isEqualToString:recentRoom.roomId]) {
NSInteger cellCount = [self.dataSource tableView:self.tableView numberOfRowsInSection:0];
for (NSInteger index = 0; index < cellCount; index ++) {
id<MXKRecentCellDataStoring> recentCellData = [self.dataSource cellDataAtIndex:index];
if ([_selectedRoomId isEqualToString:recentCellData.room.state.roomId]) {
currentSelectedCellIndexPathRow = index;
break;
}
@ -517,33 +317,12 @@
}
}
#pragma mark - KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([@"status" isEqualToString:keyPath]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self configureView];
});
} else if ([@"isActivityInProgress" isEqualToString:keyPath]) {
if (!shouldHideActivityIndicator && [MatrixSDKHandler sharedHandler].isActivityInProgress) {
[self startActivityIndicator];
} else {
[self stopActivityIndicator];
}
}
}
#pragma mark - Segues
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:@"showDetail"]) {
if ([[segue identifier] isEqualToString:@"showDetails"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
RecentRoom *recentRoom;
if (filteredRecents) {
recentRoom = filteredRecents[indexPath.row];
} else {
recentRoom = recents[indexPath.row];
}
id<MXKRecentCellDataStoring> recentCellData = [self.dataSource cellDataAtIndex:indexPath.row];
UIViewController *controller;
if ([[segue destinationViewController] isKindOfClass:[UINavigationController class]]) {
@ -560,14 +339,13 @@
}
currentRoomViewController = (RoomViewController *)controller;
MXKRoomDataSource *roomDataSource = [[MXKRoomDataSource alloc] initWithRoomId:recentRoom.roomId
MXKRoomDataSource *roomDataSource = [[MXKRoomDataSource alloc] initWithRoomId:_selectedRoomId
andMatrixSession:[MatrixSDKHandler sharedHandler].mxSession];
[currentRoomViewController displayRoom:roomDataSource];
}
// Reset unread count for this room
unreadCount -= recentRoom.unreadCount;
[recentRoom resetUnreadCount];
[recentCellData resetUnreadCount];
[self updateTitleView];
if (self.splitViewController) {
@ -596,113 +374,16 @@
}
}
#pragma mark - Table View
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
#pragma mark - MXKDataSourceDelegate
- (void)dataSource:(MXKDataSource *)dataSource didCellChange:(id)changes {
[self refreshRecentsDisplay];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (filteredRecents) {
return filteredRecents.count;
}
return recents.count;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 70;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
RecentsTableViewCell *cell = (RecentsTableViewCell*)[tableView dequeueReusableCellWithIdentifier:@"RecentsCell" forIndexPath:indexPath];
RecentRoom *recentRoom;
if (filteredRecents) {
recentRoom = filteredRecents[indexPath.row];
} else {
recentRoom = recents[indexPath.row];
}
#pragma mark - MXKRecentListViewControllerDelegate
- (void)recentListViewController:(MXKRecentListViewController *)recentListViewController didSelectRoom:(NSString *)aRoomId {
MatrixSDKHandler *mxHandler = [MatrixSDKHandler sharedHandler];
MXRoom *mxRoom = [mxHandler.mxSession roomWithRoomId:recentRoom.roomId];
cell.roomTitle.text = [mxRoom.state displayname];
cell.lastEventDescription.text = recentRoom.lastEventDescription;
// Set in bold public room name
if (mxRoom.state.isPublic) {
cell.roomTitle.font = [UIFont boldSystemFontOfSize:20];
} else {
cell.roomTitle.font = [UIFont systemFontOfSize:19];
}
if (recentRoom.lastEventOriginServerTs != kMXUndefinedTimestamp) {
NSDate *date = [NSDate dateWithTimeIntervalSince1970:recentRoom.lastEventOriginServerTs/1000];
cell.recentDate.text = [dateFormatter stringFromDate:date];
} else {
cell.recentDate.text = nil;
}
// Set background color
if (recentRoom.unreadCount) {
if (recentRoom.containsBingUnread) {
cell.backgroundColor = [UIColor colorWithRed:0.9 green:0.9 blue:1 alpha:1.0];
} else {
cell.backgroundColor = [UIColor colorWithRed:1 green:0.9 blue:0.9 alpha:1.0];
}
cell.roomTitle.text = [NSString stringWithFormat:@"%@ (%tu)", cell.roomTitle.text, recentRoom.unreadCount];
} else {
cell.backgroundColor = [UIColor clearColor];
}
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
// Return NO if you do not want the specified item to be editable.
return YES;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Leave the selected room
RecentRoom *selectedRoom;
if (filteredRecents) {
selectedRoom = filteredRecents[indexPath.row];
} else {
selectedRoom = recents[indexPath.row];
}
MXRoom *mxRoom = [[MatrixSDKHandler sharedHandler].mxSession roomWithRoomId:selectedRoom.roomId];
// cancel pending uploads/downloads
// they are useless by now
[MXKMediaManager cancelDownloadsInCacheFolder:selectedRoom.roomId];
// TODO GFO cancel pending uploads related to this room
[mxRoom leave:^{
// Remove the selected room (if it is not already done by recents listener)
for (NSUInteger index = 0; index < recents.count; index++) {
RecentRoom *recentRoom = [recents objectAtIndex:index];
if ([recentRoom.roomId isEqualToString:selectedRoom.roomId]) {
[recents removeObjectAtIndex:index];
if (filteredRecents) {
NSUInteger filteredIndex = [filteredRecents indexOfObject:selectedRoom];
if (filteredIndex != NSNotFound) {
[filteredRecents removeObjectAtIndex:filteredIndex];
}
}
break;
}
}
// Refresh table display
[self refreshRecentsDisplay];
} failure:^(NSError *error) {
NSLog(@"[RecentsVC] Failed to leave room (%@) failed: %@", selectedRoom.roomId, error);
//Alert user
[[AppDelegate theDelegate] showErrorAsAlert:error];
}];
}
// Change the current room id to open the room
self.selectedRoomId = aRoomId;
}
#pragma mark - UISearchBarDelegate
@ -717,26 +398,14 @@
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
// Update filtered list
// Apply filter
shouldScrollToTopOnRefresh = YES;
if (searchText.length) {
if (filteredRecents) {
[filteredRecents removeAllObjects];
} else {
filteredRecents = [NSMutableArray arrayWithCapacity:recents.count];
}
MatrixSDKHandler *mxHandler = [MatrixSDKHandler sharedHandler];
for (RecentRoom *recentRoom in recents) {
MXRoom *mxRoom = [mxHandler.mxSession roomWithRoomId:recentRoom.roomId];
if ([[mxRoom.state displayname] rangeOfString:searchText options:NSCaseInsensitiveSearch].location != NSNotFound) {
[filteredRecents addObject:recentRoom];
}
}
[self.dataSource searchWithPatterns:@[searchText]];
} else {
filteredRecents = nil;
[self.dataSource searchWithPatterns:nil];
}
// Refresh display
[self refreshRecentsDisplay];
[self scrollToTop];
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
@ -746,14 +415,16 @@
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
// Leave search
searchBarShouldEndEditing = YES;
[searchBar resignFirstResponder];
recentsSearchBar = nil;
filteredRecents = nil;
self.tableView.tableHeaderView = nil;
[self refreshRecentsDisplay];
[self scrollToTop];
// Refresh display
shouldScrollToTopOnRefresh = YES;
[self.dataSource searchWithPatterns:nil];
}
@end