SinaWeiboAuthorizeView.m 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. //
  2. // SinaWeiboAuthorizeView.m
  3. // sinaweibo_ios_sdk
  4. //
  5. // Created by Wade Cheng on 4/19/12.
  6. // Copyright (c) 2012 SINA. All rights reserved.
  7. //
  8. #import "SinaWeiboAuthorizeView.h"
  9. #import "SinaWeiboRequest.h"
  10. #import "SinaWeibo.h"
  11. #import "SinaWeiboConstants.h"
  12. #import <QuartzCore/QuartzCore.h>
  13. static CGFloat kBorderGray[4] = {0.3, 0.3, 0.3, 0.8};
  14. static CGFloat kBorderBlack[4] = {0.3, 0.3, 0.3, 1};
  15. static CGFloat kTransitionDuration = 0.3;
  16. static CGFloat kPadding = 0;
  17. static CGFloat kBorderWidth = 10;
  18. @implementation SinaWeiboAuthorizeView
  19. @synthesize delegate;
  20. #pragma mark - Drawing
  21. - (void)addRoundedRectToPath:(CGContextRef)context rect:(CGRect)rect radius:(float)radius
  22. {
  23. CGContextBeginPath(context);
  24. CGContextSaveGState(context);
  25. if (radius == 0)
  26. {
  27. CGContextTranslateCTM(context, CGRectGetMinX(rect), CGRectGetMinY(rect));
  28. CGContextAddRect(context, rect);
  29. }
  30. else
  31. {
  32. rect = CGRectOffset(CGRectInset(rect, 0.5, 0.5), 0.5, 0.5);
  33. CGContextTranslateCTM(context, CGRectGetMinX(rect)-0.5, CGRectGetMinY(rect)-0.5);
  34. CGContextScaleCTM(context, radius, radius);
  35. float fw = CGRectGetWidth(rect) / radius;
  36. float fh = CGRectGetHeight(rect) / radius;
  37. CGContextMoveToPoint(context, fw, fh/2);
  38. CGContextAddArcToPoint(context, fw, fh, fw/2, fh, 1);
  39. CGContextAddArcToPoint(context, 0, fh, 0, fh/2, 1);
  40. CGContextAddArcToPoint(context, 0, 0, fw/2, 0, 1);
  41. CGContextAddArcToPoint(context, fw, 0, fw, fh/2, 1);
  42. }
  43. CGContextClosePath(context);
  44. CGContextRestoreGState(context);
  45. }
  46. - (void)drawRect:(CGRect)rect fill:(const CGFloat*)fillColors radius:(CGFloat)radius
  47. {
  48. CGContextRef context = UIGraphicsGetCurrentContext();
  49. CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
  50. if (fillColors)
  51. {
  52. CGContextSaveGState(context);
  53. CGContextSetFillColor(context, fillColors);
  54. if (radius)
  55. {
  56. [self addRoundedRectToPath:context rect:rect radius:radius];
  57. CGContextFillPath(context);
  58. }
  59. else
  60. {
  61. CGContextFillRect(context, rect);
  62. }
  63. CGContextRestoreGState(context);
  64. }
  65. CGColorSpaceRelease(space);
  66. }
  67. - (void)strokeLines:(CGRect)rect stroke:(const CGFloat*)strokeColor
  68. {
  69. CGContextRef context = UIGraphicsGetCurrentContext();
  70. CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
  71. CGContextSaveGState(context);
  72. CGContextSetStrokeColorSpace(context, space);
  73. CGContextSetStrokeColor(context, strokeColor);
  74. CGContextSetLineWidth(context, 1.0);
  75. {
  76. CGPoint points[] = {{rect.origin.x+0.5, rect.origin.y-0.5},
  77. {rect.origin.x+rect.size.width, rect.origin.y-0.5}};
  78. CGContextStrokeLineSegments(context, points, 2);
  79. }
  80. {
  81. CGPoint points[] = {{rect.origin.x+0.5, rect.origin.y+rect.size.height-0.5},
  82. {rect.origin.x+rect.size.width-0.5, rect.origin.y+rect.size.height-0.5}};
  83. CGContextStrokeLineSegments(context, points, 2);
  84. }
  85. {
  86. CGPoint points[] = {{rect.origin.x+rect.size.width-0.5, rect.origin.y},
  87. {rect.origin.x+rect.size.width-0.5, rect.origin.y+rect.size.height}};
  88. CGContextStrokeLineSegments(context, points, 2);
  89. }
  90. {
  91. CGPoint points[] = {{rect.origin.x+0.5, rect.origin.y},
  92. {rect.origin.x+0.5, rect.origin.y+rect.size.height}};
  93. CGContextStrokeLineSegments(context, points, 2);
  94. }
  95. CGContextRestoreGState(context);
  96. CGColorSpaceRelease(space);
  97. }
  98. - (void)drawRect:(CGRect)rect
  99. {
  100. [self drawRect:rect fill:kBorderGray radius:0];
  101. CGRect webRect = CGRectMake(
  102. ceil(rect.origin.x+kBorderWidth), ceil(rect.origin.y+kBorderWidth)+1,
  103. rect.size.width-kBorderWidth*2, rect.size.height-(1+kBorderWidth*2));
  104. [self strokeLines:webRect stroke:kBorderBlack];
  105. }
  106. #pragma mark - Memory management
  107. - (id)init
  108. {
  109. if ((self = [super init]))
  110. {
  111. self.backgroundColor = [UIColor clearColor];
  112. self.autoresizesSubviews = YES;
  113. self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
  114. self.contentMode = UIViewContentModeRedraw;
  115. webView = [[UIWebView alloc] init];
  116. webView.delegate = self;
  117. webView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
  118. [self addSubview:webView];
  119. [webView release];
  120. UIImage* closeImage = [UIImage imageNamed:@"SinaWeibo.bundle/images/close.png"];
  121. UIColor* color = [UIColor colorWithRed:167.0/255 green:184.0/255 blue:216.0/255 alpha:1];
  122. closeButton = [UIButton buttonWithType:UIButtonTypeCustom];
  123. [closeButton setImage:closeImage forState:UIControlStateNormal];
  124. [closeButton setTitleColor:color forState:UIControlStateNormal];
  125. [closeButton setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted];
  126. [closeButton addTarget:self action:@selector(cancel)
  127. forControlEvents:UIControlEventTouchUpInside];
  128. closeButton.titleLabel.font = [UIFont boldSystemFontOfSize:12];
  129. closeButton.showsTouchWhenHighlighted = YES;
  130. closeButton.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
  131. [self addSubview:closeButton];
  132. indicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:
  133. UIActivityIndicatorViewStyleGray];
  134. indicatorView.autoresizingMask =
  135. UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin
  136. | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
  137. [self addSubview:indicatorView];
  138. modalBackgroundView = [[UIView alloc] init];
  139. }
  140. return self;
  141. }
  142. - (void)dealloc
  143. {
  144. [authParams release], authParams = nil;
  145. [appRedirectURI release], appRedirectURI = nil;
  146. [modalBackgroundView release], modalBackgroundView = nil;
  147. [super dealloc];
  148. }
  149. - (id)initWithAuthParams:(NSDictionary *)params
  150. delegate:(id<SinaWeiboAuthorizeViewDelegate>)_delegate
  151. {
  152. if ((self = [self init]))
  153. {
  154. self.delegate = _delegate;
  155. authParams = [params copy];
  156. appRedirectURI = [[authParams objectForKey:@"redirect_uri"] retain];
  157. }
  158. return self;
  159. }
  160. #pragma mark - View orientation
  161. - (BOOL)shouldRotateToOrientation:(UIInterfaceOrientation)orientation
  162. {
  163. if (orientation == previousOrientation)
  164. {
  165. return NO;
  166. }
  167. else
  168. {
  169. return orientation == UIInterfaceOrientationPortrait
  170. || orientation == UIInterfaceOrientationPortraitUpsideDown
  171. || orientation == UIInterfaceOrientationLandscapeLeft
  172. || orientation == UIInterfaceOrientationLandscapeRight;
  173. }
  174. }
  175. - (CGAffineTransform)transformForOrientation
  176. {
  177. UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
  178. if (orientation == UIInterfaceOrientationLandscapeLeft)
  179. {
  180. return CGAffineTransformMakeRotation(M_PI*1.5);
  181. }
  182. else if (orientation == UIInterfaceOrientationLandscapeRight)
  183. {
  184. return CGAffineTransformMakeRotation(M_PI/2);
  185. }
  186. else if (orientation == UIInterfaceOrientationPortraitUpsideDown)
  187. {
  188. return CGAffineTransformMakeRotation(-M_PI);
  189. }
  190. else
  191. {
  192. return CGAffineTransformIdentity;
  193. }
  194. }
  195. - (void)sizeToFitOrientation:(BOOL)transform
  196. {
  197. if (transform)
  198. {
  199. self.transform = CGAffineTransformIdentity;
  200. }
  201. CGRect frame = [UIScreen mainScreen].applicationFrame;
  202. CGPoint center = CGPointMake(frame.origin.x + ceil(frame.size.width/2),
  203. frame.origin.y + ceil(frame.size.height/2));
  204. CGFloat scaleFactor = SinaWeiboIsDeviceIPad() ? 0.6f : 1.0f;
  205. CGFloat width = floor(scaleFactor * frame.size.width) - kPadding * 2;
  206. CGFloat height = floor(scaleFactor * frame.size.height) - kPadding * 2;
  207. previousOrientation = [UIApplication sharedApplication].statusBarOrientation;
  208. if (UIInterfaceOrientationIsLandscape(previousOrientation))
  209. {
  210. self.frame = CGRectMake(kPadding, kPadding, height, width);
  211. }
  212. else
  213. {
  214. self.frame = CGRectMake(kPadding, kPadding, width, height);
  215. }
  216. self.center = center;
  217. if (transform)
  218. {
  219. self.transform = [self transformForOrientation];
  220. }
  221. }
  222. - (void)updateWebOrientation
  223. {
  224. UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
  225. if (UIInterfaceOrientationIsLandscape(orientation))
  226. {
  227. [webView stringByEvaluatingJavaScriptFromString:
  228. @"document.body.setAttribute('orientation', 90);"];
  229. }
  230. else
  231. {
  232. [webView stringByEvaluatingJavaScriptFromString:
  233. @"document.body.removeAttribute('orientation');"];
  234. }
  235. }
  236. #pragma mark - UIDeviceOrientationDidChangeNotification Methods
  237. - (void)deviceOrientationDidChange:(id)object
  238. {
  239. UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
  240. if ([self shouldRotateToOrientation:orientation])
  241. {
  242. NSTimeInterval duration = [UIApplication sharedApplication].statusBarOrientationAnimationDuration;
  243. [UIView beginAnimations:nil context:nil];
  244. [UIView setAnimationDuration:duration];
  245. [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
  246. [self sizeToFitOrientation:orientation];
  247. [UIView commitAnimations];
  248. }
  249. }
  250. #pragma mark - Animation
  251. - (void)bounce1AnimationStopped
  252. {
  253. [UIView beginAnimations:nil context:nil];
  254. [UIView setAnimationDuration:kTransitionDuration/2];
  255. [UIView setAnimationDelegate:self];
  256. [UIView setAnimationDidStopSelector:@selector(bounce2AnimationStopped)];
  257. self.transform = CGAffineTransformScale([self transformForOrientation], 0.9, 0.9);
  258. [UIView commitAnimations];
  259. }
  260. - (void)bounce2AnimationStopped
  261. {
  262. [UIView beginAnimations:nil context:nil];
  263. [UIView setAnimationDuration:kTransitionDuration/2];
  264. self.transform = [self transformForOrientation];
  265. [UIView commitAnimations];
  266. }
  267. #pragma mark Obeservers
  268. - (void)addObservers
  269. {
  270. [[NSNotificationCenter defaultCenter] addObserver:self
  271. selector:@selector(deviceOrientationDidChange:)
  272. name:@"UIDeviceOrientationDidChangeNotification" object:nil];
  273. }
  274. - (void)removeObservers
  275. {
  276. [[NSNotificationCenter defaultCenter] removeObserver:self
  277. name:@"UIDeviceOrientationDidChangeNotification" object:nil];
  278. }
  279. #pragma mark - Activity Indicator
  280. - (void)showIndicator
  281. {
  282. [indicatorView sizeToFit];
  283. [indicatorView startAnimating];
  284. indicatorView.center = webView.center;
  285. }
  286. - (void)hideIndicator
  287. {
  288. [indicatorView stopAnimating];
  289. }
  290. #pragma mark - Show / Hide
  291. - (void)load
  292. {
  293. NSString *authPagePath = [SinaWeiboRequest serializeURL:kSinaWeiboWebAuthURL
  294. params:authParams httpMethod:@"GET"];
  295. [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:authPagePath]]];
  296. }
  297. - (void)showWebView
  298. {
  299. UIWindow* window = [UIApplication sharedApplication].keyWindow;
  300. if (!window)
  301. {
  302. window = [[UIApplication sharedApplication].windows objectAtIndex:0];
  303. }
  304. modalBackgroundView.frame = window.frame;
  305. [modalBackgroundView addSubview:self];
  306. [window addSubview:modalBackgroundView];
  307. self.transform = CGAffineTransformScale([self transformForOrientation], 0.001, 0.001);
  308. [UIView beginAnimations:nil context:nil];
  309. [UIView setAnimationDuration:kTransitionDuration/1.5];
  310. [UIView setAnimationDelegate:self];
  311. [UIView setAnimationDidStopSelector:@selector(bounce1AnimationStopped)];
  312. self.transform = CGAffineTransformScale([self transformForOrientation], 1.1, 1.1);
  313. [UIView commitAnimations];
  314. }
  315. - (void)show
  316. {
  317. [self load];
  318. [self sizeToFitOrientation:NO];
  319. CGFloat innerWidth = self.frame.size.width - (kBorderWidth+1)*2;
  320. [closeButton sizeToFit];
  321. closeButton.frame = CGRectMake(2, 2, 29, 29);
  322. webView.frame = CGRectMake(kBorderWidth+1, kBorderWidth+1, innerWidth,
  323. self.frame.size.height - (1 + kBorderWidth*2));
  324. [self showWebView];
  325. [self showIndicator];
  326. [self addObservers];
  327. }
  328. - (void)_hide
  329. {
  330. [self removeFromSuperview];
  331. [modalBackgroundView removeFromSuperview];
  332. }
  333. - (void)hide
  334. {
  335. [self removeObservers];
  336. [webView stopLoading];
  337. [self performSelectorOnMainThread:@selector(_hide) withObject:nil waitUntilDone:NO];
  338. }
  339. - (void)cancel
  340. {
  341. [self hide];
  342. [delegate authorizeViewDidCancel:self];
  343. }
  344. #pragma mark - UIWebView Delegate
  345. - (void)webViewDidFinishLoad:(UIWebView *)aWebView
  346. {
  347. [self hideIndicator];
  348. }
  349. - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
  350. {
  351. [self hideIndicator];
  352. }
  353. - (BOOL)webView:(UIWebView *)aWebView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
  354. {
  355. NSString *url = request.URL.absoluteString;
  356. NSLog(@"url = %@", url);
  357. NSString *siteRedirectURI = [NSString stringWithFormat:@"%@%@", kSinaWeiboSDKOAuth2APIDomain, appRedirectURI];
  358. if ([url hasPrefix:appRedirectURI] || [url hasPrefix:siteRedirectURI])
  359. {
  360. NSString *error_code = [SinaWeiboRequest getParamValueFromUrl:url paramName:@"error_code"];
  361. if (error_code)
  362. {
  363. NSString *error = [SinaWeiboRequest getParamValueFromUrl:url paramName:@"error"];
  364. NSString *error_uri = [SinaWeiboRequest getParamValueFromUrl:url paramName:@"error_uri"];
  365. NSString *error_description = [SinaWeiboRequest getParamValueFromUrl:url paramName:@"error_description"];
  366. NSDictionary *errorInfo = [NSDictionary dictionaryWithObjectsAndKeys:
  367. error, @"error",
  368. error_uri, @"error_uri",
  369. error_code, @"error_code",
  370. error_description, @"error_description", nil];
  371. [self hide];
  372. [delegate authorizeView:self didFailWithErrorInfo:errorInfo];
  373. }
  374. else
  375. {
  376. NSString *code = [SinaWeiboRequest getParamValueFromUrl:url paramName:@"code"];
  377. if (code)
  378. {
  379. [self hide];
  380. [delegate authorizeView:self didRecieveAuthorizationCode:code];
  381. }
  382. }
  383. return NO;
  384. }
  385. return YES;
  386. }
  387. @end