From 2efefc530aa0db3f432de94aa7e3bfcd0c0bc9db Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Wed, 30 May 2018 16:59:18 +0200 Subject: [PATCH] Add DeactivateAccountViewController allowing to deactivate a user account from given Matrix session --- Riot.xcodeproj/project.pbxproj | 18 ++ .../DeactivateAccountViewController.h | 45 +++ .../DeactivateAccountViewController.m | 287 ++++++++++++++++++ ...DeactivateAccountViewController.storyboard | 130 ++++++++ 4 files changed, 480 insertions(+) create mode 100644 Riot/ViewController/DeactivateAccount/DeactivateAccountViewController.h create mode 100644 Riot/ViewController/DeactivateAccount/DeactivateAccountViewController.m create mode 100644 Riot/ViewController/DeactivateAccount/DeactivateAccountViewController.storyboard diff --git a/Riot.xcodeproj/project.pbxproj b/Riot.xcodeproj/project.pbxproj index 2908c6779..ea0bbd8d1 100644 --- a/Riot.xcodeproj/project.pbxproj +++ b/Riot.xcodeproj/project.pbxproj @@ -109,6 +109,8 @@ 92726A4B1F58737A004AD26F /* SiriIntents.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 92726A431F58737A004AD26F /* SiriIntents.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 92726A511F587410004AD26F /* Intents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 92726A501F587410004AD26F /* Intents.framework */; }; 9D686B069F967C4D4BBC610F /* Pods_RiotPods_SiriIntents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB50EEBE8214352B9EBD6394 /* Pods_RiotPods_SiriIntents.framework */; }; + B19A173920B7F94800DF0BB0 /* DeactivateAccountViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B19A173820B7F94800DF0BB0 /* DeactivateAccountViewController.m */; }; + B19A173B20B7F96700DF0BB0 /* DeactivateAccountViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B19A173A20B7F96700DF0BB0 /* DeactivateAccountViewController.storyboard */; }; DDDE2AB95F865F2292B1D315 /* Pods_RiotPods_RiotShareExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 23D7292481328A48B8D5D4ED /* Pods_RiotPods_RiotShareExtension.framework */; }; F0131DE51F2200D600CBF707 /* RiotSplitViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F0131DE41F2200D600CBF707 /* RiotSplitViewController.m */; }; F0173EB51FCF346800B5F6A3 /* Vector.strings in Resources */ = {isa = PBXBuildFile; fileRef = F0173EAF1FCF346800B5F6A3 /* Vector.strings */; }; @@ -794,6 +796,9 @@ 92726A501F587410004AD26F /* Intents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Intents.framework; path = System/Library/Frameworks/Intents.framework; sourceTree = SDKROOT; }; A5030B7C3C0B6EB83A9257BD /* Pods-RiotPods-Riot.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RiotPods-Riot.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RiotPods-Riot/Pods-RiotPods-Riot.debug.xcconfig"; sourceTree = ""; }; B0FAA1A49F76B0CE15C5CBD8 /* Pods_RiotPods_Riot.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RiotPods_Riot.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + B19A173720B7F94800DF0BB0 /* DeactivateAccountViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DeactivateAccountViewController.h; sourceTree = ""; }; + B19A173820B7F94800DF0BB0 /* DeactivateAccountViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DeactivateAccountViewController.m; sourceTree = ""; }; + B19A173A20B7F96700DF0BB0 /* DeactivateAccountViewController.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = DeactivateAccountViewController.storyboard; sourceTree = ""; }; C195C53961EA28E6900AEB68 /* Pods-Riot.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Riot.release.xcconfig"; path = "Pods/Target Support Files/Pods-Riot/Pods-Riot.release.xcconfig"; sourceTree = ""; }; C5258DFF261AA3AB228A3F11 /* Pods-RiotPods-RiotShareExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RiotPods-RiotShareExtension.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RiotPods-RiotShareExtension/Pods-RiotPods-RiotShareExtension.debug.xcconfig"; sourceTree = ""; }; DB50EEBE8214352B9EBD6394 /* Pods_RiotPods_SiriIntents.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RiotPods_SiriIntents.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -1717,6 +1722,16 @@ path = SiriIntents; sourceTree = ""; }; + B19A173520B6F89900DF0BB0 /* DeactivateAccount */ = { + isa = PBXGroup; + children = ( + B19A173720B7F94800DF0BB0 /* DeactivateAccountViewController.h */, + B19A173820B7F94800DF0BB0 /* DeactivateAccountViewController.m */, + B19A173A20B7F96700DF0BB0 /* DeactivateAccountViewController.storyboard */, + ); + path = DeactivateAccount; + sourceTree = ""; + }; F0173EAE1FCF346800B5F6A3 /* vi.lproj */ = { isa = PBXGroup; children = ( @@ -2283,6 +2298,7 @@ 24B5103F1EFA88CC004C6AD2 /* ReadReceiptsViewController.xib */, F0B4CBA31F418D0B008E99C5 /* WebViewViewController.h */, F0B4CBA41F418D0B008E99C5 /* WebViewViewController.m */, + B19A173520B6F89900DF0BB0 /* DeactivateAccount */, ); path = ViewController; sourceTree = ""; @@ -3151,6 +3167,7 @@ F083BDDA1E7009ED00A9B29C /* typing.png in Resources */, F083BE831E7009ED00A9B29C /* RecentTableViewCell.xib in Resources */, F046DC731FE1786500E3DAF0 /* GroupHomeViewController.xib in Resources */, + B19A173B20B7F96700DF0BB0 /* DeactivateAccountViewController.storyboard in Resources */, F0E5D9141FF6FF3F00560D7F /* GroupRoomTableViewCell.xib in Resources */, F083BDB71E7009ED00A9B29C /* remove_icon@2x.png in Resources */, F083BDD31E7009ED00A9B29C /* settings_icon@3x.png in Resources */, @@ -3630,6 +3647,7 @@ F0E05A021E963103004B83FB /* FavouritesViewController.m in Sources */, F083BE941E7009ED00A9B29C /* FilesSearchTableViewCell.m in Sources */, F083BE921E7009ED00A9B29C /* SimpleRoomTitleView.m in Sources */, + B19A173920B7F94800DF0BB0 /* DeactivateAccountViewController.m in Sources */, F083BE981E7009ED00A9B29C /* MessagesSearchResultTextMsgBubbleCell.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Riot/ViewController/DeactivateAccount/DeactivateAccountViewController.h b/Riot/ViewController/DeactivateAccount/DeactivateAccountViewController.h new file mode 100644 index 000000000..4d403aa40 --- /dev/null +++ b/Riot/ViewController/DeactivateAccount/DeactivateAccountViewController.h @@ -0,0 +1,45 @@ +/* + Copyright 2018 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +@import UIKit; +@import MatrixKit; + +#pragma mark - Types + +@class DeactivateAccountViewController; + +#pragma mark - Protocol + +@protocol DeactivateAccountViewControllerDelegate + +- (void)deactivateAccountViewControllerDidCancel:(DeactivateAccountViewController*)deactivateAccountViewController; +- (void)deactivateAccountViewControllerDidDeactivateWithSuccess:(DeactivateAccountViewController*)deactivateAccountViewController; + +@end + +#pragma mark - Interface + +@interface DeactivateAccountViewController : MXKViewController + +#pragma mark - Properties + +@property (nonatomic, weak) id delegate; + +#pragma mark - Class Methods + ++ (DeactivateAccountViewController*)instantiateWithMatrixSession:(MXSession*)matrixSession; + +@end diff --git a/Riot/ViewController/DeactivateAccount/DeactivateAccountViewController.m b/Riot/ViewController/DeactivateAccount/DeactivateAccountViewController.m new file mode 100644 index 000000000..c1aa43ceb --- /dev/null +++ b/Riot/ViewController/DeactivateAccount/DeactivateAccountViewController.m @@ -0,0 +1,287 @@ +/* + Copyright 2018 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "DeactivateAccountViewController.h" + +#import "RiotDesignValues.h" + +#pragma mark - Defines & Constants + +static CGFloat const kButtonCornerRadius = 5.0; +static CGFloat const kTextFontSize = 15.0; +static NSTimeInterval const kActivityIndicatorAnimationDuration = 0.3; +static CGFloat const kActivityContainerViewCornerRadius = 5.0; + +#pragma mark - Private Interface + +@interface DeactivateAccountViewController () + +#pragma mark - Outlets + +@property (weak, nonatomic) IBOutlet UILabel *deactivateAccountInfosLabel; + +@property (weak, nonatomic) IBOutlet UILabel *forgetMessagesInfoLabel; +@property (weak, nonatomic) IBOutlet UIButton *forgetMessageButton; + +@property (weak, nonatomic) IBOutlet UIButton *deactivateAcccountButton; + + +#pragma mark - Private Properties + +@property (strong, nonatomic) NSDictionary *normalStringAttributes; +@property (strong, nonatomic) NSDictionary *emphasizeStringAttributes; + +@property (strong, nonatomic) MXKErrorAlertPresentation *errorPresentation; + +@end + +#pragma mark - Implementation + +@implementation DeactivateAccountViewController + +#pragma mark - Setup & Teardown + ++ (DeactivateAccountViewController*)instantiateWithMatrixSession:(MXSession*)matrixSession +{ + DeactivateAccountViewController* viewController = [[UIStoryboard storyboardWithName:NSStringFromClass([DeactivateAccountViewController class]) bundle:[NSBundle mainBundle]] instantiateInitialViewController]; + [viewController addMatrixSession:matrixSession]; + return viewController; +} + +#pragma mark - View life cycle + +- (void)viewDidLoad +{ + [super viewDidLoad]; + // Do any additional setup after loading the view. + + self.title = NSLocalizedStringFromTable(@"deactivate_account_title", @"Vector", nil); + + self.errorPresentation = [[MXKErrorAlertPresentation alloc] init]; + [self setupStringAttributes]; + [self setupViews]; +} + +- (void)viewDidLayoutSubviews +{ + [super viewDidLayoutSubviews]; + +// [self.activityIndicatorContainerView.layer setCornerRadius:kActivityContainerViewCornerRadius]; + [self.deactivateAcccountButton.layer setCornerRadius:kButtonCornerRadius]; +} + +#pragma mark - Private + +- (void)setupStringAttributes +{ + self.normalStringAttributes = @{ + NSFontAttributeName: [UIFont systemFontOfSize:kTextFontSize], + NSForegroundColorAttributeName: kRiotPrimaryTextColor + }; + + + self.emphasizeStringAttributes = @{ + NSFontAttributeName: [UIFont systemFontOfSize:kTextFontSize weight:UIFontWeightBold], + NSForegroundColorAttributeName: kRiotPrimaryTextColor + }; +} + +- (void)setupViews +{ + [self setupNavigationBar]; + [self setupDeactivateAcccountButton]; + [self setupDeactivateAccountInfosLabel]; + [self setupForgetMessagesInfoLabel]; +} + +- (void)setupNavigationBar +{ + self.navigationController.navigationBar.titleTextAttributes = @{ NSForegroundColorAttributeName: kRiotColorRed }; + + UIBarButtonItem *cancelBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedStringFromTable(@"cancel", @"Vector", nil) style:UIBarButtonItemStylePlain target:self action:@selector(cancelButtonAction:)]; + self.navigationItem.rightBarButtonItem = cancelBarButtonItem; +} + +- (void)setupDeactivateAcccountButton +{ + // Adjust button font size for small devices + self.deactivateAcccountButton.titleLabel.adjustsFontSizeToFitWidth = YES; + self.deactivateAcccountButton.titleLabel.minimumScaleFactor = 0.5; + self.deactivateAcccountButton.titleLabel.baselineAdjustment = UIBaselineAdjustmentAlignCenters; + + self.deactivateAcccountButton.layer.masksToBounds = YES; + self.deactivateAcccountButton.backgroundColor = kRiotColorGreen; + [self.deactivateAcccountButton setTitle:NSLocalizedStringFromTable(@"deactivate_account_validate_action", @"Vector", nil) forState:UIControlStateNormal]; + [self.deactivateAcccountButton setTitleColor:kRiotColorSilver forState:UIControlStateDisabled]; +} + +- (void)setupDeactivateAccountInfosLabel +{ + NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] init]; + + [attributedString appendAttributedString:[[NSAttributedString alloc] initWithString:NSLocalizedStringFromTable(@"deactivate_account_informations_part1", @"Vector", nil) attributes:self.normalStringAttributes]]; + + [attributedString appendAttributedString:[[NSAttributedString alloc] initWithString:NSLocalizedStringFromTable(@"deactivate_account_informations_part2_emphasize", @"Vector", nil) attributes:self.emphasizeStringAttributes]]; + + [attributedString appendAttributedString:[[NSAttributedString alloc] initWithString:NSLocalizedStringFromTable(@"deactivate_account_informations_part3", @"Vector", nil) attributes:self.normalStringAttributes]]; + + [attributedString appendAttributedString:[[NSAttributedString alloc] initWithString:NSLocalizedStringFromTable(@"deactivate_account_informations_part4_emphasize", @"Vector", nil) attributes:self.emphasizeStringAttributes]]; + + [attributedString appendAttributedString:[[NSAttributedString alloc] initWithString:NSLocalizedStringFromTable(@"deactivate_account_informations_part5", @"Vector", nil) attributes:self.normalStringAttributes]]; + + [self.deactivateAccountInfosLabel setAttributedText:attributedString]; +} + +- (void)setupForgetMessagesInfoLabel +{ + NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] init]; + + [attributedString appendAttributedString:[[NSAttributedString alloc] initWithString:NSLocalizedStringFromTable(@"deactivate_account_forget_messages_information_part1", @"Vector", nil) attributes:self.normalStringAttributes]]; + + [attributedString appendAttributedString:[[NSAttributedString alloc] initWithString:NSLocalizedStringFromTable(@"deactivate_account_forget_messages_information_part2_emphasize", @"Vector", nil) attributes:self.emphasizeStringAttributes]]; + + [attributedString appendAttributedString:[[NSAttributedString alloc] initWithString:NSLocalizedStringFromTable(@"deactivate_account_forget_messages_information_part3", @"Vector", nil) attributes:self.normalStringAttributes]]; + + [self.forgetMessagesInfoLabel setAttributedText:attributedString]; +} + +- (void)enableUserActions:(BOOL)enableUserActions +{ + self.navigationItem.rightBarButtonItem.enabled = enableUserActions; + self.forgetMessageButton.enabled = enableUserActions; + self.deactivateAcccountButton.enabled = enableUserActions; +} + +- (void)presentPasswordRequiredAlertWithSubmitHandler:(void (^)(NSString *password))submitHandler + cancelHandler:(dispatch_block_t)cancelHandler +{ + UIAlertController *alert = [UIAlertController alertControllerWithTitle:NSLocalizedStringFromTable(@"deactivate_account_password_alert_title", @"Vector", nil) + message:NSLocalizedStringFromTable(@"deactivate_account_password_alert_message", @"Vector", nil) preferredStyle:UIAlertControllerStyleAlert]; + + [alert addTextFieldWithConfigurationHandler:^(UITextField *textField) { + textField.secureTextEntry = YES; + textField.placeholder = nil; + textField.keyboardType = UIKeyboardTypeDefault; + }]; + + [alert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"] + style:UIAlertActionStyleCancel + handler:^(UIAlertAction * action) { + if (cancelHandler) + { + cancelHandler(); + } + }]]; + + __weak typeof(self) weakSelf = self; + + [alert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"submit"] + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * action) { + UITextField *textField = alert.textFields.firstObject; + + typeof(weakSelf) strongSelf = weakSelf; + + if (strongSelf) + { + NSString *password = textField.text; + + if (submitHandler) + { + submitHandler(password); + } + } + }]]; + + [self presentViewController:alert animated:YES completion:nil]; +} + +- (void)deactivateAccountWithUserId:(NSString*)userId + andPassword:(NSString*)password + eraseAllMessages:(BOOL)eraseAllMessages +{ + if (password && userId) + { + [self enableUserActions:NO]; + [self startActivityIndicator]; + + // This assumes that the homeserver requires password UI auth + // for this endpoint. In reality it could be any UI auth. + + __weak typeof(self) weakSelf = self; + + NSDictionary *authParameters = @{@"user": userId, + @"password": password, + @"type": kMXLoginFlowTypePassword}; + + [self.mainSession deactivateAccountWithAuthParameters:authParameters eraseAccount:eraseAllMessages success:^{ + NSLog(@"[SettingsViewController] Deactivate account with success"); + + [weakSelf stopActivityIndicator]; + [weakSelf enableUserActions:YES]; + } failure:^(NSError *error) { + + NSLog(@"[SettingsViewController] Failed to deactivate account"); + + typeof(weakSelf) strongSelf = weakSelf; + + if (strongSelf) + { + [strongSelf stopActivityIndicator]; + [strongSelf enableUserActions:YES]; + [strongSelf.errorPresentation presentErrorFromViewController:strongSelf forError:error animated:YES handler:nil]; + } + }]; + } + else + { + NSLog(@"[SettingsViewController] Failed to deactivate account"); + [self.errorPresentation presentGenericErrorFromViewController:self animated:YES handler:nil]; + } +} + +#pragma mark - Actions + +- (void)cancelButtonAction:(id)sender +{ + [self.delegate deactivateAccountViewControllerDidCancel:self]; +} + +- (IBAction)forgetMessagesButtonAction:(UIButton*)sender +{ + self.forgetMessageButton.selected = !self.forgetMessageButton.selected; +} + +- (IBAction)deactivateAccountButtonAction:(id)sender +{ + __weak typeof(self) weakSelf = self; + + [self presentPasswordRequiredAlertWithSubmitHandler:^(NSString *password) { + + typeof(weakSelf) strongSelf = weakSelf; + + if (strongSelf) + { + NSString *userId = strongSelf.mainSession.myUser.userId; + [strongSelf deactivateAccountWithUserId:userId andPassword:password eraseAllMessages:strongSelf.forgetMessageButton.isEnabled]; + } + + } cancelHandler:^{ + + }]; +} + +@end diff --git a/Riot/ViewController/DeactivateAccount/DeactivateAccountViewController.storyboard b/Riot/ViewController/DeactivateAccount/DeactivateAccountViewController.storyboard new file mode 100644 index 000000000..0f1ec1012 --- /dev/null +++ b/Riot/ViewController/DeactivateAccount/DeactivateAccountViewController.storyboard @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +