element-ios/Riot/Modules/Room/Settings/RoomSettingsViewController.m
2023-01-16 14:58:18 +01:00

3658 lines
148 KiB
Objective-C

/*
Copyright 2016 OpenMarket Ltd
Copyright 2017 Vector Creations 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 "RoomSettingsViewController.h"
#import "TableViewCellWithLabelAndLargeTextView.h"
#import "TableViewCellWithCheckBoxAndLabel.h"
#import "SegmentedViewController.h"
#import "AvatarGenerator.h"
#import "Tools.h"
#import "MXRoom+Riot.h"
#import "MXRoomSummary+Riot.h"
#import "GeneratedInterface-Swift.h"
#import "RoomMemberDetailsViewController.h"
#import <MobileCoreServices/MobileCoreServices.h>
enum
{
SECTION_TAG_MAIN,
SECTION_TAG_ACCESS,
SECTION_TAG_PROMOTION,
SECTION_TAG_HISTORY,
SECTION_TAG_ADDRESSES,
SECTION_TAG_BANNED_USERS,
SECTION_TAG_BANNED_ADVANCED
};
enum
{
ROOM_SETTINGS_MAIN_SECTION_ROW_PHOTO,
ROOM_SETTINGS_MAIN_SECTION_ROW_NAME,
ROOM_SETTINGS_MAIN_SECTION_ROW_TOPIC,
ROOM_SETTINGS_MAIN_SECTION_ROW_TAG,
ROOM_SETTINGS_MAIN_SECTION_ROW_DIRECT_CHAT,
ROOM_SETTINGS_MAIN_SECTION_ROW_MUTE_NOTIFICATIONS
};
enum
{
ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_ACCESS,
ROOM_SETTINGS_ROOM_ACCESS_DIRECTORY_VISIBILITY,
ROOM_SETTINGS_ROOM_ACCESS_MISSING_ADDRESS_WARNING
};
enum
{
ROOM_SETTINGS_ROOM_PROMOTE_SECTION_ROW_SUGGEST
};
enum
{
ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_ANYONE,
ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_MEMBERS_ONLY,
ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_MEMBERS_ONLY_SINCE_INVITED,
ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_MEMBERS_ONLY_SINCE_JOINED
};
enum
{
ROOM_SETTINGS_ADVANCED_ROOM_ID,
ROOM_SETTINGS_ADVANCED_ENCRYPT_TO_VERIFIED,
ROOM_SETTINGS_ADVANCED_ENCRYPTION_ENABLED,
ROOM_SETTINGS_ADVANCED_ENABLE_ENCRYPTION,
ROOM_SETTINGS_ADVANCED_ENCRYPTION_DISABLED
};
enum
{
ROOM_SETTINGS_ROOM_ADDRESS_NEW_ALIAS,
ROOM_SETTINGS_ROOM_ADDRESS_NO_LOCAL_ADDRESS,
ROOM_SETTINGS_ROOM_ADDRESS_ALIAS_OFFSET = 1000
};
#define ROOM_TOPIC_CELL_HEIGHT 124
NSString *const kRoomSettingsAvatarKey = @"kRoomSettingsAvatarKey";
NSString *const kRoomSettingsAvatarURLKey = @"kRoomSettingsAvatarURLKey";
NSString *const kRoomSettingsNameKey = @"kRoomSettingsNameKey";
NSString *const kRoomSettingsTopicKey = @"kRoomSettingsTopicKey";
NSString *const kRoomSettingsTagKey = @"kRoomSettingsTagKey";
NSString *const kRoomSettingsMuteNotifKey = @"kRoomSettingsMuteNotifKey";
NSString *const kRoomSettingsDirectChatKey = @"kRoomSettingsDirectChatKey";
NSString *const kRoomSettingsJoinRuleKey = @"kRoomSettingsJoinRuleKey";
NSString *const kRoomSettingsGuestAccessKey = @"kRoomSettingsGuestAccessKey";
NSString *const kRoomSettingsDirectoryKey = @"kRoomSettingsDirectoryKey";
NSString *const kRoomSettingsHistoryVisibilityKey = @"kRoomSettingsHistoryVisibilityKey";
NSString *const kRoomSettingsNewAliasesKey = @"kRoomSettingsNewAliasesKey";
NSString *const kRoomSettingsRemovedAliasesKey = @"kRoomSettingsRemovedAliasesKey";
NSString *const kRoomSettingsCanonicalAliasKey = @"kRoomSettingsCanonicalAliasKey";
NSString *const kRoomSettingsEncryptionKey = @"kRoomSettingsEncryptionKey";
NSString *const kRoomSettingsEncryptionBlacklistUnverifiedDevicesKey = @"kRoomSettingsEncryptionBlacklistUnverifiedDevicesKey";
NSString *const kRoomSettingsNameCellViewIdentifier = @"kRoomSettingsNameCellViewIdentifier";
NSString *const kRoomSettingsTopicCellViewIdentifier = @"kRoomSettingsTopicCellViewIdentifier";
NSString *const kRoomSettingsWarningCellViewIdentifier = @"kRoomSettingsWarningCellViewIdentifier";
NSString *const kRoomSettingsNewAddressCellViewIdentifier = @"kRoomSettingsNewAddressCellViewIdentifier";
NSString *const kRoomSettingsAddressCellViewIdentifier = @"kRoomSettingsAddressCellViewIdentifier";
NSString *const kRoomSettingsAdvancedCellViewIdentifier = @"kRoomSettingsAdvancedCellViewIdentifier";
NSString *const kRoomSettingsAdvancedEnableE2eCellViewIdentifier = @"kRoomSettingsAdvancedEnableE2eCellViewIdentifier";
NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSettingsAdvancedE2eEnabledCellViewIdentifier";
@interface RoomSettingsViewController () <SingleImagePickerPresenterDelegate, TableViewSectionsDelegate, RoomAccessCoordinatorBridgePresenterDelegate, RoomSuggestionCoordinatorBridgePresenterDelegate>
{
// The updated user data
NSMutableDictionary<NSString*, id> *updatedItemsDict;
// The current table items
UITextField* nameTextField;
UITextView* topicTextView;
// The room tag items
TableViewCellWithCheckBoxes *roomTagCell;
// Room Access items
UISwitch *directoryVisibilitySwitch;
MXRoomDirectoryVisibility actualDirectoryVisibility;
MXHTTPOperation* actualDirectoryVisibilityRequest;
// History Visibility items
NSMutableDictionary<MXRoomHistoryVisibility, TableViewCellWithCheckBoxAndLabel*> *historyVisibilityTickCells;
// Room aliases
NSMutableArray<NSString *> *roomAddresses;
NSUInteger localAddressesCount;
UITextField* addAddressTextField;
// The potential image loader
MXMediaLoader *uploader;
// The pending http operation
MXHTTPOperation* pendingOperation;
UIAlertController *currentAlert;
// listen to more events than the mother class
id extraEventsListener;
// Observe kAppDelegateDidTapStatusBarNotification to handle tap on clock status bar.
id appDelegateDidTapStatusBarNotificationObserver;
// A copy of the banned members
NSArray<MXRoomMember*> *bannedMembers;
// Observe kThemeServiceDidChangeThemeNotification to handle user interface theme change.
id kThemeServiceDidChangeThemeNotificationObserver;
RoomAccessCoordinatorBridgePresenter *roomAccessPresenter;
RoomSuggestionCoordinatorBridgePresenter *roomSuggestionPresenter;
}
@property (nonatomic, strong) SingleImagePickerPresenter *imagePickerPresenter;
@property (nonatomic, strong) TableViewSections *tableViewSections;
@end
@implementation RoomSettingsViewController
- (void)finalizeInit
{
[super finalizeInit];
_selectedRoomSettingsField = RoomSettingsViewControllerFieldNone;
// Setup `MXKViewControllerHandling` properties
self.enableBarTintColorStatusChange = NO;
self.rageShakeManager = [RageShakeManager sharedManager];
}
- (void)initWithSession:(MXSession *)session andRoomId:(NSString *)roomId
{
[super initWithSession:session andRoomId:roomId];
// Add an additional listener to update banned users
self->extraEventsListener = [mxRoom listenToEventsOfTypes:@[kMXEventTypeStringRoomMember] onEvent:^(MXEvent *event, MXTimelineDirection direction, MXRoomState *roomState) {
if (direction == MXTimelineDirectionForwards)
{
[self updateRoomState:roomState];
}
}];
}
- (void)updateRoomState:(MXRoomState *)newRoomState
{
[super updateRoomState:newRoomState];
bannedMembers = [mxRoomState.members membersWithMembership:MXMembershipBan];
}
- (UINavigationItem*)getNavigationItem
{
// Check whether the view controller is currently displayed inside a segmented view controller or not.
UIViewController* topViewController = ((self.parentViewController) ? self.parentViewController : self);
return topViewController.navigationItem;
}
- (void)setNavBarButtons
{
[self getNavigationItem].rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(onSave:)];
[self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0);
[self getNavigationItem].leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(onCancel:)];
}
- (void)viewDidLoad
{
[super viewDidLoad];
updatedItemsDict = [[NSMutableDictionary alloc] init];
historyVisibilityTickCells = [[NSMutableDictionary alloc] initWithCapacity:4];
roomAddresses = [NSMutableArray array];
[self.tableView registerClass:MXKTableViewCellWithLabelAndSwitch.class forCellReuseIdentifier:[MXKTableViewCellWithLabelAndSwitch defaultReuseIdentifier]];
[self.tableView registerClass:MXKTableViewCellWithLabelAndMXKImageView.class forCellReuseIdentifier:[MXKTableViewCellWithLabelAndMXKImageView defaultReuseIdentifier]];
// Use a specific cell identifier for the room name, the topic and the address in order to be able to keep reference
// on the text input field without being disturbed by the cell dequeuing process.
[self.tableView registerClass:MXKTableViewCellWithLabelAndTextField.class forCellReuseIdentifier:kRoomSettingsNameCellViewIdentifier];
[self.tableView registerClass:TableViewCellWithLabelAndLargeTextView.class forCellReuseIdentifier:kRoomSettingsTopicCellViewIdentifier];
[self.tableView registerClass:MXKTableViewCellWithLabelAndTextField.class forCellReuseIdentifier:kRoomSettingsNewAddressCellViewIdentifier];
[self.tableView registerClass:UITableViewCell.class forCellReuseIdentifier:kRoomSettingsAddressCellViewIdentifier];
[self.tableView registerClass:UITableViewCell.class forCellReuseIdentifier:kRoomSettingsWarningCellViewIdentifier];
[self.tableView registerClass:MXKTableViewCellWithButton.class forCellReuseIdentifier:[MXKTableViewCellWithButton defaultReuseIdentifier]];
[self.tableView registerClass:TableViewCellWithCheckBoxes.class forCellReuseIdentifier:[TableViewCellWithCheckBoxes defaultReuseIdentifier]];
[self.tableView registerClass:TableViewCellWithCheckBoxAndLabel.class forCellReuseIdentifier:[TableViewCellWithCheckBoxAndLabel defaultReuseIdentifier]];
[self.tableView registerClass:MXKTableViewCell.class forCellReuseIdentifier:[MXKTableViewCell defaultReuseIdentifier]];
[self.tableView registerClass:TitleAndRightDetailTableViewCell.class forCellReuseIdentifier:[TitleAndRightDetailTableViewCell defaultReuseIdentifier]];
// Enable self sizing cells
self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 44;
[self setNavBarButtons];
// Observe user interface theme change.
kThemeServiceDidChangeThemeNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kThemeServiceDidChangeThemeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
[self userInterfaceThemeDidChange];
}];
[self userInterfaceThemeDidChange];
_tableViewSections = [TableViewSections new];
_tableViewSections.delegate = self;
[self updateSections];
}
- (void)userInterfaceThemeDidChange
{
[ThemeService.shared.theme applyStyleOnNavigationBar:self.navigationController.navigationBar];
self.activityIndicator.backgroundColor = ThemeService.shared.theme.overlayBackgroundColor;
// Check the table view style to select its bg color.
self.tableView.backgroundColor = ((self.tableView.style == UITableViewStylePlain) ? ThemeService.shared.theme.backgroundColor : ThemeService.shared.theme.headerBackgroundColor);
self.view.backgroundColor = self.tableView.backgroundColor;
self.tableView.separatorColor = ThemeService.shared.theme.lineBreakColor;
if (self.tableView.dataSource)
{
[self.tableView reloadData];
}
[self setNeedsStatusBarAppearanceUpdate];
}
- (UIStatusBarStyle)preferredStatusBarStyle
{
return ThemeService.shared.theme.statusBarStyle;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.screenTracker trackScreen];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didUpdateRules:) name:kMXNotificationCenterDidUpdateRules object:nil];
// Observe appDelegateDidTapStatusBarNotificationObserver.
appDelegateDidTapStatusBarNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kAppDelegateDidTapStatusBarNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
[self.tableView setContentOffset:CGPointMake(-self.tableView.adjustedContentInset.left, -self.tableView.adjustedContentInset.top) animated:YES];
}];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// Edit the selected field if any
if (_selectedRoomSettingsField != RoomSettingsViewControllerFieldNone)
{
self.selectedRoomSettingsField = _selectedRoomSettingsField;
}
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self dismissFirstResponder];
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMXNotificationCenterDidUpdateRules object:nil];
if (appDelegateDidTapStatusBarNotificationObserver)
{
[[NSNotificationCenter defaultCenter] removeObserver:appDelegateDidTapStatusBarNotificationObserver];
appDelegateDidTapStatusBarNotificationObserver = nil;
}
}
// Those methods are called when the viewcontroller is added or removed from a container view controller.
- (void)willMoveToParentViewController:(nullable UIViewController *)parent
{
// Check whether the view is removed from its parent.
if (!parent)
{
[self dismissFirstResponder];
// Prompt user to save changes (if any).
if (updatedItemsDict.count)
{
[self promptUserToSaveChanges];
}
}
[super willMoveToParentViewController:parent];
}
- (void)didMoveToParentViewController:(nullable UIViewController *)parent
{
[super didMoveToParentViewController:parent];
[self setNavBarButtons];
}
- (void)destroy
{
self.navigationItem.rightBarButtonItem.enabled = NO;
if (currentAlert)
{
[currentAlert dismissViewControllerAnimated:NO completion:nil];
currentAlert = nil;
}
if (uploader)
{
[uploader cancel];
uploader = nil;
}
if (pendingOperation)
{
[pendingOperation cancel];
pendingOperation = nil;
}
if (actualDirectoryVisibilityRequest)
{
[actualDirectoryVisibilityRequest cancel];
actualDirectoryVisibilityRequest = nil;
}
if (kThemeServiceDidChangeThemeNotificationObserver)
{
[[NSNotificationCenter defaultCenter] removeObserver:kThemeServiceDidChangeThemeNotificationObserver];
kThemeServiceDidChangeThemeNotificationObserver = nil;
}
if (appDelegateDidTapStatusBarNotificationObserver)
{
[[NSNotificationCenter defaultCenter] removeObserver:appDelegateDidTapStatusBarNotificationObserver];
appDelegateDidTapStatusBarNotificationObserver = nil;
}
updatedItemsDict = nil;
historyVisibilityTickCells = nil;
roomAddresses = nil;
if (extraEventsListener)
{
MXWeakify(self);
[mxRoom liveTimeline:^(id<MXEventTimeline> liveTimeline) {
MXStrongifyAndReturnIfNil(self);
[liveTimeline removeListener:self->extraEventsListener];
self->extraEventsListener = nil;
}];
}
[super destroy];
}
- (void)withdrawViewControllerAnimated:(BOOL)animated completion:(void (^)(void))completion
{
// Check whether the current view controller is displayed inside a segmented view controller in order to withdraw the right item
if (self.parentViewController && [self.parentViewController isKindOfClass:SegmentedViewController.class])
{
[((SegmentedViewController*)self.parentViewController) withdrawViewControllerAnimated:animated completion:completion];
}
else
{
[super withdrawViewControllerAnimated:animated completion:completion];
}
}
- (void)refreshRoomSettings
{
[self retrieveActualDirectoryVisibility];
// Check whether a text input is currently edited
BOOL isNameEdited = nameTextField ? nameTextField.isFirstResponder : NO;
BOOL isTopicEdited = topicTextView ? topicTextView.isFirstResponder : NO;
BOOL isAddressEdited = addAddressTextField ? addAddressTextField.isFirstResponder : NO;
// Trigger a full table reloadData
[self updateSections];
// Restore the previous edited field
if (isNameEdited)
{
[self editRoomName];
}
else if (isTopicEdited)
{
[self editRoomTopic];
}
else if (isAddressEdited)
{
[self editAddRoomAddress];
}
}
- (void)updateSections
{
// update local data
// Refresh here the room addresses list.
[roomAddresses removeAllObjects];
localAddressesCount = 0;
NSArray *removedAliases = updatedItemsDict[kRoomSettingsRemovedAliasesKey];
NSArray *aliases = mxRoomState.aliases;
if (aliases)
{
for (NSString *alias in aliases)
{
// Check whether the user did not remove it
if (!removedAliases || [removedAliases indexOfObject:alias] == NSNotFound)
{
// Add it
if ([alias hasSuffix:self.mainSession.matrixRestClient.homeserverSuffix])
{
[roomAddresses insertObject:alias atIndex:localAddressesCount];
localAddressesCount++;
}
else
{
[roomAddresses addObject:alias];
}
}
}
}
aliases = updatedItemsDict[kRoomSettingsNewAliasesKey];
for (NSString *alias in aliases)
{
// Add this new alias to local addresses
[roomAddresses insertObject:alias atIndex:localAddressesCount];
localAddressesCount++;
}
// create sections
NSMutableArray<Section*> *tmpSections = [NSMutableArray arrayWithCapacity:SECTION_TAG_BANNED_ADVANCED + 1];
Section *sectionMain = [Section sectionWithTag:SECTION_TAG_MAIN];
[sectionMain addRowWithTag:ROOM_SETTINGS_MAIN_SECTION_ROW_PHOTO];
[sectionMain addRowWithTag:ROOM_SETTINGS_MAIN_SECTION_ROW_NAME];
[sectionMain addRowWithTag:ROOM_SETTINGS_MAIN_SECTION_ROW_TOPIC];
[sectionMain addRowWithTag:ROOM_SETTINGS_MAIN_SECTION_ROW_TAG];
if (RiotSettings.shared.roomSettingsScreenShowDirectChatOption)
{
[sectionMain addRowWithTag:ROOM_SETTINGS_MAIN_SECTION_ROW_DIRECT_CHAT];
}
if (!BuildSettings.showNotificationsV2)
{
[sectionMain addRowWithTag:ROOM_SETTINGS_MAIN_SECTION_ROW_MUTE_NOTIFICATIONS];
}
[tmpSections addObject:sectionMain];
if (RiotSettings.shared.roomSettingsScreenAllowChangingAccessSettings)
{
Section *sectionAccess = [Section sectionWithTag:SECTION_TAG_ACCESS];
[sectionAccess addRowWithTag:ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_ACCESS];
// Check whether a room address is required for the current join rule
NSString *joinRule = updatedItemsDict[kRoomSettingsJoinRuleKey];
if (!joinRule)
{
// Use the actual values if no change is pending.
joinRule = mxRoomState.joinRule;
}
if ([joinRule isEqualToString:kMXRoomJoinRulePublic] && !roomAddresses.count)
{
// Notify the user that a room address is required.
[sectionAccess addRowWithTag:ROOM_SETTINGS_ROOM_ACCESS_MISSING_ADDRESS_WARNING];
}
if (mxRoom.isDirect)
{
sectionAccess.headerTitle = [VectorL10n roomDetailsAccessSectionForDm];
}
else
{
sectionAccess.headerTitle = [VectorL10n roomDetailsAccessSection];
}
[tmpSections addObject:sectionAccess];
if (RiotSettings.shared.roomSettingsScreenAllowChangingAccessSettings)
{
Section *promotionAccess = [Section sectionWithTag:SECTION_TAG_PROMOTION];
promotionAccess.headerTitle = VectorL10n.roomDetailsPromoteRoomTitle;
[promotionAccess addRowWithTag:ROOM_SETTINGS_ROOM_ACCESS_DIRECTORY_VISIBILITY];
[promotionAccess addRowWithTag:ROOM_SETTINGS_ROOM_PROMOTE_SECTION_ROW_SUGGEST];
[tmpSections addObject:promotionAccess];
}
}
if (RiotSettings.shared.roomSettingsScreenAllowChangingHistorySettings)
{
Section *sectionHistory = [Section sectionWithTag:SECTION_TAG_HISTORY];
[sectionHistory addRowWithTag:ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_ANYONE];
[sectionHistory addRowWithTag:ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_MEMBERS_ONLY];
[sectionHistory addRowWithTag:ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_MEMBERS_ONLY_SINCE_INVITED];
[sectionHistory addRowWithTag:ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_MEMBERS_ONLY_SINCE_JOINED];
sectionHistory.headerTitle = [VectorL10n roomDetailsHistorySection];
[tmpSections addObject:sectionHistory];
}
if (RiotSettings.shared.roomSettingsScreenShowAddressSettings)
{
Section *sectionAddresses = [Section sectionWithTag:SECTION_TAG_ADDRESSES];
if (localAddressesCount)
{
for (NSInteger counter = 0; counter < roomAddresses.count; counter++)
{
[sectionAddresses addRowWithTag:ROOM_SETTINGS_ROOM_ADDRESS_ALIAS_OFFSET + counter];
}
}
else
{
[sectionAddresses addRowWithTag:ROOM_SETTINGS_ROOM_ADDRESS_NO_LOCAL_ADDRESS];
}
[sectionAddresses addRowWithTag:ROOM_SETTINGS_ROOM_ADDRESS_NEW_ALIAS];
sectionAddresses.headerTitle = [VectorL10n roomDetailsAddressesSection];
[tmpSections addObject:sectionAddresses];
}
if (bannedMembers.count)
{
Section *sectionBannedUsers = [Section sectionWithTag:SECTION_TAG_BANNED_USERS];
for (NSInteger counter = 0; counter < bannedMembers.count; counter++)
{
[sectionBannedUsers addRowWithTag:counter];
}
sectionBannedUsers.headerTitle = [VectorL10n roomDetailsBannedUsersSection];
[tmpSections addObject:sectionBannedUsers];
}
if (RiotSettings.shared.roomSettingsScreenShowAdvancedSettings)
{
Section *sectionAdvanced = [Section sectionWithTag:SECTION_TAG_BANNED_ADVANCED];
[sectionAdvanced addRowWithTag:ROOM_SETTINGS_ADVANCED_ROOM_ID];
if (mxRoom.mxSession.crypto)
{
if (mxRoom.summary.isEncrypted)
{
if (RiotSettings.shared.roomSettingsScreenAdvancedShowEncryptToVerifiedOption)
{
[sectionAdvanced addRowWithTag:ROOM_SETTINGS_ADVANCED_ENCRYPT_TO_VERIFIED];
}
[sectionAdvanced addRowWithTag:ROOM_SETTINGS_ADVANCED_ENCRYPTION_ENABLED];
}
else
{
// Check user's power level to know whether the user is allowed to turn on the encryption mode
MXRoomPowerLevels *powerLevels = [mxRoomState powerLevels];
NSInteger oneSelfPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mainSession.myUser.userId];
if (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomEncryption])
{
[sectionAdvanced addRowWithTag:ROOM_SETTINGS_ADVANCED_ENABLE_ENCRYPTION];
}
else
{
[sectionAdvanced addRowWithTag:ROOM_SETTINGS_ADVANCED_ENCRYPTION_DISABLED];
}
}
}
sectionAdvanced.headerTitle = [VectorL10n roomDetailsAdvancedSection];
[tmpSections addObject:sectionAdvanced];
}
// update sections
self.tableViewSections.sections = tmpSections;
}
#pragma mark -
- (void)setSelectedRoomSettingsField:(RoomSettingsViewControllerField)selectedRoomSettingsField
{
// Check whether the view controller is already embedded inside a navigation controller
if (self.navigationController)
{
[self dismissFirstResponder];
// Check whether user allowed to change room info
NSDictionary *eventTypes = @{
@(RoomSettingsViewControllerFieldName): kMXEventTypeStringRoomName,
@(RoomSettingsViewControllerFieldTopic): kMXEventTypeStringRoomTopic,
@(RoomSettingsViewControllerFieldAvatar): kMXEventTypeStringRoomAvatar
};
NSString *eventTypeForSelectedField = eventTypes[@(selectedRoomSettingsField)];
if (!eventTypeForSelectedField)
return;
MXRoomPowerLevels *powerLevels = [mxRoomState powerLevels];
NSInteger oneSelfPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mainSession.myUser.userId];
if (oneSelfPowerLevel < [powerLevels minimumPowerLevelForSendingEventAsStateEvent:eventTypeForSelectedField])
return;
switch (selectedRoomSettingsField)
{
case RoomSettingsViewControllerFieldName:
{
[self editRoomName];
break;
}
case RoomSettingsViewControllerFieldTopic:
{
[self editRoomTopic];
break;
}
case RoomSettingsViewControllerFieldAvatar:
{
[self onRoomAvatarTap:nil];
break;
}
default:
break;
}
}
else
{
// This selection will be applied when the view controller will become active (see 'viewDidAppear')
_selectedRoomSettingsField = selectedRoomSettingsField;
}
}
#pragma mark - private
- (void)editRoomName
{
if (![nameTextField becomeFirstResponder])
{
// Retry asynchronously
dispatch_async(dispatch_get_main_queue(), ^{
[self editRoomName];
});
}
}
- (void)editRoomTopic
{
if (![topicTextView becomeFirstResponder])
{
// Retry asynchronously
dispatch_async(dispatch_get_main_queue(), ^{
[self editRoomTopic];
});
}
}
- (void)editAddRoomAddress
{
if (![addAddressTextField becomeFirstResponder])
{
// Retry asynchronously
dispatch_async(dispatch_get_main_queue(), ^{
[self editAddRoomAddress];
});
}
}
- (void)dismissFirstResponder
{
if ([topicTextView isFirstResponder])
{
[topicTextView resignFirstResponder];
}
if ([nameTextField isFirstResponder])
{
[nameTextField resignFirstResponder];
}
if ([addAddressTextField isFirstResponder])
{
[addAddressTextField resignFirstResponder];
}
_selectedRoomSettingsField = RoomSettingsViewControllerFieldNone;
}
- (void)startActivityIndicator
{
// Lock user interaction
self.tableView.userInteractionEnabled = NO;
// Check whether the current view controller is displayed inside a segmented view controller in order to run the right activity view
if (self.parentViewController && [self.parentViewController isKindOfClass:SegmentedViewController.class])
{
[((SegmentedViewController*)self.parentViewController) startActivityIndicator];
// Force stop the activity view of the view controller
[self.activityIndicator stopAnimating];
}
else
{
[super startActivityIndicator];
}
}
- (void)stopActivityIndicator
{
// Check local conditions before stop the activity indicator
if (!pendingOperation && !uploader)
{
// Unlock user interaction
self.tableView.userInteractionEnabled = YES;
// Check whether the current view controller is displayed inside a segmented view controller in order to stop the right activity view
if (self.parentViewController && [self.parentViewController isKindOfClass:SegmentedViewController.class])
{
[((SegmentedViewController*)self.parentViewController) stopActivityIndicator];
// Force stop the activity view of the view controller
[self.activityIndicator stopAnimating];
}
else
{
[super stopActivityIndicator];
}
}
}
- (void)promptUserToSaveChanges
{
// ensure that the user understands that the updates will be lost if
[currentAlert dismissViewControllerAnimated:NO completion:nil];
__weak typeof(self) weakSelf = self;
currentAlert = [UIAlertController alertControllerWithTitle:nil
message:[VectorL10n roomDetailsSaveChangesPrompt]
preferredStyle:UIAlertControllerStyleAlert];
[currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n no]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->currentAlert = nil;
[self->updatedItemsDict removeAllObjects];
if (self.delegate)
{
[self.delegate roomSettingsViewControllerDidCancel:self];
}
else
{
[self withdrawViewControllerAnimated:YES completion:nil];
}
}
}]];
[currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n yes]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->currentAlert = nil;
[self onSave:nil];
}
}]];
[currentAlert mxk_setAccessibilityIdentifier:@"RoomSettingsVCSaveChangesAlert"];
[self presentViewController:currentAlert animated:YES completion:nil];
}
- (void)promptUserToCopyRoomId:(UILabel*)roomIdLabel
{
if (roomIdLabel)
{
[currentAlert dismissViewControllerAnimated:NO completion:nil];
__weak typeof(self) weakSelf = self;
currentAlert = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
[currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n roomDetailsCopyRoomId]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->currentAlert = nil;
NSString *roomdId = roomIdLabel.text;
if (roomdId)
{
MXKPasteboardManager.shared.pasteboard.string = roomdId;
}
else
{
MXLogDebug(@"[RoomSettingsViewController] Copy room id failed. Room id is nil");
}
}
}]];
[currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n cancel]
style:UIAlertActionStyleCancel
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->currentAlert = nil;
}
}]];
[currentAlert mxk_setAccessibilityIdentifier:@"RoomSettingsVCCopyRoomIdAlert"];
[currentAlert popoverPresentationController].sourceView = roomIdLabel;
[currentAlert popoverPresentationController].sourceRect = roomIdLabel.bounds;
[self presentViewController:currentAlert animated:YES completion:nil];
}
}
- (void)promptUserOnSelectedRoomAlias:(UILabel*)roomAliasLabel
{
if (roomAliasLabel)
{
[currentAlert dismissViewControllerAnimated:NO completion:nil];
__weak typeof(self) weakSelf = self;
currentAlert = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
// Check whether the user is allowed to modify the main address.
if ([self canSetCanonicalAlias])
{
// Compare the selected alias with the current main address
NSString *currentCanonicalAlias = mxRoomState.canonicalAlias;
NSString *canonicalAlias;
if (updatedItemsDict[kRoomSettingsCanonicalAliasKey])
{
canonicalAlias = updatedItemsDict[kRoomSettingsCanonicalAliasKey];
}
else
{
canonicalAlias = currentCanonicalAlias;
}
if (canonicalAlias && [roomAliasLabel.text isEqualToString:canonicalAlias])
{
[currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n roomDetailsUnsetMainAddress]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->currentAlert = nil;
// Prompt user before removing the current main address (use dispatch_async here to not be stuck by the table refresh).
dispatch_async(dispatch_get_main_queue(), ^{
[self shouldRemoveCanonicalAlias:nil];
});
}
}]];
}
else
{
// Invite user to define this alias as the main room address
[currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n roomDetailsSetMainAddress]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->currentAlert = nil;
[self setRoomAliasAsMainAddress:roomAliasLabel.text];
}
}]];
}
}
[currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n roomDetailsCopyRoomAddress]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->currentAlert = nil;
NSString *roomAlias = roomAliasLabel.text;
if (roomAlias)
{
MXKPasteboardManager.shared.pasteboard.string = roomAlias;
}
else
{
MXLogDebug(@"[RoomSettingsViewController] Copy room address failed. Room address is nil");
}
}
}]];
[currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n roomDetailsCopyRoomUrl]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->currentAlert = nil;
// Create a matrix.to permalink to the room
NSString *permalink = [MXTools permalinkToRoom:roomAliasLabel.text];
NSURL *url = [NSURL URLWithString:permalink];
if (url)
{
MXKPasteboardManager.shared.pasteboard.URL = url;
[self.view vc_toastWithMessage:VectorL10n.roomEventCopyLinkInfo
image:AssetImages.linkIcon.image
duration:2.0
position:ToastPositionBottom
additionalMargin:0.0];
}
else
{
MXLogDebug(@"[RoomSettingsViewController] Copy room URL failed. Room URL is nil");
}
}
}]];
// The user can only delete alias they has created, even if the Admin has set it as canonical.
// So, let the server answer if it's possible to delete an alias.
[currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n delete]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->currentAlert = nil;
[self removeRoomAlias:roomAliasLabel.text];
}
}]];
[currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n cancel]
style:UIAlertActionStyleCancel
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->currentAlert = nil;
}
}]];
[currentAlert mxk_setAccessibilityIdentifier:@"RoomSettingsVCOnSelectedAliasAlert"];
[currentAlert popoverPresentationController].sourceView = roomAliasLabel;
[currentAlert popoverPresentationController].sourceRect = roomAliasLabel.bounds;
[self presentViewController:currentAlert animated:YES completion:nil];
}
}
- (void)retrieveActualDirectoryVisibility
{
if (!mxRoom || actualDirectoryVisibilityRequest)
{
return;
}
// Trigger a new request to check the actual directory visibility
__weak typeof(self) weakSelf = self;
actualDirectoryVisibilityRequest = [mxRoom directoryVisibility:^(MXRoomDirectoryVisibility directoryVisibility) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->actualDirectoryVisibilityRequest = nil;
self->actualDirectoryVisibility = directoryVisibility;
// Update the value of the displayed toggle button (if any)
if (self->directoryVisibilitySwitch)
{
// Check a potential user's change before the end of the request
MXRoomDirectoryVisibility modifiedDirectoryVisibility = self->updatedItemsDict[kRoomSettingsDirectoryKey];
if (modifiedDirectoryVisibility)
{
if ([modifiedDirectoryVisibility isEqualToString:directoryVisibility])
{
// The requested change corresponds to the actual settings
[self->updatedItemsDict removeObjectForKey:kRoomSettingsDirectoryKey];
[self getNavigationItem].rightBarButtonItem.enabled = (self->updatedItemsDict.count != 0);
}
}
self->directoryVisibilitySwitch.on = ([directoryVisibility isEqualToString:kMXRoomDirectoryVisibilityPublic]);
}
}
} failure:^(NSError *error) {
MXLogDebug(@"[RoomSettingsViewController] request to get directory visibility failed");
if (weakSelf)
{
typeof(self) self = weakSelf;
self->actualDirectoryVisibilityRequest = nil;
}
}];
}
#pragma mark - UITextViewDelegate
- (void)textViewDidBeginEditing:(UITextView *)textView;
{
if (topicTextView == textView)
{
UIView *contentView = topicTextView.superview;
if (contentView)
{
// refresh cell's layout
[contentView.superview setNeedsLayout];
}
}
}
- (void)textViewDidEndEditing:(UITextView *)textView
{
if (topicTextView == textView)
{
UIView *contentView = topicTextView.superview;
if (contentView)
{
// refresh cell's layout
[contentView.superview setNeedsLayout];
}
}
}
- (void)textViewDidChange:(UITextView *)textView
{
if (topicTextView == textView)
{
NSString* currentTopic = mxRoomState.topic;
// Remove white space from both ends
NSString* topic = [textView.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
// Check whether the topic has been actually changed
if ((topic || currentTopic) && ([topic isEqualToString:currentTopic] == NO))
{
updatedItemsDict[kRoomSettingsTopicKey] = topic ? topic : @"";
}
else
{
[updatedItemsDict removeObjectForKey:kRoomSettingsTopicKey];
}
[self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0);
}
}
#pragma mark - UITextFieldDelegate
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
if (textField == nameTextField)
{
nameTextField.textAlignment = NSTextAlignmentLeft;
}
else if (textField == addAddressTextField)
{
if (textField.text.length == 0)
{
textField.text = @"#";
}
}
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
if (textField == nameTextField)
{
nameTextField.textAlignment = NSTextAlignmentRight;
}
else if (textField == addAddressTextField)
{
if (textField.text.length < 2)
{
// reset text field
textField.text = nil;
}
else
{
// Check whether homeserver suffix should be added
NSRange range = [textField.text rangeOfString:@":"];
if (range.location == NSNotFound)
{
textField.text = [textField.text stringByAppendingString:self.mainSession.matrixRestClient.homeserverSuffix];
}
}
}
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
// Auto complete room alias
if (textField == addAddressTextField)
{
// Add # if none
if (!textField.text.length || textField.text.length == range.length)
{
if ([string hasPrefix:@"#"] == NO)
{
if ([string isEqualToString:@":"])
{
textField.text = [NSString stringWithFormat:@"#%@",self.mainSession.matrixRestClient.homeserverSuffix];
}
else
{
textField.text = [NSString stringWithFormat:@"#%@",string];
}
return NO;
}
}
else
{
// Remove default '#' if the string start with '#'
if ([string hasPrefix:@"#"] && [textField.text isEqualToString:@"#"])
{
textField.text = string;
return NO;
}
// Add homeserver automatically when user adds ':' at the end
else if (range.location == textField.text.length && [string isEqualToString:@":"])
{
textField.text = [textField.text stringByAppendingString:self.mainSession.matrixRestClient.homeserverSuffix];
return NO;
}
}
}
return YES;
}
- (BOOL)textFieldShouldClear:(UITextField *)textField
{
if (textField == addAddressTextField)
{
textField.text = @"#";
return NO;
}
return YES;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
if (textField == nameTextField)
{
// Dismiss the keyboard
[nameTextField resignFirstResponder];
}
else if (textField == addAddressTextField)
{
// Dismiss the keyboard
[addAddressTextField resignFirstResponder];
NSString *roomAlias = addAddressTextField.text;
if (!roomAlias.length || [self addRoomAlias:roomAlias])
{
// Reset the input field
addAddressTextField.text = nil;
}
}
return YES;
}
#pragma mark - actions
- (IBAction)onTextFieldUpdate:(UITextField*)textField
{
if (textField == nameTextField)
{
NSString *currentName = mxRoomState.name;
// Remove white space from both ends
NSString *displayName = [textField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
// Check whether the name has been actually changed
if ((displayName || currentName) && ([displayName isEqualToString:currentName] == NO))
{
updatedItemsDict[kRoomSettingsNameKey] = displayName ? displayName : @"";
}
else
{
[updatedItemsDict removeObjectForKey:kRoomSettingsNameKey];
}
[self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0);
}
}
- (void)didUpdateRules:(NSNotification *)notif
{
[self refreshRoomSettings];
}
- (IBAction)onCancel:(id)sender
{
[self dismissFirstResponder];
// Check whether some changes have been done
if (updatedItemsDict.count)
{
[self promptUserToSaveChanges];
}
else
{
if (self.delegate)
{
[self.delegate roomSettingsViewControllerDidCancel:self];
}
else
{
[self withdrawViewControllerAnimated:YES completion:nil];
}
}
}
- (void)onSaveFailed:(NSString*)message withKeys:(NSArray<NSString *>*)keys
{
__weak typeof(self) weakSelf = self;
[currentAlert dismissViewControllerAnimated:NO completion:nil];
currentAlert = [UIAlertController alertControllerWithTitle:nil message:message preferredStyle:UIAlertControllerStyleAlert];
[currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n cancel]
style:UIAlertActionStyleCancel
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->currentAlert = nil;
// Discard related change
for (NSString *key in keys)
{
[self->updatedItemsDict removeObjectForKey:key];
}
// Save anything else
[self onSave:nil];
}
}]];
[currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n retry]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->currentAlert = nil;
[self onSave:nil];
}
}]];
[currentAlert mxk_setAccessibilityIdentifier:@"RoomSettingsVCSaveChangesFailedAlert"];
[self presentViewController:currentAlert animated:YES completion:nil];
}
- (IBAction)onSave:(id)sender
{
if (updatedItemsDict.count)
{
[self startActivityIndicator];
__weak typeof(self) weakSelf = self;
// check if there is some updates related to room state
if (mxRoomState)
{
if (updatedItemsDict[kRoomSettingsAvatarKey])
{
// Retrieve the current picture and make sure its orientation is up
UIImage *updatedPicture = [MXKTools forceImageOrientationUp:updatedItemsDict[kRoomSettingsAvatarKey]];
// Upload picture
uploader = [MXMediaManager prepareUploaderWithMatrixSession:mxRoom.mxSession initialRange:0 andRange:1.0];
[uploader uploadData:UIImageJPEGRepresentation(updatedPicture, 0.5) filename:nil mimeType:@"image/jpeg" success:^(NSString *url) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->uploader = nil;
[self->updatedItemsDict removeObjectForKey:kRoomSettingsAvatarKey];
self->updatedItemsDict[kRoomSettingsAvatarURLKey] = url;
[self onSave:nil];
}
} failure:^(NSError *error) {
MXLogDebug(@"[RoomSettingsViewController] Image upload failed");
if (weakSelf)
{
typeof(self) self = weakSelf;
self->uploader = nil;
dispatch_async(dispatch_get_main_queue(), ^{
NSString* message = error.localizedDescription;
if (!message.length)
{
message = [VectorL10n roomDetailsFailToUpdateAvatar];
}
[self onSaveFailed:message withKeys:@[kRoomSettingsAvatarKey]];
});
}
}];
return;
}
NSString* photoUrl = updatedItemsDict[kRoomSettingsAvatarURLKey];
if (photoUrl)
{
pendingOperation = [mxRoom setAvatar:photoUrl success:^{
if (weakSelf)
{
typeof(self) self = weakSelf;
self->pendingOperation = nil;
[self->updatedItemsDict removeObjectForKey:kRoomSettingsAvatarURLKey];
[self onSave:nil];
}
} failure:^(NSError *error) {
MXLogDebug(@"[RoomSettingsViewController] Failed to update the room avatar");
if (weakSelf)
{
typeof(self) self = weakSelf;
self->pendingOperation = nil;
dispatch_async(dispatch_get_main_queue(), ^{
NSString* message = error.localizedDescription;
if (!message.length)
{
message = [VectorL10n roomDetailsFailToUpdateAvatar];
}
[self onSaveFailed:message withKeys:@[kRoomSettingsAvatarURLKey]];
});
}
}];
return;
}
// has a new room name
NSString* roomName = updatedItemsDict[kRoomSettingsNameKey];
if (roomName)
{
pendingOperation = [mxRoom setName:roomName success:^{
if (weakSelf)
{
typeof(self) self = weakSelf;
self->pendingOperation = nil;
[self->updatedItemsDict removeObjectForKey:kRoomSettingsNameKey];
[self onSave:nil];
}
} failure:^(NSError *error) {
MXLogDebug(@"[RoomSettingsViewController] Rename room failed");
if (weakSelf)
{
typeof(self) self = weakSelf;
self->pendingOperation = nil;
dispatch_async(dispatch_get_main_queue(), ^{
NSString* message = error.localizedDescription;
if (!message.length)
{
message = [VectorL10n roomDetailsFailToUpdateRoomName];
}
[self onSaveFailed:message withKeys:@[kRoomSettingsNameKey]];
});
}
}];
return;
}
// has a new room topic
NSString* roomTopic = updatedItemsDict[kRoomSettingsTopicKey];
if (roomTopic)
{
pendingOperation = [mxRoom setTopic:roomTopic success:^{
if (weakSelf)
{
typeof(self) self = weakSelf;
self->pendingOperation = nil;
[self->updatedItemsDict removeObjectForKey:kRoomSettingsTopicKey];
[self onSave:nil];
}
} failure:^(NSError *error) {
MXLogDebug(@"[RoomSettingsViewController] Rename topic failed");
if (weakSelf)
{
typeof(self) self = weakSelf;
self->pendingOperation = nil;
dispatch_async(dispatch_get_main_queue(), ^{
NSString* message = error.localizedDescription;
if (!message.length)
{
message = [VectorL10n roomDetailsFailToUpdateTopic];
}
[self onSaveFailed:message withKeys:@[kRoomSettingsTopicKey]];
});
}
}];
return;
}
// Room guest access
MXRoomGuestAccess guestAccess = updatedItemsDict[kRoomSettingsGuestAccessKey];
if (guestAccess)
{
pendingOperation = [mxRoom setGuestAccess:guestAccess success:^{
if (weakSelf)
{
typeof(self) self = weakSelf;
self->pendingOperation = nil;
[self->updatedItemsDict removeObjectForKey:kRoomSettingsGuestAccessKey];
[self onSave:nil];
}
} failure:^(NSError *error) {
MXLogDebug(@"[RoomSettingsViewController] Update guest access failed");
if (weakSelf)
{
typeof(self) self = weakSelf;
self->pendingOperation = nil;
dispatch_async(dispatch_get_main_queue(), ^{
NSString* message = error.localizedDescription;
if (!message.length)
{
message = [VectorL10n roomDetailsFailToUpdateRoomGuestAccess];
}
[self onSaveFailed:message withKeys:@[kRoomSettingsGuestAccessKey]];
});
}
}];
return;
}
// Room join rule
MXRoomJoinRule joinRule = updatedItemsDict[kRoomSettingsJoinRuleKey];
if (joinRule)
{
pendingOperation = [mxRoom setJoinRule:joinRule success:^{
if (weakSelf)
{
typeof(self) self = weakSelf;
self->pendingOperation = nil;
[self->updatedItemsDict removeObjectForKey:kRoomSettingsJoinRuleKey];
[self onSave:nil];
}
} failure:^(NSError *error) {
MXLogDebug(@"[RoomSettingsViewController] Update join rule failed");
if (weakSelf)
{
typeof(self) self = weakSelf;
self->pendingOperation = nil;
dispatch_async(dispatch_get_main_queue(), ^{
NSString* message = error.localizedDescription;
if (!message.length)
{
message = [VectorL10n roomDetailsFailToUpdateRoomJoinRule];
}
[self onSaveFailed:message withKeys:@[kRoomSettingsJoinRuleKey]];
});
}
}];
return;
}
// History visibility
MXRoomHistoryVisibility visibility = updatedItemsDict[kRoomSettingsHistoryVisibilityKey];
if (visibility)
{
pendingOperation = [mxRoom setHistoryVisibility:visibility success:^{
if (weakSelf)
{
typeof(self) self = weakSelf;
self->pendingOperation = nil;
[self->updatedItemsDict removeObjectForKey:kRoomSettingsHistoryVisibilityKey];
[self onSave:nil];
}
} failure:^(NSError *error) {
MXLogDebug(@"[RoomSettingsViewController] Update history visibility failed");
if (weakSelf)
{
typeof(self) self = weakSelf;
self->pendingOperation = nil;
dispatch_async(dispatch_get_main_queue(), ^{
NSString* message = error.localizedDescription;
if (!message.length)
{
message = [VectorL10n roomDetailsFailToUpdateHistoryVisibility];
}
[self onSaveFailed:message withKeys:@[kRoomSettingsHistoryVisibilityKey]];
});
}
}];
return;
}
// Room addresses
NSMutableArray<NSString *> *aliases = updatedItemsDict[kRoomSettingsNewAliasesKey];
if (aliases.count)
{
NSString *roomAlias = aliases.firstObject;
pendingOperation = [mxRoom addAlias:roomAlias success:^{
if (weakSelf)
{
typeof(self) self = weakSelf;
self->pendingOperation = nil;
if (aliases.count > 1)
{
[aliases removeObjectAtIndex:0];
self->updatedItemsDict[kRoomSettingsNewAliasesKey] = aliases;
}
else
{
[self->updatedItemsDict removeObjectForKey:kRoomSettingsNewAliasesKey];
}
[self onSave:nil];
}
} failure:^(NSError *error) {
MXLogDebug(@"[RoomSettingsViewController] Add room aliases failed");
if (weakSelf)
{
typeof(self) self = weakSelf;
self->pendingOperation = nil;
dispatch_async(dispatch_get_main_queue(), ^{
NSString* message = error.localizedDescription;
if (!message.length)
{
message = [VectorL10n roomDetailsFailToAddRoomAliases];
}
[self onSaveFailed:message withKeys:@[kRoomSettingsNewAliasesKey]];
});
}
}];
return;
}
aliases = updatedItemsDict[kRoomSettingsRemovedAliasesKey];
if (aliases.count)
{
NSString *roomAlias = aliases.firstObject;
pendingOperation = [mxRoom removeAlias:roomAlias success:^{
if (weakSelf)
{
typeof(self) self = weakSelf;
self->pendingOperation = nil;
if (aliases.count > 1)
{
[aliases removeObjectAtIndex:0];
self->updatedItemsDict[kRoomSettingsRemovedAliasesKey] = aliases;
}
else
{
[self->updatedItemsDict removeObjectForKey:kRoomSettingsRemovedAliasesKey];
}
[self onSave:nil];
}
} failure:^(NSError *error) {
MXLogDebug(@"[RoomSettingsViewController] Remove room aliases failed");
if (weakSelf)
{
typeof(self) self = weakSelf;
self->pendingOperation = nil;
dispatch_async(dispatch_get_main_queue(), ^{
NSString* message = error.localizedDescription;
if (!message.length)
{
message = [VectorL10n roomDetailsFailToRemoveRoomAliases];
}
[self onSaveFailed:message withKeys:@[kRoomSettingsRemovedAliasesKey]];
});
}
}];
return;
}
NSString* canonicalAlias = updatedItemsDict[kRoomSettingsCanonicalAliasKey];
if (canonicalAlias)
{
pendingOperation = [mxRoom setCanonicalAlias:canonicalAlias success:^{
if (weakSelf)
{
typeof(self) self = weakSelf;
self->pendingOperation = nil;
[self->updatedItemsDict removeObjectForKey:kRoomSettingsCanonicalAliasKey];
[self onSave:nil];
}
} failure:^(NSError *error) {
MXLogDebug(@"[RoomSettingsViewController] Update canonical alias failed");
if (weakSelf)
{
typeof(self) self = weakSelf;
self->pendingOperation = nil;
dispatch_async(dispatch_get_main_queue(), ^{
NSString* message = error.localizedDescription;
if (!message.length)
{
message = [VectorL10n roomDetailsFailToUpdateRoomCanonicalAlias];
}
[self onSaveFailed:message withKeys:@[kRoomSettingsCanonicalAliasKey]];
});
}
}];
return;
}
}
// Update here other room settings
NSString *roomTag = updatedItemsDict[kRoomSettingsTagKey];
if (roomTag)
{
if (!roomTag.length)
{
roomTag = nil;
}
[mxRoom setRoomTag:roomTag completion:^{
if (weakSelf)
{
typeof(self) self = weakSelf;
[self->updatedItemsDict removeObjectForKey:kRoomSettingsTagKey];
[self onSave:nil];
}
}];
return;
}
if (updatedItemsDict[kRoomSettingsMuteNotifKey])
{
if (((NSNumber*) updatedItemsDict[kRoomSettingsMuteNotifKey]).boolValue)
{
[mxRoom mentionsOnly:^{
if (weakSelf)
{
typeof(self) self = weakSelf;
[self->updatedItemsDict removeObjectForKey:kRoomSettingsMuteNotifKey];
[self onSave:nil];
}
}];
}
else
{
[mxRoom allMessages:^{
if (weakSelf)
{
typeof(self) self = weakSelf;
[self->updatedItemsDict removeObjectForKey:kRoomSettingsMuteNotifKey];
[self onSave:nil];
}
}];
}
return;
}
if (updatedItemsDict[kRoomSettingsDirectChatKey])
{
pendingOperation = [mxRoom setIsDirect:((NSNumber*) updatedItemsDict[kRoomSettingsDirectChatKey]).boolValue withUserId:nil success:^{
if (weakSelf)
{
typeof(self) self = weakSelf;
self->pendingOperation = nil;
[self->updatedItemsDict removeObjectForKey:kRoomSettingsDirectChatKey];
[self onSave:nil];
}
} failure:^(NSError *error) {
MXLogDebug(@"[RoomSettingsViewController] Altering DMness failed");
if (weakSelf)
{
typeof(self) self = weakSelf;
self->pendingOperation = nil;
dispatch_async(dispatch_get_main_queue(), ^{
NSString* message = error.localizedDescription;
if (!message.length)
{
message = [VectorL10n roomDetailsFailToUpdateRoomDirect];
}
[self onSaveFailed:message withKeys:@[kRoomSettingsDirectChatKey]];
});
}
}];
return;
}
// Room directory visibility
MXRoomDirectoryVisibility directoryVisibility = updatedItemsDict[kRoomSettingsDirectoryKey];
if (directoryVisibility)
{
[mxRoom setDirectoryVisibility:directoryVisibility success:^{
if (weakSelf)
{
typeof(self) self = weakSelf;
[self->updatedItemsDict removeObjectForKey:kRoomSettingsDirectoryKey];
[self onSave:nil];
}
} failure:^(NSError *error) {
MXLogDebug(@"[RoomSettingsViewController] Update room directory visibility failed");
if (weakSelf)
{
typeof(self) self = weakSelf;
self->pendingOperation = nil;
dispatch_async(dispatch_get_main_queue(), ^{
NSString* message = error.localizedDescription;
if (!message.length)
{
message = [VectorL10n roomDetailsFailToUpdateRoomDirectoryVisibility];
}
[self onSaveFailed:message withKeys:@[kRoomSettingsDirectoryKey]];
});
}
}];
return;
}
// Room encryption
if (updatedItemsDict[kRoomSettingsEncryptionKey])
{
pendingOperation = [mxRoom enableEncryptionWithAlgorithm:kMXCryptoMegolmAlgorithm success:^{
if (weakSelf)
{
typeof(self) self = weakSelf;
self->pendingOperation = nil;
[self->updatedItemsDict removeObjectForKey:kRoomSettingsEncryptionKey];
[self onSave:nil];
}
} failure:^(NSError *error) {
MXLogDebug(@"[RoomSettingsViewController] Enabling encrytion failed. Error: %@", error);
if (weakSelf)
{
typeof(self) self = weakSelf;
self->pendingOperation = nil;
dispatch_async(dispatch_get_main_queue(), ^{
NSString* message = error.localizedDescription;
if (!message.length)
{
message = [VectorL10n roomDetailsFailToEnableEncryption];
}
[self onSaveFailed:message withKeys:@[kRoomSettingsEncryptionKey]];
});
}
}];
return;
}
// Room settings on blacklist unverified devices
if (updatedItemsDict[kRoomSettingsEncryptionBlacklistUnverifiedDevicesKey])
{
BOOL blacklistUnverifiedDevices = [((NSNumber*)updatedItemsDict[kRoomSettingsEncryptionBlacklistUnverifiedDevicesKey]) boolValue];
[mxRoom.mxSession.crypto setBlacklistUnverifiedDevicesInRoom:mxRoom.roomId blacklist:blacklistUnverifiedDevices];
}
}
[self getNavigationItem].rightBarButtonItem.enabled = NO;
[self stopActivityIndicator];
if (self.delegate)
{
[self.delegate roomSettingsViewControllerDidComplete:self];
}
else
{
[self withdrawViewControllerAnimated:YES completion:nil];
}
}
#pragma mark - UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return _tableViewSections.sections.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
Section *sectionObject = [_tableViewSections sectionAtIndex:section];
return sectionObject.rows.count;
}
- (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
Section *sectionObject = [_tableViewSections sectionAtIndex:section];
return sectionObject.headerTitle;
}
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
{
if ([view isKindOfClass:UITableViewHeaderFooterView.class])
{
// Customize label style
UITableViewHeaderFooterView *tableViewHeaderFooterView = (UITableViewHeaderFooterView*)view;
tableViewHeaderFooterView.textLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
tableViewHeaderFooterView.textLabel.font = [UIFont systemFontOfSize:15];
tableViewHeaderFooterView.contentView.backgroundColor = ThemeService.shared.theme.headerBackgroundColor;
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSIndexPath *tagsIndexPath = [_tableViewSections tagsIndexPathFromTableViewIndexPath:indexPath];
NSInteger section = tagsIndexPath.section;
NSInteger row = tagsIndexPath.row;
if (section == SECTION_TAG_MAIN)
{
if (row == ROOM_SETTINGS_MAIN_SECTION_ROW_TOPIC)
{
return ROOM_TOPIC_CELL_HEIGHT;
}
}
return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSIndexPath *tagsIndexPath = [_tableViewSections tagsIndexPathFromTableViewIndexPath:indexPath];
NSInteger section = tagsIndexPath.section;
NSInteger row = tagsIndexPath.row;
UITableViewCell* cell;
// Check user's power level to know which settings are editable.
MXRoomPowerLevels *powerLevels = [mxRoomState powerLevels];
NSInteger oneSelfPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mainSession.myUser.userId];
// general settings
if (section == SECTION_TAG_MAIN)
{
if (row == ROOM_SETTINGS_MAIN_SECTION_ROW_MUTE_NOTIFICATIONS)
{
MXKTableViewCellWithLabelAndSwitch *roomNotifCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath];
[roomNotifCell.mxkSwitch addTarget:self action:@selector(toggleRoomNotification:) forControlEvents:UIControlEventValueChanged];
roomNotifCell.mxkLabel.text = [VectorL10n roomDetailsMuteNotifs];
if (updatedItemsDict[kRoomSettingsMuteNotifKey])
{
roomNotifCell.mxkSwitch.on = ((NSNumber*) updatedItemsDict[kRoomSettingsMuteNotifKey]).boolValue;
}
else
{
roomNotifCell.mxkSwitch.on = mxRoom.isMute || mxRoom.isMentionsOnly;
}
cell = roomNotifCell;
}
else if (row == ROOM_SETTINGS_MAIN_SECTION_ROW_DIRECT_CHAT)
{
MXKTableViewCellWithLabelAndSwitch *roomDirectChat = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath];
[roomDirectChat.mxkSwitch addTarget:self action:@selector(toggleDirectChat:) forControlEvents:UIControlEventValueChanged];
roomDirectChat.mxkLabel.text = [VectorL10n roomDetailsDirectChat];
if (updatedItemsDict[kRoomSettingsDirectChatKey])
{
roomDirectChat.mxkSwitch.on = ((NSNumber*) updatedItemsDict[kRoomSettingsDirectChatKey]).boolValue;
}
else
{
roomDirectChat.mxkSwitch.on = mxRoom.isDirect;
}
cell = roomDirectChat;
}
else if (row == ROOM_SETTINGS_MAIN_SECTION_ROW_PHOTO)
{
MXKTableViewCellWithLabelAndMXKImageView *roomPhotoCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithLabelAndMXKImageView defaultReuseIdentifier] forIndexPath:indexPath];
roomPhotoCell.mxkLabelLeadingConstraint.constant = tableView.vc_separatorInset.left;
roomPhotoCell.mxkImageViewTrailingConstraint.constant = 10;
roomPhotoCell.mxkImageViewWidthConstraint.constant = roomPhotoCell.mxkImageViewHeightConstraint.constant = 30;
roomPhotoCell.mxkImageViewDisplayBoxType = MXKTableViewCellDisplayBoxTypeCircle;
// Handle tap on avatar to update it
if (!roomPhotoCell.mxkImageView.gestureRecognizers.count)
{
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onRoomAvatarTap:)];
[roomPhotoCell.mxkImageView addGestureRecognizer:tap];
}
roomPhotoCell.mxkImageView.defaultBackgroundColor = [UIColor clearColor];
if (mxRoom.isDirect)
{
roomPhotoCell.mxkLabel.text = [VectorL10n roomDetailsPhotoForDm];
}
else
{
roomPhotoCell.mxkLabel.text = [VectorL10n roomDetailsPhoto];
}
roomPhotoCell.mxkLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
if (updatedItemsDict[kRoomSettingsAvatarKey])
{
roomPhotoCell.mxkImageView.image = (UIImage*) updatedItemsDict[kRoomSettingsAvatarKey];
}
else
{
[mxRoom.summary setRoomAvatarImageIn:roomPhotoCell.mxkImageView];
roomPhotoCell.userInteractionEnabled = (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomAvatar]);
roomPhotoCell.mxkImageView.alpha = roomPhotoCell.userInteractionEnabled ? 1.0f : 0.5f;
}
cell = roomPhotoCell;
}
else if (row == ROOM_SETTINGS_MAIN_SECTION_ROW_TOPIC)
{
TableViewCellWithLabelAndLargeTextView *roomTopicCell = [tableView dequeueReusableCellWithIdentifier:kRoomSettingsTopicCellViewIdentifier forIndexPath:indexPath];
roomTopicCell.labelLeadingConstraint.constant = tableView.vc_separatorInset.left;
roomTopicCell.label.text = [VectorL10n roomDetailsTopic];
topicTextView = roomTopicCell.textView;
if (updatedItemsDict[kRoomSettingsTopicKey])
{
topicTextView.text = (NSString*) updatedItemsDict[kRoomSettingsTopicKey];
}
else
{
topicTextView.text = mxRoomState.topic;
}
topicTextView.tintColor = ThemeService.shared.theme.tintColor;
topicTextView.font = [UIFont systemFontOfSize:15];
topicTextView.bounces = NO;
topicTextView.delegate = self;
// disable the edition if the user cannot update it
topicTextView.editable = (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomTopic]);
topicTextView.textColor = ThemeService.shared.theme.textSecondaryColor;
topicTextView.keyboardAppearance = ThemeService.shared.theme.keyboardAppearance;
cell = roomTopicCell;
}
else if (row == ROOM_SETTINGS_MAIN_SECTION_ROW_NAME)
{
MXKTableViewCellWithLabelAndTextField *roomNameCell = [tableView dequeueReusableCellWithIdentifier:kRoomSettingsNameCellViewIdentifier forIndexPath:indexPath];
roomNameCell.mxkLabelLeadingConstraint.constant = tableView.vc_separatorInset.left;
roomNameCell.mxkTextFieldLeadingConstraint.constant = 16;
roomNameCell.mxkTextFieldTrailingConstraint.constant = 15;
if (mxRoom.isDirect)
{
roomNameCell.mxkLabel.text = [VectorL10n roomDetailsRoomNameForDm];
}
else
{
roomNameCell.mxkLabel.text = [VectorL10n roomDetailsRoomName];
}
roomNameCell.mxkLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
roomNameCell.accessoryType = UITableViewCellAccessoryNone;
roomNameCell.accessoryView = nil;
nameTextField = roomNameCell.mxkTextField;
nameTextField.tintColor = ThemeService.shared.theme.tintColor;
nameTextField.font = [UIFont systemFontOfSize:17];
nameTextField.borderStyle = UITextBorderStyleNone;
nameTextField.textAlignment = NSTextAlignmentRight;
nameTextField.delegate = self;
if (updatedItemsDict[kRoomSettingsNameKey])
{
nameTextField.text = (NSString*) updatedItemsDict[kRoomSettingsNameKey];
}
else
{
nameTextField.text = mxRoomState.name;
}
// disable the edition if the user cannot update it
nameTextField.userInteractionEnabled = (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomName]);
nameTextField.textColor = ThemeService.shared.theme.textSecondaryColor;
// Add a "textFieldDidChange" notification method to the text field control.
[nameTextField addTarget:self action:@selector(onTextFieldUpdate:) forControlEvents:UIControlEventEditingChanged];
cell = roomNameCell;
}
else if (row == ROOM_SETTINGS_MAIN_SECTION_ROW_TAG)
{
if (RiotSettings.shared.roomSettingsScreenShowLowPriorityOption)
{
// show a muti-checkbox cell
roomTagCell = [tableView dequeueReusableCellWithIdentifier:[TableViewCellWithCheckBoxes defaultReuseIdentifier] forIndexPath:indexPath];
roomTagCell.mainContainerLeadingConstraint.constant = tableView.vc_separatorInset.left;
roomTagCell.checkBoxesNumber = 2;
roomTagCell.allowsMultipleSelection = NO;
roomTagCell.delegate = self;
NSArray *labels = roomTagCell.labels;
UILabel *label;
label = labels[0];
label.textColor = ThemeService.shared.theme.textPrimaryColor;
label.text = [VectorL10n roomDetailsFavouriteTag];
label = labels[1];
label.textColor = ThemeService.shared.theme.textPrimaryColor;
label.text = [VectorL10n roomDetailsLowPriorityTag];
if (updatedItemsDict[kRoomSettingsTagKey])
{
NSString *roomTag = updatedItemsDict[kRoomSettingsTagKey];
if ([roomTag isEqualToString:kMXRoomTagFavourite])
{
[roomTagCell setCheckBoxValue:YES atIndex:0];
}
else if ([roomTag isEqualToString:kMXRoomTagLowPriority])
{
[roomTagCell setCheckBoxValue:YES atIndex:1];
}
}
else
{
if (mxRoom.accountData.tags[kMXRoomTagFavourite] != nil)
{
[roomTagCell setCheckBoxValue:YES atIndex:0];
}
else if (mxRoom.accountData.tags[kMXRoomTagLowPriority] != nil)
{
[roomTagCell setCheckBoxValue:YES atIndex:1];
}
}
cell = roomTagCell;
}
else
{
// use a switch cell
MXKTableViewCellWithLabelAndSwitch *favoriteCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath];
[favoriteCell.mxkSwitch addTarget:self action:@selector(toggleFavorite:) forControlEvents:UIControlEventValueChanged];
favoriteCell.mxkLabel.text = [VectorL10n roomDetailsFavouriteTag];
if ([updatedItemsDict[kRoomSettingsTagKey] isEqualToString:kMXRoomTagFavourite])
{
favoriteCell.mxkSwitch.on = ((NSNumber*) updatedItemsDict[kMXRoomTagFavourite]).boolValue;
}
else
{
favoriteCell.mxkSwitch.on = mxRoom.accountData.tags[kMXRoomTagFavourite] != nil;
}
cell = favoriteCell;
}
}
}
else if (section == SECTION_TAG_ACCESS)
{
if (row == ROOM_SETTINGS_ROOM_ACCESS_DIRECTORY_VISIBILITY)
{
MXKTableViewCellWithLabelAndSwitch *directoryToggleCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath];
if (mxRoom.isDirect)
{
directoryToggleCell.mxkLabel.text = [VectorL10n roomDetailsAccessSectionDirectoryToggleForDm];
}
else
{
directoryToggleCell.mxkLabel.text = [VectorL10n roomDetailsAccessSectionDirectoryToggle];
}
[directoryToggleCell.mxkSwitch addTarget:self action:@selector(toggleDirectoryVisibility:) forControlEvents:UIControlEventValueChanged];
if (updatedItemsDict[kRoomSettingsDirectoryKey])
{
directoryToggleCell.mxkSwitch.on = ((NSNumber*) updatedItemsDict[kRoomSettingsDirectoryKey]).boolValue;
}
else
{
// Use the last retrieved value if any
directoryToggleCell.mxkSwitch.on = actualDirectoryVisibility ? [actualDirectoryVisibility isEqualToString:kMXRoomDirectoryVisibilityPublic] : NO;
}
// Check whether the user can change this option
directoryToggleCell.mxkSwitch.enabled = (oneSelfPowerLevel >= powerLevels.stateDefault);
// Store the switch to be able to update it
directoryVisibilitySwitch = directoryToggleCell.mxkSwitch;
cell = directoryToggleCell;
}
else if (row == ROOM_SETTINGS_ROOM_ACCESS_MISSING_ADDRESS_WARNING)
{
cell = [tableView dequeueReusableCellWithIdentifier:kRoomSettingsWarningCellViewIdentifier forIndexPath:indexPath];
cell.textLabel.font = [UIFont systemFontOfSize:17];
cell.textLabel.textColor = ThemeService.shared.theme.warningColor;
cell.textLabel.numberOfLines = 0;
cell.accessoryView = nil;
cell.accessoryType = UITableViewCellAccessoryNone;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.textLabel.text = [VectorL10n roomDetailsAccessSectionNoAddressWarning];
}
else if (row == ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_ACCESS)
{
TitleAndRightDetailTableViewCell *roomAccessCell = [tableView dequeueReusableCellWithIdentifier:[TitleAndRightDetailTableViewCell defaultReuseIdentifier] forIndexPath:indexPath];
// Retrieve the potential updated values for joinRule and guestAccess
NSString *joinRule = updatedItemsDict[kRoomSettingsJoinRuleKey];
NSString *guestAccess = updatedItemsDict[kRoomSettingsGuestAccessKey];
// Use the actual values if no change is pending
if (!joinRule)
{
joinRule = mxRoomState.joinRule;
}
if (!guestAccess)
{
guestAccess = mxRoomState.guestAccess;
}
roomAccessCell.titleLabel.text = [VectorL10n roomDetailsAccessRowTitle];
NSString *access = VectorL10n.private;
if ([joinRule isEqualToString:kMXRoomJoinRulePublic])
{
access = VectorL10n.public;
}
else if ([joinRule isEqualToString:kMXRoomJoinRuleRestricted])
{
access = VectorL10n.createRoomTypeRestricted;
}
roomAccessCell.detailLabel.text = access;
// Check whether the user can change this option
roomAccessCell.userInteractionEnabled = (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomJoinRules]);
cell = roomAccessCell;
}
else
{
TableViewCellWithCheckBoxAndLabel *roomAccessCell = [tableView dequeueReusableCellWithIdentifier:[TableViewCellWithCheckBoxAndLabel defaultReuseIdentifier] forIndexPath:indexPath];
roomAccessCell.checkBoxLeadingConstraint.constant = tableView.vc_separatorInset.left;
// Retrieve the potential updated values for joinRule and guestAccess
NSString *joinRule = updatedItemsDict[kRoomSettingsJoinRuleKey];
NSString *guestAccess = updatedItemsDict[kRoomSettingsGuestAccessKey];
// Use the actual values if no change is pending
if (!joinRule)
{
joinRule = mxRoomState.joinRule;
}
if (!guestAccess)
{
guestAccess = mxRoomState.guestAccess;
}
// Check whether the user can change this option
roomAccessCell.userInteractionEnabled = (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomJoinRules]);
roomAccessCell.checkBox.alpha = roomAccessCell.userInteractionEnabled ? 1.0f : 0.5f;
cell = roomAccessCell;
}
}
else if (section == SECTION_TAG_PROMOTION)
{
if (row == ROOM_SETTINGS_ROOM_ACCESS_DIRECTORY_VISIBILITY)
{
MXKTableViewCellWithLabelAndSwitch *directoryToggleCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath];
if (mxRoom.isDirect)
{
directoryToggleCell.mxkLabel.text = [VectorL10n roomDetailsAccessSectionDirectoryToggleForDm];
}
else
{
directoryToggleCell.mxkLabel.text = [VectorL10n roomDetailsAccessSectionDirectoryToggle];
}
[directoryToggleCell.mxkSwitch addTarget:self action:@selector(toggleDirectoryVisibility:) forControlEvents:UIControlEventValueChanged];
if (updatedItemsDict[kRoomSettingsDirectoryKey])
{
directoryToggleCell.mxkSwitch.on = ((NSNumber*) updatedItemsDict[kRoomSettingsDirectoryKey]).boolValue;
}
else
{
// Use the last retrieved value if any
directoryToggleCell.mxkSwitch.on = actualDirectoryVisibility ? [actualDirectoryVisibility isEqualToString:kMXRoomDirectoryVisibilityPublic] : NO;
}
// Check whether the user can change this option
directoryToggleCell.mxkSwitch.enabled = (oneSelfPowerLevel >= powerLevels.stateDefault);
// Store the switch to be able to update it
directoryVisibilitySwitch = directoryToggleCell.mxkSwitch;
cell = directoryToggleCell;
}
else if (row == ROOM_SETTINGS_ROOM_PROMOTE_SECTION_ROW_SUGGEST)
{
TitleAndRightDetailTableViewCell *roomSuggestionCell = [tableView dequeueReusableCellWithIdentifier:[TitleAndRightDetailTableViewCell defaultReuseIdentifier] forIndexPath:indexPath];
roomSuggestionCell.titleLabel.text = [VectorL10n roomDetailsPromoteRoomSuggestTitle];
roomSuggestionCell.detailLabel.text = [self.mainSession.spaceService directParentIdsOfRoomWithId:self.roomId whereRoomIsSuggested:YES].count ? [VectorL10n on] : [VectorL10n off];
// Check whether the user can change this option
roomSuggestionCell.userInteractionEnabled = (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomJoinRules]);
cell = roomSuggestionCell;
}
}
else if (section == SECTION_TAG_HISTORY)
{
TableViewCellWithCheckBoxAndLabel *historyVisibilityCell = [tableView dequeueReusableCellWithIdentifier:[TableViewCellWithCheckBoxAndLabel defaultReuseIdentifier] forIndexPath:indexPath];
historyVisibilityCell.checkBoxLeadingConstraint.constant = tableView.vc_separatorInset.left;
// Retrieve first the potential updated value for history visibility
NSString *visibility = updatedItemsDict[kRoomSettingsHistoryVisibilityKey];
// Use the actual value if no change is pending
if (!visibility)
{
visibility = mxRoomState.historyVisibility;
}
if (row == ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_ANYONE)
{
historyVisibilityCell.label.lineBreakMode = NSLineBreakByTruncatingMiddle;
historyVisibilityCell.label.text = [VectorL10n roomDetailsHistorySectionAnyone];
historyVisibilityCell.enabled = ([visibility isEqualToString:kMXRoomHistoryVisibilityWorldReadable]);
historyVisibilityTickCells[kMXRoomHistoryVisibilityWorldReadable] = historyVisibilityCell;
}
else if (row == ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_MEMBERS_ONLY)
{
historyVisibilityCell.label.lineBreakMode = NSLineBreakByTruncatingMiddle;
historyVisibilityCell.label.text = [VectorL10n roomDetailsHistorySectionMembersOnly];
historyVisibilityCell.enabled = ([visibility isEqualToString:kMXRoomHistoryVisibilityShared]);
historyVisibilityTickCells[kMXRoomHistoryVisibilityShared] = historyVisibilityCell;
}
else if (row == ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_MEMBERS_ONLY_SINCE_INVITED)
{
historyVisibilityCell.label.lineBreakMode = NSLineBreakByTruncatingMiddle;
historyVisibilityCell.label.text = [VectorL10n roomDetailsHistorySectionMembersOnlySinceInvited];
historyVisibilityCell.enabled = ([visibility isEqualToString:kMXRoomHistoryVisibilityInvited]);
historyVisibilityTickCells[kMXRoomHistoryVisibilityInvited] = historyVisibilityCell;
}
else if (row == ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_MEMBERS_ONLY_SINCE_JOINED)
{
historyVisibilityCell.label.lineBreakMode = NSLineBreakByTruncatingMiddle;
historyVisibilityCell.label.text = [VectorL10n roomDetailsHistorySectionMembersOnlySinceJoined];
historyVisibilityCell.enabled = ([visibility isEqualToString:kMXRoomHistoryVisibilityJoined]);
historyVisibilityTickCells[kMXRoomHistoryVisibilityJoined] = historyVisibilityCell;
}
// Check whether the user can change this option
historyVisibilityCell.userInteractionEnabled = (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomHistoryVisibility]);
historyVisibilityCell.checkBox.alpha = historyVisibilityCell.userInteractionEnabled ? 1.0f : 0.5f;
cell = historyVisibilityCell;
}
else if (section == SECTION_TAG_ADDRESSES)
{
if (row == ROOM_SETTINGS_ROOM_ADDRESS_NEW_ALIAS)
{
MXKTableViewCellWithLabelAndTextField *addAddressCell = [tableView dequeueReusableCellWithIdentifier:kRoomSettingsNewAddressCellViewIdentifier forIndexPath:indexPath];
// Retrieve the current edited value if any
NSString *currentValue = (addAddressTextField ? addAddressTextField.text : nil);
addAddressCell.mxkLabelLeadingConstraint.constant = 0;
addAddressCell.mxkTextFieldLeadingConstraint.constant = tableView.vc_separatorInset.left;
addAddressCell.mxkTextFieldTrailingConstraint.constant = 15;
addAddressCell.mxkLabel.text = nil;
addAddressCell.accessoryType = UITableViewCellAccessoryNone;
addAddressCell.accessoryView = [[UIImageView alloc] initWithImage:[AssetImages.plusIcon.image vc_tintedImageUsingColor:ThemeService.shared.theme.textPrimaryColor]];
addAddressTextField = addAddressCell.mxkTextField;
addAddressTextField.placeholder = [VectorL10n roomDetailsNewAddressPlaceholder:self.mainSession.matrixRestClient.homeserverSuffix];
addAddressTextField.attributedPlaceholder = [[NSAttributedString alloc]
initWithString:addAddressTextField.placeholder
attributes:@{NSForegroundColorAttributeName: ThemeService.shared.theme.placeholderTextColor}];
addAddressTextField.userInteractionEnabled = YES;
addAddressTextField.text = currentValue;
addAddressTextField.textColor = ThemeService.shared.theme.textSecondaryColor;
addAddressTextField.tintColor = ThemeService.shared.theme.tintColor;
addAddressTextField.font = [UIFont systemFontOfSize:17];
addAddressTextField.borderStyle = UITextBorderStyleNone;
addAddressTextField.textAlignment = NSTextAlignmentLeft;
addAddressTextField.autocorrectionType = UITextAutocorrectionTypeNo;
addAddressTextField.spellCheckingType = UITextSpellCheckingTypeNo;
addAddressTextField.delegate = self;
cell = addAddressCell;
}
else if (row == ROOM_SETTINGS_ROOM_ADDRESS_NO_LOCAL_ADDRESS)
{
UITableViewCell *addressCell = [tableView dequeueReusableCellWithIdentifier:kRoomSettingsAddressCellViewIdentifier forIndexPath:indexPath];
addressCell.textLabel.font = [UIFont systemFontOfSize:16];
addressCell.textLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
addressCell.textLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;
addressCell.accessoryView = nil;
addressCell.accessoryType = UITableViewCellAccessoryNone;
addressCell.selectionStyle = UITableViewCellSelectionStyleNone;
if (mxRoom.isDirect)
{
addressCell.textLabel.text = [VectorL10n roomDetailsNoLocalAddressesForDm];
}
else
{
addressCell.textLabel.text = [VectorL10n roomDetailsNoLocalAddresses];
}
cell = addressCell;
}
else
{
UITableViewCell *addressCell = [tableView dequeueReusableCellWithIdentifier:kRoomSettingsAddressCellViewIdentifier forIndexPath:indexPath];
addressCell.textLabel.font = [UIFont systemFontOfSize:16];
addressCell.textLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
addressCell.textLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;
addressCell.accessoryView = nil;
addressCell.accessoryType = UITableViewCellAccessoryNone;
addressCell.selectionStyle = UITableViewCellSelectionStyleNone;
NSInteger index = row - ROOM_SETTINGS_ROOM_ADDRESS_ALIAS_OFFSET;
if (index < roomAddresses.count)
{
NSString *alias = roomAddresses[index];
NSString *canonicalAlias;
if (updatedItemsDict[kRoomSettingsCanonicalAliasKey])
{
canonicalAlias = updatedItemsDict[kRoomSettingsCanonicalAliasKey];
}
else
{
canonicalAlias = mxRoomState.canonicalAlias;
}
addressCell.textLabel.text = alias;
// Check whether this alias is the main address
if (canonicalAlias)
{
if ([alias isEqualToString:canonicalAlias])
{
addressCell.accessoryView = [[UIImageView alloc] initWithImage:AssetImages.mainAliasIcon.image];
}
}
}
cell = addressCell;
}
}
else if (section == SECTION_TAG_BANNED_USERS)
{
UITableViewCell *addressCell = [tableView dequeueReusableCellWithIdentifier:kRoomSettingsAddressCellViewIdentifier forIndexPath:indexPath];
addressCell.textLabel.font = [UIFont systemFontOfSize:16];
addressCell.textLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
addressCell.textLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;
addressCell.accessoryView = nil;
addressCell.accessoryType = UITableViewCellAccessoryNone;
addressCell.selectionStyle = UITableViewCellSelectionStyleNone;
addressCell.textLabel.text = bannedMembers[row].userId;
cell = addressCell;
}
else if (section == SECTION_TAG_BANNED_ADVANCED)
{
if (row == ROOM_SETTINGS_ADVANCED_ROOM_ID)
{
cell = [tableView dequeueReusableCellWithIdentifier:kRoomSettingsAdvancedCellViewIdentifier];
if (!cell)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:kRoomSettingsAdvancedCellViewIdentifier];
}
cell.textLabel.font = [UIFont systemFontOfSize:17];
if (mxRoom.isDirect)
{
cell.textLabel.text = [VectorL10n roomDetailsAdvancedRoomIdForDm];
}
else
{
cell.textLabel.text = [VectorL10n roomDetailsAdvancedRoomId];
}
cell.textLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
cell.detailTextLabel.font = [UIFont systemFontOfSize:15];
cell.detailTextLabel.text = mxRoomState.roomId;
cell.detailTextLabel.textColor = ThemeService.shared.theme.textSecondaryColor;
cell.detailTextLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
else if (row == ROOM_SETTINGS_ADVANCED_ENCRYPT_TO_VERIFIED)
{
MXKTableViewCellWithLabelAndSwitch *roomBlacklistUnverifiedDevicesCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath];
[roomBlacklistUnverifiedDevicesCell.mxkSwitch addTarget:self action:@selector(toggleBlacklistUnverifiedDevice:) forControlEvents:UIControlEventValueChanged];
roomBlacklistUnverifiedDevicesCell.mxkSwitch.onTintColor = ThemeService.shared.theme.tintColor;
roomBlacklistUnverifiedDevicesCell.mxkLabel.text = [VectorL10n roomDetailsAdvancedE2eEncryptionBlacklistUnverifiedDevices];
// For the switch value, use by order:
// - the MXCrypto.globalBlacklistUnverifiedDevices if its value is YES
// In this case, the switch is disabled.
// - the changed value made by the user
// - the value used by the crypto
BOOL blacklistUnverifiedDevices;
if (mxRoom.mxSession.crypto.globalBlacklistUnverifiedDevices)
{
blacklistUnverifiedDevices = YES;
roomBlacklistUnverifiedDevicesCell.mxkSwitch.enabled = NO;
}
else
{
roomBlacklistUnverifiedDevicesCell.mxkSwitch.enabled = YES;
if (updatedItemsDict[kRoomSettingsEncryptionBlacklistUnverifiedDevicesKey])
{
blacklistUnverifiedDevices = [((NSNumber*)updatedItemsDict[kRoomSettingsEncryptionBlacklistUnverifiedDevicesKey]) boolValue];
}
else
{
blacklistUnverifiedDevices = [mxRoom.mxSession.crypto isBlacklistUnverifiedDevicesInRoom:mxRoom.roomId];
}
}
roomBlacklistUnverifiedDevicesCell.mxkSwitch.on = blacklistUnverifiedDevices;
cell = roomBlacklistUnverifiedDevicesCell;
// Force layout before reusing a cell (fix switch displayed outside the screen)
[cell layoutIfNeeded];
}
else if (row == ROOM_SETTINGS_ADVANCED_ENCRYPTION_ENABLED)
{
cell = [tableView dequeueReusableCellWithIdentifier:kRoomSettingsAdvancedE2eEnabledCellViewIdentifier];
if (!cell)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:kRoomSettingsAdvancedE2eEnabledCellViewIdentifier];
}
cell.textLabel.font = [UIFont systemFontOfSize:17];
cell.textLabel.numberOfLines = 0;
if (mxRoom.isDirect)
{
cell.textLabel.text = [VectorL10n roomDetailsAdvancedE2eEncryptionEnabledForDm];
}
else
{
cell.textLabel.text = [VectorL10n roomDetailsAdvancedE2eEncryptionEnabled];
}
cell.textLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
else if (row == ROOM_SETTINGS_ADVANCED_ENABLE_ENCRYPTION)
{
MXKTableViewCellWithLabelAndSwitch *roomEncryptionCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath];
[roomEncryptionCell.mxkSwitch addTarget:self action:@selector(toggleEncryption:) forControlEvents:UIControlEventValueChanged];
roomEncryptionCell.mxkLabel.text = [VectorL10n roomDetailsAdvancedEnableE2eEncryption];
roomEncryptionCell.mxkSwitch.on = (updatedItemsDict[kRoomSettingsEncryptionKey] != nil);
cell = roomEncryptionCell;
}
else if (row == ROOM_SETTINGS_ADVANCED_ENCRYPTION_DISABLED)
{
cell = [tableView dequeueReusableCellWithIdentifier:kRoomSettingsAdvancedE2eEnabledCellViewIdentifier];
if (!cell)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:kRoomSettingsAdvancedE2eEnabledCellViewIdentifier];
}
cell.textLabel.font = [UIFont systemFontOfSize:17];
cell.textLabel.numberOfLines = 0;
if (mxRoom.isDirect)
{
cell.textLabel.text = [VectorL10n roomDetailsAdvancedE2eEncryptionDisabledForDm];
}
else
{
cell.textLabel.text = [VectorL10n roomDetailsAdvancedE2eEncryptionDisabled];
}
cell.textLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
}
// Sanity check
if (!cell)
{
MXLogDebug(@"[RoomSettingsViewController] cellForRowAtIndexPath: invalid indexPath");
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
}
return cell;
}
- (MXKTableViewCellWithLabelAndSwitch*)getLabelAndSwitchCell:(UITableView*)tableView forIndexPath:(NSIndexPath *)indexPath
{
MXKTableViewCellWithLabelAndSwitch *cell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithLabelAndSwitch defaultReuseIdentifier] forIndexPath:indexPath];
cell.mxkLabelLeadingConstraint.constant = tableView.vc_separatorInset.left;
cell.mxkSwitchTrailingConstraint.constant = 15;
cell.mxkLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
cell.mxkSwitch.onTintColor = ThemeService.shared.theme.tintColor;
[cell.mxkSwitch removeTarget:self action:nil forControlEvents:UIControlEventValueChanged];
// Reset the stored `directoryVisibilitySwitch` if the corresponding cell is reused.
if (cell.mxkSwitch == directoryVisibilitySwitch)
{
directoryVisibilitySwitch = nil;
}
// Force layout before reusing a cell (fix switch displayed outside the screen)
[cell layoutIfNeeded];
return cell;
}
#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;
{
cell.backgroundColor = ThemeService.shared.theme.backgroundColor;
// Update the selected background view
if (ThemeService.shared.theme.selectedBackgroundColor)
{
cell.selectedBackgroundView = [[UIView alloc] init];
cell.selectedBackgroundView.backgroundColor = ThemeService.shared.theme.selectedBackgroundColor;
}
else
{
if (tableView.style == UITableViewStylePlain)
{
cell.selectedBackgroundView = nil;
}
else
{
cell.selectedBackgroundView.backgroundColor = nil;
}
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSIndexPath *tagsIndexPath = [_tableViewSections tagsIndexPathFromTableViewIndexPath:indexPath];
NSInteger section = tagsIndexPath.section;
NSInteger row = tagsIndexPath.row;
if (self.tableView == tableView)
{
[self dismissFirstResponder];
if (section == SECTION_TAG_MAIN)
{
if (row == ROOM_SETTINGS_MAIN_SECTION_ROW_PHOTO)
{
[self onRoomAvatarTap:nil];
}
else if (row == ROOM_SETTINGS_MAIN_SECTION_ROW_TOPIC)
{
if (topicTextView.editable)
{
[self editRoomTopic];
}
}
}
else if (section == SECTION_TAG_ACCESS)
{
BOOL isUpdated = NO;
if (row == ROOM_SETTINGS_ROOM_ACCESS_MISSING_ADDRESS_WARNING)
{
// Scroll to room addresses section
NSIndexPath *addressIndexPath = [_tableViewSections exactIndexPathForRowTag:0 sectionTag:SECTION_TAG_ADDRESSES];
if (addressIndexPath)
{
[tableView scrollToRowAtIndexPath:addressIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
else
{
addressIndexPath = [_tableViewSections nearestIndexPathForRowTag:0 sectionTag:SECTION_TAG_ADDRESSES];
if (addressIndexPath)
{
[tableView scrollToRowAtIndexPath:addressIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
}
}
}
else if (row == ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_ACCESS)
{
[self showRoomAccessFlow];
}
if (isUpdated)
{
[self updateSections];
[self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0);
}
}
else if (section == SECTION_TAG_PROMOTION)
{
if (row == ROOM_SETTINGS_ROOM_PROMOTE_SECTION_ROW_SUGGEST)
{
[self showSuggestToSpaceMembers];
}
}
else if (section == SECTION_TAG_HISTORY)
{
// Ignore the selection if the option is already enabled
TableViewCellWithCheckBoxAndLabel *selectedCell = [self.tableView cellForRowAtIndexPath:indexPath];
if (! selectedCell.isEnabled)
{
MXRoomHistoryVisibility historyVisibility;
if (row == ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_ANYONE)
{
historyVisibility = kMXRoomHistoryVisibilityWorldReadable;
}
else if (row == ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_MEMBERS_ONLY)
{
historyVisibility = kMXRoomHistoryVisibilityShared;
}
else if (row == ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_MEMBERS_ONLY_SINCE_INVITED)
{
historyVisibility = kMXRoomHistoryVisibilityInvited;
}
else if (row == ROOM_SETTINGS_HISTORY_VISIBILITY_SECTION_ROW_MEMBERS_ONLY_SINCE_JOINED)
{
historyVisibility = kMXRoomHistoryVisibilityJoined;
}
if (historyVisibility)
{
// Prompt the user before taking into account the change
[self shouldChangeHistoryVisibility:historyVisibility];
}
}
}
else if (section == SECTION_TAG_ADDRESSES)
{
if (row == ROOM_SETTINGS_ROOM_ADDRESS_NEW_ALIAS)
{
NSString *roomAlias = addAddressTextField.text;
if (!roomAlias.length || [self addRoomAlias:roomAlias])
{
// Reset the input field
addAddressTextField.text = nil;
}
}
else if (row >= ROOM_SETTINGS_ROOM_ADDRESS_ALIAS_OFFSET)
{
// Prompt user on selected room alias
UITableViewCell *addressCell = [tableView cellForRowAtIndexPath:indexPath];
dispatch_async(dispatch_get_main_queue(), ^{
[self promptUserOnSelectedRoomAlias:addressCell.textLabel];
});
}
}
else if (section == SECTION_TAG_BANNED_USERS)
{
// Show the RoomMemberDetailsViewController on this member so that
// if the user has enough power level, he will be able to unban him
RoomMemberDetailsViewController *roomMemberDetailsViewController = [RoomMemberDetailsViewController roomMemberDetailsViewController];
[roomMemberDetailsViewController displayRoomMember:bannedMembers[row] withMatrixRoom:mxRoom];
roomMemberDetailsViewController.delegate = self;
roomMemberDetailsViewController.enableVoipCall = NO;
[self.parentViewController.navigationController pushViewController:roomMemberDetailsViewController animated:NO];
}
else if (section == SECTION_TAG_BANNED_ADVANCED && row == ROOM_SETTINGS_ADVANCED_ROOM_ID)
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell)
{
// Prompt user to copy the room id (use dispatch_async here to not be stuck by the table refresh).
dispatch_async(dispatch_get_main_queue(), ^{
[self promptUserToCopyRoomId:cell.detailTextLabel];
});
}
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
}
- (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSIndexPath *tagsIndexPath = [_tableViewSections tagsIndexPathFromTableViewIndexPath:indexPath];
NSInteger section = tagsIndexPath.section;
NSInteger row = tagsIndexPath.row;
// Add the swipe to delete only on addresses section
if (section == SECTION_TAG_ADDRESSES && row >= ROOM_SETTINGS_ROOM_ADDRESS_ALIAS_OFFSET)
{
UIContextualAction *removeAddressAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleDestructive
title:@" "
handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
[self removeAddressAtIndexPath:indexPath];
completionHandler(YES);
}];
removeAddressAction.backgroundColor = ThemeService.shared.theme.headerBackgroundColor;
removeAddressAction.image = [AssetImages.removeIcon.image vc_notRenderedImage];
// Create swipe action configuration
NSArray<UIContextualAction*> *actions = @[
removeAddressAction
];
UISwipeActionsConfiguration *swipeActionConfiguration = [UISwipeActionsConfiguration configurationWithActions:actions];
swipeActionConfiguration.performsFirstActionWithFullSwipe = NO;
return swipeActionConfiguration;
}
return nil;
}
#pragma mark -
- (void)shouldChangeHistoryVisibility:(MXRoomHistoryVisibility)historyVisibility
{
// Prompt the user before applying the change on room history visibility
[currentAlert dismissViewControllerAnimated:NO completion:nil];
__weak typeof(self) weakSelf = self;
currentAlert = [UIAlertController alertControllerWithTitle:[VectorL10n roomDetailsHistorySectionPromptTitle]
message:[VectorL10n roomDetailsHistorySectionPromptMsg]
preferredStyle:UIAlertControllerStyleAlert];
[currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n cancel]
style:UIAlertActionStyleCancel
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->currentAlert = nil;
}
}]];
[currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n continue]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->currentAlert = nil;
[self changeHistoryVisibility:historyVisibility];
}
}]];
[currentAlert mxk_setAccessibilityIdentifier:@"RoomSettingsVCChangeHistoryVisibilityAlert"];
[self presentViewController:currentAlert animated:YES completion:nil];
}
- (void)changeHistoryVisibility:(MXRoomHistoryVisibility)historyVisibility
{
if (historyVisibility)
{
// Disable all history visibility options
NSArray *tickCells = historyVisibilityTickCells.allValues;
for (TableViewCellWithCheckBoxAndLabel *historyVisibilityTickCell in tickCells)
{
historyVisibilityTickCell.enabled = NO;
}
// Enable the selected option
historyVisibilityTickCells[historyVisibility].enabled = YES;
// Check the actual option
if ([mxRoomState.historyVisibility isEqualToString:historyVisibility])
{
// No change on history visibility
[updatedItemsDict removeObjectForKey:kRoomSettingsHistoryVisibilityKey];
}
else
{
updatedItemsDict[kRoomSettingsHistoryVisibilityKey] = historyVisibility;
}
[self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0);
}
}
- (BOOL)canSetCanonicalAlias
{
BOOL canSetCanonicalAlias = NO;
if (self.mainSession)
{
// Check user's power level to know whether the user is allowed to set the main address
MXRoomPowerLevels *powerLevels = [mxRoomState powerLevels];
NSInteger oneSelfPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mainSession.myUser.userId];
if (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomAliases])
{
canSetCanonicalAlias = YES;
}
}
return canSetCanonicalAlias;
}
- (void)shouldRemoveCanonicalAlias:(void (^)(void))didRemoveCanonicalAlias
{
// Prompt the user before removing the current main address
[currentAlert dismissViewControllerAnimated:NO completion:nil];
__weak typeof(self) weakSelf = self;
currentAlert = [UIAlertController alertControllerWithTitle:[VectorL10n roomDetailsAddressesDisableMainAddressPromptTitle]
message:[VectorL10n roomDetailsAddressesDisableMainAddressPromptMsg]
preferredStyle:UIAlertControllerStyleAlert];
[currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n cancel]
style:UIAlertActionStyleCancel
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->currentAlert = nil;
}
}]];
[currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n continue]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->currentAlert = nil;
// Remove the canonical address
if (self->mxRoomState.canonicalAlias.length)
{
self->updatedItemsDict[kRoomSettingsCanonicalAliasKey] = @"";
}
else
{
[self->updatedItemsDict removeObjectForKey:kRoomSettingsCanonicalAliasKey];
}
[self updateSections];
[self getNavigationItem].rightBarButtonItem.enabled = (self->updatedItemsDict.count != 0);
if (didRemoveCanonicalAlias)
{
didRemoveCanonicalAlias();
}
}
}]];
[currentAlert mxk_setAccessibilityIdentifier:@"RoomSettingsVCRemoveCanonicalAliasAlert"];
[self presentViewController:currentAlert animated:YES completion:nil];
}
#pragma mark - MXKRoomMemberDetailsViewControllerDelegate
- (void)roomMemberDetailsViewController:(MXKRoomMemberDetailsViewController *)roomMemberDetailsViewController startChatWithMemberId:(NSString *)matrixId completion:(void (^)(void))completion
{
[[AppDelegate theDelegate] showNewDirectChat:matrixId withMatrixSession:mxRoom.mxSession completion:completion];
}
#pragma mark - actions
- (void)onRoomAvatarTap:(UITapGestureRecognizer *)recognizer
{
SingleImagePickerPresenter *singleImagePickerPresenter = [[SingleImagePickerPresenter alloc] initWithSession:self.mainSession];
singleImagePickerPresenter.delegate = self;
UIView *sourceView;
NSIndexPath *indexPath = [_tableViewSections exactIndexPathForRowTag:ROOM_SETTINGS_MAIN_SECTION_ROW_PHOTO sectionTag:SECTION_TAG_MAIN];
if (indexPath)
{
sourceView = [self.tableView cellForRowAtIndexPath:indexPath];
}
[singleImagePickerPresenter presentFrom:self sourceView:sourceView sourceRect:sourceView.bounds animated:YES];
self.imagePickerPresenter = singleImagePickerPresenter;
}
- (void)toggleRoomNotification:(UISwitch*)theSwitch
{
if (theSwitch.on == (mxRoom.isMute || mxRoom.isMentionsOnly))
{
[updatedItemsDict removeObjectForKey:kRoomSettingsMuteNotifKey];
}
else
{
updatedItemsDict[kRoomSettingsMuteNotifKey] = @(theSwitch.on);
}
[self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0);
}
- (void)toggleFavorite:(UISwitch *)theSwitch
{
if (theSwitch.on)
{
if (mxRoom.accountData.tags[kMXRoomTagFavourite])
{
[updatedItemsDict removeObjectForKey:kRoomSettingsTagKey];
}
else
{
updatedItemsDict[kRoomSettingsTagKey] = kMXRoomTagFavourite;
}
}
else
{
// The user wants to unselect this tag
// Retrieve the current change on room tag (if any)
NSString *updatedRoomTag = updatedItemsDict[kRoomSettingsTagKey];
// Check the actual tag on mxRoom
if (mxRoom.accountData.tags[kMXRoomTagFavourite])
{
// The actual tag must be updated, check whether another tag is already set
if (!updatedRoomTag)
{
updatedItemsDict[kRoomSettingsTagKey] = @"";
}
}
else if (updatedRoomTag && [updatedRoomTag isEqualToString:kMXRoomTagFavourite])
{
// Cancel the updated tag, but take into account the cancellation of another tag when 'tappedRoomTag' was selected.
if (mxRoom.accountData.tags.count)
{
updatedItemsDict[kRoomSettingsTagKey] = @"";
}
else
{
[updatedItemsDict removeObjectForKey:kRoomSettingsTagKey];
}
}
}
[self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0);
}
- (void)toggleDirectChat:(UISwitch*)theSwitch
{
if (theSwitch.on == mxRoom.isDirect)
{
[updatedItemsDict removeObjectForKey:kRoomSettingsDirectChatKey];
}
else
{
updatedItemsDict[kRoomSettingsDirectChatKey] = @(theSwitch.on);
}
[self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0);
}
- (void)toggleEncryption:(UISwitch*)theSwitch
{
if (theSwitch.on)
{
updatedItemsDict[kRoomSettingsEncryptionKey] = @(YES);
[self getNavigationItem].rightBarButtonItem.enabled = self->updatedItemsDict.count;
}
else
{
[updatedItemsDict removeObjectForKey:kRoomSettingsEncryptionKey];
}
[self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0);
}
- (void)toggleBlacklistUnverifiedDevice:(UISwitch*)theSwitch
{
if ([mxRoom.mxSession.crypto isBlacklistUnverifiedDevicesInRoom:mxRoom.roomId] != theSwitch.on)
{
updatedItemsDict[kRoomSettingsEncryptionBlacklistUnverifiedDevicesKey] = @(theSwitch.on);
}
else
{
[updatedItemsDict removeObjectForKey:kRoomSettingsEncryptionBlacklistUnverifiedDevicesKey];
}
[self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0);
}
- (void)toggleDirectoryVisibility:(UISwitch*)theSwitch
{
MXRoomDirectoryVisibility visibility = theSwitch.on ? kMXRoomDirectoryVisibilityPublic : kMXRoomDirectoryVisibilityPrivate;
// Check whether the actual settings has been retrieved
if (actualDirectoryVisibility)
{
if ([visibility isEqualToString:actualDirectoryVisibility])
{
[updatedItemsDict removeObjectForKey:kRoomSettingsDirectoryKey];
}
else
{
updatedItemsDict[kRoomSettingsDirectoryKey] = visibility;
}
}
else
{
updatedItemsDict[kRoomSettingsDirectoryKey] = visibility;
}
[self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0);
}
- (void)showRoomAccessFlow
{
MXRoom *room = [self.mainSession roomWithRoomId:self.roomId];
if (room) {
roomAccessPresenter = [[RoomAccessCoordinatorBridgePresenter alloc] initWithRoom:room parentSpaceId:self.parentSpaceId];
roomAccessPresenter.delegate = self;
[roomAccessPresenter presentFrom:self animated:YES];
}
}
- (void)showSuggestToSpaceMembers
{
MXRoom *room = [self.mainSession roomWithRoomId:self.roomId];
if (room) {
roomSuggestionPresenter = [[RoomSuggestionCoordinatorBridgePresenter alloc] initWithRoom:room];
roomSuggestionPresenter.delegate = self;
[roomSuggestionPresenter presentFrom:self animated:YES];
}
}
- (void)setRoomAliasAsMainAddress:(NSString *)alias
{
NSString *currentCanonicalAlias = mxRoomState.canonicalAlias;
// Update the current canonical address
if ([alias isEqualToString:currentCanonicalAlias])
{
[updatedItemsDict removeObjectForKey:kRoomSettingsCanonicalAliasKey];
}
else
{
updatedItemsDict[kRoomSettingsCanonicalAliasKey] = alias;
}
[self updateSections];
[self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0);
}
- (void)removeAddressAtIndexPath:(NSIndexPath *)indexPath
{
indexPath = [_tableViewSections tagsIndexPathFromTableViewIndexPath:indexPath];
NSInteger row = indexPath.row;
row = ROOM_SETTINGS_ROOM_ADDRESS_ALIAS_OFFSET - row;
if (row < roomAddresses.count)
{
NSString *alias = roomAddresses[row];
[self removeRoomAlias:alias];
}
}
- (void)removeRoomAlias:(NSString*)roomAlias
{
NSString *canonicalAlias;
if (updatedItemsDict[kRoomSettingsCanonicalAliasKey])
{
canonicalAlias = updatedItemsDict[kRoomSettingsCanonicalAliasKey];
}
else
{
canonicalAlias = mxRoomState.canonicalAlias;
}
// Check whether this alias is the main address
if (canonicalAlias && [roomAlias isEqualToString:canonicalAlias])
{
// Prompt user before remove this alias which is the main address
[self shouldRemoveCanonicalAlias:^{
// The room alias can be removed now
[self removeRoomAlias:roomAlias];
}];
}
else
{
// Check whether the alias has just been added
NSMutableArray<NSString *> *addedAlias = updatedItemsDict[kRoomSettingsNewAliasesKey];
if (addedAlias && [addedAlias indexOfObject:roomAlias] != NSNotFound)
{
[addedAlias removeObject:roomAlias];
if (!addedAlias.count)
{
[updatedItemsDict removeObjectForKey:kRoomSettingsNewAliasesKey];
}
}
else
{
NSMutableArray<NSString *> *removedAlias = updatedItemsDict[kRoomSettingsRemovedAliasesKey];
if (!removedAlias)
{
removedAlias = [NSMutableArray array];
updatedItemsDict[kRoomSettingsRemovedAliasesKey] = removedAlias;
}
[removedAlias addObject:roomAlias];
}
[self updateSections];
[self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0);
}
}
- (BOOL)addRoomAlias:(NSString*)roomAlias
{
// Check whether the provided alias is valid
if ([MXTools isMatrixRoomAlias:roomAlias])
{
// Check whether this alias has just been deleted
NSMutableArray<NSString *> *removedAlias = updatedItemsDict[kRoomSettingsRemovedAliasesKey];
if (removedAlias && [removedAlias indexOfObject:roomAlias] != NSNotFound)
{
[removedAlias removeObject:roomAlias];
if (!removedAlias.count)
{
[updatedItemsDict removeObjectForKey:kRoomSettingsRemovedAliasesKey];
}
}
// Check whether this alias is not already defined for this room
else if ([roomAddresses indexOfObject:roomAlias] == NSNotFound)
{
NSMutableArray<NSString *> *addedAlias = updatedItemsDict[kRoomSettingsNewAliasesKey];
if (!addedAlias)
{
addedAlias = [NSMutableArray array];
updatedItemsDict[kRoomSettingsNewAliasesKey] = addedAlias;
}
[addedAlias addObject:roomAlias];
}
if (!roomAddresses.count)
{
// The first added alias is defined as the main address by default.
// Update the current canonical address.
NSString *currentCanonicalAlias = mxRoomState.canonicalAlias;
if (currentCanonicalAlias && [roomAlias isEqualToString:currentCanonicalAlias])
{
// The right canonical alias is already defined
[updatedItemsDict removeObjectForKey:kRoomSettingsCanonicalAliasKey];
}
else
{
updatedItemsDict[kRoomSettingsCanonicalAliasKey] = roomAlias;
}
}
[self updateSections];
[self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0);
return YES;
}
// Prompt here user for invalid alias
__weak typeof(self) weakSelf = self;
[currentAlert dismissViewControllerAnimated:NO completion:nil];
NSString *alertMsg = [VectorL10n roomDetailsAddressesInvalidAddressPromptMsg:roomAlias];
currentAlert = [UIAlertController alertControllerWithTitle:[VectorL10n roomDetailsAddressesInvalidAddressPromptTitle]
message:alertMsg
preferredStyle:UIAlertControllerStyleAlert];
[currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n ok]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->currentAlert = nil;
}
}]];
[currentAlert mxk_setAccessibilityIdentifier:@"RoomSettingsVCAddAliasAlert"];
[self presentViewController:currentAlert animated:YES completion:nil];
return NO;
}
#pragma mark - TableViewCellWithCheckBoxesDelegate
- (void)tableViewCellWithCheckBoxes:(TableViewCellWithCheckBoxes *)tableViewCellWithCheckBoxes didTapOnCheckBoxAtIndex:(NSUInteger)index
{
if (tableViewCellWithCheckBoxes == roomTagCell)
{
NSString *tappedRoomTag = (index == 0) ? kMXRoomTagFavourite : kMXRoomTagLowPriority;
BOOL isCurrentlySelected = [roomTagCell checkBoxValueAtIndex:index];
if (isCurrentlySelected)
{
// The user wants to unselect this tag
// Retrieve the current change on room tag (if any)
NSString *updatedRoomTag = updatedItemsDict[kRoomSettingsTagKey];
// Check the actual tag on mxRoom
if (mxRoom.accountData.tags[tappedRoomTag])
{
// The actual tag must be updated, check whether another tag is already set
if (!updatedRoomTag)
{
updatedItemsDict[kRoomSettingsTagKey] = @"";
}
}
else if (updatedRoomTag && [updatedRoomTag isEqualToString:tappedRoomTag])
{
// Cancel the updated tag, but take into account the cancellation of another tag when 'tappedRoomTag' was selected.
if (mxRoom.accountData.tags.count)
{
updatedItemsDict[kRoomSettingsTagKey] = @"";
}
else
{
[updatedItemsDict removeObjectForKey:kRoomSettingsTagKey];
}
}
// Unselect the tag
[roomTagCell setCheckBoxValue:NO atIndex:index];
}
else
{
// The user wants to select this room tag
// Check the actual tag on mxRoom
if (mxRoom.accountData.tags[tappedRoomTag])
{
[updatedItemsDict removeObjectForKey:kRoomSettingsTagKey];
}
else
{
updatedItemsDict[kRoomSettingsTagKey] = tappedRoomTag;
}
// Select the tapped tag
[roomTagCell setCheckBoxValue:YES atIndex:index];
}
[self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0);
}
}
#pragma mark - SingleImagePickerPresenterDelegate
- (void)singleImagePickerPresenterDidCancel:(SingleImagePickerPresenter *)presenter
{
[presenter dismissWithAnimated:YES completion:nil];
self.imagePickerPresenter = nil;
}
- (void)singleImagePickerPresenter:(SingleImagePickerPresenter *)presenter didSelectImageData:(NSData *)imageData withUTI:(MXKUTI *)uti
{
[presenter dismissWithAnimated:YES completion:nil];
self.imagePickerPresenter = nil;
UIImage *image = [UIImage imageWithData:imageData];
if (image)
{
[self getNavigationItem].rightBarButtonItem.enabled = YES;
updatedItemsDict[kRoomSettingsAvatarKey] = image;
[self refreshRoomSettings];
}
}
#pragma mark - TableViewSectionsDelegate
- (void)tableViewSectionsDidUpdateSections:(TableViewSections *)sections
{
[self.tableView reloadData];
}
#pragma mark - RoomAccessCoordinatorBridgePresenterDelegate
- (void)roomAccessCoordinatorBridgePresenterDelegate:(RoomAccessCoordinatorBridgePresenter *)coordinatorBridgePresenter didCancelRoomWithId:(NSString *)roomId
{
if (![roomId isEqualToString: self.roomId]) {
// Room Access Coordinator upgraded the actual room -> Need to move to replacement room
[self.delegate roomSettingsViewController:self didReplaceRoomWithReplacementId:roomId];
}
MXWeakify(self);
[roomAccessPresenter dismissWithAnimated:YES completion:^{
MXStrongifyAndReturnIfNil(self);
self->roomAccessPresenter = nil;
}];
}
- (void)roomAccessCoordinatorBridgePresenterDelegate:(RoomAccessCoordinatorBridgePresenter *)coordinatorBridgePresenter didCompleteRoomWithId:(NSString *)roomId
{
if (![roomId isEqualToString: self.roomId]) {
// Room Access Coordinator upgraded the actual room -> Need to move to replacement room
[self.delegate roomSettingsViewController:self didReplaceRoomWithReplacementId:roomId];
}
MXWeakify(self);
[roomAccessPresenter dismissWithAnimated:YES completion:^{
MXStrongifyAndReturnIfNil(self);
self->roomAccessPresenter = nil;
}];
}
#pragma mark - RoomSuggestionCoordinatorBridgePresenterDelegate
- (void)roomSuggestionCoordinatorBridgePresenterDelegateDidCancel:(RoomSuggestionCoordinatorBridgePresenter *)coordinatorBridgePresenter
{
[roomSuggestionPresenter dismissWithAnimated:YES completion:nil];
roomSuggestionPresenter = nil;
}
- (void)roomSuggestionCoordinatorBridgePresenterDelegateDidComplete:(RoomSuggestionCoordinatorBridgePresenter *)coordinatorBridgePresenter
{
MXWeakify(self);
[roomSuggestionPresenter dismissWithAnimated:YES completion:^{
MXStrongifyAndReturnIfNil(self);
self->roomSuggestionPresenter = nil;
[self refreshRoomSettings];
}];
}
@end