{"action":"created","comment":{"url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/pulls/comments/30153209","id":30153209,"diff_hunk":"@@ -0,0 +1,1366 @@\n+#import \"PostListViewController.h\"\n+\n+#import \"Blog.h\"\n+#import \"BlogService.h\"\n+#import \"ContextManager.h\"\n+#import \"EditSiteViewController.h\"\n+#import \"NavBarTitleDropdownButton.h\"\n+#import \"Post.h\"\n+#import \"PostService.h\"\n+#import \"PostCardTableViewCell.h\"\n+#import \"RestorePostTableViewCell.h\"\n+#import \"PostListFilter.h\"\n+#import \"PostListFooterView.h\"\n+#import \"PostPreviewViewController.h\"\n+#import \"PostSettingsSelectionViewController.h\"\n+#import \"PrivateSiteURLProtocol.h\"\n+#import \"StatsPostDetailsTableViewController.h\"\n+#import \"WPStatsService.h\"\n+#import \"UIView+Subviews.h\"\n+#import \"WordPressAppDelegate.h\"\n+#import \"WPAnimatedBox.h\"\n+#import \"WPLegacyEditPostViewController.h\"\n+#import \"WPNoResultsView+AnimatedBox.h\"\n+#import \"WPPostViewController.h\"\n+#import \"WPSearchController.h\"\n+#import \"WPStyleGuide+Posts.h\"\n+#import \"WPTableImageSource.h\"\n+#import \"WPTableViewHandler.h\"\n+#import \"WPToast.h\"\n+#import <WordPress-iOS-Shared/UIImage+Util.h>\n+#import <WordPress-iOS-Shared/WPStyleGuide.h>\n+#import \"WordPress-Swift.h\"\n+\n+typedef NS_ENUM(NSUInteger, PostAuthorFilter) {\n+    PostAuthorFilterMine,\n+    PostAuthorFilterEveryone,\n+};\n+\n+static NSString * const PostCardTextCellIdentifier = @\"PostCardTextCellIdentifier\";\n+static NSString * const PostCardImageCellIdentifier = @\"PostCardImageCellIdentifier\";\n+static NSString * const PostCardThumbCellIdentifier = @\"PostCardThumbCellIdentifier\";\n+static NSString * const PostCardRestoreCellIdentifier = @\"PostCardRestoreCellIdentifier\";\n+static NSString * const PostCardTextCellNibName = @\"PostCardTextCell\";\n+static NSString * const PostCardImageCellNibName = @\"PostCardImageCell\";\n+static NSString * const PostCardThumbCellNibName = @\"PostCardThumbCell\";\n+static NSString * const PostCardRestoreCellNibName = @\"RestorePostTableViewCell\";\n+static NSString * const PostsViewControllerRestorationKey = @\"PostsViewControllerRestorationKey\";\n+static NSString * const StatsStoryboardName = @\"SiteStats\";\n+static NSString * const CurrentPostListStatusFilterKey = @\"CurrentPostListStatusFilterKey\";\n+static NSString * const CurrentPostAuthorFilterKey = @\"CurrentPostAuthorFilterKey\";\n+\n+static const NSTimeInterval StatsCacheInterval = 300; // 5 minutes\n+static const NSTimeInterval PostsControllerRefreshInterval = 300; // 5 minutes\n+static const NSTimeInterval PostSearchBarAnimationDuration = 0.2; // seconds\n+\n+static const NSInteger PostsLoadMoreThreshold = 4;\n+static const NSInteger PostsFetchRequestBatchSize = 10;\n+static const CGFloat PostCardEstimatedRowHeight = 100.0;\n+static const CGFloat PostCardRestoreCellRowHeight = 54.0;\n+static const CGFloat PostsSearchBarWidth = 280.0;\n+static const CGFloat PostsSearchBariPadWidth = 210.0;\n+static const CGSize PreferredFiltersPopoverContentSize = {320.0, 220.0};\n+static const CGFloat SearchWrapperViewPortraitHeight = 64.0;\n+static const CGFloat SearchWrapperViewLandscapeHeight = 44.0;\n+\n+@interface PostListViewController () <WPTableViewHandlerDelegate,\n+                                            WPContentSyncHelperDelegate,\n+                                            UIViewControllerRestoration,\n+                                            WPNoResultsViewDelegate,\n+                                            PostCardTableViewCellDelegate,\n+                                            UIPopoverControllerDelegate,\n+                                            WPSearchControllerDelegate,\n+                                            WPSearchResultsUpdating>\n+\n+@property (nonatomic, strong) UITableViewController *postListViewController;\n+@property (nonatomic, weak) UITableView *tableView;\n+@property (nonatomic, weak) UIRefreshControl *refreshControl;\n+@property (nonatomic, strong) WPTableViewHandler *tableViewHandler;\n+@property (nonatomic, strong) WPContentSyncHelper *syncHelper;\n+@property (nonatomic, strong) PostCardTableViewCell *textCellForLayout;\n+@property (nonatomic, strong) PostCardTableViewCell *imageCellForLayout;\n+@property (nonatomic, strong) PostCardTableViewCell *thumbCellForLayout;\n+@property (nonatomic, strong) WPNoResultsView *noResultsView;\n+@property (nonatomic, strong) PostListFooterView *postListFooterView;\n+@property (nonatomic, strong) WPAnimatedBox *animatedBox;\n+@property (nonatomic, weak) IBOutlet NavBarTitleDropdownButton *filterButton;\n+@property (nonatomic, weak) IBOutlet UIView *rightBarButtonView;\n+@property (nonatomic, weak) IBOutlet UIButton *searchButton;\n+@property (nonatomic, weak) IBOutlet UIButton *addButton;\n+@property (nonatomic, weak) IBOutlet UIView *searchWrapperView; // Used on iPhone for presenting the search bar.\n+@property (nonatomic, weak) IBOutlet UIView *authorsFilterView; // Search lives here on iPad\n+@property (nonatomic, weak) IBOutlet UISegmentedControl *authorsFilter;\n+@property (nonatomic, weak) IBOutlet NSLayoutConstraint *authorsFilterViewHeightConstraint;\n+@property (nonatomic, weak) IBOutlet NSLayoutConstraint *searchWrapperViewHeightConstraint;\n+@property (nonatomic, strong) WPSearchController *searchController; // Stand-in for UISearchController\n+@property (nonatomic, strong) UIPopoverController *postFilterPopoverController;\n+@property (nonatomic, strong) NSArray *postListFilters;\n+@property (nonatomic, strong) NSMutableArray *recentlyTrashedPostIDs; // IDs of trashed posts. Cleared on refresh or when filter changes.\n+\n+@end\n+\n+@implementation PostListViewController\n+\n+#pragma mark - Lifecycle Methods\n+\n++ (instancetype)controllerWithBlog:(Blog *)blog\n+{\n+    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@\"Posts\" bundle:[NSBundle mainBundle]];\n+    PostListViewController *controller = [storyboard instantiateViewControllerWithIdentifier:@\"PostListViewController\"];\n+    controller.blog = blog;\n+    controller.restorationClass = [self class];\n+    return controller;\n+}\n+\n++ (UIViewController *)viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents coder:(NSCoder *)coder\n+{\n+    NSString *blogID = [coder decodeObjectForKey:PostsViewControllerRestorationKey];\n+    if (!blogID) {\n+        return nil;\n+    }\n+\n+    NSManagedObjectContext *context = [[ContextManager sharedInstance] mainContext];\n+    NSManagedObjectID *objectID = [context.persistentStoreCoordinator managedObjectIDForURIRepresentation:[NSURL URLWithString:blogID]];\n+    if (!objectID) {\n+        return nil;\n+    }\n+\n+    NSError *error = nil;\n+    Blog *restoredBlog = (Blog *)[context existingObjectWithID:objectID error:&error];\n+    if (error || !restoredBlog) {\n+        return nil;\n+    }\n+\n+    return [self controllerWithBlog:restoredBlog];\n+}\n+\n+- (void)encodeRestorableStateWithCoder:(NSCoder *)coder\n+{\n+    [coder encodeObject:[[self.blog.objectID URIRepresentation] absoluteString] forKey:PostsViewControllerRestorationKey];\n+    [super encodeRestorableStateWithCoder:coder];\n+}\n+\n+- (void)dealloc\n+{\n+    [PrivateSiteURLProtocol unregisterPrivateSiteURLProtocol];\n+}\n+\n+- (instancetype)initWithCoder:(NSCoder *)aDecoder\n+{\n+    self = [super initWithCoder:aDecoder];\n+    if (self) {\n+        [PrivateSiteURLProtocol registerPrivateSiteURLProtocol];\n+    }\n+    return self;\n+}\n+\n+- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender\n+{\n+    self.postListViewController = segue.destinationViewController;\n+}\n+\n+- (void)viewDidLoad\n+{\n+    [super viewDidLoad];\n+    self.recentlyTrashedPostIDs = [NSMutableArray array];\n+\n+    self.title = NSLocalizedString(@\"Posts\", @\"Tile of the screen showing the list of posts for a blog.\");\n+    self.tableView = self.postListViewController.tableView;\n+    self.refreshControl = self.postListViewController.refreshControl;\n+    [self.refreshControl addTarget:self action:@selector(refresh:) forControlEvents:UIControlEventValueChanged];\n+\n+    [self configureFilters];\n+    [self configureCellsForLayout];\n+    [self configureTableView];\n+    [self configureFooterView];\n+    [self configureSyncHelper];\n+    [self configureNavbar];\n+    [self configureAuthorFilter];\n+    [self configureSearchController];\n+    [self configureSearchBar];\n+    [self configureSearchWrapper];\n+    [self configureTableViewHandler];\n+\n+    [WPStyleGuide configureColorsForView:self.view andTableView:self.tableView];\n+    [self.tableView reloadData];\n+}\n+\n+- (void)viewWillAppear:(BOOL)animated\n+{\n+    [super viewWillAppear:animated];\n+\n+    [self configureNoResultsView];\n+}\n+\n+- (void)viewDidAppear:(BOOL)animated\n+{\n+    [super viewDidAppear:animated];\n+\n+    [self automaticallySyncIfAppropriate];\n+}\n+\n+- (void)viewWillDisappear:(BOOL)animated\n+{\n+    [super viewWillDisappear:animated];\n+    self.searchController.active = NO;\n+}\n+\n+- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration\n+{\n+    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];\n+    if ([UIDevice isPad]) {\n+        return;\n+    }\n+\n+    CGRect bounds = self.view.window.frame;\n+    CGFloat width = CGRectGetWidth(bounds);\n+    CGFloat height = CGRectGetHeight(bounds);\n+    if (UIInterfaceOrientationIsPortrait(toInterfaceOrientation)) {\n+        width = MIN(width, height);\n+    } else {\n+        width = MAX(width, height);\n+    }\n+\n+    [self.tableViewHandler refreshCachedRowHeightsForWidth:width];\n+\n+    if (self.searchWrapperViewHeightConstraint.constant > 0) {\n+        self.searchWrapperViewHeightConstraint.constant = [self heightForSearchWrapperView];\n+    }\n+}\n+\n+\n+#pragma mark - Configuration\n+\n+- (void)configureFilters\n+{\n+    self.postListFilters = [PostListFilter newPostListFilters];\n+}\n+\n+- (void)configureNavbar\n+{\n+    // IMPORTANT: this code makes sure that the back button in WPPostViewController doesn't show\n+    // this VC's title.\n+    //\n+    UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:[NSString string] style:UIBarButtonItemStylePlain target:nil action:nil];\n+    self.navigationItem.backBarButtonItem = backButton;\n+\n+    UIBarButtonItem *rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:self.rightBarButtonView];\n+    [WPStyleGuide setRightBarButtonItemWithCorrectSpacing:rightBarButtonItem forNavigationItem:self.navigationItem];\n+\n+    self.searchButton.hidden = [UIDevice isPad];\n+\n+    self.navigationItem.titleView = self.filterButton;\n+    [self updateFilterTitle];\n+}\n+\n+- (void)configureCellsForLayout\n+{\n+    self.textCellForLayout = (PostCardTableViewCell *)[[[NSBundle mainBundle] loadNibNamed:PostCardTextCellNibName owner:nil options:nil] firstObject];\n+    [self forceUpdateCellLayout:self.textCellForLayout];\n+\n+    self.imageCellForLayout = (PostCardTableViewCell *)[[[NSBundle mainBundle] loadNibNamed:PostCardImageCellNibName owner:nil options:nil] firstObject];\n+    [self forceUpdateCellLayout:self.imageCellForLayout];\n+\n+    self.thumbCellForLayout = (PostCardTableViewCell *)[[[NSBundle mainBundle] loadNibNamed:PostCardThumbCellNibName owner:nil options:nil] firstObject];\n+    [self forceUpdateCellLayout:self.thumbCellForLayout];\n+}\n+\n+- (void)forceUpdateCellLayout:(PostCardTableViewCell *)cell\n+{\n+    // Force a layout pass to ensure that constrants are configured for the\n+    // proper size class.\n+    [self.view addSubview:cell];\n+    [cell updateConstraintsIfNeeded];\n+    [cell layoutIfNeeded];\n+    [cell removeFromSuperview];\n+}\n+\n+- (void)configureTableView\n+{\n+    self.tableView.accessibilityIdentifier = @\"PostsTable\";\n+    self.tableView.isAccessibilityElement = YES;\n+    self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;\n+\n+    // Register the cells\n+    UINib *postCardTextCellNib = [UINib nibWithNibName:PostCardTextCellNibName bundle:[NSBundle mainBundle]];\n+    [self.tableView registerNib:postCardTextCellNib forCellReuseIdentifier:PostCardTextCellIdentifier];\n+\n+    UINib *postCardImageCellNib = [UINib nibWithNibName:PostCardImageCellNibName bundle:[NSBundle mainBundle]];\n+    [self.tableView registerNib:postCardImageCellNib forCellReuseIdentifier:PostCardImageCellIdentifier];\n+\n+    UINib *postCardThumbCellNib = [UINib nibWithNibName:PostCardThumbCellNibName bundle:[NSBundle mainBundle]];\n+    [self.tableView registerNib:postCardThumbCellNib forCellReuseIdentifier:PostCardThumbCellIdentifier];\n+\n+    UINib *postCardRestoreCellNib = [UINib nibWithNibName:PostCardRestoreCellNibName bundle:[NSBundle mainBundle]];\n+    [self.tableView registerNib:postCardRestoreCellNib forCellReuseIdentifier:PostCardRestoreCellIdentifier];\n+}\n+\n+- (void)configureFooterView\n+{\n+    self.postListFooterView = (PostListFooterView *)[[[NSBundle mainBundle] loadNibNamed:NSStringFromClass([PostListFooterView class]) owner:nil options:nil] firstObject];\n+    [self.postListFooterView showSpinner:NO];\n+    self.tableView.tableFooterView = self.postListFooterView;\n+}\n+\n+- (void)configureTableViewHandler\n+{\n+    self.tableViewHandler = [[WPTableViewHandler alloc] initWithTableView:self.tableView];\n+    self.tableViewHandler.cacheRowHeights = YES;\n+    self.tableViewHandler.delegate = self;\n+    self.tableViewHandler.updateRowAnimation = UITableViewRowAnimationNone;\n+}\n+\n+- (void)configureSyncHelper\n+{\n+    self.syncHelper = [[WPContentSyncHelper alloc] init];\n+    self.syncHelper.delegate = self;\n+}\n+\n+- (void)configureNoResultsView\n+{\n+    if (!self.isViewLoaded) {\n+        return;\n+    }\n+\n+    if (!self.noResultsView) {\n+        self.noResultsView = [[WPNoResultsView alloc] init];\n+        self.noResultsView.delegate = self;\n+    }\n+\n+    if ([self.tableViewHandler.resultsController.fetchedObjects count] > 0) {\n+        [self.noResultsView removeFromSuperview];\n+        self.postListFooterView.hidden = NO;\n+        return;\n+    }\n+    self.postListFooterView.hidden = YES;\n+\n+    // Refresh the NoResultsView Properties\n+    self.noResultsView.titleText        = self.noResultsTitleText;\n+    self.noResultsView.messageText      = self.noResultsMessageText;\n+    self.noResultsView.accessoryView    = self.noResultsAccessoryView;\n+    self.noResultsView.buttonTitle      = self.noResultsButtonText;\n+\n+    // Only add and animate no results view if it isn't already\n+    // in the table view\n+    if (![self.noResultsView isDescendantOfView:self.tableView]) {\n+        [self.tableView addSubviewWithFadeAnimation:self.noResultsView];\n+    } else {\n+        [self.noResultsView centerInSuperview];\n+    }\n+\n+    [self.tableView sendSubviewToBack:self.noResultsView];\n+}\n+\n+- (NSString *)noResultsTitleText\n+{\n+    if (self.syncHelper.isSyncing) {\n+        return NSLocalizedString(@\"Fetching posts...\", @\"A brief prompt shown when the reader is empty, letting the user know the app is currently fetching new posts.\");\n+    }\n+    PostListFilter *filter = [self currentPostListFilter];\n+    NSString *title;\n+    switch (filter.filterType) {\n+        case PostListStatusFilterDraft:\n+            title = NSLocalizedString(@\"You don't have any drafts.\", @\"Displayed when the user views drafts in the posts list and there are no posts\");\n+            break;\n+        case PostListStatusFilterScheduled:\n+            title = NSLocalizedString(@\"You don't have any scheduled posts.\", @\"Displayed when the user views scheduled posts in the posts list and there are no posts\");\n+            break;\n+        case PostListStatusFilterTrashed:\n+            title = NSLocalizedString(@\"You don't have any posts in your trash folder.\", @\"Displayed when the user views trashed in the posts list and there are no posts\");\n+            break;\n+        default:\n+            title = NSLocalizedString(@\"You haven't published any posts yet.\", @\"Displayed when the user views published posts in the posts list and there are no posts\");\n+            break;\n+    }\n+    return title;\n+}\n+\n+- (NSString *)noResultsMessageText {\n+    if (self.syncHelper.isSyncing) {\n+        return [NSString string];\n+    }\n+    NSString *message;\n+    PostListFilter *filter = [self currentPostListFilter];\n+    switch (filter.filterType) {\n+        case PostListStatusFilterDraft:\n+            message = NSLocalizedString(@\"Would you like to create one?\", @\"Displayed when the user views drafts in the posts list and there are no posts\");\n+            break;\n+        case PostListStatusFilterScheduled:\n+            message = NSLocalizedString(@\"Would you like to schedule a draft to publish?\", @\"Displayed when the user views scheduled posts in the posts list and there are no posts\");\n+            break;\n+        case PostListStatusFilterTrashed:\n+            message = NSLocalizedString(@\"Everything you write is solid gold.\", @\"Displayed when the user views trashed posts in the posts list and there are no posts\");\n+            break;\n+        default:\n+            message = NSLocalizedString(@\"Would you like to publish your first post?\", @\"Displayed when the user views published posts in the posts list and there are no posts\");\n+            break;\n+    }\n+    return message;\n+}\n+\n+- (UIView *)noResultsAccessoryView {\n+    if (self.syncHelper.isSyncing) {\n+        if (!self.animatedBox) {\n+            self.animatedBox = [WPAnimatedBox new];\n+        }\n+        return self.animatedBox;\n+    }\n+    return [[UIImageView alloc] initWithImage:[UIImage imageNamed:@\"penandink\"]];\n+}\n+\n+- (NSString *)noResultsButtonText\n+{\n+    if (self.syncHelper.isSyncing) {\n+        return nil;\n+    }\n+    NSString *title;\n+    PostListFilter *filter = [self currentPostListFilter];\n+    switch (filter.filterType) {\n+        case PostListStatusFilterScheduled:\n+            title = NSLocalizedString(@\"Edit Drafts\", @\"Button title, encourages users to schedule a draft post to publish.\");\n+            break;\n+        case PostListStatusFilterTrashed:\n+            title = [NSString string];\n+            break;\n+        default:\n+            title = NSLocalizedString(@\"Start a Post\", @\"Button title, encourages users to create their first post on their blog.\");\n+            break;\n+    }\n+    return title;\n+}\n+\n+- (void)configureAuthorFilter\n+{\n+    NSString *onlyMe = NSLocalizedString(@\"Only Me\", @\"Label for the post author filter. This fliter shows posts only authored by the current user.\");\n+    NSString *everyone = NSLocalizedString(@\"Everyone\", @\"Label for the post author filter. This filter shows posts for all users on the blog.\");\n+    [WPStyleGuide applyPostAuthorFilterStyle:self.authorsFilter];\n+    [self.authorsFilter setTitle:onlyMe forSegmentAtIndex:0];\n+    [self.authorsFilter setTitle:everyone forSegmentAtIndex:1];\n+    self.authorsFilter.hidden = (!self.blog.isMultiAuthor || !self.blog.account.userID);\n+\n+    self.authorsFilterView.backgroundColor = [WPStyleGuide lightGrey];\n+    if (![self.blog isMultiAuthor] && ![UIDevice isPad]) {\n+        // Collapse the view on iPhone if single author blog\n+        self.authorsFilterViewHeightConstraint.constant = 0.0;\n+    }\n+\n+    if ([self currentPostAuthorFilter] == PostAuthorFilterMine) {\n+        self.authorsFilter.selectedSegmentIndex = 0;\n+    } else {\n+        self.authorsFilter.selectedSegmentIndex = 1;\n+    }\n+}\n+\n+- (void)configureSearchController\n+{\n+    self.searchController = [[WPSearchController alloc] initWithSearchResultsController:nil];\n+    self.searchController.dimsBackgroundDuringPresentation = NO;\n+    self.searchController.hidesNavigationBarDuringPresentation = ![UIDevice isPad];\n+    self.searchController.delegate = self;\n+    self.searchController.searchResultsUpdater = self;\n+}\n+\n+- (void)configureSearchBar\n+{\n+    [self configureSearchBarPlaceholder];\n+\n+    UISearchBar *searchBar = self.searchController.searchBar;\n+    searchBar.translatesAutoresizingMaskIntoConstraints = NO;\n+    searchBar.accessibilityIdentifier = @\"Search\";\n+    searchBar.autocapitalizationType = UITextAutocapitalizationTypeNone;\n+    searchBar.backgroundImage = [[UIImage alloc] init];\n+    searchBar.tintColor = [WPStyleGuide grey]; // cursor color\n+    searchBar.translucent = NO;\n+    [searchBar setImage:[UIImage imageNamed:@\"icon-clear-textfield\"] forSearchBarIcon:UISearchBarIconClear state:UIControlStateNormal];\n+    [searchBar setImage:[UIImage imageNamed:@\"icon-post-list-search\"] forSearchBarIcon:UISearchBarIconSearch state:UIControlStateNormal];\n+    if ([UIDevice isPad]) {\n+        [self configureSearchBarForFilterView];\n+    } else {\n+        [self configureSearchBarForSearchView];\n+    }\n+}\n+\n+- (void)configureSearchBarForFilterView\n+{\n+    [[UITextField appearanceWhenContainedIn:[UISearchBar class], [self class], nil] setDefaultTextAttributes:[WPStyleGuide defaultSearchBarTextAttributes:[WPStyleGuide postListSearchBarTextColor]]];\n+    [[UIButton appearanceWhenContainedIn:[UISearchBar class], [self class], nil] setTitleColor:[WPStyleGuide wordPressBlue] forState:UIControlStateNormal];\n+    UISearchBar *searchBar = self.searchController.searchBar;\n+    searchBar.barStyle = UIBarStyleDefault;\n+    searchBar.barTintColor = [WPStyleGuide lightGrey];\n+    searchBar.showsCancelButton = NO;\n+\n+    [self.authorsFilterView insertSubview:searchBar atIndex:0];\n+\n+    NSDictionary *views = NSDictionaryOfVariableBindings(searchBar);\n+    NSDictionary *metrics = @{\n+                              @\"searchBarWidth\":@(PostsSearchBarWidth),\n+                              @\"searchBariPadWidth\":@(PostsSearchBariPadWidth)\n+                              };\n+    [self.authorsFilterView addConstraint:[NSLayoutConstraint constraintWithItem:searchBar\n+                                                                       attribute:NSLayoutAttributeCenterY\n+                                                                       relatedBy:NSLayoutRelationEqual\n+                                                                          toItem:self.authorsFilterView\n+                                                                       attribute:NSLayoutAttributeCenterY\n+                                                                      multiplier:1.0\n+                                                                        constant:0.0]];\n+    if (self.blog.isMultiAuthor) {\n+        [self.authorsFilterView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@\"[searchBar(searchBariPadWidth)]-|\"\n+                                                                                       options:0\n+                                                                                       metrics:metrics\n+                                                                                         views:views]];\n+    } else {\n+        [self.authorsFilterView addConstraint:[NSLayoutConstraint constraintWithItem:searchBar\n+                                                                           attribute:NSLayoutAttributeCenterX\n+                                                                           relatedBy:NSLayoutRelationEqual\n+                                                                              toItem:self.authorsFilterView\n+                                                                           attribute:NSLayoutAttributeCenterX\n+                                                                          multiplier:1.0\n+                                                                            constant:0.0]];\n+        [self.authorsFilterView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@\"[searchBar(searchBarWidth)]\"\n+                                                                                       options:0\n+                                                                                       metrics:metrics\n+                                                                                         views:views]];\n+    }\n+}\n+\n+- (void)configureSearchBarForSearchView\n+{\n+    [[UITextField appearanceWhenContainedIn:[UISearchBar class], [self class], nil] setDefaultTextAttributes:[WPStyleGuide defaultSearchBarTextAttributes:[UIColor whiteColor]]];\n+\n+    UISearchBar *searchBar = self.searchController.searchBar;\n+    searchBar.barStyle = UIBarStyleBlack;\n+    searchBar.barTintColor = [WPStyleGuide wordPressBlue];\n+    searchBar.showsCancelButton = YES;\n+\n+    [self.searchWrapperView addSubview:searchBar];\n+\n+    NSDictionary *views = NSDictionaryOfVariableBindings(searchBar);\n+    [self.searchWrapperView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@\"|[searchBar]|\"\n+                                                                                   options:0\n+                                                                                   metrics:nil\n+                                                                                     views:views]];\n+    [self.searchWrapperView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@\"V:[searchBar]|\"\n+                                                                                   options:0\n+                                                                                   metrics:nil\n+                                                                                     views:views]];\n+}\n+\n+- (void)configureSearchBarPlaceholder\n+{\n+    // Adjust color depending on where the search bar is being presented.\n+    UIColor *placeholderColor = [UIDevice isPad] ? [WPStyleGuide grey] : [WPStyleGuide wordPressBlue];\n+    NSString *placeholderText = NSLocalizedString(@\"Search\", @\"Placeholder text for the search bar on the post screen.\");\n+    NSAttributedString *attrPlacholderText = [[NSAttributedString alloc] initWithString:placeholderText attributes:[WPStyleGuide defaultSearchBarTextAttributes:placeholderColor]];\n+    [[UITextField appearanceWhenContainedIn:[UISearchBar class], [self class], nil] setAttributedPlaceholder:attrPlacholderText];\n+}\n+\n+- (void)configureSearchWrapper\n+{\n+    self.searchWrapperView.backgroundColor = [WPStyleGuide wordPressBlue];\n+}\n+\n+\n+#pragma mark - Actions\n+\n+- (IBAction)refresh:(id)sender\n+{\n+    [self syncItemsWithUserInteraction:YES];\n+}\n+\n+- (IBAction)handleAddButtonTapped:(id)sender\n+{\n+    [self createPost];\n+}\n+\n+- (IBAction)handleSearchButtonTapped:(id)sender\n+{\n+    [self toggleSearch];\n+}\n+\n+- (IBAction)handleAuthorFilterChanged:(id)sender\n+{\n+    if (self.authorsFilter.selectedSegmentIndex == PostAuthorFilterMine) {\n+        [self setCurrentPostAuthorFilter:PostAuthorFilterMine];\n+    } else {\n+        [self setCurrentPostAuthorFilter:PostAuthorFilterEveryone];\n+    }\n+}\n+\n+- (void)didTapNoResultsView:(WPNoResultsView *)noResultsView\n+{\n+    if ([self currentPostListFilter].filterType == PostListStatusFilterScheduled) {\n+        NSInteger index = [self indexForFilterWithType:PostListStatusFilterDraft];\n+        [self setCurrentFilterIndex:index];\n+        return;\n+    }\n+    [self createPost];\n+}\n+\n+- (IBAction)didTapFilterButton:(id)sender\n+{\n+    if (self.postFilterPopoverController) {\n+        return;\n+    }\n+    [self displayFilters];\n+}\n+\n+\n+#pragma mark - Syncing\n+\n+- (void)automaticallySyncIfAppropriate\n+{\n+    // Only automatically refresh if the view is loaded and visible on the screen\n+    if (self.isViewLoaded == NO || self.view.window == nil) {\n+        DDLogVerbose(@\"View is not visible and will not check for auto refresh.\");\n+        return;\n+    }\n+\n+    // Do not start auto-sync if connection is down\n+    WordPressAppDelegate *appDelegate = [WordPressAppDelegate sharedInstance];\n+    if (appDelegate.connectionAvailable == NO) {\n+        [self configureNoResultsView];\n+        return;\n+    }\n+\n+    NSDate *lastSynced = self.blog.lastPostsSync;\n+    if (lastSynced == nil || ABS([lastSynced timeIntervalSinceNow]) > PostsControllerRefreshInterval) {\n+        // Update in the background\n+        [self syncItemsWithUserInteraction:NO];\n+    } else {\n+        [self configureNoResultsView];\n+    }\n+}\n+\n+- (void)syncItemsWithUserInteraction:(BOOL)userInteraction\n+{\n+    [self.syncHelper syncContentWithUserInteraction:userInteraction];\n+    [self configureNoResultsView];\n+}\n+\n+- (void)setHasMore:(BOOL)hasMore forFilter:(PostListFilter *)filter\n+{\n+    filter.hasMore = hasMore;\n+}\n+\n+\n+#pragma mark - Sync Helper Delegate Methods\n+\n+- (void)syncHelper:(WPContentSyncHelper *)syncHelper syncContentWithUserInteraction:(BOOL)userInteraction success:(void (^)(BOOL))success failure:(void (^)(NSError *))failure\n+{\n+    if ([self.recentlyTrashedPostIDs count]) {\n+        [self.recentlyTrashedPostIDs removeAllObjects];\n+        [self updateAndPerformFetchRequestRefreshingCachedRowHeights];\n+    }\n+\n+    PostListFilter *filter = [self currentPostListFilter];\n+    NSArray *postStatus = filter.statuses;\n+    __weak __typeof(self) weakSelf = self;\n+    PostService *postService = [[PostService alloc] initWithManagedObjectContext:[self managedObjectContext]];\n+    [postService syncPostsOfType:PostServiceTypePost withStatuses:postStatus forBlog:self.blog success:^(BOOL hasMore){\n+        if  (success) {\n+            [weakSelf setHasMore:hasMore forFilter:filter];\n+            success(hasMore);\n+        }\n+    } failure:^(NSError *error) {\n+        if (failure) {\n+            failure(error);\n+        }\n+        if (userInteraction) {\n+            [self handleSyncFailure:error];\n+        }\n+    }];\n+}\n+\n+- (void)syncHelper:(WPContentSyncHelper *)syncHelper syncMoreWithSuccess:(void (^)(BOOL))success failure:(void (^)(NSError *))failure\n+{\n+    [self.postListFooterView showSpinner:YES];\n+    PostListFilter *filter = [self currentPostListFilter];\n+    NSArray *postStatus = filter.statuses;\n+    __weak __typeof(self) weakSelf = self;\n+    PostService *postService = [[PostService alloc] initWithManagedObjectContext:[self managedObjectContext]];\n+    [postService loadMorePostsOfType:PostServiceTypePost withStatuses:postStatus forBlog:self.blog success:^(BOOL hasMore){\n+        if (success) {\n+            [weakSelf setHasMore:hasMore forFilter:filter];\n+            success(hasMore);\n+        }\n+    } failure:^(NSError *error) {\n+        if (failure) {\n+            failure(error);\n+        }\n+        [self handleSyncFailure:error];\n+    }];\n+}\n+\n+- (void)syncContentEnded\n+{\n+    [self.refreshControl endRefreshing];\n+    [self.postListFooterView showSpinner:NO];\n+\n+    self.blog.lastPostsSync = [NSDate date];\n+\n+    [self.noResultsView removeFromSuperview];\n+    if ([[self.tableViewHandler.resultsController fetchedObjects] count] == 0) {\n+        // This is a special case.  Core data can be a bit slow about notifying\n+        // NSFetchedResultsController delegates about changes to the fetched results.\n+        // To compensate, call configureNoResultsView after a short delay.\n+        // It will be redisplayed if necessary.\n+        [self performSelector:@selector(configureNoResultsView) withObject:self afterDelay:0.1];\n+    }\n+}\n+\n+- (void)handleSyncFailure:(NSError *)error\n+{\n+    if ([error.domain isEqualToString:WPXMLRPCClientErrorDomain]) {\n+        if (error.code == 403) {\n+            [self promptForPasswordWithMessage:nil];\n+            return;\n+        }\n+    }\n+    [WPError showNetworkingAlertWithError:error title:NSLocalizedString(@\"Unable to Sync\", @\"Title of error prompt shown when a sync the user initiated fails.\")];\n+}\n+\n+- (void)promptForPasswordWithMessage:(NSString *)message\n+{\n+    if (message == nil) {\n+        message = NSLocalizedString(@\"The username or password stored in the app may be out of date. Please re-enter your password in the settings and try again.\", @\"\");\n+    }\n+    [WPError showAlertWithTitle:NSLocalizedString(@\"Unable to Connect\", @\"\") message:message];\n+\n+    // bad login/pass combination\n+    EditSiteViewController *editSiteViewController = [[EditSiteViewController alloc] initWithBlog:self.blog];\n+    editSiteViewController.isCancellable = YES;\n+\n+    UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:editSiteViewController];\n+    navController.navigationBar.translucent = NO;\n+\n+    if (IS_IPAD) {\n+        navController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;\n+        navController.modalPresentationStyle = UIModalPresentationFormSheet;\n+    }\n+\n+    [self presentViewController:navController animated:YES completion:nil];\n+}\n+\n+\n+#pragma mark - TableView Handler Delegate Methods\n+\n+- (NSManagedObjectContext *)managedObjectContext\n+{\n+    return [[ContextManager sharedInstance] mainContext];\n+}\n+\n+- (NSFetchRequest *)fetchRequest\n+{\n+    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([Post class])];\n+    fetchRequest.predicate = [self predicateForFetchRequest];\n+    NSSortDescriptor *sortDescriptorDate = [NSSortDescriptor sortDescriptorWithKey:@\"date_created_gmt\" ascending:NO];\n+    fetchRequest.sortDescriptors = @[sortDescriptorDate];\n+    fetchRequest.fetchBatchSize = PostsFetchRequestBatchSize;\n+    return fetchRequest;\n+}\n+\n+- (void)updateAndPerformFetchRequestRefreshingCachedRowHeights\n+{\n+    NSAssert([NSThread isMainThread], @\"PostsViewController Error: NSFetchedResultsController accessed in BG\");\n+\n+    NSPredicate *predicate = [self predicateForFetchRequest];\n+    NSError *error = nil;\n+    [self.tableViewHandler.resultsController.fetchRequest setPredicate:predicate];\n+    [self.tableViewHandler.resultsController performFetch:&error];\n+    if (error) {\n+        DDLogError(@\"Error fetching posts after updating the fetch request predicate: %@\", error);\n+    }\n+\n+    CGFloat width = CGRectGetWidth(self.tableView.bounds);\n+    [self.tableViewHandler refreshCachedRowHeightsForWidth:width];\n+\n+    [self.tableView reloadData];\n+    [self configureNoResultsView];\n+}\n+\n+- (NSPredicate *)predicateForFetchRequest\n+{\n+    NSMutableArray *predicates = [NSMutableArray array];\n+\n+    NSPredicate *basePredicate = [NSPredicate predicateWithFormat:@\"blog = %@ && original = nil\", self.blog];\n+    [predicates addObject:basePredicate];\n+\n+    NSPredicate *filterPredicate = [self currentPostListFilter].predicateForFetchRequest;\n+    [predicates addObject:filterPredicate];\n+\n+    if (self.blog.isMultiAuthor && ![self shouldShowPostsForEveryone] && [self.blog.account.userID integerValue] > 0) {\n+        NSPredicate *authorPredicate = [NSPredicate predicateWithFormat:@\"authorID = %@\", self.blog.account.userID];\n+        [predicates addObject:authorPredicate];\n+    }\n+\n+    NSString *searchText = self.searchController.searchBar.text;\n+    if ([searchText length] > 0) {\n+        NSPredicate *searchPredicate = [NSPredicate predicateWithFormat:@\"postTitle CONTAINS[cd] %@\", searchText];\n+        [predicates addObject:searchPredicate];\n+    }\n+\n+    NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:predicates];\n+    if ([searchText length] == 0 && [self.recentlyTrashedPostIDs count] > 0) {\n+        NSPredicate *trashedPredicate = [NSPredicate predicateWithFormat:@\"postID IN %@\", self.recentlyTrashedPostIDs];\n+        predicate = [NSCompoundPredicate orPredicateWithSubpredicates:@[predicate, trashedPredicate]];\n+    }\n+\n+    return predicate;\n+}\n+\n+- (void)tableViewDidChangeContent:(UITableView *)tableView\n+{\n+    // After any change, make sure that the no results view is properly\n+    // configured.\n+    [self configureNoResultsView];\n+}\n+\n+\n+#pragma mark - Table View Handling\n+\n+- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath\n+{\n+    Post *post = (Post *)[self.tableViewHandler.resultsController objectAtIndexPath:indexPath];\n+    if ([[self cellIdentifierForPost:post] isEqualToString:PostCardRestoreCellIdentifier]) {\n+        return PostCardRestoreCellRowHeight;\n+    }\n+\n+    return PostCardEstimatedRowHeight;\n+}\n+\n+- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath\n+{\n+    Post *post = (Post *)[self.tableViewHandler.resultsController objectAtIndexPath:indexPath];\n+    if ([[self cellIdentifierForPost:post] isEqualToString:PostCardRestoreCellIdentifier]) {\n+        return PostCardRestoreCellRowHeight;\n+    }\n+\n+    CGFloat width = CGRectGetWidth(self.tableView.bounds);\n+    return [self tableView:tableView heightForRowAtIndexPath:indexPath forWidth:width];\n+}\n+\n+- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath forWidth:(CGFloat)width\n+{\n+    PostCardTableViewCell *cell;\n+    Post *post = (Post *)[self.tableViewHandler.resultsController objectAtIndexPath:indexPath];\n+    if (![post.pathForDisplayImage length]) {\n+        cell = self.textCellForLayout;\n+    } else if(post.post_thumbnail) {\n+        cell = self.thumbCellForLayout;\n+    } else {\n+        cell = self.imageCellForLayout;\n+    }\n+    [self configureCell:cell atIndexPath:indexPath];\n+    CGSize size = [cell sizeThatFits:CGSizeMake(width, CGFLOAT_MAX)];\n+    CGFloat height = ceil(size.height);\n+    return height;\n+}\n+\n+- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath\n+{\n+    // Are we approaching the end of the table?\n+    if ((indexPath.section + 1 == self.tableView.numberOfSections) &&\n+        (indexPath.row + PostsLoadMoreThreshold >= [self.tableView numberOfRowsInSection:indexPath.section])) {\n+\n+        // Only 3 rows till the end of table\n+        if ([self currentPostListFilter].hasMore) {\n+            [self.syncHelper syncMoreContent];\n+        }\n+    }\n+}\n+\n+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath\n+{\n+    [tableView deselectRowAtIndexPath:indexPath animated:YES];\n+    AbstractPost *post = [self.tableViewHandler.resultsController objectAtIndexPath:indexPath];\n+    if (post.remoteStatus == AbstractPostRemoteStatusPushing) {\n+        // Don't allow editing while pushing changes\n+        return;\n+    }\n+\n+    if ([post.status isEqualToString:PostStatusTrash]) {\n+        // No editing posts that are trashed.\n+        return;\n+    }\n+\n+    [self editPost:post];\n+}\n+\n+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath\n+{\n+    Post *post = (Post *)[self.tableViewHandler.resultsController objectAtIndexPath:indexPath];\n+\n+    NSString *identifier = [self cellIdentifierForPost:post];\n+    PostCardTableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:identifier];\n+    [self configureCell:cell atIndexPath:indexPath];\n+\n+    return cell;\n+}\n+\n+- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath\n+{\n+    cell.accessoryType = UITableViewCellAccessoryNone;\n+    cell.selectionStyle = UITableViewCellSelectionStyleNone;\n+\n+    id<PostCardCell>postCell = (id<PostCardCell>)cell;\n+    postCell.delegate = self;\n+    Post *post = (Post *)[self.tableViewHandler.resultsController objectAtIndexPath:indexPath];\n+\n+    [postCell configureCell:post];\n+}\n+\n+- (NSString *)cellIdentifierForPost:(Post *)post\n+{\n+    NSString *identifier;\n+    if ([self.recentlyTrashedPostIDs containsObject:post.postID] && [self currentPostListFilter].filterType != PostListStatusFilterTrashed) {\n+        identifier = PostCardRestoreCellIdentifier;\n+    } else if (![post.pathForDisplayImage length]) {\n+        identifier = PostCardTextCellIdentifier;\n+    } else if (post.post_thumbnail) {\n+        identifier = PostCardThumbCellIdentifier;\n+    } else {\n+        identifier = PostCardImageCellIdentifier;\n+    }\n+    return identifier;\n+}\n+\n+\n+#pragma mark - Instance Methods\n+\n+#pragma mark - Post Actions\n+\n+- (void)createPost\n+{\n+    UINavigationController *navController;\n+\n+    if ([WPPostViewController isNewEditorEnabled]) {\n+        WPPostViewController *postViewController = [[WPPostViewController alloc] initWithDraftForBlog:self.blog];\n+        navController = [[UINavigationController alloc] initWithRootViewController:postViewController];\n+        navController.restorationIdentifier = WPEditorNavigationRestorationID;\n+        navController.restorationClass = [WPPostViewController class];\n+    } else {\n+        WPLegacyEditPostViewController *editPostViewController = [[WPLegacyEditPostViewController alloc] initWithDraftForLastUsedBlog];\n+        navController = [[UINavigationController alloc] initWithRootViewController:editPostViewController];\n+        navController.restorationIdentifier = WPLegacyEditorNavigationRestorationID;\n+        navController.restorationClass = [WPLegacyEditPostViewController class];\n+    }\n+\n+    [navController setToolbarHidden:NO]; // Fixes incorrect toolbar animation.\n+    navController.modalPresentationStyle = UIModalPresentationFullScreen;\n+\n+    [self presentViewController:navController animated:YES completion:nil];\n+\n+    [WPAnalytics track:WPAnalyticsStatEditorCreatedPost withProperties:@{ @\"tap_source\": @\"posts_view\" }];\n+}\n+\n+- (void)publishPost:(AbstractPost *)apost\n+{\n+    apost.status = PostStatusPublish;\n+    apost.dateCreated = [NSDate date];\n+    PostService *postService = [[PostService alloc] initWithManagedObjectContext:[[ContextManager sharedInstance] mainContext]];\n+    [postService uploadPost:apost\n+                    success:nil\n+                    failure:^(NSError *error) {\n+                        if([error code] == 403) {\n+                            [self promptForPasswordWithMessage:nil];\n+                        } else {\n+                            [WPError showXMLRPCErrorAlert:error];\n+                        }\n+                        [self syncItemsWithUserInteraction:NO];\n+                    }];\n+}\n+\n+- (void)editPost:(AbstractPost *)apost\n+{\n+    if ([WPPostViewController isNewEditorEnabled]) {\n+        WPPostViewController *postViewController = [[WPPostViewController alloc] initWithPost:apost\n+                                                                                         mode:kWPPostViewControllerModePreview];\n+        postViewController.hidesBottomBarWhenPushed = YES;\n+        [self.navigationController pushViewController:postViewController animated:YES];\n+    } else {\n+        // In legacy mode, view means edit\n+        WPLegacyEditPostViewController *editPostViewController = [[WPLegacyEditPostViewController alloc] initWithPost:apost];\n+        UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:editPostViewController];\n+        [navController setToolbarHidden:NO]; // Fixes incorrect toolbar animation.\n+        navController.modalPresentationStyle = UIModalPresentationFullScreen;\n+        navController.restorationIdentifier = WPLegacyEditorNavigationRestorationID;\n+        navController.restorationClass = [WPLegacyEditPostViewController class];\n+\n+        [self presentViewController:navController animated:YES completion:nil];\n+    }\n+}\n+\n+- (void)viewPost:(AbstractPost *)apost\n+{\n+    PostPreviewViewController *controller = [[PostPreviewViewController alloc] initWithPost:apost shouldHideStatusBar:NO];\n+    controller.hidesBottomBarWhenPushed = YES;\n+    [self.navigationController pushViewController:controller animated:YES];\n+}\n+\n+- (void)deletePost:(AbstractPost *)apost\n+{\n+    NSNumber *postID = apost.postID;\n+    [self.recentlyTrashedPostIDs addObject:postID];\n+    NSIndexPath *indexPath = [self.tableViewHandler.resultsController indexPathForObject:apost];\n+    [self.tableViewHandler invalidateCachedRowHeightAtIndexPath:indexPath];\n+    [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];\n+\n+    // Update the fetch request *before* making the service call.\n+    [self updateAndPerformFetchRequestRefreshingCachedRowHeights];\n+\n+    PostService *postService = [[PostService alloc] initWithManagedObjectContext:[[ContextManager sharedInstance] mainContext]];\n+    [postService trashPost:apost\n+                   success:nil\n+                    failure:^(NSError *error) {\n+                        if([error code] == 403) {","path":"WordPress/Classes/ViewRelated/Post/PostListViewController.m","position":1015,"original_position":1015,"commit_id":"1225b6c20f794a998dd79ee6ffc6169968d9713e","original_commit_id":"8ffcee320c5efebd18879a74744ea3b1fa24ee89","user":{"login":"jleandroperez","id":1195260,"avatar_url":"https://avatars.githubusercontent.com/u/1195260?v=3","gravatar_id":"","url":"https://api.github.com/users/jleandroperez","html_url":"https://github.com/jleandroperez","followers_url":"https://api.github.com/users/jleandroperez/followers","following_url":"https://api.github.com/users/jleandroperez/following{/other_user}","gists_url":"https://api.github.com/users/jleandroperez/gists{/gist_id}","starred_url":"https://api.github.com/users/jleandroperez/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jleandroperez/subscriptions","organizations_url":"https://api.github.com/users/jleandroperez/orgs","repos_url":"https://api.github.com/users/jleandroperez/repos","events_url":"https://api.github.com/users/jleandroperez/events{/privacy}","received_events_url":"https://api.github.com/users/jleandroperez/received_events","type":"User","site_admin":false},"body":"Maybe a constant here?","created_at":"2015-05-12T16:35:29Z","updated_at":"2015-05-12T16:35:29Z","html_url":"https://github.com/wordpress-mobile/WordPress-iOS/pull/3609#discussion_r30153209","pull_request_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/pulls/3609","_links":{"self":{"href":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/pulls/comments/30153209"},"html":{"href":"https://github.com/wordpress-mobile/WordPress-iOS/pull/3609#discussion_r30153209"},"pull_request":{"href":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/pulls/3609"}}},"pull_request":{"url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/pulls/3609","id":34564407,"html_url":"https://github.com/wordpress-mobile/WordPress-iOS/pull/3609","diff_url":"https://github.com/wordpress-mobile/WordPress-iOS/pull/3609.diff","patch_url":"https://github.com/wordpress-mobile/WordPress-iOS/pull/3609.patch","issue_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/issues/3609","number":3609,"state":"open","locked":false,"title":"Issue/3506 post list part 4","user":{"login":"aerych","id":1435271,"avatar_url":"https://avatars.githubusercontent.com/u/1435271?v=3","gravatar_id":"","url":"https://api.github.com/users/aerych","html_url":"https://github.com/aerych","followers_url":"https://api.github.com/users/aerych/followers","following_url":"https://api.github.com/users/aerych/following{/other_user}","gists_url":"https://api.github.com/users/aerych/gists{/gist_id}","starred_url":"https://api.github.com/users/aerych/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aerych/subscriptions","organizations_url":"https://api.github.com/users/aerych/orgs","repos_url":"https://api.github.com/users/aerych/repos","events_url":"https://api.github.com/users/aerych/events{/privacy}","received_events_url":"https://api.github.com/users/aerych/received_events","type":"User","site_admin":false},"body":"Part four of a sectioned PR for the new post list feature.\r\n\r\nThis PR includes changes UI, and corrects a couple of over sights in the previous PRs.\r\n\r\nPlease merge after #3608 \r\n\r\nSee #3577 for previous discussion.\r\n\r\ncc @sendhil @diegoreymendez\r\n","created_at":"2015-05-01T20:22:42Z","updated_at":"2015-05-12T16:35:29Z","closed_at":null,"merged_at":null,"merge_commit_sha":"e62f1f9241641feea199b275493593f7fe0bf6db","assignee":null,"milestone":{"url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/milestones/39","html_url":"https://github.com/wordpress-mobile/WordPress-iOS/milestones/5.2","labels_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/milestones/39/labels","id":1065334,"number":39,"title":"5.2","description":"","creator":{"login":"aerych","id":1435271,"avatar_url":"https://avatars.githubusercontent.com/u/1435271?v=3","gravatar_id":"","url":"https://api.github.com/users/aerych","html_url":"https://github.com/aerych","followers_url":"https://api.github.com/users/aerych/followers","following_url":"https://api.github.com/users/aerych/following{/other_user}","gists_url":"https://api.github.com/users/aerych/gists{/gist_id}","starred_url":"https://api.github.com/users/aerych/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aerych/subscriptions","organizations_url":"https://api.github.com/users/aerych/orgs","repos_url":"https://api.github.com/users/aerych/repos","events_url":"https://api.github.com/users/aerych/events{/privacy}","received_events_url":"https://api.github.com/users/aerych/received_events","type":"User","site_admin":false},"open_issues":16,"closed_issues":45,"state":"open","created_at":"2015-04-13T15:51:41Z","updated_at":"2015-05-12T16:33:07Z","due_on":"2015-05-11T05:00:00Z","closed_at":null},"commits_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/pulls/3609/commits","review_comments_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/pulls/3609/comments","review_comment_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/pulls/comments{/number}","comments_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/issues/3609/comments","statuses_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/statuses/1225b6c20f794a998dd79ee6ffc6169968d9713e","head":{"label":"wordpress-mobile:issue/3506-post-list-part-4","ref":"issue/3506-post-list-part-4","sha":"1225b6c20f794a998dd79ee6ffc6169968d9713e","user":{"login":"wordpress-mobile","id":1306301,"avatar_url":"https://avatars.githubusercontent.com/u/1306301?v=3","gravatar_id":"","url":"https://api.github.com/users/wordpress-mobile","html_url":"https://github.com/wordpress-mobile","followers_url":"https://api.github.com/users/wordpress-mobile/followers","following_url":"https://api.github.com/users/wordpress-mobile/following{/other_user}","gists_url":"https://api.github.com/users/wordpress-mobile/gists{/gist_id}","starred_url":"https://api.github.com/users/wordpress-mobile/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wordpress-mobile/subscriptions","organizations_url":"https://api.github.com/users/wordpress-mobile/orgs","repos_url":"https://api.github.com/users/wordpress-mobile/repos","events_url":"https://api.github.com/users/wordpress-mobile/events{/privacy}","received_events_url":"https://api.github.com/users/wordpress-mobile/received_events","type":"Organization","site_admin":false},"repo":{"id":8859285,"name":"WordPress-iOS","full_name":"wordpress-mobile/WordPress-iOS","owner":{"login":"wordpress-mobile","id":1306301,"avatar_url":"https://avatars.githubusercontent.com/u/1306301?v=3","gravatar_id":"","url":"https://api.github.com/users/wordpress-mobile","html_url":"https://github.com/wordpress-mobile","followers_url":"https://api.github.com/users/wordpress-mobile/followers","following_url":"https://api.github.com/users/wordpress-mobile/following{/other_user}","gists_url":"https://api.github.com/users/wordpress-mobile/gists{/gist_id}","starred_url":"https://api.github.com/users/wordpress-mobile/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wordpress-mobile/subscriptions","organizations_url":"https://api.github.com/users/wordpress-mobile/orgs","repos_url":"https://api.github.com/users/wordpress-mobile/repos","events_url":"https://api.github.com/users/wordpress-mobile/events{/privacy}","received_events_url":"https://api.github.com/users/wordpress-mobile/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/wordpress-mobile/WordPress-iOS","description":"WordPress for iOS - Official repository","fork":false,"url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS","forks_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/forks","keys_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/keys{/key_id}","collaborators_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/teams","hooks_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/hooks","issue_events_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/issues/events{/number}","events_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/events","assignees_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/assignees{/user}","branches_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/branches{/branch}","tags_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/tags","blobs_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/git/refs{/sha}","trees_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/git/trees{/sha}","statuses_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/statuses/{sha}","languages_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/languages","stargazers_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/stargazers","contributors_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/contributors","subscribers_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/subscribers","subscription_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/subscription","commits_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/commits{/sha}","git_commits_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/git/commits{/sha}","comments_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/comments{/number}","issue_comment_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/issues/comments{/number}","contents_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/contents/{+path}","compare_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/compare/{base}...{head}","merges_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/merges","archive_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/downloads","issues_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/issues{/number}","pulls_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/pulls{/number}","milestones_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/milestones{/number}","notifications_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/labels{/name}","releases_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/releases{/id}","created_at":"2013-03-18T16:59:33Z","updated_at":"2015-05-11T09:14:21Z","pushed_at":"2015-05-12T15:50:42Z","git_url":"git://github.com/wordpress-mobile/WordPress-iOS.git","ssh_url":"git@github.com:wordpress-mobile/WordPress-iOS.git","clone_url":"https://github.com/wordpress-mobile/WordPress-iOS.git","svn_url":"https://github.com/wordpress-mobile/WordPress-iOS","homepage":"http://ios.wordpress.org/","size":387631,"stargazers_count":605,"watchers_count":605,"language":"Objective-C","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":301,"mirror_url":null,"open_issues_count":345,"forks":301,"open_issues":345,"watchers":605,"default_branch":"develop"}},"base":{"label":"wordpress-mobile:issue/3506-post-list-reviewed","ref":"issue/3506-post-list-reviewed","sha":"fb02249367c339936be0e9f48f459380ab5bdb14","user":{"login":"wordpress-mobile","id":1306301,"avatar_url":"https://avatars.githubusercontent.com/u/1306301?v=3","gravatar_id":"","url":"https://api.github.com/users/wordpress-mobile","html_url":"https://github.com/wordpress-mobile","followers_url":"https://api.github.com/users/wordpress-mobile/followers","following_url":"https://api.github.com/users/wordpress-mobile/following{/other_user}","gists_url":"https://api.github.com/users/wordpress-mobile/gists{/gist_id}","starred_url":"https://api.github.com/users/wordpress-mobile/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wordpress-mobile/subscriptions","organizations_url":"https://api.github.com/users/wordpress-mobile/orgs","repos_url":"https://api.github.com/users/wordpress-mobile/repos","events_url":"https://api.github.com/users/wordpress-mobile/events{/privacy}","received_events_url":"https://api.github.com/users/wordpress-mobile/received_events","type":"Organization","site_admin":false},"repo":{"id":8859285,"name":"WordPress-iOS","full_name":"wordpress-mobile/WordPress-iOS","owner":{"login":"wordpress-mobile","id":1306301,"avatar_url":"https://avatars.githubusercontent.com/u/1306301?v=3","gravatar_id":"","url":"https://api.github.com/users/wordpress-mobile","html_url":"https://github.com/wordpress-mobile","followers_url":"https://api.github.com/users/wordpress-mobile/followers","following_url":"https://api.github.com/users/wordpress-mobile/following{/other_user}","gists_url":"https://api.github.com/users/wordpress-mobile/gists{/gist_id}","starred_url":"https://api.github.com/users/wordpress-mobile/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wordpress-mobile/subscriptions","organizations_url":"https://api.github.com/users/wordpress-mobile/orgs","repos_url":"https://api.github.com/users/wordpress-mobile/repos","events_url":"https://api.github.com/users/wordpress-mobile/events{/privacy}","received_events_url":"https://api.github.com/users/wordpress-mobile/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/wordpress-mobile/WordPress-iOS","description":"WordPress for iOS - Official repository","fork":false,"url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS","forks_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/forks","keys_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/keys{/key_id}","collaborators_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/teams","hooks_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/hooks","issue_events_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/issues/events{/number}","events_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/events","assignees_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/assignees{/user}","branches_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/branches{/branch}","tags_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/tags","blobs_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/git/refs{/sha}","trees_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/git/trees{/sha}","statuses_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/statuses/{sha}","languages_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/languages","stargazers_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/stargazers","contributors_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/contributors","subscribers_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/subscribers","subscription_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/subscription","commits_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/commits{/sha}","git_commits_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/git/commits{/sha}","comments_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/comments{/number}","issue_comment_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/issues/comments{/number}","contents_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/contents/{+path}","compare_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/compare/{base}...{head}","merges_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/merges","archive_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/downloads","issues_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/issues{/number}","pulls_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/pulls{/number}","milestones_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/milestones{/number}","notifications_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/labels{/name}","releases_url":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/releases{/id}","created_at":"2013-03-18T16:59:33Z","updated_at":"2015-05-11T09:14:21Z","pushed_at":"2015-05-12T15:50:42Z","git_url":"git://github.com/wordpress-mobile/WordPress-iOS.git","ssh_url":"git@github.com:wordpress-mobile/WordPress-iOS.git","clone_url":"https://github.com/wordpress-mobile/WordPress-iOS.git","svn_url":"https://github.com/wordpress-mobile/WordPress-iOS","homepage":"http://ios.wordpress.org/","size":387631,"stargazers_count":605,"watchers_count":605,"language":"Objective-C","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":301,"mirror_url":null,"open_issues_count":345,"forks":301,"open_issues":345,"watchers":605,"default_branch":"develop"}},"_links":{"self":{"href":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/pulls/3609"},"html":{"href":"https://github.com/wordpress-mobile/WordPress-iOS/pull/3609"},"issue":{"href":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/issues/3609"},"comments":{"href":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/issues/3609/comments"},"review_comments":{"href":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/pulls/3609/comments"},"review_comment":{"href":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/pulls/3609/commits"},"statuses":{"href":"https://api.github.com/repos/wordpress-mobile/WordPress-iOS/statuses/1225b6c20f794a998dd79ee6ffc6169968d9713e"}}}}