Merge pull request #4993 from vector-im/steve/4734_room_stack

Navigation: Enable room stacking
This commit is contained in:
SBiOSoftWhare 2021-10-21 17:33:47 +02:00 committed by GitHub
commit 7e6f5850c2
24 changed files with 776 additions and 329 deletions

View file

@ -281,6 +281,9 @@ final class BuildSettings: NSObject {
static let roomScreenAllowStickerAction: Bool = true
static let roomScreenAllowFilesAction: Bool = true
/// Allow split view detail view stacking
static let allowSplitViewDetailsScreenStacking: Bool = true
// MARK: - Room Contextual Menu
static let roomContextualMenuShowMoreOptionForMessages: Bool = true

View file

@ -31,6 +31,9 @@
@protocol LegacyAppDelegateDelegate;
@class CallBar;
@class CallPresenter;
@class RoomNavigationParameters;
@class RoomPreviewNavigationParameters;
@class UniversalLinkParameters;
#pragma mark - Notifications
/**
@ -204,15 +207,24 @@ UINavigationControllerDelegate
#pragma mark - Matrix Room handling
// Show a room and jump to the given event if event id is not nil otherwise go to last messages.
- (void)showRoom:(NSString*)roomId andEventId:(NSString*)eventId withMatrixSession:(MXSession*)mxSession restoreInitialDisplay:(BOOL)restoreInitialDisplay completion:(void (^)(void))completion;
- (void)showRoomWithParameters:(RoomNavigationParameters*)parameters completion:(void (^)(void))completion;
- (void)showRoom:(NSString*)roomId andEventId:(NSString*)eventId withMatrixSession:(MXSession*)mxSession restoreInitialDisplay:(BOOL)restoreInitialDisplay;
- (void)showRoomWithParameters:(RoomNavigationParameters*)parameters;
// Restore display and show the room
- (void)showRoom:(NSString*)roomId andEventId:(NSString*)eventId withMatrixSession:(MXSession*)mxSession;
// Creates a new direct chat with the provided user id
- (void)createDirectChatWithUserId:(NSString*)userId completion:(void (^)(void))completion;
// Show room preview
- (void)showRoomPreviewWithParameters:(RoomPreviewNavigationParameters*)parameters completion:(void (^)(void))completion;
- (void)showRoomPreviewWithParameters:(RoomPreviewNavigationParameters*)parameters;
// Restore display and show the room preview
- (void)showRoomPreview:(RoomPreviewData*)roomPreviewData;
// Reopen an existing direct room with this userId or creates a new one (if it doesn't exist)
- (void)startDirectChatWithUserId:(NSString*)userId completion:(void (^)(void))completion;
@ -241,6 +253,14 @@ UINavigationControllerDelegate
*/
- (BOOL)handleUniversalLinkURL:(NSURL*)universalLinkURL;
/**
Process universal link.
@param parameters the universal link parameters.
@return YES in case of processing success.
*/
- (BOOL)handleUniversalLinkWithParameters:(UniversalLinkParameters*)parameters;
/**
Extract params from the URL fragment part (after '#') of a vector.im Universal link:

View file

@ -1236,8 +1236,24 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
return [self handleUniversalLinkFragment:fragment fromURL:nil];
}
- (BOOL)handleUniversalLinkFragment:(NSString*)fragment fromURL:(NSURL*)universalLinkURL
{
ScreenPresentationParameters *presentationParameters = [[ScreenPresentationParameters alloc] initWithRestoreInitialDisplay:YES stackAboveVisibleViews:NO];
UniversalLinkParameters *parameters = [[UniversalLinkParameters alloc] initWithFragment:fragment universalLinkURL:universalLinkURL presentationParameters:presentationParameters];
return [self handleUniversalLinkWithParameters:parameters];
}
- (BOOL)handleUniversalLinkWithParameters:(UniversalLinkParameters*)universalLinkParameters
{
NSString *fragment = universalLinkParameters.fragment;
NSURL *universalLinkURL = universalLinkParameters.universalLinkURL;
ScreenPresentationParameters *screenPresentationParameters = universalLinkParameters.presentationParameters;
BOOL restoreInitialDisplay = screenPresentationParameters.restoreInitialDisplay;
BOOL continueUserActivity = NO;
MXKAccountManager *accountManager = [MXKAccountManager sharedManager];
@ -1338,26 +1354,23 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
if (room.summary.roomType == MXRoomTypeSpace)
{
[self restoreInitialDisplay:^{
self.spaceDetailPresenter = [SpaceDetailPresenter new];
self.spaceDetailPresenter.delegate = self;
[self.spaceDetailPresenter presentForSpaceWithId:room.roomId from:self.masterNavigationController sourceView:nil session:account.mxSession animated:YES];
}];
SpaceNavigationParameters *spaceNavigationParameters = [[SpaceNavigationParameters alloc] initWithRoomId:room.roomId mxSession:account.mxSession presentationParameters:screenPresentationParameters];
[self showSpaceWithParameters:spaceNavigationParameters];
}
else
{
// Open the room page
[self showRoom:roomId andEventId:eventId withMatrixSession:account.mxSession];
RoomNavigationParameters *roomNavigationParameters = [[RoomNavigationParameters alloc] initWithRoomId:roomId eventId:eventId mxSession:account.mxSession presentationParameters: screenPresentationParameters];
[self showRoomWithParameters:roomNavigationParameters];
}
continueUserActivity = YES;
}
else
{
// We will display something but we need to do some requests before.
// So, come back to the home VC and show its loading wheel while processing
[self restoreInitialDisplay:^{
void(^findRoom)(void) = ^{
if ([_masterTabBarController.selectedViewController isKindOfClass:MXKActivityHandlingViewController.class])
{
MXKActivityHandlingViewController *homeViewController = (MXKActivityHandlingViewController*)_masterTabBarController.selectedViewController;
@ -1398,7 +1411,9 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
{
universalLinkFragmentPendingRoomAlias = @{roomId: roomIdOrAlias};
[self handleUniversalLinkFragment:newUniversalLinkFragment fromURL:universalLinkURL];
UniversalLinkParameters *newParameters = [[UniversalLinkParameters alloc] initWithFragment:newUniversalLinkFragment universalLinkURL:universalLinkURL presentationParameters:screenPresentationParameters];
[self handleUniversalLinkWithParameters:newParameters];
}
else
{
@ -1436,7 +1451,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
if (notif.object == account.mxSession && account.mxSession.state == MXSessionStateRunning)
{
MXLogDebug(@"[AppDelegate] Universal link: The session is running. Retry the link");
[self handleUniversalLinkFragment:fragment fromURL:universalLinkURL];
[self handleUniversalLinkWithParameters:universalLinkParameters];
}
}
}];
@ -1455,26 +1470,44 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
roomPreviewData.viaServers = queryParams[@"via"];
}
RoomPreviewNavigationParameters *roomPreviewNavigationParameters = [[RoomPreviewNavigationParameters alloc] initWithPreviewData:roomPreviewData presentationParameters:screenPresentationParameters];
[account.mxSession.matrixRestClient roomSummaryWith:roomIdOrAlias via:roomPreviewData.viaServers success:^(MXPublicRoom *room) {
if ([room.roomTypeString isEqualToString:MXRoomTypeStringSpace])
{
[homeViewController stopActivityIndicator];
self.spaceDetailPresenter = [SpaceDetailPresenter new];
self.spaceDetailPresenter.delegate = self;
[self.spaceDetailPresenter presentForSpaceWithPublicRoom:room from:self.masterNavigationController sourceView:nil session:account.mxSession animated:YES];
SpacePreviewNavigationParameters *spacePreviewNavigationParameters = [[SpacePreviewNavigationParameters alloc] initWithPublicRoom:room mxSession:account.mxSession presentationParameters:screenPresentationParameters];
[self showSpacePreviewWithParameters:spacePreviewNavigationParameters];
}
else
{
[self peekInRoomWithId:roomIdOrAlias forPreviewData:roomPreviewData params:pathParams];
[self peekInRoomWithNavigationParameters:roomPreviewNavigationParameters pathParams:pathParams];
}
} failure:^(NSError *error) {
[self peekInRoomWithId:roomIdOrAlias forPreviewData:roomPreviewData params:pathParams];
[self peekInRoomWithNavigationParameters:roomPreviewNavigationParameters pathParams:pathParams];
}];
}
}
}];
};
// We will display something but we need to do some requests before.
// So, come back to the home VC and show its loading wheel while processing
if (restoreInitialDisplay)
{
[self restoreInitialDisplay:^{
findRoom();
}];
}
else
{
findRoom();
}
// Let's say we are handling the case
continueUserActivity = YES;
@ -1494,7 +1527,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
if ([universalLinkFragmentPending isEqualToString:fragment])
{
MXLogDebug(@"[AppDelegate] Universal link: The user is now logged in. Retry the link");
[self handleUniversalLinkFragment:fragment fromURL:universalLinkURL];
[self handleUniversalLinkWithParameters:universalLinkParameters];
}
}];
}
@ -1522,7 +1555,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
// Create the contact related to this member
MXKContact *contact = [[MXKContact alloc] initMatrixContactWithDisplayName:displayName andMatrixID:userId];
[self showContact:contact];
[self showContact:contact presentationParameters:screenPresentationParameters];
continueUserActivity = YES;
}
@ -1541,7 +1574,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
}
// Display the group details
[self showGroup:group withMatrixSession:account.mxSession];
[self showGroup:group withMatrixSession:account.mxSession presentationParamters:screenPresentationParameters];
continueUserActivity = YES;
}
@ -1559,7 +1592,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
if ([universalLinkFragmentPending isEqualToString:fragment])
{
MXLogDebug(@"[AppDelegate] Universal link: The user is now logged in. Retry the link");
[self handleUniversalLinkFragment:fragment fromURL:universalLinkURL];
[self handleUniversalLinkWithParameters:universalLinkParameters];
}
}];
}
@ -1577,7 +1610,10 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
// Unknown command: Do nothing except coming back to the main screen
MXLogDebug(@"[AppDelegate] Universal link: TODO: Do not know what to do with the link arguments: %@", pathParams);
[self popToHomeViewControllerAnimated:NO completion:nil];
if (restoreInitialDisplay)
{
[self popToHomeViewControllerAnimated:NO completion:nil];
}
}
return continueUserActivity;
@ -1601,8 +1637,11 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
}
}
- (void)peekInRoomWithId:(NSString*)roomIdOrAlias forPreviewData:(RoomPreviewData *)roomPreviewData params:(NSArray<NSString*> *)pathParams
- (void)peekInRoomWithNavigationParameters:(RoomPreviewNavigationParameters*)presentationParameters pathParams:(NSArray<NSString*> *)pathParams
{
RoomPreviewData *roomPreviewData = presentationParameters.previewData;
NSString *roomIdOrAlias = presentationParameters.roomId;
// Is it a link to an event of a room?
// If yes, the event will be displayed once the room is joined
roomPreviewData.eventId = (pathParams.count >= 3) ? pathParams[2] : nil;
@ -1624,7 +1663,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
}
self->universalLinkFragmentPendingRoomAlias = nil;
[self showRoomPreview:roomPreviewData];
[self showRoomPreviewWithParameters:presentationParameters];
}];
}
@ -2782,8 +2821,17 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
}
}
- (void)showRoom:(NSString*)roomId andEventId:(NSString*)eventId withMatrixSession:(MXSession*)mxSession restoreInitialDisplay:(BOOL)restoreInitialDisplay completion:(void (^)(void))completion
- (void)showRoomWithParameters:(RoomNavigationParameters*)parameters
{
[self showRoomWithParameters:parameters completion:nil];
}
- (void)showRoomWithParameters:(RoomNavigationParameters*)parameters completion:(void (^)(void))completion
{
NSString *roomId = parameters.roomId;
MXSession *mxSession = parameters.mxSession;
BOOL restoreInitialDisplay = parameters.presentationParameters.restoreInitialDisplay;
if (roomId && mxSession)
{
MXRoom *room = [mxSession roomWithRoomId:roomId];
@ -2805,8 +2853,8 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
void (^selectRoom)(void) = ^() {
// Select room to display its details (dispatch this action in order to let TabBarController end its refresh)
[self.masterTabBarController selectRoomWithId:roomId andEventId:eventId inMatrixSession:mxSession completion:^{
[self.masterTabBarController selectRoomWithParameters:parameters completion:^{
// Remove delivered notifications for this room
[self.pushNotificationService removeDeliveredNotificationsWithRoomId:roomId completion:nil];
@ -2829,23 +2877,124 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
}
}
- (void)showRoom:(NSString*)roomId andEventId:(NSString*)eventId withMatrixSession:(MXSession*)mxSession restoreInitialDisplay:(BOOL)restoreInitialDisplay
{
[self showRoom:roomId andEventId:eventId withMatrixSession:mxSession restoreInitialDisplay:restoreInitialDisplay completion:nil];
}
- (void)showRoom:(NSString*)roomId andEventId:(NSString*)eventId withMatrixSession:(MXSession*)mxSession
{
[self showRoom:roomId andEventId:eventId withMatrixSession:mxSession restoreInitialDisplay:YES completion:nil];
// Ask to restore initial display
ScreenPresentationParameters *presentationParameters = [[ScreenPresentationParameters alloc] initWithRestoreInitialDisplay:YES];
RoomNavigationParameters *parameters = [[RoomNavigationParameters alloc] initWithRoomId:roomId
eventId:eventId mxSession:mxSession presentationParameters:presentationParameters];
[self showRoomWithParameters:parameters];
}
- (void)showRoomPreviewWithParameters:(RoomPreviewNavigationParameters*)parameters completion:(void (^)(void))completion
{
void (^showRoomPreview)(void) = ^() {
[self.masterTabBarController selectRoomPreviewWithParameters:parameters completion:completion];
};
if (parameters.presentationParameters.restoreInitialDisplay)
{
[self restoreInitialDisplay:^{
showRoomPreview();
}];
}
else
{
showRoomPreview();
}
}
- (void)showRoomPreviewWithParameters:(RoomPreviewNavigationParameters*)parameters
{
[self showRoomPreviewWithParameters:parameters completion:nil];
}
- (void)showRoomPreview:(RoomPreviewData*)roomPreviewData
{
[self restoreInitialDisplay:^{
[_masterTabBarController showRoomPreview:roomPreviewData];
}];
// Ask to restore initial display
ScreenPresentationParameters *presentationParameters = [[ScreenPresentationParameters alloc] initWithRestoreInitialDisplay:YES];
RoomPreviewNavigationParameters *parameters = [[RoomPreviewNavigationParameters alloc] initWithPreviewData:roomPreviewData presentationParameters:presentationParameters];
[self showRoomPreviewWithParameters:parameters];
}
- (void)showSpacePreviewWithParameters:(SpacePreviewNavigationParameters*)parameters
{
UIViewController *presentingViewController;
UIView *sourceView;
if (parameters.presentationParameters.presentingViewController)
{
presentingViewController = parameters.presentationParameters.presentingViewController;
sourceView = parameters.presentationParameters.sourceView;
}
else
{
presentingViewController = self.masterNavigationController;
}
self.spaceDetailPresenter = [SpaceDetailPresenter new];
self.spaceDetailPresenter.delegate = self;
void(^showSpace)(void) = ^{
[self.spaceDetailPresenter presentForSpaceWithPublicRoom:parameters.publicRoom
from:presentingViewController
sourceView:sourceView
session:parameters.mxSession
animated:YES];
};
if (parameters.presentationParameters.restoreInitialDisplay)
{
[self restoreInitialDisplay:^{
showSpace();
}];
}
else
{
showSpace();
}
}
- (void)showSpaceWithParameters:(SpaceNavigationParameters*)parameters
{
UIViewController *presentingViewController;
UIView *sourceView;
if (parameters.presentationParameters.presentingViewController)
{
presentingViewController = parameters.presentationParameters.presentingViewController;
sourceView = parameters.presentationParameters.sourceView;
}
else
{
presentingViewController = self.masterNavigationController;
}
self.spaceDetailPresenter = [SpaceDetailPresenter new];
self.spaceDetailPresenter.delegate = self;
void(^showSpace)(void) = ^{
[self.spaceDetailPresenter presentForSpaceWithId:parameters.roomId
from:presentingViewController
sourceView:sourceView
session:parameters.mxSession
animated:YES];
};
if (parameters.presentationParameters.restoreInitialDisplay)
{
[self restoreInitialDisplay:^{
showSpace();
}];
}
else
{
showSpace();
}
}
- (void)setVisibleRoomId:(NSString *)roomId
@ -2960,25 +3109,43 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
#pragma mark - Contacts handling
- (void)showContact:(MXKContact*)contact
- (void)showContact:(MXKContact*)contact presentationParameters:(ScreenPresentationParameters*)presentationParameters
{
[self restoreInitialDisplay:^{
[self.masterTabBarController selectContact:contact];
}];
void(^showContact)(void) = ^{
[self.masterTabBarController selectContact:contact withPresentationParameters:presentationParameters];
};
if (presentationParameters.restoreInitialDisplay)
{
[self restoreInitialDisplay:^{
showContact();
}];
}
else
{
showContact();
}
}
#pragma mark - Matrix Groups handling
- (void)showGroup:(MXGroup*)group withMatrixSession:(MXSession*)mxSession
- (void)showGroup:(MXGroup*)group withMatrixSession:(MXSession*)mxSession presentationParamters:(ScreenPresentationParameters*)presentationParameters
{
[self restoreInitialDisplay:^{
void(^showGroup)(void) = ^{
// Select group to display its details (dispatch this action in order to let TabBarController end its refresh)
[_masterTabBarController selectGroup:group inMatrixSession:mxSession];
}];
[self.masterTabBarController selectGroup:group inMatrixSession:mxSession presentationParameters:presentationParameters];
};
if (presentationParameters.restoreInitialDisplay)
{
[self restoreInitialDisplay:^{
showGroup();
}];
}
else
{
showGroup();
}
}
- (void)promptForStunServerFallback

View file

@ -0,0 +1,50 @@
//
// Copyright 2021 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
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import Foundation
/// Navigation parameters to display a room with a provided identifier in a specific matrix session.
@objcMembers
class RoomNavigationParameters: NSObject {
// MARK: - Properties
/// The room identifier
let roomId: String
/// If not nil, the room will be opened on this event.
let eventId: String?
/// The Matrix session in which the room should be available.
let mxSession: MXSession
/// Screen presentation parameters.
let presentationParameters: ScreenPresentationParameters
// MARK: - Setup
init(roomId: String,
eventId: String?,
mxSession: MXSession,
presentationParameters: ScreenPresentationParameters) {
self.roomId = roomId
self.eventId = eventId
self.mxSession = mxSession
self.presentationParameters = presentationParameters
super.init()
}
}

View file

@ -0,0 +1,39 @@
//
// Copyright 2021 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
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import Foundation
/// Navigation parameters to display a preview of a room that is unknown for the user.
/// This room can come from an email invitation link or a simple link to a room.
@objcMembers
class RoomPreviewNavigationParameters: RoomNavigationParameters {
// MARK: - Properties
/// The data for the room preview
let previewData: RoomPreviewData
// MARK: - Setup
init(previewData: RoomPreviewData, presentationParameters: ScreenPresentationParameters) {
self.previewData = previewData
super.init(roomId: previewData.roomId,
eventId: previewData.eventId,
mxSession: previewData.mxSession,
presentationParameters: presentationParameters)
}
}

View file

@ -0,0 +1,65 @@
//
// Copyright 2021 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
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import Foundation
/// Screen presentation parameters used when a universal link is triggered
@objcMembers
class ScreenPresentationParameters: NSObject {
// MARK: - Properties
/// Indicate to pop to home and restore initial view hierarchy
let restoreInitialDisplay: Bool
/// Indicate to stack above visible views
/// If this variable is set to true `restoreInitialDisplay` should be set to false to have effect
let stackAboveVisibleViews: Bool
/// The object that triggers the universal link action.
let sender: AnyObject?
/// The view containing the anchor rectangle for the popover. Useful for iPad if a universlink trigger a pop over.
let sourceView: UIView?
/// The view controller from which the universal link is triggered. `nil` if triggered from some other kind of object.
var presentingViewController: UIViewController? {
return self.sender as? UIViewController
}
// MARK: - Properties
init(restoreInitialDisplay: Bool,
stackAboveVisibleViews: Bool,
sender: AnyObject?,
sourceView: UIView?) {
self.restoreInitialDisplay = restoreInitialDisplay
self.stackAboveVisibleViews = stackAboveVisibleViews
self.sender = sender
self.sourceView = sourceView
super.init()
}
convenience init(restoreInitialDisplay: Bool, stackAboveVisibleViews: Bool) {
self.init(restoreInitialDisplay: restoreInitialDisplay, stackAboveVisibleViews: stackAboveVisibleViews, sender: nil, sourceView: nil)
}
/// In this initializer `stackAboveVisibleViews` is set to false`
convenience init(restoreInitialDisplay: Bool) {
self.init(restoreInitialDisplay: restoreInitialDisplay, stackAboveVisibleViews: false, sender: nil, sourceView: nil)
}
}

View file

@ -0,0 +1,45 @@
//
// Copyright 2021 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
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import Foundation
/// Navigation parameters to display a space with a provided identifier in a specific matrix session.
@objcMembers
class SpaceNavigationParameters: NSObject {
// MARK: - Properties
/// The room identifier
let roomId: String
/// The Matrix session in which the room should be available.
let mxSession: MXSession
/// Screen presentation parameters.
let presentationParameters: ScreenPresentationParameters
// MARK: - Setup
init(roomId: String,
mxSession: MXSession,
presentationParameters: ScreenPresentationParameters) {
self.roomId = roomId
self.mxSession = mxSession
self.presentationParameters = presentationParameters
super.init()
}
}

View file

@ -0,0 +1,39 @@
//
// Copyright 2021 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
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import Foundation
/// Navigation parameters to display a preview of a space that is unknown for the user.
@objcMembers
class SpacePreviewNavigationParameters: SpaceNavigationParameters {
// MARK: - Properties
/// The data for the room preview
let publicRoom: MXPublicRoom
// MARK: - Setup
init(publicRoom: MXPublicRoom,
mxSession: MXSession,
presentationParameters: ScreenPresentationParameters) {
self.publicRoom = publicRoom
super.init(roomId: publicRoom.roomId,
mxSession: mxSession,
presentationParameters: presentationParameters)
}
}

View file

@ -856,16 +856,34 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro
}
}
- (void)dispayRoomWithRoomId:(NSString*)roomId inMatrixSession:(MXSession*)matrixSession
- (void)showRoomWithRoomId:(NSString*)roomId inMatrixSession:(MXSession*)matrixSession
{
// Avoid multiple openings of rooms
self.userInteractionEnabled = NO;
// Do not stack views when showing room
ScreenPresentationParameters *presentationParameters = [[ScreenPresentationParameters alloc] initWithRestoreInitialDisplay:NO stackAboveVisibleViews:NO];
[[AppDelegate theDelegate] showRoom:roomId andEventId:nil withMatrixSession:matrixSession restoreInitialDisplay:NO completion:^{
RoomNavigationParameters *parameters = [[RoomNavigationParameters alloc] initWithRoomId:roomId
eventId:nil
mxSession:matrixSession
presentationParameters:presentationParameters];
[[AppDelegate theDelegate] showRoomWithParameters:parameters completion:^{
self.userInteractionEnabled = YES;
}];
}
- (void)showRoomPreviewWithData:(RoomPreviewData*)roomPreviewData
{
// Do not stack views when showing room
ScreenPresentationParameters *presentationParameters = [[ScreenPresentationParameters alloc] initWithRestoreInitialDisplay:NO stackAboveVisibleViews:NO sender:nil sourceView:nil];
RoomPreviewNavigationParameters *parameters = [[RoomPreviewNavigationParameters alloc] initWithPreviewData:roomPreviewData presentationParameters:presentationParameters];
[[AppDelegate theDelegate] showRoomPreviewWithParameters:parameters];
}
// Disable UI interactions in this screen while we are going to open another screen.
// Interactions on reset on viewWillAppear.
- (void)setUserInteractionEnabled:(BOOL)userInteractionEnabled
@ -939,7 +957,7 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro
}
// Display the room preview
[self dispayRoomWithRoomId:invitedRoom.roomId inMatrixSession:invitedRoom.mxSession];
[self showRoomWithRoomId:invitedRoom.roomId inMatrixSession:invitedRoom.mxSession];
}
else if ([actionIdentifier isEqualToString:kInviteRecentTableViewCellAcceptButtonPressed])
{
@ -1461,8 +1479,7 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro
else if ([self canShowRoomPreviewFor:cellData.roomSummary])
{
// Display the room preview
[self dispayRoomWithRoomId:cellData.roomIdentifier
inMatrixSession:cellData.mxSession];
[self showRoomWithRoomId:cellData.roomIdentifier inMatrixSession:cellData.mxSession];
}
else
{
@ -1982,7 +1999,8 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro
if ([self.recentsDataSource.publicRoomsDirectoryDataSource.mxSession roomWithRoomId:publicRoom.roomId])
{
// Open the public room
[[AppDelegate theDelegate] showRoom:publicRoom.roomId andEventId:nil withMatrixSession:self.recentsDataSource.publicRoomsDirectoryDataSource.mxSession restoreInitialDisplay:NO];
[self showRoomWithRoomId:publicRoom.roomId
inMatrixSession:self.recentsDataSource.publicRoomsDirectoryDataSource.mxSession];
}
else
{
@ -1996,14 +2014,15 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro
// Try to get more information about the room before opening its preview
[roomPreviewData peekInRoom:^(BOOL succeeded) {
[self stopActivityIndicator];
[[AppDelegate theDelegate].masterTabBarController showRoomPreview:roomPreviewData];
[self showRoomPreviewWithData:roomPreviewData];
}];
}
else
{
RoomPreviewData *roomPreviewData = [[RoomPreviewData alloc] initWithPublicRoom:publicRoom andSession:self.recentsDataSource.publicRoomsDirectoryDataSource.mxSession];
[[AppDelegate theDelegate].masterTabBarController showRoomPreview:roomPreviewData];
[self showRoomPreviewWithData:roomPreviewData];
}
}
}
@ -2069,7 +2088,7 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro
- (void)recentListViewController:(MXKRecentListViewController *)recentListViewController didSelectRoom:(NSString *)roomId inMatrixSession:(MXSession *)matrixSession
{
[self dispayRoomWithRoomId:roomId inMatrixSession:matrixSession];
[self showRoomWithRoomId:roomId inMatrixSession:matrixSession];
}
- (void)recentListViewController:(MXKRecentListViewController *)recentListViewController didSelectSuggestedRoom:(MXSpaceChildInfo *)childInfo
@ -2080,7 +2099,7 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro
[previewData peekInRoom:^(BOOL succeeded) {
MXStrongifyAndReturnIfNil(self);
[self stopActivityIndicator];
[[AppDelegate theDelegate].masterTabBarController showRoomPreview:previewData];
[self showRoomPreviewWithData:previewData];
}];
}
@ -2123,7 +2142,7 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro
- (void)createRoomCoordinatorBridgePresenterDelegate:(CreateRoomCoordinatorBridgePresenter *)coordinatorBridgePresenter didCreateNewRoom:(MXRoom *)room
{
[coordinatorBridgePresenter dismissWithAnimated:YES completion:^{
[[AppDelegate theDelegate] showRoom:room.roomId andEventId:nil withMatrixSession:self.mainSession restoreInitialDisplay:NO];
[self showRoomWithRoomId:room.roomId inMatrixSession:self.mainSession];
}];
coordinatorBridgePresenter = nil;
}
@ -2258,7 +2277,8 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro
{
// Room is known show it directly
[coordinatorBridgePresenter dismissWithAnimated:YES completion:^{
[[AppDelegate theDelegate] showRoom:room.roomId andEventId:nil withMatrixSession:self.mainSession restoreInitialDisplay:NO];
[self showRoomWithRoomId:room.roomId
inMatrixSession:self.mainSession];
}];
coordinatorBridgePresenter = nil;
}
@ -2286,7 +2306,8 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro
if (succeeded) {
[coordinatorBridgePresenter dismissWithAnimated:YES completion:^{
[[AppDelegate theDelegate].masterTabBarController showRoomPreview:roomPreviewData];
[self showRoomPreviewWithData:roomPreviewData];
}];
self.roomsDirectoryCoordinatorBridgePresenter = nil;
} else {

View file

@ -0,0 +1,55 @@
//
// Copyright 2021 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
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import Foundation
/// Parameters describing a universal link
@objcMembers
class UniversalLinkParameters: NSObject {
// MARK: - Properties
/// The unprocessed the universal link URL
let universalLinkURL: URL
/// The fragment part of the universal link
let fragment: String
/// Presentation parameters
let presentationParameters: ScreenPresentationParameters
// MARK: - Setup
init(fragment: String,
universalLinkURL: URL,
presentationParameters: ScreenPresentationParameters) {
self.fragment = fragment
self.universalLinkURL = universalLinkURL
self.presentationParameters = presentationParameters
super.init()
}
convenience init?(universalLinkURL: URL,
presentationParameters: ScreenPresentationParameters) {
guard let fixedURL = Tools.fixURL(withSeveralHashKeys: universalLinkURL), let fragment = fixedURL.fragment else {
return nil
}
self.init(fragment: fragment, universalLinkURL: universalLinkURL, presentationParameters: presentationParameters)
}
}

View file

@ -139,6 +139,20 @@
}
}
- (void)showRoomWithId:(NSString*)roomId
andEventId:(NSString*)eventId
inMatrixSession:(MXSession*)session
{
ScreenPresentationParameters *presentationParameters = [[ScreenPresentationParameters alloc] initWithRestoreInitialDisplay:NO stackAboveVisibleViews:NO];
RoomNavigationParameters *parameters = [[RoomNavigationParameters alloc] initWithRoomId:roomId
eventId:eventId
mxSession:session
presentationParameters:presentationParameters];
[[AppDelegate theDelegate] showRoomWithParameters:parameters];
}
#pragma mark - MXKDataSourceDelegate
- (Class<MXKCellRendering>)cellViewClassForCellData:(MXKCellData*)cellData
@ -188,9 +202,9 @@
[tableView deselectRowAtIndexPath:indexPath animated:YES];
// Make the master tabBar view controller open the RoomViewController
[[AppDelegate theDelegate].masterTabBarController selectRoomWithId:cellData.roomId
andEventId:_selectedEvent.eventId
inMatrixSession:self.mainSession];
[self showRoomWithId:cellData.roomId
andEventId:_selectedEvent.eventId
inMatrixSession:self.mainSession];
// Reset the selected event. HomeViewController got it when here
_selectedEvent = nil;

View file

@ -146,6 +146,20 @@
}
}
- (void)showRoomWithId:(NSString*)roomId
andEventId:(NSString*)eventId
inMatrixSession:(MXSession*)session
{
ScreenPresentationParameters *presentationParameters = [[ScreenPresentationParameters alloc] initWithRestoreInitialDisplay:NO stackAboveVisibleViews:NO];
RoomNavigationParameters *parameters = [[RoomNavigationParameters alloc] initWithRoomId:roomId
eventId:eventId
mxSession:session
presentationParameters:presentationParameters];
[[AppDelegate theDelegate] showRoomWithParameters:parameters];
}
#pragma mark - MXKDataSourceDelegate
- (Class<MXKCellRendering>)cellViewClassForCellData:(MXKCellData*)cellData
@ -239,9 +253,9 @@
[tableView deselectRowAtIndexPath:indexPath animated:YES];
// Make the master tabBar view controller open the RoomViewController
[[AppDelegate theDelegate].masterTabBarController selectRoomWithId:cellData.roomId
andEventId:_selectedEvent.eventId
inMatrixSession:cellData.mxSession];
[self showRoomWithId:cellData.roomId
andEventId:_selectedEvent.eventId
inMatrixSession:cellData.mxSession];
// Reset the selected event. HomeViewController got it when here
_selectedEvent = nil;

View file

@ -193,7 +193,7 @@
if ([dataSource.mxSession roomWithRoomId:publicRoom.roomId])
{
// Open the public room.
[self openRoomWithId:publicRoom.roomId inMatrixSession:dataSource.mxSession];
[self showRoomWithId:publicRoom.roomId inMatrixSession:dataSource.mxSession];
}
else
{
@ -209,13 +209,13 @@
[self stopActivityIndicator];
[[AppDelegate theDelegate].masterTabBarController showRoomPreview:roomPreviewData];
[self showRoomPreviewWithData:roomPreviewData];
}];
}
else
{
RoomPreviewData *roomPreviewData = [[RoomPreviewData alloc] initWithPublicRoom:publicRoom andSession:dataSource.mxSession];
[[AppDelegate theDelegate].masterTabBarController showRoomPreview:roomPreviewData];
[self showRoomPreviewWithData:roomPreviewData];
}
}
@ -232,9 +232,23 @@
#pragma mark - Private methods
- (void)openRoomWithId:(NSString*)roomId inMatrixSession:(MXSession*)mxSession
{
[[AppDelegate theDelegate] showRoom:roomId andEventId:nil withMatrixSession:mxSession restoreInitialDisplay:NO];
- (void)showRoomWithId:(NSString*)roomId inMatrixSession:(MXSession*)mxSession
{
ScreenPresentationParameters *presentationParameters = [[ScreenPresentationParameters alloc] initWithRestoreInitialDisplay:NO stackAboveVisibleViews:NO];
RoomNavigationParameters *parameters = [[RoomNavigationParameters alloc] initWithRoomId:roomId
eventId:nil
mxSession:mxSession
presentationParameters:presentationParameters];
[[AppDelegate theDelegate] showRoomWithParameters:parameters];
}
- (void)showRoomPreviewWithData:(RoomPreviewData*)roomPreviewData
{
ScreenPresentationParameters *presentationParameters = [[ScreenPresentationParameters alloc] initWithRestoreInitialDisplay:NO stackAboveVisibleViews:NO];
RoomPreviewNavigationParameters *parameters = [[RoomPreviewNavigationParameters alloc] initWithPreviewData:roomPreviewData presentationParameters:presentationParameters];
[[AppDelegate theDelegate] showRoomPreviewWithParameters:parameters];
}
- (void)refreshCurrentSelectedCell:(BOOL)forceVisible

View file

@ -231,12 +231,8 @@ extension RoomCoordinator: RoomViewControllerDelegate {
func roomViewController(_ roomViewController: RoomViewController, showCompleteSecurityFor session: MXSession) {
AppDelegate.theDelegate().presentCompleteSecurity(for: session)
}
func roomViewController(_ roomViewController: RoomViewController, handleUniversalLinkFragment fragment: String, from universalLinkURL: URL?) -> Bool {
return AppDelegate.theDelegate().handleUniversalLinkFragment(fragment, from: universalLinkURL)
}
func roomViewController(_ roomViewController: RoomViewController, handleUniversalLinkURL universalLinkURL: URL) -> Bool {
return AppDelegate.theDelegate().handleUniversalLinkURL(universalLinkURL)
func roomViewController(_ roomViewController: RoomViewController, handleUniversalLinkWith parameters: UniversalLinkParameters) -> Bool {
return AppDelegate.theDelegate().handleUniversalLink(with: parameters)
}
}

View file

@ -1,127 +0,0 @@
//
// Copyright 2021 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
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import Foundation
/// this extension is temprorary and implements navigation to the Space bootom sheet. This should be moved to an universal link flow coordinator
extension RoomViewController {
@objc func handleSpaceUniversalLink(with url: URL) {
let url = Tools.fixURL(withSeveralHashKeys: url)
var pathParamsObjc: NSArray?
var queryParamsObjc: NSMutableDictionary?
AppDelegate.theDelegate().parseUniversalLinkFragment(url?.fragment, outPathParams: &pathParamsObjc, outQueryParams: &queryParamsObjc)
// Sanity check
guard let pathParams = pathParamsObjc as? [String], pathParams.count > 0 else {
MXLog.error("[RoomViewController] Universal link: Error: No path parameters")
return
}
var roomIdOrAliasParam: String?
var eventIdParam: String?
var userIdParam: String?
var groupIdParam: String?
// Check permalink to room or event
if pathParams[0] == "room" && pathParams.count >= 2 {
// The link is the form of "/room/[roomIdOrAlias]" or "/room/[roomIdOrAlias]/[eventId]"
roomIdOrAliasParam = pathParams[1]
// Is it a link to an event of a room?
eventIdParam = pathParams.count >= 3 ? pathParams[2] : nil
} else if pathParams[0] == "group" && pathParams.count >= 2 {
// The link is the form of "/group/[groupId]"
groupIdParam = pathParams[1]
} else if (pathParams[0].hasPrefix("#") || pathParams[0].hasPrefix("!")) && pathParams.count >= 1 {
// The link is the form of "/#/[roomIdOrAlias]" or "/#/[roomIdOrAlias]/[eventId]"
// Such links come from matrix.to permalinks
roomIdOrAliasParam = pathParams[0]
eventIdParam = pathParams.count >= 2 ? pathParams[1] : nil
} else if pathParams[0] == "user" && pathParams.count == 2 { // Check permalink to a user
// The link is the form of "/user/userId"
userIdParam = pathParams[1]
} else if pathParams[0].hasPrefix("@") && pathParams.count == 1 {
// The link is the form of "/#/[userId]"
// Such links come from matrix.to permalinks
userIdParam = pathParams[0]
}
guard let roomIdOrAlias = roomIdOrAliasParam else {
AppDelegate.theDelegate().handleUniversalLinkURL(url)
return
}
self.startActivityIndicator()
var viaServers: [String] = []
if let queryParams = queryParamsObjc as? [String: Any], let via = queryParams["via"] as? [String] {
viaServers = via
}
if roomIdOrAlias.hasPrefix("#") {
self.mainSession.matrixRestClient.roomId(forRoomAlias: roomIdOrAlias) { [weak self] response in
guard let self = self else {
return
}
guard let roomId = response.value else {
self.stopActivityIndicator()
if response.error != nil {
let errorMessage = VectorL10n.roomDoesNotExist(roomIdOrAlias)
AppDelegate.theDelegate().showAlert(withTitle: nil, message: errorMessage)
}
return
}
self.requestSummaryAndShowSpaceDetail(forRoomWithId: roomId, via: viaServers, from: url)
}
} else {
self.requestSummaryAndShowSpaceDetail(forRoomWithId: roomIdOrAlias, via: viaServers, from: url)
}
}
private func requestSummaryAndShowSpaceDetail(forRoomWithId roomId: String, via: [String], from url: URL?) {
if self.mainSession.spaceService.getSpace(withId: roomId) != nil {
self.stopActivityIndicator()
self.showSpaceDetail(withId: roomId)
return
}
self.mainSession.matrixRestClient.roomSummary(with: roomId, via: via) { [weak self] response in
guard let self = self else {
return
}
self.stopActivityIndicator()
guard let publicRoom = response.value, publicRoom.roomTypeString == MXRoomTypeString.space.rawValue else {
AppDelegate.theDelegate().handleUniversalLinkURL(url)
return
}
self.showSpaceDetail(with: publicRoom)
}
}
}

View file

@ -28,6 +28,7 @@
#import "UIViewController+RiotSearch.h"
@class BadgeLabel;
@class UniversalLinkParameters;
@protocol RoomViewControllerDelegate;
NS_ASSUME_NONNULL_BEGIN
@ -86,10 +87,6 @@ extern NSNotificationName const RoomGroupCallTileTappedNotification;
*/
- (void)displayRoomPreview:(RoomPreviewData*)roomPreviewData;
- (void)showSpaceDetailWithPublicRoom:(MXPublicRoom *)publicRoom;
- (void)showSpaceDetailWithId:(NSString *)spaceId;
/**
Action used to handle some buttons.
*/
@ -170,26 +167,14 @@ extern NSNotificationName const RoomGroupCallTileTappedNotification;
- (void)roomViewControllerPreviewDidTapCancel:(RoomViewController *)roomViewController;
/**
Handle the fragment of a universal link.
Process 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.
@param parameters the universal link parameters.
@return YES in case of processing success.
*/
- (BOOL)roomViewController:(RoomViewController *)roomViewController
handleUniversalLinkURL:(NSURL*)universalLinkURL;
handleUniversalLinkWithParameters:(UniversalLinkParameters*)parameters;
@end

View file

@ -2202,28 +2202,33 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
return [[AppDelegate theDelegate] showAlertWithTitle:title message:message];
}
- (ScreenPresentationParameters*)buildUniversalLinkPresentationParameters
{
return [[ScreenPresentationParameters alloc] initWithRestoreInitialDisplay:NO stackAboveVisibleViews:BuildSettings.allowSplitViewDetailsScreenStacking sender:self sourceView:nil];
}
- (BOOL)handleUniversalLinkURL:(NSURL*)universalLinkURL
{
if (self.delegate)
{
return [self.delegate roomViewController:self handleUniversalLinkURL:universalLinkURL];
}
else
{
[self handleSpaceUniversalLinkWith:universalLinkURL];
return YES;
}
UniversalLinkParameters *parameters = [[UniversalLinkParameters alloc] initWithUniversalLinkURL:universalLinkURL presentationParameters:[self buildUniversalLinkPresentationParameters]];
return [self handleUniversalLinkWithParameters:parameters];
}
- (BOOL)handleUniversalLinkFragment:(NSString*)fragment fromURL:(NSURL*)universalLinkURL
{
UniversalLinkParameters *parameters = [[UniversalLinkParameters alloc] initWithFragment:fragment
universalLinkURL:universalLinkURL presentationParameters:[self buildUniversalLinkPresentationParameters]];
return [self handleUniversalLinkWithParameters:parameters];
}
- (BOOL)handleUniversalLinkWithParameters:(UniversalLinkParameters*)parameters
{
if (self.delegate)
{
return [self.delegate roomViewController:self handleUniversalLinkFragment:fragment fromURL:universalLinkURL];
return [self.delegate roomViewController:self handleUniversalLinkWithParameters:parameters];
}
else
{
return [[AppDelegate theDelegate] handleUniversalLinkFragment:fragment fromURL:universalLinkURL];
return [[AppDelegate theDelegate] handleUniversalLinkWithParameters:parameters];
}
}
@ -6563,20 +6568,6 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
}];
}
- (void)showSpaceDetailWithPublicRoom:(MXPublicRoom *)publicRoom
{
self.spaceDetailPresenter = [SpaceDetailPresenter new];
self.spaceDetailPresenter.delegate = self;
[self.spaceDetailPresenter presentForSpaceWithPublicRoom:publicRoom from:self sourceView:nil session:self.mainSession animated:YES];
}
- (void)showSpaceDetailWithId:(NSString *)spaceId
{
self.spaceDetailPresenter = [SpaceDetailPresenter new];
self.spaceDetailPresenter.delegate = self;
[self.spaceDetailPresenter presentForSpaceWithId:spaceId from:self sourceView:nil session:self.mainSession animated:YES];
}
#pragma mark - SpaceDetailPresenterDelegate
- (void)spaceDetailPresenterDidComplete:(SpaceDetailPresenter *)presenter

