Files
Swiftgram/examples/ASDKgram/Sample/UserProfileViewController.m

402 lines
14 KiB
Objective-C

//
// UserProfileViewController.m
// Flickrgram
//
// Created by Hannah Troisi on 2/24/16.
// Copyright © 2016 Hannah Troisi. All rights reserved.
//
#import "UserProfileViewController.h"
#import "Utilities.h"
#define HEADER_HEIGHT 300
#define USER_AVATAR_HEIGHT 70
#define HEADER_HORIZONTAL_INSET 15
#define DEBUG_LAYOUT 0
@implementation UserProfileViewController
{
UserModel *_user;
UIImageView *_avatarImageView;
UIButton *_followingStatusBtn;
UILabel *_fullNameLabel;
UILabel *_aboutLabel;
UILabel *_domainLabel;
UILabel *_followersCountLabel;
UILabel *_followingCountLabel;
UILabel *_photoCountLabel;
BOOL _animating;
}
//- (instancetype)initWithMe
//{
// UserModel *me = [[UserModel alloc] initWithMe];
//
// [self initWithUser:me];
//}
- (instancetype)initWithUser:(UserModel *)user
{
self = [super initWithNibName:nil bundle:nil];
if (self) {
self.view.backgroundColor = [UIColor whiteColor];
_followingStatusBtn = [UIButton buttonWithType:UIButtonTypeCustom];
_followingStatusBtn.adjustsImageWhenHighlighted = NO;
[_followingStatusBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[_followingStatusBtn setTitleColor:[UIColor lightBlueColor] forState:UIControlStateSelected];
[_followingStatusBtn setTitle:@"Follow" forState:UIControlStateNormal];
[_followingStatusBtn setTitle:@"Following" forState:UIControlStateSelected];
[_followingStatusBtn addTarget:self action:@selector(toggleFollowing) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_followingStatusBtn];
_fullNameLabel = [[UILabel alloc] init];
_fullNameLabel.font = [_fullNameLabel.font fontWithSize:14];
[self.view addSubview:_fullNameLabel];
_aboutLabel = [[UILabel alloc] init];
_aboutLabel.font = [_aboutLabel.font fontWithSize:14];
_aboutLabel.numberOfLines = 3;
[self.view addSubview:_aboutLabel];
_domainLabel = [[UILabel alloc] init];
_domainLabel.font = [_domainLabel.font fontWithSize:14];
_domainLabel.textColor = [UIColor darkBlueColor];
[self.view addSubview:_domainLabel];
_followersCountLabel = [[UILabel alloc] init];
_followersCountLabel.font = [_followersCountLabel.font fontWithSize:14];
_followersCountLabel.textColor = [UIColor lightGrayColor];
_followersCountLabel.textAlignment = NSTextAlignmentCenter;
_followersCountLabel.numberOfLines = 2;
[self.view addSubview:_followersCountLabel];
_followingCountLabel = [[UILabel alloc] init];
_followingCountLabel.font = [_followingCountLabel.font fontWithSize:14];
_followingCountLabel.textColor = [UIColor lightGrayColor];
_followingCountLabel.textAlignment = NSTextAlignmentCenter;
_followingCountLabel.numberOfLines = 2;
[self.view addSubview:_followingCountLabel];
_photoCountLabel = [[UILabel alloc] init];
_photoCountLabel.font = [_photoCountLabel.font fontWithSize:14];
_photoCountLabel.textColor = [UIColor lightGrayColor];
_photoCountLabel.textAlignment = NSTextAlignmentCenter;
_photoCountLabel.numberOfLines = 2;
[self.view addSubview:_photoCountLabel];
// add to view last so that animation is on top
_avatarImageView = [[UIImageView alloc] init];
[self.view addSubview:_avatarImageView];
// This is what we have available as soon as we're created, without fetching new metadata from the network.
_fullNameLabel.text = _user.fullName;
_user = user;
self.navigationItem.title = [user.username uppercaseString];
// get full set of user data
[self loadAdditionalProfileFields];
// get avatar image
[self loadAvatarImage];
UILongPressGestureRecognizer *lpgr = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(viewWasLongPressed:)];
// [self.view addGestureRecognizer:lpgr];
lpgr.minimumPressDuration = 0.01;
if (DEBUG_LAYOUT) {
_avatarImageView.backgroundColor = [UIColor greenColor];
_fullNameLabel.backgroundColor = [UIColor greenColor];
_aboutLabel.backgroundColor = [UIColor greenColor];
_domainLabel.backgroundColor = [UIColor greenColor];
_followersCountLabel.backgroundColor = [UIColor greenColor];
_followingCountLabel.backgroundColor = [UIColor greenColor];
_photoCountLabel.backgroundColor = [UIColor greenColor];
}
}
return self;
}
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
CGSize boundsSize = self.view.bounds.size;
if (_animating) {
return;
}
// user avatar
CGFloat x = HEADER_HORIZONTAL_INSET;
CGFloat originalY = CGRectGetMaxY(self.navigationController.navigationBar.frame) + HEADER_HORIZONTAL_INSET;
CGFloat y = originalY;
_avatarImageView.frame = CGRectMake(x,
y,
USER_AVATAR_HEIGHT,
USER_AVATAR_HEIGHT);
y += _avatarImageView.frame.size.height;
if (!_avatarImageView.image) {
// We generate the rounded image at layout time (unusually late) so that we can know exactly how large
// it needs to be. This is the only way to ensure the rounded curve is perfectly smoothed / antialiased.
// _avatarImageView.image = [avatar makeCircularImageWithSize:CGSizeMake(USER_AVATAR_HEIGHT, USER_AVATAR_HEIGHT)];
}
if (_fullNameLabel.text) {
[_fullNameLabel sizeToFit];
y += HEADER_HORIZONTAL_INSET / 2.0;
_fullNameLabel.frame = CGRectMake(x,
y,
boundsSize.width - 2 * HEADER_HORIZONTAL_INSET,
_fullNameLabel.frame.size.height);
y += _fullNameLabel.frame.size.height;
}
if (_aboutLabel.text) {
[_aboutLabel sizeToFit];
y += HEADER_HORIZONTAL_INSET / 2.0;
_aboutLabel.frame = CGRectMake(x,
y,
boundsSize.width - 2 * HEADER_HORIZONTAL_INSET,
_aboutLabel.frame.size.height);
y += _aboutLabel.frame.size.height;
}
if (_domainLabel.text) {
[_domainLabel sizeToFit];
y += HEADER_HORIZONTAL_INSET / 2.0;
_domainLabel.frame = CGRectMake(x,
y,
boundsSize.width - 2 * HEADER_HORIZONTAL_INSET,
_domainLabel.frame.size.height);
}
CGFloat availableWidth = boundsSize.width - 3 * HEADER_HORIZONTAL_INSET - USER_AVATAR_HEIGHT;
CGFloat actualWidth = floorf((availableWidth - 2 * HEADER_HORIZONTAL_INSET / 2.0) / 3.0);
y = originalY;
x += USER_AVATAR_HEIGHT + HEADER_HORIZONTAL_INSET;
[_photoCountLabel sizeToFit];
_photoCountLabel.frame = CGRectMake(x,
y,
actualWidth,
_photoCountLabel.frame.size.height);
x += actualWidth;
[_followersCountLabel sizeToFit];
x += HEADER_HORIZONTAL_INSET / 2.0;
_followersCountLabel.frame = CGRectMake(x,
y,
actualWidth,
_followersCountLabel.frame.size.height);
x += actualWidth;
[_followingCountLabel sizeToFit];
x += HEADER_HORIZONTAL_INSET / 2.0;
_followingCountLabel.frame = CGRectMake(x,
y,
actualWidth,
_followingCountLabel.frame.size.height);
x = USER_AVATAR_HEIGHT + 2 * HEADER_HORIZONTAL_INSET;
y = originalY + USER_AVATAR_HEIGHT / 2.0;
_followingStatusBtn.frame = CGRectMake(x,
y,
availableWidth,
USER_AVATAR_HEIGHT / 2.0);
[self setFollowingButtonBackgroundsForRect:_followingStatusBtn.frame.size];
}
#pragma mark - Touch Events
- (void)viewWasLongPressed:(UIGestureRecognizer *)sender
{
if (sender.state == UIGestureRecognizerStateBegan) {
// determine which area of cell was tapped
CGPoint tapPoint = [sender locationInView:_avatarImageView];
if (tapPoint.y > 0) {
NSLog(@"LONG PRESS STARTED");
_animating = YES;
// FIXME: use pinremote image to download higher res photo
[UIView animateWithDuration:0.2
delay:0
usingSpringWithDamping:0.5
initialSpringVelocity:1.0f
options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseInOut
animations:^{
// FIXME: grey the background
_avatarImageView.frame = CGRectMake(100, 100, 100, 100);
} completion:^(BOOL finished) {
_animating = NO;
}];
}
}
if (sender.state == UIGestureRecognizerStateEnded) {
// determine which area of cell was tapped
CGPoint tapPoint = [sender locationInView:_avatarImageView];
if (tapPoint.y > 0) { // FIXME: all long presses work here
NSLog(@"LONG PRESS ENDED");
_animating = YES;
[UIView animateWithDuration:0.2
delay:0
usingSpringWithDamping:0.5
initialSpringVelocity:1.0f
options: UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseInOut
animations:^{
CGFloat x = HEADER_HORIZONTAL_INSET;
CGFloat originalY = CGRectGetMaxY(self.navigationController.navigationBar.frame) + HEADER_HORIZONTAL_INSET;
CGFloat y = originalY;
_avatarImageView.frame = CGRectMake(x,
y,
USER_AVATAR_HEIGHT,
USER_AVATAR_HEIGHT);
} completion:^(BOOL finished) {
_animating = NO;
}];
}
}
}
- (void)toggleFollowing
{
// toggle button state
if (_followingStatusBtn.selected) {
// stop following
NSString *urlString = [NSString stringWithFormat:@"https://api.500px.com/v1/users/%lu/friends?consumer_key=Fi13GVb8g53sGvHICzlram7QkKOlSDmAmp9s9aqC", (long)_user.userID];
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:@"DELETE"];
// FIXME: update user model
// FIXME: check for success
} else {
// start following
NSString *urlString = [NSString stringWithFormat:@"https://api.500px.com/v1/users/%lu/friends?consumer_key=Fi13GVb8g53sGvHICzlram7QkKOlSDmAmp9s9aqC", (long)_user.userID];
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:@"POST"];
}
_followingStatusBtn.selected = !_followingStatusBtn.selected;
}
- (void)getFollowers
{
NSString *urlString = [NSString stringWithFormat:@"https://api.500px.com/v1/users/%lu/friends?consumer_key=Fi13GVb8g53sGvHICzlram7QkKOlSDmAmp9s9aqC", (long)_user.userID];
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:@"GET"];
}
#pragma mark - Helper Methods
- (void)loadAdditionalProfileFields
{
// fetch full user profile info
[_user downloadCompleteUserDataWithCompletionBlock:^(UserModel *userModel) {
// check that info returning from async download is still applicable to this view
if (userModel == _user) {
_followingStatusBtn.selected = userModel.following;
_followersCountLabel.text = [NSString stringWithFormat:@"%lu\nfollowers", (long)userModel.followersCount];
_followingCountLabel.text = [NSString stringWithFormat:@"%lu\nfollowing", (long)userModel.friendsCount];
_photoCountLabel.text = [NSString stringWithFormat:@"%lu\nphotos", (long)userModel.photoCount];
_aboutLabel.text = userModel.about;
_domainLabel.text = userModel.domain;
[self.view setNeedsLayout];
}
}];
}
- (void)loadAvatarImage
{
[_user fetchAvatarImageWithCompletionBlock:^(UserModel *userModel, UIImage *avatar) {
// check that info returning from async download is still applicable to this view
if (userModel == _user) {
[self.view setNeedsLayout];
}
}];
}
#define FOLLOW_BUTTON_CORNER_RADIUS 8
- (void)setFollowingButtonBackgroundsForRect:(CGSize)size
{
CGSize unstretchedSize = CGSizeMake(2 * FOLLOW_BUTTON_CORNER_RADIUS + 1, 2 * FOLLOW_BUTTON_CORNER_RADIUS + 1);
CGRect rect = (CGRect) {CGPointZero, unstretchedSize};
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:FOLLOW_BUTTON_CORNER_RADIUS];
UIColor *lightBlue = [UIColor colorWithRed:0.0 green:122.0/255.0 blue:1.0 alpha:1.0];
// create a graphics context for the following status button
UIGraphicsBeginImageContextWithOptions(unstretchedSize, NO, 0);
[path addClip];
[lightBlue setFill];
[path fill];
UIImage *notFollowingBtnImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImage *notFollowingBtnImageStretchable = [notFollowingBtnImage stretchableImageWithLeftCapWidth:FOLLOW_BUTTON_CORNER_RADIUS topCapHeight:FOLLOW_BUTTON_CORNER_RADIUS];
[_followingStatusBtn setBackgroundImage:notFollowingBtnImageStretchable forState:UIControlStateNormal];
// create a graphics context for the not yet following status button
UIGraphicsBeginImageContextWithOptions(unstretchedSize, NO, 0);
[path addClip];
[[UIColor whiteColor] setFill];
[path fill];
path.lineWidth = 3;
[lightBlue setStroke];
[path stroke];
UIImage *followingBtnImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImage *followingBtnImageStretchable = [followingBtnImage stretchableImageWithLeftCapWidth:FOLLOW_BUTTON_CORNER_RADIUS topCapHeight:FOLLOW_BUTTON_CORNER_RADIUS];
[_followingStatusBtn setBackgroundImage:followingBtnImageStretchable forState:UIControlStateSelected];
}
@end