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 { @@ -14,15 +14,18 @@ typedef enum _ASIAuthenticationType {
14 ASIProxyAuthenticationType = 1 14 ASIProxyAuthenticationType = 1
15 } ASIAuthenticationType; 15 } ASIAuthenticationType;
16 16
17 -@interface ASIAuthenticationDialog : NSObject <UIActionSheetDelegate, UITableViewDelegate, UITableViewDataSource> { 17 +@interface ASIAuthenticationDialog : UIViewController <UIActionSheetDelegate, UITableViewDelegate, UITableViewDataSource> {
18 ASIHTTPRequest *request; 18 ASIHTTPRequest *request;
19 - UIActionSheet *loginDialog;  
20 ASIAuthenticationType type; 19 ASIAuthenticationType type;
  20 + UITableView *tableView;
  21 + UIViewController *presentingController;
  22 + CGFloat keyboardHeight;
21 } 23 }
22 + (void)presentAuthenticationDialogForRequest:(ASIHTTPRequest *)request; 24 + (void)presentAuthenticationDialogForRequest:(ASIHTTPRequest *)request;
23 + (void)presentProxyAuthenticationDialogForRequest:(ASIHTTPRequest *)request; 25 + (void)presentProxyAuthenticationDialogForRequest:(ASIHTTPRequest *)request;
24 26
  27 ++ (void)dismiss;
  28 +
25 @property (retain) ASIHTTPRequest *request; 29 @property (retain) ASIHTTPRequest *request;
26 -@property (retain) UIActionSheet *loginDialog;  
27 @property (assign) ASIAuthenticationType type; 30 @property (assign) ASIAuthenticationType type;
28 @end 31 @end
@@ -11,13 +11,17 @@ @@ -11,13 +11,17 @@
11 11
12 ASIAuthenticationDialog *sharedDialog = nil; 12 ASIAuthenticationDialog *sharedDialog = nil;
13 NSLock *dialogLock = nil; 13 NSLock *dialogLock = nil;
  14 +BOOL isDismissing = NO;
14 15
15 @interface ASIAuthenticationDialog () 16 @interface ASIAuthenticationDialog ()
16 - (void)show; 17 - (void)show;
  18 +@property (retain) UITableView *tableView;
17 @end 19 @end
18 20
19 @implementation ASIAuthenticationDialog 21 @implementation ASIAuthenticationDialog
20 22
  23 +#pragma mark init / dealloc
  24 +
