NanoTech

Change the auth dialog into a UIViewController.

This brings a few things, including iPad support
and a proper top toolbar.
... ... @@ -14,15 +14,18 @@ typedef enum _ASIAuthenticationType {
ASIProxyAuthenticationType = 1
} ASIAuthenticationType;
@interface ASIAuthenticationDialog : NSObject <UIActionSheetDelegate, UITableViewDelegate, UITableViewDataSource> {
@interface ASIAuthenticationDialog : UIViewController <UIActionSheetDelegate, UITableViewDelegate, UITableViewDataSource> {
ASIHTTPRequest *request;
UIActionSheet *loginDialog;
ASIAuthenticationType type;
UITableView *tableView;
UIViewController *presentingController;
CGFloat keyboardHeight;
}
+ (void)presentAuthenticationDialogForRequest:(ASIHTTPRequest *)request;
+ (void)presentProxyAuthenticationDialogForRequest:(ASIHTTPRequest *)request;
+ (void)dismiss;
@property (retain) ASIHTTPRequest *request;
@property (retain) UIActionSheet *loginDialog;
@property (assign) ASIAuthenticationType type;
@end
... ...
... ... @@ -11,13 +11,17 @@
ASIAuthenticationDialog *sharedDialog = nil;
NSLock *dialogLock = nil;
BOOL isDismissing = NO;
@interface ASIAuthenticationDialog ()
- (void)show;
@property (retain) UITableView *tableView;
@end
@implementation ASIAuthenticationDialog
#pragma mark init / dealloc
+ (void)initialize
{
if (self == [ASIAuthenticationDialog class]) {
... ... @@ -28,143 +32,205 @@ NSLock *dialogLock = nil;
+ (void)presentProxyAuthenticationDialogForRequest:(ASIHTTPRequest *)request
{
[dialogLock lock];
[sharedDialog release];
sharedDialog = [[self alloc] init];
if (!sharedDialog) {
sharedDialog = [[self alloc] init];
}
[sharedDialog setRequest:request];
[sharedDialog setType:ASIProxyAuthenticationType];
[sharedDialog show];
[dialogLock unlock];
[dialogLock unlock];
}
+ (void)presentAuthenticationDialogForRequest:(ASIHTTPRequest *)request
{
[dialogLock lock];
[sharedDialog release];
sharedDialog = [[self alloc] init];
if (!sharedDialog) {
sharedDialog = [[self alloc] init];
}
[sharedDialog setRequest:request];
[sharedDialog show];
[dialogLock unlock];
}
- (id)init
{
if ((self = [self initWithNibName:nil bundle:nil])) {
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
}
return self;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter]
removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[request release];
[tableView release];
[presentingController.view removeFromSuperview];
[presentingController release];
[super dealloc];
}
#pragma mark keyboard notifications
- (void)keyboardWillShow:(NSNotification *)notification
{
NSValue *keyboardBoundsValue = [[notification userInfo] objectForKey:UIKeyboardBoundsUserInfoKey];
CGRect keyboardBounds;
[keyboardBoundsValue getValue:&keyboardBounds];
UIEdgeInsets e = UIEdgeInsetsMake(0, 0, keyboardBounds.size.height, 0);
[[self tableView] setScrollIndicatorInsets:e];
[[self tableView] setContentInset:e];
}
#pragma mark utilities
- (UIViewController *)presentingController
{
if (!presentingController) {
presentingController = [[UIViewController alloc] initWithNibName:nil bundle:nil];
// Attach to the window, but don't interfere.
UIWindow *window = [[[UIApplication sharedApplication] windows] objectAtIndex:0];
[window addSubview:presentingController.view];
[[presentingController view] setFrame:CGRectZero];
[[presentingController view] setUserInteractionEnabled:NO];
}
return presentingController;
}
- (UITextField *)textFieldInRow:(NSUInteger)row section:(NSUInteger)section
{
return [[[[[self tableView] cellForRowAtIndexPath:
[NSIndexPath indexPathForRow:row inSection:section]]
contentView] subviews] objectAtIndex:0];
}
#pragma mark show / dismiss
+ (void)dismiss
{
[dialogLock lock];
[[sharedDialog parentViewController] dismissModalViewControllerAnimated:YES];
[sharedDialog release];
sharedDialog = nil;
[dialogLock unlock];
}
- (void)dismiss
{
if (self == sharedDialog) {
[[self class] dismiss];
} else {
[[self parentViewController] dismissModalViewControllerAnimated:YES];
}
}
- (void)show
{
// Create an action sheet to show the login dialog
[self setLoginDialog:[[[UIActionSheet alloc] init] autorelease]];
[[self loginDialog] setActionSheetStyle:UIActionSheetStyleBlackOpaque];
[[self loginDialog] setDelegate:self];
// We show the login form in a table view, similar to Safari's authentication dialog
UITableView *table = [[[UITableView alloc] initWithFrame:CGRectMake(0,80,320,480) style:UITableViewStyleGrouped] autorelease];
[table setDelegate:self];
[table setDataSource:self];
[[self loginDialog] addSubview:table];
[[self loginDialog] showInView:[[[UIApplication sharedApplication] windows] objectAtIndex:0]];
[[self loginDialog] setFrame:CGRectMake(0,0,320,480)];
// Setup the title (Couldn't figure out how to put this in the same toolbar as the buttons)
UIToolbar *titleBar = [[[UIToolbar alloc] initWithFrame:CGRectMake(0,0,320,30)] autorelease];
UILabel *label = [[[UILabel alloc] initWithFrame:CGRectMake(10,0,300,30)] autorelease];
// Remove all subviews
UIView *v;
while ((v = [[[self view] subviews] lastObject])) {
[v removeFromSuperview];
}
// Setup toolbar
UINavigationBar *bar = [[[UINavigationBar alloc] init] autorelease];
[[self view] addSubview:bar];
UINavigationItem *navItem = [[[UINavigationItem alloc] init] autorelease];
bar.items = [NSArray arrayWithObject:navItem];
// Setup the title
if ([self type] == ASIProxyAuthenticationType) {
[label setText:@"Login to this secure proxy server."];
[navItem setPrompt:@"Login to this secure proxy server."];
} else {
[label setText:@"Login to this secure server."];
}
[label setTextColor:[UIColor blackColor]];
[label setFont:[UIFont systemFontOfSize:13.0]];
[label setShadowColor:[UIColor colorWithRed:1 green:1 blue:1 alpha:0.5]];
[label setShadowOffset:CGSizeMake(0, 1.0)];
[label setOpaque:NO];
[label setBackgroundColor:nil];
[label setTextAlignment:UITextAlignmentCenter];
[titleBar addSubview:label];
[[self loginDialog] addSubview:titleBar];
// Setup the toolbar
UIToolbar *toolbar = [[[UIToolbar alloc] initWithFrame:CGRectMake(0,30,320,50)] autorelease];
NSMutableArray *items = [[[NSMutableArray alloc] init] autorelease];
UIBarButtonItem *backButton = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancelAuthenticationFromDialog:)] autorelease];
[items addObject:backButton];
label = [[[UILabel alloc] initWithFrame:CGRectMake(0,0,170,50)] autorelease];
[navItem setPrompt:@"Login to this secure server."];
}
// Setup toolbar buttons
if ([self type] == ASIProxyAuthenticationType) {
[label setText:[[self request] proxyHost]];
[navItem setTitle:[[self request] proxyHost]];
} else {
[label setText:[[[self request] url] host]];
}
[label setTextColor:[UIColor whiteColor]];
[label setFont:[UIFont boldSystemFontOfSize:22.0]];
[label setShadowColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:0.5]];
[label setShadowOffset:CGSizeMake(0, -1.0)];
[label setOpaque:NO];
[label setBackgroundColor:nil];
[label setTextAlignment:UITextAlignmentCenter];
[toolbar addSubview:label];
UIBarButtonItem *labelButton = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:nil action:nil] autorelease];
[labelButton setCustomView:label];
[items addObject:labelButton];
[items addObject:[[[UIBarButtonItem alloc] initWithTitle:@"Login" style:UIBarButtonItemStyleDone target:self action:@selector(loginWithCredentialsFromDialog:)] autorelease]];
[toolbar setItems:items];
[[self loginDialog] addSubview:toolbar];
[navItem setTitle:[[[self request] url] host]];
}
[navItem setLeftBarButtonItem:[[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancelAuthenticationFromDialog:)] autorelease]];
[navItem setRightBarButtonItem:[[[UIBarButtonItem alloc] initWithTitle:@"Login" style:UIBarButtonItemStyleDone target:self action:@selector(loginWithCredentialsFromDialog:)] autorelease]];
// We show the login form in a table view, similar to Safari's authentication dialog
[bar sizeToFit];
CGRect f = [[self view] bounds];
f.origin.y = [bar frame].size.height;
f.size.height -= f.origin.y;
[self setTableView:[[[UITableView alloc] initWithFrame:f style:UITableViewStyleGrouped] autorelease]];
[[self tableView] setDelegate:self];
[[self tableView] setDataSource:self];
[[self view] addSubview:[self tableView]];
// Force reload the table content, and focus the first field to show the keyboard
[table reloadData];
[[[[table cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]] subviews] objectAtIndex:2] becomeFirstResponder];
[[self tableView] reloadData];
[[[[[self tableView] cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]].contentView subviews] objectAtIndex:0] becomeFirstResponder];
[[self presentingController] presentModalViewController:self animated:YES];
}
#pragma mark button callbacks
- (void)cancelAuthenticationFromDialog:(id)sender
{
[[self request] cancelAuthentication];
[[self loginDialog] dismissWithClickedButtonIndex:0 animated:YES];
[self dismiss];
}
- (void)loginWithCredentialsFromDialog:(id)sender
{
NSString *username = [[[[[[[self loginDialog] subviews] objectAtIndex:0] cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]] subviews] objectAtIndex:2] text];
NSString *password = [[[[[[[self loginDialog] subviews] objectAtIndex:0] cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:1]] subviews] objectAtIndex:2] text];
NSString *username = [[self textFieldInRow:0 section:0] text];
NSString *password = [[self textFieldInRow:1 section:0] text];
if ([self type] == ASIProxyAuthenticationType) {
[[self request] setProxyUsername:username];
[[self request] setProxyPassword:password];
} else {
[[self request] setUsername:username];
[[self request] setPassword:password];
[[self request] setPassword:password];
}
// Handle NTLM domains
NSString *scheme = ([self type] == ASIStandardAuthenticationType) ? [[self request] authenticationScheme] : [[self request] proxyAuthenticationScheme];
if ([scheme isEqualToString:(NSString *)kCFHTTPAuthenticationSchemeNTLM]) {
NSString *domain = [[[[[[[self loginDialog] subviews] objectAtIndex:0] cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:2]] subviews] objectAtIndex:2] text];
NSString *domain = [[self textFieldInRow:0 section:2] text];
if ([self type] == ASIProxyAuthenticationType) {
[[self request] setProxyDomain:domain];
} else {
[[self request] setDomain:domain];
}
}
[[self loginDialog] dismissWithClickedButtonIndex:1 animated:YES];
[[self request] retryUsingSuppliedCredentials];
[[self request] retryUsingSuppliedCredentials];
}
#pragma mark table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
- (NSInteger)numberOfSectionsInTableView:(UITableView *)aTableView
{
NSString *scheme = ([self type] == ASIStandardAuthenticationType) ? [[self request] authenticationScheme] : [[self request] proxyAuthenticationScheme];
if ([scheme isEqualToString:(NSString *)kCFHTTPAuthenticationSchemeNTLM]) {
return 3;
return 2;
}
return 2;
return 1;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
- (CGFloat)tableView:(UITableView *)aTableView heightForFooterInSection:(NSInteger)section
{
if (section == [self numberOfSectionsInTableView:tableView]-1) {
if (section == [self numberOfSectionsInTableView:aTableView]-1) {
return 30;
}
return 0;
... ... @@ -195,30 +261,41 @@ NSLock *dialogLock = nil;
#endif
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
UITextField *textField = [[[UITextField alloc] initWithFrame:CGRectMake(20,12,260,25)] autorelease];
CGRect f = CGRectInset(cell.bounds, 10, 10);
UITextField *textField = [[[UITextField alloc] initWithFrame:f] autorelease];
[textField setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
[textField setAutocapitalizationType:UITextAutocapitalizationTypeNone];
if ([indexPath section] == 0) {
[textField setAutocorrectionType:UITextAutocorrectionTypeNo];
NSUInteger s = [indexPath section];
NSUInteger r = [indexPath row];
if (s == 0 && r == 0) {
[textField setPlaceholder:@"User"];
} else if ([indexPath section] == 1) {
} else if (s == 0 && r == 1) {
[textField setPlaceholder:@"Password"];
[textField setSecureTextEntry:YES];
} else if ([indexPath section] == 2) {
} else if (s == 1) {
[textField setPlaceholder:@"Domain"];
}
[cell addSubview:textField];
}
[cell.contentView addSubview:textField];
return cell;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1;
if (section == 0) {
return 2;
} else {
return 1;
}
}
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
- (NSString *)tableView:(UITableView *)aTableView titleForFooterInSection:(NSInteger)section
{
if (section == [self numberOfSectionsInTableView:tableView]-1) {
if (section == [self numberOfSectionsInTableView:aTableView]-1) {
// If we're using Basic authentication and the connection is not using SSL, we'll show the plain text message
if ([[[self request] authenticationScheme] isEqualToString:(NSString *)kCFHTTPAuthenticationSchemeBasic] && ![[[[self request] url] scheme] isEqualToString:@"https"]) {
return @"Password will be sent in the clear.";
... ... @@ -230,7 +307,9 @@ NSLock *dialogLock = nil;
return nil;
}
#pragma mark -
@synthesize request;
@synthesize loginDialog;
@synthesize type;
@synthesize tableView;
@end
... ...
... ... @@ -23,7 +23,7 @@
// Automatically set on build
NSString *ASIHTTPRequestVersion = @"v1.6.2-10 2010-05-14";
NSString *ASIHTTPRequestVersion = @"v1.6.2-13 2010-06-14";
NSString* const NetworkRequestErrorDomain = @"ASIHTTPRequestErrorDomain";
... ... @@ -1502,6 +1502,9 @@ static BOOL isiPhoneOS2;
#if DEBUG_REQUEST_STATUS || DEBUG_THROTTLING
NSLog(@"Request finished: %@",self);
#endif
if ([self shouldPresentAuthenticationDialog] || [self shouldPresentProxyAuthenticationDialog]) {
[self performSelectorOnMainThread:@selector(dismissAuthenticationDialog) withObject:nil waitUntilDone:[NSThread isMainThread]];
}
if ([self error] || [self mainRequest]) {
return;
}
... ... @@ -2181,6 +2184,11 @@ static BOOL isiPhoneOS2;
#endif
}
- (void)dismissAuthenticationDialog
{
[ASIAuthenticationDialog dismiss];
}
- (BOOL)askDelegateForCredentials
{
// If we have a delegate, we'll see if it can handle proxyAuthenticationNeededForRequest:.
... ...