PageRenderTime 44ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/Classes/UVSuggestionDetailsViewController.m

https://gitlab.com/lisit1003/uservoice-ios-sdk
Objective C | 590 lines | 488 code | 83 blank | 19 comment | 87 complexity | 341030b67881d9611e8ce888e5740ff5 MD5 | raw file
  1. //
  2. // UVSuggestionDetailsViewController.m
  3. // UserVoice
  4. //
  5. // Created by UserVoice on 10/29/09.
  6. // Copyright 2009 UserVoice Inc. All rights reserved.
  7. //
  8. #import <QuartzCore/QuartzCore.h>
  9. #import "UVSuggestionDetailsViewController.h"
  10. #import "UVStyleSheet.h"
  11. #import "UVSession.h"
  12. #import "UVSuggestion.h"
  13. #import "UVUser.h"
  14. #import "UVClientConfig.h"
  15. #import "UVImageView.h"
  16. #import "UVComment.h"
  17. #import "UVCommentViewController.h"
  18. #import "UVTruncatingLabel.h"
  19. #import "UVCallback.h"
  20. #import "UVBabayaga.h"
  21. #import "UVDeflection.h"
  22. #import "UVCategory.h"
  23. #import "UVUtils.h"
  24. #define MARGIN 15
  25. #define COMMENT_AVATAR_TAG 1000
  26. #define COMMENT_NAME_TAG 1001
  27. #define COMMENT_DATE_TAG 1002
  28. #define COMMENT_TEXT_TAG 1003
  29. #define SUGGESTION_DESCRIPTION 20
  30. #define ADMIN_RESPONSE 30
  31. #define LOADING 40
  32. @implementation UVSuggestionDetailsViewController {
  33. CGFloat _footerHeight;
  34. BOOL _allCommentsRetrieved;
  35. BOOL _suggestionExpanded;
  36. BOOL _responseExpanded;
  37. BOOL _subscribing;
  38. BOOL _loading;
  39. UVCallback *_subscribeCallback;
  40. UISwitch *_toggle;
  41. }
  42. - (id)init {
  43. self = [super init];
  44. if (self) {
  45. _subscribeCallback = [[UVCallback alloc] initWithTarget:self selector:@selector(doSubscribe)];
  46. }
  47. return self;
  48. }
  49. - (id)initWithSuggestion:(UVSuggestion *)theSuggestion {
  50. self = [self init];
  51. if (self) {
  52. _suggestion = theSuggestion;
  53. }
  54. return self;
  55. }
  56. - (void)retrieveMoreComments {
  57. NSInteger page = (_comments.count / 10) + 1;
  58. [self showActivityIndicator];
  59. [UVComment getWithSuggestion:_suggestion page:page delegate:self];
  60. }
  61. - (void)didRetrieveComments:(NSArray *)theComments {
  62. if (theComments.count > 0) {
  63. [_comments addObjectsFromArray:theComments];
  64. if (_comments.count >= _suggestion.commentsCount) {
  65. _allCommentsRetrieved = YES;
  66. }
  67. } else {
  68. _allCommentsRetrieved = YES;
  69. }
  70. [self hideActivityIndicator];
  71. [_tableView reloadData];
  72. }
  73. - (void)didSubscribe:(UVSuggestion *)theSuggestion {
  74. [UVBabayaga track:VOTE_IDEA id:theSuggestion.suggestionId];
  75. [UVBabayaga track:SUBSCRIBE_IDEA id:theSuggestion.suggestionId];
  76. if (_deflectingType) {
  77. [UVDeflection trackDeflection:@"subscribed" deflectingType:_deflectingType deflector:theSuggestion];
  78. UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:_helpfulPrompt
  79. delegate:self
  80. cancelButtonTitle:NSLocalizedStringFromTableInBundle(@"Cancel", @"UserVoice", [UserVoice bundle], nil)
  81. destructiveButtonTitle:nil
  82. otherButtonTitles:_returnMessage, NSLocalizedStringFromTableInBundle(@"No, I'm done", @"UserVoice", [UserVoice bundle], nil), nil];
  83. [actionSheet showInView:self.view];
  84. }
  85. [self updateSuggestion:theSuggestion];
  86. _subscribing = NO;
  87. }
  88. - (void)didUnsubscribe:(UVSuggestion *)theSuggestion {
  89. [self updateSuggestion:theSuggestion];
  90. }
  91. - (void)updateSuggestion:(UVSuggestion *)theSuggestion {
  92. _suggestion.subscribed = theSuggestion.subscribed;
  93. _suggestion.subscriberCount = theSuggestion.subscriberCount;
  94. _suggestion.rank = theSuggestion.rank;
  95. [self updateSubscriberCount];
  96. }
  97. - (void)updateSubscriberCount {
  98. if ([UVSession currentSession].clientConfig.displaySuggestionsByRank) {
  99. _subscriberCount.text = [NSString stringWithFormat:NSLocalizedStringFromTableInBundle(@"Ranked %@", @"UserVoice", [UserVoice bundle], nil), _suggestion.rankString];
  100. } else {
  101. if (_suggestion.subscriberCount == 1) {
  102. _subscriberCount.text = NSLocalizedStringFromTableInBundle(@"1 person", @"UserVoice", [UserVoice bundle], nil);
  103. } else {
  104. _subscriberCount.text = [NSString stringWithFormat:NSLocalizedStringFromTableInBundle(@"%d people", @"UserVoice", [UserVoice bundle], nil), _suggestion.subscriberCount];
  105. }
  106. }
  107. }
  108. - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
  109. if (buttonIndex == 0) {
  110. [self.navigationController popViewControllerAnimated:YES];
  111. } else if (buttonIndex == 1) {
  112. [self dismiss];
  113. }
  114. }
  115. #pragma mark ===== UITableView Methods =====
  116. - (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  117. NSString *identifier;
  118. UITableViewCellStyle style = UITableViewCellStyleDefault;
  119. BOOL selectable = NO;
  120. if (indexPath.section == 0 && indexPath.row == 0) {
  121. identifier = @"Suggestion";
  122. } else if (indexPath.section == 0 && indexPath.row == 1) {
  123. identifier = @"Response";
  124. } else if (indexPath.section == 1) {
  125. identifier = @"AddComment";
  126. selectable = YES;
  127. } else if (indexPath.row < _comments.count) {
  128. identifier = @"Comment";
  129. } else {
  130. identifier = @"Load";
  131. selectable = YES;
  132. }
  133. return [self createCellForIdentifier:identifier
  134. tableView:theTableView
  135. indexPath:indexPath
  136. style:style
  137. selectable:selectable];
  138. }
  139. - (void)initCellForComment:(UITableViewCell *)cell indexPath:(NSIndexPath *)indexPath {
  140. if (IOS7) {
  141. cell.separatorInset = UIEdgeInsetsMake(0, 64, 0, 0);
  142. }
  143. UVImageView *avatar = [UVImageView new];
  144. avatar.tag = COMMENT_AVATAR_TAG;
  145. UILabel *name = [UILabel new];
  146. name.tag = COMMENT_NAME_TAG;
  147. name.font = [UIFont boldSystemFontOfSize:13];
  148. name.textColor = [UIColor colorWithRed:0.19f green:0.20f blue:0.20f alpha:1.0f];
  149. UILabel *date = [UILabel new];
  150. date.tag = COMMENT_DATE_TAG;
  151. date.font = [UIFont systemFontOfSize:12];
  152. date.textColor = [UIColor colorWithRed:0.58f green:0.58f blue:0.60f alpha:1.0f];
  153. UILabel *text = [UILabel new];
  154. text.tag = COMMENT_TEXT_TAG;
  155. text.numberOfLines = 0;
  156. text.font = [UIFont systemFontOfSize:13];
  157. text.textColor = [UIColor colorWithRed:0.41f green:0.42f blue:0.43f alpha:1.0f];
  158. NSArray *constraints = @[
  159. @"|-16-[avatar(==40)]-[name]",
  160. @"[date]-|",
  161. @"[avatar]-[text]-|",
  162. @"V:|-14-[avatar(==40)]",
  163. @"V:|-14-[name]-[text]",
  164. @"V:|-14-[date]"
  165. ];
  166. [self configureView:cell.contentView
  167. subviews:NSDictionaryOfVariableBindings(avatar, name, date, text)
  168. constraints:constraints
  169. finalCondition:indexPath == nil
  170. finalConstraint:@"V:[text]-14-|"];
  171. }
  172. - (void)customizeCellForComment:(UITableViewCell *)cell indexPath:(NSIndexPath *)indexPath {
  173. UVComment *comment = [_comments objectAtIndex:indexPath.row];
  174. UVImageView *avatar = (UVImageView *)[cell viewWithTag:COMMENT_AVATAR_TAG];
  175. avatar.URL = comment.avatarUrl;
  176. UILabel *name = (UILabel *)[cell viewWithTag:COMMENT_NAME_TAG];
  177. name.text = comment.userName;
  178. UILabel *date = (UILabel *)[cell viewWithTag:COMMENT_DATE_TAG];
  179. date.text = [NSDateFormatter localizedStringFromDate:comment.createdAt dateStyle:NSDateFormatterMediumStyle timeStyle:NSDateFormatterNoStyle];
  180. UILabel *text = (UILabel *)[cell viewWithTag:COMMENT_TEXT_TAG];
  181. text.text = comment.text;
  182. }
  183. - (void)initCellForLoad:(UITableViewCell *)cell indexPath:(NSIndexPath *)indexPath {
  184. cell.backgroundView = [[UIView alloc] initWithFrame:cell.frame];
  185. UILabel *label = [[UILabel alloc] initWithFrame:cell.frame];
  186. label.autoresizingMask = UIViewAutoresizingFlexibleWidth;
  187. label.backgroundColor = [UIColor clearColor];
  188. label.font = [UIFont systemFontOfSize:16];
  189. label.textAlignment = NSTextAlignmentCenter;
  190. label.tag = LOADING;
  191. [cell addSubview:label];
  192. }
  193. - (void)customizeCellForLoad:(UITableViewCell *)cell indexPath:(NSIndexPath *)indexPath {
  194. UILabel *label = (UILabel *)[cell viewWithTag:LOADING];
  195. label.text = _loading ? NSLocalizedStringFromTableInBundle(@"Loading...", @"UserVoice", [UserVoice bundle], nil) : NSLocalizedStringFromTableInBundle(@"Load more", @"UserVoice", [UserVoice bundle], nil);
  196. }
  197. - (void)initCellForSuggestion:(UITableViewCell *)cell indexPath:(NSIndexPath *)indexPath {
  198. UILabel *category = [UILabel new];
  199. category.font = [UIFont systemFontOfSize:13];
  200. category.text = _suggestion.category.name ? [NSString stringWithFormat:@"%@ / %@", NSLocalizedStringFromTableInBundle(@"Feedback", @"UserVoice", [UserVoice bundle], nil), _suggestion.category.name] : NSLocalizedStringFromTableInBundle(@"Feedback", @"UserVoice", [UserVoice bundle], nil);
  201. category.adjustsFontSizeToFitWidth = YES;
  202. category.minimumScaleFactor = 0.5;
  203. category.textColor = [UIColor colorWithRed:0.41f green:0.42f blue:0.43f alpha:1.0f];
  204. UILabel *title = [UILabel new];
  205. title.font = [UIFont boldSystemFontOfSize:17];
  206. title.text = _suggestion.title;
  207. title.numberOfLines = 0;
  208. UVTruncatingLabel *desc = [UVTruncatingLabel new];
  209. desc.font = [UIFont systemFontOfSize:14];
  210. desc.fullText = _suggestion.text;
  211. desc.delegate = self;
  212. desc.tag = SUGGESTION_DESCRIPTION;
  213. NSArray *constraints = @[
  214. @"|-16-[category]-|",
  215. @"|-16-[title]-|",
  216. @"|-16-[desc]-|",
  217. @"V:|-12-[category]-8-[title]-[desc]"
  218. ];
  219. [self configureView:cell.contentView
  220. subviews:NSDictionaryOfVariableBindings(category, title, desc)
  221. constraints:constraints
  222. finalCondition:indexPath == nil
  223. finalConstraint:@"V:[desc]-|"];
  224. }
  225. - (void)customizeCellForSuggestion:(UITableViewCell *)cell indexPath:(NSIndexPath *)indexPath {
  226. UVTruncatingLabel *desc = (UVTruncatingLabel *)[cell.contentView viewWithTag:SUGGESTION_DESCRIPTION];
  227. if (_suggestionExpanded)
  228. [desc expand];
  229. }
  230. - (void)initCellForResponse:(UITableViewCell *)cell indexPath:(NSIndexPath *)indexPath {
  231. UIView *statusColor = [UIView new];
  232. statusColor.backgroundColor = _suggestion.statusColor;
  233. UILabel *status = [UILabel new];
  234. status.font = [UIFont systemFontOfSize:12];
  235. status.text = _suggestion.status.uppercaseString;
  236. status.textColor = _suggestion.statusColor;
  237. UILabel *date = [UILabel new];
  238. date.font = [UIFont systemFontOfSize:12];
  239. date.textColor = [UIColor colorWithRed:0.58f green:0.58f blue:0.60f alpha:1.0f];
  240. date.text = [NSDateFormatter localizedStringFromDate:_suggestion.responseCreatedAt dateStyle:NSDateFormatterMediumStyle timeStyle:NSDateFormatterNoStyle];
  241. if ([_suggestion.responseText length] > 0) {
  242. UVImageView *avatar = [UVImageView new];
  243. avatar.URL = _suggestion.responseUserAvatarUrl;
  244. UVTruncatingLabel *text = [UVTruncatingLabel new];
  245. text.font = [UIFont systemFontOfSize:13];
  246. text.textColor = [UIColor colorWithRed:0.41f green:0.42f blue:0.43f alpha:1.0f];
  247. text.fullText = _suggestion.responseText;
  248. text.delegate = self;
  249. text.tag = ADMIN_RESPONSE;
  250. UILabel *admin = [UILabel new];
  251. admin.font = [UIFont systemFontOfSize:11];
  252. admin.text = _suggestion.responseUserWithTitle;
  253. admin.textColor = [UIColor colorWithRed:0.69f green:0.69f blue:0.72f alpha:1.0f];
  254. admin.adjustsFontSizeToFitWidth = YES;
  255. admin.minimumScaleFactor = 0.5;
  256. NSArray *constraints = @[
  257. @"|-16-[statusColor(==10)]-[status]-|",
  258. @"[date]-|",
  259. @"|-16-[text]-[avatar(==40)]-|",
  260. @"|-16-[admin]-|",
  261. @"V:|-14-[statusColor(==10)]",
  262. @"V:|-12-[status]",
  263. @"V:|-12-[date]-[avatar(==40)]",
  264. @"V:[status]-(>=10)-[text]-[admin]",
  265. @"V:[date]-(>=10)-[text]"
  266. ];
  267. [self configureView:cell.contentView
  268. subviews:NSDictionaryOfVariableBindings(statusColor, status, date, text, admin, avatar)
  269. constraints:constraints
  270. finalCondition:indexPath == nil
  271. finalConstraint:@"V:[admin]-12-|"];
  272. } else {
  273. NSArray *constraints = @[
  274. @"|-16-[statusColor(==10)]-[status]-|",
  275. @"[date]-|",
  276. @"V:|-14-[statusColor(==10)]",
  277. @"V:|-12-[status]",
  278. @"V:|-12-[date]",
  279. ];
  280. [self configureView:cell.contentView
  281. subviews:NSDictionaryOfVariableBindings(statusColor, status, date)
  282. constraints:constraints
  283. finalCondition:indexPath == nil
  284. finalConstraint:@"V:[status]-12-|"];
  285. }
  286. }
  287. - (void)customizeCellForResponse:(UITableViewCell *)cell indexPath:(NSIndexPath *)indexPath {
  288. UVTruncatingLabel *text = (UVTruncatingLabel *)[cell.contentView viewWithTag:ADMIN_RESPONSE];
  289. if (_responseExpanded)
  290. [text expand];
  291. }
  292. - (void)initCellForAddComment:(UITableViewCell *)cell indexPath:(NSIndexPath *)indexPath {
  293. cell.textLabel.text = NSLocalizedStringFromTableInBundle(@"Add a comment", @"UserVoice", [UserVoice bundle], nil);
  294. if (IOS7) {
  295. cell.textLabel.textColor = cell.textLabel.tintColor;
  296. }
  297. }
  298. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
  299. if (section == 0) {
  300. return _suggestion.status || _suggestion.responseText ? 2 : 1;
  301. } else if (section == 1) {
  302. return 1;
  303. } else {
  304. return _comments.count + (_allCommentsRetrieved ? 0 : 1);
  305. }
  306. }
  307. - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
  308. return _instantAnswers ? 1 : 3;
  309. }
  310. - (CGFloat)tableView:(UITableView *)theTableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
  311. if (indexPath.section == 2 && indexPath.row < _comments.count) {
  312. return [self heightForDynamicRowWithReuseIdentifier:@"Comment" indexPath:indexPath];
  313. } else if (indexPath.section == 0 && indexPath.row == 0) {
  314. return [self heightForDynamicRowWithReuseIdentifier:@"Suggestion" indexPath:indexPath];
  315. } else if (indexPath.section == 0 && indexPath.row == 1) {
  316. return [self heightForDynamicRowWithReuseIdentifier:@"Response" indexPath:indexPath];
  317. } else {
  318. return 44;
  319. }
  320. }
  321. - (void)tableView:(UITableView *)theTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
  322. [theTableView deselectRowAtIndexPath:indexPath animated:YES];
  323. if (indexPath.section == 1 && indexPath.row == 0) {
  324. [self presentModalViewController:[[UVCommentViewController alloc] initWithSuggestion:_suggestion]];
  325. } else if (indexPath.section == 2 && indexPath.row == _comments.count) {
  326. if (!_loading) {
  327. [self retrieveMoreComments];
  328. }
  329. }
  330. }
  331. #pragma mark ===== Actions =====
  332. - (void)toggleSubscribed {
  333. if (_suggestion.subscribed) {
  334. [self unsubscribe];
  335. } else {
  336. [self subscribe];
  337. }
  338. }
  339. - (void)subscribe {
  340. if (_subscribing) return;
  341. _subscribing = YES;
  342. [self requireUserSignedIn:_subscribeCallback];
  343. }
  344. - (void)doSubscribe {
  345. [_suggestion subscribe:self];
  346. }
  347. - (void)unsubscribe {
  348. [_suggestion unsubscribe:self];
  349. }
  350. - (void)signinManagerDidFail {
  351. _subscribing = NO;
  352. [_toggle setOn:_suggestion.subscribed];
  353. [super signinManagerDidFail];
  354. }
  355. - (void)didReceiveError:(NSError *)error {
  356. _subscribing = NO;
  357. [_toggle setOn:_suggestion.subscribed];
  358. [super didReceiveError:error];
  359. }
  360. #pragma mark ===== Basic View Methods =====
  361. - (void)keyboardDidHide:(NSNotification*)notification {
  362. UIEdgeInsets contentInsets = UIEdgeInsetsMake([self scrollView].contentInset.top, 0.0, _footerHeight, 0.0);
  363. [self scrollView].contentInset = contentInsets;
  364. [self scrollView].scrollIndicatorInsets = contentInsets;
  365. }
  366. - (void)labelExpanded:(UVTruncatingLabel *)label {
  367. if (label.tag == SUGGESTION_DESCRIPTION) {
  368. _suggestionExpanded = YES;
  369. [_tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:0 inSection:0]] withRowAnimation:UITableViewRowAnimationFade];
  370. } else {
  371. _responseExpanded = YES;
  372. [_tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:1 inSection:0]] withRowAnimation:UITableViewRowAnimationFade];
  373. }
  374. }
  375. - (void)loadView {
  376. [super loadView];
  377. [UVBabayaga track:VIEW_IDEA id:_suggestion.suggestionId];
  378. self.view = [[UIView alloc] initWithFrame:[self contentFrame]];
  379. _footerHeight = _instantAnswers ? 46 : 66;
  380. UITableView *table = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
  381. table.delegate = self;
  382. table.dataSource = self;
  383. table.tableFooterView = [UIView new];
  384. table.contentInset = UIEdgeInsetsMake(0, 0, _footerHeight, 0);
  385. table.scrollIndicatorInsets = UIEdgeInsetsMake(0, 0, _footerHeight, 0);
  386. _tableView = table;
  387. BOOL byRank = [UVSession currentSession].clientConfig.displaySuggestionsByRank;
  388. NSArray *constraints;
  389. UIView *footer = [UIView new];
  390. footer.backgroundColor = [UIColor colorWithRed:0.97f green:0.97f blue:0.97f alpha:1.0f];
  391. UIView *border = [UIView new];
  392. border.backgroundColor = [UIColor colorWithRed:0.85f green:0.85f blue:0.85f alpha:1.0f];
  393. if (_instantAnswers) {
  394. UILabel *people = [UILabel new];
  395. people.font = [UIFont systemFontOfSize:14];
  396. people.textColor = [UIColor colorWithRed:0.58f green:0.58f blue:0.60f alpha:1.0f];
  397. people.backgroundColor = [UIColor clearColor];
  398. _subscriberCount = people;
  399. UIImageView *heart = [UVUtils imageViewWithImageNamed:@"uv_heart.png"];
  400. UILabel *this = [UILabel new];
  401. this.text = NSLocalizedStringFromTableInBundle(@"this idea", @"UserVoice", [UserVoice bundle], nil);
  402. this.font = people.font;
  403. this.backgroundColor = [UIColor clearColor];
  404. this.textColor = people.textColor;
  405. UIButton *want = [UIButton new];
  406. [want setTitle:NSLocalizedStringFromTableInBundle(@"I want this", @"UserVoice", [UserVoice bundle], nil) forState:UIControlStateNormal];
  407. [want setTitleColor:want.tintColor forState:UIControlStateNormal];
  408. [want addTarget:self action:@selector(subscribe) forControlEvents:UIControlEventTouchUpInside];
  409. if (byRank) {
  410. constraints = @[
  411. @"|[border]|", @"V:|[border(==1)]",
  412. @"|-[people]", @"[want]-|",
  413. @"V:|-14-[people]", @"V:|-6-[want]"
  414. ];
  415. } else {
  416. constraints = @[
  417. @"|[border]|", @"V:|[border(==1)]",
  418. @"|-[people]-4-[heart(==12)]-4-[this]", @"[want]-|",
  419. @"V:|-14-[people]", @"V:|-18-[heart(==11)]", @"V:|-14-[this]", @"V:|-6-[want]"
  420. ];
  421. }
  422. [self configureView:footer
  423. subviews:byRank ? NSDictionaryOfVariableBindings(border, people, want) : NSDictionaryOfVariableBindings(border, want, people, heart, this)
  424. constraints:constraints];
  425. } else {
  426. UILabel *want = [UILabel new];
  427. want.text = NSLocalizedStringFromTableInBundle(@"I want this!", @"UserVoice", [UserVoice bundle], nil);
  428. want.font = [UIFont systemFontOfSize:16];
  429. want.backgroundColor = [UIColor clearColor];
  430. UILabel *people = [UILabel new];
  431. people.font = [UIFont systemFontOfSize:13];
  432. people.textColor = [UIColor colorWithRed:0.58f green:0.58f blue:0.60f alpha:1.0f];
  433. people.backgroundColor = [UIColor clearColor];
  434. _subscriberCount = people;
  435. UIImageView *heart = [UVUtils imageViewWithImageNamed:@"uv_heart.png"];
  436. UILabel *this = [UILabel new];
  437. this.text = NSLocalizedStringFromTableInBundle(@"this", @"UserVoice", [UserVoice bundle], nil);
  438. this.font = people.font;
  439. this.backgroundColor = [UIColor clearColor];
  440. this.textColor = people.textColor;
  441. _toggle = [UISwitch new];
  442. if (_suggestion.subscribed) {
  443. _toggle.on = YES;
  444. }
  445. [_toggle addTarget:self action:@selector(toggleSubscribed) forControlEvents:UIControlEventValueChanged];
  446. if (byRank) {
  447. constraints = @[
  448. @"|[border]|", @"V:|[border(==1)]",
  449. @"|-[want]", @"|-[people]", @"[_toggle]-|",
  450. @"V:|-14-[want]-2-[people]", @"V:|-16-[_toggle]"
  451. ];
  452. } else {
  453. constraints = @[
  454. @"|[border]|", @"V:|[border(==1)]",
  455. @"|-[want]", @"|-[people]-4-[heart(==12)]-4-[this]", @"[_toggle]-|",
  456. @"V:|-14-[want]-2-[people]", @"V:[want]-6-[heart(==11)]", @"V:[want]-2-[this]", @"V:|-16-[_toggle]"
  457. ];
  458. }
  459. [self configureView:footer
  460. subviews:byRank ? NSDictionaryOfVariableBindings(border, want, people, _toggle) : NSDictionaryOfVariableBindings(border, want, people, heart, this, _toggle)
  461. constraints:constraints];
  462. }
  463. [self configureView:self.view
  464. subviews:NSDictionaryOfVariableBindings(table, footer)
  465. constraints:@[@"V:|[table]|", @"V:[footer]|", @"|[table]|", @"|[footer]|"]];
  466. [self.view addConstraint:[NSLayoutConstraint constraintWithItem:footer attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:_footerHeight]];
  467. [self.view bringSubviewToFront:footer];
  468. _allCommentsRetrieved = NO;
  469. _comments = [NSMutableArray arrayWithCapacity:10];
  470. [self retrieveMoreComments];
  471. [self updateSubscriberCount];
  472. }
  473. - (void)initNavigationItem {}
  474. /*
  475. * The point of this is to put a newly created comment at the top of the list
  476. * without screwing things up too badly. This has to be done because the new
  477. * comment won't actually appear in the list until spam filtering is done, and
  478. * we don't know when that will be.
  479. *
  480. * Cutting the comment list down to 1 page with the new comment artificially
  481. * inserted at the top seems like the best way to do this. Pagination will
  482. * be slightly inaccurate if another comment was created since the first page
  483. * was loaded, or if the new comment gets caught in the spam filter. However,
  484. * that kind of inaccuracy is to be expected for offset-based pagination.
  485. */
  486. - (void)commentCreated:(UVComment *)comment {
  487. NSMutableArray *newComments = [NSMutableArray arrayWithCapacity:10];
  488. [newComments addObject:comment];
  489. for (int i=0; i < MIN(9, _comments.count); i++) {
  490. [newComments addObject:[_comments objectAtIndex:i]];
  491. }
  492. if (_comments.count > 9)
  493. _allCommentsRetrieved = NO;
  494. _comments = newComments;
  495. [_tableView reloadData];
  496. }
  497. - (void)showActivityIndicator {
  498. _loading = YES;
  499. [_tableView reloadData];
  500. }
  501. - (void)hideActivityIndicator {
  502. _loading = NO;
  503. }
  504. - (void)dealloc {
  505. [_subscribeCallback invalidate];
  506. }
  507. @end