21 + (void)initialize 25 + (void)initialize
22 { 26 {
23 if (self == [ASIAuthenticationDialog class]) { 27 if (self == [ASIAuthenticationDialog class]) {
@@ -28,8 +32,9 @@ NSLock *dialogLock = nil; @@ -28,8 +32,9 @@ NSLock *dialogLock = nil;
28 + (void)presentProxyAuthenticationDialogForRequest:(ASIHTTPRequest *)request 32 + (void)presentProxyAuthenticationDialogForRequest:(ASIHTTPRequest *)request
29 { 33 {
30 [dialogLock lock]; 34 [dialogLock lock];
31 - [sharedDialog release]; 35 + if (!sharedDialog) {
32 sharedDialog = [[self alloc] init]; 36 sharedDialog = [[self alloc] init];
  37 + }
33 [sharedDialog setRequest:request]; 38 [sharedDialog setRequest:request];
34 [sharedDialog setType:ASIProxyAuthenticationType]; 39 [sharedDialog setType:ASIProxyAuthenticationType];
35 [sharedDialog show]; 40 [sharedDialog show];
@@ -39,95 +44,156 @@ NSLock *dialogLock = nil; @@ -39,95 +44,156 @@ NSLock *dialogLock = nil;
39 + (void)presentAuthenticationDialogForRequest:(ASIHTTPRequest *)request 44 + (void)presentAuthenticationDialogForRequest:(ASIHTTPRequest *)request
40 { 45 {
41 [dialogLock lock]; 46 [dialogLock lock];
42 - [sharedDialog release]; 47 + if (!sharedDialog) {
43 sharedDialog = [[self alloc] init]; 48 sharedDialog = [[self alloc] init];
  49 + }
44 [sharedDialog setRequest:request]; 50 [sharedDialog setRequest:request];
45 [sharedDialog show]; 51 [sharedDialog show];
46 [dialogLock unlock]; 52 [dialogLock unlock];
  53 +}
47 54
  55 +- (id)init
  56 +{
  57 + if ((self = [self initWithNibName:nil bundle:nil])) {
  58 + [[NSNotificationCenter defaultCenter]
  59 + addObserver:self
  60 + selector:@selector(keyboardWillShow:)
  61 + name:UIKeyboardWillShowNotification
  62 + object:nil];
  63 + }
  64 + return self;
48 } 65 }
49 66
50 -- (void)show 67 +- (void)dealloc
51 { 68 {
52 - // Create an action sheet to show the login dialog 69 + [[NSNotificationCenter defaultCenter]
53 - [self setLoginDialog:[[[UIActionSheet alloc] init] autorelease]]; 70 + removeObserver:self name:UIKeyboardWillShowNotification object:nil];
54 - [[self loginDialog] setActionSheetStyle:UIActionSheetStyleBlackOpaque]; 71 +
55 - [[self loginDialog] setDelegate:self]; 72 + [request release];
  73 + [tableView release];
  74 + [presentingController.view removeFromSuperview];
  75 + [presentingController release];
  76 + [super dealloc];
  77 +}
56 78
57 - // We show the login form in a table view, similar to Safari's authentication dialog 79 +#pragma mark keyboard notifications
58 - UITableView *table = [[[UITableView alloc] initWithFrame:CGRectMake(0,80,320,480) style:UITableViewStyleGrouped] autorelease]; 80 +
59 - [table setDelegate:self]; 81 +- (void)keyboardWillShow:(NSNotification *)notification
60 - [table setDataSource:self]; 82 +{
61 - [[self loginDialog] addSubview:table]; 83 + NSValue *keyboardBoundsValue = [[notification userInfo] objectForKey:UIKeyboardBoundsUserInfoKey];
62 - [[self loginDialog] showInView:[[[UIApplication sharedApplication] windows] objectAtIndex:0]]; 84 + CGRect keyboardBounds;
63 - [[self loginDialog] setFrame:CGRectMake(0,0,320,480)]; 85 + [keyboardBoundsValue getValue:&keyboardBounds];
64 - 86 + UIEdgeInsets e = UIEdgeInsetsMake(0, 0, keyboardBounds.size.height, 0);
65 - // Setup the title (Couldn't figure out how to put this in the same toolbar as the buttons) 87 + [[self tableView] setScrollIndicatorInsets:e];
66 - UIToolbar *titleBar = [[[UIToolbar alloc] initWithFrame:CGRectMake(0,0,320,30)] autorelease]; 88 + [[self tableView] setContentInset:e];
67 - UILabel *label = [[[UILabel alloc] initWithFrame:CGRectMake(10,0,300,30)] autorelease]; 89 +}
68 - if ([self type] == ASIProxyAuthenticationType) { 90 +
69 - [label setText:@"Login to this secure proxy server."]; 91 +#pragma mark utilities
  92 +
  93 +- (UIViewController *)presentingController
  94 +{
  95 + if (!presentingController) {
  96 + presentingController = [[UIViewController alloc] initWithNibName:nil bundle:nil];
  97 +
  98 + // Attach to the window, but don't interfere.
  99 + UIWindow *window = [[[UIApplication sharedApplication] windows] objectAtIndex:0];
  100 + [window addSubview:presentingController.view];
  101 + [[presentingController view] setFrame:CGRectZero];
  102 + [[presentingController view] setUserInteractionEnabled:NO];
  103 + }
  104 +
  105 + return presentingController;
  106 +}
  107 +
  108 +- (UITextField *)textFieldInRow:(NSUInteger)row section:(NSUInteger)section
  109 +{
  110 + return [[[[[self tableView] cellForRowAtIndexPath:
  111 + [NSIndexPath indexPathForRow:row inSection:section]]
  112 + contentView] subviews] objectAtIndex:0];
  113 +}
  114 +
  115 +#pragma mark show / dismiss
  116 +
  117 ++ (void)dismiss
  118 +{
  119 + [dialogLock lock];
  120 + [[sharedDialog parentViewController] dismissModalViewControllerAnimated:YES];
  121 + [sharedDialog release];
  122 + sharedDialog = nil;
  123 + [dialogLock unlock];
  124 +}
  125 +
  126 +- (void)dismiss
  127 +{
  128 + if (self == sharedDialog) {
  129 + [[self class] dismiss];
70 } else { 130 } else {
71 - [label setText:@"Login to this secure server."]; 131 + [[self parentViewController] dismissModalViewControllerAnimated:YES];
  132 + }
  133 +}
  134 +
  135 +- (void)show
  136 +{
  137 + // Remove all subviews
  138 + UIView *v;
  139 + while ((v = [[[self view] subviews] lastObject])) {
  140 + [v removeFromSuperview];
72 } 141 }
73 - [label setTextColor:[UIColor blackColor]];  
74 - [label setFont:[UIFont systemFontOfSize:13.0]];  
75 - [label setShadowColor:[UIColor colorWithRed:1 green:1 blue:1 alpha:0.5]];  
76 - [label setShadowOffset:CGSizeMake(0, 1.0)];  
77 - [label setOpaque:NO];  
78 - [label setBackgroundColor:nil];  
79 - [label setTextAlignment:UITextAlignmentCenter];  
80 142
81 - [titleBar addSubview:label]; 143 + // Setup toolbar
82 - [[self loginDialog] addSubview:titleBar]; 144 + UINavigationBar *bar = [[[UINavigationBar alloc] init] autorelease];
  145 + [[self view] addSubview:bar];
83 146
84 - // Setup the toolbar 147 + UINavigationItem *navItem = [[[UINavigationItem alloc] init] autorelease];
85 - UIToolbar *toolbar = [[[UIToolbar alloc] initWithFrame:CGRectMake(0,30,320,50)] autorelease]; 148 + bar.items = [NSArray arrayWithObject:navItem];
86 149
87 - NSMutableArray *items = [[[NSMutableArray alloc] init] autorelease]; 150 + // Setup the title
88 - UIBarButtonItem *backButton = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancelAuthenticationFromDialog:)] autorelease]; 151 + if ([self type] == ASIProxyAuthenticationType) {
89 - [items addObject:backButton]; 152 + [navItem setPrompt:@"Login to this secure proxy server."];
  153 + } else {
  154 + [navItem setPrompt:@"Login to this secure server."];
  155 + }
90 156
91 - label = [[[UILabel alloc] initWithFrame:CGRectMake(0,0,170,50)] autorelease]; 157 + // Setup toolbar buttons
92 if ([self type] == ASIProxyAuthenticationType) { 158 if ([self type] == ASIProxyAuthenticationType) {
93 - [label setText:[[self request] proxyHost]]; 159 + [navItem setTitle:[[self request] proxyHost]];
94 } else { 160 } else {
95 - [label setText:[[[self request] url] host]]; 161 + [navItem setTitle:[[[self request] url] host]];
96 } 162 }
97 - [label setTextColor:[UIColor whiteColor]];  
98 - [label setFont:[UIFont boldSystemFontOfSize:22.0]];  
99 - [label setShadowColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:0.5]];  
100 - [label setShadowOffset:CGSizeMake(0, -1.0)];  
101 - [label setOpaque:NO];  
102 - [label setBackgroundColor:nil];  
103 - [label setTextAlignment:UITextAlignmentCenter];  
104 163
105 - [toolbar addSubview:label]; 164 + [navItem setLeftBarButtonItem:[[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancelAuthenticationFromDialog:)] autorelease]];
  165 + [navItem setRightBarButtonItem:[[[UIBarButtonItem alloc] initWithTitle:@"Login" style:UIBarButtonItemStyleDone target:self action:@selector(loginWithCredentialsFromDialog:)] autorelease]];
106 166
107 - UIBarButtonItem *labelButton = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:nil action:nil] autorelease]; 167 + // We show the login form in a table view, similar to Safari's authentication dialog
108 - [labelButton setCustomView:label]; 168 + [bar sizeToFit];
109 - [items addObject:labelButton]; 169 + CGRect f = [[self view] bounds];
110 - [items addObject:[[[UIBarButtonItem alloc] initWithTitle:@"Login" style:UIBarButtonItemStyleDone target:self action:@selector(loginWithCredentialsFromDialog:)] autorelease]]; 170 + f.origin.y = [bar frame].size.height;
111 - [toolbar setItems:items]; 171 + f.size.height -= f.origin.y;
112 172
113 - [[self loginDialog] addSubview:toolbar]; 173 + [self setTableView:[[[UITableView alloc] initWithFrame:f style:UITableViewStyleGrouped] autorelease]];
  174 + [[self tableView] setDelegate:self];
  175 + [[self tableView] setDataSource:self];
  176 + [[self view] addSubview:[self tableView]];
