PageRenderTime 69ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/src/Three20UI/Sources/TTTextBarController.m

https://github.com/GetMoPix/three20
Objective C | 520 lines | 292 code | 123 blank | 105 comment | 30 complexity | 552bcf4e729396babee24075d6056145 MD5 | raw file
  1. //
  2. // Copyright 2009-2011 Facebook
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. //
  16. #import "Three20UI/TTTextBarController.h"
  17. // UI
  18. #import "Three20UI/TTNavigator.h"
  19. #import "Three20UI/TTTextBarDelegate.h"
  20. #import "Three20UI/TTButton.h"
  21. #import "Three20UI/TTTextEditor.h"
  22. #import "Three20UI/UIViewAdditions.h"
  23. // UINavigator
  24. #import "Three20UINavigator/TTGlobalNavigatorMetrics.h"
  25. // UICommon
  26. #import "Three20UICommon/TTGlobalUICommon.h"
  27. #import "Three20UICommon/UIViewControllerAdditions.h"
  28. #import "Three20UICommon/UIView+TTUICommon.h"
  29. // Style
  30. #import "Three20Style/TTGlobalStyle.h"
  31. #import "Three20Style/TTDefaultStyleSheet.h"
  32. // Core
  33. #import "Three20Core/TTGlobalCoreLocale.h"
  34. #import "Three20Core/TTCorePreprocessorMacros.h"
  35. #import "Three20Core/NSStringAdditions.h"
  36. #import "Three20Core/TTGlobalCore.h"
  37. static CGFloat kMargin = 1.0f;
  38. static CGFloat kPadding = 5.0f;
  39. ///////////////////////////////////////////////////////////////////////////////////////////////////
  40. ///////////////////////////////////////////////////////////////////////////////////////////////////
  41. ///////////////////////////////////////////////////////////////////////////////////////////////////
  42. @implementation TTTextBarController
  43. @synthesize textEditor = _textEditor;
  44. @synthesize postButton = _postButton;
  45. @synthesize footerBar = _footerBar;
  46. @synthesize delegate = _delegate;
  47. ///////////////////////////////////////////////////////////////////////////////////////////////////
  48. - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
  49. self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
  50. if (self) {
  51. }
  52. return self;
  53. }
  54. ///////////////////////////////////////////////////////////////////////////////////////////////////
  55. - (id)initWithNavigatorURL:(NSURL*)URL query:(NSDictionary*)query {
  56. self = [self initWithNibName:nil bundle:nil];
  57. if (self) {
  58. if (nil != query) {
  59. _delegate = [query objectForKey:@"delegate"];
  60. _defaultText = [[query objectForKey:@"text"] copy];
  61. }
  62. }
  63. return self;
  64. }
  65. ///////////////////////////////////////////////////////////////////////////////////////////////////
  66. - (id)init {
  67. self = [self initWithNavigatorURL:nil query:nil];
  68. if (self) {
  69. }
  70. return self;
  71. }
  72. ///////////////////////////////////////////////////////////////////////////////////////////////////
  73. - (void)dealloc {
  74. TT_RELEASE_SAFELY(_result);
  75. TT_RELEASE_SAFELY(_defaultText);
  76. TT_RELEASE_SAFELY(_footerBar);
  77. TT_RELEASE_SAFELY(_previousRightBarButtonItem);
  78. [super dealloc];
  79. }
  80. ///////////////////////////////////////////////////////////////////////////////////////////////////
  81. ///////////////////////////////////////////////////////////////////////////////////////////////////
  82. #pragma mark -
  83. #pragma mark Private
  84. ///////////////////////////////////////////////////////////////////////////////////////////////////
  85. - (void)showActivity:(NSString*)activityText {
  86. }
  87. ///////////////////////////////////////////////////////////////////////////////////////////////////
  88. - (void)showAnimationDidStop {
  89. }
  90. ///////////////////////////////////////////////////////////////////////////////////////////////////
  91. - (void)dismissAnimationDidStop {
  92. [self release];
  93. }
  94. ///////////////////////////////////////////////////////////////////////////////////////////////////
  95. - (void)dismissWithCancel {
  96. if ([_delegate respondsToSelector:@selector(textBarDidCancel:)]) {
  97. [_delegate textBarDidCancel:self];
  98. }
  99. [self dismissPopupViewControllerAnimated:YES];
  100. }
  101. ///////////////////////////////////////////////////////////////////////////////////////////////////
  102. ///////////////////////////////////////////////////////////////////////////////////////////////////
  103. #pragma mark -
  104. #pragma mark UIViewController
  105. ///////////////////////////////////////////////////////////////////////////////////////////////////
  106. - (void)loadView {
  107. CGSize screenSize = TTScreenBounds().size;
  108. self.view = [[[UIView alloc] init] autorelease];
  109. _textBar = [[TTView alloc] init];
  110. _textBar.style = TTSTYLE(textBar);
  111. [self.view addSubview:_textBar];
  112. [_textBar addSubview:self.textEditor];
  113. [_textBar addSubview:self.postButton];
  114. [self.postButton sizeToFit];
  115. _postButton.frame = CGRectMake(screenSize.width - (_postButton.width + kPadding),
  116. kMargin+kPadding, _postButton.width, 0);
  117. _textEditor.frame = CGRectMake(kPadding, kMargin,
  118. screenSize.width - (_postButton.width+kPadding*2), 0);
  119. [_textEditor sizeToFit];
  120. _postButton.height = _textEditor.size.height - 8;
  121. _textBar.frame = CGRectMake(0, 0,
  122. screenSize.width, _textEditor.height+kMargin*2);
  123. self.view.frame = CGRectMake(0, screenSize.height - (TTKeyboardHeight() + _textEditor.height),
  124. screenSize.width, _textEditor.height+kMargin*2);
  125. if (_footerBar) {
  126. _footerBar.frame = CGRectMake(0, _textBar.height, screenSize.width, _footerBar.height);
  127. [self.view addSubview:_footerBar];
  128. self.view.top -= _footerBar.height;
  129. self.view.height += _footerBar.height;
  130. }
  131. self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth
  132. | UIViewAutoresizingFlexibleTopMargin;
  133. _postButton.autoresizingMask = UIViewAutoresizingFlexibleTopMargin
  134. | UIViewAutoresizingFlexibleLeftMargin;
  135. _textEditor.autoresizingMask = UIViewAutoresizingFlexibleRightMargin;
  136. _textBar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
  137. _footerBar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
  138. }
  139. ///////////////////////////////////////////////////////////////////////////////////////////////////
  140. - (void)viewDidUnload {
  141. [super viewDidUnload];
  142. TT_RELEASE_SAFELY(_textBar);
  143. TT_RELEASE_SAFELY(_textEditor);
  144. TT_RELEASE_SAFELY(_postButton);
  145. TT_RELEASE_SAFELY(_previousRightBarButtonItem);
  146. }
  147. ///////////////////////////////////////////////////////////////////////////////////////////////////
  148. //////////////////////////////////////////////////////////////////////////////////////////////////
  149. #pragma mark -
  150. #pragma mark UIViewController (TTCategory)
  151. ///////////////////////////////////////////////////////////////////////////////////////////////////
  152. - (BOOL)persistView:(NSMutableDictionary*)state {
  153. [state setObject:[NSNumber numberWithBool:YES] forKey:@"__important__"];
  154. NSString* delegate = [[TTNavigator navigator] pathForObject:_delegate];
  155. if (delegate) {
  156. [state setObject:delegate forKey:@"delegate"];
  157. }
  158. [state setObject:_textEditor.text forKey:@"text"];
  159. NSString* title = self.navigationItem.title;
  160. if (title) {
  161. [state setObject:title forKey:@"title"];
  162. }
  163. return [super persistView:state];
  164. }
  165. ///////////////////////////////////////////////////////////////////////////////////////////////////
  166. - (void)restoreView:(NSDictionary*)state {
  167. [super restoreView:state];
  168. NSString* delegate = [state objectForKey:@"delegate"];
  169. if (delegate) {
  170. _delegate = [[TTNavigator navigator] objectForPath:delegate];
  171. }
  172. NSString* title = [state objectForKey:@"title"];
  173. if (title) {
  174. self.navigationItem.title = title;
  175. }
  176. _defaultText = [[state objectForKey:@"text"] retain];
  177. }
  178. ///////////////////////////////////////////////////////////////////////////////////////////////////
  179. ///////////////////////////////////////////////////////////////////////////////////////////////////
  180. #pragma mark -
  181. #pragma mark TTPopupViewController
  182. ///////////////////////////////////////////////////////////////////////////////////////////////////
  183. - (void)showInView:(UIView*)view animated:(BOOL)animated {
  184. self.view.transform = TTRotateTransformForOrientation(TTInterfaceOrientation());
  185. [view addSubview:self.view];
  186. if (_defaultText) {
  187. _textEditor.text = _defaultText;
  188. TT_RELEASE_SAFELY(_defaultText);
  189. } else {
  190. _defaultText = [_textEditor.text retain];
  191. }
  192. self.view.top = self.view.superview.height;
  193. [_textEditor becomeFirstResponder];
  194. }
  195. ///////////////////////////////////////////////////////////////////////////////////////////////////
  196. - (void)dismissPopupViewControllerAnimated:(BOOL)animated {
  197. if (animated) {
  198. [_textEditor resignFirstResponder];
  199. } else {
  200. UIViewController* superController = self.superController;
  201. [self.view removeFromSuperview];
  202. superController.popupViewController = nil;
  203. [superController viewWillAppear:animated];
  204. [superController viewDidAppear:animated];
  205. }
  206. }
  207. ///////////////////////////////////////////////////////////////////////////////////////////////////
  208. ///////////////////////////////////////////////////////////////////////////////////////////////////
  209. #pragma mark -
  210. #pragma mark TTTextEditorDelegate
  211. ///////////////////////////////////////////////////////////////////////////////////////////////////
  212. - (void)textEditorDidBeginEditing:(TTTextEditor*)textEditor {
  213. [self retain];
  214. _originTop = self.view.top;
  215. UIViewController* controller = self.view.viewController;
  216. _previousRightBarButtonItem = [controller.navigationItem.rightBarButtonItem retain];
  217. [controller.navigationItem setRightBarButtonItem:
  218. [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
  219. target:self action:@selector(cancel)] autorelease] animated:YES];
  220. [UIView beginAnimations:nil context:nil];
  221. [UIView setAnimationDuration:TT_TRANSITION_DURATION];
  222. [UIView setAnimationDelegate:self];
  223. [UIView setAnimationDidStopSelector:@selector(showAnimationDidStop)];
  224. CGRect rect = [self.view.superview frameWithKeyboardSubtracted:0];
  225. self.view.top = rect.size.height - self.view.height;
  226. [UIView commitAnimations];
  227. if ([_delegate respondsToSelector:@selector(textBarDidBeginEditing:)]) {
  228. [_delegate textBarDidBeginEditing:self];
  229. }
  230. }
  231. ///////////////////////////////////////////////////////////////////////////////////////////////////
  232. - (void)textEditorDidEndEditing:(TTTextEditor*)textEditor {
  233. UIViewController* controller = self.view.viewController;
  234. [controller.navigationItem setRightBarButtonItem:_previousRightBarButtonItem animated:YES];
  235. TT_RELEASE_SAFELY(_previousRightBarButtonItem);
  236. [UIView beginAnimations:nil context:nil];
  237. [UIView setAnimationDuration:TT_TRANSITION_DURATION];
  238. [UIView setAnimationDelegate:self];
  239. [UIView setAnimationDidStopSelector:@selector(dismissAnimationDidStop)];
  240. self.view.top = _originTop;
  241. [UIView commitAnimations];
  242. if ([_delegate respondsToSelector:@selector(textBarDidEndEditing:)]) {
  243. [_delegate textBarDidEndEditing:self];
  244. }
  245. }
  246. ///////////////////////////////////////////////////////////////////////////////////////////////////
  247. - (void)textEditorDidChange:(TTTextEditor*)textEditor {
  248. [_postButton setEnabled:textEditor.text.length > 0];
  249. }
  250. ///////////////////////////////////////////////////////////////////////////////////////////////////
  251. - (BOOL)textEditor:(TTTextEditor*)textEditor shouldResizeBy:(CGFloat)height {
  252. CGRect frame = self.view.frame;
  253. frame.origin.y -= height;
  254. frame.size.height += height;
  255. _textBar.height += height;
  256. _footerBar.top += height;
  257. self.view.frame = frame;
  258. return YES;
  259. }
  260. ///////////////////////////////////////////////////////////////////////////////////////////////////
  261. ///////////////////////////////////////////////////////////////////////////////////////////////////
  262. #pragma mark -
  263. #pragma mark UIAlertViewDelegate
  264. ///////////////////////////////////////////////////////////////////////////////////////////////////
  265. - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
  266. if (buttonIndex == 0) {
  267. [self dismissWithCancel];
  268. }
  269. }
  270. ///////////////////////////////////////////////////////////////////////////////////////////////////
  271. ///////////////////////////////////////////////////////////////////////////////////////////////////
  272. #pragma mark -
  273. #pragma mark Public
  274. ///////////////////////////////////////////////////////////////////////////////////////////////////
  275. - (TTTextEditor*)textEditor {
  276. if (!_textEditor) {
  277. _textEditor = [[TTTextEditor alloc] init];
  278. _textEditor.delegate = self;
  279. _textEditor.style = TTSTYLE(textBarTextField);
  280. _textEditor.backgroundColor = [UIColor clearColor];
  281. _textEditor.autoresizesToText = YES;
  282. _textEditor.maxNumberOfLines = 6;
  283. _textEditor.font = [UIFont systemFontOfSize:16];
  284. }
  285. return _textEditor;
  286. }
  287. ///////////////////////////////////////////////////////////////////////////////////////////////////
  288. - (TTButton*)postButton {
  289. if (!_postButton) {
  290. _postButton = [[TTButton buttonWithStyle:@"textBarPostButton:"
  291. title:NSLocalizedString(@"Post", @"")] retain];
  292. [_postButton addTarget: self
  293. action: @selector(post)
  294. forControlEvents: UIControlEventTouchUpInside];
  295. [_postButton setEnabled:NO];
  296. }
  297. return _postButton;
  298. }
  299. ///////////////////////////////////////////////////////////////////////////////////////////////////
  300. - (void)post {
  301. BOOL shouldDismiss = [self willPostText:_textEditor.text];
  302. if ([_delegate respondsToSelector:@selector(textBar:willPostText:)]) {
  303. shouldDismiss = [_delegate textBar:self willPostText:_textEditor.text];
  304. }
  305. _textEditor.text = @"";
  306. _postButton.enabled = NO;
  307. if (shouldDismiss) {
  308. [self dismissWithResult:nil animated:YES];
  309. } else {
  310. [self showActivity:[self titleForActivity]];
  311. }
  312. }
  313. ///////////////////////////////////////////////////////////////////////////////////////////////////
  314. - (void)cancel {
  315. if (!TTIsStringWithAnyText(_textEditor.text)
  316. && !_textEditor.text.isWhitespaceAndNewlines
  317. && !(_defaultText && [_defaultText isEqualToString:_textEditor.text])) {
  318. UIAlertView* cancelAlertView = [[[UIAlertView alloc] initWithTitle:
  319. TTLocalizedString(@"Cancel", @"")
  320. message:TTLocalizedString(@"Are you sure you want to cancel?", @"")
  321. delegate:self cancelButtonTitle:TTLocalizedString(@"Yes", @"")
  322. otherButtonTitles:TTLocalizedString(@"No", @""), nil] autorelease];
  323. [cancelAlertView show];
  324. } else {
  325. [self dismissWithCancel];
  326. }
  327. }
  328. ///////////////////////////////////////////////////////////////////////////////////////////////////
  329. - (void)dismissWithResult:(id)result animated:(BOOL)animated {
  330. [_result release];
  331. _result = [result retain];
  332. [self dismissPopupViewControllerAnimated:YES];
  333. // if (animated) {
  334. // if ([_delegate respondsToSelector:@selector(textBar:willAnimateTowards:)]) {
  335. // CGRect rect = [_delegate textBar:self willAnimateTowards:_originRect];
  336. // if (!CGRectIsEmpty(rect)) {
  337. // _originRect = rect;
  338. // }
  339. // }
  340. //
  341. // CGRect originRect = _originRect;
  342. // if (CGRectIsEmpty(originRect) && _originView) {
  343. // originRect = _originView.screenFrame;
  344. // }
  345. //
  346. // _originView.hidden = NO;
  347. // _activityView.hidden = YES;
  348. // _textEditor.hidden = YES;
  349. //
  350. // [UIView beginAnimations:nil context:nil];
  351. // [UIView setAnimationDuration:TT_TRANSITION_DURATION];
  352. // [UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
  353. // [UIView setAnimationDelegate:self];
  354. // [UIView setAnimationDidStopSelector:@selector(dismissAnimationDidStop)];
  355. //
  356. // if (!CGRectIsEmpty(originRect)) {
  357. // _screenView.frame = CGRectOffset(originRect, 0, -TTStatusHeight());
  358. //
  359. // } else {
  360. // _screenView.transform = CGAffineTransformMakeScale(0.00001, 0.00001);
  361. // }
  362. //
  363. // _innerView.alpha = 0;
  364. // _navigationBar.alpha = 0;
  365. //
  366. // [UIView commitAnimations];
  367. //
  368. // } else {
  369. // [self dismissAnimationDidStop];
  370. // }
  371. //
  372. // [self hideKeyboard];
  373. }
  374. ///////////////////////////////////////////////////////////////////////////////////////////////////
  375. - (void)failWithError:(NSError*)error {
  376. [self showActivity:nil];
  377. NSString* title = [self titleForError:error];
  378. if (title.length) {
  379. UIAlertView* alertView = [[[UIAlertView alloc] initWithTitle:TTLocalizedString(@"Error", @"")
  380. message:title delegate:nil cancelButtonTitle:TTLocalizedString(@"Ok", @"")
  381. otherButtonTitles:nil] autorelease];
  382. [alertView show];
  383. }
  384. }
  385. ///////////////////////////////////////////////////////////////////////////////////////////////////
  386. - (BOOL)willPostText:(NSString*)text {
  387. return YES;
  388. }
  389. ///////////////////////////////////////////////////////////////////////////////////////////////////
  390. - (NSString*)titleForActivity {
  391. return nil;
  392. }
  393. ///////////////////////////////////////////////////////////////////////////////////////////////////
  394. - (NSString*)titleForError:(NSError*)error {
  395. return nil;
  396. }
  397. @end