// // TokenViewController.m // ISDS // // Created by Petr Hruška on 6/30/11. // Copyright 2011 CZ.NIC, z.s.p.o. All rights reserved. // #import "TokenViewController.h" #import "OtpStatus.h" #import "DownloadCookie.h" #import "RequestManager.h" #define CONTINUE_BUTTON_INDEX 0 #define CANCEL_BUTTON_INDEX 1 @implementation TokenViewController @synthesize data=_data; @synthesize cell=_cell; @synthesize tableView=_tableView; @synthesize doneButton=_doneButton; @synthesize editing=_editing; @synthesize delegate; - (void)cancelNetworkOperations { //TODO remove from queue } - (void)dealloc { [self cancelNetworkOperations]; [_data release]; [_tableView release]; [_doneButton release]; [_editing release]; [super dealloc]; } - (void)viewDidUnload { self.tableView = nil; self.doneButton = nil; [super viewDidUnload]; } - (TokenCell*)cellAtIndex:(NSUInteger)index { return (TokenCell*)[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:index]]; } /* return [self.data count] if the focus should not be set */ - (NSUInteger)initialFocusIndex { NSUInteger index = 0; const NSUInteger count = [self.data count]; while (index < count) { OtpStatus* status = [self.data objectAtIndex:index]; if (status.status == OtpStatusShouldSendSms) { return count; } else if (status.status == OtpStatusEnterToken) { return index; } index++; } return index; } - (void)viewWillAppear:(BOOL)animated { self.doneButton.title = NSLocalizedString(@"Done", nil); self.navigationItem.rightBarButtonItem = self.doneButton; [super viewWillAppear:animated]; } - (void)viewDidAppear:(BOOL)animated { /* set focus */ NSUInteger index = [self initialFocusIndex]; if (index < [self.data count]) { TokenCell* cell = [self cellAtIndex:index]; [cell setFocus]; } [super viewDidAppear:animated]; } - (void)viewWillDisappear:(BOOL)animated { [self cancelNetworkOperations]; [super viewWillAppear:animated]; } - (NSUInteger)indexFromTask:(OtpTask*)task { const NSUInteger count = [self.data count]; for (NSUInteger index = 0; index < count; index++) { OtpStatus* status = [self.data objectAtIndex:index]; if (status.task == task) return index; } return count; } - (void)setupAccounts:(NSArray*)accounts { self.data = [NSMutableArray arrayWithCapacity:[accounts count]]; for (ISDSAccount* account in accounts) { if (account.authType != ISDSAccountAuthPass) { OtpStatus* status = [[OtpStatus alloc] initWithAccount:account]; [self.data addObject:status]; [status release]; } } } - (void)configureCell:(TokenCell*)cell withStatus:(OtpStatus*)status { cell.boxName = [status.account boxName]; cell.authType = status.account.authType; switch (status.status) { case OtpStatusShouldSendSms: cell.message = NSLocalizedString(@"click to send sms", nil); break; case OtpStatusRequestingSms: cell.message = NSLocalizedString(@"requesting sms", nil); break; case OtpStatusEnterToken: if (status.errorDescription != nil) cell.message = status.errorDescription; else cell.message = NSLocalizedString(@"enter code", nil); break; case OtpStatusRequestingCookie: cell.message = NSLocalizedString(@"requesting cookie", nil); break; case OtpStatusHasCookie: cell.message = NSLocalizedString(@"account authorized", nil); break; } [cell setStatus:status.status]; } - (IBAction)sendSms:(id)sender {/* FIXME TokenCell* cell = (TokenCell*)sender; NSUInteger index = cell.tag; OtpStatus* status = [self.data objectAtIndex:index]; status.connection = [[OtpTask alloc] initWithAccount:status.account delegate:self]; [status.connection release]; */ } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSString* reuseIdentifier = @"TokenCell"; TokenCell* cell = (TokenCell*)[tableView dequeueReusableCellWithIdentifier:reuseIdentifier]; if (cell == nil) { [[NSBundle mainBundle] loadNibNamed:@"TokenCell" owner:self options:nil]; cell = self.cell; self.cell = nil; } OtpStatus* status = [self.data objectAtIndex:[indexPath section]]; [self configureCell:cell withStatus:status]; [cell setupTag:indexPath.section]; return cell; } - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return [self.data count]; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return 1; } - (OtpTask*)createTask:(OtpStatus*)status { OtpTask* t; switch (status.account.authType) { case ISDSAccountAuthHotp: t = [[DownloadCookie alloc] initWithOtpStatus:status]; t.otpDelegate = self; [t autorelease]; break; default: t = nil; break; } return t; } - (void)done { [self.delegate tokenViewControllerDone:self]; [self.navigationController popViewControllerAnimated:YES]; } - (void)downloadCookies { NSUInteger taskCount = 0; for (OtpStatus* status in self.data) { if ([status tokenReady]) taskCount++; } if (!taskCount) { [self done]; return; } NSMutableArray* tasks = [NSMutableArray arrayWithCapacity:taskCount]; for (OtpStatus* status in self.data) if ([status tokenReady]) { OtpTask* task = [self createTask:status]; status.task = task; status.status = OtpStatusRequestingCookie; [tasks addObject:task]; } RequestManager* rm = [RequestManager requestManager]; [rm addTasks:tasks withPriority:YES]; [self.tableView reloadData]; } - (void)showActionSheet { UIActionSheet* actionSheet = [[UIActionSheet alloc] initWithTitle:NSLocalizedString(@"Some accounts are missing tokens. Do you with to continue?", nil) delegate:self cancelButtonTitle:NSLocalizedString(@"Cancel", nil) destructiveButtonTitle:NSLocalizedString(@"Continue", nil) otherButtonTitles: nil]; [actionSheet showInView:self.view]; [actionSheet release]; } - (void)markMissingUnwanted { for (OtpStatus* status in self.data) { if (![status tokenReady] && status.shouldHaveCookie) status.shouldHaveCookie = FALSE; } } - (IBAction)doneTouched { if (self.editing) [self.editing resignFirstResponder]; NSUInteger missingCount = 0; for (OtpStatus* status in self.data) { if (![status tokenReady] && status.shouldHaveCookie) missingCount++; } if (missingCount) [self showActionSheet]; else [self downloadCookies]; } - (void)reloadSectionForIndex:(NSUInteger)index { [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:index] withRowAnimation:UITableViewRowAnimationNone]; } - (BOOL)hasAllWantedCookies { for (OtpStatus* status in self.data) if (status.status != OtpStatusHasCookie && status.shouldHaveCookie) return NO; return YES; } #pragma mark - OtpTaskDelegate - (void)taskSuccessfullyDone:(ISDSTask*)task { NSUInteger index = [self indexFromTask:(OtpTask*)task]; OtpStatus* status = [self.data objectAtIndex:index]; switch (status.status) { case OtpStatusRequestingSms: status.status = OtpStatusEnterToken; [self reloadSectionForIndex:index]; break; case OtpStatusRequestingCookie: status.status = OtpStatusHasCookie; if ([self hasAllWantedCookies]) [self done]; else [self reloadSectionForIndex:index]; break; default: break; } } - (void)taskFailed:(ISDSTask*)task { NSUInteger index = [self indexFromTask:(OtpTask*)task]; if (index == [self.data count]) return; OtpStatus* status = [self.data objectAtIndex:index]; status.status = OtpStatusEnterToken; status.errorDescription = task.errorDescription; [self reloadSectionForIndex:index]; } #pragma mark - UITextFieldDelegate - (void)setupTokenFromTextField:(UITextField *)textField { NSUInteger index = textField.tag; OtpStatus* status = [self.data objectAtIndex:index]; status.token = textField.text; } - (void)textFieldDidBeginEditing:(UITextField *)textField { self.editing = textField; } - (void)textFieldDidEndEditing:(UITextField *)textField { [self setupTokenFromTextField:textField]; self.editing = nil; } - (BOOL)textFieldShouldReturn:(UITextField *)textField { [textField resignFirstResponder]; return NO; } - (BOOL)textFieldShouldClear:(UITextField *)textField { if ([textField isFirstResponder]) [textField resignFirstResponder]; else textField.text = @""; return NO; } - (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex { switch (buttonIndex) { case CONTINUE_BUTTON_INDEX: // we will not ask next time [self markMissingUnwanted]; [self downloadCookies]; break; case CANCEL_BUTTON_INDEX: break; } } @end