├── .gitignore
├── .travis.yml
├── Gemfile
├── LICENSE
├── Podfile
├── Podfile.lock
├── README.md
├── STXDynamicTableView
├── Buttons
│ ├── STXButton.h
│ └── STXButton.m
├── Categories
│ ├── NSString+Emoji.h
│ ├── NSString+Emoji.m
│ ├── UIButton+STXButton.h
│ ├── UIButton+STXButton.m
│ ├── UIImage+STXImage.h
│ ├── UIImage+STXImage.m
│ ├── UIImageView+Masking.h
│ ├── UIImageView+Masking.m
│ ├── UIViewController+Indicator.h
│ ├── UIViewController+Indicator.m
│ ├── UIViewController+Sharing.h
│ └── UIViewController+Sharing.m
├── Cells
│ ├── STXCaptionCell.h
│ ├── STXCaptionCell.m
│ ├── STXCommentCell.h
│ ├── STXCommentCell.m
│ ├── STXFeedPhotoCell.h
│ ├── STXFeedPhotoCell.m
│ ├── STXFeedPhotoCell.xib
│ ├── STXLikesCell.h
│ ├── STXLikesCell.m
│ ├── STXUserActionCell.h
│ ├── STXUserActionCell.m
│ └── STXUserActionCell.xib
├── Items
│ ├── STXCommentItem.h
│ ├── STXPostItem.h
│ └── STXUserItem.h
├── Labels
│ ├── STXAttributedLabel.h
│ ├── STXAttributedLabel.m
│ ├── STXLabel.h
│ └── STXLabel.m
├── Protocols
│ ├── STXFeedTableViewDataSource.h
│ ├── STXFeedTableViewDataSource.m
│ ├── STXFeedTableViewDelegate.h
│ └── STXFeedTableViewDelegate.m
└── STXDynamicTableView.h
├── STXDynamicTableViewExample.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
└── xcshareddata
│ └── xcschemes
│ └── STXDynamicTableViewExample.xcscheme
├── STXDynamicTableViewExample.xcworkspace
└── contents.xcworkspacedata
├── STXDynamicTableViewExample
├── Feed.storyboard
├── Images.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ └── LaunchImage.launchimage
│ │ └── Contents.json
├── LaunchScreen.storyboard
├── Models
│ ├── STXComment.h
│ ├── STXComment.m
│ ├── STXPost.h
│ ├── STXPost.m
│ ├── STXUser.h
│ └── STXUser.m
├── Resources
│ └── instagram_media_popular.json
├── STXAppDelegate.h
├── STXAppDelegate.m
├── STXDynamicTableViewExample-Info.plist
├── STXDynamicTableViewExample-Prefix.pch
├── STXFeedViewController.h
├── STXFeedViewController.m
├── en.lproj
│ └── InfoPlist.strings
└── main.m
├── STXDynamicTableViewExampleTests
├── STXDynamicTableViewExampleTests-Info.plist
├── STXDynamicTableViewExampleTests.m
└── en.lproj
│ └── InfoPlist.strings
├── bin
└── setup
└── build.sh
/.gitignore:
--------------------------------------------------------------------------------
1 | # OS X Finder
2 | .DS_Store
3 |
4 | # Xcode per-user config
5 | *.mode1
6 | *.mode1v3
7 | *.mode2v3
8 | *.perspective
9 | *.perspectivev3
10 | *.pbxuser
11 | xcuserdata
12 | *.xccheckout
13 |
14 | # Build products
15 | build/
16 | *.o
17 | *.LinkFileList
18 | *.hmap
19 |
20 | # Automatic backup files
21 | *~.nib/
22 | *.swp
23 | *~
24 | *.dat
25 | *.dep
26 |
27 | # CocoaPods
28 | #
29 | # We recommend against adding the Pods directory to your .gitignore. However
30 | # you should judge for yourself, the pros and cons are mentioned at:
31 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
32 | #
33 | Pods/
34 |
35 | # AppCode specific files
36 | .idea/
37 | *.iml
38 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: objective-c
2 | xcode_project: STXDynamicTableViewExample.xcodeproj
3 | cache:
4 | directories:
5 | - ./vendor/bundle
6 | - ./Pods
7 | before_install:
8 | - bundle update
9 | install:
10 | - bundle exec pod install
11 | script:
12 | - "./build.sh"
13 | osx_image: xcode7
14 | env:
15 | global:
16 | - REPO_SLUG="2359media/STXDynamicTableView"
17 | - PRODUCT_NAME="STXDynamicTableViewExample"
18 | - PROJECT_NAME="STXDynamicTableViewExample.xcworkspace"
19 | - SCHEME_NAME="STXDynamicTableViewExample"
20 | - CONFIGURATION_NAME="Debug"
21 | - INFO_PLIST_PATH="STXDynamicTableViewExample/STXDynamicTableViewExample-Info.plist"
22 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | gem 'cocoapods'
4 | gem 'xcpretty'
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 2359 Media Pte Ltd.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Podfile:
--------------------------------------------------------------------------------
1 | source 'https://github.com/CocoaPods/Specs.git'
2 | platform :ios, "8.0"
3 |
4 | target "STXDynamicTableViewExample" do
5 | pod 'TTTAttributedLabel'
6 | pod 'PureLayout'
7 | pod 'KZPropertyMapper'
8 | pod 'MHPrettyDate'
9 | pod 'AFNetworking'
10 | pod 'UALogger'
11 | end
12 |
13 | target "STXDynamicTableViewExampleTests" do
14 |
15 | end
16 |
17 |
--------------------------------------------------------------------------------
/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - AFNetworking (2.5.0):
3 | - AFNetworking/NSURLConnection (= 2.5.0)
4 | - AFNetworking/NSURLSession (= 2.5.0)
5 | - AFNetworking/Reachability (= 2.5.0)
6 | - AFNetworking/Security (= 2.5.0)
7 | - AFNetworking/Serialization (= 2.5.0)
8 | - AFNetworking/UIKit (= 2.5.0)
9 | - AFNetworking/NSURLConnection (2.5.0):
10 | - AFNetworking/Reachability
11 | - AFNetworking/Security
12 | - AFNetworking/Serialization
13 | - AFNetworking/NSURLSession (2.5.0):
14 | - AFNetworking/Reachability
15 | - AFNetworking/Security
16 | - AFNetworking/Serialization
17 | - AFNetworking/Reachability (2.5.0)
18 | - AFNetworking/Security (2.5.0)
19 | - AFNetworking/Serialization (2.5.0)
20 | - AFNetworking/UIKit (2.5.0):
21 | - AFNetworking/NSURLConnection
22 | - AFNetworking/NSURLSession
23 | - KZPropertyMapper (2.5.1)
24 | - MHPrettyDate (1.1.1)
25 | - PureLayout (2.0.4)
26 | - TTTAttributedLabel (1.13.0)
27 | - UALogger (0.3)
28 |
29 | DEPENDENCIES:
30 | - AFNetworking
31 | - KZPropertyMapper
32 | - MHPrettyDate
33 | - PureLayout
34 | - TTTAttributedLabel
35 | - UALogger
36 |
37 | SPEC CHECKSUMS:
38 | AFNetworking: 96ac9bf3eda33582701cb1fcc5b896aa1e20311e
39 | KZPropertyMapper: e80e83aa3bc6d37a6dd55e3d04a01afcb8c23d3c
40 | MHPrettyDate: e0e5975041f0210c0542f4c5d7e3e44d1a8537be
41 | PureLayout: 39ab7d09edec14750ba3982bf19126916861bba5
42 | TTTAttributedLabel: 8aeaf67481bb38970711e2641211cba912bd5239
43 | UALogger: ccc041e5982dbd274ab5805f914076fef9bf29cf
44 |
45 | COCOAPODS: 0.38.2
46 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://travis-ci.org/2359media/STXDynamicTableView)
2 |
3 | # STXDynamicTableView
4 |
5 | `STXDynamicTableView` is designed to solve the common use case to display a feed of photos with their corresponding likes, caption, and comments. It's inspired by Instagram feed table view.
6 |
7 |
8 |
9 |
10 |
11 | |
12 |
13 |
14 | |
15 |
16 |
17 |
18 | ---
19 | ## Example Project
20 |
21 | We're using [cocoapods](http://cocoapods.org/) to update the existing 3rd party libraries (Pods) in the sample code:
22 |
23 | $ pod install
24 |
25 | Then, open `STXDynamicTableViewExample.xcworkspace` to build and run.
26 |
27 | ---
28 | ## Usage
29 |
30 | Import the whole `STXDynamicTableView` source files into your project, and import the main header file:
31 |
32 | #import "STXDynamicTableView.h"
33 |
34 | Supply your table view in the view controller, then set the delegate and data source:
35 |
36 | STXFeedTableViewDataSource *dataSource = [[STXFeedTableViewDataSource alloc] initWithController:self tableView:self.tableView];
37 | self.tableView.dataSource = dataSource;
38 | self.tableViewDataSource = dataSource;
39 |
40 | STXFeedTableViewDelegate *delegate = [[STXFeedTableViewDelegate alloc] initWithController:self];
41 | self.tableView.delegate = delegate;
42 | self.tableViewDelegate = delegate;
43 |
44 | Populate your data models to the table view data source:
45 |
46 | NSDictionary *instagramPopularMediaDictionary = jsonObject;
47 | if (instagramPopularMediaDictionary) {
48 | id data = [instagramPopularMediaDictionary valueForKey:@"data"];
49 | NSArray *mediaDataArray = data;
50 |
51 | NSMutableArray *posts = [NSMutableArray array];
52 | for (NSDictionary *mediaDictionary in mediaDataArray) {
53 | STXPost *post = [[STXPost alloc] initWithDictionary:mediaDictionary];
54 | [posts addObject:post];
55 | }
56 |
57 | self.tableViewDataSource.posts = [posts copy];
58 |
59 | [self.tableView reloadData];
60 | }
61 |
62 | Your data models need to conform to `STXPostItem`, `STXCommentItem`, and `STXUserItem` to be able to use the built-in table view data source and delegate.
63 |
64 | ---
65 | ## Background
66 |
67 | Read [Rebuilding Instagram feed table
68 | view](http://engineering.2359media.net/blog/2014/04/16/rebuilding-instagram-feed-table-view/) to understand the challenges, difficulties, and how do we solve the issue of rebuilding the table view style popularized by Instagram app with Auto Layout.
69 |
70 | ---
71 | ## TODO
72 |
73 | * Migrate to Swift with better value types for data models and protocols
74 | * Using alternative architecture such as [AsyncDisplayKit](http://asyncdisplaykit.org/), [ComponentKit](http://componentkit.org/), or [React Native](http://www.reactnative.com/).
75 |
76 | ---
77 | ## Disclaimer
78 | `STXDynamicTableView` is simply a reusable code that you can use in your own project for any purpose as outlined in the LICENSE file. It's not a fully-fledged library, although we're taking steps to go there as time allows.
79 |
80 | ___
81 | ##Feedback
82 | We'd love to hear feedback. Create Github issues, pull requests, or hit us up on [Twitter](http://twitter.com/2359eng).
83 |
84 | ---
85 | ## Credits
86 | This project uses the following 3rd party libraries:
87 |
88 | * Tyler Fox for [PureLayout](https://github.com/smileyborg/PureLayout)
89 | * Mattt Thompson for [AFNetworking](https://github.com/AFNetworking/AFNetworking) and [TTTAttributedLabel](https://github.com/mattt/TTTAttributedLabel)
90 | * Krzysztof Zabłocki for [KZPropertyMapper](https://github.com/krzysztofzablocki/KZPropertyMapper)
91 | * Bobby Williams for [MHPrettyDate](https://github.com/bobjustbob/MHPrettyDate)
92 | * Urban Apps for [UALogger](https://github.com/UrbanApps/UALogger)
93 |
94 | ___
95 | ## License
96 | `STXDynamicTableView` is available under the MIT license. See the LICENSE file for more info.
97 |
98 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Buttons/STXButton.h:
--------------------------------------------------------------------------------
1 | //
2 | // STXButton.h
3 | // STXDynamicTableView
4 | //
5 | // Created by Jesse Armand on 4/2/14.
6 | // Copyright (c) 2014 2359 Media. All rights reserved.
7 | //
8 |
9 | @interface STXButton : UIButton
10 |
11 | - (void)stx_reverseButtonStateAppearance;
12 |
13 | - (void)stx_resetButtonStateAppearance;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Buttons/STXButton.m:
--------------------------------------------------------------------------------
1 | //
2 | // STXButton.m
3 | // STXDynamicTableView
4 | //
5 | // Created by Jesse Armand on 4/2/14.
6 | // Copyright (c) 2014 2359 Media. All rights reserved.
7 | //
8 |
9 | #import "STXButton.h"
10 |
11 | @interface STXButton ()
12 |
13 | @property (strong, nonatomic) UIImage *stx_highlightedImage;
14 | @property (strong, nonatomic) UIImage *stx_normalImage;
15 |
16 | @end
17 |
18 | @implementation STXButton
19 |
20 | - (instancetype)initWithFrame:(CGRect)frame
21 | {
22 | self = [super initWithFrame:frame];
23 | if (self) {
24 | [self stx_setupAppearance];
25 | }
26 | return self;
27 | }
28 |
29 | - (instancetype)init
30 | {
31 | self = [super init];
32 | if (self) {
33 | [self stx_setupAppearance];
34 | }
35 | return self;
36 | }
37 |
38 | - (void)awakeFromNib
39 | {
40 | [super awakeFromNib];
41 |
42 | [self stx_setupAppearance];
43 | }
44 |
45 | - (void)layoutSubviews
46 | {
47 | [super layoutSubviews];
48 |
49 | // Keep the image for each state initially when laying out subviews
50 | if (self.stx_normalImage == nil) {
51 | self.stx_normalImage = [self imageForState:UIControlStateNormal];
52 | }
53 |
54 | if (self.stx_highlightedImage == nil) {
55 | self.stx_highlightedImage = [self imageForState:UIControlStateHighlighted];
56 | }
57 | }
58 |
59 | - (void)stx_setupAppearance
60 | {
61 | }
62 |
63 | - (void)stx_reverseButtonStateAppearance
64 | {
65 | }
66 |
67 | - (void)stx_resetButtonStateAppearance
68 | {
69 | }
70 |
71 | @end
72 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Categories/NSString+Emoji.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSString+Emoji.h
3 | //
4 | // Credit to: https://gist.github.com/cihancimen/4146056
5 | //
6 | //
7 |
8 | @import Foundation;
9 |
10 | @interface NSString (Emoji)
11 |
12 | - (BOOL)stringContainsEmoji;
13 |
14 | @end
15 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Categories/NSString+Emoji.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSString+Emoji.h
3 | //
4 | // Credit to: https://gist.github.com/cihancimen/4146056
5 | //
6 | //
7 |
8 | #import "NSString+Emoji.h"
9 |
10 | @implementation NSString (Emoji)
11 |
12 | - (BOOL)stringContainsEmoji {
13 | __block BOOL returnValue = NO;
14 | [self enumerateSubstringsInRange:NSMakeRange(0, [self length]) options:NSStringEnumerationByComposedCharacterSequences usingBlock:
15 | ^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
16 |
17 | const unichar hs = [substring characterAtIndex:0];
18 | // surrogate pair
19 | if (0xd800 <= hs && hs <= 0xdbff) {
20 | if (substring.length > 1) {
21 | const unichar ls = [substring characterAtIndex:1];
22 | const int uc = ((hs - 0xd800) * 0x400) + (ls - 0xdc00) + 0x10000;
23 | if (0x1d000 <= uc && uc <= 0x1f77f) {
24 | returnValue = YES;
25 | }
26 | }
27 | } else if (substring.length > 1) {
28 | const unichar ls = [substring characterAtIndex:1];
29 | if (ls == 0x20e3) {
30 | returnValue = YES;
31 | }
32 |
33 | } else {
34 | // non surrogate
35 | if (0x2100 <= hs && hs <= 0x27ff) {
36 | returnValue = YES;
37 | } else if (0x2B05 <= hs && hs <= 0x2b07) {
38 | returnValue = YES;
39 | } else if (0x2934 <= hs && hs <= 0x2935) {
40 | returnValue = YES;
41 | } else if (0x3297 <= hs && hs <= 0x3299) {
42 | returnValue = YES;
43 | } else if (hs == 0xa9 || hs == 0xae || hs == 0x303d || hs == 0x3030 || hs == 0x2b55 || hs == 0x2b1c || hs == 0x2b1b || hs == 0x2b50) {
44 | returnValue = YES;
45 | }
46 | }
47 | }];
48 |
49 | return returnValue;
50 | }
51 |
52 | @end
53 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Categories/UIButton+STXButton.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIButton+STXButton.h
3 | // STXDynamicTableView
4 | //
5 | // Created by Jesse Armand on 28/1/14.
6 | // Copyright (c) 2014 2359 Media. All rights reserved.
7 | //
8 |
9 | @import UIKit;
10 |
11 | @interface UIButton (STXButton)
12 |
13 | - (void)stx_setNormalAppearance;
14 |
15 | - (void)stx_setSelectedAppearance;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Categories/UIButton+STXButton.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIButton+STXButton.m
3 | // STXDynamicTableView
4 | //
5 | // Created by Jesse Armand on 28/1/14.
6 | // Copyright (c) 2014 2359 Media. All rights reserved.
7 | //
8 |
9 | #import "UIButton+STXButton.h"
10 |
11 | @implementation UIButton (STXButton)
12 |
13 | - (void)stx_setNormalAppearance
14 | {
15 | [self setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal];
16 | [self setTitleColor:[UIColor blackColor] forState:UIControlStateHighlighted];
17 | [self setTitleColor:[UIColor blackColor] forState:UIControlStateSelected];
18 |
19 | self.titleLabel.backgroundColor = self.backgroundColor;
20 | }
21 |
22 | - (void)stx_setSelectedAppearance
23 | {
24 | [self setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
25 | [self setTitleColor:[UIColor lightGrayColor] forState:UIControlStateHighlighted];
26 | [self setTitleColor:[UIColor lightGrayColor] forState:UIControlStateSelected];
27 | }
28 |
29 | @end
30 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Categories/UIImage+STXImage.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIImage+STXImage.h
3 | // STXDynamicTableView
4 | //
5 | // Created by Jesse Armand on 28/2/14.
6 | // Copyright (c) 2014 2359 Media. All rights reserved.
7 | //
8 |
9 | @import UIKit;
10 |
11 | @interface UIImage (STXImage)
12 |
13 | + (UIImage *)imageWithColor:(UIColor *)color size:(CGSize)imageSize;
14 |
15 | + (UIImage *)cropImageWithInfo:(NSDictionary *)info;
16 |
17 | - (UIImage *)squareAspectFilledImage;
18 |
19 | - (UIImage *)circleBorderedAtWidth:(CGFloat)width forImageWithSize:(CGSize)imageSize;
20 |
21 | - (UIImage *)watermarkedImage;
22 |
23 | @end
24 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Categories/UIImage+STXImage.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIImage+STXImage.m
3 | // STXDynamicTableView
4 | //
5 | // Created by Jesse Armand on 28/2/14.
6 | // Copyright (c) 2014 2359 Media. All rights reserved.
7 | //
8 |
9 | #import "UIImage+STXImage.h"
10 |
11 | @implementation UIImage (STXImage)
12 |
13 | + (UIImage *)imageWithColor:(UIColor *)color size:(CGSize)imageSize
14 | {
15 | CGRect rect = CGRectMake(0.f, 0.f, imageSize.width, imageSize.height);
16 | UIGraphicsBeginImageContext(rect.size);
17 | CGContextRef context = UIGraphicsGetCurrentContext();
18 |
19 | CGContextSetFillColorWithColor(context, [color CGColor]);
20 | CGContextFillRect(context, rect);
21 |
22 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
23 | UIGraphicsEndImageContext();
24 |
25 | return image;
26 | }
27 |
28 | + (UIImage *)cropImageWithInfo:(NSDictionary *)info
29 | {
30 | UIImage *originalImage = [info objectForKey:UIImagePickerControllerOriginalImage];
31 | CGRect cropRect = [[info objectForKey:UIImagePickerControllerCropRect] CGRectValue];
32 | CGAffineTransform rotateTransform = CGAffineTransformIdentity;
33 |
34 | switch (originalImage.imageOrientation) {
35 | case UIImageOrientationDown:
36 | rotateTransform = CGAffineTransformRotate(rotateTransform, M_PI);
37 | rotateTransform = CGAffineTransformTranslate(rotateTransform, -originalImage.size.width, -originalImage.size.height);
38 | break;
39 |
40 | case UIImageOrientationLeft:
41 | rotateTransform = CGAffineTransformRotate(rotateTransform, M_PI_2);
42 | rotateTransform = CGAffineTransformTranslate(rotateTransform, 0.0, -originalImage.size.height);
43 | break;
44 |
45 | case UIImageOrientationRight:
46 | rotateTransform = CGAffineTransformRotate(rotateTransform, -M_PI_2);
47 | rotateTransform = CGAffineTransformTranslate(rotateTransform, -originalImage.size.width, 0.0);
48 | break;
49 |
50 | default:
51 | break;
52 | }
53 |
54 | CGRect rotatedCropRect = CGRectApplyAffineTransform(cropRect, rotateTransform);
55 |
56 | CGImageRef croppedImage = CGImageCreateWithImageInRect([originalImage CGImage], rotatedCropRect);
57 | UIImage *result = [UIImage imageWithCGImage:croppedImage scale:[UIScreen mainScreen].scale orientation:originalImage.imageOrientation];
58 | CGImageRelease(croppedImage);
59 |
60 | return result;
61 | }
62 |
63 | - (UIImage *)squareAspectFilledImage
64 | {
65 | // This calculates the crop area.
66 | CGFloat originalWidth = self.size.width * self.scale;
67 | CGFloat originalHeight = self.size.height * self.scale;
68 |
69 | CGFloat edge = fminf(originalWidth, originalHeight);
70 |
71 | CGFloat posX = (originalWidth - edge) / 2.f;
72 | CGFloat posY = (originalHeight - edge) / 2.f;
73 |
74 | CGRect cropSquare = CGRectMake(posX, posY, edge, edge);
75 | CGImageRef croppedCGImage = CGImageCreateWithImageInRect(self.CGImage, cropSquare);
76 | UIImage *croppedImage = [UIImage imageWithCGImage:croppedCGImage scale:self.scale orientation:self.imageOrientation];
77 | CGImageRelease(croppedCGImage);
78 | return croppedImage;
79 | }
80 |
81 | - (UIImage *)circleBorderedAtWidth:(CGFloat)width forImageWithSize:(CGSize)imageSize
82 | {
83 | UIImage *squareAspectFilledImage = [self squareAspectFilledImage];
84 |
85 | UIGraphicsBeginImageContextWithOptions(imageSize, YES, 0);
86 |
87 | [squareAspectFilledImage drawInRect:CGRectMake(0, 0, imageSize.width, imageSize.height)];
88 |
89 | CGContextRef context = UIGraphicsGetCurrentContext();
90 |
91 | [[UIColor whiteColor] setStroke];
92 |
93 | CGContextSetLineWidth(context, width * [[UIScreen mainScreen] scale]);
94 |
95 | CGRect circleRect = CGRectMake(0, 0, imageSize.width, imageSize.height);
96 | CGContextStrokeEllipseInRect(context, circleRect);
97 |
98 | UIImage *circledImage = UIGraphicsGetImageFromCurrentImageContext();
99 |
100 | UIGraphicsEndImageContext();
101 |
102 | return circledImage;
103 | }
104 |
105 | - (UIImage *)watermarkedImage
106 | {
107 | UIImage *watermarkImage = [UIImage imageNamed:@"Watermark"];
108 | CGSize watermarkSize = watermarkImage.size;
109 |
110 | CGSize totalSize = CGSizeMake(self.size.width, self.size.height + watermarkSize.height);
111 |
112 | UIGraphicsBeginImageContextWithOptions(totalSize, YES, 0);
113 |
114 | CGRect drawRect = CGRectMake(0, 0, totalSize.width, self.size.height);
115 | [self drawInRect:drawRect];
116 |
117 | CGRect watermarkRect = CGRectMake(0, self.size.height, CGRectGetWidth(drawRect), watermarkSize.height);
118 | [watermarkImage drawInRect:watermarkRect];
119 |
120 | UIImage *watermarkedImage = UIGraphicsGetImageFromCurrentImageContext();
121 | return watermarkedImage;
122 | }
123 |
124 | @end
125 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Categories/UIImageView+Masking.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIImageView+Masking.h
3 | // STXDynamicTableView
4 | //
5 | // Created by Jesse Armand on 7/2/14.
6 | // Copyright (c) 2014 2359 Media. All rights reserved.
7 | //
8 |
9 | @interface UIImageView (Masking)
10 |
11 | - (void)setCircleImageWithURL:(NSURL *)imageURL placeholderImage:(UIImage *)placeholderImage;
12 |
13 | - (void)setCircleImageWithURL:(NSURL *)imageURL placeholderImage:(UIImage *)placeholderImage borderWidth:(CGFloat)borderWidth;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Categories/UIImageView+Masking.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIImageView+Masking.m
3 | // STXDynamicTableView
4 | //
5 | // Created by Jesse Armand on 7/2/14.
6 | // Copyright (c) 2014 2359 Media. All rights reserved.
7 | //
8 |
9 | #import "UIImageView+Masking.h"
10 | #import "UIImage+STXImage.h"
11 |
12 | #import
13 | #import
14 |
15 | @interface STXImageCache : NSCache
16 | @end
17 |
18 | #pragma mark -
19 |
20 | static char kSTXSharedImageCacheKey;
21 | static char kSTXCircleImageOperationKey;
22 |
23 | @interface UIImageView (_Masking)
24 | @property (readwrite, nonatomic, strong, setter = stx_setCircleImageOperation:) NSOperation *stx_circleImageOperation;
25 | @end
26 |
27 | @implementation UIImageView (_Masking)
28 |
29 | + (NSOperationQueue *)stx_sharedCircleImageOperationQueue
30 | {
31 | static NSOperationQueue *_stx_sharedCircleImageOperationQueue = nil;
32 | static dispatch_once_t onceToken;
33 | dispatch_once(&onceToken, ^{
34 | _stx_sharedCircleImageOperationQueue = [[NSOperationQueue alloc] init];
35 | _stx_sharedCircleImageOperationQueue.maxConcurrentOperationCount = NSOperationQueueDefaultMaxConcurrentOperationCount;
36 | });
37 |
38 | return _stx_sharedCircleImageOperationQueue;
39 | }
40 |
41 | - (NSOperation *)stx_circleImageOperation
42 | {
43 | return (NSOperation *)objc_getAssociatedObject(self, &kSTXCircleImageOperationKey);
44 | }
45 |
46 | - (void)stx_setCircleImageOperation:(NSOperation *)circleImageOperation
47 | {
48 | objc_setAssociatedObject(self, &kSTXCircleImageOperationKey, circleImageOperation, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
49 | }
50 |
51 | @end
52 |
53 | @implementation UIImageView (Masking)
54 |
55 | + (id)sharedImageCache {
56 | static STXImageCache *_stx_defaultImageCache = nil;
57 | static dispatch_once_t oncePredicate;
58 | dispatch_once(&oncePredicate, ^{
59 | _stx_defaultImageCache = [[STXImageCache alloc] init];
60 |
61 | [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidReceiveMemoryWarningNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * __unused notification) {
62 | [_stx_defaultImageCache removeAllObjects];
63 | }];
64 | });
65 |
66 | #pragma clang diagnostic push
67 | #pragma clang diagnostic ignored "-Wgnu"
68 | return objc_getAssociatedObject(self, &kSTXSharedImageCacheKey) ?: _stx_defaultImageCache;
69 | #pragma clang diagnostic pop
70 | }
71 |
72 | + (void)setSharedImageCache:(id)imageCache {
73 | objc_setAssociatedObject(self, &kSTXSharedImageCacheKey, imageCache, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
74 | }
75 |
76 | - (void)setCircleImageWithURL:(NSURL *)imageURL placeholderImage:(UIImage *)placeholderImage
77 | {
78 | [self setCircleImageWithURL:imageURL placeholderImage:placeholderImage borderWidth:3];
79 | }
80 |
81 | - (void)setCircleImageWithURL:(NSURL *)imageURL placeholderImage:(UIImage *)placeholderImage borderWidth:(CGFloat)borderWidth;
82 | {
83 | [self cancelCircleImageOperation];
84 |
85 | [self addCircleMask];
86 |
87 | CGSize imageSize = CGSizeMake(CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds));
88 |
89 | __weak UIImageView *weakSelf = self;
90 |
91 | NSURLRequest *request = [NSURLRequest requestWithURL:imageURL];
92 | UIImage *cachedImage = [[[self class] sharedImageCache] cachedImageForRequest:request];
93 | if (cachedImage) {
94 | self.image = cachedImage;
95 | } else {
96 | __block NSOperationQueue *circleImageOperationQueue = [[self class] stx_sharedCircleImageOperationQueue];
97 | id imageCache = [[self class] sharedImageCache];
98 |
99 | [self setImageWithURLRequest:request placeholderImage:placeholderImage success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
100 | __strong __typeof(weakSelf)strongSelf = weakSelf;
101 |
102 | strongSelf.stx_circleImageOperation = [NSBlockOperation blockOperationWithBlock:^{
103 | UIImage *circledImage = [image circleBorderedAtWidth:borderWidth forImageWithSize:imageSize];
104 | [imageCache cacheImage:circledImage forRequest:request];
105 |
106 | [[NSOperationQueue mainQueue] addOperationWithBlock:^{
107 | strongSelf.image = circledImage;
108 | }];
109 | }];
110 |
111 | [circleImageOperationQueue addOperation:strongSelf.stx_circleImageOperation];
112 |
113 | } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
114 |
115 | __strong __typeof(weakSelf)strongSelf = weakSelf;
116 |
117 | if (strongSelf.image != nil) {
118 | return;
119 | }
120 |
121 | strongSelf.stx_circleImageOperation = [NSBlockOperation blockOperationWithBlock:^{
122 | UIImage *circledImage = [placeholderImage circleBorderedAtWidth:borderWidth forImageWithSize:imageSize];
123 |
124 | [[NSOperationQueue mainQueue] addOperationWithBlock:^{
125 | strongSelf.image = circledImage;
126 | }];
127 | }];
128 |
129 | [circleImageOperationQueue addOperation:strongSelf.stx_circleImageOperation];
130 | }];
131 | }
132 | }
133 |
134 | - (void)addCircleMask
135 | {
136 | self.clipsToBounds = YES;
137 |
138 | self.backgroundColor = [UIColor whiteColor];
139 | self.contentMode = UIViewContentModeScaleAspectFill;
140 | self.layer.cornerRadius = CGRectGetWidth(self.bounds)/2;
141 | self.layer.masksToBounds = YES;
142 | }
143 |
144 | - (void)cancelCircleImageOperation
145 | {
146 | [self.stx_circleImageOperation cancel];
147 | self.stx_circleImageOperation = nil;
148 | }
149 |
150 | @end
151 |
152 | #pragma mark - STXImageCache
153 |
154 | @implementation STXImageCache
155 |
156 | static inline NSString * STXImageCacheKeyFromURLRequest(NSURLRequest *request) {
157 | return [[request URL] absoluteString];
158 | }
159 |
160 | - (UIImage *)cachedImageForRequest:(NSURLRequest *)request {
161 | switch ([request cachePolicy]) {
162 | case NSURLRequestReloadIgnoringCacheData:
163 | case NSURLRequestReloadIgnoringLocalAndRemoteCacheData:
164 | return nil;
165 | default:
166 | break;
167 | }
168 |
169 | return [self objectForKey:STXImageCacheKeyFromURLRequest(request)];
170 | }
171 |
172 | - (void)cacheImage:(UIImage *)image forRequest:(NSURLRequest *)request
173 | {
174 | if (image && request) {
175 | [self setObject:image forKey:STXImageCacheKeyFromURLRequest(request)];
176 | }
177 | }
178 |
179 | @end
180 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Categories/UIViewController+Indicator.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIViewController+Indicator.h
3 | // STXDynamicTableView
4 | //
5 | // Created by Jesse Armand on 28/1/14.
6 | // Copyright (c) 2014 2359 Media. All rights reserved.
7 | //
8 |
9 | @interface UIViewController (Indicator)
10 |
11 | /**
12 | * Return a new UIActivityIndicatorView at the middle of the UIViewController's view
13 | * It will be positioned on top of contentView if provided, if not just add it to self.view.
14 | */
15 |
16 | - (UIActivityIndicatorView *)activityIndicatorViewOnView:(UIView *)contentView;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Categories/UIViewController+Indicator.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIViewController+Indicator.m
3 | // STXDynamicTableView
4 | //
5 | // Created by Jesse Armand on 28/1/14.
6 | // Copyright (c) 2014 2359 Media. All rights reserved.
7 | //
8 |
9 | #import "UIViewController+Indicator.h"
10 |
11 | #import
12 |
13 | @implementation UIViewController (Indicator)
14 |
15 | - (UIActivityIndicatorView *)activityIndicatorViewOnView:(UIView *)contentView
16 | {
17 | UIActivityIndicatorView *activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
18 | activityIndicatorView.translatesAutoresizingMaskIntoConstraints = NO;
19 | activityIndicatorView.hidesWhenStopped = YES;
20 |
21 | if (contentView)
22 | [self.view insertSubview:activityIndicatorView aboveSubview:contentView];
23 | else
24 | [self.view addSubview:activityIndicatorView];
25 |
26 | [activityIndicatorView autoCenterInSuperview];
27 | return activityIndicatorView;
28 | }
29 |
30 | @end
31 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Categories/UIViewController+Sharing.h:
--------------------------------------------------------------------------------
1 | //
2 | // STXViewController+Sharing.h
3 | // STXDynamicTableView
4 | //
5 | // Created by Jesse Armand on 18/2/14.
6 | // Copyright (c) 2014 2359 Media. All rights reserved.
7 | //
8 |
9 | @interface UIViewController (Sharing)
10 |
11 | - (void)shareImage:(UIImage *)image text:(NSString *)text url:(NSURL *)url;
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Categories/UIViewController+Sharing.m:
--------------------------------------------------------------------------------
1 | //
2 | // STXViewController+Sharing.m
3 | // STXDynamicTableView
4 | //
5 | // Created by Jesse Armand on 18/2/14.
6 | // Copyright (c) 2014 2359 Media. All rights reserved.
7 | //
8 |
9 | #import "UIViewController+Sharing.h"
10 |
11 | @implementation UIViewController (Sharing)
12 |
13 | - (void)shareImage:(UIImage *)image text:(NSString *)text url:(NSURL *)url
14 | {
15 | NSMutableArray *activityItems = [NSMutableArray array];
16 | if (image)
17 | [activityItems addObject:image];
18 | if (text)
19 | [activityItems addObject:text];
20 | if (url)
21 | [activityItems addObject:url];
22 |
23 | UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:nil];
24 | [self presentViewController:activityViewController animated:YES completion:nil];
25 | }
26 |
27 | @end
28 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Cells/STXCaptionCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // STXCaptionCell.h
3 | // STXDynamicTableViewExample
4 | //
5 | // Created by Jesse Armand on 10/4/14.
6 | // Copyright (c) 2014 2359 Media Pte Ltd. All rights reserved.
7 | //
8 |
9 | @import UIKit;
10 |
11 | @class STXCaptionCell;
12 |
13 | @protocol STXCaptionCellDelegate
14 |
15 | @optional
16 |
17 | - (void)captionCell:(STXCaptionCell *)captionCell didSelectHashtag:(NSString *)hashtag;
18 | - (void)captionCell:(STXCaptionCell *)captionCell didSelectMention:(NSString *)mention;
19 | - (void)captionCell:(STXCaptionCell *)captionCell didSelectPoster:(id)userItem;
20 |
21 | @end
22 |
23 | @interface STXCaptionCell : UITableViewCell
24 |
25 | @property (copy, nonatomic) NSDictionary *caption;
26 |
27 | @property (weak, nonatomic) id delegate;
28 |
29 | - (id)initWithCaption:(NSDictionary *)caption reuseIdentifier:(NSString *)reuseIdentifier;
30 |
31 | @end
--------------------------------------------------------------------------------
/STXDynamicTableView/Cells/STXCaptionCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // STXCaptionCell.m
3 | // STXDynamicTableViewExample
4 | //
5 | // Created by Jesse Armand on 10/4/14.
6 | // Copyright (c) 2014 2359 Media Pte Ltd. All rights reserved.
7 | //
8 |
9 | #import "STXCaptionCell.h"
10 | #import "STXAttributedLabel.h"
11 |
12 | static CGFloat STXCaptionViewLeadingEdgeInset = 10.f;
13 | static CGFloat STXCaptionViewTrailingEdgeInset = 10.f;
14 |
15 | static NSString *HashTagAndMentionRegex = @"(#|@)(\\w+)";
16 |
17 | @interface STXCaptionCell ()
18 |
19 | @property (strong, nonatomic) STXAttributedLabel *captionLabel;
20 | @property (nonatomic) BOOL didSetupConstraints;
21 |
22 | @end
23 |
24 | @implementation STXCaptionCell
25 |
26 | - (id)initWithCaption:(NSDictionary *)caption reuseIdentifier:(NSString *)reuseIdentifier
27 | {
28 | self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier];
29 | if (self) {
30 | NSString *text = [caption valueForKey:@"text"];
31 | _captionLabel = [self captionLabelWithText:text];
32 |
33 | [self.contentView addSubview:_captionLabel];
34 | _captionLabel.translatesAutoresizingMaskIntoConstraints = NO;
35 |
36 | self.selectionStyle = UITableViewCellSelectionStyleNone;
37 | }
38 |
39 | return self;
40 | }
41 |
42 | - (void)setSelected:(BOOL)selected animated:(BOOL)animated
43 | {
44 | [super setSelected:selected animated:animated];
45 | }
46 |
47 | - (void)layoutSubviews
48 | {
49 | [super layoutSubviews];
50 |
51 | self.captionLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.frame) - (STXCaptionViewLeadingEdgeInset + STXCaptionViewTrailingEdgeInset);
52 | }
53 |
54 | - (void)updateConstraints
55 | {
56 | if (!self.didSetupConstraints) {
57 | [self.captionLabel autoPinEdgesToSuperviewEdgesWithInsets:UIEdgeInsetsMake(0, STXCaptionViewLeadingEdgeInset, 0, STXCaptionViewTrailingEdgeInset)];
58 |
59 | self.didSetupConstraints = YES;
60 | }
61 |
62 | [super updateConstraints];
63 | }
64 |
65 | - (void)setCaption:(NSDictionary *)caption
66 | {
67 | if (_caption != caption) {
68 | _caption = caption;
69 |
70 | NSString *text = [caption valueForKey:@"text"];
71 | [self setCaptionLabel:self.captionLabel text:text];
72 | }
73 | }
74 |
75 | #pragma mark - Attributed Label
76 |
77 | - (void)setCaptionLabel:(STXAttributedLabel *)captionLabel text:(NSString *)text
78 | {
79 | NSString *trimmedText = [text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
80 |
81 | NSMutableArray *textCheckingResults = [NSMutableArray array];
82 | [captionLabel setText:trimmedText afterInheritingLabelAttributesAndConfiguringWithBlock:^NSMutableAttributedString *(NSMutableAttributedString *mutableAttributedString) {
83 | NSError *error;
84 | NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:HashTagAndMentionRegex
85 | options:NSRegularExpressionCaseInsensitive
86 | error:&error];
87 | if (error) {
88 | UALog(@"%@", error);
89 | }
90 |
91 | [regex enumerateMatchesInString:[mutableAttributedString string] options:0 range:NSMakeRange(0, [mutableAttributedString length]) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
92 | [textCheckingResults addObject:result];
93 | }];
94 |
95 | return mutableAttributedString;
96 | }];
97 |
98 | for (NSTextCheckingResult *result in textCheckingResults) {
99 | [captionLabel addLinkWithTextCheckingResult:result];
100 | }
101 | }
102 |
103 | - (STXAttributedLabel *)captionLabelWithText:(NSString *)text
104 | {
105 | STXAttributedLabel *captionLabel = [[STXAttributedLabel alloc] initForParagraphStyleWithText:text];
106 | captionLabel.textColor = [UIColor blackColor];
107 | captionLabel.lineBreakMode = NSLineBreakByWordWrapping;
108 | captionLabel.numberOfLines = 0;
109 | captionLabel.delegate = self;
110 | captionLabel.userInteractionEnabled = YES;
111 |
112 | captionLabel.linkAttributes = @{ (NSString *)kCTForegroundColorAttributeName: [UIColor blueColor],
113 | (NSString *)kCTFontAttributeName: [UIFont boldSystemFontOfSize:14],
114 | (NSString *)kCTUnderlineStyleAttributeName : @(kCTUnderlineStyleNone) };
115 | captionLabel.activeLinkAttributes = captionLabel.linkAttributes;
116 | captionLabel.inactiveLinkAttributes = captionLabel.linkAttributes;
117 | [self setCaptionLabel:captionLabel text:text];
118 |
119 | return captionLabel;
120 | }
121 |
122 | - (void)attributedLabel:(TTTAttributedLabel *)label didSelectLinkWithTextCheckingResult:(NSTextCheckingResult *)result
123 | {
124 | NSString *hashtagOrMention = [[label.attributedText string] substringWithRange:result.range];
125 | UALog(@"%@", hashtagOrMention);
126 |
127 | if ([hashtagOrMention hasPrefix:@"#"]) {
128 | NSString *hashtag = [hashtagOrMention substringFromIndex:1];
129 |
130 | if ([self.delegate respondsToSelector:@selector(captionCell:didSelectHashtag:)]) {
131 | [self.delegate captionCell:self didSelectHashtag:hashtag];
132 | }
133 | } else if ([hashtagOrMention hasPrefix:@"@"]) {
134 | NSString *mention = [hashtagOrMention substringFromIndex:1];
135 |
136 | if ([self.delegate respondsToSelector:@selector(captionCell:didSelectMention:)]) {
137 | [self.delegate captionCell:self didSelectMention:mention];
138 | }
139 | }
140 | }
141 |
142 | @end
143 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Cells/STXCommentCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // STXCommentCell.h
3 | // STXDynamicTableViewExample
4 | //
5 | // Created by Jesse Armand on 10/4/14.
6 | // Copyright (c) 2014 2359 Media Pte Ltd. All rights reserved.
7 | //
8 |
9 | @import UIKit;
10 |
11 | typedef NS_ENUM(int16_t, STXCommentCellStyle) {
12 | STXCommentCellStyleSingleComment,
13 | STXCommentCellStyleShowAllComments
14 | };
15 |
16 | @class STXCommentCell;
17 |
18 | @protocol STXCommentCellDelegate
19 |
20 | @optional
21 |
22 | - (void)commentCellWillShowAllComments:(STXCommentCell *)commentCell;
23 | - (void)commentCell:(STXCommentCell *)commentCell willShowCommenter:(id)commenter;
24 | - (void)commentCell:(STXCommentCell *)commentCell didSelectURL:(NSURL *)url;
25 | - (void)commentCell:(STXCommentCell *)commentCell didSelectHashtag:(NSString *)hashtag;
26 | - (void)commentCell:(STXCommentCell *)commentCell didSelectMention:(NSString *)mention;
27 |
28 | @end
29 |
30 | @interface STXCommentCell : UITableViewCell
31 |
32 | @property (copy, nonatomic) id comment;
33 | @property (nonatomic) NSInteger totalComments;
34 |
35 | @property (weak, nonatomic) id delegate;
36 |
37 | - (instancetype)initWithStyle:(STXCommentCellStyle)style comment:(id)comment reuseIdentifier:(NSString *)reuseIdentifier;
38 | - (instancetype)initWithStyle:(STXCommentCellStyle)style totalComments:(NSInteger)totalComments reuseIdentifier:(NSString *)reuseIdentifier;
39 |
40 | @end
41 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Cells/STXCommentCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // STXCommentCell.m
3 | // STXDynamicTableViewExample
4 | //
5 | // Created by Jesse Armand on 10/4/14.
6 | // Copyright (c) 2014 2359 Media Pte Ltd. All rights reserved.
7 | //
8 |
9 | #import "STXCommentCell.h"
10 | #import "STXAttributedLabel.h"
11 |
12 | static CGFloat STXCommentViewLeadingEdgeInset = 10.f;
13 | static CGFloat STXCommentViewTrailingEdgeInset = 10.f;
14 |
15 | static NSString *HashTagAndMentionRegex = @"(#|@)(\\w+)";
16 |
17 | @interface STXCommentCell ()
18 |
19 | @property (nonatomic) STXCommentCellStyle cellStyle;
20 | @property (strong, nonatomic) STXAttributedLabel *commentLabel;
21 |
22 | @property (nonatomic) BOOL didSetupConstraints;
23 |
24 | @end
25 |
26 | @implementation STXCommentCell
27 |
28 | - (id)initWithStyle:(STXCommentCellStyle)style comment:(id)comment totalComments:(NSInteger)totalComments reuseIdentifier:(NSString *)reuseIdentifier
29 | {
30 | self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier];
31 | if (self) {
32 | _cellStyle = style;
33 |
34 | if (style == STXCommentCellStyleShowAllComments) {
35 | NSString *title = [NSString stringWithFormat:NSLocalizedString(@"Show %d comments", nil), totalComments];
36 | _commentLabel = [self allCommentsLabelWithTitle:title];
37 | } else {
38 | id commenter = [comment from];
39 | _commentLabel = [self commentLabelWithText:[comment text] commenter:[commenter username]];
40 | }
41 |
42 | [self.contentView addSubview:_commentLabel];
43 | _commentLabel.translatesAutoresizingMaskIntoConstraints = NO;
44 |
45 | self.selectionStyle = UITableViewCellSelectionStyleNone;
46 | }
47 | return self;
48 | }
49 |
50 | - (instancetype)initWithStyle:(STXCommentCellStyle)style comment:(id)comment reuseIdentifier:(NSString *)reuseIdentifier
51 | {
52 | return [self initWithStyle:style comment:comment totalComments:0 reuseIdentifier:reuseIdentifier];
53 | }
54 |
55 | - (instancetype)initWithStyle:(STXCommentCellStyle)style totalComments:(NSInteger)totalComments reuseIdentifier:(NSString *)reuseIdentifier
56 | {
57 | return [self initWithStyle:style comment:nil totalComments:totalComments reuseIdentifier:reuseIdentifier];
58 | }
59 |
60 | - (void)setSelected:(BOOL)selected animated:(BOOL)animated
61 | {
62 | [super setSelected:selected animated:animated];
63 | }
64 |
65 | - (void)layoutSubviews
66 | {
67 | [super layoutSubviews];
68 |
69 | self.commentLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.frame) - (STXCommentViewLeadingEdgeInset + STXCommentViewTrailingEdgeInset);
70 | }
71 |
72 | - (void)updateConstraints
73 | {
74 | if (!self.didSetupConstraints) {
75 | [self.commentLabel autoPinEdgesToSuperviewEdgesWithInsets:UIEdgeInsetsMake(0, STXCommentViewLeadingEdgeInset, 0, STXCommentViewTrailingEdgeInset)];
76 |
77 | self.didSetupConstraints = YES;
78 | }
79 |
80 | [super updateConstraints];
81 | }
82 |
83 | - (void)setComment:(id)comment
84 | {
85 | if (_comment != comment) {
86 | _comment = comment;
87 |
88 | id commenter = [comment from];
89 | [self setCommentLabel:self.commentLabel text:[comment text] commenter:[commenter username]];
90 | }
91 | }
92 |
93 | - (void)setTotalComments:(NSInteger)totalComments
94 | {
95 | if (_totalComments != totalComments) {
96 | NSString *title = [NSString stringWithFormat:NSLocalizedString(@"Show %d comments", nil), totalComments];
97 | [self setAllCommentsLabel:self.commentLabel title:title];
98 | }
99 | }
100 |
101 | #pragma mark - Attributed Label
102 |
103 | - (void)setAllCommentsLabel:(STXAttributedLabel *)commentLabel title:(NSString *)title
104 | {
105 | [commentLabel setText:title];
106 | }
107 |
108 | - (void)setCommentLabel:(STXAttributedLabel *)commentLabel text:(NSString *)text commenter:(NSString *)commenter
109 | {
110 | NSString *commentText = [NSString stringWithFormat:@"%@ %@", commenter, text];
111 |
112 | NSMutableArray *textCheckingResults = [NSMutableArray array];
113 | [commentLabel setText:commentText afterInheritingLabelAttributesAndConfiguringWithBlock:^NSMutableAttributedString *(NSMutableAttributedString *mutableAttributedString) {
114 | NSRange searchRange = NSMakeRange(0, [mutableAttributedString length]);
115 |
116 | NSRange currentRange = [[mutableAttributedString string] rangeOfString:commenter options:NSLiteralSearch range:searchRange];
117 | NSTextCheckingResult *textCheckingResult = [NSTextCheckingResult linkCheckingResultWithRange:currentRange URL:nil];
118 | [textCheckingResults addObject:textCheckingResult];
119 |
120 | NSError *error;
121 | NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:HashTagAndMentionRegex
122 | options:NSRegularExpressionCaseInsensitive
123 | error:&error];
124 | if (error) {
125 | UALog(@"%@", error);
126 | }
127 |
128 | [regex enumerateMatchesInString:[mutableAttributedString string] options:0 range:NSMakeRange(0, [mutableAttributedString length]) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
129 | [textCheckingResults addObject:result];
130 | }];
131 |
132 | return mutableAttributedString;
133 | }];
134 |
135 | for (NSTextCheckingResult *result in textCheckingResults) {
136 | [commentLabel addLinkWithTextCheckingResult:result];
137 | }
138 | }
139 |
140 | - (STXAttributedLabel *)allCommentsLabelWithTitle:(NSString *)title
141 | {
142 | STXAttributedLabel *allCommentsLabel = [STXAttributedLabel newAutoLayoutView];
143 | allCommentsLabel.delegate = self;
144 | allCommentsLabel.textColor = [UIColor lightGrayColor];
145 | allCommentsLabel.enabledTextCheckingTypes = NSTextCheckingTypeLink;
146 |
147 | allCommentsLabel.linkAttributes = @{ (NSString *)kCTFontAttributeName: allCommentsLabel.font,
148 | (NSString *)kCTForegroundColorAttributeName: allCommentsLabel.textColor};
149 | allCommentsLabel.activeLinkAttributes = allCommentsLabel.linkAttributes;
150 | allCommentsLabel.inactiveLinkAttributes = allCommentsLabel.linkAttributes;
151 | [allCommentsLabel setText:title];
152 |
153 | NSTextCheckingResult *textCheckingResult = [NSTextCheckingResult linkCheckingResultWithRange:NSMakeRange(0, [title length]) URL:nil];
154 | [allCommentsLabel addLinkWithTextCheckingResult:textCheckingResult];
155 |
156 | return allCommentsLabel;
157 | }
158 |
159 | - (STXAttributedLabel *)commentLabelWithText:(NSString *)text commenter:(NSString *)commenter
160 | {
161 | NSString *trimmedText = [text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
162 | NSString *commentText = [[commenter stringByAppendingString:@" "] stringByAppendingString:trimmedText];
163 |
164 | STXAttributedLabel *commentLabel = [[STXAttributedLabel alloc] initForParagraphStyleWithText:commentText];
165 | commentLabel.delegate = self;
166 | commentLabel.numberOfLines = 0;
167 | commentLabel.lineBreakMode = NSLineBreakByWordWrapping;
168 |
169 | commentLabel.linkAttributes = @{ (NSString *)kCTForegroundColorAttributeName: [UIColor blueColor] };
170 | commentLabel.activeLinkAttributes = commentLabel.linkAttributes;
171 | commentLabel.inactiveLinkAttributes = commentLabel.linkAttributes;
172 |
173 | [self setCommentLabel:commentLabel text:text commenter:commenter];
174 |
175 | return commentLabel;
176 | }
177 |
178 | - (void)showAllComments:(id)sender
179 | {
180 | if ([self.delegate respondsToSelector:@selector(commentCellWillShowAllComments:)])
181 | [self.delegate commentCellWillShowAllComments:self];
182 | }
183 |
184 | #pragma mark - Attributed Label
185 |
186 | - (void)attributedLabel:(TTTAttributedLabel *)label didSelectLinkWithTextCheckingResult:(NSTextCheckingResult *)result
187 | {
188 | NSString *selectedText = [[label.attributedText string] substringWithRange:result.range];
189 | UALog(@"%@", selectedText);
190 |
191 | if ([selectedText hasPrefix:@"http://"] || [selectedText hasPrefix:@"https://"]) {
192 | NSURL *selectedURL = [NSURL URLWithString:selectedText];
193 |
194 | if (selectedURL) {
195 | if ([self.delegate respondsToSelector:@selector(commentCell:didSelectURL:)]) {
196 | [self.delegate commentCell:self didSelectURL:selectedURL];
197 | }
198 | return;
199 | }
200 | } else if ([selectedText hasPrefix:@"#"]) {
201 | NSString *hashtag = [selectedText substringFromIndex:1];
202 |
203 | if ([self.delegate respondsToSelector:@selector(commentCell:didSelectHashtag:)]) {
204 | [self.delegate commentCell:self didSelectHashtag:hashtag];
205 | }
206 | } else if ([selectedText hasPrefix:@"@"]) {
207 | NSString *mention = [selectedText substringFromIndex:1];
208 |
209 | if ([self.delegate respondsToSelector:@selector(commentCell:didSelectMention:)]) {
210 | [self.delegate commentCell:self didSelectMention:mention];
211 | }
212 | }
213 |
214 | if (self.cellStyle == STXCommentCellStyleShowAllComments) {
215 | [self showAllComments:label];
216 | } else {
217 | if ([self.delegate respondsToSelector:@selector(commentCell:willShowCommenter:)]) {
218 | [self.delegate commentCell:self willShowCommenter:[self.comment from]];
219 | }
220 | }
221 | }
222 |
223 | @end
224 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Cells/STXFeedPhotoCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // STXFeedPhotoCell.h
3 | // STXDynamicTableView
4 | //
5 | // Created by Triệu Khang on 24/3/14.
6 | // Copyright (c) 2014 2359 Media. All rights reserved.
7 | //
8 |
9 | @import UIKit;
10 |
11 | @protocol STXFeedPhotoCellDelegate
12 |
13 | @optional
14 |
15 | - (void)feedCellWillShowPoster:(id )poster;
16 |
17 | @end
18 |
19 | @interface STXFeedPhotoCell : UITableViewCell
20 |
21 | @property (strong, nonatomic) NSIndexPath *indexPath;
22 |
23 | @property (strong, nonatomic) id postItem;
24 | @property (strong, nonatomic) UIImage *photoImage;
25 |
26 | @property (weak, nonatomic) id delegate;
27 |
28 | - (void)cancelImageLoading;
29 |
30 | @end
31 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Cells/STXFeedPhotoCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // STXFeedPhotoCell.m
3 | // STXDynamicTableView
4 | //
5 | // Created by Triệu Khang on 24/3/14.
6 | // Copyright (c) 2014 2359 Media. All rights reserved.
7 | //
8 |
9 | #import "STXFeedPhotoCell.h"
10 |
11 | #import "UIImageView+Masking.h"
12 |
13 | @interface STXFeedPhotoCell ()
14 |
15 | @property (weak, nonatomic) IBOutlet UILabel *profileLabel;
16 | @property (weak, nonatomic) IBOutlet UILabel *dateLabel;
17 |
18 | @property (weak, nonatomic) IBOutlet UIImageView *profileImageView;
19 | @property (weak, nonatomic) IBOutlet UIImageView *postImageView;
20 |
21 | @end
22 |
23 | @implementation STXFeedPhotoCell
24 |
25 | - (void)awakeFromNib
26 | {
27 | [super awakeFromNib];
28 |
29 | self.profileImageView.userInteractionEnabled = YES;
30 |
31 | UITapGestureRecognizer *imageGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(profileTapped:)];
32 | [self.profileImageView addGestureRecognizer:imageGestureRecognizer];
33 |
34 | self.profileLabel.userInteractionEnabled = YES;
35 |
36 | UITapGestureRecognizer *labelGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(profileTapped:)];
37 | [self.profileLabel addGestureRecognizer:labelGestureRecognizer];
38 |
39 | self.dateLabel.backgroundColor = [self.dateLabel superview].backgroundColor;
40 |
41 | self.profileImageView.clipsToBounds = YES;
42 |
43 | self.postImageView.clipsToBounds = YES;
44 | }
45 |
46 | - (void)setSelected:(BOOL)selected animated:(BOOL)animated
47 | {
48 | [super setSelected:selected animated:animated];
49 | }
50 |
51 | - (void)setPostItem:(id)postItem
52 | {
53 | if (_postItem != postItem) {
54 | _postItem = postItem;
55 |
56 | self.dateLabel.textColor = [UIColor grayColor];
57 | self.dateLabel.text = [MHPrettyDate prettyDateFromDate:postItem.postDate withFormat:MHPrettyDateLongRelativeTime];
58 |
59 | id userItem = [postItem user];
60 | NSString *name = [userItem fullname];
61 | self.profileLabel.text = name;
62 | NSURL *profilePhotoURL = [userItem profilePictureURL];
63 |
64 | [self.profileImageView setCircleImageWithURL:profilePhotoURL placeholderImage:[UIImage imageNamed:@"ProfilePlaceholder"] borderWidth:2];
65 |
66 | [self.postImageView setImageWithURL:postItem.photoURL];
67 | }
68 | }
69 |
70 | - (UIImage *)photoImage
71 | {
72 | _photoImage = self.postImageView.image;
73 | return _photoImage;
74 | }
75 |
76 | - (void)cancelImageLoading
77 | {
78 | [self.profileImageView cancelImageRequestOperation];
79 | [self.profileImageView setCircleImageWithURL:nil placeholderImage:[UIImage imageNamed:@"ProfilePlaceholder"]];
80 |
81 | [self.postImageView cancelImageRequestOperation];
82 | self.postImageView.image = nil;
83 | }
84 |
85 | #pragma mark - Actions
86 |
87 | - (void)profileTapped:(UIGestureRecognizer *)recognizer
88 | {
89 | if ([self.delegate respondsToSelector:@selector(feedCellWillShowPoster:)])
90 | [self.delegate feedCellWillShowPoster:[self.postItem user]];
91 | }
92 |
93 | @end
94 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Cells/STXFeedPhotoCell.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
40 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Cells/STXLikesCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // STXLikesCell.h
3 | // STXDynamicTableViewExample
4 | //
5 | // Created by Jesse Armand on 10/4/14.
6 | // Copyright (c) 2014 2359 Media Pte Ltd. All rights reserved.
7 | //
8 |
9 | @import UIKit;
10 |
11 | typedef NS_ENUM(NSUInteger, STXLikesCellStyle) {
12 | STXLikesCellStyleLikesCount,
13 | STXLikesCellStyleLikers
14 | };
15 |
16 | @class STXLikesCell;
17 |
18 | @protocol STXLikesCellDelegate
19 |
20 | @optional
21 |
22 | - (void)likesCellWillShowLikes:(STXLikesCell *)likesCell;
23 | - (void)likesCellDidSelectLiker:(NSString *)liker;
24 |
25 | @end
26 |
27 | @interface STXLikesCell : UITableViewCell
28 |
29 | @property (copy, nonatomic) NSDictionary *likes;
30 |
31 | @property (weak, nonatomic) id delegate;
32 |
33 | - (instancetype)initWithStyle:(STXLikesCellStyle)style likes:(NSDictionary *)likes reuseIdentifier:(NSString *)reuseIdentifier;
34 |
35 | @end
36 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Cells/STXLikesCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // STXLikesCell.m
3 | // STXDynamicTableViewExample
4 | //
5 | // Created by Jesse Armand on 10/4/14.
6 | // Copyright (c) 2014 2359 Media Pte Ltd. All rights reserved.
7 | //
8 |
9 | #import "STXLikesCell.h"
10 |
11 | static CGFloat STXLikesViewLeadingEdgeInset = 10.f;
12 | static CGFloat STXLikesViewTrailingEdgeInset = 10.f;
13 |
14 | @interface STXLikesCell ()
15 |
16 | @property (nonatomic) BOOL didSetupConstraints;
17 |
18 | @property (nonatomic) STXLikesCellStyle cellStyle;
19 | @property (strong, nonatomic) TTTAttributedLabel *likesLabel;
20 |
21 | @end
22 |
23 | @implementation STXLikesCell
24 |
25 | - (instancetype)initWithStyle:(STXLikesCellStyle)style likes:(NSDictionary *)likes reuseIdentifier:(NSString *)reuseIdentifier
26 | {
27 | self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier];
28 | if (self) {
29 | _cellStyle = style;
30 |
31 | if (style == STXLikesCellStyleLikesCount) {
32 | NSInteger count = [[likes valueForKey:@"count"] integerValue];
33 | _likesLabel = [self likesLabelForCount:count];
34 | } else {
35 | NSArray *likers = [likes valueForKey:@"data"];
36 | _likesLabel = [self likersLabelForLikers:likers];
37 | }
38 |
39 | [self.contentView addSubview:_likesLabel];
40 | _likesLabel.translatesAutoresizingMaskIntoConstraints = NO;
41 |
42 | self.selectionStyle = UITableViewCellSelectionStyleNone;
43 | }
44 | return self;
45 | }
46 |
47 | - (void)setSelected:(BOOL)selected animated:(BOOL)animated
48 | {
49 | [super setSelected:selected animated:animated];
50 | }
51 |
52 | - (void)layoutSubviews
53 | {
54 | [super layoutSubviews];
55 |
56 | self.likesLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.frame) - (STXLikesViewLeadingEdgeInset + STXLikesViewTrailingEdgeInset);
57 | }
58 |
59 | - (void)updateConstraints
60 | {
61 | if (!self.didSetupConstraints) {
62 | [self.likesLabel autoPinEdgesToSuperviewEdgesWithInsets:UIEdgeInsetsMake(0, STXLikesViewLeadingEdgeInset, 0, STXLikesViewTrailingEdgeInset)];
63 |
64 | self.didSetupConstraints = YES;
65 | }
66 |
67 | [super updateConstraints];
68 | }
69 |
70 | - (void)setLikes:(NSDictionary *)likes
71 | {
72 | if (_likes != likes) {
73 | _likes = likes;
74 |
75 | NSInteger count = [[likes valueForKey:@"count"] integerValue];
76 | if (count > 2) {
77 | [self setLikesLabel:self.likesLabel count:count];
78 | } else {
79 | NSArray *likers = [likes valueForKey:@"data"];
80 | [self setLikersLabel:self.likesLabel likers:likers];
81 | }
82 | }
83 | }
84 |
85 | #pragma mark - Attributed Label
86 |
87 | - (void)setLikesLabel:(TTTAttributedLabel *)likesLabel count:(NSInteger)count
88 | {
89 | NSString *countString = [@(count) stringValue];
90 | NSString *title = [NSString stringWithFormat:NSLocalizedString(@"%@ loves", nil), countString];
91 | likesLabel.text = title;
92 | }
93 |
94 | - (void)setLikersLabel:(TTTAttributedLabel *)likersLabel likers:(NSArray *)likers
95 | {
96 | NSMutableString *likersString = [NSMutableString stringWithCapacity:0];
97 | NSUInteger likerIndex = 0;
98 | NSArray *likerNames = [likers valueForKey:@"name"];
99 | for (NSString *likerName in likerNames) {
100 | if ([likerName length] > 0) {
101 | if (likerIndex == 0)
102 | [likersString setString:likerName];
103 | else
104 | [likersString appendFormat:NSLocalizedString(@" and %@", nil), likerName];
105 | }
106 |
107 | ++likerIndex;
108 | }
109 |
110 | if ([likersString length] > 0) {
111 | if ([likerNames count] == 1) {
112 | [likersString appendString:NSLocalizedString(@" loves this", nil)];
113 | } else {
114 | [likersString appendString:NSLocalizedString(@" love this", nil)];
115 | }
116 | }
117 |
118 | NSMutableArray *textCheckingResults = [NSMutableArray array];
119 |
120 | NSString *likersText = [likersString copy];
121 |
122 | [likersLabel setText:likersText afterInheritingLabelAttributesAndConfiguringWithBlock:^NSMutableAttributedString *(NSMutableAttributedString *mutableAttributedString) {
123 |
124 | NSRange searchRange = NSMakeRange(0, [mutableAttributedString length]);
125 | for (NSString *likerName in likerNames) {
126 | NSRange currentRange = [[mutableAttributedString string] rangeOfString:likerName options:NSLiteralSearch range:searchRange];
127 |
128 | NSTextCheckingResult *result = [NSTextCheckingResult linkCheckingResultWithRange:currentRange URL:nil];
129 | [textCheckingResults addObject:result];
130 |
131 | searchRange = NSMakeRange(currentRange.length, [mutableAttributedString length] - currentRange.length);
132 | }
133 |
134 | return mutableAttributedString;
135 | }];
136 |
137 |
138 | for (NSTextCheckingResult *result in textCheckingResults)
139 | [likersLabel addLinkWithTextCheckingResult:result];
140 | }
141 |
142 | - (TTTAttributedLabel *)likesLabelForCount:(NSInteger)count
143 | {
144 | TTTAttributedLabel *likesLabel = [TTTAttributedLabel newAutoLayoutView];
145 | likesLabel.textColor = [UIColor blueColor];
146 | likesLabel.delegate = self;
147 |
148 | [self setLikesLabel:likesLabel count:count];
149 |
150 | UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(showLikers:)];
151 | [likesLabel addGestureRecognizer:recognizer];
152 |
153 | return likesLabel;
154 | }
155 |
156 | - (TTTAttributedLabel *)likersLabelForLikers:(NSArray *)likers
157 | {
158 | TTTAttributedLabel *likersLabel = [TTTAttributedLabel newAutoLayoutView];
159 | likersLabel.enabledTextCheckingTypes = NSTextCheckingTypeLink;
160 | likersLabel.numberOfLines = 0;
161 | likersLabel.lineBreakMode = NSLineBreakByWordWrapping;
162 | likersLabel.delegate = self;
163 |
164 | likersLabel.linkAttributes = @{ (NSString *)kCTForegroundColorAttributeName: [UIColor blueColor],
165 | (NSString *)kCTUnderlineStyleAttributeName : @(kCTUnderlineStyleNone) };
166 | likersLabel.activeLinkAttributes = likersLabel.linkAttributes;
167 | likersLabel.inactiveLinkAttributes = likersLabel.linkAttributes;
168 |
169 | [self setLikersLabel:likersLabel likers:likers];
170 |
171 | return likersLabel;
172 | }
173 |
174 | #pragma mark - Actions
175 |
176 | - (void)showLikers:(id)sender
177 | {
178 | if ([self.delegate respondsToSelector:@selector(likesCellWillShowLikes:)])
179 | [self.delegate likesCellWillShowLikes:self];
180 | }
181 |
182 | #pragma mark - Attributed Label
183 |
184 | - (void)attributedLabel:(TTTAttributedLabel *)label didSelectLinkWithTextCheckingResult:(NSTextCheckingResult *)result
185 | {
186 | NSString *string = [[label.attributedText string] substringWithRange:result.range];
187 | UALog(@"%@", string);
188 |
189 | if ([self.delegate respondsToSelector:@selector(likesCellDidSelectLiker:)])
190 | [self.delegate likesCellDidSelectLiker:string];
191 | }
192 |
193 | @end
194 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Cells/STXUserActionCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // STXUserActionCell.h
3 | // STXDynamicTableViewExample
4 | //
5 | // Created by Jesse Armand on 10/4/14.
6 | // Copyright (c) 2014 2359 Media Pte Ltd. All rights reserved.
7 | //
8 |
9 | @import UIKit;
10 |
11 | @class STXUserActionCell;
12 |
13 | @protocol STXUserActionDelegate
14 |
15 | - (void)userWillComment:(STXUserActionCell *)userActionCell;
16 | - (void)userWillShare:(STXUserActionCell *)userActionCell;
17 |
18 | - (void)userDidLike:(STXUserActionCell *)userActionCell;
19 | - (void)userDidUnlike:(STXUserActionCell *)userActionCell;
20 |
21 | @end
22 |
23 | @interface STXUserActionCell : UITableViewCell
24 |
25 | @property (weak, nonatomic) id delegate;
26 |
27 | @property (copy, nonatomic) id postItem;
28 | @property (copy, nonatomic) NSIndexPath *indexPath;
29 |
30 | @end
31 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Cells/STXUserActionCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // STXUserActionCell.m
3 | // STXDynamicTableViewExample
4 | //
5 | // Created by Jesse Armand on 10/4/14.
6 | // Copyright (c) 2014 2359 Media Pte Ltd. All rights reserved.
7 | //
8 |
9 | #import "STXUserActionCell.h"
10 |
11 | #import "UIButton+STXButton.h"
12 |
13 | @interface STXUserActionCell ()
14 |
15 | @property (weak, nonatomic) IBOutlet UIButton *likeButton;
16 | @property (weak, nonatomic) IBOutlet UIButton *commentButton;
17 | @property (weak, nonatomic) IBOutlet UIButton *shareButton;
18 | @property (weak, nonatomic) IBOutlet UIView *buttonDividerLeft;
19 | @property (weak, nonatomic) IBOutlet UIView *buttonDividerRight;
20 |
21 | @end
22 |
23 | @implementation STXUserActionCell
24 |
25 | - (void)awakeFromNib
26 | {
27 | self.buttonDividerLeft.backgroundColor = [UIColor grayColor];
28 | self.buttonDividerRight.backgroundColor = [UIColor grayColor];
29 |
30 | self.selectionStyle = UITableViewCellSelectionStyleNone;
31 | }
32 |
33 | - (void)layoutSubviews
34 | {
35 | [super layoutSubviews];
36 |
37 | if ([self.postItem liked]) {
38 | [self setButton:self.likeButton toLoved:YES];
39 | } else {
40 | [self setButton:self.likeButton toLoved:NO];
41 | }
42 | }
43 |
44 | - (void)setSelected:(BOOL)selected animated:(BOOL)animated
45 | {
46 | [super setSelected:selected animated:animated];
47 | }
48 |
49 | - (void)setPostItem:(id)postItem
50 | {
51 | _postItem = postItem;
52 |
53 | NSString *likeButtonTitle = postItem.liked ? NSLocalizedString(@"Loved", nil) : NSLocalizedString(@"Love", nil);
54 | [self.likeButton setTitle:likeButtonTitle forState:UIControlStateNormal];
55 |
56 | if (postItem.liked) {
57 | [self.likeButton stx_setSelectedAppearance];
58 | } else {
59 | [self.likeButton stx_setNormalAppearance];
60 | }
61 | }
62 |
63 | #pragma mark - Action
64 |
65 | - (void)setButton:(UIButton *)button toLoved:(BOOL)loved
66 | {
67 | if (loved) {
68 | [button setTitle:NSLocalizedString(@"Loved", nil) forState:UIControlStateNormal];
69 | [button stx_setSelectedAppearance];
70 | } else {
71 | [button setTitle:NSLocalizedString(@"Love", nil) forState:UIControlStateNormal];
72 | [button stx_setNormalAppearance];
73 | }
74 | }
75 |
76 | - (IBAction)like:(id)sender
77 | {
78 | // Need to return here if it's disabled, or the buttons may do a delayed
79 | // update.
80 | if (![sender isUserInteractionEnabled]) {
81 | return;
82 | }
83 |
84 | // Prevent rapid interaction
85 | [sender setUserInteractionEnabled:NO];
86 |
87 | if (![self.postItem liked]) {
88 | [self setButton:sender toLoved:YES];
89 |
90 | if ([self.delegate respondsToSelector:@selector(userDidLike:)]) {
91 | [self.delegate userDidLike:self];
92 | }
93 | } else {
94 | [self setButton:sender toLoved:NO];
95 |
96 | if ([self.delegate respondsToSelector:@selector(userDidUnlike:)]) {
97 | [self.delegate userDidUnlike:self];
98 | }
99 | }
100 | }
101 |
102 | - (IBAction)comment:(id)sender
103 | {
104 | if ([self.delegate respondsToSelector:@selector(userWillComment:)]) {
105 | [self.delegate userWillComment:self];
106 | }
107 | }
108 |
109 | - (IBAction)share:(id)sender
110 | {
111 | if ([self.delegate respondsToSelector:@selector(userWillShare:)]) {
112 | [self.delegate userWillShare:self];
113 | }
114 | }
115 |
116 | @end
117 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Cells/STXUserActionCell.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
38 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Items/STXCommentItem.h:
--------------------------------------------------------------------------------
1 | //
2 | // STXCommentItem.h
3 | // STXDynamicTableViewExample
4 | //
5 | // Created by Jesse Armand on 3/4/14.
6 | // Copyright (c) 2014 2359 Media Pte Ltd. All rights reserved.
7 | //
8 |
9 | @import Foundation;
10 |
11 | @protocol STXUserItem;
12 |
13 | @protocol STXCommentItem
14 |
15 | - (id)from;
16 |
17 | - (NSString *)commentID;
18 | - (NSString *)text;
19 | - (NSDate *)postDate;
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Items/STXPostItem.h:
--------------------------------------------------------------------------------
1 | //
2 | // STXPostItem.h
3 | // STXDynamicTableViewExample
4 | //
5 | // Created by Jesse Armand on 3/4/14.
6 | // Copyright (c) 2014 2359 Media Pte Ltd. All rights reserved.
7 | //
8 |
9 | @import Foundation;
10 |
11 | @protocol STXUserItem;
12 |
13 | @protocol STXPostItem
14 |
15 | - (NSString *)postID;
16 | - (NSDate *)postDate;
17 | - (NSURL *)sharedURL;
18 | - (NSURL *)photoURL;
19 | - (NSString *)captionText;
20 | - (NSDictionary *)caption;
21 | - (NSDictionary *)likes;
22 | - (NSArray *)comments;
23 |
24 | - (BOOL)liked;
25 |
26 | - (NSInteger)totalLikes;
27 | - (NSInteger)totalComments;
28 |
29 | - (id)user;
30 |
31 | @end
32 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Items/STXUserItem.h:
--------------------------------------------------------------------------------
1 | //
2 | // STXUserItem.h
3 | // STXDynamicTableViewExample
4 | //
5 | // Created by Jesse Armand on 3/4/14.
6 | // Copyright (c) 2014 2359 Media Pte Ltd. All rights reserved.
7 | //
8 |
9 | @import Foundation;
10 |
11 | @protocol STXUserItem
12 |
13 | - (NSString *)userID;
14 | - (NSString *)username;
15 | - (NSString *)fullname;
16 | - (NSURL *)profilePictureURL;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Labels/STXAttributedLabel.h:
--------------------------------------------------------------------------------
1 | //
2 | // STXAttributedLabel.h
3 | // STXDynamicTableView
4 | //
5 | // Created by Jesse Armand on 19/3/14.
6 | // Copyright (c) 2014 2359 Media. All rights reserved.
7 | //
8 |
9 | #import "TTTAttributedLabel.h"
10 |
11 | @interface STXAttributedLabel : TTTAttributedLabel
12 |
13 | - (instancetype)initForParagraphStyleWithText:(NSString *)text;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Labels/STXAttributedLabel.m:
--------------------------------------------------------------------------------
1 | //
2 | // STXAttributedLabel.m
3 | // STXDynamicTableView
4 | //
5 | // Created by Jesse Armand on 19/3/14.
6 | // Copyright (c) 2014 2359 Media. All rights reserved.
7 | //
8 |
9 | #import "STXAttributedLabel.h"
10 | #import "NSString+Emoji.h"
11 |
12 | static CGFloat STXAttributedLabelHeightPadding = 4.f;
13 |
14 | @implementation STXAttributedLabel
15 |
16 | - (instancetype)initForParagraphStyleWithText:(NSString *)text
17 | {
18 | self = [super init];
19 | if (self) {
20 | if ([text stringContainsEmoji]) {
21 | UIFont *commentFont = self.font;
22 | UIFont *emojiFont = [UIFont fontWithName:@"AppleColorEmoji" size:commentFont.pointSize];
23 | if (emojiFont.lineHeight > commentFont.lineHeight) {
24 | self.minimumLineHeight = emojiFont.lineHeight;
25 | self.lineHeightMultiple = emojiFont.lineHeight / commentFont.lineHeight;
26 | }
27 | }
28 | }
29 |
30 | return self;
31 | }
32 |
33 | - (CGSize)intrinsicContentSize
34 | {
35 | CGSize intrinsicContentSize = [super intrinsicContentSize];
36 | return CGSizeMake(intrinsicContentSize.width, intrinsicContentSize.height + STXAttributedLabelHeightPadding);
37 | }
38 |
39 | @end
40 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Labels/STXLabel.h:
--------------------------------------------------------------------------------
1 | //
2 | // STXLabel.h
3 | // STXDynamicTableView
4 | //
5 | // Created by Hoang Ta on 3/19/14.
6 | // Copyright (c) 2014 2359 Media. All rights reserved.
7 | //
8 |
9 | @import UIKit;
10 |
11 | @interface STXLabel : UILabel
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Labels/STXLabel.m:
--------------------------------------------------------------------------------
1 | //
2 | // STXLabel.m
3 | // STXDynamicTableView
4 | //
5 | // Created by Hoang Ta on 3/19/14.
6 | // Copyright (c) 2014 2359 Media. All rights reserved.
7 | //
8 |
9 | #import "STXLabel.h"
10 |
11 | #import "NSString+Emoji.h"
12 |
13 | @implementation STXLabel
14 |
15 | - (instancetype)initWithFrame:(CGRect)frame
16 | {
17 | self = [super initWithFrame:frame];
18 | if (self) {
19 | [self stx_setupAppearance];
20 | }
21 | return self;
22 | }
23 |
24 | - (instancetype)init
25 | {
26 | self = [super init];
27 | if (self) {
28 | [self stx_setupAppearance];
29 | }
30 | return self;
31 | }
32 |
33 | - (void)awakeFromNib
34 | {
35 | [super awakeFromNib];
36 |
37 | [self stx_setupAppearance];
38 | }
39 |
40 | - (void)stx_setupAppearance
41 | {
42 | }
43 |
44 | - (CGSize)intrinsicContentSize
45 | {
46 | CGSize intrinsicContentSize = [super intrinsicContentSize];
47 | if ([self.text stringContainsEmoji]) {
48 | UIFont *emojiFont = [UIFont fontWithName:@"AppleColorEmoji" size:self.font.pointSize];
49 | intrinsicContentSize.height = emojiFont.lineHeight;
50 | }
51 |
52 | return intrinsicContentSize;
53 | }
54 |
55 | @end
56 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Protocols/STXFeedTableViewDataSource.h:
--------------------------------------------------------------------------------
1 | //
2 | // STXFeedTableViewDataSource.h
3 | // STXDynamicTableView
4 | //
5 | // Created by Jesse Armand on 27/3/14.
6 | // Copyright (c) 2014 2359 Media. All rights reserved.
7 | //
8 |
9 | @import Foundation;
10 | @import UIKit;
11 |
12 | @protocol STXFeedPhotoCellDelegate;
13 | @protocol STXLikesCellDelegate;
14 | @protocol STXCaptionCellDelegate;
15 | @protocol STXCommentCellDelegate;
16 | @protocol STXUserActionDelegate;
17 |
18 | @class STXLikesCell;
19 | @class STXCaptionCell;
20 | @class STXCommentCell;
21 |
22 | @interface STXFeedTableViewDataSource : NSObject
23 |
24 | @property (copy, nonatomic) NSArray *posts;
25 |
26 | - (instancetype)initWithController:(id)controller
27 | tableView:(UITableView *)tableView;
28 |
29 | - (STXLikesCell *)likesCellForTableView:(UITableView *)tableView atIndexPath:(NSIndexPath *)indexPath;
30 | - (STXCaptionCell *)captionCellForTableView:(UITableView *)tableView atIndexPath:(NSIndexPath *)indexPath;
31 | - (STXCommentCell *)commentCellForTableView:(UITableView *)tableView atIndexPath:(NSIndexPath *)indexPath;
32 |
33 | @end
34 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Protocols/STXFeedTableViewDataSource.m:
--------------------------------------------------------------------------------
1 | //
2 | // STXFeedTableViewDataSource.m
3 | // STXDynamicTableView
4 | //
5 | // Created by Jesse Armand on 27/3/14.
6 | // Copyright (c) 2014 2359 Media. All rights reserved.
7 | //
8 |
9 | #import "STXFeedTableViewDataSource.h"
10 |
11 | #import "STXFeedPhotoCell.h"
12 | #import "STXLikesCell.h"
13 | #import "STXCaptionCell.h"
14 | #import "STXCommentCell.h"
15 | #import "STXUserActionCell.h"
16 |
17 | #define PHOTO_CELL_ROW 0
18 | #define LIKES_CELL_ROW 1
19 | #define CAPTION_CELL_ROW 2
20 |
21 | #define NUMBER_OF_STATIC_ROWS 4
22 | #define MAX_NUMBER_OF_COMMENTS 5
23 |
24 | @interface STXFeedTableViewDataSource ()
25 |
26 | @property (weak, nonatomic) id controller;
27 |
28 | @end
29 |
30 | @implementation STXFeedTableViewDataSource
31 |
32 | - (instancetype)initWithController:(id)controller
33 | tableView:(UITableView *)tableView
34 | {
35 | self = [super init];
36 | if (self) {
37 | _controller = controller;
38 |
39 | NSString *feedPhotoCellIdentifier = NSStringFromClass([STXFeedPhotoCell class]);
40 | UINib *feedPhotoCellNib = [UINib nibWithNibName:feedPhotoCellIdentifier bundle:nil];
41 | [tableView registerNib:feedPhotoCellNib forCellReuseIdentifier:feedPhotoCellIdentifier];
42 |
43 | NSString *userActionCellIdentifier = NSStringFromClass([STXUserActionCell class]);
44 | UINib *userActionCellNib = [UINib nibWithNibName:userActionCellIdentifier bundle:nil];
45 | [tableView registerNib:userActionCellNib forCellReuseIdentifier:userActionCellIdentifier];
46 | }
47 |
48 | return self;
49 | }
50 |
51 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
52 | {
53 | return [self.posts count];
54 | }
55 |
56 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
57 | {
58 | id postItem = self.posts[section];
59 | NSInteger commentsCount = MIN(MAX_NUMBER_OF_COMMENTS, [postItem totalComments]);
60 | return NUMBER_OF_STATIC_ROWS + commentsCount;
61 | }
62 |
63 | - (STXFeedPhotoCell *)photoCellForTableView:(UITableView *)tableView atIndexPath:(NSIndexPath *)indexPath
64 | {
65 | NSString *CellIdentifier = NSStringFromClass([STXFeedPhotoCell class]);
66 | STXFeedPhotoCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
67 | cell.selectionStyle = UITableViewCellSelectionStyleNone;
68 |
69 | if (cell.indexPath != nil && cell.indexPath.section != indexPath.section) {
70 | [cell cancelImageLoading];
71 | }
72 |
73 | cell.indexPath = indexPath;
74 |
75 | if (indexPath.section < [self.posts count]) {
76 | id post = self.posts[indexPath.section];
77 | cell.postItem = post;
78 | cell.delegate = self.controller;
79 | }
80 |
81 | return cell;
82 | }
83 |
84 | - (STXLikesCell *)likesCellForTableView:(UITableView *)tableView atIndexPath:(NSIndexPath *)indexPath
85 | {
86 | id post = self.posts[indexPath.section];
87 | STXLikesCell *cell;
88 |
89 | if (cell == nil) {
90 | NSDictionary *likes = [post likes];
91 | NSInteger count = [[likes valueForKey:@"count"] integerValue];
92 | if (count > 2) {
93 | static NSString *CellIdentifier = @"STXLikesCountCell";
94 | cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
95 | if (cell == nil) {
96 | cell = [[STXLikesCell alloc] initWithStyle:STXLikesCellStyleLikesCount likes:likes reuseIdentifier:CellIdentifier];
97 | }
98 | } else {
99 | static NSString *CellIdentifier = @"STXLikersCell";
100 | cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
101 | if (cell == nil) {
102 | cell = [[STXLikesCell alloc] initWithStyle:STXLikesCellStyleLikers likes:likes reuseIdentifier:CellIdentifier];
103 | }
104 | }
105 |
106 | cell.delegate = self.controller;
107 | }
108 |
109 | cell.likes = [post likes];
110 |
111 | return cell;
112 | }
113 |
114 | - (STXCaptionCell *)captionCellForTableView:(UITableView *)tableView atIndexPath:(NSIndexPath *)indexPath
115 | {
116 | id post = self.posts[indexPath.section];
117 |
118 | NSString *CellIdentifier = NSStringFromClass([STXCaptionCell class]);
119 | STXCaptionCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
120 | if (cell == nil) {
121 | cell = [[STXCaptionCell alloc] initWithCaption:[post caption] reuseIdentifier:CellIdentifier];
122 | cell.delegate = self.controller;
123 | }
124 |
125 | cell.caption = [post caption];
126 |
127 | return cell;
128 | }
129 |
130 | - (STXCommentCell *)commentCellForTableView:(UITableView *)tableView atIndexPath:(NSIndexPath *)indexPath
131 | {
132 | id post = self.posts[indexPath.section];
133 | STXCommentCell *cell;
134 |
135 | if (indexPath.row == 0 && [post totalComments] > MAX_NUMBER_OF_COMMENTS) {
136 |
137 | static NSString *AllCommentsCellIdentifier = @"STXAllCommentsCell";
138 | cell = [tableView dequeueReusableCellWithIdentifier:AllCommentsCellIdentifier];
139 |
140 | if (cell == nil) {
141 | cell = [[STXCommentCell alloc] initWithStyle:STXCommentCellStyleShowAllComments
142 | totalComments:[post totalComments]
143 | reuseIdentifier:AllCommentsCellIdentifier];
144 | } else {
145 | cell.totalComments = [post totalComments];
146 | }
147 |
148 | } else {
149 | static NSString *CellIdentifier = @"STXSingleCommentCell";
150 | cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
151 |
152 | NSArray *comments = [post comments];
153 | id comment = comments[indexPath.row];
154 |
155 | if (indexPath.row < [comments count]) {
156 | if (cell == nil) {
157 | cell = [[STXCommentCell alloc] initWithStyle:STXCommentCellStyleSingleComment
158 | comment:comment
159 | reuseIdentifier:CellIdentifier];
160 | } else {
161 | cell.comment = comment;
162 | }
163 | }
164 | }
165 |
166 | cell.delegate = self.controller;
167 |
168 | return cell;
169 | }
170 |
171 | - (STXUserActionCell *)userActionCellForTableView:(UITableView *)tableView atIndexPath:(NSIndexPath *)indexPath
172 | {
173 | STXUserActionCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([STXUserActionCell class]) forIndexPath:indexPath];
174 | cell.delegate = self.controller;
175 | return cell;
176 | }
177 |
178 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
179 | {
180 | UITableViewCell *cell;
181 |
182 | NSInteger captionRowOffset = 3;
183 |
184 | id postItem = self.posts[indexPath.section];
185 | NSInteger commentsCount = MIN(MAX_NUMBER_OF_COMMENTS, [postItem totalComments]);
186 | NSInteger commentsRowLimit = captionRowOffset + commentsCount;
187 |
188 | if (indexPath.row == PHOTO_CELL_ROW) {
189 | cell = [self photoCellForTableView:tableView atIndexPath:indexPath];
190 | } else if (indexPath.row == LIKES_CELL_ROW) {
191 | cell = [self likesCellForTableView:tableView atIndexPath:indexPath];
192 | } else if (indexPath.row == CAPTION_CELL_ROW) {
193 | cell = [self captionCellForTableView:tableView atIndexPath:indexPath];
194 | } else if (indexPath.row > CAPTION_CELL_ROW && indexPath.row < commentsRowLimit) {
195 | NSIndexPath *commentIndexPath = [NSIndexPath indexPathForRow:indexPath.row-captionRowOffset inSection:indexPath.section];
196 | cell = [self commentCellForTableView:tableView atIndexPath:commentIndexPath];
197 | } else {
198 | cell = [self userActionCellForTableView:tableView atIndexPath:indexPath];
199 | }
200 |
201 | [cell setNeedsUpdateConstraints];
202 | [cell updateConstraintsIfNeeded];
203 |
204 | return cell;
205 | }
206 |
207 | @end
208 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Protocols/STXFeedTableViewDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // STXFeedTableViewDelegate.h
3 | // STXDynamicTableView
4 | //
5 | // Created by Jesse Armand on 27/3/14.
6 | // Copyright (c) 2014 2359 Media. All rights reserved.
7 | //
8 |
9 | @import Foundation;
10 |
11 | @protocol STXFeedPhotoCellDelegate;
12 | @protocol STXLikesCellDelegate;
13 | @protocol STXCaptionCellDelegate;
14 | @protocol STXCommentCellDelegate;
15 | @protocol STXUserActionDelegate;
16 |
17 | @interface STXFeedTableViewDelegate : NSObject
18 |
19 | @property (nonatomic) BOOL insertingRow;
20 |
21 | - (instancetype)initWithController:(id)controller;
22 |
23 | - (void)reloadAtIndexPath:(NSIndexPath *)indexPath forTableView:(UITableView *)tableView;
24 |
25 | @end
26 |
--------------------------------------------------------------------------------
/STXDynamicTableView/Protocols/STXFeedTableViewDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // STXFeedTableViewDelegate.m
3 | // STXDynamicTableView
4 | //
5 | // Created by Jesse Armand on 27/3/14.
6 | // Copyright (c) 2014 2359 Media. All rights reserved.
7 | //
8 |
9 | #import "STXFeedTableViewDelegate.h"
10 | #import "STXFeedTableViewDataSource.h"
11 |
12 | #import "STXFeedPhotoCell.h"
13 | #import "STXLikesCell.h"
14 | #import "STXCaptionCell.h"
15 | #import "STXCommentCell.h"
16 | #import "STXUserActionCell.h"
17 |
18 | #import "STXPostItem.h"
19 |
20 | #define PHOTO_CELL_ROW 0
21 | #define LIKES_CELL_ROW 1
22 | #define CAPTION_CELL_ROW 2
23 |
24 | #define MAX_NUMBER_OF_COMMENTS 5
25 |
26 | static CGFloat const PhotoCellRowHeight = 344;
27 | static CGFloat const UserActionCellHeight = 44;
28 |
29 | @interface STXFeedTableViewDelegate ()
30 |
31 | @property (weak, nonatomic) id controller;
32 |
33 | @end
34 |
35 | @implementation STXFeedTableViewDelegate
36 |
37 | - (instancetype)initWithController:(id)controller
38 | {
39 | self = [super init];
40 | if (self) {
41 | _controller = controller;
42 | }
43 |
44 | return self;
45 | }
46 |
47 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
48 | {
49 | if (indexPath.row == PHOTO_CELL_ROW) {
50 | return PhotoCellRowHeight;
51 | }
52 |
53 | return UITableViewAutomaticDimension;
54 | }
55 |
56 | - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
57 | {
58 | if (indexPath.row == PHOTO_CELL_ROW) {
59 | return PhotoCellRowHeight;
60 | }
61 |
62 | return UserActionCellHeight;
63 | }
64 |
65 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
66 | {
67 | [tableView deselectRowAtIndexPath:indexPath animated:NO];
68 | }
69 |
70 | #pragma mark - Row Updates
71 |
72 | - (void)reloadAtIndexPath:(NSIndexPath *)indexPath forTableView:(UITableView *)tableView
73 | {
74 | self.insertingRow = YES;
75 |
76 | [tableView reloadSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationNone];
77 | }
78 |
79 | #pragma mark - Scroll View
80 |
81 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView
82 | {
83 | id scrollViewDelegate = (id)self.controller;
84 | if ([scrollViewDelegate respondsToSelector:@selector(scrollViewDidScroll:)]) {
85 | [scrollViewDelegate scrollViewDidScroll:scrollView];
86 | }
87 | }
88 |
89 | @end
90 |
--------------------------------------------------------------------------------
/STXDynamicTableView/STXDynamicTableView.h:
--------------------------------------------------------------------------------
1 | //
2 | // STXDynamicTableView.h
3 | // STXDynamicTableViewExample
4 | //
5 | // Created by Jesse Armand on 3/4/14.
6 | // Copyright (c) 2014 2359 Media Pte Ltd. All rights reserved.
7 | //
8 |
9 | #import "STXUserItem.h"
10 | #import "STXPostItem.h"
11 | #import "STXCommentItem.h"
12 |
13 | #import "STXFeedTableViewDelegate.h"
14 | #import "STXFeedTableViewDataSource.h"
15 |
16 | #import "UIViewController+Indicator.h"
17 | #import "UIViewController+Sharing.h"
18 |
19 | #import "STXFeedPhotoCell.h"
20 | #import "STXLikesCell.h"
21 | #import "STXCaptionCell.h"
22 | #import "STXCommentCell.h"
23 | #import "STXUserActionCell.h"
24 |
--------------------------------------------------------------------------------
/STXDynamicTableViewExample.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 010BA83218EC11D40030AF40 /* STXFeedPhotoCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 010BA82318EC11D40030AF40 /* STXFeedPhotoCell.m */; };
11 | 010BA83318EC11D40030AF40 /* STXFeedPhotoCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 010BA82418EC11D40030AF40 /* STXFeedPhotoCell.xib */; };
12 | 010BA83618EC11D40030AF40 /* STXAttributedLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = 010BA82C18EC11D40030AF40 /* STXAttributedLabel.m */; };
13 | 010BA83718EC11D40030AF40 /* STXLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = 010BA82E18EC11D40030AF40 /* STXLabel.m */; };
14 | 010BA83C18ED10800030AF40 /* NSString+Emoji.m in Sources */ = {isa = PBXBuildFile; fileRef = 010BA83B18ED10800030AF40 /* NSString+Emoji.m */; };
15 | 010BA83D18ED10800030AF40 /* NSString+Emoji.m in Sources */ = {isa = PBXBuildFile; fileRef = 010BA83B18ED10800030AF40 /* NSString+Emoji.m */; };
16 | 010BA84718ED43AC0030AF40 /* STXFeedViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 010BA84618ED43AC0030AF40 /* STXFeedViewController.m */; };
17 | 010BA85A18ED5D680030AF40 /* UIViewController+Indicator.m in Sources */ = {isa = PBXBuildFile; fileRef = 010BA85918ED5D680030AF40 /* UIViewController+Indicator.m */; };
18 | 011A76A51BC41EC300B0A046 /* Feed.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 011A76A41BC41EC300B0A046 /* Feed.storyboard */; settings = {ASSET_TAGS = (); }; };
19 | 011A76A71BC4213700B0A046 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 011A76A61BC4213700B0A046 /* LaunchScreen.storyboard */; settings = {ASSET_TAGS = (); }; };
20 | 011A76AD1BC4283F00B0A046 /* STXFeedTableViewDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 011A76AA1BC4283F00B0A046 /* STXFeedTableViewDataSource.m */; settings = {ASSET_TAGS = (); }; };
21 | 011A76AE1BC4283F00B0A046 /* STXFeedTableViewDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 011A76AC1BC4283F00B0A046 /* STXFeedTableViewDelegate.m */; settings = {ASSET_TAGS = (); }; };
22 | 017D674A18F6771800DD096A /* STXLikesCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 017D674818F6771800DD096A /* STXLikesCell.m */; };
23 | 017D674F18F6773100DD096A /* STXCaptionCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 017D674D18F6773100DD096A /* STXCaptionCell.m */; };
24 | 0196482518EAB434001185C3 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0196482418EAB434001185C3 /* Foundation.framework */; };
25 | 0196482718EAB434001185C3 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0196482618EAB434001185C3 /* CoreGraphics.framework */; };
26 | 0196482918EAB434001185C3 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0196482818EAB434001185C3 /* UIKit.framework */; };
27 | 0196482F18EAB434001185C3 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0196482D18EAB434001185C3 /* InfoPlist.strings */; };
28 | 0196483118EAB434001185C3 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 0196483018EAB434001185C3 /* main.m */; };
29 | 0196483518EAB434001185C3 /* STXAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 0196483418EAB434001185C3 /* STXAppDelegate.m */; };
30 | 0196483718EAB434001185C3 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0196483618EAB434001185C3 /* Images.xcassets */; };
31 | 0196483E18EAB434001185C3 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0196483D18EAB434001185C3 /* XCTest.framework */; };
32 | 0196483F18EAB434001185C3 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0196482418EAB434001185C3 /* Foundation.framework */; };
33 | 0196484018EAB434001185C3 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0196482818EAB434001185C3 /* UIKit.framework */; };
34 | 0196484818EAB434001185C3 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0196484618EAB434001185C3 /* InfoPlist.strings */; };
35 | 0196484A18EAB434001185C3 /* STXDynamicTableViewExampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0196484918EAB434001185C3 /* STXDynamicTableViewExampleTests.m */; };
36 | 0196485518EAB48F001185C3 /* instagram_media_popular.json in Resources */ = {isa = PBXBuildFile; fileRef = 0196485418EAB48F001185C3 /* instagram_media_popular.json */; };
37 | 01C4B21B18F7A92100712436 /* STXComment.m in Sources */ = {isa = PBXBuildFile; fileRef = 01C4B21A18F7A92100712436 /* STXComment.m */; };
38 | 01E383A618F537150094BCC1 /* UIViewController+Sharing.m in Sources */ = {isa = PBXBuildFile; fileRef = 01E383A518F537150094BCC1 /* UIViewController+Sharing.m */; };
39 | 01E383AA18F539B00094BCC1 /* STXButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 01E383A918F539B00094BCC1 /* STXButton.m */; };
40 | 01E383AD18F53DDA0094BCC1 /* UIImageView+Masking.m in Sources */ = {isa = PBXBuildFile; fileRef = 01E383AC18F53DDA0094BCC1 /* UIImageView+Masking.m */; };
41 | 01E383B018F5491D0094BCC1 /* UIButton+STXButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 01E383AF18F5491D0094BCC1 /* UIButton+STXButton.m */; };
42 | 01E383B318F54B890094BCC1 /* UIImage+STXImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 01E383B218F54B890094BCC1 /* UIImage+STXImage.m */; };
43 | 01E383B918F55D390094BCC1 /* STXPost.m in Sources */ = {isa = PBXBuildFile; fileRef = 01E383B818F55D390094BCC1 /* STXPost.m */; };
44 | 01E383BC18F596050094BCC1 /* STXUser.m in Sources */ = {isa = PBXBuildFile; fileRef = 01E383BB18F596050094BCC1 /* STXUser.m */; };
45 | 01E383C018F638030094BCC1 /* STXCommentCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 01E383BE18F638030094BCC1 /* STXCommentCell.m */; };
46 | 01E383C518F65C6D0094BCC1 /* STXUserActionCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 01E383C318F65C6D0094BCC1 /* STXUserActionCell.m */; };
47 | 01E383C618F65C6D0094BCC1 /* STXUserActionCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 01E383C418F65C6D0094BCC1 /* STXUserActionCell.xib */; };
48 | 1A1DFC0356454E938E07048F /* libPods-STXDynamicTableViewExample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EAD1347E22D244BC88270CFB /* libPods-STXDynamicTableViewExample.a */; };
49 | /* End PBXBuildFile section */
50 |
51 | /* Begin PBXContainerItemProxy section */
52 | 0196484118EAB434001185C3 /* PBXContainerItemProxy */ = {
53 | isa = PBXContainerItemProxy;
54 | containerPortal = 0196481918EAB434001185C3 /* Project object */;
55 | proxyType = 1;
56 | remoteGlobalIDString = 0196482018EAB434001185C3;
57 | remoteInfo = STXDynamicTableViewExample;
58 | };
59 | /* End PBXContainerItemProxy section */
60 |
61 | /* Begin PBXFileReference section */
62 | 010BA82218EC11D40030AF40 /* STXFeedPhotoCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STXFeedPhotoCell.h; sourceTree = ""; };
63 | 010BA82318EC11D40030AF40 /* STXFeedPhotoCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STXFeedPhotoCell.m; sourceTree = ""; };
64 | 010BA82418EC11D40030AF40 /* STXFeedPhotoCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = STXFeedPhotoCell.xib; sourceTree = ""; };
65 | 010BA82B18EC11D40030AF40 /* STXAttributedLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STXAttributedLabel.h; sourceTree = ""; };
66 | 010BA82C18EC11D40030AF40 /* STXAttributedLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STXAttributedLabel.m; sourceTree = ""; };
67 | 010BA82D18EC11D40030AF40 /* STXLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STXLabel.h; sourceTree = ""; };
68 | 010BA82E18EC11D40030AF40 /* STXLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STXLabel.m; sourceTree = ""; };
69 | 010BA83A18ED10800030AF40 /* NSString+Emoji.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+Emoji.h"; sourceTree = ""; };
70 | 010BA83B18ED10800030AF40 /* NSString+Emoji.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+Emoji.m"; sourceTree = ""; };
71 | 010BA84518ED43AC0030AF40 /* STXFeedViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STXFeedViewController.h; sourceTree = ""; };
72 | 010BA84618ED43AC0030AF40 /* STXFeedViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STXFeedViewController.m; sourceTree = ""; };
73 | 010BA84B18ED4B610030AF40 /* STXPostItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STXPostItem.h; sourceTree = ""; };
74 | 010BA84F18ED4BD80030AF40 /* STXCommentItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STXCommentItem.h; sourceTree = ""; };
75 | 010BA85318ED4C150030AF40 /* STXUserItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STXUserItem.h; sourceTree = ""; };
76 | 010BA85718ED4F420030AF40 /* STXDynamicTableView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = STXDynamicTableView.h; sourceTree = ""; };
77 | 010BA85818ED5D680030AF40 /* UIViewController+Indicator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIViewController+Indicator.h"; sourceTree = ""; };
78 | 010BA85918ED5D680030AF40 /* UIViewController+Indicator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIViewController+Indicator.m"; sourceTree = ""; };
79 | 011A76A41BC41EC300B0A046 /* Feed.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = Feed.storyboard; path = ../Feed.storyboard; sourceTree = ""; };
80 | 011A76A61BC4213700B0A046 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = STXDynamicTableViewExample/LaunchScreen.storyboard; sourceTree = SOURCE_ROOT; };
81 | 011A76A91BC4283F00B0A046 /* STXFeedTableViewDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STXFeedTableViewDataSource.h; sourceTree = ""; };
82 | 011A76AA1BC4283F00B0A046 /* STXFeedTableViewDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STXFeedTableViewDataSource.m; sourceTree = ""; };
83 | 011A76AB1BC4283F00B0A046 /* STXFeedTableViewDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STXFeedTableViewDelegate.h; sourceTree = ""; };
84 | 011A76AC1BC4283F00B0A046 /* STXFeedTableViewDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STXFeedTableViewDelegate.m; sourceTree = ""; };
85 | 017D674718F6771800DD096A /* STXLikesCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STXLikesCell.h; sourceTree = ""; };
86 | 017D674818F6771800DD096A /* STXLikesCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STXLikesCell.m; sourceTree = ""; };
87 | 017D674C18F6773100DD096A /* STXCaptionCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STXCaptionCell.h; sourceTree = ""; };
88 | 017D674D18F6773100DD096A /* STXCaptionCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STXCaptionCell.m; sourceTree = ""; };
89 | 0196482118EAB434001185C3 /* STXDynamicTableViewExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = STXDynamicTableViewExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
90 | 0196482418EAB434001185C3 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
91 | 0196482618EAB434001185C3 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
92 | 0196482818EAB434001185C3 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
93 | 0196482C18EAB434001185C3 /* STXDynamicTableViewExample-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "STXDynamicTableViewExample-Info.plist"; sourceTree = ""; };
94 | 0196482E18EAB434001185C3 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; };
95 | 0196483018EAB434001185C3 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
96 | 0196483218EAB434001185C3 /* STXDynamicTableViewExample-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "STXDynamicTableViewExample-Prefix.pch"; sourceTree = ""; };
97 | 0196483318EAB434001185C3 /* STXAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = STXAppDelegate.h; sourceTree = ""; };
98 | 0196483418EAB434001185C3 /* STXAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = STXAppDelegate.m; sourceTree = ""; };
99 | 0196483618EAB434001185C3 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
100 | 0196483C18EAB434001185C3 /* STXDynamicTableViewExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = STXDynamicTableViewExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
101 | 0196483D18EAB434001185C3 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
102 | 0196484518EAB434001185C3 /* STXDynamicTableViewExampleTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "STXDynamicTableViewExampleTests-Info.plist"; sourceTree = ""; };
103 | 0196484718EAB434001185C3 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; };
104 | 0196484918EAB434001185C3 /* STXDynamicTableViewExampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = STXDynamicTableViewExampleTests.m; sourceTree = ""; };
105 | 0196485418EAB48F001185C3 /* instagram_media_popular.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = instagram_media_popular.json; sourceTree = ""; };
106 | 01C4B21918F7A92100712436 /* STXComment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STXComment.h; sourceTree = ""; };
107 | 01C4B21A18F7A92100712436 /* STXComment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STXComment.m; sourceTree = ""; };
108 | 01E383A418F537150094BCC1 /* UIViewController+Sharing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIViewController+Sharing.h"; sourceTree = ""; };
109 | 01E383A518F537150094BCC1 /* UIViewController+Sharing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIViewController+Sharing.m"; sourceTree = ""; };
110 | 01E383A818F539B00094BCC1 /* STXButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STXButton.h; sourceTree = ""; };
111 | 01E383A918F539B00094BCC1 /* STXButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STXButton.m; sourceTree = ""; };
112 | 01E383AB18F53DDA0094BCC1 /* UIImageView+Masking.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImageView+Masking.h"; sourceTree = ""; };
113 | 01E383AC18F53DDA0094BCC1 /* UIImageView+Masking.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImageView+Masking.m"; sourceTree = ""; };
114 | 01E383AE18F5491D0094BCC1 /* UIButton+STXButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIButton+STXButton.h"; sourceTree = ""; };
115 | 01E383AF18F5491D0094BCC1 /* UIButton+STXButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIButton+STXButton.m"; sourceTree = ""; };
116 | 01E383B118F54B890094BCC1 /* UIImage+STXImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+STXImage.h"; sourceTree = ""; };
117 | 01E383B218F54B890094BCC1 /* UIImage+STXImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+STXImage.m"; sourceTree = ""; };
118 | 01E383B718F55D390094BCC1 /* STXPost.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STXPost.h; sourceTree = ""; };
119 | 01E383B818F55D390094BCC1 /* STXPost.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STXPost.m; sourceTree = ""; };
120 | 01E383BA18F596050094BCC1 /* STXUser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STXUser.h; sourceTree = ""; };
121 | 01E383BB18F596050094BCC1 /* STXUser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STXUser.m; sourceTree = ""; };
122 | 01E383BD18F638030094BCC1 /* STXCommentCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STXCommentCell.h; sourceTree = ""; };
123 | 01E383BE18F638030094BCC1 /* STXCommentCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STXCommentCell.m; sourceTree = ""; };
124 | 01E383C218F65C6D0094BCC1 /* STXUserActionCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STXUserActionCell.h; sourceTree = ""; };
125 | 01E383C318F65C6D0094BCC1 /* STXUserActionCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STXUserActionCell.m; sourceTree = ""; };
126 | 01E383C418F65C6D0094BCC1 /* STXUserActionCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = STXUserActionCell.xib; sourceTree = ""; };
127 | 2BDE37AE74C190EAE2837A7A /* Pods-STXDynamicTableViewExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-STXDynamicTableViewExample.release.xcconfig"; path = "Pods/Target Support Files/Pods-STXDynamicTableViewExample/Pods-STXDynamicTableViewExample.release.xcconfig"; sourceTree = ""; };
128 | 9AED87155782343E4057840A /* Pods-STXDynamicTableViewExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-STXDynamicTableViewExample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-STXDynamicTableViewExample/Pods-STXDynamicTableViewExample.debug.xcconfig"; sourceTree = ""; };
129 | EAD1347E22D244BC88270CFB /* libPods-STXDynamicTableViewExample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-STXDynamicTableViewExample.a"; sourceTree = BUILT_PRODUCTS_DIR; };
130 | /* End PBXFileReference section */
131 |
132 | /* Begin PBXFrameworksBuildPhase section */
133 | 0196481E18EAB434001185C3 /* Frameworks */ = {
134 | isa = PBXFrameworksBuildPhase;
135 | buildActionMask = 2147483647;
136 | files = (
137 | 0196482718EAB434001185C3 /* CoreGraphics.framework in Frameworks */,
138 | 0196482918EAB434001185C3 /* UIKit.framework in Frameworks */,
139 | 0196482518EAB434001185C3 /* Foundation.framework in Frameworks */,
140 | 1A1DFC0356454E938E07048F /* libPods-STXDynamicTableViewExample.a in Frameworks */,
141 | );
142 | runOnlyForDeploymentPostprocessing = 0;
143 | };
144 | 0196483918EAB434001185C3 /* Frameworks */ = {
145 | isa = PBXFrameworksBuildPhase;
146 | buildActionMask = 2147483647;
147 | files = (
148 | 0196483E18EAB434001185C3 /* XCTest.framework in Frameworks */,
149 | 0196484018EAB434001185C3 /* UIKit.framework in Frameworks */,
150 | 0196483F18EAB434001185C3 /* Foundation.framework in Frameworks */,
151 | );
152 | runOnlyForDeploymentPostprocessing = 0;
153 | };
154 | /* End PBXFrameworksBuildPhase section */
155 |
156 | /* Begin PBXGroup section */
157 | 010BA7FC18EC07C90030AF40 /* STXDynamicTableView */ = {
158 | isa = PBXGroup;
159 | children = (
160 | 011A76A81BC4283F00B0A046 /* Protocols */,
161 | 010BA83918ED10640030AF40 /* Categories */,
162 | 010BA81E18EC11D40030AF40 /* Cells */,
163 | 010BA83818EC13530030AF40 /* Items */,
164 | 01E383A718F539B00094BCC1 /* Buttons */,
165 | 010BA82A18EC11D40030AF40 /* Labels */,
166 | 010BA85718ED4F420030AF40 /* STXDynamicTableView.h */,
167 | );
168 | path = STXDynamicTableView;
169 | sourceTree = "";
170 | };
171 | 010BA81E18EC11D40030AF40 /* Cells */ = {
172 | isa = PBXGroup;
173 | children = (
174 | 010BA82218EC11D40030AF40 /* STXFeedPhotoCell.h */,
175 | 010BA82318EC11D40030AF40 /* STXFeedPhotoCell.m */,
176 | 010BA82418EC11D40030AF40 /* STXFeedPhotoCell.xib */,
177 | 017D674718F6771800DD096A /* STXLikesCell.h */,
178 | 017D674818F6771800DD096A /* STXLikesCell.m */,
179 | 017D674C18F6773100DD096A /* STXCaptionCell.h */,
180 | 017D674D18F6773100DD096A /* STXCaptionCell.m */,
181 | 01E383BD18F638030094BCC1 /* STXCommentCell.h */,
182 | 01E383BE18F638030094BCC1 /* STXCommentCell.m */,
183 | 01E383C218F65C6D0094BCC1 /* STXUserActionCell.h */,
184 | 01E383C318F65C6D0094BCC1 /* STXUserActionCell.m */,
185 | 01E383C418F65C6D0094BCC1 /* STXUserActionCell.xib */,
186 | );
187 | path = Cells;
188 | sourceTree = "";
189 | };
190 | 010BA82A18EC11D40030AF40 /* Labels */ = {
191 | isa = PBXGroup;
192 | children = (
193 | 010BA82B18EC11D40030AF40 /* STXAttributedLabel.h */,
194 | 010BA82C18EC11D40030AF40 /* STXAttributedLabel.m */,
195 | 010BA82D18EC11D40030AF40 /* STXLabel.h */,
196 | 010BA82E18EC11D40030AF40 /* STXLabel.m */,
197 | );
198 | path = Labels;
199 | sourceTree = "";
200 | };
201 | 010BA83818EC13530030AF40 /* Items */ = {
202 | isa = PBXGroup;
203 | children = (
204 | 010BA84B18ED4B610030AF40 /* STXPostItem.h */,
205 | 010BA84F18ED4BD80030AF40 /* STXCommentItem.h */,
206 | 010BA85318ED4C150030AF40 /* STXUserItem.h */,
207 | );
208 | path = Items;
209 | sourceTree = "";
210 | };
211 | 010BA83918ED10640030AF40 /* Categories */ = {
212 | isa = PBXGroup;
213 | children = (
214 | 01E383AE18F5491D0094BCC1 /* UIButton+STXButton.h */,
215 | 01E383AF18F5491D0094BCC1 /* UIButton+STXButton.m */,
216 | 01E383B118F54B890094BCC1 /* UIImage+STXImage.h */,
217 | 01E383B218F54B890094BCC1 /* UIImage+STXImage.m */,
218 | 01E383AB18F53DDA0094BCC1 /* UIImageView+Masking.h */,
219 | 01E383AC18F53DDA0094BCC1 /* UIImageView+Masking.m */,
220 | 01E383A418F537150094BCC1 /* UIViewController+Sharing.h */,
221 | 01E383A518F537150094BCC1 /* UIViewController+Sharing.m */,
222 | 010BA85818ED5D680030AF40 /* UIViewController+Indicator.h */,
223 | 010BA85918ED5D680030AF40 /* UIViewController+Indicator.m */,
224 | 010BA83A18ED10800030AF40 /* NSString+Emoji.h */,
225 | 010BA83B18ED10800030AF40 /* NSString+Emoji.m */,
226 | );
227 | path = Categories;
228 | sourceTree = "";
229 | };
230 | 011A76A81BC4283F00B0A046 /* Protocols */ = {
231 | isa = PBXGroup;
232 | children = (
233 | 011A76A91BC4283F00B0A046 /* STXFeedTableViewDataSource.h */,
234 | 011A76AA1BC4283F00B0A046 /* STXFeedTableViewDataSource.m */,
235 | 011A76AB1BC4283F00B0A046 /* STXFeedTableViewDelegate.h */,
236 | 011A76AC1BC4283F00B0A046 /* STXFeedTableViewDelegate.m */,
237 | );
238 | path = Protocols;
239 | sourceTree = "";
240 | };
241 | 0196481818EAB434001185C3 = {
242 | isa = PBXGroup;
243 | children = (
244 | 010BA7FC18EC07C90030AF40 /* STXDynamicTableView */,
245 | 0196482A18EAB434001185C3 /* STXDynamicTableViewExample */,
246 | 0196484318EAB434001185C3 /* STXDynamicTableViewExampleTests */,
247 | 0196482318EAB434001185C3 /* Frameworks */,
248 | 0196482218EAB434001185C3 /* Products */,
249 | 7D3E8B648949E9F59F51A766 /* Pods */,
250 | );
251 | sourceTree = "";
252 | };
253 | 0196482218EAB434001185C3 /* Products */ = {
254 | isa = PBXGroup;
255 | children = (
256 | 0196482118EAB434001185C3 /* STXDynamicTableViewExample.app */,
257 | 0196483C18EAB434001185C3 /* STXDynamicTableViewExampleTests.xctest */,
258 | );
259 | name = Products;
260 | sourceTree = "";
261 | };
262 | 0196482318EAB434001185C3 /* Frameworks */ = {
263 | isa = PBXGroup;
264 | children = (
265 | 0196482418EAB434001185C3 /* Foundation.framework */,
266 | 0196482618EAB434001185C3 /* CoreGraphics.framework */,
267 | 0196482818EAB434001185C3 /* UIKit.framework */,
268 | 0196483D18EAB434001185C3 /* XCTest.framework */,
269 | EAD1347E22D244BC88270CFB /* libPods-STXDynamicTableViewExample.a */,
270 | );
271 | name = Frameworks;
272 | sourceTree = "";
273 | };
274 | 0196482A18EAB434001185C3 /* STXDynamicTableViewExample */ = {
275 | isa = PBXGroup;
276 | children = (
277 | 01E383B618F55D090094BCC1 /* Models */,
278 | 010BA84518ED43AC0030AF40 /* STXFeedViewController.h */,
279 | 010BA84618ED43AC0030AF40 /* STXFeedViewController.m */,
280 | 0196483318EAB434001185C3 /* STXAppDelegate.h */,
281 | 0196483418EAB434001185C3 /* STXAppDelegate.m */,
282 | 0196483618EAB434001185C3 /* Images.xcassets */,
283 | 0196485318EAB48F001185C3 /* Resources */,
284 | 0196482B18EAB434001185C3 /* Supporting Files */,
285 | );
286 | path = STXDynamicTableViewExample;
287 | sourceTree = "";
288 | };
289 | 0196482B18EAB434001185C3 /* Supporting Files */ = {
290 | isa = PBXGroup;
291 | children = (
292 | 0196482C18EAB434001185C3 /* STXDynamicTableViewExample-Info.plist */,
293 | 0196482D18EAB434001185C3 /* InfoPlist.strings */,
294 | 0196483018EAB434001185C3 /* main.m */,
295 | 0196483218EAB434001185C3 /* STXDynamicTableViewExample-Prefix.pch */,
296 | );
297 | name = "Supporting Files";
298 | sourceTree = "";
299 | };
300 | 0196484318EAB434001185C3 /* STXDynamicTableViewExampleTests */ = {
301 | isa = PBXGroup;
302 | children = (
303 | 0196484918EAB434001185C3 /* STXDynamicTableViewExampleTests.m */,
304 | 0196484418EAB434001185C3 /* Supporting Files */,
305 | );
306 | path = STXDynamicTableViewExampleTests;
307 | sourceTree = "";
308 | };
309 | 0196484418EAB434001185C3 /* Supporting Files */ = {
310 | isa = PBXGroup;
311 | children = (
312 | 0196484518EAB434001185C3 /* STXDynamicTableViewExampleTests-Info.plist */,
313 | 0196484618EAB434001185C3 /* InfoPlist.strings */,
314 | );
315 | name = "Supporting Files";
316 | sourceTree = "";
317 | };
318 | 0196485318EAB48F001185C3 /* Resources */ = {
319 | isa = PBXGroup;
320 | children = (
321 | 011A76A41BC41EC300B0A046 /* Feed.storyboard */,
322 | 011A76A61BC4213700B0A046 /* LaunchScreen.storyboard */,
323 | 0196485418EAB48F001185C3 /* instagram_media_popular.json */,
324 | );
325 | path = Resources;
326 | sourceTree = "";
327 | };
328 | 01E383A718F539B00094BCC1 /* Buttons */ = {
329 | isa = PBXGroup;
330 | children = (
331 | 01E383A818F539B00094BCC1 /* STXButton.h */,
332 | 01E383A918F539B00094BCC1 /* STXButton.m */,
333 | );
334 | path = Buttons;
335 | sourceTree = "";
336 | };
337 | 01E383B618F55D090094BCC1 /* Models */ = {
338 | isa = PBXGroup;
339 | children = (
340 | 01C4B21918F7A92100712436 /* STXComment.h */,
341 | 01C4B21A18F7A92100712436 /* STXComment.m */,
342 | 01E383B718F55D390094BCC1 /* STXPost.h */,
343 | 01E383B818F55D390094BCC1 /* STXPost.m */,
344 | 01E383BA18F596050094BCC1 /* STXUser.h */,
345 | 01E383BB18F596050094BCC1 /* STXUser.m */,
346 | );
347 | path = Models;
348 | sourceTree = "";
349 | };
350 | 7D3E8B648949E9F59F51A766 /* Pods */ = {
351 | isa = PBXGroup;
352 | children = (
353 | 9AED87155782343E4057840A /* Pods-STXDynamicTableViewExample.debug.xcconfig */,
354 | 2BDE37AE74C190EAE2837A7A /* Pods-STXDynamicTableViewExample.release.xcconfig */,
355 | );
356 | name = Pods;
357 | sourceTree = "";
358 | };
359 | /* End PBXGroup section */
360 |
361 | /* Begin PBXNativeTarget section */
362 | 0196482018EAB434001185C3 /* STXDynamicTableViewExample */ = {
363 | isa = PBXNativeTarget;
364 | buildConfigurationList = 0196484D18EAB434001185C3 /* Build configuration list for PBXNativeTarget "STXDynamicTableViewExample" */;
365 | buildPhases = (
366 | 1DE0784B99E84F7AA6A1219D /* Check Pods Manifest.lock */,
367 | 0196481D18EAB434001185C3 /* Sources */,
368 | 0196481E18EAB434001185C3 /* Frameworks */,
369 | 0196481F18EAB434001185C3 /* Resources */,
370 | 46FB61A0D3734DDC91CA4CEC /* Copy Pods Resources */,
371 | );
372 | buildRules = (
373 | );
374 | dependencies = (
375 | );
376 | name = STXDynamicTableViewExample;
377 | productName = STXDynamicTableViewExample;
378 | productReference = 0196482118EAB434001185C3 /* STXDynamicTableViewExample.app */;
379 | productType = "com.apple.product-type.application";
380 | };
381 | 0196483B18EAB434001185C3 /* STXDynamicTableViewExampleTests */ = {
382 | isa = PBXNativeTarget;
383 | buildConfigurationList = 0196485018EAB434001185C3 /* Build configuration list for PBXNativeTarget "STXDynamicTableViewExampleTests" */;
384 | buildPhases = (
385 | 0196483818EAB434001185C3 /* Sources */,
386 | 0196483918EAB434001185C3 /* Frameworks */,
387 | 0196483A18EAB434001185C3 /* Resources */,
388 | );
389 | buildRules = (
390 | );
391 | dependencies = (
392 | 0196484218EAB434001185C3 /* PBXTargetDependency */,
393 | );
394 | name = STXDynamicTableViewExampleTests;
395 | productName = STXDynamicTableViewExampleTests;
396 | productReference = 0196483C18EAB434001185C3 /* STXDynamicTableViewExampleTests.xctest */;
397 | productType = "com.apple.product-type.bundle.unit-test";
398 | };
399 | /* End PBXNativeTarget section */
400 |
401 | /* Begin PBXProject section */
402 | 0196481918EAB434001185C3 /* Project object */ = {
403 | isa = PBXProject;
404 | attributes = {
405 | CLASSPREFIX = STX;
406 | LastUpgradeCheck = 0700;
407 | ORGANIZATIONNAME = "2359 Media Pte Ltd";
408 | TargetAttributes = {
409 | 0196483B18EAB434001185C3 = {
410 | TestTargetID = 0196482018EAB434001185C3;
411 | };
412 | };
413 | };
414 | buildConfigurationList = 0196481C18EAB434001185C3 /* Build configuration list for PBXProject "STXDynamicTableViewExample" */;
415 | compatibilityVersion = "Xcode 3.2";
416 | developmentRegion = English;
417 | hasScannedForEncodings = 0;
418 | knownRegions = (
419 | en,
420 | );
421 | mainGroup = 0196481818EAB434001185C3;
422 | productRefGroup = 0196482218EAB434001185C3 /* Products */;
423 | projectDirPath = "";
424 | projectRoot = "";
425 | targets = (
426 | 0196482018EAB434001185C3 /* STXDynamicTableViewExample */,
427 | 0196483B18EAB434001185C3 /* STXDynamicTableViewExampleTests */,
428 | );
429 | };
430 | /* End PBXProject section */
431 |
432 | /* Begin PBXResourcesBuildPhase section */
433 | 0196481F18EAB434001185C3 /* Resources */ = {
434 | isa = PBXResourcesBuildPhase;
435 | buildActionMask = 2147483647;
436 | files = (
437 | 01E383C618F65C6D0094BCC1 /* STXUserActionCell.xib in Resources */,
438 | 0196482F18EAB434001185C3 /* InfoPlist.strings in Resources */,
439 | 011A76A51BC41EC300B0A046 /* Feed.storyboard in Resources */,
440 | 0196485518EAB48F001185C3 /* instagram_media_popular.json in Resources */,
441 | 0196483718EAB434001185C3 /* Images.xcassets in Resources */,
442 | 010BA83318EC11D40030AF40 /* STXFeedPhotoCell.xib in Resources */,
443 | 011A76A71BC4213700B0A046 /* LaunchScreen.storyboard in Resources */,
444 | );
445 | runOnlyForDeploymentPostprocessing = 0;
446 | };
447 | 0196483A18EAB434001185C3 /* Resources */ = {
448 | isa = PBXResourcesBuildPhase;
449 | buildActionMask = 2147483647;
450 | files = (
451 | 0196484818EAB434001185C3 /* InfoPlist.strings in Resources */,
452 | );
453 | runOnlyForDeploymentPostprocessing = 0;
454 | };
455 | /* End PBXResourcesBuildPhase section */
456 |
457 | /* Begin PBXShellScriptBuildPhase section */
458 | 1DE0784B99E84F7AA6A1219D /* Check Pods Manifest.lock */ = {
459 | isa = PBXShellScriptBuildPhase;
460 | buildActionMask = 2147483647;
461 | files = (
462 | );
463 | inputPaths = (
464 | );
465 | name = "Check Pods Manifest.lock";
466 | outputPaths = (
467 | );
468 | runOnlyForDeploymentPostprocessing = 0;
469 | shellPath = /bin/sh;
470 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
471 | showEnvVarsInLog = 0;
472 | };
473 | 46FB61A0D3734DDC91CA4CEC /* Copy Pods Resources */ = {
474 | isa = PBXShellScriptBuildPhase;
475 | buildActionMask = 2147483647;
476 | files = (
477 | );
478 | inputPaths = (
479 | );
480 | name = "Copy Pods Resources";
481 | outputPaths = (
482 | );
483 | runOnlyForDeploymentPostprocessing = 0;
484 | shellPath = /bin/sh;
485 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-STXDynamicTableViewExample/Pods-STXDynamicTableViewExample-resources.sh\"\n";
486 | showEnvVarsInLog = 0;
487 | };
488 | /* End PBXShellScriptBuildPhase section */
489 |
490 | /* Begin PBXSourcesBuildPhase section */
491 | 0196481D18EAB434001185C3 /* Sources */ = {
492 | isa = PBXSourcesBuildPhase;
493 | buildActionMask = 2147483647;
494 | files = (
495 | 01E383BC18F596050094BCC1 /* STXUser.m in Sources */,
496 | 010BA83C18ED10800030AF40 /* NSString+Emoji.m in Sources */,
497 | 01E383AA18F539B00094BCC1 /* STXButton.m in Sources */,
498 | 0196483518EAB434001185C3 /* STXAppDelegate.m in Sources */,
499 | 01E383C018F638030094BCC1 /* STXCommentCell.m in Sources */,
500 | 011A76AD1BC4283F00B0A046 /* STXFeedTableViewDataSource.m in Sources */,
501 | 01E383B318F54B890094BCC1 /* UIImage+STXImage.m in Sources */,
502 | 01E383C518F65C6D0094BCC1 /* STXUserActionCell.m in Sources */,
503 | 010BA83718EC11D40030AF40 /* STXLabel.m in Sources */,
504 | 0196483118EAB434001185C3 /* main.m in Sources */,
505 | 01C4B21B18F7A92100712436 /* STXComment.m in Sources */,
506 | 010BA83218EC11D40030AF40 /* STXFeedPhotoCell.m in Sources */,
507 | 01E383AD18F53DDA0094BCC1 /* UIImageView+Masking.m in Sources */,
508 | 01E383A618F537150094BCC1 /* UIViewController+Sharing.m in Sources */,
509 | 01E383B918F55D390094BCC1 /* STXPost.m in Sources */,
510 | 017D674F18F6773100DD096A /* STXCaptionCell.m in Sources */,
511 | 010BA83618EC11D40030AF40 /* STXAttributedLabel.m in Sources */,
512 | 010BA84718ED43AC0030AF40 /* STXFeedViewController.m in Sources */,
513 | 010BA85A18ED5D680030AF40 /* UIViewController+Indicator.m in Sources */,
514 | 017D674A18F6771800DD096A /* STXLikesCell.m in Sources */,
515 | 011A76AE1BC4283F00B0A046 /* STXFeedTableViewDelegate.m in Sources */,
516 | 01E383B018F5491D0094BCC1 /* UIButton+STXButton.m in Sources */,
517 | );
518 | runOnlyForDeploymentPostprocessing = 0;
519 | };
520 | 0196483818EAB434001185C3 /* Sources */ = {
521 | isa = PBXSourcesBuildPhase;
522 | buildActionMask = 2147483647;
523 | files = (
524 | 010BA83D18ED10800030AF40 /* NSString+Emoji.m in Sources */,
525 | 0196484A18EAB434001185C3 /* STXDynamicTableViewExampleTests.m in Sources */,
526 | );
527 | runOnlyForDeploymentPostprocessing = 0;
528 | };
529 | /* End PBXSourcesBuildPhase section */
530 |
531 | /* Begin PBXTargetDependency section */
532 | 0196484218EAB434001185C3 /* PBXTargetDependency */ = {
533 | isa = PBXTargetDependency;
534 | target = 0196482018EAB434001185C3 /* STXDynamicTableViewExample */;
535 | targetProxy = 0196484118EAB434001185C3 /* PBXContainerItemProxy */;
536 | };
537 | /* End PBXTargetDependency section */
538 |
539 | /* Begin PBXVariantGroup section */
540 | 0196482D18EAB434001185C3 /* InfoPlist.strings */ = {
541 | isa = PBXVariantGroup;
542 | children = (
543 | 0196482E18EAB434001185C3 /* en */,
544 | );
545 | name = InfoPlist.strings;
546 | sourceTree = "";
547 | };
548 | 0196484618EAB434001185C3 /* InfoPlist.strings */ = {
549 | isa = PBXVariantGroup;
550 | children = (
551 | 0196484718EAB434001185C3 /* en */,
552 | );
553 | name = InfoPlist.strings;
554 | sourceTree = "";
555 | };
556 | /* End PBXVariantGroup section */
557 |
558 | /* Begin XCBuildConfiguration section */
559 | 0196484B18EAB434001185C3 /* Debug */ = {
560 | isa = XCBuildConfiguration;
561 | buildSettings = {
562 | ALWAYS_SEARCH_USER_PATHS = NO;
563 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
564 | CLANG_CXX_LIBRARY = "libc++";
565 | CLANG_ENABLE_MODULES = YES;
566 | CLANG_ENABLE_OBJC_ARC = YES;
567 | CLANG_WARN_BOOL_CONVERSION = YES;
568 | CLANG_WARN_CONSTANT_CONVERSION = YES;
569 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
570 | CLANG_WARN_EMPTY_BODY = YES;
571 | CLANG_WARN_ENUM_CONVERSION = YES;
572 | CLANG_WARN_INT_CONVERSION = YES;
573 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
574 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
575 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
576 | COPY_PHASE_STRIP = NO;
577 | ENABLE_TESTABILITY = YES;
578 | GCC_C_LANGUAGE_STANDARD = gnu99;
579 | GCC_DYNAMIC_NO_PIC = NO;
580 | GCC_OPTIMIZATION_LEVEL = 0;
581 | GCC_PREPROCESSOR_DEFINITIONS = (
582 | "DEBUG=1",
583 | "$(inherited)",
584 | );
585 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
586 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
587 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
588 | GCC_WARN_UNDECLARED_SELECTOR = YES;
589 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
590 | GCC_WARN_UNUSED_FUNCTION = YES;
591 | GCC_WARN_UNUSED_VARIABLE = YES;
592 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
593 | ONLY_ACTIVE_ARCH = YES;
594 | SDKROOT = iphoneos;
595 | TARGETED_DEVICE_FAMILY = "1,2";
596 | };
597 | name = Debug;
598 | };
599 | 0196484C18EAB434001185C3 /* Release */ = {
600 | isa = XCBuildConfiguration;
601 | buildSettings = {
602 | ALWAYS_SEARCH_USER_PATHS = NO;
603 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
604 | CLANG_CXX_LIBRARY = "libc++";
605 | CLANG_ENABLE_MODULES = YES;
606 | CLANG_ENABLE_OBJC_ARC = YES;
607 | CLANG_WARN_BOOL_CONVERSION = YES;
608 | CLANG_WARN_CONSTANT_CONVERSION = YES;
609 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
610 | CLANG_WARN_EMPTY_BODY = YES;
611 | CLANG_WARN_ENUM_CONVERSION = YES;
612 | CLANG_WARN_INT_CONVERSION = YES;
613 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
614 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
615 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
616 | COPY_PHASE_STRIP = YES;
617 | ENABLE_NS_ASSERTIONS = NO;
618 | GCC_C_LANGUAGE_STANDARD = gnu99;
619 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
620 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
621 | GCC_WARN_UNDECLARED_SELECTOR = YES;
622 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
623 | GCC_WARN_UNUSED_FUNCTION = YES;
624 | GCC_WARN_UNUSED_VARIABLE = YES;
625 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
626 | SDKROOT = iphoneos;
627 | TARGETED_DEVICE_FAMILY = "1,2";
628 | VALIDATE_PRODUCT = YES;
629 | };
630 | name = Release;
631 | };
632 | 0196484E18EAB434001185C3 /* Debug */ = {
633 | isa = XCBuildConfiguration;
634 | baseConfigurationReference = 9AED87155782343E4057840A /* Pods-STXDynamicTableViewExample.debug.xcconfig */;
635 | buildSettings = {
636 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
637 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
638 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
639 | GCC_PREFIX_HEADER = "STXDynamicTableViewExample/STXDynamicTableViewExample-Prefix.pch";
640 | INFOPLIST_FILE = "STXDynamicTableViewExample/STXDynamicTableViewExample-Info.plist";
641 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
642 | PRODUCT_BUNDLE_IDENTIFIER = "com.2359media.${PRODUCT_NAME:rfc1034identifier}";
643 | PRODUCT_NAME = "$(TARGET_NAME)";
644 | WRAPPER_EXTENSION = app;
645 | };
646 | name = Debug;
647 | };
648 | 0196484F18EAB434001185C3 /* Release */ = {
649 | isa = XCBuildConfiguration;
650 | baseConfigurationReference = 2BDE37AE74C190EAE2837A7A /* Pods-STXDynamicTableViewExample.release.xcconfig */;
651 | buildSettings = {
652 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
653 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
654 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
655 | GCC_PREFIX_HEADER = "STXDynamicTableViewExample/STXDynamicTableViewExample-Prefix.pch";
656 | INFOPLIST_FILE = "STXDynamicTableViewExample/STXDynamicTableViewExample-Info.plist";
657 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
658 | PRODUCT_BUNDLE_IDENTIFIER = "com.2359media.${PRODUCT_NAME:rfc1034identifier}";
659 | PRODUCT_NAME = "$(TARGET_NAME)";
660 | WRAPPER_EXTENSION = app;
661 | };
662 | name = Release;
663 | };
664 | 0196485118EAB434001185C3 /* Debug */ = {
665 | isa = XCBuildConfiguration;
666 | baseConfigurationReference = 9AED87155782343E4057840A /* Pods-STXDynamicTableViewExample.debug.xcconfig */;
667 | buildSettings = {
668 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/STXDynamicTableViewExample.app/STXDynamicTableViewExample";
669 | FRAMEWORK_SEARCH_PATHS = (
670 | "$(SDKROOT)/Developer/Library/Frameworks",
671 | "$(inherited)",
672 | "$(DEVELOPER_FRAMEWORKS_DIR)",
673 | );
674 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
675 | GCC_PREFIX_HEADER = "STXDynamicTableViewExample/STXDynamicTableViewExample-Prefix.pch";
676 | GCC_PREPROCESSOR_DEFINITIONS = (
677 | "DEBUG=1",
678 | "$(inherited)",
679 | );
680 | INFOPLIST_FILE = "STXDynamicTableViewExampleTests/STXDynamicTableViewExampleTests-Info.plist";
681 | PRODUCT_BUNDLE_IDENTIFIER = "com.2359media.${PRODUCT_NAME:rfc1034identifier}";
682 | PRODUCT_NAME = "$(TARGET_NAME)";
683 | TEST_HOST = "$(BUNDLE_LOADER)";
684 | WRAPPER_EXTENSION = xctest;
685 | };
686 | name = Debug;
687 | };
688 | 0196485218EAB434001185C3 /* Release */ = {
689 | isa = XCBuildConfiguration;
690 | baseConfigurationReference = 2BDE37AE74C190EAE2837A7A /* Pods-STXDynamicTableViewExample.release.xcconfig */;
691 | buildSettings = {
692 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/STXDynamicTableViewExample.app/STXDynamicTableViewExample";
693 | FRAMEWORK_SEARCH_PATHS = (
694 | "$(SDKROOT)/Developer/Library/Frameworks",
695 | "$(inherited)",
696 | "$(DEVELOPER_FRAMEWORKS_DIR)",
697 | );
698 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
699 | GCC_PREFIX_HEADER = "STXDynamicTableViewExample/STXDynamicTableViewExample-Prefix.pch";
700 | INFOPLIST_FILE = "STXDynamicTableViewExampleTests/STXDynamicTableViewExampleTests-Info.plist";
701 | PRODUCT_BUNDLE_IDENTIFIER = "com.2359media.${PRODUCT_NAME:rfc1034identifier}";
702 | PRODUCT_NAME = "$(TARGET_NAME)";
703 | TEST_HOST = "$(BUNDLE_LOADER)";
704 | WRAPPER_EXTENSION = xctest;
705 | };
706 | name = Release;
707 | };
708 | /* End XCBuildConfiguration section */
709 |
710 | /* Begin XCConfigurationList section */
711 | 0196481C18EAB434001185C3 /* Build configuration list for PBXProject "STXDynamicTableViewExample" */ = {
712 | isa = XCConfigurationList;
713 | buildConfigurations = (
714 | 0196484B18EAB434001185C3 /* Debug */,
715 | 0196484C18EAB434001185C3 /* Release */,
716 | );
717 | defaultConfigurationIsVisible = 0;
718 | defaultConfigurationName = Release;
719 | };
720 | 0196484D18EAB434001185C3 /* Build configuration list for PBXNativeTarget "STXDynamicTableViewExample" */ = {
721 | isa = XCConfigurationList;
722 | buildConfigurations = (
723 | 0196484E18EAB434001185C3 /* Debug */,
724 | 0196484F18EAB434001185C3 /* Release */,
725 | );
726 | defaultConfigurationIsVisible = 0;
727 | defaultConfigurationName = Release;
728 | };
729 | 0196485018EAB434001185C3 /* Build configuration list for PBXNativeTarget "STXDynamicTableViewExampleTests" */ = {
730 | isa = XCConfigurationList;
731 | buildConfigurations = (
732 | 0196485118EAB434001185C3 /* Debug */,
733 | 0196485218EAB434001185C3 /* Release */,
734 | );
735 | defaultConfigurationIsVisible = 0;
736 | defaultConfigurationName = Release;
737 | };
738 | /* End XCConfigurationList section */
739 | };
740 | rootObject = 0196481918EAB434001185C3 /* Project object */;
741 | }
742 |
--------------------------------------------------------------------------------
/STXDynamicTableViewExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/STXDynamicTableViewExample.xcodeproj/xcshareddata/xcschemes/STXDynamicTableViewExample.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
44 |
45 |
47 |
53 |
54 |
55 |
56 |
57 |
63 |
64 |
65 |
66 |
67 |
68 |
78 |
80 |
86 |
87 |
88 |
89 |
90 |
91 |
97 |
99 |
105 |
106 |
107 |
108 |
110 |
111 |
114 |
115 |
116 |
--------------------------------------------------------------------------------
/STXDynamicTableViewExample.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/STXDynamicTableViewExample/Feed.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/STXDynamicTableViewExample/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "40x40",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "60x60",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "ipad",
20 | "size" : "29x29",
21 | "scale" : "1x"
22 | },
23 | {
24 | "idiom" : "ipad",
25 | "size" : "29x29",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "ipad",
30 | "size" : "40x40",
31 | "scale" : "1x"
32 | },
33 | {
34 | "idiom" : "ipad",
35 | "size" : "40x40",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "ipad",
40 | "size" : "76x76",
41 | "scale" : "1x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "76x76",
46 | "scale" : "2x"
47 | }
48 | ],
49 | "info" : {
50 | "version" : 1,
51 | "author" : "xcode"
52 | }
53 | }
--------------------------------------------------------------------------------
/STXDynamicTableViewExample/Images.xcassets/LaunchImage.launchimage/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "orientation" : "portrait",
5 | "idiom" : "iphone",
6 | "extent" : "full-screen",
7 | "minimum-system-version" : "7.0",
8 | "scale" : "2x"
9 | },
10 | {
11 | "orientation" : "portrait",
12 | "idiom" : "iphone",
13 | "subtype" : "retina4",
14 | "extent" : "full-screen",
15 | "minimum-system-version" : "7.0",
16 | "scale" : "2x"
17 | },
18 | {
19 | "orientation" : "portrait",
20 | "idiom" : "ipad",
21 | "extent" : "full-screen",
22 | "minimum-system-version" : "7.0",
23 | "scale" : "1x"
24 | },
25 | {
26 | "orientation" : "landscape",
27 | "idiom" : "ipad",
28 | "extent" : "full-screen",
29 | "minimum-system-version" : "7.0",
30 | "scale" : "1x"
31 | },
32 | {
33 | "orientation" : "portrait",
34 | "idiom" : "ipad",
35 | "extent" : "full-screen",
36 | "minimum-system-version" : "7.0",
37 | "scale" : "2x"
38 | },
39 | {
40 | "orientation" : "landscape",
41 | "idiom" : "ipad",
42 | "extent" : "full-screen",
43 | "minimum-system-version" : "7.0",
44 | "scale" : "2x"
45 | }
46 | ],
47 | "info" : {
48 | "version" : 1,
49 | "author" : "xcode"
50 | }
51 | }
--------------------------------------------------------------------------------
/STXDynamicTableViewExample/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/STXDynamicTableViewExample/Models/STXComment.h:
--------------------------------------------------------------------------------
1 | //
2 | // STXComment.h
3 | // STXDynamicTableView
4 | //
5 | // Created by Jesse Armand on 27/1/14.
6 | // Copyright (c) 2014 2359 Media. All rights reserved.
7 | //
8 |
9 | @interface STXComment : NSObject
10 |
11 | /**
12 | * Initialize data model from dictionary
13 | */
14 |
15 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/STXDynamicTableViewExample/Models/STXComment.m:
--------------------------------------------------------------------------------
1 | //
2 | // STXComment.m
3 | // STXDynamicTableView
4 | //
5 | // Created by Jesse Armand on 27/1/14.
6 | // Copyright (c) 2014 2359 Media. All rights reserved.
7 | //
8 |
9 | #import "STXComment.h"
10 | #import "STXUser.h"
11 |
12 | @interface STXComment ()
13 |
14 | @property (copy, nonatomic) NSString *commentID;
15 | @property (copy, nonatomic) NSString *text;
16 | @property (copy, nonatomic) NSDate *postDate;
17 | @property (copy, nonatomic) NSDictionary *fromDictionary;
18 |
19 | @end
20 |
21 | @implementation STXComment
22 |
23 | #pragma mark - NSCoding
24 |
25 | - (void)encodeWithCoder:(NSCoder *)encoder
26 | {
27 | [encoder encodeObject:_commentID forKey:@"commentID"];
28 | [encoder encodeObject:_text forKey:@"text"];
29 | [encoder encodeObject:_postDate forKey:@"postDate"];
30 | [encoder encodeObject:_fromDictionary forKey:@"fromDictionary"];
31 | }
32 |
33 | - (instancetype)initWithCoder:(NSCoder *)decoder
34 | {
35 | self = [super init];
36 | if (self) {
37 | _commentID = [decoder decodeObjectForKey:@"commentID"];
38 | _text = [decoder decodeObjectForKey:@"text"];
39 | _postDate = [decoder decodeObjectForKey:@"postDate"];
40 | _fromDictionary = [decoder decodeObjectForKey:@"fromDictionary"];
41 | }
42 |
43 | return self;
44 | }
45 |
46 | - (instancetype)copyWithZone:(NSZone *)zone
47 | {
48 | STXComment *theCopy = [[[self class] allocWithZone:zone] init];
49 | [theCopy setCommentID:[_commentID copy]];
50 | [theCopy setText:[_text copy]];
51 | [theCopy setPostDate:[_postDate copy]];
52 | [theCopy setFromDictionary:[_fromDictionary copy]];
53 |
54 | return theCopy;
55 | }
56 |
57 | #pragma mark - Initializers
58 |
59 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary
60 | {
61 | self = [super init];
62 | if (self) {
63 | NSArray *errors;
64 | NSDictionary *mappingDictionary = @{ @"id": KZProperty(commentID),
65 | @"text": KZProperty(text),
66 | @"created_time": KZBox(Date, postDate),
67 | @"from": KZProperty(fromDictionary) };
68 |
69 | [KZPropertyMapper mapValuesFrom:dictionary toInstance:self usingMapping:mappingDictionary errors:&errors];
70 | }
71 | return self;
72 | }
73 |
74 | - (NSUInteger)hash
75 | {
76 | return [_commentID hash];
77 | }
78 |
79 | - (BOOL)isEqualToComment:(STXComment *)comment
80 | {
81 | return [comment.commentID isEqualToString:_commentID];
82 | }
83 |
84 | - (BOOL)isEqual:(id)object
85 | {
86 | if (self == object) {
87 | return YES;
88 | }
89 |
90 | if (![object isKindOfClass:[STXComment class]]) {
91 | return NO;
92 | }
93 |
94 | return [self isEqualToComment:(STXComment *)object];
95 | }
96 |
97 | - (NSString *)description
98 | {
99 | NSDictionary *dictionary = @{ @"commentID": self.commentID ? : @"",
100 | @"from": self.from ? [self.from username] : @"",
101 | @"text": self.text ? : @"" };
102 | return [NSString stringWithFormat:@"<%@: %p> %@", NSStringFromClass([self class]), self, dictionary];
103 | }
104 |
105 | #pragma mark - STXCommentItem
106 |
107 | - (id)from
108 | {
109 | STXUser *user = [[STXUser alloc] initWithDictionary:self.fromDictionary];
110 | return user;
111 | }
112 |
113 | @end
114 |
--------------------------------------------------------------------------------
/STXDynamicTableViewExample/Models/STXPost.h:
--------------------------------------------------------------------------------
1 | //
2 | // STXPost.h
3 | // STXDynamicTableViewExample
4 | //
5 | // Created by Jesse Armand on 9/4/14.
6 | // Copyright (c) 2014 2359 Media Pte Ltd. All rights reserved.
7 | //
8 |
9 | @import Foundation;
10 |
11 | #import "STXPostItem.h"
12 |
13 | @interface STXPost : NSObject
14 |
15 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/STXDynamicTableViewExample/Models/STXPost.m:
--------------------------------------------------------------------------------
1 | //
2 | // STXPost.m
3 | // STXDynamicTableViewExample
4 | //
5 | // Created by Jesse Armand on 9/4/14.
6 | // Copyright (c) 2014 2359 Media Pte Ltd. All rights reserved.
7 | //
8 |
9 | #import "STXPost.h"
10 | #import "STXUser.h"
11 | #import "STXComment.h"
12 |
13 | @interface STXPost ()
14 |
15 | @property (copy, nonatomic) NSString *postID;
16 | @property (copy, nonatomic) NSDate *postDate;
17 |
18 | @property (copy, nonatomic) NSURL *imageURL;
19 | @property (copy, nonatomic) NSURL *link;
20 |
21 | @property (copy, nonatomic) NSDictionary *caption;
22 | @property (copy, nonatomic) NSDictionary *userDictionary;
23 |
24 | @property (copy, nonatomic) NSDictionary *likes;
25 | @property (copy, nonatomic) NSArray *comments;
26 | @property (copy, nonatomic) NSDictionary *commentsDictionary;
27 |
28 | @property (nonatomic) BOOL liked;
29 |
30 | @end
31 |
32 | @implementation STXPost
33 |
34 | #pragma mark - NSCoding
35 |
36 | - (void)encodeWithCoder:(NSCoder *)encoder
37 | {
38 | [encoder encodeObject:_postID forKey:@"postID"];
39 | [encoder encodeObject:_postDate forKey:@"postDate"];
40 | [encoder encodeObject:_imageURL forKey:@"imageURL"];
41 | [encoder encodeObject:_link forKey:@"link"];
42 | [encoder encodeObject:_caption forKey:@"caption"];
43 | [encoder encodeObject:_userDictionary forKey:@"userDictionary"];
44 | [encoder encodeObject:_likes forKey:@"likes"];
45 | [encoder encodeObject:_comments forKey:@"comments"];
46 | [encoder encodeObject:_commentsDictionary forKey:@"commentsDictionary"];
47 | [encoder encodeBool:_liked forKey:@"liked"];
48 | }
49 |
50 | - (instancetype)initWithCoder:(NSCoder *)decoder
51 | {
52 | self = [super init];
53 | if (self) {
54 | _postID = [decoder decodeObjectForKey:@"postID"];
55 | _postDate = [decoder decodeObjectForKey:@"postDate"];
56 | _imageURL = [decoder decodeObjectForKey:@"imageURL"];
57 | _link = [decoder decodeObjectForKey:@"link"];
58 | _caption = [decoder decodeObjectForKey:@"caption"];
59 | _userDictionary = [decoder decodeObjectForKey:@"userDictionary"];
60 | _likes = [decoder decodeObjectForKey:@"likes"];
61 | _comments = [decoder decodeObjectForKey:@"comments"];
62 | _commentsDictionary = [decoder decodeObjectForKey:@"commentsDictionary"];
63 | _liked = [decoder decodeBoolForKey:@"liked"];
64 | }
65 | return self;
66 | }
67 |
68 | - (instancetype)copyWithZone:(NSZone *)zone
69 | {
70 | STXPost *theCopy = [[STXPost allocWithZone:zone] init]; // use designated initializer
71 |
72 | [theCopy setPostID:[_postID copy]];
73 | [theCopy setPostDate:[_postDate copy]];
74 | [theCopy setImageURL:[_imageURL copy]];
75 | [theCopy setLink:[_link copy]];
76 | [theCopy setCaption:[_caption copy]];
77 | [theCopy setUserDictionary:[_userDictionary copy]];
78 | [theCopy setLikes:[_likes copy]];
79 | [theCopy setComments:[_comments copy]];
80 | [theCopy setCommentsDictionary:[_commentsDictionary copy]];
81 | [theCopy setLiked:_liked];
82 |
83 | return theCopy;
84 | }
85 |
86 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary
87 | {
88 | self = [super init];
89 | if (self) {
90 | NSArray *errors;
91 | NSDictionary *mappingDictionary = @{ @"id": KZProperty(postID),
92 | @"link": KZBox(URL, link),
93 | @"caption": KZProperty(caption),
94 | @"user": KZProperty(userDictionary),
95 | @"user_has_liked": KZProperty(liked),
96 | @"images": @{ @"standard_resolution": @{ @"url": KZBox(URL, imageURL) } },
97 | @"likes": KZProperty(likes),
98 | @"comments": KZProperty(commentsDictionary) };
99 |
100 | [KZPropertyMapper mapValuesFrom:dictionary toInstance:self usingMapping:mappingDictionary errors:&errors];
101 | }
102 |
103 | return self;
104 | }
105 |
106 |
107 | #pragma mark - NSObject
108 |
109 | - (NSUInteger)hash
110 | {
111 | return [_postID hash];
112 | }
113 |
114 | - (BOOL)isEqualToPost:(STXPost *)post
115 | {
116 | return [post.postID isEqualToString:_postID];
117 | }
118 |
119 | - (BOOL)isEqual:(id)object
120 | {
121 | if (self == object) {
122 | return YES;
123 | }
124 |
125 | if (![object isKindOfClass:[STXPost class]]) {
126 | return NO;
127 | }
128 |
129 | return [self isEqualToPost:(STXPost *)object];
130 | }
131 |
132 | - (NSString *)description
133 | {
134 | NSDictionary *dictionary = @{ @"postID": self.postID ? : @"",
135 | @"postDate": self.postDate ? : @"",
136 | @"sharedURL": self.sharedURL ? : @"" };
137 | return [NSString stringWithFormat:@"<%@: %p> %@", NSStringFromClass([self class]), self, dictionary];
138 | }
139 |
140 | #pragma mark - STXPostItem
141 |
142 | - (NSDate *)postDate
143 | {
144 | NSTimeInterval createdTime = [[self.caption valueForKey:@"created_time"] doubleValue];
145 | return [NSDate dateWithTimeIntervalSince1970:createdTime];
146 | }
147 |
148 | - (NSString *)captionText
149 | {
150 | return [self.caption valueForKey:@"text"];
151 | }
152 |
153 | - (NSURL *)sharedURL
154 | {
155 | return self.link;
156 | }
157 |
158 | - (NSURL *)photoURL
159 | {
160 | return self.imageURL;
161 | }
162 |
163 | - (NSArray *)comments
164 | {
165 | if (_comments == nil) {
166 |
167 | NSMutableArray *mutableComments = [NSMutableArray array];
168 |
169 | NSArray *commentsArray = [self.commentsDictionary valueForKey:@"data"];
170 | for (NSDictionary *commentDictionary in commentsArray) {
171 | STXComment *comment = [[STXComment alloc] initWithDictionary:commentDictionary];
172 | [mutableComments addObject:comment];
173 | }
174 |
175 | _comments = [mutableComments copy];
176 | }
177 |
178 | return [_comments copy];
179 | }
180 |
181 | - (NSInteger)totalLikes
182 | {
183 | NSNumber *count = [self.likes valueForKey:@"count"];
184 | return [count integerValue];
185 | }
186 |
187 | - (NSInteger)totalComments
188 | {
189 | NSNumber *count = [self.commentsDictionary valueForKey:@"count"];
190 | return [count integerValue];
191 | }
192 |
193 | - (id)user
194 | {
195 | STXUser *user = [[STXUser alloc] initWithDictionary:self.userDictionary];
196 | return user;
197 | }
198 |
199 | @end
200 |
--------------------------------------------------------------------------------
/STXDynamicTableViewExample/Models/STXUser.h:
--------------------------------------------------------------------------------
1 | //
2 | // STXUser.h
3 | // STXDynamicTableViewExample
4 | //
5 | // Created by Jesse Armand on 9/4/14.
6 | // Copyright (c) 2014 2359 Media Pte Ltd. All rights reserved.
7 | //
8 |
9 | @import Foundation;
10 |
11 | #import "STXUserItem.h"
12 |
13 | @interface STXUser : NSObject
14 |
15 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/STXDynamicTableViewExample/Models/STXUser.m:
--------------------------------------------------------------------------------
1 | //
2 | // STXUser.m
3 | // STXDynamicTableViewExample
4 | //
5 | // Created by Jesse Armand on 9/4/14.
6 | // Copyright (c) 2014 2359 Media Pte Ltd. All rights reserved.
7 | //
8 |
9 | #import "STXUser.h"
10 |
11 | @interface STXUser ()
12 |
13 | @property (copy, nonatomic) NSString *userID;
14 | @property (copy, nonatomic) NSString *username;
15 | @property (copy, nonatomic) NSString *fullname;
16 | @property (copy, nonatomic) NSURL *profilePictureURL;
17 |
18 | @end
19 |
20 | @implementation STXUser
21 |
22 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary
23 | {
24 | self = [super init];
25 | if (self) {
26 | NSArray *errors;
27 | NSDictionary *mappingDictionary = @{ @"id": KZProperty(userID),
28 | @"username": KZProperty(username),
29 | @"full_name": KZProperty(fullname),
30 | @"profile_picture": KZBox(URL, profilePictureURL) };
31 |
32 | [KZPropertyMapper mapValuesFrom:dictionary toInstance:self usingMapping:mappingDictionary errors:&errors];
33 | }
34 |
35 | return self;
36 | }
37 |
38 | - (NSUInteger)hash
39 | {
40 | return [_userID hash];
41 | }
42 |
43 | - (BOOL)isEqualToUser:(STXUser *)user
44 | {
45 | return [user.userID isEqualToString:_userID];
46 | }
47 |
48 | - (BOOL)isEqual:(id)object
49 | {
50 | if (self == object) {
51 | return YES;
52 | }
53 |
54 | if (![object isKindOfClass:[STXUser class]]) {
55 | return NO;
56 | }
57 |
58 | return [self isEqualToUser:(STXUser *)object];
59 | }
60 |
61 | - (NSString *)description
62 | {
63 | NSDictionary *dictionary = @{ @"userID": self.userID ? : @"",
64 | @"username": self.username ? : @"",
65 | @"fullname": self.fullname ? : @"",
66 | @"profilePictureURL": self.profilePictureURL ? : @"" };
67 | return [NSString stringWithFormat:@"<%@: %p> %@", NSStringFromClass([self class]), self, dictionary];
68 | }
69 |
70 | @end
71 |
--------------------------------------------------------------------------------
/STXDynamicTableViewExample/STXAppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // STXAppDelegate.h
3 | // STXDynamicTableViewExample
4 | //
5 | // Created by Jesse Armand on 1/4/14.
6 | // Copyright (c) 2014 2359 Media Pte Ltd. All rights reserved.
7 | //
8 |
9 | @import UIKit;
10 |
11 | @interface STXAppDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow *window;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/STXDynamicTableViewExample/STXAppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // STXAppDelegate.m
3 | // STXDynamicTableViewExample
4 | //
5 | // Created by Jesse Armand on 1/4/14.
6 | // Copyright (c) 2014 2359 Media Pte Ltd. All rights reserved.
7 | //
8 |
9 | #import "STXAppDelegate.h"
10 |
11 | #import "STXFeedViewController.h"
12 |
13 | @implementation STXAppDelegate
14 |
15 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
16 | {
17 | return YES;
18 | }
19 |
20 | - (void)applicationWillResignActive:(UIApplication *)application
21 | {
22 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
23 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
24 | }
25 |
26 | - (void)applicationDidEnterBackground:(UIApplication *)application
27 | {
28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | - (void)applicationWillEnterForeground:(UIApplication *)application
33 | {
34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
35 | }
36 |
37 | - (void)applicationDidBecomeActive:(UIApplication *)application
38 | {
39 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
40 | }
41 |
42 | - (void)applicationWillTerminate:(UIApplication *)application
43 | {
44 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
45 | }
46 |
47 | @end
48 |
--------------------------------------------------------------------------------
/STXDynamicTableViewExample/STXDynamicTableViewExample-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | ${PRODUCT_NAME}
9 | CFBundleExecutable
10 | ${EXECUTABLE_NAME}
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | ${PRODUCT_NAME}
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1.0
25 | LSRequiresIPhoneOS
26 |
27 | UILaunchStoryboardName
28 | LaunchScreen
29 | UIMainStoryboardFile
30 | Feed
31 | NSAppTransportSecurity
32 |
33 | NSAllowsArbitraryLoads
34 |
35 |
36 | UIRequiredDeviceCapabilities
37 |
38 | armv7
39 |
40 | UISupportedInterfaceOrientations
41 |
42 | UIInterfaceOrientationPortrait
43 | UIInterfaceOrientationPortraitUpsideDown
44 | UIInterfaceOrientationLandscapeLeft
45 | UIInterfaceOrientationLandscapeRight
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/STXDynamicTableViewExample/STXDynamicTableViewExample-Prefix.pch:
--------------------------------------------------------------------------------
1 | //
2 | // Prefix header
3 | //
4 | // The contents of this file are implicitly included at the beginning of every source file.
5 | //
6 |
7 | #import
8 |
9 | #ifndef __IPHONE_7_0
10 | #warning "This project uses features only available in iOS SDK 7.0 and later."
11 | #endif
12 |
13 | #ifdef __OBJC__
14 | @import UIKit;
15 | @import Foundation;
16 |
17 | #import
18 | #import
19 | #import
20 | #import
21 | #import
22 | #import
23 | #import
24 |
25 | #import "STXDynamicTableView.h"
26 | #endif
27 |
--------------------------------------------------------------------------------
/STXDynamicTableViewExample/STXFeedViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // STXFeedViewController.h
3 | //
4 | // Created by Jesse Armand on 20/1/14.
5 | // Copyright (c) 2014 2359 Media. All rights reserved.
6 | //
7 |
8 | @interface STXFeedViewController : UIViewController
9 |
10 | @end
11 |
--------------------------------------------------------------------------------
/STXDynamicTableViewExample/STXFeedViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // STXFeedViewController.m
3 | //
4 | // Created by Jesse Armand on 20/1/14.
5 | // Copyright (c) 2014 2359 Media. All rights reserved.
6 | //
7 |
8 | #import "STXFeedViewController.h"
9 |
10 | #import "STXPost.h"
11 |
12 | #define PHOTO_CELL_ROW 0
13 |
14 | @interface STXFeedViewController ()
15 |
16 | @property (weak, nonatomic) IBOutlet UITableView *tableView;
17 | @property (strong, nonatomic) UIActivityIndicatorView *activityIndicatorView;
18 |
19 | @property (strong, nonatomic) STXFeedTableViewDataSource *tableViewDataSource;
20 | @property (strong, nonatomic) STXFeedTableViewDelegate *tableViewDelegate;
21 |
22 | @end
23 |
24 | @implementation STXFeedViewController
25 |
26 | - (void)viewDidLoad
27 | {
28 | [super viewDidLoad];
29 |
30 | self.title = NSLocalizedString(@"Feed", nil);
31 |
32 | self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
33 |
34 | STXFeedTableViewDataSource *dataSource = [[STXFeedTableViewDataSource alloc] initWithController:self tableView:self.tableView];
35 | self.tableView.dataSource = dataSource;
36 | self.tableViewDataSource = dataSource;
37 |
38 | STXFeedTableViewDelegate *delegate = [[STXFeedTableViewDelegate alloc] initWithController:self];
39 | self.tableView.delegate = delegate;
40 | self.tableViewDelegate = delegate;
41 |
42 | self.activityIndicatorView = [self activityIndicatorViewOnView:self.view];
43 |
44 | [self loadFeed];
45 | }
46 |
47 | - (void)dealloc
48 | {
49 | // To prevent crash when popping this from navigation controller
50 | self.tableView.delegate = nil;
51 | self.tableView.dataSource = nil;
52 | }
53 |
54 | - (void)viewDidAppear:(BOOL)animated
55 | {
56 | [super viewDidAppear:animated];
57 |
58 | // This will be notified when the Dynamic Type user setting changes (from the system Settings app)
59 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contentSizeCategoryChanged:) name:UIContentSizeCategoryDidChangeNotification object:nil];
60 |
61 | if ([self.tableViewDataSource.posts count] == 0) {
62 | [self.activityIndicatorView startAnimating];
63 | }
64 | }
65 |
66 | - (void)viewDidDisappear:(BOOL)animated
67 | {
68 | [super viewDidDisappear:animated];
69 |
70 | [[NSNotificationCenter defaultCenter] removeObserver:self name:UIContentSizeCategoryDidChangeNotification object:nil];
71 | }
72 |
73 | - (void)didReceiveMemoryWarning
74 | {
75 | [super didReceiveMemoryWarning];
76 | }
77 |
78 | - (void)contentSizeCategoryChanged:(NSNotification *)notification
79 | {
80 | [self.tableView reloadData];
81 | }
82 |
83 | #pragma mark - Feed
84 |
85 | - (void)loadFeed
86 | {
87 | NSString *feedPath = [[NSBundle mainBundle] pathForResource:@"instagram_media_popular" ofType:@"json"];
88 |
89 | NSError *error;
90 | NSData *jsonData = [NSData dataWithContentsOfFile:feedPath options:NSDataReadingMappedIfSafe error:&error];
91 | if (jsonData) {
92 | NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingAllowFragments error:&error];
93 | if (error) {
94 | UALog(@"%@", error);
95 | }
96 |
97 | NSDictionary *instagramPopularMediaDictionary = jsonObject;
98 | if (instagramPopularMediaDictionary) {
99 | NSArray *mediaDataArray = [instagramPopularMediaDictionary valueForKey:@"data"];
100 |
101 | NSMutableArray *posts = [NSMutableArray array];
102 | for (NSDictionary *mediaDictionary in mediaDataArray) {
103 | STXPost *post = [[STXPost alloc] initWithDictionary:mediaDictionary];
104 | [posts addObject:post];
105 | }
106 |
107 | self.tableViewDataSource.posts = [posts copy];
108 |
109 | [self.tableView reloadData];
110 |
111 | } else {
112 | if (error) {
113 | UALog(@"%@", error);
114 | }
115 | }
116 | } else {
117 | if (error) {
118 | UALog(@"%@", error);
119 | }
120 | }
121 |
122 | }
123 |
124 | #pragma mark - User Action Cell
125 |
126 | - (void)userDidLike:(STXUserActionCell *)userActionCell
127 | {
128 |
129 | }
130 |
131 | - (void)userDidUnlike:(STXUserActionCell *)userActionCell
132 | {
133 |
134 | }
135 |
136 | - (void)userWillComment:(STXUserActionCell *)userActionCell
137 | {
138 |
139 | }
140 |
141 | - (void)userWillShare:(STXUserActionCell *)userActionCell
142 | {
143 | id postItem = userActionCell.postItem;
144 |
145 | NSIndexPath *photoCellIndexPath = [NSIndexPath indexPathForRow:PHOTO_CELL_ROW inSection:userActionCell.indexPath.section];
146 | STXFeedPhotoCell *photoCell = (STXFeedPhotoCell *)[self.tableView cellForRowAtIndexPath:photoCellIndexPath];
147 | UIImage *photoImage = photoCell.photoImage;
148 |
149 | [self shareImage:photoImage text:postItem.captionText url:postItem.sharedURL];
150 | }
151 |
152 | @end
153 |
--------------------------------------------------------------------------------
/STXDynamicTableViewExample/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/STXDynamicTableViewExample/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // STXDynamicTableViewExample
4 | //
5 | // Created by Jesse Armand on 1/4/14.
6 | // Copyright (c) 2014 2359 Media Pte Ltd. All rights reserved.
7 | //
8 |
9 | @import UIKit;
10 |
11 | #import "STXAppDelegate.h"
12 |
13 | int main(int argc, char * argv[])
14 | {
15 | @autoreleasepool {
16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([STXAppDelegate class]));
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/STXDynamicTableViewExampleTests/STXDynamicTableViewExampleTests-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundlePackageType
14 | BNDL
15 | CFBundleShortVersionString
16 | 1.0
17 | CFBundleSignature
18 | ????
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/STXDynamicTableViewExampleTests/STXDynamicTableViewExampleTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // STXDynamicTableViewExampleTests.m
3 | // STXDynamicTableViewExampleTests
4 | //
5 | // Created by Jesse Armand on 1/4/14.
6 | // Copyright (c) 2014 2359 Media Pte Ltd. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface STXDynamicTableViewExampleTests : XCTestCase
12 |
13 | @end
14 |
15 | @implementation STXDynamicTableViewExampleTests
16 |
17 | - (void)setUp
18 | {
19 | [super setUp];
20 | // Put setup code here. This method is called before the invocation of each test method in the class.
21 | }
22 |
23 | - (void)tearDown
24 | {
25 | // Put teardown code here. This method is called after the invocation of each test method in the class.
26 | [super tearDown];
27 | }
28 |
29 | - (void)testExample
30 | {
31 | XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__);
32 | }
33 |
34 | @end
35 |
--------------------------------------------------------------------------------
/STXDynamicTableViewExampleTests/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/bin/setup:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | bundle install
4 | pod install
5 |
--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # The script exits immediately if any statement or command returns non-true value
4 | set -e
5 |
6 | xcodebuild -workspace "$PROJECT_NAME" -scheme "$SCHEME_NAME" -configuration "$CONFIGURATION_NAME" -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO | xcpretty -c && exit ${PIPESTATUS[0]}
7 |
8 |
--------------------------------------------------------------------------------