diff --git a/WordPress/Classes/NSDate+StringFormatting.h b/WordPress/Classes/NSDate+StringFormatting.h new file mode 100644 index 000000000000..272d4fd205af --- /dev/null +++ b/WordPress/Classes/NSDate+StringFormatting.h @@ -0,0 +1,15 @@ +// +// NSDate+StringFormatting.h +// WordPress +// +// Created by Michael Johnston on 11/17/13. +// Copyright (c) 2013 WordPress. All rights reserved. +// + +#import + +@interface NSDate (StringFormatting) + +- (NSString *)shortString; + +@end diff --git a/WordPress/Classes/NSDate+StringFormatting.m b/WordPress/Classes/NSDate+StringFormatting.m new file mode 100644 index 000000000000..f5709da3eebe --- /dev/null +++ b/WordPress/Classes/NSDate+StringFormatting.m @@ -0,0 +1,30 @@ +// +// NSDate+StringFormatting.m +// WordPress +// +// Created by Michael Johnston on 11/17/13. +// Copyright (c) 2013 WordPress. All rights reserved. +// + +#import "NSDate+StringFormatting.h" + +@implementation NSDate (StringFormatting) + +- (NSString *)shortString { + NSString *shortString; + NSTimeInterval diff = [[NSDate date] timeIntervalSince1970] - [self timeIntervalSince1970]; + + if(diff < 60) { + shortString = [NSString stringWithFormat:@"%is", (int)diff]; + } else if(diff < 3600) { + shortString = [NSString stringWithFormat:@"%im", (int)floor(diff / 60)]; + } else if (diff < 86400) { + shortString = [NSString stringWithFormat:@"%ih", (int)floor(diff / 3600)]; + } else { + shortString = [NSString stringWithFormat:@"%id", (int)floor(diff / 86400)]; + } + + return shortString; +} + +@end diff --git a/WordPress/Classes/ReaderComment.h b/WordPress/Classes/ReaderComment.h index ffc0b13c72a2..6a3d1ea792a7 100644 --- a/WordPress/Classes/ReaderComment.h +++ b/WordPress/Classes/ReaderComment.h @@ -62,6 +62,4 @@ + (void)createOrUpdateWithDictionary:(NSDictionary *)dict forPost:(ReaderPost *)post withContext:(NSManagedObjectContext *)context; -- (NSString *)shortDate; - @end diff --git a/WordPress/Classes/ReaderComment.m b/WordPress/Classes/ReaderComment.m index 2103d5a09857..85de8aa5487c 100644 --- a/WordPress/Classes/ReaderComment.m +++ b/WordPress/Classes/ReaderComment.m @@ -185,24 +185,4 @@ - (void)updateFromDictionary:(NSDictionary *)dict { } - -- (NSString *)shortDate { - - NSString *str; - NSTimeInterval diff = [[NSDate date] timeIntervalSince1970] - [self.dateCreated timeIntervalSince1970]; - - if(diff < 60) { - str = [NSString stringWithFormat:@"%is", (int)diff]; - } else if(diff < 3600) { - str = [NSString stringWithFormat:@"%im", (int)floor(diff / 60)]; - } else if (diff < 86400) { - str = [NSString stringWithFormat:@"%ih", (int)floor(diff / 3600)]; - } else { - str = [NSString stringWithFormat:@"%id", (int)floor(diff / 86400)]; - } - - return str; - -} - @end diff --git a/WordPress/Classes/ReaderCommentTableViewCell.m b/WordPress/Classes/ReaderCommentTableViewCell.m index 47ec110a93b2..e993c92b4515 100644 --- a/WordPress/Classes/ReaderCommentTableViewCell.m +++ b/WordPress/Classes/ReaderCommentTableViewCell.m @@ -11,6 +11,7 @@ #import "UIImageView+Gravatar.h" #import "WordPressAppDelegate.h" #import "WPWebViewController.h" +#import "NSDate+StringFormatting.h" #define RCTVCVerticalPadding 5.0f #define RCTVCIndentationWidth 10.0f @@ -197,7 +198,7 @@ - (void)configureCell:(ReaderComment *)comment { [self.contentView addSubview:self.cellImageView]; - _dateLabel.text = [comment shortDate]; + _dateLabel.text = [comment.dateCreated shortString]; _authorLabel.text = comment.author; [self.cellImageView setImageWithURL:[NSURL URLWithString:comment.authorAvatarURL] placeholderImage:[UIImage imageNamed:@"blavatar-wpcom.png"]]; diff --git a/WordPress/Classes/ReaderPost.h b/WordPress/Classes/ReaderPost.h index 16a24b28fd68..9153c9c23880 100644 --- a/WordPress/Classes/ReaderPost.h +++ b/WordPress/Classes/ReaderPost.h @@ -45,6 +45,10 @@ extern NSString *const ReaderExtrasArrayKey; @property (nonatomic, strong) NSString *summary; @property (nonatomic, strong) NSMutableSet *comments; @property (nonatomic, readonly, strong) NSURL *featuredImageURL; +@property (nonatomic, strong) NSString *primaryTagName; +@property (nonatomic, strong) NSString *primaryTagSlug; +@property (nonatomic, strong) NSString *tags; + /** An array of dictionaries representing available REST API endpoints to retrieve posts for the Reader. @@ -111,6 +115,7 @@ extern NSString *const ReaderExtrasArrayKey; - (NSString *)prettyDateString; +- (BOOL)isFollowable; - (BOOL)isFreshlyPressed; @@ -129,6 +134,7 @@ extern NSString *const ReaderExtrasArrayKey; - (NSDictionary *)getStoredComment; +- (NSString *)authorString; - (NSString *)avatar; diff --git a/WordPress/Classes/ReaderPost.m b/WordPress/Classes/ReaderPost.m index 05490e50343f..72f23f5e5e45 100644 --- a/WordPress/Classes/ReaderPost.m +++ b/WordPress/Classes/ReaderPost.m @@ -62,6 +62,9 @@ @implementation ReaderPost @dynamic storedComment; @dynamic summary; @dynamic comments; +@dynamic primaryTagName; +@dynamic primaryTagSlug; +@dynamic tags; + (void)load { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleLogoutNotification:) name:WordPressComApiDidLogoutNotification object:nil]; @@ -209,6 +212,12 @@ + (void)createOrUpdateWithDictionary:(NSDictionary *)dict forEndpoint:(NSString NSNumber *blogSiteID = [dict numberForKey:@"site_id"]; NSNumber *siteID = [dict numberForKey:@"blog_id"]; NSNumber *postID = [dict numberForKey:@"ID"]; + + // Some endpoints (e.g. tags) use different case + if (siteID == nil) { + siteID = [dict numberForKey:@"site_ID"]; + blogSiteID = [dict numberForKey:@"site_ID"]; + } // following, likes and topics endpoints if ([dict valueForKey:@"blog_site_id"] != nil) { @@ -282,7 +291,6 @@ - (void)updateFromDictionary:(NSDictionary *)dict { self.dateSynced = [NSDate date]; } - - (void)updateFromRESTDictionary:(NSDictionary *)dict { // REST api. Freshly Pressed, sites/site/posts @@ -351,6 +359,16 @@ - (void)updateFromRESTDictionary:(NSDictionary *)dict { self.blogURL = [NSString stringWithFormat:@"%@://%@/", url.scheme, url.host]; self.summary = [self createSummary:self.content makePlainText:YES]; + + NSDictionary *tagsDict = [dict objectForKey:@"tags"]; + NSArray *tagsList = [NSArray arrayWithArray:[tagsDict allKeys]]; + self.tags = [tagsList componentsJoinedByString:@", "]; + + if ([tagsDict count] > 0) { + NSDictionary *tagDict = [[tagsDict allValues] objectAtIndex:0]; + self.primaryTagSlug = tagDict[@"slug"]; + self.primaryTagName = tagDict[@"name"]; + } } @@ -423,6 +441,22 @@ - (void)updateFromReaderDictionary:(NSDictionary *)dict { img = [img stringByDecodingXMLCharacters]; self.postAvatar = [self parseImageSrcFromHTML:img]; } + + NSDictionary *tagsDict = [dict objectForKey:@"topics"]; + + if ([tagsDict count] > 0) { + NSArray *tagsList = [NSArray arrayWithArray:[tagsDict allValues]]; + self.tags = [tagsList componentsJoinedByString:@", "]; + } + + NSDictionary *primaryTagDict = [dict objectForKey:@"primary_tag"]; + if ([primaryTagDict isKindOfClass:[NSDictionary class]]) { + self.primaryTagName = primaryTagDict[@"name"]; + self.primaryTagSlug = primaryTagDict[@"slug"]; + } else if ([tagsDict count] > 0) { + self.primaryTagSlug = [[tagsDict allKeys] objectAtIndex:0]; + self.primaryTagName = [tagsDict objectForKey:self.primaryTagSlug]; + } } @@ -606,6 +640,9 @@ - (NSString *)prettyDateString { return [formatter stringFromDate:date]; } +- (BOOL)isFollowable { + return self.siteID != nil; +} - (BOOL)isFreshlyPressed { return ([self.endpoint rangeOfString:@"freshly-pressed"].location != NSNotFound)? YES : NO; @@ -643,6 +680,15 @@ - (NSDictionary *)getStoredComment { return @{@"commentID":commentID, @"comment":commentText}; } +- (NSString *)authorString { + if ([self.blogName length] > 0) { + return self.blogName; + } else if ([self.authorDisplayName length] > 0) { + return self.authorDisplayName; + } else { + return self.author; + } +} - (NSString *)avatar { return (self.postAvatar == nil) ? self.authorAvatarURL : self.postAvatar; diff --git a/WordPress/Classes/ReaderPostTableViewCell.h b/WordPress/Classes/ReaderPostTableViewCell.h index 7ff914e30ac4..cb8a14a9de9c 100644 --- a/WordPress/Classes/ReaderPostTableViewCell.h +++ b/WordPress/Classes/ReaderPostTableViewCell.h @@ -14,10 +14,22 @@ @property (nonatomic, strong) UIImageView *avatarImageView; + (CGFloat)cellHeightForPost:(ReaderPost *)post withWidth:(CGFloat)width; ++ (ReaderPostTableViewCell *)cellForSubview:(UIView *)subview; - (void)configureCell:(ReaderPost *)post; -- (void)setReblogTarget:(id)target action:(SEL)selector; - (void)setFeaturedImage:(UIImage *)image; - (void)setAvatar:(UIImage *)avatar; +@property (nonatomic, strong) ReaderPost *post; +@property (nonatomic, strong) UIButton *followButton; +@property (nonatomic, strong) UIButton *tagButton; +@property (nonatomic, strong) UIButton *likeButton; +@property (nonatomic, strong) UIButton *reblogButton; +@property (nonatomic, strong) UIButton *commentButton; +@property (nonatomic, strong) UIButton *timeButton; + +extern CGFloat const RPTVCMaxImageHeightPercentage; + +- (void)updateControlBar; + @end diff --git a/WordPress/Classes/ReaderPostTableViewCell.m b/WordPress/Classes/ReaderPostTableViewCell.m index a95812f6d1a4..fb0d21c28c73 100644 --- a/WordPress/Classes/ReaderPostTableViewCell.m +++ b/WordPress/Classes/ReaderPostTableViewCell.m @@ -16,34 +16,43 @@ #import "UILabel+SuggestSize.h" #import "WPAvatarSource.h" #import "ReaderButton.h" - -const CGFloat RPTVCVerticalPadding = 10.0f; -const CGFloat RPTVCHorizontalPadding = 10.0f; -const CGFloat RPTVCMetaViewHeightWithButtons = 101.0f; -const CGFloat RPTVCMetaViewHeightSansButtons = 52.0f; +#import "NSDate+StringFormatting.h" +#import "UIColor+Helpers.h" + +const CGFloat RPTVCAuthorPadding = 8.0f; +const CGFloat RPTVCHorizontalInnerPadding = 12.0f; +const CGFloat RPTVCHorizontalOuterPadding = 8.0f; +const CGFloat RPTVCMetaViewHeight = 48.0f; +const CGFloat RPTVCAuthorViewHeight = 32.0f; +const CGFloat RPTVCVerticalPadding = 16.0f; +const CGFloat RPTVCAvatarSize = 32.0f; +const CGFloat RPTVCBorderHeight = 1.0f; +const CGFloat RPTVCSmallButtonLeftPadding = 2; // Follow, tag +const CGFloat RPTVCMaxImageHeightPercentage = 0.59f; +const CGFloat RPTVCMaxSummaryHeight = 88.0f; +const CGFloat RPTVCLineHeightMultiple = 1.15f; + +// Control buttons (Like, Reblog, ...) +const CGFloat RPTVCControlButtonHeight = 48.0f; +const CGFloat RPTVCControlButtonWidth = 48.0f; +const CGFloat RPTVCControlButtonSpacing = 12.0f; +const CGFloat RPTVCControlButtonBorderSize = 0.0f; @interface ReaderPostTableViewCell() -@property (nonatomic, strong) ReaderPost *post; @property (nonatomic, strong) UIView *containerView; @property (nonatomic, strong) UILabel *titleLabel; +@property (nonatomic, strong) CALayer *titleBorder; @property (nonatomic, strong) UILabel *snippetLabel; @property (nonatomic, strong) UIView *metaView; - +@property (nonatomic, strong) CALayer *metaBorder; @property (nonatomic, strong) UIView *byView; @property (nonatomic, strong) UILabel *bylineLabel; - @property (nonatomic, strong) UIView *controlView; -@property (nonatomic, strong) UIButton *likeButton; -@property (nonatomic, strong) UIButton *reblogButton; @property (nonatomic, assign) BOOL showImage; -- (void)buildPostContent; -- (void)buildMetaContent; -- (void)handleLikeButtonTapped:(id)sender; - @end @implementation ReaderPostTableViewCell { @@ -53,7 +62,6 @@ @implementation ReaderPostTableViewCell { + (CGFloat)cellHeightForPost:(ReaderPost *)post withWidth:(CGFloat)width { CGFloat desiredHeight = 0.0f; - CGFloat vpadding = RPTVCVerticalPadding; // Margins CGFloat contentWidth = width; @@ -63,36 +71,98 @@ + (CGFloat)cellHeightForPost:(ReaderPost *)post withWidth:(CGFloat)width { // iPhone has extra padding around each cell if (IS_IPHONE) { - contentWidth -= RPTVCHorizontalPadding * 2; + contentWidth -= RPTVCHorizontalOuterPadding * 2; } + desiredHeight += RPTVCAuthorPadding; + desiredHeight += RPTVCAuthorViewHeight; + desiredHeight += RPTVCAuthorPadding; + // Are we showing an image? What size should it be? - if(post.featuredImageURL) { - CGFloat height = ceilf((contentWidth * 0.66f)); + if (post.featuredImageURL) { + CGFloat height = ceilf((contentWidth * RPTVCMaxImageHeightPercentage)); desiredHeight += height; } + + // Everything but the image has inner padding + contentWidth -= RPTVCHorizontalInnerPadding * 2; + + // Title + desiredHeight += RPTVCVerticalPadding; + NSAttributedString *postTitle = [self titleAttributedStringForPost:post]; + desiredHeight += [postTitle boundingRectWithSize:CGSizeMake(contentWidth, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading context:nil].size.height; + desiredHeight += RPTVCVerticalPadding; + + // Post summary + if ([post.summary length] > 0) { + NSAttributedString *postSummary = [self summaryAttributedStringForPost:post]; + desiredHeight += [postSummary boundingRectWithSize:CGSizeMake(contentWidth, RPTVCMaxSummaryHeight) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading context:nil].size.height; + desiredHeight += RPTVCVerticalPadding; + } + + // Tag + NSString *tagName = post.primaryTagName; + if ([tagName length] > 0) { + desiredHeight += [tagName sizeWithFont:[self summaryFont] constrainedToSize:CGSizeMake(contentWidth, CGFLOAT_MAX) lineBreakMode:NSLineBreakByClipping].height; + } - desiredHeight += vpadding; - - desiredHeight += [post.postTitle sizeWithFont:[UIFont fontWithName:@"OpenSans-Light" size:20.0f] constrainedToSize:CGSizeMake(contentWidth, CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping].height; - desiredHeight += vpadding; - - desiredHeight += [post.summary sizeWithFont:[UIFont fontWithName:@"OpenSans" size:13.0f] constrainedToSize:CGSizeMake(contentWidth, CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping].height; - desiredHeight += vpadding; + // Padding above and below the line + desiredHeight += RPTVCVerticalPadding * 2; // Size of the meta view - if ([post isWPCom]) { - desiredHeight += RPTVCMetaViewHeightWithButtons; - } else { - desiredHeight += RPTVCMetaViewHeightSansButtons; - } - - // bottom padding - desiredHeight += vpadding; + desiredHeight += RPTVCMetaViewHeight; return ceil(desiredHeight); } ++ (NSAttributedString *)titleAttributedStringForPost:(ReaderPost *)post { + NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init]; + [style setLineHeightMultiple:RPTVCLineHeightMultiple]; + NSDictionary *attributes = @{NSParagraphStyleAttributeName : style, + NSFontAttributeName : [self titleFont]}; + NSMutableAttributedString *titleString = [[NSMutableAttributedString alloc] initWithString:[post.postTitle trim] + attributes:attributes]; + + return titleString; +} + ++ (NSAttributedString *)summaryAttributedStringForPost:(ReaderPost *)post { + NSString *summary = [post.summary trim]; + NSInteger newline = [post.summary rangeOfString:@"\n"].location; + + if (newline != NSNotFound) + summary = [post.summary substringToIndex:newline]; + + NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init]; + [style setLineHeightMultiple:RPTVCLineHeightMultiple]; + NSDictionary *attributes = @{NSParagraphStyleAttributeName : style, + NSFontAttributeName : [self summaryFont]}; + NSMutableAttributedString *attributedSummary = [[NSMutableAttributedString alloc] initWithString:summary + attributes:attributes]; + + return attributedSummary; +} + ++ (UIFont *)titleFont { + return [UIFont fontWithName:@"Merriweather-Bold" size:21.0f]; +} + ++ (UIFont *)summaryFont { + return [UIFont fontWithName:@"OpenSans" size:14.0f]; +} + ++ (ReaderPostTableViewCell *)cellForSubview:(UIView *)subview { + UIView *view = subview; + while (![view isKindOfClass:self]) { + view = (UIView *)view.superview; + } + + if (view == subview) + return nil; + + return (ReaderPostTableViewCell *)view; +} + #pragma mark - Lifecycle Methods @@ -147,11 +217,9 @@ - (void)setHighlightedEffect:(BOOL)highlighted animated:(BOOL)animated { } completion:nil]; } - - (void)setPost:(ReaderPost *)post { - if ([post isEqual:_post]) { + if ([post isEqual:_post]) return; - } if (_post) { [_post removeObserver:self forKeyPath:@"isReblogged" context:@"reblogging"]; @@ -161,14 +229,12 @@ - (void)setPost:(ReaderPost *)post { [_post addObserver:self forKeyPath:@"isReblogged" options:NSKeyValueObservingOptionNew context:@"reblogging"]; } - - (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated { BOOL previouslyHighlighted = self.highlighted; [super setHighlighted:highlighted animated:animated]; - if (previouslyHighlighted == highlighted) { + if (previouslyHighlighted == highlighted) return; - } if (highlighted) { [self setHighlightedEffect:highlighted animated:animated]; @@ -186,7 +252,6 @@ - (void)setSelected:(BOOL)selected animated:(BOOL)animated { [self setHighlightedEffect:selected animated:animated]; } - - (void)buildPostContent { self.cellImageView.contentMode = UIViewContentModeScaleAspectFill; [_containerView addSubview:self.cellImageView]; @@ -194,56 +259,91 @@ - (void)buildPostContent { self.titleLabel = [[UILabel alloc] init]; _titleLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth; _titleLabel.backgroundColor = [UIColor clearColor]; - _titleLabel.font = [UIFont fontWithName:@"OpenSans-Light" size:20.0f]; - _titleLabel.textColor = [UIColor colorWithRed:64.0f/255.0f green:64.0f/255.0f blue:64.0f/255.0f alpha:1.0]; + _titleLabel.textColor = [UIColor colorWithHexString:@"333"]; _titleLabel.lineBreakMode = NSLineBreakByWordWrapping; _titleLabel.numberOfLines = 0; [_containerView addSubview:_titleLabel]; + + self.titleBorder = [[CALayer alloc] init]; + _titleBorder.backgroundColor = [[UIColor colorWithHexString:@"f1f1f1"] CGColor]; + [_containerView.layer addSublayer:_titleBorder]; self.snippetLabel = [[UILabel alloc] init]; _snippetLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth; _snippetLabel.backgroundColor = [UIColor clearColor]; - _snippetLabel.font = [UIFont fontWithName:@"OpenSans" size:13.0f]; - _snippetLabel.textColor = [UIColor colorWithRed:64.0f/255.0f green:64.0f/255.0f blue:64.0f/255.0f alpha:1.0]; - _snippetLabel.lineBreakMode = NSLineBreakByWordWrapping; - _snippetLabel.numberOfLines = 0; + _snippetLabel.textColor = [UIColor colorWithHexString:@"333"]; + _snippetLabel.lineBreakMode = NSLineBreakByTruncatingTail; + _snippetLabel.numberOfLines = 4; [_containerView addSubview:_snippetLabel]; -} - - -- (void)buildMetaContent { - self.metaView = [[UIView alloc] init]; - _metaView.autoresizingMask = UIViewAutoresizingFlexibleWidth; - _metaView.backgroundColor = [UIColor colorWithWhite:0.95703125f alpha:1.f]; - [_containerView addSubview:_metaView]; - - self.byView = [[UIView alloc] init]; + + self.byView = [[UIView alloc] init]; _byView.autoresizingMask = UIViewAutoresizingFlexibleWidth; _byView.backgroundColor = [UIColor whiteColor]; - [_metaView addSubview:_byView]; + _byView.userInteractionEnabled = YES; + [_containerView addSubview:_byView]; - self.avatarImageView = [[UIImageView alloc] initWithFrame:CGRectMake(10.0f, 10.0f, 32.0f, 32.0f)]; + CGRect avatarFrame = CGRectMake(RPTVCHorizontalInnerPadding, RPTVCAuthorPadding, RPTVCAvatarSize, RPTVCAvatarSize); + self.avatarImageView = [[UIImageView alloc] initWithFrame:avatarFrame]; [_byView addSubview:_avatarImageView]; self.bylineLabel = [[UILabel alloc] init]; _bylineLabel.backgroundColor = [UIColor clearColor]; - _bylineLabel.numberOfLines = 2; + _bylineLabel.numberOfLines = 1; _bylineLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth; _bylineLabel.font = [UIFont fontWithName:@"OpenSans" size:12.0f]; _bylineLabel.adjustsFontSizeToFitWidth = NO; - _bylineLabel.textColor = DTColorCreateWithHexString(@"c0c0c0"); + _bylineLabel.textColor = [UIColor colorWithHexString:@"333"]; [_byView addSubview:_bylineLabel]; + + self.followButton = [ReaderButton buttonWithType:UIButtonTypeCustom]; + [_followButton setSelected:[self.post.isFollowing boolValue]]; + _followButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft; + _followButton.backgroundColor = [UIColor clearColor]; + _followButton.titleLabel.font = [UIFont fontWithName:@"OpenSans" size:12.0f]; + NSString *followString = NSLocalizedString(@"Follow", @"Prompt to follow a blog."); + NSString *followedString = NSLocalizedString(@"Following", @"User is following the blog."); + [_followButton setTitle:followString forState:UIControlStateNormal]; + [_followButton setTitle:followedString forState:UIControlStateSelected]; + [_followButton setTitleEdgeInsets: UIEdgeInsetsMake(0, RPTVCSmallButtonLeftPadding, 0, 0)]; + [_followButton setImage:[UIImage imageNamed:@"reader-postaction-follow"] forState:UIControlStateNormal]; + [_followButton setImage:[UIImage imageNamed:@"reader-postaction-following"] forState:UIControlStateSelected]; + [_followButton setTitleColor:[UIColor colorWithHexString:@"aaa"] forState:UIControlStateNormal]; + [_byView addSubview:_followButton]; + + self.tagButton = [ReaderButton buttonWithType:UIButtonTypeCustom]; + _tagButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft; + _tagButton.backgroundColor = [UIColor clearColor]; + _tagButton.titleLabel.font = [UIFont fontWithName:@"OpenSans" size:12.0f]; + [_tagButton setTitleEdgeInsets: UIEdgeInsetsMake(0, RPTVCSmallButtonLeftPadding, 0, 0)]; + [_tagButton setImage:[UIImage imageNamed:@"reader-postaction-tag"] forState:UIControlStateNormal]; + [_tagButton setTitleColor:[UIColor colorWithHexString:@"aaa"] forState:UIControlStateNormal]; + [_containerView addSubview:_tagButton]; +} + +- (void)buildMetaContent { + self.metaView = [[UIView alloc] init]; + _metaView.autoresizingMask = UIViewAutoresizingFlexibleWidth; + _metaView.backgroundColor = [UIColor clearColor]; + [_containerView addSubview:_metaView]; + + self.metaBorder = [[CALayer alloc] init]; + _metaBorder.backgroundColor = [[UIColor colorWithHexString:@"f1f1f1"] CGColor]; + [_metaView.layer addSublayer:_metaBorder]; + + self.timeButton = [UIButton buttonWithType:UIButtonTypeCustom]; + _timeButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft; + _timeButton.backgroundColor = [UIColor clearColor]; + _timeButton.titleLabel.font = [UIFont fontWithName:@"OpenSans" size:12.0f]; + [_timeButton setTitleEdgeInsets: UIEdgeInsetsMake(0, RPTVCSmallButtonLeftPadding, 0, 0)]; + [_timeButton setImage:[UIImage imageNamed:@"reader-postaction-time"] forState:UIControlStateNormal]; + [_timeButton setTitleColor:[UIColor colorWithHexString:@"aaa"] forState:UIControlStateNormal]; + [_metaView addSubview:_timeButton]; self.likeButton = [ReaderButton buttonWithType:UIButtonTypeCustom]; _likeButton.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin; _likeButton.backgroundColor = [UIColor whiteColor]; - [_likeButton setTitleEdgeInsets:UIEdgeInsetsMake(0.0f, -5.0f, 0.0f, 0.0f)]; - [_likeButton.titleLabel setFont:[UIFont fontWithName:@"OpenSans-Bold" size:10.0f]]; - [_likeButton setTitleColor:[UIColor colorWithRed:84.0f/255.0f green:173.0f/255.0f blue:211.0f/255.0f alpha:1.0f] forState:UIControlStateNormal]; - [_likeButton setTitleColor:[UIColor colorWithRed:221.0f/255.0f green:118.0f/255.0f blue:43.0f/255.0f alpha:1.0f] forState:UIControlStateSelected]; [_likeButton setImage:[UIImage imageNamed:@"reader-postaction-like-blue"] forState:UIControlStateNormal]; [_likeButton setImage:[UIImage imageNamed:@"reader-postaction-like-active"] forState:UIControlStateSelected]; - [_likeButton addTarget:self action:@selector(handleLikeButtonTapped:) forControlEvents:UIControlEventTouchUpInside]; [_metaView addSubview:_likeButton]; self.reblogButton = [ReaderButton buttonWithType:UIButtonTypeCustom]; @@ -252,53 +352,106 @@ - (void)buildMetaContent { [_reblogButton setImage:[UIImage imageNamed:@"reader-postaction-reblog-blue"] forState:UIControlStateNormal]; [_reblogButton setImage:[UIImage imageNamed:@"reader-postaction-reblog-done"] forState:UIControlStateSelected]; [_metaView addSubview:_reblogButton]; - + + self.commentButton = [ReaderButton buttonWithType:UIButtonTypeCustom]; + _commentButton.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin; + _commentButton.backgroundColor = [UIColor whiteColor]; + [_commentButton setImage:[UIImage imageNamed:@"reader-postaction-comment-blue"] forState:UIControlStateNormal]; + [_commentButton setImage:[UIImage imageNamed:@"reader-postaction-comment-active"] forState:UIControlStateSelected]; + [_metaView addSubview:_commentButton]; } - (void)layoutSubviews { [super layoutSubviews]; - CGFloat leftPadding = IS_IPHONE ? RPTVCHorizontalPadding : 0; + CGFloat leftPadding = IS_IPHONE ? RPTVCHorizontalOuterPadding : 0; CGFloat contentWidth = self.frame.size.width - leftPadding * 2; - CGFloat innerContentWidth = contentWidth - RPTVCHorizontalPadding * 2; - CGFloat vpadding = RPTVCVerticalPadding; - CGFloat nextY = vpadding; + CGFloat innerContentWidth = contentWidth - RPTVCHorizontalInnerPadding * 2; + CGFloat nextY = RPTVCAuthorPadding; CGFloat height = 0.0f; - CGRect frame = CGRectMake(leftPadding, 0.0f, contentWidth, self.frame.size.height - RPTVCVerticalPadding); + CGRect frame = CGRectMake(leftPadding, 0, contentWidth, self.frame.size.height - RPTVCVerticalPadding); _containerView.frame = frame; + + _byView.frame = CGRectMake(0, 0, contentWidth, RPTVCAuthorViewHeight + RPTVCAuthorPadding * 2); + CGFloat bylineX = RPTVCAvatarSize + RPTVCAuthorPadding + RPTVCHorizontalInnerPadding; + _bylineLabel.frame = CGRectMake(bylineX, RPTVCAuthorPadding - 2, contentWidth - bylineX, 18); + + if ([self.post isFollowable]) { + _followButton.hidden = NO; + CGFloat followX = bylineX - 4; // Fudge factor for image alignment + CGFloat followY = RPTVCAuthorPadding + _bylineLabel.frame.size.height - 2; + height = ceil([_followButton.titleLabel suggestedSizeForWidth:innerContentWidth].height); + _followButton.frame = CGRectMake(followX, followY, contentWidth - bylineX, height); + } else { + _followButton.hidden = YES; + } + + nextY += RPTVCAuthorViewHeight + RPTVCAuthorPadding; // Are we showing an image? What size should it be? - if(_showImage) { - height = ceilf(contentWidth * 0.66f); - self.cellImageView.frame = CGRectMake(RPTVCHorizontalPadding, nextY, innerContentWidth, height); + if (_showImage) { + _titleBorder.hidden = YES; + height = ceilf(contentWidth * RPTVCMaxImageHeightPercentage); + self.cellImageView.frame = CGRectMake(0, nextY, contentWidth, height); nextY += height; + } else { + _titleBorder.hidden = NO; + _titleBorder.frame = CGRectMake(RPTVCHorizontalInnerPadding, nextY, contentWidth - RPTVCHorizontalInnerPadding * 2, RPTVCBorderHeight); } // Position the title - height = ceil([_titleLabel suggestedSizeForWidth:contentWidth].height); - _titleLabel.frame = CGRectMake(RPTVCHorizontalPadding, nextY, innerContentWidth, height); - nextY += height + vpadding; + nextY += RPTVCVerticalPadding; + height = ceil([_titleLabel suggestedSizeForWidth:innerContentWidth].height); + _titleLabel.frame = CGRectMake(RPTVCHorizontalInnerPadding, nextY, innerContentWidth, height); + nextY += height + RPTVCVerticalPadding; // Position the snippet - height = ceil([_snippetLabel suggestedSizeForWidth:contentWidth].height); - _snippetLabel.frame = CGRectMake(RPTVCHorizontalPadding, nextY, innerContentWidth, height); - nextY += ceilf(height + vpadding); + if ([self.post.summary length] > 0) { + height = ceil([_snippetLabel suggestedSizeForWidth:innerContentWidth].height); + height = MIN(height, RPTVCMaxSummaryHeight); + _snippetLabel.frame = CGRectMake(RPTVCHorizontalInnerPadding, nextY, innerContentWidth, height); + nextY += ceilf(height + RPTVCVerticalPadding); + } + + // Tag + if ([self.post.primaryTagName length] > 0) { + height = ceil([_tagButton.titleLabel suggestedSizeForWidth:innerContentWidth].height); + _tagButton.frame = CGRectMake(RPTVCHorizontalInnerPadding, nextY, innerContentWidth, height); + nextY += height + RPTVCVerticalPadding; + self.tagButton.hidden = NO; + } else { + self.tagButton.hidden = YES; + } + + // Position the meta view and its subviews + _metaView.frame = CGRectMake(0, nextY, contentWidth, RPTVCMetaViewHeight); + _metaBorder.frame = CGRectMake(RPTVCHorizontalInnerPadding, 0, contentWidth - RPTVCHorizontalInnerPadding * 2, RPTVCBorderHeight); - // position the meta view and its subviews - _byView.frame = CGRectMake(0.0f, 0.0f, contentWidth, 52.0f); + BOOL commentsOpen = [[self.post commentsOpen] boolValue] && [self.post isWPCom]; + CGFloat buttonWidth = RPTVCControlButtonWidth; + CGFloat buttonX = _metaView.frame.size.width - RPTVCControlButtonWidth; + CGFloat buttonY = RPTVCBorderHeight; // Just below the line - height = [self.post isWPCom] ? RPTVCMetaViewHeightWithButtons : RPTVCMetaViewHeightSansButtons; - _metaView.frame = CGRectMake(0.0f, nextY, contentWidth, height); - - CGFloat w = ceilf(_metaView.frame.size.width / 2.0f); - _likeButton.frame = CGRectMake(0.0f, 53.0f, w, 48.0f); - _reblogButton.frame = CGRectMake(w + 1.0f, 53.0f, w - 1.f, 48.0f); - _bylineLabel.frame = CGRectMake(47.0f, 8.0f, contentWidth - 57.0f, 36.0f); + // Button order from right-to-left: Like, [Comment], Reblog, + _likeButton.frame = CGRectMake(buttonX, buttonY, buttonWidth, RPTVCControlButtonHeight); + buttonX -= buttonWidth + RPTVCControlButtonSpacing; - CGFloat sideBorderX = RPTVCHorizontalPadding - 1; // Just to the left of the container - CGFloat sideBorderHeight = self.frame.size.height - RPTVCVerticalPadding + 1.f; // Just below it - _sideBorderView.frame = CGRectMake(sideBorderX, 1.f, self.frame.size.width - sideBorderX*2, sideBorderHeight); + if (commentsOpen) { + self.commentButton.hidden = NO; + self.commentButton.frame = CGRectMake(buttonX, buttonY, buttonWidth, RPTVCControlButtonHeight); + buttonX -= buttonWidth + RPTVCControlButtonSpacing; + } else { + self.commentButton.hidden = YES; + } + _reblogButton.frame = CGRectMake(buttonX, buttonY, buttonWidth - RPTVCControlButtonBorderSize, RPTVCControlButtonHeight); + + CGFloat timeWidth = contentWidth - _reblogButton.frame.origin.x; + _timeButton.frame = CGRectMake(RPTVCHorizontalInnerPadding, RPTVCBorderHeight, timeWidth, RPTVCControlButtonHeight); + + CGFloat sideBorderX = RPTVCHorizontalOuterPadding - 1; // Just to the left of the container + CGFloat sideBorderHeight = self.frame.size.height - RPTVCVerticalPadding; // Just below it + _sideBorderView.frame = CGRectMake(sideBorderX, 1, self.frame.size.width - sideBorderX * 2, sideBorderHeight); } - (void)prepareForReuse { @@ -309,6 +462,7 @@ - (void)prepareForReuse { _bylineLabel.text = nil; _titleLabel.text = nil; _snippetLabel.text = nil; + [_tagButton setTitle:nil forState:UIControlStateNormal]; [self setHighlightedEffect:NO animated:NO]; } @@ -320,25 +474,19 @@ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(N [self updateControlBar]; } - -- (void)setReblogTarget:(id)target action:(SEL)selector { - [_reblogButton addTarget:target action:selector forControlEvents:UIControlEventTouchUpInside]; -} - - - (void)configureCell:(ReaderPost *)post { - self.post = post; // This will show the placeholder avatar. Do this here instead of prepareForReusue // so avatars show up after a cell is created, and not dequeued. [self setAvatar:nil]; - _titleLabel.text = [post.postTitle trim]; - _snippetLabel.text = post.summary; + _titleLabel.attributedText = [ReaderPostTableViewCell titleAttributedStringForPost:post]; + _snippetLabel.attributedText = [ReaderPostTableViewCell summaryAttributedStringForPost:post]; - NSString *onBlog = [NSString stringWithFormat:NSLocalizedString(@"on %@", @"'on ', displayed on reader list for each post"), post.blogName]; - _bylineLabel.text = [NSString stringWithFormat:@"%@\n%@", [post prettyDateString], onBlog]; + _bylineLabel.text = [post authorString]; + + [_timeButton setTitle:[post.dateCreated shortString] forState:UIControlStateNormal]; self.showImage = NO; self.cellImageView.hidden = YES; @@ -348,13 +496,22 @@ - (void)configureCell:(ReaderPost *)post { self.showImage = YES; self.cellImageView.hidden = NO; } + + if ([self.post.primaryTagName length] > 0) { + _tagButton.hidden = NO; + [_tagButton setTitle:self.post.primaryTagName forState:UIControlStateNormal]; + } else { + _tagButton.hidden = YES; + } if ([self.post isWPCom]) { _likeButton.hidden = NO; _reblogButton.hidden = NO; + _commentButton.hidden = NO; } else { _likeButton.hidden = YES; _reblogButton.hidden = YES; + _commentButton.hidden = YES; } _reblogButton.userInteractionEnabled = ![post.isReblogged boolValue]; @@ -362,16 +519,16 @@ - (void)configureCell:(ReaderPost *)post { [self updateControlBar]; } - - (void)setAvatar:(UIImage *)avatar { - if (_avatarIsSet) { + if (_avatarIsSet) return; - } + static UIImage *wpcomBlavatar; static UIImage *wporgBlavatar; if (!wpcomBlavatar) { wpcomBlavatar = [UIImage imageNamed:@"wpcom_blavatar"]; } + if (!wporgBlavatar) { wporgBlavatar = [UIImage imageNamed:@"wporg_blavatar"]; } @@ -384,27 +541,21 @@ - (void)setAvatar:(UIImage *)avatar { } } - - (void)setFeaturedImage:(UIImage *)image { self.cellImageView.contentMode = UIViewContentModeScaleAspectFill; self.cellImageView.image = image; } - - (void)updateControlBar { - if (!_post) return; + if (!_post) + return; _likeButton.selected = _post.isLiked.boolValue; _reblogButton.selected = _post.isReblogged.boolValue; _reblogButton.userInteractionEnabled = !_reblogButton.selected; - - NSString *str = ([self.post.likeCount integerValue] > 0) ? [self.post.likeCount stringValue] : nil; - [_likeButton setTitle:str forState:UIControlStateNormal]; } - -- (void)handleLikeButtonTapped:(id)sender { - +- (void)likeAction:(id)sender { [self.post toggleLikedWithSuccess:^{ if ([self.post.isLiked boolValue]) { [WPMobileStats trackEventForWPCom:StatsEventReaderLikedPost]; @@ -419,5 +570,4 @@ - (void)handleLikeButtonTapped:(id)sender { [self updateControlBar]; } - @end diff --git a/WordPress/Classes/ReaderPostsViewController.m b/WordPress/Classes/ReaderPostsViewController.m index 52b354f35dda..a152274401de 100644 --- a/WordPress/Classes/ReaderPostsViewController.m +++ b/WordPress/Classes/ReaderPostsViewController.m @@ -29,10 +29,9 @@ #import "WPPopoverBackgroundView.h" #import "IOS7CorrectedTextView.h" -#define IPAD_DETAIL_WIDTH 448.0f - -static CGFloat const ScrollingFastVelocityThreshold = 30.f; -NSString *const WPReaderViewControllerDisplayedNativeFriendFinder = @"DisplayedNativeFriendFinder"; +static CGFloat const RPVCScrollingFastVelocityThreshold = 30.f; +static CGFloat const RPVCHeaderHeightPhone = 10.f; +NSString *const RPVCDisplayedNativeFriendFinder = @"DisplayedNativeFriendFinder"; @interface ReaderPostsViewController () { BOOL _hasMoreContent; @@ -44,21 +43,11 @@ @interface ReaderPostsViewController () ScrollingFastVelocityThreshold && self.isScrolling) { + if (velocity > RPVCScrollingFastVelocityThreshold && self.isScrolling) { _isScrollingFast = YES; } else { _isScrollingFast = NO; @@ -479,9 +467,8 @@ - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { [self loadImagesForVisibleRows]; NSIndexPath *selectedIndexPath = [self.tableView indexPathForSelectedRow]; - if (!selectedIndexPath) { + if (!selectedIndexPath) return; - } __block BOOL found = NO; [[self.tableView indexPathsForVisibleRows] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { @@ -492,19 +479,13 @@ - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { *stop = YES; }]; - if (found) return; + if (found) + return; [self hideReblogForm]; } -#pragma mark - DetailView Delegate Methods - -- (void)resetView { - -} - - #pragma mark - WPTableViewSublass methods @@ -544,29 +525,23 @@ - (NSString *)noResultsPrompt { return prompt; } - - (UIView *)createNoResultsView { return [WPInfoView WPInfoViewWithTitle:[self noResultsPrompt] message:nil cancelButton:nil]; } - - (NSString *)entityName { return @"ReaderPost"; } - - (NSString *)resultsControllerCacheName { return [ReaderPost currentEndpoint]; } - - (NSDate *)lastSyncDate { return (NSDate *)[[NSUserDefaults standardUserDefaults] objectForKey:ReaderLastSyncDateKey]; } - - (NSFetchRequest *)fetchRequest { - NSString *endpoint = [ReaderPost currentEndpoint]; NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; @@ -580,26 +555,27 @@ - (NSFetchRequest *)fetchRequest { return fetchRequest; } - - (NSString *)sectionNameKeyPath { return nil; } - - (UITableViewCell *)newCell { NSString *cellIdentifier = @"ReaderPostCell"; ReaderPostTableViewCell *cell = (ReaderPostTableViewCell *)[self.tableView dequeueReusableCellWithIdentifier:cellIdentifier]; if (cell == nil) { cell = [[ReaderPostTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]; - cell.parentController = self; - [cell setReblogTarget:self action:@selector(handleReblogButtonTapped:)]; + [cell.reblogButton addTarget:self action:@selector(reblogAction:) forControlEvents:UIControlEventTouchUpInside]; + [cell.likeButton addTarget:self action:@selector(likeAction:) forControlEvents:UIControlEventTouchUpInside]; + [cell.followButton addTarget:self action:@selector(followAction:) forControlEvents:UIControlEventTouchUpInside]; + [cell.commentButton addTarget:self action:@selector(commentAction:) forControlEvents:UIControlEventTouchUpInside]; + [cell.tagButton addTarget:self action:@selector(tagAction:) forControlEvents:UIControlEventTouchUpInside]; } return cell; } - - (void)configureCell:(UITableViewCell *)aCell atIndexPath:(NSIndexPath *)indexPath { - if(!aCell) return; + if (!aCell) + return; ReaderPostTableViewCell *cell = (ReaderPostTableViewCell *)aCell; cell.selectionStyle = UITableViewCellSelectionStyleNone; @@ -624,13 +600,13 @@ - (void)configureCell:(UITableViewCell *)aCell atIndexPath:(NSIndexPath *)indexP - (void)setImageForPost:(ReaderPost *)post forCell:(ReaderPostTableViewCell *)cell indexPath:(NSIndexPath *)indexPath { NSURL *imageURL = post.featuredImageURL; - if (!imageURL) { + if (!imageURL) return; - } + CGSize imageSize = cell.cellImageView.bounds.size; if (CGSizeEqualToSize(imageSize, CGSizeZero)) { imageSize.width = self.tableView.bounds.size.width; - imageSize.height = round(imageSize.width * 0.66f); + imageSize.height = round(imageSize.width * RPTVCMaxImageHeightPercentage); } UIImage *image = [_featuredImageSource imageForURL:imageURL withSize:imageSize]; if (image) { @@ -644,16 +620,14 @@ - (BOOL)hasMoreContent { return _hasMoreContent; } - - (void)syncItemsWithSuccess:(void (^)())success failure:(void (^)(NSError *))failure { WPFLogMethod(); // if needs auth. - if([WPCookie hasCookieForURL:[NSURL URLWithString:@"https://wordpress.com"] andUsername:[[WPAccount defaultWordPressComAccount] username]]) { + if ([WPCookie hasCookieForURL:[NSURL URLWithString:@"https://wordpress.com"] andUsername:[[WPAccount defaultWordPressComAccount] username]]) { [self syncReaderItemsWithSuccess:success failure:failure]; return; } - - // + [[WordPressAppDelegate sharedWordPressApplicationDelegate] useDefaultUserAgent]; NSString *username = [[WPAccount defaultWordPressComAccount] username]; NSString *password = [[WPAccount defaultWordPressComAccount] password]; @@ -681,7 +655,6 @@ - (void)syncItemsWithSuccess:(void (^)())success failure:(void (^)(NSError *))fa [authRequest start]; } - - (void)syncReaderItemsWithSuccess:(void (^)())success failure:(void (^)(NSError *))failure { WPFLogMethod(); NSString *endpoint = [ReaderPost currentEndpoint]; @@ -705,22 +678,21 @@ - (void)syncReaderItemsWithSuccess:(void (^)())success failure:(void (^)(NSError [WPMobileStats pingWPComStatsEndpoint:@"home_page_refresh"]; } - - (void)loadMoreWithSuccess:(void (^)())success failure:(void (^)(NSError *error))failure { WPFLogMethod(); - if ([self.resultsController.fetchedObjects count] == 0) { + if ([self.resultsController.fetchedObjects count] == 0) return; - } - if (_loadingMore) return; + if (_loadingMore) + return; + _loadingMore = YES; - ReaderPost *post = self.resultsController.fetchedObjects.lastObject; NSNumber *numberToSync = [NSNumber numberWithInteger:ReaderPostsToSync]; NSString *endpoint = [ReaderPost currentEndpoint]; id before; - if([endpoint isEqualToString:@"freshly-pressed"]) { + if ([endpoint isEqualToString:@"freshly-pressed"]) { // freshly-pressed wants an ISO string but the rest want a timestamp. before = [DateUtils isoStringFromDate:post.date_created_gmt]; } else { @@ -749,12 +721,10 @@ - (void)loadMoreWithSuccess:(void (^)())success failure:(void (^)(NSError *error [WPMobileStats logQuantcastEvent:@"mobile.infinite_scroll"]; } - - (UITableViewRowAnimation)tableViewRowAnimation { return UITableViewRowAnimationNone; } - - (void)onSyncSuccess:(AFHTTPRequestOperation *)operation response:(id)responseObject { WPFLogMethod(); BOOL wasLoadingMore = _loadingMore; @@ -764,7 +734,7 @@ - (void)onSyncSuccess:(AFHTTPRequestOperation *)operation response:(id)responseO NSArray *postsArr = [resp arrayForKey:@"posts"]; if (!postsArr) { - if(wasLoadingMore) { + if (wasLoadingMore) { _hasMoreContent = NO; } return; @@ -774,8 +744,6 @@ - (void)onSyncSuccess:(AFHTTPRequestOperation *)operation response:(id)responseO if ([postsArr count] < ReaderPostsToSync && wasLoadingMore) { _hasMoreContent = NO; } - - [self configureTableHeader]; } @@ -786,6 +754,12 @@ - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPa return [ReaderPostTableViewCell cellHeightForPost:[self.resultsController objectAtIndexPath:indexPath] withWidth:self.tableView.bounds.size.width]; } +- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { + if (IS_IPHONE) + return RPVCHeaderHeightPhone; + + return [super tableView:tableView heightForHeaderInSection:section]; +} - (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath { if (_readerReblogFormView.superview != nil) { @@ -804,7 +778,6 @@ - (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NS return indexPath; } - - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { if (IS_IPAD) { [tableView deselectRowAtIndexPath:indexPath animated:YES]; @@ -819,7 +792,6 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath [WPMobileStats pingWPComStatsEndpoint:@"details_page"]; } - - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)aCell forRowAtIndexPath:(NSIndexPath *)indexPath { [super tableView:tableView willDisplayCell:aCell forRowAtIndexPath:indexPath]; @@ -828,6 +800,7 @@ - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)aC [self setImageForPost:post forCell:cell indexPath:indexPath]; } + #pragma mark - ReaderTopicsDelegate Methods - (void)readerTopicChanged { @@ -844,8 +817,6 @@ - (void)readerTopicChanged { [self.tableView reloadData]; [self syncItems]; - [self configureTableHeader]; - self.title = [[ReaderPost currentTopic] stringForKey:@"title"]; if ([WordPressAppDelegate sharedWordPressApplicationDelegate].connectionAvailable == YES && ![self isSyncing] ) { @@ -866,28 +837,24 @@ - (void)readerTopicChanged { #pragma mark - Utility -- (BOOL)isCurrentCategoryFreshlyPressed -{ +- (BOOL)isCurrentCategoryFreshlyPressed { return [[self currentCategory] isEqualToString:@"freshly-pressed"]; } -- (NSString *)currentCategory -{ +- (NSString *)currentCategory { NSDictionary *categoryDetails = [[NSUserDefaults standardUserDefaults] objectForKey:ReaderCurrentTopicKey]; NSString *category = [categoryDetails stringForKey:@"endpoint"]; if (category == nil) return @"reader/following"; - else - return category; + + return category; } -- (NSDictionary *)categoryPropertyForStats -{ +- (NSDictionary *)categoryPropertyForStats { return @{@"category": [self currentCategory]}; } - (void)fetchBlogsAndPrimaryBlog { - NSURL *xmlrpc; NSString *username, *password; WPAccount *account = [WPAccount defaultWordPressComAccount]; @@ -901,14 +868,12 @@ - (void)fetchBlogsAndPrimaryBlog { success:^(AFHTTPRequestOperation *operation, id responseObject) { NSArray *usersBlogs = responseObject; - if([usersBlogs count] > 0) { - + if ([usersBlogs count] > 0) { [usersBlogs enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { NSString *title = [obj valueForKey:@"blogName"]; title = [title stringByDecodingXMLCharacters]; [obj setValue:title forKey:@"blogName"]; }]; - } [[NSUserDefaults standardUserDefaults] setObject:usersBlogs forKey:@"wpcom_users_blogs"]; @@ -957,20 +922,28 @@ - (void)fetchBlogsAndPrimaryBlog { }]; } +- (CGSize)tabBarSize { + CGSize tabBarSize = CGSizeZero; + if ([self tabBarController]) { + tabBarSize = [[[self tabBarController] tabBar] bounds].size; + } + + return tabBarSize; +} + #pragma mark - Friend Finder Button -- (BOOL) shouldDisplayfriendFinderNudgeView { +- (BOOL)shouldDisplayfriendFinderNudgeView { NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; - return ![userDefaults boolForKey:WPReaderViewControllerDisplayedNativeFriendFinder] && self.friendFinderNudgeView == nil; + return ![userDefaults boolForKey:RPVCDisplayedNativeFriendFinder] && self.friendFinderNudgeView == nil; } - -- (void) showFriendFinderNudgeView:(id)sender { +- (void)showFriendFinderNudgeView:(id)sender { if ([self shouldDisplayfriendFinderNudgeView]) { NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; - [userDefaults setBool:YES forKey:WPReaderViewControllerDisplayedNativeFriendFinder]; + [userDefaults setBool:YES forKey:RPVCDisplayedNativeFriendFinder]; [userDefaults synchronize]; CGRect buttonFrame = CGRectMake(0,self.navigationController.view.frame.size.height,self.view.frame.size.width, 0.f); @@ -979,10 +952,7 @@ - (void) showFriendFinderNudgeView:(id)sender { self.friendFinderNudgeView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin; [self.navigationController.view addSubview:self.friendFinderNudgeView]; - CGSize tabBarSize = CGSizeZero; - if ([self tabBarController]) { - tabBarSize = [[[self tabBarController] tabBar] bounds].size; - } + CGSize tabBarSize = [self tabBarSize]; buttonFrame = self.friendFinderNudgeView.frame; buttonFrame.origin.y = self.navigationController.view.frame.size.height - buttonFrame.size.height - tabBarSize.height; @@ -996,11 +966,9 @@ - (void) showFriendFinderNudgeView:(id)sender { } } - -- (void) hideFriendFinderNudgeView:(id)sender { - if (self.friendFinderNudgeView == nil) { +- (void)hideFriendFinderNudgeView:(id)sender { + if (self.friendFinderNudgeView == nil) return; - } CGRect buttonFrame = self.friendFinderNudgeView.frame; CGRect viewFrame = self.view.frame; @@ -1013,7 +981,6 @@ - (void) hideFriendFinderNudgeView:(id)sender { }]; } - - (void)openFriendFinder:(id)sender { [self hideFriendFinderNudgeView:sender]; WPFriendFinderViewController *controller = [[WPFriendFinderViewController alloc] initWithNibName:@"WPWebViewController" bundle:nil]; @@ -1033,8 +1000,7 @@ - (void)openFriendFinder:(id)sender { #pragma mark - WPTableImageSourceDelegate -- (void)tableImageSource:(WPTableImageSource *)tableImageSource imageReady:(UIImage *)image forIndexPath:(NSIndexPath *)indexPath -{ +- (void)tableImageSource:(WPTableImageSource *)tableImageSource imageReady:(UIImage *)image forIndexPath:(NSIndexPath *)indexPath { if (!_isScrollingFast) { ReaderPostTableViewCell *cell = (ReaderPostTableViewCell *)[self.tableView cellForRowAtIndexPath:indexPath]; [cell setFeaturedImage:image]; diff --git a/WordPress/Classes/ReaderTableViewCell.h b/WordPress/Classes/ReaderTableViewCell.h index 918ad2dacbdf..671be6ad51eb 100644 --- a/WordPress/Classes/ReaderTableViewCell.h +++ b/WordPress/Classes/ReaderTableViewCell.h @@ -13,7 +13,6 @@ @interface ReaderTableViewCell : WPTableViewCell -@property (nonatomic, weak) UIViewController *parentController; @property (nonatomic, strong) UIImageView *cellImageView; @end diff --git a/WordPress/Classes/UIColor+Helpers.h b/WordPress/Classes/UIColor+Helpers.h index 226ef31987ca..ee2bdf19c3a0 100644 --- a/WordPress/Classes/UIColor+Helpers.h +++ b/WordPress/Classes/UIColor+Helpers.h @@ -10,12 +10,13 @@ @interface UIColor (Helpers) -//[UIColor UIColorFromRGBAColorWithRed:10 green:20 blue:30 alpha:0.8] -+(UIColor *)UIColorFromRGBColorWithRed:(CGFloat)r green:(CGFloat)g blue:(CGFloat)b; -+(UIColor *)UIColorFromRGBAColorWithRed: (CGFloat)r green:(CGFloat)g blue:(CGFloat)b alpha:(CGFloat)a; +// [UIColor UIColorFromRGBAColorWithRed:10 green:20 blue:30 alpha:0.8] ++ (UIColor *)UIColorFromRGBColorWithRed:(CGFloat)r green:(CGFloat)g blue:(CGFloat)b; ++ (UIColor *)UIColorFromRGBAColorWithRed: (CGFloat)r green:(CGFloat)g blue:(CGFloat)b alpha:(CGFloat)a; -//[UIColor UIColorFromHex:0xc5c5c5 alpha:0.8]; -+(UIColor *)UIColorFromHex:(NSUInteger)rgb alpha:(CGFloat)alpha; -+(UIColor *)UIColorFromHex:(NSUInteger)rgb; +// [UIColor UIColorFromHex:0xc5c5c5 alpha:0.8]; ++ (UIColor *)UIColorFromHex:(NSUInteger)rgb alpha:(CGFloat)alpha; ++ (UIColor *)UIColorFromHex:(NSUInteger)rgb; ++ (UIColor *)colorWithHexString:(NSString *)hex; @end diff --git a/WordPress/Classes/UIColor+Helpers.m b/WordPress/Classes/UIColor+Helpers.m index 28eec3f02bc8..2897513a86c6 100644 --- a/WordPress/Classes/UIColor+Helpers.m +++ b/WordPress/Classes/UIColor+Helpers.m @@ -7,30 +7,47 @@ // #import "UIColor+Helpers.h" +#import "NSString+HTML.h" @implementation UIColor (Helpers) -//[UIColor UIColorFromRGBAColorWithRed:10 green:20 blue:30 alpha:0.8] -+(UIColor *)UIColorFromRGBAColorWithRed: (CGFloat)r green:(CGFloat)g blue:(CGFloat)b alpha:(CGFloat)a { +// [UIColor UIColorFromRGBAColorWithRed:10 green:20 blue:30 alpha:0.8] ++ (UIColor *)UIColorFromRGBAColorWithRed: (CGFloat)r green:(CGFloat)g blue:(CGFloat)b alpha:(CGFloat)a { return [UIColor colorWithRed: r/255.0 green: g/255.0 blue: b/255.0 alpha:a]; } -//[UIColor UIColorFromRGBColorWithRed:10 green:20 blue:30] -+(UIColor *)UIColorFromRGBColorWithRed:(CGFloat)r green:(CGFloat)g blue:(CGFloat)b { +// [UIColor UIColorFromRGBColorWithRed:10 green:20 blue:30] ++ (UIColor *)UIColorFromRGBColorWithRed:(CGFloat)r green:(CGFloat)g blue:(CGFloat)b { return [UIColor colorWithRed: r/255.0 green: g/255.0 blue: b/255.0 alpha: 0.5]; } -//[UIColor UIColorFromHex:0xc5c5c5 alpha:0.8]; -+(UIColor *)UIColorFromHex:(NSUInteger)rgb alpha:(CGFloat)alpha { +// [UIColor UIColorFromHex:0xc5c5c5 alpha:0.8]; ++ (UIColor *)UIColorFromHex:(NSUInteger)rgb alpha:(CGFloat)alpha { return [UIColor colorWithRed:((float)((rgb & 0xFF0000) >> 16))/255.0 green:((float)((rgb & 0xFF00) >> 8))/255.0 blue:((float)(rgb & 0xFF))/255.0 alpha:alpha]; } -//[UIColor UIColorFromHex:0xc5c5c5]; -+(UIColor *)UIColorFromHex:(NSUInteger)rgb { +// [UIColor UIColorFromHex:0xc5c5c5]; ++ (UIColor *)UIColorFromHex:(NSUInteger)rgb { return [UIColor UIColorFromHex:rgb alpha:1.0]; } ++ (UIColor *)colorWithHexString:(NSString *)hex { + if ([hex length]!=6 && [hex length]!=3) + { + return nil; + } + + NSUInteger digits = [hex length]/3; + CGFloat maxValue = (digits==1)?15.0:255.0; + + CGFloat red = [[hex substringWithRange:NSMakeRange(0, digits)] integerValueFromHex]/maxValue; + CGFloat green = [[hex substringWithRange:NSMakeRange(digits, digits)] integerValueFromHex]/maxValue; + CGFloat blue = [[hex substringWithRange:NSMakeRange(2*digits, digits)] integerValueFromHex]/maxValue; + + return [UIColor colorWithRed:red green:green blue:blue alpha:1.0]; +} + @end diff --git a/WordPress/Classes/UILabel+SuggestSize.h b/WordPress/Classes/UILabel+SuggestSize.h index e3811feee887..2f2542a90e05 100644 --- a/WordPress/Classes/UILabel+SuggestSize.h +++ b/WordPress/Classes/UILabel+SuggestSize.h @@ -11,6 +11,7 @@ @interface UILabel (SuggestSize) - (CGSize)suggestedSizeForWidth:(CGFloat)width; -- (CGSize)suggestSizeForString:(NSString *)string atWidth:(CGFloat)width; +- (CGSize)suggestSizeForAttributedString:(NSAttributedString *)string width:(CGFloat)width; +- (CGSize)suggestSizeForString:(NSString *)string width:(CGFloat)width; @end diff --git a/WordPress/Classes/UILabel+SuggestSize.m b/WordPress/Classes/UILabel+SuggestSize.m index ef4362be89e9..e59c89ca7bef 100644 --- a/WordPress/Classes/UILabel+SuggestSize.m +++ b/WordPress/Classes/UILabel+SuggestSize.m @@ -11,16 +11,18 @@ @implementation UILabel (SuggestSize) - (CGSize)suggestedSizeForWidth:(CGFloat)width { - - return [self suggestSizeForString:self.text atWidth:width]; - + if (self.attributedText) + return [self suggestSizeForAttributedString:self.attributedText width:width]; + + return [self suggestSizeForString:self.text width:width]; } +- (CGSize)suggestSizeForAttributedString:(NSAttributedString *)string width:(CGFloat)width { + return [string boundingRectWithSize:CGSizeMake(width, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading context:nil].size; +} -- (CGSize)suggestSizeForString:(NSString *)string atWidth:(CGFloat)width { - - return [string sizeWithFont:self.font constrainedToSize:CGSizeMake(width, 9999.0f) lineBreakMode:self.lineBreakMode]; - +- (CGSize)suggestSizeForString:(NSString *)string width:(CGFloat)width { + return [string sizeWithFont:self.font constrainedToSize:CGSizeMake(width, CGFLOAT_MAX) lineBreakMode:self.lineBreakMode]; } @end diff --git a/WordPress/Classes/WordPress.xcdatamodeld/.xccurrentversion b/WordPress/Classes/WordPress.xcdatamodeld/.xccurrentversion index c3e07b633d3c..3a9336008fb5 100644 --- a/WordPress/Classes/WordPress.xcdatamodeld/.xccurrentversion +++ b/WordPress/Classes/WordPress.xcdatamodeld/.xccurrentversion @@ -3,6 +3,6 @@ _XCCurrentVersionName - WordPress 12.xcdatamodel + WordPress 13.xcdatamodel diff --git a/WordPress/Classes/WordPress.xcdatamodeld/WordPress 13.xcdatamodel/elements b/WordPress/Classes/WordPress.xcdatamodeld/WordPress 13.xcdatamodel/elements new file mode 100644 index 000000000000..ef09848e36b0 Binary files /dev/null and b/WordPress/Classes/WordPress.xcdatamodeld/WordPress 13.xcdatamodel/elements differ diff --git a/WordPress/Classes/WordPress.xcdatamodeld/WordPress 13.xcdatamodel/layout b/WordPress/Classes/WordPress.xcdatamodeld/WordPress 13.xcdatamodel/layout new file mode 100644 index 000000000000..e2ac3a0bbdeb Binary files /dev/null and b/WordPress/Classes/WordPress.xcdatamodeld/WordPress 13.xcdatamodel/layout differ diff --git a/WordPress/Info.plist b/WordPress/Info.plist index f06e1535e03a..967f0e3eb133 100644 --- a/WordPress/Info.plist +++ b/WordPress/Info.plist @@ -54,6 +54,7 @@ OpenSans-Italic.ttf OpenSans-BoldItalic.ttf OpenSans-LightItalic.ttf + Merriweather-Bold.ttf UIBackgroundModes diff --git a/WordPress/Merriweather-Bold.ttf b/WordPress/Merriweather-Bold.ttf new file mode 100755 index 000000000000..2340777c83a7 Binary files /dev/null and b/WordPress/Merriweather-Bold.ttf differ diff --git a/WordPress/Resources/Images/reader-postaction-comment-blue.png b/WordPress/Resources/Images/reader-postaction-comment-blue.png index aff9f6d04200..390ce5d72b74 100644 Binary files a/WordPress/Resources/Images/reader-postaction-comment-blue.png and b/WordPress/Resources/Images/reader-postaction-comment-blue.png differ diff --git a/WordPress/Resources/Images/reader-postaction-comment-blue@2x.png b/WordPress/Resources/Images/reader-postaction-comment-blue@2x.png index ba9f9543c815..811e1dbe2187 100644 Binary files a/WordPress/Resources/Images/reader-postaction-comment-blue@2x.png and b/WordPress/Resources/Images/reader-postaction-comment-blue@2x.png differ diff --git a/WordPress/Resources/Images/reader-postaction-follow.png b/WordPress/Resources/Images/reader-postaction-follow.png index 5c6be6097a08..8aecf396f1ab 100644 Binary files a/WordPress/Resources/Images/reader-postaction-follow.png and b/WordPress/Resources/Images/reader-postaction-follow.png differ diff --git a/WordPress/Resources/Images/reader-postaction-follow@2x.png b/WordPress/Resources/Images/reader-postaction-follow@2x.png index 173970cc906e..3cd80a817078 100644 Binary files a/WordPress/Resources/Images/reader-postaction-follow@2x.png and b/WordPress/Resources/Images/reader-postaction-follow@2x.png differ diff --git a/WordPress/Resources/Images/reader-postaction-following.png b/WordPress/Resources/Images/reader-postaction-following.png index ef7173e14ee6..450bf693c9ae 100644 Binary files a/WordPress/Resources/Images/reader-postaction-following.png and b/WordPress/Resources/Images/reader-postaction-following.png differ diff --git a/WordPress/Resources/Images/reader-postaction-following@2x.png b/WordPress/Resources/Images/reader-postaction-following@2x.png index 192ff8983d2a..8301b27a7761 100644 Binary files a/WordPress/Resources/Images/reader-postaction-following@2x.png and b/WordPress/Resources/Images/reader-postaction-following@2x.png differ diff --git a/WordPress/Resources/Images/reader-postaction-like-blue.png b/WordPress/Resources/Images/reader-postaction-like-blue.png index 937e991ea04c..40257bb876ce 100644 Binary files a/WordPress/Resources/Images/reader-postaction-like-blue.png and b/WordPress/Resources/Images/reader-postaction-like-blue.png differ diff --git a/WordPress/Resources/Images/reader-postaction-like-blue@2x.png b/WordPress/Resources/Images/reader-postaction-like-blue@2x.png index 171c01791159..1a9f0615267a 100644 Binary files a/WordPress/Resources/Images/reader-postaction-like-blue@2x.png and b/WordPress/Resources/Images/reader-postaction-like-blue@2x.png differ diff --git a/WordPress/Resources/Images/reader-postaction-reblog-blue.png b/WordPress/Resources/Images/reader-postaction-reblog-blue.png index 027f0160b449..818c87a90030 100644 Binary files a/WordPress/Resources/Images/reader-postaction-reblog-blue.png and b/WordPress/Resources/Images/reader-postaction-reblog-blue.png differ diff --git a/WordPress/Resources/Images/reader-postaction-reblog-blue@2x.png b/WordPress/Resources/Images/reader-postaction-reblog-blue@2x.png index 3fc42553a5a5..ad82fa24938e 100644 Binary files a/WordPress/Resources/Images/reader-postaction-reblog-blue@2x.png and b/WordPress/Resources/Images/reader-postaction-reblog-blue@2x.png differ diff --git a/WordPress/Resources/Images/reader-postaction-tag.png b/WordPress/Resources/Images/reader-postaction-tag.png new file mode 100644 index 000000000000..8d737ce0eb18 Binary files /dev/null and b/WordPress/Resources/Images/reader-postaction-tag.png differ diff --git a/WordPress/Resources/Images/reader-postaction-tag@2x.png b/WordPress/Resources/Images/reader-postaction-tag@2x.png new file mode 100644 index 000000000000..548f0e116f14 Binary files /dev/null and b/WordPress/Resources/Images/reader-postaction-tag@2x.png differ diff --git a/WordPress/Resources/Images/reader-postaction-time.png b/WordPress/Resources/Images/reader-postaction-time.png new file mode 100644 index 000000000000..2a4425624b86 Binary files /dev/null and b/WordPress/Resources/Images/reader-postaction-time.png differ diff --git a/WordPress/Resources/Images/reader-postaction-time@2x.png b/WordPress/Resources/Images/reader-postaction-time@2x.png new file mode 100644 index 000000000000..53680cd28574 Binary files /dev/null and b/WordPress/Resources/Images/reader-postaction-time@2x.png differ diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 7955602267f0..383a47b26a9a 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -292,6 +292,12 @@ 462F4E0A18369F0B0028D2F8 /* BlogDetailsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 462F4E0718369F0B0028D2F8 /* BlogDetailsViewController.m */; }; 462F4E0B18369F0B0028D2F8 /* BlogListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 462F4E0918369F0B0028D2F8 /* BlogListViewController.m */; }; 462F4E0E18369F300028D2F8 /* WPTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 462F4E0D18369F300028D2F8 /* WPTableViewCell.m */; }; + 462F4E10183867AE0028D2F8 /* Merriweather-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 462F4E0F183867AE0028D2F8 /* Merriweather-Bold.ttf */; }; + 46F8714B1838BB4E00BC149B /* reader-postaction-tag.png in Resources */ = {isa = PBXBuildFile; fileRef = 46F871491838BB4E00BC149B /* reader-postaction-tag.png */; }; + 46F8714C1838BB4E00BC149B /* reader-postaction-tag@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 46F8714A1838BB4E00BC149B /* reader-postaction-tag@2x.png */; }; + 46F8714F1838C41600BC149B /* NSDate+StringFormatting.m in Sources */ = {isa = PBXBuildFile; fileRef = 46F8714E1838C41600BC149B /* NSDate+StringFormatting.m */; }; + 46F871521839528C00BC149B /* reader-postaction-time.png in Resources */ = {isa = PBXBuildFile; fileRef = 46F871501839528C00BC149B /* reader-postaction-time.png */; }; + 46F871531839528C00BC149B /* reader-postaction-time@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 46F871511839528C00BC149B /* reader-postaction-time@2x.png */; }; 5D0077A7182AE9DF00F865DB /* ReaderMediaQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D0077A6182AE9DF00F865DB /* ReaderMediaQueue.m */; }; 5D119DA3176FBE040073D83A /* UIImageView+AFNetworkingExtra.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D119DA2176FBE040073D83A /* UIImageView+AFNetworkingExtra.m */; }; 5D1392A7157D4D92007D51B8 /* StatsWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D1392A6157D4D92007D51B8 /* StatsWebViewController.m */; }; @@ -1301,6 +1307,14 @@ 462F4E0918369F0B0028D2F8 /* BlogListViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BlogListViewController.m; sourceTree = ""; }; 462F4E0C18369F300028D2F8 /* WPTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WPTableViewCell.h; sourceTree = ""; }; 462F4E0D18369F300028D2F8 /* WPTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WPTableViewCell.m; sourceTree = ""; }; + 462F4E0F183867AE0028D2F8 /* Merriweather-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Merriweather-Bold.ttf"; sourceTree = ""; }; + 46F871491838BB4E00BC149B /* reader-postaction-tag.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "reader-postaction-tag.png"; path = "Resources/Images/reader-postaction-tag.png"; sourceTree = ""; }; + 46F8714A1838BB4E00BC149B /* reader-postaction-tag@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "reader-postaction-tag@2x.png"; path = "Resources/Images/reader-postaction-tag@2x.png"; sourceTree = ""; }; + 46F8714D1838C41600BC149B /* NSDate+StringFormatting.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDate+StringFormatting.h"; sourceTree = ""; }; + 46F8714E1838C41600BC149B /* NSDate+StringFormatting.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDate+StringFormatting.m"; sourceTree = ""; }; + 46F871501839528C00BC149B /* reader-postaction-time.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "reader-postaction-time.png"; path = "Resources/Images/reader-postaction-time.png"; sourceTree = ""; }; + 46F871511839528C00BC149B /* reader-postaction-time@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "reader-postaction-time@2x.png"; path = "Resources/Images/reader-postaction-time@2x.png"; sourceTree = ""; }; + 46F871551839802100BC149B /* WordPress 13.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = file; path = "WordPress 13.xcdatamodel"; sourceTree = ""; }; 5D0077A5182AE9DF00F865DB /* ReaderMediaQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReaderMediaQueue.h; sourceTree = ""; }; 5D0077A6182AE9DF00F865DB /* ReaderMediaQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ReaderMediaQueue.m; sourceTree = ""; }; 5D119DA1176FBE040073D83A /* UIImageView+AFNetworkingExtra.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImageView+AFNetworkingExtra.h"; sourceTree = ""; }; @@ -3100,6 +3114,7 @@ 858DE3FF172F9991000AC628 /* Fonts */ = { isa = PBXGroup; children = ( + 462F4E0F183867AE0028D2F8 /* Merriweather-Bold.ttf */, 5D358D6417723DB500739AA4 /* OpenSans-Bold.ttf */, 858DE41017303BB4000AC628 /* OpenSans-Light.ttf */, 858DE41117303BB4000AC628 /* OpenSans-Regular.ttf */, @@ -3333,6 +3348,10 @@ isa = PBXGroup; children = ( 462F4E0518369B370028D2F8 /* Tabs */, + 46F871501839528C00BC149B /* reader-postaction-time.png */, + 46F871511839528C00BC149B /* reader-postaction-time@2x.png */, + 46F871491838BB4E00BC149B /* reader-postaction-tag.png */, + 46F8714A1838BB4E00BC149B /* reader-postaction-tag@2x.png */, E14D65C117E08617007E3EA4 /* reader-postaction-comment-blue.png */, E14D65C217E08617007E3EA4 /* reader-postaction-comment-blue@2x.png */, E14D65BD17E08524007E3EA4 /* reader-postaction-reblog-blue.png */, @@ -3765,6 +3784,8 @@ 5DF59C0A1770AE3A00171208 /* UILabel+SuggestSize.m */, 851734411798C64700A30E27 /* NSURL+Util.h */, 851734421798C64700A30E27 /* NSURL+Util.m */, + 46F8714D1838C41600BC149B /* NSDate+StringFormatting.h */, + 46F8714E1838C41600BC149B /* NSDate+StringFormatting.m */, ); name = Categories; sourceTree = ""; @@ -4346,6 +4367,7 @@ E177087E13AAC19700EA6C72 /* redo~ipad.png in Resources */, E177087F13AAC19700EA6C72 /* redoDisabled~ipad.png in Resources */, 85AC70F017C71B5100985E3B /* comment-default-gravatar-image.png in Resources */, + 462F4E10183867AE0028D2F8 /* Merriweather-Bold.ttf in Resources */, E177088013AAC19700EA6C72 /* undo~ipad.png in Resources */, E177088113AAC19700EA6C72 /* undoDisabled~ipad.png in Resources */, 85325A4417BB0DF8008E87D1 /* icon-menu-pages-active.png in Resources */, @@ -4429,6 +4451,7 @@ 857F55CF17CEC5E100E154E1 /* keyboardButtonHighlighted-ios7@2x.png in Resources */, E18165FD14E4428B006CE885 /* loader.html in Resources */, E128566415103A3600406BC9 /* keyboardButtoniPad@2x.png in Resources */, + 46F871531839528C00BC149B /* reader-postaction-time@2x.png in Resources */, E128566515103A3600406BC9 /* keyboardButtoniPadHighlighted@2x.png in Resources */, 30811743151057880028A15E /* Default-Portrait@2x.png in Resources */, 30811744151057880028A15E /* Default-Landscape@2x.png in Resources */, @@ -4493,6 +4516,7 @@ 462F4E0118369B200028D2F8 /* icon-tab-notifications.png in Resources */, 374F18C415A5897500524ED0 /* sidebar_read.png in Resources */, 374F18C515A5897500524ED0 /* sidebar_read@2x.png in Resources */, + 46F8714C1838BB4E00BC149B /* reader-postaction-tag@2x.png in Resources */, 85ED54F317CC1A01006564AE /* icon-posts-editor-preview.png in Resources */, 374F18C615A5897500524ED0 /* sidebar_settings.png in Resources */, 374F18C715A5897500524ED0 /* sidebar_settings@2x.png in Resources */, @@ -4555,6 +4579,7 @@ 37B159F415AC7CEB00333C91 /* sidebar_cell_bg@2x.png in Resources */, 37B159F515AC7CEB00333C91 /* sidebar_cell_bg.png in Resources */, 30E9683C15AE4EB10047DD84 /* sidebar-logo.png in Resources */, + 46F8714B1838BB4E00BC149B /* reader-postaction-tag.png in Resources */, 30E9683D15AE4EB10047DD84 /* sidebar-logo@2x.png in Resources */, 30E9684115AE60B20047DD84 /* navbar_add.png in Resources */, E232E603182EA16200792CA0 /* icon-password-field.png in Resources */, @@ -4651,6 +4676,7 @@ 5D15F4DD15B8C43E001B14EA /* toolbarBoldHighlighted@2x.png in Resources */, 5D15F4DE15B8C43E001B14EA /* toolbarBoldiPad.png in Resources */, 5D15F4DF15B8C43E001B14EA /* toolbarBoldiPad@2x.png in Resources */, + 46F871521839528C00BC149B /* reader-postaction-time.png in Resources */, 5D15F4E015B8C43E001B14EA /* toolbarCodeHighlighted.png in Resources */, 5D15F4E115B8C43E001B14EA /* toolbarCodeHighlighted@2x.png in Resources */, 5D15F4E215B8C43E001B14EA /* toolbarCodeiPad.png in Resources */, @@ -5037,6 +5063,7 @@ 031663070FFB151A0045D052 /* PostTableViewCell.m in Sources */, 031666AE0FFC3E130045D052 /* CommentTableViewCell.m in Sources */, 03958062100D6CFC00850742 /* WPLabel.m in Sources */, + 46F8714F1838C41600BC149B /* NSDate+StringFormatting.m in Sources */, 296526FE105810E100597FA3 /* NSString+Helpers.m in Sources */, 2994EEEE10DF0FCD008336A6 /* ReplyToCommentViewController.m in Sources */, 2906F812110CDA8900169D56 /* EditCommentViewController.m in Sources */, @@ -5666,6 +5693,7 @@ E125443B12BF5A7200D87A0A /* WordPress.xcdatamodeld */ = { isa = XCVersionGroup; children = ( + 46F871551839802100BC149B /* WordPress 13.xcdatamodel */, 5D42A3BB175E686F005CFF05 /* WordPress 12.xcdatamodel */, E17B98E7171FFB450073E30D /* WordPress 11.xcdatamodel */, FDFB011916B1EA1C00F589A8 /* WordPress 10.xcdatamodel */, @@ -5679,7 +5707,7 @@ 8350E15911D28B4A00A7B073 /* WordPress.xcdatamodel */, E125443D12BF5A7200D87A0A /* WordPress 2.xcdatamodel */, ); - currentVersion = 5D42A3BB175E686F005CFF05 /* WordPress 12.xcdatamodel */; + currentVersion = 46F871551839802100BC149B /* WordPress 13.xcdatamodel */; name = WordPress.xcdatamodeld; path = Classes/WordPress.xcdatamodeld; sourceTree = "";