mirror of
https://github.com/vector-im/element-ios.git
synced 2024-09-28 23:32:41 +00:00
Merge remote-tracking branch 'origin/develop'
This commit is contained in:
commit
e4de36cfa1
17 changed files with 816 additions and 429 deletions
|
@ -39,7 +39,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 */; };
|
||||
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 */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
|
@ -108,8 +111,12 @@
|
|||
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>"; };
|
||||
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 */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
@ -153,6 +160,8 @@
|
|||
F01628B519E298710071C473 /* Assets */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F0F90C6A1A325ABF00455977 /* icon_search@2x.png */,
|
||||
F0F90C681A32596700455977 /* icon_search.png */,
|
||||
F08B6FCB1A1DE7F80094A35B /* matrixConsole.jpg */,
|
||||
F02BCE221A1A5A2B00543B47 /* play.png */,
|
||||
F024098119E7D177006E741B /* tab_recents@2x.png */,
|
||||
|
@ -204,6 +213,8 @@
|
|||
F0465AF71A251F85003639F9 /* Model */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F0D942F41A31F3A300826CC1 /* RecentRoom.h */,
|
||||
F0D942F51A31F3A300826CC1 /* RecentRoom.m */,
|
||||
F0465AF81A251F85003639F9 /* RoomMessage.h */,
|
||||
F0465AF91A251F85003639F9 /* RoomMessage.m */,
|
||||
F01A0FF11A27314B009FAE2F /* RoomMessageComponent.h */,
|
||||
|
@ -372,7 +383,9 @@
|
|||
F0CEA5AF19E6895E00E47915 /* tab_recents.png in Resources */,
|
||||
F01628C319E29C660071C473 /* logo.png in Resources */,
|
||||
F01628C119E29C660071C473 /* default-profile.png in Resources */,
|
||||
F0F90C6B1A325ABF00455977 /* icon_search@2x.png in Resources */,
|
||||
F0CEA5AE19E6895E00E47915 /* logoHighRes.png in Resources */,
|
||||
F0F90C691A32596700455977 /* icon_search.png in Resources */,
|
||||
F0CEA5B119E6898800E47915 /* tab_home.ico in Resources */,
|
||||
F07A80E619DD9DE700B621A1 /* Images.xcassets in Resources */,
|
||||
F08B6FCC1A1DE7F80094A35B /* matrixConsole.jpg in Resources */,
|
||||
|
@ -435,6 +448,7 @@
|
|||
F03EF5FA19F171EB00A0EE52 /* RoomViewController.m in Sources */,
|
||||
F03EF5F819F171EB00A0EE52 /* MasterTabBarController.m in Sources */,
|
||||
F03EF5F619F171EB00A0EE52 /* HomeViewController.m in Sources */,
|
||||
F0D942F61A31F3A300826CC1 /* RecentRoom.m in Sources */,
|
||||
F03EF60219F19E7C00A0EE52 /* MediaManager.m in Sources */,
|
||||
F03EF5F919F171EB00A0EE52 /* RecentsViewController.m in Sources */,
|
||||
F0465AFA1A251F85003639F9 /* RoomMessage.m in Sources */,
|
||||
|
|
|
@ -70,10 +70,16 @@
|
|||
[self.errorNotification dismiss:NO];
|
||||
self.errorNotification = nil;
|
||||
}
|
||||
|
||||
// Suspend Matrix handler
|
||||
[[MatrixHandler sharedHandler] pause];
|
||||
}
|
||||
|
||||
- (void)applicationWillEnterForeground:(UIApplication *)application {
|
||||
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
|
||||
|
||||
// Resume Matrix handler
|
||||
[[MatrixHandler sharedHandler] resume];
|
||||
}
|
||||
|
||||
- (void)applicationDidBecomeActive:(UIApplication *)application {
|
||||
|
|
BIN
matrixConsole/matrixConsole/Assets/icon_search.png
Normal file
BIN
matrixConsole/matrixConsole/Assets/icon_search.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.8 KiB |
BIN
matrixConsole/matrixConsole/Assets/icon_search@2x.png
Normal file
BIN
matrixConsole/matrixConsole/Assets/icon_search@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 823 B |
|
@ -1024,7 +1024,7 @@
|
|||
</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="gray" id="4dn-O0-IJ0">
|
||||
<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>
|
||||
|
|
|
@ -27,6 +27,7 @@ extern NSString *const kMatrixHandlerUnsupportedMessagePrefix;
|
|||
@property (strong, nonatomic) NSString *homeServer;
|
||||
@property (strong, nonatomic) NSString *userLogin;
|
||||
@property (strong, nonatomic) NSString *userId;
|
||||
@property (strong, nonatomic, readonly) NSString *localPartFromUserId;
|
||||
@property (strong, nonatomic) NSString *accessToken;
|
||||
|
||||
// The type of events to display
|
||||
|
@ -38,9 +39,12 @@ extern NSString *const kMatrixHandlerUnsupportedMessagePrefix;
|
|||
|
||||
@property (nonatomic,readonly) BOOL isLogged;
|
||||
@property (nonatomic,readonly) BOOL isInitialSyncDone;
|
||||
@property (nonatomic,readonly) BOOL isResumeDone;
|
||||
|
||||
+ (MatrixHandler *)sharedHandler;
|
||||
|
||||
- (void)pause;
|
||||
- (void)resume;
|
||||
- (void)logout;
|
||||
|
||||
// Flush and restore Matrix data
|
||||
|
@ -50,6 +54,10 @@ extern NSString *const kMatrixHandlerUnsupportedMessagePrefix;
|
|||
|
||||
- (BOOL)isSupportedAttachment:(MXEvent*)event;
|
||||
- (BOOL)isEmote:(MXEvent*)event;
|
||||
|
||||
// Note: the room state expected by the 3 following methods is the room state right before handling the event
|
||||
- (NSString*)senderDisplayNameForEvent:(MXEvent*)event withRoomState:(MXRoomState*)roomState;
|
||||
- (NSString*)senderAvatarUrlForEvent:(MXEvent*)event withRoomState:(MXRoomState*)roomState;
|
||||
- (NSString*)displayTextForEvent:(MXEvent*)event withRoomState:(MXRoomState*)roomState inSubtitleMode:(BOOL)isSubtitle;
|
||||
|
||||
@end
|
||||
|
|
|
@ -28,12 +28,13 @@ static MatrixHandler *sharedHandler = nil;
|
|||
BOOL notifyOpenSessionFailure;
|
||||
|
||||
// Handle user's settings change
|
||||
id roomMembersListener;
|
||||
id userUpdateListener;
|
||||
// Handle events notification
|
||||
id eventsListener;
|
||||
}
|
||||
|
||||
@property (nonatomic,readwrite) BOOL isInitialSyncDone;
|
||||
@property (nonatomic,readwrite) BOOL isResumeDone;
|
||||
@property (strong, nonatomic) CustomAlert *mxNotification;
|
||||
|
||||
@end
|
||||
|
@ -58,6 +59,7 @@ static MatrixHandler *sharedHandler = nil;
|
|||
-(MatrixHandler *)init {
|
||||
if (self = [super init]) {
|
||||
_isInitialSyncDone = NO;
|
||||
_isResumeDone = NO;
|
||||
notifyOpenSessionFailure = YES;
|
||||
|
||||
// Read potential homeserver url in shared defaults object
|
||||
|
@ -109,7 +111,7 @@ static MatrixHandler *sharedHandler = nil;
|
|||
self.mxSession = [[MXSession alloc] initWithMatrixRestClient:self.mxRestClient andStore:store];
|
||||
// Check here whether the app user wants to display all the events
|
||||
if ([[AppSettings sharedSettings] displayAllEvents]) {
|
||||
// Use a filter to retrieve all the events
|
||||
// Use a filter to retrieve all the events (except kMXEventTypeStringPresence which are not related to a specific room)
|
||||
self.eventsFilterForMessages = @[
|
||||
kMXEventTypeStringRoomName,
|
||||
kMXEventTypeStringRoomTopic,
|
||||
|
@ -117,13 +119,9 @@ static MatrixHandler *sharedHandler = nil;
|
|||
kMXEventTypeStringRoomCreate,
|
||||
kMXEventTypeStringRoomJoinRules,
|
||||
kMXEventTypeStringRoomPowerLevels,
|
||||
kMXEventTypeStringRoomAddStateLevel,
|
||||
kMXEventTypeStringRoomSendEventLevel,
|
||||
kMXEventTypeStringRoomOpsLevel,
|
||||
kMXEventTypeStringRoomAliases,
|
||||
kMXEventTypeStringRoomMessage,
|
||||
kMXEventTypeStringRoomMessageFeedback,
|
||||
kMXEventTypeStringPresence
|
||||
kMXEventTypeStringRoomMessageFeedback
|
||||
];
|
||||
}
|
||||
else {
|
||||
|
@ -139,21 +137,16 @@ static MatrixHandler *sharedHandler = nil;
|
|||
// Launch mxSession
|
||||
[self.mxSession start:^{
|
||||
self.isInitialSyncDone = YES;
|
||||
_isResumeDone = YES;
|
||||
|
||||
// Register listener to update user's information
|
||||
roomMembersListener = [self.mxSession listenToEventsOfTypes:@[kMXEventTypeStringPresence] onEvent:^(MXEvent *event, MXEventDirection direction, id customObject) {
|
||||
// Consider only live events
|
||||
if (direction == MXEventDirectionForwards) {
|
||||
// Consider only events from app user
|
||||
if ([event.userId isEqualToString:self.userId]) {
|
||||
// Update local storage
|
||||
if (![self.userDisplayName isEqualToString:event.content[@"displayname"]]) {
|
||||
self.userDisplayName = event.content[@"displayname"];
|
||||
}
|
||||
if (![self.userPictureURL isEqualToString:event.content[@"avatar_url"]]) {
|
||||
self.userPictureURL = event.content[@"avatar_url"];
|
||||
}
|
||||
}
|
||||
userUpdateListener = [self.mxSession.myUser listenToUserUpdate:^(MXEvent *event) {
|
||||
// Update local storage
|
||||
if (![self.userDisplayName isEqualToString:event.content[@"displayname"]]) {
|
||||
self.userDisplayName = event.content[@"displayname"];
|
||||
}
|
||||
if (![self.userPictureURL isEqualToString:event.content[@"avatar_url"]]) {
|
||||
self.userPictureURL = event.content[@"avatar_url"];
|
||||
}
|
||||
}];
|
||||
|
||||
|
@ -182,9 +175,9 @@ static MatrixHandler *sharedHandler = nil;
|
|||
[self.mxSession removeListener:eventsListener];
|
||||
eventsListener = nil;
|
||||
}
|
||||
if (roomMembersListener) {
|
||||
[self.mxSession removeListener:roomMembersListener];
|
||||
roomMembersListener = nil;
|
||||
if (userUpdateListener) {
|
||||
[self.mxSession.myUser removeListener:userUpdateListener];
|
||||
userUpdateListener = nil;
|
||||
}
|
||||
[self.mxSession close];
|
||||
self.mxSession = nil;
|
||||
|
@ -197,6 +190,7 @@ static MatrixHandler *sharedHandler = nil;
|
|||
}
|
||||
|
||||
self.isInitialSyncDone = NO;
|
||||
_isResumeDone = NO;
|
||||
notifyOpenSessionFailure = YES;
|
||||
}
|
||||
|
||||
|
@ -226,9 +220,25 @@ static MatrixHandler *sharedHandler = nil;
|
|||
return (self.accessToken != nil);
|
||||
}
|
||||
|
||||
- (void)pause {
|
||||
if (self.mxSession) {
|
||||
[self.mxSession pause];
|
||||
self.isResumeDone = NO;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)resume {
|
||||
if (self.mxSession) {
|
||||
[self.mxSession resume:^{
|
||||
self.isResumeDone = YES;
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)logout {
|
||||
// Reset access token (mxSession is closed by setter)
|
||||
self.accessToken = nil;
|
||||
self.userId = nil;
|
||||
|
||||
// Reset local storage of user's settings
|
||||
self.userDisplayName = @"";
|
||||
|
@ -247,8 +257,8 @@ static MatrixHandler *sharedHandler = nil;
|
|||
if (isEnabled) {
|
||||
// Register events listener
|
||||
eventsListener = [self.mxSession listenToEventsOfTypes:self.eventsFilterForMessages onEvent:^(MXEvent *event, MXEventDirection direction, id customObject) {
|
||||
// Consider only live event (Ignore presence event)
|
||||
if (direction == MXEventDirectionForwards && (event.eventType != MXEventTypePresence)) {
|
||||
// Consider only live event
|
||||
if (direction == MXEventDirectionForwards) {
|
||||
MXRoomState* roomState = (MXRoomState*)customObject;
|
||||
// If we are running on background, show a local notif
|
||||
if (UIApplicationStateBackground == [UIApplication sharedApplication].applicationState)
|
||||
|
@ -258,8 +268,10 @@ static MatrixHandler *sharedHandler = nil;
|
|||
localNotification.hasAction = YES;
|
||||
[localNotification setAlertBody:[self displayTextForEvent:event withRoomState:roomState inSubtitleMode:YES]];
|
||||
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
|
||||
} else if ([[AppDelegate theDelegate].masterTabBarController.visibleRoomId isEqualToString:event.roomId] == NO) {
|
||||
// The concerned room is not presently visible, we display a notification by removing existing one (if any)
|
||||
} else if (![event.userId isEqualToString:self.userId]
|
||||
&& ![[AppDelegate theDelegate].masterTabBarController.visibleRoomId isEqualToString:event.roomId]) {
|
||||
// The sender is not the user and the concerned room is not presently visible,
|
||||
// we display a notification by removing existing one (if any)
|
||||
if (self.mxNotification) {
|
||||
[self.mxNotification dismiss:NO];
|
||||
}
|
||||
|
@ -347,12 +359,28 @@ static MatrixHandler *sharedHandler = nil;
|
|||
- (void)setUserId:(NSString *)inUserId {
|
||||
if (inUserId.length) {
|
||||
[[NSUserDefaults standardUserDefaults] setObject:inUserId forKey:@"userid"];
|
||||
|
||||
// Deduce local userid
|
||||
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"localuserid"];
|
||||
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"@(.*):\\w+" options:NSRegularExpressionCaseInsensitive error:nil];
|
||||
NSTextCheckingResult *match = [regex firstMatchInString:inUserId options:0 range:NSMakeRange(0, [inUserId length])];
|
||||
if (match.numberOfRanges == 2) {
|
||||
NSString* localId = [inUserId substringWithRange:[match rangeAtIndex:1]];
|
||||
if (localId) {
|
||||
[[NSUserDefaults standardUserDefaults] setObject:localId forKey:@"localuserid"];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"userid"];
|
||||
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"localuserid"];
|
||||
}
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
}
|
||||
|
||||
- (NSString *)localPartFromUserId {
|
||||
return [[NSUserDefaults standardUserDefaults] objectForKey:@"localuserid"];
|
||||
}
|
||||
|
||||
- (NSString *)accessToken {
|
||||
return [[NSUserDefaults standardUserDefaults] objectForKey:@"accesstoken"];
|
||||
}
|
||||
|
@ -438,10 +466,32 @@ static MatrixHandler *sharedHandler = nil;
|
|||
}
|
||||
|
||||
|
||||
- (NSString*)senderDisplayNameForEvent:(MXEvent*)event withRoomState:(MXRoomState*)roomState {
|
||||
// Consider first the current display name defined in provided room state (Note: this room state is supposed to not take the new event into account)
|
||||
NSString *senderDisplayName = [roomState memberName:event.userId];
|
||||
// Check whether this sender name is updated by the current event (This happens in case of new joined member)
|
||||
if ([event.content[@"displayname"] length]) {
|
||||
// Use the actual display name
|
||||
senderDisplayName = event.content[@"displayname"];
|
||||
}
|
||||
return senderDisplayName;
|
||||
}
|
||||
|
||||
- (NSString*)senderAvatarUrlForEvent:(MXEvent*)event withRoomState:(MXRoomState*)roomState {
|
||||
// Consider first the avatar url defined in provided room state (Note: this room state is supposed to not take the new event into account)
|
||||
NSString *senderAvatarUrl = [roomState memberWithUserId:event.userId].avatarUrl;
|
||||
// Check whether this avatar url is updated by the current event (This happens in case of new joined member)
|
||||
if ([event.content[@"avatar_url"] length]) {
|
||||
// Use the actual display name
|
||||
senderAvatarUrl = event.content[@"avatar_url"];
|
||||
}
|
||||
return senderAvatarUrl;
|
||||
}
|
||||
|
||||
- (NSString*)displayTextForEvent:(MXEvent*)event withRoomState:(MXRoomState*)roomState inSubtitleMode:(BOOL)isSubtitle {
|
||||
NSString *displayText = nil;
|
||||
// Prepare display name for concerned users
|
||||
NSString *memberDisplayName = [roomState memberName:event.userId];
|
||||
NSString *senderDisplayName = [self senderDisplayNameForEvent:event withRoomState:roomState];
|
||||
NSString *targetDisplayName = nil;
|
||||
if (event.stateKey) {
|
||||
targetDisplayName = [roomState memberName:event.stateKey];
|
||||
|
@ -449,11 +499,11 @@ static MatrixHandler *sharedHandler = nil;
|
|||
|
||||
switch (event.eventType) {
|
||||
case MXEventTypeRoomName: {
|
||||
displayText = [NSString stringWithFormat:@"%@ changed the room name to: %@", memberDisplayName, event.content[@"name"]];
|
||||
displayText = [NSString stringWithFormat:@"%@ changed the room name to: %@", senderDisplayName, event.content[@"name"]];
|
||||
break;
|
||||
}
|
||||
case MXEventTypeRoomTopic: {
|
||||
displayText = [NSString stringWithFormat:@"%@ changed the topic to: %@", memberDisplayName, event.content[@"topic"]];
|
||||
displayText = [NSString stringWithFormat:@"%@ changed the topic to: %@", senderDisplayName, event.content[@"topic"]];
|
||||
break;
|
||||
}
|
||||
case MXEventTypeRoomMember: {
|
||||
|
@ -494,30 +544,30 @@ static MatrixHandler *sharedHandler = nil;
|
|||
if (displayText) {
|
||||
displayText = [NSString stringWithFormat:@"%@ (picture profile was changed too)", displayText];
|
||||
} else {
|
||||
displayText = [NSString stringWithFormat:@"%@ changed their picture profile", memberDisplayName];
|
||||
displayText = [NSString stringWithFormat:@"%@ changed their picture profile", senderDisplayName];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Consider here a membership change
|
||||
if ([membership isEqualToString:@"invite"]) {
|
||||
displayText = [NSString stringWithFormat:@"%@ invited %@", memberDisplayName, targetDisplayName];
|
||||
displayText = [NSString stringWithFormat:@"%@ invited %@", senderDisplayName, targetDisplayName];
|
||||
} else if ([membership isEqualToString:@"join"]) {
|
||||
displayText = [NSString stringWithFormat:@"%@ joined", memberDisplayName];
|
||||
displayText = [NSString stringWithFormat:@"%@ joined", senderDisplayName];
|
||||
} else if ([membership isEqualToString:@"leave"]) {
|
||||
if ([event.userId isEqualToString:event.stateKey]) {
|
||||
displayText = [NSString stringWithFormat:@"%@ left", memberDisplayName];
|
||||
displayText = [NSString stringWithFormat:@"%@ left", senderDisplayName];
|
||||
} else if (prevMembership) {
|
||||
if ([prevMembership isEqualToString:@"join"] || [prevMembership isEqualToString:@"invite"]) {
|
||||
displayText = [NSString stringWithFormat:@"%@ kicked %@", memberDisplayName, targetDisplayName];
|
||||
displayText = [NSString stringWithFormat:@"%@ kicked %@", senderDisplayName, targetDisplayName];
|
||||
if (event.content[@"reason"]) {
|
||||
displayText = [NSString stringWithFormat:@"%@: %@", displayText, event.content[@"reason"]];
|
||||
}
|
||||
} else if ([prevMembership isEqualToString:@"ban"]) {
|
||||
displayText = [NSString stringWithFormat:@"%@ unbanned %@", memberDisplayName, targetDisplayName];
|
||||
displayText = [NSString stringWithFormat:@"%@ unbanned %@", senderDisplayName, targetDisplayName];
|
||||
}
|
||||
}
|
||||
} else if ([membership isEqualToString:@"ban"]) {
|
||||
displayText = [NSString stringWithFormat:@"%@ banned %@", memberDisplayName, targetDisplayName];
|
||||
displayText = [NSString stringWithFormat:@"%@ banned %@", senderDisplayName, targetDisplayName];
|
||||
if (event.content[@"reason"]) {
|
||||
displayText = [NSString stringWithFormat:@"%@: %@", displayText, event.content[@"reason"]];
|
||||
}
|
||||
|
@ -559,6 +609,9 @@ static MatrixHandler *sharedHandler = nil;
|
|||
if (event.content[@"redact"]) {
|
||||
displayText = [NSString stringWithFormat:@"%@\r\n\u2022 redact: %@", displayText, event.content[@"redact"]];
|
||||
}
|
||||
if (event.content[@"invite"]) {
|
||||
displayText = [NSString stringWithFormat:@"%@\r\n\u2022 invite: %@", displayText, event.content[@"invite"]];
|
||||
}
|
||||
|
||||
displayText = [NSString stringWithFormat:@"%@\r\nThe minimum power levels related to events are:", displayText];
|
||||
NSDictionary *events = event.content[@"events"];
|
||||
|
@ -573,27 +626,6 @@ static MatrixHandler *sharedHandler = nil;
|
|||
}
|
||||
break;
|
||||
}
|
||||
// case MXEventTypeRoomAddStateLevel: {
|
||||
// NSString *minLevel = event.content[@"level"];
|
||||
// if (minLevel) {
|
||||
// displayText = [NSString stringWithFormat:@"The minimum power level a user needs to add state is: %@", minLevel];
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
// case MXEventTypeRoomSendEventLevel: {
|
||||
// NSString *minLevel = event.content[@"level"];
|
||||
// if (minLevel) {
|
||||
// displayText = [NSString stringWithFormat:@"The minimum power level a user needs to send an event is: %@", minLevel];
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
// case MXEventTypeRoomOpsLevel: {
|
||||
// displayText = @"The minimum power levels that a user must have before acting are:";
|
||||
// for (NSString *key in event.content.allKeys) {
|
||||
// displayText = [NSString stringWithFormat:@"%@\r\n%@:%@", displayText, key, [event.content objectForKey:key]];
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
case MXEventTypeRoomAliases: {
|
||||
NSArray *aliases = event.content[@"aliases"];
|
||||
if (aliases) {
|
||||
|
@ -606,7 +638,7 @@ static MatrixHandler *sharedHandler = nil;
|
|||
displayText = [event.content[@"body"] isKindOfClass:[NSString class]] ? event.content[@"body"] : nil;
|
||||
|
||||
if ([msgtype isEqualToString:kMXMessageTypeEmote]) {
|
||||
displayText = [NSString stringWithFormat:@"* %@ %@", memberDisplayName, displayText];
|
||||
displayText = [NSString stringWithFormat:@"* %@ %@", senderDisplayName, displayText];
|
||||
} else if ([msgtype isEqualToString:kMXMessageTypeImage]) {
|
||||
displayText = displayText? displayText : @"image attachment";
|
||||
// Check attachment validity
|
||||
|
@ -654,7 +686,7 @@ static MatrixHandler *sharedHandler = nil;
|
|||
|
||||
// Check whether the sender name has to be added
|
||||
if (isSubtitle && [msgtype isEqualToString:kMXMessageTypeEmote] == NO) {
|
||||
displayText = [NSString stringWithFormat:@"%@: %@", memberDisplayName, displayText];
|
||||
displayText = [NSString stringWithFormat:@"%@: %@", senderDisplayName, displayText];
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
28
matrixConsole/matrixConsole/Model/RecentRoom.h
Normal file
28
matrixConsole/matrixConsole/Model/RecentRoom.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
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>
|
||||
|
||||
@interface RecentRoom : NSObject
|
||||
|
||||
@property (nonatomic, readonly) NSString *roomId;
|
||||
@property (nonatomic, readonly) MXEvent *lastEvent;
|
||||
@property (nonatomic, readonly) NSUInteger unreadCount;
|
||||
|
||||
- (id)initWithLastEvent:(MXEvent*)event andMarkAsUnread:(BOOL)isUnread;
|
||||
- (void)updateWithLastEvent:(MXEvent*)event andMarkAsUnread:(BOOL)isUnread;
|
||||
- (void)resetUnreadCount;
|
||||
|
||||
@end
|
50
matrixConsole/matrixConsole/Model/RecentRoom.m
Normal file
50
matrixConsole/matrixConsole/Model/RecentRoom.m
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
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"
|
||||
|
||||
@implementation RecentRoom
|
||||
|
||||
- (id)initWithLastEvent:(MXEvent*)event andMarkAsUnread:(BOOL)isUnread {
|
||||
if (self = [super init]) {
|
||||
_lastEvent = event;
|
||||
_unreadCount = isUnread ? 1 : 0;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)updateWithLastEvent:(MXEvent*)event andMarkAsUnread:(BOOL)isUnread {
|
||||
_lastEvent = event;
|
||||
if (isUnread) {
|
||||
_unreadCount ++;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)resetUnreadCount {
|
||||
_unreadCount = 0;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
_lastEvent = nil;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (NSString*)roomId {
|
||||
return _lastEvent.roomId;
|
||||
}
|
||||
|
||||
@end
|
|
@ -36,15 +36,16 @@ static NSAttributedString *messageSeparator = nil;
|
|||
|
||||
- (id)initWithEvent:(MXEvent*)event andRoomState:(MXRoomState*)roomState {
|
||||
if (self = [super init]) {
|
||||
MatrixHandler *mxHandler = [MatrixHandler sharedHandler];
|
||||
|
||||
_senderId = event.userId;
|
||||
_senderName = [roomState memberName:event.userId];
|
||||
_senderAvatarUrl = [roomState memberWithUserId:event.userId].avatarUrl;
|
||||
_senderName = [mxHandler senderDisplayNameForEvent:event withRoomState:roomState];
|
||||
_senderAvatarUrl = [mxHandler senderAvatarUrlForEvent:event withRoomState:roomState];
|
||||
_contentSize = CGSizeZero;
|
||||
currentAttributedTextMsg = nil;
|
||||
|
||||
// Set message type (consider text by default), and check attachment if any
|
||||
_messageType = RoomMessageTypeText;
|
||||
MatrixHandler *mxHandler = [MatrixHandler sharedHandler];
|
||||
if ([mxHandler isSupportedAttachment:event]) {
|
||||
// Note: event.eventType is equal here to MXEventTypeRoomMessage
|
||||
NSString *msgtype = event.content[@"msgtype"];
|
||||
|
@ -101,12 +102,14 @@ static NSAttributedString *messageSeparator = nil;
|
|||
}
|
||||
|
||||
// Check sender information
|
||||
if ((_senderName || [roomState memberName:event.userId]) &&
|
||||
([_senderName isEqualToString:[roomState memberName:event.userId]] == NO)) {
|
||||
NSString *eventSenderName = [mxHandler senderDisplayNameForEvent:event withRoomState:roomState];
|
||||
NSString *eventSenderAvatar = [mxHandler senderAvatarUrlForEvent:event withRoomState:roomState];
|
||||
if ((_senderName || eventSenderName) &&
|
||||
([_senderName isEqualToString:eventSenderName] == NO)) {
|
||||
return NO;
|
||||
}
|
||||
if ((_senderAvatarUrl || [roomState memberWithUserId:event.userId].avatarUrl) &&
|
||||
([_senderAvatarUrl isEqualToString:[roomState memberWithUserId:event.userId].avatarUrl] == NO)) {
|
||||
if ((_senderAvatarUrl || eventSenderAvatar) &&
|
||||
([_senderAvatarUrl isEqualToString:eventSenderAvatar] == NO)) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ extern NSString *const kFailedEventId;
|
|||
|
||||
typedef enum : NSUInteger {
|
||||
RoomMessageComponentStyleDefault,
|
||||
RoomMessageComponentStyleHighlighted,
|
||||
RoomMessageComponentStyleBing,
|
||||
RoomMessageComponentStyleInProgress,
|
||||
RoomMessageComponentStyleFailed,
|
||||
RoomMessageComponentStyleUnsupported
|
||||
|
|
|
@ -33,7 +33,7 @@ NSString *const kFailedEventId = @"failedEventId";
|
|||
_eventId = event.eventId;
|
||||
_height = 0;
|
||||
|
||||
NSString *senderName = [roomState memberName:event.userId];
|
||||
NSString *senderName = [mxHandler senderDisplayNameForEvent:event withRoomState:roomState];
|
||||
_startsWithSenderName = ([textMessage hasPrefix:senderName] || [mxHandler isEmote:event]);
|
||||
|
||||
// Set date time text label
|
||||
|
@ -43,21 +43,22 @@ NSString *const kFailedEventId = @"failedEventId";
|
|||
_date = nil;
|
||||
}
|
||||
|
||||
// Set state event flag
|
||||
_isStateEvent = (event.eventType != MXEventTypeRoomMessage);
|
||||
|
||||
// Set style
|
||||
BOOL isIncomingMsg = ([event.userId isEqualToString:mxHandler.userId] == NO);
|
||||
if ([textMessage hasPrefix:kMatrixHandlerUnsupportedMessagePrefix]) {
|
||||
_style = RoomMessageComponentStyleUnsupported;
|
||||
} else if ([_eventId hasPrefix:kFailedEventId]) {
|
||||
_style = RoomMessageComponentStyleFailed;
|
||||
} else if (isIncomingMsg && ([textMessage rangeOfString:mxHandler.userDisplayName options:NSCaseInsensitiveSearch].location != NSNotFound || [textMessage rangeOfString:mxHandler.userId options:NSCaseInsensitiveSearch].location != NSNotFound)) {
|
||||
_style = RoomMessageComponentStyleHighlighted;
|
||||
} else if (isIncomingMsg && !_isStateEvent && [self containsBingWord]) {
|
||||
_style = RoomMessageComponentStyleBing;
|
||||
} else if (!isIncomingMsg && [_eventId hasPrefix:kLocalEchoEventIdPrefix]) {
|
||||
_style = RoomMessageComponentStyleInProgress;
|
||||
} else {
|
||||
_style = RoomMessageComponentStyleDefault;
|
||||
}
|
||||
|
||||
_isStateEvent = (event.eventType != MXEventTypeRoomMessage);
|
||||
} else {
|
||||
// Ignore this event
|
||||
self = nil;
|
||||
|
@ -66,6 +67,29 @@ NSString *const kFailedEventId = @"failedEventId";
|
|||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)containsBingWord {
|
||||
MatrixHandler *mxHandler = [MatrixHandler sharedHandler];
|
||||
NSString *pattern = nil;
|
||||
if (mxHandler.userDisplayName.length) {
|
||||
pattern = [NSString stringWithFormat:@"\\b%@\\b", mxHandler.userDisplayName];
|
||||
}
|
||||
if (mxHandler.localPartFromUserId.length) {
|
||||
if (pattern) {
|
||||
pattern = [NSString stringWithFormat:@"(%@|\\b%@\\b)", pattern, mxHandler.localPartFromUserId];
|
||||
} else {
|
||||
pattern = [NSString stringWithFormat:@"\\b%@\\b", mxHandler.localPartFromUserId];
|
||||
}
|
||||
}
|
||||
|
||||
if (pattern) {
|
||||
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern options:NSRegularExpressionCaseInsensitive error:nil];
|
||||
if ([regex numberOfMatchesInString:_textMessage options:0 range:NSMakeRange(0, [_textMessage length])]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSDictionary*)stringAttributes {
|
||||
UIColor *textColor;
|
||||
UIFont *font;
|
||||
|
@ -74,7 +98,7 @@ NSString *const kFailedEventId = @"failedEventId";
|
|||
case RoomMessageComponentStyleDefault:
|
||||
textColor = [UIColor blackColor];
|
||||
break;
|
||||
case RoomMessageComponentStyleHighlighted:
|
||||
case RoomMessageComponentStyleBing:
|
||||
textColor = [UIColor blueColor];
|
||||
break;
|
||||
case RoomMessageComponentStyleInProgress:
|
||||
|
|
|
@ -51,38 +51,23 @@
|
|||
self.backgroundColor = [UIColor whiteColor];
|
||||
|
||||
// Handle power level display
|
||||
self.userPowerLevel.hidden = NO;
|
||||
NSDictionary *powerLevels;
|
||||
if (room.state.powerLevels[@"users"]){
|
||||
// In Matrix 0.5, users power levels are listed under the `users` dictionnary
|
||||
powerLevels = room.state.powerLevels[@"users"];
|
||||
}
|
||||
else {
|
||||
// @TODO: Remove this backward compatibility
|
||||
powerLevels = room.state.powerLevels;
|
||||
}
|
||||
|
||||
if (powerLevels) {
|
||||
int maxLevel = 0;
|
||||
for (NSString *powerLevel in powerLevels.allValues) {
|
||||
int level = [powerLevel intValue];
|
||||
if (level > maxLevel) {
|
||||
maxLevel = level;
|
||||
}
|
||||
self.userPowerLevel.hidden = NO;
|
||||
MXRoomPowerLevels *roomPowerLevels = room.state.powerLevels;
|
||||
|
||||
int maxLevel = 0;
|
||||
for (NSString *powerLevel in roomPowerLevels.users.allValues) {
|
||||
int level = [powerLevel intValue];
|
||||
if (level > maxLevel) {
|
||||
maxLevel = level;
|
||||
}
|
||||
NSString *userPowerLevel = [powerLevels objectForKey:roomMember.userId]; // CAUTION: we invoke objectForKey here because user_id starts with an '@' character
|
||||
if (userPowerLevel == nil) {
|
||||
userPowerLevel = [powerLevels valueForKey:@"default"];
|
||||
}
|
||||
float userPowerLevelFloat = 0.0;
|
||||
if (userPowerLevel) {
|
||||
userPowerLevelFloat = [userPowerLevel floatValue];
|
||||
}
|
||||
self.userPowerLevel.progress = maxLevel ? userPowerLevelFloat / maxLevel : 1;
|
||||
} else {
|
||||
self.userPowerLevel.progress = 0;
|
||||
}
|
||||
|
||||
NSUInteger userPowerLevel = [roomPowerLevels powerLevelOfUserWithUserID:roomMember.userId];
|
||||
float userPowerLevelFloat = 0.0;
|
||||
if (userPowerLevel) {
|
||||
userPowerLevelFloat = userPowerLevel;
|
||||
}
|
||||
self.userPowerLevel.progress = maxLevel ? userPowerLevelFloat / maxLevel : 1;
|
||||
|
||||
if (roomMember.membership == MXMembershipInvite) {
|
||||
self.lastActiveAgoLabel.backgroundColor = [UIColor lightGrayColor];
|
||||
self.lastActiveAgoLabel.text = @"invited";
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface HomeViewController : UITableViewController <UITextFieldDelegate>
|
||||
@interface HomeViewController : UITableViewController <UITextFieldDelegate, UISearchBarDelegate>
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -19,12 +19,17 @@
|
|||
#import "MatrixHandler.h"
|
||||
#import "AppDelegate.h"
|
||||
|
||||
|
||||
|
||||
@interface HomeViewController () {
|
||||
NSArray *publicRooms;
|
||||
|
||||
// List of public room names to highlight in displayed list
|
||||
NSArray* highlightedPublicRooms;
|
||||
|
||||
// Search in public room
|
||||
UISearchBar *recentsSearchBar;
|
||||
NSMutableArray *filteredPublicRooms;
|
||||
BOOL searchBarShouldEndEditing;
|
||||
UIView *savedTableHeaderView;
|
||||
}
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UITableView *publicRoomsTable;
|
||||
|
@ -64,6 +69,10 @@
|
|||
- (void)dealloc{
|
||||
publicRooms = nil;
|
||||
highlightedPublicRooms = nil;
|
||||
|
||||
recentsSearchBar = nil;
|
||||
filteredPublicRooms = nil;
|
||||
savedTableHeaderView = nil;
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
|
@ -84,6 +93,10 @@
|
|||
|
||||
- (void)viewWillDisappear:(BOOL)animated {
|
||||
[super viewWillDisappear:animated];
|
||||
// Leave potential search session
|
||||
if (recentsSearchBar) {
|
||||
[self searchBarCancelButtonClicked:recentsSearchBar];
|
||||
}
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:UITextFieldTextDidChangeNotification object:nil];
|
||||
}
|
||||
|
@ -110,6 +123,29 @@
|
|||
|
||||
}
|
||||
|
||||
- (void)search:(id)sender {
|
||||
if (!recentsSearchBar) {
|
||||
// Check whether there are data in which search
|
||||
if (publicRooms.count) {
|
||||
// Create search bar
|
||||
recentsSearchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 44)];
|
||||
recentsSearchBar.showsCancelButton = YES;
|
||||
recentsSearchBar.returnKeyType = UIReturnKeyDone;
|
||||
recentsSearchBar.delegate = self;
|
||||
[recentsSearchBar becomeFirstResponder];
|
||||
// Hide table header during search session
|
||||
savedTableHeaderView = self.tableView.tableHeaderView;
|
||||
self.tableView.tableHeaderView = nil;
|
||||
// Reload table in order to display search bar as section header
|
||||
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];
|
||||
[self.tableView reloadData];
|
||||
|
||||
}
|
||||
} else {
|
||||
[self searchBarCancelButtonClicked: recentsSearchBar];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dismissKeyboard {
|
||||
// Hide the keyboard
|
||||
[_roomNameTextField resignFirstResponder];
|
||||
|
@ -289,32 +325,64 @@
|
|||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
if (filteredPublicRooms) {
|
||||
return filteredPublicRooms.count;
|
||||
}
|
||||
return publicRooms.count;
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
|
||||
if (recentsSearchBar) {
|
||||
return (recentsSearchBar.frame.size.height + 40);
|
||||
}
|
||||
return 40;
|
||||
}
|
||||
|
||||
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
|
||||
UILabel *sectionHeader = [[UILabel alloc] initWithFrame:[tableView rectForHeaderInSection:section]];
|
||||
sectionHeader.font = [UIFont boldSystemFontOfSize:16];
|
||||
UIView *sectionHeader = [[UIView alloc] initWithFrame:[tableView rectForHeaderInSection:section]];
|
||||
sectionHeader.backgroundColor = [UIColor colorWithRed:0.9 green:0.9 blue:0.9 alpha:1.0];
|
||||
UILabel *sectionLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, sectionHeader.frame.size.width, 40)];
|
||||
sectionLabel.font = [UIFont boldSystemFontOfSize:16];
|
||||
sectionLabel.backgroundColor = [UIColor clearColor];
|
||||
[sectionHeader addSubview:sectionLabel];
|
||||
|
||||
if (publicRooms) {
|
||||
NSString *homeserver = [MatrixHandler sharedHandler].homeServerURL;
|
||||
if (homeserver.length) {
|
||||
sectionHeader.text = [NSString stringWithFormat:@" Public Rooms (at %@):", homeserver];
|
||||
sectionLabel.text = [NSString stringWithFormat:@" Public Rooms (at %@):", homeserver];
|
||||
} else {
|
||||
sectionHeader.text = @" Public Rooms:";
|
||||
sectionLabel.text = @" Public Rooms:";
|
||||
}
|
||||
|
||||
UIButton *searchButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[searchButton setImage:[UIImage imageNamed:@"icon_search"] forState:UIControlStateNormal];
|
||||
[searchButton setImage:[UIImage imageNamed:@"icon_search"] forState:UIControlStateHighlighted];
|
||||
[searchButton addTarget:self action:@selector(search:) forControlEvents:UIControlEventTouchUpInside];
|
||||
searchButton.frame = CGRectMake(sectionLabel.frame.size.width - 45, 0, 40, 40);
|
||||
[sectionHeader addSubview:searchButton];
|
||||
sectionHeader.userInteractionEnabled = YES;
|
||||
if (recentsSearchBar) {
|
||||
CGRect frame = recentsSearchBar.frame;
|
||||
frame.origin.y = 40;
|
||||
recentsSearchBar.frame = frame;
|
||||
[sectionHeader addSubview:recentsSearchBar];
|
||||
}
|
||||
} else {
|
||||
sectionHeader.text = @" No Public Rooms";
|
||||
sectionLabel.text = @" No Public Rooms";
|
||||
}
|
||||
|
||||
return sectionHeader;
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
// Cell is larger for public room with topic
|
||||
MXPublicRoom *publicRoom = [publicRooms objectAtIndex:indexPath.row];
|
||||
MXPublicRoom *publicRoom;
|
||||
if (filteredPublicRooms) {
|
||||
publicRoom = [filteredPublicRooms objectAtIndex:indexPath.row];
|
||||
} else {
|
||||
publicRoom = [publicRooms objectAtIndex:indexPath.row];
|
||||
}
|
||||
|
||||
if (publicRoom.topic) {
|
||||
return 60;
|
||||
}
|
||||
|
@ -322,8 +390,13 @@
|
|||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
MXPublicRoom *publicRoom = [publicRooms objectAtIndex:indexPath.row];
|
||||
UITableViewCell *cell;
|
||||
MXPublicRoom *publicRoom;
|
||||
if (filteredPublicRooms) {
|
||||
publicRoom = [filteredPublicRooms objectAtIndex:indexPath.row];
|
||||
} else {
|
||||
publicRoom = [publicRooms objectAtIndex:indexPath.row];
|
||||
}
|
||||
|
||||
// Check whether this public room has topic
|
||||
if (publicRoom.topic) {
|
||||
|
@ -351,10 +424,15 @@
|
|||
#pragma mark - Table view delegate
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
MatrixHandler *mxHandler = [MatrixHandler sharedHandler];
|
||||
MXPublicRoom *publicRoom;
|
||||
if (filteredPublicRooms) {
|
||||
publicRoom = [filteredPublicRooms objectAtIndex:indexPath.row];
|
||||
} else {
|
||||
publicRoom = [publicRooms objectAtIndex:indexPath.row];
|
||||
}
|
||||
|
||||
// Check whether the user has already joined the selected public room
|
||||
MXPublicRoom *publicRoom = [publicRooms objectAtIndex:indexPath.row];
|
||||
MatrixHandler *mxHandler = [MatrixHandler sharedHandler];
|
||||
if ([mxHandler.mxSession roomWithRoomId:publicRoom.roomId]) {
|
||||
// Open selected room
|
||||
[[AppDelegate theDelegate].masterTabBarController showRoom:publicRoom.roomId];
|
||||
|
@ -385,4 +463,55 @@
|
|||
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||
}
|
||||
|
||||
#pragma mark - UISearchBarDelegate
|
||||
|
||||
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar {
|
||||
searchBarShouldEndEditing = NO;
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar {
|
||||
return searchBarShouldEndEditing;
|
||||
}
|
||||
|
||||
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
|
||||
// Update filtered list
|
||||
if (searchText.length) {
|
||||
if (filteredPublicRooms) {
|
||||
[filteredPublicRooms removeAllObjects];
|
||||
} else {
|
||||
filteredPublicRooms = [NSMutableArray arrayWithCapacity:publicRooms.count];
|
||||
}
|
||||
for (MXPublicRoom *publicRoom in publicRooms) {
|
||||
if ([[publicRoom displayname] rangeOfString:searchText options:NSCaseInsensitiveSearch].location != NSNotFound) {
|
||||
[filteredPublicRooms addObject:publicRoom];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
filteredPublicRooms = nil;
|
||||
}
|
||||
// Refresh display
|
||||
[self.tableView reloadData];
|
||||
if (filteredPublicRooms.count) {
|
||||
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
|
||||
// "Done" key has been pressed
|
||||
searchBarShouldEndEditing = YES;
|
||||
[searchBar resignFirstResponder];
|
||||
}
|
||||
|
||||
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
|
||||
// Leave search
|
||||
searchBarShouldEndEditing = YES;
|
||||
[searchBar resignFirstResponder];
|
||||
recentsSearchBar = nil;
|
||||
filteredPublicRooms = nil;
|
||||
// Restore table header and refresh table display
|
||||
self.tableView.tableHeaderView = savedTableHeaderView;
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -17,12 +17,14 @@
|
|||
#import "RecentsViewController.h"
|
||||
#import "RoomViewController.h"
|
||||
|
||||
#import "RecentRoom.h"
|
||||
#import "RecentsTableViewCell.h"
|
||||
|
||||
#import "AppDelegate.h"
|
||||
#import "MatrixHandler.h"
|
||||
|
||||
@interface RecentsViewController () {
|
||||
// Array of RecentRooms
|
||||
NSMutableArray *recents;
|
||||
id recentsListener;
|
||||
|
||||
|
@ -59,16 +61,19 @@
|
|||
UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(createNewRoom:)];
|
||||
self.navigationItem.rightBarButtonItems = @[searchButton, addButton];
|
||||
|
||||
// Add activity indicator
|
||||
[self.view addSubview:_activityIndicator];
|
||||
_activityIndicator.center = CGPointMake(self.view.center.x, 100);
|
||||
[self.view bringSubviewToFront:_activityIndicator];
|
||||
// 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;
|
||||
|
||||
NSString *dateFormat = @"MMM dd HH:mm";
|
||||
NSString *dateFormat = @"MMM dd HH:mm";
|
||||
dateFormatter = [[NSDateFormatter alloc] init];
|
||||
[dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:[[[NSBundle mainBundle] preferredLocalizations] objectAtIndex:0]]];
|
||||
[dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
|
||||
|
@ -79,6 +84,7 @@
|
|||
- (void)dealloc {
|
||||
if (currentRoomViewController) {
|
||||
currentRoomViewController.roomId = nil;
|
||||
currentRoomViewController = nil;
|
||||
}
|
||||
if (recentsListener) {
|
||||
[[MatrixHandler sharedHandler].mxSession removeListener:recentsListener];
|
||||
|
@ -102,9 +108,10 @@
|
|||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Refresh recents table
|
||||
// Refresh display
|
||||
[self configureView];
|
||||
[[MatrixHandler sharedHandler] addObserver:self forKeyPath:@"isInitialSyncDone" options:0 context:nil];
|
||||
[[MatrixHandler sharedHandler] addObserver:self forKeyPath:@"isResumeDone" options:0 context:nil];
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated {
|
||||
|
@ -116,14 +123,22 @@
|
|||
if (recentsSearchBar) {
|
||||
[self searchBarCancelButtonClicked:recentsSearchBar];
|
||||
}
|
||||
|
||||
if (recentsListener) {
|
||||
[[MatrixHandler sharedHandler].mxSession removeListener:recentsListener];
|
||||
recentsListener = nil;
|
||||
}
|
||||
// Hide activity indicator
|
||||
[self stopActivityIndicator];
|
||||
|
||||
_preSelectedRoomId = nil;
|
||||
[[MatrixHandler sharedHandler] removeObserver:self forKeyPath:@"isInitialSyncDone"];
|
||||
[[MatrixHandler sharedHandler] removeObserver:self forKeyPath:@"isResumeDone"];
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated {
|
||||
[super viewDidAppear:animated];
|
||||
|
||||
// Release potential Room ViewController if none is visible (Note: check on room visibility is required to handle correctly splitViewController)
|
||||
if ([AppDelegate theDelegate].masterTabBarController.visibleRoomId == nil && currentRoomViewController) {
|
||||
currentRoomViewController.roomId = nil;
|
||||
currentRoomViewController = nil;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
@ -142,8 +157,8 @@
|
|||
// Look for the room index in recents list
|
||||
NSIndexPath *indexPath = nil;
|
||||
for (NSUInteger index = 0; index < recents.count; index++) {
|
||||
MXEvent *mxEvent = [recents objectAtIndex:index];
|
||||
if ([roomId isEqualToString:mxEvent.roomId]) {
|
||||
RecentRoom *recentRoom = [recents objectAtIndex:index];
|
||||
if ([roomId isEqualToString:recentRoom.roomId]) {
|
||||
indexPath = [NSIndexPath indexPathForRow:index inSection:0];
|
||||
break;
|
||||
}
|
||||
|
@ -159,7 +174,7 @@
|
|||
// Postpone room details display. We run activity indicator until recents are updated
|
||||
_preSelectedRoomId = roomId;
|
||||
// Start activity indicator
|
||||
[_activityIndicator startAnimating];
|
||||
[self startActivityIndicator];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -169,41 +184,74 @@
|
|||
- (void)configureView {
|
||||
MatrixHandler *mxHandler = [MatrixHandler sharedHandler];
|
||||
|
||||
// Remove potential listener
|
||||
if (recentsListener && mxHandler.mxSession) {
|
||||
[mxHandler.mxSession removeListener:recentsListener];
|
||||
recentsListener = nil;
|
||||
}
|
||||
|
||||
[_activityIndicator startAnimating];
|
||||
[self startActivityIndicator];
|
||||
|
||||
if ([mxHandler isInitialSyncDone] || [mxHandler isLogged] == NO) {
|
||||
// Update recents
|
||||
// Create/Update recents
|
||||
if (mxHandler.mxSession) {
|
||||
recents = [NSMutableArray arrayWithArray:[mxHandler.mxSession recentsWithTypeIn:mxHandler.eventsFilterForMessages]];
|
||||
// Register recent listener
|
||||
recentsListener = [mxHandler.mxSession listenToEventsOfTypes:mxHandler.eventsFilterForMessages onEvent:^(MXEvent *event, MXEventDirection direction, id customObject) {
|
||||
// consider only live event
|
||||
if (direction == MXEventDirectionForwards) {
|
||||
// Refresh the whole recents list
|
||||
recents = [NSMutableArray arrayWithArray:[mxHandler.mxSession recentsWithTypeIn:mxHandler.eventsFilterForMessages]];
|
||||
// Reload table
|
||||
[self.tableView reloadData];
|
||||
[_activityIndicator stopAnimating];
|
||||
|
||||
// Check whether a room is preselected
|
||||
if (_preSelectedRoomId) {
|
||||
self.preSelectedRoomId = _preSelectedRoomId;
|
||||
if (!recents) {
|
||||
NSArray *recentEvents = [NSMutableArray arrayWithArray:[mxHandler.mxSession recentsWithTypeIn:mxHandler.eventsFilterForMessages]];
|
||||
recents = [NSMutableArray arrayWithCapacity:recentEvents.count];
|
||||
for (MXEvent *mxEvent in recentEvents) {
|
||||
RecentRoom *recentRoom = [[RecentRoom alloc] initWithLastEvent:mxEvent andMarkAsUnread:NO];
|
||||
if (recentRoom) {
|
||||
[recents addObject:recentRoom];
|
||||
}
|
||||
}
|
||||
}];
|
||||
|
||||
// Register recent listener
|
||||
recentsListener = [mxHandler.mxSession listenToEventsOfTypes:mxHandler.eventsFilterForMessages onEvent:^(MXEvent *event, MXEventDirection direction, id customObject) {
|
||||
// Consider only 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;
|
||||
if (isLeft) {
|
||||
// Remove left room
|
||||
[recents removeObjectAtIndex:index];
|
||||
} else {
|
||||
[recentRoom updateWithLastEvent:event andMarkAsUnread:isUnread];
|
||||
// Move this room at first position
|
||||
[recents removeObjectAtIndex:index];
|
||||
[recents insertObject:recentRoom atIndex:0];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isFound && !isLeft) {
|
||||
// Insert in first position this new room
|
||||
RecentRoom *recentRoom = [[RecentRoom alloc] initWithLastEvent:event andMarkAsUnread:isUnread];
|
||||
if (recentRoom) {
|
||||
[recents insertObject:recentRoom atIndex:0];
|
||||
}
|
||||
}
|
||||
|
||||
// Reload table
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
}];
|
||||
}
|
||||
// else nothing to do
|
||||
} else {
|
||||
recents = nil;
|
||||
}
|
||||
|
||||
// Reload table
|
||||
[self.tableView reloadData];
|
||||
[_activityIndicator stopAnimating];
|
||||
if ([mxHandler isResumeDone]) {
|
||||
[self stopActivityIndicator];
|
||||
}
|
||||
|
||||
// Check whether a room is preselected
|
||||
if (_preSelectedRoomId) {
|
||||
|
@ -213,6 +261,14 @@
|
|||
recents = nil;
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
if (!recents) {
|
||||
// Remove potential listener
|
||||
if (recentsListener && mxHandler.mxSession) {
|
||||
[mxHandler.mxSession removeListener:recentsListener];
|
||||
recentsListener = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)createNewRoom:(id)sender {
|
||||
|
@ -238,6 +294,18 @@
|
|||
}
|
||||
}
|
||||
|
||||
- (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];
|
||||
}
|
||||
|
||||
#pragma mark - KVO
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
|
||||
|
@ -245,6 +313,12 @@
|
|||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self configureView];
|
||||
});
|
||||
} else if ([@"isResumeDone" isEqualToString:keyPath]) {
|
||||
if ([[MatrixHandler sharedHandler] isResumeDone]) {
|
||||
[self stopActivityIndicator];
|
||||
} else {
|
||||
[self startActivityIndicator];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -253,11 +327,11 @@
|
|||
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
|
||||
if ([[segue identifier] isEqualToString:@"showDetail"]) {
|
||||
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
|
||||
MXEvent *mxEvent;
|
||||
RecentRoom *recentRoom;
|
||||
if (filteredRecents) {
|
||||
mxEvent = filteredRecents[indexPath.row];
|
||||
recentRoom = filteredRecents[indexPath.row];
|
||||
} else {
|
||||
mxEvent = recents[indexPath.row];
|
||||
recentRoom = recents[indexPath.row];
|
||||
}
|
||||
|
||||
UIViewController *controller;
|
||||
|
@ -268,18 +342,24 @@
|
|||
}
|
||||
|
||||
if ([controller isKindOfClass:[RoomViewController class]]) {
|
||||
// Release potential Room ViewController
|
||||
if (currentRoomViewController) {
|
||||
if ((currentRoomViewController != controller) || (![currentRoomViewController.roomId isEqualToString:mxEvent.roomId])) {
|
||||
// Release the current one
|
||||
currentRoomViewController.roomId = nil;
|
||||
}
|
||||
currentRoomViewController.roomId = nil;
|
||||
currentRoomViewController = nil;
|
||||
}
|
||||
currentRoomViewController = (RoomViewController *)controller;
|
||||
currentRoomViewController.roomId = mxEvent.roomId;
|
||||
currentRoomViewController.roomId = recentRoom.roomId;
|
||||
}
|
||||
|
||||
controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
|
||||
controller.navigationItem.leftItemsSupplementBackButton = YES;
|
||||
// Reset unread count for this room
|
||||
[recentRoom resetUnreadCount];
|
||||
|
||||
if (self.splitViewController) {
|
||||
// Refresh display (required in case of splitViewController)
|
||||
[self.tableView reloadData];
|
||||
controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
|
||||
controller.navigationItem.leftItemsSupplementBackButton = YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -314,18 +394,18 @@
|
|||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
RecentsTableViewCell *cell = (RecentsTableViewCell*)[tableView dequeueReusableCellWithIdentifier:@"RecentsCell" forIndexPath:indexPath];
|
||||
|
||||
MXEvent *mxEvent;
|
||||
RecentRoom *recentRoom;
|
||||
if (filteredRecents) {
|
||||
mxEvent = filteredRecents[indexPath.row];
|
||||
recentRoom = filteredRecents[indexPath.row];
|
||||
} else {
|
||||
mxEvent = recents[indexPath.row];
|
||||
recentRoom = recents[indexPath.row];
|
||||
}
|
||||
|
||||
MatrixHandler *mxHandler = [MatrixHandler sharedHandler];
|
||||
MXRoom *mxRoom = [mxHandler.mxSession roomWithRoomId:mxEvent.roomId];
|
||||
MXRoom *mxRoom = [mxHandler.mxSession roomWithRoomId:recentRoom.roomId];
|
||||
|
||||
cell.roomTitle.text = [mxRoom.state displayname];
|
||||
cell.lastEventDescription.text = [mxHandler displayTextForEvent:mxEvent withRoomState:mxRoom.state inSubtitleMode:YES];
|
||||
cell.lastEventDescription.text = [mxHandler displayTextForEvent:recentRoom.lastEvent withRoomState:mxRoom.state inSubtitleMode:YES];
|
||||
|
||||
// Set in bold public room name
|
||||
if (mxRoom.state.isPublic) {
|
||||
|
@ -334,12 +414,20 @@
|
|||
cell.roomTitle.font = [UIFont systemFontOfSize:19];
|
||||
}
|
||||
|
||||
if (mxEvent.originServerTs != kMXUndefinedTimestamp) {
|
||||
NSDate *date = [NSDate dateWithTimeIntervalSince1970:mxEvent.originServerTs/1000];
|
||||
if (recentRoom.lastEvent.originServerTs != kMXUndefinedTimestamp) {
|
||||
NSDate *date = [NSDate dateWithTimeIntervalSince1970:recentRoom.lastEvent.originServerTs/1000];
|
||||
cell.recentDate.text = [dateFormatter stringFromDate:date];
|
||||
} else {
|
||||
cell.recentDate.text = nil;
|
||||
}
|
||||
}
|
||||
|
||||
// set background color
|
||||
if (recentRoom.unreadCount) {
|
||||
cell.backgroundColor = [UIColor colorWithRed:1 green:0.9 blue:0.9 alpha:1.0];
|
||||
cell.roomTitle.text = [NSString stringWithFormat:@"%@ (%lu)", cell.roomTitle.text, (unsigned long)recentRoom.unreadCount];
|
||||
} else {
|
||||
cell.backgroundColor = [UIColor clearColor];
|
||||
}
|
||||
return cell;
|
||||
}
|
||||
|
||||
|
@ -351,13 +439,13 @@
|
|||
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
if (editingStyle == UITableViewCellEditingStyleDelete) {
|
||||
// Leave the selected room
|
||||
MXEvent *mxEvent;
|
||||
RecentRoom *recentRoom;
|
||||
if (filteredRecents) {
|
||||
mxEvent = filteredRecents[indexPath.row];
|
||||
recentRoom = filteredRecents[indexPath.row];
|
||||
} else {
|
||||
mxEvent = recents[indexPath.row];
|
||||
recentRoom = recents[indexPath.row];
|
||||
}
|
||||
MXRoom *mxRoom = [[MatrixHandler sharedHandler].mxSession roomWithRoomId:mxEvent.roomId];
|
||||
MXRoom *mxRoom = [[MatrixHandler sharedHandler].mxSession roomWithRoomId:recentRoom.roomId];
|
||||
[mxRoom leave:^{
|
||||
// Refresh table display
|
||||
if (filteredRecents) {
|
||||
|
@ -367,7 +455,7 @@
|
|||
}
|
||||
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
|
||||
} failure:^(NSError *error) {
|
||||
NSLog(@"Failed to leave room (%@) failed: %@", mxEvent.roomId, error);
|
||||
NSLog(@"Failed to leave room (%@) failed: %@", recentRoom.roomId, error);
|
||||
//Alert user
|
||||
[[AppDelegate theDelegate] showErrorAsAlert:error];
|
||||
}];
|
||||
|
@ -376,6 +464,11 @@
|
|||
|
||||
#pragma mark - UISearchBarDelegate
|
||||
|
||||
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar {
|
||||
searchBarShouldEndEditing = NO;
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar {
|
||||
return searchBarShouldEndEditing;
|
||||
}
|
||||
|
@ -389,10 +482,10 @@
|
|||
filteredRecents = [NSMutableArray arrayWithCapacity:recents.count];
|
||||
}
|
||||
MatrixHandler *mxHandler = [MatrixHandler sharedHandler];
|
||||
for (MXEvent *mxEvent in recents) {
|
||||
MXRoom *mxRoom = [mxHandler.mxSession roomWithRoomId:mxEvent.roomId];
|
||||
for (RecentRoom *recentRoom in recents) {
|
||||
MXRoom *mxRoom = [mxHandler.mxSession roomWithRoomId:recentRoom.roomId];
|
||||
if ([[mxRoom.state displayname] rangeOfString:searchText options:NSCaseInsensitiveSearch].location != NSNotFound) {
|
||||
[filteredRecents addObject:mxEvent];
|
||||
[filteredRecents addObject:recentRoom];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -28,7 +28,8 @@
|
|||
|
||||
#import "MediaManager.h"
|
||||
|
||||
#define UPLOAD_FILE_SIZE 5000000
|
||||
#define ROOMVIEWCONTROLLER_UPLOAD_FILE_SIZE 5000000
|
||||
#define ROOMVIEWCONTROLLER_BACK_PAGINATION_SIZE 20
|
||||
|
||||
#define ROOM_MESSAGE_CELL_DEFAULT_HEIGHT 50
|
||||
#define ROOM_MESSAGE_CELL_DEFAULT_TEXTVIEW_TOP_CONST 10
|
||||
|
@ -57,7 +58,7 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
|
||||
// Back pagination
|
||||
BOOL isBackPaginationInProgress;
|
||||
NSUInteger backPaginationAddedItemsNb;
|
||||
NSUInteger backPaginationAddedMsgNb;
|
||||
|
||||
// Members list
|
||||
NSArray *members;
|
||||
|
@ -96,6 +97,8 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
[super viewDidLoad];
|
||||
// Do any additional setup after loading the view, typically from a nib.
|
||||
forceScrollToBottomOnViewDidAppear = YES;
|
||||
// Hide messages table by default in order to hide initial scrolling to the bottom
|
||||
self.messagesTableView.hidden = YES;
|
||||
|
||||
UIButton *button = [UIButton buttonWithType:UIButtonTypeInfoLight];
|
||||
[button addTarget:self action:@selector(showHideRoomMembers:) forControlEvents:UIControlEventTouchUpInside];
|
||||
|
@ -130,6 +133,7 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
[mxRoom removeListener:messagesListener];
|
||||
messagesListener = nil;
|
||||
[[AppSettings sharedSettings] removeObserver:self forKeyPath:@"hideUnsupportedMessages"];
|
||||
[[AppSettings sharedSettings] removeObserver:self forKeyPath:@"displayAllEvents"];
|
||||
}
|
||||
mxRoom = nil;
|
||||
|
||||
|
@ -165,9 +169,6 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onKeyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onTextFieldChange:) name:UITextFieldTextDidChangeNotification object:nil];
|
||||
|
||||
// Set visible room id
|
||||
[AppDelegate theDelegate].masterTabBarController.visibleRoomId = self.roomId;
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated {
|
||||
|
@ -185,21 +186,29 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:UITextFieldTextDidChangeNotification object:nil];
|
||||
|
||||
// Reset visible room id
|
||||
[AppDelegate theDelegate].masterTabBarController.visibleRoomId = nil;
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated {
|
||||
[super viewDidAppear:animated];
|
||||
|
||||
// Set visible room id
|
||||
[AppDelegate theDelegate].masterTabBarController.visibleRoomId = self.roomId;
|
||||
|
||||
if (forceScrollToBottomOnViewDidAppear) {
|
||||
// Scroll to the bottom
|
||||
[self scrollToBottomAnimated:animated];
|
||||
forceScrollToBottomOnViewDidAppear = NO;
|
||||
self.messagesTableView.hidden = NO;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)viewDidDisappear:(BOOL)animated {
|
||||
[super viewDidDisappear:animated];
|
||||
|
||||
// Reset visible room id
|
||||
[AppDelegate theDelegate].masterTabBarController.visibleRoomId = nil;
|
||||
}
|
||||
|
||||
#pragma mark - room ID
|
||||
|
||||
- (void)setRoomId:(NSString *)roomId {
|
||||
|
@ -240,6 +249,7 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
[mxRoom removeListener:messagesListener];
|
||||
messagesListener = nil;
|
||||
[[AppSettings sharedSettings] removeObserver:self forKeyPath:@"hideUnsupportedMessages"];
|
||||
[[AppSettings sharedSettings] removeObserver:self forKeyPath:@"displayAllEvents"];
|
||||
}
|
||||
// The whole room history is flushed here to rebuild it from the current instant (live)
|
||||
messages = nil;
|
||||
|
@ -247,10 +257,12 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
self.roomNameTextField.enabled = NO;
|
||||
|
||||
// Update room data
|
||||
MatrixHandler *mxHandler = [MatrixHandler sharedHandler];
|
||||
mxRoom = nil;
|
||||
if (self.roomId) {
|
||||
MatrixHandler *mxHandler = [MatrixHandler sharedHandler];
|
||||
mxRoom = [mxHandler.mxSession roomWithRoomId:self.roomId];
|
||||
|
||||
}
|
||||
if (mxRoom) {
|
||||
// Update room title
|
||||
self.roomNameTextField.text = mxRoom.state.displayname;
|
||||
|
||||
|
@ -279,37 +291,38 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
|
||||
messages = [NSMutableArray array];
|
||||
[[AppSettings sharedSettings] addObserver:self forKeyPath:@"hideUnsupportedMessages" options:0 context:nil];
|
||||
[[AppSettings sharedSettings] addObserver:self forKeyPath:@"displayAllEvents" options:0 context:nil];
|
||||
// Register a listener to handle messages
|
||||
messagesListener = [mxRoom listenToEventsOfTypes:mxHandler.eventsFilterForMessages onEvent:^(MXEvent *event, MXEventDirection direction, MXRoomState *roomState) {
|
||||
BOOL shouldScrollToBottom = NO;
|
||||
|
||||
// Handle first live events
|
||||
if (direction == MXEventDirectionForwards) {
|
||||
// Check user's membership in live room state (Indeed we have to go back on recents when user leaves, or is kicked/banned)
|
||||
if (mxRoom.state.membership == MXMembershipLeave || mxRoom.state.membership == MXMembershipBan) {
|
||||
[self.navigationController popViewControllerAnimated:NO];
|
||||
return;
|
||||
}
|
||||
|
||||
// We will scroll to bottom after updating tableView only if the most recent message is entirely visible.
|
||||
CGFloat maxPositionY = self.messagesTableView.contentOffset.y + (self.messagesTableView.frame.size.height - self.messagesTableView.contentInset.bottom);
|
||||
shouldScrollToBottom = (maxPositionY >= self.messagesTableView.contentSize.height);
|
||||
|
||||
// Update Table
|
||||
NSIndexPath *indexPathForInsertedRow = nil;
|
||||
NSIndexPath *indexPathForDeletedRow = nil;
|
||||
NSMutableArray *indexPathsForUpdatedRows = [NSMutableArray array];
|
||||
BOOL isComplete = NO;
|
||||
BOOL isHandled = NO;
|
||||
// For outgoing message, remove the temporary event
|
||||
if ([event.userId isEqualToString:[MatrixHandler sharedHandler].userId] && messages.count) {
|
||||
// Consider first the last message
|
||||
RoomMessage *message = [messages lastObject];
|
||||
NSUInteger index = messages.count - 1;
|
||||
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0];
|
||||
if ([message containsEventId:event.eventId]) {
|
||||
if (message.messageType == RoomMessageTypeText) {
|
||||
// Removing temporary event (local echo)
|
||||
[message removeEvent:event.eventId];
|
||||
// Update message with the received event
|
||||
isComplete = [message addEvent:event withRoomState:roomState];
|
||||
if (message.attributedTextMessage.length) {
|
||||
[indexPathsForUpdatedRows addObject:indexPath];
|
||||
} else {
|
||||
isHandled = [message addEvent:event withRoomState:roomState];
|
||||
if (! message.attributedTextMessage.length) {
|
||||
[messages removeObjectAtIndex:index];
|
||||
indexPathForDeletedRow = indexPath;
|
||||
}
|
||||
} else {
|
||||
// Create a new message to handle attachment
|
||||
|
@ -317,31 +330,24 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
if (!message) {
|
||||
// Ignore unsupported/unexpected events
|
||||
[messages removeObjectAtIndex:index];
|
||||
indexPathForDeletedRow = indexPath;
|
||||
} else {
|
||||
[messages replaceObjectAtIndex:index withObject:message];
|
||||
[indexPathsForUpdatedRows addObject:indexPath];
|
||||
}
|
||||
isComplete = YES;
|
||||
isHandled = YES;
|
||||
}
|
||||
} else {
|
||||
while (index--) {
|
||||
message = [messages objectAtIndex:index];
|
||||
indexPath = [NSIndexPath indexPathForRow:index inSection:0];
|
||||
if ([message containsEventId:event.eventId]) {
|
||||
if (message.messageType == RoomMessageTypeText) {
|
||||
// Removing temporary event (local echo)
|
||||
[message removeEvent:event.eventId];
|
||||
if (message.attributedTextMessage.length) {
|
||||
[indexPathsForUpdatedRows addObject:indexPath];
|
||||
} else {
|
||||
if (!message.attributedTextMessage.length) {
|
||||
[messages removeObjectAtIndex:index];
|
||||
indexPathForDeletedRow = indexPath;
|
||||
}
|
||||
} else {
|
||||
// Remove the local event (a new one will be added to messages)
|
||||
[messages removeObjectAtIndex:index];
|
||||
indexPathForDeletedRow = indexPath;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -349,51 +355,29 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
}
|
||||
}
|
||||
|
||||
if (isComplete == NO) {
|
||||
if (isHandled == NO) {
|
||||
// Check whether the event may be grouped with last message
|
||||
RoomMessage *lastMessage = [messages lastObject];
|
||||
if (lastMessage && [lastMessage addEvent:event withRoomState:roomState]) {
|
||||
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:(messages.count - 1) inSection:0];
|
||||
[indexPathsForUpdatedRows addObject:indexPath];
|
||||
isHandled = YES;
|
||||
} else {
|
||||
// Create a new item
|
||||
lastMessage = [[RoomMessage alloc] initWithEvent:event andRoomState:roomState];
|
||||
if (lastMessage) {
|
||||
indexPathForInsertedRow = [NSIndexPath indexPathForRow:messages.count inSection:0];
|
||||
[messages addObject:lastMessage];
|
||||
isHandled = YES;
|
||||
} // else ignore unsupported/unexpected events
|
||||
}
|
||||
}
|
||||
|
||||
// Refresh table display
|
||||
BOOL isModified = NO;
|
||||
[UIView setAnimationsEnabled:NO];
|
||||
[self.messagesTableView beginUpdates];
|
||||
if (indexPathForDeletedRow) {
|
||||
if (indexPathForInsertedRow) {
|
||||
[indexPathsForUpdatedRows removeAllObjects];
|
||||
NSUInteger index = indexPathForDeletedRow.row;
|
||||
for (; index < messages.count; index++) {
|
||||
[indexPathsForUpdatedRows addObject:[NSIndexPath indexPathForRow:index inSection:0]];
|
||||
// Refresh table display except if a back pagination is in progress
|
||||
if (!isBackPaginationInProgress) {
|
||||
[self.messagesTableView reloadData];
|
||||
if (isHandled) {
|
||||
if ([[AppDelegate theDelegate].masterTabBarController.visibleRoomId isEqualToString:self.roomId] == NO) {
|
||||
// Some new events are received for this room while it is not visible, scroll to bottom on viewDidAppear to focus on them
|
||||
forceScrollToBottomOnViewDidAppear = YES;
|
||||
}
|
||||
} else {
|
||||
[self.messagesTableView deleteRowsAtIndexPaths:@[indexPathForDeletedRow] withRowAnimation:UITableViewRowAnimationNone];
|
||||
isModified = YES;
|
||||
}
|
||||
} else if (indexPathForInsertedRow) {
|
||||
[self.messagesTableView insertRowsAtIndexPaths:@[indexPathForInsertedRow] withRowAnimation:UITableViewRowAnimationNone];
|
||||
isModified = YES;
|
||||
}
|
||||
if (indexPathsForUpdatedRows.count) {
|
||||
[self.messagesTableView reloadRowsAtIndexPaths:indexPathsForUpdatedRows withRowAnimation:UITableViewRowAnimationNone];
|
||||
isModified = YES;
|
||||
}
|
||||
[self.messagesTableView endUpdates];
|
||||
[UIView setAnimationsEnabled:YES];
|
||||
|
||||
if (isModified) {
|
||||
if ([[AppDelegate theDelegate].masterTabBarController.visibleRoomId isEqualToString:self.roomId] == NO) {
|
||||
// Some new events are received for this room while it is not visible, scroll to bottom on viewDidAppear to focus on them
|
||||
forceScrollToBottomOnViewDidAppear = YES;
|
||||
}
|
||||
}
|
||||
} else if (isBackPaginationInProgress && direction == MXEventDirectionBackwards) {
|
||||
|
@ -403,7 +387,7 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
firstMessage = [[RoomMessage alloc] initWithEvent:event andRoomState:roomState];
|
||||
if (firstMessage) {
|
||||
[messages insertObject:firstMessage atIndex:0];
|
||||
backPaginationAddedItemsNb++;
|
||||
backPaginationAddedMsgNb++;
|
||||
}
|
||||
// Ignore unsupported/unexpected events
|
||||
}
|
||||
|
@ -419,7 +403,6 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
[mxRoom resetBackState];
|
||||
[self triggerBackPagination];
|
||||
} else {
|
||||
mxRoom = nil;
|
||||
// Update room title
|
||||
self.roomNameTextField.text = nil;
|
||||
}
|
||||
|
@ -445,72 +428,81 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
if (mxRoom.canPaginate) {
|
||||
[_activityIndicator startAnimating];
|
||||
isBackPaginationInProgress = YES;
|
||||
backPaginationAddedItemsNb = 0;
|
||||
backPaginationAddedMsgNb = 0;
|
||||
|
||||
[mxRoom paginateBackMessages:20 complete:^{
|
||||
// Sanity check: check whether the view controller has not been released while back pagination was running
|
||||
if (self.roomId == nil) {
|
||||
return;
|
||||
}
|
||||
if (backPaginationAddedItemsNb) {
|
||||
// Prepare insertion of new rows at the top of the table (compute cumulative height of added cells)
|
||||
NSMutableArray *indexPaths = [NSMutableArray arrayWithCapacity:backPaginationAddedItemsNb];
|
||||
NSIndexPath *indexPath;
|
||||
CGFloat verticalOffset = 0;
|
||||
for (NSUInteger index = 0; index < backPaginationAddedItemsNb; index++) {
|
||||
indexPath = [NSIndexPath indexPathForRow:index inSection:0];
|
||||
[indexPaths addObject:indexPath];
|
||||
verticalOffset += [self tableView:self.messagesTableView heightForRowAtIndexPath:indexPath];
|
||||
}
|
||||
// Here indexPath corresponds to the first added message (We will reuse it at the end of table update to make it visible)
|
||||
// Reset count to enable tableView update
|
||||
backPaginationAddedItemsNb = 0;
|
||||
|
||||
// Disable animation during cells insertion to prevent flickering
|
||||
[UIView setAnimationsEnabled:NO];
|
||||
// Store the current content offset
|
||||
CGPoint contentOffset = self.messagesTableView.contentOffset;
|
||||
[self.messagesTableView beginUpdates];
|
||||
[self.messagesTableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
|
||||
[self.messagesTableView endUpdates];
|
||||
// Enable animation again
|
||||
[UIView setAnimationsEnabled:YES];
|
||||
// Fix vertical offset in order to prevent scrolling down
|
||||
contentOffset.y += verticalOffset;
|
||||
[self.messagesTableView setContentOffset:contentOffset animated:NO];
|
||||
[_activityIndicator stopAnimating];
|
||||
isBackPaginationInProgress = NO;
|
||||
|
||||
// Scroll tableView in order to make visible the first added message (dispatch this action in order to let table end its refresh)
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (indexPath.row == messages.count - 1) {
|
||||
[self scrollToBottomAnimated:NO];
|
||||
} else {
|
||||
[self.messagesTableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Here there was no event related to the listened types
|
||||
[_activityIndicator stopAnimating];
|
||||
isBackPaginationInProgress = NO;
|
||||
// Trigger a new back pagination (if possible)
|
||||
[self triggerBackPagination];
|
||||
}
|
||||
} failure:^(NSError *error) {
|
||||
[_activityIndicator stopAnimating];
|
||||
isBackPaginationInProgress = NO;
|
||||
backPaginationAddedItemsNb = 0;
|
||||
NSLog(@"Failed to paginate back: %@", error);
|
||||
//Alert user
|
||||
[[AppDelegate theDelegate] showErrorAsAlert:error];
|
||||
}];
|
||||
[self paginateBackMessages:ROOMVIEWCONTROLLER_BACK_PAGINATION_SIZE];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)paginateBackMessages:(NSUInteger)requestedItemsNb {
|
||||
[mxRoom paginateBackMessages:requestedItemsNb complete:^{
|
||||
// Sanity check: check whether the view controller has not been released while back pagination was running
|
||||
if (self.roomId == nil) {
|
||||
return;
|
||||
}
|
||||
// Compute number of received items
|
||||
NSUInteger itemsCount = 0;
|
||||
for (NSUInteger index = 0; index < backPaginationAddedMsgNb; index++) {
|
||||
RoomMessage *message = [messages objectAtIndex:index];
|
||||
itemsCount += message.components.count;
|
||||
}
|
||||
// Check whether we got enough items
|
||||
if (itemsCount < requestedItemsNb && mxRoom.canPaginate) {
|
||||
// Ask more items
|
||||
[self paginateBackMessages:(requestedItemsNb - itemsCount)];
|
||||
} else {
|
||||
[self onBackPaginationComplete];
|
||||
}
|
||||
} failure:^(NSError *error) {
|
||||
[self onBackPaginationComplete];
|
||||
NSLog(@"Failed to paginate back: %@", error);
|
||||
//Alert user
|
||||
[[AppDelegate theDelegate] showErrorAsAlert:error];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)onBackPaginationComplete {
|
||||
if (backPaginationAddedMsgNb) {
|
||||
// We scroll to bottom when table is loaded for the first time
|
||||
BOOL shouldScrollToBottom = (self.messagesTableView.contentSize.height == 0);
|
||||
|
||||
CGFloat verticalOffset = 0;
|
||||
if (shouldScrollToBottom == NO) {
|
||||
// In this case, we will adjust the vertical offset in order to make visible only a few part of added messages (at the top of the table)
|
||||
NSIndexPath *indexPath;
|
||||
// Compute the cumulative height of the added messages
|
||||
for (NSUInteger index = 0; index < backPaginationAddedMsgNb; index++) {
|
||||
indexPath = [NSIndexPath indexPathForRow:index inSection:0];
|
||||
verticalOffset += [self tableView:self.messagesTableView heightForRowAtIndexPath:indexPath];
|
||||
}
|
||||
// Deduce the vertical offset from this height
|
||||
verticalOffset -= 100;
|
||||
}
|
||||
// Reset count to enable tableView update
|
||||
backPaginationAddedMsgNb = 0;
|
||||
// Reload
|
||||
[self.messagesTableView reloadData];
|
||||
// Adjust vertical content offset
|
||||
if (shouldScrollToBottom) {
|
||||
[self scrollToBottomAnimated:NO];
|
||||
} else if (verticalOffset > 0) {
|
||||
// Adjust vertical offset in order to limit scrolling down
|
||||
CGPoint contentOffset = self.messagesTableView.contentOffset;
|
||||
contentOffset.y = verticalOffset - self.messagesTableView.contentInset.top;
|
||||
[self.messagesTableView setContentOffset:contentOffset animated:NO];
|
||||
}
|
||||
}
|
||||
[_activityIndicator stopAnimating];
|
||||
isBackPaginationInProgress = NO;
|
||||
}
|
||||
|
||||
#pragma mark - KVO
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
|
||||
if ([@"hideUnsupportedMessages" isEqualToString:keyPath]) {
|
||||
if ([@"displayAllEvents" isEqualToString:keyPath]) {
|
||||
// Back to recents (Room details are not available until the end of initial sync)
|
||||
[self.navigationController popViewControllerAnimated:NO];
|
||||
} else if ([@"hideUnsupportedMessages" isEqualToString:keyPath]) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self configureView];
|
||||
});
|
||||
|
@ -800,7 +792,7 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
return members.count;
|
||||
}
|
||||
|
||||
if (backPaginationAddedItemsNb) {
|
||||
if (backPaginationAddedMsgNb) {
|
||||
// Here some old messages have been added to messages during back pagination.
|
||||
// Stop table refreshing, the table will be refreshed at the end of pagination
|
||||
return 0;
|
||||
|
@ -1093,7 +1085,6 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
// Check table view members vs messages
|
||||
if (tableView == self.membersTableView) {
|
||||
// List action(s) available on this member
|
||||
// TODO: Check user's power level before allowing an action (kick, ban, ...)
|
||||
MXRoomMember *roomMember = [members objectAtIndex:indexPath.row];
|
||||
MatrixHandler *mxHandler = [MatrixHandler sharedHandler];
|
||||
__weak typeof(self) weakSelf = self;
|
||||
|
@ -1120,92 +1111,117 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
}
|
||||
}];
|
||||
} else {
|
||||
// Check user's power level before allowing an action (kick, ban, ...)
|
||||
MXRoomPowerLevels *powerLevels = [mxRoom.state powerLevels];
|
||||
NSUInteger userPowerLevel = [powerLevels powerLevelOfUserWithUserID:mxHandler.userId];
|
||||
NSUInteger memberPowerLevel = [powerLevels powerLevelOfUserWithUserID:roomMember.userId];
|
||||
// Consider membership of the selected member
|
||||
switch (roomMember.membership) {
|
||||
case MXMembershipInvite:
|
||||
case MXMembershipJoin: {
|
||||
self.actionMenu = [[CustomAlert alloc] initWithTitle:@"Select an action:" message:nil style:CustomAlertStyleActionSheet];
|
||||
[self.actionMenu addActionWithTitle:@"Kick" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) {
|
||||
if (weakSelf) {
|
||||
weakSelf.actionMenu = nil;
|
||||
[[MatrixHandler sharedHandler].mxRestClient kickUser:roomMember.userId
|
||||
fromRoom:weakSelf.roomId
|
||||
reason:nil
|
||||
success:^{
|
||||
}
|
||||
failure:^(NSError *error) {
|
||||
NSLog(@"Kick %@ failed: %@", roomMember.userId, error);
|
||||
//Alert user
|
||||
[[AppDelegate theDelegate] showErrorAsAlert:error];
|
||||
}];
|
||||
// Check conditions to be able to kick someone
|
||||
if (userPowerLevel >= [powerLevels kick] && userPowerLevel >= memberPowerLevel) {
|
||||
self.actionMenu = [[CustomAlert alloc] initWithTitle:@"Select an action:" message:nil style:CustomAlertStyleActionSheet];
|
||||
[self.actionMenu addActionWithTitle:@"Kick" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) {
|
||||
if (weakSelf) {
|
||||
weakSelf.actionMenu = nil;
|
||||
[[MatrixHandler sharedHandler].mxRestClient kickUser:roomMember.userId
|
||||
fromRoom:weakSelf.roomId
|
||||
reason:nil
|
||||
success:^{
|
||||
}
|
||||
failure:^(NSError *error) {
|
||||
NSLog(@"Kick %@ failed: %@", roomMember.userId, error);
|
||||
//Alert user
|
||||
[[AppDelegate theDelegate] showErrorAsAlert:error];
|
||||
}];
|
||||
}
|
||||
}];
|
||||
}
|
||||
// Check conditions to be able to ban someone
|
||||
if (userPowerLevel >= [powerLevels ban] && userPowerLevel >= memberPowerLevel) {
|
||||
if (!self.actionMenu) {
|
||||
self.actionMenu = [[CustomAlert alloc] initWithTitle:@"Select an action:" message:nil style:CustomAlertStyleActionSheet];
|
||||
}
|
||||
}];
|
||||
[self.actionMenu addActionWithTitle:@"Ban" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) {
|
||||
if (weakSelf) {
|
||||
weakSelf.actionMenu = nil;
|
||||
[[MatrixHandler sharedHandler].mxRestClient banUser:roomMember.userId
|
||||
inRoom:weakSelf.roomId
|
||||
reason:nil
|
||||
success:^{
|
||||
}
|
||||
failure:^(NSError *error) {
|
||||
NSLog(@"Ban %@ failed: %@", roomMember.userId, error);
|
||||
//Alert user
|
||||
[[AppDelegate theDelegate] showErrorAsAlert:error];
|
||||
}];
|
||||
}
|
||||
}];
|
||||
[self.actionMenu addActionWithTitle:@"Ban" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) {
|
||||
if (weakSelf) {
|
||||
weakSelf.actionMenu = nil;
|
||||
[[MatrixHandler sharedHandler].mxRestClient banUser:roomMember.userId
|
||||
inRoom:weakSelf.roomId
|
||||
reason:nil
|
||||
success:^{
|
||||
}
|
||||
failure:^(NSError *error) {
|
||||
NSLog(@"Ban %@ failed: %@", roomMember.userId, error);
|
||||
//Alert user
|
||||
[[AppDelegate theDelegate] showErrorAsAlert:error];
|
||||
}];
|
||||
}
|
||||
}];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MXMembershipLeave: {
|
||||
self.actionMenu = [[CustomAlert alloc] initWithTitle:@"Select an action:" message:nil style:CustomAlertStyleActionSheet];
|
||||
[self.actionMenu addActionWithTitle:@"Invite" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) {
|
||||
if (weakSelf) {
|
||||
weakSelf.actionMenu = nil;
|
||||
[[MatrixHandler sharedHandler].mxRestClient inviteUser:roomMember.userId
|
||||
toRoom:weakSelf.roomId
|
||||
success:^{
|
||||
}
|
||||
failure:^(NSError *error) {
|
||||
NSLog(@"Invite %@ failed: %@", roomMember.userId, error);
|
||||
//Alert user
|
||||
[[AppDelegate theDelegate] showErrorAsAlert:error];
|
||||
}];
|
||||
// Check conditions to be able to invite someone
|
||||
if (userPowerLevel >= [powerLevels invite]) {
|
||||
self.actionMenu = [[CustomAlert alloc] initWithTitle:@"Select an action:" message:nil style:CustomAlertStyleActionSheet];
|
||||
[self.actionMenu addActionWithTitle:@"Invite" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) {
|
||||
if (weakSelf) {
|
||||
weakSelf.actionMenu = nil;
|
||||
[[MatrixHandler sharedHandler].mxRestClient inviteUser:roomMember.userId
|
||||
toRoom:weakSelf.roomId
|
||||
success:^{
|
||||
}
|
||||
failure:^(NSError *error) {
|
||||
NSLog(@"Invite %@ failed: %@", roomMember.userId, error);
|
||||
//Alert user
|
||||
[[AppDelegate theDelegate] showErrorAsAlert:error];
|
||||
}];
|
||||
}
|
||||
}];
|
||||
}
|
||||
// Check conditions to be able to ban someone
|
||||
if (userPowerLevel >= [powerLevels ban] && userPowerLevel >= memberPowerLevel) {
|
||||
if (!self.actionMenu) {
|
||||
self.actionMenu = [[CustomAlert alloc] initWithTitle:@"Select an action:" message:nil style:CustomAlertStyleActionSheet];
|
||||
}
|
||||
}];
|
||||
[self.actionMenu addActionWithTitle:@"Ban" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) {
|
||||
if (weakSelf) {
|
||||
weakSelf.actionMenu = nil;
|
||||
[[MatrixHandler sharedHandler].mxRestClient banUser:roomMember.userId
|
||||
inRoom:weakSelf.roomId
|
||||
reason:nil
|
||||
success:^{
|
||||
}
|
||||
failure:^(NSError *error) {
|
||||
NSLog(@"Ban %@ failed: %@", roomMember.userId, error);
|
||||
//Alert user
|
||||
[[AppDelegate theDelegate] showErrorAsAlert:error];
|
||||
}];
|
||||
}
|
||||
}];
|
||||
[self.actionMenu addActionWithTitle:@"Ban" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) {
|
||||
if (weakSelf) {
|
||||
weakSelf.actionMenu = nil;
|
||||
[[MatrixHandler sharedHandler].mxRestClient banUser:roomMember.userId
|
||||
inRoom:weakSelf.roomId
|
||||
reason:nil
|
||||
success:^{
|
||||
}
|
||||
failure:^(NSError *error) {
|
||||
NSLog(@"Ban %@ failed: %@", roomMember.userId, error);
|
||||
//Alert user
|
||||
[[AppDelegate theDelegate] showErrorAsAlert:error];
|
||||
}];
|
||||
}
|
||||
}];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MXMembershipBan: {
|
||||
self.actionMenu = [[CustomAlert alloc] initWithTitle:@"Select an action:" message:nil style:CustomAlertStyleActionSheet];
|
||||
[self.actionMenu addActionWithTitle:@"Unban" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) {
|
||||
if (weakSelf) {
|
||||
weakSelf.actionMenu = nil;
|
||||
[[MatrixHandler sharedHandler].mxRestClient unbanUser:roomMember.userId
|
||||
inRoom:weakSelf.roomId
|
||||
success:^{
|
||||
}
|
||||
failure:^(NSError *error) {
|
||||
NSLog(@"Unban %@ failed: %@", roomMember.userId, error);
|
||||
//Alert user
|
||||
[[AppDelegate theDelegate] showErrorAsAlert:error];
|
||||
}];
|
||||
}
|
||||
}];
|
||||
// Check conditions to be able to unban someone
|
||||
if (userPowerLevel >= [powerLevels ban] && userPowerLevel >= memberPowerLevel) {
|
||||
self.actionMenu = [[CustomAlert alloc] initWithTitle:@"Select an action:" message:nil style:CustomAlertStyleActionSheet];
|
||||
[self.actionMenu addActionWithTitle:@"Unban" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) {
|
||||
if (weakSelf) {
|
||||
weakSelf.actionMenu = nil;
|
||||
[[MatrixHandler sharedHandler].mxRestClient unbanUser:roomMember.userId
|
||||
inRoom:weakSelf.roomId
|
||||
success:^{
|
||||
}
|
||||
failure:^(NSError *error) {
|
||||
NSLog(@"Unban %@ failed: %@", roomMember.userId, error);
|
||||
//Alert user
|
||||
[[AppDelegate theDelegate] showErrorAsAlert:error];
|
||||
}];
|
||||
}
|
||||
}];
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
|
@ -1214,14 +1230,18 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
}
|
||||
}
|
||||
|
||||
// Display the action sheet (if any)
|
||||
// Notify user when his power is too weak
|
||||
if (!self.actionMenu) {
|
||||
self.actionMenu = [[CustomAlert alloc] initWithTitle:nil message:@"You are not authorized to change the status of this member" style:CustomAlertStyleAlert];
|
||||
}
|
||||
|
||||
// Display the action sheet (or the alert)
|
||||
if (self.actionMenu) {
|
||||
self.actionMenu.cancelButtonIndex = [self.actionMenu addActionWithTitle:@"Cancel" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) {
|
||||
weakSelf.actionMenu = nil;
|
||||
}];
|
||||
[self.actionMenu showInViewController:self];
|
||||
}
|
||||
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||
} else if (tableView == self.messagesTableView) {
|
||||
// Dismiss keyboard when user taps on messages table view content
|
||||
|
@ -1235,7 +1255,9 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
// paginate ?
|
||||
if (scrollView.contentOffset.y < -64)
|
||||
{
|
||||
[self triggerBackPagination];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self triggerBackPagination];
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1258,8 +1280,26 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
|
||||
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
|
||||
if (textField == self.roomNameTextField) {
|
||||
self.roomNameTextField.borderStyle = UITextBorderStyleRoundedRect;
|
||||
self.roomNameTextField.backgroundColor = [UIColor whiteColor];
|
||||
// Check whether the user has enough power to rename the room
|
||||
MXRoomPowerLevels *powerLevels = [mxRoom.state powerLevels];
|
||||
NSUInteger userPowerLevel = [powerLevels powerLevelOfUserWithUserID:[MatrixHandler sharedHandler].userId];
|
||||
if (userPowerLevel >= [powerLevels minimumPowerLevelForPostingEventAsStateEvent:kMXEventTypeStringRoomName]) {
|
||||
self.roomNameTextField.borderStyle = UITextBorderStyleRoundedRect;
|
||||
self.roomNameTextField.backgroundColor = [UIColor whiteColor];
|
||||
return YES;
|
||||
} else {
|
||||
// Alert user
|
||||
__weak typeof(self) weakSelf = self;
|
||||
if (self.actionMenu) {
|
||||
[self.actionMenu dismiss:NO];
|
||||
}
|
||||
self.actionMenu = [[CustomAlert alloc] initWithTitle:nil message:@"You are not authorized to edit this room name" style:CustomAlertStyleAlert];
|
||||
self.actionMenu.cancelButtonIndex = [self.actionMenu addActionWithTitle:@"Cancel" style:CustomAlertActionStyleDefault handler:^(CustomAlert *alert) {
|
||||
weakSelf.actionMenu = nil;
|
||||
}];
|
||||
[self.actionMenu showInViewController:self];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
@ -1268,14 +1308,7 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
if (textField == self.roomNameTextField) {
|
||||
self.roomNameTextField.borderStyle = UITextBorderStyleNone;
|
||||
self.roomNameTextField.backgroundColor = [UIColor clearColor];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)textFieldShouldReturn:(UITextField*) textField {
|
||||
// "Done" key has been pressed
|
||||
[textField resignFirstResponder];
|
||||
|
||||
if (textField == self.roomNameTextField) {
|
||||
|
||||
NSString *roomName = self.roomNameTextField.text;
|
||||
if ([roomName isEqualToString:mxRoom.state.name] == NO) {
|
||||
[self.activityIndicator startAnimating];
|
||||
|
@ -1296,6 +1329,11 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
}];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)textFieldShouldReturn:(UITextField*) textField {
|
||||
// "Done" key has been pressed
|
||||
[textField resignFirstResponder];
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
@ -1409,17 +1447,12 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
while (index--) {
|
||||
message = [messages objectAtIndex:index];
|
||||
if ([message containsEventId:localEvent.eventId]) {
|
||||
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0];
|
||||
localEvent.content = msgContent;
|
||||
if (message.messageType == RoomMessageTypeText) {
|
||||
[message removeEvent:localEvent.eventId];
|
||||
[message addEvent:localEvent withRoomState:mxRoom.state];
|
||||
if (message.attributedTextMessage.length) {
|
||||
// Refresh table display
|
||||
[self.messagesTableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
|
||||
} else {
|
||||
if (!message.attributedTextMessage.length) {
|
||||
[messages removeObjectAtIndex:index];
|
||||
[self.messagesTableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
|
||||
}
|
||||
} else {
|
||||
// Create a new message
|
||||
|
@ -1427,15 +1460,14 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
if (message) {
|
||||
// Refresh table display
|
||||
[messages replaceObjectAtIndex:index withObject:message];
|
||||
[self.messagesTableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
|
||||
} else {
|
||||
[messages removeObjectAtIndex:index];
|
||||
[self.messagesTableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
[self.messagesTableView reloadData];
|
||||
} else {
|
||||
// Create a temporary event to displayed outgoing message (local echo)
|
||||
NSString* localEventId = [NSString stringWithFormat:@"%@%@", kLocalEchoEventIdPrefix, [[NSProcessInfo processInfo] globallyUniqueString]];
|
||||
|
@ -1449,19 +1481,16 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
localEvent.originServerTs = kMXUndefinedTimestamp;
|
||||
// Check whether this new event may be grouped with last message
|
||||
RoomMessage *lastMessage = [messages lastObject];
|
||||
if (lastMessage && [lastMessage addEvent:localEvent withRoomState:mxRoom.state]) {
|
||||
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:(messages.count - 1) inSection:0];
|
||||
[self.messagesTableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
|
||||
} else {
|
||||
if (lastMessage == nil || [lastMessage addEvent:localEvent withRoomState:mxRoom.state] == NO) {
|
||||
// Create a new item
|
||||
lastMessage = [[RoomMessage alloc] initWithEvent:localEvent andRoomState:mxRoom.state];
|
||||
if (lastMessage) {
|
||||
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:messages.count inSection:0];
|
||||
[messages addObject:lastMessage];
|
||||
[self.messagesTableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
|
||||
} else {
|
||||
NSLog(@"ERROR: Unable to add local event: %@", localEvent.description);
|
||||
}
|
||||
}
|
||||
[self.messagesTableView reloadData];
|
||||
[self scrollToBottomAnimated:NO];
|
||||
}
|
||||
|
||||
|
@ -1482,7 +1511,6 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
while (index--) {
|
||||
RoomMessage *message = [messages objectAtIndex:index];
|
||||
if ([message containsEventId:localEvent.eventId]) {
|
||||
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0];
|
||||
if (message.messageType == RoomMessageTypeText) {
|
||||
[message removeEvent:localEvent.eventId];
|
||||
if (isEventAlreadyAddedToRoom == NO) {
|
||||
|
@ -1490,12 +1518,8 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
localEvent.eventId = event_id;
|
||||
[message addEvent:localEvent withRoomState:mxRoom.state];
|
||||
}
|
||||
if (message.attributedTextMessage.length) {
|
||||
// Refresh table display
|
||||
[self.messagesTableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
|
||||
} else {
|
||||
if (! message.attributedTextMessage.length) {
|
||||
[messages removeObjectAtIndex:index];
|
||||
[self.messagesTableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
|
||||
}
|
||||
} else {
|
||||
message = nil;
|
||||
|
@ -1507,15 +1531,14 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
if (message) {
|
||||
// Refresh table display
|
||||
[messages replaceObjectAtIndex:index withObject:message];
|
||||
[self.messagesTableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
|
||||
} else {
|
||||
[messages removeObjectAtIndex:index];
|
||||
[self.messagesTableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
[self.messagesTableView reloadData];
|
||||
} failure:^(NSError *error) {
|
||||
[self handleError:error forLocalEvent:localEvent];
|
||||
}];
|
||||
|
@ -1564,13 +1587,11 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
// Update table sources
|
||||
RoomMessage *message = [[RoomMessage alloc] initWithEvent:mxEvent andRoomState:mxRoom.state];
|
||||
if (message) {
|
||||
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:messages.count inSection:0];
|
||||
[messages addObject:message];
|
||||
[self.messagesTableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
|
||||
} else {
|
||||
NSLog(@"ERROR: Unable to add local event for attachment: %@", mxEvent.description);
|
||||
}
|
||||
|
||||
[self.messagesTableView reloadData];
|
||||
[self scrollToBottomAnimated:NO];
|
||||
return mxEvent;
|
||||
}
|
||||
|
@ -1588,17 +1609,12 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
RoomMessage *message = [messages objectAtIndex:index];
|
||||
if ([message containsEventId:localEvent.eventId]) {
|
||||
NSLog(@"Posted event: %@", localEvent.description);
|
||||
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0];
|
||||
if (message.messageType == RoomMessageTypeText) {
|
||||
[message removeEvent:localEvent.eventId];
|
||||
localEvent.eventId = kFailedEventId;
|
||||
[message addEvent:localEvent withRoomState:mxRoom.state];
|
||||
if (message.attributedTextMessage.length) {
|
||||
// Refresh table display
|
||||
[self.messagesTableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
|
||||
} else {
|
||||
if (!message.attributedTextMessage.length) {
|
||||
[messages removeObjectAtIndex:index];
|
||||
[self.messagesTableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
|
||||
}
|
||||
} else {
|
||||
// Create a new message
|
||||
|
@ -1607,15 +1623,14 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
if (message) {
|
||||
// Refresh table display
|
||||
[messages replaceObjectAtIndex:index withObject:message];
|
||||
[self.messagesTableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
|
||||
} else {
|
||||
[messages removeObjectAtIndex:index];
|
||||
[self.messagesTableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
[self.messagesTableView reloadData];
|
||||
}
|
||||
|
||||
- (BOOL)isIRCStyleCommand:(NSString*)text{
|
||||
|
@ -1878,7 +1893,7 @@ NSString *const kCmdResetUserPowerLevel = @"/deop";
|
|||
NSData *videoData = [NSData dataWithContentsOfURL:tmpVideoLocation];
|
||||
[[NSFileManager defaultManager] removeItemAtPath:[tmpVideoLocation path] error:nil];
|
||||
if (videoData) {
|
||||
if (videoData.length < UPLOAD_FILE_SIZE) {
|
||||
if (videoData.length < ROOMVIEWCONTROLLER_UPLOAD_FILE_SIZE) {
|
||||
[videoInfo setValue:[NSNumber numberWithUnsignedInteger:videoData.length] forKey:@"size"];
|
||||
[mxHandler.mxRestClient uploadContent:videoData mimeType:videoInfo[@"mimetype"] timeout:30 success:^(NSString *url) {
|
||||
[videoContent setValue:url forKey:@"url"];
|
||||
|
|
Loading…
Reference in a new issue