mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-22 09:32:52 +02:00
Start DM on first message (#6367)
Start DM on first message Co-authored-by: Philippe Loriaux <philippel@element.io>
This commit is contained in:
@@ -93,6 +93,7 @@ static const int kThreadListBarButtonItemTag = 99;
|
||||
static UIEdgeInsets kThreadListBarButtonItemContentInsetsNoDot;
|
||||
static UIEdgeInsets kThreadListBarButtonItemContentInsetsDot;
|
||||
static CGSize kThreadListBarButtonItemImageSize;
|
||||
NSString *const RoomViewControllerErrorDomain = @"RoomViewControllerErrorDomain";
|
||||
|
||||
@interface RoomViewController () <UISearchBarDelegate, UIGestureRecognizerDelegate, UIScrollViewAccessibilityDelegate, RoomTitleViewTapGestureDelegate, MXKRoomMemberDetailsViewControllerDelegate, ContactsTableViewControllerDelegate, MXServerNoticesDelegate, RoomContextualMenuViewControllerDelegate,
|
||||
ReactionsMenuViewModelCoordinatorDelegate, EditHistoryCoordinatorBridgePresenterDelegate, MXKDocumentPickerPresenterDelegate, EmojiPickerCoordinatorBridgePresenterDelegate,
|
||||
@@ -224,6 +225,9 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
|
||||
@property (nonatomic, readwrite) RoomDisplayConfiguration *displayConfiguration;
|
||||
|
||||
// The direct chat target user. The room timeline is presented without an actual room until the direct chat is created
|
||||
@property (nonatomic, nullable, strong) MXUser *directChatTargetUser;
|
||||
|
||||
// When layout of the screen changes (e.g. height), we no longer know whether
|
||||
// to autoscroll to the bottom again or not. Instead we need to capture the
|
||||
// scroll state just before the layout change, and restore it after the layout.
|
||||
@@ -1025,6 +1029,9 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
[self removeMatrixSession:self.mainSession];
|
||||
}
|
||||
|
||||
// Set potential discussion target user to nil, now use the dataSource to populate the view
|
||||
self.directChatTargetUser = nil;
|
||||
|
||||
// Enable the read marker display, and disable its update.
|
||||
dataSource.showReadMarker = YES;
|
||||
self.updateRoomReadMarker = NO;
|
||||
@@ -1103,6 +1110,10 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
[self forceLayoutRefresh];
|
||||
}
|
||||
}
|
||||
else if (self.isNewDirectChat)
|
||||
{
|
||||
[self refreshRoomInputToolbar];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self showPreviewHeader:NO];
|
||||
@@ -1188,8 +1199,8 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
{
|
||||
[super setRoomInputToolbarViewClass:roomInputToolbarViewClass];
|
||||
|
||||
// The voice message toolbar cannot be set on DisabledInputToolbarView.
|
||||
if ([self.inputToolbarView isKindOfClass:RoomInputToolbarView.class])
|
||||
// The voice message toolbar cannot be set on DisabledInputToolbarView and on new direct chat.
|
||||
if ([self.inputToolbarView isKindOfClass:RoomInputToolbarView.class] && !self.isNewDirectChat)
|
||||
{
|
||||
[(RoomInputToolbarView *)self.inputToolbarView setVoiceMessageToolbarView:self.voiceMessageController.voiceMessageToolbarView];
|
||||
}
|
||||
@@ -1322,40 +1333,49 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
|
||||
- (void)sendTextMessage:(NSString*)msgTxt
|
||||
{
|
||||
// The event modified is always fetch from the actual data source
|
||||
MXEvent *eventModified = [self.roomDataSource eventWithEventId:self.customizedRoomDataSource.selectedEventId];
|
||||
|
||||
// In the case the event is a reply or and edit, and it's done on a non-live timeline
|
||||
// we have to fetch live timeline in order to display the event properly
|
||||
[self setupRoomDataSourceToResolveEvent:^(MXKRoomDataSource *roomDataSource) {
|
||||
if (self.inputToolBarSendMode == RoomInputToolbarViewSendModeReply && eventModified)
|
||||
// Create or invite again the left member before sending the message in case of a discussion (direct chat)
|
||||
MXWeakify(self);
|
||||
[self createOrRestoreDiscussionIfNeeded:^(BOOL readyToSend) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
if (readyToSend)
|
||||
{
|
||||
[roomDataSource sendReplyToEvent:eventModified withTextMessage:msgTxt success:nil failure:^(NSError *error) {
|
||||
// Just log the error. The message will be displayed in red in the room history
|
||||
MXLogDebug(@"[MXKRoomViewController] sendTextMessage failed.");
|
||||
// The event modified is always fetch from the actual data source
|
||||
MXEvent *eventModified = [self.roomDataSource eventWithEventId:self.customizedRoomDataSource.selectedEventId];
|
||||
|
||||
// In the case the event is a reply or and edit, and it's done on a non-live timeline
|
||||
// we have to fetch live timeline in order to display the event properly
|
||||
[self setupRoomDataSourceToResolveEvent:^(MXKRoomDataSource *roomDataSource) {
|
||||
if (self.inputToolBarSendMode == RoomInputToolbarViewSendModeReply && eventModified)
|
||||
{
|
||||
[roomDataSource sendReplyToEvent:eventModified withTextMessage:msgTxt success:nil failure:^(NSError *error) {
|
||||
// Just log the error. The message will be displayed in red in the room history
|
||||
MXLogDebug(@"[MXKRoomViewController] sendTextMessage failed.");
|
||||
}];
|
||||
}
|
||||
else if (self.inputToolBarSendMode == RoomInputToolbarViewSendModeEdit && eventModified)
|
||||
{
|
||||
[roomDataSource replaceTextMessageForEvent:eventModified withTextMessage:msgTxt success:nil failure:^(NSError *error) {
|
||||
// Just log the error. The message will be displayed in red
|
||||
MXLogDebug(@"[MXKRoomViewController] sendTextMessage failed.");
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Let the datasource send it and manage the local echo
|
||||
[roomDataSource sendTextMessage:msgTxt success:nil failure:^(NSError *error)
|
||||
{
|
||||
// Just log the error. The message will be displayed in red in the room history
|
||||
MXLogDebug(@"[MXKRoomViewController] sendTextMessage failed.");
|
||||
}];
|
||||
}
|
||||
|
||||
if (self.customizedRoomDataSource.selectedEventId)
|
||||
{
|
||||
[self cancelEventSelection];
|
||||
}
|
||||
}];
|
||||
}
|
||||
else if (self.inputToolBarSendMode == RoomInputToolbarViewSendModeEdit && eventModified)
|
||||
{
|
||||
[roomDataSource replaceTextMessageForEvent:eventModified withTextMessage:msgTxt success:nil failure:^(NSError *error) {
|
||||
// Just log the error. The message will be displayed in red
|
||||
MXLogDebug(@"[MXKRoomViewController] sendTextMessage failed.");
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Let the datasource send it and manage the local echo
|
||||
[roomDataSource sendTextMessage:msgTxt success:nil failure:^(NSError *error)
|
||||
{
|
||||
// Just log the error. The message will be displayed in red in the room history
|
||||
MXLogDebug(@"[MXKRoomViewController] sendTextMessage failed.");
|
||||
}];
|
||||
}
|
||||
|
||||
if (self.customizedRoomDataSource.selectedEventId)
|
||||
{
|
||||
[self cancelEventSelection];
|
||||
}
|
||||
// Errors are handled at the request level. This should be improved in case of code rewriting.
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -1401,6 +1421,7 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
[self setValue:titleView forKey:@"titleView"];
|
||||
titleView.delegate = self;
|
||||
titleView.mxRoom = self.roomDataSource.room;
|
||||
titleView.mxUser = self.directChatTargetUser;
|
||||
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:titleView];
|
||||
|
||||
if ([titleView isKindOfClass:RoomTitleView.class])
|
||||
@@ -1490,6 +1511,149 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
[super destroy];
|
||||
}
|
||||
|
||||
#pragma mark - Start DM
|
||||
|
||||
/**
|
||||
Check whether the current room is a direct chat left by the other member.
|
||||
*/
|
||||
- (void)isDirectChatLeftByTheOther:(void (^)(BOOL isEmptyDirect, NSError *error))onComplete
|
||||
{
|
||||
// In the case of a direct chat, we check if the other member has left the room.
|
||||
if (self.roomDataSource)
|
||||
{
|
||||
NSString *directUserId = self.roomDataSource.room.directUserId;
|
||||
if (directUserId)
|
||||
{
|
||||
[self.roomDataSource.room members:^(MXRoomMembers *roomMembers) {
|
||||
MXRoomMember *directUserMember = [roomMembers memberWithUserId:directUserId];
|
||||
if (directUserMember)
|
||||
{
|
||||
MXMembership directUserMembership = directUserMember.membership;
|
||||
if (directUserMembership != MXMembershipJoin && directUserMembership != MXMembershipInvite)
|
||||
{
|
||||
onComplete(YES, nil);
|
||||
}
|
||||
else
|
||||
{
|
||||
onComplete(NO, nil);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MXLogDebug(@"[RoomViewController] isEmptyDirectChat: the direct user has disappeared");
|
||||
onComplete(YES, nil);
|
||||
}
|
||||
} failure:^(NSError *error) {
|
||||
MXLogDebug(@"[RoomViewController] isEmptyDirectChat: cannot get all room members");
|
||||
onComplete(NO, error);
|
||||
}];
|
||||
return;
|
||||
}
|
||||
|
||||
// This is not a direct chat
|
||||
onComplete(NO, nil);
|
||||
} else {
|
||||
NSError* error = [NSError errorWithDomain:RoomViewControllerErrorDomain
|
||||
code:0
|
||||
userInfo:@{ NSLocalizedDescriptionKey: [VectorL10n errorCommonMessage] }];
|
||||
// Stop the current process
|
||||
onComplete(NO, error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Check whether the current room is a direct chat left by the other member.
|
||||
In this case, this method will invite again the left member.
|
||||
*/
|
||||
- (void)restoreDiscussionIfNeeded:(void (^)(BOOL readyToSend))onComplete
|
||||
{
|
||||
[self isDirectChatLeftByTheOther:^(BOOL isEmptyDirect, NSError *error) {
|
||||
if (error != nil) {
|
||||
MXLogDebug(@"[RoomViewController] restoreDiscussionIfNeeded: isDirectChatLeftByTheOther finished with error : %@ ", error.localizedDescription);
|
||||
[self showError:error];
|
||||
onComplete(NO);
|
||||
} else if (isEmptyDirect) {
|
||||
NSString *directUserId = self.roomDataSource.room.directUserId;
|
||||
|
||||
MXWeakify(self);
|
||||
MXLogDebug(@"[RoomViewController] restoreDiscussionIfNeeded: check left member %@", directUserId);
|
||||
// Invite again the direct user
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
MXLogDebug(@"[RoomViewController] restoreDiscussionIfNeeded: invite again %@", directUserId);
|
||||
[self.roomDataSource.room inviteUser:directUserId success:^{
|
||||
// Delay the completion in order to display the invite before the local echo of the new message.
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
onComplete(YES);
|
||||
});
|
||||
} failure:^(NSError *error) {
|
||||
MXLogDebug(@"[RoomViewController] restoreDiscussionIfNeeded: invite failed");
|
||||
// Alert user
|
||||
[[AppDelegate theDelegate] showErrorAsAlert:error];
|
||||
onComplete(NO);
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Nothing to do
|
||||
onComplete(YES);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
Create a direct chat with given user.
|
||||
*/
|
||||
- (void)createDiscussionWithUser:(MXUser*)user completion:(void (^)(BOOL success))onComplete
|
||||
{
|
||||
[self startActivityIndicator];
|
||||
|
||||
[[AppDelegate theDelegate] createDirectChatWithUserId:user.userId completion:^(NSString *roomId) {
|
||||
if (roomId)
|
||||
{
|
||||
MXKRoomDataSourceManager *roomDataSourceManager = [MXKRoomDataSourceManager sharedManagerForMatrixSession:self.mainSession];
|
||||
[roomDataSourceManager roomDataSourceForRoom:roomId create:YES onComplete:^(MXKRoomDataSource *roomDataSource) {
|
||||
[self stopActivityIndicator];
|
||||
[self setRoomInputToolbarViewClass:nil];
|
||||
[self displayRoom:roomDataSource];
|
||||
|
||||
onComplete(YES);
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self stopActivityIndicator];
|
||||
onComplete(NO);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
Check whether the current room is a direct chat left by the other member.
|
||||
In this case, this method will invite again the left member.
|
||||
*/
|
||||
- (void)createOrRestoreDiscussionIfNeeded:(void (^)(BOOL readyToSend))onComplete
|
||||
{
|
||||
// Disable the input tool bar during this operation. This prevents us from creating several discussions, or
|
||||
// trying to send several invites.
|
||||
self.inputToolbarView.userInteractionEnabled = false;
|
||||
|
||||
void(^completion)(BOOL) = ^(BOOL readyToSend) {
|
||||
self.inputToolbarView.userInteractionEnabled = true;
|
||||
if (onComplete) {
|
||||
onComplete(readyToSend);
|
||||
}
|
||||
};
|
||||
|
||||
if (self.directChatTargetUser)
|
||||
{
|
||||
[self createDiscussionWithUser:self.directChatTargetUser completion:completion];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self restoreDiscussionIfNeeded:completion];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
|
||||
-(void)setActivitiesViewExpanded:(BOOL)activitiesViewExpanded
|
||||
@@ -1658,6 +1822,12 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Indicates if a new direct chat with a target user (without associated room) is occuring.
|
||||
- (BOOL)isNewDirectChat
|
||||
{
|
||||
return self.directChatTargetUser != nil;
|
||||
}
|
||||
|
||||
- (BOOL)isEncryptionEnabled
|
||||
{
|
||||
return self.roomDataSource.room.summary.isEncrypted && self.mainSession.crypto != nil;
|
||||
@@ -1859,14 +2029,45 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (self.isNewDirectChat)
|
||||
{
|
||||
[self showPreviewHeader:NO];
|
||||
|
||||
[self setRoomTitleViewClass:RoomTitleView.class];
|
||||
MXKImageView *userPictureView = ((RoomTitleView*)self.titleView).pictureView;
|
||||
|
||||
// Set user picture in input toolbar
|
||||
if (userPictureView)
|
||||
{
|
||||
[userPictureView vc_setRoomAvatarImageWith:self.directChatTargetUser.avatarUrl
|
||||
roomId:self.directChatTargetUser.userId
|
||||
displayName:self.directChatTargetUser.displayname
|
||||
mediaManager:self.mainSession.mediaManager];
|
||||
}
|
||||
}
|
||||
|
||||
self.navigationItem.rightBarButtonItems = rightBarButtonItems;
|
||||
}
|
||||
|
||||
- (void)updateInputToolBarVisibility
|
||||
{
|
||||
BOOL hideInputToolBar = NO;
|
||||
|
||||
if (self.roomDataSource)
|
||||
{
|
||||
hideInputToolBar = (self.roomDataSource.state != MXKDataSourceStateReady);
|
||||
}
|
||||
|
||||
self.inputToolbarView.hidden = hideInputToolBar;
|
||||
}
|
||||
|
||||
- (void)refreshRoomInputToolbar
|
||||
{
|
||||
MXKImageView *userPictureView;
|
||||
|
||||
// Show or hide input tool bar
|
||||
[self updateInputToolBarVisibility];
|
||||
|
||||
// Check whether the input toolbar is ready before updating it.
|
||||
if (self.inputToolbarView && [self.inputToolbarView isKindOfClass:RoomInputToolbarView.class])
|
||||
{
|
||||
@@ -1877,6 +2078,13 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
|
||||
// Update actions when the input toolbar refreshed
|
||||
[self setupActions];
|
||||
|
||||
// Update placeholder and hide voice message view
|
||||
if (self.isNewDirectChat)
|
||||
{
|
||||
[self setInputToolBarSendMode:RoomInputToolbarViewSendModeCreateDM forEventWithId:nil];
|
||||
[roomInputToolbarView setVoiceMessageToolbarView:nil];
|
||||
}
|
||||
}
|
||||
else if (self.inputToolbarView && [self.inputToolbarView isKindOfClass:DisabledRoomInputToolbarView.class])
|
||||
{
|
||||
@@ -2139,7 +2347,7 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
[self showMediaPickerAnimated:YES];
|
||||
}]];
|
||||
}
|
||||
if (RiotSettings.shared.roomScreenAllowStickerAction)
|
||||
if (RiotSettings.shared.roomScreenAllowStickerAction && !self.isNewDirectChat)
|
||||
{
|
||||
[actionItems addObject:[[RoomActionItem alloc] initWithImage:AssetImages.actionSticker.image andAction:^{
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
@@ -2159,7 +2367,7 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
[self roomInputToolbarViewDidTapFileUpload];
|
||||
}]];
|
||||
}
|
||||
if (BuildSettings.pollsEnabled && self.displayConfiguration.sendingPollsEnabled)
|
||||
if (BuildSettings.pollsEnabled && self.displayConfiguration.sendingPollsEnabled && !self.isNewDirectChat)
|
||||
{
|
||||
[actionItems addObject:[[RoomActionItem alloc] initWithImage:AssetImages.actionPoll.image andAction:^{
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
@@ -2169,7 +2377,7 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
[self.delegate roomViewControllerDidRequestPollCreationFormPresentation:self];
|
||||
}]];
|
||||
}
|
||||
if (BuildSettings.locationSharingEnabled)
|
||||
if (BuildSettings.locationSharingEnabled && !self.isNewDirectChat)
|
||||
{
|
||||
[actionItems addObject:[[RoomActionItem alloc] initWithImage:AssetImages.actionLocation.image andAction:^{
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
@@ -2303,7 +2511,15 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
|
||||
// Set the chosen preset and send the video (conversion takes place in the SDK).
|
||||
[MXSDKOptions sharedInstance].videoConversionPresetName = presetName;
|
||||
[roomInputToolbarView sendSelectedVideoAsset:videoAsset isPhotoLibraryAsset:isPhotoLibraryAsset];
|
||||
|
||||
// Create or invite again the left member before sending the message in case of a discussion (direct chat)
|
||||
[self createOrRestoreDiscussionIfNeeded:^(BOOL readyToSend) {
|
||||
if (readyToSend)
|
||||
{
|
||||
[[self inputToolbarViewAsRoomInputToolbarView] sendSelectedVideoAsset:videoAsset isPhotoLibraryAsset:isPhotoLibraryAsset];
|
||||
}
|
||||
// Errors are handled at the request level. This should be improved in case of code rewriting.
|
||||
}];
|
||||
}];
|
||||
compressionPrompt.popoverPresentationController.sourceView = roomInputToolbarView.attachMediaButton;
|
||||
compressionPrompt.popoverPresentationController.sourceRect = roomInputToolbarView.attachMediaButton.bounds;
|
||||
@@ -2314,7 +2530,15 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
{
|
||||
// Otherwise default to 1080p and send the video.
|
||||
[MXSDKOptions sharedInstance].videoConversionPresetName = AVAssetExportPreset1920x1080;
|
||||
[roomInputToolbarView sendSelectedVideoAsset:videoAsset isPhotoLibraryAsset:isPhotoLibraryAsset];
|
||||
|
||||
// Create or invite again the left member before sending the message in case of a discussion (direct chat)
|
||||
[self createOrRestoreDiscussionIfNeeded:^(BOOL readyToSend) {
|
||||
if (readyToSend)
|
||||
{
|
||||
[[self inputToolbarViewAsRoomInputToolbarView] sendSelectedVideoAsset:videoAsset isPhotoLibraryAsset:isPhotoLibraryAsset];
|
||||
}
|
||||
// Errors are handled at the request level. This should be improved in case of code rewriting.
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2384,7 +2608,7 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
[[AppDelegate theDelegate] createDirectChatWithUserId:userId completion:completion];
|
||||
[[AppDelegate theDelegate] showNewDirectChat:userId withMatrixSession:self.mainSession completion:completion];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2814,6 +3038,23 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - New discussion
|
||||
|
||||
- (void)displayNewDirectChatWithTargetUser:(nonnull MXUser*)directChatTargetUser session:(nonnull MXSession*)session
|
||||
{
|
||||
// Release existing room data source or preview
|
||||
[self displayRoom:nil];
|
||||
|
||||
self.directChatTargetUser = directChatTargetUser;
|
||||
|
||||
self.eventsAcknowledgementEnabled = NO;
|
||||
|
||||
[self addMatrixSession:session];
|
||||
|
||||
[self refreshRoomTitle];
|
||||
[self refreshRoomInputToolbar];
|
||||
}
|
||||
|
||||
#pragma mark - MXKDataSourceDelegate
|
||||
|
||||
- (Class<MXKCellRendering>)cellViewClassForCellData:(MXKCellData*)cellData
|
||||
@@ -4798,28 +5039,37 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
|
||||
- (void)roomInputToolbarView:(RoomInputToolbarView *)toolbarView sendAttributedTextMessage:(NSAttributedString *)attributedTextMessage
|
||||
{
|
||||
BOOL isMessageAHandledCommand = NO;
|
||||
// "/me" command is supported with Pills in RoomDataSource.
|
||||
if (![attributedTextMessage.string hasPrefix:kMXKSlashCmdEmote])
|
||||
{
|
||||
// Other commands currently work with identifiers (e.g. ban, invite, op, etc).
|
||||
NSString *message;
|
||||
if (@available(iOS 15.0, *))
|
||||
{
|
||||
message = [PillsFormatter stringByReplacingPillsIn:attributedTextMessage mode:PillsReplacementTextModeIdentifier];
|
||||
// Create or invite again the left member before sending the message in case of a discussion (direct chat)
|
||||
MXWeakify(self);
|
||||
[self createOrRestoreDiscussionIfNeeded:^(BOOL readyToSend) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
if (readyToSend) {
|
||||
BOOL isMessageAHandledCommand = NO;
|
||||
// "/me" command is supported with Pills in RoomDataSource.
|
||||
if (![attributedTextMessage.string hasPrefix:kMXKSlashCmdEmote])
|
||||
{
|
||||
// Other commands currently work with identifiers (e.g. ban, invite, op, etc).
|
||||
NSString *message;
|
||||
if (@available(iOS 15.0, *))
|
||||
{
|
||||
message = [PillsFormatter stringByReplacingPillsIn:attributedTextMessage mode:PillsReplacementTextModeIdentifier];
|
||||
}
|
||||
else
|
||||
{
|
||||
message = attributedTextMessage.string;
|
||||
}
|
||||
// Try to send the slash command
|
||||
isMessageAHandledCommand = [self sendAsIRCStyleCommandIfPossible:message];
|
||||
}
|
||||
|
||||
if (!isMessageAHandledCommand)
|
||||
{
|
||||
[self sendAttributedTextMessage:attributedTextMessage];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
message = attributedTextMessage.string;
|
||||
}
|
||||
// Try to send the slash command
|
||||
isMessageAHandledCommand = [self sendAsIRCStyleCommandIfPossible:message];
|
||||
}
|
||||
|
||||
if (!isMessageAHandledCommand)
|
||||
{
|
||||
[self sendAttributedTextMessage:attributedTextMessage];
|
||||
}
|
||||
// Errors are handled at the request level. This should be improved in case of code rewriting.
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - MXKRoomMemberDetailsViewControllerDelegate
|
||||
@@ -4973,7 +5223,7 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
[self checkReadMarkerVisibility];
|
||||
|
||||
// Switch back to the live mode when the user scrolls to the bottom of the non live timeline.
|
||||
if (!self.roomDataSource.isLive && ![self isRoomPreview])
|
||||
if (!self.roomDataSource.isLive && ![self isRoomPreview] && !self.isNewDirectChat)
|
||||
{
|
||||
CGFloat contentBottomPosY = self.bubblesTableView.contentOffset.y + self.bubblesTableView.frame.size.height - self.bubblesTableView.adjustedContentInset.bottom;
|
||||
if (contentBottomPosY >= self.bubblesTableView.contentSize.height && ![self.roomDataSource.timeline canPaginate:MXTimelineDirectionForwards])
|
||||
@@ -7248,24 +7498,15 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
{
|
||||
NSData *imageData = [[NSData alloc] initWithContentsOfURL:url];
|
||||
|
||||
[self.roomDataSource sendImage:imageData mimeType:mimeType success:nil failure:^(NSError *error) {
|
||||
// Nothing to do. The image is marked as unsent in the room history by the datasource
|
||||
MXLogDebug(@"[MXKRoomViewController] sendImage failed.");
|
||||
}];
|
||||
[self sendImage:imageData mimeType:mimeType];
|
||||
}
|
||||
else if (fileUTI.isVideo)
|
||||
{
|
||||
[(RoomDataSource*)self.roomDataSource sendVideo:url success:nil failure:^(NSError *error) {
|
||||
// Nothing to do. The video is marked as unsent in the room history by the datasource
|
||||
MXLogDebug(@"[MXKRoomViewController] sendVideo failed.");
|
||||
}];
|
||||
[self sendVideo:url];
|
||||
}
|
||||
else if (fileUTI.isFile)
|
||||
{
|
||||
[self.roomDataSource sendFile:url mimeType:mimeType success:nil failure:^(NSError *error) {
|
||||
// Nothing to do. The file is marked as unsent in the room history by the datasource
|
||||
MXLogDebug(@"[MXKRoomViewController] sendFile failed.");
|
||||
}];
|
||||
[self sendFile:url mimeType:mimeType];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -7276,6 +7517,57 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)sendImage:(NSData *)imageData mimeType:(NSString *)mimeType {
|
||||
// Create or invite again the left member before sending the message in case of a discussion (direct chat)
|
||||
MXWeakify(self);
|
||||
[self createOrRestoreDiscussionIfNeeded:^(BOOL readyToSend) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
if (readyToSend)
|
||||
{
|
||||
// Let the datasource send it and manage the local echo
|
||||
[self.roomDataSource sendImage:imageData mimeType:mimeType success:nil failure:^(NSError *error) {
|
||||
// Nothing to do. The image is marked as unsent in the room history by the datasource
|
||||
MXLogDebug(@"[MXKRoomViewController] sendImage failed.");
|
||||
}];
|
||||
}
|
||||
// Errors are handled at the request level. This should be improved in case of code rewriting.
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)sendVideo:(NSURL * _Nonnull)url {
|
||||
// Create or invite again the left member before sending the message in case of a discussion (direct chat)
|
||||
MXWeakify(self);
|
||||
[self createOrRestoreDiscussionIfNeeded:^(BOOL readyToSend) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
if (readyToSend)
|
||||
{
|
||||
// Let the datasource send it and manage the local echo
|
||||
[(RoomDataSource*)self.roomDataSource sendVideo:url success:nil failure:^(NSError *error) {
|
||||
// Nothing to do. The video is marked as unsent in the room history by the datasource
|
||||
MXLogDebug(@"[MXKRoomViewController] sendVideo failed.");
|
||||
}];
|
||||
}
|
||||
// Errors are handled at the request level. This should be improved in case of code rewriting.
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)sendFile:(NSURL * _Nonnull)url mimeType:(NSString *)mimeType {
|
||||
// Create or invite again the left member before sending the message in case of a discussion (direct chat)
|
||||
MXWeakify(self);
|
||||
[self createOrRestoreDiscussionIfNeeded:^(BOOL readyToSend) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
if (readyToSend)
|
||||
{
|
||||
// Let the datasource send it and manage the local echo
|
||||
[self.roomDataSource sendFile:url mimeType:mimeType success:nil failure:^(NSError *error) {
|
||||
// Nothing to do. The file is marked as unsent in the room history by the datasource
|
||||
MXLogDebug(@"[MXKRoomViewController] sendFile failed.");
|
||||
}];
|
||||
}
|
||||
// Errors are handled at the request level. This should be improved in case of code rewriting.
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - EmojiPickerCoordinatorBridgePresenterDelegate
|
||||
|
||||
- (void)emojiPickerCoordinatorBridgePresenter:(EmojiPickerCoordinatorBridgePresenter *)coordinatorBridgePresenter didAddEmoji:(NSString *)emoji forEventId:(NSString *)eventId
|
||||
@@ -7339,15 +7631,19 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
[cameraPresenter dismissWithAnimated:YES completion:nil];
|
||||
self.cameraPresenter = nil;
|
||||
|
||||
RoomInputToolbarView *roomInputToolbarView = [self inputToolbarViewAsRoomInputToolbarView];
|
||||
if (roomInputToolbarView)
|
||||
{
|
||||
NSData *imageData = UIImageJPEGRepresentation(image, 1.0);
|
||||
[roomInputToolbarView sendSelectedImage:imageData
|
||||
withMimeType:MXKUTI.jpeg.mimeType
|
||||
andCompressionMode:MediaCompressionHelper.defaultCompressionMode
|
||||
isPhotoLibraryAsset:NO];
|
||||
}
|
||||
NSData *imageData = UIImageJPEGRepresentation(image, 1.0);
|
||||
|
||||
// Create or invite again the left member before sending the message in case of a discussion (direct chat)
|
||||
[self createOrRestoreDiscussionIfNeeded:^(BOOL readyToSend) {
|
||||
if (readyToSend)
|
||||
{
|
||||
[[self inputToolbarViewAsRoomInputToolbarView] sendSelectedImage:imageData
|
||||
withMimeType:MXKUTI.jpeg.mimeType
|
||||
andCompressionMode:MediaCompressionHelper.defaultCompressionMode
|
||||
isPhotoLibraryAsset:NO];
|
||||
}
|
||||
// Errors are handled at the request level. This should be improved in case of code rewriting.
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)cameraPresenter:(CameraPresenter *)cameraPresenter didSelectVideoAt:(NSURL *)url
|
||||
@@ -7372,14 +7668,17 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
[coordinatorBridgePresenter dismissWithAnimated:YES completion:nil];
|
||||
self.mediaPickerPresenter = nil;
|
||||
|
||||
RoomInputToolbarView *roomInputToolbarView = [self inputToolbarViewAsRoomInputToolbarView];
|
||||
if (roomInputToolbarView)
|
||||
{
|
||||
[roomInputToolbarView sendSelectedImage:imageData
|
||||
withMimeType:uti.mimeType
|
||||
andCompressionMode:MediaCompressionHelper.defaultCompressionMode
|
||||
isPhotoLibraryAsset:YES];
|
||||
}
|
||||
// Create or invite again the left member before sending the message in case of a discussion (direct chat)
|
||||
[self createOrRestoreDiscussionIfNeeded:^(BOOL readyToSend) {
|
||||
if (readyToSend)
|
||||
{
|
||||
[[self inputToolbarViewAsRoomInputToolbarView] sendSelectedImage:imageData
|
||||
withMimeType:uti.mimeType
|
||||
andCompressionMode:MediaCompressionHelper.defaultCompressionMode
|
||||
isPhotoLibraryAsset:YES];
|
||||
}
|
||||
// Errors are handled at the request level. This should be improved in case of code rewriting.
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)mediaPickerCoordinatorBridgePresenter:(MediaPickerCoordinatorBridgePresenter *)coordinatorBridgePresenter didSelectVideo:(AVAsset *)videoAsset
|
||||
@@ -7395,14 +7694,17 @@ static CGSize kThreadListBarButtonItemImageSize;
|
||||
[coordinatorBridgePresenter dismissWithAnimated:YES completion:nil];
|
||||
self.mediaPickerPresenter = nil;
|
||||
|
||||
RoomInputToolbarView *roomInputToolbarView = [self inputToolbarViewAsRoomInputToolbarView];
|
||||
if (roomInputToolbarView)
|
||||
{
|
||||
// Set a 1080p video conversion preset as compression mode only has an effect on the images.
|
||||
[MXSDKOptions sharedInstance].videoConversionPresetName = AVAssetExportPreset1920x1080;
|
||||
|
||||
[roomInputToolbarView sendSelectedAssets:assets withCompressionMode:MediaCompressionHelper.defaultCompressionMode];
|
||||
}
|
||||
// Set a 1080p video conversion preset as compression mode only has an effect on the images.
|
||||
[MXSDKOptions sharedInstance].videoConversionPresetName = AVAssetExportPreset1920x1080;
|
||||
|
||||
// Create or invite again the left member before sending the message in case of a discussion (direct chat)
|
||||
[self createOrRestoreDiscussionIfNeeded:^(BOOL readyToSend) {
|
||||
if (readyToSend)
|
||||
{
|
||||
[[self inputToolbarViewAsRoomInputToolbarView] sendSelectedAssets:assets withCompressionMode:MediaCompressionHelper.defaultCompressionMode];
|
||||
}
|
||||
// Errors are handled at the request level. This should be improved in case of code rewriting.
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - RoomCreationModalCoordinatorBridgePresenter
|
||||
|
||||
Reference in New Issue
Block a user