114 177
115 // Force reload the table content, and focus the first field to show the keyboard 178 // Force reload the table content, and focus the first field to show the keyboard
116 - [table reloadData]; 179 + [[self tableView] reloadData];
117 - [[[[table cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]] subviews] objectAtIndex:2] becomeFirstResponder]; 180 + [[[[[self tableView] cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]].contentView subviews] objectAtIndex:0] becomeFirstResponder];
118 181
  182 + [[self presentingController] presentModalViewController:self animated:YES];
119 } 183 }
120 184
  185 +#pragma mark button callbacks
  186 +
121 - (void)cancelAuthenticationFromDialog:(id)sender 187 - (void)cancelAuthenticationFromDialog:(id)sender
122 { 188 {
123 [[self request] cancelAuthentication]; 189 [[self request] cancelAuthentication];
124 - [[self loginDialog] dismissWithClickedButtonIndex:0 animated:YES]; 190 + [self dismiss];
125 } 191 }
126 192
127 - (void)loginWithCredentialsFromDialog:(id)sender 193 - (void)loginWithCredentialsFromDialog:(id)sender
128 { 194 {
129 - NSString *username = [[[[[[[self loginDialog] subviews] objectAtIndex:0] cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]] subviews] objectAtIndex:2] text]; 195 + NSString *username = [[self textFieldInRow:0 section:0] text];
130 - NSString *password = [[[[[[[self loginDialog] subviews] objectAtIndex:0] cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:1]] subviews] objectAtIndex:2] text]; 196 + NSString *password = [[self textFieldInRow:1 section:0] text];
131 197
132 if ([self type] == ASIProxyAuthenticationType) { 198 if ([self type] == ASIProxyAuthenticationType) {
133 [[self request] setProxyUsername:username]; 199 [[self request] setProxyUsername:username];
@@ -140,7 +206,7 @@ NSLock *dialogLock = nil; @@ -140,7 +206,7 @@ NSLock *dialogLock = nil;
140 // Handle NTLM domains 206 // Handle NTLM domains
141 NSString *scheme = ([self type] == ASIStandardAuthenticationType) ? [[self request] authenticationScheme] : [[self request] proxyAuthenticationScheme]; 207 NSString *scheme = ([self type] == ASIStandardAuthenticationType) ? [[self request] authenticationScheme] : [[self request] proxyAuthenticationScheme];
142 if ([scheme isEqualToString:(NSString *)kCFHTTPAuthenticationSchemeNTLM]) { 208 if ([scheme isEqualToString:(NSString *)kCFHTTPAuthenticationSchemeNTLM]) {
143 - NSString *domain = [[[[[[[self loginDialog] subviews] objectAtIndex:0] cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:2]] subviews] objectAtIndex:2] text]; 209 + NSString *domain = [[self textFieldInRow:0 section:2] text];
144 if ([self type] == ASIProxyAuthenticationType) { 210 if ([self type] == ASIProxyAuthenticationType) {
145 [[self request] setProxyDomain:domain]; 211 [[self request] setProxyDomain:domain];
146 } else { 212 } else {
@@ -148,23 +214,23 @@ NSLock *dialogLock = nil; @@ -148,23 +214,23 @@ NSLock *dialogLock = nil;
148 } 214 }
149 } 215 }
150 216
151 - [[self loginDialog] dismissWithClickedButtonIndex:1 animated:YES];  
152 [[self request] retryUsingSuppliedCredentials]; 217 [[self request] retryUsingSuppliedCredentials];
153 } 218 }
154 219
  220 +#pragma mark table view data source