View file

@ -88,17 +88,18 @@ class SpaceDetailPresenter: NSObject {
private func present(_ viewController: SpaceDetailViewController, animated: Bool) {
guard let presentingViewController = self.presentingViewController?.presentedViewController ?? self.presentingViewController else {
MXLog.error("[SpaceDetailPresenter] present no presentingViewController found")
return
}
if UIDevice.current.isPhone {
guard let rootViewController = self.presentingViewController else {
MXLog.error("[SpaceDetailPresenter] present no rootViewController found")
return
}
slidingModalPresenter.present(viewController, from: rootViewController.presentedViewController ?? rootViewController, animated: true, completion: nil)
slidingModalPresenter.present(viewController, from: presentingViewController, animated: true, completion: nil)
} else {
// Configure source view when view controller is presented with a popover
viewController.modalPresentationStyle = .popover
if let sourceView = self.sourceView, let popoverPresentationController = viewController.popoverPresentationController {
if let popoverPresentationController = viewController.popoverPresentationController, let sourceView = sourceView ?? presentingViewController.view {
popoverPresentationController.sourceView = sourceView
popoverPresentationController.sourceRect = sourceView.bounds
}

View file

@ -351,4 +351,8 @@ extension SplitViewCoordinator: SplitViewMasterPresentableDelegate {
detailNavigationRouter.push(detailPresentable, animated: true, popCompletion: popCompletion)
}
func splitViewMasterPresentableWantsToResetDetail(_ presentable: Presentable) {
self.resetDetailNavigationControllerWithPlaceholder(animated: false)
}
}

View file

@ -26,6 +26,9 @@ protocol SplitViewMasterPresentableDelegate: AnyObject {
/// Stack the detailPresentable on the existing split view detail stack
func splitViewMasterPresentable(_ presentable: Presentable, wantsToStack detailPresentable: Presentable, popCompletion: (() -> Void)?)
/// Reset detail stack with placeholder
func splitViewMasterPresentableWantsToResetDetail(_ presentable: Presentable)
}
/// `SplitViewMasterPresentableDelegate` default implementation

View file

@ -42,7 +42,9 @@ typedef NS_ENUM(NSUInteger, MasterTabBarIndex) {
};
@protocol MasterTabBarControllerDelegate;
@class RoomNavigationParameters;
@class RoomPreviewNavigationParameters;
@class ScreenPresentationParameters;
@interface MasterTabBarController : UITabBarController
@ -79,47 +81,34 @@ typedef NS_ENUM(NSUInteger, MasterTabBarIndex) {
*/
- (void)showAuthenticationScreenAfterSoftLogout:(MXCredentials*)softLogoutCredentials;
/**
Open the room with the provided identifier in a specific matrix session.
@param roomId the room identifier.
@param eventId if not nil, the room will be opened on this event.
@param mxSession the matrix session in which the room should be available.
*/
- (void)selectRoomWithId:(NSString*)roomId andEventId:(NSString*)eventId inMatrixSession:(MXSession*)mxSession;
/// Open the room with the provided identifier in a specific matrix session.
/// @param parameters the presentation parameters that contains room information plus display information.
/// @param completion the block to execute at the end of the operation.
- (void)selectRoomWithParameters:(RoomNavigationParameters*)parameters completion:(void (^)(void))completion;
/**
Open the room with the provided identifier in a specific matrix session.
@param roomId the room identifier.
@param eventId if not nil, the room will be opened on this event.
@param matrixSession the matrix session in which the room should be available.
@param completion the block to execute at the end of the operation.
*/
- (void)selectRoomWithId:(NSString*)roomId andEventId:(NSString*)eventId inMatrixSession:(MXSession*)matrixSession completion:(void (^)(void))completion;
/**
Open the RoomViewController to display the preview of a room that is unknown for the user.
This room can come from an email invitation link or a simple link to a room.
@param roomPreviewData the data for the room preview.
*/
- (void)showRoomPreview:(RoomPreviewData*)roomPreviewData;
/// Open the RoomViewController to display the preview of a room that is unknown for the user.
/// This room can come from an email invitation link or a simple link to a room.
/// @param parameters the presentation parameters that contains room preview information plus display information.
/// @param completion the block to execute at the end of the operation.
- (void)selectRoomPreviewWithParameters:(RoomPreviewNavigationParameters*)parameters completion:(void (^)(void))completion;
/**
Open a ContactDetailsViewController to display the information of the provided contact.
*/
- (void)selectContact:(MXKContact*)contact;
- (void)selectContact:(MXKContact*)contact withPresentationParameters:(ScreenPresentationParameters*)presentationParameters;
/**
Open a GroupDetailsViewController to display the information of the provided group.
@param group
@param group Selected community.
@param matrixSession the matrix session in which the group should be available.
*/
- (void)selectGroup:(MXGroup*)group inMatrixSession:(MXSession*)matrixSession;
- (void)selectGroup:(MXGroup*)group inMatrixSession:(MXSession*)matrixSession presentationParameters:(ScreenPresentationParameters*)presentationParameters;
/**
Release the current selected item (if any).
*/
@ -202,9 +191,9 @@ typedef NS_ENUM(NSUInteger, MasterTabBarIndex) {
- (void)masterTabBarControllerDidCompleteAuthentication:(MasterTabBarController *)masterTabBarController;
- (void)masterTabBarController:(MasterTabBarController*)masterTabBarController needsSideMenuIconWithNotification:(BOOL)displayNotification;
- (void)masterTabBarController:(MasterTabBarController *)masterTabBarController didSelectRoomWithId:(NSString*)roomId andEventId:(NSString*)eventId inMatrixSession:(MXSession*)matrixSession completion:(void (^)(void))completion;
- (void)masterTabBarController:(MasterTabBarController *)masterTabBarController didSelectRoomPreviewWithData:(RoomPreviewData*)roomPreviewData;
- (void)masterTabBarController:(MasterTabBarController *)masterTabBarController didSelectContact:(MXKContact*)contact;
- (void)masterTabBarController:(MasterTabBarController *)masterTabBarController didSelectGroup:(MXGroup*)group inMatrixSession:(MXSession*)matrixSession;
- (void)masterTabBarController:(MasterTabBarController *)masterTabBarController didSelectRoomWithParameters:(RoomNavigationParameters*)roomNavigationParameters completion:(void (^)(void))completion;
- (void)masterTabBarController:(MasterTabBarController *)masterTabBarController didSelectRoomPreviewWithParameters:(RoomPreviewNavigationParameters*)roomPreviewNavigationParameters completion:(void (^)(void))completion;
- (void)masterTabBarController:(MasterTabBarController *)masterTabBarController didSelectContact:(MXKContact*)contact withPresentationParameters:(ScreenPresentationParameters*)presentationParameters;
- (void)masterTabBarController:(MasterTabBarController *)masterTabBarController didSelectGroup:(MXGroup*)group inMatrixSession:(MXSession*)matrixSession presentationParameters:(ScreenPresentationParameters*)presentationParameters;
@end

View file

@ -586,56 +586,67 @@
}
}
- (void)selectRoomWithId:(NSString*)roomId andEventId:(NSString*)eventId inMatrixSession:(MXSession*)matrixSession
{
[self selectRoomWithId:roomId andEventId:eventId inMatrixSession:matrixSession completion:nil];
}
- (void)selectRoomWithId:(NSString*)roomId andEventId:(NSString*)eventId inMatrixSession:(MXSession*)matrixSession completion:(void (^)(void))completion
- (void)selectRoomWithParameters:(RoomNavigationParameters*)paramaters completion:(void (^)(void))completion
{
[self releaseSelectedItem];
_selectedRoomId = roomId;
_selectedEventId = eventId;
_selectedRoomSession = matrixSession;
_selectedRoomId = paramaters.roomId;
_selectedEventId = paramaters.eventId;
_selectedRoomSession = paramaters.mxSession;
[self.masterTabBarDelegate masterTabBarController:self didSelectRoomWithId:roomId andEventId:eventId inMatrixSession:matrixSession completion:completion];
[self.masterTabBarDelegate masterTabBarController:self didSelectRoomWithParameters:paramaters completion:completion];
[self refreshSelectedControllerSelectedCellIfNeeded];
}
- (void)showRoomPreview:(RoomPreviewData *)roomPreviewData
- (void)selectRoomPreviewWithParameters:(RoomPreviewNavigationParameters*)parameters completion:(void (^)(void))completion
{
[self releaseSelectedItem];
RoomPreviewData *roomPreviewData = parameters.previewData;
_selectedRoomPreviewData = roomPreviewData;
_selectedRoomId = roomPreviewData.roomId;
_selectedRoomSession = roomPreviewData.mxSession;
[self.masterTabBarDelegate masterTabBarController:self didSelectRoomPreviewWithData:roomPreviewData];
[self.masterTabBarDelegate masterTabBarController:self didSelectRoomPreviewWithParameters:parameters completion:completion];
[self refreshSelectedControllerSelectedCellIfNeeded];
}
- (void)selectContact:(MXKContact*)contact
{
ScreenPresentationParameters *presentationParameters = [[ScreenPresentationParameters alloc] initWithRestoreInitialDisplay:YES stackAboveVisibleViews:NO];
[self selectContact:contact withPresentationParameters:presentationParameters];
}
- (void)selectContact:(MXKContact*)contact withPresentationParameters:(ScreenPresentationParameters*)presentationParameters
{
[self releaseSelectedItem];
_selectedContact = contact;
[self.masterTabBarDelegate masterTabBarController:self didSelectContact:contact];
[self.masterTabBarDelegate masterTabBarController:self didSelectContact:contact withPresentationParameters:presentationParameters];
[self refreshSelectedControllerSelectedCellIfNeeded];
}
- (void)selectGroup:(MXGroup*)group inMatrixSession:(MXSession*)matrixSession
{
ScreenPresentationParameters *presentationParameters = [[ScreenPresentationParameters alloc] initWithRestoreInitialDisplay:YES stackAboveVisibleViews:NO];
[self selectGroup:group inMatrixSession:matrixSession presentationParameters:presentationParameters];
}
- (void)selectGroup:(MXGroup*)group inMatrixSession:(MXSession*)matrixSession presentationParameters:(ScreenPresentationParameters*)presentationParameters
{
[self releaseSelectedItem];
_selectedGroup = group;
_selectedGroupSession = matrixSession;
[self.masterTabBarDelegate masterTabBarController:self didSelectGroup:group inMatrixSession:matrixSession];
[self.masterTabBarDelegate masterTabBarController:self didSelectGroup:group inMatrixSession:matrixSession presentationParameters:presentationParameters];
[self refreshSelectedControllerSelectedCellIfNeeded];
}

View file

@ -340,32 +340,31 @@ final class TabBarCoordinator: NSObject, TabBarCoordinatorType {
}
// FIXME: Should be displayed from a tab.
private func showContactDetails(with contact: MXKContact) {
private func showContactDetails(with contact: MXKContact, presentationParameters: ScreenPresentationParameters) {
let coordinatorParameters = ContactDetailsCoordinatorParameters(contact: contact)
let coordinator = ContactDetailsCoordinator(parameters: coordinatorParameters)
coordinator.start()
self.add(childCoordinator: coordinator)
self.replaceSplitViewDetails(with: coordinator) { [weak self] in
self.showSplitViewDetails(with: coordinator, stackedOnSplitViewDetail: presentationParameters.stackAboveVisibleViews) { [weak self] in
self?.remove(childCoordinator: coordinator)
}
}
// FIXME: Should be displayed from a tab.
private func showGroupDetails(with group: MXGroup, for matrixSession: MXSession) {
private func showGroupDetails(with group: MXGroup, for matrixSession: MXSession, presentationParameters: ScreenPresentationParameters) {
let coordinatorParameters = GroupDetailsCoordinatorParameters(session: matrixSession, group: group)
let coordinator = GroupDetailsCoordinator(parameters: coordinatorParameters)
coordinator.start()
self.add(childCoordinator: coordinator)
self.replaceSplitViewDetails(with: coordinator) {
[weak self] in
self.showSplitViewDetails(with: coordinator, stackedOnSplitViewDetail: presentationParameters.stackAboveVisibleViews) { [weak self] in
self?.remove(childCoordinator: coordinator)
}
}
private func showRoom(with roomId: String) {
private func showRoom(withId roomId: String) {
guard let matrixSession = self.parameters.userSessionsService.mainUserSession?.matrixSession else {
return
@ -374,6 +373,18 @@ final class TabBarCoordinator: NSObject, TabBarCoordinatorType {
self.showRoom(with: roomId, eventId: nil, matrixSession: matrixSession)
}
private func showRoom(withNavigationParameters roomNavigationParameters: RoomNavigationParameters, completion: (() -> Void)?) {
let roomCoordinatorParameters = RoomCoordinatorParameters(navigationRouterStore: NavigationRouterStore.shared,
session: roomNavigationParameters.mxSession,
roomId: roomNavigationParameters.roomId,
eventId: roomNavigationParameters.eventId)
self.showRoom(with: roomCoordinatorParameters,
stackOnSplitViewDetail: roomNavigationParameters.presentationParameters.stackAboveVisibleViews,
completion: completion)
}
private func showRoom(with roomId: String, eventId: String?, matrixSession: MXSession, completion: (() -> Void)? = nil) {
// RoomCoordinator will be presented by the split view.
@ -394,7 +405,19 @@ final class TabBarCoordinator: NSObject, TabBarCoordinatorType {
self.showRoom(with: roomCoordinatorParameters)
}
private func showRoom(with parameters: RoomCoordinatorParameters, completion: (() -> Void)? = nil) {
private func showRoomPreview(withNavigationParameters roomPreviewNavigationParameters: RoomPreviewNavigationParameters, completion: (() -> Void)?) {
let roomCoordinatorParameters = RoomCoordinatorParameters(navigationRouterStore: NavigationRouterStore.shared,
previewData: roomPreviewNavigationParameters.previewData)
self.showRoom(with: roomCoordinatorParameters,
stackOnSplitViewDetail: roomPreviewNavigationParameters.presentationParameters.stackAboveVisibleViews,
completion: completion)
}
private func showRoom(with parameters: RoomCoordinatorParameters,
stackOnSplitViewDetail: Bool = false,
completion: (() -> Void)? = nil) {
if let topRoomCoordinator = self.splitViewMasterPresentableDelegate?.detailModules.last as? RoomCoordinatorProtocol,
parameters.roomId == topRoomCoordinator.roomId && parameters.session == topRoomCoordinator.mxSession {
@ -415,19 +438,38 @@ final class TabBarCoordinator: NSObject, TabBarCoordinatorType {
coordinator.delegate = self
coordinator.start(withCompletion: completion)
self.add(childCoordinator: coordinator)
self.replaceSplitViewDetails(with: coordinator) {
[weak self] in
self.showSplitViewDetails(with: coordinator, stackedOnSplitViewDetail: stackOnSplitViewDetail) { [weak self] in
// NOTE: The RoomDataSource releasing is handled in SplitViewCoordinator
self?.remove(childCoordinator: coordinator)
}
}
// MARK: Split view
/// If the split view is collapsed (one column visible) it will push the Presentable on the primary navigation controller, otherwise it will show the Presentable as the secondary view of the split view.
private func replaceSplitViewDetails(with presentable: Presentable, popCompletion: (() -> Void)? = nil) {
self.splitViewMasterPresentableDelegate?.splitViewMasterPresentable(self, wantsToReplaceDetailWith: presentable, popCompletion: popCompletion)
}
/// If the split view is collapsed (one column visible) it will push the Presentable on the primary navigation controller, otherwise it will show the Presentable as the secondary view of the split view on top of existing views.
private func stackSplitViewDetails(with presentable: Presentable, popCompletion: (() -> Void)? = nil) {
self.splitViewMasterPresentableDelegate?.splitViewMasterPresentable(self, wantsToStack: presentable, popCompletion: popCompletion)
}
private func showSplitViewDetails(with presentable: Presentable, stackedOnSplitViewDetail: Bool, popCompletion: (() -> Void)? = nil) {
if stackedOnSplitViewDetail {
self.stackSplitViewDetails(with: presentable, popCompletion: popCompletion)
} else {
self.replaceSplitViewDetails(with: presentable, popCompletion: popCompletion)
}
}
private func resetSplitViewDetails() {
self.splitViewMasterPresentableDelegate?.splitViewMasterPresentableWantsToResetDetail(self)
}
// MARK: UserSessions management
private func registerUserSessionsServiceNotifications() {
@ -485,13 +527,17 @@ final class TabBarCoordinator: NSObject, TabBarCoordinatorType {
// MARK: - MasterTabBarControllerDelegate
extension TabBarCoordinator: MasterTabBarControllerDelegate {
func masterTabBarController(_ masterTabBarController: MasterTabBarController!, didSelectRoomPreviewWith roomPreviewData: RoomPreviewData!) {
self.showRoomPreview(with: roomPreviewData)
func masterTabBarController(_ masterTabBarController: MasterTabBarController!, didSelectRoomWith roomNavigationParameters: RoomNavigationParameters!, completion: (() -> Void)!) {
self.showRoom(withNavigationParameters: roomNavigationParameters, completion: completion)
}
func masterTabBarController(_ masterTabBarController: MasterTabBarController!, didSelect contact: MXKContact!) {
self.showContactDetails(with: contact)
func masterTabBarController(_ masterTabBarController: MasterTabBarController!, didSelectRoomPreviewWith roomPreviewScreenParameters: RoomPreviewNavigationParameters!, completion: (() -> Void)!) {
self.showRoomPreview(withNavigationParameters: roomPreviewScreenParameters, completion: completion)
}
func masterTabBarController(_ masterTabBarController: MasterTabBarController!, didSelect contact: MXKContact!, with presentationParameters: ScreenPresentationParameters!) {
self.showContactDetails(with: contact, presentationParameters: presentationParameters)
}
func masterTabBarControllerDidCompleteAuthentication(_ masterTabBarController: MasterTabBarController!) {
@ -502,8 +548,8 @@ extension TabBarCoordinator: MasterTabBarControllerDelegate {
self.showRoom(with: roomId, eventId: eventId, matrixSession: matrixSession, completion: completion)
}
func masterTabBarController(_ masterTabBarController: MasterTabBarController!, didSelect group: MXGroup!, inMatrixSession matrixSession: MXSession!) {
self.showGroupDetails(with: group, for: matrixSession)
func masterTabBarController(_ masterTabBarController: MasterTabBarController!, didSelect group: MXGroup!, inMatrixSession matrixSession: MXSession!, presentationParameters: ScreenPresentationParameters!) {
self.showGroupDetails(with: group, for: matrixSession, presentationParameters: presentationParameters)
}
func masterTabBarController(_ masterTabBarController: MasterTabBarController!, needsSideMenuIconWithNotification displayNotification: Bool) {
@ -525,7 +571,8 @@ extension TabBarCoordinator: RoomCoordinatorDelegate {
}
func roomCoordinatorDidLeaveRoom(_ coordinator: RoomCoordinatorProtocol) {
self.navigationRouter.popModule(animated: true)
// For the moment when a room is left, reset the split detail with placeholder
self.resetSplitViewDetails()
}
func roomCoordinatorDidCancelRoomPreview(_ coordinator: RoomCoordinatorProtocol) {
@ -533,7 +580,7 @@ extension TabBarCoordinator: RoomCoordinatorDelegate {
}
func roomCoordinator(_ coordinator: RoomCoordinatorProtocol, didSelectRoomWithId roomId: String) {
self.showRoom(with: roomId)
self.showRoom(withId: roomId)
}
}

1
changelog.d/4834.change Normal file
View file

@ -0,0 +1 @@
Navigation: Enable room stacking.