element-ios/Riot/Modules/Room/Settings/RoomSettingsViewController.m

4032 lines
170 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 "Riot-Swift.h"
#import "RoomMemberDetailsViewController.h"
#import <MobileCoreServices/MobileCoreServices.h>
enum
{
SECTION_TAG_MAIN,
SECTION_TAG_ACCESS,
SECTION_TAG_HISTORY,
SECTION_TAG_ADDRESSES,
SECTION_TAG_FLAIR,
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,
ROOM_SETTINGS_MAIN_SECTION_ROW_LEAVE
};
enum
{
ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_INVITED_ONLY,
ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_ANYONE_APART_FROM_GUEST,
ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_ANYONE,
ROOM_SETTINGS_ROOM_ACCESS_DIRECTORY_VISIBILITY,
ROOM_SETTINGS_ROOM_ACCESS_MISSING_ADDRESS_WARNING
};
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_RELATED_GROUPS_NEW_GROUP,
ROOM_SETTINGS_RELATED_GROUPS_OFFSET = 1000
};
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 kRoomSettingsNewRelatedGroupKey = @"kRoomSettingsNewRelatedGroupKey";
NSString *const kRoomSettingsRemovedRelatedGroupKey = @"kRoomSettingsRemovedRelatedGroupKey";
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 kRoomSettingsNewCommunityCellViewIdentifier = @"kRoomSettingsNewCommunityCellViewIdentifier";
NSString *const kRoomSettingsAddressCellViewIdentifier = @"kRoomSettingsAddressCellViewIdentifier";
NSString *const kRoomSettingsAdvancedCellViewIdentifier = @"kRoomSettingsAdvancedCellViewIdentifier";
NSString *const kRoomSettingsAdvancedEnableE2eCellViewIdentifier = @"kRoomSettingsAdvancedEnableE2eCellViewIdentifier";
NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSettingsAdvancedE2eEnabledCellViewIdentifier";
@interface RoomSettingsViewController () <SingleImagePickerPresenterDelegate, TableViewSectionsDelegate>
{
// 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
TableViewCellWithCheckBoxAndLabel *accessInvitedOnlyTickCell;
TableViewCellWithCheckBoxAndLabel *accessAnyoneApartGuestTickCell;
TableViewCellWithCheckBoxAndLabel *accessAnyoneTickCell;
UISwitch *directoryVisibilitySwitch;
MXRoomDirectoryVisibility actualDirectoryVisibility;
MXHTTPOperation* actualDirectoryVisibilityRequest;
// History Visibility items
NSMutableDictionary<MXRoomHistoryVisibility, TableViewCellWithCheckBoxAndLabel*> *historyVisibilityTickCells;
// Room aliases
NSMutableArray<NSString *> *roomAddresses;
NSUInteger localAddressesCount;
UITextField* addAddressTextField;
// Related groups/communities
NSMutableArray<NSString *> *relatedGroups;
UITextField* addGroupTextField;
// The potential image loader
MXMediaLoader *uploader;
// The pending http operation
MXHTTPOperation* pendingOperation;
// the updating spinner
UIActivityIndicatorView* updatingSpinner;
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;
}
@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];
relatedGroups = [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:MXKTableViewCellWithLabelAndTextField.class forCellReuseIdentifier:kRoomSettingsNewCommunityCellViewIdentifier];
[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]];
// 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];
// Screen tracking
[[Analytics sharedInstance] trackScreen:@"RoomSettings"];
[[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.mxk_adjustedContentInset.left, -self.tableView.mxk_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;
relatedGroups = nil;
if (extraEventsListener)
{
MXWeakify(self);
[mxRoom liveTimeline:^(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++;
}
[self refreshRelatedGroups];
// 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.roomSettingsScreenShowNotificationsV2)
{
[sectionMain addRowWithTag:ROOM_SETTINGS_MAIN_SECTION_ROW_MUTE_NOTIFICATIONS];
}
[sectionMain addRowWithTag:ROOM_SETTINGS_MAIN_SECTION_ROW_LEAVE];
[tmpSections addObject:sectionMain];
if (RiotSettings.shared.roomSettingsScreenAllowChangingAccessSettings)
{
Section *sectionAccess = [Section sectionWithTag:SECTION_TAG_ACCESS];
[sectionAccess addRowWithTag:ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_INVITED_ONLY];
[sectionAccess addRowWithTag:ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_ANYONE_APART_FROM_GUEST];
[sectionAccess addRowWithTag:ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_ANYONE];
// 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];
}
[sectionAccess addRowWithTag:ROOM_SETTINGS_ROOM_ACCESS_DIRECTORY_VISIBILITY];
if (mxRoom.isDirect)
{
sectionAccess.headerTitle = NSLocalizedStringFromTable(@"room_details_access_section_for_dm", @"Vector", nil);
}
else
{
sectionAccess.headerTitle = NSLocalizedStringFromTable(@"room_details_access_section", @"Vector", nil);
}
[tmpSections addObject:sectionAccess];
}
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 = NSLocalizedStringFromTable(@"room_details_history_section", @"Vector", nil);
[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 = NSLocalizedStringFromTable(@"room_details_addresses_section", @"Vector", nil);
[tmpSections addObject:sectionAddresses];
}
if (RiotSettings.shared.roomSettingsScreenShowFlairSettings)
{
Section *sectionFlair = [Section sectionWithTag:SECTION_TAG_FLAIR];
for (NSInteger counter = 0; counter < relatedGroups.count; counter++)
{
[sectionFlair addRowWithTag:counter + ROOM_SETTINGS_RELATED_GROUPS_OFFSET];
}
if (self.mainSession)
{
// Check user's power level to know whether the user is allowed to add communities to this room
MXRoomPowerLevels *powerLevels = [mxRoomState powerLevels];
NSInteger oneSelfPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mainSession.myUser.userId];
if (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomRelatedGroups])
{
[sectionFlair addRowWithTag:ROOM_SETTINGS_RELATED_GROUPS_NEW_GROUP];
}
}
sectionFlair.headerTitle = NSLocalizedStringFromTable(@"room_details_flair_section", @"Vector", nil);
if ([sectionFlair hasAnyRows])
{
[tmpSections addObject:sectionFlair];
}
}
if (bannedMembers.count)
{
Section *sectionBannedUsers = [Section sectionWithTag:SECTION_TAG_BANNED_USERS];
for (NSInteger counter = 0; counter < bannedMembers.count; counter++)
{
[sectionBannedUsers addRowWithTag:counter];
}
sectionBannedUsers.headerTitle = NSLocalizedStringFromTable(@"room_details_banned_users_section", @"Vector", nil);
[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 = NSLocalizedStringFromTable(@"room_details_advanced_section", @"Vector", nil);
[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:NSLocalizedStringFromTable(@"room_details_save_changes_prompt", @"Vector", nil) preferredStyle:UIAlertControllerStyleAlert];
[currentAlert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"no"]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->currentAlert = nil;
[self->updatedItemsDict removeAllObjects];
[self withdrawViewControllerAnimated:YES completion:nil];
}
}]];
[currentAlert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"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:NSLocalizedStringFromTable(@"room_details_copy_room_id", @"Vector", nil)
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:[NSBundle mxk_localizedStringForKey:@"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:NSLocalizedStringFromTable(@"room_details_unset_main_address", @"Vector", nil)
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:NSLocalizedStringFromTable(@"room_details_set_main_address", @"Vector", nil)
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->currentAlert = nil;
[self setRoomAliasAsMainAddress:roomAliasLabel.text];
}
}]];
}
}
[currentAlert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"room_details_copy_room_address", @"Vector", nil)
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:NSLocalizedStringFromTable(@"room_details_copy_room_url", @"Vector", nil)
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];
if (permalink)
{
MXKPasteboardManager.shared.pasteboard.string = permalink;
}
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:[NSBundle mxk_localizedStringForKey:@"delete"]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->currentAlert = nil;
[self removeRoomAlias:roomAliasLabel.text];
}
}]];
[currentAlert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"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;
}
}];
}
- (void)refreshRelatedGroups
{
// Refresh here the related communities list.
[relatedGroups removeAllObjects];
[relatedGroups addObjectsFromArray:mxRoomState.relatedGroups];
NSArray *removedCommunities = updatedItemsDict[kRoomSettingsRemovedRelatedGroupKey];
if (removedCommunities.count)
{
for (NSUInteger index = 0; index < relatedGroups.count;)
{
NSString *groupId = relatedGroups[index];
// Check whether the user did not remove it
if ([removedCommunities indexOfObject:groupId] != NSNotFound)
{
[relatedGroups removeObjectAtIndex:index];
}
else
{
index++;
}
}
}
NSArray *communities = updatedItemsDict[kRoomSettingsNewRelatedGroupKey];
if (communities)
{
[relatedGroups addObjectsFromArray:communities];
}
}
#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;
}
}
else if (textField == addGroupTextField)
{
// Dismiss the keyboard
[addGroupTextField resignFirstResponder];
NSString *groupId = addGroupTextField.text;
if (!groupId.length || [self addCommunity:groupId])
{
// Reset the input field
addGroupTextField.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
{
[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:[NSBundle mxk_localizedStringForKey:@"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:NSLocalizedStringFromTable(@"retry", @"Vector", nil)
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 = NSLocalizedStringFromTable(@"room_details_fail_to_update_avatar", @"Vector", nil);
}
[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 = NSLocalizedStringFromTable(@"room_details_fail_to_update_avatar", @"Vector", nil);
}
[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 = NSLocalizedStringFromTable(@"room_details_fail_to_update_room_name", @"Vector", nil);
}
[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 = NSLocalizedStringFromTable(@"room_details_fail_to_update_topic", @"Vector", nil);
}
[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 = NSLocalizedStringFromTable(@"room_details_fail_to_update_room_guest_access", @"Vector", nil);
}
[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 = NSLocalizedStringFromTable(@"room_details_fail_to_update_room_join_rule", @"Vector", nil);
}
[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 = NSLocalizedStringFromTable(@"room_details_fail_to_update_history_visibility", @"Vector", nil);
}
[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 = NSLocalizedStringFromTable(@"room_details_fail_to_add_room_aliases", @"Vector", nil);
}
[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 = NSLocalizedStringFromTable(@"room_details_fail_to_remove_room_aliases", @"Vector", nil);
}
[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 = NSLocalizedStringFromTable(@"room_details_fail_to_update_room_canonical_alias", @"Vector", nil);
}
[self onSaveFailed:message withKeys:@[kRoomSettingsCanonicalAliasKey]];
});
}
}];
return;
}
// Related groups
if (updatedItemsDict[kRoomSettingsNewRelatedGroupKey] || updatedItemsDict[kRoomSettingsRemovedRelatedGroupKey])
{
[self refreshRelatedGroups];
pendingOperation = [mxRoom setRelatedGroups:relatedGroups success:^{
if (weakSelf)
{
typeof(self) self = weakSelf;
self->pendingOperation = nil;
[self->updatedItemsDict removeObjectForKey:kRoomSettingsNewRelatedGroupKey];
[self->updatedItemsDict removeObjectForKey:kRoomSettingsRemovedRelatedGroupKey];
[self onSave:nil];
}
} failure:^(NSError *error) {
MXLogDebug(@"[RoomSettingsViewController] Update room communities failed");
if (weakSelf)
{
typeof(self) self = weakSelf;
self->pendingOperation = nil;
dispatch_async(dispatch_get_main_queue(), ^{
NSString* message = error.localizedDescription;
if (!message.length)
{
message = NSLocalizedStringFromTable(@"room_details_fail_to_update_room_communities", @"Vector", nil);
}
[self onSaveFailed:message withKeys:@[kRoomSettingsNewRelatedGroupKey,kRoomSettingsRemovedRelatedGroupKey]];
});
}
}];
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 = NSLocalizedStringFromTable(@"room_details_fail_to_update_room_direct", @"Vector", nil);
}
[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 = NSLocalizedStringFromTable(@"room_details_fail_to_update_room_directory_visibility", @"Vector", nil);
}
[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 = NSLocalizedStringFromTable(@"room_details_fail_to_enable_encryption", @"Vector", nil);
}
[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];
[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 = NSLocalizedStringFromTable(@"room_details_mute_notifs", @"Vector", nil);
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 = NSLocalizedStringFromTable(@"room_details_direct_chat", @"Vector", nil);
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 = roomPhotoCell.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 = NSLocalizedStringFromTable(@"room_details_photo_for_dm", @"Vector", nil);
}
else
{
roomPhotoCell.mxkLabel.text = NSLocalizedStringFromTable(@"room_details_photo", @"Vector", nil);
}
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 = roomTopicCell.vc_separatorInset.left;
roomTopicCell.label.text = NSLocalizedStringFromTable(@"room_details_topic", @"Vector", nil);
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 = roomNameCell.vc_separatorInset.left;
roomNameCell.mxkTextFieldLeadingConstraint.constant = 16;
roomNameCell.mxkTextFieldTrailingConstraint.constant = 15;
if (mxRoom.isDirect)
{
roomNameCell.mxkLabel.text = NSLocalizedStringFromTable(@"room_details_room_name_for_dm", @"Vector", nil);
}
else
{
roomNameCell.mxkLabel.text = NSLocalizedStringFromTable(@"room_details_room_name", @"Vector", nil);
}
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 = roomTagCell.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 = NSLocalizedStringFromTable(@"room_details_favourite_tag", @"Vector", nil);
label = labels[1];
label.textColor = ThemeService.shared.theme.textPrimaryColor;
label.text = NSLocalizedStringFromTable(@"room_details_low_priority_tag", @"Vector", nil);
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 = NSLocalizedStringFromTable(@"room_details_favourite_tag", @"Vector", nil);
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 (row == ROOM_SETTINGS_MAIN_SECTION_ROW_LEAVE)
{
MXKTableViewCellWithButton *leaveCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithButton defaultReuseIdentifier] forIndexPath:indexPath];
NSString* title = NSLocalizedStringFromTable(@"leave", @"Vector", nil);
[leaveCell.mxkButton setTitle:title forState:UIControlStateNormal];
[leaveCell.mxkButton setTitle:title forState:UIControlStateHighlighted];
[leaveCell.mxkButton setTintColor:ThemeService.shared.theme.tintColor];
leaveCell.mxkButton.titleLabel.font = [UIFont systemFontOfSize:17];
[leaveCell.mxkButton removeTarget:self action:nil forControlEvents:UIControlEventTouchUpInside];
[leaveCell.mxkButton addTarget:self action:@selector(onLeave:) forControlEvents:UIControlEventTouchUpInside];
cell = leaveCell;
}
}
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 = NSLocalizedStringFromTable(@"room_details_access_section_directory_toggle_for_dm", @"Vector", nil);
}
else
{
directoryToggleCell.mxkLabel.text = NSLocalizedStringFromTable(@"room_details_access_section_directory_toggle", @"Vector", nil);
}
[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 = NSLocalizedStringFromTable(@"room_details_access_section_no_address_warning", @"Vector", nil);
}
else
{
TableViewCellWithCheckBoxAndLabel *roomAccessCell = [tableView dequeueReusableCellWithIdentifier:[TableViewCellWithCheckBoxAndLabel defaultReuseIdentifier] forIndexPath:indexPath];
roomAccessCell.checkBoxLeadingConstraint.constant = roomAccessCell.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;
}
if (row == ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_INVITED_ONLY)
{
roomAccessCell.label.text = NSLocalizedStringFromTable(@"room_details_access_section_invited_only", @"Vector", nil);
roomAccessCell.enabled = ([joinRule isEqualToString:kMXRoomJoinRuleInvite]);
accessInvitedOnlyTickCell = roomAccessCell;
}
else if (row == ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_ANYONE_APART_FROM_GUEST)
{
if (mxRoom.isDirect)
{
roomAccessCell.label.text = NSLocalizedStringFromTable(@"room_details_access_section_anyone_apart_from_guest_for_dm", @"Vector", nil);
}
else
{
roomAccessCell.label.text = NSLocalizedStringFromTable(@"room_details_access_section_anyone_apart_from_guest", @"Vector", nil);
}
roomAccessCell.enabled = ([joinRule isEqualToString:kMXRoomJoinRulePublic] && [guestAccess isEqualToString:kMXRoomGuestAccessForbidden]);
accessAnyoneApartGuestTickCell = roomAccessCell;
}
else if (row == ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_ANYONE)
{
if (mxRoom.isDirect)
{
roomAccessCell.label.text = NSLocalizedStringFromTable(@"room_details_access_section_anyone_for_dm", @"Vector", nil);
}
else
{
roomAccessCell.label.text = NSLocalizedStringFromTable(@"room_details_access_section_anyone", @"Vector", nil);
}
roomAccessCell.enabled = ([joinRule isEqualToString:kMXRoomJoinRulePublic] && [guestAccess isEqualToString:kMXRoomGuestAccessCanJoin]);
accessAnyoneTickCell = roomAccessCell;
}
// 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_HISTORY)
{
TableViewCellWithCheckBoxAndLabel *historyVisibilityCell = [tableView dequeueReusableCellWithIdentifier:[TableViewCellWithCheckBoxAndLabel defaultReuseIdentifier] forIndexPath:indexPath];
historyVisibilityCell.checkBoxLeadingConstraint.constant = historyVisibilityCell.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 = NSLocalizedStringFromTable(@"room_details_history_section_anyone", @"Vector", nil);
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 = NSLocalizedStringFromTable(@"room_details_history_section_members_only", @"Vector", nil);
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 = NSLocalizedStringFromTable(@"room_details_history_section_members_only_since_invited", @"Vector", nil);
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 = NSLocalizedStringFromTable(@"room_details_history_section_members_only_since_joined", @"Vector", nil);
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 = addAddressCell.vc_separatorInset.left;
addAddressCell.mxkTextFieldTrailingConstraint.constant = 15;
addAddressCell.mxkLabel.text = nil;
addAddressCell.accessoryType = UITableViewCellAccessoryNone;
addAddressCell.accessoryView = [[UIImageView alloc] initWithImage:[[UIImage imageNamed:@"plus_icon"] vc_tintedImageUsingColor:ThemeService.shared.theme.textPrimaryColor]];
addAddressTextField = addAddressCell.mxkTextField;
addAddressTextField.placeholder = [NSString stringWithFormat:NSLocalizedStringFromTable(@"room_details_new_address_placeholder", @"Vector", nil), 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 = NSLocalizedStringFromTable(@"room_details_no_local_addresses_for_dm", @"Vector", nil);
}
else
{
addressCell.textLabel.text = NSLocalizedStringFromTable(@"room_details_no_local_addresses", @"Vector", nil);
}
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:[UIImage imageNamed:@"main_alias_icon"]];
}
}
}
cell = addressCell;
}
}
else if (section == SECTION_TAG_FLAIR)
{
if (row == ROOM_SETTINGS_RELATED_GROUPS_NEW_GROUP)
{
MXKTableViewCellWithLabelAndTextField *addCommunityCell = [tableView dequeueReusableCellWithIdentifier:kRoomSettingsNewCommunityCellViewIdentifier forIndexPath:indexPath];
// Retrieve the current edited value if any
NSString *currentValue = (addGroupTextField ? addGroupTextField.text : nil);
addCommunityCell.mxkLabelLeadingConstraint.constant = 0;
addCommunityCell.mxkTextFieldLeadingConstraint.constant = addCommunityCell.vc_separatorInset.left;
addCommunityCell.mxkTextFieldTrailingConstraint.constant = 15;
addCommunityCell.mxkLabel.text = nil;
addCommunityCell.accessoryType = UITableViewCellAccessoryNone;
addCommunityCell.accessoryView = [[UIImageView alloc] initWithImage:[[UIImage imageNamed:@"plus_icon"] vc_tintedImageUsingColor:ThemeService.shared.theme.textPrimaryColor]];
addGroupTextField = addCommunityCell.mxkTextField;
addGroupTextField.placeholder = [NSString stringWithFormat:NSLocalizedStringFromTable(@"room_details_new_flair_placeholder", @"Vector", nil), self.mainSession.matrixRestClient.homeserverSuffix];
addGroupTextField.attributedPlaceholder = [[NSAttributedString alloc]
initWithString:addGroupTextField.placeholder
attributes:@{NSForegroundColorAttributeName: ThemeService.shared.theme.placeholderTextColor}];
addGroupTextField.userInteractionEnabled = YES;
addGroupTextField.text = currentValue;
addGroupTextField.textColor = ThemeService.shared.theme.textSecondaryColor;
addGroupTextField.tintColor = ThemeService.shared.theme.tintColor;
addGroupTextField.font = [UIFont systemFontOfSize:17];
addGroupTextField.borderStyle = UITextBorderStyleNone;
addGroupTextField.textAlignment = NSTextAlignmentLeft;
addGroupTextField.autocorrectionType = UITextAutocorrectionTypeNo;
addGroupTextField.spellCheckingType = UITextSpellCheckingTypeNo;
addGroupTextField.delegate = self;
cell = addCommunityCell;
}
else if (row >= ROOM_SETTINGS_RELATED_GROUPS_OFFSET)
{
UITableViewCell *communityCell = [tableView dequeueReusableCellWithIdentifier:kRoomSettingsAddressCellViewIdentifier forIndexPath:indexPath];
communityCell.textLabel.font = [UIFont systemFontOfSize:16];
communityCell.textLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
communityCell.textLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;
communityCell.accessoryView = nil;
communityCell.accessoryType = UITableViewCellAccessoryNone;
communityCell.selectionStyle = UITableViewCellSelectionStyleNone;
NSInteger index = row - ROOM_SETTINGS_RELATED_GROUPS_OFFSET;
if (index < relatedGroups.count)
{
communityCell.textLabel.text = relatedGroups[index];
}
cell = communityCell;
}
}
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 = NSLocalizedStringFromTable(@"room_details_advanced_room_id_for_dm", @"Vector", nil);
}
else
{
cell.textLabel.text = NSLocalizedStringFromTable(@"room_details_advanced_room_id", @"Vector", nil);
}
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 = NSLocalizedStringFromTable(@"room_details_advanced_e2e_encryption_blacklist_unverified_devices", @"Vector", nil);
// 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 = NSLocalizedStringFromTable(@"room_details_advanced_e2e_encryption_enabled_for_dm", @"Vector", nil);
}
else
{
cell.textLabel.text = NSLocalizedStringFromTable(@"room_details_advanced_e2e_encryption_enabled", @"Vector", nil);
}
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 = NSLocalizedStringFromTable(@"room_details_advanced_enable_e2e_encryption", @"Vector", nil);
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 = NSLocalizedStringFromTable(@"room_details_advanced_e2e_encryption_disabled_for_dm", @"Vector", nil);
}
else
{
cell.textLabel.text = NSLocalizedStringFromTable(@"room_details_advanced_e2e_encryption_disabled", @"Vector", nil);
}
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 = cell.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_SECTION_ROW_INVITED_ONLY)
{
// Ignore the selection if the option is already enabled
if (! accessInvitedOnlyTickCell.isEnabled)
{
// Enable this option
accessInvitedOnlyTickCell.enabled = YES;
// Disable other options
accessAnyoneApartGuestTickCell.enabled = NO;
accessAnyoneTickCell.enabled = NO;
// Check the actual option
if ([mxRoomState.joinRule isEqualToString:kMXRoomJoinRuleInvite])
{
// No change on room access
[updatedItemsDict removeObjectForKey:kRoomSettingsJoinRuleKey];
[updatedItemsDict removeObjectForKey:kRoomSettingsGuestAccessKey];
}
else
{
updatedItemsDict[kRoomSettingsJoinRuleKey] = kMXRoomJoinRuleInvite;
// Update guest access to allow guest on invitation.
// Note: if guest_access is "forbidden" here, guests cannot join this room even if explicitly invited.
if ([mxRoomState.guestAccess isEqualToString:kMXRoomGuestAccessCanJoin])
{
[updatedItemsDict removeObjectForKey:kRoomSettingsGuestAccessKey];
}
else
{
updatedItemsDict[kRoomSettingsGuestAccessKey] = kMXRoomGuestAccessCanJoin;
}
}
isUpdated = YES;
}
}
else if (row == ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_ANYONE_APART_FROM_GUEST)
{
// Ignore the selection if the option is already enabled
if (! accessAnyoneApartGuestTickCell.isEnabled)
{
// Enable this option
accessAnyoneApartGuestTickCell.enabled = YES;
// Disable other options
accessInvitedOnlyTickCell.enabled = NO;
accessAnyoneTickCell.enabled = NO;
// Check the actual option
if ([mxRoomState.joinRule isEqualToString:kMXRoomJoinRulePublic] && [mxRoomState.guestAccess isEqualToString:kMXRoomGuestAccessForbidden])
{
// No change on room access
[updatedItemsDict removeObjectForKey:kRoomSettingsJoinRuleKey];
[updatedItemsDict removeObjectForKey:kRoomSettingsGuestAccessKey];
}
else
{
if ([mxRoomState.joinRule isEqualToString:kMXRoomJoinRulePublic])
{
[updatedItemsDict removeObjectForKey:kRoomSettingsJoinRuleKey];
}
else
{
updatedItemsDict[kRoomSettingsJoinRuleKey] = kMXRoomJoinRulePublic;
}
if ([mxRoomState.guestAccess isEqualToString:kMXRoomGuestAccessForbidden])
{
[updatedItemsDict removeObjectForKey:kRoomSettingsGuestAccessKey];
}
else
{
updatedItemsDict[kRoomSettingsGuestAccessKey] = kMXRoomGuestAccessForbidden;
}
}
isUpdated = YES;
}
}
else if (row == ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_ANYONE)
{
// Ignore the selection if the option is already enabled
if (! accessAnyoneTickCell.isEnabled)
{
// Enable this option
accessAnyoneTickCell.enabled = YES;
// Disable other options
accessInvitedOnlyTickCell.enabled = NO;
accessAnyoneApartGuestTickCell.enabled = NO;
// Check the actual option
if ([mxRoomState.joinRule isEqualToString:kMXRoomJoinRulePublic] && [mxRoomState.guestAccess isEqualToString:kMXRoomGuestAccessCanJoin])
{
// No change on room access
[updatedItemsDict removeObjectForKey:kRoomSettingsJoinRuleKey];
[updatedItemsDict removeObjectForKey:kRoomSettingsGuestAccessKey];
}
else
{
if ([mxRoomState.joinRule isEqualToString:kMXRoomJoinRulePublic])
{
[updatedItemsDict removeObjectForKey:kRoomSettingsJoinRuleKey];
}
else
{
updatedItemsDict[kRoomSettingsJoinRuleKey] = kMXRoomJoinRulePublic;
}
if ([mxRoomState.guestAccess isEqualToString:kMXRoomGuestAccessCanJoin])
{
[updatedItemsDict removeObjectForKey:kRoomSettingsGuestAccessKey];
}
else
{
updatedItemsDict[kRoomSettingsGuestAccessKey] = kMXRoomGuestAccessCanJoin;
}
}
isUpdated = YES;
}
}
else 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];
}
}
}
if (isUpdated)
{
[self updateSections];
[self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0);
}
}
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_FLAIR)
{
if (row == ROOM_SETTINGS_RELATED_GROUPS_NEW_GROUP)
{
NSString *groupId = addGroupTextField.text;
if (!groupId.length || [self addCommunity:groupId])
{
// Reset the input field
addGroupTextField.text = nil;
}
}
}
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 = [[UIImage imageNamed:@"remove_icon"] vc_notRenderedImage];
// Create swipe action configuration
NSArray<UIContextualAction*> *actions = @[
removeAddressAction
];
UISwipeActionsConfiguration *swipeActionConfiguration = [UISwipeActionsConfiguration configurationWithActions:actions];
swipeActionConfiguration.performsFirstActionWithFullSwipe = NO;
return swipeActionConfiguration;
}
else if (section == SECTION_TAG_FLAIR && row >= ROOM_SETTINGS_RELATED_GROUPS_OFFSET)
{
UIContextualAction *removeAddressAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleDestructive
title:@" "
handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
[self removeCommunityAtIndexPath:indexPath];
completionHandler(YES);
}];
removeAddressAction.backgroundColor = ThemeService.shared.theme.headerBackgroundColor;
removeAddressAction.image = [[UIImage imageNamed:@"remove_icon"] 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:NSLocalizedStringFromTable(@"room_details_history_section_prompt_title", @"Vector", nil) message:NSLocalizedStringFromTable(@"room_details_history_section_prompt_msg", @"Vector", nil) preferredStyle:UIAlertControllerStyleAlert];
[currentAlert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"]
style:UIAlertActionStyleCancel
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->currentAlert = nil;
}
}]];
[currentAlert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"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:NSLocalizedStringFromTable(@"room_details_addresses_disable_main_address_prompt_title", @"Vector", nil) message:NSLocalizedStringFromTable(@"room_details_addresses_disable_main_address_prompt_msg", @"Vector", nil) preferredStyle:UIAlertControllerStyleAlert];
[currentAlert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"]
style:UIAlertActionStyleCancel
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->currentAlert = nil;
}
}]];
[currentAlert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"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] createDirectChatWithUserId:matrixId completion:completion];
}
#pragma mark - actions
- (void)onLeave:(id)sender
{
// Prompt user before leaving the room
__weak typeof(self) weakSelf = self;
[currentAlert dismissViewControllerAnimated:NO completion:nil];
NSString *title, *message;
if ([self.mainSession roomWithRoomId:self.roomId].isDirect)
{
title = NSLocalizedStringFromTable(@"room_participants_leave_prompt_title_for_dm", @"Vector", nil);
message = NSLocalizedStringFromTable(@"room_participants_leave_prompt_msg_for_dm", @"Vector", nil);
}
else
{
title = NSLocalizedStringFromTable(@"room_participants_leave_prompt_title", @"Vector", nil);
message = NSLocalizedStringFromTable(@"room_participants_leave_prompt_msg", @"Vector", nil);
}
currentAlert = [UIAlertController alertControllerWithTitle:title
message:message
preferredStyle:UIAlertControllerStyleAlert];
[currentAlert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"]
style:UIAlertActionStyleCancel
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->currentAlert = nil;
}
}]];
[currentAlert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"leave", @"Vector", nil)
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->currentAlert = nil;
[self startActivityIndicator];
[self->mxRoom leave:^{
[self withdrawViewControllerAnimated:YES completion:nil];
} failure:^(NSError *error) {
[self stopActivityIndicator];
MXLogDebug(@"[RoomSettingsViewController] Leave room failed");
// Alert user
[[AppDelegate theDelegate] showErrorAsAlert:error];
}];
}
}]];
[currentAlert mxk_setAccessibilityIdentifier:@"RoomSettingsVCLeaveAlert"];
[self presentViewController:currentAlert animated:YES completion:nil];
}
- (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)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)removeCommunityAtIndexPath:(NSIndexPath *)indexPath
{
indexPath = [_tableViewSections tagsIndexPathFromTableViewIndexPath:indexPath];
NSInteger row = indexPath.row;
NSInteger index = row - ROOM_SETTINGS_RELATED_GROUPS_OFFSET;
if (index < relatedGroups.count)
{
NSString *groupId = relatedGroups[index];
[self removeCommunity:groupId];
}
}
- (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);
}
}
- (void)removeCommunity:(NSString*)groupId
{
// Check whether the alias has just been added
NSMutableArray<NSString *> *addedGroup = updatedItemsDict[kRoomSettingsNewRelatedGroupKey];
if (addedGroup && [addedGroup indexOfObject:groupId] != NSNotFound)
{
[addedGroup removeObject:groupId];
if (!addedGroup.count)
{
[updatedItemsDict removeObjectForKey:kRoomSettingsNewRelatedGroupKey];
}
}
else
{
NSMutableArray<NSString *> *removedGroup = updatedItemsDict[kRoomSettingsRemovedRelatedGroupKey];
if (!removedGroup)
{
removedGroup = [NSMutableArray array];
updatedItemsDict[kRoomSettingsRemovedRelatedGroupKey] = removedGroup;
}
[removedGroup addObject:groupId];
}
[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 = [NSString stringWithFormat:NSLocalizedStringFromTable(@"room_details_addresses_invalid_address_prompt_msg", @"Vector", nil), roomAlias];
currentAlert = [UIAlertController alertControllerWithTitle:NSLocalizedStringFromTable(@"room_details_addresses_invalid_address_prompt_title", @"Vector", nil)
message:alertMsg
preferredStyle:UIAlertControllerStyleAlert];
[currentAlert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"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;
}
- (BOOL)addCommunity:(NSString*)groupId
{
// Check whether the provided id is valid
if ([MXTools isMatrixGroupIdentifier:groupId])
{
// Check whether this group has just been deleted
NSMutableArray<NSString *> *removedGroups = updatedItemsDict[kRoomSettingsRemovedRelatedGroupKey];
if (removedGroups && [removedGroups indexOfObject:groupId] != NSNotFound)
{
[removedGroups removeObject:groupId];
if (!removedGroups.count)
{
[updatedItemsDict removeObjectForKey:kRoomSettingsRemovedRelatedGroupKey];
}
}
// Check whether this alias is not already defined for this room
else if ([relatedGroups indexOfObject:groupId] == NSNotFound)
{
NSMutableArray<NSString *> *addedGroup = updatedItemsDict[kRoomSettingsNewRelatedGroupKey];
if (!addedGroup)
{
addedGroup = [NSMutableArray array];
updatedItemsDict[kRoomSettingsNewRelatedGroupKey] = addedGroup;
}
[addedGroup addObject:groupId];
}
[self updateSections];
[self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0);
return YES;
}
// Prompt here user for invalid id
__weak typeof(self) weakSelf = self;
[currentAlert dismissViewControllerAnimated:NO completion:nil];
NSString *alertMsg = [NSString stringWithFormat:NSLocalizedStringFromTable(@"room_details_flair_invalid_id_prompt_msg", @"Vector", nil), groupId];
currentAlert = [UIAlertController alertControllerWithTitle:NSLocalizedStringFromTable(@"room_details_flair_invalid_id_prompt_title", @"Vector", nil)
message:alertMsg
preferredStyle:UIAlertControllerStyleAlert];
[currentAlert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"ok"]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->currentAlert = nil;
}
}]];
[currentAlert mxk_setAccessibilityIdentifier:@"RoomSettingsVCAddCommunityAlert"];
[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];
}
@end