mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-05-14 03:40:00 +02:00
Merge pull request #1943 from vector-im/async_timeline_and_state
MXRoom: Make access to liveTimeline data async
This commit is contained in:
+170
-147
@@ -1108,37 +1108,42 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
|
||||
{
|
||||
NSArray* mxAccounts = [MXKAccountManager sharedManager].activeAccounts;
|
||||
MXKRoomDataSource* roomDataSource = nil;
|
||||
MXKRoomDataSourceManager* manager;
|
||||
for (MXKAccount* account in mxAccounts)
|
||||
{
|
||||
MXRoom* room = [account.mxSession roomWithRoomId:roomId];
|
||||
if (room)
|
||||
{
|
||||
MXKRoomDataSourceManager* manager = [MXKRoomDataSourceManager sharedManagerForMatrixSession:account.mxSession];
|
||||
manager = [MXKRoomDataSourceManager sharedManagerForMatrixSession:account.mxSession];
|
||||
if (manager)
|
||||
{
|
||||
roomDataSource = [manager roomDataSourceForRoom:roomId create:YES];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (roomDataSource == nil)
|
||||
if (manager == nil)
|
||||
{
|
||||
NSLog(@"[AppDelegate][Push] handleActionWithIdentifier: room with id %@ not found", roomId);
|
||||
}
|
||||
else
|
||||
{
|
||||
NSString* responseText = [responseInfo objectForKey:UIUserNotificationActionResponseTypedTextKey];
|
||||
if (responseText != nil && responseText.length != 0)
|
||||
{
|
||||
NSLog(@"[AppDelegate][Push] handleActionWithIdentifier: sending message to room: %@", roomId);
|
||||
[roomDataSource sendTextMessage:responseText success:^(NSString* eventId) {} failure:^(NSError* error) {
|
||||
UILocalNotification* failureNotification = [[UILocalNotification alloc] init];
|
||||
failureNotification.alertBody = NSLocalizedStringFromTable(@"room_event_failed_to_send", @"Vector", nil);
|
||||
failureNotification.userInfo = notification.userInfo;
|
||||
[[UIApplication sharedApplication] scheduleLocalNotification: failureNotification];
|
||||
NSLog(@"[AppDelegate][Push] handleActionWithIdentifier: error sending text message: %@", error);
|
||||
}];
|
||||
}
|
||||
[manager roomDataSourceForRoom:roomId create:YES onComplete:^(MXKRoomDataSource *roomDataSource) {
|
||||
NSString* responseText = [responseInfo objectForKey:UIUserNotificationActionResponseTypedTextKey];
|
||||
if (responseText != nil && responseText.length != 0)
|
||||
{
|
||||
NSLog(@"[AppDelegate][Push] handleActionWithIdentifier: sending message to room: %@", roomId);
|
||||
[roomDataSource sendTextMessage:responseText success:^(NSString* eventId) {} failure:^(NSError* error) {
|
||||
UILocalNotification* failureNotification = [[UILocalNotification alloc] init];
|
||||
failureNotification.alertBody = NSLocalizedStringFromTable(@"room_event_failed_to_send", @"Vector", nil);
|
||||
failureNotification.userInfo = notification.userInfo;
|
||||
[[UIApplication sharedApplication] scheduleLocalNotification: failureNotification];
|
||||
NSLog(@"[AppDelegate][Push] handleActionWithIdentifier: error sending text message: %@", error);
|
||||
}];
|
||||
}
|
||||
|
||||
completionHandler();
|
||||
}];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1308,7 +1313,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
|
||||
NSLog(@"[AppDelegate][Push] handleLocalNotificationsForAccount: eventsToNotify: %@", eventsToNotify[@(account.mxSession.hash)]);
|
||||
NSLog(@"[AppDelegate][Push] handleLocalNotificationsForAccount: incomingPushEventIds: %@", self.incomingPushEventIds[@(account.mxSession.hash)]);
|
||||
|
||||
NSUInteger scheduledNotifications = 0;
|
||||
__block NSUInteger scheduledNotifications = 0;
|
||||
|
||||
// The call invite are handled here only when the callkit is not active.
|
||||
BOOL isCallKitActive = [MXCallKitAdapter callKitAvailable] && [MXKAppSettings standardAppSettings].isCallKitEnabled;
|
||||
@@ -1385,54 +1390,56 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
|
||||
|
||||
// Prepare the local notification
|
||||
MXPushRule *rule = eventDict[@"push_rule"];
|
||||
|
||||
NSString *notificationBody = [self notificationBodyForEvent:event pushRule:rule inAccount:account];
|
||||
if (notificationBody)
|
||||
{
|
||||
// Printf style escape characters are stripped from the string prior to display;
|
||||
// to include a percent symbol (%) in the message, use two percent symbols (%%).
|
||||
notificationBody = [notificationBody stringByReplacingOccurrencesOfString:@"%" withString:@"%%"];
|
||||
|
||||
UILocalNotification *eventNotification = [[UILocalNotification alloc] init];
|
||||
eventNotification.alertBody = notificationBody;
|
||||
eventNotification.userInfo = @{
|
||||
@"type": @"full",
|
||||
@"room_id": event.roomId,
|
||||
@"event_id": event.eventId,
|
||||
@"user_id": account.mxCredentials.userId
|
||||
};
|
||||
|
||||
BOOL isNotificationContentShown = !event.isEncrypted || RiotSettings.shared.showDecryptedContentInNotifications;
|
||||
|
||||
if ((event.eventType == MXEventTypeRoomMessage || event.eventType == MXEventTypeRoomEncrypted) && isNotificationContentShown)
|
||||
{
|
||||
eventNotification.category = @"QUICK_REPLY";
|
||||
}
|
||||
|
||||
// Set sound name based on the value provided in action of MXPushRule
|
||||
for (MXPushRuleAction *action in rule.actions)
|
||||
[self notificationBodyForEvent:event pushRule:rule inAccount:account onComplete:^(NSString * _Nullable notificationBody) {
|
||||
|
||||
if (notificationBody)
|
||||
{
|
||||
if (action.actionType == MXPushRuleActionTypeSetTweak)
|
||||
// Printf style escape characters are stripped from the string prior to display;
|
||||
// to include a percent symbol (%) in the message, use two percent symbols (%%).
|
||||
notificationBody = [notificationBody stringByReplacingOccurrencesOfString:@"%" withString:@"%%"];
|
||||
|
||||
UILocalNotification *eventNotification = [[UILocalNotification alloc] init];
|
||||
eventNotification.alertBody = notificationBody;
|
||||
eventNotification.userInfo = @{
|
||||
@"type": @"full",
|
||||
@"room_id": event.roomId,
|
||||
@"event_id": event.eventId,
|
||||
@"user_id": account.mxCredentials.userId
|
||||
};
|
||||
|
||||
BOOL isNotificationContentShown = !event.isEncrypted || RiotSettings.shared.showDecryptedContentInNotifications;
|
||||
|
||||
if ((event.eventType == MXEventTypeRoomMessage || event.eventType == MXEventTypeRoomEncrypted) && isNotificationContentShown)
|
||||
{
|
||||
if ([action.parameters[@"set_tweak"] isEqualToString:@"sound"])
|
||||
eventNotification.category = @"QUICK_REPLY";
|
||||
}
|
||||
|
||||
// Set sound name based on the value provided in action of MXPushRule
|
||||
for (MXPushRuleAction *action in rule.actions)
|
||||
{
|
||||
if (action.actionType == MXPushRuleActionTypeSetTweak)
|
||||
{
|
||||
NSString *soundName = action.parameters[@"value"];
|
||||
if ([soundName isEqualToString:@"default"])
|
||||
soundName = @"message.mp3";
|
||||
|
||||
eventNotification.soundName = soundName;
|
||||
if ([action.parameters[@"set_tweak"] isEqualToString:@"sound"])
|
||||
{
|
||||
NSString *soundName = action.parameters[@"value"];
|
||||
if ([soundName isEqualToString:@"default"])
|
||||
soundName = @"message.mp3";
|
||||
|
||||
eventNotification.soundName = soundName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NSLog(@"[AppDelegate][Push] handleLocalNotificationsForAccount: Display notification for event %@", event.eventId);
|
||||
[[UIApplication sharedApplication] scheduleLocalNotification:eventNotification];
|
||||
scheduledNotifications++;
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"[AppDelegate][Push] handleLocalNotificationsForAccount: Skip event with empty generated notificationBody. Event id: %@", event.eventId);
|
||||
}
|
||||
NSLog(@"[AppDelegate][Push] handleLocalNotificationsForAccount: Display notification for event %@", event.eventId);
|
||||
[[UIApplication sharedApplication] scheduleLocalNotification:eventNotification];
|
||||
scheduledNotifications++;
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"[AppDelegate][Push] handleLocalNotificationsForAccount: Skip event with empty generated notificationBody. Event id: %@", event.eventId);
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1441,120 +1448,130 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
|
||||
[eventsArray removeAllObjects];
|
||||
}
|
||||
|
||||
- (nullable NSString *)notificationBodyForEvent:(MXEvent *)event pushRule:(MXPushRule*)rule inAccount:(MXKAccount*)account
|
||||
- (void)notificationBodyForEvent:(MXEvent *)event pushRule:(MXPushRule*)rule inAccount:(MXKAccount*)account onComplete:(void (^)(NSString * _Nullable notificationBody))onComplete;
|
||||
{
|
||||
if (!event.content || !event.content.count)
|
||||
{
|
||||
NSLog(@"[AppDelegate][Push] notificationBodyForEvent: empty event content");
|
||||
return nil;
|
||||
onComplete (nil);
|
||||
return;
|
||||
}
|
||||
|
||||
MXRoom *room = [account.mxSession roomWithRoomId:event.roomId];
|
||||
MXRoomState *roomState = room.state;
|
||||
|
||||
NSString *notificationBody;
|
||||
NSString *eventSenderName = [roomState.members memberName:event.sender];
|
||||
|
||||
if (event.eventType == MXEventTypeRoomMessage || event.eventType == MXEventTypeRoomEncrypted)
|
||||
if (!room)
|
||||
{
|
||||
if (room.isMentionsOnly)
|
||||
NSLog(@"[AppDelegate][Push] notificationBodyForEvent: Unknown room");
|
||||
onComplete (nil);
|
||||
return;
|
||||
}
|
||||
|
||||
[room members:^(MXRoomMembers *roomMembers) {
|
||||
|
||||
NSString *notificationBody;
|
||||
NSString *eventSenderName = [roomMembers memberName:event.sender];
|
||||
|
||||
if (event.eventType == MXEventTypeRoomMessage || event.eventType == MXEventTypeRoomEncrypted)
|
||||
{
|
||||
// A local notification will be displayed only for highlighted notification.
|
||||
BOOL isHighlighted = NO;
|
||||
|
||||
// Check whether is there an highlight tweak on it
|
||||
for (MXPushRuleAction *ruleAction in rule.actions)
|
||||
if (room.isMentionsOnly)
|
||||
{
|
||||
if (ruleAction.actionType == MXPushRuleActionTypeSetTweak)
|
||||
// A local notification will be displayed only for highlighted notification.
|
||||
BOOL isHighlighted = NO;
|
||||
|
||||
// Check whether is there an highlight tweak on it
|
||||
for (MXPushRuleAction *ruleAction in rule.actions)
|
||||
{
|
||||
if ([ruleAction.parameters[@"set_tweak"] isEqualToString:@"highlight"])
|
||||
if (ruleAction.actionType == MXPushRuleActionTypeSetTweak)
|
||||
{
|
||||
// Check the highlight tweak "value"
|
||||
// If not present, highlight. Else check its value before highlighting
|
||||
if (nil == ruleAction.parameters[@"value"] || YES == [ruleAction.parameters[@"value"] boolValue])
|
||||
if ([ruleAction.parameters[@"set_tweak"] isEqualToString:@"highlight"])
|
||||
{
|
||||
isHighlighted = YES;
|
||||
break;
|
||||
// Check the highlight tweak "value"
|
||||
// If not present, highlight. Else check its value before highlighting
|
||||
if (nil == ruleAction.parameters[@"value"] || YES == [ruleAction.parameters[@"value"] boolValue])
|
||||
{
|
||||
isHighlighted = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isHighlighted)
|
||||
{
|
||||
// Ignore this notif.
|
||||
NSLog(@"[AppDelegate][Push] notificationBodyForEvent: Ignore non highlighted notif in mentions only room");
|
||||
onComplete(nil);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isHighlighted)
|
||||
|
||||
NSString *msgType = event.content[@"msgtype"];
|
||||
NSString *content = event.content[@"body"];
|
||||
|
||||
if (event.isEncrypted && !RiotSettings.shared.showDecryptedContentInNotifications)
|
||||
{
|
||||
// Ignore this notif.
|
||||
NSLog(@"[AppDelegate][Push] notificationBodyForEvent: Ignore non highlighted notif in mentions only room");
|
||||
return nil;
|
||||
// Hide the content
|
||||
msgType = nil;
|
||||
}
|
||||
|
||||
NSString *roomDisplayName = room.summary.displayname;
|
||||
|
||||
// Display the room name only if it is different than the sender name
|
||||
if (roomDisplayName.length && ![roomDisplayName isEqualToString:eventSenderName])
|
||||
{
|
||||
if ([msgType isEqualToString:@"m.text"])
|
||||
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"MSG_FROM_USER_IN_ROOM_WITH_CONTENT", nil), eventSenderName,roomDisplayName, content];
|
||||
else if ([msgType isEqualToString:@"m.emote"])
|
||||
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"ACTION_FROM_USER_IN_ROOM", nil), roomDisplayName, eventSenderName, content];
|
||||
else if ([msgType isEqualToString:@"m.image"])
|
||||
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"IMAGE_FROM_USER_IN_ROOM", nil), eventSenderName, content, roomDisplayName];
|
||||
else
|
||||
// Encrypted messages falls here
|
||||
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"MSG_FROM_USER_IN_ROOM", nil), eventSenderName, roomDisplayName];
|
||||
}
|
||||
else
|
||||
{
|
||||
if ([msgType isEqualToString:@"m.text"])
|
||||
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"MSG_FROM_USER_WITH_CONTENT", nil), eventSenderName, content];
|
||||
else if ([msgType isEqualToString:@"m.emote"])
|
||||
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"ACTION_FROM_USER", nil), eventSenderName, content];
|
||||
else if ([msgType isEqualToString:@"m.image"])
|
||||
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"IMAGE_FROM_USER", nil), eventSenderName, content];
|
||||
else
|
||||
// Encrypted messages falls here
|
||||
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"MSG_FROM_USER", nil), eventSenderName];
|
||||
}
|
||||
}
|
||||
|
||||
NSString *msgType = event.content[@"msgtype"];
|
||||
NSString *content = event.content[@"body"];
|
||||
|
||||
if (event.isEncrypted && !RiotSettings.shared.showDecryptedContentInNotifications)
|
||||
else if (event.eventType == MXEventTypeCallInvite)
|
||||
{
|
||||
// Hide the content
|
||||
msgType = nil;
|
||||
}
|
||||
|
||||
NSString *roomDisplayName = room.summary.displayname;
|
||||
|
||||
// Display the room name only if it is different than the sender name
|
||||
if (roomDisplayName.length && ![roomDisplayName isEqualToString:eventSenderName])
|
||||
{
|
||||
if ([msgType isEqualToString:@"m.text"])
|
||||
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"MSG_FROM_USER_IN_ROOM_WITH_CONTENT", nil), eventSenderName,roomDisplayName, content];
|
||||
else if ([msgType isEqualToString:@"m.emote"])
|
||||
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"ACTION_FROM_USER_IN_ROOM", nil), roomDisplayName, eventSenderName, content];
|
||||
else if ([msgType isEqualToString:@"m.image"])
|
||||
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"IMAGE_FROM_USER_IN_ROOM", nil), eventSenderName, content, roomDisplayName];
|
||||
NSString *sdp = event.content[@"offer"][@"sdp"];
|
||||
BOOL isVideoCall = [sdp rangeOfString:@"m=video"].location != NSNotFound;
|
||||
|
||||
if (!isVideoCall)
|
||||
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"VOICE_CALL_FROM_USER", nil), eventSenderName];
|
||||
else
|
||||
// Encrypted messages falls here
|
||||
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"VIDEO_CALL_FROM_USER", nil), eventSenderName];
|
||||
}
|
||||
else if (event.eventType == MXEventTypeRoomMember)
|
||||
{
|
||||
NSString *roomDisplayName = room.summary.displayname;
|
||||
|
||||
if (roomDisplayName.length && ![roomDisplayName isEqualToString:eventSenderName])
|
||||
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"USER_INVITE_TO_NAMED_ROOM", nil), eventSenderName, roomDisplayName];
|
||||
else
|
||||
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"USER_INVITE_TO_CHAT", nil), eventSenderName];
|
||||
}
|
||||
else if (event.eventType == MXEventTypeSticker)
|
||||
{
|
||||
NSString *roomDisplayName = room.summary.displayname;
|
||||
|
||||
if (roomDisplayName.length && ![roomDisplayName isEqualToString:eventSenderName])
|
||||
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"MSG_FROM_USER_IN_ROOM", nil), eventSenderName, roomDisplayName];
|
||||
}
|
||||
else
|
||||
{
|
||||
if ([msgType isEqualToString:@"m.text"])
|
||||
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"MSG_FROM_USER_WITH_CONTENT", nil), eventSenderName, content];
|
||||
else if ([msgType isEqualToString:@"m.emote"])
|
||||
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"ACTION_FROM_USER", nil), eventSenderName, content];
|
||||
else if ([msgType isEqualToString:@"m.image"])
|
||||
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"IMAGE_FROM_USER", nil), eventSenderName, content];
|
||||
else
|
||||
// Encrypted messages falls here
|
||||
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"MSG_FROM_USER", nil), eventSenderName];
|
||||
}
|
||||
}
|
||||
else if (event.eventType == MXEventTypeCallInvite)
|
||||
{
|
||||
NSString *sdp = event.content[@"offer"][@"sdp"];
|
||||
BOOL isVideoCall = [sdp rangeOfString:@"m=video"].location != NSNotFound;
|
||||
|
||||
if (!isVideoCall)
|
||||
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"VOICE_CALL_FROM_USER", nil), eventSenderName];
|
||||
else
|
||||
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"VIDEO_CALL_FROM_USER", nil), eventSenderName];
|
||||
}
|
||||
else if (event.eventType == MXEventTypeRoomMember)
|
||||
{
|
||||
NSString *roomDisplayName = room.summary.displayname;
|
||||
|
||||
if (roomDisplayName.length && ![roomDisplayName isEqualToString:eventSenderName])
|
||||
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"USER_INVITE_TO_NAMED_ROOM", nil), eventSenderName, roomDisplayName];
|
||||
else
|
||||
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"USER_INVITE_TO_CHAT", nil), eventSenderName];
|
||||
}
|
||||
else if (event.eventType == MXEventTypeSticker)
|
||||
{
|
||||
NSString *roomDisplayName = room.summary.displayname;
|
||||
|
||||
if (roomDisplayName.length && ![roomDisplayName isEqualToString:eventSenderName])
|
||||
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"MSG_FROM_USER_IN_ROOM", nil), eventSenderName, roomDisplayName];
|
||||
else
|
||||
notificationBody = [NSString stringWithFormat:NSLocalizedString(@"MSG_FROM_USER", nil), eventSenderName];
|
||||
}
|
||||
|
||||
return notificationBody;
|
||||
|
||||
onComplete(notificationBody);
|
||||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2888,7 +2905,9 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
|
||||
- (void)enableLocalNotificationsFromMatrixSession:(MXSession*)mxSession
|
||||
{
|
||||
// Prepare listener block.
|
||||
MXWeakify(self);
|
||||
MXOnNotification notificationListenerBlock = ^(MXEvent *event, MXRoomState *roomState, MXPushRule *rule) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
// Ignore this event if the app is not running in background.
|
||||
if ([[UIApplication sharedApplication] applicationState] != UIApplicationStateBackground)
|
||||
@@ -2910,7 +2929,11 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
|
||||
}
|
||||
|
||||
// Add it to the list of the events to notify.
|
||||
[eventsToNotify[@(mxSession.hash)] addObject:@{@"event_id": event.eventId, @"room_id": event.roomId, @"push_rule": rule}];
|
||||
[self->eventsToNotify[@(mxSession.hash)] addObject:@{
|
||||
@"event_id": event.eventId,
|
||||
@"room_id": event.roomId,
|
||||
@"push_rule": rule
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -74,7 +74,7 @@ WidgetManagerErrorCode;
|
||||
@param room the room to check.
|
||||
@return a list of widgets.
|
||||
*/
|
||||
- (NSArray<Widget*> *)widgetsInRoom:(MXRoom*)room;
|
||||
- (NSArray<Widget*> *)widgetsInRoom:(MXRoom*)room withRoomState:(MXRoomState*)roomState;
|
||||
|
||||
/**
|
||||
List all active widgets of a given type in a room.
|
||||
@@ -83,7 +83,7 @@ WidgetManagerErrorCode;
|
||||
@param room the room to check.
|
||||
@return a list of widgets.
|
||||
*/
|
||||
- (NSArray<Widget*> *)widgetsOfTypes:(NSArray<NSString*>*)widgetTypes inRoom:(MXRoom*)room;
|
||||
- (NSArray<Widget*> *)widgetsOfTypes:(NSArray<NSString*>*)widgetTypes inRoom:(MXRoom*)room withRoomState:(MXRoomState*)roomState;
|
||||
|
||||
/**
|
||||
List all active widgets of a given type in a room, excluding some types.
|
||||
@@ -92,7 +92,7 @@ WidgetManagerErrorCode;
|
||||
@param room the room to check.
|
||||
@return a list of widgets.
|
||||
*/
|
||||
- (NSArray<Widget*> *)widgetsNotOfTypes:(NSArray<NSString*>*)notWidgetTypes inRoom:(MXRoom*)room;
|
||||
- (NSArray<Widget*> *)widgetsNotOfTypes:(NSArray<NSString*>*)notWidgetTypes inRoom:(MXRoom*)room withRoomState:(MXRoomState*)roomState;
|
||||
|
||||
/**
|
||||
List all widgets of an account.
|
||||
@@ -157,7 +157,7 @@ WidgetManagerErrorCode;
|
||||
@return a MXHTTPOperation instance.
|
||||
*/
|
||||
- (MXHTTPOperation *)closeWidget:(NSString*)widgetId inRoom:(MXRoom*)room
|
||||
success:(void (^)())success
|
||||
success:(void (^)(void))success
|
||||
failure:(void (^)(NSError *error))failure;
|
||||
|
||||
|
||||
|
||||
@@ -84,29 +84,29 @@ NSString *const WidgetManagerErrorDomain = @"WidgetManagerErrorDomain";
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSArray<Widget *> *)widgetsInRoom:(MXRoom *)room
|
||||
- (NSArray<Widget *> *)widgetsInRoom:(MXRoom*)room withRoomState:(MXRoomState*)roomState
|
||||
{
|
||||
return [self widgetsOfTypes:nil inRoom:room];
|
||||
return [self widgetsOfTypes:nil inRoom:room withRoomState:roomState];
|
||||
}
|
||||
|
||||
- (NSArray<Widget*> *)widgetsOfTypes:(NSArray<NSString*>*)widgetTypes inRoom:(MXRoom*)room;
|
||||
- (NSArray<Widget*> *)widgetsOfTypes:(NSArray<NSString*>*)widgetTypes inRoom:(MXRoom*)room withRoomState:(MXRoomState*)roomState
|
||||
{
|
||||
return [self widgetsOfTypes:widgetTypes butNotTypesOf:nil inRoom:room];
|
||||
return [self widgetsOfTypes:widgetTypes butNotTypesOf:nil inRoom:room withRoomState:roomState];
|
||||
}
|
||||
|
||||
- (NSArray<Widget*> *)widgetsNotOfTypes:(NSArray<NSString*>*)notWidgetTypes inRoom:(MXRoom*)room
|
||||
- (NSArray<Widget*> *)widgetsNotOfTypes:(NSArray<NSString*>*)notWidgetTypes inRoom:(MXRoom*)room withRoomState:(MXRoomState*)roomState;
|
||||
{
|
||||
return [self widgetsOfTypes:nil butNotTypesOf:notWidgetTypes inRoom:room];
|
||||
return [self widgetsOfTypes:nil butNotTypesOf:notWidgetTypes inRoom:room withRoomState:roomState];
|
||||
}
|
||||
|
||||
- (NSArray<Widget*> *)widgetsOfTypes:(NSArray<NSString*>*)widgetTypes butNotTypesOf:(NSArray<NSString*>*)notWidgetTypes inRoom:(MXRoom*)room;
|
||||
- (NSArray<Widget*> *)widgetsOfTypes:(NSArray<NSString*>*)widgetTypes butNotTypesOf:(NSArray<NSString*>*)notWidgetTypes inRoom:(MXRoom*)room withRoomState:(MXRoomState*)roomState;
|
||||
{
|
||||
// Widget id -> widget
|
||||
NSMutableDictionary <NSString*, Widget *> *widgets = [NSMutableDictionary dictionary];
|
||||
|
||||
// Get all widgets state events in the room
|
||||
NSMutableArray<MXEvent*> *widgetEvents = [NSMutableArray arrayWithArray:[room.state stateEventsWithType:kWidgetMatrixEventTypeString]];
|
||||
[widgetEvents addObjectsFromArray:[room.state stateEventsWithType:kWidgetModularEventTypeString]];
|
||||
NSMutableArray<MXEvent*> *widgetEvents = [NSMutableArray arrayWithArray:[roomState stateEventsWithType:kWidgetMatrixEventTypeString]];
|
||||
[widgetEvents addObjectsFromArray:[roomState stateEventsWithType:kWidgetModularEventTypeString]];
|
||||
|
||||
// There can be several widgets state events for a same widget but
|
||||
// only the last one must be considered.
|
||||
@@ -221,27 +221,38 @@ NSString *const WidgetManagerErrorDomain = @"WidgetManagerErrorDomain";
|
||||
success:(void (^)(Widget *widget))success
|
||||
failure:(void (^)(NSError *error))failure
|
||||
{
|
||||
NSError *permissionError = [self checkWidgetPermissionInRoom:room];
|
||||
if (permissionError)
|
||||
{
|
||||
// Create an empty operation that will be mutated later
|
||||
MXHTTPOperation *operation = [[MXHTTPOperation alloc] init];
|
||||
|
||||
MXWeakify(self);
|
||||
[self checkWidgetPermissionInRoom:room success:^{
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
NSString *hash = [NSString stringWithFormat:@"%p", room.mxSession];
|
||||
self->successBlockForWidgetCreation[hash][widgetId] = success;
|
||||
self->failureBlockForWidgetCreation[hash][widgetId] = failure;
|
||||
|
||||
// Send a state event with the widget data
|
||||
// TODO: This API will be shortly replaced by a pure modular API
|
||||
// TODO: Move to kWidgetMatrixEventTypeString ("m.widget") type but when?
|
||||
MXHTTPOperation *operation2 = [room sendStateEventOfType:kWidgetModularEventTypeString
|
||||
content:widgetContent
|
||||
stateKey:widgetId
|
||||
success:nil failure:failure];
|
||||
|
||||
if (operation2)
|
||||
{
|
||||
[operation mutateTo:operation2];
|
||||
}
|
||||
|
||||
} failure:^(NSError *error) {
|
||||
if (failure)
|
||||
{
|
||||
failure(permissionError);
|
||||
failure(error);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
}];
|
||||
|
||||
NSString *hash = [NSString stringWithFormat:@"%p", room.mxSession];
|
||||
successBlockForWidgetCreation[hash][widgetId] = success;
|
||||
failureBlockForWidgetCreation[hash][widgetId] = failure;
|
||||
|
||||
// Send a state event with the widget data
|
||||
// TODO: This API will be shortly replaced by a pure modular API
|
||||
// TODO: Move to kWidgetMatrixEventTypeString ("m.widget") type but when?
|
||||
return [room sendStateEventOfType:kWidgetModularEventTypeString
|
||||
content:widgetContent
|
||||
stateKey:widgetId
|
||||
success:nil failure:failure];
|
||||
return operation;
|
||||
}
|
||||
|
||||
|
||||
@@ -279,31 +290,40 @@ NSString *const WidgetManagerErrorDomain = @"WidgetManagerErrorDomain";
|
||||
failure:failure];
|
||||
}
|
||||
|
||||
- (MXHTTPOperation *)closeWidget:(NSString *)widgetId inRoom:(MXRoom *)room success:(void (^)())success failure:(void (^)(NSError *))failure
|
||||
- (MXHTTPOperation *)closeWidget:(NSString *)widgetId inRoom:(MXRoom *)room success:(void (^)(void))success failure:(void (^)(NSError *))failure
|
||||
{
|
||||
NSError *permissionError = [self checkWidgetPermissionInRoom:room];
|
||||
if (permissionError)
|
||||
{
|
||||
// Create an empty operation that will be mutated later
|
||||
MXHTTPOperation *operation = [[MXHTTPOperation alloc] init];
|
||||
|
||||
[self checkWidgetPermissionInRoom:room success:^{
|
||||
|
||||
// Send a state event with an empty content to disable the widget
|
||||
// TODO: This API will be shortly replaced by a pure modular API
|
||||
// TODO: Move to kWidgetMatrixEventTypeString ("m.widget") type but when?
|
||||
MXHTTPOperation *operation2 = [room sendStateEventOfType:kWidgetModularEventTypeString
|
||||
content:@{}
|
||||
stateKey:widgetId
|
||||
success:^(NSString *eventId)
|
||||
{
|
||||
if (success)
|
||||
{
|
||||
success();
|
||||
}
|
||||
} failure:failure];
|
||||
|
||||
if (operation2)
|
||||
{
|
||||
[operation mutateTo:operation2];
|
||||
}
|
||||
|
||||
} failure:^(NSError *error) {
|
||||
if (failure)
|
||||
{
|
||||
failure(permissionError);
|
||||
failure(error);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
}];
|
||||
|
||||
// Send a state event with an empty content to disable the widget
|
||||
// TODO: This API will be shortly replaced by a pure modular API
|
||||
// TODO: Move to kWidgetMatrixEventTypeString ("m.widget") type but when?
|
||||
return [room sendStateEventOfType:kWidgetModularEventTypeString
|
||||
content:@{}
|
||||
stateKey:widgetId
|
||||
success:^(NSString *eventId)
|
||||
{
|
||||
if (success)
|
||||
{
|
||||
success();
|
||||
}
|
||||
} failure:failure];
|
||||
return operation;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -312,25 +332,35 @@ NSString *const WidgetManagerErrorDomain = @"WidgetManagerErrorDomain";
|
||||
@param room the room to check.
|
||||
@return an NSError if the user cannot act on widgets in this room. Else, nil.
|
||||
*/
|
||||
- (NSError *)checkWidgetPermissionInRoom:(MXRoom *)room
|
||||
- (void)checkWidgetPermissionInRoom:(MXRoom *)room success:(dispatch_block_t)success failure:(void (^)(NSError *))failure
|
||||
{
|
||||
NSError *error;
|
||||
[room state:^(MXRoomState *roomState) {
|
||||
|
||||
// Check user's power in the room
|
||||
MXRoomPowerLevels *powerLevels = room.state.powerLevels;
|
||||
NSInteger oneSelfPowerLevel = [powerLevels powerLevelOfUserWithUserID:room.mxSession.myUser.userId];
|
||||
NSError *error;
|
||||
|
||||
// The user must be able to send state events to manage widgets
|
||||
if (oneSelfPowerLevel < powerLevels.stateDefault)
|
||||
{
|
||||
error = [NSError errorWithDomain:WidgetManagerErrorDomain
|
||||
code:WidgetManagerErrorCodeNotEnoughPower
|
||||
userInfo:@{
|
||||
NSLocalizedDescriptionKey: NSLocalizedStringFromTable(@"widget_no_power_to_manage", @"Vector", nil)
|
||||
}];
|
||||
}
|
||||
// Check user's power in the room
|
||||
MXRoomPowerLevels *powerLevels = roomState.powerLevels;
|
||||
NSInteger oneSelfPowerLevel = [powerLevels powerLevelOfUserWithUserID:room.mxSession.myUser.userId];
|
||||
|
||||
return error;
|
||||
// The user must be able to send state events to manage widgets
|
||||
if (oneSelfPowerLevel < powerLevels.stateDefault)
|
||||
{
|
||||
error = [NSError errorWithDomain:WidgetManagerErrorDomain
|
||||
code:WidgetManagerErrorCodeNotEnoughPower
|
||||
userInfo:@{
|
||||
NSLocalizedDescriptionKey: NSLocalizedStringFromTable(@"widget_no_power_to_manage", @"Vector", nil)
|
||||
}];
|
||||
}
|
||||
|
||||
if (error)
|
||||
{
|
||||
failure(error);
|
||||
}
|
||||
else
|
||||
{
|
||||
success();
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)addMatrixSession:(MXSession *)mxSession
|
||||
|
||||
@@ -79,37 +79,45 @@
|
||||
|
||||
- (void)peekInRoom:(void (^)(BOOL succeeded))completion
|
||||
{
|
||||
MXWeakify(self);
|
||||
[_mxSession peekInRoomWithRoomId:_roomId success:^(MXPeekingRoom *peekingRoom) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
// Create the room data source
|
||||
_roomDataSource = [[RoomDataSource alloc] initWithPeekingRoom:peekingRoom andInitialEventId:_eventId];
|
||||
[_roomDataSource finalizeInitialization];
|
||||
_roomDataSource.markTimelineInitialEvent = YES;
|
||||
MXWeakify(self);
|
||||
[RoomDataSource loadRoomDataSourceWithPeekingRoom:peekingRoom andInitialEventId:self.eventId onComplete:^(id roomDataSource) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
_roomName = peekingRoom.summary.displayname;
|
||||
_roomAvatarUrl = peekingRoom.summary.avatar;
|
||||
|
||||
_roomTopic = [MXTools stripNewlineCharacters:peekingRoom.summary.topic];;
|
||||
_roomAliases = peekingRoom.state.aliases;
|
||||
|
||||
// Room members count
|
||||
// Note that room members presence/activity is not available
|
||||
_numJoinedMembers = 0;
|
||||
for (MXRoomMember *mxMember in peekingRoom.state.members.members)
|
||||
{
|
||||
if (mxMember.membership == MXMembershipJoin)
|
||||
self->_roomDataSource = roomDataSource;
|
||||
|
||||
[self.roomDataSource finalizeInitialization];
|
||||
self.roomDataSource.markTimelineInitialEvent = YES;
|
||||
|
||||
self->_roomName = peekingRoom.summary.displayname;
|
||||
self->_roomAvatarUrl = peekingRoom.summary.avatar;
|
||||
|
||||
self->_roomTopic = [MXTools stripNewlineCharacters:peekingRoom.summary.topic];;
|
||||
self->_roomAliases = self.roomDataSource.roomState.aliases;
|
||||
|
||||
// Room members count
|
||||
// Note that room members presence/activity is not available
|
||||
self->_numJoinedMembers = 0;
|
||||
for (MXRoomMember *mxMember in self.roomDataSource.roomState.members.members)
|
||||
{
|
||||
_numJoinedMembers ++;
|
||||
if (mxMember.membership == MXMembershipJoin)
|
||||
{
|
||||
self->_numJoinedMembers ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
completion(YES);
|
||||
completion(YES);
|
||||
}];
|
||||
|
||||
} failure:^(NSError *error) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
_roomName = _roomId;
|
||||
self->_roomName = self->_roomId;
|
||||
completion(NO);
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
@@ -569,13 +569,13 @@
|
||||
if ([self.mxSession roomWithRoomId:roomId])
|
||||
{
|
||||
MXKRoomDataSourceManager *roomDataSourceManager = [MXKRoomDataSourceManager sharedManagerForMatrixSession:self.mxSession];
|
||||
MXKRoomDataSource *roomDataSource = [roomDataSourceManager roomDataSourceForRoom:roomId create:YES];
|
||||
|
||||
// Open this room
|
||||
RoomViewController *roomViewController = [RoomViewController roomViewController];
|
||||
roomViewController.showMissedDiscussionsBadge = NO;
|
||||
[roomViewController displayRoom:roomDataSource];
|
||||
[self pushViewController:roomViewController];
|
||||
[roomDataSourceManager roomDataSourceForRoom:roomId create:YES onComplete:^(MXKRoomDataSource *roomDataSource) {
|
||||
// Open this room
|
||||
RoomViewController *roomViewController = [RoomViewController roomViewController];
|
||||
roomViewController.showMissedDiscussionsBadge = NO;
|
||||
[roomViewController displayRoom:roomDataSource];
|
||||
[self pushViewController:roomViewController];
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -534,14 +534,15 @@
|
||||
// Check first if the user already joined this room.
|
||||
if ([self.mxSession roomWithRoomId:room.roomId])
|
||||
{
|
||||
MXKRoomDataSourceManager *roomDataSourceManager = [MXKRoomDataSourceManager sharedManagerForMatrixSession:self.mxSession];
|
||||
MXKRoomDataSource *roomDataSource = [roomDataSourceManager roomDataSourceForRoom:room.roomId create:YES];
|
||||
|
||||
// Open this room
|
||||
RoomViewController *roomViewController = [RoomViewController roomViewController];
|
||||
roomViewController.showMissedDiscussionsBadge = NO;
|
||||
[roomViewController displayRoom:roomDataSource];
|
||||
[self pushViewController:roomViewController];
|
||||
MXKRoomDataSourceManager *roomDataSourceManager = [MXKRoomDataSourceManager sharedManagerForMatrixSession:self.mxSession];
|
||||
[roomDataSourceManager roomDataSourceForRoom:room.roomId create:YES onComplete:^(MXKRoomDataSource *roomDataSource) {
|
||||
|
||||
RoomViewController *roomViewController = [RoomViewController roomViewController];
|
||||
roomViewController.showMissedDiscussionsBadge = NO;
|
||||
[roomViewController displayRoom:roomDataSource];
|
||||
[self pushViewController:roomViewController];
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -55,21 +55,38 @@
|
||||
}
|
||||
|
||||
date = [searchDataSource.eventFormatter dateStringFromEvent:event withTime:NO];
|
||||
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (void)cellDataWithSearchResult:(MXSearchResult *)searchResult andSearchDataSource:(MXKSearchDataSource *)searchDataSource onComplete:(void (^)(id<MXKSearchCellDataStoring>))onComplete
|
||||
{
|
||||
FilesSearchCellData *cellData = [[self alloc] initWithSearchResult:searchResult andSearchDataSource:searchDataSource];
|
||||
if (cellData)
|
||||
{
|
||||
// Retrieve the sender display name from the current room state
|
||||
MXRoom *room = [searchDataSource.mxSession roomWithRoomId:roomId];
|
||||
MXRoom *room = [searchDataSource.mxSession roomWithRoomId:cellData.roomId];
|
||||
if (room)
|
||||
{
|
||||
senderDisplayName = [room.state.members memberName:event.sender];
|
||||
[room state:^(MXRoomState *roomState) {
|
||||
cellData->senderDisplayName = [roomState.members memberName:searchResult.result.sender];
|
||||
cellData->message = cellData->senderDisplayName;
|
||||
|
||||
onComplete(cellData);
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
senderDisplayName = event.sender;
|
||||
cellData->senderDisplayName = searchResult.result.sender;
|
||||
cellData->message = cellData->senderDisplayName;
|
||||
|
||||
onComplete(cellData);
|
||||
}
|
||||
|
||||
message = senderDisplayName;
|
||||
}
|
||||
return self;
|
||||
else
|
||||
{
|
||||
onComplete(nil);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setShouldShowRoomDisplayName:(BOOL)shouldShowRoomDisplayName2
|
||||
|
||||
@@ -33,9 +33,11 @@
|
||||
[super destroy];
|
||||
}
|
||||
|
||||
- (void)convertHomeserverResultsIntoCells:(MXSearchRoomEventResults *)roomEventResults
|
||||
- (void)convertHomeserverResultsIntoCells:(MXSearchRoomEventResults *)roomEventResults onComplete:(dispatch_block_t)onComplete
|
||||
{
|
||||
MXKRoomDataSourceManager *roomDataSourceManager = [MXKRoomDataSourceManager sharedManagerForMatrixSession:self.mxSession];
|
||||
|
||||
dispatch_group_t group = dispatch_group_create();
|
||||
|
||||
// Convert the HS results into `RoomViewController` cells
|
||||
for (MXSearchResult *result in roomEventResults.results)
|
||||
@@ -43,48 +45,57 @@
|
||||
// Retrieve the local room data source thanks to the room identifier
|
||||
// Note: if no local room data source exist the result is ignored.
|
||||
NSString *roomId = result.result.roomId;
|
||||
UIFont *patternFont = nil;
|
||||
MXKRoomDataSource *roomDataSource;
|
||||
if (roomId)
|
||||
{
|
||||
dispatch_group_enter(group);
|
||||
|
||||
// Check whether the user knows this room to create the room data source if it doesn't exist.
|
||||
roomDataSource = [roomDataSourceManager roomDataSourceForRoom:roomId create:([self.mxSession roomWithRoomId:roomId])];
|
||||
if (roomDataSource)
|
||||
{
|
||||
// Prepare text font used to highlight the search pattern.
|
||||
patternFont = [roomDataSource.eventFormatter bingTextFont];
|
||||
|
||||
// Let the `RoomViewController` ecosystem do the job
|
||||
// The search result contains only room message events, no state events.
|
||||
// Thus, passing the current room state is not a huge problem. Only
|
||||
// the user display name and his avatar may be wrong.
|
||||
RoomBubbleCellData *cellData = [[RoomBubbleCellData alloc] initWithEvent:result.result andRoomState:roomDataSource.room.state andRoomDataSource:roomDataSource];
|
||||
if (cellData)
|
||||
[roomDataSourceManager roomDataSourceForRoom:roomId create:[self.mxSession roomWithRoomId:roomId] onComplete:^(MXKRoomDataSource *roomDataSource) {
|
||||
|
||||
if (roomDataSource)
|
||||
{
|
||||
// Highlight the search pattern
|
||||
[cellData highlightPatternInTextMessage:self.searchText withForegroundColor:kRiotColorGreen andFont:patternFont];
|
||||
|
||||
[cellDataArray insertObject:cellData atIndex:0];
|
||||
// Prepare text font used to highlight the search pattern.
|
||||
UIFont *patternFont = [roomDataSource.eventFormatter bingTextFont];
|
||||
|
||||
// Let the `RoomViewController` ecosystem do the job
|
||||
// The search result contains only room message events, no state events.
|
||||
// Thus, passing the current room state is not a huge problem. Only
|
||||
// the user display name and his avatar may be wrong.
|
||||
RoomBubbleCellData *cellData = [[RoomBubbleCellData alloc] initWithEvent:result.result andRoomState:roomDataSource.roomState andRoomDataSource:roomDataSource];
|
||||
if (cellData)
|
||||
{
|
||||
// Highlight the search pattern
|
||||
[cellData highlightPatternInTextMessage:self.searchText withForegroundColor:kRiotColorGreen andFont:patternFont];
|
||||
|
||||
[self->cellDataArray insertObject:cellData atIndex:0];
|
||||
}
|
||||
}
|
||||
|
||||
dispatch_group_leave(group);
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
|
||||
|
||||
// In case of successive messages from the same room,
|
||||
// we use the pagination flag to display the room name only on the first message.
|
||||
NSString *currentRoomId;
|
||||
for (RoomBubbleCellData *cellData in self->cellDataArray)
|
||||
{
|
||||
if (currentRoomId && [currentRoomId isEqualToString:cellData.roomId])
|
||||
{
|
||||
cellData.isPaginationFirstBubble = NO;
|
||||
}
|
||||
else
|
||||
{
|
||||
cellData.isPaginationFirstBubble = YES;
|
||||
currentRoomId = cellData.roomId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// In case of successive messages from the same room,
|
||||
// we use the pagination flag to display the room name only on the first message.
|
||||
NSString *currentRoomId;
|
||||
for (RoomBubbleCellData *cellData in cellDataArray)
|
||||
{
|
||||
if (currentRoomId && [currentRoomId isEqualToString:cellData.roomId])
|
||||
{
|
||||
cellData.isPaginationFirstBubble = NO;
|
||||
}
|
||||
else
|
||||
{
|
||||
cellData.isPaginationFirstBubble = YES;
|
||||
currentRoomId = cellData.roomId;
|
||||
}
|
||||
}
|
||||
|
||||
onComplete();
|
||||
});
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
|
||||
@@ -69,34 +69,24 @@ NSString *const kIntegrationManagerAddIntegrationScreen = @"add_integ";
|
||||
|
||||
if (!self.URL && !operation)
|
||||
{
|
||||
__weak __typeof__(self) weakSelf = self;
|
||||
|
||||
[self startActivityIndicator];
|
||||
|
||||
// Make sure we have a scalar token
|
||||
MXWeakify(self);
|
||||
operation = [[WidgetManager sharedManager] getScalarTokenForMXSession:mxSession success:^(NSString *theScalarToken) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
typeof(self) self = weakSelf;
|
||||
self->operation = nil;
|
||||
self->scalarToken = theScalarToken;
|
||||
|
||||
if (self)
|
||||
{
|
||||
self->operation = nil;
|
||||
|
||||
scalarToken = theScalarToken;
|
||||
|
||||
// Launch the webview on the right modular webapp page
|
||||
self.URL = [self interfaceUrl];
|
||||
}
|
||||
// Launch the webview on the right modular webapp page
|
||||
self.URL = [self interfaceUrl];
|
||||
|
||||
} failure:^(NSError *error) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
typeof(self) self = weakSelf;
|
||||
|
||||
if (self)
|
||||
{
|
||||
self->operation = nil;
|
||||
[self stopActivityIndicator];
|
||||
}
|
||||
self->operation = nil;
|
||||
[self stopActivityIndicator];
|
||||
}];
|
||||
}
|
||||
}
|
||||
@@ -253,26 +243,28 @@ NSString *const kIntegrationManagerAddIntegrationScreen = @"add_integ";
|
||||
|
||||
#pragma mark - Private methods
|
||||
|
||||
- (MXRoom *)roomCheckForRequest:(NSString*)requestId data:(NSDictionary*)requestData
|
||||
- (void)roomCheckForRequest:(NSString*)requestId data:(NSDictionary*)requestData onComplete:(void (^)(MXRoom *room, MXRoomState *roomState))onComplete
|
||||
{
|
||||
MXRoom *room = [mxSession roomWithRoomId:roomId];
|
||||
if (!room)
|
||||
if (room)
|
||||
{
|
||||
[room state:^(MXRoomState *roomState) {
|
||||
onComplete(room, roomState);
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self sendLocalisedError:@"widget_integration_room_not_recognised" toRequest:requestId];
|
||||
}
|
||||
|
||||
return room;
|
||||
}
|
||||
|
||||
- (void)inviteUser:(NSString*)userId request:(NSString*)requestId data:(NSDictionary*)requestData
|
||||
{
|
||||
NSLog(@"[IntegrationManagerVC] Received request to invite %@ into room %@.", userId, roomId);
|
||||
|
||||
MXRoom *room = [self roomCheckForRequest:requestId data:requestData];
|
||||
|
||||
if (room)
|
||||
{
|
||||
MXRoomMember *member = [room.state.members memberWithUserId:userId];
|
||||
[self roomCheckForRequest:requestId data:requestData onComplete:^(MXRoom *room, MXRoomState *roomState) {
|
||||
|
||||
MXRoomMember *member = [roomState.members memberWithUserId:userId];
|
||||
if (member && member.membership == MXMembershipJoin)
|
||||
{
|
||||
[self sendNSObjectResponse:@{
|
||||
@@ -282,29 +274,22 @@ NSString *const kIntegrationManagerAddIntegrationScreen = @"add_integ";
|
||||
}
|
||||
else
|
||||
{
|
||||
__weak __typeof__(self) weakSelf = self;
|
||||
|
||||
MXWeakify(self);
|
||||
[room inviteUser:userId success:^{
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
typeof(self) self = weakSelf;
|
||||
if (self)
|
||||
{
|
||||
[self sendNSObjectResponse:@{
|
||||
@"success": @(YES)
|
||||
}
|
||||
toRequest:requestId];
|
||||
}
|
||||
[self sendNSObjectResponse:@{
|
||||
@"success": @(YES)
|
||||
}
|
||||
toRequest:requestId];
|
||||
|
||||
} failure:^(NSError *error) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
typeof(self) self = weakSelf;
|
||||
if (self)
|
||||
{
|
||||
[self sendLocalisedError:@"widget_integration_need_to_be_able_to_invite" toRequest:requestId];
|
||||
}
|
||||
[self sendLocalisedError:@"widget_integration_need_to_be_able_to_invite" toRequest:requestId];
|
||||
}];
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)setWidget:(NSString*)requestId data:(NSDictionary*)requestData
|
||||
@@ -396,9 +381,8 @@ NSString *const kIntegrationManagerAddIntegrationScreen = @"add_integ";
|
||||
else
|
||||
{
|
||||
// Room widget
|
||||
MXRoom *room = [self roomCheckForRequest:requestId data:requestData];
|
||||
if (room)
|
||||
{
|
||||
[self roomCheckForRequest:requestId data:requestData onComplete:^(MXRoom *room, MXRoomState *roomState) {
|
||||
|
||||
// TODO: Move to kWidgetMatrixEventTypeString ("m.widget") type but when?
|
||||
[room sendStateEventOfType:kWidgetModularEventTypeString
|
||||
content:widgetEventContent
|
||||
@@ -422,51 +406,50 @@ NSString *const kIntegrationManagerAddIntegrationScreen = @"add_integ";
|
||||
[self sendLocalisedError:@"widget_integration_failed_to_send_request" toRequest:requestId];
|
||||
}
|
||||
}];
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)getWidgets:(NSString*)requestId data:(NSDictionary*)requestData
|
||||
{
|
||||
MXRoom *room = [self roomCheckForRequest:requestId data:requestData];
|
||||
NSMutableArray<NSDictionary*> *widgetStateEvents = [NSMutableArray array];
|
||||
MXWeakify(self);
|
||||
[self roomCheckForRequest:requestId data:requestData onComplete:^(MXRoom *room, MXRoomState *roomState) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
if (room)
|
||||
{
|
||||
NSArray<Widget*> *widgets = [[WidgetManager sharedManager] widgetsInRoom:room];
|
||||
NSMutableArray<NSDictionary*> *widgetStateEvents = [NSMutableArray array];
|
||||
|
||||
NSArray<Widget*> *widgets = [[WidgetManager sharedManager] widgetsInRoom:room withRoomState:roomState];
|
||||
for (Widget *widget in widgets)
|
||||
{
|
||||
[widgetStateEvents addObject:widget.widgetEvent.JSONDictionary];
|
||||
}
|
||||
}
|
||||
|
||||
// Add user widgets (not linked to a specific room)
|
||||
for (Widget *widget in [[WidgetManager sharedManager] userWidgets:mxSession])
|
||||
{
|
||||
[widgetStateEvents addObject:widget.widgetEvent.JSONDictionary];
|
||||
}
|
||||
// Add user widgets (not linked to a specific room)
|
||||
for (Widget *widget in [[WidgetManager sharedManager] userWidgets:self->mxSession])
|
||||
{
|
||||
[widgetStateEvents addObject:widget.widgetEvent.JSONDictionary];
|
||||
}
|
||||
|
||||
[self sendNSObjectResponse:widgetStateEvents toRequest:requestId];
|
||||
[self sendNSObjectResponse:widgetStateEvents toRequest:requestId];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)getRoomEncState:(NSString*)requestId data:(NSDictionary*)requestData
|
||||
{
|
||||
MXRoom *room = [self roomCheckForRequest:requestId data:requestData];
|
||||
if (room)
|
||||
{
|
||||
[self roomCheckForRequest:requestId data:requestData onComplete:^(MXRoom *room, MXRoomState *roomState) {
|
||||
[self sendBoolResponse:room.summary.isEncrypted toRequest:requestId];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)canSendEvent:(NSString*)requestId data:(NSDictionary*)requestData
|
||||
{
|
||||
NSString *eventType;
|
||||
BOOL isState = NO;
|
||||
MXWeakify(self);
|
||||
[self roomCheckForRequest:requestId data:requestData onComplete:^(MXRoom *room, MXRoomState *roomState) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
MXRoom *room = [self roomCheckForRequest:requestId data:requestData];
|
||||
NSString *eventType;
|
||||
BOOL isState = NO;
|
||||
|
||||
if (room)
|
||||
{
|
||||
if (room.summary.membership != MXMembershipJoin)
|
||||
{
|
||||
[self sendLocalisedError:@"widget_integration_must_be_in_room" toRequest:requestId];
|
||||
@@ -476,8 +459,8 @@ NSString *const kIntegrationManagerAddIntegrationScreen = @"add_integ";
|
||||
MXJSONModelSetString(eventType, requestData[@"event_type"]);
|
||||
MXJSONModelSetBoolean(isState, requestData[@"is_state"]);
|
||||
|
||||
MXRoomPowerLevels *powerLevels = room.state.powerLevels;
|
||||
NSInteger userPowerLevel = [powerLevels powerLevelOfUserWithUserID:mxSession.myUser.userId];
|
||||
MXRoomPowerLevels *powerLevels = roomState.powerLevels;
|
||||
NSInteger userPowerLevel = [powerLevels powerLevelOfUserWithUserID:self->mxSession.myUser.userId];
|
||||
|
||||
BOOL canSend = NO;
|
||||
|
||||
@@ -498,47 +481,42 @@ NSString *const kIntegrationManagerAddIntegrationScreen = @"add_integ";
|
||||
{
|
||||
[self sendLocalisedError:@"widget_integration_no_permission_in_room" toRequest:requestId];
|
||||
}
|
||||
}
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)getMembershipState:(NSString*)userId request:(NSString*)requestId data:(NSDictionary*)requestData
|
||||
{
|
||||
NSLog(@"[IntegrationManagerVC] membership_state of %@ in room %@ requested.", userId, roomId);
|
||||
|
||||
MXRoom *room = [self roomCheckForRequest:requestId data:requestData];
|
||||
if (room)
|
||||
{
|
||||
MXRoomMember *member = [room.state.members memberWithUserId:userId];
|
||||
[self roomCheckForRequest:requestId data:requestData onComplete:^(MXRoom *room, MXRoomState *roomState) {
|
||||
MXRoomMember *member = [roomState.members memberWithUserId:userId];
|
||||
[self sendNSObjectResponse:member.originalEvent.content toRequest:requestId];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)getJoinRules:(NSString*)requestId data:(NSDictionary*)requestData
|
||||
{
|
||||
NSLog(@"[IntegrationManagerVC] join_rules of %@ requested.", roomId);
|
||||
|
||||
MXRoom *room = [self roomCheckForRequest:requestId data:requestData];
|
||||
if (room)
|
||||
{
|
||||
MXEvent *event = [room.state stateEventsWithType:kMXEventTypeStringRoomJoinRules].lastObject;
|
||||
[self roomCheckForRequest:requestId data:requestData onComplete:^(MXRoom *room, MXRoomState *roomState) {
|
||||
MXEvent *event = [roomState stateEventsWithType:kMXEventTypeStringRoomJoinRules].lastObject;
|
||||
[self sendNSObjectResponse:event.JSONDictionary toRequest:requestId];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)setPlumbingState:(NSString*)requestId data:(NSDictionary*)requestData
|
||||
{
|
||||
NSLog(@"[IntegrationManagerVC] Received request to set plumbing state to status %@ in room %@.", requestData[@"status"], roomId);
|
||||
|
||||
MXRoom *room = [self roomCheckForRequest:requestId data:requestData];
|
||||
if (room)
|
||||
{
|
||||
[self roomCheckForRequest:requestId data:requestData onComplete:^(MXRoom *room, MXRoomState *roomState) {
|
||||
NSString *status;
|
||||
MXJSONModelSetString(status, requestData[@"status"]);
|
||||
|
||||
if (status)
|
||||
{
|
||||
__weak __typeof__(self) weakSelf = self;
|
||||
|
||||
__weak __typeof__(self) weakSelf = self;
|
||||
|
||||
[room sendStateEventOfType:kMXEventTypeStringRoomPlumbing
|
||||
content:@{
|
||||
@"status": status
|
||||
@@ -552,7 +530,7 @@ NSString *const kIntegrationManagerAddIntegrationScreen = @"add_integ";
|
||||
[self sendNSObjectResponse:@{
|
||||
@"success": @(YES)
|
||||
}
|
||||
toRequest:requestId];
|
||||
toRequest:requestId];
|
||||
}
|
||||
}
|
||||
failure:^(NSError *error) {
|
||||
@@ -568,19 +546,18 @@ NSString *const kIntegrationManagerAddIntegrationScreen = @"add_integ";
|
||||
{
|
||||
NSLog(@"[IntegrationManagerVC] setPlumbingState. Error: Plumbing state status should be a string.");
|
||||
}
|
||||
}
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)getBotOptions:(NSString*)userId request:(NSString*)requestId data:(NSDictionary*)requestData
|
||||
{
|
||||
NSLog(@"[IntegrationManagerVC] Received request to get options for bot %@ in room %@", userId, roomId);
|
||||
|
||||
MXRoom *room = [self roomCheckForRequest:requestId data:requestData];
|
||||
if (room)
|
||||
{
|
||||
[self roomCheckForRequest:requestId data:requestData onComplete:^(MXRoom *room, MXRoomState *roomState) {
|
||||
NSString *stateKey = [NSString stringWithFormat:@"_%@", userId];
|
||||
|
||||
NSArray<MXEvent*> *stateEvents = [room.state stateEventsWithType:kMXEventTypeStringRoomBotOptions];
|
||||
NSArray<MXEvent*> *stateEvents = [roomState stateEventsWithType:kMXEventTypeStringRoomBotOptions];
|
||||
|
||||
MXEvent *botOptionsEvent;
|
||||
|
||||
@@ -590,22 +567,21 @@ NSString *const kIntegrationManagerAddIntegrationScreen = @"add_integ";
|
||||
{
|
||||
if (!botOptionsEvent || stateEvent.ageLocalTs > botOptionsEvent.ageLocalTs)
|
||||
{
|
||||
botOptionsEvent = stateEvent;
|
||||
botOptionsEvent = stateEvent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[self sendNSObjectResponse:botOptionsEvent.JSONDictionary toRequest:requestId];
|
||||
}
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)setBotOptions:(NSString*)userId request:(NSString*)requestId data:(NSDictionary*)requestData
|
||||
{
|
||||
NSLog(@"[IntegrationManagerVC] Received request to set options for bot %@ in room %@", userId, roomId);
|
||||
|
||||
MXRoom *room = [self roomCheckForRequest:requestId data:requestData];
|
||||
if (room)
|
||||
{
|
||||
[self roomCheckForRequest:requestId data:requestData onComplete:^(MXRoom *room, MXRoomState *roomState) {
|
||||
NSDictionary *content;
|
||||
MXJSONModelSetDictionary(content, requestData[@"content"]);
|
||||
|
||||
@@ -626,7 +602,7 @@ NSString *const kIntegrationManagerAddIntegrationScreen = @"add_integ";
|
||||
[self sendNSObjectResponse:@{
|
||||
@"success": @(YES)
|
||||
}
|
||||
toRequest:requestId];
|
||||
toRequest:requestId];
|
||||
}
|
||||
}
|
||||
failure:^(NSError *error) {
|
||||
@@ -642,16 +618,14 @@ NSString *const kIntegrationManagerAddIntegrationScreen = @"add_integ";
|
||||
{
|
||||
NSLog(@"[IntegrationManagerVC] setBotOptions. Error: options should be a dict.");
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)setBotPower:(NSString*)userId request:(NSString*)requestId data:(NSDictionary*)requestData
|
||||
{
|
||||
NSLog(@"[IntegrationManagerVC] Received request to set power level to %@ for bot %@ in room %@.", requestData[@"level"], userId, roomId);
|
||||
|
||||
MXRoom *room = [self roomCheckForRequest:requestId data:requestData];
|
||||
if (room)
|
||||
{
|
||||
[self roomCheckForRequest:requestId data:requestData onComplete:^(MXRoom *room, MXRoomState *roomState) {
|
||||
NSInteger level = -1;
|
||||
MXJSONModelSetInteger(level, requestData[@"level"]);
|
||||
|
||||
@@ -667,7 +641,7 @@ NSString *const kIntegrationManagerAddIntegrationScreen = @"add_integ";
|
||||
[self sendNSObjectResponse:@{
|
||||
@"success": @(YES)
|
||||
}
|
||||
toRequest:requestId];
|
||||
toRequest:requestId];
|
||||
}
|
||||
|
||||
} failure:^(NSError *error) {
|
||||
@@ -684,17 +658,15 @@ NSString *const kIntegrationManagerAddIntegrationScreen = @"add_integ";
|
||||
NSLog(@"[IntegrationManagerVC] setBotPower. Power level must be positive integer.");
|
||||
[self sendLocalisedError:@"widget_integration_positive_power_level" toRequest:requestId];
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)getMembershipCount:(NSString*)requestId data:(NSDictionary*)requestData
|
||||
{
|
||||
MXRoom *room = [self roomCheckForRequest:requestId data:requestData];
|
||||
if (room)
|
||||
{
|
||||
[self roomCheckForRequest:requestId data:requestData onComplete:^(MXRoom *room, MXRoomState *roomState) {
|
||||
NSUInteger membershipCount = room.summary.membersCount.joined;
|
||||
[self sendIntegerResponse:membershipCount toRequest:requestId];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -49,64 +49,66 @@
|
||||
|
||||
- (void)showInViewController:(MXKViewController *)mxkViewController
|
||||
{
|
||||
UIAlertAction *alertAction;
|
||||
MXKRoomDataSourceManager *roomDataSourceManager = [MXKRoomDataSourceManager sharedManagerForMatrixSession:mxSession];
|
||||
[roomDataSourceManager roomDataSourceForRoom:roomId create:NO onComplete:^(MXKRoomDataSource *roomDataSource) {
|
||||
|
||||
MXRoom *room = [mxSession roomWithRoomId:roomId];
|
||||
UIAlertAction *alertAction;
|
||||
|
||||
NSArray<Widget*> *widgets = [[WidgetManager sharedManager] widgetsNotOfTypes:@[kWidgetTypeJitsi]
|
||||
inRoom:room];
|
||||
NSArray<Widget*> *widgets = [[WidgetManager sharedManager] widgetsNotOfTypes:@[kWidgetTypeJitsi]
|
||||
inRoom:roomDataSource.room
|
||||
withRoomState:roomDataSource.roomState];
|
||||
|
||||
// List widgets
|
||||
for (Widget *widget in widgets)
|
||||
{
|
||||
alertAction = [UIAlertAction actionWithTitle:widget.name ? widget.name : widget.type
|
||||
// List widgets
|
||||
for (Widget *widget in widgets)
|
||||
{
|
||||
alertAction = [UIAlertAction actionWithTitle:widget.name ? widget.name : widget.type
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * _Nonnull action)
|
||||
{
|
||||
// Hide back button title
|
||||
mxkViewController.navigationItem.backBarButtonItem =[[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil];
|
||||
|
||||
// Display the widget
|
||||
[widget widgetUrl:^(NSString * _Nonnull widgetUrl) {
|
||||
|
||||
WidgetViewController *widgetVC = [[WidgetViewController alloc] initWithUrl:widgetUrl forWidget:widget];
|
||||
|
||||
widgetVC.roomDataSource = roomDataSource;
|
||||
|
||||
[mxkViewController.navigationController pushViewController:widgetVC animated:YES];
|
||||
|
||||
} failure:^(NSError * _Nonnull error) {
|
||||
|
||||
NSLog(@"[WidgetPickerVC] Cannot display widget %@", widget);
|
||||
[[AppDelegate theDelegate] showErrorAsAlert:error];
|
||||
}];
|
||||
}];
|
||||
[self.alertController addAction:alertAction];
|
||||
}
|
||||
|
||||
// Link to the integration manager
|
||||
alertAction = [UIAlertAction actionWithTitle:@"Manage integrations..."
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * _Nonnull action)
|
||||
{
|
||||
// Hide back button title
|
||||
mxkViewController.navigationItem.backBarButtonItem =[[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil];
|
||||
IntegrationManagerViewController *modularVC = [[IntegrationManagerViewController alloc] initForMXSession:self->mxSession
|
||||
inRoom:self->roomId
|
||||
screen:kIntegrationManagerMainScreen
|
||||
widgetId:nil];
|
||||
|
||||
// Display the widget
|
||||
[widget widgetUrl:^(NSString * _Nonnull widgetUrl) {
|
||||
|
||||
WidgetViewController *widgetVC = [[WidgetViewController alloc] initWithUrl:widgetUrl forWidget:widget];
|
||||
|
||||
MXKRoomDataSourceManager *roomDataSourceManager = [MXKRoomDataSourceManager sharedManagerForMatrixSession:mxSession];
|
||||
widgetVC.roomDataSource = [roomDataSourceManager roomDataSourceForRoom:roomId create:NO];
|
||||
|
||||
[mxkViewController.navigationController pushViewController:widgetVC animated:YES];
|
||||
|
||||
} failure:^(NSError * _Nonnull error) {
|
||||
|
||||
NSLog(@"[WidgetPickerVC] Cannot display widget %@", widget);
|
||||
[[AppDelegate theDelegate] showErrorAsAlert:error];
|
||||
}];
|
||||
[mxkViewController presentViewController:modularVC animated:NO completion:nil];
|
||||
}];
|
||||
[_alertController addAction:alertAction];
|
||||
}
|
||||
[self.alertController addAction:alertAction];
|
||||
|
||||
// Link to the integration manager
|
||||
alertAction = [UIAlertAction actionWithTitle:@"Manage integrations..."
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * _Nonnull action)
|
||||
{
|
||||
IntegrationManagerViewController *modularVC = [[IntegrationManagerViewController alloc] initForMXSession:self->mxSession
|
||||
inRoom:self->roomId
|
||||
screen:kIntegrationManagerMainScreen
|
||||
widgetId:nil];
|
||||
// Cancel
|
||||
alertAction = [UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"]
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:nil];
|
||||
[self.alertController addAction:alertAction];
|
||||
|
||||
[mxkViewController presentViewController:modularVC animated:NO completion:nil];
|
||||
}];
|
||||
[_alertController addAction:alertAction];
|
||||
|
||||
// Cancel
|
||||
alertAction = [UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"]
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:nil];
|
||||
[_alertController addAction:alertAction];
|
||||
|
||||
// And show it
|
||||
[mxkViewController presentViewController:_alertController animated:YES completion:nil];
|
||||
}
|
||||
// And show it
|
||||
[mxkViewController presentViewController:_alertController animated:YES completion:nil];
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -271,7 +271,7 @@
|
||||
|
||||
for (MXReceiptData* data in receipts)
|
||||
{
|
||||
MXRoomMember * roomMember = [self.room.state.members memberWithUserId:data.userId];
|
||||
MXRoomMember * roomMember = [self.roomState.members memberWithUserId:data.userId];
|
||||
if (roomMember)
|
||||
{
|
||||
[roomMembers addObject:roomMember];
|
||||
@@ -495,7 +495,7 @@
|
||||
Widget *jitsiWidget;
|
||||
|
||||
// Note: Manage only one jitsi widget at a time for the moment
|
||||
jitsiWidget = [[WidgetManager sharedManager] widgetsOfTypes:@[kWidgetTypeJitsi] inRoom:self.room].firstObject;
|
||||
jitsiWidget = [[WidgetManager sharedManager] widgetsOfTypes:@[kWidgetTypeJitsi] inRoom:self.room withRoomState:self.roomState].firstObject;
|
||||
|
||||
return jitsiWidget;
|
||||
}
|
||||
|
||||
@@ -367,22 +367,27 @@
|
||||
self.roomMemberNameLabel.text = self.mxRoomMember.displayname ? self.mxRoomMember.displayname : self.mxRoomMember.userId;
|
||||
|
||||
// Update member badge
|
||||
MXRoomPowerLevels *powerLevels = [self.mxRoom.state powerLevels];
|
||||
NSInteger powerLevel = [powerLevels powerLevelOfUserWithUserID:self.mxRoomMember.userId];
|
||||
if (powerLevel >= kRiotRoomAdminLevel)
|
||||
{
|
||||
memberTitleView.memberBadge.image = [UIImage imageNamed:@"admin_icon"];
|
||||
memberTitleView.memberBadge.hidden = NO;
|
||||
}
|
||||
else if (powerLevel >= kRiotRoomModeratorLevel)
|
||||
{
|
||||
memberTitleView.memberBadge.image = [UIImage imageNamed:@"mod_icon"];
|
||||
memberTitleView.memberBadge.hidden = NO;
|
||||
}
|
||||
else
|
||||
{
|
||||
memberTitleView.memberBadge.hidden = YES;
|
||||
}
|
||||
MXWeakify(self);
|
||||
[self.mxRoom state:^(MXRoomState *roomState) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
MXRoomPowerLevels *powerLevels = [roomState powerLevels];
|
||||
NSInteger powerLevel = [powerLevels powerLevelOfUserWithUserID:self.mxRoomMember.userId];
|
||||
if (powerLevel >= kRiotRoomAdminLevel)
|
||||
{
|
||||
self->memberTitleView.memberBadge.image = [UIImage imageNamed:@"admin_icon"];
|
||||
self->memberTitleView.memberBadge.hidden = NO;
|
||||
}
|
||||
else if (powerLevel >= kRiotRoomModeratorLevel)
|
||||
{
|
||||
self->memberTitleView.memberBadge.image = [UIImage imageNamed:@"mod_icon"];
|
||||
self->memberTitleView.memberBadge.hidden = NO;
|
||||
}
|
||||
else
|
||||
{
|
||||
self->memberTitleView.memberBadge.hidden = YES;
|
||||
}
|
||||
}];
|
||||
|
||||
NSString* presenceText;
|
||||
|
||||
@@ -477,7 +482,7 @@
|
||||
BOOL isOneself = NO;
|
||||
|
||||
// Check user's power level before allowing an action (kick, ban, ...)
|
||||
MXRoomPowerLevels *powerLevels = [self.mxRoom.state powerLevels];
|
||||
MXRoomPowerLevels *powerLevels = [self.mxRoom.dangerousSyncState powerLevels];
|
||||
NSInteger memberPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mxRoomMember.userId];
|
||||
NSInteger oneSelfPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mainSession.myUser.userId];
|
||||
|
||||
@@ -930,7 +935,9 @@
|
||||
{
|
||||
case MXKRoomMemberDetailsActionSetDefaultPowerLevel:
|
||||
{
|
||||
[self setPowerLevel:self.mxRoom.state.powerLevels.usersDefault promptUser:YES];
|
||||
[self.mxRoom state:^(MXRoomState *roomState) {
|
||||
[self setPowerLevel:roomState.powerLevels.usersDefault promptUser:YES];
|
||||
}];
|
||||
break;
|
||||
}
|
||||
case MXKRoomMemberDetailsActionSetModerator:
|
||||
|
||||
@@ -216,8 +216,13 @@
|
||||
|
||||
if (membersListener)
|
||||
{
|
||||
[self.mxRoom.liveTimeline removeListener:membersListener];
|
||||
membersListener = nil;
|
||||
MXWeakify(self);
|
||||
[self.mxRoom liveTimeline:^(MXEventTimeline *liveTimeline) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
[liveTimeline removeListener:self->membersListener];
|
||||
self->membersListener = nil;
|
||||
}];
|
||||
}
|
||||
|
||||
if (currentAlert)
|
||||
@@ -330,142 +335,159 @@
|
||||
{
|
||||
// Cancel any pending search
|
||||
[self searchBarCancelButtonClicked:_searchBarView];
|
||||
|
||||
// Remove previous room registration (if any).
|
||||
if (_mxRoom)
|
||||
{
|
||||
// Remove the previous listener
|
||||
if (leaveRoomNotificationObserver)
|
||||
|
||||
// Make sure we can access synchronously to self.mxRoom and mxRoom data
|
||||
// to avoid race conditions
|
||||
MXWeakify(self);
|
||||
[_mxRoom.mxSession preloadRoomsData:@[_mxRoom.roomId, mxRoom.roomId] onComplete:^{
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
// Remove previous room registration (if any).
|
||||
if (self.mxRoom)
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:leaveRoomNotificationObserver];
|
||||
leaveRoomNotificationObserver = nil;
|
||||
}
|
||||
if (roomDidFlushDataNotificationObserver)
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:roomDidFlushDataNotificationObserver];
|
||||
roomDidFlushDataNotificationObserver = nil;
|
||||
}
|
||||
if (membersListener)
|
||||
{
|
||||
[_mxRoom.liveTimeline removeListener:membersListener];
|
||||
membersListener = nil;
|
||||
}
|
||||
|
||||
[self removeMatrixSession:_mxRoom.mxSession];
|
||||
}
|
||||
|
||||
_mxRoom = mxRoom;
|
||||
|
||||
if (_mxRoom)
|
||||
{
|
||||
_searchBarHeader.hidden = NO;
|
||||
|
||||
// Update the current matrix session.
|
||||
[self addMatrixSession:_mxRoom.mxSession];
|
||||
|
||||
// Observe kMXSessionWillLeaveRoomNotification to be notified if the user leaves the current room.
|
||||
leaveRoomNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXSessionWillLeaveRoomNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
|
||||
|
||||
// Check whether the user will leave the room related to the displayed participants
|
||||
if (notif.object == _mxRoom.mxSession)
|
||||
// Remove the previous listener
|
||||
if (self->leaveRoomNotificationObserver)
|
||||
{
|
||||
NSString *roomId = notif.userInfo[kMXSessionNotificationRoomIdKey];
|
||||
if (roomId && [roomId isEqualToString:_mxRoom.roomId])
|
||||
{
|
||||
// We remove the current view controller.
|
||||
[self withdrawViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self->leaveRoomNotificationObserver];
|
||||
self->leaveRoomNotificationObserver = nil;
|
||||
}
|
||||
}];
|
||||
|
||||
// Observe room history flush (sync with limited timeline, or state event redaction)
|
||||
roomDidFlushDataNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXRoomDidFlushDataNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
|
||||
|
||||
MXRoom *room = notif.object;
|
||||
if (_mxRoom.mxSession == room.mxSession && [_mxRoom.roomId isEqualToString:room.roomId])
|
||||
if (self->roomDidFlushDataNotificationObserver)
|
||||
{
|
||||
// The existing room history has been flushed during server sync. Take into account the updated room members list.
|
||||
[self refreshParticipantsFromRoomMembers];
|
||||
|
||||
[self refreshTableView];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self->roomDidFlushDataNotificationObserver];
|
||||
self->roomDidFlushDataNotificationObserver = nil;
|
||||
}
|
||||
|
||||
}];
|
||||
|
||||
// Register a listener for events that concern room members
|
||||
NSArray *mxMembersEvents = @[kMXEventTypeStringRoomMember, kMXEventTypeStringRoomThirdPartyInvite, kMXEventTypeStringRoomPowerLevels];
|
||||
membersListener = [_mxRoom.liveTimeline listenToEventsOfTypes:mxMembersEvents onEvent:^(MXEvent *event, MXTimelineDirection direction, id customObject) {
|
||||
|
||||
// Consider only live event
|
||||
if (direction == MXTimelineDirectionForwards)
|
||||
if (self->membersListener)
|
||||
{
|
||||
switch (event.eventType)
|
||||
MXWeakify(self);
|
||||
[self.mxRoom liveTimeline:^(MXEventTimeline *liveTimeline) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
[liveTimeline removeListener:self->membersListener];
|
||||
self->membersListener = nil;
|
||||
}];
|
||||
}
|
||||
|
||||
[self removeMatrixSession:self.mxRoom.mxSession];
|
||||
}
|
||||
|
||||
self->_mxRoom = mxRoom;
|
||||
|
||||
if (self.mxRoom)
|
||||
{
|
||||
self.searchBarHeader.hidden = NO;
|
||||
|
||||
// Update the current matrix session.
|
||||
[self addMatrixSession:self.mxRoom.mxSession];
|
||||
|
||||
// Observe kMXSessionWillLeaveRoomNotification to be notified if the user leaves the current room.
|
||||
self->leaveRoomNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXSessionWillLeaveRoomNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
|
||||
|
||||
// Check whether the user will leave the room related to the displayed participants
|
||||
if (notif.object == self.mxRoom.mxSession)
|
||||
{
|
||||
case MXEventTypeRoomMember:
|
||||
NSString *roomId = notif.userInfo[kMXSessionNotificationRoomIdKey];
|
||||
if (roomId && [roomId isEqualToString:self.mxRoom.roomId])
|
||||
{
|
||||
// Take into account updated member
|
||||
// Ignore here change related to the current user (this change is handled by leaveRoomNotificationObserver)
|
||||
if ([event.stateKey isEqualToString:self.mxRoom.mxSession.myUser.userId] == NO)
|
||||
// We remove the current view controller.
|
||||
[self withdrawViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
}
|
||||
}];
|
||||
|
||||
// Observe room history flush (sync with limited timeline, or state event redaction)
|
||||
self->roomDidFlushDataNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXRoomDidFlushDataNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
|
||||
|
||||
MXRoom *room = notif.object;
|
||||
if (self.mxRoom.mxSession == room.mxSession && [self.mxRoom.roomId isEqualToString:room.roomId])
|
||||
{
|
||||
// The existing room history has been flushed during server sync. Take into account the updated room members list.
|
||||
[self refreshParticipantsFromRoomMembers];
|
||||
|
||||
[self refreshTableView];
|
||||
}
|
||||
|
||||
}];
|
||||
|
||||
// Register a listener for events that concern room members
|
||||
NSArray *mxMembersEvents = @[kMXEventTypeStringRoomMember, kMXEventTypeStringRoomThirdPartyInvite, kMXEventTypeStringRoomPowerLevels];
|
||||
|
||||
MXWeakify(self);
|
||||
[self.mxRoom liveTimeline:^(MXEventTimeline *liveTimeline) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
self->membersListener = [liveTimeline listenToEventsOfTypes:mxMembersEvents onEvent:^(MXEvent *event, MXTimelineDirection direction, id customObject) {
|
||||
|
||||
// Consider only live event
|
||||
if (direction == MXTimelineDirectionForwards)
|
||||
{
|
||||
switch (event.eventType)
|
||||
{
|
||||
MXRoomMember *mxMember = [self.mxRoom.state.members memberWithUserId:event.stateKey];
|
||||
if (mxMember)
|
||||
case MXEventTypeRoomMember:
|
||||
{
|
||||
// Remove previous occurrence of this member (if any)
|
||||
[self removeParticipantByKey:mxMember.userId];
|
||||
|
||||
// If any, remove 3pid invite corresponding to this room member
|
||||
if (mxMember.thirdPartyInviteToken)
|
||||
// Take into account updated member
|
||||
// Ignore here change related to the current user (this change is handled by leaveRoomNotificationObserver)
|
||||
if ([event.stateKey isEqualToString:self.mxRoom.mxSession.myUser.userId] == NO)
|
||||
{
|
||||
[self removeParticipantByKey:mxMember.thirdPartyInviteToken];
|
||||
MXRoomMember *mxMember = [liveTimeline.state.members memberWithUserId:event.stateKey];
|
||||
if (mxMember)
|
||||
{
|
||||
// Remove previous occurrence of this member (if any)
|
||||
[self removeParticipantByKey:mxMember.userId];
|
||||
|
||||
// If any, remove 3pid invite corresponding to this room member
|
||||
if (mxMember.thirdPartyInviteToken)
|
||||
{
|
||||
[self removeParticipantByKey:mxMember.thirdPartyInviteToken];
|
||||
}
|
||||
|
||||
[self handleRoomMember:mxMember];
|
||||
|
||||
[self finalizeParticipantsList:liveTimeline.state];
|
||||
|
||||
[self refreshTableView];
|
||||
}
|
||||
}
|
||||
|
||||
[self handleRoomMember:mxMember];
|
||||
|
||||
[self finalizeParticipantsList];
|
||||
|
||||
[self refreshTableView];
|
||||
|
||||
break;
|
||||
}
|
||||
case MXEventTypeRoomThirdPartyInvite:
|
||||
{
|
||||
MXRoomThirdPartyInvite *thirdPartyInvite = [liveTimeline.state thirdPartyInviteWithToken:event.stateKey];
|
||||
if (thirdPartyInvite)
|
||||
{
|
||||
[self addRoomThirdPartyInviteToParticipants:thirdPartyInvite roomState:liveTimeline.state];
|
||||
|
||||
[self finalizeParticipantsList:liveTimeline.state];
|
||||
|
||||
[self refreshTableView];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MXEventTypeRoomPowerLevels:
|
||||
{
|
||||
[self refreshParticipantsFromRoomMembers];
|
||||
|
||||
[self refreshTableView];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case MXEventTypeRoomThirdPartyInvite:
|
||||
{
|
||||
MXRoomThirdPartyInvite *thirdPartyInvite = [self.mxRoom.state thirdPartyInviteWithToken:event.stateKey];
|
||||
if (thirdPartyInvite)
|
||||
{
|
||||
[self addRoomThirdPartyInviteToParticipants:thirdPartyInvite];
|
||||
|
||||
[self finalizeParticipantsList];
|
||||
|
||||
[self refreshTableView];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MXEventTypeRoomPowerLevels:
|
||||
{
|
||||
[self refreshParticipantsFromRoomMembers];
|
||||
|
||||
[self refreshTableView];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Search bar header is hidden when no room is provided
|
||||
_searchBarHeader.hidden = YES;
|
||||
}
|
||||
|
||||
// Refresh the members list.
|
||||
[self refreshParticipantsFromRoomMembers];
|
||||
|
||||
[self refreshTableView];
|
||||
}];
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Search bar header is hidden when no room is provided
|
||||
self.searchBarHeader.hidden = YES;
|
||||
}
|
||||
|
||||
// Refresh the members list.
|
||||
[self refreshParticipantsFromRoomMembers];
|
||||
|
||||
[self refreshTableView];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)setEnableMention:(BOOL)enableMention
|
||||
@@ -686,36 +708,41 @@
|
||||
if (self.mxRoom)
|
||||
{
|
||||
// Retrieve the current members from the room state
|
||||
NSArray *members = [self.mxRoom.state.members membersWithoutConferenceUser];
|
||||
NSString *userId = self.mxRoom.mxSession.myUser.userId;
|
||||
NSArray *roomThirdPartyInvites = self.mxRoom.state.thirdPartyInvites;
|
||||
|
||||
for (MXRoomMember *mxMember in members)
|
||||
{
|
||||
// Update the current participants list
|
||||
if ([mxMember.userId isEqualToString:userId])
|
||||
MXWeakify(self);
|
||||
[self.mxRoom state:^(MXRoomState *roomState) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
NSArray *members = [roomState.members membersWithoutConferenceUser];
|
||||
NSString *userId = self.mxRoom.mxSession.myUser.userId;
|
||||
NSArray *roomThirdPartyInvites = roomState.thirdPartyInvites;
|
||||
|
||||
for (MXRoomMember *mxMember in members)
|
||||
{
|
||||
if (mxMember.membership == MXMembershipJoin || mxMember.membership == MXMembershipInvite)
|
||||
// Update the current participants list
|
||||
if ([mxMember.userId isEqualToString:userId])
|
||||
{
|
||||
// The user is in this room
|
||||
NSString *displayName = NSLocalizedStringFromTable(@"you", @"Vector", nil);
|
||||
|
||||
userParticipant = [[Contact alloc] initMatrixContactWithDisplayName:displayName andMatrixID:userId];
|
||||
userParticipant.mxMember = [self.mxRoom.state.members memberWithUserId:userId];
|
||||
if (mxMember.membership == MXMembershipJoin || mxMember.membership == MXMembershipInvite)
|
||||
{
|
||||
// The user is in this room
|
||||
NSString *displayName = NSLocalizedStringFromTable(@"you", @"Vector", nil);
|
||||
|
||||
self->userParticipant = [[Contact alloc] initMatrixContactWithDisplayName:displayName andMatrixID:userId];
|
||||
self->userParticipant.mxMember = [roomState.members memberWithUserId:userId];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
[self handleRoomMember:mxMember];
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
for (MXRoomThirdPartyInvite *roomThirdPartyInvite in roomThirdPartyInvites)
|
||||
{
|
||||
[self handleRoomMember:mxMember];
|
||||
[self addRoomThirdPartyInviteToParticipants:roomThirdPartyInvite roomState:roomState];
|
||||
}
|
||||
}
|
||||
|
||||
for (MXRoomThirdPartyInvite *roomThirdPartyInvite in roomThirdPartyInvites)
|
||||
{
|
||||
[self addRoomThirdPartyInviteToParticipants:roomThirdPartyInvite];
|
||||
}
|
||||
|
||||
[self finalizeParticipantsList];
|
||||
|
||||
[self finalizeParticipantsList:roomState];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -766,10 +793,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)addRoomThirdPartyInviteToParticipants:(MXRoomThirdPartyInvite*)roomThirdPartyInvite
|
||||
- (void)addRoomThirdPartyInviteToParticipants:(MXRoomThirdPartyInvite*)roomThirdPartyInvite roomState:(MXRoomState*)roomState
|
||||
{
|
||||
// If the homeserver has converted the 3pid invite into a room member, do no show it
|
||||
if (![self.mxRoom.state memberWithThirdPartyInviteToken:roomThirdPartyInvite.token])
|
||||
if (![roomState memberWithThirdPartyInviteToken:roomThirdPartyInvite.token])
|
||||
{
|
||||
Contact *contact = [[Contact alloc] initMatrixContactWithDisplayName:roomThirdPartyInvite.displayname andMatrixID:nil];
|
||||
contact.isThirdPartyInvite = YES;
|
||||
@@ -819,7 +846,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)finalizeParticipantsList
|
||||
- (void)finalizeParticipantsList:(MXRoomState*)roomState
|
||||
{
|
||||
// Sort contacts by last active, with "active now" first.
|
||||
// ...and then by power
|
||||
@@ -846,7 +873,7 @@
|
||||
if (userA.currentlyActive && userB.currentlyActive)
|
||||
{
|
||||
// Order first by power levels (admins then moderators then others)
|
||||
MXRoomPowerLevels *powerLevels = [self.mxRoom.state powerLevels];
|
||||
MXRoomPowerLevels *powerLevels = [roomState powerLevels];
|
||||
NSInteger powerLevelA = [powerLevels powerLevelOfUserWithUserID:contactA.mxMember.userId];
|
||||
NSInteger powerLevelB = [powerLevels powerLevelOfUserWithUserID:contactB.mxMember.userId];
|
||||
|
||||
@@ -1094,8 +1121,10 @@
|
||||
|
||||
if (contact.mxMember)
|
||||
{
|
||||
MXRoomState *roomState = self.mxRoom.dangerousSyncState;
|
||||
|
||||
// Update member badge
|
||||
MXRoomPowerLevels *powerLevels = [self.mxRoom.state powerLevels];
|
||||
MXRoomPowerLevels *powerLevels = [roomState powerLevels];
|
||||
NSInteger powerLevel = [powerLevels powerLevelOfUserWithUserID:contact.mxMember.userId];
|
||||
if (powerLevel >= kRiotRoomAdminLevel)
|
||||
{
|
||||
@@ -1111,7 +1140,7 @@
|
||||
// Update the contact display name by considering the current room state.
|
||||
if (contact.mxMember.userId)
|
||||
{
|
||||
participantCell.contactDisplayNameLabel.text = [self.mxRoom.state.members memberName:contact.mxMember.userId];
|
||||
participantCell.contactDisplayNameLabel.text = [roomState.members memberName:contact.mxMember.userId];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -545,9 +545,13 @@
|
||||
|
||||
// Observe missed notifications
|
||||
mxRoomSummaryDidChangeObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXRoomSummaryDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
|
||||
|
||||
[self refreshMissedDiscussionsCount:NO];
|
||||
|
||||
|
||||
MXRoomSummary *roomSummary = notif.object;
|
||||
|
||||
if ([roomSummary.roomId isEqualToString:self.roomDataSource.roomId])
|
||||
{
|
||||
[self refreshMissedDiscussionsCount:NO];
|
||||
}
|
||||
}];
|
||||
[self refreshMissedDiscussionsCount:YES];
|
||||
|
||||
@@ -931,9 +935,9 @@
|
||||
Class roomInputToolbarViewClass = RoomInputToolbarView.class;
|
||||
|
||||
// Check the user has enough power to post message
|
||||
if (self.roomDataSource.room.state)
|
||||
if (self.roomDataSource.roomState)
|
||||
{
|
||||
MXRoomPowerLevels *powerLevels = self.roomDataSource.room.state.powerLevels;
|
||||
MXRoomPowerLevels *powerLevels = self.roomDataSource.roomState.powerLevels;
|
||||
NSInteger userPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mainSession.myUser.userId];
|
||||
|
||||
BOOL canSend = (userPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsMessage:kMXEventTypeStringRoomMessage]);
|
||||
@@ -1894,7 +1898,7 @@
|
||||
{
|
||||
if ([actionIdentifier isEqualToString:kMXKRoomBubbleCellTapOnAvatarView])
|
||||
{
|
||||
selectedRoomMember = [self.roomDataSource.room.state.members memberWithUserId:userInfo[kMXKRoomBubbleCellUserIdKey]];
|
||||
selectedRoomMember = [self.roomDataSource.roomState.members memberWithUserId:userInfo[kMXKRoomBubbleCellUserIdKey]];
|
||||
if (selectedRoomMember)
|
||||
{
|
||||
[self performSegueWithIdentifier:@"showMemberDetails" sender:self];
|
||||
@@ -1903,7 +1907,7 @@
|
||||
else if ([actionIdentifier isEqualToString:kMXKRoomBubbleCellLongPressOnAvatarView])
|
||||
{
|
||||
// Add the member display name in text input
|
||||
MXRoomMember *roomMember = [self.roomDataSource.room.state.members memberWithUserId:userInfo[kMXKRoomBubbleCellUserIdKey]];
|
||||
MXRoomMember *roomMember = [self.roomDataSource.roomState.members memberWithUserId:userInfo[kMXKRoomBubbleCellUserIdKey]];
|
||||
if (roomMember)
|
||||
{
|
||||
[self mention:roomMember];
|
||||
@@ -2656,7 +2660,7 @@
|
||||
|
||||
NSString *userId = absoluteURLString;
|
||||
|
||||
MXRoomMember* member = [self.roomDataSource.room.state.members memberWithUserId:userId];
|
||||
MXRoomMember* member = [self.roomDataSource.roomState.members memberWithUserId:userId];
|
||||
if (member)
|
||||
{
|
||||
// Use the room member detail VC for room members
|
||||
@@ -2765,7 +2769,11 @@
|
||||
// Files tab
|
||||
[titles addObject: NSLocalizedStringFromTable(@"room_details_files", @"Vector", nil)];
|
||||
RoomFilesViewController *roomFilesViewController = [RoomFilesViewController roomViewController];
|
||||
MXKRoomDataSource *roomFilesDataSource = [[MXKRoomDataSource alloc] initWithRoomId:roomId andMatrixSession:session];
|
||||
// @TODO (async-state): This call should be synchronous. Every thing will be fine
|
||||
__block MXKRoomDataSource *roomFilesDataSource;
|
||||
[MXKRoomDataSource loadRoomDataSourceWithRoomId:roomId andMatrixSession:session onComplete:^(id roomDataSource) {
|
||||
roomFilesDataSource = roomDataSource;
|
||||
}];
|
||||
roomFilesDataSource.filterMessagesWithURL = YES;
|
||||
[roomFilesDataSource finalizeInitialization];
|
||||
// Give the data source ownership to the room files view controller.
|
||||
@@ -2858,25 +2866,18 @@
|
||||
contactsDataSource.contactCellAccessoryImage = [UIImage imageNamed:@"plus_icon"];
|
||||
|
||||
// List all the participants matrix user id to ignore them during the contacts search.
|
||||
MXSession* session = self.roomDataSource.mxSession;
|
||||
NSString* roomId = self.roomDataSource.roomId;
|
||||
MXRoom *room = [session roomWithRoomId:roomId];
|
||||
if (room)
|
||||
NSArray *members = [self.roomDataSource.roomState.members membersWithoutConferenceUser];
|
||||
for (MXRoomMember *mxMember in members)
|
||||
{
|
||||
NSArray *members = [room.state.members membersWithoutConferenceUser];
|
||||
|
||||
for (MXRoomMember *mxMember in members)
|
||||
// Check his status
|
||||
if (mxMember.membership == MXMembershipJoin || mxMember.membership == MXMembershipInvite)
|
||||
{
|
||||
// Check his status
|
||||
if (mxMember.membership == MXMembershipJoin || mxMember.membership == MXMembershipInvite)
|
||||
{
|
||||
// Create the contact related to this member
|
||||
MXKContact *contact = [[MXKContact alloc] initMatrixContactWithDisplayName:mxMember.displayname andMatrixID:mxMember.userId];
|
||||
[contactsDataSource.ignoredContactsByMatrixId setObject:contact forKey:mxMember.userId];
|
||||
}
|
||||
// Create the contact related to this member
|
||||
MXKContact *contact = [[MXKContact alloc] initMatrixContactWithDisplayName:mxMember.displayname andMatrixID:mxMember.userId];
|
||||
[contactsDataSource.ignoredContactsByMatrixId setObject:contact forKey:mxMember.userId];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[contactsPickerViewController showSearch:YES];
|
||||
contactsPickerViewController.searchBar.placeholder = NSLocalizedStringFromTable(@"room_participants_invite_another_user", @"Vector", nil);
|
||||
|
||||
@@ -3067,7 +3068,7 @@
|
||||
|
||||
// In case of conference call, check that the user has enough power level
|
||||
else if (self.roomDataSource.room.summary.membersCount.joined > 2 &&
|
||||
![MXCallManager canPlaceConferenceCallInRoom:self.roomDataSource.room])
|
||||
![MXCallManager canPlaceConferenceCallInRoom:self.roomDataSource.room roomState:self.roomDataSource.roomState])
|
||||
{
|
||||
[currentAlert dismissViewControllerAnimated:NO completion:nil];
|
||||
|
||||
@@ -3195,18 +3196,21 @@
|
||||
[self showExpandedHeader:NO];
|
||||
// Dismiss potential keyboard.
|
||||
[self dismissKeyboard];
|
||||
|
||||
MXKRoomDataSource *roomDataSource;
|
||||
|
||||
// Jump to the last unread event by using a temporary room data source initialized with the last unread event id.
|
||||
roomDataSource = [[RoomDataSource alloc] initWithRoomId:self.roomDataSource.roomId initialEventId:self.roomDataSource.room.accountData.readMarkerEventId andMatrixSession:self.mainSession];
|
||||
[roomDataSource finalizeInitialization];
|
||||
|
||||
// Center the bubbles table content on the bottom of the read marker event in order to display correctly the read marker view.
|
||||
self.centerBubblesTableViewContentOnTheInitialEventBottom = YES;
|
||||
[self displayRoom:roomDataSource];
|
||||
|
||||
// Give the data source ownership to the room view controller.
|
||||
self.hasRoomDataSourceOwnership = YES;
|
||||
MXWeakify(self);
|
||||
[RoomDataSource loadRoomDataSourceWithRoomId:self.roomDataSource.roomId initialEventId:self.roomDataSource.room.accountData.readMarkerEventId andMatrixSession:self.mainSession onComplete:^(id roomDataSource) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
[roomDataSource finalizeInitialization];
|
||||
|
||||
// Center the bubbles table content on the bottom of the read marker event in order to display correctly the read marker view.
|
||||
self.centerBubblesTableViewContentOnTheInitialEventBottom = YES;
|
||||
[self displayRoom:roomDataSource];
|
||||
|
||||
// Give the data source ownership to the room view controller.
|
||||
self.hasRoomDataSourceOwnership = YES;
|
||||
}];
|
||||
}
|
||||
else if (sender == self.resetReadMarkerButton)
|
||||
{
|
||||
@@ -3474,13 +3478,17 @@
|
||||
// If an event was specified, replace the datasource by a non live datasource showing the event
|
||||
if (eventId)
|
||||
{
|
||||
RoomDataSource *roomDataSource = [[RoomDataSource alloc] initWithRoomId:self.roomDataSource.roomId initialEventId:eventId andMatrixSession:self.mainSession];
|
||||
[roomDataSource finalizeInitialization];
|
||||
roomDataSource.markTimelineInitialEvent = YES;
|
||||
|
||||
[self displayRoom:roomDataSource];
|
||||
|
||||
self.hasRoomDataSourceOwnership = YES;
|
||||
MXWeakify(self);
|
||||
[RoomDataSource loadRoomDataSourceWithRoomId:self.roomDataSource.roomId initialEventId:eventId andMatrixSession:self.mainSession onComplete:^(id roomDataSource) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
[roomDataSource finalizeInitialization];
|
||||
((RoomDataSource*)roomDataSource).markTimelineInitialEvent = YES;
|
||||
|
||||
[self displayRoom:roomDataSource];
|
||||
|
||||
self.hasRoomDataSourceOwnership = YES;
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3555,8 +3563,13 @@
|
||||
// Remove the previous live listener
|
||||
if (typingNotifListener)
|
||||
{
|
||||
[self.roomDataSource.room.liveTimeline removeListener:typingNotifListener];
|
||||
typingNotifListener = nil;
|
||||
MXWeakify(self);
|
||||
[self.roomDataSource.room liveTimeline:^(MXEventTimeline *liveTimeline) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
[liveTimeline removeListener:self->typingNotifListener];
|
||||
self->typingNotifListener = nil;
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3568,8 +3581,10 @@
|
||||
if (self.roomDataSource)
|
||||
{
|
||||
// Add typing notification listener
|
||||
typingNotifListener = [self.roomDataSource.room.liveTimeline listenToEventsOfTypes:@[kMXEventTypeStringTypingNotification] onEvent:^(MXEvent *event, MXTimelineDirection direction, MXRoomState *roomState) {
|
||||
|
||||
MXWeakify(self);
|
||||
self->typingNotifListener = [self.roomDataSource.room listenToEventsOfTypes:@[kMXEventTypeStringTypingNotification] onEvent:^(MXEvent *event, MXTimelineDirection direction, MXRoomState *roomState) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
// Handle only live events
|
||||
if (direction == MXTimelineDirectionForwards)
|
||||
{
|
||||
@@ -3581,17 +3596,16 @@
|
||||
{
|
||||
[typingUsers removeObjectAtIndex:index];
|
||||
}
|
||||
|
||||
|
||||
// Ignore this notification if both arrays are empty
|
||||
if (currentTypingUsers.count || typingUsers.count)
|
||||
if (self->currentTypingUsers.count || typingUsers.count)
|
||||
{
|
||||
currentTypingUsers = typingUsers;
|
||||
self->currentTypingUsers = typingUsers;
|
||||
[self refreshActivitiesViewDisplay];
|
||||
}
|
||||
}
|
||||
|
||||
}];
|
||||
|
||||
|
||||
// Retrieve the current typing users list
|
||||
NSMutableArray *typingUsers = [NSMutableArray arrayWithArray:self.roomDataSource.room.typingUsers];
|
||||
// Remove typing info for the current user
|
||||
@@ -3621,7 +3635,7 @@
|
||||
{
|
||||
NSString* name = [currentTypingUsers objectAtIndex:i];
|
||||
|
||||
MXRoomMember* member = [self.roomDataSource.room.state.members memberWithUserId:name];
|
||||
MXRoomMember* member = [self.roomDataSource.roomState.members memberWithUserId:name];
|
||||
|
||||
if (member && member.displayname.length)
|
||||
{
|
||||
@@ -3754,7 +3768,8 @@
|
||||
- (NSUInteger)widgetsCount:(BOOL)includeUserWidgets
|
||||
{
|
||||
NSUInteger widgetsCount = [[WidgetManager sharedManager] widgetsNotOfTypes:@[kWidgetTypeJitsi]
|
||||
inRoom:self.roomDataSource.room].count;
|
||||
inRoom:self.roomDataSource.room
|
||||
withRoomState:self.roomDataSource.roomState].count;
|
||||
if (includeUserWidgets)
|
||||
{
|
||||
widgetsCount += [[WidgetManager sharedManager] userWidgets:self.roomDataSource.room.mxSession].count;
|
||||
@@ -3783,7 +3798,7 @@
|
||||
{
|
||||
[roomActivitiesView displayNetworkErrorNotification:NSLocalizedStringFromTable(@"room_offline_notification", @"Vector", nil)];
|
||||
}
|
||||
else if (customizedRoomDataSource.room.state.isOngoingConferenceCall)
|
||||
else if (customizedRoomDataSource.roomState.isOngoingConferenceCall)
|
||||
{
|
||||
// Show the "Ongoing conference call" banner only if the user is not in the conference
|
||||
MXCall *callInRoom = [self.roomDataSource.mxSession.callManager callInRoom:self.roomDataSource.roomId];
|
||||
@@ -3928,24 +3943,28 @@
|
||||
{
|
||||
// Switch back to the room live timeline managed by MXKRoomDataSourceManager
|
||||
MXKRoomDataSourceManager *roomDataSourceManager = [MXKRoomDataSourceManager sharedManagerForMatrixSession:self.mainSession];
|
||||
MXKRoomDataSource *roomDataSource = [roomDataSourceManager roomDataSourceForRoom:self.roomDataSource.roomId create:YES];
|
||||
|
||||
// Scroll to bottom the bubble history on the display refresh.
|
||||
shouldScrollToBottomOnTableRefresh = YES;
|
||||
|
||||
[self displayRoom:roomDataSource];
|
||||
|
||||
// The room view controller do not have here the data source ownership.
|
||||
self.hasRoomDataSourceOwnership = NO;
|
||||
|
||||
[self refreshActivitiesViewDisplay];
|
||||
[self refreshJumpToLastUnreadBannerDisplay];
|
||||
|
||||
if (self.saveProgressTextInput)
|
||||
{
|
||||
// Restore the potential message partially typed before jump to last unread messages.
|
||||
self.inputToolbarView.textMessage = roomDataSource.partialTextMessage;
|
||||
}
|
||||
|
||||
MXWeakify(self);
|
||||
[roomDataSourceManager roomDataSourceForRoom:self.roomDataSource.roomId create:YES onComplete:^(MXKRoomDataSource *roomDataSource) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
// Scroll to bottom the bubble history on the display refresh.
|
||||
self->shouldScrollToBottomOnTableRefresh = YES;
|
||||
|
||||
[self displayRoom:roomDataSource];
|
||||
|
||||
// The room view controller do not have here the data source ownership.
|
||||
self.hasRoomDataSourceOwnership = NO;
|
||||
|
||||
[self refreshActivitiesViewDisplay];
|
||||
[self refreshJumpToLastUnreadBannerDisplay];
|
||||
|
||||
if (self.saveProgressTextInput)
|
||||
{
|
||||
// Restore the potential message partially typed before jump to last unread messages.
|
||||
self.inputToolbarView.textMessage = roomDataSource.partialTextMessage;
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
[super destroy];
|
||||
}
|
||||
|
||||
- (void)convertHomeserverResultsIntoCells:(MXSearchRoomEventResults *)roomEventResults
|
||||
- (void)convertHomeserverResultsIntoCells:(MXSearchRoomEventResults *)roomEventResults onComplete:(dispatch_block_t)onComplete
|
||||
{
|
||||
// Prepare text font used to highlight the search pattern.
|
||||
UIFont *patternFont = [roomDataSource.eventFormatter bingTextFont];
|
||||
@@ -64,7 +64,7 @@
|
||||
// The search result contains only room message events, no state events.
|
||||
// Thus, passing the current room state is not a huge problem. Only
|
||||
// the user display name and his avatar may be wrong.
|
||||
RoomBubbleCellData *cellData = [[RoomBubbleCellData alloc] initWithEvent:result.result andRoomState:roomDataSource.room.state andRoomDataSource:roomDataSource];
|
||||
RoomBubbleCellData *cellData = [[RoomBubbleCellData alloc] initWithEvent:result.result andRoomState:roomDataSource.roomState andRoomDataSource:roomDataSource];
|
||||
if (cellData)
|
||||
{
|
||||
// Highlight the search pattern
|
||||
@@ -73,6 +73,8 @@
|
||||
[cellDataArray insertObject:cellData atIndex:0];
|
||||
}
|
||||
}
|
||||
|
||||
onComplete();
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
|
||||
@@ -290,14 +290,19 @@
|
||||
if (selectedSearchEvent)
|
||||
{
|
||||
RoomViewController *roomViewController = segue.destinationViewController;
|
||||
RoomDataSource *roomDataSource = [[RoomDataSource alloc] initWithRoomId:selectedSearchEvent.roomId initialEventId:selectedSearchEvent.eventId andMatrixSession:selectedSearchEventSession];
|
||||
[roomDataSource finalizeInitialization];
|
||||
roomDataSource.markTimelineInitialEvent = YES;
|
||||
|
||||
[roomViewController displayRoom:roomDataSource];
|
||||
roomViewController.hasRoomDataSourceOwnership = YES;
|
||||
|
||||
roomViewController.navigationItem.leftItemsSupplementBackButton = YES;
|
||||
|
||||
[RoomDataSource loadRoomDataSourceWithRoomId:selectedSearchEvent.roomId
|
||||
initialEventId:selectedSearchEvent.eventId
|
||||
andMatrixSession:selectedSearchEventSession onComplete:^(RoomDataSource *roomDataSource) {
|
||||
|
||||
[roomDataSource finalizeInitialization];
|
||||
roomDataSource.markTimelineInitialEvent = YES;
|
||||
|
||||
[roomViewController displayRoom:roomDataSource];
|
||||
roomViewController.hasRoomDataSourceOwnership = YES;
|
||||
|
||||
roomViewController.navigationItem.leftItemsSupplementBackButton = YES;
|
||||
}];
|
||||
}
|
||||
|
||||
// Hide back button title
|
||||
|
||||
@@ -190,8 +190,8 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
|
||||
[super initWithSession:session andRoomId:roomId];
|
||||
|
||||
// Add an additional listener to update banned users
|
||||
extraEventsListener = [mxRoom.liveTimeline listenToEventsOfTypes:@[kMXEventTypeStringRoomMember] onEvent:^(MXEvent *event, MXTimelineDirection direction, MXRoomState *roomState) {
|
||||
|
||||
self->extraEventsListener = [mxRoom listenToEventsOfTypes:@[kMXEventTypeStringRoomMember] onEvent:^(MXEvent *event, MXTimelineDirection direction, MXRoomState *roomState) {
|
||||
|
||||
if (direction == MXTimelineDirectionForwards)
|
||||
{
|
||||
[self updateRoomState:roomState];
|
||||
@@ -399,8 +399,13 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
|
||||
|
||||
if (extraEventsListener)
|
||||
{
|
||||
[mxRoom.liveTimeline removeListener:extraEventsListener];
|
||||
extraEventsListener = nil;
|
||||
MXWeakify(self);
|
||||
[mxRoom liveTimeline:^(MXEventTimeline *liveTimeline) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
[liveTimeline removeListener:self->extraEventsListener];
|
||||
self->extraEventsListener = nil;
|
||||
}];
|
||||
}
|
||||
|
||||
[super destroy];
|
||||
@@ -467,7 +472,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
|
||||
if (!eventTypeForSelectedField)
|
||||
return;
|
||||
|
||||
MXRoomPowerLevels *powerLevels = [mxRoom.state powerLevels];
|
||||
MXRoomPowerLevels *powerLevels = [mxRoomState powerLevels];
|
||||
NSInteger oneSelfPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mainSession.myUser.userId];
|
||||
|
||||
if (oneSelfPowerLevel < [powerLevels minimumPowerLevelForSendingEventAsStateEvent:eventTypeForSelectedField])
|
||||
@@ -1963,7 +1968,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
|
||||
if (self.mainSession)
|
||||
{
|
||||
// Check user's power level to know whether the user is allowed to add room alias
|
||||
MXRoomPowerLevels *powerLevels = [mxRoom.state powerLevels];
|
||||
MXRoomPowerLevels *powerLevels = [mxRoomState powerLevels];
|
||||
NSInteger oneSelfPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mainSession.myUser.userId];
|
||||
|
||||
if (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomAliases])
|
||||
@@ -1981,7 +1986,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
|
||||
if (self.mainSession)
|
||||
{
|
||||
// Check user's power level to know whether the user is allowed to add communities to this room
|
||||
MXRoomPowerLevels *powerLevels = [mxRoom.state powerLevels];
|
||||
MXRoomPowerLevels *powerLevels = [mxRoomState powerLevels];
|
||||
NSInteger oneSelfPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mainSession.myUser.userId];
|
||||
|
||||
if (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomRelatedGroups])
|
||||
@@ -2118,7 +2123,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
|
||||
UITableViewCell* cell;
|
||||
|
||||
// Check user's power level to know which settings are editable.
|
||||
MXRoomPowerLevels *powerLevels = [mxRoom.state powerLevels];
|
||||
MXRoomPowerLevels *powerLevels = [mxRoomState powerLevels];
|
||||
NSInteger oneSelfPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mainSession.myUser.userId];
|
||||
|
||||
// general settings
|
||||
@@ -2732,7 +2737,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
|
||||
else
|
||||
{
|
||||
// Check user's power level to know whether the user is allowed to turn on the encryption mode
|
||||
MXRoomPowerLevels *powerLevels = [mxRoom.state powerLevels];
|
||||
MXRoomPowerLevels *powerLevels = [mxRoomState powerLevels];
|
||||
NSInteger oneSelfPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mainSession.myUser.userId];
|
||||
|
||||
if (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomEncryption])
|
||||
|
||||
@@ -65,46 +65,51 @@
|
||||
self.roomTopic.text = [MXTools stripNewlineCharacters:self.mxRoom.summary.topic];
|
||||
|
||||
// Compute active members count
|
||||
NSArray *members = [self.mxRoom.state.members membersWithMembership:MXMembershipJoin includeConferenceUser:NO];
|
||||
NSUInteger activeCount = 0;
|
||||
NSUInteger memberCount = 0;
|
||||
for (MXRoomMember *mxMember in members)
|
||||
{
|
||||
memberCount ++;
|
||||
MXWeakify(self);
|
||||
[self.mxRoom members:^(MXRoomMembers *roomMembers) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
// Get the user that corresponds to this member
|
||||
MXUser *user = [self.mxRoom.mxSession userWithUserId:mxMember.userId];
|
||||
// existing user ?
|
||||
if (user && user.presence == MXPresenceOnline)
|
||||
NSArray *members = [roomMembers membersWithMembership:MXMembershipJoin includeConferenceUser:NO];
|
||||
NSUInteger activeCount = 0;
|
||||
NSUInteger memberCount = 0;
|
||||
for (MXRoomMember *mxMember in members)
|
||||
{
|
||||
activeCount ++;
|
||||
}
|
||||
}
|
||||
memberCount ++;
|
||||
|
||||
if (memberCount)
|
||||
{
|
||||
// Check whether the logged in user is alone in this room
|
||||
if (memberCount == 1 && self.mxRoom.summary.membership == MXMembershipJoin)
|
||||
{
|
||||
self.roomMembers.text = NSLocalizedStringFromTable(@"room_title_invite_members", @"Vector", nil);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (activeCount > 1)
|
||||
// Get the user that corresponds to this member
|
||||
MXUser *user = [self.mxRoom.mxSession userWithUserId:mxMember.userId];
|
||||
// existing user ?
|
||||
if (user && user.presence == MXPresenceOnline)
|
||||
{
|
||||
self.roomMembers.text = [NSString stringWithFormat:NSLocalizedStringFromTable(@"room_title_multiple_active_members", @"Vector", nil), @(activeCount), @(memberCount)];
|
||||
activeCount ++;
|
||||
}
|
||||
}
|
||||
|
||||
if (memberCount)
|
||||
{
|
||||
// Check whether the logged in user is alone in this room
|
||||
if (memberCount == 1 && self.mxRoom.summary.membership == MXMembershipJoin)
|
||||
{
|
||||
self.roomMembers.text = NSLocalizedStringFromTable(@"room_title_invite_members", @"Vector", nil);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.roomMembers.text = [NSString stringWithFormat:NSLocalizedStringFromTable(@"room_title_one_active_member", @"Vector", nil), @(activeCount), @(memberCount)];
|
||||
if (activeCount > 1)
|
||||
{
|
||||
self.roomMembers.text = [NSString stringWithFormat:NSLocalizedStringFromTable(@"room_title_multiple_active_members", @"Vector", nil), @(activeCount), @(memberCount)];
|
||||
}
|
||||
else
|
||||
{
|
||||
self.roomMembers.text = [NSString stringWithFormat:NSLocalizedStringFromTable(@"room_title_one_active_member", @"Vector", nil), @(activeCount), @(memberCount)];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Should not happen
|
||||
self.roomMembers.text = nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Should not happen
|
||||
self.roomMembers.text = nil;
|
||||
}
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -182,51 +182,56 @@
|
||||
self.roomTopic.text = [MXTools stripNewlineCharacters:self.mxRoom.summary.topic];
|
||||
|
||||
// Compute active members count, and look for the inviter
|
||||
NSArray *members = self.mxRoom.state.members.members;
|
||||
NSUInteger activeCount = 0;
|
||||
NSUInteger memberCount = 0;
|
||||
NSString *inviter = nil;
|
||||
|
||||
for (MXRoomMember *mxMember in members)
|
||||
{
|
||||
if (mxMember.membership == MXMembershipJoin)
|
||||
MXWeakify(self);
|
||||
[self.mxRoom members:^(MXRoomMembers *roomMembers) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
NSArray *members = roomMembers.members;
|
||||
NSUInteger activeCount = 0;
|
||||
NSUInteger memberCount = 0;
|
||||
NSString *inviter = nil;
|
||||
|
||||
for (MXRoomMember *mxMember in members)
|
||||
{
|
||||
memberCount ++;
|
||||
|
||||
// Get the user that corresponds to this member
|
||||
MXUser *user = [self.mxRoom.mxSession userWithUserId:mxMember.userId];
|
||||
// existing user ?
|
||||
if (user && user.presence == MXPresenceOnline)
|
||||
if (mxMember.membership == MXMembershipJoin)
|
||||
{
|
||||
activeCount ++;
|
||||
memberCount ++;
|
||||
|
||||
// Get the user that corresponds to this member
|
||||
MXUser *user = [self.mxRoom.mxSession userWithUserId:mxMember.userId];
|
||||
// existing user ?
|
||||
if (user && user.presence == MXPresenceOnline)
|
||||
{
|
||||
activeCount ++;
|
||||
}
|
||||
|
||||
// Presently only one member is available from invited room data
|
||||
// This is the inviter
|
||||
inviter = mxMember.displayname.length ? mxMember.displayname : mxMember.userId;
|
||||
}
|
||||
|
||||
// Presently only one member is available from invited room data
|
||||
// This is the inviter
|
||||
inviter = mxMember.displayname.length ? mxMember.displayname : mxMember.userId;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Display members status when it will be available
|
||||
self.roomMembers.text = nil;
|
||||
// if (memberCount)
|
||||
// {
|
||||
// if (activeCount > 1)
|
||||
// {
|
||||
// self.roomMembers.text = [NSString stringWithFormat:NSLocalizedStringFromTable(@"room_title_multiple_active_members", @"Vector", nil), @(activeCount), @(memberCount)];
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// self.roomMembers.text = [NSString stringWithFormat:NSLocalizedStringFromTable(@"room_title_one_active_member", @"Vector", nil), @(activeCount), @(memberCount)];
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// // Should not happen
|
||||
// self.roomMembers.text = nil;
|
||||
// }
|
||||
|
||||
self.previewLabel.text = [NSString stringWithFormat:NSLocalizedStringFromTable(@"room_preview_invitation_format", @"Vector", nil), inviter];
|
||||
|
||||
// FIXME: Display members status when it will be available
|
||||
self.roomMembers.text = nil;
|
||||
// if (memberCount)
|
||||
// {
|
||||
// if (activeCount > 1)
|
||||
// {
|
||||
// self.roomMembers.text = [NSString stringWithFormat:NSLocalizedStringFromTable(@"room_title_multiple_active_members", @"Vector", nil), @(activeCount), @(memberCount)];
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// self.roomMembers.text = [NSString stringWithFormat:NSLocalizedStringFromTable(@"room_title_one_active_member", @"Vector", nil), @(activeCount), @(memberCount)];
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// // Should not happen
|
||||
// self.roomMembers.text = nil;
|
||||
// }
|
||||
|
||||
self.previewLabel.text = [NSString stringWithFormat:NSLocalizedStringFromTable(@"room_preview_invitation_format", @"Vector", nil), inviter];
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -2975,8 +2975,9 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
|
||||
{
|
||||
if (room.summary.isEncrypted)
|
||||
{
|
||||
MXKRoomDataSource *roomDataSource = [roomDataSourceManager roomDataSourceForRoom:room.roomId create:NO];
|
||||
[roomDataSource reload];
|
||||
[roomDataSourceManager roomDataSourceForRoom:room.roomId create:NO onComplete:^(MXKRoomDataSource *roomDataSource) {
|
||||
[roomDataSource reload];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
Copyright 2017 Vector Creations Ltd
|
||||
|
||||
Copyright 2018 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
@@ -510,59 +511,37 @@
|
||||
|
||||
if ([[segue identifier] isEqualToString:@"showRoomDetails"])
|
||||
{
|
||||
// Replace the rootviewcontroller with a room view controller
|
||||
// Get the RoomViewController from the storyboard
|
||||
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
|
||||
_currentRoomViewController = [storyboard instantiateViewControllerWithIdentifier:@"RoomViewControllerStoryboardId"];
|
||||
|
||||
navigationController.viewControllers = @[_currentRoomViewController];
|
||||
|
||||
if (!_selectedRoomPreviewData)
|
||||
{
|
||||
MXKRoomDataSource *roomDataSource;
|
||||
|
||||
// Check whether an event has been selected from messages or files search tab.
|
||||
MXEvent *selectedSearchEvent = unifiedSearchViewController.selectedSearchEvent;
|
||||
MXSession *selectedSearchEventSession = unifiedSearchViewController.selectedSearchEventSession;
|
||||
|
||||
if (!selectedSearchEvent)
|
||||
{
|
||||
if (!_selectedEventId)
|
||||
{
|
||||
// LIVE: Show the room live timeline managed by MXKRoomDataSourceManager
|
||||
MXKRoomDataSourceManager *roomDataSourceManager = [MXKRoomDataSourceManager sharedManagerForMatrixSession:_selectedRoomSession];
|
||||
roomDataSource = [roomDataSourceManager roomDataSourceForRoom:_selectedRoomId create:YES];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Open the room on the requested event
|
||||
roomDataSource = [[RoomDataSource alloc] initWithRoomId:_selectedRoomId initialEventId:_selectedEventId andMatrixSession:_selectedRoomSession];
|
||||
[roomDataSource finalizeInitialization];
|
||||
|
||||
((RoomDataSource*)roomDataSource).markTimelineInitialEvent = YES;
|
||||
|
||||
// Give the data source ownership to the room view controller.
|
||||
_currentRoomViewController.hasRoomDataSourceOwnership = YES;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Search result: Create a temp timeline from the selected event
|
||||
roomDataSource = [[RoomDataSource alloc] initWithRoomId:selectedSearchEvent.roomId initialEventId:selectedSearchEvent.eventId andMatrixSession:selectedSearchEventSession];
|
||||
[roomDataSource finalizeInitialization];
|
||||
|
||||
((RoomDataSource*)roomDataSource).markTimelineInitialEvent = YES;
|
||||
|
||||
// Give the data source ownership to the room view controller.
|
||||
_currentRoomViewController.hasRoomDataSourceOwnership = YES;
|
||||
}
|
||||
|
||||
[_currentRoomViewController displayRoom:roomDataSource];
|
||||
MXWeakify(self);
|
||||
[self dataSourceOfRoomToDisplay:^(MXKRoomDataSource *roomDataSource) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
// Replace the rootviewcontroller with a room view controller
|
||||
// Get the RoomViewController from the storyboard
|
||||
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
|
||||
self->_currentRoomViewController = [storyboard instantiateViewControllerWithIdentifier:@"RoomViewControllerStoryboardId"];
|
||||
|
||||
navigationController.viewControllers = @[self.currentRoomViewController];
|
||||
|
||||
[self.currentRoomViewController displayRoom:roomDataSource];
|
||||
|
||||
[self setupLeftBarButtonItem];
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Replace the rootviewcontroller with a room view controller
|
||||
// Get the RoomViewController from the storyboard
|
||||
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
|
||||
_currentRoomViewController = [storyboard instantiateViewControllerWithIdentifier:@"RoomViewControllerStoryboardId"];
|
||||
|
||||
navigationController.viewControllers = @[_currentRoomViewController];
|
||||
|
||||
[_currentRoomViewController displayRoomPreview:_selectedRoomPreviewData];
|
||||
_selectedRoomPreviewData = nil;
|
||||
|
||||
[self setupLeftBarButtonItem];
|
||||
}
|
||||
}
|
||||
else if ([[segue identifier] isEqualToString:@"showContactDetails"])
|
||||
@@ -573,6 +552,8 @@
|
||||
_currentContactDetailViewController.contact = _selectedContact;
|
||||
|
||||
navigationController.viewControllers = @[_currentContactDetailViewController];
|
||||
|
||||
[self setupLeftBarButtonItem];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -581,28 +562,8 @@
|
||||
[_currentGroupDetailViewController setGroup:_selectedGroup withMatrixSession:_selectedGroupSession];
|
||||
|
||||
navigationController.viewControllers = @[_currentGroupDetailViewController];
|
||||
}
|
||||
|
||||
if (self.splitViewController)
|
||||
{
|
||||
// Refresh selected cell without scrolling the selected cell (We suppose it's visible here)
|
||||
[self refreshCurrentSelectedCell:NO];
|
||||
|
||||
if (_currentRoomViewController)
|
||||
{
|
||||
_currentRoomViewController.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
|
||||
_currentRoomViewController.navigationItem.leftItemsSupplementBackButton = YES;
|
||||
}
|
||||
else if (_currentContactDetailViewController)
|
||||
{
|
||||
_currentContactDetailViewController.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
|
||||
_currentContactDetailViewController.navigationItem.leftItemsSupplementBackButton = YES;
|
||||
}
|
||||
else if (_currentGroupDetailViewController)
|
||||
{
|
||||
_currentGroupDetailViewController.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
|
||||
_currentGroupDetailViewController.navigationItem.leftItemsSupplementBackButton = YES;
|
||||
}
|
||||
|
||||
[self setupLeftBarButtonItem];
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -647,6 +608,84 @@
|
||||
self.navigationController.topViewController.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil];
|
||||
}
|
||||
|
||||
/**
|
||||
Load the data source of the room to open.
|
||||
|
||||
@param onComplete a block providing the loaded room data source.
|
||||
*/
|
||||
- (void)dataSourceOfRoomToDisplay:(void (^)(MXKRoomDataSource *roomDataSource))onComplete
|
||||
{
|
||||
// Check whether an event has been selected from messages or files search tab.
|
||||
MXEvent *selectedSearchEvent = unifiedSearchViewController.selectedSearchEvent;
|
||||
MXSession *selectedSearchEventSession = unifiedSearchViewController.selectedSearchEventSession;
|
||||
|
||||
if (!selectedSearchEvent)
|
||||
{
|
||||
if (!_selectedEventId)
|
||||
{
|
||||
// LIVE: Show the room live timeline managed by MXKRoomDataSourceManager
|
||||
MXKRoomDataSourceManager *roomDataSourceManager = [MXKRoomDataSourceManager sharedManagerForMatrixSession:_selectedRoomSession];
|
||||
|
||||
[roomDataSourceManager roomDataSourceForRoom:_selectedRoomId create:YES onComplete:^(MXKRoomDataSource *roomDataSource) {
|
||||
onComplete(roomDataSource);
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Open the room on the requested event
|
||||
[RoomDataSource loadRoomDataSourceWithRoomId:_selectedRoomId initialEventId:_selectedEventId andMatrixSession:_selectedRoomSession onComplete:^(id roomDataSource) {
|
||||
|
||||
((RoomDataSource*)roomDataSource).markTimelineInitialEvent = YES;
|
||||
|
||||
// Give the data source ownership to the room view controller.
|
||||
self.currentRoomViewController.hasRoomDataSourceOwnership = YES;
|
||||
|
||||
onComplete(roomDataSource);
|
||||
}];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Search result: Create a temp timeline from the selected event
|
||||
[RoomDataSource loadRoomDataSourceWithRoomId:selectedSearchEvent.roomId initialEventId:selectedSearchEvent.eventId andMatrixSession:selectedSearchEventSession onComplete:^(id roomDataSource) {
|
||||
|
||||
[roomDataSource finalizeInitialization];
|
||||
|
||||
((RoomDataSource*)roomDataSource).markTimelineInitialEvent = YES;
|
||||
|
||||
// Give the data source ownership to the room view controller.
|
||||
self.currentRoomViewController.hasRoomDataSourceOwnership = YES;
|
||||
|
||||
onComplete(roomDataSource);
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setupLeftBarButtonItem
|
||||
{
|
||||
if (self.splitViewController)
|
||||
{
|
||||
// Refresh selected cell without scrolling the selected cell (We suppose it's visible here)
|
||||
[self refreshCurrentSelectedCell:NO];
|
||||
|
||||
if (_currentRoomViewController)
|
||||
{
|
||||
_currentRoomViewController.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
|
||||
_currentRoomViewController.navigationItem.leftItemsSupplementBackButton = YES;
|
||||
}
|
||||
else if (_currentContactDetailViewController)
|
||||
{
|
||||
_currentContactDetailViewController.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
|
||||
_currentContactDetailViewController.navigationItem.leftItemsSupplementBackButton = YES;
|
||||
}
|
||||
else if (_currentGroupDetailViewController)
|
||||
{
|
||||
_currentGroupDetailViewController.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
|
||||
_currentGroupDetailViewController.navigationItem.leftItemsSupplementBackButton = YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion
|
||||
{
|
||||
// Keep ref on presented view controller
|
||||
|
||||
@@ -262,9 +262,9 @@ NSString *const kEventFormatterOnReRequestKeysLinkActionSeparator = @"/";
|
||||
|
||||
#pragma mark - MXRoomSummaryUpdating
|
||||
|
||||
- (BOOL)session:(MXSession *)session updateRoomSummary:(MXRoomSummary *)summary withStateEvents:(NSArray<MXEvent *> *)stateEvents
|
||||
- (BOOL)session:(MXSession *)session updateRoomSummary:(MXRoomSummary *)summary withStateEvents:(NSArray<MXEvent *> *)stateEvents roomState:(MXRoomState *)roomState
|
||||
{
|
||||
BOOL ret = [super session:session updateRoomSummary:summary withStateEvents:stateEvents];
|
||||
BOOL ret = [super session:session updateRoomSummary:summary withStateEvents:stateEvents roomState:roomState];
|
||||
|
||||
// Check whether the room display name and/or the room avatar url should be updated at Riot level.
|
||||
BOOL refreshRiotRoomDisplayName = NO;
|
||||
@@ -303,7 +303,7 @@ NSString *const kEventFormatterOnReRequestKeysLinkActionSeparator = @"/";
|
||||
|
||||
if (refreshRiotRoomDisplayName)
|
||||
{
|
||||
NSString *riotRoomDisplayName = [self riotRoomDisplayNameFromRoomState:summary.room.state];
|
||||
NSString *riotRoomDisplayName = [self riotRoomDisplayNameFromRoomState:roomState];
|
||||
|
||||
if (riotRoomDisplayName.length && ![summary.displayname isEqualToString:riotRoomDisplayName])
|
||||
{
|
||||
@@ -313,7 +313,7 @@ NSString *const kEventFormatterOnReRequestKeysLinkActionSeparator = @"/";
|
||||
}
|
||||
if (refreshRiotRoomAvatarURL)
|
||||
{
|
||||
NSString *riotRoomAvatarURL = [self riotRoomAvatarURLFromRoomState:summary.room.state];
|
||||
NSString *riotRoomAvatarURL = [self riotRoomAvatarURLFromRoomState:roomState];
|
||||
|
||||
if (riotRoomAvatarURL.length && ![summary.avatar isEqualToString:riotRoomAvatarURL])
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user