-
Notifications
You must be signed in to change notification settings - Fork 30
/
UserProfileViewController.m
573 lines (468 loc) · 22.8 KB
/
UserProfileViewController.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
//
// UserProfileViewController.m
// candpiosapp
//
// Created by Stephen Birarda on 2/1/12.
// Copyright (c) 2012 Coffee and Power Inc. All rights reserved.
//
#import "UserProfileViewController.h"
#import "FoursquareAPIClient.h"
#import "AFJSONRequestOperation.h"
#import "GRMustache.h"
#import "VenueInfoViewController.h"
#import "GTMNSString+HTML.h"
#import "UserProfileLinkedInViewController.h"
#import "FaceToFaceHelper.h"
#import "CPUserAction.h"
#import "CPMarkerManager.h"
#define kResumeWebViewOffsetTop 304
@interface UserProfileViewController() <UIWebViewDelegate, UIActionSheetDelegate>
@property (strong, nonatomic) UITapGestureRecognizer *tapRecon;
@property (strong, nonatomic) NSString* resumeHTML;
@property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
@property (weak, nonatomic) IBOutlet UILabel *checkedIn;
@property (strong, nonatomic) IBOutlet MKMapView *mapView;
@property (weak, nonatomic) IBOutlet UIView *userCard;
@property (weak, nonatomic) IBOutlet UIImageView *cardImage;
@property (weak, nonatomic) IBOutlet UILabel *cardStatus;
@property (weak, nonatomic) IBOutlet UILabel *cardNickname;
@property (weak, nonatomic) IBOutlet UILabel *cardJobPosition;
@property (weak, nonatomic) IBOutlet UIView *venueView;
@property (weak, nonatomic) IBOutlet UIButton *venueViewButton;
@property (weak, nonatomic) IBOutlet UILabel *venueName;
@property (weak, nonatomic) IBOutlet UILabel *venueAddress;
@property (weak, nonatomic) IBOutlet UIImageView *venueOthersIcon;
@property (weak, nonatomic) IBOutlet UILabel *venueOthers;
@property (weak, nonatomic) IBOutlet UIView *availabilityView;
@property (weak, nonatomic) IBOutlet UILabel *distanceLabel;
@property (weak, nonatomic) IBOutlet UILabel *hoursAvailable;
@property (weak, nonatomic) IBOutlet UILabel *minutesAvailable;
@property (weak, nonatomic) IBOutlet UIView *resumeView;
@property (weak, nonatomic) IBOutlet UILabel *resumeLabel;
@property (weak, nonatomic) IBOutlet UILabel *resumeRate;
@property (weak, nonatomic) IBOutlet UILabel *resumeEarned;
@property (weak, nonatomic) IBOutlet UILabel *loveReceived;
@property (weak, nonatomic) IBOutlet UIWebView *resumeWebView;
@property (weak, nonatomic) IBOutlet UIButton *payButton;
@property (weak, nonatomic) IBOutlet UILabel *propNoteLabel;
@property (weak, nonatomic) IBOutlet UIImageView *mapMarker;
@property (weak, nonatomic) IBOutlet CPUserActionCell *userActionCell;
@property (weak, nonatomic) UIView *blueOverlayExtend;
@property (strong, nonatomic) NSOperationQueue *operationQueue;
@property (nonatomic) BOOL firstLoad;
@property (nonatomic) int othersAtPlace;
@property (nonatomic) NSInteger selectedFavoriteVenueIndex;
@property (nonatomic) BOOL mapAndDistanceLoaded;
-(NSString *)htmlStringWithResumeText;
-(IBAction)venueViewButtonPressed:(id)sender;
@end
@implementation UserProfileViewController
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Profile"
style:UIBarButtonItemStylePlain
target:nil
action:nil];
// keep our own queue, so we can safely cancel
self.operationQueue = [NSOperationQueue new];
// set the navigation controller title to the user's nickname
self.title = self.user.nickname;
// set the booleans this VC uses in later control statements
self.firstLoad = YES;
self.mapAndDistanceLoaded = NO;
// set LeagueGothic font where applicable
[CPUIHelper changeFontForLabel:self.checkedIn toLeagueGothicOfSize:24];
[CPUIHelper changeFontForLabel:self.resumeLabel toLeagueGothicOfSize:26];
[CPUIHelper changeFontForLabel:self.cardNickname toLeagueGothicOfSize:28];
// set the paper background color where applicable
UIColor *paper = [UIColor colorWithPatternImage:[UIImage imageNamed:@"paper-texture.png"]];
self.userCard.backgroundColor = paper;
self.resumeView.backgroundColor = paper;
self.resumeWebView.opaque = NO;
self.resumeWebView.backgroundColor = paper;
self.userActionCell.user = self.user;
self.userActionCell.delegate = self;
// set the labels on the user business card
self.cardNickname.text = self.user.nickname;
[self setUserStatusWithQuotes:self.user.status];
self.cardJobPosition.text = self.user.jobTitle;
// set the card image to the user's profile image
[CPUIHelper profileImageView:self.cardImage
withProfileImageUrl:self.user.photoURL];
// don't allow scrolling in the mustache view until it's loaded
self.resumeWebView.userInteractionEnabled = NO;
if (self.isF2FInvite) {
// we're in an F2F invite
[self placeUserDataOnProfile];
} else {
// lock the scrollView
self.scrollView.scrollEnabled = NO;
// get a user object with resume data
[self.user loadUserResumeOnQueue:self.operationQueue completion:^(NSError *error) {
if (!error) {
// fill out the resume and unlock the scrollView
NSLog(@"Received resume response.");
self.scrollView.scrollEnabled = YES;
[self placeUserDataOnProfile];
} else {
// error checking for load of user
NSLog(@"Error loading resume: %@", error);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Resume Load"
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
}
}];
}
}
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
// when pulling the scroll view top down, present the map
self.mapView.frame = CGRectUnion(self.mapView.frame,
CGRectOffset(self.mapView.frame, 0, -self.mapView.frame.size.height));
// add the blue overlay gradient in front of the map
[self addGradientWithFrame:self.mapView.frame
locations:@[[NSNumber numberWithFloat:0.25],
[NSNumber numberWithFloat:0.30],
[NSNumber numberWithFloat:0.5],
[NSNumber numberWithFloat:0.90],
[NSNumber numberWithFloat:1.0]]
colors:@[(id)[[UIColor colorWithRed:0.67 green:0.83 blue:0.94 alpha:1.0] CGColor],
(id)[[UIColor colorWithRed:0.67 green:0.83 blue:0.94 alpha:0.75] CGColor],
(id)[[UIColor colorWithRed:0.40 green:0.62 blue:0.64 alpha:0.4] CGColor],
(id)[[UIColor colorWithRed:0.67 green:0.83 blue:0.94 alpha:0.75] CGColor],
(id)[[UIColor colorWithRed:0.67 green:0.83 blue:0.94 alpha:1.0] CGColor]]
];
// make sure there's a shadow on the userCard and resumeView
[CPUIHelper addShadowToView:self.userCard color:[UIColor blackColor] offset:CGSizeMake(2, 2) radius:3 opacity:0.38];
[CPUIHelper addShadowToView:self.resumeView color:[UIColor blackColor] offset:CGSizeMake(2, 2) radius:3 opacity:0.38];
// check if this is an F2F invite
if (!self.isF2FInvite) {
// put three animated dots after the Loading Resume text
[CPUIHelper animatedEllipsisAfterLabel:self.resumeLabel start:YES];
[CPUIHelper animatedEllipsisAfterLabel:self.checkedIn start:YES];
}
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// custom back button to allow event capture
if(!_tapRecon){
_tapRecon = [[UITapGestureRecognizer alloc]
initWithTarget:self action:@selector(navigationBarTitleTap:)];
_tapRecon.numberOfTapsRequired = 1;
_tapRecon.cancelsTouchesInView = NO;
[self.navigationController.navigationBar addGestureRecognizer:_tapRecon];
}
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[CPUserActionCell cancelOpenSlideActionButtonsNotification:nil];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self.navigationController.navigationBar removeGestureRecognizer:_tapRecon];
self.tapRecon = nil;
}
- (void)addGradientWithFrame:(CGRect)frame locations:(NSArray*)locations colors:(NSArray*)colors
{
// add gradient overlay
UIView *overlay = [[UIView alloc] initWithFrame:frame];
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = overlay.bounds;
gradient.colors = colors;
gradient.locations = locations;
[overlay.layer insertSublayer:gradient atIndex:0];
[self.scrollView insertSubview:overlay atIndex:1];
}
- (void)updateLastUserCheckin
{
if (self.firstLoad) {
// if the user is checked in show how much longer they'll be available for
if ([self.user.checkoutEpoch timeIntervalSinceNow] > 0) {
self.checkedIn.text = @"Checked in";
// get the number of seconds until they'll checkout
NSTimeInterval secondsToCheckout = [self.user.checkoutEpoch timeIntervalSinceNow];
// convert to minutes and then hours + minutes to next our
int minutesToCheckout = floor(secondsToCheckout / 60.0);
int hoursToCheckout = floor(minutesToCheckout / 60.0);
int minutesToHour = minutesToCheckout % 60;
// only show hours if there's at least one
if (hoursToCheckout > 0) {
self.hoursAvailable.text = [NSString stringWithFormat:@"%d hrs", hoursToCheckout];
} else {
self.hoursAvailable.text = @"";
}
self.minutesAvailable.text = [NSString stringWithFormat:@"%d mins", minutesToHour];
// show the availability view
self.availabilityView.alpha = 1.0;
[UIView animateWithDuration:0.4 animations:^{self.availabilityView.alpha = 1.0;}];
} else {
// change the label since the user isn't here anymore
self.checkedIn.text = @"Last checked in";
// otherwise don't show the availability view
self.availabilityView.alpha = 0.0;
self.hoursAvailable.text = @"";
self.minutesAvailable.text = @"";
}
}
self.venueName.text = self.user.placeCheckedIn.name;
self.venueAddress.text = self.user.placeCheckedIn.address;
self.othersAtPlace = self.user.checkedIn ? [self.user.placeCheckedIn.checkedInNow intValue] - 1 : [self.user.placeCheckedIn.checkedInNow intValue];
if (self.firstLoad) {
if (self.othersAtPlace == 0) {
// hide the little man, nobody else is here
self.venueOthersIcon.alpha = 0.0;
self.venueOthers.text = @"";
} else {
// show the little man
self.venueOthersIcon.alpha = 1.0;
// otherwise put 1 other or x others here now
self.venueOthers.text = [NSString stringWithFormat:@"%d %@ here now", self.othersAtPlace, self.othersAtPlace == 1 ? @"other" : @"others"];
}
self.firstLoad = NO;
}
// animate the display of the venueView and availabilityView
// if they aren't already on screen
[CPUIHelper animatedEllipsisAfterLabel:self.checkedIn start:NO];
[UIView animateWithDuration:0.4 animations:^{self.venueView.alpha = 1.0;}];
}
- (void)updateMapAndDistanceToUser
{
if (!self.mapAndDistanceLoaded) {
// make an MKCoordinate region for the zoom level on the map
MKCoordinateRegion region = MKCoordinateRegionMake(self.user.location, MKCoordinateSpanMake(0.005, 0.005));
[self.mapView setRegion:region];
// use method in CPUIHelper to shift the map to the right spot
[CPUIHelper shiftMapView:self.mapView forPinCenterInMapview:[self.mapView convertPoint:self.mapMarker.center fromView:self.scrollView]];
CLLocation *myLocation = [CPAppDelegate locationManager].location;
CLLocation *otherUserLocation = [[CLLocation alloc] initWithLatitude:self.user.location.latitude longitude:self.user.location.longitude];
NSString *distance = [CPUtils localizedDistanceofLocationA:myLocation awayFromLocationB:otherUserLocation];
[self.scrollView insertSubview:self.mapView atIndex:0];
self.distanceLabel.text = distance;
[UIView animateWithDuration:0.3 animations:^{
self.mapView.alpha = 1;
} completion:^(BOOL finished) {
if (finished) {
[UIView animateWithDuration:1 animations:^{
self.distanceLabel.alpha = 1;
self.mapMarker.alpha = 1;
}];
}
}];
self.mapAndDistanceLoaded = YES;
}
}
- (void)setUserStatusWithQuotes:(NSString *)status
{
if ([self.user.status length] > 0 && self.user.checkedIn) {
self.cardStatus.text = [NSString stringWithFormat:@"\"%@\"", status];
} else {
self.cardStatus.text = @"";
}
}
- (void)placeUserDataOnProfile
{
// dismiss the SVProgressHUD if it's up
[SVProgressHUD dismiss];
[CPUIHelper profileImageView:self.cardImage
withProfileImageUrl:self.user.photoURL];
self.cardNickname.text = self.user.nickname;
self.title = self.user.nickname;
self.cardJobPosition.text = self.user.jobTitle;
[self setUserStatusWithQuotes:self.user.status];
// if the user has an hourly rate then put it, otherwise it comes up as N/A
if (self.user.hourlyRate) {
self.resumeRate.text = self.user.hourlyRate;
}
self.resumeEarned.text = [NSString stringWithFormat:@"%d", self.user.totalHours];
self.loveReceived.text = [self.user.reviews objectForKey:@"love_received"];
if ([self.user.isContact boolValue]) {
self.userActionCell.rightStyle = CPUserActionCellSwipeStyleReducedAction;
}
dispatch_queue_t q_profile = dispatch_queue_create("com.candp.profile", NULL);
dispatch_async(q_profile, ^{
// load html into the bottom of the resume view for all the user data
// get the mustache rendering off the main thread
NSString *htmlString = [self htmlStringWithResumeText];
[self updateResumeWithHTML:htmlString];
dispatch_async(dispatch_get_main_queue(), ^{
[self updateMapAndDistanceToUser];
[self updateLastUserCheckin];
});
});
}
- (NSString *)htmlStringWithResumeText
{
if (!self.resumeHTML) {
NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:self.user, @"user",nil];
NSArray *reviews = [self.user.reviews objectForKey:@"rows"];
NSDictionary *originalData = @{
@"reviews": reviews,
@"user_id": self.user.userID,
@"server_api_url": [NSString stringWithFormat:@"%@api.php", kCandPWebServiceUrl]
};
NSError *error;
NSString *originalDataJSON = [[NSString alloc] initWithData:
[NSJSONSerialization dataWithJSONObject:originalData
options:kNilOptions
error:&error]
encoding:NSUTF8StringEncoding];
[dictionary setValue:[NSNumber numberWithBool:reviews.count > 0] forKey:@"hasAnyReview"];
[dictionary setValue:originalDataJSON forKey:@"originalData"];
NSError *mustacheError;
self.resumeHTML = [GRMustacheTemplate renderObject:dictionary fromResource:@"UserResume" bundle:nil error:&mustacheError];
#if DEBUG
if (mustacheError) {
NSLog(@"Error mustaching user resume: %@", mustacheError.localizedDescription);
}
#endif
}
return self.resumeHTML;
}
- (void) updateResumeWithHTML:(NSString*)html
{
NSString *path = [[NSBundle mainBundle] bundlePath];
NSURL *baseURL = [NSURL fileURLWithPath:path];
[self.resumeWebView loadHTMLString:html baseURL:baseURL];
NSLog(@"HTML updated.");
}
#pragma mark -
#pragma mark UIWebViewDelegate
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
NSURL *url = [request URL];
if ([url.scheme isEqualToString:@"favorite-venue-id"]) {
NSNumber *venueID = @([url.host integerValue]);
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"venueID == %@", venueID];
NSMutableArray *venues = self.user.favoritePlaces;
[venues filterUsingPredicate:predicate];
CPVenue *place = [venues objectAtIndex:0];
CPVenue *activeVenue = [[CPMarkerManager sharedManager] markerVenueWithID:venueID];
if (activeVenue) {
// we had this venue in the map dictionary of activeVenues so use that
place = activeVenue;
}
VenueInfoViewController *venueVC = [[UIStoryboard storyboardWithName:@"VenueStoryboard_iPhone" bundle:nil] instantiateInitialViewController];
venueVC.venue = place;
[self.navigationController pushViewController:venueVC animated:YES];
return NO;
}
if ([url.scheme isEqualToString:@"linkedin-view"]) {
[self performSegueWithIdentifier:@"ShowLinkedInProfileWebView" sender:self];
return NO;
}
if ([url.scheme isEqualToString:@"recompute-webview-height"]) {
[self performSelector:@selector(resetResumeWebViewHeight)
withObject:nil
afterDelay:0.05];
return NO;
}
return YES;
}
- (void)resetResumeWebViewHeight
{
self.resumeWebView.scrollView.scrollsToTop = NO;
self.resumeWebView.userInteractionEnabled = YES;
// resize the webView frame depending on the size of the content
CGRect frame = self.resumeWebView.frame;
frame.size.height = 1;
self.resumeWebView.frame = frame;
CGSize fittingSize = [self.resumeWebView sizeThatFits:CGSizeZero];
frame.size = fittingSize;
self.resumeWebView.frame = frame;
CGRect resumeFrame = self.resumeView.frame;
resumeFrame.size.height = self.resumeWebView.frame.origin.y + fittingSize.height;
self.resumeView.frame = resumeFrame;
[CPUIHelper addShadowToView:self.resumeView color:[UIColor blackColor] offset:CGSizeMake(2, 2) radius:3 opacity:0.38];
// if this is an f2f invite we need some extra height in the scrollview content size
double f2fbar = 0;
if (self.isF2FInvite) {
f2fbar = 81;
}
// set the scrollview content size to accomodate for the resume data
self.scrollView.contentSize = CGSizeMake(320, self.resumeView.frame.origin.y + self.resumeView.frame.size.height + 50 + f2fbar);
self.blueOverlayExtend.frame = CGRectMake(0, 416, 320, self.scrollView.contentSize.height - 416);
if (self.scrollToReviews) {
self.scrollToReviews = NO;
int offsetTop = [[self.resumeWebView stringByEvaluatingJavaScriptFromString:@"document.getElementById('reviews').offsetTop"] intValue];
if (offsetTop > 0) {
offsetTop += kResumeWebViewOffsetTop;
int bottomOffset = (int) (self.scrollView.contentSize.height - self.scrollView.bounds.size.height);
[self.scrollView setContentOffset:CGPointMake(0, MIN(offsetTop, bottomOffset)) animated:YES];
}
}
}
- (void)webViewDidFinishLoad:(UIWebView *)aWebView {
[self resetResumeWebViewHeight];
// add the blue overlay where the gradient ends
[self.scrollView insertSubview:self.blueOverlayExtend atIndex:0];
// call the JS function in the mustache file that will lazyload the images
[aWebView stringByEvaluatingJavaScriptFromString:@"lazyLoad();"];
// reveal the resume
[UIView animateWithDuration:0.3 animations:^{
self.resumeWebView.alpha = 1.0;
}];
[CPUIHelper animatedEllipsisAfterLabel:self.resumeLabel start:NO];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:@"ProfileToOneOnOneSegue"])
{
[[segue destinationViewController] setUser:self.user];
}
else if ([[segue identifier] isEqualToString:@"ProfileToPayUserSegue"])
{
[[segue destinationViewController] setUser:self.user];
} else if ([[segue identifier] isEqualToString:@"ShowLinkedInProfileWebView"]) {
// set the linkedInPublicProfileUrl in the destination VC
[[segue destinationViewController] setLinkedInProfileUrlAddress:self.user.linkedInPublicProfileUrl];
} else if ([[segue identifier] isEqualToString:@"SendLoveToUser"]) {
[[segue destinationViewController] setUser:self.user];
[[segue destinationViewController] setDelegate:self];
}
}
-(IBAction)venueViewButtonPressed:(id)sender {
VenueInfoViewController *venueVC = [[UIStoryboard storyboardWithName:@"VenueStoryboard_iPhone" bundle:nil] instantiateInitialViewController];
CPVenue *markerVenue = [[CPMarkerManager sharedManager] markerVenueWithID:self.user.placeCheckedIn.venueID];
venueVC.venue = markerVenue ? markerVenue : self.user.placeCheckedIn;
[self.navigationController pushViewController:venueVC animated:YES];
}
- (void)navigationBarTitleTap:(UIGestureRecognizer*)recognizer {
[_scrollView setContentOffset:CGPointMake(0,0) animated:YES];
}
#pragma mark - UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
[CPUserActionCell cancelOpenSlideActionButtonsNotification:nil];
}
#pragma mark - CPUserActionCellDelegate
- (void)cell:(CPUserActionCell*)cell didSelectSendLoveToUser:(CPUser *)user
{
[CPUserAction cell:cell sendLoveFromViewController:self];
}
- (void)cell:(CPUserActionCell*)cell didSelectSendMessageToUser:(CPUser *)user
{
[CPUserAction cell:cell sendMessageFromViewController:self];
}
- (void)cell:(CPUserActionCell*)cell didSelectExchangeContactsWithUser:(CPUser *)user
{
[CPUserAction cell:cell exchangeContactsFromViewController:self];
}
#pragma mark - properties
- (UIView *)blueOverlayExtend
{
if (!_blueOverlayExtend) {
UIView *blueOverlayExtend = [[UIView alloc] initWithFrame:CGRectMake(0, 416, 320, self.scrollView.contentSize.height - 416)];
blueOverlayExtend.backgroundColor = [UIColor colorWithRed:0.67 green:0.83 blue:0.94 alpha:1.0];
self.view.backgroundColor = blueOverlayExtend.backgroundColor;
}
return _blueOverlayExtend;
}
@end