--- /dev/null
+//
+// SWCViewController.m
+// SharedWebCredentialViewService
+//
+// Copyright (c) 2014 Apple Inc. All Rights Reserved.
+//
+
+#import "SWCViewController.h"
+#import <UIKit/UIViewController_Private.h>
+#import <UIKit/UIFont_Private.h>
+
+#import <UIKit/UIAlertController_Private.h>
+#import <UIKit/UITableViewCell_Private.h>
+
+#include <bsm/libbsm.h>
+#include <ipc/securityd_client.h>
+#include "SharedWebCredential/swcagent_client.h"
+
+const NSString* SWC_PASSWORD_KEY = @"spwd";
+const NSString* SWC_ACCOUNT_KEY = @"acct";
+const NSString* SWC_SERVER_KEY = @"srvr";
+
+//
+// SWCDictionaryAdditions
+//
+
+@interface NSDictionary (SWCDictionaryAdditions)
+- (NSComparisonResult) compareCredentialDictionaryAscending:(NSDictionary *)other;
+@end
+
+@implementation NSDictionary (SWCDictionaryAdditions)
+- (NSComparisonResult)compareCredentialDictionaryAscending:(NSDictionary *)other
+{
+ NSComparisonResult result;
+ NSString *str1 = [self objectForKey:SWC_ACCOUNT_KEY], *str2 = [other objectForKey:SWC_ACCOUNT_KEY];
+ if (!str1) str1 = @"";
+ if (!str2) str2 = @"";
+
+ // primary sort by account name
+ result = [str1 localizedCaseInsensitiveCompare:str2];
+ if (result == NSOrderedSame) {
+ // secondary sort by domain name
+ NSString *str3 = [self objectForKey:SWC_SERVER_KEY], *str4 = [other objectForKey:SWC_SERVER_KEY];
+ if (!str3) str3 = @"";
+ if (!str4) str4 = @"";
+
+ result = [str3 localizedCaseInsensitiveCompare:str4];
+ }
+
+ return result;
+}
+@end
+
+
+//
+// SWCItemCell
+//
+@interface SWCItemCell : UITableViewCell
+{
+ NSDictionary *_dict;
+ BOOL _isTicked;
+ UIView *_bottomLine;
+ UIView *_bottomLineSelected;
+ UIView *_topLine;
+ UIView *_topLineSelected;
+ BOOL _showSeparator;
+ BOOL _showTopSeparator;
+}
+
+- (id)initWithDictionary:(NSDictionary *)dict;
+@property (nonatomic, readonly) id userInfo;
+@property (nonatomic, assign) BOOL showSeparator;
+@end
+
+@implementation SWCItemCell
+
+@synthesize showSeparator = _showSeparator;
+
+- (id)initWithDictionary:(NSDictionary *)dict
+{
+ if ((self = [super initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:nil]))
+ {
+ _dict = dict;
+
+ self.selectionStyle = UITableViewCellSelectionStyleNone;
+
+ self.backgroundColor = [UIColor colorWithWhite:0.1 alpha:0.005];
+
+ self.textLabel.textColor = [UIColor blackColor];
+ self.textLabel.textAlignment = NSTextAlignmentLeft;
+ self.textLabel.AdjustsFontSizeToFitWidth = YES;
+ self.textLabel.baselineAdjustment = UIBaselineAdjustmentAlignCenters;
+
+ NSString *title = [dict objectForKey:SWC_ACCOUNT_KEY];
+ self.textLabel.text = title ? title : @"--";
+
+ self.detailTextLabel.textColor = [UIColor darkGrayColor];
+ self.detailTextLabel.textAlignment = NSTextAlignmentLeft;
+ self.detailTextLabel.AdjustsFontSizeToFitWidth = YES;
+ self.detailTextLabel.baselineAdjustment = UIBaselineAdjustmentAlignCenters;
+
+ NSString *subtitle = [dict objectForKey:SWC_SERVER_KEY];
+ self.detailTextLabel.text = subtitle ? subtitle : @"--";
+
+ self.backgroundView = [[UIView alloc] init];
+ self.backgroundView.backgroundColor = self.backgroundColor;
+
+ self.imageView.image = [self _checkmarkImage: NO];
+ self.imageView.hidden = YES;
+
+ }
+
+ return self;
+}
+
+- (void)setTicked: (BOOL) selected
+{
+ _isTicked = selected;
+}
+
+- (void)layoutSubviews
+{
+
+ if (_bottomLine) {
+ CGFloat scale = [[UIScreen mainScreen] scale];
+ [_bottomLine setFrame:CGRectMake(0, self.frame.size.height - (1 / scale), self.frame.size.width, 1 / scale)];
+ }
+
+ if (_bottomLineSelected) {
+ CGFloat scale = [[UIScreen mainScreen] scale];
+ [_bottomLineSelected setFrame:CGRectMake(0, self.frame.size.height - (1 / scale), self.frame.size.width, 1 / scale)];
+ }
+
+ if (_topLine) {
+ CGFloat scale = [[UIScreen mainScreen] scale];
+ [_topLine setFrame:CGRectMake(0, 0, self.frame.size.width, 1 / scale)];
+ }
+
+ if (_topLineSelected) {
+ CGFloat scale = [[UIScreen mainScreen] scale];
+ [_topLineSelected setFrame:CGRectMake(0, 0, self.frame.size.width, 1 / scale)];
+ }
+
+ if (_isTicked)
+ {
+ self.imageView.hidden = NO;
+ } else {
+ self.imageView.hidden = YES;
+ }
+
+ [super layoutSubviews];
+
+}
+
+- (void)setShowSeparator:(BOOL)showSeparator {
+ if (_showSeparator != showSeparator) {
+ _showSeparator = showSeparator;
+
+ if (_showSeparator) {
+ if (!_bottomLine) {
+ CGRect rectZero = CGRectMake(0, 0, 0, 0);
+ _bottomLine = [[UIView alloc] initWithFrame:rectZero];
+ _bottomLine.backgroundColor = [UIColor colorWithWhite:.5 alpha:.5];
+ [self.backgroundView addSubview:_bottomLine];
+ }
+ if (!_bottomLineSelected) {
+ CGRect rectZero = CGRectMake(0, 0, 0, 0);
+ _bottomLineSelected = [[UIView alloc] initWithFrame:rectZero];
+ _bottomLineSelected.backgroundColor = [UIColor colorWithWhite:.5 alpha:.5];
+ [self.selectedBackgroundView addSubview: _bottomLineSelected];
+ }
+
+ } else {
+ if (_bottomLine) {
+ [_bottomLine removeFromSuperview];
+ _bottomLine = nil;
+ }
+ if (_bottomLineSelected) {
+ [_bottomLineSelected removeFromSuperview];
+ _bottomLineSelected = nil;
+ }
+ }
+ }
+}
+
+- (void)setShowTopSeparator:(BOOL)showTopSeparator {
+ if (_showTopSeparator != showTopSeparator) {
+ _showTopSeparator = showTopSeparator;
+
+ if (_showTopSeparator) {
+ if (!_topLine) {
+ CGRect rectZero = CGRectMake(0, 0, 0, 0);
+ _topLine = [[UIView alloc] initWithFrame:rectZero];
+ _topLine.backgroundColor = [UIColor colorWithWhite:.5 alpha:.5];
+ [self.backgroundView addSubview:_topLine];
+ }
+ if (!_topLineSelected) {
+ CGRect rectZero = CGRectMake(0, 0, 0, 0);
+ _topLineSelected = [[UIView alloc] initWithFrame:rectZero];
+ _topLineSelected.backgroundColor = [UIColor colorWithWhite:.5 alpha:.5];
+ [self.selectedBackgroundView addSubview: _topLineSelected];
+ }
+
+ } else {
+ if (_topLine) {
+ [_topLine removeFromSuperview];
+ _topLine = nil;
+ }
+ if (_topLineSelected) {
+ [_topLineSelected removeFromSuperview];
+ _topLineSelected = nil;
+ }
+ }
+ }
+}
+
+@end
+
+
+//
+// SWCViewController
+//
+
+@interface SWCViewController ()
+{
+ NSMutableArray *_credentials; // array of NSDictionary
+ UILabel *_topLabel;
+ UILabel *_middleLabel;
+ UITableView *_table;
+ NSDictionary *_selectedDict;
+ NSIndexPath *_selectedCell;
+}
+
+@end
+
+@implementation SWCViewController
+
+- (NSDictionary *)selectedItem
+{
+ return _selectedDict;
+}
+
+- (void)setCredentials:(NSArray *)inArray
+{
+ NSMutableArray *credentials = [[NSMutableArray alloc] initWithArray:inArray];
+ [credentials sortUsingSelector:@selector(compareCredentialDictionaryAscending:)];
+ _credentials = credentials;
+ if (_table)
+ [_table reloadData];
+}
+
+- (void)_enableTable
+{
+ [_table setUserInteractionEnabled:YES];
+}
+
+- (UITableView *)tableView
+{
+ if (_table == nil) {
+ _table = [[UITableView alloc] init];
+ [_table setTranslatesAutoresizingMaskIntoConstraints:NO];
+ [_table setAutoresizingMask:UIViewAutoresizingNone];
+ [_table setBackgroundColor:[UIColor clearColor]];
+ [_table setSeparatorStyle:UITableViewCellSeparatorStyleNone];
+ }
+ [_table sizeToFit];
+
+ return (UITableView *)_table;
+}
+
+-(void)loadView
+{
+
+ UIView* view = [[UIView alloc] init];
+
+ UITableView* table = [self tableView];
+ [table setDelegate: self];
+ [table setDataSource: self];
+
+ [view addSubview: table];
+
+ CFErrorRef error = NULL;
+ audit_token_t auditToken = {};
+ memset(&auditToken, 0, sizeof(auditToken));
+ CFArrayRef credentialList = swca_copy_pairs(swca_copy_pairs_request_id, &auditToken, &error);
+ if (error) {
+ NSLog(@"Unable to get accounts: %@", [(__bridge NSError*)error localizedDescription]);
+ }
+
+ [self setCredentials:(__bridge NSArray*)credentialList];
+ if (credentialList) {
+ CFRelease(credentialList);
+ }
+
+
+ NSDictionary* views = NSDictionaryOfVariableBindings(table);
+
+ if ([_credentials count] > 2)
+ {
+
+ NSDictionary *metrics = @{@"height":@120.0};
+ [view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[table]-|" options:0 metrics:metrics views:views]];
+ [view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[table(height)]-|" options:0 metrics:metrics views:views]];
+
+ CGFloat scale = [[UIScreen mainScreen] scale];
+ table.layer.borderWidth = 1.0 / scale;
+ table.layer.borderColor = [UIColor colorWithWhite:.5 alpha:.5].CGColor;
+
+ [self setPreferredContentSize:CGSizeMake(0,140)];
+
+ } else if ([_credentials count] == 2) {
+
+ NSDictionary *metrics = @{@"height":@90.0};
+ [view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[table]|" options:0 metrics:metrics views:views]];
+ [view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[table(height)]-|" options:0 metrics:metrics views:views]];
+
+ [self setPreferredContentSize:CGSizeMake(0,90)];
+ [table setScrollEnabled: NO];
+
+ } else { // [_credentials count] == 1
+
+ NSDictionary *metrics = @{@"height":@45.0};
+ [view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[table]|" options:0 metrics:metrics views:views]];
+ [view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[table(height)]|" options:0 metrics:metrics views:views]];
+
+ [self setPreferredContentSize:CGSizeMake(0,45)];
+ [table setScrollEnabled: NO];
+
+ }
+
+ [self setView:view];
+}
+
+-(void)viewWillAppear:(BOOL)animated
+{
+
+ // Select the first cell by default
+
+ NSDictionary *dict = [_credentials objectAtIndex: 0];
+ _selectedDict = dict;
+ _selectedCell = [NSIndexPath indexPathForItem:0 inSection: 0];
+ SWCItemCell *cell = (SWCItemCell *)[_table cellForRowAtIndexPath: _selectedCell];
+ [cell setTicked: YES];
+ [_table selectRowAtIndexPath: _selectedCell animated: NO scrollPosition: UITableViewScrollPositionTop];
+
+ CFErrorRef error = NULL;
+ audit_token_t auditToken = {};
+ memset(&auditToken, 0, sizeof(auditToken));
+ bool result = swca_set_selection(swca_set_selection_request_id,
+ &auditToken, (__bridge CFDictionaryRef)dict, &error);
+ if (!result) {
+ NSLog(@"Unable to select item: %@", [(__bridge NSError*)error localizedDescription]);
+ }
+
+ [super viewWillAppear:animated];
+}
+
+
+//
+// UITableView delegate methods
+//
+
+- (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section
+{
+ return [_credentials count];
+}
+
+- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
+{
+ NSUInteger row = indexPath.row;
+
+ NSDictionary *dict = [_credentials objectAtIndex:row];
+ _selectedDict = dict;
+
+ CFErrorRef error = NULL;
+ audit_token_t auditToken = {};
+ memset(&auditToken, 0, sizeof(auditToken));
+ bool result = swca_set_selection(swca_set_selection_request_id,
+ &auditToken, (__bridge CFDictionaryRef)dict, &error);
+ if (!result) {
+ NSLog(@"Unable to select item: %@", [(__bridge NSError*)error localizedDescription]);
+ }
+
+ _selectedCell = indexPath;
+ SWCItemCell *cell = (SWCItemCell *)[tableView cellForRowAtIndexPath: indexPath];
+ [cell setTicked: YES];
+ [cell layoutSubviews];
+}
+
+- (void) tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
+{
+ SWCItemCell *cell = (SWCItemCell *)[tableView cellForRowAtIndexPath: indexPath];
+ [cell setTicked: NO];
+ [cell layoutSubviews];
+
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
+{
+
+ NSDictionary *dict = [_credentials objectAtIndex:[indexPath row]];
+ SWCItemCell *cell = [[SWCItemCell alloc] initWithDictionary:dict];
+
+ // show separator on top cell if there's only or or two items
+ if ([_credentials count] <= 2) {
+ cell.showTopSeparator = YES;
+ } else {
+ cell.showSeparator = YES;
+
+ if (indexPath.row == 0)
+ {
+ cell.showTopSeparator = YES;
+ }
+
+ }
+
+ if (_selectedCell == indexPath)
+ {
+ [cell setTicked: YES];
+ } else {
+ [cell setTicked: NO];
+ }
+
+ return cell;
+}
+
+
+@end