diff --git a/examples/ASDKgram/Sample.xcodeproj/project.pbxproj b/examples/ASDKgram/Sample.xcodeproj/project.pbxproj index a76797d57..a4b54adb1 100644 --- a/examples/ASDKgram/Sample.xcodeproj/project.pbxproj +++ b/examples/ASDKgram/Sample.xcodeproj/project.pbxproj @@ -17,7 +17,6 @@ 768843851CAA37EF00D8629E /* ImageURLModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 7688436D1CAA37EF00D8629E /* ImageURLModel.m */; }; 768843891CAA37EF00D8629E /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 768843711CAA37EF00D8629E /* main.m */; }; 7688438B1CAA37EF00D8629E /* PhotoCellNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 768843731CAA37EF00D8629E /* PhotoCellNode.m */; }; - 7688438C1CAA37EF00D8629E /* PhotoCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 768843741CAA37EF00D8629E /* PhotoCollectionViewCell.m */; }; 7688438D1CAA37EF00D8629E /* PhotoFeedModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 768843751CAA37EF00D8629E /* PhotoFeedModel.m */; }; 7688438E1CAA37EF00D8629E /* PhotoFeedNodeController.m in Sources */ = {isa = PBXBuildFile; fileRef = 768843761CAA37EF00D8629E /* PhotoFeedNodeController.m */; }; 768843901CAA37EF00D8629E /* PhotoModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 768843781CAA37EF00D8629E /* PhotoModel.m */; }; @@ -49,7 +48,6 @@ 768843511CAA37EF00D8629E /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = AppDelegate.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 768843561CAA37EF00D8629E /* ImageURLModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = ImageURLModel.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 7688435B1CAA37EF00D8629E /* PhotoCellNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = PhotoCellNode.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; - 7688435C1CAA37EF00D8629E /* PhotoCollectionViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = PhotoCollectionViewCell.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 7688435D1CAA37EF00D8629E /* PhotoFeedModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = PhotoFeedModel.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 7688435E1CAA37EF00D8629E /* PhotoFeedNodeController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = PhotoFeedNodeController.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 768843601CAA37EF00D8629E /* PhotoModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = PhotoModel.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; @@ -62,7 +60,6 @@ 7688436D1CAA37EF00D8629E /* ImageURLModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ImageURLModel.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 768843711CAA37EF00D8629E /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = main.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 768843731CAA37EF00D8629E /* PhotoCellNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = PhotoCellNode.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; - 768843741CAA37EF00D8629E /* PhotoCollectionViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = PhotoCollectionViewCell.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 768843751CAA37EF00D8629E /* PhotoFeedModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = PhotoFeedModel.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 768843761CAA37EF00D8629E /* PhotoFeedNodeController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = PhotoFeedNodeController.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 768843781CAA37EF00D8629E /* PhotoModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = PhotoModel.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; @@ -236,8 +233,6 @@ children = ( 768843611CAA37EF00D8629E /* PhotoTableViewCell.h */, 768843791CAA37EF00D8629E /* PhotoTableViewCell.m */, - 7688435C1CAA37EF00D8629E /* PhotoCollectionViewCell.h */, - 768843741CAA37EF00D8629E /* PhotoCollectionViewCell.m */, ); name = UIKit; sourceTree = ""; @@ -364,7 +359,6 @@ buildActionMask = 2147483647; files = ( 768843891CAA37EF00D8629E /* main.m in Sources */, - 7688438C1CAA37EF00D8629E /* PhotoCollectionViewCell.m in Sources */, 768843921CAA37EF00D8629E /* PhotoFeedViewController.m in Sources */, 76229A781CBB79E000B62CEF /* WindowWithStatusBarUnderlay.m in Sources */, 768843961CAA37EF00D8629E /* Utilities.m in Sources */, diff --git a/examples/ASDKgram/Sample/PhotoCellNode.m b/examples/ASDKgram/Sample/PhotoCellNode.m index eef2bb06b..5353da65b 100644 --- a/examples/ASDKgram/Sample/PhotoCellNode.m +++ b/examples/ASDKgram/Sample/PhotoCellNode.m @@ -60,7 +60,7 @@ - (instancetype)initWithPhotoObject:(PhotoModel *)photo; // FIXME: autocomplete for this line seems broken [_userAvatarImageNode setImageModificationBlock:^UIImage *(UIImage *image) { CGSize profileImageSize = CGSizeMake(USER_IMAGE_HEIGHT, USER_IMAGE_HEIGHT); - return [image makeCircularImageWithSize:profileImageSize]; + return [image makeCircularImageWithSize:profileImageSize backgroundColor:nil]; }]; _photoImageNode = [[ASNetworkImageNode alloc] init]; diff --git a/examples/ASDKgram/Sample/PhotoCollectionViewCell.h b/examples/ASDKgram/Sample/PhotoCollectionViewCell.h deleted file mode 100644 index d277b5a57..000000000 --- a/examples/ASDKgram/Sample/PhotoCollectionViewCell.h +++ /dev/null @@ -1,16 +0,0 @@ -// -// PhotoCollectionViewCell.h -// Texture -// -// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved. -// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved. -// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0 -// - -#import "PhotoModel.h" - -@interface PhotoCollectionViewCell : UICollectionViewCell - -- (void)updateCellWithPhotoObject:(PhotoModel *)photo; - -@end diff --git a/examples/ASDKgram/Sample/PhotoCollectionViewCell.m b/examples/ASDKgram/Sample/PhotoCollectionViewCell.m deleted file mode 100644 index d04fe1ca5..000000000 --- a/examples/ASDKgram/Sample/PhotoCollectionViewCell.m +++ /dev/null @@ -1,58 +0,0 @@ -// -// PhotoCollectionViewCell.m -// Texture -// -// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved. -// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved. -// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0 -// - -#import "PhotoCollectionViewCell.h" -#import "PINImageView+PINRemoteImage.h" -#import "PINButton+PINRemoteImage.h" - -@implementation PhotoCollectionViewCell -{ - UIImageView *_photoImageView; -} - -#pragma mark - Lifecycle - -- (instancetype)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - - if (self) { - - _photoImageView = [[UIImageView alloc] init]; - [_photoImageView setPin_updateWithProgress:YES]; - [self.contentView addSubview:_photoImageView]; - } - - return self; -} - -- (void)layoutSubviews -{ - [super layoutSubviews]; - - _photoImageView.frame = self.bounds; -} - -- (void)prepareForReuse -{ - [super prepareForReuse]; - - // remove images so that the old content doesn't appear before the new content is loaded - _photoImageView.image = nil; -} - -#pragma mark - Instance Methods - -- (void)updateCellWithPhotoObject:(PhotoModel *)photo -{ - // async download of photo using PINRemoteImage - [_photoImageView pin_setImageFromURL:photo.URL]; -} - -@end diff --git a/examples/ASDKgram/Sample/PhotoFeedBaseController.m b/examples/ASDKgram/Sample/PhotoFeedBaseController.m index d94a34e92..fa03d73c9 100644 --- a/examples/ASDKgram/Sample/PhotoFeedBaseController.m +++ b/examples/ASDKgram/Sample/PhotoFeedBaseController.m @@ -67,7 +67,9 @@ - (void)insertNewRows:(NSArray *)newPhotos NSIndexPath *path = [NSIndexPath indexPathForRow:row inSection:section]; [indexPaths addObject:path]; } + [self.tableView beginUpdates]; [self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone]; + [self.tableView endUpdates]; } - (UIStatusBarStyle)preferredStatusBarStyle diff --git a/examples/ASDKgram/Sample/PhotoFeedViewController.m b/examples/ASDKgram/Sample/PhotoFeedViewController.m index c3f9a4aef..479749f55 100644 --- a/examples/ASDKgram/Sample/PhotoFeedViewController.m +++ b/examples/ASDKgram/Sample/PhotoFeedViewController.m @@ -14,11 +14,12 @@ #define AUTO_TAIL_LOADING_NUM_SCREENFULS 2.5 +static NSString *TableViewCellIdentifier = @"PhotoCell"; + @interface PhotoFeedViewController () @end -@implementation PhotoFeedViewController -{ +@implementation PhotoFeedViewController { UITableView *_tableView; } @@ -45,10 +46,16 @@ - (instancetype)init - (void)viewDidLoad { [super viewDidLoad]; - + [self.view addSubview:_tableView]; + [_tableView registerClass:[PhotoTableViewCell class] forCellReuseIdentifier:TableViewCellIdentifier]; +} + +- (void)viewDidLayoutSubviews +{ + [super viewDidLayoutSubviews]; + _tableView.frame = self.view.bounds; - [_tableView registerClass:[PhotoTableViewCell class] forCellReuseIdentifier:@"photoCell"]; } #pragma mark - Subclassing @@ -74,7 +81,7 @@ - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { - PhotoTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"photoCell" forIndexPath:indexPath]; + PhotoTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:TableViewCellIdentifier forIndexPath:indexPath]; [cell updateCellWithPhotoObject:[self.photoFeed objectAtIndex:indexPath.row]]; return cell; @@ -83,13 +90,13 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { PhotoModel *photo = [self.photoFeed objectAtIndex:indexPath.row]; - return [PhotoTableViewCell heightForPhotoModel:photo withWidth:self.view.bounds.size.width]; + return [PhotoTableViewCell heightForPhotoModel:photo withWidth:CGRectGetWidth(tableView.bounds)]; } #pragma mark - UITableViewDelegate methods // table automatic tail loading --(void)scrollViewDidScroll:(UIScrollView *)scrollView +- (void)scrollViewDidScroll:(UIScrollView *)scrollView { CGFloat currentOffSetY = scrollView.contentOffset.y; CGFloat contentHeight = scrollView.contentSize.height; diff --git a/examples/ASDKgram/Sample/PhotoTableViewCell.m b/examples/ASDKgram/Sample/PhotoTableViewCell.m index 9cc5fa785..4f7beba1a 100644 --- a/examples/ASDKgram/Sample/PhotoTableViewCell.m +++ b/examples/ASDKgram/Sample/PhotoTableViewCell.m @@ -13,7 +13,7 @@ #import "PINButton+PINRemoteImage.h" #define DEBUG_PHOTOCELL_LAYOUT 0 -#define USE_UIKIT_AUTOLAYOUT 1 +#define USE_UIKIT_AUTOLAYOUT 0 #define USE_UIKIT_MANUAL_LAYOUT !USE_UIKIT_AUTOLAYOUT #define HEADER_HEIGHT 50 @@ -24,15 +24,15 @@ @implementation PhotoTableViewCell { - PhotoModel *_photoModel; + PhotoModel *_photoModel; - UIImageView *_userAvatarImageView; - UIImageView *_photoImageView; - UILabel *_userNameLabel; - UILabel *_photoLocationLabel; - UILabel *_photoTimeIntervalSincePostLabel; - UILabel *_photoLikesLabel; - UILabel *_photoDescriptionLabel; + UIImageView *_userAvatarImageView; + UIImageView *_photoImageView; + UILabel *_userNameLabel; + UILabel *_photoLocationLabel; + UILabel *_photoTimeIntervalSincePostLabel; + UILabel *_photoLikesLabel; + UILabel *_photoDescriptionLabel; NSLayoutConstraint *_userNameYPositionWithPhotoLocation; NSLayoutConstraint *_userNameYPositionWithoutPhotoLocation; @@ -45,14 +45,18 @@ + (CGFloat)heightForPhotoModel:(PhotoModel *)photo withWidth:(CGFloat)width; { CGFloat photoHeight = width; - UIFont *font = [UIFont systemFontOfSize:FONT_SIZE]; + UIFont *font = [UIFont systemFontOfSize:FONT_SIZE]; CGFloat likesHeight = roundf([font lineHeight]); - - NSAttributedString *descriptionAttrString = [photo descriptionAttributedStringWithFontSize:FONT_SIZE]; - CGFloat availableWidth = (width - HORIZONTAL_BUFFER * 2); - CGFloat descriptionHeight = [descriptionAttrString boundingRectWithSize:CGSizeMake(availableWidth, CGFLOAT_MAX) - options:NSStringDrawingUsesLineFragmentOrigin - context:nil].size.height; + + static UILabel *sizingLabel = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sizingLabel = [[UILabel alloc] init]; + sizingLabel.numberOfLines = 3; + }); + + sizingLabel.attributedText = [photo descriptionAttributedStringWithFontSize:FONT_SIZE];; + CGFloat descriptionHeight = [sizingLabel sizeThatFits:CGSizeMake(width - HORIZONTAL_BUFFER * 2, CGFLOAT_MAX)].height; return HEADER_HEIGHT + photoHeight + likesHeight + descriptionHeight + (4 * VERTICAL_BUFFER); } @@ -64,23 +68,31 @@ - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSStr self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) { - _userAvatarImageView = [[UIImageView alloc] init]; - _photoImageView = [[UIImageView alloc] init]; - _photoImageView.contentMode = UIViewContentModeScaleAspectFill; - _userNameLabel = [[UILabel alloc] init]; - _photoLocationLabel = [[UILabel alloc] init]; - _photoTimeIntervalSincePostLabel = [[UILabel alloc] init]; - _photoLikesLabel = [[UILabel alloc] init]; - _photoDescriptionLabel = [[UILabel alloc] init]; + _userAvatarImageView = [[UIImageView alloc] init]; + _userAvatarImageView.backgroundColor = [UIColor backgroundColor]; + _photoImageView = [[UIImageView alloc] init]; + _photoImageView.contentMode = UIViewContentModeScaleAspectFill; + _photoImageView.clipsToBounds = YES; + _photoImageView.backgroundColor = [UIColor backgroundColor]; + _userNameLabel = [[UILabel alloc] init]; + _userNameLabel.backgroundColor = [UIColor whiteColor]; + _photoLocationLabel = [[UILabel alloc] init]; + _photoLocationLabel.backgroundColor = [UIColor backgroundColor]; + _photoTimeIntervalSincePostLabel = [[UILabel alloc] init]; + _photoTimeIntervalSincePostLabel.backgroundColor = [UIColor whiteColor]; + _photoLikesLabel = [[UILabel alloc] init]; + _photoLikesLabel.backgroundColor = [UIColor whiteColor]; + _photoDescriptionLabel = [[UILabel alloc] init]; _photoDescriptionLabel.numberOfLines = 3; + _photoDescriptionLabel.backgroundColor = [UIColor whiteColor]; - [self addSubview:_userAvatarImageView]; - [self addSubview:_photoImageView]; - [self addSubview:_userNameLabel]; - [self addSubview:_photoLocationLabel]; - [self addSubview:_photoTimeIntervalSincePostLabel]; - [self addSubview:_photoLikesLabel]; - [self addSubview:_photoDescriptionLabel]; + [self.contentView addSubview:_userAvatarImageView]; + [self.contentView addSubview:_photoImageView]; + [self.contentView addSubview:_userNameLabel]; + [self.contentView addSubview:_photoLocationLabel]; + [self.contentView addSubview:_photoTimeIntervalSincePostLabel]; + [self.contentView addSubview:_photoLikesLabel]; + [self.contentView addSubview:_photoDescriptionLabel]; #if USE_UIKIT_AUTOLAYOUT [_userAvatarImageView setTranslatesAutoresizingMaskIntoConstraints:NO]; @@ -108,10 +120,7 @@ - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSStr return self; } --(void)setFrame:(CGRect)frame -{ - [super setFrame:frame]; -} +#if USE_UIKIT_AUTOLAYOUT - (void)setupConstraints { @@ -294,13 +303,14 @@ - (void)setupConstraints attribute:NSLayoutAttributeWidth multiplier:1.0 constant:-HORIZONTAL_BUFFER]]; + } - (void)updateConstraints { [super updateConstraints]; - if (_photoLocationLabel.attributedText) { + if (_photoLocationLabel.attributedText.length) { _userNameYPositionWithoutPhotoLocation.active = NO; _userNameYPositionWithPhotoLocation.active = YES; _photoLocationYPosition.active = YES; @@ -311,29 +321,34 @@ - (void)updateConstraints } } +#endif + - (void)layoutSubviews { [super layoutSubviews]; -#if USE_UIKIT_PROGRAMMATIC_LAYOUT - CGSize boundsSize = self.bounds.size; +#if USE_UIKIT_MANUAL_LAYOUT + CGSize boundsSize = self.contentView.bounds.size; CGRect rect = CGRectMake(HORIZONTAL_BUFFER, (HEADER_HEIGHT - USER_IMAGE_HEIGHT) / 2.0, USER_IMAGE_HEIGHT, USER_IMAGE_HEIGHT); _userAvatarImageView.frame = rect; + [_photoTimeIntervalSincePostLabel sizeToFit]; rect.size = _photoTimeIntervalSincePostLabel.bounds.size; rect.origin.x = boundsSize.width - HORIZONTAL_BUFFER - rect.size.width; rect.origin.y = (HEADER_HEIGHT - rect.size.height) / 2.0; _photoTimeIntervalSincePostLabel.frame = rect; CGFloat availableWidth = CGRectGetMinX(_photoTimeIntervalSincePostLabel.frame) - HORIZONTAL_BUFFER; + [_userNameLabel sizeToFit]; rect.size = _userNameLabel.bounds.size; rect.size.width = MIN(availableWidth, rect.size.width); rect.origin.x = HORIZONTAL_BUFFER + USER_IMAGE_HEIGHT + HORIZONTAL_BUFFER; - - if (_photoLocationLabel.attributedText) { + + [_photoLocationLabel sizeToFit]; + if (_photoLocationLabel.attributedText.length) { CGSize locationSize = _photoLocationLabel.bounds.size; locationSize.width = MIN(availableWidth, locationSize.width); @@ -351,13 +366,13 @@ - (void)layoutSubviews _photoImageView.frame = CGRectMake(0, HEADER_HEIGHT, boundsSize.width, boundsSize.width); - // FIXME: Make PhotoCellFooterView + + [_photoLikesLabel sizeToFit]; rect.size = _photoLikesLabel.bounds.size; rect.origin = CGPointMake(HORIZONTAL_BUFFER, CGRectGetMaxY(_photoImageView.frame) + VERTICAL_BUFFER); _photoLikesLabel.frame = rect; - rect.size = _photoDescriptionLabel.bounds.size; - rect.size.width = MIN(boundsSize.width - HORIZONTAL_BUFFER * 2, rect.size.width); + rect.size = [_photoDescriptionLabel sizeThatFits:CGSizeMake(boundsSize.width - HORIZONTAL_BUFFER * 2, CGFLOAT_MAX)]; rect.origin.y = CGRectGetMaxY(_photoLikesLabel.frame) + VERTICAL_BUFFER; _photoDescriptionLabel.frame = rect; #endif @@ -367,58 +382,60 @@ - (void)prepareForReuse { [super prepareForReuse]; - _userAvatarImageView.image = nil; - _photoImageView.image = nil; - _userNameLabel.attributedText = nil; - _photoLocationLabel.attributedText = nil; - _photoLocationLabel.frame = CGRectZero; // next cell might not have a _photoLocationLabel + _userAvatarImageView.image = nil; + _photoImageView.image = nil; + _userNameLabel.attributedText = nil; + _photoLocationLabel.attributedText = nil; _photoTimeIntervalSincePostLabel.attributedText = nil; - _photoLikesLabel.attributedText = nil; - _photoDescriptionLabel.attributedText = nil; + _photoLikesLabel.attributedText = nil; + _photoDescriptionLabel.attributedText = nil; } #pragma mark - Instance Methods - (void)updateCellWithPhotoObject:(PhotoModel *)photo { - _photoModel = photo; - _userNameLabel.attributedText = [photo.ownerUserProfile usernameAttributedStringWithFontSize:FONT_SIZE]; + _photoModel = photo; + _userNameLabel.attributedText = [photo.ownerUserProfile usernameAttributedStringWithFontSize:FONT_SIZE]; _photoTimeIntervalSincePostLabel.attributedText = [photo uploadDateAttributedStringWithFontSize:FONT_SIZE]; - _photoLikesLabel.attributedText = [photo likesAttributedStringWithFontSize:FONT_SIZE]; - _photoDescriptionLabel.attributedText = [photo descriptionAttributedStringWithFontSize:FONT_SIZE]; - - [_userNameLabel sizeToFit]; - [_photoTimeIntervalSincePostLabel sizeToFit]; - [_photoLikesLabel sizeToFit]; - [_photoDescriptionLabel sizeToFit]; - CGRect rect = _photoDescriptionLabel.frame; - CGFloat availableWidth = (self.bounds.size.width - HORIZONTAL_BUFFER * 2); - rect.size = [_photoDescriptionLabel sizeThatFits:CGSizeMake(availableWidth, CGFLOAT_MAX)]; - _photoDescriptionLabel.frame = rect; + _photoLikesLabel.attributedText = [photo likesAttributedStringWithFontSize:FONT_SIZE]; + _photoDescriptionLabel.attributedText = [photo descriptionAttributedStringWithFontSize:FONT_SIZE]; + _photoLocationLabel.attributedText = [photo locationAttributedStringWithFontSize:FONT_SIZE]; - [UIImage downloadImageForURL:photo.URL completion:^(UIImage *image) { + NSURL *photoURLLoading = photo.URL; + [UIImage downloadImageForURL:photoURLLoading completion:^(UIImage *image) { + if (![photoURLLoading isEqual:_photoModel.URL]) { + return; + } _photoImageView.image = image; }]; - - [self downloadAndProcessUserAvatarForPhoto:photo]; - - //update location - _photoLocationLabel.attributedText = [photo locationAttributedStringWithFontSize:FONT_SIZE]; - [_photoLocationLabel sizeToFit]; - - dispatch_async(dispatch_get_main_queue(), ^{ - [self updateConstraints]; - [self setNeedsLayout]; - }); + + [self downloadAndProcessUserAvatar]; + + // Update active state of photo location label adjustment + [self setNeedsUpdateConstraints]; + [self setNeedsLayout]; } #pragma mark - Helper Methods -- (void)downloadAndProcessUserAvatarForPhoto:(PhotoModel *)photo +static NSURL *UserProfileURLForPhotoModel(PhotoModel *photoModel) { + return photoModel.ownerUserProfile != nil + ? photoModel.ownerUserProfile.userPicURL + : photoModel.URL; +} + +- (void)downloadAndProcessUserAvatar { - [UIImage downloadImageForURL:photo.URL completion:^(UIImage *image) { + NSURL *userProfileURL = UserProfileURLForPhotoModel(_photoModel); + + [UIImage downloadImageForURL:userProfileURL completion:^(UIImage *image) { + if (![userProfileURL isEqual:UserProfileURLForPhotoModel(_photoModel)]) { + return; + } + CGSize profileImageSize = CGSizeMake(USER_IMAGE_HEIGHT, USER_IMAGE_HEIGHT); - _userAvatarImageView.image = [image makeCircularImageWithSize:profileImageSize]; + _userAvatarImageView.image = [image makeCircularImageWithSize:profileImageSize backgroundColor:[UIColor backgroundColor]]; }]; } diff --git a/examples/ASDKgram/Sample/Utilities.h b/examples/ASDKgram/Sample/Utilities.h index 63f2ab055..803f6a62f 100644 --- a/examples/ASDKgram/Sample/Utilities.h +++ b/examples/ASDKgram/Sample/Utilities.h @@ -9,6 +9,7 @@ @interface UIColor (Additions) ++ (UIColor *)backgroundColor; + (UIColor *)darkBlueColor; + (UIColor *)lightBlueColor; @@ -16,10 +17,8 @@ @interface UIImage (Additions) -+ (UIImage *)followingButtonStretchableImageForCornerRadius:(CGFloat)cornerRadius following:(BOOL)followingEnabled; + (void)downloadImageForURL:(NSURL *)url completion:(void (^)(UIImage *))block; - -- (UIImage *)makeCircularImageWithSize:(CGSize)size; +- (UIImage *)makeCircularImageWithSize:(CGSize)size backgroundColor:(nullable UIColor *)backgroundColor; @end diff --git a/examples/ASDKgram/Sample/Utilities.m b/examples/ASDKgram/Sample/Utilities.m index 732c5f817..008a3c284 100644 --- a/examples/ASDKgram/Sample/Utilities.m +++ b/examples/ASDKgram/Sample/Utilities.m @@ -92,6 +92,11 @@ static time_t parseRfc3339ToTimeT(const char *string) @implementation UIColor (Additions) ++ (UIColor *)backgroundColor +{ + return [UIColor whiteColor]; +} + + (UIColor *)darkBlueColor { return [UIColor colorWithRed:70.0/255.0 green:102.0/255.0 blue:118.0/255.0 alpha:1.0]; @@ -106,55 +111,20 @@ + (UIColor *)lightBlueColor @implementation UIImage (Additions) -+ (UIImage *)followingButtonStretchableImageForCornerRadius:(CGFloat)cornerRadius following:(BOOL)followingEnabled ++ (void)downloadImageForURL:(NSURL *)url completion:(void (^)(UIImage *))block { - CGSize unstretchedSize = CGSizeMake(2 * cornerRadius + 1, 2 * cornerRadius + 1); - CGRect rect = (CGRect) {CGPointZero, unstretchedSize}; - UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:cornerRadius]; - - // create a graphics context for the following status button - UIGraphicsBeginImageContextWithOptions(unstretchedSize, NO, 0); - - [path addClip]; - - if (followingEnabled) { - - [[UIColor whiteColor] setFill]; - [path fill]; - - path.lineWidth = 3; - [[UIColor lightBlueColor] setStroke]; - [path stroke]; - - } else { - - [[UIColor lightBlueColor] setFill]; - [path fill]; + if (!block) { + return; } - - UIImage *followingBtnImage = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - - UIImage *followingBtnImageStretchable = [followingBtnImage stretchableImageWithLeftCapWidth:cornerRadius - topCapHeight:cornerRadius]; - return followingBtnImageStretchable; -} -+ (void)downloadImageForURL:(NSURL *)url completion:(void (^)(UIImage *))block -{ - static NSCache *simpleImageCache = nil; + static NSCache *cache = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ - simpleImageCache = [[NSCache alloc] init]; - simpleImageCache.countLimit = 10; + cache = [[NSCache alloc] init]; }); - - if (!block) { - return; - } - + // check if image is cached - UIImage *image = [simpleImageCache objectForKey:url]; + UIImage *image = [cache objectForKey:url]; if (image) { dispatch_async(dispatch_get_main_queue(), ^{ block(image); @@ -165,6 +135,7 @@ + (void)downloadImageForURL:(NSURL *)url completion:(void (^)(UIImage *))block NSURLSessionDataTask *task = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { if (data) { UIImage *image = [UIImage imageWithData:data]; + [cache setObject:image forKey:url]; dispatch_async(dispatch_get_main_queue(), ^{ block(image); }); @@ -174,13 +145,19 @@ + (void)downloadImageForURL:(NSURL *)url completion:(void (^)(UIImage *))block } } -- (UIImage *)makeCircularImageWithSize:(CGSize)size +- (UIImage *)makeCircularImageWithSize:(CGSize)size backgroundColor:(UIColor *)backgroundColor { // make a CGRect with the image's size CGRect circleRect = (CGRect) {CGPointZero, size}; // begin the image context since we're not in a drawRect: - UIGraphicsBeginImageContextWithOptions(circleRect.size, NO, 0); + UIGraphicsBeginImageContextWithOptions(circleRect.size, backgroundColor != nil, 0); + + // Draw background color for opaqueness + if (backgroundColor) { + [backgroundColor set]; + UIRectFill(circleRect); + } // create a UIBezierPath circle UIBezierPath *circle = [UIBezierPath bezierPathWithRoundedRect:circleRect cornerRadius:circleRect.size.width/2];