mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-09-06 04:32:06 +00:00
Update to unsplash (#938)
* Switch photos from 500px to Unsplash * Good bye comment view :( * Update license headers
This commit is contained in:
parent
8b890f07be
commit
9ccba7fe74
@ -14,12 +14,7 @@
|
||||
767A5F111CAA3BFE004CDA8D /* tabBarIcons in Resources */ = {isa = PBXBuildFile; fileRef = 767A5F101CAA3BFE004CDA8D /* tabBarIcons */; };
|
||||
767A5F131CAA3C66004CDA8D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 767A5F121CAA3C66004CDA8D /* Assets.xcassets */; };
|
||||
768843801CAA37EF00D8629E /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 768843681CAA37EF00D8629E /* AppDelegate.m */; };
|
||||
768843811CAA37EF00D8629E /* CommentFeedModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 768843691CAA37EF00D8629E /* CommentFeedModel.m */; };
|
||||
768843821CAA37EF00D8629E /* CommentModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 7688436A1CAA37EF00D8629E /* CommentModel.m */; };
|
||||
768843831CAA37EF00D8629E /* CommentsNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 7688436B1CAA37EF00D8629E /* CommentsNode.m */; };
|
||||
768843841CAA37EF00D8629E /* CommentView.m in Sources */ = {isa = PBXBuildFile; fileRef = 7688436C1CAA37EF00D8629E /* CommentView.m */; };
|
||||
768843851CAA37EF00D8629E /* ImageURLModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 7688436D1CAA37EF00D8629E /* ImageURLModel.m */; };
|
||||
768843881CAA37EF00D8629E /* LocationModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 768843701CAA37EF00D8629E /* LocationModel.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 */; };
|
||||
@ -52,12 +47,7 @@
|
||||
767A5F101CAA3BFE004CDA8D /* tabBarIcons */ = {isa = PBXFileReference; lastKnownFileType = folder; path = tabBarIcons; sourceTree = "<group>"; };
|
||||
767A5F121CAA3C66004CDA8D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
768843511CAA37EF00D8629E /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = AppDelegate.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
|
||||
768843521CAA37EF00D8629E /* CommentFeedModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = CommentFeedModel.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
|
||||
768843531CAA37EF00D8629E /* CommentModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = CommentModel.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
|
||||
768843541CAA37EF00D8629E /* CommentsNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = CommentsNode.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
|
||||
768843551CAA37EF00D8629E /* CommentView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = CommentView.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
|
||||
768843561CAA37EF00D8629E /* ImageURLModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = ImageURLModel.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
|
||||
768843591CAA37EF00D8629E /* LocationModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = LocationModel.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
|
||||
7688435B1CAA37EF00D8629E /* PhotoCellNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = PhotoCellNode.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
|
||||
7688435C1CAA37EF00D8629E /* PhotoCollectionViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = PhotoCollectionViewCell.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
|
||||
7688435D1CAA37EF00D8629E /* PhotoFeedModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = PhotoFeedModel.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
|
||||
@ -69,12 +59,7 @@
|
||||
768843661CAA37EF00D8629E /* Utilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = Utilities.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
|
||||
768843671CAA37EF00D8629E /* Sample.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = Sample.pch; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
||||
768843681CAA37EF00D8629E /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = AppDelegate.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
||||
768843691CAA37EF00D8629E /* CommentFeedModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = CommentFeedModel.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
||||
7688436A1CAA37EF00D8629E /* CommentModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = CommentModel.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
||||
7688436B1CAA37EF00D8629E /* CommentsNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = CommentsNode.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
||||
7688436C1CAA37EF00D8629E /* CommentView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = CommentView.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
||||
7688436D1CAA37EF00D8629E /* ImageURLModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ImageURLModel.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
||||
768843701CAA37EF00D8629E /* LocationModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = LocationModel.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
||||
768843711CAA37EF00D8629E /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = main.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
||||
768843731CAA37EF00D8629E /* PhotoCellNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = PhotoCellNode.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
||||
768843741CAA37EF00D8629E /* PhotoCollectionViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = PhotoCollectionViewCell.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
||||
@ -227,14 +212,8 @@
|
||||
768843781CAA37EF00D8629E /* PhotoModel.m */,
|
||||
768843561CAA37EF00D8629E /* ImageURLModel.h */,
|
||||
7688436D1CAA37EF00D8629E /* ImageURLModel.m */,
|
||||
768843521CAA37EF00D8629E /* CommentFeedModel.h */,
|
||||
768843691CAA37EF00D8629E /* CommentFeedModel.m */,
|
||||
768843531CAA37EF00D8629E /* CommentModel.h */,
|
||||
7688436A1CAA37EF00D8629E /* CommentModel.m */,
|
||||
768843631CAA37EF00D8629E /* UserModel.h */,
|
||||
7688437B1CAA37EF00D8629E /* UserModel.m */,
|
||||
768843591CAA37EF00D8629E /* LocationModel.h */,
|
||||
768843701CAA37EF00D8629E /* LocationModel.m */,
|
||||
768843661CAA37EF00D8629E /* Utilities.h */,
|
||||
7688437E1CAA37EF00D8629E /* Utilities.m */,
|
||||
);
|
||||
@ -257,8 +236,6 @@
|
||||
768843791CAA37EF00D8629E /* PhotoTableViewCell.m */,
|
||||
7688435C1CAA37EF00D8629E /* PhotoCollectionViewCell.h */,
|
||||
768843741CAA37EF00D8629E /* PhotoCollectionViewCell.m */,
|
||||
768843551CAA37EF00D8629E /* CommentView.h */,
|
||||
7688436C1CAA37EF00D8629E /* CommentView.m */,
|
||||
);
|
||||
name = UIKit;
|
||||
sourceTree = "<group>";
|
||||
@ -272,8 +249,6 @@
|
||||
CC6350BA1E1C482D002BC613 /* TailLoadingNode.m */,
|
||||
7688435B1CAA37EF00D8629E /* PhotoCellNode.h */,
|
||||
768843731CAA37EF00D8629E /* PhotoCellNode.m */,
|
||||
768843541CAA37EF00D8629E /* CommentsNode.h */,
|
||||
7688436B1CAA37EF00D8629E /* CommentsNode.m */,
|
||||
);
|
||||
name = ASDK;
|
||||
sourceTree = "<group>";
|
||||
@ -393,7 +368,7 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
F012A6F39E0149F18F564F50 /* [CP] Copy Pods Resources */ = {
|
||||
@ -422,20 +397,15 @@
|
||||
7688438C1CAA37EF00D8629E /* PhotoCollectionViewCell.m in Sources */,
|
||||
768843921CAA37EF00D8629E /* PhotoFeedViewController.m in Sources */,
|
||||
76229A781CBB79E000B62CEF /* WindowWithStatusBarUnderlay.m in Sources */,
|
||||
768843821CAA37EF00D8629E /* CommentModel.m in Sources */,
|
||||
768843831CAA37EF00D8629E /* CommentsNode.m in Sources */,
|
||||
768843961CAA37EF00D8629E /* Utilities.m in Sources */,
|
||||
E5F128F01E09625400B4335F /* PhotoFeedBaseController.m in Sources */,
|
||||
768843931CAA37EF00D8629E /* UserModel.m in Sources */,
|
||||
CC5532171E15CC1E0011C01F /* ASCollectionSectionController.m in Sources */,
|
||||
768843801CAA37EF00D8629E /* AppDelegate.m in Sources */,
|
||||
768843811CAA37EF00D8629E /* CommentFeedModel.m in Sources */,
|
||||
CCEDDDD7200C4C0E00FFCD0A /* TextureConfigDelegate.m in Sources */,
|
||||
7688438E1CAA37EF00D8629E /* PhotoFeedNodeController.m in Sources */,
|
||||
CC6350BB1E1C482D002BC613 /* TailLoadingNode.m in Sources */,
|
||||
CC85250F1E36B392008EABE6 /* FeedHeaderNode.m in Sources */,
|
||||
768843841CAA37EF00D8629E /* CommentView.m in Sources */,
|
||||
768843881CAA37EF00D8629E /* LocationModel.m in Sources */,
|
||||
768843901CAA37EF00D8629E /* PhotoModel.m in Sources */,
|
||||
768843911CAA37EF00D8629E /* PhotoTableViewCell.m in Sources */,
|
||||
CC00D1571E15912F004E5502 /* PhotoFeedListKitViewController.m in Sources */,
|
||||
|
@ -1,37 +0,0 @@
|
||||
//
|
||||
// CommentFeedModel.h
|
||||
// Sample
|
||||
//
|
||||
// Created by Hannah Troisi on 3/9/16.
|
||||
//
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
#import "CommentModel.h"
|
||||
|
||||
@interface CommentFeedModel : NSObject
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
- (instancetype)initWithPhotoID:(NSString *)photoID NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
- (NSUInteger)numberOfItemsInFeed;
|
||||
- (CommentModel *)objectAtIndex:(NSUInteger)index;
|
||||
|
||||
- (NSUInteger)numberOfCommentsForPhoto;
|
||||
- (BOOL)numberOfCommentsForPhotoExceedsInteger:(NSUInteger)number;
|
||||
- (NSAttributedString *)viewAllCommentsAttributedString;
|
||||
|
||||
- (void)requestPageWithCompletionBlock:(void (^)(NSArray *))block;
|
||||
- (void)refreshFeedWithCompletionBlock:(void (^)(NSArray *))block;
|
||||
|
||||
@end
|
@ -1,206 +0,0 @@
|
||||
//
|
||||
// CommentFeedModel.m
|
||||
// Sample
|
||||
//
|
||||
// Created by Hannah Troisi on 3/9/16.
|
||||
//
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
#import "CommentFeedModel.h"
|
||||
#import "Utilities.h"
|
||||
|
||||
#define NUM_COMMENTS_TO_SHOW 3
|
||||
|
||||
#define fiveHundredPX_ENDPOINT_HOST @"https://api.500px.com/v1/"
|
||||
#define fiveHundredPX_ENDPOINT_COMMENTS @"photos/4928401/comments"
|
||||
#define fiveHundredPX_ENDPOINT_SEARCH @"photos/search?geo=" //latitude,longitude,radius<units>
|
||||
#define fiveHundredPX_ENDPOINT_USER @"photos?user_id="
|
||||
#define fiveHundredPX_CONSUMER_KEY_PARAM @"&consumer_key=Fi13GVb8g53sGvHICzlram7QkKOlSDmAmp9s9aqC"
|
||||
|
||||
@implementation CommentFeedModel
|
||||
{
|
||||
NSMutableArray *_comments; // array of CommentModel objects
|
||||
|
||||
NSString *_photoID;
|
||||
NSString *_urlString;
|
||||
NSUInteger _currentPage;
|
||||
NSUInteger _totalPages;
|
||||
NSUInteger _totalItems;
|
||||
|
||||
BOOL _fetchPageInProgress;
|
||||
BOOL _refreshFeedInProgress;
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
|
||||
- (NSMutableArray *)comments
|
||||
{
|
||||
return _comments;
|
||||
}
|
||||
|
||||
#pragma mark - Lifecycle
|
||||
|
||||
- (instancetype)initWithPhotoID:(NSString *)photoID
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self) {
|
||||
_photoID = photoID;
|
||||
_currentPage = 0;
|
||||
_totalPages = 0;
|
||||
_totalItems = 0;
|
||||
_comments = [[NSMutableArray alloc] init];
|
||||
_urlString = [NSString stringWithFormat:@"https://api.500px.com/v1/photos/%@/comments?",photoID];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Instance Methods
|
||||
|
||||
- (NSUInteger)numberOfItemsInFeed
|
||||
{
|
||||
return [_comments count];
|
||||
}
|
||||
|
||||
- (CommentModel *)objectAtIndex:(NSUInteger)index
|
||||
{
|
||||
return [_comments objectAtIndex:index];
|
||||
}
|
||||
|
||||
- (NSUInteger)numberOfCommentsForPhoto
|
||||
{
|
||||
return _totalItems;
|
||||
}
|
||||
|
||||
- (BOOL)numberOfCommentsForPhotoExceedsInteger:(NSUInteger)number
|
||||
{
|
||||
return (_totalItems > number);
|
||||
}
|
||||
|
||||
- (NSAttributedString *)viewAllCommentsAttributedString
|
||||
{
|
||||
NSString *string = [NSString stringWithFormat:@"View all %@ comments", [NSNumber numberWithUnsignedInteger:_totalItems]];
|
||||
NSAttributedString *attrString = [NSAttributedString attributedStringWithString:string fontSize:14 color:[UIColor lightGrayColor] firstWordColor:nil];
|
||||
return attrString;
|
||||
}
|
||||
|
||||
- (void)requestPageWithCompletionBlock:(void (^)(NSArray *))block
|
||||
{
|
||||
// only one fetch at a time
|
||||
if (_fetchPageInProgress) {
|
||||
return;
|
||||
} else {
|
||||
_fetchPageInProgress = YES;
|
||||
[self fetchPageWithCompletionBlock:block];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)refreshFeedWithCompletionBlock:(void (^)(NSArray *))block
|
||||
{
|
||||
// only one fetch at a time
|
||||
if (_refreshFeedInProgress) {
|
||||
return;
|
||||
} else {
|
||||
_refreshFeedInProgress = YES;
|
||||
_currentPage = 0;
|
||||
|
||||
// FIXME: blow away any other requests in progress
|
||||
|
||||
[self fetchPageWithCompletionBlock:^(NSArray *newPhotos) {
|
||||
if (block) {
|
||||
block(newPhotos);
|
||||
}
|
||||
_refreshFeedInProgress = NO;
|
||||
} replaceData:YES];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Helper Methods
|
||||
- (void)fetchPageWithCompletionBlock:(void (^)(NSArray *))block
|
||||
{
|
||||
[self fetchPageWithCompletionBlock:block replaceData:NO];
|
||||
}
|
||||
|
||||
- (void)fetchPageWithCompletionBlock:(void (^)(NSArray *))block replaceData:(BOOL)replaceData
|
||||
{
|
||||
// early return if reached end of pages
|
||||
if (_totalPages) {
|
||||
if (_currentPage == _totalPages) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
|
||||
NSMutableArray *newComments = [NSMutableArray array];
|
||||
|
||||
NSUInteger nextPage = _currentPage + 1;
|
||||
|
||||
NSString *urlAdditions = [NSString stringWithFormat:@"page=%lu", (unsigned long)nextPage];
|
||||
NSURL *url = [NSURL URLWithString:[_urlString stringByAppendingString:urlAdditions]];
|
||||
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration]];
|
||||
NSURLSessionDataTask *task = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||
|
||||
if (data) {
|
||||
|
||||
NSDictionary *response = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
|
||||
|
||||
if ([response isKindOfClass:[NSDictionary class]]) {
|
||||
|
||||
_currentPage = [[response valueForKeyPath:@"current_page"] integerValue];
|
||||
_totalPages = [[response valueForKeyPath:@"total_pages"] integerValue];
|
||||
_totalItems = [[response valueForKeyPath:@"total_items"] integerValue];
|
||||
|
||||
NSArray *comments = [response valueForKeyPath:@"comments"];
|
||||
|
||||
if ([comments isKindOfClass:[NSArray class]]) {
|
||||
|
||||
NSUInteger numComments = [comments count];
|
||||
if (numComments > NUM_COMMENTS_TO_SHOW) {
|
||||
comments = [comments subarrayWithRange:(NSRange){numComments-NUM_COMMENTS_TO_SHOW, NUM_COMMENTS_TO_SHOW}];
|
||||
}
|
||||
|
||||
for (NSDictionary *commentDictionary in comments) {
|
||||
|
||||
if ([response isKindOfClass:[NSDictionary class]]) {
|
||||
|
||||
CommentModel *comment = [[CommentModel alloc] initWithDictionary:commentDictionary];
|
||||
|
||||
if (comment) {
|
||||
[newComments addObject:comment];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
_fetchPageInProgress = NO;
|
||||
if (replaceData) {
|
||||
_comments = [newComments mutableCopy];
|
||||
} else {
|
||||
[_comments addObjectsFromArray:newComments];
|
||||
}
|
||||
if (block) {
|
||||
block(newComments);
|
||||
}
|
||||
});
|
||||
}];
|
||||
[task resume];
|
||||
});
|
||||
}
|
||||
|
||||
@end
|
@ -1,35 +0,0 @@
|
||||
//
|
||||
// CommentModel.h
|
||||
// Sample
|
||||
//
|
||||
// Created by Hannah Troisi on 3/9/16.
|
||||
//
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
@interface CommentModel : NSObject
|
||||
|
||||
@property (nonatomic, assign, readonly) NSUInteger ID;
|
||||
@property (nonatomic, assign, readonly) NSUInteger commenterID;
|
||||
@property (nonatomic, strong, readonly) NSString *commenterUsername;
|
||||
@property (nonatomic, strong, readonly) NSString *commenterAvatarURL;
|
||||
@property (nonatomic, strong, readonly) NSString *body;
|
||||
@property (nonatomic, strong, readonly) NSString *uploadDateString;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
- (instancetype)initWithDictionary:(NSDictionary *)photoDictionary NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
- (NSAttributedString *)commentAttributedString;
|
||||
- (NSAttributedString *)uploadDateAttributedStringWithFontSize:(CGFloat)size;
|
||||
|
||||
@end
|
@ -1,62 +0,0 @@
|
||||
//
|
||||
// CommentModel.m
|
||||
// Sample
|
||||
//
|
||||
// Created by Hannah Troisi on 3/9/16.
|
||||
//
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
#import "CommentModel.h"
|
||||
#import "Utilities.h"
|
||||
|
||||
@implementation CommentModel
|
||||
{
|
||||
NSDictionary *_dictionaryRepresentation;
|
||||
NSString *_uploadDateRaw;
|
||||
}
|
||||
|
||||
#pragma mark - Lifecycle
|
||||
|
||||
- (instancetype)initWithDictionary:(NSDictionary *)photoDictionary
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self) {
|
||||
_dictionaryRepresentation = photoDictionary;
|
||||
_ID = [[photoDictionary objectForKey:@"id"] integerValue];
|
||||
_commenterID = [[photoDictionary objectForKey:@"user_id"] integerValue];
|
||||
_commenterUsername = [photoDictionary valueForKeyPath:@"user.username"];
|
||||
_commenterAvatarURL = [photoDictionary valueForKeyPath:@"user.userpic_url"];
|
||||
_body = [photoDictionary objectForKey:@"body"];
|
||||
_uploadDateRaw = [photoDictionary valueForKeyPath:@"created_at"];
|
||||
_uploadDateString = [NSString elapsedTimeStringSinceDate:_uploadDateRaw];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Instance Methods
|
||||
|
||||
- (NSAttributedString *)commentAttributedString
|
||||
{
|
||||
NSString *commentString = [NSString stringWithFormat:@"%@ %@",[_commenterUsername lowercaseString], _body];
|
||||
return [NSAttributedString attributedStringWithString:commentString fontSize:14 color:[UIColor darkGrayColor] firstWordColor:[UIColor darkBlueColor]];
|
||||
}
|
||||
|
||||
- (NSAttributedString *)uploadDateAttributedStringWithFontSize:(CGFloat)size;
|
||||
{
|
||||
return [NSAttributedString attributedStringWithString:self.uploadDateString fontSize:size color:[UIColor lightGrayColor] firstWordColor:nil];
|
||||
}
|
||||
|
||||
@end
|
@ -1,28 +0,0 @@
|
||||
//
|
||||
// CommentView.h
|
||||
// Sample
|
||||
//
|
||||
// Created by Hannah Troisi on 3/9/16.
|
||||
//
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
#import "CommentFeedModel.h"
|
||||
|
||||
@interface CommentView : UIView
|
||||
|
||||
+ (CGFloat)heightForCommentFeedModel:(CommentFeedModel *)feed withWidth:(CGFloat)width;
|
||||
|
||||
- (void)updateWithCommentFeedModel:(CommentFeedModel *)feed;
|
||||
|
||||
@end
|
@ -1,149 +0,0 @@
|
||||
//
|
||||
// CommentView.m
|
||||
// Sample
|
||||
//
|
||||
// Created by Hannah Troisi on 3/9/16.
|
||||
//
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
#import "CommentView.h"
|
||||
#import "PhotoFeedModel.h"
|
||||
#import "Utilities.h"
|
||||
|
||||
#define INTER_COMMENT_SPACING 5
|
||||
#define NUM_COMMENTS_TO_SHOW 3
|
||||
|
||||
@implementation CommentView
|
||||
{
|
||||
CommentFeedModel *_commentFeed;
|
||||
NSMutableArray <UILabel *> *_commentLabels;
|
||||
}
|
||||
|
||||
#pragma mark - Class Methods
|
||||
|
||||
+ (CGFloat)heightForCommentFeedModel:(CommentFeedModel *)feed withWidth:(CGFloat)width
|
||||
{
|
||||
NSAttributedString *string;
|
||||
CGRect rect;
|
||||
CGFloat height = 0;
|
||||
|
||||
BOOL addViewAllCommentsLabel = [feed numberOfCommentsForPhotoExceedsInteger:NUM_COMMENTS_TO_SHOW];
|
||||
if (addViewAllCommentsLabel) {
|
||||
string = [feed viewAllCommentsAttributedString];
|
||||
rect = [string boundingRectWithSize:CGSizeMake(width, CGFLOAT_MAX)
|
||||
options:NSStringDrawingUsesLineFragmentOrigin
|
||||
context:nil];
|
||||
height += rect.size.height;
|
||||
}
|
||||
|
||||
NSUInteger numCommentsInFeed = [feed numberOfItemsInFeed];
|
||||
|
||||
for (int i = 0; i < numCommentsInFeed; i++) {
|
||||
|
||||
string = [[feed objectAtIndex:i] commentAttributedString];
|
||||
rect = [string boundingRectWithSize:CGSizeMake(width, CGFLOAT_MAX)
|
||||
options:NSStringDrawingUsesLineFragmentOrigin
|
||||
context:nil];
|
||||
height += rect.size.height + INTER_COMMENT_SPACING;
|
||||
}
|
||||
|
||||
return roundf(height);
|
||||
}
|
||||
|
||||
#pragma mark - Lifecycle
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_commentLabels = [[NSMutableArray alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
[super layoutSubviews];
|
||||
|
||||
CGSize boundsSize = self.bounds.size;
|
||||
CGRect rect = CGRectMake(0, 0, boundsSize.width, -INTER_COMMENT_SPACING);
|
||||
|
||||
for (UILabel *commentsLabel in _commentLabels) {
|
||||
rect.origin.y += rect.size.height + INTER_COMMENT_SPACING;
|
||||
rect.size = [commentsLabel sizeThatFits:CGSizeMake(boundsSize.width, CGFLOAT_MAX)];
|
||||
commentsLabel.frame = rect;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Instance Methods
|
||||
|
||||
- (void)updateWithCommentFeedModel:(CommentFeedModel *)feed
|
||||
{
|
||||
_commentFeed = feed;
|
||||
[self removeCommentLabels];
|
||||
|
||||
if (_commentFeed) {
|
||||
[self createCommentLabels];
|
||||
|
||||
BOOL addViewAllCommentsLabel = [feed numberOfCommentsForPhotoExceedsInteger:NUM_COMMENTS_TO_SHOW];
|
||||
NSAttributedString *commentLabelString;
|
||||
int labelsIndex = 0;
|
||||
|
||||
if (addViewAllCommentsLabel) {
|
||||
commentLabelString = [_commentFeed viewAllCommentsAttributedString];
|
||||
[[_commentLabels objectAtIndex:labelsIndex] setAttributedText:commentLabelString];
|
||||
labelsIndex++;
|
||||
}
|
||||
|
||||
NSUInteger numCommentsInFeed = [_commentFeed numberOfItemsInFeed];
|
||||
|
||||
for (int feedIndex = 0; feedIndex < numCommentsInFeed; feedIndex++) {
|
||||
commentLabelString = [[_commentFeed objectAtIndex:feedIndex] commentAttributedString];
|
||||
[[_commentLabels objectAtIndex:labelsIndex] setAttributedText:commentLabelString];
|
||||
labelsIndex++;
|
||||
}
|
||||
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Helper Methods
|
||||
|
||||
- (void)removeCommentLabels
|
||||
{
|
||||
for (UILabel *commentLabel in _commentLabels) {
|
||||
[commentLabel removeFromSuperview];
|
||||
}
|
||||
|
||||
[_commentLabels removeAllObjects];
|
||||
}
|
||||
|
||||
- (void)createCommentLabels
|
||||
{
|
||||
BOOL addViewAllCommentsLabel = [_commentFeed numberOfCommentsForPhotoExceedsInteger:NUM_COMMENTS_TO_SHOW];
|
||||
NSUInteger numCommentsInFeed = [_commentFeed numberOfItemsInFeed];
|
||||
|
||||
NSUInteger numLabelsToAdd = (addViewAllCommentsLabel) ? numCommentsInFeed + 1 : numCommentsInFeed;
|
||||
|
||||
for (NSUInteger i = 0; i < numLabelsToAdd; i++) {
|
||||
|
||||
UILabel *commentLabel = [[UILabel alloc] init];
|
||||
commentLabel.numberOfLines = 3;
|
||||
|
||||
[_commentLabels addObject:commentLabel];
|
||||
[self addSubview:commentLabel];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
@ -1,27 +0,0 @@
|
||||
//
|
||||
// CommentsNode.h
|
||||
// Sample
|
||||
//
|
||||
// Created by Hannah Troisi on 3/21/16.
|
||||
//
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
#import <AsyncDisplayKit/AsyncDisplayKit.h>
|
||||
#import "CommentFeedModel.h"
|
||||
|
||||
@interface CommentsNode : ASDisplayNode
|
||||
|
||||
- (void)updateWithCommentFeedModel:(CommentFeedModel *)feed;
|
||||
|
||||
@end
|
@ -1,106 +0,0 @@
|
||||
//
|
||||
// CommentsNode.m
|
||||
// Sample
|
||||
//
|
||||
// Created by Hannah Troisi on 3/21/16.
|
||||
//
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
#import "CommentsNode.h"
|
||||
|
||||
#define INTER_COMMENT_SPACING 5
|
||||
#define NUM_COMMENTS_TO_SHOW 3
|
||||
|
||||
@implementation CommentsNode
|
||||
{
|
||||
CommentFeedModel *_commentFeed;
|
||||
NSMutableArray <ASTextNode *> *_commentNodes;
|
||||
}
|
||||
|
||||
#pragma mark - Lifecycle
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.automaticallyManagesSubnodes = YES;
|
||||
|
||||
_commentNodes = [[NSMutableArray alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize
|
||||
{
|
||||
return [ASStackLayoutSpec
|
||||
stackLayoutSpecWithDirection:ASStackLayoutDirectionVertical
|
||||
spacing:INTER_COMMENT_SPACING
|
||||
justifyContent:ASStackLayoutJustifyContentStart
|
||||
alignItems:ASStackLayoutAlignItemsStretch
|
||||
children:[_commentNodes copy]];
|
||||
}
|
||||
|
||||
#pragma mark - Instance Methods
|
||||
|
||||
- (void)updateWithCommentFeedModel:(CommentFeedModel *)feed
|
||||
{
|
||||
_commentFeed = feed;
|
||||
[_commentNodes removeAllObjects];
|
||||
|
||||
if (_commentFeed) {
|
||||
[self createCommentLabels];
|
||||
|
||||
BOOL addViewAllCommentsLabel = [feed numberOfCommentsForPhotoExceedsInteger:NUM_COMMENTS_TO_SHOW];
|
||||
NSAttributedString *commentLabelString;
|
||||
int labelsIndex = 0;
|
||||
|
||||
if (addViewAllCommentsLabel) {
|
||||
commentLabelString = [_commentFeed viewAllCommentsAttributedString];
|
||||
[_commentNodes[labelsIndex] setAttributedText:commentLabelString];
|
||||
labelsIndex++;
|
||||
}
|
||||
|
||||
NSUInteger numCommentsInFeed = [_commentFeed numberOfItemsInFeed];
|
||||
|
||||
for (int feedIndex = 0; feedIndex < numCommentsInFeed; feedIndex++) {
|
||||
commentLabelString = [[_commentFeed objectAtIndex:feedIndex] commentAttributedString];
|
||||
[_commentNodes[labelsIndex] setAttributedText:commentLabelString];
|
||||
labelsIndex++;
|
||||
}
|
||||
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Helper Methods
|
||||
|
||||
- (void)createCommentLabels
|
||||
{
|
||||
BOOL addViewAllCommentsLabel = [_commentFeed numberOfCommentsForPhotoExceedsInteger:NUM_COMMENTS_TO_SHOW];
|
||||
NSUInteger numCommentsInFeed = [_commentFeed numberOfItemsInFeed];
|
||||
|
||||
NSUInteger numLabelsToAdd = (addViewAllCommentsLabel) ? numCommentsInFeed + 1 : numCommentsInFeed;
|
||||
|
||||
for (NSUInteger i = 0; i < numLabelsToAdd; i++) {
|
||||
|
||||
ASTextNode *commentLabel = [[ASTextNode alloc] init];
|
||||
commentLabel.layerBacked = YES;
|
||||
commentLabel.maximumNumberOfLines = 3;
|
||||
|
||||
[_commentNodes addObject:commentLabel];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
@ -1,33 +0,0 @@
|
||||
//
|
||||
// LocationModel.h
|
||||
// Sample
|
||||
//
|
||||
// Created by Hannah Troisi on 2/26/16.
|
||||
//
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
#import "CoreLocation/CoreLocation.h"
|
||||
|
||||
@interface LocationModel : NSObject
|
||||
|
||||
@property (nonatomic, assign, readonly) CLLocationCoordinate2D coordinates;
|
||||
@property (nonatomic, strong, readonly) CLPlacemark *placemark;
|
||||
@property (nonatomic, strong, readonly) NSString *locationString;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
- (instancetype)initWith500pxPhoto:(NSDictionary *)dictionary NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
- (void)reverseGeocodedLocationWithCompletionBlock:(void (^)(LocationModel *))blockName;
|
||||
|
||||
@end
|
@ -1,146 +0,0 @@
|
||||
//
|
||||
// LocationModel.m
|
||||
// Sample
|
||||
//
|
||||
// Created by Hannah Troisi on 2/26/16.
|
||||
//
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
#import "LocationModel.h"
|
||||
#import <CoreLocation/CLGeocoder.h>
|
||||
|
||||
@implementation LocationModel
|
||||
{
|
||||
BOOL _placemarkFetchInProgress;
|
||||
void (^_placemarkCallbackBlock)(LocationModel *);
|
||||
}
|
||||
|
||||
#pragma mark - Lifecycle
|
||||
|
||||
- (nullable instancetype)initWith500pxPhoto:(NSDictionary *)dictionary
|
||||
{
|
||||
NSNumber *latitude = [dictionary objectForKey:@"latitude"];
|
||||
NSNumber *longitude = [dictionary objectForKey:@"longitude"];
|
||||
|
||||
// early return if location is "<null>"
|
||||
if (![latitude isKindOfClass:[NSNumber class]] || ![longitude isKindOfClass:[NSNumber class]]) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
self = [super init];
|
||||
|
||||
if (self) {
|
||||
// set coordiantes
|
||||
_coordinates = CLLocationCoordinate2DMake([latitude floatValue], [longitude floatValue]);
|
||||
|
||||
// get CLPlacemark with MKReverseGeocoder
|
||||
[self beginReverseGeocodingLocationFromCoordinates];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Instance Methods
|
||||
|
||||
// return location placemark if fetched, else set completion block for fetch finish
|
||||
- (void)reverseGeocodedLocationWithCompletionBlock:(void (^)(LocationModel *))blockName
|
||||
{
|
||||
if (_placemark) {
|
||||
|
||||
// call block if placemark already fetched
|
||||
if (blockName) {
|
||||
blockName(self);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// set placemark reverse geocoding completion block
|
||||
_placemarkCallbackBlock = blockName;
|
||||
|
||||
// if fetch not in progress, begin
|
||||
if (!_placemarkFetchInProgress) {
|
||||
|
||||
[self beginReverseGeocodingLocationFromCoordinates];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Helper Methods
|
||||
|
||||
- (void)beginReverseGeocodingLocationFromCoordinates
|
||||
{
|
||||
if (_placemarkFetchInProgress) {
|
||||
return;
|
||||
}
|
||||
_placemarkFetchInProgress = YES;
|
||||
|
||||
CLLocation *location = [[CLLocation alloc] initWithLatitude:_coordinates.latitude longitude:_coordinates.longitude];
|
||||
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
|
||||
|
||||
[geocoder reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
|
||||
|
||||
// completion handler gets called on main thread
|
||||
_placemark = [placemarks lastObject];
|
||||
_locationString = [self locationStringFromCLPlacemark];
|
||||
|
||||
// check if completion block set, call it - DO NOT CALL A NIL BLOCK!
|
||||
if (_placemarkCallbackBlock) {
|
||||
|
||||
// call the block with arguments
|
||||
_placemarkCallbackBlock(self);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (nullable NSString *)locationStringFromCLPlacemark
|
||||
{
|
||||
// early return if no location info
|
||||
if (!_placemark)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
// @property (nonatomic, readonly, copy, nullable) NSString *name; // eg. Apple Inc.
|
||||
// @property (nonatomic, readonly, copy, nullable) NSString *thoroughfare; // street name, eg. Infinite Loop
|
||||
// @property (nonatomic, readonly, copy, nullable) NSString *subThoroughfare; // eg. 1
|
||||
// @property (nonatomic, readonly, copy, nullable) NSString *locality; // city, eg. Cupertino
|
||||
// @property (nonatomic, readonly, copy, nullable) NSString *subLocality; // neighborhood, common name, eg. Mission District
|
||||
// @property (nonatomic, readonly, copy, nullable) NSString *administrativeArea; // state, eg. CA
|
||||
// @property (nonatomic, readonly, copy, nullable) NSString *subAdministrativeArea; // county, eg. Santa Clara
|
||||
// @property (nonatomic, readonly, copy, nullable) NSString *postalCode; // zip code, eg. 95014
|
||||
// @property (nonatomic, readonly, copy, nullable) NSString *ISOcountryCode; // eg. US
|
||||
// @property (nonatomic, readonly, copy, nullable) NSString *country; // eg. United States
|
||||
// @property (nonatomic, readonly, copy, nullable) NSString *inlandWater; // eg. Lake Tahoe
|
||||
// @property (nonatomic, readonly, copy, nullable) NSString *ocean; // eg. Pacific Ocean
|
||||
// @property (nonatomic, readonly, copy, nullable) NSArray<NSString *> *areasOfInterest; // eg. Golden Gate Park
|
||||
|
||||
NSString *locationString;
|
||||
|
||||
if (_placemark.inlandWater) {
|
||||
locationString = _placemark.inlandWater;
|
||||
} else if (_placemark.subLocality && _placemark.locality) {
|
||||
locationString = [NSString stringWithFormat:@"%@, %@", _placemark.subLocality, _placemark.locality];
|
||||
} else if (_placemark.administrativeArea && _placemark.subAdministrativeArea) {
|
||||
locationString = [NSString stringWithFormat:@"%@, %@", _placemark.subAdministrativeArea, _placemark.administrativeArea];
|
||||
} else if (_placemark.country) {
|
||||
locationString = _placemark.country;
|
||||
} else {
|
||||
locationString = @"ERROR";
|
||||
}
|
||||
|
||||
return locationString;
|
||||
}
|
||||
|
||||
@end
|
@ -1,23 +1,20 @@
|
||||
//
|
||||
// PhotoCellNode.h
|
||||
// Sample
|
||||
//
|
||||
// Created by Hannah Troisi on 2/17/16.
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
// LICENSE file in the /ASDK-Licenses directory of this source tree. An additional
|
||||
// grant of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// Modifications to this file made after 4/13/2017 are: Copyright (c) through the present,
|
||||
// Pinterest, Inc. Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import <CoreLocation/CLLocation.h>
|
||||
#import "PhotoModel.h"
|
||||
#import <AsyncDisplayKit/AsyncDisplayKit.h>
|
||||
#import "PhotoTableViewCell.h" // PhotoTableViewCellProtocol
|
||||
|
@ -1,20 +1,18 @@
|
||||
//
|
||||
// PhotoCellNode.m
|
||||
// Sample
|
||||
//
|
||||
// Created by Hannah Troisi on 2/17/16.
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
// LICENSE file in the /ASDK-Licenses directory of this source tree. An additional
|
||||
// grant of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// Modifications to this file made after 4/13/2017 are: Copyright (c) through the present,
|
||||
// Pinterest, Inc. Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import "PhotoCellNode.h"
|
||||
@ -23,7 +21,6 @@
|
||||
#import <AsyncDisplayKit/ASDisplayNode+Beta.h>
|
||||
|
||||
#import "Utilities.h"
|
||||
#import "CommentsNode.h"
|
||||
#import "PINImageView+PINRemoteImage.h"
|
||||
#import "PINButton+PINRemoteImage.h"
|
||||
|
||||
@ -50,7 +47,6 @@
|
||||
@implementation PhotoCellNode
|
||||
{
|
||||
PhotoModel *_photoModel;
|
||||
CommentsNode *_photoCommentsNode;
|
||||
ASNetworkImageNode *_userAvatarImageNode;
|
||||
ASNetworkImageNode *_photoImageNode;
|
||||
ASTextNode *_userNameLabel;
|
||||
@ -89,26 +85,13 @@
|
||||
|
||||
_photoLocationLabel = [[ASTextNode alloc] init];
|
||||
_photoLocationLabel.maximumNumberOfLines = 1;
|
||||
[photo.location reverseGeocodedLocationWithCompletionBlock:^(LocationModel *locationModel) {
|
||||
|
||||
// check and make sure this is still relevant for this cell (and not an old cell)
|
||||
// make sure to use _photoModel instance variable as photo may change when cell is reused,
|
||||
// where as local variable will never change
|
||||
if (locationModel == _photoModel.location) {
|
||||
_photoLocationLabel.attributedText = [photo locationAttributedStringWithFontSize:FONT_SIZE];
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
}];
|
||||
_photoLocationLabel.attributedText = [photo locationAttributedStringWithFontSize:FONT_SIZE];
|
||||
|
||||
_photoTimeIntervalSincePostLabel = [self createLayerBackedTextNodeWithString:[photo uploadDateAttributedStringWithFontSize:FONT_SIZE]];
|
||||
_photoLikesLabel = [self createLayerBackedTextNodeWithString:[photo likesAttributedStringWithFontSize:FONT_SIZE]];
|
||||
_photoDescriptionLabel = [self createLayerBackedTextNodeWithString:[photo descriptionAttributedStringWithFontSize:FONT_SIZE]];
|
||||
_photoDescriptionLabel.maximumNumberOfLines = 3;
|
||||
|
||||
_photoCommentsNode = [[CommentsNode alloc] init];
|
||||
|
||||
_photoCommentsNode.layerBacked = YES;
|
||||
|
||||
// instead of adding everything addSubnode:
|
||||
self.automaticallyManagesSubnodes = YES;
|
||||
|
||||
@ -175,7 +158,7 @@
|
||||
// Create the last stack before assembling everything: the Footer Stack contains the description and comments.
|
||||
ASStackLayoutSpec *footerStack = [ASStackLayoutSpec verticalStackLayoutSpec];
|
||||
footerStack.spacing = VERTICAL_BUFFER;
|
||||
footerStack.children = @[_photoLikesLabel, _photoDescriptionLabel, _photoCommentsNode];
|
||||
footerStack.children = @[_photoLikesLabel, _photoDescriptionLabel];
|
||||
|
||||
// Main Vertical Stack: contains header, large main photo with fixed aspect ratio, and footer.
|
||||
ASStackLayoutSpec *verticalStack = [ASStackLayoutSpec verticalStackLayoutSpec];
|
||||
@ -268,8 +251,7 @@
|
||||
alignItems:ASStackLayoutAlignItemsStretch
|
||||
children:@[
|
||||
_photoLikesLabel,
|
||||
_photoDescriptionLabel,
|
||||
_photoCommentsNode
|
||||
_photoDescriptionLabel
|
||||
]]
|
||||
]
|
||||
]];
|
||||
@ -282,10 +264,6 @@
|
||||
- (void)didEnterPreloadState
|
||||
{
|
||||
[super didEnterPreloadState];
|
||||
|
||||
[_photoModel.commentFeed refreshFeedWithCompletionBlock:^(NSArray *newComments) {
|
||||
[self loadCommentsForPhoto:_photoModel];
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Network Image Delegate
|
||||
@ -311,15 +289,6 @@
|
||||
return textNode;
|
||||
}
|
||||
|
||||
- (void)loadCommentsForPhoto:(PhotoModel *)photo
|
||||
{
|
||||
if (photo.commentFeed.numberOfItemsInFeed > 0) {
|
||||
[_photoCommentsNode updateWithCommentFeedModel:photo.commentFeed];
|
||||
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setupYogaLayoutIfNeeded
|
||||
{
|
||||
#if YOGA_LAYOUT
|
||||
|
@ -1,20 +1,18 @@
|
||||
//
|
||||
// PhotoFeedBaseController.h
|
||||
// Sample
|
||||
//
|
||||
// Created by Huy Nguyen on 20/12/16.
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
// LICENSE file in the /ASDK-Licenses directory of this source tree. An additional
|
||||
// grant of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// Modifications to this file made after 4/13/2017 are: Copyright (c) through the present,
|
||||
// Pinterest, Inc. Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import <AsyncDisplayKit/AsyncDisplayKit.h>
|
||||
@ -34,6 +32,5 @@
|
||||
#pragma mark - Subclasses must override these methods
|
||||
|
||||
- (void)loadPage;
|
||||
- (void)requestCommentsForPhotos:(NSArray *)newPhotos;
|
||||
|
||||
@end
|
||||
|
@ -1,21 +1,18 @@
|
||||
//
|
||||
// PhotoFeedBaseController.m
|
||||
// Sample
|
||||
//
|
||||
// Created by Huy Nguyen on 20/12/16.
|
||||
// Copyright © 2016 Facebook. All rights reserved.
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
// LICENSE file in the /ASDK-Licenses directory of this source tree. An additional
|
||||
// grant of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// Modifications to this file made after 4/13/2017 are: Copyright (c) through the present,
|
||||
// Pinterest, Inc. Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import "PhotoFeedBaseController.h"
|
||||
@ -60,7 +57,6 @@
|
||||
[_activityIndicatorView stopAnimating];
|
||||
|
||||
[self.tableView reloadData];
|
||||
[self requestCommentsForPhotos:newPhotos];
|
||||
|
||||
// immediately start second larger fetch
|
||||
[self loadPage];
|
||||
@ -116,9 +112,4 @@
|
||||
NSAssert(NO, @"Subclasses must override this method");
|
||||
}
|
||||
|
||||
- (void)requestCommentsForPhotos:(NSArray *)newPhotos
|
||||
{
|
||||
NSAssert(NO, @"Subclasses must override this method");
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -1,20 +1,18 @@
|
||||
//
|
||||
// PhotoFeedModel.h
|
||||
// Sample
|
||||
//
|
||||
// Created by Hannah Troisi on 2/28/16.
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
// LICENSE file in the /ASDK-Licenses directory of this source tree. An additional
|
||||
// grant of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// Modifications to this file made after 4/13/2017 are: Copyright (c) through the present,
|
||||
// Pinterest, Inc. Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import "PhotoModel.h"
|
||||
@ -38,7 +36,6 @@ typedef NS_ENUM(NSInteger, PhotoFeedModelType) {
|
||||
- (PhotoModel *)objectAtIndex:(NSUInteger)index;
|
||||
- (NSInteger)indexOfPhotoModel:(PhotoModel *)photoModel;
|
||||
|
||||
- (void)updatePhotoFeedModelTypeLocationCoordinates:(CLLocationCoordinate2D)coordinate radiusInMiles:(NSUInteger)radius;
|
||||
- (void)updatePhotoFeedModelTypeUserId:(NSUInteger)userID;
|
||||
|
||||
- (void)clearFeed;
|
||||
|
@ -18,11 +18,12 @@
|
||||
#import "PhotoFeedModel.h"
|
||||
#import "ImageURLModel.h"
|
||||
|
||||
#define fiveHundredPX_ENDPOINT_HOST @"https://api.500px.com/v1/"
|
||||
#define fiveHundredPX_ENDPOINT_POPULAR @"photos?feature=popular&exclude=Nude,People,Fashion&sort=rating&image_size=3&include_store=store_download&include_states=voted"
|
||||
#define fiveHundredPX_ENDPOINT_SEARCH @"photos/search?geo=" //latitude,longitude,radius<units>
|
||||
#define fiveHundredPX_ENDPOINT_USER @"photos?user_id="
|
||||
#define fiveHundredPX_CONSUMER_KEY_PARAM @"&consumer_key=Fi13GVb8g53sGvHICzlram7QkKOlSDmAmp9s9aqC" // PLEASE REQUEST YOUR OWN 500PX CONSUMER KEY
|
||||
#define unsplash_ENDPOINT_HOST @"https://api.unsplash.com/"
|
||||
#define unsplash_ENDPOINT_POPULAR @"photos?order_by=popular"
|
||||
#define unsplash_ENDPOINT_SEARCH @"photos/search?geo=" //latitude,longitude,radius<units>
|
||||
#define unsplash_ENDPOINT_USER @"photos?user_id="
|
||||
#define unsplash_CONSUMER_KEY_PARAM @"&client_id=3b99a69cee09770a4a0bbb870b437dbda53efb22f6f6de63714b71c4df7c9642" // PLEASE REQUEST YOUR OWN UNSPLASH CONSUMER KEY
|
||||
#define unsplash_IMAGES_PER_PAGE 30
|
||||
|
||||
@implementation PhotoFeedModel
|
||||
{
|
||||
@ -40,8 +41,6 @@
|
||||
BOOL _refreshFeedInProgress;
|
||||
NSURLSessionDataTask *_task;
|
||||
|
||||
CLLocationCoordinate2D _location;
|
||||
NSUInteger _locationRadius;
|
||||
NSUInteger _userID;
|
||||
}
|
||||
|
||||
@ -61,21 +60,21 @@
|
||||
NSString *apiEndpointString;
|
||||
switch (type) {
|
||||
case (PhotoFeedModelTypePopular):
|
||||
apiEndpointString = fiveHundredPX_ENDPOINT_POPULAR;
|
||||
apiEndpointString = unsplash_ENDPOINT_POPULAR;
|
||||
break;
|
||||
|
||||
case (PhotoFeedModelTypeLocation):
|
||||
apiEndpointString = fiveHundredPX_ENDPOINT_SEARCH;
|
||||
apiEndpointString = unsplash_ENDPOINT_SEARCH;
|
||||
break;
|
||||
|
||||
case (PhotoFeedModelTypeUserPhotos):
|
||||
apiEndpointString = fiveHundredPX_ENDPOINT_USER;
|
||||
apiEndpointString = unsplash_ENDPOINT_USER;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
_urlString = [[fiveHundredPX_ENDPOINT_HOST stringByAppendingString:apiEndpointString] stringByAppendingString:fiveHundredPX_CONSUMER_KEY_PARAM];
|
||||
_urlString = [[unsplash_ENDPOINT_HOST stringByAppendingString:apiEndpointString] stringByAppendingString:unsplash_CONSUMER_KEY_PARAM];
|
||||
}
|
||||
|
||||
return self;
|
||||
@ -108,24 +107,14 @@
|
||||
return [_photos indexOfObjectIdenticalTo:photoModel];
|
||||
}
|
||||
|
||||
- (void)updatePhotoFeedModelTypeLocationCoordinates:(CLLocationCoordinate2D)coordinate radiusInMiles:(NSUInteger)radius;
|
||||
{
|
||||
_location = coordinate;
|
||||
_locationRadius = radius;
|
||||
NSString *locationString = [NSString stringWithFormat:@"%f,%f,%lumi", coordinate.latitude, coordinate.longitude, (unsigned long)radius];
|
||||
|
||||
_urlString = [fiveHundredPX_ENDPOINT_HOST stringByAppendingString:fiveHundredPX_ENDPOINT_SEARCH];
|
||||
_urlString = [[_urlString stringByAppendingString:locationString] stringByAppendingString:fiveHundredPX_CONSUMER_KEY_PARAM];
|
||||
}
|
||||
|
||||
- (void)updatePhotoFeedModelTypeUserId:(NSUInteger)userID
|
||||
{
|
||||
_userID = userID;
|
||||
|
||||
NSString *userString = [NSString stringWithFormat:@"%lu", (long)userID];
|
||||
_urlString = [fiveHundredPX_ENDPOINT_HOST stringByAppendingString:fiveHundredPX_ENDPOINT_USER];
|
||||
_urlString = [unsplash_ENDPOINT_HOST stringByAppendingString:unsplash_ENDPOINT_USER];
|
||||
_urlString = [[_urlString stringByAppendingString:userString] stringByAppendingString:@"&sort=created_at&image_size=3&include_store=store_download&include_states=voted"];
|
||||
_urlString = [_urlString stringByAppendingString:fiveHundredPX_CONSUMER_KEY_PARAM];
|
||||
_urlString = [_urlString stringByAppendingString:unsplash_CONSUMER_KEY_PARAM];
|
||||
}
|
||||
|
||||
- (void)clearFeed
|
||||
@ -191,7 +180,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
NSUInteger numPhotos = (numResults < 100) ? numResults : 100;
|
||||
NSUInteger numPhotos = (numResults < unsplash_IMAGES_PER_PAGE) ? numResults : unsplash_IMAGES_PER_PAGE;
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
NSMutableArray *newPhotos = [NSMutableArray array];
|
||||
@ -200,23 +189,28 @@
|
||||
@synchronized(self) {
|
||||
NSUInteger nextPage = _currentPage + 1;
|
||||
NSString *imageSizeParam = [ImageURLModel imageParameterForClosestImageSize:_imageSize];
|
||||
NSString *urlAdditions = [NSString stringWithFormat:@"&page=%lu&rpp=%lu%@", (unsigned long)nextPage, (long)numPhotos, imageSizeParam];
|
||||
NSString *urlAdditions = [NSString stringWithFormat:@"&page=%lu&per_page=%lu%@", (unsigned long)nextPage, (long)numPhotos, imageSizeParam];
|
||||
NSURL *url = [NSURL URLWithString:[_urlString stringByAppendingString:urlAdditions]];
|
||||
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration]];
|
||||
_task = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||
if (data) {
|
||||
NSDictionary *response = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
|
||||
@synchronized(self) {
|
||||
NSHTTPURLResponse *httpResponse = nil;
|
||||
if (data && [response isKindOfClass:[NSHTTPURLResponse class]]) {
|
||||
httpResponse = (NSHTTPURLResponse *)response;
|
||||
NSArray *objects = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
|
||||
|
||||
if ([response isKindOfClass:[NSDictionary class]]) {
|
||||
_currentPage = [[response valueForKeyPath:@"current_page"] integerValue];
|
||||
_totalPages = [[response valueForKeyPath:@"total_pages"] integerValue];
|
||||
_totalItems = [[response valueForKeyPath:@"total_items"] integerValue];
|
||||
if ([objects isKindOfClass:[NSArray class]]) {
|
||||
_currentPage = nextPage;
|
||||
_totalItems = [[httpResponse allHeaderFields][@"x-total"] integerValue];
|
||||
_totalPages = _totalItems / unsplash_IMAGES_PER_PAGE; // default per page is 10
|
||||
if (_totalItems % unsplash_IMAGES_PER_PAGE != 0) {
|
||||
_totalPages += 1;
|
||||
}
|
||||
|
||||
NSArray *photos = [response valueForKeyPath:@"photos"];
|
||||
if ([photos isKindOfClass:[NSArray class]]) {
|
||||
NSArray *photos = objects;
|
||||
for (NSDictionary *photoDictionary in photos) {
|
||||
if ([response isKindOfClass:[NSDictionary class]]) {
|
||||
PhotoModel *photo = [[PhotoModel alloc] initWith500pxPhoto:photoDictionary];
|
||||
if ([photoDictionary isKindOfClass:[NSDictionary class]]) {
|
||||
PhotoModel *photo = [[PhotoModel alloc] initWithUnsplashPhoto:photoDictionary];
|
||||
if (photo) {
|
||||
if (replaceData || ![_ids containsObject:photo.photoID]) {
|
||||
[newPhotos addObject:photo];
|
||||
@ -228,18 +222,21 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (replaceData) {
|
||||
_photos = [newPhotos mutableCopy];
|
||||
_ids = [newIDs mutableCopy];
|
||||
} else {
|
||||
[_photos addObjectsFromArray:newPhotos];
|
||||
[_ids addObjectsFromArray:newIDs];
|
||||
@synchronized(self) {
|
||||
if (replaceData) {
|
||||
_photos = [newPhotos mutableCopy];
|
||||
_ids = [newIDs mutableCopy];
|
||||
} else {
|
||||
[_photos addObjectsFromArray:newPhotos];
|
||||
[_ids addObjectsFromArray:newIDs];
|
||||
}
|
||||
if (block) {
|
||||
block(newPhotos);
|
||||
}
|
||||
_fetchPageInProgress = NO;
|
||||
}
|
||||
if (block) {
|
||||
block(newPhotos);
|
||||
}
|
||||
_fetchPageInProgress = NO;
|
||||
});
|
||||
}];
|
||||
[_task resume];
|
||||
|
@ -66,7 +66,6 @@
|
||||
[self.photoFeed requestPageWithCompletionBlock:^(NSArray *newPhotos){
|
||||
|
||||
[self insertNewRows:newPhotos];
|
||||
[self requestCommentsForPhotos:newPhotos];
|
||||
if (context) {
|
||||
[context completeBatchFetching:YES];
|
||||
}
|
||||
@ -85,11 +84,6 @@
|
||||
[self loadPageWithContext:nil];
|
||||
}
|
||||
|
||||
- (void)requestCommentsForPhotos:(NSArray *)newPhotos
|
||||
{
|
||||
// Do nothing (#1530).
|
||||
}
|
||||
|
||||
#pragma mark - ASTableDataSource methods
|
||||
|
||||
- (NSInteger)tableNode:(ASTableNode *)tableNode numberOfRowsInSection:(NSInteger)section
|
||||
|
@ -1,27 +1,24 @@
|
||||
//
|
||||
// PhotoFeedViewController.m
|
||||
// Sample
|
||||
//
|
||||
// Created by Hannah Troisi on 2/17/16.
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
// LICENSE file in the /ASDK-Licenses directory of this source tree. An additional
|
||||
// grant of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// Modifications to this file made after 4/13/2017 are: Copyright (c) through the present,
|
||||
// Pinterest, Inc. Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import "PhotoFeedViewController.h"
|
||||
#import "Utilities.h"
|
||||
#import "PhotoTableViewCell.h"
|
||||
#import "PhotoFeedModel.h"
|
||||
#import "CommentView.h"
|
||||
|
||||
#define AUTO_TAIL_LOADING_NUM_SCREENFULS 2.5
|
||||
|
||||
@ -73,35 +70,9 @@
|
||||
{
|
||||
[self.photoFeed requestPageWithCompletionBlock:^(NSArray *newPhotos){
|
||||
[self insertNewRows:newPhotos];
|
||||
[self requestCommentsForPhotos:newPhotos];
|
||||
} numResultsToReturn:20];
|
||||
}
|
||||
|
||||
- (void)requestCommentsForPhotos:(NSArray *)newPhotos
|
||||
{
|
||||
for (PhotoModel *photo in newPhotos) {
|
||||
[photo.commentFeed refreshFeedWithCompletionBlock:^(NSArray *newComments) {
|
||||
|
||||
NSInteger rowNum = [self.photoFeed indexOfPhotoModel:photo];
|
||||
NSIndexPath *cellPath = [NSIndexPath indexPathForRow:rowNum inSection:0];
|
||||
PhotoTableViewCell *cell = [_tableView cellForRowAtIndexPath:cellPath];
|
||||
|
||||
if (cell) {
|
||||
[cell loadCommentsForPhoto:photo];
|
||||
[_tableView beginUpdates];
|
||||
[_tableView endUpdates];
|
||||
|
||||
// adjust scrollView contentOffset if inserting above visible cells
|
||||
NSIndexPath *visibleCellPath = [_tableView indexPathForCell:_tableView.visibleCells.firstObject];
|
||||
if (cellPath.row < visibleCellPath.row) {
|
||||
CGFloat commentViewHeight = [CommentView heightForCommentFeedModel:photo.commentFeed withWidth:self.view.bounds.size.width];
|
||||
_tableView.contentOffset = CGPointMake(_tableView.contentOffset.x, _tableView.contentOffset.y + commentViewHeight);
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - UITableViewDataSource methods
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
||||
|
@ -1,25 +1,21 @@
|
||||
//
|
||||
// PhotoModel.h
|
||||
// Sample
|
||||
//
|
||||
// Created by Hannah Troisi on 2/26/16.
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
// LICENSE file in the /ASDK-Licenses directory of this source tree. An additional
|
||||
// grant of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// Modifications to this file made after 4/13/2017 are: Copyright (c) through the present,
|
||||
// Pinterest, Inc. Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import "UserModel.h"
|
||||
#import "LocationModel.h"
|
||||
#import "CommentFeedModel.h"
|
||||
#import <IGListKit/IGListKit.h>
|
||||
|
||||
@interface PhotoModel : NSObject <IGListDiffable>
|
||||
@ -27,16 +23,15 @@
|
||||
@property (nonatomic, strong, readonly) NSURL *URL;
|
||||
@property (nonatomic, strong, readonly) NSString *photoID;
|
||||
@property (nonatomic, strong, readonly) NSString *uploadDateString;
|
||||
@property (nonatomic, strong, readonly) NSString *title;
|
||||
@property (nonatomic, strong, readonly) NSString *descriptionText;
|
||||
@property (nonatomic, assign, readonly) NSUInteger commentsCount;
|
||||
@property (nonatomic, assign, readonly) NSUInteger likesCount;
|
||||
@property (nonatomic, strong, readonly) LocationModel *location;
|
||||
@property (nonatomic, strong, readonly) NSString *location;
|
||||
@property (nonatomic, strong, readonly) UserModel *ownerUserProfile;
|
||||
@property (nonatomic, strong, readonly) CommentFeedModel *commentFeed;
|
||||
@property (nonatomic, assign, readonly) NSUInteger width;
|
||||
@property (nonatomic, assign, readonly) NSUInteger height;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
- (instancetype)initWith500pxPhoto:(NSDictionary *)photoDictionary NS_DESIGNATED_INITIALIZER;
|
||||
- (instancetype)initWithUnsplashPhoto:(NSDictionary *)photoDictionary NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
- (NSAttributedString *)descriptionAttributedStringWithFontSize:(CGFloat)size;
|
||||
- (NSAttributedString *)uploadDateAttributedStringWithFontSize:(CGFloat)size;
|
||||
|
@ -22,41 +22,30 @@
|
||||
{
|
||||
NSDictionary *_dictionaryRepresentation;
|
||||
NSString *_uploadDateRaw;
|
||||
CommentFeedModel *_commentFeed;
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
|
||||
- (CommentFeedModel *)commentFeed
|
||||
{
|
||||
if (!_commentFeed) {
|
||||
_commentFeed = [[CommentFeedModel alloc] initWithPhotoID:_photoID];
|
||||
}
|
||||
|
||||
return _commentFeed;
|
||||
}
|
||||
|
||||
#pragma mark - Lifecycle
|
||||
|
||||
- (instancetype)initWith500pxPhoto:(NSDictionary *)photoDictionary
|
||||
- (instancetype)initWithUnsplashPhoto:(NSDictionary *)photoDictionary
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self) {
|
||||
_dictionaryRepresentation = photoDictionary;
|
||||
_uploadDateRaw = [photoDictionary objectForKey:@"created_at"];
|
||||
_photoID = [[photoDictionary objectForKey:@"id"] description];
|
||||
_title = [photoDictionary objectForKey:@"title"];
|
||||
_descriptionText = [photoDictionary valueForKeyPath:@"name"];
|
||||
_commentsCount = [[photoDictionary objectForKey:@"comments_count"] integerValue];
|
||||
_likesCount = [[photoDictionary objectForKey:@"positive_votes_count"] integerValue];
|
||||
_photoID = [photoDictionary objectForKey:@"id"];
|
||||
_descriptionText = [photoDictionary valueForKeyPath:@"description"];
|
||||
_likesCount = [[photoDictionary objectForKey:@"likes"] integerValue];
|
||||
_location = [photoDictionary objectForKey:@"location"];
|
||||
|
||||
NSString *urlString = [[photoDictionary objectForKey:@"image_url"] firstObject];
|
||||
NSString *urlString = [photoDictionary objectForKey:@"urls"][@"regular"];
|
||||
_URL = urlString ? [NSURL URLWithString:urlString] : nil;
|
||||
|
||||
_location = [[LocationModel alloc] initWith500pxPhoto:photoDictionary];
|
||||
_ownerUserProfile = [[UserModel alloc] initWith500pxPhoto:photoDictionary];
|
||||
_ownerUserProfile = [[UserModel alloc] initWithUnsplashPhoto:photoDictionary];
|
||||
_uploadDateString = [NSString elapsedTimeStringSinceDate:_uploadDateRaw];
|
||||
|
||||
_height = [[photoDictionary objectForKey:@"height"] integerValue];
|
||||
_width = [[photoDictionary objectForKey:@"width"] integerValue];
|
||||
}
|
||||
|
||||
return self;
|
||||
@ -88,7 +77,7 @@
|
||||
|
||||
- (NSAttributedString *)locationAttributedStringWithFontSize:(CGFloat)size
|
||||
{
|
||||
return [NSAttributedString attributedStringWithString:self.location.locationString fontSize:size color:[UIColor lightBlueColor] firstWordColor:nil];
|
||||
return [NSAttributedString attributedStringWithString:self.location fontSize:size color:[UIColor lightBlueColor] firstWordColor:nil];
|
||||
}
|
||||
|
||||
- (NSString *)description
|
||||
|
@ -1,23 +1,20 @@
|
||||
//
|
||||
// PhotoTableViewCell.h
|
||||
// Sample
|
||||
//
|
||||
// Created by Hannah Troisi on 2/17/16.
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
// LICENSE file in the /ASDK-Licenses directory of this source tree. An additional
|
||||
// grant of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// Modifications to this file made after 4/13/2017 are: Copyright (c) through the present,
|
||||
// Pinterest, Inc. Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import <CoreLocation/CLLocation.h>
|
||||
#import "PhotoModel.h"
|
||||
|
||||
@interface PhotoTableViewCell : UITableViewCell
|
||||
@ -25,6 +22,5 @@
|
||||
+ (CGFloat)heightForPhotoModel:(PhotoModel *)photo withWidth:(CGFloat)width;
|
||||
|
||||
- (void)updateCellWithPhotoObject:(PhotoModel *)photo;
|
||||
- (void)loadCommentsForPhoto:(PhotoModel *)photo;
|
||||
|
||||
@end
|
||||
|
@ -1,27 +1,24 @@
|
||||
//
|
||||
// PhotoTableViewCell.m
|
||||
// Sample
|
||||
//
|
||||
// Created by Hannah Troisi on 2/17/16.
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
// LICENSE file in the /ASDK-Licenses directory of this source tree. An additional
|
||||
// grant of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// Modifications to this file made after 4/13/2017 are: Copyright (c) through the present,
|
||||
// Pinterest, Inc. Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import "PhotoTableViewCell.h"
|
||||
#import "Utilities.h"
|
||||
#import "PINImageView+PINRemoteImage.h"
|
||||
#import "PINButton+PINRemoteImage.h"
|
||||
#import "CommentView.h"
|
||||
|
||||
#define DEBUG_PHOTOCELL_LAYOUT 0
|
||||
#define USE_UIKIT_AUTOLAYOUT 1
|
||||
@ -36,7 +33,6 @@
|
||||
@implementation PhotoTableViewCell
|
||||
{
|
||||
PhotoModel *_photoModel;
|
||||
CommentView *_photoCommentsView;
|
||||
|
||||
UIImageView *_userAvatarImageView;
|
||||
UIImageView *_photoImageView;
|
||||
@ -66,9 +62,7 @@
|
||||
options:NSStringDrawingUsesLineFragmentOrigin
|
||||
context:nil].size.height;
|
||||
|
||||
CGFloat commentViewHeight = [CommentView heightForCommentFeedModel:photo.commentFeed withWidth:availableWidth];
|
||||
|
||||
return HEADER_HEIGHT + photoHeight + likesHeight + descriptionHeight + commentViewHeight + (4 * VERTICAL_BUFFER);
|
||||
return HEADER_HEIGHT + photoHeight + likesHeight + descriptionHeight + (4 * VERTICAL_BUFFER);
|
||||
}
|
||||
|
||||
#pragma mark - Lifecycle
|
||||
@ -78,10 +72,9 @@
|
||||
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
|
||||
|
||||
if (self) {
|
||||
|
||||
_photoCommentsView = [[CommentView alloc] init];
|
||||
_userAvatarImageView = [[UIImageView alloc] init];
|
||||
_photoImageView = [[UIImageView alloc] init];
|
||||
_photoImageView.contentMode = UIViewContentModeScaleAspectFill;
|
||||
_userNameLabel = [[UILabel alloc] init];
|
||||
_photoLocationLabel = [[UILabel alloc] init];
|
||||
_photoTimeIntervalSincePostLabel = [[UILabel alloc] init];
|
||||
@ -89,7 +82,6 @@
|
||||
_photoDescriptionLabel = [[UILabel alloc] init];
|
||||
_photoDescriptionLabel.numberOfLines = 3;
|
||||
|
||||
[self addSubview:_photoCommentsView];
|
||||
[self addSubview:_userAvatarImageView];
|
||||
[self addSubview:_photoImageView];
|
||||
[self addSubview:_userNameLabel];
|
||||
@ -99,7 +91,6 @@
|
||||
[self addSubview:_photoDescriptionLabel];
|
||||
|
||||
#if USE_UIKIT_AUTOLAYOUT
|
||||
[_photoCommentsView setTranslatesAutoresizingMaskIntoConstraints:NO];
|
||||
[_userAvatarImageView setTranslatesAutoresizingMaskIntoConstraints:NO];
|
||||
[_photoImageView setTranslatesAutoresizingMaskIntoConstraints:NO];
|
||||
[_userNameLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
|
||||
@ -107,7 +98,6 @@
|
||||
[_photoTimeIntervalSincePostLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
|
||||
[_photoLikesLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
|
||||
[_photoDescriptionLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
|
||||
[_photoCommentsView setTranslatesAutoresizingMaskIntoConstraints:NO];
|
||||
|
||||
[self setupConstraints];
|
||||
[self updateConstraints];
|
||||
@ -118,7 +108,6 @@
|
||||
_userNameLabel.backgroundColor = [UIColor greenColor];
|
||||
_photoLocationLabel.backgroundColor = [UIColor greenColor];
|
||||
_photoTimeIntervalSincePostLabel.backgroundColor = [UIColor greenColor];
|
||||
_photoCommentsView.backgroundColor = [UIColor greenColor];
|
||||
_photoDescriptionLabel.backgroundColor = [UIColor greenColor];
|
||||
_photoLikesLabel.backgroundColor = [UIColor greenColor];
|
||||
#endif
|
||||
@ -313,31 +302,6 @@
|
||||
attribute:NSLayoutAttributeWidth
|
||||
multiplier:1.0
|
||||
constant:-HORIZONTAL_BUFFER]];
|
||||
|
||||
// _photoCommentsView
|
||||
[self addConstraint:[NSLayoutConstraint constraintWithItem:_photoCommentsView
|
||||
attribute:NSLayoutAttributeTop
|
||||
relatedBy:NSLayoutRelationEqual
|
||||
toItem:_photoDescriptionLabel
|
||||
attribute:NSLayoutAttributeBottom
|
||||
multiplier:1.0
|
||||
constant:VERTICAL_BUFFER]];
|
||||
|
||||
[self addConstraint:[NSLayoutConstraint constraintWithItem:_photoCommentsView
|
||||
attribute:NSLayoutAttributeLeft
|
||||
relatedBy:NSLayoutRelationEqual
|
||||
toItem:_photoCommentsView.superview
|
||||
attribute:NSLayoutAttributeLeft
|
||||
multiplier:1.0
|
||||
constant:HORIZONTAL_BUFFER]];
|
||||
|
||||
[self addConstraint:[NSLayoutConstraint constraintWithItem:_photoCommentsView
|
||||
attribute:NSLayoutAttributeWidth
|
||||
relatedBy:NSLayoutRelationEqual
|
||||
toItem:_photoCommentsView.superview
|
||||
attribute:NSLayoutAttributeWidth
|
||||
multiplier:1.0
|
||||
constant:-HORIZONTAL_BUFFER]];
|
||||
}
|
||||
|
||||
- (void)updateConstraints
|
||||
@ -404,11 +368,6 @@
|
||||
rect.size.width = MIN(boundsSize.width - HORIZONTAL_BUFFER * 2, rect.size.width);
|
||||
rect.origin.y = CGRectGetMaxY(_photoLikesLabel.frame) + VERTICAL_BUFFER;
|
||||
_photoDescriptionLabel.frame = rect;
|
||||
|
||||
rect.size = _photoCommentsView.bounds.size;
|
||||
rect.size.width = boundsSize.width - HORIZONTAL_BUFFER * 2;
|
||||
rect.origin.y = CGRectGetMaxY(_photoDescriptionLabel.frame) + VERTICAL_BUFFER;
|
||||
_photoCommentsView.frame = rect;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -416,9 +375,6 @@
|
||||
{
|
||||
[super prepareForReuse];
|
||||
|
||||
_photoCommentsView.frame = CGRectZero; // next cell might not have a _photoCommentsView
|
||||
[_photoCommentsView updateWithCommentFeedModel:nil];
|
||||
|
||||
_userAvatarImageView.image = nil;
|
||||
_photoImageView.image = nil;
|
||||
_userNameLabel.attributedText = nil;
|
||||
@ -453,23 +409,15 @@
|
||||
}];
|
||||
|
||||
[self downloadAndProcessUserAvatarForPhoto:photo];
|
||||
[self loadCommentsForPhoto:photo];
|
||||
[self reverseGeocodeLocationForPhoto:photo];
|
||||
}
|
||||
|
||||
- (void)loadCommentsForPhoto:(PhotoModel *)photo
|
||||
{
|
||||
if (photo.commentFeed.numberOfItemsInFeed > 0) {
|
||||
[_photoCommentsView updateWithCommentFeedModel:photo.commentFeed];
|
||||
|
||||
CGRect frame = _photoCommentsView.frame;
|
||||
CGFloat availableWidth = (self.bounds.size.width - HORIZONTAL_BUFFER * 2);
|
||||
frame.size.width = availableWidth;
|
||||
frame.size.height = [CommentView heightForCommentFeedModel:photo.commentFeed withWidth:availableWidth];
|
||||
_photoCommentsView.frame = frame;
|
||||
//update location
|
||||
_photoLocationLabel.attributedText = [photo locationAttributedStringWithFontSize:FONT_SIZE];
|
||||
[_photoLocationLabel sizeToFit];
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self updateConstraints];
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark - Helper Methods
|
||||
@ -482,23 +430,4 @@
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)reverseGeocodeLocationForPhoto:(PhotoModel *)photo
|
||||
{
|
||||
[photo.location reverseGeocodedLocationWithCompletionBlock:^(LocationModel *locationModel) {
|
||||
|
||||
// check and make sure this is still relevant for this cell (and not an old cell)
|
||||
// make sure to use _photoModel instance variable as photo may change when cell is reused,
|
||||
// where as local variable will never change
|
||||
if (locationModel == _photoModel.location) {
|
||||
_photoLocationLabel.attributedText = [photo locationAttributedStringWithFontSize:FONT_SIZE];
|
||||
[_photoLocationLabel sizeToFit];
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self updateConstraints];
|
||||
[self setNeedsLayout];
|
||||
});
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -1,35 +1,30 @@
|
||||
//
|
||||
// UserModel.h
|
||||
// Sample
|
||||
//
|
||||
// Created by Hannah Troisi on 2/26/16.
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
// LICENSE file in the /ASDK-Licenses directory of this source tree. An additional
|
||||
// grant of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// Modifications to this file made after 4/13/2017 are: Copyright (c) through the present,
|
||||
// Pinterest, Inc. Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
@interface UserModel : NSObject
|
||||
|
||||
@property (nonatomic, strong, readonly) NSDictionary *dictionaryRepresentation;
|
||||
@property (nonatomic, assign, readonly) NSUInteger userID;
|
||||
@property (nonatomic, assign, readonly) NSString *userID;
|
||||
@property (nonatomic, strong, readonly) NSString *username;
|
||||
@property (nonatomic, strong, readonly) NSString *firstName;
|
||||
@property (nonatomic, strong, readonly) NSString *lastName;
|
||||
@property (nonatomic, strong, readonly) NSString *fullName;
|
||||
@property (nonatomic, strong, readonly) NSString *city;
|
||||
@property (nonatomic, strong, readonly) NSString *state;
|
||||
@property (nonatomic, strong, readonly) NSString *country;
|
||||
@property (nonatomic, strong, readonly) NSString *location;
|
||||
@property (nonatomic, strong, readonly) NSString *about;
|
||||
@property (nonatomic, strong, readonly) NSString *domain;
|
||||
@property (nonatomic, strong, readonly) NSURL *userPicURL;
|
||||
@property (nonatomic, assign, readonly) NSUInteger photoCount;
|
||||
@property (nonatomic, assign, readonly) NSUInteger galleriesCount;
|
||||
@ -39,7 +34,7 @@
|
||||
@property (nonatomic, assign, readonly) BOOL following;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
- (instancetype)initWith500pxPhoto:(NSDictionary *)dictionary NS_DESIGNATED_INITIALIZER;
|
||||
- (instancetype)initWithUnsplashPhoto:(NSDictionary *)dictionary NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
- (NSAttributedString *)usernameAttributedStringWithFontSize:(CGFloat)size;
|
||||
- (NSAttributedString *)fullNameAttributedStringWithFontSize:(CGFloat)size;
|
||||
|
@ -1,20 +1,18 @@
|
||||
//
|
||||
// UserModel.m
|
||||
// Sample
|
||||
//
|
||||
// Created by Hannah Troisi on 2/26/16.
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
// LICENSE file in the /ASDK-Licenses directory of this source tree. An additional
|
||||
// grant of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// Modifications to this file made after 4/13/2017 are: Copyright (c) through the present,
|
||||
// Pinterest, Inc. Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import "UserModel.h"
|
||||
@ -29,7 +27,7 @@
|
||||
|
||||
#pragma mark - Lifecycle
|
||||
|
||||
- (instancetype)initWith500pxPhoto:(NSDictionary *)dictionary
|
||||
- (instancetype)initWithUnsplashPhoto:(NSDictionary *)dictionary
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
@ -110,7 +108,7 @@
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
|
||||
// fetch JSON data from server
|
||||
NSString *urlString = [NSString stringWithFormat:@"https://api.500px.com/v1/users/show?id=%lu&consumer_key=Fi13GVb8g53sGvHICzlram7QkKOlSDmAmp9s9aqC", (unsigned long)_userID];
|
||||
NSString *urlString = [NSString stringWithFormat:@"https://api.500px.com/v1/users/show?id=%@&consumer_key=Fi13GVb8g53sGvHICzlram7QkKOlSDmAmp9s9aqC", _userID];
|
||||
|
||||
NSURL *url = [NSURL URLWithString:urlString];
|
||||
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration]];
|
||||
@ -148,30 +146,23 @@
|
||||
return;
|
||||
}
|
||||
|
||||
_userID = [[self guardJSONElement:[userDictionary objectForKey:@"id"]] integerValue];
|
||||
_userID = [self guardJSONElement:[userDictionary objectForKey:@"id"]];
|
||||
_username = [[self guardJSONElement:[userDictionary objectForKey:@"username"]] lowercaseString];
|
||||
|
||||
if ([_username isKindOfClass:[NSNumber class]]) {
|
||||
if (_username == nil) {
|
||||
_username = @"Anonymous";
|
||||
}
|
||||
|
||||
_firstName = [self guardJSONElement:[userDictionary objectForKey:@"firstname"]];
|
||||
_lastName = [self guardJSONElement:[userDictionary objectForKey:@"lastname"]];
|
||||
_fullName = [self guardJSONElement:[userDictionary objectForKey:@"fullname"]];
|
||||
_city = [self guardJSONElement:[userDictionary objectForKey:@"city"]];
|
||||
_state = [self guardJSONElement:[userDictionary objectForKey:@"state"]];
|
||||
_country = [self guardJSONElement:[userDictionary objectForKey:@"country"]];
|
||||
_about = [self guardJSONElement:[userDictionary objectForKey:@"about"]];
|
||||
_domain = [self guardJSONElement:[userDictionary objectForKey:@"domain"]];
|
||||
_photoCount = [[self guardJSONElement:[userDictionary objectForKey:@"photos_count"]] integerValue];
|
||||
_galleriesCount = [[self guardJSONElement:[userDictionary objectForKey:@"galleries_count"]] integerValue];
|
||||
_affection = [[self guardJSONElement:[userDictionary objectForKey:@"affection"]] integerValue];
|
||||
_friendsCount = [[self guardJSONElement:[userDictionary objectForKey:@"friends_count"]] integerValue];
|
||||
_followersCount = [[self guardJSONElement:[userDictionary objectForKey:@"followers_count"]] integerValue];
|
||||
_following = [[self guardJSONElement:[userDictionary objectForKey:@"following"]] boolValue];
|
||||
_firstName = [self guardJSONElement:[userDictionary objectForKey:@"first_name"]];
|
||||
_lastName = [self guardJSONElement:[userDictionary objectForKey:@"last_name"]];
|
||||
_fullName = [self guardJSONElement:[userDictionary objectForKey:@"name"]];
|
||||
_location = [self guardJSONElement:[userDictionary objectForKey:@"location"]];
|
||||
_about = [self guardJSONElement:[userDictionary objectForKey:@"bio"]];
|
||||
_photoCount = [[self guardJSONElement:[userDictionary objectForKey:@"total_photos"]] integerValue];
|
||||
_galleriesCount = [[self guardJSONElement:[userDictionary objectForKey:@"total_collections"]] integerValue];
|
||||
_dictionaryRepresentation = userDictionary;
|
||||
|
||||
NSString *urlString = [self guardJSONElement:[userDictionary objectForKey:@"userpic_url"]];
|
||||
NSString *urlString = [self guardJSONElement:[userDictionary objectForKey:@"profile_image"][@"medium"]];
|
||||
_userPicURL = urlString ? [NSURL URLWithString:urlString] : nil;
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user