FRAAccountTableViewController.m revision 2250b453beee63acbe65426ed5f4aaa90e360435
e2d1c3c0c150e511b0df83a3c49451ae773ea93aCraig McDonnell * The contents of this file are subject to the terms of the Common Development and
e2d1c3c0c150e511b0df83a3c49451ae773ea93aCraig McDonnell * Distribution License (the License). You may not use this file except in compliance with the
e2d1c3c0c150e511b0df83a3c49451ae773ea93aCraig McDonnell * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
e2d1c3c0c150e511b0df83a3c49451ae773ea93aCraig McDonnell * specific language governing permission and limitations under the License.
e2d1c3c0c150e511b0df83a3c49451ae773ea93aCraig McDonnell * When distributing Covered Software, include this CDDL Header Notice in each file and include
e2d1c3c0c150e511b0df83a3c49451ae773ea93aCraig McDonnell * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
e2d1c3c0c150e511b0df83a3c49451ae773ea93aCraig McDonnell * Header, with the fields enclosed by brackets [] replaced by your own identifying
e2d1c3c0c150e511b0df83a3c49451ae773ea93aCraig McDonnell * information: "Portions copyright [year] [name of copyright owner]".
e2d1c3c0c150e511b0df83a3c49451ae773ea93aCraig McDonnell * Copyright 2016 ForgeRock AS.
e2d1c3c0c150e511b0df83a3c49451ae773ea93aCraig McDonnell#import "FRAAccountTableViewController.h"
fb63998ce7684bddab24e10c0b593809df1b7bffCraig McDonnell#import "FRABlockAlertView.h"
e2d1c3c0c150e511b0df83a3c49451ae773ea93aCraig McDonnell#import "FRAIdentityDatabase.h"
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell#import "FRANotificationsTableViewController.h"
e2d1c3c0c150e511b0df83a3c49451ae773ea93aCraig McDonnell#import "FRAOathMechanism.h"
fb63998ce7684bddab24e10c0b593809df1b7bffCraig McDonnell#import "FRAOathMechanismTableViewCell.h"
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell#import "FRAOathMechanismTableViewCellController.h"
415243fbc81341293a852ff6aa14e9608d08685cCraig McDonnell#import "FRAPushMechanism.h"
916ef74523ecddc8140815c084ab6971ee366bcfCraig McDonnellNSString * const FRAAccountTableViewControllerStoryboardIdentifer = @"AccountTableViewController";
916ef74523ecddc8140815c084ab6971ee366bcfCraig McDonnellNSString * const FRAAccountTableViewControllerShowNotificationsSegue = @"showNotificationsSegue";
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell/*! row index of static cell defining UI for OATH mechanism (cell is hidden if no such mechanism is registered) */
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnellstatic const NSInteger OATH_MECHANISM_ROW_INDEX = 1;
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell/*! row index of static cell defining UI for push mechanism (cell is hidden if no such mechanism is registered) */
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnellstatic const NSInteger PUSH_MECHANISM_ROW_INDEX = 2;
fb63998ce7684bddab24e10c0b593809df1b7bffCraig McDonnell@implementation FRAAccountTableViewController
fb63998ce7684bddab24e10c0b593809df1b7bffCraig McDonnell self.navigationItem.rightBarButtonItem = self.editButtonItem;
fb63998ce7684bddab24e10c0b593809df1b7bffCraig McDonnell // Show issuer logo in circle
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell self.image.layer.cornerRadius = self.image.frame.size.width / 2;
fb63998ce7684bddab24e10c0b593809df1b7bffCraig McDonnell // Bind identity model to UI
415243fbc81341293a852ff6aa14e9608d08685cCraig McDonnell // _image = ... // TODO: Use UIImageView+AFNetworking category provided by AFNetworking
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell self.accountName.text = self.identity.accountName;
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell self.oathTableViewCell.delegate = [FRAOathMechanismTableViewCellController
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell controllerWithView:self.oathTableViewCell mechanism:[self oathMechanism]];
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell self.pushTableViewCell.delegate = [FRAPushMechanismTableViewCellController
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell controllerWithView:self.pushTableViewCell mechanism:[self pushMechanism]];
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell [self.oathTableViewCell.delegate viewWillAppear:animated];
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell [self.pushTableViewCell.delegate viewWillAppear:animated];
415243fbc81341293a852ff6aa14e9608d08685cCraig McDonnell [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleIdentityDatabaseChanged:) name:FRAIdentityDatabaseChangedNotification object:nil];
3cb6a584a87fa8fec140b0bb20dd91731d13e751Diego Colantoni self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerCallback:) userInfo:nil repeats:YES];
415243fbc81341293a852ff6aa14e9608d08685cCraig McDonnell [[NSNotificationCenter defaultCenter] removeObserver:self];
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell [self.oathTableViewCell.delegate viewWillDisappear:animated];
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell [self.pushTableViewCell.delegate viewWillDisappear:animated];
e2d1c3c0c150e511b0df83a3c49451ae773ea93aCraig McDonnell // make table cell separator lines full width (normally, they leave a ~10% gap at the left edge)
e2d1c3c0c150e511b0df83a3c49451ae773ea93aCraig McDonnell if ([self.tableView respondsToSelector:@selector(setSeparatorInset:)]) {
e2d1c3c0c150e511b0df83a3c49451ae773ea93aCraig McDonnell [self.tableView setSeparatorInset:UIEdgeInsetsZero];
e2d1c3c0c150e511b0df83a3c49451ae773ea93aCraig McDonnell if ([self.tableView respondsToSelector:@selector(setLayoutMargins:)]) {
e2d1c3c0c150e511b0df83a3c49451ae773ea93aCraig McDonnell [self.tableView setLayoutMargins:UIEdgeInsetsZero];
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
916ef74523ecddc8140815c084ab6971ee366bcfCraig McDonnell if ([segue.identifier isEqualToString:FRAAccountTableViewControllerShowNotificationsSegue]) {
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell FRANotificationsTableViewController *controller = (FRANotificationsTableViewController *)segue.destinationViewController;
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell controller.pushMechanism = [self pushMechanism];
fb63998ce7684bddab24e10c0b593809df1b7bffCraig McDonnell- (BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath {
fb63998ce7684bddab24e10c0b593809df1b7bffCraig McDonnell // only indent mechanisms when in edit mode as only mechanisms can be deleted
fb63998ce7684bddab24e10c0b593809df1b7bffCraig McDonnell return [self hasMechanismAtIndexPath:indexPath];
fb63998ce7684bddab24e10c0b593809df1b7bffCraig McDonnell-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
fb63998ce7684bddab24e10c0b593809df1b7bffCraig McDonnell // make table cell separator lines full width (normally, they leave a ~10% gap at the left edge)
fb63998ce7684bddab24e10c0b593809df1b7bffCraig McDonnell if ([cell respondsToSelector:@selector(setSeparatorInset:)]) {
fb63998ce7684bddab24e10c0b593809df1b7bffCraig McDonnell if ([cell respondsToSelector:@selector(setLayoutMargins:)]) {
094b0368ec64814f07f74f090192a2fe81c8d0b7Craig McDonnell- (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(nonnull NSIndexPath *)indexPath {
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell if (indexPath.row == OATH_MECHANISM_ROW_INDEX) {
094b0368ec64814f07f74f090192a2fe81c8d0b7Craig McDonnell [tableView deselectRowAtIndexPath:indexPath animated:YES];
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell [self.oathTableViewCell.delegate didTouchUpInside];
fb63998ce7684bddab24e10c0b593809df1b7bffCraig McDonnell- (UITableViewCellEditingStyle)tableView:(UITableView *)aTableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
fb63998ce7684bddab24e10c0b593809df1b7bffCraig McDonnell // Only offer delete option on mechanism rows when in edit mode (disables swipe to delete)
fb63998ce7684bddab24e10c0b593809df1b7bffCraig McDonnell if (self.tableView.editing && [self hasMechanismAtIndexPath:indexPath]) {
e2d1c3c0c150e511b0df83a3c49451ae773ea93aCraig McDonnell- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell if (indexPath.row == OATH_MECHANISM_ROW_INDEX && ![self identityHasOathMechanism]) {
e2d1c3c0c150e511b0df83a3c49451ae773ea93aCraig McDonnell return 0; // hide the cell if OATH mechanism not registered
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell } else if (indexPath.row == PUSH_MECHANISM_ROW_INDEX && ![self identityHasPushMechanism]) {
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell return 0; // hide the cell if push mechanism not registered
e2d1c3c0c150e511b0df83a3c49451ae773ea93aCraig McDonnell return [super tableView:tableView heightForRowAtIndexPath:indexPath];
fb63998ce7684bddab24e10c0b593809df1b7bffCraig McDonnell- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
fb63998ce7684bddab24e10c0b593809df1b7bffCraig McDonnell if (editingStyle != UITableViewCellEditingStyleDelete) {
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell FRAMechanism *mechanism = [self mechanismAtIndexPath:indexPath];
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell initWithTitle:@"Removing this will NOT turn off 2-step verification"
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell message:[NSString stringWithFormat:@"This may prevent you from logging into your %@ account.", self.identity.issuer]
fb63998ce7684bddab24e10c0b593809df1b7bffCraig McDonnell#pragma mark FRAAccountTableViewController (private)
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell- (BOOL)hasMechanismAtIndexPath:(NSIndexPath*)indexPath {
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell return indexPath.row == OATH_MECHANISM_ROW_INDEX || indexPath.row == PUSH_MECHANISM_ROW_INDEX;
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell return (FRAOathMechanism *)[self.identity mechanismOfClass:[FRAOathMechanism class]];
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell return (FRAPushMechanism *)[self.identity mechanismOfClass:[FRAPushMechanism class]];
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell- (FRAMechanism *)mechanismAtIndexPath:(NSIndexPath *)indexPath {
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell if (indexPath.row == OATH_MECHANISM_ROW_INDEX) {
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell } else if (indexPath.row == PUSH_MECHANISM_ROW_INDEX) {
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell- (void)deleteMechanism:(FRAMechanism *)mechanism {
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell // If this is the only mechanism registered to the identity, then remove the identity itself
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell // (after navigating back to the accounts screen so that it's removal can be animated)
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell [self.navigationController popViewControllerAnimated:YES];
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott // TODO: Handle error?
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott [self.identityModel removeIdentity:parent error:&error];
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell // If the parent identity has other mechanisms registered to it, then just remove this mechanism
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell // and leave the UI updates to be triggered in response to the database change event handler
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott // TODO: Handle error?
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott [mechanism.parent removeMechanism:mechanism error:&error];
415243fbc81341293a852ff6aa14e9608d08685cCraig McDonnell- (void)handleIdentityDatabaseChanged:(NSNotification *)notification {
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell [FRAOathMechanismTableViewCellController controllerWithView:self.oathTableViewCell mechanism:[self oathMechanism]];
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell [self.oathTableViewCell.delegate reloadData];
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell [FRAPushMechanismTableViewCellController controllerWithView:self.pushTableViewCell mechanism:[self pushMechanism]];