155 221
156 -- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 222 +- (NSInteger)numberOfSectionsInTableView:(UITableView *)aTableView
157 { 223 {
158 NSString *scheme = ([self type] == ASIStandardAuthenticationType) ? [[self request] authenticationScheme] : [[self request] proxyAuthenticationScheme]; 224 NSString *scheme = ([self type] == ASIStandardAuthenticationType) ? [[self request] authenticationScheme] : [[self request] proxyAuthenticationScheme];
159 if ([scheme isEqualToString:(NSString *)kCFHTTPAuthenticationSchemeNTLM]) { 225 if ([scheme isEqualToString:(NSString *)kCFHTTPAuthenticationSchemeNTLM]) {
160 - return 3;  
161 - }  
162 return 2; 226 return 2;
  227 + }
  228 + return 1;
163 } 229 }
164 230
165 -- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section 231 +- (CGFloat)tableView:(UITableView *)aTableView heightForFooterInSection:(NSInteger)section
166 { 232 {
167 - if (section == [self numberOfSectionsInTableView:tableView]-1) { 233 + if (section == [self numberOfSectionsInTableView:aTableView]-1) {
168 return 30; 234 return 30;
169 } 235 }
170 return 0; 236 return 0;
@@ -195,30 +261,41 @@ NSLock *dialogLock = nil; @@ -195,30 +261,41 @@ NSLock *dialogLock = nil;
195 #endif 261 #endif
196 262
197 [cell setSelectionStyle:UITableViewCellSelectionStyleNone]; 263 [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
198 - UITextField *textField = [[[UITextField alloc] initWithFrame:CGRectMake(20,12,260,25)] autorelease]; 264 +
  265 + CGRect f = CGRectInset(cell.bounds, 10, 10);
  266 + UITextField *textField = [[[UITextField alloc] initWithFrame:f] autorelease];
  267 + [textField setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
199 [textField setAutocapitalizationType:UITextAutocapitalizationTypeNone]; 268 [textField setAutocapitalizationType:UITextAutocapitalizationTypeNone];
200 - if ([indexPath section] == 0) { 269 + [textField setAutocorrectionType:UITextAutocorrectionTypeNo];
  270 +
  271 + NSUInteger s = [indexPath section];
  272 + NSUInteger r = [indexPath row];
  273 +
  274 + if (s == 0 && r == 0) {
201 [textField setPlaceholder:@"User"]; 275 [textField setPlaceholder:@"User"];
202 - } else if ([indexPath section] == 1) { 276 + } else if (s == 0 && r == 1) {
203 [textField setPlaceholder:@"Password"]; 277 [textField setPlaceholder:@"Password"];
204 [textField setSecureTextEntry:YES]; 278 [textField setSecureTextEntry:YES];
205 - } else if ([indexPath section] == 2) { 279 + } else if (s == 1) {
206 [textField setPlaceholder:@"Domain"]; 280 [textField setPlaceholder:@"Domain"];
207 } 281 }
208 - [cell addSubview:textField]; 282 + [cell.contentView addSubview:textField];
209 283
210 return cell; 284 return cell;
211 } 285 }
212 286
213 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 287 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
214 { 288 {
  289 + if (section == 0) {
  290 + return 2;
  291 + } else {
215 return 1; 292 return 1;
  293 + }
216 } 294 }
217 295
218 - 296 +- (NSString *)tableView:(UITableView *)aTableView titleForFooterInSection:(NSInteger)section
219 -- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section  
220 { 297 {
221 - if (section == [self numberOfSectionsInTableView:tableView]-1) { 298 + if (section == [self numberOfSectionsInTableView:aTableView]-1) {
222 // If we're using Basic authentication and the connection is not using SSL, we'll show the plain text message 299 // If we're using Basic authentication and the connection is not using SSL, we'll show the plain text message
223 if ([[[self request] authenticationScheme] isEqualToString:(NSString *)kCFHTTPAuthenticationSchemeBasic] && ![[[[self request] url] scheme] isEqualToString:@"https"]) { 300 if ([[[self request] authenticationScheme] isEqualToString:(NSString *)kCFHTTPAuthenticationSchemeBasic] && ![[[[self request] url] scheme] isEqualToString:@"https"]) {
224 return @"Password will be sent in the clear."; 301 return @"Password will be sent in the clear.";
@@ -230,7 +307,9 @@ NSLock *dialogLock = nil; @@ -230,7 +307,9 @@ NSLock *dialogLock = nil;
230 return nil; 307 return nil;
231 } 308 }
232 309
  310 +#pragma mark -
  311 +
233 @synthesize request; 312 @synthesize request;
234 -@synthesize loginDialog;  
235 @synthesize type; 313 @synthesize type;
  314 +@synthesize tableView;
236 @end 315 @end
@@ -23,7 +23,7 @@ @@ -23,7 +23,7 @@
23 23
24 24
25 // Automatically set on build 25 // Automatically set on build
26 -NSString *ASIHTTPRequestVersion = @"v1.6.2-10 2010-05-14"; 26 +NSString *ASIHTTPRequestVersion = @"v1.6.2-13 2010-06-14";
27 27
28 NSString* const NetworkRequestErrorDomain = @"ASIHTTPRequestErrorDomain"; 28 NSString* const NetworkRequestErrorDomain = @"ASIHTTPRequestErrorDomain";
29 29
@@ -1502,6 +1502,9 @@ static BOOL isiPhoneOS2; @@ -1502,6 +1502,9 @@ static BOOL isiPhoneOS2;
1502 #if DEBUG_REQUEST_STATUS || DEBUG_THROTTLING 1502 #if DEBUG_REQUEST_STATUS || DEBUG_THROTTLING
1503 NSLog(@"Request finished: %@",self); 1503 NSLog(@"Request finished: %@",self);
1504 #endif 1504 #endif
  1505 + if ([self shouldPresentAuthenticationDialog] || [self shouldPresentProxyAuthenticationDialog]) {
  1506 + [self performSelectorOnMainThread:@selector(dismissAuthenticationDialog) withObject:nil waitUntilDone:[NSThread isMainThread]];
  1507 + }
1505 if ([self error] || [self mainRequest]) { 1508 if ([self error] || [self mainRequest]) {
1506 return; 1509 return;
1507 } 1510 }
@@ -2181,6 +2184,11 @@ static BOOL isiPhoneOS2; @@ -2181,6 +2184,11 @@ static BOOL isiPhoneOS2;
2181 #endif 2184 #endif
2182 } 2185 }
2183 2186
  2187 +- (void)dismissAuthenticationDialog
  2188 +{
  2189 + [ASIAuthenticationDialog dismiss];
  2190 +}
  2191 +
2184 - (BOOL)askDelegateForCredentials 2192 - (BOOL)askDelegateForCredentials
2185 { 2193 {
2186 // If we have a delegate, we'll see if it can handle proxyAuthenticationNeededForRequest:. 2194 // If we have a delegate, we'll see if it can handle proxyAuthenticationNeededForRequest:.