diff --git a/Riot/Modules/Room/RoomViewController.h b/Riot/Modules/Room/RoomViewController.h index dac5cbb05a..6e70591a44 100644 --- a/Riot/Modules/Room/RoomViewController.h +++ b/Riot/Modules/Room/RoomViewController.h @@ -28,6 +28,9 @@ #import "UIViewController+RiotSearch.h" @class BadgeLabel; +@protocol RoomViewControllerDelegate; + +NS_ASSUME_NONNULL_BEGIN /** Notification string used to indicate call tile tapped in a room. Notification object will be the `RoomBubbleCellData` object. @@ -41,28 +44,32 @@ extern NSNotificationName const RoomGroupCallTileTappedNotification; @interface RoomViewController : MXKRoomViewController + +// The delegate for the view controller. +@property (weak, nonatomic, nullable) id delegate; + // The preview header -@property (weak, nonatomic) IBOutlet UIView *previewHeaderContainer; -@property (weak, nonatomic) IBOutlet NSLayoutConstraint *previewHeaderContainerHeightConstraint; +@property (weak, nonatomic, nullable) IBOutlet UIView *previewHeaderContainer; +@property (weak, nonatomic, nullable) IBOutlet NSLayoutConstraint *previewHeaderContainerHeightConstraint; // The jump to last unread banner -@property (weak, nonatomic) IBOutlet UIView *jumpToLastUnreadBannerContainer; -@property (weak, nonatomic) IBOutlet UIView *jumpToLastUnreadBanner; -@property (weak, nonatomic) IBOutlet UIImageView *jumpToLastUnreadImageView; -@property (weak, nonatomic) IBOutlet UIButton *jumpToLastUnreadButton; -@property (weak, nonatomic) IBOutlet UILabel *jumpToLastUnreadLabel; -@property (weak, nonatomic) IBOutlet UIButton *resetReadMarkerButton; -@property (weak, nonatomic) IBOutlet UIView *inputBackgroundView; -@property (weak, nonatomic) IBOutlet UIButton *scrollToBottomButton; -@property (weak, nonatomic) IBOutlet BadgeLabel *scrollToBottomBadgeLabel; +@property (weak, nonatomic, nullable) IBOutlet UIView *jumpToLastUnreadBannerContainer; +@property (weak, nonatomic, nullable) IBOutlet UIView *jumpToLastUnreadBanner; +@property (weak, nonatomic, nullable) IBOutlet UIImageView *jumpToLastUnreadImageView; +@property (weak, nonatomic, nullable) IBOutlet UIButton *jumpToLastUnreadButton; +@property (weak, nonatomic, nullable) IBOutlet UILabel *jumpToLastUnreadLabel; +@property (weak, nonatomic, nullable) IBOutlet UIButton *resetReadMarkerButton; +@property (weak, nonatomic, nullable) IBOutlet UIView *inputBackgroundView; +@property (weak, nonatomic, nullable) IBOutlet UIButton *scrollToBottomButton; +@property (weak, nonatomic, nullable) IBOutlet BadgeLabel *scrollToBottomBadgeLabel; // Remove Jitsi widget container -@property (weak, nonatomic) IBOutlet UIView *removeJitsiWidgetContainer; +@property (weak, nonatomic, nullable) IBOutlet UIView *removeJitsiWidgetContainer; /** Preview data for a room invitation received by email, or a link to a room. */ -@property (nonatomic, readonly) RoomPreviewData *roomPreviewData; +@property (nonatomic, readonly, nullable) RoomPreviewData *roomPreviewData; /** Tell whether a badge must be added next to the chevron (back button) showing number of unread rooms. @@ -86,5 +93,100 @@ extern NSNotificationName const RoomGroupCallTileTappedNotification; - (IBAction)scrollToBottomAction:(id)sender; +/** + Creates and returns a new `RoomViewController` object. + + @return An initialized `RoomViewController` object. + */ ++ (instancetype)instantiate; + +@end + +/** + `RoomViewController` delegate. + */ +@protocol RoomViewControllerDelegate + +/** + Tells the delegate that the user wants to open the room details (members, files, settings). + + @param roomViewController the `RoomViewController` instance. + */ +- (void)roomViewControllerShowRoomDetails:(RoomViewController *)roomViewController; + +/** + Tells the delegate that the user wants to display the details of a room member. + + @param roomViewController the `RoomViewController` instance. + @param roomMember the selected member + */ +- (void)roomViewController:(RoomViewController *)roomViewController + showMemberDetails:(MXRoomMember *)roomMember; + +/** + Tells the delegate that the user wants to display another room. + + @param roomViewController the `RoomViewController` instance. + @param roomID the selected roomId + */ +- (void)roomViewController:(RoomViewController *)roomViewController + showRoomWithId:(NSString *)roomID; + +/** + Tells the delegate that the user wants to start a direct chat with a user. + + @param roomViewController the `RoomViewController` instance. + @param userId the selected user id + @param completion Blocks called when the chat is created. + */ +- (void)roomViewController:(RoomViewController *)roomViewController + startChatWithUserId:(NSString*)userId + completion:(void (^)(void))completion; + +/** + Tells the delegate that the user wants to show complete security screen. + + @param roomViewController the `RoomViewController` instance. + @param session The selected Matrix session. + */ +- (void)roomViewController:(RoomViewController *)roomViewController showCompleteSecurityForSession:(MXSession*)session; + +/** + Tells the delegate that the user left the room. + + @param roomViewController the `RoomViewController` instance. + */ +- (void)roomViewControllerDidLeaveRoom:(RoomViewController *)roomViewController; + +/** + Tells the delegate that the user wants to cancel the room preview. + + @param roomViewController the `RoomViewController` instance. + */ +- (void)roomViewControllerPreviewDidTapCancel:(RoomViewController *)roomViewController; + +/** + Handle the fragment of a universal link. + + @param roomViewController the `RoomViewController` instance. + @param fragment the fragment part of the universal link. + @param universalLinkURL the unprocessed the universal link URL (optional). + @return true to indicate that the fragment has been handled, or false when the fragment is not supported. + */ +- (BOOL)roomViewController:(RoomViewController *)roomViewController +handleUniversalLinkFragment:(NSString*)fragment + fromURL:(nullable NSURL*)universalLinkURL; + +/** + Process universal link. + + @param roomViewController the `RoomViewController` instance. + @param universalLinkURL the universal link URL. + @return YES in case of processing success. + */ +- (BOOL)roomViewController:(RoomViewController *)roomViewController + handleUniversalLinkURL:(NSURL*)universalLinkURL; + @end +NS_ASSUME_NONNULL_END diff --git a/Riot/Modules/Room/RoomViewController.m b/Riot/Modules/Room/RoomViewController.m index dd9b7109e8..301c568ba8 100644 --- a/Riot/Modules/Room/RoomViewController.m +++ b/Riot/Modules/Room/RoomViewController.m @@ -266,6 +266,12 @@ + (instancetype)roomViewController bundle:[NSBundle bundleForClass:self.class]]; } ++ (instancetype)instantiate +{ + UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]]; + return [storyboard instantiateViewControllerWithIdentifier:@"RoomViewControllerStoryboardId"]; +} + #pragma mark - - (instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullable NSBundle *)nibBundleOrNil @@ -664,7 +670,7 @@ - (void)viewDidAppear:(BOOL)animated self.keyboardHeight = MAX(self.keyboardHeight, 0); if (hasJitsiCall && - ![[AppDelegate theDelegate].callPresenter.jitsiVC.widget.roomId isEqualToString:self.roomDataSource.roomId]) + !self.isRoomHavingAJitsiCall) { // the room had a Jitsi call before, but not now hasJitsiCall = NO; @@ -699,9 +705,8 @@ - (void)viewDidDisappear:(BOOL)animated [[NSNotificationCenter defaultCenter] removeObserver:mxEventDidDecryptNotificationObserver]; mxEventDidDecryptNotificationObserver = nil; } - - JitsiViewController *jitsiVC = [AppDelegate theDelegate].callPresenter.jitsiVC; - if ([jitsiVC.widget.roomId isEqualToString:self.roomDataSource.roomId]) + + if (self.isRoomHavingAJitsiCall) { hasJitsiCall = YES; [self reloadBubblesTable:YES]; @@ -1089,7 +1094,14 @@ - (void)leaveRoomOnEvent:(MXEvent*)event [super leaveRoomOnEvent:event]; - [[LegacyAppDelegate theDelegate] restoreInitialDisplay:nil]; + if (self.delegate) + { + [self.delegate roomViewControllerDidLeaveRoom:self]; + } + else + { + [[AppDelegate theDelegate] restoreInitialDisplay:nil]; + } } // Set the input toolbar according to the current display @@ -1204,15 +1216,14 @@ - (BOOL)isIRCStyleCommand:(NSString*)string { // TODO: /join command does not support via parameters yet [self.mainSession joinRoom:roomAlias viaServers:nil success:^(MXRoom *room) { - - // Show the room - [[AppDelegate theDelegate] showRoom:room.roomId andEventId:nil withMatrixSession:self.mainSession]; + + [self showRoomWithId:room.roomId]; } failure:^(NSError *error) { MXLogDebug(@"[RoomVC] Join roomAlias (%@) failed", roomAlias); //Alert user - [[AppDelegate theDelegate] showErrorAsAlert:error]; + [self showError:error]; }]; } @@ -1602,8 +1613,7 @@ - (void)refreshRoomTitle // video call button for Jitsi call if (self.isCallActive) { - JitsiViewController *jitsiVC = [AppDelegate theDelegate].callPresenter.jitsiVC; - if ([jitsiVC.widget.roomId isEqualToString:self.roomDataSource.roomId]) + if (self.isRoomHavingAJitsiCall) { // show a disabled call button UIBarButtonItem *item = [self videoCallBarButtonItem]; @@ -1999,7 +2009,7 @@ - (void)roomInputToolbarViewPresentStickerPicker } failure:^(NSError * _Nonnull error) { MXLogDebug(@"[RoomVC] Cannot display widget %@", widget); - [[AppDelegate theDelegate] showErrorAsAlert:error]; + [self showError:error]; }]; } else @@ -2098,6 +2108,125 @@ - (void)sendVideoAsset:(AVAsset *)videoAsset isPhotoLibraryAsset:(BOOL)isPhotoLi } } +- (void)showRoomWithId:(NSString*)roomId +{ + if (self.delegate) + { + [self.delegate roomViewController:self showRoomWithId:roomId]; + } + else + { + [[AppDelegate theDelegate] showRoom:roomId andEventId:nil withMatrixSession:self.roomDataSource.mxSession]; + } +} + +- (void)leaveRoom +{ + [self startActivityIndicator]; + + [self.roomDataSource.room leave:^{ + + [self stopActivityIndicator]; + + // We remove the current view controller. + if (self.delegate) + { + [self.delegate roomViewControllerDidLeaveRoom:self]; + } + else + { + [[AppDelegate theDelegate] restoreInitialDisplay:^{}]; + } + + } failure:^(NSError *error) { + + [self stopActivityIndicator]; + MXLogDebug(@"[RoomVC] Failed to reject an invited room (%@) failed", self.roomDataSource.room.roomId); + + }]; +} + +- (void)roomPreviewDidTapCancelAction +{ + // Decline this invitation = leave this page + if (self.delegate) + { + [self.delegate roomViewControllerPreviewDidTapCancel:self]; + } + else + { + [[AppDelegate theDelegate] restoreInitialDisplay:^{}]; + } +} + +- (void)startChatWithUserId:(NSString *)userId completion:(void (^)(void))completion +{ + if (self.delegate) + { + [self.delegate roomViewController:self startChatWithUserId:userId completion:completion]; + } + else + { + [[AppDelegate theDelegate] createDirectChatWithUserId:userId completion:completion]; + } +} + +- (void)showError:(NSError*)error +{ + [[AppDelegate theDelegate] showErrorAsAlert:error]; +} + +- (UIAlertController*)showAlertWithTitle:(NSString*)title message:(NSString*)message +{ + return [[AppDelegate theDelegate] showAlertWithTitle:title message:message]; +} + +- (BOOL)handleUniversalLinkURL:(NSURL*)universalLinkURL +{ + if (self.delegate) + { + return [self.delegate roomViewController:self handleUniversalLinkURL:universalLinkURL]; + } + else + { + return [[AppDelegate theDelegate] handleUniversalLinkURL:universalLinkURL]; + } +} + +- (BOOL)handleUniversalLinkFragment:(NSString*)fragment fromURL:(NSURL*)universalLinkURL +{ + if (self.delegate) + { + return [self.delegate roomViewController:self handleUniversalLinkFragment:fragment fromURL:universalLinkURL]; + } + else + { + return [[AppDelegate theDelegate] handleUniversalLinkFragment:fragment fromURL:universalLinkURL]; + } +} + +#pragma mark - Jitsi + +- (void)showJitsiCallWithWidget:(Widget*)widget +{ + [[AppDelegate theDelegate].callPresenter displayJitsiCallWithWidget:widget]; +} + +- (void)endActiveJitsiCall +{ + [[AppDelegate theDelegate].callPresenter endActiveJitsiCall]; +} + +- (BOOL)isRoomHavingAJitsiCall +{ + return [self isRoomHavingAJitsiCallForWidgetId:self.roomDataSource.roomId]; +} + +- (BOOL)isRoomHavingAJitsiCallForWidgetId:(NSString*)widgetId +{ + return [[AppDelegate theDelegate].callPresenter.jitsiVC.widget.roomId isEqualToString:widgetId]; +} + #pragma mark - Dialpad - (void)openDialpad @@ -2645,7 +2774,7 @@ - (void)dataSource:(MXKDataSource *)dataSource didRecognizeAction:(NSString *)ac if (predecessorRoomId) { // Show predecessor room - [[AppDelegate theDelegate] showRoom:predecessorRoomId andEventId:nil withMatrixSession:self.mainSession]; + [self showRoomWithId:predecessorRoomId]; } else { @@ -2721,7 +2850,7 @@ - (void)dataSource:(MXKDataSource *)dataSource didRecognizeAction:(NSString *)ac [roomDataSource acceptVerificationRequestForEventId:eventId success:^{ } failure:^(NSError *error) { - [[AppDelegate theDelegate] showErrorAsAlert:error]; + [self showError:error]; }]; } else if ([actionIdentifier isEqualToString:kMXKRoomBubbleCellKeyVerificationIncomingRequestDeclinePressed]) @@ -2733,7 +2862,7 @@ - (void)dataSource:(MXKDataSource *)dataSource didRecognizeAction:(NSString *)ac [roomDataSource declineVerificationRequestForEventId:eventId success:^{ } failure:^(NSError *error) { - [[AppDelegate theDelegate] showErrorAsAlert:error]; + [self showError:error]; }]; } else if ([actionIdentifier isEqualToString:kMXKRoomBubbleCellTapOnAttachmentView]) @@ -2863,7 +2992,7 @@ - (void)dataSource:(MXKDataSource *)dataSource didRecognizeAction:(NSString *)ac Widget *jitsiWidget = [self->customizedRoomDataSource jitsiWidget]; if (jitsiWidget) { - [[AppDelegate theDelegate].callPresenter displayJitsiCallWithWidget:jitsiWidget]; + [self showJitsiCallWithWidget:jitsiWidget]; } } else @@ -2879,7 +3008,7 @@ - (void)dataSource:(MXKDataSource *)dataSource didRecognizeAction:(NSString *)ac } else if ([actionIdentifier isEqualToString:RoomGroupCallStatusBubbleCell.leaveAction]) { - [[AppDelegate theDelegate].callPresenter endActiveJitsiCall]; + [self endActiveJitsiCall]; [self reloadBubblesTable:YES]; } else if ([actionIdentifier isEqualToString:RoomGroupCallStatusBubbleCell.declineAction]) @@ -3103,7 +3232,7 @@ - (void)showAdditionalActionsMenuForEvent:(MXEvent*)selectedEvent inCell:(id