From 9ee3b6f769a535c6aff9657523b8d5454b755be2 Mon Sep 17 00:00:00 2001 From: manuroe Date: Tue, 19 Sep 2017 09:00:44 +0200 Subject: [PATCH 1/7] Modular integrations Manager: Open URL in safari not within the webview --- .../Widgets/IntegrationManagerViewController.m | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Riot/ViewController/Widgets/IntegrationManagerViewController.m b/Riot/ViewController/Widgets/IntegrationManagerViewController.m index 6add0083c..4b420239b 100644 --- a/Riot/ViewController/Widgets/IntegrationManagerViewController.m +++ b/Riot/ViewController/Widgets/IntegrationManagerViewController.m @@ -188,6 +188,14 @@ NSString *const kJavascriptSendResponseToModular = @"riotIOS.sendResponse('%@', return NO; } + + if (navigationType == UIWebViewNavigationTypeLinkClicked ) + { + // Open links outside the app + [[UIApplication sharedApplication] openURL:[request URL]]; + return NO; + } + return YES; } From 978159a3a739b80aaef04f275c0fe3a754ccd29a Mon Sep 17 00:00:00 2001 From: manuroe Date: Tue, 19 Sep 2017 09:59:04 +0200 Subject: [PATCH 2/7] Modular integrations Manager: Manage lack of network --- .../IntegrationManagerViewController.m | 72 ++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/Riot/ViewController/Widgets/IntegrationManagerViewController.m b/Riot/ViewController/Widgets/IntegrationManagerViewController.m index 4b420239b..f423f3614 100644 --- a/Riot/ViewController/Widgets/IntegrationManagerViewController.m +++ b/Riot/ViewController/Widgets/IntegrationManagerViewController.m @@ -17,6 +17,7 @@ #import "IntegrationManagerViewController.h" #import "WidgetManager.h" +#import "AppDelegate.h" #import @@ -90,7 +91,6 @@ NSString *const kJavascriptSendResponseToModular = @"riotIOS.sendResponse('%@', if (self) { self->operation = nil; - [self stopActivityIndicator]; scalarToken = theScalarToken; @@ -156,6 +156,43 @@ NSString *const kJavascriptSendResponseToModular = @"riotIOS.sendResponse('%@', [webView stringByEvaluatingJavaScriptFromString:@"console.debug = console.log; console.info = console.log; console.warn = console.log; console.error = console.log;"]; } +- (void)showErrorAsAlert:(NSError*)error +{ + NSString *title = [error.userInfo valueForKey:NSLocalizedFailureReasonErrorKey]; + NSString *msg = [error.userInfo valueForKey:NSLocalizedDescriptionKey]; + if (!title) + { + if (msg) + { + title = msg; + msg = nil; + } + else + { + title = [NSBundle mxk_localizedStringForKey:@"error"]; + } + } + + __weak __typeof__(self) weakSelf = self; + + UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:msg preferredStyle:UIAlertControllerStyleAlert]; + [alert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"ok"] + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * action) { + + typeof(self) self = weakSelf; + + if (self) + { + // Leave this Intergrations Manager VC + [self withdrawViewControllerAnimated:YES completion:nil]; + } + + }]]; + + [self presentViewController:alert animated:YES completion:nil]; +} + #pragma mark - UIWebViewDelegate -(void)webViewDidFinishLoad:(UIWebView *)theWebView @@ -166,6 +203,22 @@ NSString *const kJavascriptSendResponseToModular = @"riotIOS.sendResponse('%@', NSString *path = [[NSBundle mainBundle] pathForResource:@"IntegrationManager" ofType:@"js"]; NSString *js = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil]; [webView stringByEvaluatingJavaScriptFromString:js]; + + [self stopActivityIndicator]; + + // Check connectivity + if ([AppDelegate theDelegate].isOffline) + { + // The web page may be in the cache, so its loading will be successful + // but we cannot go further, it often leads to a blank screen. + // So, display an error so that the user can escape. + NSError *error = [NSError errorWithDomain:NSURLErrorDomain + code:NSURLErrorNotConnectedToInternet + userInfo:@{ + NSLocalizedDescriptionKey : NSLocalizedStringFromTable(@"network_offline_prompt", @"Vector", nil) + }]; + [self showErrorAsAlert:error]; + } } - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType @@ -199,6 +252,23 @@ NSString *const kJavascriptSendResponseToModular = @"riotIOS.sendResponse('%@', return YES; } +- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error +{ + // Filter out the users's scalar token + NSString *errorDescription = error.description; + NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"scalar_token=\\w*" + options:NSRegularExpressionCaseInsensitive error:nil]; + errorDescription = [regex stringByReplacingMatchesInString:errorDescription + options:0 + range:NSMakeRange(0, errorDescription.length) + withTemplate:@"scalar_token=..."]; + + NSLog(@"[IntegrationManagerVC] didFailLoadWithError: %@", errorDescription); + + [self stopActivityIndicator]; + [self showErrorAsAlert:error]; +} + #pragma mark - Modular postMessage API - (void)onMessage:(NSDictionary*)JSData From 5664eb2cfd677f3f7d2cee7f5f24a70776d7c69c Mon Sep 17 00:00:00 2001 From: manuroe Date: Tue, 19 Sep 2017 10:04:19 +0200 Subject: [PATCH 3/7] Widget: Fix crash. Handle the case where a scalar token is not required (jitsi). --- Riot/Utils/Widgets/Widget.m | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Riot/Utils/Widgets/Widget.m b/Riot/Utils/Widgets/Widget.m index ce3ffbbc4..9fe5e12b1 100644 --- a/Riot/Utils/Widgets/Widget.m +++ b/Riot/Utils/Widgets/Widget.m @@ -48,7 +48,16 @@ withString:mxSession.myUser.avatarUrl ? mxSession.myUser.avatarUrl : @""]; // And their scalar token - _url = [_url stringByAppendingString:[NSString stringWithFormat:@"&scalar_token=%@", [[WidgetManager sharedManager] scalarTokenForMXSession:mxSession]]]; + NSString *scalarToken = [[WidgetManager sharedManager] scalarTokenForMXSession:mxSession]; + if (scalarToken) + { + _url = [_url stringByAppendingString:[NSString stringWithFormat:@"&scalar_token=%@", scalarToken]]; + } + else + { + // Some widget can live without scalar token (ex: Jitsi widget) + NSLog(@"[Widget] Note: There is no scalar token for %@", self); + } } return self; From e3cfd7df3fae5a6cc9e2f53391554eee042f5cdd Mon Sep 17 00:00:00 2001 From: manuroe Date: Tue, 19 Sep 2017 10:24:28 +0200 Subject: [PATCH 4/7] Modular integrations Manager: Manage dark theme --- .../IntegrationManagerViewController.m | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/Riot/ViewController/Widgets/IntegrationManagerViewController.m b/Riot/ViewController/Widgets/IntegrationManagerViewController.m index f423f3614..f8fbf782b 100644 --- a/Riot/ViewController/Widgets/IntegrationManagerViewController.m +++ b/Riot/ViewController/Widgets/IntegrationManagerViewController.m @@ -36,6 +36,9 @@ NSString *const kJavascriptSendResponseToModular = @"riotIOS.sendResponse('%@', NSString *scalarToken; MXHTTPOperation *operation; + + // Observe kRiotDesignValuesDidChangeThemeNotification to handle user interface theme change. + id kRiotDesignValuesDidChangeThemeNotificationObserver; } @end @@ -61,6 +64,12 @@ NSString *const kJavascriptSendResponseToModular = @"riotIOS.sendResponse('%@', [operation cancel]; operation = nil; + + if (kRiotDesignValuesDidChangeThemeNotificationObserver) + { + [[NSNotificationCenter defaultCenter] removeObserver:kRiotDesignValuesDidChangeThemeNotificationObserver]; + kRiotDesignValuesDidChangeThemeNotificationObserver = nil; + } } - (void)viewDidLoad @@ -71,6 +80,23 @@ NSString *const kJavascriptSendResponseToModular = @"riotIOS.sendResponse('%@', webView.scrollView.bounces = NO; webView.delegate = self; + + // Observe user interface theme change. + kRiotDesignValuesDidChangeThemeNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kRiotDesignValuesDidChangeThemeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { + + [self userInterfaceThemeDidChange]; + + }]; + [self userInterfaceThemeDidChange]; +} + +- (void)userInterfaceThemeDidChange +{ + self.view.backgroundColor = kRiotPrimaryBgColor; + webView.backgroundColor = kRiotPrimaryBgColor; + webView.opaque = NO; + + self.activityIndicator.backgroundColor = kRiotOverlayColor; } - (void)viewWillAppear:(BOOL)animated From c7796068f0ea51c13ad638961177dcee0ccbb9d2 Mon Sep 17 00:00:00 2001 From: manuroe Date: Tue, 19 Sep 2017 13:36:43 +0200 Subject: [PATCH 5/7] Modular integrations Manager: Improve dark theme management --- .../IntegrationManagerViewController.m | 29 ++----------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/Riot/ViewController/Widgets/IntegrationManagerViewController.m b/Riot/ViewController/Widgets/IntegrationManagerViewController.m index f8fbf782b..742c522e8 100644 --- a/Riot/ViewController/Widgets/IntegrationManagerViewController.m +++ b/Riot/ViewController/Widgets/IntegrationManagerViewController.m @@ -36,9 +36,6 @@ NSString *const kJavascriptSendResponseToModular = @"riotIOS.sendResponse('%@', NSString *scalarToken; MXHTTPOperation *operation; - - // Observe kRiotDesignValuesDidChangeThemeNotification to handle user interface theme change. - id kRiotDesignValuesDidChangeThemeNotificationObserver; } @end @@ -64,12 +61,6 @@ NSString *const kJavascriptSendResponseToModular = @"riotIOS.sendResponse('%@', [operation cancel]; operation = nil; - - if (kRiotDesignValuesDidChangeThemeNotificationObserver) - { - [[NSNotificationCenter defaultCenter] removeObserver:kRiotDesignValuesDidChangeThemeNotificationObserver]; - kRiotDesignValuesDidChangeThemeNotificationObserver = nil; - } } - (void)viewDidLoad @@ -79,24 +70,10 @@ NSString *const kJavascriptSendResponseToModular = @"riotIOS.sendResponse('%@', webView.scalesPageToFit = NO; webView.scrollView.bounces = NO; - webView.delegate = self; - - // Observe user interface theme change. - kRiotDesignValuesDidChangeThemeNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kRiotDesignValuesDidChangeThemeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { - - [self userInterfaceThemeDidChange]; - - }]; - [self userInterfaceThemeDidChange]; -} - -- (void)userInterfaceThemeDidChange -{ - self.view.backgroundColor = kRiotPrimaryBgColor; - webView.backgroundColor = kRiotPrimaryBgColor; + // Disable opacity so that the webview background uses the current interface theme webView.opaque = NO; - - self.activityIndicator.backgroundColor = kRiotOverlayColor; + + webView.delegate = self; } - (void)viewWillAppear:(BOOL)animated From 10b746eec4a82ce1abc3075d39b38e40d653b871 Mon Sep 17 00:00:00 2001 From: manuroe Date: Wed, 20 Sep 2017 09:10:29 +0200 Subject: [PATCH 6/7] BugReportVC: Force users to add a description in crash reports. This makes github happier and will help us on triaging. --- Riot/ViewController/BugReportViewController.m | 3 --- 1 file changed, 3 deletions(-) diff --git a/Riot/ViewController/BugReportViewController.m b/Riot/ViewController/BugReportViewController.m index cc0a332d6..92ec61141 100644 --- a/Riot/ViewController/BugReportViewController.m +++ b/Riot/ViewController/BugReportViewController.m @@ -89,9 +89,6 @@ { _titleLabel.text = NSLocalizedStringFromTable(@"bug_report_title", @"Vector", nil); _descriptionLabel.text = NSLocalizedStringFromTable(@"bug_report_description", @"Vector", nil); - - // Allow to send empty description for crash report but not for bug report - _sendButton.enabled = NO; } [_cancelButton setTitle:[NSBundle mxk_localizedStringForKey:@"cancel"] forState:UIControlStateNormal]; From 8ee6e6f8f0a9f5bb2f2962e0a44022477f218c71 Mon Sep 17 00:00:00 2001 From: Giom Foret Date: Wed, 20 Sep 2017 15:08:25 +0200 Subject: [PATCH 7/7] Improvement: Alter DMness from Room Settings. https://github.com/vector-im/riot-ios/issues/1370 --- Riot/Assets/en.lproj/Vector.strings | 2 + Riot/Assets/fr.lproj/Vector.strings | 2 + .../RoomSettingsViewController.m | 401 +++++++++--------- 3 files changed, 216 insertions(+), 189 deletions(-) diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 6a0650869..0691ddaa0 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -389,6 +389,7 @@ "room_details_favourite_tag" = "Favourite"; "room_details_low_priority_tag" = "Low priority"; "room_details_mute_notifs" = "Mute notifications"; +"room_details_direct_chat" = "Direct Chat"; "room_details_access_section"="Who can access this room?"; "room_details_access_section_invited_only"="Only people who have been invited"; "room_details_access_section_anyone_apart_from_guest"="Anyone who knows the room's link, apart from guests"; @@ -428,6 +429,7 @@ "room_details_fail_to_add_room_aliases" = "Fail to add the new room addresses"; "room_details_fail_to_remove_room_aliases" = "Fail to remove the room addresses"; "room_details_fail_to_update_room_canonical_alias" = "Fail to update the main address"; +"room_details_fail_to_update_room_direct" = "Fail to update the direct flag of this room"; "room_details_fail_to_enable_encryption" = "Fail to enable encryption in this room"; "room_details_save_changes_prompt" = "Do you want to save changes?"; "room_details_set_main_address" = "Set as Main Address"; diff --git a/Riot/Assets/fr.lproj/Vector.strings b/Riot/Assets/fr.lproj/Vector.strings index 8bf60b617..7cf68651c 100644 --- a/Riot/Assets/fr.lproj/Vector.strings +++ b/Riot/Assets/fr.lproj/Vector.strings @@ -313,6 +313,7 @@ "room_details_favourite_tag" = "Favoris"; "room_details_low_priority_tag" = "Priorité basse"; "room_details_mute_notifs" = "Désactiver les notifications"; +"room_details_direct_chat" = "Discussion directe"; "room_details_access_section" = "Qui peut accéder à ce salon ?"; "room_details_access_section_invited_only" = "Seulement les personnes qui ont été invitées"; "room_details_access_section_anyone_apart_from_guest" = "N'importe qui ayant un lien vers le salon, hormis les visiteurs"; @@ -352,6 +353,7 @@ "room_details_fail_to_add_room_aliases" = "Impossible d'ajouter les nouvelles adresses au salon"; "room_details_fail_to_remove_room_aliases" = "Impossible de supprimer les adresses du salon"; "room_details_fail_to_update_room_canonical_alias" = "Impossible de modifier l'adresse principale"; +"room_details_fail_to_update_room_direct" = "Impossible de modifier l'état de discussion directe"; "room_details_fail_to_enable_encryption" = "Impossible d'activer le chiffrement sur ce salon"; "room_details_save_changes_prompt" = "Voulez-vous enregistrer les changements ?"; "room_details_set_main_address" = "Configurer comme adresse principale"; diff --git a/Riot/ViewController/RoomSettingsViewController.m b/Riot/ViewController/RoomSettingsViewController.m index 68d3ff632..3b3794b27 100644 --- a/Riot/ViewController/RoomSettingsViewController.m +++ b/Riot/ViewController/RoomSettingsViewController.m @@ -46,9 +46,10 @@ #define ROOM_SETTINGS_MAIN_SECTION_ROW_NAME 1 #define ROOM_SETTINGS_MAIN_SECTION_ROW_TOPIC 2 #define ROOM_SETTINGS_MAIN_SECTION_ROW_TAG 3 -#define ROOM_SETTINGS_MAIN_SECTION_ROW_MUTE_NOTIFICATIONS 4 -#define ROOM_SETTINGS_MAIN_SECTION_ROW_LEAVE 5 -#define ROOM_SETTINGS_MAIN_SECTION_ROW_COUNT 6 +#define ROOM_SETTINGS_MAIN_SECTION_ROW_DIRECT_CHAT 4 +#define ROOM_SETTINGS_MAIN_SECTION_ROW_MUTE_NOTIFICATIONS 5 +#define ROOM_SETTINGS_MAIN_SECTION_ROW_LEAVE 6 +#define ROOM_SETTINGS_MAIN_SECTION_ROW_COUNT 7 #define ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_INVITED_ONLY 0 #define ROOM_SETTINGS_ROOM_ACCESS_SECTION_ROW_ANYONE_APART_FROM_GUEST 1 @@ -71,6 +72,7 @@ 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"; @@ -138,11 +140,6 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti // picker MediaPickerViewController* mediaPicker; - // switches - UISwitch *roomNotifSwitch; - UISwitch *roomEncryptionSwitch; - UISwitch *roomEncryptionBlacklistUnverifiedDevicesSwitch; - // Observe kAppDelegateDidTapStatusBarNotification to handle tap on clock status bar. id appDelegateDidTapStatusBarNotificationObserver; @@ -1598,7 +1595,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti if ([updatedItemsDict objectForKey:kRoomSettingsMuteNotifKey]) { - if (roomNotifSwitch.on) + if (((NSNumber*)[updatedItemsDict objectForKey:kRoomSettingsMuteNotifKey]).boolValue) { [mxRoom mentionsOnly:^{ @@ -1629,6 +1626,45 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti return; } + if ([updatedItemsDict objectForKey:kRoomSettingsDirectChatKey]) + { + pendingOperation = [mxRoom setIsDirect:((NSNumber*)[updatedItemsDict objectForKey:kRoomSettingsDirectChatKey]).boolValue withUserId:nil success:^{ + + if (weakSelf) + { + typeof(self) self = weakSelf; + + self->pendingOperation = nil; + [self->updatedItemsDict removeObjectForKey:kRoomSettingsDirectChatKey]; + [self onSave:nil]; + } + + } failure:^(NSError *error) { + + NSLog(@"[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 withKey:kRoomSettingsDirectChatKey]; + + }); + } + + }]; + return; + } + // Room directory visibility MXRoomDirectoryVisibility directoryVisibility = [updatedItemsDict objectForKey:kRoomSettingsDirectoryKey]; if (directoryVisibility) @@ -1944,31 +1980,41 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti { if (row == ROOM_SETTINGS_MAIN_SECTION_ROW_MUTE_NOTIFICATIONS) { - MXKTableViewCellWithLabelAndSwitch *roomNotifCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithLabelAndSwitch defaultReuseIdentifier] forIndexPath:indexPath]; - - roomNotifCell.mxkLabelLeadingConstraint.constant = roomNotifCell.separatorInset.left; - roomNotifCell.mxkSwitchTrailingConstraint.constant = 15; - - [roomNotifCell.mxkSwitch addTarget:self action:@selector(onSwitchUpdate:) forControlEvents:UIControlEventValueChanged]; - roomNotifCell.mxkSwitch.onTintColor = kRiotColorGreen; + 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); - roomNotifCell.mxkLabel.textColor = kRiotPrimaryTextColor; - roomNotifSwitch = roomNotifCell.mxkSwitch; if ([updatedItemsDict objectForKey:kRoomSettingsMuteNotifKey]) { - roomNotifSwitch.on = ((NSNumber*)[updatedItemsDict objectForKey:kRoomSettingsMuteNotifKey]).boolValue; + roomNotifCell.mxkSwitch.on = ((NSNumber*)[updatedItemsDict objectForKey:kRoomSettingsMuteNotifKey]).boolValue; } else { - roomNotifSwitch.on = mxRoom.isMute || mxRoom.isMentionsOnly; + 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]; - // Force layout before reusing a cell (fix switch displayed outside the screen) - [cell layoutIfNeeded]; + [roomDirectChat.mxkSwitch addTarget:self action:@selector(toggleDirectChat:) forControlEvents:UIControlEventValueChanged]; + + roomDirectChat.mxkLabel.text = NSLocalizedStringFromTable(@"room_details_direct_chat", @"Vector", nil); + + if ([updatedItemsDict objectForKey:kRoomSettingsDirectChatKey]) + { + roomDirectChat.mxkSwitch.on = ((NSNumber*)[updatedItemsDict objectForKey:kRoomSettingsDirectChatKey]).boolValue; + } + else + { + roomDirectChat.mxkSwitch.on = mxRoom.isDirect; + } + + cell = roomDirectChat; } else if (row == ROOM_SETTINGS_MAIN_SECTION_ROW_PHOTO) { @@ -2144,51 +2190,29 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti { if (indexPath.row == directoryVisibilityIndex) { - MXKTableViewCellWithLabelAndSwitch *directoryToggleCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithLabelAndSwitch defaultReuseIdentifier] forIndexPath:indexPath]; - - directoryToggleCell.mxkLabelLeadingConstraint.constant = directoryToggleCell.separatorInset.left; - directoryToggleCell.mxkSwitchTrailingConstraint.constant = 15; + MXKTableViewCellWithLabelAndSwitch *directoryToggleCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath]; directoryToggleCell.mxkLabel.text = NSLocalizedStringFromTable(@"room_details_access_section_directory_toggle", @"Vector", nil); - directoryToggleCell.mxkLabel.textColor = kRiotPrimaryTextColor; - directoryVisibilitySwitch = directoryToggleCell.mxkSwitch; - - // Workaround to avoid mixing between switches - // TODO: this is a design issue with switch within UITableViewCell that must fix everywhere - if (roomEncryptionSwitch == directoryVisibilitySwitch) - { - roomEncryptionSwitch = nil; - } - else if (roomNotifSwitch == directoryVisibilitySwitch) - { - roomNotifSwitch = nil; - } - else if (roomEncryptionBlacklistUnverifiedDevicesSwitch == directoryVisibilitySwitch) - { - roomEncryptionBlacklistUnverifiedDevicesSwitch = nil; - } - - [directoryVisibilitySwitch addTarget:self action:@selector(onSwitchUpdate:) forControlEvents:UIControlEventValueChanged]; - directoryVisibilitySwitch.onTintColor = kRiotColorGreen; + [directoryToggleCell.mxkSwitch addTarget:self action:@selector(toggleDirectoryVisibility:) forControlEvents:UIControlEventValueChanged]; if ([updatedItemsDict objectForKey:kRoomSettingsDirectoryKey]) { - directoryVisibilitySwitch.on = ((NSNumber*)[updatedItemsDict objectForKey:kRoomSettingsDirectoryKey]).boolValue; + directoryToggleCell.mxkSwitch.on = ((NSNumber*)[updatedItemsDict objectForKey:kRoomSettingsDirectoryKey]).boolValue; } else { // Use the last retrieved value if any - directoryVisibilitySwitch.on = actualDirectoryVisibility ? [actualDirectoryVisibility isEqualToString:kMXRoomDirectoryVisibilityPublic] : NO; + directoryToggleCell.mxkSwitch.on = actualDirectoryVisibility ? [actualDirectoryVisibility isEqualToString:kMXRoomDirectoryVisibilityPublic] : NO; } // Check whether the user can change this option - directoryVisibilitySwitch.enabled = (oneSelfPowerLevel >= powerLevels.stateDefault); + directoryToggleCell.mxkSwitch.enabled = (oneSelfPowerLevel >= powerLevels.stateDefault); + + // Store the switch to be able to update it + directoryVisibilitySwitch = directoryToggleCell.mxkSwitch; cell = directoryToggleCell; - - // Force layout before reusing a cell (fix switch displayed outside the screen) - [cell layoutIfNeeded]; } else if (indexPath.row == missingAddressWarningIndex) { @@ -2443,33 +2467,12 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti { if (indexPath.row == 1) { - MXKTableViewCellWithLabelAndSwitch *roomBlacklistUnverifiedDevicesCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithLabelAndSwitch defaultReuseIdentifier] forIndexPath:indexPath]; + MXKTableViewCellWithLabelAndSwitch *roomBlacklistUnverifiedDevicesCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath]; - roomBlacklistUnverifiedDevicesCell.mxkLabelLeadingConstraint.constant = roomBlacklistUnverifiedDevicesCell.separatorInset.left; - roomBlacklistUnverifiedDevicesCell.mxkSwitchTrailingConstraint.constant = 15; - - [roomBlacklistUnverifiedDevicesCell.mxkSwitch addTarget:self action:@selector(onSwitchUpdate:) forControlEvents:UIControlEventValueChanged]; + [roomBlacklistUnverifiedDevicesCell.mxkSwitch addTarget:self action:@selector(toggleBlacklistUnverifiedDevice:) forControlEvents:UIControlEventValueChanged]; roomBlacklistUnverifiedDevicesCell.mxkSwitch.onTintColor = kRiotColorGreen; roomBlacklistUnverifiedDevicesCell.mxkLabel.text = NSLocalizedStringFromTable(@"room_details_advanced_e2e_encryption_blacklist_unverified_devices", @"Vector", nil); - roomBlacklistUnverifiedDevicesCell.mxkLabel.textColor = kRiotPrimaryTextColor; - - roomEncryptionBlacklistUnverifiedDevicesSwitch = roomBlacklistUnverifiedDevicesCell.mxkSwitch; - - // Workaround to avoid mixing between switches - // TODO: this is a design issue with switch within UITableViewCell that must fix everywhere - if (directoryVisibilitySwitch == roomEncryptionBlacklistUnverifiedDevicesSwitch) - { - directoryVisibilitySwitch = nil; - } - else if (roomNotifSwitch == roomEncryptionBlacklistUnverifiedDevicesSwitch) - { - roomNotifSwitch = nil; - } - else if (roomEncryptionSwitch == roomEncryptionBlacklistUnverifiedDevicesSwitch) - { - roomEncryptionSwitch = nil; - } // For the switch value, use by order: // - the MXCrypto.globalBlacklistUnverifiedDevices if its value is YES @@ -2480,11 +2483,11 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti if (mxRoom.mxSession.crypto.globalBlacklistUnverifiedDevices) { blacklistUnverifiedDevices = YES; - roomEncryptionBlacklistUnverifiedDevicesSwitch.enabled = NO; + roomBlacklistUnverifiedDevicesCell.mxkSwitch.enabled = NO; } else { - roomEncryptionBlacklistUnverifiedDevicesSwitch.enabled = YES; + roomBlacklistUnverifiedDevicesCell.mxkSwitch.enabled = YES; if ([updatedItemsDict objectForKey:kRoomSettingsEncryptionBlacklistUnverifiedDevicesKey]) { @@ -2496,7 +2499,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti } } - roomEncryptionBlacklistUnverifiedDevicesSwitch.on = blacklistUnverifiedDevices; + roomBlacklistUnverifiedDevicesCell.mxkSwitch.on = blacklistUnverifiedDevices; cell = roomBlacklistUnverifiedDevicesCell; @@ -2527,40 +2530,15 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti if (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomEncryption]) { - MXKTableViewCellWithLabelAndSwitch *roomEncryptionCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithLabelAndSwitch defaultReuseIdentifier] forIndexPath:indexPath]; + MXKTableViewCellWithLabelAndSwitch *roomEncryptionCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath]; - roomEncryptionCell.mxkLabelLeadingConstraint.constant = roomEncryptionCell.separatorInset.left; - roomEncryptionCell.mxkSwitchTrailingConstraint.constant = 15; - - [roomEncryptionCell.mxkSwitch addTarget:self action:@selector(onSwitchUpdate:) forControlEvents:UIControlEventValueChanged]; - roomEncryptionCell.mxkSwitch.onTintColor = kRiotColorGreen; + [roomEncryptionCell.mxkSwitch addTarget:self action:@selector(toggleEncryption:) forControlEvents:UIControlEventValueChanged]; roomEncryptionCell.mxkLabel.text = NSLocalizedStringFromTable(@"room_details_advanced_enable_e2e_encryption", @"Vector", nil); - roomEncryptionCell.mxkLabel.textColor = kRiotPrimaryTextColor; - roomEncryptionSwitch = roomEncryptionCell.mxkSwitch; - - // Workaround to avoid mixing between switches - // TODO: this is a design issue with switch within UITableViewCell that must fix everywhere - if (directoryVisibilitySwitch == roomEncryptionSwitch) - { - directoryVisibilitySwitch = nil; - } - else if (roomNotifSwitch == roomEncryptionSwitch) - { - roomNotifSwitch = nil; - } - else if (roomEncryptionBlacklistUnverifiedDevicesSwitch == roomEncryptionSwitch) - { - roomEncryptionBlacklistUnverifiedDevicesSwitch = nil; - } - - roomEncryptionSwitch.on = ([updatedItemsDict objectForKey:kRoomSettingsEncryptionKey] != nil); + roomEncryptionCell.mxkSwitch.on = ([updatedItemsDict objectForKey:kRoomSettingsEncryptionKey] != nil); cell = roomEncryptionCell; - - // Force layout before reusing a cell (fix switch displayed outside the screen) - [cell layoutIfNeeded]; } else { @@ -2608,6 +2586,30 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti // iOS8 requires this method to enable editing (see editActionsForRowAtIndexPath). } +- (MXKTableViewCellWithLabelAndSwitch*)getLabelAndSwitchCell:(UITableView*)tableview forIndexPath:(NSIndexPath *)indexPath +{ + MXKTableViewCellWithLabelAndSwitch *cell = [tableview dequeueReusableCellWithIdentifier:[MXKTableViewCellWithLabelAndSwitch defaultReuseIdentifier] forIndexPath:indexPath]; + + cell.mxkLabelLeadingConstraint.constant = cell.separatorInset.left; + cell.mxkSwitchTrailingConstraint.constant = 15; + + cell.mxkLabel.textColor = kRiotPrimaryTextColor; + + cell.mxkSwitch.onTintColor = kRiotColorGreen; + [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; @@ -3136,102 +3138,123 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti [self presentViewController:navigationController animated:YES completion:nil]; } -- (void)onSwitchUpdate:(UISwitch*)theSwitch +- (void)toggleRoomNotification:(UISwitch*)theSwitch { - if (theSwitch == roomNotifSwitch) + if (theSwitch.on == (mxRoom.isMute || mxRoom.isMentionsOnly)) { - if (roomNotifSwitch.on == (mxRoom.isMute || mxRoom.isMentionsOnly)) - { - [updatedItemsDict removeObjectForKey:kRoomSettingsMuteNotifKey]; - } - else - { - [updatedItemsDict setObject:[NSNumber numberWithBool:roomNotifSwitch.on] forKey:kRoomSettingsMuteNotifKey]; - } + [updatedItemsDict removeObjectForKey:kRoomSettingsMuteNotifKey]; } - else if (theSwitch == directoryVisibilitySwitch) + else { - MXRoomDirectoryVisibility visibility = directoryVisibilitySwitch.on ? kMXRoomDirectoryVisibilityPublic : kMXRoomDirectoryVisibilityPrivate; + [updatedItemsDict setObject:[NSNumber numberWithBool:theSwitch.on] forKey:kRoomSettingsMuteNotifKey]; + } + + [self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0); +} + +- (void)toggleDirectChat:(UISwitch*)theSwitch +{ + if (theSwitch.on == mxRoom.isDirect) + { + [updatedItemsDict removeObjectForKey:kRoomSettingsDirectChatKey]; + } + else + { + [updatedItemsDict setObject:[NSNumber numberWithBool:theSwitch.on] forKey:kRoomSettingsDirectChatKey]; + } + + [self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0); +} + +- (void)toggleEncryption:(UISwitch*)theSwitch +{ + if (theSwitch.on) + { + // Prompt here user before turning on the data encryption + __weak typeof(self) weakSelf = self; - // Check whether the actual settings has been retrieved - if (actualDirectoryVisibility) + [currentAlert dismissViewControllerAnimated:NO completion:nil]; + + currentAlert = [UIAlertController alertControllerWithTitle:NSLocalizedStringFromTable(@"warning", @"Vector", nil) + message:NSLocalizedStringFromTable(@"room_details_advanced_e2e_encryption_prompt_message", @"Vector", nil) + preferredStyle:UIAlertControllerStyleAlert]; + + [currentAlert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"] + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * action) { + + if (weakSelf) + { + typeof(self) self = weakSelf; + self->currentAlert = nil; + } + + // Reset switch change + theSwitch.on = NO; + + }]]; + + [currentAlert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"ok"] + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * action) { + + if (weakSelf) + { + typeof(self) self = weakSelf; + self->currentAlert = nil; + + [self->updatedItemsDict setObject:@(YES) forKey:kRoomSettingsEncryptionKey]; + + [self getNavigationItem].rightBarButtonItem.enabled = self->updatedItemsDict.count; + } + + }]]; + + [currentAlert mxk_setAccessibilityIdentifier:@"RoomSettingsVCEnableEncryptionAlert"]; + [self presentViewController:currentAlert animated:YES completion:nil]; + } + 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]) { - if ([visibility isEqualToString:actualDirectoryVisibility]) - { - [updatedItemsDict removeObjectForKey:kRoomSettingsDirectoryKey]; - } - else - { - [updatedItemsDict setObject:visibility forKey:kRoomSettingsDirectoryKey]; - } + [updatedItemsDict removeObjectForKey:kRoomSettingsDirectoryKey]; } else { [updatedItemsDict setObject:visibility forKey:kRoomSettingsDirectoryKey]; } } - else if (theSwitch == roomEncryptionSwitch) + else { - if (roomEncryptionSwitch.on) - { - // Prompt here user before turning on the data encryption - __weak typeof(self) weakSelf = self; - - [currentAlert dismissViewControllerAnimated:NO completion:nil]; - - currentAlert = [UIAlertController alertControllerWithTitle:NSLocalizedStringFromTable(@"warning", @"Vector", nil) - message:NSLocalizedStringFromTable(@"room_details_advanced_e2e_encryption_prompt_message", @"Vector", nil) - preferredStyle:UIAlertControllerStyleAlert]; - - [currentAlert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"] - style:UIAlertActionStyleDefault - handler:^(UIAlertAction * action) { - - if (weakSelf) - { - typeof(self) self = weakSelf; - self->currentAlert = nil; - } - - // Reset switch change - theSwitch.on = NO; - - }]]; - - [currentAlert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"ok"] - style:UIAlertActionStyleDefault - handler:^(UIAlertAction * action) { - - if (weakSelf) - { - typeof(self) self = weakSelf; - self->currentAlert = nil; - - [self->updatedItemsDict setObject:@(YES) forKey:kRoomSettingsEncryptionKey]; - - [self getNavigationItem].rightBarButtonItem.enabled = self->updatedItemsDict.count; - } - - }]]; - - [currentAlert mxk_setAccessibilityIdentifier:@"RoomSettingsVCEnableEncryptionAlert"]; - [self presentViewController:currentAlert animated:YES completion:nil]; - } - else - { - [updatedItemsDict removeObjectForKey:kRoomSettingsEncryptionKey]; - } - } - else if (theSwitch == roomEncryptionBlacklistUnverifiedDevicesSwitch) - { - if ([mxRoom.mxSession.crypto isBlacklistUnverifiedDevicesInRoom:mxRoom.roomId] != roomEncryptionBlacklistUnverifiedDevicesSwitch.on) - { - updatedItemsDict[kRoomSettingsEncryptionBlacklistUnverifiedDevicesKey] = @(roomEncryptionBlacklistUnverifiedDevicesSwitch.on); - } - else - { - [updatedItemsDict removeObjectForKey:kRoomSettingsEncryptionBlacklistUnverifiedDevicesKey]; - } + [updatedItemsDict setObject:visibility forKey:kRoomSettingsDirectoryKey]; } [self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0);