mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-18 23:48:29 +02:00
Use live timeline of a thread
This commit is contained in:
@@ -201,6 +201,7 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
|
||||
@property (nonatomic, assign) BOOL shouldStopBackPagination;
|
||||
|
||||
@property (nonatomic, readwrite) MXRoom *room;
|
||||
@property (nonatomic, readwrite) MXThread *thread;
|
||||
|
||||
@property (nonatomic, readwrite) MXRoom *secondaryRoom;
|
||||
@property (nonatomic, strong) id<MXEventTimeline> secondaryTimeline;
|
||||
@@ -258,9 +259,18 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
|
||||
|
||||
// Asynchronously preload data here so that the data will be ready later
|
||||
// to synchronously respond to that request
|
||||
[roomDataSource.room liveTimeline:^(id<MXEventTimeline> liveTimeline) {
|
||||
onComplete(roomDataSource);
|
||||
}];
|
||||
if (roomDataSource.threadId)
|
||||
{
|
||||
[roomDataSource.thread liveTimeline:^(id<MXEventTimeline> _Nonnull liveTimeline) {
|
||||
onComplete(roomDataSource);
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
[roomDataSource.room liveTimeline:^(id<MXEventTimeline> liveTimeline) {
|
||||
onComplete(roomDataSource);
|
||||
}];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -622,209 +632,311 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
|
||||
{
|
||||
if (MXSessionStateStoreDataReady <= self.mxSession.state)
|
||||
{
|
||||
// Check whether the room is not already set
|
||||
if (!_room)
|
||||
if (_threadId)
|
||||
{
|
||||
// Are we peeking into a random room or displaying a room the user is part of?
|
||||
if (peekingRoom)
|
||||
[self initializeTimelineForThread];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self initializeTimelineForRoom];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)initializeTimelineForRoom
|
||||
{
|
||||
// Check whether the room is not already set
|
||||
if (!_room)
|
||||
{
|
||||
// Are we peeking into a random room or displaying a room the user is part of?
|
||||
if (peekingRoom)
|
||||
{
|
||||
self.room = peekingRoom;
|
||||
}
|
||||
else
|
||||
{
|
||||
self.room = [self.mxSession roomWithRoomId:_roomId];
|
||||
}
|
||||
|
||||
if (_room)
|
||||
{
|
||||
// This is the time to set up the timeline according to the called init method
|
||||
if (_isLive)
|
||||
{
|
||||
self.room = peekingRoom;
|
||||
// LIVE
|
||||
MXWeakify(self);
|
||||
[_room liveTimeline:^(id<MXEventTimeline> liveTimeline) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
self->_timeline = liveTimeline;
|
||||
|
||||
// Only one pagination process can be done at a time by an MXRoom object.
|
||||
// This assumption is satisfied by MatrixKit. Only MXRoomDataSource does it.
|
||||
[self.timeline resetPagination];
|
||||
|
||||
// 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.mxSession == room.mxSession && ([self.roomId isEqualToString:room.roomId] ||
|
||||
([self.secondaryRoomId isEqualToString:room.roomId])))
|
||||
{
|
||||
// The existing room history has been flushed during server sync because a gap has been observed between local and server storage.
|
||||
[self reload];
|
||||
}
|
||||
|
||||
}];
|
||||
|
||||
// Add the event listeners, by considering all the event types (the event filtering is applying by the event formatter),
|
||||
// except if only the events with a url key in their content must be handled.
|
||||
[self refreshEventListeners:(self.filterMessagesWithURL ? @[kMXEventTypeStringRoomMessage] : [MXKAppSettings standardAppSettings].allEventTypesForMessages)];
|
||||
|
||||
// display typing notifications is optional
|
||||
// the inherited class can manage them by its own.
|
||||
if (self.showTypingNotifications)
|
||||
{
|
||||
// Register on typing notif
|
||||
[self listenTypingNotifications];
|
||||
}
|
||||
|
||||
// Manage unsent messages
|
||||
[self handleUnsentMessages];
|
||||
|
||||
// Update here data source state if it is not already ready
|
||||
if (!self->_secondaryRoomId)
|
||||
{
|
||||
[self setState:MXKDataSourceStateReady];
|
||||
}
|
||||
|
||||
// Check user membership in this room
|
||||
MXMembership membership = self.room.summary.membership;
|
||||
if (membership == MXMembershipUnknown || membership == MXMembershipInvite)
|
||||
{
|
||||
// Here the initial sync is not ended or the room is a pending invitation.
|
||||
// Note: In case of invitation, a full sync will be triggered if the user joins this room.
|
||||
|
||||
// We have to observe here 'kMXRoomInitialSyncNotification' to reload room data when room sync is done.
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didMXRoomInitialSynced:) name:kMXRoomInitialSyncNotification object:self.room];
|
||||
}
|
||||
}];
|
||||
|
||||
if (!_secondaryRoom && _secondaryRoomId)
|
||||
{
|
||||
_secondaryRoom = [self.mxSession roomWithRoomId:_secondaryRoomId];
|
||||
|
||||
if (_secondaryRoom)
|
||||
{
|
||||
MXWeakify(self);
|
||||
[_secondaryRoom liveTimeline:^(id<MXEventTimeline> liveTimeline) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
self->_secondaryTimeline = liveTimeline;
|
||||
|
||||
// Only one pagination process can be done at a time by an MXRoom object.
|
||||
// This assumption is satisfied by MatrixKit. Only MXRoomDataSource does it.
|
||||
[self.secondaryTimeline resetPagination];
|
||||
|
||||
// Add the secondary event listeners, by considering the event types in self.secondaryRoomEventTypes
|
||||
[self refreshSecondaryEventListeners:self.secondaryRoomEventTypes];
|
||||
|
||||
// Update here data source state if it is not already ready
|
||||
[self setState:MXKDataSourceStateReady];
|
||||
|
||||
// Check user membership in the secondary room
|
||||
MXMembership membership = self.secondaryRoom.summary.membership;
|
||||
if (membership == MXMembershipUnknown || membership == MXMembershipInvite)
|
||||
{
|
||||
// Here the initial sync is not ended or the room is a pending invitation.
|
||||
// Note: In case of invitation, a full sync will be triggered if the user joins this room.
|
||||
|
||||
// We have to observe here 'kMXRoomInitialSyncNotification' to reload room data when room sync is done.
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didMXRoomInitialSynced:) name:kMXRoomInitialSyncNotification object:self.secondaryRoom];
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.room = [self.mxSession roomWithRoomId:_roomId];
|
||||
// Past timeline
|
||||
// Less things need to configured
|
||||
_timeline = [_room timelineOnEvent:initialEventId];
|
||||
|
||||
// Refresh the event listeners. Note: events for past timelines come only from pagination request
|
||||
[self refreshEventListeners:nil];
|
||||
|
||||
MXWeakify(self);
|
||||
|
||||
// Preload the state and some messages around the initial event
|
||||
[_timeline resetPaginationAroundInitialEventWithLimit:_paginationLimitAroundInitialEvent success:^{
|
||||
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
// Do a "classic" reset. The room view controller will paginate
|
||||
// from the events stored in the timeline store
|
||||
[self.timeline resetPagination];
|
||||
|
||||
// Update here data source state if it is not already ready
|
||||
[self setState:MXKDataSourceStateReady];
|
||||
|
||||
} failure:^(NSError *error) {
|
||||
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
MXLogDebug(@"[MXKRoomDataSource][%p] Failed to resetPaginationAroundInitialEventWithLimit", self);
|
||||
|
||||
// Notify the error
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kMXKRoomDataSourceTimelineError
|
||||
object:self
|
||||
userInfo:@{
|
||||
kMXKRoomDataSourceTimelineErrorErrorKey: error
|
||||
}];
|
||||
}];
|
||||
}
|
||||
|
||||
if (_room)
|
||||
}
|
||||
else
|
||||
{
|
||||
MXLogDebug(@"[MXKRoomDataSource][%p] Warning: The user does not know the room %@", self, _roomId);
|
||||
|
||||
// Update here data source state if it is not already ready
|
||||
[self setState:MXKDataSourceStateFailed];
|
||||
}
|
||||
}
|
||||
|
||||
if (_room && MXSessionStateRunning == self.mxSession.state)
|
||||
{
|
||||
// Flair handling: observe the update in the publicised groups by users when the flair is enabled in the room.
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMXSessionDidUpdatePublicisedGroupsForUsersNotification object:self.mxSession];
|
||||
[self.room state:^(MXRoomState *roomState) {
|
||||
if (roomState.relatedGroups.count)
|
||||
{
|
||||
// This is the time to set up the timeline according to the called init method
|
||||
if (_isLive)
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didMXSessionUpdatePublicisedGroupsForUsers:) name:kMXSessionDidUpdatePublicisedGroupsForUsersNotification object:self.mxSession];
|
||||
|
||||
// Get a fresh profile for all the related groups. Trigger a table refresh when all requests are done.
|
||||
__block NSUInteger count = roomState.relatedGroups.count;
|
||||
for (NSString *groupId in roomState.relatedGroups)
|
||||
{
|
||||
// LIVE
|
||||
MXWeakify(self);
|
||||
[_room liveTimeline:^(id<MXEventTimeline> liveTimeline) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
self->_timeline = liveTimeline;
|
||||
|
||||
// Only one pagination process can be done at a time by an MXRoom object.
|
||||
// This assumption is satisfied by MatrixKit. Only MXRoomDataSource does it.
|
||||
[self.timeline resetPagination];
|
||||
|
||||
// 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.mxSession == room.mxSession && ([self.roomId isEqualToString:room.roomId] ||
|
||||
([self.secondaryRoomId isEqualToString:room.roomId])))
|
||||
{
|
||||
// The existing room history has been flushed during server sync because a gap has been observed between local and server storage.
|
||||
[self reload];
|
||||
}
|
||||
|
||||
}];
|
||||
|
||||
// Add the event listeners, by considering all the event types (the event filtering is applying by the event formatter),
|
||||
// except if only the events with a url key in their content must be handled.
|
||||
[self refreshEventListeners:(self.filterMessagesWithURL ? @[kMXEventTypeStringRoomMessage] : [MXKAppSettings standardAppSettings].allEventTypesForMessages)];
|
||||
|
||||
// display typing notifications is optional
|
||||
// the inherited class can manage them by its own.
|
||||
if (self.showTypingNotifications)
|
||||
{
|
||||
// Register on typing notif
|
||||
[self listenTypingNotifications];
|
||||
}
|
||||
|
||||
// Manage unsent messages
|
||||
[self handleUnsentMessages];
|
||||
|
||||
// Update here data source state if it is not already ready
|
||||
if (!self->_secondaryRoomId)
|
||||
{
|
||||
[self setState:MXKDataSourceStateReady];
|
||||
}
|
||||
|
||||
// Check user membership in this room
|
||||
MXMembership membership = self.room.summary.membership;
|
||||
if (membership == MXMembershipUnknown || membership == MXMembershipInvite)
|
||||
{
|
||||
// Here the initial sync is not ended or the room is a pending invitation.
|
||||
// Note: In case of invitation, a full sync will be triggered if the user joins this room.
|
||||
|
||||
// We have to observe here 'kMXRoomInitialSyncNotification' to reload room data when room sync is done.
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didMXRoomInitialSynced:) name:kMXRoomInitialSyncNotification object:self.room];
|
||||
}
|
||||
}];
|
||||
|
||||
if (!_secondaryRoom && _secondaryRoomId)
|
||||
MXGroup *group = [self.mxSession groupWithGroupId:groupId];
|
||||
if (!group)
|
||||
{
|
||||
_secondaryRoom = [self.mxSession roomWithRoomId:_secondaryRoomId];
|
||||
|
||||
if (_secondaryRoom)
|
||||
{
|
||||
MXWeakify(self);
|
||||
[_secondaryRoom liveTimeline:^(id<MXEventTimeline> liveTimeline) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
self->_secondaryTimeline = liveTimeline;
|
||||
|
||||
// Only one pagination process can be done at a time by an MXRoom object.
|
||||
// This assumption is satisfied by MatrixKit. Only MXRoomDataSource does it.
|
||||
[self.secondaryTimeline resetPagination];
|
||||
|
||||
// Add the secondary event listeners, by considering the event types in self.secondaryRoomEventTypes
|
||||
[self refreshSecondaryEventListeners:self.secondaryRoomEventTypes];
|
||||
|
||||
// Update here data source state if it is not already ready
|
||||
[self setState:MXKDataSourceStateReady];
|
||||
|
||||
// Check user membership in the secondary room
|
||||
MXMembership membership = self.secondaryRoom.summary.membership;
|
||||
if (membership == MXMembershipUnknown || membership == MXMembershipInvite)
|
||||
{
|
||||
// Here the initial sync is not ended or the room is a pending invitation.
|
||||
// Note: In case of invitation, a full sync will be triggered if the user joins this room.
|
||||
|
||||
// We have to observe here 'kMXRoomInitialSyncNotification' to reload room data when room sync is done.
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didMXRoomInitialSynced:) name:kMXRoomInitialSyncNotification object:self.secondaryRoom];
|
||||
}
|
||||
}];
|
||||
}
|
||||
// Create a group instance for the groups that the current user did not join.
|
||||
group = [[MXGroup alloc] initWithGroupId:groupId];
|
||||
[self->externalRelatedGroups setObject:group forKey:groupId];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Past timeline
|
||||
// Less things need to configured
|
||||
_timeline = [_room timelineOnEvent:initialEventId];
|
||||
|
||||
// Refresh the event listeners. Note: events for past timelines come only from pagination request
|
||||
[self refreshEventListeners:nil];
|
||||
|
||||
MXWeakify(self);
|
||||
// Refresh the group profile from server.
|
||||
[self.mxSession updateGroupProfile:group success:^{
|
||||
|
||||
// Preload the state and some messages around the initial event
|
||||
[_timeline resetPaginationAroundInitialEventWithLimit:_paginationLimitAroundInitialEvent success:^{
|
||||
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
// Do a "classic" reset. The room view controller will paginate
|
||||
// from the events stored in the timeline store
|
||||
[self.timeline resetPagination];
|
||||
|
||||
// Update here data source state if it is not already ready
|
||||
[self setState:MXKDataSourceStateReady];
|
||||
if (self.delegate && !(--count))
|
||||
{
|
||||
// All the requests have been done.
|
||||
[self.delegate dataSource:self didCellChange:nil];
|
||||
}
|
||||
|
||||
} failure:^(NSError *error) {
|
||||
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
MXLogDebug(@"[MXKRoomDataSource][%p] Failed to resetPaginationAroundInitialEventWithLimit", self);
|
||||
MXLogDebug(@"[MXKRoomDataSource][%p] group profile update failed %@", self, groupId);
|
||||
|
||||
if (self.delegate && !(--count))
|
||||
{
|
||||
// All the requests have been done.
|
||||
[self.delegate dataSource:self didCellChange:nil];
|
||||
}
|
||||
|
||||
// Notify the error
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kMXKRoomDataSourceTimelineError
|
||||
object:self
|
||||
userInfo:@{
|
||||
kMXKRoomDataSourceTimelineErrorErrorKey: error
|
||||
}];
|
||||
}];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MXLogDebug(@"[MXKRoomDataSource][%p] Warning: The user does not know the room %@", self, _roomId);
|
||||
|
||||
// Update here data source state if it is not already ready
|
||||
[self setState:MXKDataSourceStateFailed];
|
||||
}
|
||||
}
|
||||
|
||||
if (_room && MXSessionStateRunning == self.mxSession.state)
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)initializeTimelineForThread
|
||||
{
|
||||
// Check whether the thread is not already set
|
||||
if (_thread && self.state == MXKDataSourceStateReady)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_thread = [self.mxSession.threadingService threadWithId:_threadId];
|
||||
|
||||
if (!_thread)
|
||||
{
|
||||
// there is not a thread yet available, this will be a new thread
|
||||
_thread = [self.mxSession.threadingService createTempThreadWithId:_threadId roomId:_roomId];
|
||||
}
|
||||
|
||||
if (!_room)
|
||||
{
|
||||
// also hold a reference to the room
|
||||
_room = [self.mxSession roomWithRoomId:_roomId];
|
||||
}
|
||||
|
||||
if (_thread)
|
||||
{
|
||||
if (_isLive)
|
||||
{
|
||||
// Flair handling: observe the update in the publicised groups by users when the flair is enabled in the room.
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMXSessionDidUpdatePublicisedGroupsForUsersNotification object:self.mxSession];
|
||||
[self.room state:^(MXRoomState *roomState) {
|
||||
if (roomState.relatedGroups.count)
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didMXSessionUpdatePublicisedGroupsForUsers:) name:kMXSessionDidUpdatePublicisedGroupsForUsersNotification object:self.mxSession];
|
||||
|
||||
// Get a fresh profile for all the related groups. Trigger a table refresh when all requests are done.
|
||||
__block NSUInteger count = roomState.relatedGroups.count;
|
||||
for (NSString *groupId in roomState.relatedGroups)
|
||||
{
|
||||
MXGroup *group = [self.mxSession groupWithGroupId:groupId];
|
||||
if (!group)
|
||||
{
|
||||
// Create a group instance for the groups that the current user did not join.
|
||||
group = [[MXGroup alloc] initWithGroupId:groupId];
|
||||
[self->externalRelatedGroups setObject:group forKey:groupId];
|
||||
}
|
||||
|
||||
// Refresh the group profile from server.
|
||||
[self.mxSession updateGroupProfile:group success:^{
|
||||
|
||||
if (self.delegate && !(--count))
|
||||
{
|
||||
// All the requests have been done.
|
||||
[self.delegate dataSource:self didCellChange:nil];
|
||||
}
|
||||
|
||||
} failure:^(NSError *error) {
|
||||
|
||||
MXLogDebug(@"[MXKRoomDataSource][%p] group profile update failed %@", self, groupId);
|
||||
|
||||
if (self.delegate && !(--count))
|
||||
{
|
||||
// All the requests have been done.
|
||||
[self.delegate dataSource:self didCellChange:nil];
|
||||
}
|
||||
|
||||
}];
|
||||
}
|
||||
}
|
||||
[_thread liveTimeline:^(id<MXEventTimeline> _Nonnull liveTimeline) {
|
||||
self->_timeline = liveTimeline;
|
||||
|
||||
// Only one pagination process can be done at a time by an MXThread object.
|
||||
// This assumption is satisfied by MXRoomDataSource.
|
||||
[self.timeline resetPagination];
|
||||
|
||||
// Add the event listeners, by considering all the event types (the event filtering is applying by the event formatter),
|
||||
// except if only the events with a url key in their content must be handled.
|
||||
[self refreshEventListeners:(self.filterMessagesWithURL ? @[kMXEventTypeStringRoomMessage] : [MXKAppSettings standardAppSettings].allEventTypesForMessages)];
|
||||
|
||||
// Manage unsent messages
|
||||
[self handleUnsentMessages];
|
||||
|
||||
[self setState:MXKDataSourceStateReady];
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Past timeline
|
||||
// Less things need to configured
|
||||
_timeline = [_thread timelineOnEvent:initialEventId];
|
||||
|
||||
// Refresh the event listeners. Note: events for past timelines come only from pagination request
|
||||
[self refreshEventListeners:nil];
|
||||
|
||||
MXWeakify(self);
|
||||
|
||||
// Preload the state and some messages around the initial event
|
||||
[_timeline resetPaginationAroundInitialEventWithLimit:_paginationLimitAroundInitialEvent success:^{
|
||||
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
// Do a "classic" reset. The room view controller will paginate
|
||||
// from the events stored in the timeline store
|
||||
[self.timeline resetPagination];
|
||||
|
||||
// Update here data source state if it is not already ready
|
||||
[self setState:MXKDataSourceStateReady];
|
||||
|
||||
} failure:^(NSError *error) {
|
||||
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
MXLogDebug(@"[MXKRoomDataSource][%p] Failed to resetPaginationAroundInitialEventWithLimit", self);
|
||||
|
||||
// Notify the error
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kMXKRoomDataSourceTimelineError
|
||||
object:self
|
||||
userInfo:@{
|
||||
kMXKRoomDataSourceTimelineErrorErrorKey: error
|
||||
}];
|
||||
}];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MXLogDebug(@"[MXKRoomDataSource][%p] Warning: The user does not know the thread %@", self, _threadId);
|
||||
|
||||
// Update here data source state if it is not already ready
|
||||
[self setState:MXKDataSourceStateFailed];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user